use private storage for textures

This commit is contained in:
2024-08-06 16:34:51 +10:00
parent a26d80ea5b
commit 10d7f8281c

View File

@ -123,7 +123,7 @@ class Renderer {
// Create a default texture // Create a default texture
do { do {
self.defaultTexture = try Self.loadTexture(device, image2D: Image2D(Data([ self.defaultTexture = try Self.loadTexture(device, queue, image2D: Image2D(Data([
0xFF, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF,
0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF
]), format: .abgr8888, width: 2, height: 2, stride: 2 * 4)) ]), format: .abgr8888, width: 2, height: 2, stride: 2 * 4))
@ -133,7 +133,7 @@ class Renderer {
// Load texture from a file in the bundle // Load texture from a file in the bundle
do { do {
self.cubeTexture = try Self.loadTexture(device, resourcePath: "test.png") self.cubeTexture = try Self.loadTexture(device, queue, resourcePath: "test.png")
} catch RendererError.loadFailure(let message) { } catch RendererError.loadFailure(let message) {
printErr("Failed to load texture image: \(message)") printErr("Failed to load texture image: \(message)")
} catch { } catch {
@ -145,42 +145,65 @@ class Renderer {
} }
static func loadTexture(_ device: MTLDevice, resourcePath path: String) throws -> MTLTexture { static func loadTexture(_ device: MTLDevice, _ queue: MTLCommandQueue, resourcePath path: String) throws -> MTLTexture {
do { do {
return try loadTexture(device, url: Bundle.main.getResource(path)) return try loadTexture(device, queue, url: Bundle.main.getResource(path))
} catch ContentError.resourceNotFound(let message) { } catch ContentError.resourceNotFound(let message) {
throw RendererError.loadFailure(message) throw RendererError.loadFailure(message)
} }
} }
static func loadTexture(_ device: MTLDevice, url imageUrl: URL) throws -> MTLTexture { static func loadTexture(_ device: MTLDevice, _ queue: MTLCommandQueue, url imageUrl: URL) throws -> MTLTexture {
do { do {
return try loadTexture(device, image2D: try NSImageLoader.open(url: imageUrl)) return try loadTexture(device, queue, image2D: try NSImageLoader.open(url: imageUrl))
} catch ImageLoaderError.openFailed(let message) { } catch ImageLoaderError.openFailed(let message) {
throw RendererError.loadFailure(message) throw RendererError.loadFailure(message)
} }
} }
static func loadTexture(_ device: MTLDevice, image2D image: Image2D) throws -> MTLTexture { static func loadTexture(_ device: MTLDevice, _ queue: MTLCommandQueue, image2D image: Image2D) throws -> MTLTexture {
let texDesc = MTLTextureDescriptor() let texDesc = MTLTextureDescriptor()
texDesc.width = image.width texDesc.width = image.width
texDesc.height = image.height texDesc.height = image.height
texDesc.pixelFormat = .rgba8Unorm_srgb texDesc.pixelFormat = .rgba8Unorm_srgb
texDesc.textureType = .type2D texDesc.textureType = .type2D
texDesc.storageMode = .managed texDesc.storageMode = .private
texDesc.usage = .shaderRead texDesc.usage = .shaderRead
guard let newTexture = device.makeTexture(descriptor: texDesc) else { guard let newTexture = device.makeTexture(descriptor: texDesc) else {
throw RendererError.loadFailure("Failed to create texture descriptor") throw RendererError.loadFailure("Failed to create texture descriptor")
} }
image.data.withUnsafeBytes { bytes in
newTexture.replace( guard let texData = image.data.withUnsafeBytes({ bytes in
region: .init( device.makeBuffer(bytes: bytes.baseAddress!, length: bytes.count, options: [ .storageModeShared ])
origin: .init(x: 0, y: 0, z: 0), }) else {
size: .init(width: image.width, height: image.height, depth: 1)), throw RendererError.loadFailure("Failed to create shared texture data buffer")
mipmapLevel: 0,
withBytes: bytes.baseAddress!,
bytesPerRow: image.stride)
} }
guard let cmdBuffer = queue.makeCommandBuffer(),
let blitEncoder = cmdBuffer.makeBlitCommandEncoder()
else {
throw RendererError.loadFailure("Failed to create blit command encoder")
}
blitEncoder.copy(
from: texData,
sourceOffset: 0,
sourceBytesPerRow: image.stride,
sourceBytesPerImage: image.stride * image.height,
sourceSize: .init(width: image.width, height: image.height, depth: 1),
to: newTexture,
destinationSlice: 0,
destinationLevel: 0,
destinationOrigin: .init(x: 0, y: 0, z: 0))
blitEncoder.endEncoding()
cmdBuffer.addCompletedHandler { _ in
//FIXME: look into if this needs to be synchronised
//printErr("Texture was added?")
}
cmdBuffer.commit()
return newTexture return newTexture
} }