0

I just need to create a transparent texture.(pixels with alpha 0).

func layerTexture()-> MTLTexture {

        let width = Int(self.drawableSize.width  )
        let height = Int(self.drawableSize.height )


        let texDescriptor = MTLTextureDescriptor.texture2DDescriptor(pixelFormat: .bgra8Unorm, width: width , height: height, mipmapped: false)
        let temparyTexture = self.device?.makeTexture(descriptor: texDescriptor)

        return temparyTexture!
    }

when I open temparyTexture using preview,it's appeared to be black. What is the missing here?

UPDATE

I just tried to create texture using transparent image. code.

 func layerTexture(imageData:Data)-> MTLTexture {

        let width = Int(self.drawableSize.width  )
        let height = Int(self.drawableSize.height )
        let bytesPerRow = width * 4


        let texDescriptor = MTLTextureDescriptor.texture2DDescriptor(pixelFormat: .rgba8Unorm, width: width , height: height, mipmapped: false)

        let temparyTexture = self.device?.makeTexture(descriptor: texDescriptor)

         let region = MTLRegionMake2D(0, 0, width, height)

        imageData.withUnsafeBytes { (u8Ptr: UnsafePointer<UInt8>) in
            let rawPtr = UnsafeRawPointer(u8Ptr)

            temparyTexture?.replace(region: region, mipmapLevel: 0, withBytes: rawPtr, bytesPerRow: bytesPerRow)
        }


        return temparyTexture!
    }

method is get called as follows

let image = UIImage(named: "layer1.png")!

let imageData = UIImagePNGRepresentation(image)

self.layerTexture(imageData: imageData!)

where layer1.png is a transparent png. But even though it is crashing with message "Thread 1: EXC_BAD_ACCESS (code=1, address=0x107e8c000) " at the point I try to replace texture. I believe it's because image data is compressed and rawpointer should point to uncompressed data. How can I resolve this?

Am I in correct path or completely in wrong direction? Is there any other alternatives. What I just need is to create transparent texture.

  • By "preview", you mean Preview.app? If so, how did you get the texture into Preview.app? I assume you somehow saved it to an image file. Show the code you used for that. – Ken Thomases Sep 04 '18 at 14:05
  • made a break point before return and when made mouse pointer on top of it we can see the texture.On top of that it says open with preview.So when clicked, it opens with preview.I believe it is a default app comes with mac os.After open it we can see background(view -> showbackground). But it is not transparent – Kasun Palihakkara Sep 05 '18 at 03:56

1 Answers1

2

Pre-edit: When you quick-look a transparent texture, it will appear black. I just double-checked with some code I have running stably in production - that is the expected result.

Post-edit: You are correct, you should not be copying PNG or JPEG data to a MTLTexture's contents directly. I would recommend doing something like this:

    var pixelBuffer: CVPixelBuffer?

    let attrs = [kCVPixelBufferCGImageCompatibilityKey: kCFBooleanTrue,
                 kCVPixelBufferCGBitmapContextCompatibilityKey: kCFBooleanTrue,
                 kCVPixelBufferMetalCompatibilityKey: kCFBooleanTrue]

    var status = CVPixelBufferCreate(nil, Int(image.size.width), Int(image.size.height),
                                     kCVPixelFormatType_32BGRA, attrs as CFDictionary,
                                     &pixelBuffer)
    assert(status == noErr)

    let coreImage = CIImage(image: image)!
    let context = CIContext(mtlDevice: MTLCreateSystemDefaultDevice()!)
    context.render(coreImage, to: pixelBuffer!)

    var textureWrapper: CVMetalTexture?

    status = CVMetalTextureCacheCreateTextureFromImage(kCFAllocatorDefault,
                                                       GPUManager.shared.textureCache, pixelBuffer!, nil, .bgra8Unorm,
                                                       CVPixelBufferGetWidth(pixelBuffer!), CVPixelBufferGetHeight(pixelBuffer!), 0, &textureWrapper)

    let texture = CVMetalTextureGetTexture(textureWrapper!)!

    // use texture now for your Metal texture. the texture is now map-bound to the CVPixelBuffer's underlying memory.

The issue you are running into is that it is actually pretty hard to fully grasp how bitmaps work and how they can be laid out differently. Graphics is a very closed field with lots of esoteric terminology, some of which refers to things that take years to grasp, some of which refers to things that are trivial but people just picked a weird word to call them by. My main pointers are:

  • Get out of UIImage land as early in your code as possible. The best way to avoiding overhead and delays when you go into Metal land is to get your images into a GPU-compatible representation as soon as you can.
  • Once you are outside of UIImage land, always know your channel order (RGBA, BGRA). At any point in code that you are editing, you should have a mental model of what pixel format each CVPixelBuffer / MTLTexture has.
  • Read up on premultiplied vs non-premultiplied alpha, you may not run into issues with this, but it threw me off repeatedly when I was first learning.
  • total byte size of a bitmap/pixelbuffer = bytesPerRow * height
Chen OT
  • 3,486
  • 2
  • 24
  • 46
Dennis L
  • 1,713
  • 14
  • 21
  • BTW how can i set texture usage here? Can you please explain more? – Kasun Palihakkara Sep 10 '18 at 11:22
  • @user8028778 in this case, I'm not 100% sure but I believe the texture will have all usage flags set (a google turned up results that on iOS it sets texture usage unknown, which may be slightly worse for perf, but should let you prototype with reads/writes as needed). As far as I am aware, the only way to set explicit usage is to use a MTLTextureDescriptor. – Dennis L Sep 11 '18 at 06:15