Merge branch 'master' into amd-gpu-shader-half-float

This commit is contained in:
Chip Davis 2019-01-15 15:44:47 -06:00 committed by GitHub
commit 2450c890dd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
24 changed files with 742 additions and 316 deletions

View File

@ -23,7 +23,8 @@ Table of Contents
- [Build and Runtime Requirements](#requirements) - [Build and Runtime Requirements](#requirements)
- [Install as Static Framework, Static Library, or Dynamic Library](#install_lib) - [Install as Static Framework, Static Library, or Dynamic Library](#install_lib)
- [Interacting with the **MoltenVK** Runtime](#interaction) - [Interacting with the **MoltenVK** Runtime](#interaction)
- [MoltenVK Extension](#moltenvk_extension) - [MoltenVK `VK_MVK_moltenvk` Extension](#moltenvk_extension)
- [Configuring MoltenVK](#moltenvk_config)
- [*Metal Shading Language* Shaders](#shaders) - [*Metal Shading Language* Shaders](#shaders)
- [MoltenVKShaderConverter Shader Converter Tool](#shader_converter_tool) - [MoltenVKShaderConverter Shader Converter Tool](#shader_converter_tool)
- [Troubleshooting Shader Conversion](#spv_vs_msl) - [Troubleshooting Shader Conversion](#spv_vs_msl)
@ -243,9 +244,9 @@ In addition to the core *Vulkan* API, **MoltenVK** also supports the following
- `VK_KHR_swapchain_mutable_format` - `VK_KHR_swapchain_mutable_format`
- `VK_EXT_shader_viewport_index_layer` - `VK_EXT_shader_viewport_index_layer`
- `VK_EXT_vertex_attribute_divisor` - `VK_EXT_vertex_attribute_divisor`
- `VK_MVK_moltenvk`
- `VK_MVK_macos_surface` (macOS) - `VK_MVK_macos_surface` (macOS)
- `VK_MVK_ios_surface` (iOS) - `VK_MVK_ios_surface` (iOS)
- `VK_MVK_moltenvk`
- `VK_AMD_gpu_shader_half_float` - `VK_AMD_gpu_shader_half_float`
- `VK_AMD_negative_viewport_height` - `VK_AMD_negative_viewport_height`
- `VK_IMG_format_pvrtc` (iOS) - `VK_IMG_format_pvrtc` (iOS)
@ -260,9 +261,9 @@ of the `mvk_vulkan.h` file below for a convenient way to enable these extensions
When using the `VK_MVK_macos_surface ` extension, the `pView` member of the `VkMacOSSurfaceCreateInfoMVK` When using the `VK_MVK_macos_surface ` extension, the `pView` member of the `VkMacOSSurfaceCreateInfoMVK`
structure passed in the `vkCreateMacOSSurfaceMVK` function can be either an `NSView` whose layer is a structure passed in the `vkCreateMacOSSurfaceMVK` function can be either an `NSView` whose layer is a
`CAMetalLayer`, or the `CAMetalLayer` itself. Passing the `CAMetalLayer` itself is recommended when calling `CAMetalLayer`, or the `CAMetalLayer` itself. Passing the `CAMetalLayer` itself is recommended when
the `vkCreateMacOSSurfaceMVK` function from outside the main application thread, as `NSView` should only be calling the `vkCreateMacOSSurfaceMVK` function from outside the main application thread, as `NSView`
accessed from the main application thread. should only be accessed from the main application thread.
When using the `VK_MVK_ios_surface ` extension, the `pView` member of the `VkIOSSurfaceCreateInfoMVK` When using the `VK_MVK_ios_surface ` extension, the `pView` member of the `VkIOSSurfaceCreateInfoMVK`
structure passed in the `vkCreateIOSSurfaceMVK` function can be either a `UIView` whose layer is a structure passed in the `vkCreateIOSSurfaceMVK` function can be either a `UIView` whose layer is a
@ -270,14 +271,14 @@ structure passed in the `vkCreateIOSSurfaceMVK` function can be either a `UIView
calling the `vkCreateIOSSurfaceMVK ` function from outside the main application thread, as `UIView` calling the `vkCreateIOSSurfaceMVK ` function from outside the main application thread, as `UIView`
should only be accessed from the main application thread. should only be accessed from the main application thread.
<a name="moltenvk_extension"></a>
### MoltenVK Extension
The `VK_MVK_moltenvk` *Vulkan* extension provides functionality beyond the standard *Vulkan* <a name="moltenvk_extension"></a>
API, to support configuration options, license registration, and behaviour that is specific ### MoltenVK `VK_MVK_moltenvk` Extension
to the **MoltenVK** implementation of *Vulkan*. You can access this functionality by including
the `vk_mvk_moltenvk.h` header file in your code. The `vk_mvk_moltenvk.h` file also includes The `VK_MVK_moltenvk` *Vulkan* extension provides functionality beyond the standard *Vulkan* API, to
the API documentation for this `VK_MVK_moltenvk` extension. support configuration options and behaviour that is specific to the **MoltenVK** implementation of *Vulkan*.
You can access this functionality by including the `vk_mvk_moltenvk.h` header file in your code.
The `vk_mvk_moltenvk.h` file also includes the API documentation for this `VK_MVK_moltenvk` extension.
The following API header files are included in the **MoltenVK** package, each of which The following API header files are included in the **MoltenVK** package, each of which
can be included in your application source code as follows: can be included in your application source code as follows:
@ -306,6 +307,30 @@ where `HEADER_FILE` is one of the following:
directly, or simply logging data values. directly, or simply logging data values.
<a name="moltenvk_config"></a>
### Configuring MoltenVK
The `VK_MVK_moltenvk` *Vulkan* extension provides the ability to configure and optimize
**MoltenVK** for your particular application runtime requirements.
There are three mechanisms for setting the values of the **MoltenVK** configuration parameters:
- Runtime API via the `vkGetMoltenVKConfigurationMVK()/vkSetMoltenVKConfigurationMVK()` functions.
- Application runtime environment variables.
- Build settings at **MoltenVK** build time.
To change the **MoltenVK** configuration settings at runtime using a programmatic API, use the
`vkGetMoltenVKConfigurationMVK()` and `vkSetMoltenVKConfigurationMVK()` functions to retrieve,
modify, and set a copy of the `MVKConfiguration` structure.
The initial value of each of the configuration settings can established at runtime
by a corresponding environment variable, or if the environment variable is not set,
by a corresponding build setting at the time **MoltenVK** is compiled. The environment
variable and build setting for each configuration parameter share the same name.
See the description of the `MVKConfiguration` structure parameters in the `vk_mvk_moltenvk.h`
file for more info about configuring and optimizing **MoltenVK** at build time or runtime.
<a name="shaders"></a> <a name="shaders"></a>
*Metal Shading Language* Shaders *Metal Shading Language* Shaders
@ -377,21 +402,16 @@ you can address the issue as follows:
- Errors encountered during **Runtime Shader Conversion** are logged to the console. - Errors encountered during **Runtime Shader Conversion** are logged to the console.
- To help understand conversion issues during **Runtime Shader Conversion**, you can enable - To help understand conversion issues during **Runtime Shader Conversion**, you can enable the
the logging of the *SPIR-V* and *MSL* shader source code during conversion as follows: logging of the *SPIR-V* and *MSL* shader source code during shader conversion, by turning on
the `MVKConfiguration::debugMode` configuration parameter, or setting the value of the `MVK_DEBUG`
#include <MoltenVK/vk_mvk_moltenvk.h> runtime environment variable to `1`. See the [*MoltenVK Configuration*](#moltenvk_config)
... description above.
MVKConfiguration mvkConfig;
size_t appConfigSize = sizeof(mvkConfig);
vkGetMoltenVKConfigurationMVK(vkInstance, &mvkConfig, &appConfigSize);
mvkConfig.debugMode = true;
vkSetMoltenVKConfigurationMVK(vkInstance, &mvkConfig, &appConfigSize);
Performing these steps will enable debug mode in **MoltenVK**, which includes shader conversion Enabling debug mode in **MoltenVK** includes shader conversion logging, which causes both
logging, and causes both the incoming *SPIR-V* code and the converted *MSL* source code to be the incoming *SPIR-V* code and the converted *MSL* source code to be logged to the console
logged to the console (in human-readable form). This allows you to manually verify the conversions, in human-readable form. This allows you to manually verify the conversions, and can help
and can help you diagnose issues that might occur during shader conversion. you diagnose issues that might occur during shader conversion.
- For minor issues, you may be able to adjust your *SPIR-V* code so that it behaves the same - For minor issues, you may be able to adjust your *SPIR-V* code so that it behaves the same
under *Vulkan*, but is easier to automatically convert to *MSL*. under *Vulkan*, but is easier to automatically convert to *MSL*.

View File

@ -13,6 +13,35 @@ For best results, use a Markdown reader.*
MoltenVK 1.0.31
---------------
Released 2018/01/15
- Support runtime config via runtime environment variables
- Add full ImageView swizzling to config, and disable it by default.
- Add GPU switching to config, and enable it by default.
- Add queue family specialization to config, and disable it by default.
- Enable synchronous queue submits as config default.
- Support 4 queue families.
- Pad fragment shader output to 4 components when needed.
- Add support for copying to and from PVRTC images.
- Log Vulkan versions in human readable form when reporting version error.
- Update `VK_MVK_MOLTENVK_SPEC_VERSION` to 16.
- Update copyright to 2019.
- Update to latest SPIRV-Cross version:
- MSL: Support SPV_KHR_variable_pointers.
- MSL: Workaround missing gradient2d() on macOS for typical cascaded shadow mapping.
- MSL: Fix mapping of identity-swizzled components.
- MSL: Support composites inside I/O blocks.
- MSL: Fix case where we pass arrays to functions by value.
- MSL: Add option to pad fragment outputs.
- MSL: Fix passing a sampled image to a function.
- Performance improvements on iterating internal constructs.
- Update copyright to 2019.
MoltenVK 1.0.30 MoltenVK 1.0.30
--------------- ---------------

View File

@ -1 +1 @@
ed16b3e69985feaf565efbecea70a1cc2fca2a58 9e3a41ad00ca48b9119d805cd96f337984458fe7

View File

@ -204,6 +204,9 @@ bool mvkMTLPixelFormatIsDepthFormat(MTLPixelFormat mtlFormat);
/** Returns whether the specified Metal MTLPixelFormat can be used as a stencil format. */ /** Returns whether the specified Metal MTLPixelFormat can be used as a stencil format. */
bool mvkMTLPixelFormatIsStencilFormat(MTLPixelFormat mtlFormat); 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. */ /** Returns the Metal texture type from the specified Vulkan image properties. */
MTLTextureType mvkMTLTextureTypeFromVkImageType(VkImageType vkImageType, MTLTextureType mvkMTLTextureTypeFromVkImageType(VkImageType vkImageType,
uint32_t arraySize, uint32_t arraySize,

View File

@ -48,28 +48,37 @@ extern "C" {
*/ */
#define MVK_VERSION_MAJOR 1 #define MVK_VERSION_MAJOR 1
#define MVK_VERSION_MINOR 0 #define MVK_VERSION_MINOR 0
#define MVK_VERSION_PATCH 30 #define MVK_VERSION_PATCH 31
#define MVK_MAKE_VERSION(major, minor, patch) (((major) * 10000) + ((minor) * 100) + (patch)) #define MVK_MAKE_VERSION(major, minor, patch) (((major) * 10000) + ((minor) * 100) + (patch))
#define MVK_VERSION MVK_MAKE_VERSION(MVK_VERSION_MAJOR, MVK_VERSION_MINOR, MVK_VERSION_PATCH) #define MVK_VERSION MVK_MAKE_VERSION(MVK_VERSION_MAJOR, MVK_VERSION_MINOR, MVK_VERSION_PATCH)
#define VK_MVK_MOLTENVK_SPEC_VERSION 15 #define VK_MVK_MOLTENVK_SPEC_VERSION 16
#define VK_MVK_MOLTENVK_EXTENSION_NAME "VK_MVK_moltenvk" #define VK_MVK_MOLTENVK_EXTENSION_NAME "VK_MVK_moltenvk"
/** /**
* MoltenVK configuration settings. * MoltenVK configuration settings.
* *
* To change the MoltenVK configuration settings, use the vkGetMoltenVKConfigurationMVK() and
* vkSetMoltenVKConfigurationMVK() functions to retrieve, modify, and set a copy of this structure.
*
* To be active, some configuration settings must be set before a VkDevice is created. * To be active, some configuration settings must be set before a VkDevice is created.
* See the description of the individual configuration structure members for more information. * See the description of the individual configuration structure members for more information.
* *
* The initial value of several of these settings is deterined when MolttenVK is compiled by the * There are three mechanisms for setting the values of the MoltenVK configuration parameters:
* presence of a DEBUG build setting, By default the DEBUG build setting is present when MoltenVK * - Runtime API via the vkGetMoltenVKConfigurationMVK()/vkSetMoltenVKConfigurationMVK() functions.
* is compiled in Debug mode, and not present when compiled in Release mode. The initial values * - Application runtime environment variables.
* of the other settings are determined by other build settings when MoltenVK is compiled. * - Build settings at MoltenVK build time.
* See the description of the individual configuration structure members for more information. *
* To change the MoltenVK configuration settings at runtime using a programmatic API,
* use the vkGetMoltenVKConfigurationMVK() and vkSetMoltenVKConfigurationMVK() functions
* to retrieve, modify, and set a copy of the MVKConfiguration structure.
*
* The initial value of each of the configuration settings can established at runtime
* by a corresponding environment variable, or if the environment variable is not set,
* by a corresponding build setting at the time MoltenVK is compiled. The environment
* variable and build setting for each configuration parameter share the same name.
*
* For example, the initial value of the shaderConversionFlipVertexY configuration setting
* is set by the MVK_CONFIG_SHADER_CONVERSION_FLIP_VERTEX_Y at runtime, or by the
* MVK_CONFIG_SHADER_CONVERSION_FLIP_VERTEX_Y build setting when MoltenVK is compiled.
* *
* This structure may be extended as new features are added to MoltenVK. If you are linking to * This structure may be extended as new features are added to MoltenVK. If you are linking to
* an implementation of MoltenVK that was compiled from a different VK_MVK_MOLTENVK_SPEC_VERSION * an implementation of MoltenVK that was compiled from a different VK_MVK_MOLTENVK_SPEC_VERSION
@ -78,28 +87,43 @@ extern "C" {
* vkSetMoltenVKConfigurationMVK() functions for information about how to handle this. * vkSetMoltenVKConfigurationMVK() functions for information about how to handle this.
* *
* TO SUPPORT DYNAMIC LINKING TO THIS STRUCTURE AS DESCRIBED ABOVE, THIS STRUCTURE SHOULD NOT * TO SUPPORT DYNAMIC LINKING TO THIS STRUCTURE AS DESCRIBED ABOVE, THIS STRUCTURE SHOULD NOT
* BE CHANGE EXCEPT TO ADD ADDITIONAL MEMBERS ON THE END. EXISTING MEMBERS, AND THEIR ORDER, * BE CHANGED EXCEPT TO ADD ADDITIONAL MEMBERS ON THE END. EXISTING MEMBERS, AND THEIR ORDER,
* SHOULD NOT BE CHANGED. * SHOULD NOT BE CHANGED.
*/ */
typedef struct { typedef struct {
/** /**
* If enabled, debugging capabilities will be enabled, including logging shader code * If enabled, debugging capabilities will be enabled, including logging
* during runtime shader conversion. * shader code during runtime shader conversion.
* *
* Initial value is true in the presence of the DEBUG build setting, and false otherwise. * The value of this parameter may be changed at any time during application runtime,
* and the changed value will immediately effect subsequent MoltenVK behaviour.
*
* The initial value or this parameter is set by the
* MVK_DEBUG
* runtime environment variable or MoltenVK compile-time build setting.
* If neither is set, the value of this parameter is false if MoltenVK was
* built in Release mode, and true if MoltenVK was built in Debug mode.
*/ */
VkBool32 debugMode; VkBool32 debugMode;
/** /**
* If enabled, MSL vertex shader code created during runtime shader conversion will * If enabled, MSL vertex shader code created during runtime shader conversion will
* flip the Y-axis of each vertex, as the Vulkan Y-axis is the inverse of OpenGL. * flip the Y-axis of each vertex, as the Vulkan Y-axis is the inverse of OpenGL.
*
* An alternate way to reverse the Y-axis is to employ a negative Y-axis value on * An alternate way to reverse the Y-axis is to employ a negative Y-axis value on
* the viewport, in which case this parameter can be disabled. * the viewport, in which case this parameter can be disabled.
* *
* Initial value is set by the MVK_CONFIG_SHADER_CONVERSION_FLIP_VERTEX_Y build setting * The value of this parameter may be changed at any time during application runtime,
* when MoltenVK is compiled. By default the MVK_CONFIG_SHADER_CONVERSION_FLIP_VERTEX_Y * and the changed value will immediately effect subsequent MoltenVK behaviour.
* build setting is set to true. * Specifically, this parameter can be enabled when compiling some pipelines,
* and disabled when compiling others. Existing pipelines are not automatically
* re-compiled when this parameter is changed.
*
* The initial value or this parameter is set by the
* MVK_CONFIG_SHADER_CONVERSION_FLIP_VERTEX_Y
* runtime environment variable or MoltenVK compile-time build setting.
* If neither is set, the value of this parameter defaults to true.
*/ */
VkBool32 shaderConversionFlipVertexY; VkBool32 shaderConversionFlipVertexY;
@ -109,10 +133,13 @@ typedef struct {
* will be dispatched to a GCD dispatch_queue whose priority is determined by * will be dispatched to a GCD dispatch_queue whose priority is determined by
* VkDeviceQueueCreateInfo::pQueuePriorities during vkCreateDevice(). * VkDeviceQueueCreateInfo::pQueuePriorities during vkCreateDevice().
* *
* Initial value is set by the MVK_CONFIG_SYNCHRONOUS_QUEUE_SUBMITS build setting when MoltenVK * The value of this parameter may be changed before creating a VkDevice,
* is compiled. By default the MVK_CONFIG_SYNCHRONOUS_QUEUE_SUBMITS build setting is set to false, * for the change to take effect.
* and command processing will be handled on a prioritizable queue thread. Changing the value of *
* this parameter must be done before creating a VkDevice, for the change to take effect. * The initial value or this parameter is set by the
* MVK_CONFIG_SYNCHRONOUS_QUEUE_SUBMITS
* runtime environment variable or MoltenVK compile-time build setting.
* If neither is set, the value of this parameter defaults to true.
*/ */
VkBool32 synchronousQueueSubmits; VkBool32 synchronousQueueSubmits;
@ -146,8 +173,15 @@ typedef struct {
* command buffers do not support the concept of being reset after being filled. Depending on when * command buffers do not support the concept of being reset after being filled. Depending on when
* and how often you do this, it may cause unexpected visual artifacts and unnecessary GPU load. * and how often you do this, it may cause unexpected visual artifacts and unnecessary GPU load.
* *
* Initial value is set by the MVK_CONFIG_PREFILL_METAL_COMMAND_BUFFERS build setting when MoltenVK * The value of this parameter may be changed at any time during application runtime,
* is compiled. By default the MVK_CONFIG_PREFILL_METAL_COMMAND_BUFFERS build setting is set to false. * and the changed value will immediately effect subsequent MoltenVK behaviour.
* Specifically, this parameter can be enabled when filling some command buffers,
* and disabled when filling others.
*
* The initial value or this parameter is set by the
* MVK_CONFIG_PREFILL_METAL_COMMAND_BUFFERS
* runtime environment variable or MoltenVK compile-time build setting.
* If neither is set, the value of this parameter defaults to false.
*/ */
VkBool32 prefillMetalCommandBuffers; VkBool32 prefillMetalCommandBuffers;
@ -159,10 +193,13 @@ typedef struct {
* is required per command buffer queue submission, which may be significantly less than the * is required per command buffer queue submission, which may be significantly less than the
* number of Vulkan command buffers. * number of Vulkan command buffers.
* *
* Initial value is set by the MVK_CONFIG_MAX_ACTIVE_METAL_COMMAND_BUFFERS_PER_POOL build setting * The value of this parameter may be changed before creating a VkDevice,
* when MoltenVK is compiled. By default the MVK_CONFIG_MAX_ACTIVE_METAL_COMMAND_BUFFERS_PER_POOL * for the change to take effect.
* build setting is set to 64. Changing the value of this parameter must be done before creating *
* a VkDevice, for the change to take effect. * The initial value or this parameter is set by the
* MVK_CONFIG_MAX_ACTIVE_METAL_COMMAND_BUFFERS_PER_QUEUE
* runtime environment variable or MoltenVK compile-time build setting.
* If neither is set, the value of this parameter defaults to 64.
*/ */
uint32_t maxActiveMetalCommandBuffersPerQueue; uint32_t maxActiveMetalCommandBuffersPerQueue;
@ -174,9 +211,15 @@ typedef struct {
* within a renderpass. If disabled, one MTLBuffer will be shared by all query pools, * within a renderpass. If disabled, one MTLBuffer will be shared by all query pools,
* which improves performance, but limits the total device queries to 8192. * which improves performance, but limits the total device queries to 8192.
* *
* Initial value is set by the MVK_CONFIG_SUPPORT_LARGE_QUERY_POOLS build setting * The value of this parameter may be changed at any time during application runtime,
* when MoltenVK is compiled. By default the MVK_CONFIG_SUPPORT_LARGE_QUERY_POOLS * and the changed value will immediately effect subsequent MoltenVK behaviour.
* build setting is set to true. * Specifically, this parameter can be enabled when creating some query pools,
* and disabled when creating others.
*
* The initial value or this parameter is set by the
* MVK_CONFIG_SUPPORT_LARGE_QUERY_POOLS
* runtime environment variable or MoltenVK compile-time build setting.
* If neither is set, the value of this parameter defaults to true.
*/ */
VkBool32 supportLargeQueryPools; VkBool32 supportLargeQueryPools;
@ -184,8 +227,13 @@ typedef struct {
* If enabled, each surface presentation is scheduled using a command buffer. Enabling this * If enabled, each surface presentation is scheduled using a command buffer. Enabling this
* setting may improve rendering frame synchronization, but may result in reduced frame rates. * setting may improve rendering frame synchronization, but may result in reduced frame rates.
* *
* Initial value is set by the MVK_CONFIG_PRESENT_WITH_COMMAND_BUFFER build setting when MoltenVK * The value of this parameter may be changed at any time during application runtime,
* is compiled. By default the MVK_CONFIG_PRESENT_WITH_COMMAND_BUFFER build setting is set to true. * and the changed value will immediately effect subsequent MoltenVK behaviour.
*
* The initial value or this parameter is set by the
* MVK_CONFIG_PRESENT_WITH_COMMAND_BUFFER
* runtime environment variable or MoltenVK compile-time build setting.
* If neither is set, the value of this parameter defaults to true.
*/ */
VkBool32 presentWithCommandBuffer; VkBool32 presentWithCommandBuffer;
@ -197,9 +245,13 @@ typedef struct {
* multiples of display pixels (eg- macOS Retina, and typical of graphics apps and games), * multiples of display pixels (eg- macOS Retina, and typical of graphics apps and games),
* but may cause aliasing effects when using non-integer display scaling. * but may cause aliasing effects when using non-integer display scaling.
* *
* Initial value is set by the MVK_CONFIG_SWAPCHAIN_MAG_FILTER_USE_NEAREST build setting * The value of this parameter may be changed before creating a VkSwapchain,
* when MoltenVK is compiled. By default the MVK_CONFIG_SWAPCHAIN_MAG_FILTER_USE_NEAREST * for the change to take effect.
* build setting is set to true. *
* The initial value or this parameter is set by the
* MVK_CONFIG_SWAPCHAIN_MAG_FILTER_USE_NEAREST
* runtime environment variable or MoltenVK compile-time build setting.
* If neither is set, the value of this parameter defaults to true.
*/ */
VkBool32 swapchainMagFilterUseNearest; VkBool32 swapchainMagFilterUseNearest;
@ -209,8 +261,13 @@ typedef struct {
* within the Metal compiler can stall the thread for up to 30 seconds. Setting this value * within the Metal compiler can stall the thread for up to 30 seconds. Setting this value
* limits that delay to a specified amount of time, allowing shader compilations to fail fast. * limits that delay to a specified amount of time, allowing shader compilations to fail fast.
* *
* Initial value is set by the MVK_CONFIG_METAL_COMPILE_TIMEOUT build setting when MoltenVK * The value of this parameter may be changed at any time during application runtime,
* is compiled. By default the MVK_CONFIG_METAL_COMPILE_TIMEOUT build setting is infinite. * and the changed value will immediately effect subsequent MoltenVK behaviour.
*
* The initial value or this parameter is set by the
* MVK_CONFIG_METAL_COMPILE_TIMEOUT
* runtime environment variable or MoltenVK compile-time build setting.
* If neither is set, the value of this parameter defaults to infinite.
*/ */
uint64_t metalCompileTimeout; uint64_t metalCompileTimeout;
@ -219,7 +276,13 @@ typedef struct {
* retrieved via the vkGetSwapchainPerformanceMVK() function, and various performance statistics * retrieved via the vkGetSwapchainPerformanceMVK() function, and various performance statistics
* are tracked, logged, and can be retrieved via the vkGetPerformanceStatisticsMVK() function. * are tracked, logged, and can be retrieved via the vkGetPerformanceStatisticsMVK() function.
* *
* Initial value is true in the presence of the DEBUG build setting, and false otherwise. * The value of this parameter may be changed at any time during application runtime,
* and the changed value will immediately effect subsequent MoltenVK behaviour.
*
* The initial value or this parameter is set by the
* MVK_CONFIG_PERFORMANCE_TRACKING
* runtime environment variable or MoltenVK compile-time build setting.
* If neither is set, the value of this parameter defaults to false.
*/ */
VkBool32 performanceTracking; VkBool32 performanceTracking;
@ -227,7 +290,13 @@ typedef struct {
* If non-zero, performance statistics will be periodically logged to the console, on a repeating * If non-zero, performance statistics will be periodically logged to the console, on a repeating
* cycle of this many frames per swapchain. The performanceTracking capability must also be enabled. * cycle of this many frames per swapchain. The performanceTracking capability must also be enabled.
* *
* Initial value is 300 in the presence of the DEBUG build setting, and zero otherwise. * The value of this parameter may be changed at any time during application runtime,
* and the changed value will immediately effect subsequent MoltenVK behaviour.
*
* The initial value or this parameter is set by the
* MVK_CONFIG_PERFORMANCE_LOGGING_FRAME_COUNT
* runtime environment variable or MoltenVK compile-time build setting.
* If neither is set, the value of this parameter defaults to zero.
*/ */
uint32_t performanceLoggingFrameCount; uint32_t performanceLoggingFrameCount;
@ -235,11 +304,116 @@ typedef struct {
* If enabled, a MoltenVK logo watermark will be rendered on top of the scene. * If enabled, a MoltenVK logo watermark will be rendered on top of the scene.
* This can be enabled for publicity during demos. * This can be enabled for publicity during demos.
* *
* Initial value is set by the MVK_CONFIG_DISPLAY_WATERMARK build setting when MoltenVK * The value of this parameter may be changed at any time during application runtime,
* is compiled. By default the MVK_CONFIG_DISPLAY_WATERMARK build setting is set to false. * and the changed value will immediately effect subsequent MoltenVK behaviour.
*
* The initial value or this parameter is set by the
* MVK_CONFIG_DISPLAY_WATERMARK
* runtime environment variable or MoltenVK compile-time build setting.
* If neither is set, the value of this parameter defaults to false.
*/ */
VkBool32 displayWatermark; VkBool32 displayWatermark;
/**
* Metal does not distinguish functionality between queues, which would normally mean only
* a single general-purpose queue family with multiple queues is needed. However, Vulkan
* associates command buffers with a queue family, whereas Metal associates command buffers
* with a specific Metal queue. In order to allow a Metal command buffer to be prefilled
* before is is formally submitted to a Vulkan queue, each Vulkan queue family can support
* only a single Metal queue. As a result, in order to provide parallel queue operations,
* MoltenVK provides multiple queue families, each with a single queue.
*
* If this parameter is disabled, all queue families will be advertised as having general-purpose
* graphics + compute + transfer functionality, which is how the actual Metal queues behave.
*
* If this parameter is enabled, one queue family will be advertised as having general-purpose
* graphics + compute + transfer functionality, and the remaining queue families will be advertised
* as having specialized graphics OR compute OR transfer functionality, to make it easier for some
* apps to select a queue family with the appropriate requirements.
*
* The value of this parameter may be changed before creating a VkDevice, and before
* querying a VkPhysicalDevice for queue family properties, for the change to take effect.
*
* The initial value or this parameter is set by the
* MVK_CONFIG_SPECIALIZED_QUEUE_FAMILIES
* runtime environment variable or MoltenVK compile-time build setting.
* If neither is set, the value of this parameter defaults to false.
*/
VkBool32 specializedQueueFamilies;
/**
* If enabled, when the app creates a VkDevice from a VkPhysicalDevice (GPU) that is neither
* headless nor low-power, and is different than the GPU used by the windowing system, the
* windowing system will be forced to switch to use the GPU selected by the Vulkan app.
* When the Vulkan app is ended, the windowing system will automatically switch back to
* using the previous GPU, depending on the usage requirements of other running apps.
*
* If disabled, the Vulkan app will render using its selected GPU, and if the windowing
* system uses a different GPU, the windowing system compositor will automatically copy
* framebuffer content from the app GPU to the windowing system GPU.
*
* The value of this parmeter has no effect on systems with a single GPU, or when the
* Vulkan app creates a VkDevice from a low-power or headless VkPhysicalDevice (GPU).
*
* Switching the windowing system GPU to match the Vulkan app GPU maximizes app performance,
* because it avoids the windowing system compositor from having to copy framebuffer content
* between GPUs on each rendered frame. However, doing so forces the entire system to
* potentially switch to using a GPU that may consume more power while the app is running.
*
* Some Vulkan apps may want to render using a high-power GPU, but leave it up to the
* system window compositor to determine how best to blend content with the windowing
* system, and as a result, may want to disable this parameter.
*
* The value of this parameter may be changed before creating a VkDevice,
* for the change to take effect.
*
* The initial value or this parameter is set by the
* MVK_CONFIG_SWITCH_SYSTEM_GPU
* runtime environment variable or MoltenVK compile-time build setting.
* If neither is set, the value of this parameter defaults to true.
*/
VkBool32 switchSystemGPU;
/**
* If enabled, arbitrary ImageView component swizzles are supported, as defined
* in VkImageViewCreateInfo::components when creating a VkImageView.
*
* If disabled, a very limited set of ImageView component swizzles are supported
* via format substitutions.
*
* Metal does not natively support per-texture swizzling. If this parameter is enabled
* when a pipeline is compiled, ImageView swizzling is automatically performed in the
* converted Metal shader code during all texture sampling and reading operations,
* regardless of whether a swizzle has been specified for the ImageView associated
* with the Metal texture. This may result in reduced performance.
*
* The value of this parameter may be changed at any time during application runtime,
* and the changed value will immediately effect subsequent MoltenVK behaviour.
* Specifically, this parameter can be enabled when compiling some pipelines,
* and disabled when compiling others. Existing pipelines are not automatically
* re-compiled when this parameter is changed.
*
* If this parameter is disabled, the following limited set of ImageView swizzles
* are supported by MoltenVK, via automatic format substitution:
*
* Texture format Swizzle
* -------------- -------
* VK_FORMAT_R8_UNORM ZERO, ANY, ANY, RED
* VK_FORMAT_A8_UNORM ALPHA, ANY, ANY, ZERO
* VK_FORMAT_R8G8B8A8_UNORM BLUE, GREEN, RED, ALPHA
* VK_FORMAT_R8G8B8A8_SRGB BLUE, GREEN, RED, ALPHA
* VK_FORMAT_B8G8R8A8_UNORM BLUE, GREEN, RED, ALPHA
* VK_FORMAT_B8G8R8A8_SRGB BLUE, GREEN, RED, ALPHA
* VK_FORMAT_D32_SFLOAT_S8_UINT RED, ANY, ANY, ANY (stencil only)
* VK_FORMAT_D24_UNORM_S8_UINT RED, ANY, ANY, ANY (stencil only)
*
* The initial value or this parameter is set by the
* MVK_CONFIG_FULL_IMAGE_VIEW_SWIZZLE
* runtime environment variable or MoltenVK compile-time build setting.
* If neither is set, the value of this parameter defaults to false.
*/
VkBool32 fullImageViewSwizzle;
} MVKConfiguration; } MVKConfiguration;
/** /**
@ -253,7 +427,7 @@ typedef struct {
* for information about how to handle this. * for information about how to handle this.
* *
* TO SUPPORT DYNAMIC LINKING TO THIS STRUCTURE AS DESCRIBED ABOVE, THIS STRUCTURE SHOULD NOT * TO SUPPORT DYNAMIC LINKING TO THIS STRUCTURE AS DESCRIBED ABOVE, THIS STRUCTURE SHOULD NOT
* BE CHANGE EXCEPT TO ADD ADDITIONAL MEMBERS ON THE END. EXISTING MEMBERS, AND THEIR ORDER, * BE CHANGED EXCEPT TO ADD ADDITIONAL MEMBERS ON THE END. EXISTING MEMBERS, AND THEIR ORDER,
* SHOULD NOT BE CHANGED. * SHOULD NOT BE CHANGED.
*/ */
typedef struct { typedef struct {
@ -293,7 +467,7 @@ typedef struct {
* information about how to handle this. * information about how to handle this.
* *
* TO SUPPORT DYNAMIC LINKING TO THIS STRUCTURE AS DESCRIBED ABOVE, THIS STRUCTURE SHOULD NOT * TO SUPPORT DYNAMIC LINKING TO THIS STRUCTURE AS DESCRIBED ABOVE, THIS STRUCTURE SHOULD NOT
* BE CHANGE EXCEPT TO ADD ADDITIONAL MEMBERS ON THE END. EXISTING MEMBERS, AND THEIR ORDER, * BE CHANGED EXCEPT TO ADD ADDITIONAL MEMBERS ON THE END. EXISTING MEMBERS, AND THEIR ORDER,
* SHOULD NOT BE CHANGED. * SHOULD NOT BE CHANGED.
*/ */
typedef struct { typedef struct {
@ -345,7 +519,7 @@ typedef struct {
* information about how to handle this. * information about how to handle this.
* *
* TO SUPPORT DYNAMIC LINKING TO THIS STRUCTURE AS DESCRIBED ABOVE, THIS STRUCTURE SHOULD NOT * TO SUPPORT DYNAMIC LINKING TO THIS STRUCTURE AS DESCRIBED ABOVE, THIS STRUCTURE SHOULD NOT
* BE CHANGE EXCEPT TO ADD ADDITIONAL MEMBERS ON THE END. EXISTING MEMBERS, AND THEIR ORDER, * BE CHANGED EXCEPT TO ADD ADDITIONAL MEMBERS ON THE END. EXISTING MEMBERS, AND THEIR ORDER,
* SHOULD NOT BE CHANGED. * SHOULD NOT BE CHANGED.
*/ */
typedef struct { typedef struct {

View File

@ -704,6 +704,13 @@ void MVKCmdBufferImageCopy::encode(MVKCommandEncoder* cmdEncoder) {
blitOptions |= MTLBlitOptionStencilFromDepthStencil; blitOptions |= MTLBlitOptionStencilFromDepthStencil;
} }
} }
#if MVK_IOS
if (mvkMTLPixelFormatIsPVRTCFormat(mtlPixFmt)) {
blitOptions |= MTLBlitOptionRowLinearPVRTC;
}
#endif
#if MVK_MACOS #if MVK_MACOS
if (_toImage && mvkFormatTypeFromMTLPixelFormat(mtlPixFmt) == kMVKFormatCompressed && if (_toImage && mvkFormatTypeFromMTLPixelFormat(mtlPixFmt) == kMVKFormatCompressed &&
mtlTexture.textureType == MTLTextureType3D) { mtlTexture.textureType == MTLTextureType3D) {

View File

@ -351,7 +351,7 @@ void MVKCommandEncoder::clearRenderArea() {
} }
void MVKCommandEncoder::finalizeDispatchState() { void MVKCommandEncoder::finalizeDispatchState() {
_computePipelineState.encode(); _computePipelineState.encode(); // Must do first..it sets others
_computeResourcesState.encode(); _computeResourcesState.encode();
_computePushConstants.encode(); _computePushConstants.encode();
} }

View File

@ -374,6 +374,13 @@ protected:
bindings.push_back(db); bindings.push_back(db);
} }
// For texture bindings, we also keep track of whether any bindings need a texture swizzle
void bind(const MVKMTLTextureBinding& tb, MVKVector<MVKMTLTextureBinding>& texBindings,
bool& bindingsDirtyFlag, bool& needsSwizzleFlag) {
bind(tb, texBindings, bindingsDirtyFlag);
if (tb.swizzle != 0) { needsSwizzleFlag = true; }
}
// Template function that executes a lambda expression on each dirty element of // Template function that executes a lambda expression on each dirty element of
// a vector of bindings, and marks the bindings and the vector as no longer dirty. // a vector of bindings, and marks the bindings and the vector as no longer dirty.
template<class T> template<class T>
@ -391,11 +398,6 @@ protected:
} }
} }
// Updates the swizzle for an image in the given vector.
void updateSwizzle(MVKVector<uint32_t> &constants, uint32_t index, uint32_t swizzle) {
if (index >= constants.size()) { constants.resize(index + 1); }
constants[index] = swizzle;
}
}; };
@ -434,7 +436,9 @@ public:
} }
/** Sets the current auxiliary buffer state. */ /** Sets the current auxiliary buffer state. */
void bindAuxBuffer(const MVKShaderAuxBufferBinding& binding, bool needVertexAuxBuffer, bool needFragmentAuxBuffer); void bindAuxBuffer(const MVKShaderAuxBufferBinding& binding,
bool needVertexAuxBuffer,
bool needFragmentAuxBuffer);
#pragma mark Construction #pragma mark Construction
@ -464,6 +468,9 @@ protected:
bool _areFragmentTextureBindingsDirty = false; bool _areFragmentTextureBindingsDirty = false;
bool _areVertexSamplerStateBindingsDirty = false; bool _areVertexSamplerStateBindingsDirty = false;
bool _areFragmentSamplerStateBindingsDirty = false; bool _areFragmentSamplerStateBindingsDirty = false;
bool _needsVertexSwizzle = false;
bool _needsFragmentSwizzle = false;
}; };
@ -485,7 +492,7 @@ public:
void bindSamplerState(const MVKMTLSamplerStateBinding& binding); void bindSamplerState(const MVKMTLSamplerStateBinding& binding);
/** Sets the current auxiliary buffer state. */ /** Sets the current auxiliary buffer state. */
void bindAuxBuffer(const MVKShaderAuxBufferBinding& binding); void bindAuxBuffer(const MVKShaderAuxBufferBinding& binding, bool needAuxBuffer);
#pragma mark Construction #pragma mark Construction
@ -506,6 +513,8 @@ protected:
bool _areBufferBindingsDirty = false; bool _areBufferBindingsDirty = false;
bool _areTextureBindingsDirty = false; bool _areTextureBindingsDirty = false;
bool _areSamplerStateBindingsDirty = false; bool _areSamplerStateBindingsDirty = false;
bool _needsSwizzle = false;
}; };

View File

@ -398,6 +398,31 @@ void MVKBlendColorCommandEncoderState::resetImpl() {
} }
#pragma mark -
#pragma mark MVKResourcesCommandEncoderState
// Updates the swizzle for an image in the given vector.
static void updateSwizzle(MVKVector<uint32_t> &constants, uint32_t index, uint32_t swizzle) {
if (index >= constants.size()) { constants.resize(index + 1); }
constants[index] = swizzle;
}
// If a swizzle is needed for this stage, iterates all the bindings and logs errors for those that need texture swizzling.
static void assertMissingSwizzles(bool needsSwizzle, const char* stageName, MVKVector<MVKMTLTextureBinding>& texBindings) {
if (needsSwizzle) {
for (MVKMTLTextureBinding& tb : texBindings) {
VkComponentMapping vkcm = mvkUnpackSwizzle(tb.swizzle);
MVKLogError("Pipeline does not support component swizzle (%s, %s, %s, %s) required by a VkImageView used in the %s shader."
" Full VkImageView component swizzling will be supported by a pipeline if the MVKConfiguration::fullImageViewSwizzle"
" config parameter or MVK_CONFIG_FULL_IMAGE_VIEW_SWIZZLE environment variable was enabled when the pipeline is compiled.",
mvkVkComponentSwizzleName(vkcm.r), mvkVkComponentSwizzleName(vkcm.g),
mvkVkComponentSwizzleName(vkcm.b), mvkVkComponentSwizzleName(vkcm.a), stageName);
MVKAssert(false, "See previous logged error.");
}
}
}
#pragma mark - #pragma mark -
#pragma mark MVKGraphicsResourcesCommandEncoderState #pragma mark MVKGraphicsResourcesCommandEncoderState
@ -410,11 +435,11 @@ void MVKGraphicsResourcesCommandEncoderState::bindFragmentBuffer(const MVKMTLBuf
} }
void MVKGraphicsResourcesCommandEncoderState::bindVertexTexture(const MVKMTLTextureBinding& binding) { void MVKGraphicsResourcesCommandEncoderState::bindVertexTexture(const MVKMTLTextureBinding& binding) {
bind(binding, _vertexTextureBindings, _areVertexTextureBindingsDirty); bind(binding, _vertexTextureBindings, _areVertexTextureBindingsDirty, _needsVertexSwizzle);
} }
void MVKGraphicsResourcesCommandEncoderState::bindFragmentTexture(const MVKMTLTextureBinding& binding) { void MVKGraphicsResourcesCommandEncoderState::bindFragmentTexture(const MVKMTLTextureBinding& binding) {
bind(binding, _fragmentTextureBindings, _areFragmentTextureBindingsDirty); bind(binding, _fragmentTextureBindings, _areFragmentTextureBindingsDirty, _needsFragmentSwizzle);
} }
void MVKGraphicsResourcesCommandEncoderState::bindVertexSamplerState(const MVKMTLSamplerStateBinding& binding) { void MVKGraphicsResourcesCommandEncoderState::bindVertexSamplerState(const MVKMTLSamplerStateBinding& binding) {
@ -425,7 +450,9 @@ void MVKGraphicsResourcesCommandEncoderState::bindFragmentSamplerState(const MVK
bind(binding, _fragmentSamplerStateBindings, _areFragmentSamplerStateBindingsDirty); bind(binding, _fragmentSamplerStateBindings, _areFragmentSamplerStateBindingsDirty);
} }
void MVKGraphicsResourcesCommandEncoderState::bindAuxBuffer(const MVKShaderAuxBufferBinding& binding, bool needVertexAuxBuffer, bool needFragmentAuxBuffer) { void MVKGraphicsResourcesCommandEncoderState::bindAuxBuffer(const MVKShaderAuxBufferBinding& binding,
bool needVertexAuxBuffer,
bool needFragmentAuxBuffer) {
_vertexAuxBufferBinding.index = binding.vertex; _vertexAuxBufferBinding.index = binding.vertex;
_vertexAuxBufferBinding.isDirty = needVertexAuxBuffer; _vertexAuxBufferBinding.isDirty = needVertexAuxBuffer;
_fragmentAuxBufferBinding.index = binding.fragment; _fragmentAuxBufferBinding.index = binding.fragment;
@ -445,20 +472,6 @@ void MVKGraphicsResourcesCommandEncoderState::markDirty() {
void MVKGraphicsResourcesCommandEncoderState::encodeImpl() { void MVKGraphicsResourcesCommandEncoderState::encodeImpl() {
if (_vertexAuxBufferBinding.isDirty) {
for (auto& b : _vertexTextureBindings) {
if (b.isDirty)
updateSwizzle(_vertexSwizzleConstants, b.index, b.swizzle);
}
}
if (_fragmentAuxBufferBinding.isDirty) {
for (auto& b : _fragmentTextureBindings) {
if (b.isDirty)
updateSwizzle(_fragmentSwizzleConstants, b.index, b.swizzle);
}
}
encodeBinding<MVKMTLBufferBinding>(_vertexBufferBindings, _areVertexBufferBindingsDirty, encodeBinding<MVKMTLBufferBinding>(_vertexBufferBindings, _areVertexBufferBindingsDirty,
[](MVKCommandEncoder* cmdEncoder, MVKMTLBufferBinding& b)->void { [](MVKCommandEncoder* cmdEncoder, MVKMTLBufferBinding& b)->void {
[cmdEncoder->_mtlRenderEncoder setVertexBuffer: b.mtlBuffer [cmdEncoder->_mtlRenderEncoder setVertexBuffer: b.mtlBuffer
@ -474,17 +487,33 @@ void MVKGraphicsResourcesCommandEncoderState::encodeImpl() {
}); });
if (_vertexAuxBufferBinding.isDirty) { if (_vertexAuxBufferBinding.isDirty) {
_cmdEncoder->setVertexBytes(_cmdEncoder->_mtlRenderEncoder,
for (auto& b : _vertexTextureBindings) {
if (b.isDirty) { updateSwizzle(_vertexSwizzleConstants, b.index, b.swizzle); }
}
_cmdEncoder->setVertexBytes(_cmdEncoder->_mtlRenderEncoder,
_vertexSwizzleConstants.data(), _vertexSwizzleConstants.data(),
_vertexSwizzleConstants.size() * sizeof(uint32_t), _vertexSwizzleConstants.size() * sizeof(uint32_t),
_vertexAuxBufferBinding.index); _vertexAuxBufferBinding.index);
}
} else {
assertMissingSwizzles(_needsVertexSwizzle, "vertex", _vertexTextureBindings);
}
if (_fragmentAuxBufferBinding.isDirty) { if (_fragmentAuxBufferBinding.isDirty) {
_cmdEncoder->setFragmentBytes(_cmdEncoder->_mtlRenderEncoder,
for (auto& b : _fragmentTextureBindings) {
if (b.isDirty) { updateSwizzle(_fragmentSwizzleConstants, b.index, b.swizzle); }
}
_cmdEncoder->setFragmentBytes(_cmdEncoder->_mtlRenderEncoder,
_fragmentSwizzleConstants.data(), _fragmentSwizzleConstants.data(),
_fragmentSwizzleConstants.size() * sizeof(uint32_t), _fragmentSwizzleConstants.size() * sizeof(uint32_t),
_fragmentAuxBufferBinding.index); _fragmentAuxBufferBinding.index);
} else {
assertMissingSwizzles(_needsFragmentSwizzle, "fragment", _fragmentTextureBindings);
} }
encodeBinding<MVKMTLTextureBinding>(_vertexTextureBindings, _areVertexTextureBindingsDirty, encodeBinding<MVKMTLTextureBinding>(_vertexTextureBindings, _areVertexTextureBindingsDirty,
@ -530,6 +559,9 @@ void MVKGraphicsResourcesCommandEncoderState::resetImpl() {
_areFragmentSamplerStateBindingsDirty = false; _areFragmentSamplerStateBindingsDirty = false;
_vertexAuxBufferBinding.isDirty = false; _vertexAuxBufferBinding.isDirty = false;
_fragmentAuxBufferBinding.isDirty = false; _fragmentAuxBufferBinding.isDirty = false;
_needsVertexSwizzle = false;
_needsFragmentSwizzle = false;
} }
@ -541,16 +573,17 @@ void MVKComputeResourcesCommandEncoderState::bindBuffer(const MVKMTLBufferBindin
} }
void MVKComputeResourcesCommandEncoderState::bindTexture(const MVKMTLTextureBinding& binding) { void MVKComputeResourcesCommandEncoderState::bindTexture(const MVKMTLTextureBinding& binding) {
bind(binding, _textureBindings, _areTextureBindingsDirty); bind(binding, _textureBindings, _areTextureBindingsDirty, _needsSwizzle);
} }
void MVKComputeResourcesCommandEncoderState::bindSamplerState(const MVKMTLSamplerStateBinding& binding) { void MVKComputeResourcesCommandEncoderState::bindSamplerState(const MVKMTLSamplerStateBinding& binding) {
bind(binding, _samplerStateBindings, _areSamplerStateBindingsDirty); bind(binding, _samplerStateBindings, _areSamplerStateBindingsDirty);
} }
void MVKComputeResourcesCommandEncoderState::bindAuxBuffer(const MVKShaderAuxBufferBinding& binding) { void MVKComputeResourcesCommandEncoderState::bindAuxBuffer(const MVKShaderAuxBufferBinding& binding,
bool needAuxBuffer) {
_auxBufferBinding.index = binding.compute; _auxBufferBinding.index = binding.compute;
_auxBufferBinding.isDirty = true; _auxBufferBinding.isDirty = needAuxBuffer;
} }
// Mark everything as dirty // Mark everything as dirty
@ -563,13 +596,6 @@ void MVKComputeResourcesCommandEncoderState::markDirty() {
void MVKComputeResourcesCommandEncoderState::encodeImpl() { void MVKComputeResourcesCommandEncoderState::encodeImpl() {
if (_auxBufferBinding.isDirty) {
for (auto& b : _textureBindings) {
if (b.isDirty)
updateSwizzle(_swizzleConstants, b.index, b.swizzle);
}
}
encodeBinding<MVKMTLBufferBinding>(_bufferBindings, _areBufferBindingsDirty, encodeBinding<MVKMTLBufferBinding>(_bufferBindings, _areBufferBindingsDirty,
[](MVKCommandEncoder* cmdEncoder, MVKMTLBufferBinding& b)->void { [](MVKCommandEncoder* cmdEncoder, MVKMTLBufferBinding& b)->void {
[cmdEncoder->getMTLComputeEncoder(kMVKCommandUseDispatch) setBuffer: b.mtlBuffer [cmdEncoder->getMTLComputeEncoder(kMVKCommandUseDispatch) setBuffer: b.mtlBuffer
@ -578,10 +604,18 @@ void MVKComputeResourcesCommandEncoderState::encodeImpl() {
}); });
if (_auxBufferBinding.isDirty) { if (_auxBufferBinding.isDirty) {
_cmdEncoder->setComputeBytes(_cmdEncoder->getMTLComputeEncoder(kMVKCommandUseDispatch),
for (auto& b : _textureBindings) {
if (b.isDirty) { updateSwizzle(_swizzleConstants, b.index, b.swizzle); }
}
_cmdEncoder->setComputeBytes(_cmdEncoder->getMTLComputeEncoder(kMVKCommandUseDispatch),
_swizzleConstants.data(), _swizzleConstants.data(),
_swizzleConstants.size() * sizeof(uint32_t), _swizzleConstants.size() * sizeof(uint32_t),
_auxBufferBinding.index); _auxBufferBinding.index);
} else {
assertMissingSwizzles(_needsSwizzle, "compute", _textureBindings);
} }
encodeBinding<MVKMTLTextureBinding>(_textureBindings, _areTextureBindingsDirty, encodeBinding<MVKMTLTextureBinding>(_textureBindings, _areTextureBindingsDirty,
@ -607,6 +641,8 @@ void MVKComputeResourcesCommandEncoderState::resetImpl() {
_areTextureBindingsDirty = false; _areTextureBindingsDirty = false;
_areSamplerStateBindingsDirty = false; _areSamplerStateBindingsDirty = false;
_auxBufferBinding.isDirty = false; _auxBufferBinding.isDirty = false;
_needsSwizzle = false;
} }

View File

@ -277,7 +277,7 @@ protected:
void initFeatures(); void initFeatures();
void initProperties(); void initProperties();
void initMemoryProperties(); void initMemoryProperties();
void initQueueFamilies(); std::vector<MVKQueueFamily*>& getQueueFamilies();
void initPipelineCacheUUID(); void initPipelineCacheUUID();
MTLFeatureSet getHighestMTLFeatureSet(); MTLFeatureSet getHighestMTLFeatureSet();
void logGPUInfo(); void logGPUInfo();
@ -581,6 +581,7 @@ protected:
MVKResource* addResource(MVKResource* rez); MVKResource* addResource(MVKResource* rez);
MVKResource* removeResource(MVKResource* rez); MVKResource* removeResource(MVKResource* rez);
void initPerformanceTracking(); void initPerformanceTracking();
void initPhysicalDevice(MVKPhysicalDevice* physicalDevice);
void initQueues(const VkDeviceCreateInfo* pCreateInfo); void initQueues(const VkDeviceCreateInfo* pCreateInfo);
const char* getActivityPerformanceDescription(MVKPerformanceTracker& shaderCompilationEvent); const char* getActivityPerformanceDescription(MVKPerformanceTracker& shaderCompilationEvent);
uint64_t getPerformanceTimestampImpl(); uint64_t getPerformanceTimestampImpl();

View File

@ -442,10 +442,47 @@ VkResult MVKPhysicalDevice::getSurfacePresentModes(MVKSurface* surface,
#pragma mark Queues #pragma mark Queues
// Returns the queue families supported by this instance, lazily creating them if necessary.
// Metal does not distinguish functionality between queues, which would normally lead us
// to create only only one general-purpose queue family. However, Vulkan associates command
// buffers with a queue family, whereas Metal associates command buffers with a Metal queue.
// In order to allow a Metal command buffer to be prefilled before is is formally submitted to
// a Vulkan queue, we need to enforce that each Vulkan queue family can have only one Metal queue.
// In order to provide parallel queue operations, we therefore provide multiple queue families.
vector<MVKQueueFamily*>& MVKPhysicalDevice::getQueueFamilies() {
if (_queueFamilies.empty()) {
VkQueueFamilyProperties qfProps;
bool specialize = _mvkInstance->getMoltenVKConfiguration()->specializedQueueFamilies;
uint32_t qfIdx = 0;
qfProps.queueCount = 1; // Each queue family must have a single Metal queue (see above)
qfProps.timestampValidBits = 64;
qfProps.minImageTransferGranularity = { 1, 1, 1};
// General-purpose queue family
qfProps.queueFlags = (VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT | VK_QUEUE_TRANSFER_BIT);
_queueFamilies.push_back(new MVKQueueFamily(this, qfIdx++, &qfProps));
// Dedicated graphics queue family...or another general-purpose queue family.
if (specialize) { qfProps.queueFlags = (VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_TRANSFER_BIT); }
_queueFamilies.push_back(new MVKQueueFamily(this, qfIdx++, &qfProps));
// Dedicated compute queue family...or another general-purpose queue family.
if (specialize) { qfProps.queueFlags = (VK_QUEUE_COMPUTE_BIT | VK_QUEUE_TRANSFER_BIT); }
_queueFamilies.push_back(new MVKQueueFamily(this, qfIdx++, &qfProps));
// Dedicated transfer queue family...or another general-purpose queue family.
if (specialize) { qfProps.queueFlags = VK_QUEUE_TRANSFER_BIT; }
_queueFamilies.push_back(new MVKQueueFamily(this, qfIdx++, &qfProps));
}
return _queueFamilies;
}
VkResult MVKPhysicalDevice::getQueueFamilyProperties(uint32_t* pCount, VkResult MVKPhysicalDevice::getQueueFamilyProperties(uint32_t* pCount,
VkQueueFamilyProperties* queueProperties) { VkQueueFamilyProperties* queueProperties) {
uint32_t qfCnt = uint32_t(_queueFamilies.size()); vector<MVKQueueFamily*> qFams = getQueueFamilies();
uint32_t qfCnt = uint32_t(qFams.size());
// If properties aren't actually being requested yet, simply update the returned count // If properties aren't actually being requested yet, simply update the returned count
if ( !queueProperties ) { if ( !queueProperties ) {
@ -459,7 +496,7 @@ VkResult MVKPhysicalDevice::getQueueFamilyProperties(uint32_t* pCount,
// Now populate the queue families // Now populate the queue families
if (queueProperties) { if (queueProperties) {
for (uint32_t qfIdx = 0; qfIdx < *pCount; qfIdx++) { for (uint32_t qfIdx = 0; qfIdx < *pCount; qfIdx++) {
_queueFamilies[qfIdx]->getProperties(&queueProperties[qfIdx]); qFams[qfIdx]->getProperties(&queueProperties[qfIdx]);
} }
} }
@ -469,7 +506,8 @@ VkResult MVKPhysicalDevice::getQueueFamilyProperties(uint32_t* pCount,
VkResult MVKPhysicalDevice::getQueueFamilyProperties(uint32_t* pCount, VkResult MVKPhysicalDevice::getQueueFamilyProperties(uint32_t* pCount,
VkQueueFamilyProperties2KHR* queueProperties) { VkQueueFamilyProperties2KHR* queueProperties) {
uint32_t qfCnt = uint32_t(_queueFamilies.size()); vector<MVKQueueFamily*> qFams = getQueueFamilies();
uint32_t qfCnt = uint32_t(qFams.size());
// If properties aren't actually being requested yet, simply update the returned count // If properties aren't actually being requested yet, simply update the returned count
if ( !queueProperties ) { if ( !queueProperties ) {
@ -484,7 +522,7 @@ VkResult MVKPhysicalDevice::getQueueFamilyProperties(uint32_t* pCount,
if (queueProperties) { if (queueProperties) {
for (uint32_t qfIdx = 0; qfIdx < *pCount; qfIdx++) { for (uint32_t qfIdx = 0; qfIdx < *pCount; qfIdx++) {
queueProperties[qfIdx].sType = VK_STRUCTURE_TYPE_QUEUE_FAMILY_PROPERTIES_2_KHR; queueProperties[qfIdx].sType = VK_STRUCTURE_TYPE_QUEUE_FAMILY_PROPERTIES_2_KHR;
_queueFamilies[qfIdx]->getProperties(&queueProperties[qfIdx].queueFamilyProperties); qFams[qfIdx]->getProperties(&queueProperties[qfIdx].queueFamilyProperties);
} }
} }
@ -511,6 +549,17 @@ VkResult MVKPhysicalDevice::getPhysicalDeviceMemoryProperties(VkPhysicalDeviceMe
#pragma mark Construction #pragma mark Construction
MVKPhysicalDevice::MVKPhysicalDevice(MVKInstance* mvkInstance, id<MTLDevice> mtlDevice) {
_mvkInstance = mvkInstance;
_mtlDevice = [mtlDevice retain];
initMetalFeatures(); // Call first.
initFeatures(); // Call second.
initProperties(); // Call third.
initMemoryProperties();
logGPUInfo();
}
/** Initializes the Metal-specific physical device features of this instance. */ /** Initializes the Metal-specific physical device features of this instance. */
void MVKPhysicalDevice::initMetalFeatures() { void MVKPhysicalDevice::initMetalFeatures() {
memset(&_metalFeatures, 0, sizeof(_metalFeatures)); // Start with everything cleared memset(&_metalFeatures, 0, sizeof(_metalFeatures)); // Start with everything cleared
@ -1272,33 +1321,6 @@ void MVKPhysicalDevice::logGPUInfo() {
SPIRVToMSLConverterOptions::printMSLVersion(_metalFeatures.mslVersion).c_str()); SPIRVToMSLConverterOptions::printMSLVersion(_metalFeatures.mslVersion).c_str());
} }
// Initializes the queue families supported by this instance.
void MVKPhysicalDevice::initQueueFamilies() {
VkQueueFamilyProperties qfProps;
uint32_t qfIdx;
qfProps.queueCount = 1; // In Metal, each family must have a single queue
qfIdx = 0;
qfProps.queueFlags = (VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT | VK_QUEUE_TRANSFER_BIT);
qfProps.timestampValidBits = 64;
qfProps.minImageTransferGranularity = { 1, 1, 1};
_queueFamilies.push_back(new MVKQueueFamily(this, qfIdx, &qfProps));
}
MVKPhysicalDevice::MVKPhysicalDevice(MVKInstance* mvkInstance, id<MTLDevice> mtlDevice) {
_mvkInstance = mvkInstance;
_mtlDevice = [mtlDevice retain];
initMetalFeatures(); // Call first.
initFeatures(); // Call second.
initProperties(); // Call third.
initMemoryProperties();
initQueueFamilies();
logGPUInfo();
}
MVKPhysicalDevice::~MVKPhysicalDevice() { MVKPhysicalDevice::~MVKPhysicalDevice() {
mvkDestroyContainerContents(_queueFamilies); mvkDestroyContainerContents(_queueFamilies);
[_mtlDevice release]; [_mtlDevice release];
@ -1771,27 +1793,7 @@ uint32_t MVKDevice::expandVisibilityResultMTLBuffer(uint32_t queryCount) {
MVKDevice::MVKDevice(MVKPhysicalDevice* physicalDevice, const VkDeviceCreateInfo* pCreateInfo) { MVKDevice::MVKDevice(MVKPhysicalDevice* physicalDevice, const VkDeviceCreateInfo* pCreateInfo) {
initPerformanceTracking(); initPerformanceTracking();
initPhysicalDevice(physicalDevice);
#if MVK_MACOS
//on mac OS, the wrong GPU will drive the screen (graphics switching will not occur)
//unless we call this specific MTLCreateSystemDefaultDevice method to create the metal device
id<MTLDevice> device = physicalDevice->getMTLDevice();
if (!device.headless && !device.lowPower) {
id<MTLDevice> sysDefaultDevice = MTLCreateSystemDefaultDevice();
//lets be 100% sure this is the device the user asked for
if (sysDefaultDevice.registryID == device.registryID) {
physicalDevice->replaceMTLDevice(sysDefaultDevice);
}
}
#endif
_physicalDevice = physicalDevice;
_pMVKConfig = _physicalDevice->_mvkInstance->getMoltenVKConfiguration();
_pFeatures = &_physicalDevice->_features;
_pMetalFeatures = _physicalDevice->getMetalFeatures();
_pProperties = &_physicalDevice->_properties;
_pMemoryProperties = &_physicalDevice->_memoryProperties;
_globalVisibilityResultMTLBuffer = nil; _globalVisibilityResultMTLBuffer = nil;
_globalVisibilityQueryCount = 0; _globalVisibilityQueryCount = 0;
@ -1831,13 +1833,38 @@ void MVKDevice::initPerformanceTracking() {
_performanceStatistics.queue.mtlQueueAccess = initPerf; _performanceStatistics.queue.mtlQueueAccess = initPerf;
} }
void MVKDevice::initPhysicalDevice(MVKPhysicalDevice* physicalDevice) {
_physicalDevice = physicalDevice;
_pMVKConfig = _physicalDevice->_mvkInstance->getMoltenVKConfiguration();
_pFeatures = &_physicalDevice->_features;
_pMetalFeatures = _physicalDevice->getMetalFeatures();
_pProperties = &_physicalDevice->_properties;
_pMemoryProperties = &_physicalDevice->_memoryProperties;
#if MVK_MACOS
// If we have selected a high-power GPU and want to force the window system
// to use it, force the window system to use a high-power GPU by calling the
// MTLCreateSystemDefaultDevice function, and if that GPU is the same as the
// selected GPU, update the MTLDevice instance used by the MVKPhysicalDevice.
id<MTLDevice> mtlDevice = _physicalDevice->getMTLDevice();
if (_pMVKConfig->switchSystemGPU && !(mtlDevice.lowPower || mtlDevice.headless) ) {
id<MTLDevice> sysMTLDevice = MTLCreateSystemDefaultDevice();
if (sysMTLDevice.registryID == mtlDevice.registryID) {
_physicalDevice->replaceMTLDevice(sysMTLDevice);
}
}
#endif
}
// Create the command queues // Create the command queues
void MVKDevice::initQueues(const VkDeviceCreateInfo* pCreateInfo) { void MVKDevice::initQueues(const VkDeviceCreateInfo* pCreateInfo) {
vector<MVKQueueFamily*> qFams = _physicalDevice->getQueueFamilies();
uint32_t qrCnt = pCreateInfo->queueCreateInfoCount; uint32_t qrCnt = pCreateInfo->queueCreateInfoCount;
for (uint32_t qrIdx = 0; qrIdx < qrCnt; qrIdx++) { for (uint32_t qrIdx = 0; qrIdx < qrCnt; qrIdx++) {
const VkDeviceQueueCreateInfo* pQFInfo = &pCreateInfo->pQueueCreateInfos[qrIdx]; const VkDeviceQueueCreateInfo* pQFInfo = &pCreateInfo->pQueueCreateInfos[qrIdx];
uint32_t qfIdx = pQFInfo->queueFamilyIndex; uint32_t qfIdx = pQFInfo->queueFamilyIndex;
MVKQueueFamily* qFam = _physicalDevice->_queueFamilies[qfIdx]; MVKQueueFamily* qFam = qFams[qfIdx];
_queuesByQueueFamilyIndex.resize(qfIdx + 1); // Ensure an entry for this queue family exists _queuesByQueueFamilyIndex.resize(qfIdx + 1); // Ensure an entry for this queue family exists
auto& queues = _queuesByQueueFamilyIndex[qfIdx]; auto& queues = _queuesByQueueFamilyIndex[qfIdx];
for (uint32_t qIdx = 0; qIdx < pQFInfo->queueCount; qIdx++) { for (uint32_t qIdx = 0; qIdx < pQFInfo->queueCount; qIdx++) {

View File

@ -289,8 +289,6 @@ protected:
void initMTLTextureViewSupport(); void initMTLTextureViewSupport();
MTLPixelFormat getSwizzledMTLPixelFormat(VkFormat format, VkComponentMapping components, bool& useSwizzle); MTLPixelFormat getSwizzledMTLPixelFormat(VkFormat format, VkComponentMapping components, bool& useSwizzle);
bool matchesSwizzle(VkComponentMapping components, VkComponentMapping pattern); bool matchesSwizzle(VkComponentMapping components, VkComponentMapping pattern);
const char* getSwizzleName(VkComponentSwizzle swizzle);
uint32_t packSwizzle(VkComponentMapping components);
void validateImageViewConfig(const VkImageViewCreateInfo* pCreateInfo); void validateImageViewConfig(const VkImageViewCreateInfo* pCreateInfo);
MVKImage* _image; MVKImage* _image;

View File

@ -798,7 +798,7 @@ MVKImageView::MVKImageView(MVKDevice* device, const VkImageViewCreateInfo* pCrea
_mtlPixelFormat = getSwizzledMTLPixelFormat(pCreateInfo->format, pCreateInfo->components, useSwizzle); _mtlPixelFormat = getSwizzledMTLPixelFormat(pCreateInfo->format, pCreateInfo->components, useSwizzle);
_mtlTextureType = mvkMTLTextureTypeFromVkImageViewType(pCreateInfo->viewType, (_image->getSampleCount() != VK_SAMPLE_COUNT_1_BIT)); _mtlTextureType = mvkMTLTextureTypeFromVkImageViewType(pCreateInfo->viewType, (_image->getSampleCount() != VK_SAMPLE_COUNT_1_BIT));
initMTLTextureViewSupport(); initMTLTextureViewSupport();
_packedSwizzle = useSwizzle ? packSwizzle(pCreateInfo->components) : 0; _packedSwizzle = useSwizzle ? mvkPackSwizzle(pCreateInfo->components) : 0;
} }
// Validate whether the image view configuration can be supported // Validate whether the image view configuration can be supported
@ -896,19 +896,6 @@ MTLPixelFormat MVKImageView::getSwizzledMTLPixelFormat(VkFormat format, VkCompon
return mtlPF; return mtlPF;
} }
const char* MVKImageView::getSwizzleName(VkComponentSwizzle swizzle) {
switch (swizzle) {
case VK_COMPONENT_SWIZZLE_IDENTITY: return "VK_COMPONENT_SWIZZLE_IDENTITY";
case VK_COMPONENT_SWIZZLE_ZERO: return "VK_COMPONENT_SWIZZLE_ZERO";
case VK_COMPONENT_SWIZZLE_ONE: return "VK_COMPONENT_SWIZZLE_ONE";
case VK_COMPONENT_SWIZZLE_R: return "VK_COMPONENT_SWIZZLE_R";
case VK_COMPONENT_SWIZZLE_G: return "VK_COMPONENT_SWIZZLE_G";
case VK_COMPONENT_SWIZZLE_B: return "VK_COMPONENT_SWIZZLE_B";
case VK_COMPONENT_SWIZZLE_A: return "VK_COMPONENT_SWIZZLE_A";
default: return "VK_COMPONENT_SWIZZLE_UNKNOWN";
}
}
// Returns whether the swizzle components of the internal VkComponentMapping matches the // Returns whether the swizzle components of the internal VkComponentMapping matches the
// swizzle pattern, by comparing corresponding elements of the two structures. The pattern // swizzle pattern, by comparing corresponding elements of the two structures. The pattern
// supports wildcards, in that any element of pattern can be set to VK_COMPONENT_SWIZZLE_MAX_ENUM // supports wildcards, in that any element of pattern can be set to VK_COMPONENT_SWIZZLE_MAX_ENUM
@ -926,12 +913,6 @@ bool MVKImageView::matchesSwizzle(VkComponentMapping components, VkComponentMapp
return true; return true;
} }
// Packs a VkComponentMapping structure into a single 32-bit word.
uint32_t MVKImageView::packSwizzle(VkComponentMapping components) {
return ((components.r & 0xFF) << 0) | ((components.g & 0xFF) << 8) |
((components.b & 0xFF) << 16) | ((components.a & 0xFF) << 24);
}
// Determine whether this image view should use a Metal texture view, // Determine whether this image view should use a Metal texture view,
// and set the _useMTLTextureView variable appropriately. // and set the _useMTLTextureView variable appropriately.
void MVKImageView::initMTLTextureViewSupport() { void MVKImageView::initMTLTextureViewSupport() {

View File

@ -22,6 +22,7 @@
#include "MVKFoundation.h" #include "MVKFoundation.h"
#include "MVKEnvironment.h" #include "MVKEnvironment.h"
#include "MVKSurface.h" #include "MVKSurface.h"
#include "MVKOSExtensions.h"
using namespace std; using namespace std;
@ -125,7 +126,10 @@ MVKInstance::MVKInstance(const VkInstanceCreateInfo* pCreateInfo) {
if (MVK_VULKAN_API_VERSION_CONFORM(MVK_VULKAN_API_VERSION) < if (MVK_VULKAN_API_VERSION_CONFORM(MVK_VULKAN_API_VERSION) <
MVK_VULKAN_API_VERSION_CONFORM(_appInfo.apiVersion)) { MVK_VULKAN_API_VERSION_CONFORM(_appInfo.apiVersion)) {
setConfigurationResult(mvkNotifyErrorWithText(VK_ERROR_INCOMPATIBLE_DRIVER, "Request for driver version %x is not compatible with provided version %x.", _appInfo.apiVersion, MVK_VULKAN_API_VERSION)); setConfigurationResult(mvkNotifyErrorWithText(VK_ERROR_INCOMPATIBLE_DRIVER,
"Request for Vulkan version %s is not compatible with supported version %s.",
mvkGetVulkanVersionString(_appInfo.apiVersion).c_str(),
mvkGetVulkanVersionString(MVK_VULKAN_API_VERSION).c_str()));
} }
// Populate the array of physical GPU devices // Populate the array of physical GPU devices
@ -338,31 +342,32 @@ void MVKInstance::initProcAddrs() {
} }
void MVKInstance::logVersions() { void MVKInstance::logVersions() {
uint32_t buffLen = 32; string logMsg = "MoltenVK version ";
char mvkVer[buffLen]; logMsg += mvkGetMoltenVKVersionString(MVK_VERSION);
char vkVer[buffLen]; logMsg += ". Vulkan version ";
vkGetVersionStringsMVK(mvkVer, buffLen, vkVer, buffLen); logMsg += mvkGetVulkanVersionString(MVK_VULKAN_API_VERSION);
logMsg += ".\n\tThe following Vulkan extensions are supported:";
string logMsg = "MoltenVK version %s. Vulkan version %s.";
logMsg += "\n\tThe following Vulkan extensions are supported:";
logMsg += getDriverLayer()->getSupportedExtensions()->enabledNamesString("\n\t\t", true); logMsg += getDriverLayer()->getSupportedExtensions()->enabledNamesString("\n\t\t", true);
MVKLogInfo(logMsg.c_str(), mvkVer, vkVer); MVKLogInfo("%s", logMsg.c_str());
} }
// Init config. // Init config.
void MVKInstance::initConfig() { void MVKInstance::initConfig() {
_mvkConfig.debugMode = MVK_DEBUG; MVK_SET_FROM_ENV_OR_BUILD_BOOL( _mvkConfig.debugMode, MVK_DEBUG);
_mvkConfig.shaderConversionFlipVertexY = MVK_CONFIG_SHADER_CONVERSION_FLIP_VERTEX_Y; MVK_SET_FROM_ENV_OR_BUILD_BOOL( _mvkConfig.shaderConversionFlipVertexY, MVK_CONFIG_SHADER_CONVERSION_FLIP_VERTEX_Y);
_mvkConfig.synchronousQueueSubmits = MVK_CONFIG_SYNCHRONOUS_QUEUE_SUBMITS; MVK_SET_FROM_ENV_OR_BUILD_BOOL( _mvkConfig.synchronousQueueSubmits, MVK_CONFIG_SYNCHRONOUS_QUEUE_SUBMITS);
_mvkConfig.prefillMetalCommandBuffers = MVK_CONFIG_PREFILL_METAL_COMMAND_BUFFERS; MVK_SET_FROM_ENV_OR_BUILD_BOOL( _mvkConfig.prefillMetalCommandBuffers, MVK_CONFIG_PREFILL_METAL_COMMAND_BUFFERS);
_mvkConfig.maxActiveMetalCommandBuffersPerQueue = MVK_CONFIG_MAX_ACTIVE_METAL_COMMAND_BUFFERS_PER_POOL; MVK_SET_FROM_ENV_OR_BUILD_INT32(_mvkConfig.maxActiveMetalCommandBuffersPerQueue, MVK_CONFIG_MAX_ACTIVE_METAL_COMMAND_BUFFERS_PER_QUEUE);
_mvkConfig.supportLargeQueryPools = MVK_CONFIG_SUPPORT_LARGE_QUERY_POOLS; MVK_SET_FROM_ENV_OR_BUILD_BOOL( _mvkConfig.supportLargeQueryPools, MVK_CONFIG_SUPPORT_LARGE_QUERY_POOLS);
_mvkConfig.presentWithCommandBuffer = MVK_CONFIG_PRESENT_WITH_COMMAND_BUFFER; MVK_SET_FROM_ENV_OR_BUILD_BOOL( _mvkConfig.presentWithCommandBuffer, MVK_CONFIG_PRESENT_WITH_COMMAND_BUFFER);
_mvkConfig.swapchainMagFilterUseNearest = MVK_CONFIG_SWAPCHAIN_MAG_FILTER_USE_NEAREST; MVK_SET_FROM_ENV_OR_BUILD_BOOL( _mvkConfig.swapchainMagFilterUseNearest, MVK_CONFIG_SWAPCHAIN_MAG_FILTER_USE_NEAREST);
_mvkConfig.displayWatermark = MVK_CONFIG_DISPLAY_WATERMARK; MVK_SET_FROM_ENV_OR_BUILD_INT64(_mvkConfig.metalCompileTimeout, MVK_CONFIG_METAL_COMPILE_TIMEOUT);
_mvkConfig.performanceTracking = MVK_DEBUG; MVK_SET_FROM_ENV_OR_BUILD_BOOL( _mvkConfig.performanceTracking, MVK_CONFIG_PERFORMANCE_TRACKING);
_mvkConfig.performanceLoggingFrameCount = MVK_DEBUG ? 300 : 0; MVK_SET_FROM_ENV_OR_BUILD_INT32(_mvkConfig.performanceLoggingFrameCount, MVK_CONFIG_PERFORMANCE_LOGGING_FRAME_COUNT);
_mvkConfig.metalCompileTimeout = MVK_CONFIG_METAL_COMPILE_TIMEOUT; MVK_SET_FROM_ENV_OR_BUILD_BOOL( _mvkConfig.displayWatermark, MVK_CONFIG_DISPLAY_WATERMARK);
MVK_SET_FROM_ENV_OR_BUILD_BOOL( _mvkConfig.specializedQueueFamilies, MVK_CONFIG_SPECIALIZED_QUEUE_FAMILIES);
MVK_SET_FROM_ENV_OR_BUILD_BOOL( _mvkConfig.switchSystemGPU, MVK_CONFIG_SWITCH_SYSTEM_GPU);
MVK_SET_FROM_ENV_OR_BUILD_BOOL( _mvkConfig.fullImageViewSwizzle, MVK_CONFIG_FULL_IMAGE_VIEW_SWIZZLE);
} }
VkResult MVKInstance::verifyLayers(uint32_t count, const char* const* names) { VkResult MVKInstance::verifyLayers(uint32_t count, const char* const* names) {

View File

@ -35,18 +35,14 @@ class MVKPipelineCache;
#pragma mark - #pragma mark -
#pragma mark MVKShaderAuxBufferBinding #pragma mark MVKPipelineLayout
struct MVKShaderAuxBufferBinding { struct MVKShaderAuxBufferBinding {
uint32_t vertex; uint32_t vertex = 0;
uint32_t fragment; uint32_t fragment = 0;
uint32_t compute; uint32_t compute = 0;
}; };
#pragma mark -
#pragma mark MVKPipelineLayout
/** Represents a Vulkan pipeline layout. */ /** Represents a Vulkan pipeline layout. */
class MVKPipelineLayout : public MVKBaseDeviceObject { class MVKPipelineLayout : public MVKBaseDeviceObject {
@ -129,12 +125,6 @@ public:
/** Returns whether this pipeline permits dynamic setting of the specifie state. */ /** Returns whether this pipeline permits dynamic setting of the specifie state. */
bool supportsDynamicState(VkDynamicState state); bool supportsDynamicState(VkDynamicState state);
/** Returns whether or not the vertex shader needs a buffer to hold auxiliary state. */
bool needsVertexAuxBuffer() { return _needsVertexAuxBuffer; }
/** Returns whether or not the fragment shader needs a buffer to hold auxiliary state. */
bool needsFragmentAuxBuffer() { return _needsFragmentAuxBuffer; }
/** Constructs an instance for the device and parent (which may be NULL). */ /** Constructs an instance for the device and parent (which may be NULL). */
MVKGraphicsPipeline(MVKDevice* device, MVKGraphicsPipeline(MVKDevice* device,
MVKPipelineCache* pipelineCache, MVKPipelineCache* pipelineCache,
@ -167,8 +157,8 @@ protected:
bool _dynamicStateEnabled[VK_DYNAMIC_STATE_RANGE_SIZE]; bool _dynamicStateEnabled[VK_DYNAMIC_STATE_RANGE_SIZE];
bool _hasDepthStencilInfo; bool _hasDepthStencilInfo;
bool _needsVertexAuxBuffer; bool _needsVertexAuxBuffer = false;
bool _needsFragmentAuxBuffer; bool _needsFragmentAuxBuffer = false;
}; };
@ -183,9 +173,6 @@ public:
/** Binds this pipeline to the specified command encoder. */ /** Binds this pipeline to the specified command encoder. */
void encode(MVKCommandEncoder* cmdEncoder) override; void encode(MVKCommandEncoder* cmdEncoder) override;
/** Returns whether or not the compute shader needs a buffer to hold auxiliary state. */
bool needsAuxBuffer() { return _needsAuxBuffer; }
/** Constructs an instance for the device and parent (which may be NULL). */ /** Constructs an instance for the device and parent (which may be NULL). */
MVKComputePipeline(MVKDevice* device, MVKComputePipeline(MVKDevice* device,
MVKPipelineCache* pipelineCache, MVKPipelineCache* pipelineCache,
@ -199,7 +186,7 @@ protected:
id<MTLComputePipelineState> _mtlPipelineState; id<MTLComputePipelineState> _mtlPipelineState;
MTLSize _mtlThreadgroupSize; MTLSize _mtlThreadgroupSize;
bool _needsAuxBuffer; bool _needsAuxBuffer = false;
}; };

View File

@ -138,7 +138,7 @@ MVKPipelineLayout::MVKPipelineLayout(MVKDevice* device,
_pushConstants.push_back(pCreateInfo->pPushConstantRanges[i]); _pushConstants.push_back(pCreateInfo->pPushConstantRanges[i]);
} }
// Set auxiliary buffer offsets // Set auxiliary buffer indices
_auxBufferIndex.vertex = _pushConstantsMTLResourceIndexes.vertexStage.bufferIndex + 1; _auxBufferIndex.vertex = _pushConstantsMTLResourceIndexes.vertexStage.bufferIndex + 1;
_auxBufferIndex.fragment = _pushConstantsMTLResourceIndexes.fragmentStage.bufferIndex + 1; _auxBufferIndex.fragment = _pushConstantsMTLResourceIndexes.fragmentStage.bufferIndex + 1;
_auxBufferIndex.compute = _pushConstantsMTLResourceIndexes.computeStage.bufferIndex + 1; _auxBufferIndex.compute = _pushConstantsMTLResourceIndexes.computeStage.bufferIndex + 1;
@ -307,9 +307,6 @@ MTLRenderPipelineDescriptor* MVKGraphicsPipeline::getMTLRenderPipelineDescriptor
SPIRVToMSLConverterContext shaderContext; SPIRVToMSLConverterContext shaderContext;
initMVKShaderConverterContext(shaderContext, pCreateInfo); initMVKShaderConverterContext(shaderContext, pCreateInfo);
auto* mvkLayout = (MVKPipelineLayout*)pCreateInfo->layout;
_auxBufferIndex = mvkLayout->getAuxBufferIndex();
// Retrieve the render subpass for which this pipeline is being constructed // Retrieve the render subpass for which this pipeline is being constructed
MVKRenderPass* mvkRendPass = (MVKRenderPass*)pCreateInfo->renderPass; MVKRenderPass* mvkRendPass = (MVKRenderPass*)pCreateInfo->renderPass;
MVKRenderSubpass* mvkRenderSubpass = mvkRendPass->getSubpass(pCreateInfo->subpass); MVKRenderSubpass* mvkRenderSubpass = mvkRendPass->getSubpass(pCreateInfo->subpass);
@ -318,7 +315,7 @@ MTLRenderPipelineDescriptor* MVKGraphicsPipeline::getMTLRenderPipelineDescriptor
uint32_t vbCnt = pCreateInfo->pVertexInputState->vertexBindingDescriptionCount; uint32_t vbCnt = pCreateInfo->pVertexInputState->vertexBindingDescriptionCount;
// Add shader stages. Compile vertex shder before others just in case conversion changes anything...like rasterizaion disable. // Add shader stages. Compile vertex shader before others just in case conversion changes anything...like rasterizaion disable.
for (uint32_t i = 0; i < pCreateInfo->stageCount; i++) { for (uint32_t i = 0; i < pCreateInfo->stageCount; i++) {
const VkPipelineShaderStageCreateInfo* pSS = &pCreateInfo->pStages[i]; const VkPipelineShaderStageCreateInfo* pSS = &pCreateInfo->pStages[i];
if (mvkAreFlagsEnabled(pSS->stage, VK_SHADER_STAGE_VERTEX_BIT)) { if (mvkAreFlagsEnabled(pSS->stage, VK_SHADER_STAGE_VERTEX_BIT)) {
@ -327,7 +324,7 @@ MTLRenderPipelineDescriptor* MVKGraphicsPipeline::getMTLRenderPipelineDescriptor
shaderContext.options.entryPointName = pSS->pName; shaderContext.options.entryPointName = pSS->pName;
id<MTLFunction> mtlFunction = ((MVKShaderModule*)pSS->module)->getMTLFunction(&shaderContext, pSS->pSpecializationInfo, _pipelineCache).mtlFunction; id<MTLFunction> mtlFunction = ((MVKShaderModule*)pSS->module)->getMTLFunction(&shaderContext, pSS->pSpecializationInfo, _pipelineCache).mtlFunction;
if ( !mtlFunction ) { if ( !mtlFunction ) {
setConfigurationResult(mvkNotifyErrorWithText(VK_ERROR_INITIALIZATION_FAILED, "Vertex shader function could not be compiled into pipeline. See previous error.")); setConfigurationResult(mvkNotifyErrorWithText(VK_ERROR_INITIALIZATION_FAILED, "Vertex shader function could not be compiled into pipeline. See previous logged error."));
return nil; return nil;
} }
plDesc.vertexFunction = mtlFunction; plDesc.vertexFunction = mtlFunction;
@ -350,7 +347,7 @@ MTLRenderPipelineDescriptor* MVKGraphicsPipeline::getMTLRenderPipelineDescriptor
shaderContext.options.entryPointName = pSS->pName; shaderContext.options.entryPointName = pSS->pName;
id<MTLFunction> mtlFunction = ((MVKShaderModule*)pSS->module)->getMTLFunction(&shaderContext, pSS->pSpecializationInfo, _pipelineCache).mtlFunction; id<MTLFunction> mtlFunction = ((MVKShaderModule*)pSS->module)->getMTLFunction(&shaderContext, pSS->pSpecializationInfo, _pipelineCache).mtlFunction;
if ( !mtlFunction ) { if ( !mtlFunction ) {
setConfigurationResult(mvkNotifyErrorWithText(VK_ERROR_INITIALIZATION_FAILED, "Fragment shader function could not be compiled into pipeline. See previous error.")); setConfigurationResult(mvkNotifyErrorWithText(VK_ERROR_INITIALIZATION_FAILED, "Fragment shader function could not be compiled into pipeline. See previous logged error."));
} }
plDesc.fragmentFunction = mtlFunction; plDesc.fragmentFunction = mtlFunction;
_needsFragmentAuxBuffer = shaderContext.options.needsAuxBuffer; _needsFragmentAuxBuffer = shaderContext.options.needsAuxBuffer;
@ -482,10 +479,12 @@ void MVKGraphicsPipeline::initMVKShaderConverterContext(SPIRVToMSLConverterConte
MVKPipelineLayout* layout = (MVKPipelineLayout*)pCreateInfo->layout; MVKPipelineLayout* layout = (MVKPipelineLayout*)pCreateInfo->layout;
layout->populateShaderConverterContext(shaderContext); layout->populateShaderConverterContext(shaderContext);
_auxBufferIndex = layout->getAuxBufferIndex();
shaderContext.options.isRenderingPoints = isRenderingPoints(pCreateInfo); shaderContext.options.isRenderingPoints = isRenderingPoints(pCreateInfo);
shaderContext.options.isRasterizationDisabled = (pCreateInfo->pRasterizationState && (pCreateInfo->pRasterizationState->rasterizerDiscardEnable)); shaderContext.options.isRasterizationDisabled = (pCreateInfo->pRasterizationState && (pCreateInfo->pRasterizationState->rasterizerDiscardEnable));
shaderContext.options.shouldFlipVertexY = _device->_pMVKConfig->shaderConversionFlipVertexY; shaderContext.options.shouldFlipVertexY = _device->_pMVKConfig->shaderConversionFlipVertexY;
shaderContext.options.shouldSwizzleTextureSamples = _device->_pMVKConfig->fullImageViewSwizzle;
// Set the shader context vertex attribute information // Set the shader context vertex attribute information
shaderContext.vertexAttributes.clear(); shaderContext.vertexAttributes.clear();
@ -565,9 +564,7 @@ MVKGraphicsPipeline::~MVKGraphicsPipeline() {
void MVKComputePipeline::encode(MVKCommandEncoder* cmdEncoder) { void MVKComputePipeline::encode(MVKCommandEncoder* cmdEncoder) {
[cmdEncoder->getMTLComputeEncoder(kMVKCommandUseDispatch) setComputePipelineState: _mtlPipelineState]; [cmdEncoder->getMTLComputeEncoder(kMVKCommandUseDispatch) setComputePipelineState: _mtlPipelineState];
cmdEncoder->_mtlThreadgroupSize = _mtlThreadgroupSize; cmdEncoder->_mtlThreadgroupSize = _mtlThreadgroupSize;
if (_needsAuxBuffer) { cmdEncoder->_computeResourcesState.bindAuxBuffer(_auxBufferIndex, _needsAuxBuffer);
cmdEncoder->_computeResourcesState.bindAuxBuffer(_auxBufferIndex);
}
} }
MVKComputePipeline::MVKComputePipeline(MVKDevice* device, MVKComputePipeline::MVKComputePipeline(MVKDevice* device,
@ -584,7 +581,7 @@ MVKComputePipeline::MVKComputePipeline(MVKDevice* device,
setConfigurationResult(plc->getConfigurationResult()); setConfigurationResult(plc->getConfigurationResult());
plc->destroy(); plc->destroy();
} else { } else {
setConfigurationResult(mvkNotifyErrorWithText(VK_ERROR_INITIALIZATION_FAILED, "Compute shader function could not be compiled into pipeline. See previous error.")); setConfigurationResult(mvkNotifyErrorWithText(VK_ERROR_INITIALIZATION_FAILED, "Compute shader function could not be compiled into pipeline. See previous logged error."));
} }
if (_needsAuxBuffer && _auxBufferIndex.compute == ~0u) { if (_needsAuxBuffer && _auxBufferIndex.compute == ~0u) {
@ -602,6 +599,7 @@ MVKMTLFunction MVKComputePipeline::getMTLFunction(const VkComputePipelineCreateI
shaderContext.options.entryPointName = pCreateInfo->stage.pName; shaderContext.options.entryPointName = pCreateInfo->stage.pName;
shaderContext.options.entryPointStage = spv::ExecutionModelGLCompute; shaderContext.options.entryPointStage = spv::ExecutionModelGLCompute;
shaderContext.options.mslVersion = _device->_pMetalFeatures->mslVersion; shaderContext.options.mslVersion = _device->_pMetalFeatures->mslVersion;
shaderContext.options.shouldSwizzleTextureSamples = _device->_pMVKConfig->fullImageViewSwizzle;
MVKPipelineLayout* layout = (MVKPipelineLayout*)pCreateInfo->layout; MVKPipelineLayout* layout = (MVKPipelineLayout*)pCreateInfo->layout;
layout->populateShaderConverterContext(shaderContext); layout->populateShaderConverterContext(shaderContext);
@ -609,12 +607,11 @@ MVKMTLFunction MVKComputePipeline::getMTLFunction(const VkComputePipelineCreateI
shaderContext.options.auxBufferIndex = _auxBufferIndex.compute; shaderContext.options.auxBufferIndex = _auxBufferIndex.compute;
MVKShaderModule* mvkShdrMod = (MVKShaderModule*)pSS->module; MVKShaderModule* mvkShdrMod = (MVKShaderModule*)pSS->module;
auto func = mvkShdrMod->getMTLFunction(&shaderContext, pSS->pSpecializationInfo, _pipelineCache); MVKMTLFunction func = mvkShdrMod->getMTLFunction(&shaderContext, pSS->pSpecializationInfo, _pipelineCache);
_needsAuxBuffer = shaderContext.options.needsAuxBuffer; _needsAuxBuffer = shaderContext.options.needsAuxBuffer;
return func; return func;
} }
MVKComputePipeline::~MVKComputePipeline() { MVKComputePipeline::~MVKComputePipeline() {
[_mtlPipelineState release]; [_mtlPipelineState release];
} }
@ -682,6 +679,7 @@ namespace mvk {
opt.auxBufferIndex, opt.auxBufferIndex,
opt.shouldFlipVertexY, opt.shouldFlipVertexY,
opt.isRenderingPoints, opt.isRenderingPoints,
opt.shouldSwizzleTextureSamples,
opt.isRasterizationDisabled, opt.isRasterizationDisabled,
opt.needsAuxBuffer); opt.needsAuxBuffer);
} }

View File

@ -19,6 +19,8 @@
#pragma once #pragma once
#include "mvk_vulkan.h" #include "mvk_vulkan.h"
#include "MVKFoundation.h"
#include <string>
#import <Metal/Metal.h> #import <Metal/Metal.h>
@ -67,6 +69,69 @@ inline void mvkDispatchToMainAndWait(dispatch_block_t block) {
} }
#pragma mark -
#pragma mark Process environment
/**
* Returns the value of the environment variable at the given name,
* or an empty string if no environment variable with that name exists.
*
* If pWasFound is not null, it's value is set to true if the environment
* variable exists, or false if not.
*/
inline std::string mvkGetEnvVar(std::string varName, bool* pWasFound = nullptr) {
NSDictionary* env = [[NSProcessInfo processInfo] environment];
NSString* envStr = env[@(varName.c_str())];
if (pWasFound) { *pWasFound = envStr != nil; }
return envStr ? envStr.UTF8String : "";
}
/**
* Returns the value of the environment variable at the given name,
* or zero if no environment variable with that name exists.
*
* If pWasFound is not null, it's value is set to true if the environment
* variable exists, or false if not.
*/
inline int64_t mvkGetEnvVarInt64(std::string varName, bool* pWasFound = nullptr) {
return strtoll(mvkGetEnvVar(varName, pWasFound).c_str(), NULL, 0);
}
/**
* Returns the value of the environment variable at the given name,
* or false if no environment variable with that name exists.
*
* If pWasFound is not null, it's value is set to true if the environment
* variable exists, or false if not.
*/
inline bool mvkGetEnvVarBool(std::string varName, bool* pWasFound = nullptr) {
return mvkGetEnvVarInt64(varName, pWasFound) != 0;
}
#define MVK_SET_FROM_ENV_OR_BUILD_BOOL(cfgVal, EV) \
do { \
bool wasFound = false; \
bool ev = mvkGetEnvVarBool(#EV, &wasFound); \
cfgVal = wasFound ? ev : EV; \
} while(false)
#define MVK_SET_FROM_ENV_OR_BUILD_INT64(cfgVal, EV) \
do { \
bool wasFound = false; \
int64_t ev = mvkGetEnvVarInt64(#EV, &wasFound); \
cfgVal = wasFound ? ev : EV; \
} while(false)
#define MVK_SET_FROM_ENV_OR_BUILD_INT32(cfgVal, EV) \
do { \
bool wasFound = false; \
int64_t ev = mvkGetEnvVarInt64(#EV, &wasFound); \
int64_t val = wasFound ? ev : EV; \
cfgVal = (int32_t)mvkClamp(val, (int64_t)INT32_MIN, (int64_t)INT32_MAX); \
} while(false)
#pragma mark - #pragma mark -
#pragma mark MTLDevice #pragma mark MTLDevice

View File

@ -44,9 +44,9 @@
# define MVK_CONFIG_SHADER_CONVERSION_FLIP_VERTEX_Y 1 # define MVK_CONFIG_SHADER_CONVERSION_FLIP_VERTEX_Y 1
#endif #endif
/** Process command queue submissions on the same thread on which the submission call was made. Disabled by default. */ /** Process command queue submissions on the same thread on which the submission call was made. Enable by default. */
#ifndef MVK_CONFIG_SYNCHRONOUS_QUEUE_SUBMITS #ifndef MVK_CONFIG_SYNCHRONOUS_QUEUE_SUBMITS
# define MVK_CONFIG_SYNCHRONOUS_QUEUE_SUBMITS 0 # define MVK_CONFIG_SYNCHRONOUS_QUEUE_SUBMITS 1
#endif #endif
/** Fill a Metal command buffers when each Vulkan command buffer is filled. */ /** Fill a Metal command buffers when each Vulkan command buffer is filled. */
@ -58,8 +58,8 @@
* The maximum number of Metal command buffers that can be concurrently * The maximum number of Metal command buffers that can be concurrently
* active per Vulkan queue. Default is Metal's default value of 64. * active per Vulkan queue. Default is Metal's default value of 64.
*/ */
#ifndef MVK_CONFIG_MAX_ACTIVE_METAL_COMMAND_BUFFERS_PER_POOL #ifndef MVK_CONFIG_MAX_ACTIVE_METAL_COMMAND_BUFFERS_PER_QUEUE
# define MVK_CONFIG_MAX_ACTIVE_METAL_COMMAND_BUFFERS_PER_POOL 64 # define MVK_CONFIG_MAX_ACTIVE_METAL_COMMAND_BUFFERS_PER_QUEUE 64
#endif #endif
/** Support more than 8192 occlusion queries per buffer. Enabled by default. */ /** Support more than 8192 occlusion queries per buffer. Enabled by default. */
@ -77,16 +77,42 @@
# define MVK_CONFIG_SWAPCHAIN_MAG_FILTER_USE_NEAREST 1 # define MVK_CONFIG_SWAPCHAIN_MAG_FILTER_USE_NEAREST 1
#endif #endif
/** The maximum amount of time, in nanoseconds, to wait for a Metal library. Default is infinite. */
#ifndef MVK_CONFIG_METAL_COMPILE_TIMEOUT
# define MVK_CONFIG_METAL_COMPILE_TIMEOUT INT64_MAX
#endif
/** Track performance. Disabled by default. */
#ifndef MVK_CONFIG_PERFORMANCE_TRACKING
# define MVK_CONFIG_PERFORMANCE_TRACKING 0
#endif
/** Log performance once every this number of frames. Default is zero (never). */
#ifndef MVK_CONFIG_PERFORMANCE_LOGGING_FRAME_COUNT
# define MVK_CONFIG_PERFORMANCE_LOGGING_FRAME_COUNT 0
#endif
/** Display the MoltenVK logo watermark. Disabled by default. */ /** Display the MoltenVK logo watermark. Disabled by default. */
#ifndef MVK_CONFIG_DISPLAY_WATERMARK #ifndef MVK_CONFIG_DISPLAY_WATERMARK
# define MVK_CONFIG_DISPLAY_WATERMARK 0 # define MVK_CONFIG_DISPLAY_WATERMARK 0
#endif #endif
/** The maximum amount of time, in nanoseconds, to wait for a Metal library. Default is infinite. */ /** Advertise specialized queue families. Disabled by default. */
#ifndef MVK_CONFIG_METAL_COMPILE_TIMEOUT #ifndef MVK_CONFIG_SPECIALIZED_QUEUE_FAMILIES
# define MVK_CONFIG_METAL_COMPILE_TIMEOUT INT64_MAX # define MVK_CONFIG_SPECIALIZED_QUEUE_FAMILIES 0
#endif #endif
/** If the Vulkan app selects a high-power GPU, force the system to use it. Enabled by default. */
#ifndef MVK_CONFIG_SWITCH_SYSTEM_GPU
# define MVK_CONFIG_SWITCH_SYSTEM_GPU 1
#endif
/** Support full ImageView swizzles. Disabled by default. */
#ifndef MVK_CONFIG_FULL_IMAGE_VIEW_SWIZZLE
# define MVK_CONFIG_FULL_IMAGE_VIEW_SWIZZLE 0
#endif
/** /**
* IOSurfaces are supported on macOS, and on iOS starting with iOS 11. * IOSurfaces are supported on macOS, and on iOS starting with iOS 11.
* *

View File

@ -19,45 +19,59 @@
#include "MVKFoundation.h" #include "MVKFoundation.h"
#include "MVKLogging.h" #include "MVKLogging.h"
#define CASE_RESULT(R) case R: return strcpy(name, #R);
char* mvkResultName(VkResult vkResult, char* name) { #define CASE_STRINGIFY(V) case V: return #V
const char* mvkVkResultName(VkResult vkResult) {
switch (vkResult) { switch (vkResult) {
CASE_RESULT(VK_SUCCESS)
CASE_RESULT(VK_NOT_READY)
CASE_RESULT(VK_TIMEOUT)
CASE_RESULT(VK_EVENT_SET)
CASE_RESULT(VK_EVENT_RESET)
CASE_RESULT(VK_INCOMPLETE)
CASE_RESULT(VK_ERROR_OUT_OF_HOST_MEMORY) CASE_STRINGIFY(VK_SUCCESS);
CASE_RESULT(VK_ERROR_OUT_OF_DEVICE_MEMORY) CASE_STRINGIFY(VK_NOT_READY);
CASE_RESULT(VK_ERROR_INITIALIZATION_FAILED) CASE_STRINGIFY(VK_TIMEOUT);
CASE_RESULT(VK_ERROR_DEVICE_LOST) CASE_STRINGIFY(VK_EVENT_SET);
CASE_RESULT(VK_ERROR_MEMORY_MAP_FAILED) CASE_STRINGIFY(VK_EVENT_RESET);
CASE_RESULT(VK_ERROR_LAYER_NOT_PRESENT) CASE_STRINGIFY(VK_INCOMPLETE);
CASE_RESULT(VK_ERROR_EXTENSION_NOT_PRESENT)
CASE_RESULT(VK_ERROR_FEATURE_NOT_PRESENT)
CASE_RESULT(VK_ERROR_INCOMPATIBLE_DRIVER)
CASE_RESULT(VK_ERROR_TOO_MANY_OBJECTS)
CASE_RESULT(VK_ERROR_FORMAT_NOT_SUPPORTED)
CASE_RESULT(VK_ERROR_FRAGMENTED_POOL)
CASE_RESULT(VK_ERROR_SURFACE_LOST_KHR) CASE_STRINGIFY(VK_ERROR_OUT_OF_HOST_MEMORY);
CASE_RESULT(VK_ERROR_NATIVE_WINDOW_IN_USE_KHR) CASE_STRINGIFY(VK_ERROR_OUT_OF_DEVICE_MEMORY);
CASE_RESULT(VK_SUBOPTIMAL_KHR) CASE_STRINGIFY(VK_ERROR_INITIALIZATION_FAILED);
CASE_RESULT(VK_ERROR_OUT_OF_DATE_KHR) CASE_STRINGIFY(VK_ERROR_DEVICE_LOST);
CASE_RESULT(VK_ERROR_INCOMPATIBLE_DISPLAY_KHR) CASE_STRINGIFY(VK_ERROR_MEMORY_MAP_FAILED);
CASE_STRINGIFY(VK_ERROR_LAYER_NOT_PRESENT);
CASE_STRINGIFY(VK_ERROR_EXTENSION_NOT_PRESENT);
CASE_STRINGIFY(VK_ERROR_FEATURE_NOT_PRESENT);
CASE_STRINGIFY(VK_ERROR_INCOMPATIBLE_DRIVER);
CASE_STRINGIFY(VK_ERROR_TOO_MANY_OBJECTS);
CASE_STRINGIFY(VK_ERROR_FORMAT_NOT_SUPPORTED);
CASE_STRINGIFY(VK_ERROR_FRAGMENTED_POOL);
CASE_RESULT(VK_ERROR_VALIDATION_FAILED_EXT) CASE_STRINGIFY(VK_ERROR_SURFACE_LOST_KHR);
CASE_RESULT(VK_ERROR_INVALID_SHADER_NV) CASE_STRINGIFY(VK_ERROR_NATIVE_WINDOW_IN_USE_KHR);
CASE_STRINGIFY(VK_SUBOPTIMAL_KHR);
CASE_STRINGIFY(VK_ERROR_OUT_OF_DATE_KHR);
CASE_STRINGIFY(VK_ERROR_INCOMPATIBLE_DISPLAY_KHR);
CASE_RESULT(VK_ERROR_OUT_OF_POOL_MEMORY) CASE_STRINGIFY(VK_ERROR_VALIDATION_FAILED_EXT);
CASE_RESULT(VK_ERROR_INVALID_EXTERNAL_HANDLE) CASE_STRINGIFY(VK_ERROR_INVALID_SHADER_NV);
default: CASE_STRINGIFY(VK_ERROR_OUT_OF_POOL_MEMORY);
sprintf(name, "UNKNOWN_VkResult(%d)", vkResult); CASE_STRINGIFY(VK_ERROR_INVALID_EXTERNAL_HANDLE);
return name;
default: return "VK_UNKNOWN_VK_Result";
}
}
const char* mvkVkComponentSwizzleName(VkComponentSwizzle swizzle) {
switch (swizzle) {
CASE_STRINGIFY(VK_COMPONENT_SWIZZLE_IDENTITY);
CASE_STRINGIFY(VK_COMPONENT_SWIZZLE_ZERO);
CASE_STRINGIFY(VK_COMPONENT_SWIZZLE_ONE);
CASE_STRINGIFY(VK_COMPONENT_SWIZZLE_R);
CASE_STRINGIFY(VK_COMPONENT_SWIZZLE_G);
CASE_STRINGIFY(VK_COMPONENT_SWIZZLE_B);
CASE_STRINGIFY(VK_COMPONENT_SWIZZLE_A);
default: return "VK_UNKNOWN_VKComponentSwizzle";
} }
} }
@ -65,10 +79,8 @@ VkResult mvkNotifyErrorWithText(VkResult vkErr, const char* errFmt, ...) {
va_list args; va_list args;
va_start(args, errFmt); va_start(args, errFmt);
char vkRsltName[MVKResultNameMaxLen];
mvkResultName(vkErr, vkRsltName);
// Prepend the error code to the format string // Prepend the error code to the format string
const char* vkRsltName = mvkVkResultName(vkErr);
char fmtStr[strlen(vkRsltName) + strlen(errFmt) + 4]; char fmtStr[strlen(vkRsltName) + strlen(errFmt) + 4];
sprintf(fmtStr, "%s: %s", vkRsltName, errFmt); sprintf(fmtStr, "%s: %s", vkRsltName, errFmt);

View File

@ -23,6 +23,7 @@
#include "mvk_vulkan.h" #include "mvk_vulkan.h"
#include "MVKLogging.h" #include "MVKLogging.h"
#include <algorithm> #include <algorithm>
#include <string>
#include <simd/simd.h> #include <simd/simd.h>
@ -100,13 +101,33 @@ typedef enum {
kMVKCommandUseDispatch, /**< vkCmdDispatch. */ kMVKCommandUseDispatch, /**< vkCmdDispatch. */
} MVKCommandUse; } MVKCommandUse;
/** /** Returns the name of the result value. */
* Copies the name of the specified VkResult code to the specified string. const char* mvkVkResultName(VkResult vkResult);
*
* Returns a pointer to that string. /** Returns the name of the component swizzle. */
*/ const char* mvkVkComponentSwizzleName(VkComponentSwizzle swizzle);
#define MVKResultNameMaxLen 64
char* mvkResultName(VkResult vkResult, char* name); /** Returns the Vulkan API version number as a string. */
static inline std::string mvkGetVulkanVersionString(uint32_t vkVersion) {
std::string verStr;
verStr += std::to_string(VK_VERSION_MAJOR(vkVersion));
verStr += ".";
verStr += std::to_string(VK_VERSION_MINOR(vkVersion));
verStr += ".";
verStr += std::to_string(VK_VERSION_PATCH(vkVersion));
return verStr;
}
/** Returns the MoltenVK API version number as a string. */
static inline std::string mvkGetMoltenVKVersionString(uint32_t mvkVersion) {
std::string verStr;
verStr += std::to_string(mvkVersion / 10000);
verStr += ".";
verStr += std::to_string((mvkVersion % 10000) / 100);
verStr += ".";
verStr += std::to_string(mvkVersion % 100);
return verStr;
}
/** /**
* Notifies the app of an error code and error message, via the following methods: * Notifies the app of an error code and error message, via the following methods:
@ -260,6 +281,22 @@ static inline VkOffset3D mvkVkOffset3DDifference(VkOffset3D minuend, VkOffset3D
return rslt; return rslt;
} }
/** Packs the four swizzle components into a single 32-bit word. */
static inline uint32_t mvkPackSwizzle(VkComponentMapping components) {
return ((components.r & 0xFF) << 0) | ((components.g & 0xFF) << 8) |
((components.b & 0xFF) << 16) | ((components.a & 0xFF) << 24);
}
/** Unpacks a single 32-bit word containing four swizzle components. */
static inline VkComponentMapping mvkUnpackSwizzle(uint32_t packed) {
VkComponentMapping components;
components.r = (VkComponentSwizzle)((packed >> 0) & 0xFF);
components.g = (VkComponentSwizzle)((packed >> 8) & 0xFF);
components.b = (VkComponentSwizzle)((packed >> 16) & 0xFF);
components.a = (VkComponentSwizzle)((packed >> 24) & 0xFF);
return components;
}
#pragma mark - #pragma mark -
#pragma mark Template functions #pragma mark Template functions

View File

@ -454,14 +454,14 @@ static const MVKFormatDesc _formatDescriptions[] {
MVK_MAKE_FMT_STRUCT( VK_FORMAT_ASTC_12x12_UNORM_BLOCK, MTLPixelFormatASTC_12x12_LDR, MTLPixelFormatInvalid, 8.0, kMTLFmtNA, 12, 12, 16, MTLVertexFormatInvalid, MTLVertexFormatInvalid, kMTLFmtNA, kMTLFmtNA, kMVKFormatCompressed, MVK_FMT_COMPRESSED_FEATS, MVK_FMT_NO_FEATS ), MVK_MAKE_FMT_STRUCT( VK_FORMAT_ASTC_12x12_UNORM_BLOCK, MTLPixelFormatASTC_12x12_LDR, MTLPixelFormatInvalid, 8.0, kMTLFmtNA, 12, 12, 16, MTLVertexFormatInvalid, MTLVertexFormatInvalid, kMTLFmtNA, kMTLFmtNA, kMVKFormatCompressed, MVK_FMT_COMPRESSED_FEATS, MVK_FMT_NO_FEATS ),
MVK_MAKE_FMT_STRUCT( VK_FORMAT_ASTC_12x12_SRGB_BLOCK, MTLPixelFormatASTC_12x12_sRGB, MTLPixelFormatInvalid, 8.0, kMTLFmtNA, 12, 12, 16, MTLVertexFormatInvalid, MTLVertexFormatInvalid, kMTLFmtNA, kMTLFmtNA, kMVKFormatCompressed, MVK_FMT_COMPRESSED_FEATS, MVK_FMT_NO_FEATS ), MVK_MAKE_FMT_STRUCT( VK_FORMAT_ASTC_12x12_SRGB_BLOCK, MTLPixelFormatASTC_12x12_sRGB, MTLPixelFormatInvalid, 8.0, kMTLFmtNA, 12, 12, 16, MTLVertexFormatInvalid, MTLVertexFormatInvalid, kMTLFmtNA, kMTLFmtNA, kMVKFormatCompressed, MVK_FMT_COMPRESSED_FEATS, MVK_FMT_NO_FEATS ),
// Extension VK_IMG_format_pvrtc // Extension VK_IMG_format_pvrtc
MVK_MAKE_FMT_STRUCT( VK_FORMAT_PVRTC1_2BPP_UNORM_BLOCK_IMG, MTLPixelFormatPVRTC_RGBA_2BPP, MTLPixelFormatInvalid, 8.0, kMTLFmtNA, 8, 4, 8, MTLVertexFormatInvalid, MTLVertexFormatInvalid, kMTLFmtNA, kMTLFmtNA, kMVKFormatCompressed, MVK_FMT_COMPRESSED_FEATS, MVK_FMT_NO_FEATS ), MVK_MAKE_FMT_STRUCT( VK_FORMAT_PVRTC1_2BPP_UNORM_BLOCK_IMG, MTLPixelFormatPVRTC_RGBA_2BPP, MTLPixelFormatInvalid, 8.0, kMTLFmtNA, 8, 4, 8, MTLVertexFormatInvalid, MTLVertexFormatInvalid, kMTLFmtNA, kMTLFmtNA, kMVKFormatCompressed, MVK_FMT_COMPRESSED_FEATS, MVK_FMT_NO_FEATS ),
MVK_MAKE_FMT_STRUCT( VK_FORMAT_PVRTC1_4BPP_UNORM_BLOCK_IMG, MTLPixelFormatPVRTC_RGBA_4BPP, MTLPixelFormatInvalid, 8.0, kMTLFmtNA, 8, 4, 8, MTLVertexFormatInvalid, MTLVertexFormatInvalid, kMTLFmtNA, kMTLFmtNA, kMVKFormatCompressed, MVK_FMT_COMPRESSED_FEATS, MVK_FMT_NO_FEATS ), MVK_MAKE_FMT_STRUCT( VK_FORMAT_PVRTC1_4BPP_UNORM_BLOCK_IMG, MTLPixelFormatPVRTC_RGBA_4BPP, MTLPixelFormatInvalid, 8.0, kMTLFmtNA, 4, 4, 8, MTLVertexFormatInvalid, MTLVertexFormatInvalid, kMTLFmtNA, kMTLFmtNA, kMVKFormatCompressed, MVK_FMT_COMPRESSED_FEATS, MVK_FMT_NO_FEATS ),
MVK_MAKE_FMT_STRUCT( VK_FORMAT_PVRTC2_2BPP_UNORM_BLOCK_IMG, MTLPixelFormatInvalid, MTLPixelFormatInvalid, kMTLFmtNA, kMTLFmtNA, 4, 4, 8, MTLVertexFormatInvalid, MTLVertexFormatInvalid, kMTLFmtNA, kMTLFmtNA, kMVKFormatCompressed, MVK_FMT_NO_FEATS, MVK_FMT_NO_FEATS ), MVK_MAKE_FMT_STRUCT( VK_FORMAT_PVRTC2_2BPP_UNORM_BLOCK_IMG, MTLPixelFormatInvalid, MTLPixelFormatInvalid, kMTLFmtNA, kMTLFmtNA, 8, 4, 8, MTLVertexFormatInvalid, MTLVertexFormatInvalid, kMTLFmtNA, kMTLFmtNA, kMVKFormatCompressed, MVK_FMT_NO_FEATS, MVK_FMT_NO_FEATS ),
MVK_MAKE_FMT_STRUCT( VK_FORMAT_PVRTC2_4BPP_UNORM_BLOCK_IMG, MTLPixelFormatInvalid, MTLPixelFormatInvalid, kMTLFmtNA, kMTLFmtNA, 4, 4, 8, MTLVertexFormatInvalid, MTLVertexFormatInvalid, kMTLFmtNA, kMTLFmtNA, kMVKFormatCompressed, MVK_FMT_NO_FEATS, MVK_FMT_NO_FEATS ), MVK_MAKE_FMT_STRUCT( VK_FORMAT_PVRTC2_4BPP_UNORM_BLOCK_IMG, MTLPixelFormatInvalid, MTLPixelFormatInvalid, kMTLFmtNA, kMTLFmtNA, 4, 4, 8, MTLVertexFormatInvalid, MTLVertexFormatInvalid, kMTLFmtNA, kMTLFmtNA, kMVKFormatCompressed, MVK_FMT_NO_FEATS, MVK_FMT_NO_FEATS ),
MVK_MAKE_FMT_STRUCT( VK_FORMAT_PVRTC1_2BPP_SRGB_BLOCK_IMG, MTLPixelFormatPVRTC_RGBA_2BPP_sRGB, MTLPixelFormatInvalid, 8.0, kMTLFmtNA, 8, 4, 8, MTLVertexFormatInvalid, MTLVertexFormatInvalid, kMTLFmtNA, kMTLFmtNA, kMVKFormatCompressed, MVK_FMT_COMPRESSED_FEATS, MVK_FMT_NO_FEATS ), MVK_MAKE_FMT_STRUCT( VK_FORMAT_PVRTC1_2BPP_SRGB_BLOCK_IMG, MTLPixelFormatPVRTC_RGBA_2BPP_sRGB, MTLPixelFormatInvalid, 8.0, kMTLFmtNA, 8, 4, 8, MTLVertexFormatInvalid, MTLVertexFormatInvalid, kMTLFmtNA, kMTLFmtNA, kMVKFormatCompressed, MVK_FMT_COMPRESSED_FEATS, MVK_FMT_NO_FEATS ),
MVK_MAKE_FMT_STRUCT( VK_FORMAT_PVRTC1_4BPP_SRGB_BLOCK_IMG, MTLPixelFormatPVRTC_RGBA_4BPP_sRGB, MTLPixelFormatInvalid, 8.0, kMTLFmtNA, 8, 4, 8, MTLVertexFormatInvalid, MTLVertexFormatInvalid, kMTLFmtNA, kMTLFmtNA, kMVKFormatCompressed, MVK_FMT_COMPRESSED_FEATS, MVK_FMT_NO_FEATS ), MVK_MAKE_FMT_STRUCT( VK_FORMAT_PVRTC1_4BPP_SRGB_BLOCK_IMG, MTLPixelFormatPVRTC_RGBA_4BPP_sRGB, MTLPixelFormatInvalid, 8.0, kMTLFmtNA, 4, 4, 8, MTLVertexFormatInvalid, MTLVertexFormatInvalid, kMTLFmtNA, kMTLFmtNA, kMVKFormatCompressed, MVK_FMT_COMPRESSED_FEATS, MVK_FMT_NO_FEATS ),
MVK_MAKE_FMT_STRUCT( VK_FORMAT_PVRTC2_2BPP_SRGB_BLOCK_IMG, MTLPixelFormatInvalid, MTLPixelFormatInvalid, kMTLFmtNA, kMTLFmtNA, 4, 4, 8, MTLVertexFormatInvalid, MTLVertexFormatInvalid, kMTLFmtNA, kMTLFmtNA, kMVKFormatCompressed, MVK_FMT_NO_FEATS, MVK_FMT_NO_FEATS ), MVK_MAKE_FMT_STRUCT( VK_FORMAT_PVRTC2_2BPP_SRGB_BLOCK_IMG, MTLPixelFormatInvalid, MTLPixelFormatInvalid, kMTLFmtNA, kMTLFmtNA, 8, 4, 8, MTLVertexFormatInvalid, MTLVertexFormatInvalid, kMTLFmtNA, kMTLFmtNA, kMVKFormatCompressed, MVK_FMT_NO_FEATS, MVK_FMT_NO_FEATS ),
MVK_MAKE_FMT_STRUCT( VK_FORMAT_PVRTC2_4BPP_SRGB_BLOCK_IMG, MTLPixelFormatInvalid, MTLPixelFormatInvalid, kMTLFmtNA, kMTLFmtNA, 4, 4, 8, MTLVertexFormatInvalid, MTLVertexFormatInvalid, kMTLFmtNA, kMTLFmtNA, kMVKFormatCompressed, MVK_FMT_NO_FEATS, MVK_FMT_NO_FEATS ), MVK_MAKE_FMT_STRUCT( VK_FORMAT_PVRTC2_4BPP_SRGB_BLOCK_IMG, MTLPixelFormatInvalid, MTLPixelFormatInvalid, kMTLFmtNA, kMTLFmtNA, 4, 4, 8, MTLVertexFormatInvalid, MTLVertexFormatInvalid, kMTLFmtNA, kMTLFmtNA, kMVKFormatCompressed, MVK_FMT_NO_FEATS, MVK_FMT_NO_FEATS ),
// Future extension VK_KHX_color_conversion and Vulkan 1.1. // Future extension VK_KHX_color_conversion and Vulkan 1.1.
@ -763,6 +763,24 @@ MVK_PUBLIC_SYMBOL bool mvkMTLPixelFormatIsStencilFormat(MTLPixelFormat mtlFormat
} }
} }
MVK_PUBLIC_SYMBOL bool mvkMTLPixelFormatIsPVRTCFormat(MTLPixelFormat mtlFormat) {
switch (mtlFormat) {
#if MVK_IOS
case MTLPixelFormatPVRTC_RGBA_2BPP:
case MTLPixelFormatPVRTC_RGBA_2BPP_sRGB:
case MTLPixelFormatPVRTC_RGBA_4BPP:
case MTLPixelFormatPVRTC_RGBA_4BPP_sRGB:
case MTLPixelFormatPVRTC_RGB_2BPP:
case MTLPixelFormatPVRTC_RGB_2BPP_sRGB:
case MTLPixelFormatPVRTC_RGB_4BPP:
case MTLPixelFormatPVRTC_RGB_4BPP_sRGB:
return true;
#endif
default:
return false;
}
}
MVK_PUBLIC_SYMBOL MTLTextureType mvkMTLTextureTypeFromVkImageType(VkImageType vkImageType, MVK_PUBLIC_SYMBOL MTLTextureType mvkMTLTextureTypeFromVkImageType(VkImageType vkImageType,
uint32_t arraySize, uint32_t arraySize,
bool isMultisample) { bool isMultisample) {

View File

@ -92,30 +92,20 @@ MVK_PUBLIC_SYMBOL VkResult vkGetPerformanceStatisticsMVK(
} }
MVK_PUBLIC_SYMBOL void vkGetVersionStringsMVK( MVK_PUBLIC_SYMBOL void vkGetVersionStringsMVK(
char* pMoltenVersionStringBuffer, char* pMoltenVersionStringBuffer,
uint32_t moltenVersionStringBufferLength, uint32_t moltenVersionStringBufferLength,
char* pVulkanVersionStringBuffer, char* pVulkanVersionStringBuffer,
uint32_t vulkanVersionStringBufferLength) { uint32_t vulkanVersionStringBufferLength) {
size_t len; size_t len;
string mvkVer; string mvkVer = mvkGetMoltenVKVersionString(MVK_VERSION);
mvkVer += to_string(MVK_VERSION / 10000); len = mvkVer.copy(pMoltenVersionStringBuffer, moltenVersionStringBufferLength - 1);
mvkVer += "."; pMoltenVersionStringBuffer[len] = 0; // terminator
mvkVer += to_string((MVK_VERSION % 10000) / 100);
mvkVer += ".";
mvkVer += to_string(MVK_VERSION % 100);
len = mvkVer.copy(pMoltenVersionStringBuffer, moltenVersionStringBufferLength - 1);
pMoltenVersionStringBuffer[len] = 0; // terminator
string vkVer; string vkVer = mvkGetVulkanVersionString(MVK_VULKAN_API_VERSION);
vkVer += to_string(VK_VERSION_MAJOR(MVK_VULKAN_API_VERSION)); len = vkVer.copy(pVulkanVersionStringBuffer, vulkanVersionStringBufferLength - 1);
vkVer += "."; pVulkanVersionStringBuffer[len] = 0; // terminator
vkVer += to_string(VK_VERSION_MINOR(MVK_VULKAN_API_VERSION));
vkVer += ".";
vkVer += to_string(VK_VERSION_PATCH(MVK_VULKAN_API_VERSION));
len = vkVer.copy(pVulkanVersionStringBuffer, vulkanVersionStringBufferLength - 1);
pVulkanVersionStringBuffer[len] = 0; // terminator
} }
MVK_PUBLIC_SYMBOL void vkGetMTLDeviceMVK( MVK_PUBLIC_SYMBOL void vkGetMTLDeviceMVK(

View File

@ -45,6 +45,7 @@ MVK_PUBLIC_SYMBOL bool SPIRVToMSLConverterOptions::matches(const SPIRVToMSLConve
if (auxBufferIndex != other.auxBufferIndex) { return false; } if (auxBufferIndex != other.auxBufferIndex) { return false; }
if (!!shouldFlipVertexY != !!other.shouldFlipVertexY) { return false; } if (!!shouldFlipVertexY != !!other.shouldFlipVertexY) { return false; }
if (!!isRenderingPoints != !!other.isRenderingPoints) { return false; } if (!!isRenderingPoints != !!other.isRenderingPoints) { return false; }
if (!!shouldSwizzleTextureSamples != !!other.shouldSwizzleTextureSamples) { return false; }
if (entryPointName != other.entryPointName) { return false; } if (entryPointName != other.entryPointName) { return false; }
return true; return true;
} }
@ -237,7 +238,8 @@ MVK_PUBLIC_SYMBOL bool SPIRVToMSLConverter::convert(SPIRVToMSLConverterContext&
mslOpts.aux_buffer_index = context.options.auxBufferIndex; mslOpts.aux_buffer_index = context.options.auxBufferIndex;
mslOpts.enable_point_size_builtin = context.options.isRenderingPoints; mslOpts.enable_point_size_builtin = context.options.isRenderingPoints;
mslOpts.disable_rasterization = context.options.isRasterizationDisabled; mslOpts.disable_rasterization = context.options.isRasterizationDisabled;
mslOpts.swizzle_texture_samples = true; mslOpts.swizzle_texture_samples = context.options.shouldSwizzleTextureSamples;
mslOpts.pad_fragment_output_components = true;
pMSLCompiler->set_msl_options(mslOpts); pMSLCompiler->set_msl_options(mslOpts);
auto scOpts = pMSLCompiler->get_common_options(); auto scOpts = pMSLCompiler->get_common_options();

View File

@ -40,6 +40,7 @@ namespace mvk {
uint32_t auxBufferIndex = 0; uint32_t auxBufferIndex = 0;
bool shouldFlipVertexY = true; bool shouldFlipVertexY = true;
bool isRenderingPoints = false; bool isRenderingPoints = false;
bool shouldSwizzleTextureSamples = false;
bool isRasterizationDisabled = false; bool isRasterizationDisabled = false;
bool needsAuxBuffer = false; bool needsAuxBuffer = false;