Merge branch 'master' into amd-gpu-shader-half-float
This commit is contained in:
commit
2450c890dd
@ -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*.
|
||||
|
@ -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
|
||||
---------------
|
||||
|
||||
|
@ -1 +1 @@
|
||||
ed16b3e69985feaf565efbecea70a1cc2fca2a58
|
||||
9e3a41ad00ca48b9119d805cd96f337984458fe7
|
||||
|
@ -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,
|
||||
|
@ -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 {
|
||||
|
@ -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) {
|
||||
|
@ -351,7 +351,7 @@ void MVKCommandEncoder::clearRenderArea() {
|
||||
}
|
||||
|
||||
void MVKCommandEncoder::finalizeDispatchState() {
|
||||
_computePipelineState.encode();
|
||||
_computePipelineState.encode(); // Must do first..it sets others
|
||||
_computeResourcesState.encode();
|
||||
_computePushConstants.encode();
|
||||
}
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
@ -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();
|
||||
|
@ -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++) {
|
||||
|
@ -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;
|
||||
|
@ -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() {
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
|
||||
|
@ -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.
|
||||
*
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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
|
||||
|
@ -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) {
|
||||
|
@ -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(
|
||||
|
@ -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();
|
||||
|
@ -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;
|
||||
|
Loading…
x
Reference in New Issue
Block a user