Compare commits

...

18 Commits

Author SHA1 Message Date
matthieu.ranger
04714c26d7 Fixed couple of Vulkan 1.0 features and added JakeJayLee123's float bugfix 2020-12-11 19:51:29 -05:00
matthieu.ranger
e57c9be21f Added shader_draw_parameters (failed to add extension in previous versions on metal) 2020-07-05 22:37:13 -04:00
matthieu.ranger
930b10878a Addressed review comments 2020-07-01 23:23:03 -04:00
matthieu.ranger
d8a9618a62 Added full image swizzle through runtime env var 2020-06-29 22:56:33 -04:00
matthieu.ranger
0ca23681fc Bunch of ifdef hacks to get it to boot games 2020-06-29 12:43:12 -04:00
matthieu.ranger
d72afe2ac0 ref style fixes 2020-06-27 19:05:14 -04:00
matthieu.ranger
f89e096617 Moved incompatible extensions out of Apple vulkan requirements 2020-06-27 18:51:02 -04:00
matthieu.ranger
d28e0f51fa Fixed Bug where metal surface pointer wasnt actually set 2020-06-27 18:46:38 -04:00
matthieu.ranger
0079a09305 Added macOS surface in bootmanager 2020-06-26 11:43:38 -04:00
matthieu.ranger
7763f62f93 added declaration for preparewindow (warning raised error) 2020-06-26 09:34:57 -04:00
matthieu.ranger
29c1772097 Reverted build bug introduced 2020-06-25 19:54:08 -04:00
matthieu.ranger
1f4b5f7a73 Reverted clang format difference changes between build server and macos clang format 2020-06-25 19:39:58 -04:00
matthieu.ranger
a21690f3f7 Refactored windowsysteminfo to directly get drawsurface raw ptr 2020-06-25 19:16:51 -04:00
matthieu.ranger
6a02f655aa Clang format everything; revert apple-based compiler options to previous 2020-06-25 18:22:07 -04:00
matthieu.ranger
c272931f23 Maybe Unused param added 2020-06-25 18:03:51 -04:00
matthieu.ranger
ad7e5c84d4 Clang-Format run over changed files 2020-06-25 17:58:48 -04:00
matthieu.ranger
a4fcd02ee7 Fixed some formatting issues 2020-06-25 17:43:44 -04:00
matthieu.ranger
da4640a016 Added moltenvk 2020-06-25 16:21:22 -04:00
24 changed files with 1917 additions and 27 deletions

View File

@@ -6,7 +6,16 @@ list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/externals/find-module
include(DownloadExternals)
include(CMakeDependentOption)
project(yuzu)
if (APPLE)
project(yuzu C CXX ASM)
option(OSX_USE_DEFAULT_SEARCH_PATH "Don't prioritize system library paths" OFF)
else()
project(yuzu)
endif()
# Pin build to minimum supported OSX version.
# 10.15 supports metal 3 so has additional unsupported MVK extensions
set(CMAKE_OSX_DEPLOYMENT_TARGET "10.14.0" CACHE STRING "")
# Set bundled sdl2/qt as dependent options.
# OFF by default, but if ENABLE_SDL2 and MSVC are true then ON
@@ -414,6 +423,30 @@ if (APPLE)
# Umbrella framework for everything GUI-related
find_library(COCOA_LIBRARY Cocoa)
set(PLATFORM_LIBRARIES ${COCOA_LIBRARY} ${IOKIT_LIBRARY} ${COREVIDEO_LIBRARY})
if(NOT OSX_USE_DEFAULT_SEARCH_PATH)
# Hack up the path to prioritize the path to built-in OS libraries to
# increase the chance of not depending on a bunch of copies of them
# installed by MacPorts, Fink, Homebrew, etc, and ending up copying
# them into the bundle. Since we optionally depend on libraries which
# are not part of OS X (ffmpeg, etc.), however, don't remove the default
# path entirely as was done in a previous version of this file. This is
# still kinda evil, since it defeats the user's path settings...
# See http://www.cmake.org/cmake/help/v3.0/command/find_program.html
list(APPEND CMAKE_PREFIX_PATH "/usr")
endif()
# Linker flags.
# Drop unreachable code and data.
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-dead_strip,-dead_strip_dylibs")
find_library(APPKIT_LIBRARY AppKit)
find_library(APPSERV_LIBRARY ApplicationServices)
find_library(CARBON_LIBRARY Carbon)
find_library(COCOA_LIBRARY Cocoa)
find_library(COREFOUNDATION_LIBRARY CoreFoundation)
find_library(CORESERV_LIBRARY CoreServices)
find_library(FOUNDATION_LIBRARY Foundation)
find_library(IOK_LIBRARY IOKit)
elseif (WIN32)
# WSAPoll and SHGetKnownFolderPath (AppData/Roaming) didn't exist before WinNT 6.x (Vista)
add_definitions(-D_WIN32_WINNT=0x0600 -DWINVER=0x0600)

View File

@@ -0,0 +1,46 @@
# This module can be used in two different ways.
#
# When invoked as `cmake -P PostprocessBundle.cmake`, it fixes up an
# application folder to be standalone. It bundles all required libraries from
# the system and fixes up library IDs. Any additional shared libraries, like
# plugins, that are found under Contents/MacOS/ will be made standalone as well.
#
# When called with `include(PostprocessBundle)`, it defines a helper
# function `postprocess_bundle` that sets up the command form of the
# module as a post-build step.
if(CMAKE_GENERATOR)
# Being called as include(PostprocessBundle), so define a helper function.
set(_POSTPROCESS_BUNDLE_MODULE_LOCATION "${CMAKE_CURRENT_LIST_FILE}")
function(postprocess_bundle target)
add_custom_command(TARGET ${target} POST_BUILD
COMMAND ${CMAKE_COMMAND} -DBUNDLE_PATH="$<TARGET_FILE_DIR:${target}>/../.."
-P "${_POSTPROCESS_BUNDLE_MODULE_LOCATION}"
)
endfunction()
return()
endif()
get_filename_component(BUNDLE_PATH "${BUNDLE_PATH}" REALPATH)
message(STATUS "Fixing up application bundle: ${BUNDLE_PATH}")
# Make sure to fix up any additional shared libraries (like plugins) that are
# needed.
file(GLOB_RECURSE extra_libs "${BUNDLE_PATH}/Contents/MacOS/*.dylib")
# BundleUtilities doesn't support DYLD_FALLBACK_LIBRARY_PATH behavior, which
# makes it sometimes break on libraries that do weird things with @rpath. Specify
# equivalent search directories until https://gitlab.kitware.com/cmake/cmake/issues/16625
# is fixed and in our minimum CMake version.
set(extra_dirs "/usr/local/lib" "/lib" "/usr/lib")
# BundleUtilities is overly verbose, so disable most of its messages
function(message)
if(NOT ARGV MATCHES "^STATUS;")
_message(${ARGV})
endif()
endfunction()
include(BundleUtilities)
set(BU_CHMOD_BUNDLE_ITEMS ON)
fixup_bundle("${BUNDLE_PATH}" "${extra_libs}" "${extra_dirs}")

View File

@@ -0,0 +1,7 @@
{
"file_format_version": "1.0.0",
"ICD": {
"library_path": "../../../lib/libMoltenVK.dylib",
"api_version": "1.0.0"
}
}

View File

