1
CAMetalLayer provides MTLTexture objects through -[CAMetalLayer nextDrawable] as you noticed. By default these MTLTexture are created with MTLTextureUsageRenderTarget only as usage flag, so you can only write to them through a render pipeline. This might be what you need anyway as this allows easily applying some transform to your input texture while rendering it into the drawable texture.
In case you can guarantee that your RGBA data width and height will always match the size of the drawable texture, and you don't need to apply any transformation, things can be a bit simpler: you can set CAMetalLayer.framebufferOnly property to false so that the provided textures also become writable, which means that you can copy from your own (with shared or managed MTLStorageMode) MTLTexture to the drawable texture with a simple blit command instead of render command, which would remove the need for a custom shader. So the pipeline would look as follow:
At init:
create 3 staging textures with shared/managed storage mode
At each frame:
pick current staging texture and fill it with the contents rendered by Skia
ask for the drawable texture
schedule blit from your staging texture to your drawable texture
commit
increase staging texture index
One thing I don't know is the MTLStorageMode of the drawable texture: in case it's already shared/managed, you don't need the staging texture and can directly fill the drawable texture instead of going through a staging texture fill + blit command.
Bonus: as an additional optimization and in case drawable texture isn't shared/managed, if you detect that your MTLDevice is an Apple one, you don't need to render with Skia to some buffer before filling the MTLTexture: you can render with Skia directly into the MTLTexture. To do that: create MTLBuffer objects of the appropriate size with shared storage mode, use -[MTLBuffer newTextureWithDescriptor:offset:bytesPerRow:] to create each staging texture from them. Now if you render with Skia into MTLBuffer.contents, this will be directly available when you use the MTLTexture for your render or blit command. Just don't forget to use -[MTLBuffer didModifyRange:] after writing to MTLBuffer.contents.
2
Just from above sample code I don't know, because the only shown render pass is using drawable.texture, and the drawable would already properly configure the texture. 0x01 is MTLTextureUsageShaderRead so you might have another render pipeline somewhere trying to render in a texture with that usage. When you get this error, I assume that the debugger shows the callstack for the command buffer being submitted that has this issue.
3
I suppose that you mean "when is the GPU done with using the texture that was filled with data from Skia" ? In that case the answer is: when the command buffer that references that texture has completed (you can know it through -[MTLCommandBuffer addCompletedHandler:]). Before that it's not safe to fill again the texture with new data. That's why in above pipeline I'm using 3 staging textures: this way you can continue filling textures while the GPU is using the previously filled ones. I picked number 3 because that's the maximum for CAMetalerLayer.maximumDrawableCount, so you can't have more than 3 staging textures needed at a time.
By the way this means that your current usage of _textureMutex is not useful as is and also doesn't prevent the GPU from reading the texture while you write to it for next frame scheduling.