diff --git a/base/sources/backends/metal_gpu.h b/base/sources/backends/metal_gpu.h index ca51827e..b225d8ef 100644 --- a/base/sources/backends/metal_gpu.h +++ b/base/sources/backends/metal_gpu.h @@ -15,7 +15,6 @@ typedef struct { typedef struct { void *_tex; void *data; - void *_readback; } gpu_texture_impl_t; typedef struct { diff --git a/base/sources/backends/metal_gpu.m b/base/sources/backends/metal_gpu.m index 19605033..fa26eb2f 100644 --- a/base/sources/backends/metal_gpu.m +++ b/base/sources/backends/metal_gpu.m @@ -30,6 +30,7 @@ static gpu_texture_t *current_textures[GPU_MAX_TEXTURES] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }; +static void *readback_buffer; static MTLBlendFactor convert_blending_factor(gpu_blending_factor_t factor) { switch (factor) { @@ -107,12 +108,11 @@ static int format_byte_size(gpu_texture_format_t format) { } void gpu_render_target_init2(gpu_texture_t *target, int width, int height, gpu_texture_format_t format, int framebuffer_index) { - memset(target, 0, sizeof(gpu_texture_t)); target->width = width; target->height = height; target->format = format; target->state = GPU_TEXTURE_STATE_RENDER_TARGET; - target->impl._readback = NULL; + target->buffer = NULL; if (framebuffer_index < 0) { id device = getMetalDevice(); @@ -131,6 +131,8 @@ void gpu_render_target_init2(gpu_texture_t *target, int width, int height, gpu_t } void gpu_destroy(void) { + id readback = (__bridge_transfer id)readback_buffer; + readback = nil; } void gpu_resize_internal(int width, int height) { @@ -356,44 +358,32 @@ void gpu_set_index_buffer(gpu_buffer_t *buffer) { void gpu_get_render_target_pixels(gpu_texture_t *render_target, uint8_t *data) { gpu_execute_and_wait(); - // Create readback buffer - if (render_target->impl._readback == NULL) { + if (readback_buffer == NULL) { id device = getMetalDevice(); - MTLTextureDescriptor *descriptor = [MTLTextureDescriptor new]; - descriptor.textureType = MTLTextureType2D; - descriptor.width = render_target->width; - descriptor.height = render_target->height; - descriptor.depth = 1; - descriptor.pixelFormat = [(__bridge id)render_target->impl._tex pixelFormat]; - descriptor.arrayLength = 1; - descriptor.mipmapLevelCount = 1; - descriptor.usage = MTLTextureUsageUnknown; - descriptor.resourceOptions = MTLResourceStorageModeShared; - render_target->impl._readback = (__bridge_retained void *)[device newTextureWithDescriptor:descriptor]; + NSUInteger buffer_size = render_target->width * render_target->height * format_byte_size(render_target->format); + readback_buffer = (__bridge_retained void *)[device newBufferWithLength:buffer_size options:MTLResourceStorageModeShared]; } // Copy render target to readback buffer id queue = getMetalQueue(); - id commandBuffer = [queue commandBuffer]; - id commandEncoder = [commandBuffer blitCommandEncoder]; - [commandEncoder copyFromTexture:(__bridge id)render_target->impl._tex - sourceSlice:0 - sourceLevel:0 - sourceOrigin:MTLOriginMake(0, 0, 0) - sourceSize:MTLSizeMake(render_target->width, render_target->height, 1) - toTexture:(__bridge id)render_target->impl._readback - destinationSlice:0 - destinationLevel:0 - destinationOrigin:MTLOriginMake(0, 0, 0)]; - [commandEncoder endEncoding]; - [commandBuffer commit]; - [commandBuffer waitUntilCompleted]; + id command_buffer = [queue commandBuffer]; + id command_encoder = [command_buffer blitCommandEncoder]; + [command_encoder copyFromTexture:(__bridge id)render_target->impl._tex + sourceSlice:0 + sourceLevel:0 + sourceOrigin:MTLOriginMake(0, 0, 0) + sourceSize:MTLSizeMake(render_target->width, render_target->height, 1) + toBuffer:(__bridge id)readback_buffer + destinationOffset:0 + destinationBytesPerRow:render_target->width * format_byte_size(render_target->format) + destinationBytesPerImage:0]; + [command_encoder endEncoding]; + [command_buffer commit]; + [command_buffer waitUntilCompleted]; // Read buffer - id tex = (__bridge id)render_target->impl._readback; - int byte_size = format_byte_size(render_target->format); - MTLRegion region = MTLRegionMake2D(0, 0, render_target->width, render_target->height); - [tex getBytes:data bytesPerRow:byte_size * render_target->width fromRegion:region mipmapLevel:0]; + id buffer = (__bridge id)readback_buffer; + memcpy(data, [buffer contents], render_target->width * render_target->height * format_byte_size(render_target->format)); } void gpu_set_constant_buffer(gpu_buffer_t *buffer, int offset, size_t size) { @@ -542,6 +532,7 @@ void gpu_texture_init_from_bytes(gpu_texture_t *texture, void *data, int width, texture->height = height; texture->format = format; texture->state = GPU_TEXTURE_STATE_SHADER_RESOURCE; + target->buffer = NULL; MTLPixelFormat mtlformat = convert_texture_format(format); if (mtlformat == MTLPixelFormatBGRA8Unorm) { @@ -575,10 +566,6 @@ void gpu_texture_destroy(gpu_texture_t *target) { id tex = (__bridge_transfer id)target->impl._tex; tex = nil; target->impl._tex = NULL; - - id readback = (__bridge_transfer id)target->impl._readback; - readback = nil; - target->impl._readback = NULL; } void gpu_render_target_init(gpu_texture_t *target, int width, int height, gpu_texture_format_t format) { @@ -586,7 +573,6 @@ void gpu_render_target_init(gpu_texture_t *target, int width, int height, gpu_te } void gpu_vertex_buffer_init(gpu_buffer_t *buffer, int count, gpu_vertex_structure_t *structure) { - memset(&buffer->impl, 0, sizeof(buffer->impl)); buffer->count = count; for (int i = 0; i < structure->size; ++i) { gpu_vertex_element_t element = structure->elements[i];