@@ -0,0 +1,468 @@
/*
* mvk_datatypes.h
*
* Copyright (c) 2015-2020 The Brenwill Workshop Ltd. (http://www.brenwill.com)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* This file contains functions for converting between Vulkan and Metal data types.
*
* The functions here are used internally by MoltenVK, and are exposed here
* as a convenience for use elsewhere within applications using MoltenVK.
*/
#ifndef __mvkDataTypes_h_
#define __mvkDataTypes_h_ 1
#ifdef __cplusplus
extern "C" {
#endif // __cplusplus
#include "mvk_vulkan.h"
#import <Metal/Metal.h>
#import <CoreGraphics/CoreGraphics.h>
#pragma mark -
#pragma mark Image properties
#pragma mark Texture formats
/** Enumerates the data type of a format. */
typedef enum {
kMVKFormatNone, /**< Format type is unknown. */
kMVKFormatColorHalf, /**< A 16-bit floating point color. */
kMVKFormatColorFloat, /**< A 32-bit floating point color. */
kMVKFormatColorInt8, /**< A signed 8-bit integer color. */
kMVKFormatColorUInt8, /**< An unsigned 8-bit integer color. */
kMVKFormatColorInt16, /**< A signed 16-bit integer color. */
kMVKFormatColorUInt16, /**< An unsigned 16-bit integer color. */
kMVKFormatColorInt32, /**< A signed 32-bit integer color. */
kMVKFormatColorUInt32, /**< An unsigned 32-bit integer color. */
kMVKFormatDepthStencil, /**< A depth and stencil value. */
kMVKFormatCompressed, /**< A block-compressed color. */
} MVKFormatType;
/** Returns whether the VkFormat is supported by this implementation. */
bool mvkVkFormatIsSupported(VkFormat vkFormat);
/** Returns whether the MTLPixelFormat is supported by this implementation. */
bool mvkMTLPixelFormatIsSupported(MTLPixelFormat mtlFormat);
/** Returns the format type corresponding to the specified Vulkan VkFormat, */
MVKFormatType mvkFormatTypeFromVkFormat(VkFormat vkFormat);
/** Returns the format type corresponding to the specified Metal MTLPixelFormat, */
MVKFormatType mvkFormatTypeFromMTLPixelFormat(MTLPixelFormat mtlFormat);
/**
* Returns the Metal MTLPixelFormat corresponding to the specified Vulkan VkFormat,
* or returns MTLPixelFormatInvalid if no corresponding MTLPixelFormat exists.
*
* Not all MTLPixelFormats returned by this function are supported by all GPU's,
* and, internally, MoltenVK may substitute and use a different MTLPixelFormat than
* is returned by this function for a particular Vulkan VkFormat value.
*
* Not all macOS GPU's support the MTLPixelFormatDepth24Unorm_Stencil8 pixel format.
* Even though this function will return that value when passed the corresponding
* VkFormat value, internally, MoltenVK will use the MTLPixelFormatDepth32Float_Stencil8
* instead when a GPU does not support the MTLPixelFormatDepth24Unorm_Stencil8 pixel format.
* On an macOS device that has more than one GPU, one of the GPU's may support the
* MTLPixelFormatDepth24Unorm_Stencil8 pixel format while another may not.
*/
MTLPixelFormat mvkMTLPixelFormatFromVkFormat(VkFormat vkFormat);
/**
* Returns the Vulkan VkFormat corresponding to the specified Metal MTLPixelFormat,
* or returns VK_FORMAT_UNDEFINED if no corresponding VkFormat exists.
*/
VkFormat mvkVkFormatFromMTLPixelFormat(MTLPixelFormat mtlFormat);
/**
* Returns the size, in bytes, of a texel block of the specified Vulkan format.
* For uncompressed formats, the returned value corresponds to the size in bytes of a single texel.
*/
uint32_t mvkVkFormatBytesPerBlock(VkFormat vkFormat);
/**
* Returns the size, in bytes, of a texel block of the specified Metal format.
* For uncompressed formats, the returned value corresponds to the size in bytes of a single texel.
*/
uint32_t mvkMTLPixelFormatBytesPerBlock(MTLPixelFormat mtlFormat);
/**
* Returns the size of the compression block, measured in texels for a Vulkan format.
* The returned value will be {1, 1} for non-compressed formats.
*/
VkExtent2D mvkVkFormatBlockTexelSize(VkFormat vkFormat);
/**
* Returns the size of the compression block, measured in texels for a Metal format.
* The returned value will be {1, 1} for non-compressed formats.
*/
VkExtent2D mvkMTLPixelFormatBlockTexelSize(MTLPixelFormat mtlFormat);
/**
* Returns the size, in bytes, of a texel of the specified Vulkan format.
* The returned value may be fractional for certain compressed formats.
*/
float mvkVkFormatBytesPerTexel(VkFormat vkFormat);
/**
* Returns the size, in bytes, of a texel of the specified Metal format.
* The returned value may be fractional for certain compressed formats.
*/
float mvkMTLPixelFormatBytesPerTexel(MTLPixelFormat mtlFormat);
/**
* Returns the size, in bytes, of a row of texels of the specified Vulkan format.
*
* For compressed formats, this takes into consideration the compression block size,
* and texelsPerRow should specify the width in texels, not blocks. The result is rounded
* up if texelsPerRow is not an integer multiple of the compression block width.
*/
size_t mvkVkFormatBytesPerRow(VkFormat vkFormat, uint32_t texelsPerRow);
/**
* Returns the size, in bytes, of a row of texels of the specified Metal format.
*
* For compressed formats, this takes into consideration the compression block size,
* and texelsPerRow should specify the width in texels, not blocks. The result is rounded
* up if texelsPerRow is not an integer multiple of the compression block width.
*/
size_t mvkMTLPixelFormatBytesPerRow(MTLPixelFormat mtlFormat, uint32_t texelsPerRow);
/**
* Returns the size, in bytes, of a texture layer of the specified Vulkan format.
*
* For compressed formats, this takes into consideration the compression block size,
* and texelRowsPerLayer should specify the height in texels, not blocks. The result is
* rounded up if texelRowsPerLayer is not an integer multiple of the compression block height.
*/
size_t mvkVkFormatBytesPerLayer(VkFormat vkFormat, size_t bytesPerRow, uint32_t texelRowsPerLayer);
/**
* Returns the size, in bytes, of a texture layer of the specified Metal format.
* For compressed formats, this takes into consideration the compression block size,
* and texelRowsPerLayer should specify the height in texels, not blocks. The result is
* rounded up if texelRowsPerLayer is not an integer multiple of the compression block height.
*/
size_t mvkMTLPixelFormatBytesPerLayer(MTLPixelFormat mtlFormat, size_t bytesPerRow, uint32_t texelRowsPerLayer);
/** Returns the default properties for the specified Vulkan format. */
VkFormatProperties mvkVkFormatProperties(VkFormat vkFormat);
/** Returns the name of the specified Vulkan format. */
const char* mvkVkFormatName(VkFormat vkFormat);
/** Returns the name of the specified Metal pixel format. */
const char* mvkMTLPixelFormatName(MTLPixelFormat mtlFormat);
/**
* Returns the MTLClearColor value corresponding to the color value in the VkClearValue,
* extracting the color value that is VkFormat for the VkFormat.
*/
MTLClearColor mvkMTLClearColorFromVkClearValue(VkClearValue vkClearValue,
VkFormat vkFormat);
/** Returns the Metal depth value corresponding to the depth value in the specified VkClearValue. */
double mvkMTLClearDepthFromVkClearValue(VkClearValue vkClearValue);
/** Returns the Metal stencil value corresponding to the stencil value in the specified VkClearValue. */
uint32_t mvkMTLClearStencilFromVkClearValue(VkClearValue vkClearValue);
/** Returns whether the specified Metal MTLPixelFormat can be used as a depth format. */
bool mvkMTLPixelFormatIsDepthFormat(MTLPixelFormat mtlFormat);
/** Returns whether the specified Metal MTLPixelFormat can be used as a stencil format. */
bool mvkMTLPixelFormatIsStencilFormat(MTLPixelFormat mtlFormat);
/** Returns whether the specified Metal MTLPixelFormat is a PVRTC format. */
bool mvkMTLPixelFormatIsPVRTCFormat(MTLPixelFormat mtlFormat);
/** Returns the Metal texture type from the specified Vulkan image properties. */
MTLTextureType mvkMTLTextureTypeFromVkImageType(VkImageType vkImageType,
uint32_t arraySize,
bool isMultisample);
/** Returns the Vulkan image type from the Metal texture type. */
VkImageType mvkVkImageTypeFromMTLTextureType(MTLTextureType mtlTextureType);
/** Returns the Metal MTLTextureType corresponding to the Vulkan VkImageViewType. */
MTLTextureType mvkMTLTextureTypeFromVkImageViewType(VkImageViewType vkImageViewType, bool isMultisample);
/** Returns the Metal texture usage from the Vulkan image usage taking into considertion usage limits for the pixel format. */
MTLTextureUsage mvkMTLTextureUsageFromVkImageUsageFlags(VkImageUsageFlags vkImageUsageFlags, MTLPixelFormat mtlPixFmt);
/** Returns the Vulkan image usage from the Metal texture usage and format. */
VkImageUsageFlags mvkVkImageUsageFlagsFromMTLTextureUsage(MTLTextureUsage mtlUsage, MTLPixelFormat mtlFormat);
/**
* Returns the numeric sample count corresponding to the specified Vulkan sample count flag.
*
* The specified flags value should have only one bit set, otherwise an invalid numeric value will be returned.
*/
uint32_t mvkSampleCountFromVkSampleCountFlagBits(VkSampleCountFlagBits vkSampleCountFlag);
/** Returns the Vulkan bit flags corresponding to the numeric sample count, which must be a PoT value. */
VkSampleCountFlagBits mvkVkSampleCountFlagBitsFromSampleCount(NSUInteger sampleCount);
/** Returns the Metal texture swizzle from the Vulkan component swizzle. */
MTLTextureSwizzle mvkMTLTextureSwizzleFromVkComponentSwizzle(VkComponentSwizzle vkSwizzle);
/** Returns all four Metal texture swizzles from the Vulkan component mapping. */
MTLTextureSwizzleChannels mvkMTLTextureSwizzleChannelsFromVkComponentMapping(VkComponentMapping vkMapping);
#pragma mark Mipmaps
/**
* Returns the number of mipmap levels available to an image with the specified side dimension.
*
* If the specified dimension is a power-of-two, the value returned is (log2(dim) + 1).
* If the specified dimension is NOT a power-of-two, the value returned is 0, indicating
* that the image cannot support mipmaps.
*/
uint32_t mvkMipmapLevels(uint32_t dim);
/**
* Returns the number of mipmap levels available to an image with the specified extent.
*
* If each dimension in the specified extent is a power-of-two, the value returned
* is MAX(log2(dim) + 1) across both dimensions. If either dimension in the specified
* extent is NOT a power-of-two, the value returned is 1, indicating that the image
* cannot support mipmaps, and that only the base mip level can be used.
*/
uint32_t mvkMipmapLevels2D(VkExtent2D extent);
/**
* Returns the number of mipmap levels available to an image with the specified extent.
*
* If each dimension in the specified extent is a power-of-two, the value returned
* is MAX(log2(dim) + 1) across all dimensions. If either dimension in the specified
* extent is NOT a power-of-two, the value returned is 1, indicating that the image
* cannot support mipmaps, and that only the base mip level can be used.
*/
uint32_t mvkMipmapLevels3D(VkExtent3D extent);
/**
* Returns the size of the specified zero-based mipmap level,
* when the size of the base level is the specified size.
*/
VkExtent2D mvkMipmapLevelSizeFromBaseSize2D(VkExtent2D baseSize, uint32_t level);
/**
* Returns the size of the specified zero-based mipmap level,
* when the size of the base level is the specified size.
*/
VkExtent3D mvkMipmapLevelSizeFromBaseSize3D(VkExtent3D baseSize, uint32_t level);
/**
* Returns the size of the mipmap base level, when the size of
* the specified zero-based mipmap level is the specified size.
*/
VkExtent2D mvkMipmapBaseSizeFromLevelSize2D(VkExtent2D levelSize, uint32_t level);
/**
* Returns the size of the mipmap base level, when the size of
* the specified zero-based mipmap level is the specified size.
*/
VkExtent3D mvkMipmapBaseSizeFromLevelSize3D(VkExtent3D levelSize, uint32_t level);
#pragma mark Samplers
/**
* Returns the Metal MTLSamplerAddressMode corresponding to the specified Vulkan VkSamplerAddressMode,
* or returns MTLSamplerAddressModeMirrorClampToEdge if no corresponding MTLSamplerAddressMode exists.
*/
MTLSamplerAddressMode mvkMTLSamplerAddressModeFromVkSamplerAddressMode(VkSamplerAddressMode vkMode);
#ifdef __MAC_OS_X_VERSION_MAX_ALLOWED
/**
* Returns the Metal MTLSamplerBorderColor corresponding to the specified Vulkan VkBorderColor,
* or returns MTLSamplerBorderColorTransparentBlack if no corresponding MTLSamplerBorderColor exists.
*/
MTLSamplerBorderColor mvkMTLSamplerBorderColorFromVkBorderColor(VkBorderColor vkColor);
#endif
/**
* Returns the Metal MTLSamplerMinMagFilter corresponding to the specified Vulkan VkFilter,
* or returns MTLSamplerMinMagFilterNearest if no corresponding MTLSamplerMinMagFilter exists.
*/
MTLSamplerMinMagFilter mvkMTLSamplerMinMagFilterFromVkFilter(VkFilter vkFilter);
/**
* Returns the Metal MTLSamplerMipFilter corresponding to the specified Vulkan VkSamplerMipmapMode,
* or returns MTLSamplerMipFilterNotMipmapped if no corresponding MTLSamplerMipFilter exists.
*/
MTLSamplerMipFilter mvkMTLSamplerMipFilterFromVkSamplerMipmapMode(VkSamplerMipmapMode vkMode);
#pragma mark -
#pragma mark Render pipeline
/** Identifies a particular shading stage in a pipeline. */
typedef enum {
kMVKShaderStageVertex = 0,
kMVKShaderStageTessCtl,
kMVKShaderStageTessEval,
kMVKShaderStageFragment,
kMVKShaderStageCompute,
kMVKShaderStageMax
} MVKShaderStage;
/** Returns the Metal MTLColorWriteMask corresponding to the specified Vulkan VkColorComponentFlags. */
MTLColorWriteMask mvkMTLColorWriteMaskFromVkChannelFlags(VkColorComponentFlags vkWriteFlags);
/** Returns the Metal MTLBlendOperation corresponding to the specified Vulkan VkBlendOp. */
MTLBlendOperation mvkMTLBlendOperationFromVkBlendOp(VkBlendOp vkBlendOp);
/** Returns the Metal MTLBlendFactor corresponding to the specified Vulkan VkBlendFactor. */
MTLBlendFactor mvkMTLBlendFactorFromVkBlendFactor(VkBlendFactor vkBlendFactor);
/**
* Returns the Metal MTLVertexFormat corresponding to the specified
* Vulkan VkFormat as used as a vertex attribute format.
*/
MTLVertexFormat mvkMTLVertexFormatFromVkFormat(VkFormat vkFormat);
/** Returns the Metal MTLVertexStepFunction corresponding to the specified Vulkan VkVertexInputRate. */
MTLVertexStepFunction mvkMTLVertexStepFunctionFromVkVertexInputRate(VkVertexInputRate vkVtxStep);
/** Returns the Metal MTLPrimitiveType corresponding to the specified Vulkan VkPrimitiveTopology. */
MTLPrimitiveType mvkMTLPrimitiveTypeFromVkPrimitiveTopology(VkPrimitiveTopology vkTopology);
/** Returns the Metal MTLPrimitiveTopologyClass corresponding to the specified Vulkan VkPrimitiveTopology. */
MTLPrimitiveTopologyClass mvkMTLPrimitiveTopologyClassFromVkPrimitiveTopology(VkPrimitiveTopology vkTopology);
/** Returns the Metal MTLTriangleFillMode corresponding to the specified Vulkan VkPolygonMode, */
MTLTriangleFillMode mvkMTLTriangleFillModeFromVkPolygonMode(VkPolygonMode vkFillMode);
/** Returns the Metal MTLLoadAction corresponding to the specified Vulkan VkAttachmentLoadOp. */
MTLLoadAction mvkMTLLoadActionFromVkAttachmentLoadOp(VkAttachmentLoadOp vkLoadOp);
/** Returns the Metal MTLStoreAction corresponding to the specified Vulkan VkAttachmentStoreOp. */
MTLStoreAction mvkMTLStoreActionFromVkAttachmentStoreOp(VkAttachmentStoreOp vkStoreOp, bool hasResolveAttachment);
/** Returns the Metal MTLViewport corresponding to the specified Vulkan VkViewport. */
MTLViewport mvkMTLViewportFromVkViewport(VkViewport vkViewport);
/** Returns the Metal MTLScissorRect corresponding to the specified Vulkan VkRect2D. */
MTLScissorRect mvkMTLScissorRectFromVkRect2D(VkRect2D vkRect);
/** Returns the Metal MTLCompareFunction corresponding to the specified Vulkan VkCompareOp, */
MTLCompareFunction mvkMTLCompareFunctionFromVkCompareOp(VkCompareOp vkOp);
/** Returns the Metal MTLStencilOperation corresponding to the specified Vulkan VkStencilOp, */
MTLStencilOperation mvkMTLStencilOperationFromVkStencilOp(VkStencilOp vkOp);
/** Returns the Metal MTLCullMode corresponding to the specified Vulkan VkCullModeFlags, */
MTLCullMode mvkMTLCullModeFromVkCullModeFlags(VkCullModeFlags vkCull);
/** Returns the Metal MTLWinding corresponding to the specified Vulkan VkFrontFace, */
MTLWinding mvkMTLWindingFromVkFrontFace(VkFrontFace vkWinding);
/** Returns the Metal MTLIndexType corresponding to the specified Vulkan VkIndexType, */
MTLIndexType mvkMTLIndexTypeFromVkIndexType(VkIndexType vkIdxType);
/** Returns the size, in bytes, of a vertex index of the specified type. */
size_t mvkMTLIndexTypeSizeInBytes(MTLIndexType mtlIdxType);
/** Returns the MoltenVK MVKShaderStage corresponding to the specified Vulkan VkShaderStageFlagBits. */
MVKShaderStage mvkShaderStageFromVkShaderStageFlagBits(VkShaderStageFlagBits vkStage);
/** Returns the Vulkan VkShaderStageFlagBits corresponding to the specified MoltenVK MVKShaderStage. */
VkShaderStageFlagBits mvkVkShaderStageFlagBitsFromMVKShaderStage(MVKShaderStage mvkStage);
/** Returns the Metal MTLWinding corresponding to the specified SPIR-V spv::ExecutionMode. */
MTLWinding mvkMTLWindingFromSpvExecutionMode(uint32_t spvMode);
/** Returns the Metal MTLTessellationPartitionMode corresponding to the specified SPIR-V spv::ExecutionMode. */
MTLTessellationPartitionMode mvkMTLTessellationPartitionModeFromSpvExecutionMode(uint32_t spvMode);
/**
* Returns the combination of Metal MTLRenderStage bits corresponding to the specified Vulkan VkPiplineStageFlags,
* taking into consideration whether the barrier is to be placed before or after the specified pipeline stages.
*/
MTLRenderStages mvkMTLRenderStagesFromVkPipelineStageFlags(VkPipelineStageFlags vkStages, bool placeBarrierBefore);
/** Returns the combination of Metal MTLBarrierScope bits corresponding to the specified Vulkan VkAccessFlags. */
MTLBarrierScope mvkMTLBarrierScopeFromVkAccessFlags(VkAccessFlags vkAccess);
#pragma mark -
#pragma mark Geometry conversions
/** Returns a VkExtent2D that corresponds to the specified CGSize. */
static inline VkExtent2D mvkVkExtent2DFromCGSize(CGSize cgSize) {
VkExtent2D vkExt;
vkExt.width = cgSize.width;
vkExt.height = cgSize.height;
return vkExt;
}
/** Returns a Metal MTLOrigin constructed from a VkOffset3D. */
static inline MTLOrigin mvkMTLOriginFromVkOffset3D(VkOffset3D vkOffset) {
return MTLOriginMake(vkOffset.x, vkOffset.y, vkOffset.z);
}
/** Returns a Vulkan VkOffset3D constructed from a Metal MTLOrigin. */
static inline VkOffset3D mvkVkOffset3DFromMTLSize(MTLOrigin mtlOrigin) {
return { (int32_t)mtlOrigin.x, (int32_t)mtlOrigin.y, (int32_t)mtlOrigin.z };
}
/** Returns a Metal MTLSize constructed from a VkExtent3D. */
static inline MTLSize mvkMTLSizeFromVkExtent3D(VkExtent3D vkExtent) {
return MTLSizeMake(vkExtent.width, vkExtent.height, vkExtent.depth);
}
/** Returns a Vulkan VkExtent3D constructed from a Metal MTLSize. */
static inline VkExtent3D mvkVkExtent3DFromMTLSize(MTLSize mtlSize) {
return { (uint32_t)mtlSize.width, (uint32_t)mtlSize.height, (uint32_t)mtlSize.depth };
}
#pragma mark -
#pragma mark Memory options
/** Macro indicating the Vulkan memory type bits corresponding to Metal private memory (not host visible). */
#define MVK_VK_MEMORY_TYPE_METAL_PRIVATE (VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT)
/** Macro indicating the Vulkan memory type bits corresponding to Metal shared memory (host visible and coherent). */
#define MVK_VK_MEMORY_TYPE_METAL_SHARED (VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT)
/** Macro indicating the Vulkan memory type bits corresponding to Metal managed memory (host visible and non-coherent). */
#define MVK_VK_MEMORY_TYPE_METAL_MANAGED (VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT | VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_CACHED_BIT)
/** Macro indicating the Vulkan memory type bits corresponding to Metal memoryless memory (not host visible and lazily allocated). */
#define MVK_VK_MEMORY_TYPE_METAL_MEMORYLESS (VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT | VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT)
/** Returns the Metal storage mode corresponding to the specified Vulkan memory flags. */
MTLStorageMode mvkMTLStorageModeFromVkMemoryPropertyFlags(VkMemoryPropertyFlags vkFlags);
/** Returns the Metal CPU cache mode corresponding to the specified Vulkan memory flags. */
MTLCPUCacheMode mvkMTLCPUCacheModeFromVkMemoryPropertyFlags(VkMemoryPropertyFlags vkFlags);
/** Returns the Metal resource option flags corresponding to the Metal storage mode and cache mode. */
MTLResourceOptions mvkMTLResourceOptions(MTLStorageMode mtlStorageMode, MTLCPUCacheMode mtlCPUCacheMode);
#ifdef __cplusplus
}
#endif // __cplusplus
#endif

