Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/image-processing/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Image processing 使用Swift 4在金属计算内核中传递参数_Image Processing_Kernel_Swift4_Metal_Metalkit - Fatal编程技术网

Image processing 使用Swift 4在金属计算内核中传递参数

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 } 在运

在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
  }
在运行内核之前,我将数据传递给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
from
simd
,而不是
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 
}