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)
- [Install as Static Framework, Static Library, or Dynamic Library](#install_lib)
- [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)
- [MoltenVKShaderConverter Shader Converter Tool](#shader_converter_tool)
- [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_EXT_shader_viewport_index_layer`
- `VK_EXT_vertex_attribute_divisor`
- `VK_MVK_moltenvk`
- `VK_MVK_macos_surface` (macOS)
- `VK_MVK_ios_surface` (iOS)
- `VK_MVK_moltenvk`
- `VK_AMD_gpu_shader_half_float`
- `VK_AMD_negative_viewport_height`
- `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`
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
the `vkCreateMacOSSurfaceMVK` function from outside the main application thread, as `NSView` should only be
accessed from the main application thread.
`CAMetalLayer`, or the `CAMetalLayer` itself. Passing the `CAMetalLayer` itself is recommended when
calling the `vkCreateMacOSSurfaceMVK` function from outside the main application thread, as `NSView`
should only be accessed from the main application thread.
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
@ -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`
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*
API, to support configuration options, license registration, 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.
<a name="moltenvk_extension"></a>
### MoltenVK `VK_MVK_moltenvk` Extension
The `VK_MVK_moltenvk` *Vulkan* extension provides functionality beyond the standard *Vulkan* API, to
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
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.
<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>
*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.
- To help understand conversion issues during **Runtime Shader Conversion**, you can enable
the logging of the *SPIR-V* and *MSL* shader source code during conversion as follows:
#include <MoltenVK/vk_mvk_moltenvk.h>
...
MVKConfiguration mvkConfig;
size_t appConfigSize = sizeof(mvkConfig);
vkGetMoltenVKConfigurationMVK(vkInstance, &mvkConfig, &appConfigSize);
mvkConfig.debugMode = true;
vkSetMoltenVKConfigurationMVK(vkInstance, &mvkConfig, &appConfigSize);
- To help understand conversion issues during **Runtime Shader Conversion**, you can enable the
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`
runtime environment variable to `1`. See the [*MoltenVK Configuration*](#moltenvk_config)
description above.
Performing these steps will enable debug mode in **MoltenVK**, which includes shader conversion
logging, and causes both the incoming *SPIR-V* code and the converted *MSL* source code to be
logged to the console (in human-readable form). This allows you to manually verify the conversions,
and can help you diagnose issues that might occur during shader conversion.
Enabling debug mode in **MoltenVK** includes shader conversion logging, which causes both
the incoming *SPIR-V* code and the converted *MSL* source code to be logged to the console
in human-readable form. This allows you to manually verify the conversions, and can help
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
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
---------------

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. */
bool mvkMTLPixelFormatIsStencilFormat(MTLPixelFormat mtlFormat);
/** Returns whether the specified Metal MTLPixelFormat is a PVRTC format. */
bool mvkMTLPixelFormatIsPVRTCFormat(MTLPixelFormat mtlFormat);
/** Returns the Metal texture type from the specified Vulkan image properties. */
MTLTextureType mvkMTLTextureTypeFromVkImageType(VkImageType vkImageType,
uint32_t arraySize,

View File

@ -48,28 +48,37 @@ extern "C" {
*/
#define MVK_VERSION_MAJOR 1
#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_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"
/**
* 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.
* 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
* presence of a DEBUG build setting, By default the DEBUG build setting is present when MoltenVK
* is compiled in Debug mode, and not present when compiled in Release mode. The initial values
* of the other settings are determined by other build settings when MoltenVK is compiled.
* See the description of the individual configuration structure members for more information.
* 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.
*
* 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
* 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.
*
* 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.
*/
typedef struct {
/**
* If enabled, debugging capabilities will be enabled, including logging shader code
* during runtime shader conversion.
* If enabled, debugging capabilities will be enabled, including logging
* 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;
/**
* 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.
*
* 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.
*
* Initial value is set by the MVK_CONFIG_SHADER_CONVERSION_FLIP_VERTEX_Y build setting
* when MoltenVK is compiled. By default the MVK_CONFIG_SHADER_CONVERSION_FLIP_VERTEX_Y
* build setting is set to true.
* 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.
*
* 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;
@ -109,10 +133,13 @@ typedef struct {
* will be dispatched to a GCD dispatch_queue whose priority is determined by
* VkDeviceQueueCreateInfo::pQueuePriorities during vkCreateDevice().
*
* Initial value is set by the MVK_CONFIG_SYNCHRONOUS_QUEUE_SUBMITS build setting when MoltenVK
* is compiled. By default the MVK_CONFIG_SYNCHRONOUS_QUEUE_SUBMITS build setting is set to false,
* 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 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_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;
@ -146,8 +173,15 @@ typedef struct {
* 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.
*
* Initial value is set by the MVK_CONFIG_PREFILL_METAL_COMMAND_BUFFERS build setting when MoltenVK
* is compiled. By default the MVK_CONFIG_PREFILL_METAL_COMMAND_BUFFERS build setting is set to false.
* 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 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;
@ -159,10 +193,13 @@ typedef struct {
* is required per command buffer queue submission, which may be significantly less than the
* number of Vulkan command buffers.
*
* Initial value is set by the MVK_CONFIG_MAX_ACTIVE_METAL_COMMAND_BUFFERS_PER_POOL build setting
* when MoltenVK is compiled. By default the MVK_CONFIG_MAX_ACTIVE_METAL_COMMAND_BUFFERS_PER_POOL
* 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 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_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;
@ -174,9 +211,15 @@ typedef struct {
* 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.
*
* Initial value is set by the MVK_CONFIG_SUPPORT_LARGE_QUERY_POOLS build setting
* when MoltenVK is compiled. By default the MVK_CONFIG_SUPPORT_LARGE_QUERY_POOLS
* build setting is set to true.
* 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 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;
@ -184,8 +227,13 @@ typedef struct {
* 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.
*
* Initial value is set by the MVK_CONFIG_PRESENT_WITH_COMMAND_BUFFER build setting when MoltenVK
* is compiled. By default the MVK_CONFIG_PRESENT_WITH_COMMAND_BUFFER build setting is set to true.
* 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_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;
@ -197,9 +245,13 @@ typedef struct {
* 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.
*
* Initial value is set by the MVK_CONFIG_SWAPCHAIN_MAG_FILTER_USE_NEAREST build setting
* when MoltenVK is compiled. By default the MVK_CONFIG_SWAPCHAIN_MAG_FILTER_USE_NEAREST
* build setting is set to true.
* The value of this parameter may be changed before creating a VkSwapchain,
* for the change to take effect.
*
* 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;
@ -209,8 +261,13 @@ typedef struct {
* 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.
*
* Initial value is set by the MVK_CONFIG_METAL_COMPILE_TIMEOUT build setting when MoltenVK
* is compiled. By default the MVK_CONFIG_METAL_COMPILE_TIMEOUT build setting is infinite.
* 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_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;
@ -219,7 +276,13 @@ typedef struct {
* retrieved via the vkGetSwapchainPerformanceMVK() function, and various performance statistics
* 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;
@ -227,7 +290,13 @@ typedef struct {
* 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.
*
* 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;
@ -235,11 +304,116 @@ typedef struct {
* If enabled, a MoltenVK logo watermark will be rendered on top of the scene.
* This can be enabled for publicity during demos.
*
* Initial value is set by the MVK_CONFIG_DISPLAY_WATERMARK build setting when MoltenVK
* is compiled. By default the MVK_CONFIG_DISPLAY_WATERMARK build setting is set to false.
* 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_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;
/**
* 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;
/**
@ -253,7 +427,7 @@ typedef struct {
* for information about how to handle this.
*
* 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.
*/
typedef struct {
@ -293,7 +467,7 @@ typedef struct {
* information about how to handle this.
*
* 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.
*/
typedef struct {
@ -345,7 +519,7 @@ typedef struct {
* information about how to handle this.
*
* 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.
*/
typedef struct {

View File

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

View File

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

View File

@ -374,6 +374,13 @@ protected:
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
// a vector of bindings, and marks the bindings and the vector as no longer dirty.
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. */
void bindAuxBuffer(const MVKShaderAuxBufferBinding& binding, bool needVertexAuxBuffer, bool needFragmentAuxBuffer);
void bindAuxBuffer(const MVKShaderAuxBufferBinding& binding,
bool needVertexAuxBuffer,
bool needFragmentAuxBuffer);
#pragma mark Construction
@ -464,6 +468,9 @@ protected:
bool _areFragmentTextureBindingsDirty = false;
bool _areVertexSamplerStateBindingsDirty = false;
bool _areFragmentSamplerStateBindingsDirty = false;
bool _needsVertexSwizzle = false;
bool _needsFragmentSwizzle = false;
};
@ -485,7 +492,7 @@ public:
void bindSamplerState(const MVKMTLSamplerStateBinding& binding);
/** Sets the current auxiliary buffer state. */
void bindAuxBuffer(const MVKShaderAuxBufferBinding& binding);
void bindAuxBuffer(const MVKShaderAuxBufferBinding& binding, bool needAuxBuffer);
#pragma mark Construction
@ -506,6 +513,8 @@ protected:
bool _areBufferBindingsDirty = false;
bool _areTextureBindingsDirty = 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 MVKGraphicsResourcesCommandEncoderState
@ -410,11 +435,11 @@ void MVKGraphicsResourcesCommandEncoderState::bindFragmentBuffer(const MVKMTLBuf
}
void MVKGraphicsResourcesCommandEncoderState::bindVertexTexture(const MVKMTLTextureBinding& binding) {
bind(binding, _vertexTextureBindings, _areVertexTextureBindingsDirty);
bind(binding, _vertexTextureBindings, _areVertexTextureBindingsDirty, _needsVertexSwizzle);
}
void MVKGraphicsResourcesCommandEncoderState::bindFragmentTexture(const MVKMTLTextureBinding& binding) {
bind(binding, _fragmentTextureBindings, _areFragmentTextureBindingsDirty);
bind(binding, _fragmentTextureBindings, _areFragmentTextureBindingsDirty, _needsFragmentSwizzle);
}
void MVKGraphicsResourcesCommandEncoderState::bindVertexSamplerState(const MVKMTLSamplerStateBinding& binding) {
@ -425,7 +450,9 @@ void MVKGraphicsResourcesCommandEncoderState::bindFragmentSamplerState(const MVK
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.isDirty = needVertexAuxBuffer;
_fragmentAuxBufferBinding.index = binding.fragment;
@ -445,20 +472,6 @@ void MVKGraphicsResourcesCommandEncoderState::markDirty() {
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,
[](MVKCommandEncoder* cmdEncoder, MVKMTLBufferBinding& b)->void {
[cmdEncoder->_mtlRenderEncoder setVertexBuffer: b.mtlBuffer
@ -474,17 +487,33 @@ void MVKGraphicsResourcesCommandEncoderState::encodeImpl() {
});
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.size() * sizeof(uint32_t),
_vertexAuxBufferBinding.index);
}
} else {
assertMissingSwizzles(_needsVertexSwizzle, "vertex", _vertexTextureBindings);
}
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.size() * sizeof(uint32_t),
_fragmentAuxBufferBinding.index);
} else {
assertMissingSwizzles(_needsFragmentSwizzle, "fragment", _fragmentTextureBindings);
}
encodeBinding<MVKMTLTextureBinding>(_vertexTextureBindings, _areVertexTextureBindingsDirty,
@ -530,6 +559,9 @@ void MVKGraphicsResourcesCommandEncoderState::resetImpl() {
_areFragmentSamplerStateBindingsDirty = false;
_vertexAuxBufferBinding.isDirty = false;
_fragmentAuxBufferBinding.isDirty = false;
_needsVertexSwizzle = false;
_needsFragmentSwizzle = false;
}
@ -541,16 +573,17 @@ void MVKComputeResourcesCommandEncoderState::bindBuffer(const MVKMTLBufferBindin
}
void MVKComputeResourcesCommandEncoderState::bindTexture(const MVKMTLTextureBinding& binding) {
bind(binding, _textureBindings, _areTextureBindingsDirty);
bind(binding, _textureBindings, _areTextureBindingsDirty, _needsSwizzle);
}
void MVKComputeResourcesCommandEncoderState::bindSamplerState(const MVKMTLSamplerStateBinding& binding) {
bind(binding, _samplerStateBindings, _areSamplerStateBindingsDirty);
}
void MVKComputeResourcesCommandEncoderState::bindAuxBuffer(const MVKShaderAuxBufferBinding& binding) {
void MVKComputeResourcesCommandEncoderState::bindAuxBuffer(const MVKShaderAuxBufferBinding& binding,
bool needAuxBuffer) {
_auxBufferBinding.index = binding.compute;
_auxBufferBinding.isDirty = true;
_auxBufferBinding.isDirty = needAuxBuffer;
}
// Mark everything as dirty
@ -563,13 +596,6 @@ void MVKComputeResourcesCommandEncoderState::markDirty() {
void MVKComputeResourcesCommandEncoderState::encodeImpl() {
if (_auxBufferBinding.isDirty) {
for (auto& b : _textureBindings) {
if (b.isDirty)
updateSwizzle(_swizzleConstants, b.index, b.swizzle);
}
}
encodeBinding<MVKMTLBufferBinding>(_bufferBindings, _areBufferBindingsDirty,
[](MVKCommandEncoder* cmdEncoder, MVKMTLBufferBinding& b)->void {
[cmdEncoder->getMTLComputeEncoder(kMVKCommandUseDispatch) setBuffer: b.mtlBuffer
@ -578,10 +604,18 @@ void MVKComputeResourcesCommandEncoderState::encodeImpl() {
});
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.size() * sizeof(uint32_t),
_auxBufferBinding.index);
} else {
assertMissingSwizzles(_needsSwizzle, "compute", _textureBindings);
}
encodeBinding<MVKMTLTextureBinding>(_textureBindings, _areTextureBindingsDirty,
@ -607,6 +641,8 @@ void MVKComputeResourcesCommandEncoderState::resetImpl() {
_areTextureBindingsDirty = false;
_areSamplerStateBindingsDirty = false;
_auxBufferBinding.isDirty = false;
_needsSwizzle = false;
}

View File

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

View File

@ -442,10 +442,47 @@ VkResult MVKPhysicalDevice::getSurfacePresentModes(MVKSurface* surface,
#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,
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 ( !queueProperties ) {
@ -459,7 +496,7 @@ VkResult MVKPhysicalDevice::getQueueFamilyProperties(uint32_t* pCount,
// Now populate the queue families
if (queueProperties) {
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,
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 ( !queueProperties ) {
@ -484,7 +522,7 @@ VkResult MVKPhysicalDevice::getQueueFamilyProperties(uint32_t* pCount,
if (queueProperties) {
for (uint32_t qfIdx = 0; qfIdx < *pCount; qfIdx++) {
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
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. */
void MVKPhysicalDevice::initMetalFeatures() {
memset(&_metalFeatures, 0, sizeof(_metalFeatures)); // Start with everything cleared
@ -1272,33 +1321,6 @@ void MVKPhysicalDevice::logGPUInfo() {
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() {
mvkDestroyContainerContents(_queueFamilies);
[_mtlDevice release];
@ -1771,27 +1793,7 @@ uint32_t MVKDevice::expandVisibilityResultMTLBuffer(uint32_t queryCount) {
MVKDevice::MVKDevice(MVKPhysicalDevice* physicalDevice, const VkDeviceCreateInfo* pCreateInfo) {
initPerformanceTracking();
#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;
initPhysicalDevice(physicalDevice);
_globalVisibilityResultMTLBuffer = nil;
_globalVisibilityQueryCount = 0;
@ -1831,13 +1833,38 @@ void MVKDevice::initPerformanceTracking() {
_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
void MVKDevice::initQueues(const VkDeviceCreateInfo* pCreateInfo) {
vector<MVKQueueFamily*> qFams = _physicalDevice->getQueueFamilies();
uint32_t qrCnt = pCreateInfo->queueCreateInfoCount;
for (uint32_t qrIdx = 0; qrIdx < qrCnt; qrIdx++) {
const VkDeviceQueueCreateInfo* pQFInfo = &pCreateInfo->pQueueCreateInfos[qrIdx];
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
auto& queues = _queuesByQueueFamilyIndex[qfIdx];
for (uint32_t qIdx = 0; qIdx < pQFInfo->queueCount; qIdx++) {

View File

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

View File

@ -798,7 +798,7 @@ MVKImageView::MVKImageView(MVKDevice* device, const VkImageViewCreateInfo* pCrea
_mtlPixelFormat = getSwizzledMTLPixelFormat(pCreateInfo->format, pCreateInfo->components, useSwizzle);
_mtlTextureType = mvkMTLTextureTypeFromVkImageViewType(pCreateInfo->viewType, (_image->getSampleCount() != VK_SAMPLE_COUNT_1_BIT));
initMTLTextureViewSupport();
_packedSwizzle = useSwizzle ? packSwizzle(pCreateInfo->components) : 0;
_packedSwizzle = useSwizzle ? mvkPackSwizzle(pCreateInfo->components) : 0;
}
// Validate whether the image view configuration can be supported
@ -896,19 +896,6 @@ MTLPixelFormat MVKImageView::getSwizzledMTLPixelFormat(VkFormat format, VkCompon
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
// 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
@ -926,12 +913,6 @@ bool MVKImageView::matchesSwizzle(VkComponentMapping components, VkComponentMapp
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,
// and set the _useMTLTextureView variable appropriately.
void MVKImageView::initMTLTextureViewSupport() {

View File

@ -22,6 +22,7 @@
#include "MVKFoundation.h"
#include "MVKEnvironment.h"
#include "MVKSurface.h"
#include "MVKOSExtensions.h"
using namespace std;
@ -125,7 +126,10 @@ MVKInstance::MVKInstance(const VkInstanceCreateInfo* pCreateInfo) {
if (MVK_VULKAN_API_VERSION_CONFORM(MVK_VULKAN_API_VERSION) <
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
@ -338,31 +342,32 @@ void MVKInstance::initProcAddrs() {
}
void MVKInstance::logVersions() {
uint32_t buffLen = 32;
char mvkVer[buffLen];
char vkVer[buffLen];
vkGetVersionStringsMVK(mvkVer, buffLen, vkVer, buffLen);
string logMsg = "MoltenVK version %s. Vulkan version %s.";
logMsg += "\n\tThe following Vulkan extensions are supported:";
string logMsg = "MoltenVK version ";
logMsg += mvkGetMoltenVKVersionString(MVK_VERSION);
logMsg += ". Vulkan version ";
logMsg += mvkGetVulkanVersionString(MVK_VULKAN_API_VERSION);
logMsg += ".\n\tThe following Vulkan extensions are supported:";
logMsg += getDriverLayer()->getSupportedExtensions()->enabledNamesString("\n\t\t", true);
MVKLogInfo(logMsg.c_str(), mvkVer, vkVer);
MVKLogInfo("%s", logMsg.c_str());
}
// Init config.
void MVKInstance::initConfig() {
_mvkConfig.debugMode = MVK_DEBUG;
_mvkConfig.shaderConversionFlipVertexY = MVK_CONFIG_SHADER_CONVERSION_FLIP_VERTEX_Y;
_mvkConfig.synchronousQueueSubmits = MVK_CONFIG_SYNCHRONOUS_QUEUE_SUBMITS;
_mvkConfig.prefillMetalCommandBuffers = MVK_CONFIG_PREFILL_METAL_COMMAND_BUFFERS;
_mvkConfig.maxActiveMetalCommandBuffersPerQueue = MVK_CONFIG_MAX_ACTIVE_METAL_COMMAND_BUFFERS_PER_POOL;
_mvkConfig.supportLargeQueryPools = MVK_CONFIG_SUPPORT_LARGE_QUERY_POOLS;
_mvkConfig.presentWithCommandBuffer = MVK_CONFIG_PRESENT_WITH_COMMAND_BUFFER;
_mvkConfig.swapchainMagFilterUseNearest = MVK_CONFIG_SWAPCHAIN_MAG_FILTER_USE_NEAREST;
_mvkConfig.displayWatermark = MVK_CONFIG_DISPLAY_WATERMARK;
_mvkConfig.performanceTracking = MVK_DEBUG;
_mvkConfig.performanceLoggingFrameCount = MVK_DEBUG ? 300 : 0;
_mvkConfig.metalCompileTimeout = MVK_CONFIG_METAL_COMPILE_TIMEOUT;
MVK_SET_FROM_ENV_OR_BUILD_BOOL( _mvkConfig.debugMode, MVK_DEBUG);
MVK_SET_FROM_ENV_OR_BUILD_BOOL( _mvkConfig.shaderConversionFlipVertexY, MVK_CONFIG_SHADER_CONVERSION_FLIP_VERTEX_Y);
MVK_SET_FROM_ENV_OR_BUILD_BOOL( _mvkConfig.synchronousQueueSubmits, MVK_CONFIG_SYNCHRONOUS_QUEUE_SUBMITS);
MVK_SET_FROM_ENV_OR_BUILD_BOOL( _mvkConfig.prefillMetalCommandBuffers, MVK_CONFIG_PREFILL_METAL_COMMAND_BUFFERS);
MVK_SET_FROM_ENV_OR_BUILD_INT32(_mvkConfig.maxActiveMetalCommandBuffersPerQueue, MVK_CONFIG_MAX_ACTIVE_METAL_COMMAND_BUFFERS_PER_QUEUE);
MVK_SET_FROM_ENV_OR_BUILD_BOOL( _mvkConfig.supportLargeQueryPools, MVK_CONFIG_SUPPORT_LARGE_QUERY_POOLS);
MVK_SET_FROM_ENV_OR_BUILD_BOOL( _mvkConfig.presentWithCommandBuffer, MVK_CONFIG_PRESENT_WITH_COMMAND_BUFFER);
MVK_SET_FROM_ENV_OR_BUILD_BOOL( _mvkConfig.swapchainMagFilterUseNearest, MVK_CONFIG_SWAPCHAIN_MAG_FILTER_USE_NEAREST);
MVK_SET_FROM_ENV_OR_BUILD_INT64(_mvkConfig.metalCompileTimeout, MVK_CONFIG_METAL_COMPILE_TIMEOUT);
MVK_SET_FROM_ENV_OR_BUILD_BOOL( _mvkConfig.performanceTracking, MVK_CONFIG_PERFORMANCE_TRACKING);
MVK_SET_FROM_ENV_OR_BUILD_INT32(_mvkConfig.performanceLoggingFrameCount, MVK_CONFIG_PERFORMANCE_LOGGING_FRAME_COUNT);
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) {

View File

@ -35,18 +35,14 @@ class MVKPipelineCache;
#pragma mark -
#pragma mark MVKShaderAuxBufferBinding
#pragma mark MVKPipelineLayout
struct MVKShaderAuxBufferBinding {
uint32_t vertex;
uint32_t fragment;
uint32_t compute;
uint32_t vertex = 0;
uint32_t fragment = 0;
uint32_t compute = 0;
};
#pragma mark -
#pragma mark MVKPipelineLayout
/** Represents a Vulkan pipeline layout. */
class MVKPipelineLayout : public MVKBaseDeviceObject {
@ -129,12 +125,6 @@ public:
/** Returns whether this pipeline permits dynamic setting of the specifie 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). */
MVKGraphicsPipeline(MVKDevice* device,
MVKPipelineCache* pipelineCache,
@ -167,8 +157,8 @@ protected:
bool _dynamicStateEnabled[VK_DYNAMIC_STATE_RANGE_SIZE];
bool _hasDepthStencilInfo;
bool _needsVertexAuxBuffer;
bool _needsFragmentAuxBuffer;
bool _needsVertexAuxBuffer = false;
bool _needsFragmentAuxBuffer = false;
};
@ -183,9 +173,6 @@ public:
/** Binds this pipeline to the specified command encoder. */
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). */
MVKComputePipeline(MVKDevice* device,
MVKPipelineCache* pipelineCache,
@ -199,7 +186,7 @@ protected:
id<MTLComputePipelineState> _mtlPipelineState;
MTLSize _mtlThreadgroupSize;
bool _needsAuxBuffer;
bool _needsAuxBuffer = false;
};

View File

@ -138,7 +138,7 @@ MVKPipelineLayout::MVKPipelineLayout(MVKDevice* device,
_pushConstants.push_back(pCreateInfo->pPushConstantRanges[i]);
}
// Set auxiliary buffer offsets
// Set auxiliary buffer indices
_auxBufferIndex.vertex = _pushConstantsMTLResourceIndexes.vertexStage.bufferIndex + 1;
_auxBufferIndex.fragment = _pushConstantsMTLResourceIndexes.fragmentStage.bufferIndex + 1;
_auxBufferIndex.compute = _pushConstantsMTLResourceIndexes.computeStage.bufferIndex + 1;
@ -307,9 +307,6 @@ MTLRenderPipelineDescriptor* MVKGraphicsPipeline::getMTLRenderPipelineDescriptor
SPIRVToMSLConverterContext shaderContext;
initMVKShaderConverterContext(shaderContext, pCreateInfo);
auto* mvkLayout = (MVKPipelineLayout*)pCreateInfo->layout;
_auxBufferIndex = mvkLayout->getAuxBufferIndex();
// Retrieve the render subpass for which this pipeline is being constructed
MVKRenderPass* mvkRendPass = (MVKRenderPass*)pCreateInfo->renderPass;
MVKRenderSubpass* mvkRenderSubpass = mvkRendPass->getSubpass(pCreateInfo->subpass);
@ -318,7 +315,7 @@ MTLRenderPipelineDescriptor* MVKGraphicsPipeline::getMTLRenderPipelineDescriptor
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++) {
const VkPipelineShaderStageCreateInfo* pSS = &pCreateInfo->pStages[i];
if (mvkAreFlagsEnabled(pSS->stage, VK_SHADER_STAGE_VERTEX_BIT)) {
@ -327,7 +324,7 @@ MTLRenderPipelineDescriptor* MVKGraphicsPipeline::getMTLRenderPipelineDescriptor
shaderContext.options.entryPointName = pSS->pName;
id<MTLFunction> mtlFunction = ((MVKShaderModule*)pSS->module)->getMTLFunction(&shaderContext, pSS->pSpecializationInfo, _pipelineCache).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;
}
plDesc.vertexFunction = mtlFunction;
@ -350,7 +347,7 @@ MTLRenderPipelineDescriptor* MVKGraphicsPipeline::getMTLRenderPipelineDescriptor
shaderContext.options.entryPointName = pSS->pName;
id<MTLFunction> mtlFunction = ((MVKShaderModule*)pSS->module)->getMTLFunction(&shaderContext, pSS->pSpecializationInfo, _pipelineCache).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;
_needsFragmentAuxBuffer = shaderContext.options.needsAuxBuffer;
@ -482,10 +479,12 @@ void MVKGraphicsPipeline::initMVKShaderConverterContext(SPIRVToMSLConverterConte
MVKPipelineLayout* layout = (MVKPipelineLayout*)pCreateInfo->layout;
layout->populateShaderConverterContext(shaderContext);
_auxBufferIndex = layout->getAuxBufferIndex();
shaderContext.options.isRenderingPoints = isRenderingPoints(pCreateInfo);
shaderContext.options.isRasterizationDisabled = (pCreateInfo->pRasterizationState && (pCreateInfo->pRasterizationState->rasterizerDiscardEnable));
shaderContext.options.shouldFlipVertexY = _device->_pMVKConfig->shaderConversionFlipVertexY;
shaderContext.options.shouldSwizzleTextureSamples = _device->_pMVKConfig->fullImageViewSwizzle;
// Set the shader context vertex attribute information
shaderContext.vertexAttributes.clear();
@ -565,9 +564,7 @@ MVKGraphicsPipeline::~MVKGraphicsPipeline() {
void MVKComputePipeline::encode(MVKCommandEncoder* cmdEncoder) {
[cmdEncoder->getMTLComputeEncoder(kMVKCommandUseDispatch) setComputePipelineState: _mtlPipelineState];
cmdEncoder->_mtlThreadgroupSize = _mtlThreadgroupSize;
if (_needsAuxBuffer) {
cmdEncoder->_computeResourcesState.bindAuxBuffer(_auxBufferIndex);
}
cmdEncoder->_computeResourcesState.bindAuxBuffer(_auxBufferIndex, _needsAuxBuffer);
}
MVKComputePipeline::MVKComputePipeline(MVKDevice* device,
@ -584,7 +581,7 @@ MVKComputePipeline::MVKComputePipeline(MVKDevice* device,
setConfigurationResult(plc->getConfigurationResult());
plc->destroy();
} 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) {
@ -602,6 +599,7 @@ MVKMTLFunction MVKComputePipeline::getMTLFunction(const VkComputePipelineCreateI
shaderContext.options.entryPointName = pCreateInfo->stage.pName;
shaderContext.options.entryPointStage = spv::ExecutionModelGLCompute;
shaderContext.options.mslVersion = _device->_pMetalFeatures->mslVersion;
shaderContext.options.shouldSwizzleTextureSamples = _device->_pMVKConfig->fullImageViewSwizzle;
MVKPipelineLayout* layout = (MVKPipelineLayout*)pCreateInfo->layout;
layout->populateShaderConverterContext(shaderContext);
@ -609,12 +607,11 @@ MVKMTLFunction MVKComputePipeline::getMTLFunction(const VkComputePipelineCreateI
shaderContext.options.auxBufferIndex = _auxBufferIndex.compute;
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;
return func;
}
MVKComputePipeline::~MVKComputePipeline() {
[_mtlPipelineState release];
}
@ -682,6 +679,7 @@ namespace mvk {
opt.auxBufferIndex,
opt.shouldFlipVertexY,
opt.isRenderingPoints,
opt.shouldSwizzleTextureSamples,
opt.isRasterizationDisabled,
opt.needsAuxBuffer);
}

View File

@ -19,6 +19,8 @@
#pragma once
#include "mvk_vulkan.h"
#include "MVKFoundation.h"
#include <string>
#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 MTLDevice

View File

@ -44,9 +44,9 @@
# define MVK_CONFIG_SHADER_CONVERSION_FLIP_VERTEX_Y 1
#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
# define MVK_CONFIG_SYNCHRONOUS_QUEUE_SUBMITS 0
# define MVK_CONFIG_SYNCHRONOUS_QUEUE_SUBMITS 1
#endif
/** 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
* active per Vulkan queue. Default is Metal's default value of 64.
*/
#ifndef MVK_CONFIG_MAX_ACTIVE_METAL_COMMAND_BUFFERS_PER_POOL
# define MVK_CONFIG_MAX_ACTIVE_METAL_COMMAND_BUFFERS_PER_POOL 64
#ifndef MVK_CONFIG_MAX_ACTIVE_METAL_COMMAND_BUFFERS_PER_QUEUE
# define MVK_CONFIG_MAX_ACTIVE_METAL_COMMAND_BUFFERS_PER_QUEUE 64
#endif
/** Support more than 8192 occlusion queries per buffer. Enabled by default. */
@ -77,16 +77,42 @@
# define MVK_CONFIG_SWAPCHAIN_MAG_FILTER_USE_NEAREST 1
#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. */
#ifndef MVK_CONFIG_DISPLAY_WATERMARK
# define MVK_CONFIG_DISPLAY_WATERMARK 0
#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
/** Advertise specialized queue families. Disabled by default. */
#ifndef MVK_CONFIG_SPECIALIZED_QUEUE_FAMILIES
# define MVK_CONFIG_SPECIALIZED_QUEUE_FAMILIES 0
#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.
*

View File

@ -19,45 +19,59 @@
#include "MVKFoundation.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) {
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_RESULT(VK_ERROR_OUT_OF_DEVICE_MEMORY)
CASE_RESULT(VK_ERROR_INITIALIZATION_FAILED)
CASE_RESULT(VK_ERROR_DEVICE_LOST)
CASE_RESULT(VK_ERROR_MEMORY_MAP_FAILED)
CASE_RESULT(VK_ERROR_LAYER_NOT_PRESENT)
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_STRINGIFY(VK_SUCCESS);
CASE_STRINGIFY(VK_NOT_READY);
CASE_STRINGIFY(VK_TIMEOUT);
CASE_STRINGIFY(VK_EVENT_SET);
CASE_STRINGIFY(VK_EVENT_RESET);
CASE_STRINGIFY(VK_INCOMPLETE);
CASE_RESULT(VK_ERROR_SURFACE_LOST_KHR)
CASE_RESULT(VK_ERROR_NATIVE_WINDOW_IN_USE_KHR)
CASE_RESULT(VK_SUBOPTIMAL_KHR)
CASE_RESULT(VK_ERROR_OUT_OF_DATE_KHR)
CASE_RESULT(VK_ERROR_INCOMPATIBLE_DISPLAY_KHR)
CASE_STRINGIFY(VK_ERROR_OUT_OF_HOST_MEMORY);
CASE_STRINGIFY(VK_ERROR_OUT_OF_DEVICE_MEMORY);
CASE_STRINGIFY(VK_ERROR_INITIALIZATION_FAILED);
CASE_STRINGIFY(VK_ERROR_DEVICE_LOST);
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_RESULT(VK_ERROR_INVALID_SHADER_NV)
CASE_STRINGIFY(VK_ERROR_SURFACE_LOST_KHR);
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_RESULT(VK_ERROR_INVALID_EXTERNAL_HANDLE)
CASE_STRINGIFY(VK_ERROR_VALIDATION_FAILED_EXT);
CASE_STRINGIFY(VK_ERROR_INVALID_SHADER_NV);
default:
sprintf(name, "UNKNOWN_VkResult(%d)", vkResult);
return name;
CASE_STRINGIFY(VK_ERROR_OUT_OF_POOL_MEMORY);
CASE_STRINGIFY(VK_ERROR_INVALID_EXTERNAL_HANDLE);
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_start(args, errFmt);
char vkRsltName[MVKResultNameMaxLen];
mvkResultName(vkErr, vkRsltName);
// Prepend the error code to the format string
const char* vkRsltName = mvkVkResultName(vkErr);
char fmtStr[strlen(vkRsltName) + strlen(errFmt) + 4];
sprintf(fmtStr, "%s: %s", vkRsltName, errFmt);

View File

@ -23,6 +23,7 @@
#include "mvk_vulkan.h"
#include "MVKLogging.h"
#include <algorithm>
#include <string>
#include <simd/simd.h>
@ -100,13 +101,33 @@ typedef enum {
kMVKCommandUseDispatch, /**< vkCmdDispatch. */
} MVKCommandUse;
/**
* Copies the name of the specified VkResult code to the specified string.
*
* Returns a pointer to that string.
*/
#define MVKResultNameMaxLen 64
char* mvkResultName(VkResult vkResult, char* name);
/** Returns the name of the result value. */
const char* mvkVkResultName(VkResult vkResult);
/** Returns the name of the component swizzle. */
const char* mvkVkComponentSwizzleName(VkComponentSwizzle swizzle);
/** 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:
@ -260,6 +281,22 @@ static inline VkOffset3D mvkVkOffset3DDifference(VkOffset3D minuend, VkOffset3D
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 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_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_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_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_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, 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_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_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_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, 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 ),
// 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,
uint32_t arraySize,
bool isMultisample) {

View File

@ -92,30 +92,20 @@ MVK_PUBLIC_SYMBOL VkResult vkGetPerformanceStatisticsMVK(
}
MVK_PUBLIC_SYMBOL void vkGetVersionStringsMVK(
char* pMoltenVersionStringBuffer,
uint32_t moltenVersionStringBufferLength,
char* pVulkanVersionStringBuffer,
uint32_t vulkanVersionStringBufferLength) {
char* pMoltenVersionStringBuffer,
uint32_t moltenVersionStringBufferLength,
char* pVulkanVersionStringBuffer,
uint32_t vulkanVersionStringBufferLength) {
size_t len;
size_t len;
string mvkVer;
mvkVer += to_string(MVK_VERSION / 10000);
mvkVer += ".";
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 mvkVer = mvkGetMoltenVKVersionString(MVK_VERSION);
len = mvkVer.copy(pMoltenVersionStringBuffer, moltenVersionStringBufferLength - 1);
pMoltenVersionStringBuffer[len] = 0; // terminator
string vkVer;
vkVer += to_string(VK_VERSION_MAJOR(MVK_VULKAN_API_VERSION));
vkVer += ".";
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
string vkVer = mvkGetVulkanVersionString(MVK_VULKAN_API_VERSION);
len = vkVer.copy(pVulkanVersionStringBuffer, vulkanVersionStringBufferLength - 1);
pVulkanVersionStringBuffer[len] = 0; // terminator
}
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 (!!shouldFlipVertexY != !!other.shouldFlipVertexY) { return false; }
if (!!isRenderingPoints != !!other.isRenderingPoints) { return false; }
if (!!shouldSwizzleTextureSamples != !!other.shouldSwizzleTextureSamples) { return false; }
if (entryPointName != other.entryPointName) { return false; }
return true;
}
@ -237,7 +238,8 @@ MVK_PUBLIC_SYMBOL bool SPIRVToMSLConverter::convert(SPIRVToMSLConverterContext&
mslOpts.aux_buffer_index = context.options.auxBufferIndex;
mslOpts.enable_point_size_builtin = context.options.isRenderingPoints;
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);
auto scOpts = pMSLCompiler->get_common_options();

View File

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