Image processing 使用Swift 4在金属计算内核中传递参数
在CPU方面,我有一个要传递给计算内核的结构:Image processing 使用Swift 4在金属计算内核中传递参数,image-processing,kernel,swift4,metal,metalkit,Image Processing,Kernel,Swift4,Metal,Metalkit,在CPU方面,我有一个要传递给计算内核的结构: private struct BoundingBoxParameters { var x: Float = 0 var y: Float = 0 var width: Float = 0 var height: Float = 0 var levelOfDetail: Float = 1.0 var dummy: Float = 1.0 // Needed for success } 在运
private struct BoundingBoxParameters {
var x: Float = 0
var y: Float = 0
var width: Float = 0
var height: Float = 0
var levelOfDetail: Float = 1.0
var dummy: Float = 1.0 // Needed for success
}
在运行内核之前,我将数据传递给MTLComputeCommandEncoder:
备选案文1(直接):
错误如下:
validateComputeFunctionArguments:820: failed assertion `Compute Function(resizeImage): argument params[0] from buffer(0) with offset(0) and length(20) has space for 20 bytes, but argument has a length(24).'
在金属内核方面,以下是相关的代码片段:
struct BoundingBoxParameters {
float2 topLeft;
float2 size;
float levelOfDetail;
};
kernel void resizeImage(constant BoundingBoxParameters *params [[buffer(0)]],
texture2d<half, access::sample> sourceTexture [[texture(0)]],
texture2d<half, access::write> destTexture [[texture(1)]],
sampler samp [[sampler(0)]],
uint2 gridPosition [[thread_position_in_grid]]) {
float2 destSize = float2(destTexture.get_width(0), destTexture.get_height(0));
float2 sourceCoords = float2(gridPosition) / destSize;
sourceCoords *= params->size;
sourceCoords += params->topLeft;
float lod = params->levelOfDetail;
half4 color = sourceTexture.sample(samp, sourceCoords, level(lod));
destTexture.write(color, gridPosition);
}
struct BoundingBoxParameters{
左上角2;
2号;
细节的浮动水平;
};
内核void resizeImage(常量BoundingBoxParameters*params[[buffer(0)],
texture2d sourceTexture[[纹理(0)],
纹理2d destTexture[[纹理(1)],
采样器samp[[采样器(0)],
uint2 gridPosition[[thread_position_in_grid]]{
float2 destSize=float2(destTexture.get_width(0),destTexture.get_height(0));
float2 sourceCoords=float2(网格位置)/destSize;
sourceCoords*=参数->大小;
sourceCoords+=参数->左上角;
浮动lod=参数->细节级别;
half4 color=sourceTexture.sample(samp、sourceCoords、level(lod));
destTexture.write(颜色、网格位置);
}
在尝试将3x3矩阵传递给另一个计算内核时,我也遇到了类似的问题。它抱怨提供了36个字节,但期望48个字节
有人对这个问题有什么想法吗?首先,我想指出,当您需要在内存中列出Swift类型的实际长度时,不应该使用。你应该用这个。根据斯威夫特的报告: 最终尺寸和对齐度是骨料的尺寸和对齐度。该类型的步幅是向上舍入至对齐的最终尺寸 如果您想更好地理解该主题,请在Swift中详细介绍内存布局
问题在于,使用
float2
的Metal结构和用两个单独的Float
字段替换它的Swift结构具有不同的内存布局
结构的大小(如果是Swift,则为跨距)需要是任何结构成员最大对齐的倍数。Metal结构中的最大对齐方式是8字节(对齐方式为float2
),因此在float
值之后的结构尾部有一个填充
struct BoundingBoxParameters {
float2 topLeft; // 8 bytes
float2 size; // 8 bytes
float levelOfDetail; // 4 bytes
// 4 bytes of padding so that size of struct is multiple
// of the largest alignment (which is 8 bytes)
}; // 24 bytes in total
因此,正如错误所示,您的金属结构实际上占用了24个字节
同时,您的Swift结构
,具有4个字节的最大对齐,只需要20个字节
这就是为什么它们最终彼此不兼容,并且伪
字段将丢失的4个字节补偿到Swift struct
为了解决这个问题,我建议您在Swift中使用float2
fromsimd
,而不是Float
s:
import simd
private struct BoundingBoxParameters {
var topLeft = float2(x: 0, y: 0)
var size = float2(x: 0, y: 0)
var levelOfDetail: Float = 1.0
}
不要忘记使用MemoryLayout.stride
(24字节)来获取长度,而不是size
(20字节)
3x3矩阵的情况也是如此:Metal的float3x3
大小为48字节,对齐方式为16字节。我假设,您已经创建了一个带有9个Float的Swift结构,该结构的跨距/大小为36字节,对齐方式为4字节。因此,错误的对齐。使用来自simd
的矩阵\u float3x3
一般来说,在金属中使用向量或矩阵时,应在Swift中使用相应的simd
类型 谢谢你的回答。这就解决了问题。我希望一个月前能找到你的simd建议。解释得很好,很有帮助。谢谢!:)
struct BoundingBoxParameters {
float2 topLeft;
float2 size;
float levelOfDetail;
};
kernel void resizeImage(constant BoundingBoxParameters *params [[buffer(0)]],
texture2d<half, access::sample> sourceTexture [[texture(0)]],
texture2d<half, access::write> destTexture [[texture(1)]],
sampler samp [[sampler(0)]],
uint2 gridPosition [[thread_position_in_grid]]) {
float2 destSize = float2(destTexture.get_width(0), destTexture.get_height(0));
float2 sourceCoords = float2(gridPosition) / destSize;
sourceCoords *= params->size;
sourceCoords += params->topLeft;
float lod = params->levelOfDetail;
half4 color = sourceTexture.sample(samp, sourceCoords, level(lod));
destTexture.write(color, gridPosition);
}
struct BoundingBoxParameters {
float2 topLeft; // 8 bytes
float2 size; // 8 bytes
float levelOfDetail; // 4 bytes
// 4 bytes of padding so that size of struct is multiple
// of the largest alignment (which is 8 bytes)
}; // 24 bytes in total
private struct BoundingBoxParameters {
var x: Float = 0 // 4 bytes
var y: Float = 0 // 4 bytes
var width: Float = 0 // 4 bytes
var height: Float = 0 // 4 bytes
var levelOfDetail: Float = 1.0 // 4 bytes
// no need for any padding
} // 20 bytes in total
import simd
private struct BoundingBoxParameters {
var topLeft = float2(x: 0, y: 0)
var size = float2(x: 0, y: 0)
var levelOfDetail: Float = 1.0
}