MTLTextureUsageShaderWrite & MetalKit

I have a handful of projects (including ParticleLab) that use compute shaders to write to a MetalKit view's `drawable.texture` which have all worked without issue since WWDC.


However, since updating to Xcode 7.1 and iOS 9, I'm now unable to use any of my existing code and I'm getting:


/BuildRoot/Library/Caches/com.apple.xbs/Sources/Metal/Metal-55.1.1/ToolsLayers/Debug/MTLDebugComputeCommandEncoder.mm:654: failed assertion `Function writes texture (outTexture[0]) whos usage (0x05) doesn't specify MTLTextureUsageShaderWrite (0x02)'


Is this a bug or a new breaking change? I can't make a MetalKit's view writable, can I?


Simon

Replies

....one point, both release and debug builds stop the application from running because of the failed assertion. However, if I unplug my iPhone, the application actually works.

I am seeing the same issue in some code that was working fine on iOS 9.0 and is now breaking on iOS 9.1.



/BuildRoot/Library/Caches/com.apple.xbs/Sources/Metal/Metal-55.1.1/ToolsLayers/Debug/MTLDebugComputeCommandEncoder.mm:654: failed assertion `Function writes texture (outputTexture.coerce[0]) whos usage (0x05) doesn't specify MTLTextureUsageShaderWrite (0x02)'

I have started to catch the same problem. It solves if I stop debuging an launch app standalone. Does it have any solution?

Same issue here.Hope this can be fixed soon.In the mean time,I've worked around by init a MTLTexture that fits compute shader's access demand,write to it and then copy it to currentDrawable by a blitcommander.But since I can't modify the MetalPerformanceShaders I have to implement some filters on my own.

I have worked around this issue by disabling GPU Frame Capture in the application's Scheme. Find that setting under Edit Scheme > Run > Options > GPU Frame Capture. Set it to Disabled.

Bit thankyou to Kalvr for the work around. Unfortunately I am having this issue with the current versions of Xcode and iOS. Did this issue ever go away or has it still stuck around? It is a pretty critical problem....

Another interesting workaround is to use a bitwise or operator on the usage enum. I feel like I am probably going to cause Metal issues since the documentation does not mention doing this and they did not expose this functionality to swift (for some reason you can only or them in objective-c).


To do this I just created a bridging header with an objective c class in it with a method that returned the result of the or operation of textureRead and renderTarget like so


- (MTLTextureUsage)readAndWrite {
    return MTLTextureUsageShaderRead | MTLTextureUsageRenderTarget | MTLTextureUsageShaderWrite;
}


Again even though this works and allows you to turn frame capture back on I feel like this likely will mess up something with the Metal layer of the app.

I think you can do it all right for all MTLTextures you create. From what I understand, this is hint that lets Metal/GPU optimize texture to the usage that you plan for it, on the particular device. For example (now I am turning to guessing!) if your texture usage is just MTLTextureUsageRenderTarget maybe it could be stored in plain (not "tiled/swizzled" for texture unit caching needs) format, texel after texel, just like ordinary bitmap.


With that being said, as of today one does not have fine control over MTLTextures created by CAMetalLayer (so also MTKView) as drawables. However, if you look into header (and I recommend reading the headers in case of doubts with Metal, they often help):

/ This property controls whether or not the returned drawables'
* MTLTextures may only be used for framebuffer attachments (YES) or
* whether they may also be used for texture sampling and pixel
* read/write operations (NO). A value of YES allows CAMetalLayer to
* allocate the MTLTexture objects in ways that are optimized for display
* purposes that makes them unsuitable for sampling. The recommended
* value for most applications is YES. */
@property BOOL framebufferOnly;

So I guess setting framebufferOnly to NO should force usage of MTLTextures being returned as drawables from CAMetalLayer/MTKView to include more options (they specifically name sampling, read and write operations). Hope that helps.

Hi Simon,


I stumbled about the same issue when playing around with your Metal Reaction Diffusion Code, and this thread helped me tremendously to solve it.


Basically, when you create an MTLTextureDescriptor with let textureDescriptor = MTLTextureDescriptor.texture2DDescriptor(…), you have to add the .shaderWrite option to textureDescriptor.usage.


Hope it helps, if not you, than others.


Klaus

Post not yet marked as solved Up vote reply of Kabe Down vote reply of Kabe

I solved the issue adding :


textureDescriptor?.usage = [.shaderRead, .shaderWrite]


after initialization


Done! :]

   MTLTextureDescriptor *textureDescriptor = [[MTLTextureDescriptor alloc] init];   textureDescriptor.textureType = inTexture.textureType;   textureDescriptor.pixelFormat = inTexture.pixelFormat;   textureDescriptor.width = inTexture.width;   textureDescriptor.height = inTexture.height;   textureDescriptor.usage = inTexture.usage;

  textureDescriptor.usage = MTLTextureUsageShaderRead | MTLTextureUsageShaderWrite; // the key statement solved the issue