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

242 lines
7.2 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 srgb_enabled_;
/** Whether the primary Frame-buffer attachment is an SRGB target or not. */
bool is_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 srgb_enabled_;
}
bool get_is_srgb()
{
return is_srgb_;
}
private:
/* Clears a render target by force-opening a render pass. */
void force_clear();
MEM_CXX_CLASS_ALLOC_FUNCS("MTLFrameBuffer");
};
} // namespace blender::gpu