2

I'm trying to port my OpenGL code to Metal one. As part of it I need to draw PNG textures, and I'm using MTKTextureLoader to load them. Here is my pipeline code:

texturePipelineDescriptor.vertexFunction = textureVertexFunc;
texturePipelineDescriptor.fragmentFunction = textureFragmentFunc;
texturePipelineDescriptor.colorAttachments[0].pixelFormat = MTLPixelFormatRGBA8Unorm;

texturePipelineDescriptor.colorAttachments[0].blendingEnabled = YES;
texturePipelineDescriptor.colorAttachments[0].rgbBlendOperation = MTLBlendOperationAdd;
texturePipelineDescriptor.colorAttachments[0].sourceRGBBlendFactor = MTLBlendFactorSourceAlpha;
texturePipelineDescriptor.colorAttachments[0].destinationRGBBlendFactor = MTLBlendFactorOneMinusSourceAlpha;

And here is my loader code:

NSData* imageData = [NSData dataWithBytes:imageBuffer length:imageBufferSize];
id<MTLTexture> newMTLTexture = [m_metal_renderer.metalTextureLoader newTextureWithData:imageData options:nil error:&error];

And here is the result. The entire image should be orange, like the small parts.

enter image description here

If I change this line:

texturePipelineDescriptor.colorAttachments[0].pixelFormat = MTLPixelFormatRGBA8Unorm;

To this line:

texturePipelineDescriptor.colorAttachments[0].pixelFormat = MTLPixelFormatBGRA8Unorm;

I will get the following results:

enter image description here

As you can see,images changed R and B channels, When I loading the textures, in ALL OF THEM

newMTLTexture.pixelFormat = MTLPixelFormatBGRA8Unorm;

regardless whether they are drawn correctly or not. I would suspect there is something wrong with PNG files, but they seems absolutely normal in any PNG viewer.

Any clues what I can do to resolve it? Is it a bug In MTLTextureLoader? Is there another way of loading PNG picture?

P.S. The software is written for MacOS and not iOS.

user16217248
  • 3,119
  • 19
  • 19
  • 37
Iron-Eagle
  • 1,707
  • 2
  • 17
  • 34

1 Answers1

0

I found the problem. It seems that some of the PNG files were stored in RGB (24 bit) format, while another were stored in RGBA (32 bit) format. All color became right after converting images to 32bit format.

I would expect MTKTextureLoader to be able to handle that, but apparently it is not. If someone knows the option I missed or another way to correctly load those PNG's to Metal (Other than adding 4th channel manually) it will be great!

Iron-Eagle
  • 1,707
  • 2
  • 17
  • 34
  • Can you just load the PNG images with CGImageSourceCreateWithData() using the ImageIO framework? Also, keep in mind that the input data is sRGB not plain linear RGB data, so you should be using MTLPixelFormatBGRA8Unorm_sRGB. – MoDJ Jul 24 '19 at 01:25
  • Loading PNG with CGImageSourceCreateWithData() - Have been thinking about that, or using pnglib. Didn't come to that yet. Do you, by chance, have an example? As for MTLPixelFormatBGRA8Unorm_sRGB - I am not setting the format. MTKTextureLoader set it to the Texture it loaded. Setting it to texturePipelineDescriptor.colorAttachments[0].pixelFormat didn't change a thing but somehow images were more dark and contrast. – Iron-Eagle Jul 24 '19 at 06:36
  • Re CGImageSourceCreateWithData() just take a look at the Apple docs, usage is trivial. You need to allocate your own metal texture and set MTLPixelFormatBGRA8Unorm_sRGB. – MoDJ Jul 24 '19 at 07:21