简体   繁体   English

在金属中手动设置1D纹理

[英]Manually set a 1D Texture in Metal

I'm trying to fill a 1D texture with values manually and pass that texture to a compute shader (these are 2 pixels that I want to set via code, they don't represent any image). 我试图手动用值填充一维纹理并将该纹理传递到计算着色器(这些是我要通过代码设置的2个像素,它们不代表任何图像)。

Due to the current small amount of Metal examples, all examples I could find deal with 2D textures that load the texture by converting a loaded UIImage to raw bytes data, but creating a dummy UIImage felt like a hack for me. 由于目前仅有少量的Metal示例,我可以找到所有示例,这些示例都涉及2D纹理 ,该2D纹理通过将已加载的UIImage转换为原始字节数据来加载纹理,但是创建虚拟UIImage对我来说就像是hack。

This is the "naive" way I started with - 这是我开始的“天真”方式-

...
var manualTextureData: [Float] = [ 1.0, 0.0, 0.0, 1.0,
                                   0.0, 0.0, 1.0, 1.0 ];
let region: MTLRegion = MTLRegionMake1D(0, textureDescriptor.width);
myTexture.replaceRegion(region, mipmapLevel: 0, withBytes: &manualTextureData, bytesPerRow: 0);

but Metal doesn't recognize those values in the shader (it gets an empty texture, except for the first value). 但是Metal无法在着色器中识别这些值(除第一个值外,它将获得空纹理)。

I quickly realized that the Float array probably has to be converted into a bytes array (eg UInt8 ), but couldn't find a way to convert from [Float] to [UInt8] either. 我很快意识到Float数组可能必须转换为字节数组(例如UInt8 ),但是也找不到从[Float]转换为[UInt8]方法。

Another possible option I consider is using a CVPixelBuffer object, but that also felt like a workaround to the problem. 我考虑的另一个可能的选择是使用CVPixelBuffer对象,但这也感觉像是解决该问题的方法。

So whats the right way to tackle that? 那么解决这个问题的正确方法是什么?

Thanks in advance. 提前致谢。

  • Please note I'm not familiar with Objective-C , hence I'm not sure whether using CVPixelBuffer / UIImage is exaggerated for something which should be straight-forward. 请注意,我对Objective-C并不熟悉,因此我不确定使用CVPixelBuffer / UIImage是否会因为某些简单的事情而被夸大。

If you want a float texture bytesPerRow should be 4 for times the width, because a float has a size of 4 bytes. 如果要浮动纹理,则bytesPerRow应为宽度的4倍,因为浮动的大小为4个字节。 Metal copies the memory and dont care about the values. Metal复制内存,而不关心值。 That is your task ;-) 那是你的任务;-)

Something like: 就像是:

myTexture.replaceRegion(region, mipmapLevel: 0, withBytes: &manualTextureData, bytesPerRow: manualTextureData.count * sizeof(Float));

I don't see any reason for you to pass data using 1D texture. 我看不出有任何理由使用1D纹理传递数据。 Instead I would go with just passing a buffer. 相反,我会只传递一个缓冲区。 Like this: 像这样:

var dataBuffer:MTLBuffer? = device.newBufferWithBytes(&manualTextureData, length: sizeOf(manualTextureData), options: MTLResourceOptions.OptionCPUCacheModeDefault)

Then you hook it to your renderCommandEncoder like this: 然后像这样将其挂接到您的renderCommandEncoder

renderCommandEncoder.setFragmentBuffer(dataBuffer, offset: 0, atIndex: 1)//Note that if you want this buffer to be passed to you vertex shader you should use setVertexBuffer

Then in your shader, you should add parameter like this const device float* bufferPassed [[ buffer(1) ]] 然后在您的着色器中,应添加类似此const device float* bufferPassed [[ buffer(1) ]]参数const device float* bufferPassed [[ buffer(1) ]]

And then use it like this, inside your shader implementation: 然后在着色器实现中像这样使用它:

float firstFloat = bufferPassed[0];

This will get the job done. 这样就可以完成工作。

Not really answering your question, but you could just define an array in your metal shader instead of passing the values as a texture. 不能真正回答您的问题,但是您可以在金属着色器中定义一个数组,而不是将值作为纹理传递。

Something like: 就像是:

constant float manualData[8] = { 1.0, 0.0, 0.0, 1.0,
                               0.0, 0.0, 1.0, 1.0 };

vertex float4 world_vertex(unsigned int vid[[vertex_id]], ...) {
    int manualIndex = vid % 8;
    float manualValue = manualData[manualIndex];
    // something deep and meaningful here...
    return float4(manualValue);
}

Please forgive the terse reply, but you may find it useful to take a look at my experiments with Swift and Metal. 请原谅简短的答复,但您可能会发现查看我对Swift和Metal的实验很有用。 I've created a particle system in Swift which is passed to a Metal compute shader as a one dimensional array of Particle structs. 我已经在Swift中创建了一个粒子系统,该系统作为粒子结构的一维数组传递到Metal计算着色器。 By using posix_memalign, I'm able to eliminate the bottleneck caused by passing the array between Metal and Swift. 通过使用posix_memalign,我可以消除在Metal和Swift之间传递数组引起的瓶颈。

I've blogged extensively about this: http://flexmonkey.blogspot.co.uk/search/label/Metal 我已经在此广泛地写过博客: http : //flexmonkey.blogspot.co.uk/search/label/Metal

I hope this helps. 我希望这有帮助。

Simon 西蒙

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM