Retrieve linear image memory alignment requirements from Metal device.

Add mvkMTLPixelFormatLinearTextureAlignment() function.
Add MVKDevice::getVkFormatTexelBufferAlignment() and use for Linear image memory alignment.
For non-linear image memory alignment, use mvkVkFormatBytesPerBlock().
Rename MVKDevice::mtlPixelFormatFromVkFormat() to getMTLPixelFormatFromVkFormat().
This commit is contained in:
Bill Hollings 2018-12-08 14:09:53 -05:00
parent 231e39bd7f
commit f459bf34e3
10 changed files with 49 additions and 26 deletions

View File

@ -839,13 +839,13 @@ void MVKCmdClearAttachments::encode(MVKCommandEncoder* cmdEncoder) {
uint32_t caCnt = subpass->getColorAttachmentCount();
for (uint32_t caIdx = 0; caIdx < caCnt; caIdx++) {
VkFormat vkAttFmt = subpass->getColorAttachmentFormat(caIdx);
_rpsKey.attachmentMTLPixelFormats[caIdx] = cmdPool->mtlPixelFormatFromVkFormat(vkAttFmt);
_rpsKey.attachmentMTLPixelFormats[caIdx] = cmdPool->getMTLPixelFormatFromVkFormat(vkAttFmt);
MTLClearColor mtlCC = mvkMTLClearColorFromVkClearValue(_vkClearValues[caIdx], vkAttFmt);
_clearColors[caIdx] = { (float)mtlCC.red, (float)mtlCC.green, (float)mtlCC.blue, (float)mtlCC.alpha};
}
VkFormat vkAttFmt = subpass->getDepthStencilFormat();
MTLPixelFormat mtlAttFmt = cmdPool->mtlPixelFormatFromVkFormat(vkAttFmt);
MTLPixelFormat mtlAttFmt = cmdPool->getMTLPixelFormatFromVkFormat(vkAttFmt);
_rpsKey.attachmentMTLPixelFormats[kMVKAttachmentFormatDepthStencilIndex] = mtlAttFmt;
bool isClearingDepth = _isClearingDepth && mvkMTLPixelFormatIsDepthFormat(mtlAttFmt);
bool isClearingStencil = _isClearingStencil && mvkMTLPixelFormatIsStencilFormat(mtlAttFmt);

View File

@ -155,7 +155,7 @@ id<MTLTexture> MVKBufferView::getMTLTexture() {
MVKBufferView::MVKBufferView(MVKDevice* device, const VkBufferViewCreateInfo* pCreateInfo) : MVKRefCountedDeviceObject(device) {
_buffer = (MVKBuffer*)pCreateInfo->buffer;
_mtlBufferOffset = _buffer->getMTLBufferOffset() + pCreateInfo->offset;
_mtlPixelFormat = mtlPixelFormatFromVkFormat(pCreateInfo->format);
_mtlPixelFormat = getMTLPixelFormatFromVkFormat(pCreateInfo->format);
VkExtent2D fmtBlockSize = mvkVkFormatBlockTexelSize(pCreateInfo->format); // Pixel size of format
size_t bytesPerBlock = mvkVkFormatBytesPerBlock(pCreateInfo->format);
_mtlTexture = nil;
@ -166,9 +166,10 @@ MVKBufferView::MVKBufferView(MVKDevice* device, const VkBufferViewCreateInfo* pC
size_t blockCount = byteCount / bytesPerBlock;
// But Metal requires the texture to be a 2D texture. Determine the number of 2D rows we need and their width.
// Multiple rows will automatically align with PoT max texture dimension, but need to align upwards if less than full single row.
size_t maxBlocksPerRow = _device->_pMetalFeatures->maxTextureDimension / fmtBlockSize.width;
size_t blocksPerRow = min(blockCount, maxBlocksPerRow);
_mtlBytesPerRow = mvkAlignByteOffset(blocksPerRow * bytesPerBlock, _device->_pProperties->limits.minTexelBufferOffsetAlignment);
_mtlBytesPerRow = mvkAlignByteOffset(blocksPerRow * bytesPerBlock, _device->getVkFormatTexelBufferAlignment(pCreateInfo->format));
size_t rowCount = blockCount / blocksPerRow;
if (blockCount % blocksPerRow) { rowCount++; }

View File

@ -502,7 +502,10 @@ public:
*
* All other pixel formats are returned unchanged.
*/
MTLPixelFormat mtlPixelFormatFromVkFormat(VkFormat vkFormat);
MTLPixelFormat getMTLPixelFormatFromVkFormat(VkFormat vkFormat);
/** Returns the memory alignment required for the format when used in a texel buffer. */
VkDeviceSize getVkFormatTexelBufferAlignment(VkFormat format);
/**
* Returns the MTLBuffer used to hold occlusion query results,
@ -608,12 +611,12 @@ public:
* Returns the Metal MTLPixelFormat corresponding to the specified Vulkan VkFormat,
* or returns MTLPixelFormatInvalid if no corresponding MTLPixelFormat exists.
*
* This function delegates to the MVKDevice::mtlPixelFormatFromVkFormat() function.
* This function delegates to the MVKDevice::getMTLPixelFormatFromVkFormat() function.
* See the notes for that function for more information about how MTLPixelFormats
* are managed for each platform device.
*/
inline MTLPixelFormat mtlPixelFormatFromVkFormat(VkFormat vkFormat) {
return _device->mtlPixelFormatFromVkFormat(vkFormat);
inline MTLPixelFormat getMTLPixelFormatFromVkFormat(VkFormat vkFormat) {
return _device->getMTLPixelFormatFromVkFormat(vkFormat);
}
/** Constructs an instance for the specified device. */

View File

@ -1635,7 +1635,7 @@ uint32_t MVKDevice::getMetalBufferIndexForVertexAttributeBinding(uint32_t bindin
return ((_pMetalFeatures->maxPerStageBufferCount - 1) - binding);
}
MTLPixelFormat MVKDevice::mtlPixelFormatFromVkFormat(VkFormat vkFormat) {
MTLPixelFormat MVKDevice::getMTLPixelFormatFromVkFormat(VkFormat vkFormat) {
MTLPixelFormat mtlPixFmt = mvkMTLPixelFormatFromVkFormat(vkFormat);
#if MVK_MACOS
if (mtlPixFmt == MTLPixelFormatDepth24Unorm_Stencil8 &&
@ -1646,6 +1646,11 @@ MTLPixelFormat MVKDevice::mtlPixelFormatFromVkFormat(VkFormat vkFormat) {
return mtlPixFmt;
}
VkDeviceSize MVKDevice::getVkFormatTexelBufferAlignment(VkFormat format) {
VkDeviceSize deviceAlignment = mvkMTLPixelFormatLinearTextureAlignment(getMTLPixelFormatFromVkFormat(format), getMTLDevice());
return deviceAlignment ? deviceAlignment : _pProperties->limits.minTexelBufferOffsetAlignment;
}
id<MTLBuffer> MVKDevice::getGlobalVisibilityResultMTLBuffer() {
lock_guard<mutex> lock(_vizLock);
return _globalVisibilityResultMTLBuffer;

View File

@ -480,8 +480,6 @@ void MVKImage::getMTLTextureContent(MVKImageSubresource& subresource,
MVKImage::MVKImage(MVKDevice* device, const VkImageCreateInfo* pCreateInfo) : MVKResource(device) {
_byteAlignment = _device->_pProperties->limits.minTexelBufferOffsetAlignment;
if (pCreateInfo->flags & VK_IMAGE_CREATE_BLOCK_TEXEL_VIEW_COMPATIBLE_BIT) {
mvkNotifyErrorWithText(VK_ERROR_FEATURE_NOT_PRESENT, "vkCreateImage() : Metal may not allow uncompressed views of compressed images.");
}
@ -508,7 +506,7 @@ MVKImage::MVKImage(MVKDevice* device, const VkImageCreateInfo* pCreateInfo) : MV
_mtlTexture = nil;
_ioSurface = nil;
_mtlPixelFormat = mtlPixelFormatFromVkFormat(pCreateInfo->format);
_mtlPixelFormat = getMTLPixelFormatFromVkFormat(pCreateInfo->format);
_mtlTextureType = mvkMTLTextureTypeFromVkImageType(pCreateInfo->imageType,
_arrayLayers,
(pCreateInfo->samples > 1));
@ -529,6 +527,8 @@ MVKImage::MVKImage(MVKDevice* device, const VkImageCreateInfo* pCreateInfo) : MV
_isLinear = validateLinear(pCreateInfo);
_usesTexelBuffer = false;
_byteAlignment = _isLinear ? _device->getVkFormatTexelBufferAlignment(pCreateInfo->format) : mvkVkFormatBytesPerBlock(pCreateInfo->format);
// Calc _byteCount after _mtlTexture & _byteAlignment
for (uint32_t mipLvl = 0; mipLvl < _mipLevels; mipLvl++) {
_byteCount += getBytesPerLayer(mipLvl) * _extent.depth * _arrayLayers;
@ -754,7 +754,7 @@ void MVKImageView::validateImageViewConfig(const VkImageViewCreateInfo* pCreateI
// alignments of existing MTLPixelFormats of the same structure. If swizzling is not possible for a
// particular combination of format and swizzle spec, the original MTLPixelFormat is returned.
MTLPixelFormat MVKImageView::getSwizzledMTLPixelFormat(VkFormat format, VkComponentMapping components, bool& useSwizzle) {
MTLPixelFormat mtlPF = mtlPixelFormatFromVkFormat(format);
MTLPixelFormat mtlPF = getMTLPixelFormatFromVkFormat(format);
useSwizzle = false;
switch (mtlPF) {

View File

@ -412,7 +412,7 @@ MTLRenderPipelineDescriptor* MVKGraphicsPipeline::getMTLRenderPipelineDescriptor
const VkPipelineColorBlendAttachmentState* pCA = &pCreateInfo->pColorBlendState->pAttachments[caIdx];
MTLRenderPipelineColorAttachmentDescriptor* colorDesc = plDesc.colorAttachments[caIdx];
colorDesc.pixelFormat = mtlPixelFormatFromVkFormat(mvkRenderSubpass->getColorAttachmentFormat(caIdx));
colorDesc.pixelFormat = getMTLPixelFormatFromVkFormat(mvkRenderSubpass->getColorAttachmentFormat(caIdx));
colorDesc.writeMask = mvkMTLColorWriteMaskFromVkChannelFlags(pCA->colorWriteMask);
// Don't set the blend state if we're not using this attachment.
// The pixel format will be MTLPixelFormatInvalid in that case, and
@ -431,7 +431,7 @@ MTLRenderPipelineDescriptor* MVKGraphicsPipeline::getMTLRenderPipelineDescriptor
}
// Depth & stencil attachments
MTLPixelFormat mtlDSFormat = mtlPixelFormatFromVkFormat(mvkRenderSubpass->getDepthStencilFormat());
MTLPixelFormat mtlDSFormat = getMTLPixelFormatFromVkFormat(mvkRenderSubpass->getDepthStencilFormat());
if (mvkMTLPixelFormatIsDepthFormat(mtlDSFormat)) { plDesc.depthAttachmentPixelFormat = mtlDSFormat; }
if (mvkMTLPixelFormatIsStencilFormat(mtlDSFormat)) { plDesc.stencilAttachmentPixelFormat = mtlDSFormat; }

View File

@ -178,7 +178,7 @@ void MVKRenderSubpass::populateClearAttachments(vector<VkClearAttachment>& clear
cAtt.colorAttachment = 0;
cAtt.clearValue = clearValues[attIdx];
MTLPixelFormat mtlDSFmt = _renderPass->mtlPixelFormatFromVkFormat(getDepthStencilFormat());
MTLPixelFormat mtlDSFmt = _renderPass->getMTLPixelFormatFromVkFormat(getDepthStencilFormat());
if (mvkMTLPixelFormatIsDepthFormat(mtlDSFmt)) { cAtt.aspectMask |= VK_IMAGE_ASPECT_DEPTH_BIT; }
if (mvkMTLPixelFormatIsStencilFormat(mtlDSFmt)) { cAtt.aspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT; }
if (cAtt.aspectMask) { clearAtts.push_back(cAtt); }

View File

@ -192,7 +192,7 @@ void MVKSwapchain::initCAMetalLayer(const VkSwapchainCreateInfoKHR* pCreateInfo)
MVKSurface* mvkSrfc = (MVKSurface*)pCreateInfo->surface;
_mtlLayer = mvkSrfc->getCAMetalLayer();
_mtlLayer.device = getMTLDevice();
_mtlLayer.pixelFormat = mtlPixelFormatFromVkFormat(pCreateInfo->imageFormat);
_mtlLayer.pixelFormat = getMTLPixelFormatFromVkFormat(pCreateInfo->imageFormat);
_mtlLayer.displaySyncEnabledMVK = (pCreateInfo->presentMode != VK_PRESENT_MODE_IMMEDIATE_KHR);
_mtlLayer.magnificationFilter = _device->_pMVKConfig->swapchainMagFilterUseNearest ? kCAFilterNearest : kCAFilterLinear;
_mtlLayer.framebufferOnly = !mvkIsAnyFlagEnabled(pCreateInfo->imageUsage, (VK_IMAGE_USAGE_TRANSFER_SRC_BIT |

View File

@ -57,6 +57,15 @@ double mvkGetTimestampPeriod();
*/
double mvkGetElapsedMilliseconds(uint64_t startTimestamp = 0, uint64_t endTimestamp = 0);
/** Ensures the block is executed on the main thread. */
inline void mvkDispatchToMainAndWait(dispatch_block_t block) {
if (NSThread.isMainThread) {
block();
} else {
dispatch_sync(dispatch_get_main_queue(), block);
}
}
#pragma mark -
#pragma mark MTLDevice
@ -67,11 +76,9 @@ uint64_t mvkRecommendedMaxWorkingSetSize(id<MTLDevice> mtlDevice);
/** Populate the propertes with info about the GPU represented by the MTLDevice. */
void mvkPopulateGPUInfo(VkPhysicalDeviceProperties& devProps, id<MTLDevice> mtlDevice);
/** Ensures the block is executed on the main thread. */
inline void mvkDispatchToMainAndWait(dispatch_block_t block) {
if (NSThread.isMainThread) {
block();
} else {
dispatch_sync(dispatch_get_main_queue(), block);
}
}
/**
* If the MTLDevice defines a texture memory alignment for the format, it is retrieved from
* the MTLDevice and returned, or returns zero if the MTLDevice does not define an alignment.
* The format must support linear texture memory (must not be depth, stencil, or compressed).
*/
VkDeviceSize mvkMTLPixelFormatLinearTextureAlignment(MTLPixelFormat mtlPixelFormat, id<MTLDevice> mtlDevice);

View File

@ -188,4 +188,11 @@ void mvkPopulateGPUInfo(VkPhysicalDeviceProperties& devProps, id<MTLDevice> mtlD
}
#endif //MVK_IOS
VkDeviceSize mvkMTLPixelFormatLinearTextureAlignment(MTLPixelFormat mtlPixelFormat,
id<MTLDevice> mtlDevice) {
if ([mtlDevice respondsToSelector: @selector(minimumLinearTextureAlignmentForPixelFormat:)]) {
return [mtlDevice minimumLinearTextureAlignmentForPixelFormat: mtlPixelFormat];
} else {
return 0;
}
}