This repository has been archived on 2023-10-09. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
blender-archive/source/blender/gpu/metal/mtl_framebuffer.hh
Jason Fielder ed8f3dc9c7 Fix T103399: correctly apply SRGB framebuffer and shader conversion mode in Metal.
First binding of a framebuffer lead to an incorrect SRGB conversion state being applied, as attachments, where presence of SRGB is determined, were processed after the SRGB check rather than before.
This DIFF also cleans up SRGB naming conventions and caching of fallback non-srgb texture view, for use when SRGB mode is disabled.

Authored by Apple: Michael Parkin-White

Ref T103399
Ref T96261

Reviewed By: fclem

Maniphest Tasks: T103399, T96261

Differential Revision: https://developer.blender.org/D16907
2023-01-08 16:00:48 +01:00

242 lines
7.1 KiB
C++

/* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup gpu
*
* Encapsulation of Frame-buffer states (attached textures, viewport, scissors).
*/
#pragma once
#include "GPU_common_types.h"
#include "MEM_guardedalloc.h"
#include "gpu_framebuffer_private.hh"
#include "mtl_texture.hh"
#include <Metal/Metal.h>
namespace blender::gpu {
class MTLContext;
struct MTLAttachment {
bool used;
gpu::MTLTexture *texture;
union {
float color[4];
float depth;
uint stencil;
} clear_value;
eGPULoadOp load_action;
eGPUStoreOp store_action;
uint mip;
uint slice;
uint depth_plane;
/* If Array Length is larger than zero, use multilayered rendering. */
uint render_target_array_length;
};
/**
* Implementation of FrameBuffer object using Metal.
*/
class MTLFrameBuffer : public FrameBuffer {
private:
/* Context Handle. */
MTLContext *context_;
/* Metal Attachment properties. */
uint colour_attachment_count_;
MTLAttachment mtl_color_attachments_[GPU_FB_MAX_COLOR_ATTACHMENT];
MTLAttachment mtl_depth_attachment_;
MTLAttachment mtl_stencil_attachment_;
bool use_multilayered_rendering_ = false;
/* State. */
/**
* Whether global frame-buffer properties have changed and require
* re-generation of #MTLRenderPassDescriptor / #RenderCommandEncoders.
*/
bool is_dirty_;
/** Whether `loadstore` properties have changed (only affects certain cached configurations). */
bool is_loadstore_dirty_;
/**
* Context that the latest modified state was last applied to.
* If this does not match current ctx, re-apply state.
*/
MTLContext *dirty_state_ctx_;
/**
* Whether a clear is pending -- Used to toggle between clear and load FB configurations
* (without dirtying the state) - Frame-buffer load config is used if no `GPU_clear_*` command
* was issued after binding the #FrameBuffer.
*/
bool has_pending_clear_;
/**
* Render Pass Descriptors:
* There are 3 #MTLRenderPassDescriptors for different ways in which a frame-buffer
* can be configured:
* [0] = CLEAR CONFIG -- Used when a GPU_framebuffer_clear_* command has been issued.
* [1] = LOAD CONFIG -- Used if bound, but no clear is required.
* [2] = CUSTOM CONFIG -- When using GPU_framebuffer_bind_ex to manually specify
* load-store configuration for optimal bandwidth utilization.
* -- We cache these different configs to avoid re-generation --
*/
typedef enum {
MTL_FB_CONFIG_CLEAR = 0,
MTL_FB_CONFIG_LOAD = 1,
MTL_FB_CONFIG_CUSTOM = 2
} MTL_FB_CONFIG;
#define MTL_FB_CONFIG_MAX (MTL_FB_CONFIG_CUSTOM + 1)
MTLRenderPassDescriptor *framebuffer_descriptor_[MTL_FB_CONFIG_MAX];
MTLRenderPassColorAttachmentDescriptor
*colour_attachment_descriptors_[GPU_FB_MAX_COLOR_ATTACHMENT];
/** Whether `MTLRenderPassDescriptor[N]` requires updating with latest state. */
bool descriptor_dirty_[MTL_FB_CONFIG_MAX];
/** Whether SRGB is enabled for this frame-buffer configuration. */
bool enabled_srgb_;
/** Whether the primary Frame-buffer attachment is an SRGB target or not. */
bool srgb_;
public:
/**
* Create a conventional framebuffer to attach texture to.
*/
MTLFrameBuffer(MTLContext *ctx, const char *name);
~MTLFrameBuffer();
void bind(bool enabled_srgb) override;
bool check(char err_out[256]) override;
void clear(eGPUFrameBufferBits buffers,
const float clear_col[4],
float clear_depth,
uint clear_stencil) override;
void clear_multi(const float (*clear_cols)[4]) override;
void clear_attachment(GPUAttachmentType type,
eGPUDataFormat data_format,
const void *clear_value) override;
void attachment_set_loadstore_op(GPUAttachmentType type,
eGPULoadOp load_action,
eGPUStoreOp store_action) override;
void read(eGPUFrameBufferBits planes,
eGPUDataFormat format,
const int area[4],
int channel_len,
int slot,
void *r_data) override;
void blit_to(eGPUFrameBufferBits planes,
int src_slot,
FrameBuffer *dst,
int dst_slot,
int dst_offset_x,
int dst_offset_y) override;
void apply_state();
/* State. */
/* Flag MTLFramebuffer configuration as having changed. */
void mark_dirty();
void mark_loadstore_dirty();
/* Mark that a pending clear has been performed. */
void mark_cleared();
/* Mark that we have a pending clear. */
void mark_do_clear();
/* Attachment management. */
/* When dirty_attachments_ is true, we need to reprocess attachments to extract Metal
* information. */
void update_attachments(bool update_viewport);
bool add_color_attachment(gpu::MTLTexture *texture, uint slot, int miplevel, int layer);
bool add_depth_attachment(gpu::MTLTexture *texture, int miplevel, int layer);
bool add_stencil_attachment(gpu::MTLTexture *texture, int miplevel, int layer);
bool remove_color_attachment(uint slot);
bool remove_depth_attachment();
bool remove_stencil_attachment();
void remove_all_attachments();
void ensure_render_target_size();
/* Clear values -> Load/store actions. */
bool set_color_attachment_clear_color(uint slot, const float clear_color[4]);
bool set_depth_attachment_clear_value(float depth_clear);
bool set_stencil_attachment_clear_value(uint stencil_clear);
bool set_color_loadstore_op(uint slot, eGPULoadOp load_action, eGPUStoreOp store_action);
bool set_depth_loadstore_op(eGPULoadOp load_action, eGPUStoreOp store_action);
bool set_stencil_loadstore_op(eGPULoadOp load_action, eGPUStoreOp store_action);
/* Remove any pending clears - Ensure "load" configuration is used. */
bool reset_clear_state();
/* Fetch values */
bool has_attachment_at_slot(uint slot);
bool has_color_attachment_with_texture(gpu::MTLTexture *texture);
bool has_depth_attachment();
bool has_stencil_attachment();
int get_color_attachment_slot_from_texture(gpu::MTLTexture *texture);
uint get_attachment_count();
uint get_attachment_limit()
{
return GPU_FB_MAX_COLOR_ATTACHMENT;
};
MTLAttachment get_color_attachment(uint slot);
MTLAttachment get_depth_attachment();
MTLAttachment get_stencil_attachment();
/* Metal API resources and validation. */
bool validate_render_pass();
MTLRenderPassDescriptor *bake_render_pass_descriptor(bool load_contents);
/* Blitting. */
void blit(uint read_slot,
uint src_x_offset,
uint src_y_offset,
MTLFrameBuffer *metal_fb_write,
uint write_slot,
uint dst_x_offset,
uint dst_y_offset,
uint width,
uint height,
eGPUFrameBufferBits blit_buffers);
int get_width();
int get_height();
bool get_dirty()
{
return is_dirty_ || is_loadstore_dirty_;
}
bool get_pending_clear()
{
return has_pending_clear_;
}
bool get_srgb_enabled()
{
return enabled_srgb_;
}
bool get_is_srgb()
{
return srgb_;
}
private:
/* Clears a render target by force-opening a render pass. */
void force_clear();
MEM_CXX_CLASS_ALLOC_FUNCS("MTLFrameBuffer");
};
} // namespace blender::gpu