Reputation: 489
I'm creating an engine and need a dummy single-pixel texture for objects which do not have one of required materials. It should be 4 channel texture and example invocation could look as follows:
let dummy = device.makeSolidTexture(device: device, color: simd_float4(0, 0, 1, 1))!
Code I'm using
extension MTLDevice {
func makeSolidTexture(device: MTLDevice,
color: simd_float4,
pixelFormat: MTLPixelFormat = .bgra8Unorm) -> MTLTexture? {
let descriptor = MTLTextureDescriptor()
descriptor.width = 1
descriptor.height = 1
descriptor.mipmapLevelCount = 1
descriptor.storageMode = .managed
descriptor.arrayLength = 1
descriptor.sampleCount = 1
descriptor.cpuCacheMode = .writeCombined
descriptor.allowGPUOptimizedContents = false
descriptor.pixelFormat = pixelFormat
descriptor.textureType = .type2D
descriptor.usage = .shaderRead
guard let texture = device.makeTexture(descriptor: descriptor) else {
return nil
}
let origin = MTLOrigin(x: 0, y: 0, z: 0)
let size = MTLSize(width: texture.width, height: texture.height, depth: texture.depth)
let region = MTLRegion(origin: origin, size: size)
withUnsafePointer(to: color) { ptr in
texture.replace(region: region, mipmapLevel: 0, withBytes: ptr, bytesPerRow: 4)
}
return texture
}
}
The problem is that when I inspect the texture after capturing a frame I see:
What do I miss? Why is it black?
Upvotes: 0
Views: 645
Reputation: 489
It turned out that I made two mistakes there. First is that a textures MUST be aligned to 256 bytes, so I extended to size to 8 x 8 what considering the pixel format meets the requirement. My second mistake was to create a texture from float vector directly. Underlying type of the texture store the number in range 0-255, so the float vector passed to the function must be scaled and then converted to simd_uchar4
type.
Here is how it should look like
extension MTLDevice {
func makeSolid2DTexture(device: MTLDevice,
color: simd_float4,
pixelFormat: MTLPixelFormat = .bgra8Unorm) -> MTLTexture? {
let descriptor = MTLTextureDescriptor()
descriptor.width = 8
descriptor.height = 8
descriptor.mipmapLevelCount = 1
descriptor.storageMode = .managed
descriptor.arrayLength = 1
descriptor.sampleCount = 1
descriptor.cpuCacheMode = .writeCombined
descriptor.allowGPUOptimizedContents = false
descriptor.pixelFormat = pixelFormat
descriptor.textureType = .type2D
descriptor.usage = .shaderRead
guard let texture = device.makeTexture(descriptor: descriptor) else {
return nil
}
let origin = MTLOrigin(x: 0, y: 0, z: 0)
let size = MTLSize(width: texture.width, height: texture.height, depth: texture.depth)
let region = MTLRegion(origin: origin, size: size)
let mappedColor = simd_uchar4(color * 255)
Array<simd_uchar4>(repeating: mappedColor, count: 64).withUnsafeBytes { ptr in
texture.replace(region: region, mipmapLevel: 0, withBytes: ptr.baseAddress!, bytesPerRow: 32)
}
return texture
}
}
// bgra format in range [0, 1]
let foo = device.makeSolid2DTexture(device: device, color: simd_float4(1, 0, 0, 1))!
Upvotes: 3