diff options
| author | Andre Weissflog <floooh@gmail.com> | 2019-04-06 15:23:42 +0200 |
|---|---|---|
| committer | Andre Weissflog <floooh@gmail.com> | 2019-04-06 15:23:42 +0200 |
| commit | 86e7357d15b0d7792a9fef5e4b0fcadf52cd0ca8 (patch) | |
| tree | 9ff63a4e2b4f09e0d4294d31e630709527f1632c | |
| parent | 35f6c9c502dd564220f4ea3c25b5a66d6218159e (diff) | |
sokol_gfx.h Metal: clean up MTLTextureDesc intitialization a bit
| -rw-r--r-- | sokol_gfx.h | 160 |
1 files changed, 114 insertions, 46 deletions
diff --git a/sokol_gfx.h b/sokol_gfx.h index c87affe9..ec1a869c 100644 --- a/sokol_gfx.h +++ b/sokol_gfx.h @@ -7234,6 +7234,99 @@ _SOKOL_PRIVATE void _sg_mtl_copy_image_content(const _sg_image_t* img, __unsafe_ } } +/* + FIXME: METAL RESOURCE STORAGE MODE FOR macOS AND iOS + + For immutable textures on macOS, the recommended procedure is to create + a MTLStorageModeManaged texture with the immutable content first, + and then use the GPU to blit the content into a MTLStorageModePrivate + texture before the first use. + + On iOS use the same one-time-blit procedure, but from a + MTLStorageModeShared to a MTLStorageModePrivate texture. + + It probably makes sense to handle this in a separate 'resource manager' + with a recycable pool of blit-source-textures? +*/ + +/* initialize MTLTextureDescritor with common attributes */ +_SOKOL_PRIVATE bool _sg_mtl_init_texdesc_common(MTLTextureDescriptor* mtl_desc, _sg_image_t* img) { + mtl_desc.textureType = _sg_mtl_texture_type(img->type); + if (img->render_target) { + if (_sg_is_valid_rendertarget_color_format(img->pixel_format)) { + mtl_desc.pixelFormat = _sg_mtl_rendertarget_color_format(img->pixel_format); + } + else { + mtl_desc.pixelFormat = _sg_mtl_rendertarget_depth_format(img->pixel_format); + } + } + else { + mtl_desc.pixelFormat = _sg_mtl_texture_format(img->pixel_format); + } + if (MTLPixelFormatInvalid == mtl_desc.pixelFormat) { + SOKOL_LOG("Unsupported texture pixel format!\n"); + return false; + } + mtl_desc.width = img->width; + mtl_desc.height = img->height; + if (SG_IMAGETYPE_3D == img->type) { + mtl_desc.depth = img->depth; + } + else { + mtl_desc.depth = 1; + } + mtl_desc.mipmapLevelCount = img->num_mipmaps; + if (SG_IMAGETYPE_ARRAY == img->type) { + mtl_desc.arrayLength = img->depth; + } + else { + mtl_desc.arrayLength = 1; + } + mtl_desc.usage = MTLTextureUsageShaderRead; + if (img->usage != SG_USAGE_IMMUTABLE) { + mtl_desc.cpuCacheMode = MTLCPUCacheModeWriteCombined; + } + #if defined(TARGET_OS_IPHONE) && !TARGET_OS_IPHONE + /* macOS: use managed textures */ + mtl_desc.resourceOptions = MTLResourceStorageModeManaged; + mtl_desc.storageMode = MTLStorageModeManaged; + #else + /* iOS: use CPU/GPU shared memory */ + mtl_desc.resourceOptions = MTLResourceStorageModeShared; + mtl_desc.storageMode = MTLStorageModeShared; + #endif + return true; +} + +/* initialize MTLTextureDescritor with rendertarget attributes */ +_SOKOL_PRIVATE void _sg_mtl_init_texdesc_rt(MTLTextureDescriptor* mtl_desc, _sg_image_t* img) { + SOKOL_ASSERT(img->render_target); + /* reset the cpuCacheMode to 'default' */ + mtl_desc.cpuCacheMode = MTLCPUCacheModeDefaultCache; + /* render targets are only visible to the GPU */ + mtl_desc.resourceOptions = MTLResourceStorageModePrivate; + mtl_desc.storageMode = MTLStorageModePrivate; + /* non-MSAA render targets are shader-readable */ + mtl_desc.usage = MTLTextureUsageShaderRead | MTLTextureUsageRenderTarget; +} + +/* initialize MTLTextureDescritor with MSAA attributes */ +_SOKOL_PRIVATE void _sg_mtl_init_texdesc_rt_msaa(MTLTextureDescriptor* mtl_desc, _sg_image_t* img) { + SOKOL_ASSERT(img->sample_count > 1); + /* reset the cpuCacheMode to 'default' */ + mtl_desc.cpuCacheMode = MTLCPUCacheModeDefaultCache; + /* render targets are only visible to the GPU */ + mtl_desc.resourceOptions = MTLResourceStorageModePrivate; + mtl_desc.storageMode = MTLStorageModePrivate; + /* MSAA render targets are not shader-readable (instead they are resolved) */ + mtl_desc.usage = MTLTextureUsageRenderTarget; + mtl_desc.textureType = MTLTextureType2DMultisample; + mtl_desc.depth = 1; + mtl_desc.arrayLength = 1; + mtl_desc.mipmapLevelCount = 1; + mtl_desc.sampleCount = img->sample_count; +} + _SOKOL_PRIVATE sg_resource_state _sg_create_image(_sg_image_t* img, const sg_image_desc* desc) { SOKOL_ASSERT(img && desc); img->type = desc->type; @@ -7255,6 +7348,7 @@ _SOKOL_PRIVATE sg_resource_state _sg_create_image(_sg_image_t* img, const sg_ima img->num_slots = (img->usage == SG_USAGE_IMMUTABLE) ? 1 :SG_NUM_INFLIGHT_FRAMES; img->active_slot = 0; const bool injected = (0 != desc->mtl_textures[0]); + const bool msaa = (img->sample_count > 1); /* first initialize all Metal resource pool slots to 'empty' */ for (int i = 0; i < SG_NUM_INFLIGHT_FRAMES; i++) { @@ -7266,61 +7360,39 @@ _SOKOL_PRIVATE sg_resource_state _sg_create_image(_sg_image_t* img, const sg_ima /* initialize a Metal texture descriptor with common attributes */ MTLTextureDescriptor* mtl_desc = [[MTLTextureDescriptor alloc] init]; - mtl_desc.textureType = _sg_mtl_texture_type(img->type); - if (img->render_target) { - if (_sg_is_valid_rendertarget_color_format(img->pixel_format)) { - mtl_desc.pixelFormat = _sg_mtl_rendertarget_color_format(img->pixel_format); - } - else { - mtl_desc.pixelFormat = _sg_mtl_rendertarget_depth_format(img->pixel_format); - } - } - else { - mtl_desc.pixelFormat = _sg_mtl_texture_format(img->pixel_format); - } - if (MTLPixelFormatInvalid == mtl_desc.pixelFormat) { - SOKOL_LOG("Unsupported texture pixel format!\n"); + if (!_sg_mtl_init_texdesc_common(mtl_desc, img)) { return SG_RESOURCESTATE_FAILED; } - mtl_desc.width = img->width; - mtl_desc.height = img->height; - if (SG_IMAGETYPE_3D == img->type) { - mtl_desc.depth = img->depth; - } - else { - mtl_desc.depth = 1; - } - mtl_desc.mipmapLevelCount = img->num_mipmaps; - if (SG_IMAGETYPE_ARRAY == img->type) { - mtl_desc.arrayLength = img->depth; - } - else { - mtl_desc.arrayLength = 1; - } - if (img->render_target) { - mtl_desc.resourceOptions = MTLResourceStorageModePrivate; - mtl_desc.cpuCacheMode = MTLCPUCacheModeDefaultCache; - mtl_desc.storageMode = MTLStorageModePrivate; - mtl_desc.usage |= MTLTextureUsageRenderTarget; - } /* special case depth-stencil-buffer? */ if (_sg_is_valid_rendertarget_depth_format(img->pixel_format)) { - /* create only a depth texture */ + /* depth-stencil buffer texture must always be a render target */ SOKOL_ASSERT(img->render_target); SOKOL_ASSERT(img->type == SG_IMAGETYPE_2D); SOKOL_ASSERT(img->num_mipmaps == 1); SOKOL_ASSERT(!injected); - if (img->sample_count > 1) { - mtl_desc.textureType = MTLTextureType2DMultisample; - mtl_desc.sampleCount = img->sample_count; + if (msaa) { + _sg_mtl_init_texdesc_rt_msaa(mtl_desc, img); + } + else { + _sg_mtl_init_texdesc_rt(mtl_desc, img); } id<MTLTexture> tex = [_sg_mtl_device newTextureWithDescriptor:mtl_desc]; SOKOL_ASSERT(nil != tex); img->mtl_depth_tex = _sg_mtl_add_resource(tex); } else { - /* create the color texture(s) */ + /* create the color texture + In case this is a render target without MSAA, add the relevant + render-target descriptor attributes. + In case this is a render target *with* MSAA, the color texture + will serve as MSAA-resolve target (not as render target), and rendering + will go into a separate render target texture of type + MTLTextureType2DMultisample. + */ + if (img->render_target && !msaa) { + _sg_mtl_init_texdesc_rt(mtl_desc, img); + } for (int slot = 0; slot < img->num_slots; slot++) { id<MTLTexture> tex; if (injected) { @@ -7337,12 +7409,8 @@ _SOKOL_PRIVATE sg_resource_state _sg_create_image(_sg_image_t* img, const sg_ima } /* if MSAA color render target, create an additional MSAA render-surface texture */ - if (img->render_target && (img->sample_count > 1)) { - mtl_desc.textureType = MTLTextureType2DMultisample; - mtl_desc.depth = 1; - mtl_desc.arrayLength = 1; - mtl_desc.mipmapLevelCount = 1; - mtl_desc.sampleCount = img->sample_count; + if (img->render_target && msaa) { + _sg_mtl_init_texdesc_rt_msaa(mtl_desc, img); id<MTLTexture> tex = [_sg_mtl_device newTextureWithDescriptor:mtl_desc]; img->mtl_msaa_tex = _sg_mtl_add_resource(tex); } |