Welcome to mirror list, hosted at ThFree Co, Russian Federation.

mtl_framebuffer.hh « metal « gpu « blender « source - git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: 434d1a15b4371e0c2c4f47eea1cfa2c0c7c156db (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
/* 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