<p>The float2 type in the Metal structure requires an alignment of 8 bytes. The stride of the struct then becomes 24 so every value is aligned properly if you use it in an array.  Your Swift structure only uses float which requires an alignment of 4 bytes, and an overall stride of 20.</p>

<p><a href="http://devstreaming.apple.com/videos/wwdc/2014/604xxg7crkljcr8/604/604_working_with_metal_fundamentals.pdf" rel="nofollow noreferrer">This presentation by Apple</a> goes into some detail (starting at 30:20 of <a href="https://developer.apple.com/videos/play/wwdc2014/604/" rel="nofollow noreferrer">the video</a>). The <a href="https://developer.apple.com/metal/Metal-Shading-Language-Specification.pdf" rel="nofollow noreferrer">Metal Shading Language
Specification </a> lists the alignment of vector and matrix data types in sections 2.2 and 2.3.</p>

<p>Similarly, float3x3 has a size of 48 and an alignment of 16 in Metal. But an array of 9 floats would only have a size of 36 and an alignment of 4. Using the simd module can provide you data types in Swift with the same size and alignment requirements as those used in Metal.</p>

<p>As a side note, you should be using MemoryLayout&lt;>.stride instead of MemoryLayout&lt;>.size when you call setBytes.  The following Swift structure has a stride of 24 but a size of only 20.</p>

<pre><code>struct BoundingBoxParameters {
    var topLeft: float2 = float2(0)   // float2 is from "import simd"
    var size: float2 = float2(0)
    var levelOfDetail: Float = 1.0
}
</code></pre>

CC BY-SA 3.0
2018-02-12T04:47:31.577Z
2018-02-12T04:47:31.577Z
MemoryStomp
<p>Utilize <code>simd</code> to synchronize your alignment:</p>

<p>import simd</p>

<pre><code>private struct BoundingBoxParameters {

    let topLeft: float2 = float2(0.0, 0.0)
    let size: float2 = float2(0.0, 0.0)
    let levelOfDetail: Float = 1.0

    init(topLeft: float2,
         size: float2,
         levelOfDetail: Float) {
        self.topLeft = topLeft
        self.size = size 
        self.levelOfDetail = levelOfDetail
    }
}
</code></pre>

CC BY-SA 4.0
2019-02-25T07:12:19.120Z
2019-02-26T09:50:00.073Z
2019-02-26T09:50:00.073Z
AndyRoid
<p>On the CPU side, I have a structure I want to pass to the compute kernel:</p>

<pre><code>  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
  }
</code></pre>

<p>Before running the kernel, I pass in the data to the MTLComputeCommandEncoder:</p>

<p>Option 1 (directly):</p>

<pre><code>commandEncoder!.setBytes(&amp;params, length: MemoryLayout&lt;BoundingBoxParameters&gt;.size, index: 0)
</code></pre>

<p>Option 2 (indirectly via MTLBuffer):</p>

<pre><code>boundingBoxBuffer.contents().copyBytes(from: &amp;params, count: MemoryLayout&lt;BoundingBoxParameters&gt;.size)
commandEncoder!.setBuffer(boundingBoxBuffer, offset: 0, index: 0)
</code></pre>

<p>Either option works fine if the 'dummy' variable exists in the structure, but fails if the 'dummy' variable does not exists. The code fails in the call to:</p>

<pre><code>commandEncoder!.dispatchThreadgroups(threadGroups, threadsPerThreadgroup: threadGroupCount)
</code></pre>

<p>With the error:</p>

<pre><code>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).'
</code></pre>

<p>On the Metal Kernel Side, here's the relevant code snippets:</p>

<pre><code>struct BoundingBoxParameters {
  float2 topLeft;
  float2 size;
  float levelOfDetail;
};

