diff --git a/CMakeLists.txt b/CMakeLists.txt index 480f011..c5c24d5 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -22,7 +22,9 @@ endif() if(${CMAKE_SYSTEM_NAME} STREQUAL "Darwin" AND NOT IOS) message("macOS build detected!") - set(ENABLE_METAL TRUE) + find_package(SDL2 REQUIRED) + + set(ENABLE_VULKAN TRUE) set(ENABLE_DARWIN TRUE) set(ENABLE_MACOS TRUE) diff --git a/engine/gfx/metal/CMakeLists.txt b/engine/gfx/metal/CMakeLists.txt deleted file mode 100755 index c2c9841..0000000 --- a/engine/gfx/metal/CMakeLists.txt +++ /dev/null @@ -1,29 +0,0 @@ -set(SRC - include/gfx_metal.hpp - - src/gfx_metal.mm - src/gfx_metal_buffer.hpp - src/gfx_metal_pipeline.hpp - src/gfx_metal_texture.hpp - src/gfx_metal_framebuffer.hpp - src/gfx_metal_renderpass.hpp - src/gfx_metal_sampler.hpp) - -add_library(GFXMetal STATIC - ${SRC}) - -set_target_properties(GFXMetal PROPERTIES - FRAMEWORK TRUE - FRAMEWORK_VERSION OBJC - PUBLIC_HEADER "${HEADERS}" -) -target_link_libraries(GFXMetal PUBLIC - GFX - Core - Log - "-framework Metal") -target_include_directories(GFXMetal PUBLIC - include - PRIVATE - src) -set_engine_properties(GFXMetal) diff --git a/engine/gfx/metal/include/gfx_metal.hpp b/engine/gfx/metal/include/gfx_metal.hpp deleted file mode 100755 index 143a268..0000000 --- a/engine/gfx/metal/include/gfx_metal.hpp +++ /dev/null @@ -1,70 +0,0 @@ -#pragma once - -#include -#include - -#include "gfx.hpp" - -class GFXMetal : public GFX { -public: - bool is_supported() override; - GFXContext required_context() override { return GFXContext::Metal; } - ShaderLanguage accepted_shader_language() override { return ShaderLanguage::MSL; } - const char* get_name() override; - - bool supports_feature(const GFXFeature feature) override; - - bool initialize(const GFXCreateInfo& createInfo) override; - - void initialize_view(void* native_handle, const int identifier, const uint32_t width, const uint32_t height) override; - void remove_view(const int identifier) override; - - // buffer operations - GFXBuffer* create_buffer(void* data, const GFXSize size, const bool dynamicData, const GFXBufferUsage usage) override; - void copy_buffer(GFXBuffer* buffer, void* data, const GFXSize offset, const GFXSize size) override; - - void* get_buffer_contents(GFXBuffer* buffer) override; - - // texture operations - GFXTexture* create_texture(const GFXTextureCreateInfo& info) override; - void copy_texture(GFXTexture* texture, void* data, GFXSize size) override; - void copy_texture(GFXTexture* from, GFXTexture* to) override; - void copy_texture(GFXTexture* from, GFXBuffer* to) override; - - // sampler opeations - GFXSampler* create_sampler(const GFXSamplerCreateInfo& info) override; - - // framebuffer operations - GFXFramebuffer* create_framebuffer(const GFXFramebufferCreateInfo& info) override; - - // render pass operations - GFXRenderPass* create_render_pass(const GFXRenderPassCreateInfo& info) override; - - // pipeline operations - GFXPipeline* create_graphics_pipeline(const GFXGraphicsPipelineCreateInfo& info) override; - GFXPipeline* create_compute_pipeline(const GFXComputePipelineCreateInfo& info) override; - - GFXCommandBuffer* acquire_command_buffer(bool for_presentation_use = false) override; - - void submit(GFXCommandBuffer* command_buffer, const int window = -1) override; - -private: - struct NativeMTLView { - int identifier = -1; - CAMetalLayer* layer = nullptr; - }; - - std::vector nativeViews; - - NativeMTLView* getNativeView(int identifier) { - for(auto& view : nativeViews) { - if(view->identifier == identifier) - return view; - } - - return nullptr; - } - - id device = nil; - id command_queue = nil; -}; diff --git a/engine/gfx/metal/src/gfx_metal.mm b/engine/gfx/metal/src/gfx_metal.mm deleted file mode 100755 index 37c6c16..0000000 --- a/engine/gfx/metal/src/gfx_metal.mm +++ /dev/null @@ -1,1115 +0,0 @@ -#include "gfx_metal.hpp" - -#include "gfx_metal_buffer.hpp" -#include "gfx_metal_pipeline.hpp" -#include "gfx_commandbuffer.hpp" -#include "gfx_metal_texture.hpp" -#include "gfx_metal_renderpass.hpp" -#include "gfx_metal_framebuffer.hpp" -#include "gfx_metal_sampler.hpp" -#include "file.hpp" -#include "log.hpp" -#include "utility.hpp" -#include "string_utils.hpp" - -static inline bool debug_enabled = false; - -static inline std::array command_buffers; -static inline std::array free_command_buffers; - -MTLPixelFormat toPixelFormat(GFXPixelFormat format) { - switch(format) { - case GFXPixelFormat::R_32F: - return MTLPixelFormatR32Float; - case GFXPixelFormat::R_16F: - return MTLPixelFormatR16Float; - case GFXPixelFormat::RGBA_32F: - return MTLPixelFormatRGBA32Float; - case GFXPixelFormat::RGBA8_UNORM: - return MTLPixelFormatRGBA8Unorm; - case GFXPixelFormat::R8_UNORM: - return MTLPixelFormatR8Unorm; - case GFXPixelFormat::R8G8_UNORM: - return MTLPixelFormatRG8Unorm; - case GFXPixelFormat::R8G8_SFLOAT: - return MTLPixelFormatRG16Float; - case GFXPixelFormat::R8G8B8A8_UNORM: - return MTLPixelFormatRGBA8Unorm; - case GFXPixelFormat::R16G16B16A16_SFLOAT: - return MTLPixelFormatRGBA16Float; - case GFXPixelFormat::DEPTH_32F: - return MTLPixelFormatDepth32Float; - } -} - -MTLBlendFactor toBlendFactor(GFXBlendFactor factor) { - switch(factor) { - case GFXBlendFactor::One: - return MTLBlendFactorOne; - case GFXBlendFactor::Zero: - return MTLBlendFactorZero; - case GFXBlendFactor::SrcColor: - return MTLBlendFactorSourceColor; - case GFXBlendFactor::DstColor: - return MTLBlendFactorDestinationColor; - case GFXBlendFactor::SrcAlpha: - return MTLBlendFactorSourceAlpha; - case GFXBlendFactor::DstAlpha: - return MTLBlendFactorDestinationAlpha; - case GFXBlendFactor::OneMinusSrcAlpha: - return MTLBlendFactorOneMinusSourceAlpha; - case GFXBlendFactor::OneMinusSrcColor: - return MTLBlendFactorOneMinusSourceColor; - } -} - -MTLSamplerAddressMode toSamplingMode(SamplingMode mode) { - switch(mode) { - case SamplingMode::Repeat: - return MTLSamplerAddressModeRepeat; - case SamplingMode::ClampToEdge: - return MTLSamplerAddressModeClampToEdge; - case SamplingMode::ClampToBorder: - { -#if defined(PLATFORM_IOS) || defined(PLATFORM_TVOS) - return MTLSamplerAddressModeRepeat; -#else - return MTLSamplerAddressModeClampToBorderColor; -#endif - } - } -} - -#if !defined(PLATFORM_IOS) && !defined(PLATFORM_TVOS) -MTLSamplerBorderColor toBorderColor(GFXBorderColor color) { - switch(color) { - case GFXBorderColor::OpaqueWhite: - return MTLSamplerBorderColorOpaqueWhite; - case GFXBorderColor::OpaqueBlack: - return MTLSamplerBorderColorOpaqueBlack; - } -} -#endif - -MTLCompareFunction toCompare(GFXCompareFunction function) { - switch(function) { - case GFXCompareFunction::Never: - return MTLCompareFunctionNever; - case GFXCompareFunction::Less: - return MTLCompareFunctionLess; - case GFXCompareFunction::Equal: - return MTLCompareFunctionEqual; - case GFXCompareFunction::LessOrEqual: - return MTLCompareFunctionLessEqual; - case GFXCompareFunction::Greater: - return MTLCompareFunctionGreater; - case GFXCompareFunction::NotEqual: - return MTLCompareFunctionNotEqual; - case GFXCompareFunction::GreaterOrEqual: - return MTLCompareFunctionGreaterEqual; - case GFXCompareFunction::Always: - return MTLCompareFunctionAlways; - } -} - -MTLSamplerMinMagFilter toFilter(GFXFilter filter) { - switch(filter) { - case GFXFilter::Nearest: - return MTLSamplerMinMagFilterNearest; - case GFXFilter::Linear: - return MTLSamplerMinMagFilterLinear; - } -} - -MTLWinding toWinding(GFXWindingMode mode) { - switch(mode) { - case GFXWindingMode::Clockwise: - return MTLWindingClockwise; - case GFXWindingMode::CounterClockwise: - return MTLWindingCounterClockwise; - } -} - -bool GFXMetal::is_supported() { - return true; -} - -bool GFXMetal::initialize(const GFXCreateInfo& createInfo) { - debug_enabled = createInfo.api_validation_enabled; - - device = MTLCreateSystemDefaultDevice(); - if(device) { - command_queue = [device newCommandQueue]; - - for(int i = 0; i < 15; i++) { - command_buffers[i] = new GFXCommandBuffer(); - free_command_buffers[i] = true; - } - - return true; - } else { - return false; - } -} - -const char* GFXMetal::get_name() { - return "Metal"; -} - -bool GFXMetal::supports_feature(const GFXFeature feature) { - if(feature == GFXFeature::CubemapArray) { -#if defined(PLATFORM_TVOS) - return false; -#else - return true; -#endif - } - - return false; -} - -void GFXMetal::initialize_view(void* native_handle, const int identifier, const uint32_t, const uint32_t) { - NativeMTLView* native = new NativeMTLView(); - native->identifier = identifier; - - native->layer = (CAMetalLayer*)native_handle; - native->layer.device = device; - - native->layer.allowsNextDrawableTimeout = true; - - nativeViews.push_back(native); -} - -void GFXMetal::remove_view(const int identifier) { - utility::erase_if(nativeViews, [identifier](NativeMTLView* view) { - return view->identifier == identifier; - }); -} - -GFXBuffer* GFXMetal::create_buffer(void* data, const GFXSize size, const bool dynamicData, const GFXBufferUsage) { - GFXMetalBuffer* buffer = new GFXMetalBuffer(); - buffer->dynamicData = dynamicData; - - if(buffer->dynamicData) { - for(int i = 0; i < 3; i++) { - if(data == nullptr) { - buffer->handles[i] = [device newBufferWithLength:(NSUInteger)size options:MTLResourceStorageModeShared]; - } else { - buffer->handles[i] = [device newBufferWithBytes:data - length:(NSUInteger)size - options:MTLResourceStorageModeShared]; - } - } - } else { - if(data == nullptr) { - buffer->handles[0] = [device newBufferWithLength:(NSUInteger)size options:MTLResourceStorageModeShared]; - } else { - buffer->handles[0] = [device newBufferWithBytes:data - length:(NSUInteger)size - options:MTLResourceStorageModeShared]; - } - } - - return buffer; -} - -int currentFrameIndex = 0; - -void GFXMetal::copy_buffer(GFXBuffer* buffer, void* data, const GFXSize offset, const GFXSize size) { - GFXMetalBuffer* metalBuffer = (GFXMetalBuffer*)buffer; - - const unsigned char * src = reinterpret_cast(data); - unsigned char * dest = reinterpret_cast(metalBuffer->get(currentFrameIndex).contents); - if(dest != nullptr) - memcpy(dest + offset, src, size); -} - -void* GFXMetal::get_buffer_contents(GFXBuffer* buffer) { - GFXMetalBuffer* metalBuffer = (GFXMetalBuffer*)buffer; - - return reinterpret_cast(metalBuffer->get(currentFrameIndex).contents); -} - -GFXTexture* GFXMetal::create_texture(const GFXTextureCreateInfo& info) { - GFXMetalTexture* texture = new GFXMetalTexture(); - - MTLTextureDescriptor* textureDescriptor = [[MTLTextureDescriptor alloc] init]; - - MTLPixelFormat mtlFormat = toPixelFormat(info.format); - - switch(info.type) { - case GFXTextureType::Single2D: - textureDescriptor.textureType = MTLTextureType2D; - break; - case GFXTextureType::Array2D: - textureDescriptor.textureType = MTLTextureType2DArray; - break; - case GFXTextureType::Cubemap: - { - textureDescriptor.textureType = MTLTextureTypeCube; - texture->is_cubemap = true; - } - break; - case GFXTextureType::CubemapArray: - { - textureDescriptor.textureType = MTLTextureTypeCubeArray; - texture->is_cubemap = true; - } - break; - } - - if((info.usage & GFXTextureUsage::Attachment) == GFXTextureUsage::Attachment) { - textureDescriptor.storageMode = MTLStorageModePrivate; - textureDescriptor.usage |= MTLTextureUsageRenderTarget; - } else { -#if defined(PLATFORM_IOS) || defined(PLATFORM_TVOS) - textureDescriptor.storageMode = MTLStorageModeShared; -#else - textureDescriptor.storageMode = MTLStorageModeManaged; -#endif - } - - if((info.usage & GFXTextureUsage::Sampled) == GFXTextureUsage::Sampled) { - textureDescriptor.usage |= MTLTextureUsageShaderRead; - } - - if((info.usage & GFXTextureUsage::ShaderWrite) == GFXTextureUsage::ShaderWrite) { - textureDescriptor.usage |= MTLTextureUsageShaderWrite; - } - - textureDescriptor.pixelFormat = mtlFormat; - textureDescriptor.width = info.width; - textureDescriptor.height = info.height; - textureDescriptor.arrayLength = info.array_length; - - texture->array_length = info.array_length; - - textureDescriptor.mipmapLevelCount = info.mip_count; - - texture->format = mtlFormat; - - texture->handle = [device newTextureWithDescriptor:textureDescriptor]; - - texture->width = info.width; - texture->height = info.height; - - MTLSamplerDescriptor* samplerDescriptor = [MTLSamplerDescriptor new]; - samplerDescriptor.minFilter = MTLSamplerMinMagFilterLinear; - samplerDescriptor.magFilter = MTLSamplerMinMagFilterLinear; - samplerDescriptor.sAddressMode = toSamplingMode(info.samplingMode); - samplerDescriptor.tAddressMode = toSamplingMode(info.samplingMode); - samplerDescriptor.mipFilter = MTLSamplerMipFilterLinear; - samplerDescriptor.maxAnisotropy = 16; - -#if !defined(PLATFORM_IOS) && !defined(PLATFORM_TVOS) - samplerDescriptor.borderColor = toBorderColor(info.border_color); -#endif - - if(info.compare_enabled) - samplerDescriptor.compareFunction = toCompare(info.compare_function); - - texture->sampler = [device newSamplerStateWithDescriptor:samplerDescriptor]; - - return texture; -} - -void GFXMetal::copy_texture(GFXTexture* texture, void* data, const GFXSize) { - GFXMetalTexture* metalTexture = (GFXMetalTexture*)texture; - - MTLRegion region = { - { 0, 0, 0 }, - { - static_cast(texture->width), - static_cast(texture->height), - 1 - } - }; - - NSUInteger byteSize = 1; - if(metalTexture->format == MTLPixelFormatRGBA8Unorm) - byteSize = 4; - else if(metalTexture->format == MTLPixelFormatRG8Unorm) - byteSize = 2; - - [metalTexture->handle replaceRegion:region mipmapLevel:0 withBytes:data bytesPerRow:(NSUInteger)texture->width * byteSize]; -} - -void GFXMetal::copy_texture(GFXTexture* from, GFXTexture* to) { - GFXMetalTexture* metalFromTexture = (GFXMetalTexture*)from; - GFXMetalTexture* metalToTexture = (GFXMetalTexture*)to; - - id commandBuffer = [command_queue commandBuffer]; - id commandEncoder = [commandBuffer blitCommandEncoder]; - [commandEncoder copyFromTexture:metalFromTexture->handle toTexture:metalToTexture->handle]; - [commandEncoder endEncoding]; - [commandBuffer commit]; - [commandBuffer waitUntilCompleted]; -} - -void GFXMetal::copy_texture(GFXTexture* from, GFXBuffer* to) { - GFXMetalTexture* metalFromTexture = (GFXMetalTexture*)from; - GFXMetalBuffer* metalToBuffer = (GFXMetalBuffer*)to; - - MTLOrigin origin; - origin.x = 0; - origin.y = 0; - origin.z = 0; - - MTLSize size; - size.width = from->width; - size.height = from->height; - size.depth = 1; - - NSUInteger byteSize = 1; - if(metalFromTexture->format == MTLPixelFormatRGBA8Unorm) - byteSize = 4; - - id commandBuffer = [command_queue commandBuffer]; - id commandEncoder = [commandBuffer blitCommandEncoder]; - [commandEncoder copyFromTexture:metalFromTexture->handle - sourceSlice:0 - sourceLevel:0 - sourceOrigin:origin - sourceSize:size - toBuffer:metalToBuffer->get(currentFrameIndex) - destinationOffset:0 - destinationBytesPerRow:(NSUInteger)metalFromTexture->width * byteSize - destinationBytesPerImage:0]; - [commandEncoder endEncoding]; - [commandBuffer commit]; - [commandBuffer waitUntilCompleted]; -} - -GFXSampler* GFXMetal::create_sampler(const GFXSamplerCreateInfo& info) { - GFXMetalSampler* sampler = new GFXMetalSampler(); - - MTLSamplerDescriptor* samplerDescriptor = [MTLSamplerDescriptor new]; - samplerDescriptor.minFilter = toFilter(info.min_filter); - samplerDescriptor.magFilter = toFilter(info.mag_filter); - samplerDescriptor.sAddressMode = toSamplingMode(info.samplingMode); - samplerDescriptor.tAddressMode = toSamplingMode(info.samplingMode); - samplerDescriptor.mipFilter = MTLSamplerMipFilterLinear; - samplerDescriptor.maxAnisotropy = 16; - -#if !defined(PLATFORM_IOS) && !defined(PLATFORM_TVOS) - samplerDescriptor.borderColor = toBorderColor(info.border_color); -#endif - - if(info.compare_enabled) - samplerDescriptor.compareFunction = toCompare(info.compare_function); - - sampler->handle = [device newSamplerStateWithDescriptor:samplerDescriptor]; - - return sampler; -} - -GFXFramebuffer* GFXMetal::create_framebuffer(const GFXFramebufferCreateInfo& info) { - GFXMetalFramebuffer* framebuffer = new GFXMetalFramebuffer(); - - for(auto& attachment : info.attachments) - framebuffer->attachments.push_back((GFXMetalTexture*)attachment); - - return framebuffer; -} - -GFXRenderPass* GFXMetal::create_render_pass(const GFXRenderPassCreateInfo& info) { - GFXMetalRenderPass* renderPass = new GFXMetalRenderPass(); - - for(const auto& attachment : info.attachments) - renderPass->attachments.push_back(toPixelFormat(attachment)); - - return renderPass; -} - -MTLFunctionConstantValues* get_constant_values(GFXShaderConstants constants) { - MTLFunctionConstantValues* constantValues = [MTLFunctionConstantValues new]; - - for(auto& constant : constants) { - switch(constant.type) { - case GFXShaderConstant::Type::Integer: - [constantValues setConstantValue:&constant.value type:MTLDataTypeInt atIndex:constant.index]; - break; - } - } - - return constantValues; -} - -GFXPipeline* GFXMetal::create_graphics_pipeline(const GFXGraphicsPipelineCreateInfo& info) { - GFXMetalPipeline* pipeline = new GFXMetalPipeline(); - - NSError* error = nil; - - MTLRenderPipelineDescriptor *pipelineDescriptor = [MTLRenderPipelineDescriptor new]; - - const bool has_vertex_stage = !info.shaders.vertex_src.empty(); - const bool has_fragment_stage = !info.shaders.fragment_src.empty(); - - if(has_vertex_stage) { - id vertexLibrary; - { - std::string vertex_src; - if(info.shaders.vertex_src.is_string()) { - vertex_src = info.shaders.vertex_src.as_string(); - } else { - const auto vertex_path = info.shaders.vertex_src.as_path().string(); - - auto file = prism::open_file(prism::internal_domain / vertex_path); - if(file != std::nullopt) { - vertex_src = file->read_as_string(); - } else { - prism::log::error(System::GFX, "Failed to load vertex shader from {}!", vertex_path.data()); - } - } - - vertexLibrary = [device newLibraryWithSource:[NSString stringWithFormat:@"%s", vertex_src.c_str()] options:nil error:&error]; - if(!vertexLibrary) - NSLog(@"%@", error.debugDescription); - - auto vertex_constants = get_constant_values(info.shaders.vertex_constants); - - id vertexFunc = [vertexLibrary newFunctionWithName:@"main0" constantValues:vertex_constants error:nil]; - - if(debug_enabled && info.shaders.vertex_src.is_path()) - vertexFunc.label = [NSString stringWithFormat:@"%s", info.shaders.vertex_src.as_path().string().data()]; - - pipelineDescriptor.vertexFunction = vertexFunc; - } - } - - if(has_fragment_stage) { - id fragmentLibrary; - { - std::string fragment_src; - if(info.shaders.fragment_src.is_string()) { - fragment_src = info.shaders.fragment_src.as_string(); - } else { - const auto fragment_path = info.shaders.fragment_src.as_path().string(); - - auto file = prism::open_file(prism::internal_domain / fragment_path); - if(file != std::nullopt) { - fragment_src = file->read_as_string(); - } else { - prism::log::error(System::GFX, "Failed to load fragment shader from {}!", fragment_path.data()); - } - } - - fragmentLibrary = [device newLibraryWithSource:[NSString stringWithFormat:@"%s", fragment_src.c_str()] options:nil error:&error]; - if(!fragmentLibrary) - NSLog(@"%@", error.debugDescription); - } - - auto fragment_constants = get_constant_values(info.shaders.fragment_constants); - - id fragmentFunc = [fragmentLibrary newFunctionWithName:@"main0" constantValues:fragment_constants error:nil]; - - if(debug_enabled && info.shaders.fragment_src.is_path()) - fragmentFunc.label = [NSString stringWithFormat:@"%s", info.shaders.fragment_src.as_path().string().data()]; - - pipelineDescriptor.fragmentFunction = fragmentFunc; - } - - MTLVertexDescriptor* descriptor = [MTLVertexDescriptor new]; - - for(auto input : info.vertex_input.inputs) { - descriptor.layouts[input.location].stride = (NSUInteger)input.stride; - descriptor.layouts[input.location].stepFunction = MTLVertexStepFunctionPerVertex; - - GFXMetalPipeline::VertexStride vs; - vs.location = input.location; - vs.stride = input.stride; - - pipeline->vertexStrides.push_back(vs); - } - - for(auto attribute : info.vertex_input.attributes) { - NSUInteger format = MTLVertexFormatFloat3; - switch(attribute.format) { - case GFXVertexFormat::FLOAT2: - format = MTLVertexFormatFloat2; - break; - case GFXVertexFormat::FLOAT3: - format = MTLVertexFormatFloat3; - break; - case GFXVertexFormat::FLOAT4: - format = MTLVertexFormatFloat4; - break; - case GFXVertexFormat::INT: - format = MTLVertexFormatInt; - break; - case GFXVertexFormat::UNORM4: - format = MTLVertexFormatUChar4Normalized; - break; - case GFXVertexFormat::INT4: - format = MTLVertexFormatInt4; - break; - } - - descriptor.attributes[attribute.location].format = (MTLVertexFormat)format; - descriptor.attributes[attribute.location].bufferIndex = (NSUInteger)attribute.binding; - descriptor.attributes[attribute.location].offset = (NSUInteger)attribute.offset; - } - - if(info.render_pass != nullptr) { - GFXMetalRenderPass* metalRenderPass = (GFXMetalRenderPass*)info.render_pass; - - unsigned int i = 0; - for(const auto& attachment : metalRenderPass->attachments) { - if(attachment != MTLPixelFormatDepth32Float) { - pipelineDescriptor.colorAttachments[i].pixelFormat = attachment; - pipelineDescriptor.colorAttachments[i].blendingEnabled = info.blending.enable_blending; - - pipelineDescriptor.colorAttachments[i].sourceRGBBlendFactor = toBlendFactor(info.blending.src_rgb); - pipelineDescriptor.colorAttachments[i].destinationRGBBlendFactor = toBlendFactor(info.blending.dst_rgb); - - pipelineDescriptor.colorAttachments[i].sourceAlphaBlendFactor = toBlendFactor(info.blending.src_alpha); - pipelineDescriptor.colorAttachments[i].destinationAlphaBlendFactor = toBlendFactor(info.blending.dst_alpha); - - i++; - } else { - pipelineDescriptor.depthAttachmentPixelFormat = MTLPixelFormatDepth32Float; - } - } - } else { - pipelineDescriptor.colorAttachments[0].pixelFormat = [nativeViews[0]->layer pixelFormat]; - pipelineDescriptor.colorAttachments[0].blendingEnabled = info.blending.enable_blending; - - pipelineDescriptor.colorAttachments[0].sourceRGBBlendFactor = toBlendFactor(info.blending.src_rgb); - pipelineDescriptor.colorAttachments[0].destinationRGBBlendFactor = toBlendFactor(info.blending.dst_rgb); - - pipelineDescriptor.colorAttachments[0].sourceAlphaBlendFactor = toBlendFactor(info.blending.src_alpha); - pipelineDescriptor.colorAttachments[0].destinationAlphaBlendFactor = toBlendFactor(info.blending.dst_alpha); - } - - pipelineDescriptor.vertexDescriptor = descriptor; - - if(debug_enabled) { - pipelineDescriptor.label = [NSString stringWithFormat:@"%s", info.label.data()]; - pipeline->label = info.label; - } - - pipeline->handle = [device newRenderPipelineStateWithDescriptor:pipelineDescriptor error:&error]; - if(!pipeline->handle) - NSLog(@"%@", error.debugDescription); - - switch(info.rasterization.primitive_type) { - case GFXPrimitiveType::Triangle: - pipeline->primitiveType = MTLPrimitiveTypeTriangle; - break; - case GFXPrimitiveType::TriangleStrip: - pipeline->primitiveType = MTLPrimitiveTypeTriangleStrip; - break; - } - - for(auto& binding : info.shader_input.bindings) { - if(binding.type == GFXBindingType::PushConstant) - pipeline->pushConstantIndex = binding.binding; - } - - pipeline->winding_mode = info.rasterization.winding_mode; - - MTLDepthStencilDescriptor* depthStencil = [MTLDepthStencilDescriptor new]; - - if(info.depth.depth_mode != GFXDepthMode::None) { - switch(info.depth.depth_mode) { - case GFXDepthMode::Less: - depthStencil.depthCompareFunction = MTLCompareFunctionLess; - break; - case GFXDepthMode::LessOrEqual: - depthStencil.depthCompareFunction = MTLCompareFunctionLessEqual; - break; - case GFXDepthMode::Greater: - depthStencil.depthCompareFunction = MTLCompareFunctionGreater; - break; - } - depthStencil.depthWriteEnabled = true; - } - - pipeline->depthStencil = [device newDepthStencilStateWithDescriptor:depthStencil]; - - switch(info.rasterization.culling_mode) { - case GFXCullingMode::Frontface: - pipeline->cullMode = MTLCullModeFront; - break; - case GFXCullingMode::Backface: - pipeline->cullMode = MTLCullModeBack; - break; - case GFXCullingMode::None: - pipeline->cullMode = MTLCullModeNone; - break; - } - - if(info.rasterization.polygon_type == GFXPolygonType::Line) - pipeline->renderWire = true; - - return pipeline; -} - -GFXPipeline* GFXMetal::create_compute_pipeline(const GFXComputePipelineCreateInfo& info) { - GFXMetalPipeline* pipeline = new GFXMetalPipeline(); - - NSError* error = nil; - - // vertex - id computeLibrary; - { - std::string compute_src; - if(info.compute_src.is_string()) { - compute_src = info.compute_src.as_string(); - } else { - const auto compute_path = info.compute_src.as_path().string(); - - auto file = prism::open_file(prism::internal_domain / compute_path); - if(file != std::nullopt) { - compute_src = file->read_as_string(); - } else { - prism::log::error(System::GFX, "Failed to load compute shader from {}!", compute_path.data()); - } - } - - computeLibrary = [device newLibraryWithSource:[NSString stringWithFormat:@"%s", compute_src.c_str()] options:nil error:&error]; - if(!computeLibrary) - NSLog(@"%@", error.debugDescription); - } - - id computeFunc = [computeLibrary newFunctionWithName:@"main0"]; - - MTLComputePipelineDescriptor* pipelineDescriptor = [MTLComputePipelineDescriptor new]; - pipelineDescriptor.computeFunction = computeFunc; - - pipeline->threadGroupSize = MTLSizeMake(info.workgroup_size_x, info.workgroup_size_y, info.workgroup_size_z); - - if(debug_enabled) { - pipelineDescriptor.label = [NSString stringWithFormat:@"%s", info.label.data()]; - pipeline->label = info.label; - } - - pipeline->compute_handle = [device newComputePipelineStateWithDescriptor:pipelineDescriptor error:&error]; - if(!pipeline->handle) - NSLog(@"%@", error.debugDescription); - - for(auto& binding : info.shader_input.bindings) { - if(binding.type == GFXBindingType::PushConstant) - pipeline->pushConstantIndex = binding.binding; - } - - [computeLibrary release]; - - return pipeline; -} - -GFXCommandBuffer* GFXMetal::acquire_command_buffer(bool for_presentation_use) { - GFXCommandBuffer* cmdbuf = nullptr; - while(cmdbuf == nullptr) { - for(const auto [i, buffer_status] : utility::enumerate(free_command_buffers)) { - if(buffer_status) { - GFXCommandBuffer* buffer = command_buffers[i]; - - free_command_buffers[i] = false; - - buffer->commands.clear(); - - return buffer; - } - } - } - - return cmdbuf; -} - -void GFXMetal::submit(GFXCommandBuffer* command_buffer, const int window) { - @autoreleasepool { - NativeMTLView* native = getNativeView(window); - id drawable = nil; - if(native != nullptr) - drawable = [native->layer nextDrawable]; - - id commandBuffer = [command_queue commandBuffer]; - - id renderEncoder = nil; - id computeEncoder = nil; - id blitEncoder = nil; - - GFXMetalRenderPass* currentRenderPass = nullptr; - GFXMetalFramebuffer* currentFramebuffer = nullptr; - GFXMetalPipeline* currentPipeline = nullptr; - GFXMetalBuffer* currentIndexBuffer = nullptr; - IndexType currentIndextype = IndexType::UINT32; - MTLViewport currentViewport = MTLViewport(); - MTLClearColor currentClearColor; - - enum class CurrentEncoder { - None, - Render, - Compute, - Blit - } current_encoder = CurrentEncoder::None; - - const auto needEncoder = [&](CurrentEncoder encoder, bool needs_reset = false) { - if(encoder != current_encoder || needs_reset) { - if(renderEncoder != nil) - [renderEncoder endEncoding]; - - if(computeEncoder != nil) - [computeEncoder endEncoding]; - - if(blitEncoder != nil) - [blitEncoder endEncoding]; - - renderEncoder = nil; - computeEncoder = nil; - blitEncoder = nil; - } - - if(current_encoder == encoder && !needs_reset) - return; - - switch(encoder) { - case CurrentEncoder::None: - break; - case CurrentEncoder::Render: - { - MTLRenderPassDescriptor* descriptor = [MTLRenderPassDescriptor new]; - - if(currentRenderPass != nullptr && currentFramebuffer != nullptr) { - unsigned int i = 0; - for(const auto& attachment : currentFramebuffer->attachments) { - if(attachment->format == MTLPixelFormatDepth32Float) { - descriptor.depthAttachment.texture = attachment->handle; - descriptor.depthAttachment.loadAction = MTLLoadActionClear; - descriptor.depthAttachment.storeAction = MTLStoreActionStore; - } else { - descriptor.colorAttachments[i].texture = attachment->handle; - descriptor.colorAttachments[i].loadAction = MTLLoadActionClear; - descriptor.colorAttachments[i].storeAction = MTLStoreActionStore; - descriptor.colorAttachments[i].clearColor = currentClearColor; - - i++; - } - } - - renderEncoder = [commandBuffer renderCommandEncoderWithDescriptor:descriptor]; - } else { - descriptor.colorAttachments[0].texture = drawable.texture; - descriptor.colorAttachments[0].loadAction = MTLLoadActionClear; - descriptor.colorAttachments[0].clearColor = MTLClearColorMake(0.0,0.0,0.0,1.0); - - renderEncoder = [commandBuffer renderCommandEncoderWithDescriptor:descriptor]; - } - - if(currentViewport.width != 0.0f && currentViewport.height != 0.0f) - [renderEncoder setViewport:currentViewport]; - - [descriptor release]; - } - break; - case CurrentEncoder::Compute: - { - computeEncoder = [commandBuffer computeCommandEncoder]; - } - break; - case CurrentEncoder::Blit: - { - blitEncoder = [commandBuffer blitCommandEncoder]; - } - break; - } - - current_encoder = encoder; - }; - - for(auto command : command_buffer->commands) { - switch(command.type) { - case GFXCommandType::Invalid: - break; - case GFXCommandType::SetRenderPass: - { - currentClearColor = MTLClearColorMake(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 ); - - currentFramebuffer = (GFXMetalFramebuffer*)command.data.set_render_pass.framebuffer; - currentRenderPass = (GFXMetalRenderPass*)command.data.set_render_pass.render_pass; - - currentViewport = MTLViewport(); - - needEncoder(CurrentEncoder::Render, true); - } - break; - case GFXCommandType::SetGraphicsPipeline: - { - needEncoder(CurrentEncoder::Render); - - [renderEncoder setRenderPipelineState:((GFXMetalPipeline*)command.data.set_graphics_pipeline.pipeline)->handle]; - - currentPipeline = (GFXMetalPipeline*)command.data.set_graphics_pipeline.pipeline; - - [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)]; - - if(currentPipeline->renderWire) - [renderEncoder setTriangleFillMode:MTLTriangleFillModeLines]; - else - [renderEncoder setTriangleFillMode:MTLTriangleFillModeFill]; - } - break; - case GFXCommandType::SetComputePipeline: - { - needEncoder(CurrentEncoder::Compute); - - currentPipeline = (GFXMetalPipeline*)command.data.set_compute_pipeline.pipeline; - - [computeEncoder setComputePipelineState:((GFXMetalPipeline*)command.data.set_compute_pipeline.pipeline)->compute_handle]; - - } - break; - case GFXCommandType::SetVertexBuffer: - { - needEncoder(CurrentEncoder::Render); - - [renderEncoder setVertexBuffer:((GFXMetalBuffer*)command.data.set_vertex_buffer.buffer)->get(currentFrameIndex) offset:(NSUInteger)command.data.set_vertex_buffer.offset atIndex:(NSUInteger)command.data.set_vertex_buffer.index ]; - } - break; - case GFXCommandType::SetIndexBuffer: - { - currentIndexBuffer = (GFXMetalBuffer*)command.data.set_index_buffer.buffer; - currentIndextype = command.data.set_index_buffer.index_type; - } - break; - case GFXCommandType::SetPushConstant: - { - if(currentPipeline == nullptr) - continue; - - if(current_encoder == CurrentEncoder::Render) { - [renderEncoder setVertexBytes:command.data.set_push_constant.bytes.data() length:(NSUInteger)command.data.set_push_constant.size atIndex:(NSUInteger)currentPipeline->pushConstantIndex]; - [renderEncoder setFragmentBytes:command.data.set_push_constant.bytes.data() length:(NSUInteger)command.data.set_push_constant.size atIndex:(NSUInteger)currentPipeline->pushConstantIndex]; - } else if(current_encoder == CurrentEncoder::Compute) { - [computeEncoder setBytes:command.data.set_push_constant.bytes.data() length:(NSUInteger)command.data.set_push_constant.size atIndex:(NSUInteger)currentPipeline->pushConstantIndex]; - } - } - break; - case GFXCommandType::BindShaderBuffer: - { - if(current_encoder == CurrentEncoder::Render) { - [renderEncoder setVertexBuffer:((GFXMetalBuffer*)command.data.bind_shader_buffer.buffer)->get(currentFrameIndex) offset:(NSUInteger)command.data.bind_shader_buffer.offset atIndex:(NSUInteger)command.data.bind_shader_buffer.index ]; - - [renderEncoder setFragmentBuffer:((GFXMetalBuffer*)command.data.bind_shader_buffer.buffer)->get(currentFrameIndex) offset:(NSUInteger)command.data.bind_shader_buffer.offset atIndex:(NSUInteger)command.data.bind_shader_buffer.index ]; - } else if(current_encoder == CurrentEncoder::Compute) { - [computeEncoder setBuffer:((GFXMetalBuffer*)command.data.bind_shader_buffer.buffer)->get(currentFrameIndex) offset:(NSUInteger)command.data.bind_shader_buffer.offset atIndex:(NSUInteger)command.data.bind_shader_buffer.index ]; - } - } - break; - case GFXCommandType::BindTexture: - { - if(current_encoder == CurrentEncoder::Render) { - if(command.data.bind_texture.texture != nullptr) { - [renderEncoder setVertexSamplerState:((GFXMetalTexture*)command.data.bind_texture.texture)->sampler atIndex:(NSUInteger)command.data.bind_texture.index]; - - [renderEncoder setVertexTexture:((GFXMetalTexture*)command.data.bind_texture.texture)->handle atIndex:(NSUInteger)command.data.bind_texture.index]; - - [renderEncoder setFragmentSamplerState:((GFXMetalTexture*)command.data.bind_texture.texture)->sampler atIndex:(NSUInteger)command.data.bind_texture.index]; - - [renderEncoder setFragmentTexture:((GFXMetalTexture*)command.data.bind_texture.texture)->handle atIndex:(NSUInteger)command.data.bind_texture.index]; - } else { - [renderEncoder setVertexTexture:nil atIndex:(NSUInteger)command.data.bind_texture.index]; - - [renderEncoder setFragmentTexture:nil atIndex:(NSUInteger)command.data.bind_texture.index]; - } - } else if(current_encoder == CurrentEncoder::Compute) { - [computeEncoder setTexture:((GFXMetalTexture*)command.data.bind_texture.texture)->handle atIndex:(NSUInteger)command.data.bind_texture.index]; - } - } - break; - case GFXCommandType::BindSampler: - { - needEncoder(CurrentEncoder::Render); - - if(command.data.bind_sampler.sampler != nullptr) { - [renderEncoder setFragmentSamplerState:((GFXMetalSampler*)command.data.bind_sampler.sampler)->handle atIndex:(NSUInteger)command.data.bind_sampler.index]; - } else { - [renderEncoder setFragmentSamplerState:nil atIndex:(NSUInteger)command.data.bind_sampler.index]; - } - } - break; - case GFXCommandType::Draw: - { - needEncoder(CurrentEncoder::Render); - - if(currentPipeline == nullptr) - continue; - - [renderEncoder drawPrimitives:currentPipeline->primitiveType vertexStart:(NSUInteger)command.data.draw.vertex_offset vertexCount:(NSUInteger)command.data.draw.vertex_count instanceCount:(NSUInteger)command.data.draw.instance_count - baseInstance:(NSUInteger)command.data.draw.base_instance]; - } - break; - case GFXCommandType::DrawIndexed: - { - needEncoder(CurrentEncoder::Render); - - if(currentIndexBuffer == nullptr) - continue; - - if(currentPipeline == nullptr) - continue; - - MTLIndexType indexType; - int indexSize; - switch(currentIndextype) { - case IndexType::UINT16: - { - indexType = MTLIndexTypeUInt16; - indexSize = sizeof(uint16_t); - } - break; - case IndexType::UINT32: - { - indexType = MTLIndexTypeUInt32; - indexSize = sizeof(uint32_t); - } - break; - } - - for(auto& stride : currentPipeline->vertexStrides) - [renderEncoder setVertexBufferOffset:(NSUInteger)command.data.draw_indexed.vertex_offset * stride.stride atIndex:stride.location]; - - [renderEncoder - drawIndexedPrimitives:currentPipeline->primitiveType - indexCount:(NSUInteger)command.data.draw_indexed.index_count - indexType:indexType - indexBuffer:currentIndexBuffer->get(currentFrameIndex) - indexBufferOffset:(NSUInteger)command.data.draw_indexed.first_index * indexSize]; - } - break; - case GFXCommandType::MemoryBarrier: - { - needEncoder(CurrentEncoder::Render); - - #ifdef PLATFORM_MACOS - [renderEncoder memoryBarrierWithScope:MTLBarrierScopeTextures afterStages:MTLRenderStageFragment beforeStages:MTLRenderStageFragment]; - #endif - } - break; - case GFXCommandType::CopyTexture: - { - needEncoder(CurrentEncoder::Blit); - - GFXMetalTexture* metalFromTexture = (GFXMetalTexture*)command.data.copy_texture.src; - GFXMetalTexture* metalToTexture = (GFXMetalTexture*)command.data.copy_texture.dst; - if(metalFromTexture != nullptr && metalToTexture != nullptr) { - const int slice_offset = command.data.copy_texture.to_slice + command.data.copy_texture.to_layer * 6; - - [blitEncoder - copyFromTexture:metalFromTexture->handle - sourceSlice:0 - sourceLevel:0 - sourceOrigin:MTLOriginMake(0, 0, 0) - sourceSize:MTLSizeMake(command.data.copy_texture.width, command.data.copy_texture.height, 1) - toTexture:metalToTexture->handle - destinationSlice: slice_offset - destinationLevel:command.data.copy_texture.to_level - destinationOrigin: MTLOriginMake(0, 0, 0)]; - } - } - break; - case GFXCommandType::SetViewport: - { - MTLViewport viewport; - viewport.originX = command.data.set_viewport.viewport.x; - viewport.originY = command.data.set_viewport.viewport.y; - viewport.width = command.data.set_viewport.viewport.width; - viewport.height = command.data.set_viewport.viewport.height; - viewport.znear = command.data.set_viewport.viewport.min_depth; - viewport.zfar = command.data.set_viewport.viewport.max_depth; - - if(renderEncoder != nil) - [renderEncoder setViewport:viewport]; - - currentViewport = viewport; - } - break; - case GFXCommandType::SetScissor: - { - needEncoder(CurrentEncoder::Render); - - MTLScissorRect rect; - rect.x = (NSUInteger)command.data.set_scissor.rect.offset.x; - rect.y = (NSUInteger)command.data.set_scissor.rect.offset.y; - rect.width = (NSUInteger)command.data.set_scissor.rect.extent.width; - rect.height = (NSUInteger)command.data.set_scissor.rect.extent.height; - - [renderEncoder setScissorRect:rect]; - } - break; - case GFXCommandType::GenerateMipmaps: { - needEncoder(CurrentEncoder::Blit); - - GFXMetalTexture* metalTexture = (GFXMetalTexture*)command.data.generate_mipmaps.texture; - - [blitEncoder generateMipmapsForTexture: metalTexture->handle]; - } - break; - case GFXCommandType::SetDepthBias: { - needEncoder(CurrentEncoder::Render); - - [renderEncoder setDepthBias:command.data.set_depth_bias.constant - slopeScale:command.data.set_depth_bias.slope_factor - clamp:command.data.set_depth_bias.clamp]; - } - break; - case GFXCommandType::PushGroup: { - [commandBuffer pushDebugGroup:[NSString stringWithUTF8String:command.data.push_group.name.data()]]; - } - break; - case GFXCommandType::PopGroup: { - [commandBuffer popDebugGroup]; - } - break; - case GFXCommandType::InsertLabel: { - switch(current_encoder) { - case CurrentEncoder::Render: - [renderEncoder insertDebugSignpost:[NSString stringWithUTF8String:command.data.insert_label.name.data()]]; - break; - case CurrentEncoder::Blit: - [blitEncoder insertDebugSignpost:[NSString stringWithUTF8String:command.data.insert_label.name.data()]]; - break; - default: - break; - } - } - break; - case GFXCommandType::Dispatch: { - needEncoder(CurrentEncoder::Compute); - - [computeEncoder dispatchThreadgroups:MTLSizeMake(command.data.dispatch.group_count_x, command.data.dispatch.group_count_y, command.data.dispatch.group_count_z) threadsPerThreadgroup:currentPipeline->threadGroupSize]; - } - break; - } - } - - if(renderEncoder != nil) - [renderEncoder endEncoding]; - - if(blitEncoder != nil) - [blitEncoder endEncoding]; - - [commandBuffer addCompletedHandler:^(id _Nonnull) { - for(auto [i, buffer] : utility::enumerate(command_buffers)) { - if(buffer == command_buffer) - free_command_buffers[i] = true; - } - }]; - - if(window != -1) { - [commandBuffer presentDrawable:drawable]; - [commandBuffer commit]; - - currentFrameIndex = (currentFrameIndex + 1) % 3; - } else { - [commandBuffer commit]; - } - } -} diff --git a/engine/gfx/metal/src/gfx_metal_buffer.hpp b/engine/gfx/metal/src/gfx_metal_buffer.hpp deleted file mode 100755 index 670b8a9..0000000 --- a/engine/gfx/metal/src/gfx_metal_buffer.hpp +++ /dev/null @@ -1,19 +0,0 @@ -#pragma once - -#include - -#include "gfx_buffer.hpp" - -class GFXMetalBuffer : public GFXBuffer { -public: - id handles[3] = {nil, nil, nil}; - bool dynamicData = false; - - id get(int frameIndex) { - if(dynamicData) { - return handles[frameIndex]; - } else { - return handles[0]; - } - } -}; diff --git a/engine/gfx/metal/src/gfx_metal_framebuffer.hpp b/engine/gfx/metal/src/gfx_metal_framebuffer.hpp deleted file mode 100755 index 9c0eeb0..0000000 --- a/engine/gfx/metal/src/gfx_metal_framebuffer.hpp +++ /dev/null @@ -1,13 +0,0 @@ -#pragma once - -#include -#include - -#include "gfx_framebuffer.hpp" - -class GFXMetalTexture; - -class GFXMetalFramebuffer : public GFXFramebuffer { -public: - std::vector attachments; -}; diff --git a/engine/gfx/metal/src/gfx_metal_pipeline.hpp b/engine/gfx/metal/src/gfx_metal_pipeline.hpp deleted file mode 100755 index 8c94c96..0000000 --- a/engine/gfx/metal/src/gfx_metal_pipeline.hpp +++ /dev/null @@ -1,32 +0,0 @@ -#pragma once - -#include - -#include "gfx_pipeline.hpp" - -class GFXMetalPipeline : public GFXPipeline { -public: - std::string label; - - id handle = nil; - id compute_handle = nil; - - MTLSize threadGroupSize; - - id depthStencil = nil; - MTLPrimitiveType primitiveType; - - MTLCullMode cullMode; - GFXWindingMode winding_mode; - - struct VertexStride { - int location, stride; - }; - - std::vector vertexStrides; - - int pushConstantSize = 0; - int pushConstantIndex = 0; - - bool renderWire = false; -}; diff --git a/engine/gfx/metal/src/gfx_metal_renderpass.hpp b/engine/gfx/metal/src/gfx_metal_renderpass.hpp deleted file mode 100755 index d793af9..0000000 --- a/engine/gfx/metal/src/gfx_metal_renderpass.hpp +++ /dev/null @@ -1,10 +0,0 @@ -#pragma once - -#include - -#include "gfx_renderpass.hpp" - -class GFXMetalRenderPass : public GFXRenderPass { -public: - std::vector attachments; -}; diff --git a/engine/gfx/metal/src/gfx_metal_sampler.hpp b/engine/gfx/metal/src/gfx_metal_sampler.hpp deleted file mode 100755 index aadef10..0000000 --- a/engine/gfx/metal/src/gfx_metal_sampler.hpp +++ /dev/null @@ -1,10 +0,0 @@ -#pragma once - -#include - -#include "gfx_sampler.hpp" - -class GFXMetalSampler : public GFXSampler { -public: - id handle = nil; -}; diff --git a/engine/gfx/metal/src/gfx_metal_texture.hpp b/engine/gfx/metal/src/gfx_metal_texture.hpp deleted file mode 100755 index 8eecab3..0000000 --- a/engine/gfx/metal/src/gfx_metal_texture.hpp +++ /dev/null @@ -1,16 +0,0 @@ -#pragma once - -#include - -#include "gfx_texture.hpp" - -class GFXMetalTexture : public GFXTexture { -public: - id handle = nil; - id sampler = nil; - - int array_length = 1; - bool is_cubemap = false; - - MTLPixelFormat format; -}; diff --git a/platforms/CMakeLists.txt b/platforms/CMakeLists.txt index 19230f2..31b1272 100755 --- a/platforms/CMakeLists.txt +++ b/platforms/CMakeLists.txt @@ -7,7 +7,7 @@ if(ENABLE_LINUX) endif() if(ENABLE_MACOS) - add_subdirectory(mac) + add_subdirectory(sdl) endif() if(ENABLE_IOS) diff --git a/platforms/mac/CMakeLists.txt b/platforms/mac/CMakeLists.txt deleted file mode 100755 index b68280d..0000000 --- a/platforms/mac/CMakeLists.txt +++ /dev/null @@ -1,29 +0,0 @@ -include(../../cmake/AddPlatformExecutable.cmake) - -add_platform( - MAIN_FILE - main.mm.in - SRC - ${CMAKE_CURRENT_SOURCE_DIR}/file.mm - EXECUTABLE_PROPERTIES - MACOSX_BUNDLE ON - MACOSX_BUNDLE_INFO_PLIST "${CMAKE_CURRENT_SOURCE_DIR}/Info.plist.in" - LINK_LIBRARIES - Core - GFXMetal - "-framework Cocoa" - "-framework QuartzCore" - "-framework GameController" - COMPILE_OPTIONS - -std=c++17 -) - -function(add_platform_commands target) - target_link_options(${target} BEFORE PRIVATE -pagezero_size 10000 -image_base 100000000 -) - if(NOT SKIP_DATA) - add_custom_command(TARGET ${target} POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/data $/../Resources/data) - endif() - - add_custom_command(TARGET ${target} POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_BINARY_DIR}/shaders $/../Resources/shaders) -endfunction() diff --git a/platforms/mac/file.mm b/platforms/mac/file.mm deleted file mode 100755 index 14af39e..0000000 --- a/platforms/mac/file.mm +++ /dev/null @@ -1,42 +0,0 @@ -#include "file.hpp" - -#import -#include - -#import - -#include "string_utils.hpp" - -#include "log.hpp" - -inline std::string clean_path(const std::string_view path) { - auto p = replace_substring(path, "%20", " "); - - // this is a path returned by an editor, so skip it - // TODO: find a better way to do this!! NOO!! - if(p.find("file:///") != std::string::npos) - return p.substr(7, p.length()); - else - return p; -} - -void prism::set_domain_path(const prism::domain domain, const prism::path path) { - NSBundle* bundle = [NSBundle mainBundle]; - NSString* resourceFolderPath = [bundle resourcePath]; - - std::string s = std::string(path); - s = replace_substring(s, "{resource_dir}", [resourceFolderPath cStringUsingEncoding:NSUTF8StringEncoding]); - - // basically, if we pass a relative path this will convert it to an absolute one, making get_relative_path functional. - NSURL * bundleURL = [[bundle bundleURL] URLByDeletingLastPathComponent]; - NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:@"%s", s.c_str()] relativeToURL:bundleURL]; - - domain_data[static_cast(domain)] = clean_path([[[url absoluteURL] absoluteString] cStringUsingEncoding:NSUTF8StringEncoding]); -} - -prism::path prism::get_writeable_directory() { - NSArray* paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); - NSString* resourceFolderPath = paths[0]; - - return [resourceFolderPath cStringUsingEncoding:NSUTF8StringEncoding]; -} diff --git a/platforms/mac/main.mm.in b/platforms/mac/main.mm.in deleted file mode 100755 index 402ba69..0000000 --- a/platforms/mac/main.mm.in +++ /dev/null @@ -1,634 +0,0 @@ -#import -#import -#import -#include -#include -#include -#include -#include -#include -#include - -#include <@APP_INCLUDE@> - -uint64_t last_time = 0; -bool is_qutting = false; - -static std::map inputToKeyCode = { { - {InputButton::C, 8}, - {InputButton::V, 9}, - {InputButton::X, 7}, - {InputButton::Q, 12}, - {InputButton::Y, 16}, - {InputButton::Z, 6}, - {InputButton::Backspace, 51}, - {InputButton::Enter, 36}, - {InputButton::Space, 49}, - {InputButton::Shift, 10}, - {InputButton::A, 0}, - {InputButton::W, 13}, - {InputButton::S, 1}, - {InputButton::D, 2}, - {InputButton::Escape, 53}, - {InputButton::Tab, 48}, - {InputButton::LeftArrow, 123}, - {InputButton::RightArrow, 124} -}}; - -struct NativeWindow; - -const char* platform::get_name() { - return "macOS"; -} - -int platform::get_keycode(InputButton key) { - if(inputToKeyCode.count(key)) - return inputToKeyCode[key]; - else - return -1; -} - -GFX* interface = nullptr; - -@APP_CLASS@* app = nullptr; - -float scrollX = 0.0f, scrollY = 0.0f; - -std::array inputKeys; - -float rightX = 0.0f, rightY = 0.0f; -float leftX = 0.0f, leftY = 0.0f; - -@interface GameView : NSObject - -@property NativeWindow *native; - -@end - -struct NativeWindow { - int index = 0; - NSWindow* window; - GameView* delegate; - CAMetalLayer* layer; - bool willCaptureMouse = false; - - int currentWidth = 0, currentHeight = 0; - int timeout = 0; - - NSPoint currentMousePos; - bool showingCursor = true; - bool inFocus = true; -}; - -std::vector windows; - -NativeWindow* get_window(const int index) { - for(auto& window : windows) { - if(window->index == index) - return window; - } - - return nullptr; -} - -@implementation GameView - -- (void)gameQuit { - engine->prepare_quit(); -} -- (void)gameFocus { - if(![self native]->showingCursor) - [NSCursor hide]; - - [self native]->inFocus = true; -} -- (void)gameLostFocus { - if(![self native]->showingCursor) - [NSCursor unhide]; - - [self native]->inFocus = false; -} - -const double NANOSECONDS_TO_MILLISECONDS = 1.0 / 1000000000.0; - -- (void)update { - const bool is_main_window = [self native]->index == 0; - - if(is_main_window) { - if([self native]->willCaptureMouse && [self native]->timeout > 5 && [self native]->inFocus) { - NSPoint point; - point.x = [self native]->window.frame.origin.x + ([self native]->currentWidth / 2); - point.y = [NSScreen mainScreen].frame.size.height - ([self native]->window.frame.origin.y + ([self native]->currentHeight / 2)); - - CGWarpMouseCursorPosition(point); - CGAssociateMouseAndMouseCursorPosition(true); - - [self native]->currentMousePos.x = [self native]->currentWidth / 2; - [self native]->currentMousePos.y = [self native]->currentHeight / 2; - - [self native]->timeout = 0; - } - - [self native]->timeout++; - } -} - -- (void)render { - engine->render([self native]->index); -} - -- (void)windowDidResize:(NSNotification *)notification { - [self native]->currentWidth = [self native]->window.contentView.frame.size.width; - [self native]->currentHeight = [self native]->window.contentView.frame.size.height; - - NSRect bounds = [[self native]->layer bounds]; - bounds = [[self native]->window convertRectToBacking:bounds]; - - [self native]->layer.drawableSize = NSSizeToCGSize(bounds.size);; - - engine->resize([self native]->index, {static_cast([self native]->currentWidth), static_cast([self native]->currentHeight)}); -} - --(void)windowWillClose:(NSNotification *)notification { - if([self native]->index == 0) - is_qutting = app->should_quit(); -} - -- (void) controllerConnected { - GCController* controller = [GCController controllers][0]; - [[controller extendedGamepad] setValueChangedHandler:^(GCExtendedGamepad * _Nonnull gamepad, GCControllerElement * _Nonnull element) { - const auto& handle_element = [element](int index, GCControllerElement* e) { - if(element == e) - inputKeys[index] = [(GCControllerButtonInput*)e value] == 1.0f; - }; - - handle_element(0, [[controller extendedGamepad] buttonA]); - handle_element(1, [[controller extendedGamepad] buttonB]); - handle_element(2, [[controller extendedGamepad] buttonX]); - handle_element(3, [[controller extendedGamepad] buttonY]); - - if(element == [[controller extendedGamepad] dpad]) { - inputKeys[4] = [[[[controller extendedGamepad] dpad] up] value] == 1.0f; - inputKeys[5] = [[[[controller extendedGamepad] dpad] down] value] == 1.0f; - inputKeys[6] = [[[[controller extendedGamepad] dpad] left] value] == 1.0f; - inputKeys[7] = [[[[controller extendedGamepad] dpad] right] value] == 1.0f; - } - - if(element == [[controller extendedGamepad] leftThumbstick]) { - leftX = [[[[controller extendedGamepad] leftThumbstick] xAxis] value]; - leftY = [[[[controller extendedGamepad] leftThumbstick] yAxis] value]; - } - - if(element == [[controller extendedGamepad] rightThumbstick]) { - rightX = [[[[controller extendedGamepad] rightThumbstick] xAxis] value]; - rightY = [[[[controller extendedGamepad] rightThumbstick] yAxis] value]; - } - }]; -} - -@end - -std::map pressed; -NSString* currentCharString = nil; - -bool platform::supports_feature(const PlatformFeature feature) { - switch(feature) { - case PlatformFeature::Windowing: - return true; - } - - return false; -} - -bool platform::get_key_down(const InputButton key) { - if(key == InputButton::ButtonA) - return inputKeys[0]; - - if(key == InputButton::ButtonB) - return inputKeys[1]; - - if(key == InputButton::ButtonX) - return inputKeys[2]; - - if(key == InputButton::ButtonY) - return inputKeys[3]; - - if(key == InputButton::DPadUp) - return inputKeys[4]; - - if(key == InputButton::DPadDown) - return inputKeys[5]; - - if(key == InputButton::DPadLeft) - return inputKeys[6]; - - if(key == InputButton::DPadRight) - return inputKeys[7]; - - if(inputToKeyCode.count(key)) - return pressed[inputToKeyCode[key]]; - else - return false; -} - -char* platform::translate_keycode(const unsigned int keycode) { - return const_cast([currentCharString UTF8String]); -} - -inline std::string clean_path(const std::string_view path) { - auto p = replace_substring(path, "%20", " "); - - // this is a path returned by an editor, so skip it - // TODO: find a better way to do this!! NOO!! - if(p.find("file:///") != std::string::npos) - return p.substr(7, p.length()); - else - return p; -} - -void platform::open_dialog(const bool existing, std::function returnFunction, bool openDirectory) { - NSOpenPanel* openDlg = [NSOpenPanel openPanel]; - - [openDlg setCanChooseFiles:YES]; - - [openDlg setAllowsMultipleSelection:NO]; - - [openDlg setCanChooseDirectories:openDirectory]; - - [openDlg setCanChooseFiles:!openDirectory]; - - if([openDlg runModal] == NSModalResponseOK) - returnFunction(clean_path([openDlg.URLs[0].absoluteString UTF8String])); -} - -void platform::save_dialog(std::function returnFunction) { - NSSavePanel* openDlg = [NSSavePanel savePanel]; - - if ([openDlg runModal] == NSModalResponseOK) - returnFunction(clean_path([openDlg.URL.absoluteString UTF8String])); -} - -void platform::capture_mouse(const bool capture) { - windows[0]->willCaptureMouse = capture; - - if(windows[0]->showingCursor && capture) { - [NSCursor hide]; - windows[0]->showingCursor = false; - } else if(!windows[0]->showingCursor && !capture) { - [NSCursor unhide]; - windows[0]->showingCursor = true; - } -} - -float platform::get_window_dpi(const int index) { - auto window = get_window(index); - return [window->window backingScaleFactor]; -} - -float platform::get_monitor_dpi() { - return [[NSScreen mainScreen] backingScaleFactor]; -} - -CGRect toTopLeftSpace(NSRect frame) { - frame.origin.y = NSMaxY([[NSScreen mainScreen] frame]) - NSMaxY(frame); - return NSRectToCGRect(frame); -} - -prism::Rectangle platform::get_monitor_resolution() { - auto frame = toTopLeftSpace([[NSScreen mainScreen] frame]); - - return {static_cast(frame.origin.x), static_cast(frame.origin.y), static_cast(frame.size.width), static_cast(frame.size.height)}; -} - -prism::Rectangle platform::get_monitor_work_area() { - auto frame = toTopLeftSpace([[NSScreen mainScreen] visibleFrame]); - - return {static_cast(frame.origin.x), static_cast(frame.origin.y), static_cast(frame.size.width), static_cast(frame.size.height)}; -} - -NSPoint get_fixed_cursor_point(NSPoint point) { - return {point.x, std::max(windows[0]->currentHeight - point.y, 0.0)}; -} - -prism::Offset platform::get_cursor_position() { - return {static_cast(windows[0]->currentMousePos.x), static_cast(windows[0]->currentMousePos.y)}; -} - -prism::Offset platform::get_screen_cursor_position() { - return {static_cast([NSEvent mouseLocation].x), static_cast([[NSScreen mainScreen] frame].size.height - [NSEvent mouseLocation].y)}; -} - -std::tuple platform::get_wheel_delta() { - return {scrollX, scrollY}; -} - -std::tuple platform::get_left_stick_position() { - return {leftX, leftY}; -} - -std::tuple platform::get_right_stick_position() { - return {rightX, rightY}; -} - -prism::Extent platform::get_window_size(const int index) { - auto window = get_window(index); - return {static_cast(window->currentWidth), static_cast(window->currentHeight)}; -} - -prism::Extent platform::get_window_drawable_size(const int index) { - auto window = get_window(index); - return {static_cast(window->currentWidth * window->window.backingScaleFactor), static_cast(window->currentHeight * window->window.backingScaleFactor)}; -} - -prism::Offset platform::get_window_position(const int index) { - auto window = get_window(index); - - auto frame = toTopLeftSpace([window->window contentRectForFrameRect:[window->window frame]]); - - return {static_cast(frame.origin.x), static_cast(frame.origin.y)}; -} - -bool platform::is_window_focused(const int index) { - auto window = get_window(index); - - return [window->window isKeyWindow]; -} - -void platform::set_window_focused(const int index) { - auto window = get_window(index); - [window->window makeKeyWindow]; -} - -bool platform::get_mouse_button_down(const int button) { - return (button + 1) & [NSEvent pressedMouseButtons]; -} - -void platform::set_window_position(const int index, const prism::Offset offset) { - auto window = get_window(index); - - NSPoint p; - p.x = offset.x; - p.y = [[NSScreen mainScreen] frame].size.height - offset.y; - - [window->window setFrameTopLeftPoint:p]; -} - -void platform::set_window_size(const int index, const prism::Extent extent) { - auto window = get_window(index); - - NSSize size; - size.width = extent.width; - size.height = extent.height; - - [window->window setContentSize:size]; -} - -void platform::set_window_title(const int index, const std::string_view title) { - auto window = get_window(index); - [window->window setTitle:[NSString stringWithUTF8String:title.data()]]; -} - -void platform::mute_output() {} -void platform::unmute_output() {} - -PlatformTheme platform::get_theme() { - auto str = [[[NSApplication sharedApplication] effectiveAppearance] name]; - - if(str == NSAppearanceNameAqua) - return PlatformTheme::Light; - else if(str == NSAppearanceNameDarkAqua) - return PlatformTheme::Dark; - - return PlatformTheme::Light; -} - -int platform::open_window(const std::string_view title, const prism::Rectangle rect, const WindowFlags flags) { - NativeWindow* native = new NativeWindow(); - native->index = windows.size(); - GameView* del = [[GameView alloc] init]; - native->delegate = del; - windows.push_back(native); - - NSRect nrect = NSMakeRect(rect.offset.x, rect.offset.y, rect.extent.width, rect.extent.height); - - NSWindowStyleMask windowStyle = NSWindowStyleMaskTitled - | NSWindowStyleMaskClosable - | NSWindowStyleMaskMiniaturizable; - - if(flags == WindowFlags::Resizable) - windowStyle |= NSWindowStyleMaskResizable; - else if(flags == WindowFlags::Borderless) - windowStyle = NSWindowStyleMaskBorderless; - - native->window = [[NSWindow alloc] - initWithContentRect: nrect - styleMask:windowStyle - backing: NSBackingStoreBuffered - defer: NO]; - - native->currentWidth = rect.extent.width; - native->currentHeight = rect.extent.height; - - native->layer = [CAMetalLayer layer]; - - NSView* view = [[NSView alloc] init]; - view.wantsLayer = YES; - view.layer = native->layer; - - native->layer.contentsScale = [native->window backingScaleFactor]; - - engine->add_window(view.layer, native->index, rect.extent); - - [native->window setContentView:view]; - - if(native->index == 0) - app->initialize_render(); - - [native->window setTitle:[NSString stringWithUTF8String:title.data()]]; - - [del setNative:native]; - - [native->window setDelegate:del]; - [native->window orderFrontRegardless]; - - if(native->index == 0) { - NSNotificationCenter* nc = [NSNotificationCenter defaultCenter]; - [nc addObserver:del - selector:@selector(gameQuit) - name:NSApplicationWillTerminateNotification - object:nil]; - - [nc addObserver:del - selector:@selector(gameFocus) - name:NSApplicationDidBecomeActiveNotification - object:nil]; - - [nc addObserver:del - selector:@selector(gameLostFocus) - name:NSApplicationDidResignActiveNotification - object:nil]; - - [nc addObserver:del - selector:@selector(controllerConnected) - name:GCControllerDidConnectNotification - object:nil]; - } - - return native->index; -} - -void platform::close_window(const int index) { - auto window = get_window(index); - - engine->remove_window(window->index); - - [window->window close]; - - utility::erase(windows, window); -} - -void platform::force_quit() { - [NSApp terminate:nil]; -} - -int main(int argc, char* argv[]) { - NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; - - NSApp = [NSApplication sharedApplication]; - - engine = new prism::engine(argc, argv); - - app = new @APP_CLASS@(); - engine->set_app(app); - - GFXCreateInfo createInfo = {}; - createInfo.api_validation_enabled = true; - - interface = new GFXMetal(); - if(interface->initialize(createInfo)) { - engine->set_gfx(interface); - } else { - NSLog(@"Failed to create Metal context!"); - - return -1; - } - - app_main(engine); - - [NSEvent addLocalMonitorForEventsMatchingMask:NSEventMaskKeyDown handler:^(NSEvent *event) { - pressed[event.keyCode] = true; - currentCharString = event.characters; - - engine->process_key_down(event.keyCode); - - return (NSEvent*)nil; - }]; - - [NSEvent addLocalMonitorForEventsMatchingMask:NSEventMaskKeyUp handler:^(NSEvent *event) { - pressed[event.keyCode] = false; - - engine->process_key_up(event.keyCode); - - return (NSEvent*)nil; - }]; - - [NSEvent addLocalMonitorForEventsMatchingMask:NSEventMaskMouseMoved handler:^(NSEvent *event) { - windows[0]->currentMousePos = get_fixed_cursor_point(event.locationInWindow); - - return event; - }]; - - [NSEvent addLocalMonitorForEventsMatchingMask:NSEventMaskLeftMouseDown handler:^(NSEvent *event) { - auto point = get_fixed_cursor_point(event.locationInWindow); - engine->process_mouse_down(0, {static_cast(point.x), static_cast(point.y)}); - - return event; - }]; - - [NSEvent addLocalMonitorForEventsMatchingMask:NSEventMaskRightMouseDown handler:^(NSEvent *event) { - auto point = get_fixed_cursor_point(event.locationInWindow); - engine->process_mouse_down(1, {static_cast(point.x), static_cast(point.y)}); - - return event; - }]; - - [NSEvent addLocalMonitorForEventsMatchingMask:NSEventMaskRightMouseDragged handler:^(NSEvent *event) { - windows[0]->currentMousePos = get_fixed_cursor_point(event.locationInWindow); - - return event; - }]; - - [NSEvent addLocalMonitorForEventsMatchingMask:NSEventMaskLeftMouseDragged handler:^(NSEvent *event) { - windows[0]->currentMousePos = get_fixed_cursor_point(event.locationInWindow); - - return event; - }]; - - [NSEvent addLocalMonitorForEventsMatchingMask:NSEventMaskScrollWheel handler:^(NSEvent *event) { - double wheel_dx = 0.0; - double wheel_dy = 0.0; - - wheel_dx = [event scrollingDeltaX]; - wheel_dy = [event scrollingDeltaY]; - if ([event hasPreciseScrollingDeltas]) - { - wheel_dx *= 0.1; - wheel_dy *= 0.1; - } - - scrollX += wheel_dx * 0.1f; - scrollY += wheel_dy * 0.1f; - - return event; - }]; - - last_time = clock_gettime_nsec_np(CLOCK_UPTIME_RAW); - - while (!is_qutting) { - @autoreleasepool { - NSEvent* event = nullptr; - do { - event = [NSApp nextEventMatchingMask: NSEventMaskAny - untilDate: nil - inMode: NSDefaultRunLoopMode - dequeue: YES]; - if(event) - [NSApp sendEvent: event]; - } while(event); - - const uint64_t current = clock_gettime_nsec_np(CLOCK_UPTIME_RAW); - const uint64_t elapsed = current - last_time; - - if(engine->is_quitting()) - is_qutting = true; - - for(auto& window : windows) { - if(window != nullptr) - [window->delegate update]; - } - - engine->update(elapsed * NANOSECONDS_TO_MILLISECONDS); - - engine->begin_frame(elapsed * NANOSECONDS_TO_MILLISECONDS); - - for(auto& window : windows) { - if(window != nullptr) - [window->delegate render]; - } - - engine->end_frame(); - - scrollX = 0.0f; - scrollY = 0.0f; - - last_time = current; - } - } - - app->prepare_quit(); - - [NSApp release]; - [pool release]; - - return 0; -} diff --git a/platforms/sdl/CMakeLists.txt b/platforms/sdl/CMakeLists.txt index 0b4d79c..788c264 100644 --- a/platforms/sdl/CMakeLists.txt +++ b/platforms/sdl/CMakeLists.txt @@ -4,6 +4,9 @@ add_platform( SRC ${CMAKE_CURRENT_SOURCE_DIR}/file.cpp MAIN_FILE main.cpp.in + EXECUTABLE_PROPERTIES + MACOSX_BUNDLE ON + MACOSX_BUNDLE_INFO_PLIST "${CMAKE_CURRENT_SOURCE_DIR}/Info.plist.in" LINK_LIBRARIES SDL2::Main Core diff --git a/platforms/mac/Info.plist.in b/platforms/sdl/Info.plist.in similarity index 100% rename from platforms/mac/Info.plist.in rename to platforms/sdl/Info.plist.in