Support linear filtering when using vkCmdBlitImage().
Fixes linear filtering when using vkCmdBlitImage(), useful for mipmap generation. Move MVKCmdBlitImage sampler definition to shader as a constexpr sampler, and ensure mip_filter and filter are set correctly. Add MVKRPSKeyBlitImg::srcFilter. Include MVKCommonEnvironment.h in MVKLogging.h. Update MoltenVK version to 1.0.39.
This commit is contained in:
parent
025abe501a
commit
9b13006018
@ -23,6 +23,8 @@
|
||||
extern "C" {
|
||||
#endif // __cplusplus
|
||||
|
||||
#include "MVKCommonEnvironment.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
@ -14,6 +14,16 @@ For best results, use a Markdown reader.*
|
||||
|
||||
|
||||
|
||||
MoltenVK 1.0.39
|
||||
---------------
|
||||
|
||||
Released TBD
|
||||
|
||||
- Support linear filtering when using `vkCmdBlitImage()`.
|
||||
- Support *Xcode 11.2*.
|
||||
|
||||
|
||||
|
||||
MoltenVK 1.0.38
|
||||
---------------
|
||||
|
||||
@ -47,7 +57,7 @@ Released 2019/10/30
|
||||
- Set value of `VkPhysicalDeviceLimits::maxTexelBufferElements` to more realistic value.
|
||||
- Add linking separate shader texts to `GLSLToSPRIVConverter`.
|
||||
- Move generation of `SPIRV-Cross/mvkSpirvCrossRevisionDerived.h` to separate script.
|
||||
- Support Xcode 11.1.
|
||||
- Support *Xcode 11.1*.
|
||||
- Update dependency libraries to match *Vulkan SDK 1.1.126*.
|
||||
- Update to latest SPIRV-Cross version:
|
||||
- MSL: Support option for treating 1D textures as 2D textures of height 1.
|
||||
|
@ -50,7 +50,7 @@ typedef unsigned long MTLLanguageVersion;
|
||||
*/
|
||||
#define MVK_VERSION_MAJOR 1
|
||||
#define MVK_VERSION_MINOR 0
|
||||
#define MVK_VERSION_PATCH 38
|
||||
#define MVK_VERSION_PATCH 39
|
||||
|
||||
#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)
|
||||
|
@ -116,7 +116,6 @@ protected:
|
||||
void initMTLRenderPassDescriptor();
|
||||
|
||||
MTLRenderPassDescriptor* _mtlRenderPassDescriptor;
|
||||
MTLSamplerMinMagFilter _mtlFilter;
|
||||
MVKRPSKeyBlitImg _blitKey;
|
||||
MVKVectorInline<MVKImageBlitRender, 4> _mvkImageBlitRenders;
|
||||
};
|
||||
|
@ -220,11 +220,10 @@ void MVKCmdBlitImage::setContent(VkImage srcImage,
|
||||
|
||||
MVKCmdCopyImage::setContent(srcImage, srcImageLayout, dstImage, dstImageLayout, true, commandUse);
|
||||
|
||||
_mtlFilter = mvkMTLSamplerMinMagFilterFromVkFilter(filter);
|
||||
|
||||
_blitKey.srcMTLPixelFormat = (uint32_t)_srcMTLPixFmt;
|
||||
_blitKey.srcMTLTextureType = (uint32_t)_srcImage->getMTLTextureType();
|
||||
_blitKey.dstMTLPixelFormat = (uint32_t)_dstMTLPixFmt;
|
||||
_blitKey.srcMTLPixelFormat = _srcMTLPixFmt;
|
||||
_blitKey.srcMTLTextureType = _srcImage->getMTLTextureType();
|
||||
_blitKey.dstMTLPixelFormat = _dstMTLPixFmt;
|
||||
_blitKey.srcFilter = mvkMTLSamplerMinMagFilterFromVkFilter(filter);
|
||||
_blitKey.dstSampleCount = _dstSampleCount;
|
||||
|
||||
_mvkImageBlitRenders.clear(); // Clear for reuse
|
||||
@ -355,31 +354,31 @@ void MVKCmdBlitImage::encode(MVKCommandEncoder* cmdEncoder) {
|
||||
mtlColorAttDesc.texture = dstMTLTex;
|
||||
|
||||
uint32_t vtxBuffIdx = getDevice()->getMetalBufferIndexForVertexAttributeBinding(kMVKVertexContentBufferIndex);
|
||||
|
||||
MVKCommandEncodingPool* cmdEncPool = getCommandEncodingPool();
|
||||
id<MTLRenderPipelineState> mtlRPS = getCommandEncodingPool()->getCmdBlitImageMTLRenderPipelineState(_blitKey);
|
||||
|
||||
for (auto& bltRend : _mvkImageBlitRenders) {
|
||||
|
||||
mtlColorAttDesc.level = bltRend.region.dstSubresource.mipLevel;
|
||||
|
||||
uint32_t srcBaseLayer = bltRend.region.srcSubresource.baseArrayLayer;
|
||||
uint32_t dstBaseLayer = bltRend.region.dstSubresource.baseArrayLayer;
|
||||
|
||||
uint32_t layCnt = bltRend.region.srcSubresource.layerCount;
|
||||
for (uint32_t layIdx = 0; layIdx < layCnt; layIdx++) {
|
||||
// Update the render pass descriptor for the texture level and slice, and create a render encoder.
|
||||
mtlColorAttDesc.slice = dstBaseLayer + layIdx;
|
||||
mtlColorAttDesc.slice = bltRend.region.dstSubresource.baseArrayLayer + layIdx;
|
||||
id<MTLRenderCommandEncoder> mtlRendEnc = [cmdEncoder->_mtlCmdBuffer renderCommandEncoderWithDescriptor: _mtlRenderPassDescriptor];
|
||||
setLabelIfNotNil(mtlRendEnc, mvkMTLRenderCommandEncoderLabel(_commandUse));
|
||||
|
||||
[mtlRendEnc pushDebugGroup: @"vkCmdBlitImage"];
|
||||
[mtlRendEnc setRenderPipelineState: cmdEncPool->getCmdBlitImageMTLRenderPipelineState(_blitKey)];
|
||||
[mtlRendEnc setRenderPipelineState: mtlRPS];
|
||||
cmdEncoder->setVertexBytes(mtlRendEnc, bltRend.vertices, sizeof(bltRend.vertices), vtxBuffIdx);
|
||||
|
||||
[mtlRendEnc setFragmentTexture: srcMTLTex atIndex: 0];
|
||||
[mtlRendEnc setFragmentSamplerState: cmdEncPool->getCmdBlitImageMTLSamplerState(_mtlFilter) atIndex: 0];
|
||||
uint32_t srcSlice = srcBaseLayer + layIdx;
|
||||
cmdEncoder->setFragmentBytes(mtlRendEnc, &srcSlice, sizeof(srcSlice), 0);
|
||||
|
||||
struct {
|
||||
uint slice;
|
||||
float lod;
|
||||
} texSubRez;
|
||||
texSubRez.slice = bltRend.region.srcSubresource.baseArrayLayer + layIdx;
|
||||
texSubRez.lod = bltRend.region.srcSubresource.mipLevel;
|
||||
cmdEncoder->setFragmentBytes(mtlRendEnc, &texSubRez, sizeof(texSubRez), 0);
|
||||
|
||||
[mtlRendEnc drawPrimitives: MTLPrimitiveTypeTriangleStrip vertexStart: 0 vertexCount: kMVKBlitVertexCount];
|
||||
[mtlRendEnc popDebugGroup];
|
||||
|
@ -51,12 +51,6 @@ public:
|
||||
/** Returns a MTLRenderPipelineState to support certain Vulkan BLIT commands. */
|
||||
id<MTLRenderPipelineState> getCmdBlitImageMTLRenderPipelineState(MVKRPSKeyBlitImg& blitKey);
|
||||
|
||||
/**
|
||||
* Returns a MTLSamplerState dedicated to rendering to a texture using the
|
||||
* specified min/mag filter value to support certain Vulkan BLIT commands.
|
||||
*/
|
||||
id<MTLSamplerState> getCmdBlitImageMTLSamplerState(MTLSamplerMinMagFilter mtlFilter);
|
||||
|
||||
/**
|
||||
* Returns a MTLDepthStencilState dedicated to rendering to several attachments
|
||||
* to support clearing regions of those attachments.
|
||||
@ -88,10 +82,10 @@ public:
|
||||
* with content held in Private storage. The object returned can be used as a
|
||||
* temporary image during image transfers.
|
||||
*
|
||||
* The same image instance will be returned for two calls to this funciton with
|
||||
* The same image instance will be returned for two calls to this function with
|
||||
* the same image descriptor data. This implies that the same image instance could
|
||||
* be used by two transfers within the same encoder or queue. This is acceptable
|
||||
* becuase the content only needss to be valid during the transfer, and it can be
|
||||
* becuase the content only needs to be valid during the transfer, and it can be
|
||||
* reused by subsequent transfers in the same encoding run.
|
||||
*/
|
||||
MVKImage* getTransferMVKImage(MVKImageDescriptorData& imgData);
|
||||
@ -148,8 +142,6 @@ protected:
|
||||
std::unordered_map<MVKBufferDescriptorData, MVKBuffer*> _transferBuffers;
|
||||
std::unordered_map<MVKBufferDescriptorData, MVKDeviceMemory*> _transferBufferMemory;
|
||||
MVKMTLBufferAllocator _mtlBufferAllocator;
|
||||
id<MTLSamplerState> _cmdBlitImageLinearMTLSamplerState = nil;
|
||||
id<MTLSamplerState> _cmdBlitImageNearestMTLSamplerState = nil;
|
||||
id<MTLDepthStencilState> _cmdClearDepthOnlyDepthStencilState = nil;
|
||||
id<MTLDepthStencilState> _cmdClearStencilOnlyDepthStencilState = nil;
|
||||
id<MTLDepthStencilState> _cmdClearDepthAndStencilDepthStencilState = nil;
|
||||
|
@ -60,18 +60,6 @@ id<MTLRenderPipelineState> MVKCommandEncodingPool::getCmdBlitImageMTLRenderPipel
|
||||
MVK_ENC_REZ_ACCESS(_cmdBlitImageMTLRenderPipelineStates[blitKey], newCmdBlitImageMTLRenderPipelineState(blitKey, _commandPool));
|
||||
}
|
||||
|
||||
id<MTLSamplerState> MVKCommandEncodingPool::getCmdBlitImageMTLSamplerState(MTLSamplerMinMagFilter mtlFilter) {
|
||||
switch (mtlFilter) {
|
||||
case MTLSamplerMinMagFilterNearest: {
|
||||
MVK_ENC_REZ_ACCESS(_cmdBlitImageNearestMTLSamplerState, newCmdBlitImageMTLSamplerState(mtlFilter));
|
||||
}
|
||||
|
||||
case MTLSamplerMinMagFilterLinear: {
|
||||
MVK_ENC_REZ_ACCESS(_cmdBlitImageLinearMTLSamplerState, newCmdBlitImageMTLSamplerState(mtlFilter));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
id<MTLDepthStencilState> MVKCommandEncodingPool::getMTLDepthStencilState(bool useDepth, bool useStencil) {
|
||||
|
||||
if (useDepth && useStencil) {
|
||||
@ -168,12 +156,6 @@ void MVKCommandEncodingPool::destroyMetalResources() {
|
||||
for (auto& pair : _transferBufferMemory) { mvkDev->freeMemory(pair.second, nullptr); }
|
||||
_transferBufferMemory.clear();
|
||||
|
||||
[_cmdBlitImageLinearMTLSamplerState release];
|
||||
_cmdBlitImageLinearMTLSamplerState = nil;
|
||||
|
||||
[_cmdBlitImageNearestMTLSamplerState release];
|
||||
_cmdBlitImageNearestMTLSamplerState = nil;
|
||||
|
||||
[_cmdClearDepthAndStencilDepthStencilState release];
|
||||
_cmdClearDepthAndStencilDepthStencilState = nil;
|
||||
|
||||
|
@ -30,7 +30,7 @@
|
||||
#pragma mark MVKRPSKeyBlitImg
|
||||
|
||||
/**
|
||||
* Key to use for looking up cached MTLRenderPipelineState instances based on MTLPixelFormat and MTLTextureType.
|
||||
* Key to use for looking up cached MTLRenderPipelineState instances based on BLIT info.
|
||||
*
|
||||
* This structure can be used as a key in a std::map and std::unordered_map.
|
||||
*/
|
||||
@ -38,12 +38,14 @@ typedef struct MVKRPSKeyBlitImg_t {
|
||||
uint16_t srcMTLPixelFormat = 0; /**< as MTLPixelFormat */
|
||||
uint16_t srcMTLTextureType = 0; /**< as MTLTextureType */
|
||||
uint16_t dstMTLPixelFormat = 0; /**< as MTLPixelFormat */
|
||||
uint16_t dstSampleCount = 0;
|
||||
uint8_t srcFilter = 0; /**< as MTLSamplerMinMagFilter */
|
||||
uint8_t dstSampleCount = 0;
|
||||
|
||||
bool operator==(const MVKRPSKeyBlitImg_t& rhs) const {
|
||||
if (srcMTLPixelFormat != rhs.srcMTLPixelFormat) { return false; }
|
||||
if (srcMTLTextureType != rhs.srcMTLTextureType) { return false; }
|
||||
if (dstMTLPixelFormat != rhs.dstMTLPixelFormat) { return false; }
|
||||
if (srcFilter != rhs.srcFilter) { return false; }
|
||||
if (dstSampleCount != rhs.dstSampleCount) { return false; }
|
||||
return true;
|
||||
}
|
||||
@ -52,20 +54,29 @@ typedef struct MVKRPSKeyBlitImg_t {
|
||||
|
||||
inline MTLPixelFormat getDstMTLPixelFormat() { return (MTLPixelFormat)dstMTLPixelFormat; }
|
||||
|
||||
inline MTLSamplerMinMagFilter getSrcMTLSamplerMinMagFilter() { return (MTLSamplerMinMagFilter)srcFilter; }
|
||||
|
||||
inline bool isSrcArrayType() {
|
||||
return (srcMTLTextureType == MTLTextureType2DArray ||
|
||||
#if MVK_MACOS
|
||||
srcMTLTextureType == MTLTextureType2DMultisampleArray ||
|
||||
#endif
|
||||
srcMTLTextureType == MTLTextureType1DArray); }
|
||||
srcMTLTextureType == MTLTextureType1DArray);
|
||||
}
|
||||
|
||||
std::size_t hash() const {
|
||||
std::size_t hash = srcMTLPixelFormat;
|
||||
|
||||
hash <<= 16;
|
||||
hash |= srcMTLTextureType;
|
||||
|
||||
hash <<= 16;
|
||||
hash |= dstMTLPixelFormat;
|
||||
hash <<= 16;
|
||||
|
||||
hash <<= 8;
|
||||
hash |= srcFilter;
|
||||
|
||||
hash <<= 8;
|
||||
hash |= dstSampleCount;
|
||||
return hash;
|
||||
}
|
||||
|
@ -156,8 +156,10 @@ id<MTLFunction> MVKCommandResourceFactory::newBlitFragFunction(MVKRPSKeyBlitImg&
|
||||
NSString* typeStr = getMTLFormatTypeString(blitKey.getSrcMTLPixelFormat());
|
||||
|
||||
bool isArrayType = blitKey.isSrcArrayType();
|
||||
bool isLinearFilter = (blitKey.getSrcMTLSamplerMinMagFilter() == MTLSamplerMinMagFilterLinear);
|
||||
NSString* arraySuffix = isArrayType ? @"_array" : @"";
|
||||
NSString* sliceArg = isArrayType ? @", srcSlice" : @"";
|
||||
NSString* sliceArg = isArrayType ? @", subRez.slice" : @"";
|
||||
NSString* srcFilter = isLinearFilter ? @"linear" : @"nearest";
|
||||
|
||||
NSMutableString* msl = [NSMutableString stringWithCapacity: (2 * KIBI) ];
|
||||
[msl appendLineMVK: @"#include <metal_stdlib>"];
|
||||
@ -168,19 +170,26 @@ id<MTLFunction> MVKCommandResourceFactory::newBlitFragFunction(MVKRPSKeyBlitImg&
|
||||
[msl appendLineMVK: @" float2 v_texCoord;"];
|
||||
[msl appendLineMVK: @"} VaryingsPosTex;"];
|
||||
[msl appendLineMVK];
|
||||
[msl appendLineMVK: @"typedef struct {"];
|
||||
[msl appendLineMVK: @" uint slice;"];
|
||||
[msl appendLineMVK: @" float lod;"];
|
||||
[msl appendLineMVK: @"} TexSubrez;"];
|
||||
[msl appendLineMVK];
|
||||
|
||||
NSString* funcName = @"fragBlit";
|
||||
[msl appendFormat: @"constexpr sampler ce_sampler(mip_filter::nearest, filter::%@);", srcFilter];
|
||||
[msl appendLineMVK];
|
||||
|
||||
NSString* funcName = @"fragCmdBlitImage";
|
||||
[msl appendFormat: @"fragment %@4 %@(VaryingsPosTex varyings [[stage_in]],", typeStr, funcName];
|
||||
[msl appendLineMVK];
|
||||
[msl appendFormat: @" texture2d%@<%@> texture [[texture(0)]],", arraySuffix, typeStr];
|
||||
[msl appendFormat: @" texture2d%@<%@> tex [[texture(0)]],", arraySuffix, typeStr];
|
||||
[msl appendLineMVK];
|
||||
[msl appendLineMVK: @" sampler sampler [[sampler(0)]],"];
|
||||
[msl appendLineMVK: @" constant uint& srcSlice [[buffer(0)]]) {"];
|
||||
[msl appendFormat: @" return texture.sample(sampler, varyings.v_texCoord%@);", sliceArg];
|
||||
[msl appendLineMVK: @" constant TexSubrez& subRez [[buffer(0)]]) {"];
|
||||
[msl appendFormat: @" return tex.sample(ce_sampler, varyings.v_texCoord%@, level(subRez.lod));", sliceArg];
|
||||
[msl appendLineMVK];
|
||||
[msl appendLineMVK: @"}"];
|
||||
|
||||
// MVKLogDebug("\n%s", msl.UTF8String);
|
||||
MVKLogDebug("\n%s", msl.UTF8String);
|
||||
|
||||
return newMTLFunction(msl, funcName);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user