From e959b9d9a6a013a751f1110b831ebf37a917c5e2 Mon Sep 17 00:00:00 2001 From: Bill Hollings Date: Wed, 27 Jun 2018 18:03:30 -0400 Subject: [PATCH 1/2] Support larger VkBufferViews by using 2D Metal textures. Map 1D buffer view contents to 2D Metal texture. Add MVKPhysicalDeviceMetalFeatures::maxTextureDimension element. Set VkPhysicalDeviceLimits::maxTexelBufferElements to maxTextureDimension ^ 2. Shaders accessing buffer view use special function to map 1D buffer view coordinates to 2D Metal texture coordinates. Pass maxTextureDimension to shader. Update to latest SPIRV-Cross version for appropriate shaders. Update MoltenVK version to 1.0.13. --- ExternalRevisions/SPIRV-Cross_repo_revision | 2 +- MoltenVK/MoltenVK/API/vk_mvk_moltenvk.h | 3 +- MoltenVK/MoltenVK/GPUObjects/MVKBuffer.h | 19 ++------ MoltenVK/MoltenVK/GPUObjects/MVKBuffer.mm | 29 +++++++----- MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm | 46 ++++++++----------- MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm | 2 + .../SPIRVToMSLConverter.cpp | 2 + .../SPIRVToMSLConverter.h | 1 + .../MoltenVKShaderConverter.xcscheme | 2 +- 9 files changed, 47 insertions(+), 59 deletions(-) diff --git a/ExternalRevisions/SPIRV-Cross_repo_revision b/ExternalRevisions/SPIRV-Cross_repo_revision index 65d2cf6b..0f1794a3 100644 --- a/ExternalRevisions/SPIRV-Cross_repo_revision +++ b/ExternalRevisions/SPIRV-Cross_repo_revision @@ -1 +1 @@ -e59cc244958af6059f7bd1d16d833e17409dec37 +d67e586b2e16a46a5cc1515093e8a04bff31c594 diff --git a/MoltenVK/MoltenVK/API/vk_mvk_moltenvk.h b/MoltenVK/MoltenVK/API/vk_mvk_moltenvk.h index c9e762cd..2a484e2d 100644 --- a/MoltenVK/MoltenVK/API/vk_mvk_moltenvk.h +++ b/MoltenVK/MoltenVK/API/vk_mvk_moltenvk.h @@ -48,7 +48,7 @@ extern "C" { */ #define MVK_VERSION_MAJOR 1 #define MVK_VERSION_MINOR 0 -#define MVK_VERSION_PATCH 12 +#define MVK_VERSION_PATCH 13 #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) @@ -87,6 +87,7 @@ typedef struct { VkBool32 texelBuffers; /**< If true, texel buffers are supported, allowing the contents of a buffer to be interpreted as an image via a VkBufferView. */ VkBool32 depthClipMode; /**< If true, the device supports both depth clipping and depth clamping per the depthClampEnable flag of VkPipelineRasterizationStateCreateInfo in VkGraphicsPipelineCreateInfo. */ VkBool32 presentModeImmediate; /**< If true, the device supports immediate surface present mode (VK_PRESENT_MODE_IMMEDIATE_KHR), allowing a swapchain image to be presented immediately, without waiting for the vertical sync period of the display. */ + uint32_t maxTextureDimension; /**< The maximum size of each texture dimension (width, height, or depth). */ uint32_t maxPerStageBufferCount; /**< The total number of per-stage Metal buffers available for shader uniform content and attributes. */ uint32_t maxPerStageTextureCount; /**< The total number of per-stage Metal textures available for shader uniform content. */ uint32_t maxPerStageSamplerCount; /**< The total number of per-stage Metal samplers available for shader uniform content. */ diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKBuffer.h b/MoltenVK/MoltenVK/GPUObjects/MVKBuffer.h index 369ed4a6..5bf52522 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKBuffer.h +++ b/MoltenVK/MoltenVK/GPUObjects/MVKBuffer.h @@ -85,21 +85,8 @@ class MVKBufferView : public MVKBaseDeviceObject { public: - -#pragma mark Resource memory - - /** Returns the number of bytes used by this buffer view. */ - inline VkDeviceSize getByteCount() { return _byteCount; }; - - #pragma mark Metal - /** Returns the Metal buffer underlying this memory allocation. */ - inline id getMTLBuffer() { return _buffer->getMTLBuffer(); } - - /** Returns the offset at which the contents of this instance starts within the underlying Metal buffer. */ - inline NSUInteger getMTLBufferOffset() { return _mtlBufferOffset; } - /** Returns a Metal texture that overlays this buffer view. */ id getMTLTexture(); @@ -112,10 +99,10 @@ public: protected: MVKBuffer* _buffer; + id _mtlTexture; + MTLPixelFormat _mtlPixelFormat; NSUInteger _mtlBufferOffset; - MTLPixelFormat _mtlPixelFormat; - id _mtlTexture; - VkDeviceSize _byteCount; + NSUInteger _mtlBytesPerRow; VkExtent2D _textureSize; std::mutex _lock; }; diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKBuffer.mm b/MoltenVK/MoltenVK/GPUObjects/MVKBuffer.mm index ed71b3f3..67b3b538 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKBuffer.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKBuffer.mm @@ -111,15 +111,13 @@ id MVKBufferView::getMTLTexture() { lock_guard lock(_lock); if (_mtlTexture) { return _mtlTexture; } - VkDeviceSize byteAlign = _device->_pProperties->limits.minTexelBufferOffsetAlignment; - NSUInteger mtlByteCnt = mvkAlignByteOffset(_byteCount, byteAlign); MTLTextureDescriptor* mtlTexDesc = [MTLTextureDescriptor texture2DDescriptorWithPixelFormat: _mtlPixelFormat width: _textureSize.width height: _textureSize.height mipmapped: NO]; - _mtlTexture = [getMTLBuffer() newTextureWithDescriptor: mtlTexDesc - offset: _mtlBufferOffset - bytesPerRow: mtlByteCnt]; + _mtlTexture = [_buffer->getMTLBuffer() newTextureWithDescriptor: mtlTexDesc + offset: _mtlBufferOffset + bytesPerRow: _mtlBytesPerRow]; } return _mtlTexture; } @@ -131,18 +129,25 @@ MVKBufferView::MVKBufferView(MVKDevice* device, const VkBufferViewCreateInfo* pC _buffer = (MVKBuffer*)pCreateInfo->buffer; _mtlBufferOffset = _buffer->getMTLBufferOffset() + pCreateInfo->offset; _mtlPixelFormat = mtlPixelFormatFromVkFormat(pCreateInfo->format); - _mtlTexture = nil; VkExtent2D fmtBlockSize = mvkVkFormatBlockTexelSize(pCreateInfo->format); // Pixel size of format size_t bytesPerBlock = mvkVkFormatBytesPerBlock(pCreateInfo->format); + _mtlTexture = nil; // Layout texture as a 1D array of texel blocks (which are texels for non-compressed textures) that covers the bytes - _byteCount = pCreateInfo->range; - if (_byteCount == VK_WHOLE_SIZE) { _byteCount = _buffer->getByteCount() - _mtlBufferOffset; } // Remaining bytes in buffer - size_t blockCount = _byteCount / bytesPerBlock; - _byteCount = blockCount * bytesPerBlock; // Round down + VkDeviceSize byteCount = pCreateInfo->range; + if (byteCount == VK_WHOLE_SIZE) { byteCount = _buffer->getByteCount() - _mtlBufferOffset; } // Remaining bytes in buffer + size_t blockCount = byteCount / bytesPerBlock; - _textureSize.width = (uint32_t)blockCount * fmtBlockSize.width; - _textureSize.height = fmtBlockSize.height; + // But Metal requires the texture to be a 2D texture. Determine the number of 2D rows we need and their width. + size_t maxBlocksPerRow = _device->_pMetalFeatures->maxTextureDimension / fmtBlockSize.width; + size_t blocksPerRow = min(blockCount, maxBlocksPerRow); + _mtlBytesPerRow = mvkAlignByteOffset(blocksPerRow * bytesPerBlock, _device->_pProperties->limits.minTexelBufferOffsetAlignment); + + size_t rowCount = blockCount / blocksPerRow; + if (blockCount % blocksPerRow) { rowCount++; } + + _textureSize.width = uint32_t(blocksPerRow * fmtBlockSize.width); + _textureSize.height = uint32_t(rowCount * fmtBlockSize.height); if ( !_device->_pMetalFeatures->texelBuffers ) { setConfigurationResult(mvkNotifyErrorWithText(VK_ERROR_FEATURE_NOT_PRESENT, "Texel buffers are not supported on this device.")); diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm index 470a1563..e18a65bd 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm @@ -319,16 +319,12 @@ void MVKPhysicalDevice::initMetalFeatures() { _metalFeatures.mtlBufferAlignment = 64; _metalFeatures.mtlCopyBufferAlignment = 1; _metalFeatures.texelBuffers = true; - - if ( [_mtlDevice supportsFeatureSet: MTLFeatureSet_iOS_GPUFamily3_v1] ) { - _metalFeatures.indirectDrawing = true; - _metalFeatures.baseVertexInstanceDrawing = true; - _metalFeatures.mtlBufferAlignment = 16; // Min float4 alignment for typical vertex buffers. MTLBuffer may go down to 4 bytes for other data. - } + _metalFeatures.maxTextureDimension = (4 * KIBI); if ( [_mtlDevice supportsFeatureSet: MTLFeatureSet_iOS_GPUFamily1_v2] ) { _metalFeatures.mslVersion = SPIRVToMSLConverterOptions::makeMSLVersion(1, 1); _metalFeatures.dynamicMTLBuffers = true; + _metalFeatures.maxTextureDimension = (8 * KIBI); } if ( [_mtlDevice supportsFeatureSet: MTLFeatureSet_iOS_GPUFamily1_v3] ) { _metalFeatures.mslVersion = SPIRVToMSLConverterOptions::makeMSLVersion(1, 2); @@ -341,6 +337,13 @@ void MVKPhysicalDevice::initMetalFeatures() { if ( [_mtlDevice supportsFeatureSet: MTLFeatureSet_iOS_GPUFamily2_v4] ) { _metalFeatures.depthClipMode = true; } + + if ( [_mtlDevice supportsFeatureSet: MTLFeatureSet_iOS_GPUFamily3_v1] ) { + _metalFeatures.indirectDrawing = true; + _metalFeatures.baseVertexInstanceDrawing = true; + _metalFeatures.mtlBufferAlignment = 16; // Min float4 alignment for typical vertex buffers. MTLBuffer may go down to 4 bytes for other data. + _metalFeatures.maxTextureDimension = (16 * KIBI); + } #endif #if MVK_MACOS @@ -352,6 +355,7 @@ void MVKPhysicalDevice::initMetalFeatures() { _metalFeatures.baseVertexInstanceDrawing = true; _metalFeatures.ioSurfaces = true; _metalFeatures.depthClipMode = true; + _metalFeatures.maxTextureDimension = (16 * KIBI); if ( [_mtlDevice supportsFeatureSet: MTLFeatureSet_macOS_GPUFamily1_v2] ) { _metalFeatures.mslVersion = SPIRVToMSLConverterOptions::makeMSLVersion(1, 2); @@ -513,29 +517,15 @@ void MVKPhysicalDevice::initProperties() { _properties.limits.sampledImageStencilSampleCounts = _metalFeatures.supportedSampleCounts; _properties.limits.storageImageSampleCounts = _metalFeatures.supportedSampleCounts; - uint32_t maxTextureDimension; -#if MVK_IOS - if ( [_mtlDevice supportsFeatureSet: MTLFeatureSet_iOS_GPUFamily3_v1] ) { - maxTextureDimension = (16 * KIBI); - } else if ( [_mtlDevice supportsFeatureSet: MTLFeatureSet_iOS_GPUFamily1_v2] ) { - maxTextureDimension = (8 * KIBI); - } else { - maxTextureDimension = (4 * KIBI); - } -#endif -#if MVK_MACOS - maxTextureDimension = (16 * KIBI); -#endif - - _properties.limits.maxImageDimension1D = maxTextureDimension; - _properties.limits.maxImageDimension2D = maxTextureDimension; - _properties.limits.maxImageDimensionCube = maxTextureDimension; - _properties.limits.maxFramebufferWidth = maxTextureDimension; - _properties.limits.maxFramebufferHeight = maxTextureDimension; + _properties.limits.maxImageDimension1D = _metalFeatures.maxTextureDimension; + _properties.limits.maxImageDimension2D = _metalFeatures.maxTextureDimension; + _properties.limits.maxImageDimensionCube = _metalFeatures.maxTextureDimension; + _properties.limits.maxFramebufferWidth = _metalFeatures.maxTextureDimension; + _properties.limits.maxFramebufferHeight = _metalFeatures.maxTextureDimension; _properties.limits.maxFramebufferLayers = 256; - _properties.limits.maxViewportDimensions[0] = maxTextureDimension; - _properties.limits.maxViewportDimensions[1] = maxTextureDimension; + _properties.limits.maxViewportDimensions[0] = _metalFeatures.maxTextureDimension; + _properties.limits.maxViewportDimensions[1] = _metalFeatures.maxTextureDimension; float maxVPDim = max(_properties.limits.maxViewportDimensions[0], _properties.limits.maxViewportDimensions[1]); _properties.limits.viewportBoundsRange[0] = (-2.0 * maxVPDim); _properties.limits.viewportBoundsRange[1] = (2.0 * maxVPDim) - 1; @@ -569,7 +559,7 @@ void MVKPhysicalDevice::initProperties() { _properties.limits.maxDescriptorSetSampledImages = (_properties.limits.maxPerStageDescriptorSampledImages * 2); _properties.limits.maxDescriptorSetStorageImages = (_properties.limits.maxPerStageDescriptorStorageImages * 2); - _properties.limits.maxTexelBufferElements = (uint32_t)_metalFeatures.maxMTLBufferSize; + _properties.limits.maxTexelBufferElements = _properties.limits.maxImageDimension2D * _properties.limits.maxImageDimension2D; _properties.limits.maxUniformBufferRange = (uint32_t)_metalFeatures.maxMTLBufferSize; _properties.limits.maxStorageBufferRange = (uint32_t)_metalFeatures.maxMTLBufferSize; _properties.limits.maxPushConstantsSize = (4 * KIBI); diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm b/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm index e9c814a9..1a7dee94 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm @@ -357,6 +357,7 @@ void MVKGraphicsPipeline::initMVKShaderConverterContext(SPIRVToMSLConverterConte const VkGraphicsPipelineCreateInfo* pCreateInfo) { shaderContext.options.mslVersion = _device->_pMetalFeatures->mslVersion; + shaderContext.options.texelBufferTextureWidth = _device->_pMetalFeatures->maxTextureDimension; MVKPipelineLayout* layout = (MVKPipelineLayout*)pCreateInfo->layout; layout->populateShaderConverterContext(shaderContext); @@ -501,6 +502,7 @@ namespace mvk { archive(opt.entryPointName, opt.entryPointStage, opt.mslVersion, + opt.texelBufferTextureWidth, opt.shouldFlipVertexY, opt.isRenderingPoints); } diff --git a/MoltenVKShaderConverter/MoltenVKSPIRVToMSLConverter/SPIRVToMSLConverter.cpp b/MoltenVKShaderConverter/MoltenVKSPIRVToMSLConverter/SPIRVToMSLConverter.cpp index a39cc4ca..f1e3308d 100644 --- a/MoltenVKShaderConverter/MoltenVKSPIRVToMSLConverter/SPIRVToMSLConverter.cpp +++ b/MoltenVKShaderConverter/MoltenVKSPIRVToMSLConverter/SPIRVToMSLConverter.cpp @@ -41,6 +41,7 @@ bool contains(const vector& vec, const T& val) { MVK_PUBLIC_SYMBOL bool SPIRVToMSLConverterOptions::matches(const SPIRVToMSLConverterOptions& other) const { if (entryPointStage != other.entryPointStage) { return false; } if (mslVersion != other.mslVersion) { return false; } + if (texelBufferTextureWidth != other.texelBufferTextureWidth) { return false; } if (!!shouldFlipVertexY != !!other.shouldFlipVertexY) { return false; } if (!!isRenderingPoints != !!other.isRenderingPoints) { return false; } if (entryPointName != other.entryPointName) { return false; } @@ -199,6 +200,7 @@ MVK_PUBLIC_SYMBOL bool SPIRVToMSLConverter::convert(SPIRVToMSLConverterContext& #endif mslOpts.msl_version = context.options.mslVersion; + mslOpts.texel_buffer_texture_width = context.options.texelBufferTextureWidth; mslOpts.enable_point_size_builtin = context.options.isRenderingPoints; mslOpts.resolve_specialized_array_lengths = true; pMSLCompiler->set_msl_options(mslOpts); diff --git a/MoltenVKShaderConverter/MoltenVKSPIRVToMSLConverter/SPIRVToMSLConverter.h b/MoltenVKShaderConverter/MoltenVKSPIRVToMSLConverter/SPIRVToMSLConverter.h index c7b16e56..0106cde2 100644 --- a/MoltenVKShaderConverter/MoltenVKSPIRVToMSLConverter/SPIRVToMSLConverter.h +++ b/MoltenVKShaderConverter/MoltenVKSPIRVToMSLConverter/SPIRVToMSLConverter.h @@ -36,6 +36,7 @@ namespace mvk { spv::ExecutionModel entryPointStage = spv::ExecutionModelMax; uint32_t mslVersion = makeMSLVersion(2); + uint32_t texelBufferTextureWidth = 4096; bool shouldFlipVertexY = true; bool isRenderingPoints = false; diff --git a/MoltenVKShaderConverter/MoltenVKShaderConverter.xcodeproj/xcshareddata/xcschemes/MoltenVKShaderConverter.xcscheme b/MoltenVKShaderConverter/MoltenVKShaderConverter.xcodeproj/xcshareddata/xcschemes/MoltenVKShaderConverter.xcscheme index 6168219b..c3d1e188 100644 --- a/MoltenVKShaderConverter/MoltenVKShaderConverter.xcodeproj/xcshareddata/xcschemes/MoltenVKShaderConverter.xcscheme +++ b/MoltenVKShaderConverter/MoltenVKShaderConverter.xcodeproj/xcshareddata/xcschemes/MoltenVKShaderConverter.xcscheme @@ -75,7 +75,7 @@ isEnabled = "YES"> Date: Thu, 28 Jun 2018 14:07:58 -0400 Subject: [PATCH 2/2] Improve crispness of visuals on macOS Retina displays. Set CAMetalLayer magnificationFilter property to Nearest by default. Add MVKDeviceConfiguration::swapchainMagFilterUseNearest member to allow overrides. --- MoltenVK/MoltenVK/API/vk_mvk_moltenvk.h | 3 +- MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm | 1 + MoltenVK/MoltenVK/GPUObjects/MVKSwapchain.h | 1 + MoltenVK/MoltenVK/GPUObjects/MVKSwapchain.mm | 48 ++++++++++---------- 4 files changed, 28 insertions(+), 25 deletions(-) diff --git a/MoltenVK/MoltenVK/API/vk_mvk_moltenvk.h b/MoltenVK/MoltenVK/API/vk_mvk_moltenvk.h index 2a484e2d..d0df3e36 100644 --- a/MoltenVK/MoltenVK/API/vk_mvk_moltenvk.h +++ b/MoltenVK/MoltenVK/API/vk_mvk_moltenvk.h @@ -69,7 +69,8 @@ typedef struct { VkBool32 shaderConversionFlipVertexY; /**< If enabled, MSL vertex shader code created during Runtime Shader Conversion will flip the Y-axis of each vertex, as Vulkan coordinate system is inverse of OpenGL. Default is true. */ VkBool32 synchronousQueueSubmits; /**< If enabled, queue command submissions (vkQueueSubmit() & vkQueuePresentKHR()) will be processed on the thread that called the submission function. If disabled, processing will be dispatched to a GCD dispatch_queue whose priority is determined by VkDeviceQueueCreateInfo::pQueuePriorities during vkCreateDevice(). This setting affects how much command processing should be performed on the rendering thread, or offloaded to a secondary thread. Default value is false, and command processing will be handled on a prioritizable queue thread. */ VkBool32 supportLargeQueryPools; /**< Metal allows only 8192 occlusion queries per MTLBuffer. If enabled, MoltenVK allocates a MTLBuffer for each query pool, allowing each query pool to support 8192 queries, which may slow performance or cause unexpected behaviour if the query pool is not established prior to a Metal renderpass, or if the query pool is changed within a Metal renderpass. If disabled, one MTLBuffer will be shared by all query pools, which improves performance, but limits the total device queries to 8192. Default value is true. */ - VkBool32 presentWithCommandBuffer; /**< If enabled, each surface presentation is scheduled using a command buffer. Enabling this may improve rendering frame synchronization, but may result in reduced frame rates. Default value is false if the MVK_PRESENT_WITHOUT_COMMAND_BUFFER build setting is defined when MoltenVK is compiled, and true otherwise. By default the MVK_PRESENT_WITHOUT_COMMAND_BUFFER build setting is not defined and the value of this setting is true. */ + VkBool32 presentWithCommandBuffer; /**< 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. Default value is false if the MVK_PRESENT_WITHOUT_COMMAND_BUFFER build setting is defined when MoltenVK is compiled, and true otherwise. By default the MVK_PRESENT_WITHOUT_COMMAND_BUFFER build setting is not defined and the value of this setting is true. */ + VkBool32 swapchainMagFilterUseNearest; /**< If enabled, swapchain images will use simple Nearest sampling when magnifying the swapchain image to fit a physical display surface. If disabled, swapchain images will use Linear sampling when magnifying the swapchain image to fit a physical display surface. Enabling this setting avoids smearing effects when swapchain images are simple interger 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. Default value is true. */ VkBool32 displayWatermark; /**< If enabled, a MoltenVK logo watermark will be rendered on top of the scene. This can be enabled for publicity during demos. Default value is true if the MVK_DISPLAY_WATERMARK build setting is defined when MoltenVK is compiled, and false otherwise. By default the MVK_DISPLAY_WATERMARK build setting is not defined. */ VkBool32 performanceTracking; /**< If enabled, per-frame performance statistics are tracked, optionally logged, and can be retrieved via the vkGetSwapchainPerformanceMVK() function, and various performance statistics are tracked, logged, and can be retrieved via the vkGetPerformanceStatisticsMVK() function. Default value is true in the presence of the DEBUG build setting, and false otherwise. */ uint32_t performanceLoggingFrameCount; /**< 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. Default value is 300 in the presence of the DEBUG build setting, and zero otherwise. */ diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm index e18a65bd..a48259c2 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm @@ -1441,6 +1441,7 @@ MVKDevice::MVKDevice(MVKPhysicalDevice* physicalDevice, const VkDeviceCreateInfo pCfg->supportLargeQueryPools = true; pCfg->shaderConversionFlipVertexY = true; pCfg->presentWithCommandBuffer = MVK_PRESENT_WITH_COMMAND_BUFFER_BOOL; + pCfg->swapchainMagFilterUseNearest = true; pCfg->displayWatermark = MVK_DISPLAY_WATERMARK_BOOL; pCfg->performanceTracking = MVK_DEBUG; pCfg->performanceLoggingFrameCount = MVK_DEBUG ? 300 : 0; diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKSwapchain.h b/MoltenVK/MoltenVK/GPUObjects/MVKSwapchain.h index ceaa852f..77604e94 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKSwapchain.h +++ b/MoltenVK/MoltenVK/GPUObjects/MVKSwapchain.h @@ -87,6 +87,7 @@ public: protected: friend class MVKSwapchainImage; + void initCAMetalLayer(const VkSwapchainCreateInfoKHR* pCreateInfo); void initSurfaceImages(const VkSwapchainCreateInfoKHR* pCreateInfo); void initFrameIntervalTracking(); void releaseUndisplayedSurfaces(); diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKSwapchain.mm b/MoltenVK/MoltenVK/GPUObjects/MVKSwapchain.mm index 97d6b796..62d63911 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKSwapchain.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKSwapchain.mm @@ -183,36 +183,36 @@ MVKSwapchain::MVKSwapchain(MVKDevice* device, MVKSwapchain* oldSwapchain = (MVKSwapchain*)pCreateInfo->oldSwapchain; if (oldSwapchain) { oldSwapchain->releaseUndisplayedSurfaces(); } - // Get the layer underlying the surface view, which must be a CAMetalLayer. - MVKSurface* mvkSrfc = (MVKSurface*)pCreateInfo->surface; - _mtlLayer = mvkSrfc->getCAMetalLayer(); - _mtlLayer.device = getMTLDevice(); - _mtlLayer.pixelFormat = mtlPixelFormatFromVkFormat(pCreateInfo->imageFormat); - _mtlLayer.framebufferOnly = !mvkIsAnyFlagEnabled(pCreateInfo->imageUsage, (VK_IMAGE_USAGE_TRANSFER_SRC_BIT | - VK_IMAGE_USAGE_TRANSFER_DST_BIT | - VK_IMAGE_USAGE_SAMPLED_BIT | - VK_IMAGE_USAGE_STORAGE_BIT)); - - if (pCreateInfo->presentMode == VK_PRESENT_MODE_IMMEDIATE_KHR) { - _mtlLayer.displaySyncEnabledMVK = NO; - } else { - _mtlLayer.displaySyncEnabledMVK = YES; - } - - // TODO: set additional CAMetalLayer properties before extracting drawables: - // - presentsWithTransaction - // - maximumDrawableCount (maybe for MAILBOX?) - // - drawsAsynchronously - // - colorspace (macOS only) Vulkan only supports sRGB colorspace for now. - // - wantsExtendedDynamicRangeContent (macOS only) - + initCAMetalLayer(pCreateInfo); initSurfaceImages(pCreateInfo); initFrameIntervalTracking(); _licenseWatermark = NULL; } -/** Initializes the array of images used for the surfaces of this swapchain. */ +// Initializes the CAMetalLayer underlying the surface of this swapchain. +void MVKSwapchain::initCAMetalLayer(const VkSwapchainCreateInfoKHR* pCreateInfo) { + + MVKSurface* mvkSrfc = (MVKSurface*)pCreateInfo->surface; + _mtlLayer = mvkSrfc->getCAMetalLayer(); + _mtlLayer.device = getMTLDevice(); + _mtlLayer.pixelFormat = mtlPixelFormatFromVkFormat(pCreateInfo->imageFormat); + _mtlLayer.displaySyncEnabledMVK = (pCreateInfo->presentMode != VK_PRESENT_MODE_IMMEDIATE_KHR); + _mtlLayer.magnificationFilter = _device->_mvkConfig.swapchainMagFilterUseNearest ? kCAFilterNearest : kCAFilterLinear; + _mtlLayer.framebufferOnly = !mvkIsAnyFlagEnabled(pCreateInfo->imageUsage, (VK_IMAGE_USAGE_TRANSFER_SRC_BIT | + VK_IMAGE_USAGE_TRANSFER_DST_BIT | + VK_IMAGE_USAGE_SAMPLED_BIT | + VK_IMAGE_USAGE_STORAGE_BIT)); + + // TODO: set additional CAMetalLayer properties before extracting drawables: + // - presentsWithTransaction + // - maximumDrawableCount (maybe for MAILBOX?) + // - drawsAsynchronously + // - colorspace (macOS only) Vulkan only supports sRGB colorspace for now. + // - wantsExtendedDynamicRangeContent (macOS only) +} + +// Initializes the array of images used for the surface of this swapchain. void MVKSwapchain::initSurfaceImages(const VkSwapchainCreateInfoKHR* pCreateInfo) { _mtlLayerOrigDrawSize = _mtlLayer.updatedDrawableSizeMVK;