GPU: Add support for memoryless textures
Memoryless textures are only used as intermediate attachments during rasterization, but do not have any backing storage. This is particularly useful if a virutal framebuffer is needed, or, there is a situation where a depth buffer is only needed within the pass itself and the results are discarded once the pass completes. Authored by Apple: Michael Parkin-White Pull Request: https://projects.blender.org/blender/blender/pulls/111749
This commit is contained in:
committed by
Clément Foucault
parent
109bc2d416
commit
c375e9725f
@@ -546,9 +546,12 @@ typedef enum eGPUTextureUsage {
|
||||
GPU_TEXTURE_USAGE_MIP_SWIZZLE_VIEW = (1 << 3),
|
||||
/* Whether the texture needs to be read from by the CPU. */
|
||||
GPU_TEXTURE_USAGE_HOST_READ = (1 << 4),
|
||||
/* When used, the texture will not have any backing storage and can solely exist as a virtual
|
||||
* framebuffer attachment. */
|
||||
GPU_TEXTURE_USAGE_MEMORYLESS = (1 << 5),
|
||||
/* Create a texture whose usage cannot be defined prematurely.
|
||||
* This is unoptimized and should not be used. */
|
||||
GPU_TEXTURE_USAGE_GENERAL = 0xFF,
|
||||
GPU_TEXTURE_USAGE_GENERAL = (0xFF & (~GPU_TEXTURE_USAGE_MEMORYLESS)),
|
||||
} eGPUTextureUsage;
|
||||
|
||||
ENUM_OPERATORS(eGPUTextureUsage, GPU_TEXTURE_USAGE_GENERAL);
|
||||
|
||||
@@ -1633,6 +1633,9 @@ MTLRenderPassDescriptor *MTLFrameBuffer::bake_render_pass_descriptor(bool load_c
|
||||
MTL_LOG_ERROR("Attempting to assign invalid texture as attachment");
|
||||
}
|
||||
|
||||
bool texture_is_memoryless = (mtl_color_attachments_[attachment_ind].texture->usage_get() &
|
||||
GPU_TEXTURE_USAGE_MEMORYLESS);
|
||||
|
||||
/* IF SRGB is enabled, but we are rendering with SRGB disabled, sample texture view. */
|
||||
id<MTLTexture> source_color_texture = texture;
|
||||
if (this->get_is_srgb() &&
|
||||
@@ -1651,11 +1654,23 @@ MTLRenderPassDescriptor *MTLFrameBuffer::bake_render_pass_descriptor(bool load_c
|
||||
/* MTL_FB_CONFIG_LOAD must always load. */
|
||||
load_action = GPU_LOADACTION_LOAD;
|
||||
}
|
||||
else if (descriptor_config == MTL_FB_CONFIG_CUSTOM && load_action == GPU_LOADACTION_CLEAR)
|
||||
else if (descriptor_config == MTL_FB_CONFIG_CUSTOM &&
|
||||
load_action == GPU_LOADACTION_CLEAR && !texture_is_memoryless)
|
||||
{
|
||||
/* Custom config should be LOAD or DONT_CARE only. */
|
||||
/* Custom config should be LOAD or DONT_CARE only, unless attachment is memoryless and
|
||||
* cannot be cleared/written to by another pass. */
|
||||
load_action = GPU_LOADACTION_LOAD;
|
||||
}
|
||||
|
||||
/* Ensure memoryless attachment cannot load or store results. */
|
||||
eGPUStoreOp store_action = mtl_color_attachments_[attachment_ind].store_action;
|
||||
if (texture_is_memoryless && load_action == GPU_LOADACTION_LOAD) {
|
||||
load_action = GPU_LOADACTION_DONT_CARE;
|
||||
}
|
||||
if (texture_is_memoryless && store_action == GPU_STOREACTION_STORE) {
|
||||
store_action = GPU_STOREACTION_DONT_CARE;
|
||||
}
|
||||
|
||||
attachment.texture = source_color_texture;
|
||||
attachment.loadAction = mtl_load_action_from_gpu(load_action);
|
||||
attachment.clearColor =
|
||||
@@ -1665,8 +1680,7 @@ MTLRenderPassDescriptor *MTLFrameBuffer::bake_render_pass_descriptor(bool load_c
|
||||
mtl_color_attachments_[attachment_ind].clear_value.color[2],
|
||||
mtl_color_attachments_[attachment_ind].clear_value.color[3]) :
|
||||
MTLClearColorMake(0.0, 0.0, 0.0, 0.0);
|
||||
attachment.storeAction = mtl_store_action_from_gpu(
|
||||
mtl_color_attachments_[attachment_ind].store_action);
|
||||
attachment.storeAction = mtl_store_action_from_gpu(store_action);
|
||||
attachment.level = mtl_color_attachments_[attachment_ind].mip;
|
||||
attachment.slice = mtl_color_attachments_[attachment_ind].slice;
|
||||
attachment.depthPlane = mtl_color_attachments_[attachment_ind].depth_plane;
|
||||
@@ -1690,6 +1704,9 @@ MTLRenderPassDescriptor *MTLFrameBuffer::bake_render_pass_descriptor(bool load_c
|
||||
framebuffer_descriptor_[descriptor_config].depthAttachment.texture =
|
||||
(id<MTLTexture>)mtl_depth_attachment_.texture->get_metal_handle_base();
|
||||
|
||||
bool texture_is_memoryless = (mtl_depth_attachment_.texture->usage_get() &
|
||||
GPU_TEXTURE_USAGE_MEMORYLESS);
|
||||
|
||||
/* Resolve appropriate load action -- IF force load, perform load.
|
||||
* If clear but framebuffer has no pending clear, also load. */
|
||||
eGPULoadOp load_action = mtl_depth_attachment_.load_action;
|
||||
@@ -1697,16 +1714,29 @@ MTLRenderPassDescriptor *MTLFrameBuffer::bake_render_pass_descriptor(bool load_c
|
||||
/* MTL_FB_CONFIG_LOAD must always load. */
|
||||
load_action = GPU_LOADACTION_LOAD;
|
||||
}
|
||||
else if (descriptor_config == MTL_FB_CONFIG_CUSTOM && load_action == GPU_LOADACTION_CLEAR) {
|
||||
/* Custom config should be LOAD or DONT_CARE only. */
|
||||
else if (descriptor_config == MTL_FB_CONFIG_CUSTOM && load_action == GPU_LOADACTION_CLEAR &&
|
||||
!texture_is_memoryless)
|
||||
{
|
||||
/* Custom config should be LOAD or DONT_CARE only, unless attachment is memoryless and
|
||||
* cannot be cleared/written to by another pass. */
|
||||
load_action = GPU_LOADACTION_LOAD;
|
||||
}
|
||||
|
||||
/* Ensure memoryless attachment cannot load or store results. */
|
||||
eGPUStoreOp store_action = mtl_depth_attachment_.store_action;
|
||||
if (texture_is_memoryless && load_action == GPU_LOADACTION_LOAD) {
|
||||
load_action = GPU_LOADACTION_DONT_CARE;
|
||||
}
|
||||
if (texture_is_memoryless && store_action == GPU_STOREACTION_STORE) {
|
||||
store_action = GPU_STOREACTION_DONT_CARE;
|
||||
}
|
||||
|
||||
framebuffer_descriptor_[descriptor_config].depthAttachment.loadAction =
|
||||
mtl_load_action_from_gpu(load_action);
|
||||
framebuffer_descriptor_[descriptor_config].depthAttachment.clearDepth =
|
||||
(load_action == GPU_LOADACTION_CLEAR) ? mtl_depth_attachment_.clear_value.depth : 0;
|
||||
framebuffer_descriptor_[descriptor_config].depthAttachment.storeAction =
|
||||
mtl_store_action_from_gpu(mtl_depth_attachment_.store_action);
|
||||
mtl_store_action_from_gpu(store_action);
|
||||
framebuffer_descriptor_[descriptor_config].depthAttachment.level = mtl_depth_attachment_.mip;
|
||||
framebuffer_descriptor_[descriptor_config].depthAttachment.slice =
|
||||
mtl_depth_attachment_.slice;
|
||||
@@ -1722,6 +1752,9 @@ MTLRenderPassDescriptor *MTLFrameBuffer::bake_render_pass_descriptor(bool load_c
|
||||
framebuffer_descriptor_[descriptor_config].stencilAttachment.texture =
|
||||
(id<MTLTexture>)mtl_stencil_attachment_.texture->get_metal_handle_base();
|
||||
|
||||
bool texture_is_memoryless = (mtl_stencil_attachment_.texture->usage_get() &
|
||||
GPU_TEXTURE_USAGE_MEMORYLESS);
|
||||
|
||||
/* Resolve appropriate load action -- IF force load, perform load.
|
||||
* If clear but framebuffer has no pending clear, also load. */
|
||||
eGPULoadOp load_action = mtl_stencil_attachment_.load_action;
|
||||
@@ -1729,16 +1762,29 @@ MTLRenderPassDescriptor *MTLFrameBuffer::bake_render_pass_descriptor(bool load_c
|
||||
/* MTL_FB_CONFIG_LOAD must always load. */
|
||||
load_action = GPU_LOADACTION_LOAD;
|
||||
}
|
||||
else if (descriptor_config == MTL_FB_CONFIG_CUSTOM && load_action == GPU_LOADACTION_CLEAR) {
|
||||
/* Custom config should be LOAD or DONT_CARE only. */
|
||||
else if (descriptor_config == MTL_FB_CONFIG_CUSTOM && load_action == GPU_LOADACTION_CLEAR &&
|
||||
!texture_is_memoryless)
|
||||
{
|
||||
/* Custom config should be LOAD or DONT_CARE only, unless attachment is memoryless and
|
||||
* cannot be cleared/written to by another pass. */
|
||||
load_action = GPU_LOADACTION_LOAD;
|
||||
}
|
||||
|
||||
/* Ensure memoryless attachment cannot load or store results. */
|
||||
eGPUStoreOp store_action = mtl_stencil_attachment_.store_action;
|
||||
if (texture_is_memoryless && load_action == GPU_LOADACTION_LOAD) {
|
||||
load_action = GPU_LOADACTION_DONT_CARE;
|
||||
}
|
||||
if (texture_is_memoryless && store_action == GPU_STOREACTION_STORE) {
|
||||
store_action = GPU_STOREACTION_DONT_CARE;
|
||||
}
|
||||
|
||||
framebuffer_descriptor_[descriptor_config].stencilAttachment.loadAction =
|
||||
mtl_load_action_from_gpu(load_action);
|
||||
framebuffer_descriptor_[descriptor_config].stencilAttachment.clearStencil =
|
||||
(load_action == GPU_LOADACTION_CLEAR) ? mtl_stencil_attachment_.clear_value.stencil : 0;
|
||||
framebuffer_descriptor_[descriptor_config].stencilAttachment.storeAction =
|
||||
mtl_store_action_from_gpu(mtl_stencil_attachment_.store_action);
|
||||
mtl_store_action_from_gpu(store_action);
|
||||
framebuffer_descriptor_[descriptor_config].stencilAttachment.level =
|
||||
mtl_stencil_attachment_.mip;
|
||||
framebuffer_descriptor_[descriptor_config].stencilAttachment.slice =
|
||||
|
||||
@@ -2136,10 +2136,22 @@ void gpu::MTLTexture::ensure_baked()
|
||||
/* Determine Resource Mode. */
|
||||
resource_mode_ = MTL_TEXTURE_MODE_DEFAULT;
|
||||
|
||||
/* Override storage mode if memoryless attachments are being used. */
|
||||
if (gpu_image_usage_flags_ & GPU_TEXTURE_USAGE_MEMORYLESS) {
|
||||
texture_descriptor_.storageMode = MTLStorageModeMemoryless;
|
||||
}
|
||||
|
||||
/* Standard texture allocation. */
|
||||
texture_ = [ctx->device newTextureWithDescriptor:texture_descriptor_];
|
||||
#ifndef NDEBUG
|
||||
if (gpu_image_usage_flags_ & GPU_TEXTURE_USAGE_MEMORYLESS) {
|
||||
texture_.label = [NSString stringWithFormat:@"MemorylessTexture_%s", this->get_name()];
|
||||
}
|
||||
else {
|
||||
texture_.label = [NSString stringWithFormat:@"Texture_%s", this->get_name()];
|
||||
}
|
||||
#endif
|
||||
|
||||
texture_.label = [NSString stringWithUTF8String:this->get_name()];
|
||||
BLI_assert(texture_);
|
||||
is_baked_ = true;
|
||||
is_dirty_ = false;
|
||||
|
||||
Reference in New Issue
Block a user