diff --git a/projects/apis/metal/src/devices/metal_output_device.m b/projects/apis/metal/src/devices/metal_output_device.m index ab369bc..615a612 100644 --- a/projects/apis/metal/src/devices/metal_output_device.m +++ b/projects/apis/metal/src/devices/metal_output_device.m @@ -13,6 +13,8 @@ gnReturnCode createMetalOutputDevice(gnInstanceHandle instance, gnOutputDeviceHa outputDevice->outputDevice->device = deviceInfo.physicalDevice->physicalDevice->device.retain; outputDevice->outputDevice->transferQueue = outputDevice->outputDevice->device.newCommandQueue; + outputDevice->outputDevice->stagingBuffer = [outputDevice->outputDevice->device newBufferWithLength:(128 * 1024 * 1024) options:MTLResourceStorageModeShared]; + // create full screen quad float verticies[] = { -1.0f, -1.0f, 0.0f, 1.0f, diff --git a/projects/apis/metal/src/devices/metal_output_devices.h b/projects/apis/metal/src/devices/metal_output_devices.h index 8e95e6d..d84715e 100644 --- a/projects/apis/metal/src/devices/metal_output_devices.h +++ b/projects/apis/metal/src/devices/metal_output_devices.h @@ -15,6 +15,8 @@ struct gnPlatformOutputDevice_t { id executingCommandBuffer; id transferQueue; + id stagingBuffer; + id fullScreenQuadBuffer; id fullScreenShader; id fullScreenVertex, fullScreenFragment; diff --git a/projects/apis/metal/src/texture/metal_texture.m b/projects/apis/metal/src/texture/metal_texture.m index f15b523..1c53b98 100644 --- a/projects/apis/metal/src/texture/metal_texture.m +++ b/projects/apis/metal/src/texture/metal_texture.m @@ -18,7 +18,7 @@ gnReturnCode createMetalTexture(gnTexture texture, gnDevice device, const gnText MTLTextureDescriptor *textureDescriptor = [[MTLTextureDescriptor alloc] init]; textureDescriptor.sampleCount = mtlSampleCount(info.samples); textureDescriptor.usage = MTLTextureUsageRenderTarget | MTLTextureUsageShaderRead; - textureDescriptor.storageMode = MTLStorageModeShared; // Most efficient for GPU-only textures + textureDescriptor.storageMode = MTLStorageModePrivate; textureDescriptor.depth = info.extent.depth; textureDescriptor.width = info.extent.width; textureDescriptor.height = info.extent.height; @@ -45,16 +45,65 @@ gnReturnCode createMetalTexture(gnTexture texture, gnDevice device, const gnText } void metalTextureData(gnTextureHandle texture, void* pixelData) { - MTLRegion region = { - { 0, 0, 0 }, - {texture->info.extent.width, texture->info.extent.height, texture->info.extent.depth} - }; + NSUInteger fullBytesPerRow = 4 * texture->info.extent.width; + id stagingBuffer = [texture->device->outputDevice->stagingBuffer retain]; + NSUInteger maxRowsPerChunk = stagingBuffer.length / fullBytesPerRow; + if (maxRowsPerChunk == 0) maxRowsPerChunk = 1; + NSUInteger yOffset = 0; + while (yOffset < texture->info.extent.height) { + NSUInteger rowsThisChunk = MIN(maxRowsPerChunk, texture->info.extent.height - yOffset); + NSUInteger chunkSize = rowsThisChunk * fullBytesPerRow; + + // Copy chunk of pixel data into staging buffer + memcpy(stagingBuffer.contents, (uint8_t*)pixelData + yOffset * fullBytesPerRow, chunkSize); + + id cmd = [texture->device->outputDevice->transferQueue commandBuffer]; + id blitEncoder = [cmd blitCommandEncoder]; + + MTLOrigin origin = { 0, (NSUInteger)yOffset, 0 }; + MTLSize size = { (NSUInteger)texture->info.extent.width, (NSUInteger)rowsThisChunk, 1 }; + + [blitEncoder copyFromBuffer:stagingBuffer + sourceOffset:0 + sourceBytesPerRow:fullBytesPerRow + sourceBytesPerImage:chunkSize + sourceSize:size + toTexture:texture->texture->texture + destinationSlice:0 + destinationLevel:0 + destinationOrigin:origin]; + + [blitEncoder endEncoding]; + [cmd commit]; + + yOffset += rowsThisChunk; + } + + [stagingBuffer release]; + + // NSUInteger chunkSize = texture->device->outputDevice->stagingBuffer.length; + // NSUInteger totalSize = texture->info.extent.width * texture->info.extent.height * texture->info.extent.depth * 4; + // NSUInteger offset = 0; + + // while (offset < totalSize) { + // NSUInteger sizeToCopy = MIN(chunkSize, totalSize - offset); + // memcpy(texture->device->outputDevice->stagingBuffer.contents, (char*)pixelData + offset, sizeToCopy); + + // id transfer = [texture->device->outputDevice->transferQueue commandBuffer]; + // id blit = [transfer blitCommandEncoder]; + + // [blit copyFromBuffer:texture->device->outputDevice->stagingBuffer + // sourceOffset:0 + // toTexture:gpuBuffer + // destinationOffset:offset + // size:sizeToCopy]; + + // [blit endEncoding]; + // [transfer commit]; + + // offset += sizeToCopy; + // } - NSUInteger bytesPerRow = 4 * texture->info.extent.width; // TODO: fix this should not be set to 4 - [texture->texture->texture replaceRegion:region - mipmapLevel:0 - withBytes:pixelData - bytesPerRow:bytesPerRow]; } void metalDestroyTexture(gnTexture texture) {