View File

@@ -0,0 +1,49 @@
/*
* mvk_vulkan.h
*
* Copyright (c) 2015-2020 The Brenwill Workshop Ltd. (http://www.brenwill.com)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* This is a convenience header file that loads vulkan.h with the appropriate Vulkan platform extensions.
*
* This header automatically enables the VK_EXT_metal_surface Vulkan extension.
*
* When building for iOS, this header also automatically enables the obsolete VK_MVK_ios_surface Vulkan extension.
* When building for macOS, this header also automatically enables the obsolete VK_MVK_macos_surface Vulkan extension.
* Both of these extensions are obsolete. Consider using the portable VK_EXT_metal_surface extension instead.
*/
#ifndef __mvk_vulkan_h_
#define __mvk_vulkan_h_ 1
#include <Availability.h>
#define VK_USE_PLATFORM_METAL_EXT 1
#ifdef __IPHONE_OS_VERSION_MAX_ALLOWED
# define VK_USE_PLATFORM_IOS_MVK 1
#endif
#ifdef __MAC_OS_X_VERSION_MAX_ALLOWED
# define VK_USE_PLATFORM_MACOS_MVK 1
#endif
#include <vulkan/vulkan.h>
#include <vulkan-portability/vk_extx_portability_subset.h>
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,76 @@
#ifndef VK_EXTX_PORTABILITY_SUBSET_H_
#define VK_EXTX_PORTABILITY_SUBSET_H_ 1
#ifdef __cplusplus
extern "C" {
#endif
/*
** Copyright (c) 2018 The Khronos Group Inc.
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
** You may obtain a copy of the License at
**
** http://www.apache.org/licenses/LICENSE-2.0
**
** Unless required by applicable law or agreed to in writing, software
** distributed under the License is distributed on an "AS IS" BASIS,
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
** See the License for the specific language governing permissions and
** limitations under the License.
*/
/*
Please Note: This extension is currently defined as "EXTX", meaning "multivendor experimental".
That means the definition of this extension is in active development, and may break compatibility
between point releases (defined as any increment of VK_EXTX_PORTABILITY_SUBSET_SPEC_VERSION).
You are free to explore the extension and provide feedback, but it is not recommended to use this
extension for shipping applications, particularly applications that require the driver implementing this
extension to be linked dynamically and potentially "dropped-in" to the application execution environment.
*/
#include "vulkan/vulkan.h"
#define VK_EXTX_PORTABILITY_SUBSET_SPEC_VERSION 1
#define VK_EXTX_PORTABILITY_SUBSET_EXTENSION_NAME "VK_EXTX_portability_subset"
#define VK_EXTX_PORTABILITY_SUBSET_EXTENSION_ID 164
// See enum_offset() from https://www.khronos.org/registry/vulkan/specs/1.1/styleguide.html#_assigning_extension_token_values
#define VK_EXTX_PORTABILITY_SUBSET_STYPE_ID(x) \
((VkStructureType)(1000000000 + 1000 * (VK_EXTX_PORTABILITY_SUBSET_EXTENSION_ID - 1) + x))
#define VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PORTABILITY_SUBSET_FEATURES_EXTX VK_EXTX_PORTABILITY_SUBSET_STYPE_ID(0)
#define VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PORTABILITY_SUBSET_PROPERTIES_EXTX VK_EXTX_PORTABILITY_SUBSET_STYPE_ID(1)
#define VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_VIEW_SUPPORT_EXTX VK_EXTX_PORTABILITY_SUBSET_STYPE_ID(2)
typedef struct VkPhysicalDevicePortabilitySubsetFeaturesEXTX {
VkStructureType sType;
void* pNext;
VkBool32 triangleFans;
VkBool32 separateStencilMaskRef;
VkBool32 events;
VkBool32 standardImageViews;
VkBool32 samplerMipLodBias;
} VkPhysicalDevicePortabilitySubsetFeaturesEXTX;
typedef struct VkPhysicalDevicePortabilitySubsetPropertiesEXTX {
VkStructureType sType;
void* pNext;
uint32_t minVertexInputBindingStrideAlignment;
} VkPhysicalDevicePortabilitySubsetPropertiesEXTX;
typedef struct VkPhysicalDeviceImageViewSupportEXTX {
VkStructureType sType;
void* pNext;
VkImageViewCreateFlags flags;
VkImageViewType viewType;
VkFormat format;
VkComponentMapping components;
VkImageAspectFlags aspectMask;
} VkPhysicalDeviceImageViewSupportEXTX;
#ifdef __cplusplus
}
#endif
#endif // VK_EXTX_PORTABILITY_SUBSET_H_