kernel void resizeImage(constant BoundingBoxParameters *params [[buffer(0)]],
                        texture2d&lt;half, access::sample&gt; sourceTexture [[texture(0)]],
                        texture2d&lt;half, access::write&gt; 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-&gt;size;
  sourceCoords += params-&gt;topLeft;
  float lod = params-&gt;levelOfDetail;
  half4 color = sourceTexture.sample(samp, sourceCoords, level(lod));
  destTexture.write(color, gridPosition);
}
</code></pre>

<p>I also get a similar issue when trying to pass in a 3x3 matrix to the compute kernel. It complains that 36 bytes are provided but expecting 48.</p>

<p>Anyone got any ideas on the issue?</p>

<image-processing><compute-shader><metal>
Passing parameters in Metal Compute Kernel using Swift 4
Labeno
# Passing parameters in Metal Compute Kernel using Swift 4

(Asked by: username_0 on 2018-02-10)

On the CPU side, I have a structure I want to pass to the compute kernel:

```
  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
  }

```

Before running the kernel, I pass in the data to the MTLComputeCommandEncoder:

Option 1 (directly):

```
commandEncoder!.setBytes(&params, length: MemoryLayout<BoundingBoxParameters>.size, index: 0)

```

Option 2 (indirectly via MTLBuffer):

```
boundingBoxBuffer.contents().copyBytes(from: &params, count: MemoryLayout<BoundingBoxParameters>.size)
commandEncoder!.setBuffer(boundingBoxBuffer, offset: 0, index: 0)

```

Either option works fine if the 'dummy' variable exists in the structure, but fails if the 'dummy' variable does not exists. The code fails in the call to:

```
commandEncoder!.dispatchThreadgroups(threadGroups, threadsPerThreadgroup: threadGroupCount)

```

With the error:

```
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).'

```

On the Metal Kernel Side, here's the relevant code snippets:

```
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);
}

```

I also get a similar issue when trying to pass in a 3x3 matrix to the compute kernel. It complains that 36 bytes are provided but expecting 48.

Anyone got any ideas on the issue?

**Tags:** image-processing, compute-shader, metal


---

## 2 answers

### Answer by username_1 on 2018-02-12. Score: 4

The float2 type in the Metal structure requires an alignment of 8 bytes. The stride of the struct then becomes 24 so every value is aligned properly if you use it in an array. Your Swift structure only uses float which requires an alignment of 4 bytes, and an overall stride of 20.

[This presentation by Apple](http://devstreaming.apple.com/videos/wwdc/2014/604xxg7crkljcr8/604/604_working_with_metal_fundamentals.pdf) goes into some detail (starting at 30:20 of [the video](https://developer.apple.com/videos/play/wwdc2014/604/)). The [Metal Shading Language
Specification](https://developer.apple.com/metal/Metal-Shading-Language-Specification.pdf)  lists the alignment of vector and matrix data types in sections 2.2 and 2.3.

Similarly, float3x3 has a size of 48 and an alignment of 16 in Metal. But an array of 9 floats would only have a size of 36 and an alignment of 4. Using the simd module can provide you data types in Swift with the same size and alignment requirements as those used in Metal.

As a side note, you should be using MemoryLayout<>.stride instead of MemoryLayout<>.size when you call setBytes. The following Swift structure has a stride of 24 but a size of only 20.

```
struct BoundingBoxParameters {
    var topLeft: float2 = float2(0)   // float2 is from "import simd"
    var size: float2 = float2(0)
    var levelOfDetail: Float = 1.0
}

```


---

### Answer by username_2 on 2019-02-25. Score: 0

Utilize `simd` to synchronize your alignment:

import simd

```
private struct BoundingBoxParameters {

    let topLeft: float2 = float2(0.0, 0.0)
    let size: float2 = float2(0.0, 0.0)
    let levelOfDetail: Float = 1.0

    init(topLeft: float2,
         size: float2,
         levelOfDetail: Float) {
        self.topLeft = topLeft
        self.size = size 
        self.levelOfDetail = levelOfDetail
    }
}

```


---