BIN
externals/MoltenVK/lib/libMoltenVK.dylib vendored Executable file

Binary file not shown.

Binary file not shown.

BIN
externals/MoltenVK/lib/libvulkan.dylib vendored Executable file

Binary file not shown.

View File

@@ -62,10 +62,6 @@ else()
-Wno-unused-parameter
)
if (APPLE AND CMAKE_CXX_COMPILER_ID STREQUAL Clang)
add_compile_options("-stdlib=libc++")
endif()
# Set file offset size to 64 bits.
#
# On modern Unixes, this is typically already the case. The lone exception is

View File

@@ -14,12 +14,7 @@ namespace Core::Frontend {
/// Information for the Graphics Backends signifying what type of screen pointer is in
/// WindowInformation
enum class WindowSystemType {
Headless,
Windows,
X11,
Wayland,
};
enum class WindowSystemType { Headless, Windows, X11, Wayland, MacOS };
/**
* Represents a drawing context that supports graphics operations.
@@ -156,6 +151,14 @@ public:
return window_info;
}
/**
* Returns drawing area raw pointer
* Unsafe version for MoltenVK to modify pointer
*/
void*& GetRenderSurface() {
return window_info.render_surface;
}
/**
* Gets the framebuffer layout (width, height, and screen regions)
* @note This method is thread-safe

View File

@@ -258,3 +258,7 @@ if (MSVC)
else()
target_compile_options(video_core PRIVATE -Werror=conversion -Wno-error=sign-conversion)
endif()
if (APPLE)
target_include_directories(video_core PRIVATE ../../externals/MoltenVK/include)
endif()

View File

@@ -40,6 +40,13 @@
#include <vulkan/vulkan_win32.h>
#endif
#ifdef __APPLE__
#define VK_USE_PLATFORM_METAL_EXT
#include <objc/message.h>
#include "vulkan/vulkan_macos.h"
#include "vulkan/vulkan_metal.h"
#endif
#if !defined(_WIN32) && !defined(__APPLE__)
#include <X11/Xlib.h>
#include <vulkan/vulkan_wayland.h>
@@ -118,6 +125,11 @@ vk::Instance CreateInstance(Common::DynamicLibrary& library, vk::InstanceDispatc
extensions.push_back(VK_KHR_WIN32_SURFACE_EXTENSION_NAME);
break;
#endif
#ifdef __APPLE__
case Core::Frontend::WindowSystemType::MacOS:
extensions.push_back(VK_EXT_METAL_SURFACE_EXTENSION_NAME);
break;
#endif
#if !defined(_WIN32) && !defined(__APPLE__)
case Core::Frontend::WindowSystemType::X11:
extensions.push_back(VK_KHR_XLIB_SURFACE_EXTENSION_NAME);
@@ -137,7 +149,7 @@ vk::Instance CreateInstance(Common::DynamicLibrary& library, vk::InstanceDispatc
extensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
}
extensions.push_back(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
extensions.push_back(VK_KHR_GET_SURFACE_CAPABILITIES_2_EXTENSION_NAME);
const std::optional properties = vk::EnumerateInstanceExtensionProperties(dld);
if (!properties) {
LOG_ERROR(Render_Vulkan, "Failed to query extension properties");
@@ -155,7 +167,7 @@ vk::Instance CreateInstance(Common::DynamicLibrary& library, vk::InstanceDispatc
}
}
static constexpr std::array layers_data{"VK_LAYER_LUNARG_standard_validation"};
static constexpr std::array layers_data{"VK_LAYER_KHRONOS_validation"};
vk::Span<const char*> layers = layers_data;
if (!enable_layers) {
layers = {};
@@ -264,20 +276,56 @@ bool RendererVulkan::TryPresent(int /*timeout_ms*/) {
return true;
}
void PrepareMetalWindow([[maybe_unused]] void*& render_surface) {
#if defined(VK_USE_PLATFORM_METAL_EXT)
// Hackish: avoids having to write Objective C++ just to create a metal layer.
id view = reinterpret_cast<id>(render_surface);
Class clsCAMetalLayer = objc_getClass("CAMetalLayer");
if (!clsCAMetalLayer) {
LOG_ERROR(Render_Vulkan, "Failed to get CAMetalLayer class.");
return;
}
// [CAMetalLayer layer]
id layer = reinterpret_cast<id (*)(Class, SEL)>(objc_msgSend)(objc_getClass("CAMetalLayer"),
sel_getUid("layer"));
if (!layer) {
LOG_ERROR(Render_Vulkan, "Failed to create Metal layer.");
return;
}
// [view setWantsLayer:YES]
reinterpret_cast<void (*)(id, SEL, BOOL)>(objc_msgSend)(view, sel_getUid("setWantsLayer:"),
YES);
// [view setLayer:layer]
reinterpret_cast<void (*)(id, SEL, id)>(objc_msgSend)(view, sel_getUid("setLayer:"), layer);
// NSScreen* screen = [NSScreen mainScreen]
id screen = reinterpret_cast<id (*)(Class, SEL)>(objc_msgSend)(objc_getClass("NSScreen"),
sel_getUid("mainScreen"));
// CGFloat factor = [screen backingScaleFactor]
double factor = reinterpret_cast<double (*)(id, SEL)>(objc_msgSend)(
screen, sel_getUid("backingScaleFactor"));
// layer.contentsScale = factor
reinterpret_cast<void (*)(id, SEL, double)>(objc_msgSend)(
layer, sel_getUid("setContentsScale:"), factor);
// Store layer ptr, so MoltenVK doesn't call [NSView layer] outside main thread.
render_surface = layer;
#endif
}
bool RendererVulkan::Init() {
#ifdef __APPLE__
PrepareMetalWindow(render_window.GetRenderSurface());
#endif
library = OpenVulkanLibrary();
instance = CreateInstance(library, dld, render_window.GetWindowInfo().type,
Settings::values.renderer_debug);
if (!instance || !CreateDebugCallback() || !CreateSurface() || !PickDevices()) {
return false;
}
Report();
memory_manager = std::make_unique<VKMemoryManager>(*device);
resource_manager = std::make_unique<VKResourceManager>(*device);
const auto& framebuffer = render_window.GetFramebufferLayout();
swapchain = std::make_unique<VKSwapchain>(*surface, *device);
swapchain->Create(framebuffer.width, framebuffer.height, false);
@@ -329,7 +377,6 @@ bool RendererVulkan::CreateDebugCallback() {
bool RendererVulkan::CreateSurface() {
[[maybe_unused]] const auto& window_info = render_window.GetWindowInfo();
VkSurfaceKHR unsafe_surface = nullptr;
#ifdef _WIN32
if (window_info.type == Core::Frontend::WindowSystemType::Windows) {
const HWND hWnd = static_cast<HWND>(window_info.render_surface);
@@ -372,12 +419,26 @@ bool RendererVulkan::CreateSurface() {
return false;
}
}
#endif
#ifdef VK_USE_PLATFORM_METAL_EXT
if (window_info.type == Core::Frontend::WindowSystemType::MacOS) {
VkMetalSurfaceCreateInfoEXT surface_create_info = {
VK_STRUCTURE_TYPE_METAL_SURFACE_CREATE_INFO_EXT, nullptr, 0,
static_cast<const CAMetalLayer*>(window_info.render_surface)};
const auto vkCreateMetalSurfaceEXT = reinterpret_cast<PFN_vkCreateMetalSurfaceEXT>(
dld.vkGetInstanceProcAddr(*instance, "vkCreateMetalSurfaceEXT"));
if (!vkCreateMetalSurfaceEXT ||
vkCreateMetalSurfaceEXT(*instance, &surface_create_info, nullptr, &unsafe_surface) !=
VK_SUCCESS) {
LOG_ERROR(Render_Vulkan, "Failed to initialize Metal surface");
return false;
}
}
#endif
if (!unsafe_surface) {
LOG_ERROR(Render_Vulkan, "Presentation not supported on this platform");
return false;
}
surface = vk::SurfaceKHR(unsafe_surface, *instance, dld);
return true;
}

View File

@@ -36,6 +36,8 @@ struct VKScreenInfo {
bool is_srgb{};
};
void PrepareMetalWindow([[maybe_unused]] void*& render_surface);
class RendererVulkan final : public VideoCore::RendererBase {
public:
explicit RendererVulkan(Core::Frontend::EmuWindow& window, Core::System& system);

View File

@@ -33,12 +33,17 @@ constexpr std::array REQUIRED_EXTENSIONS = {
VK_KHR_SWAPCHAIN_EXTENSION_NAME,
VK_KHR_16BIT_STORAGE_EXTENSION_NAME,
VK_KHR_8BIT_STORAGE_EXTENSION_NAME,
VK_KHR_DRIVER_PROPERTIES_EXTENSION_NAME,
VK_KHR_DESCRIPTOR_UPDATE_TEMPLATE_EXTENSION_NAME,
VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_EXTENSION_NAME,
VK_EXT_HOST_QUERY_RESET_EXTENSION_NAME,
// If device doesn't support draw_parameters there's no chance it runs anything
VK_KHR_SHADER_DRAW_PARAMETERS_EXTENSION_NAME,
#ifndef __APPLE__
VK_KHR_DRIVER_PROPERTIES_EXTENSION_NAME,
// Subgroup ballot/vote will be supported by MoltenVK shortly
VK_EXT_SHADER_SUBGROUP_BALLOT_EXTENSION_NAME,
VK_EXT_SHADER_SUBGROUP_VOTE_EXTENSION_NAME,
VK_EXT_HOST_QUERY_RESET_EXTENSION_NAME,
#endif
};
template <typename T>
@@ -180,7 +185,11 @@ bool VKDevice::Create() {
features.fullDrawIndexUint32 = false;
features.imageCubeArray = false;
features.independentBlend = true;
#ifdef __APPLE__
features.geometryShader = false;
#else
features.geometryShader = true;
#endif
features.tessellationShader = true;
features.sampleRateShading = false;
features.dualSrcBlend = false;
@@ -495,13 +504,15 @@ bool VKDevice::IsSuitable(vk::PhysicalDevice physical, VkSurfaceKHR surface) {
std::make_pair(features.largePoints, "largePoints"),
std::make_pair(features.multiViewport, "multiViewport"),
std::make_pair(features.depthBiasClamp, "depthBiasClamp"),
std::make_pair(features.geometryShader, "geometryShader"),
std::make_pair(features.tessellationShader, "tessellationShader"),
std::make_pair(features.occlusionQueryPrecise, "occlusionQueryPrecise"),
std::make_pair(features.fragmentStoresAndAtomics, "fragmentStoresAndAtomics"),
std::make_pair(features.shaderImageGatherExtended, "shaderImageGatherExtended"),
std::make_pair(features.shaderStorageImageWriteWithoutFormat,
"shaderStorageImageWriteWithoutFormat"),
#ifndef __APPLE__
std::make_pair(features.geometryShader, "geometryShader"),
#endif
};
for (const auto& [supported, name] : feature_report) {
if (supported) {

View File

@@ -595,8 +595,11 @@ void RasterizerVulkan::WaitForIdle() {
VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT | VK_PIPELINE_STAGE_VERTEX_INPUT_BIT |
VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT |
VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT |
VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT |
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT |
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT | VK_PIPELINE_STAGE_TRANSFER_BIT;
#ifndef __APPLE__
flags = flags | VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT;
#endif
if (device.IsExtTransformFeedbackSupported()) {
flags |= VK_PIPELINE_STAGE_TRANSFORM_FEEDBACK_BIT_EXT;
}

View File

@@ -276,14 +276,19 @@ class SPIRVDecompiler final : public Sirit::Module {
public:
explicit SPIRVDecompiler(const VKDevice& device, const ShaderIR& ir, ShaderType stage,
const Registry& registry, const Specialization& specialization)
: Module(0x00010300), device{device}, ir{ir}, stage{stage}, header{ir.GetHeader()},
:
#ifdef __APPLE__
Module(0x00010000),
#else
Module(0x00010300),
#endif
device{device}, ir{ir}, stage{stage}, header{ir.GetHeader()},
registry{registry}, specialization{specialization} {
if (stage != ShaderType::Compute) {
transform_feedback = BuildTransformFeedback(registry.GetGraphicsInfo());
}
AddCapability(spv::Capability::Shader);
AddCapability(spv::Capability::UniformAndStorageBuffer16BitAccess);
AddCapability(spv::Capability::ImageQuery);
AddCapability(spv::Capability::Image1D);
AddCapability(spv::Capability::ImageBuffer);
@@ -291,13 +296,19 @@ public:
AddCapability(spv::Capability::SampledBuffer);
AddCapability(spv::Capability::StorageImageWriteWithoutFormat);
AddCapability(spv::Capability::DrawParameters);
AddCapability(spv::Capability::UniformAndStorageBuffer16BitAccess);
#ifndef __APPLE__
// These can be added back when MoltenVK finally supports vk 1.1
AddCapability(spv::Capability::SubgroupBallotKHR);
AddCapability(spv::Capability::SubgroupVoteKHR);
AddExtension("SPV_KHR_shader_ballot");
AddExtension("SPV_KHR_subgroup_vote");
AddExtension("SPV_KHR_storage_buffer_storage_class");
#endif
// Uniform 16bit Storage should only be added if version < 1.1
AddExtension(VK_KHR_16BIT_STORAGE_EXTENSION_NAME);
AddExtension(VK_KHR_SHADER_DRAW_PARAMETERS_EXTENSION_NAME);
AddExtension(VK_KHR_STORAGE_BUFFER_STORAGE_CLASS_EXTENSION_NAME);
AddExtension("SPV_KHR_variable_pointers");
AddExtension("SPV_KHR_shader_draw_parameters");
if (!transform_feedback.empty()) {
if (device.IsExtTransformFeedbackSupported()) {
@@ -514,6 +525,8 @@ private:
}
void DeclareCommon() {
#ifndef __APPLE__
//subgrouplocalinvocationId requires VK_EXT_shader_subgroup_ballot - isn't in metal yet
thread_id =
DeclareInputBuiltIn(spv::BuiltIn::SubgroupLocalInvocationId, t_in_uint, "thread_id");
thread_masks[0] =
@@ -526,6 +539,7 @@ private:
DeclareInputBuiltIn(spv::BuiltIn::SubgroupLeMask, t_in_uint4, "thread_le_mask");
thread_masks[4] =
DeclareInputBuiltIn(spv::BuiltIn::SubgroupLtMask, t_in_uint4, "thread_lt_mask");
#endif
}
void DeclareVertex() {
@@ -631,7 +645,11 @@ private:
void DeclareRegisters() {
for (const u32 gpr : ir.GetRegisters()) {
#ifdef __APPLE__
const Id id = OpVariable(t_prv_float, spv::StorageClass::Private);
#else
const Id id = OpVariable(t_prv_float, spv::StorageClass::Private, v_float_zero);
#endif
Name(id, fmt::format("gpr_{}", gpr));
registers.emplace(gpr, AddGlobalVariable(id));
}
@@ -640,7 +658,11 @@ private:
void DeclareCustomVariables() {
const u32 num_custom_variables = ir.GetNumCustomVariables();
for (u32 i = 0; i < num_custom_variables; ++i) {
#ifdef __APPLE__
const Id id = OpVariable(t_prv_float, spv::StorageClass::Private);
#else
const Id id = OpVariable(t_prv_float, spv::StorageClass::Private, v_float_zero);
#endif
Name(id, fmt::format("custom_var_{}", i));
custom_variables.emplace(i, AddGlobalVariable(id));
}
@@ -648,7 +670,11 @@ private:
void DeclarePredicates() {
for (const auto pred : ir.GetPredicates()) {
#ifdef __APPLE__
const Id id = OpVariable(t_prv_bool, spv::StorageClass::Private);
#else
const Id id = OpVariable(t_prv_bool, spv::StorageClass::Private, v_false);
#endif
Name(id, fmt::format("pred_{}", static_cast<u32>(pred)));
predicates.emplace(pred, AddGlobalVariable(id));
}
@@ -656,7 +682,11 @@ private:
void DeclareFlowVariables() {
for (u32 i = 0; i < ir.GetASTNumVariables(); i++) {
#ifdef __APPLE__
const Id id = OpVariable(t_prv_bool, spv::StorageClass::Private);
#else
const Id id = OpVariable(t_prv_bool, spv::StorageClass::Private, v_false);
#endif
Name(id, fmt::format("flow_var_{}", static_cast<u32>(i)));
flow_variables.emplace(i, AddGlobalVariable(id));
}
@@ -703,7 +733,11 @@ private:
constexpr std::array names = {"zero", "sign", "carry", "overflow"};
for (std::size_t flag = 0; flag < INTERNAL_FLAGS_COUNT; ++flag) {
const auto flag_code = static_cast<InternalFlag>(flag);
#ifdef __APPLE__
const Id id = OpVariable(t_prv_bool, spv::StorageClass::Private);
#else
const Id id = OpVariable(t_prv_bool, spv::StorageClass::Private, v_false);
#endif
internal_flags[flag] = AddGlobalVariable(Name(id, names[flag]));
}
}
@@ -1327,10 +1361,11 @@ private:
}
if (const auto comment = std::get_if<CommentNode>(&*node)) {
#ifndef __APPLE__ // This doesn't work at all on moltenVK
Name(OpUndef(t_void), comment->GetText());
#endif
return {};
}
UNREACHABLE();
return {};
}

View File

@@ -373,7 +373,11 @@ Instance Instance::Create(Span<const char*> layers, Span<const char*> extensions
application_info.applicationVersion = VK_MAKE_VERSION(0, 1, 0);
application_info.pEngineName = "yuzu Emulator";
application_info.engineVersion = VK_MAKE_VERSION(0, 1, 0);
#ifdef __APPLE__
application_info.apiVersion = VK_API_VERSION_1_0;
#else
application_info.apiVersion = VK_API_VERSION_1_1;
#endif
VkInstanceCreateInfo ci;
ci.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;

View File

@@ -16,6 +16,10 @@
#define VK_NO_PROTOTYPES
#include <vulkan/vulkan.h>
#ifdef __APPLE__
#include <MoltenVK/vk_mvk_moltenvk.h>
#endif
#include "common/common_types.h"
namespace Vulkan::vk {

View File

@@ -216,3 +216,47 @@ if (ENABLE_VULKAN)
target_include_directories(yuzu PRIVATE ../../externals/Vulkan-Headers/include)
target_compile_definitions(yuzu PRIVATE HAS_VULKAN)
endif()
if(APPLE)
target_include_directories(yuzu PRIVATE ../../externals/MoltenVK/include)
#include(BundleUtilities)
set(BUNDLE_PATH ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/yuzu.app)
# Ask for an application bundle.
set_target_properties(yuzu PROPERTIES
MACOSX_BUNDLE true
MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/Info.plist
)
# Copy Qt plugins into the bundle
get_target_property(qtcocoa_location Qt5::QCocoaIntegrationPlugin LOCATION)
target_sources(yuzu PRIVATE "${qtcocoa_location}")
set_source_files_properties("${qtcocoa_location}" PROPERTIES MACOSX_PACKAGE_LOCATION MacOS/platforms)
get_target_property(qtmacstyle_location Qt5::QMacStylePlugin LOCATION)
target_sources(yuzu PRIVATE "${qtmacstyle_location}")
set_source_files_properties("${qtmacstyle_location}" PROPERTIES MACOSX_PACKAGE_LOCATION MacOS/styles)
# Copy MoltenVK into the bundle
target_sources(yuzu PRIVATE "${CMAKE_SOURCE_DIR}/externals/MoltenVK/lib/libMoltenVK.dylib")
set_source_files_properties("${CMAKE_SOURCE_DIR}/externals/MoltenVK/lib/libMoltenVK.dylib" PROPERTIES MACOSX_PACKAGE_LOCATION Frameworks)
target_sources(yuzu PRIVATE "${CMAKE_SOURCE_DIR}/externals/MoltenVK/lib/libvulkan.dylib")
set_source_files_properties("${CMAKE_SOURCE_DIR}/externals/MoltenVK/lib/libvulkan.dylib" PROPERTIES MACOSX_PACKAGE_LOCATION Frameworks)
# Copy validation layers as well
target_sources(yuzu PRIVATE "${CMAKE_SOURCE_DIR}/externals/MoltenVK/lib/libVkLayer_khronos_validation.dylib")
set_source_files_properties("${CMAKE_SOURCE_DIR}/externals/MoltenVK/lib/libVkLayer_khronos_validation.dylib" PROPERTIES MACOSX_PACKAGE_LOCATION Frameworks)
target_sources(yuzu PRIVATE "${CMAKE_SOURCE_DIR}/externals/MoltenVK/Resources/vulkan/icd.d/MoltenVK_icd.json")
set_source_files_properties("${CMAKE_SOURCE_DIR}/externals/MoltenVK/Resources/vulkan/icd.d/MoltenVK_icd.json" PROPERTIES MACOSX_PACKAGE_LOCATION "Resources/vulkan/icd.d")
# Update library references to make the bundle portable
include(PostprocessBundle)
#postprocess_bundle(yuzu)
# Fix rpath
add_custom_command(TARGET yuzu
POST_BUILD COMMAND
${CMAKE_INSTALL_NAME_TOOL} -add_rpath "@executable_path/../Frameworks/"
$<TARGET_FILE:yuzu>)
endif()

View File

@@ -261,6 +261,8 @@ static Core::Frontend::WindowSystemType GetWindowSystemType() {
return Core::Frontend::WindowSystemType::X11;
else if (platform_name == QStringLiteral("wayland"))
return Core::Frontend::WindowSystemType::Wayland;
else if (platform_name == QStringLiteral("cocoa"))
return Core::Frontend::WindowSystemType::MacOS;
LOG_CRITICAL(Frontend, "Unknown Qt platform!");
return Core::Frontend::WindowSystemType::Windows;

View File

@@ -8,6 +8,7 @@
#include <thread>
#ifdef __APPLE__
#include <unistd.h> // for chdir
#include <stdlib.h> // for setenv
#endif
// VFS includes must be before glad as they will conflict with Windows file api, which uses defines.
@@ -2442,6 +2443,9 @@ int main(int argc, char* argv[]) {
QCoreApplication::setApplicationName(QStringLiteral("yuzu"));
#ifdef __APPLE__
// Set MoltenVK Environment Variable. Done before anything else so before graphics backend init
// This avoids a nightmare of calling vk_mvk_moltenvk to set config settings
setenv("MVK_CONFIG_FULL_IMAGE_VIEW_SWIZZLE", "1", 1);
// If you start a bundle (binary) on OSX without the Terminal, the working directory is "/".
// But since we require the working directory to be the executable path for the location of the
// user folder in the Qt Frontend, we need to cd into that working directory

View File

@@ -43,3 +43,7 @@ if (MSVC)
copy_yuzu_SDL_deps(yuzu-cmd)
copy_yuzu_unicorn_deps(yuzu-cmd)
endif()
if (APPLE AND ENABLE_VULKAN)
target_include_directories(yuzu-cmd PRIVATE ../../externals/MoltenVK/include)
endif()