Blender  V3.3
gl_framebuffer.cc
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later
2  * Copyright 2020 Blender Foundation. All rights reserved. */
3 
8 #include "BKE_global.h"
9 
10 #include "gl_backend.hh"
11 #include "gl_debug.hh"
12 #include "gl_state.hh"
13 #include "gl_texture.hh"
14 
15 #include "gl_framebuffer.hh"
16 
17 namespace blender::gpu {
18 
19 /* -------------------------------------------------------------------- */
23 GLFrameBuffer::GLFrameBuffer(const char *name) : FrameBuffer(name)
24 {
25  /* Just-In-Time init. See #GLFrameBuffer::init(). */
26  immutable_ = false;
27  fbo_id_ = 0;
28 }
29 
31  const char *name, GLContext *ctx, GLenum target, GLuint fbo, int w, int h)
32  : FrameBuffer(name)
33 {
34  context_ = ctx;
35  state_manager_ = static_cast<GLStateManager *>(ctx->state_manager);
36  immutable_ = true;
37  fbo_id_ = fbo;
38  gl_attachments_[0] = target;
39  /* Never update an internal frame-buffer. */
40  dirty_attachments_ = false;
41  width_ = w;
42  height_ = h;
43  srgb_ = false;
44 
45  viewport_[0] = scissor_[0] = 0;
46  viewport_[1] = scissor_[1] = 0;
47  viewport_[2] = scissor_[2] = w;
48  viewport_[3] = scissor_[3] = h;
49 
50  if (fbo_id_) {
51  debug::object_label(GL_FRAMEBUFFER, fbo_id_, name_);
52  }
53 }
54 
56 {
57  if (context_ == nullptr) {
58  return;
59  }
60 
61  /* Context might be partially freed. This happens when destroying the window frame-buffers. */
62  if (context_ == Context::get()) {
63  glDeleteFramebuffers(1, &fbo_id_);
64  }
65  else {
66  context_->fbo_free(fbo_id_);
67  }
68  /* Restore default frame-buffer if this frame-buffer was bound. */
69  if (context_->active_fb == this && context_->back_left != this) {
70  /* If this assert triggers it means the frame-buffer is being freed while in use by another
71  * context which, by the way, is TOTALLY UNSAFE! */
72  BLI_assert(context_ == Context::get());
74  }
75 }
76 
77 void GLFrameBuffer::init()
78 {
79  context_ = GLContext::get();
80  state_manager_ = static_cast<GLStateManager *>(context_->state_manager);
81  glGenFramebuffers(1, &fbo_id_);
82  /* Binding before setting the label is needed on some drivers.
83  * This is not an issue since we call this function only before binding. */
84  glBindFramebuffer(GL_FRAMEBUFFER, fbo_id_);
85 
86  debug::object_label(GL_FRAMEBUFFER, fbo_id_, name_);
87 }
88 
91 /* -------------------------------------------------------------------- */
95 bool GLFrameBuffer::check(char err_out[256])
96 {
97  this->bind(true);
98 
99  GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
100 
101 #define FORMAT_STATUS(X) \
102  case X: { \
103  err = #X; \
104  break; \
105  }
106 
107  const char *err;
108  switch (status) {
109  FORMAT_STATUS(GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT);
110  FORMAT_STATUS(GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT);
111  FORMAT_STATUS(GL_FRAMEBUFFER_UNSUPPORTED);
112  FORMAT_STATUS(GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER);
113  FORMAT_STATUS(GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER);
114  FORMAT_STATUS(GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE);
115  FORMAT_STATUS(GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS);
116  FORMAT_STATUS(GL_FRAMEBUFFER_UNDEFINED);
117  case GL_FRAMEBUFFER_COMPLETE:
118  return true;
119  default:
120  err = "unknown";
121  break;
122  }
123 
124 #undef FORMAT_STATUS
125 
126  const char *format = "GPUFrameBuffer: %s status %s\n";
127 
128  if (err_out) {
129  BLI_snprintf(err_out, 256, format, this->name_, err);
130  }
131  else {
132  fprintf(stderr, format, this->name_, err);
133  }
134 
135  return false;
136 }
137 
138 void GLFrameBuffer::update_attachments()
139 {
140  /* Default frame-buffers cannot have attachments. */
141  BLI_assert(immutable_ == false);
142 
143  /* First color texture OR the depth texture if no color is attached.
144  * Used to determine frame-buffer color-space and dimensions. */
145  GPUAttachmentType first_attachment = GPU_FB_MAX_ATTACHMENT;
146  /* NOTE: Inverse iteration to get the first color texture. */
147  for (GPUAttachmentType type = GPU_FB_MAX_ATTACHMENT - 1; type >= 0; --type) {
148  GPUAttachment &attach = attachments_[type];
149  GLenum gl_attachment = to_gl(type);
150 
152  gl_attachments_[type - GPU_FB_COLOR_ATTACHMENT0] = (attach.tex) ? gl_attachment : GL_NONE;
153  first_attachment = (attach.tex) ? type : first_attachment;
154  }
155  else if (first_attachment == GPU_FB_MAX_ATTACHMENT) {
156  /* Only use depth texture to get information if there is no color attachment. */
157  first_attachment = (attach.tex) ? type : first_attachment;
158  }
159 
160  if (attach.tex == nullptr) {
161  glFramebufferTexture(GL_FRAMEBUFFER, gl_attachment, 0, 0);
162  continue;
163  }
164  GLuint gl_tex = static_cast<GLTexture *>(unwrap(attach.tex))->tex_id_;
165  if (attach.layer > -1 && GPU_texture_cube(attach.tex) && !GPU_texture_array(attach.tex)) {
166  /* Could be avoided if ARB_direct_state_access is required. In this case
167  * #glFramebufferTextureLayer would bind the correct face. */
168  GLenum gl_target = GL_TEXTURE_CUBE_MAP_POSITIVE_X + attach.layer;
169  glFramebufferTexture2D(GL_FRAMEBUFFER, gl_attachment, gl_target, gl_tex, attach.mip);
170  }
171  else if (attach.layer > -1) {
172  glFramebufferTextureLayer(GL_FRAMEBUFFER, gl_attachment, gl_tex, attach.mip, attach.layer);
173  }
174  else {
175  /* The whole texture level is attached. The frame-buffer is potentially layered. */
176  glFramebufferTexture(GL_FRAMEBUFFER, gl_attachment, gl_tex, attach.mip);
177  }
178  /* We found one depth buffer type. Stop here, otherwise we would
179  * override it by setting GPU_FB_DEPTH_ATTACHMENT */
181  break;
182  }
183  }
184 
186  /* Fill normally un-occupied slots to avoid rendering artifacts on some hardware. */
187  GLuint gl_tex = 0;
188  /* NOTE: Inverse iteration to get the first color texture. */
189  for (int i = ARRAY_SIZE(gl_attachments_) - 1; i >= 0; --i) {
191  GPUAttachment &attach = attachments_[type];
192  if (attach.tex != nullptr) {
193  gl_tex = static_cast<GLTexture *>(unwrap(attach.tex))->tex_id_;
194  }
195  else if (gl_tex != 0) {
196  GLenum gl_attachment = to_gl(type);
197  gl_attachments_[i] = gl_attachment;
198  glFramebufferTexture(GL_FRAMEBUFFER, gl_attachment, gl_tex, 0);
199  }
200  }
201  }
202 
203  if (first_attachment != GPU_FB_MAX_ATTACHMENT) {
204  GPUAttachment &attach = attachments_[first_attachment];
205  int size[3];
206  GPU_texture_get_mipmap_size(attach.tex, attach.mip, size);
207  this->size_set(size[0], size[1]);
208  srgb_ = (GPU_texture_format(attach.tex) == GPU_SRGB8_A8);
209  }
210 
211  dirty_attachments_ = false;
212 
213  glDrawBuffers(ARRAY_SIZE(gl_attachments_), gl_attachments_);
214 
215  if (G.debug & G_DEBUG_GPU) {
216  BLI_assert(this->check(nullptr));
217  }
218 }
219 
221 {
222  if (dirty_state_ == false) {
223  return;
224  }
225 
226  glViewport(UNPACK4(viewport_));
227  glScissor(UNPACK4(scissor_));
228 
229  if (scissor_test_) {
230  glEnable(GL_SCISSOR_TEST);
231  }
232  else {
233  glDisable(GL_SCISSOR_TEST);
234  }
235 
236  dirty_state_ = false;
237 }
238 
241 /* -------------------------------------------------------------------- */
245 void GLFrameBuffer::bind(bool enabled_srgb)
246 {
247  if (!immutable_ && fbo_id_ == 0) {
248  this->init();
249  }
250 
251  if (context_ != GLContext::get()) {
252  BLI_assert_msg(0, "Trying to use the same frame-buffer in multiple context");
253  return;
254  }
255 
256  if (context_->active_fb != this) {
257  glBindFramebuffer(GL_FRAMEBUFFER, fbo_id_);
258  /* Internal frame-buffers have only one color output and needs to be set every time. */
259  if (immutable_ && fbo_id_ == 0) {
260  glDrawBuffer(gl_attachments_[0]);
261  }
262  }
263 
264  if (dirty_attachments_) {
265  this->update_attachments();
266  this->viewport_reset();
267  this->scissor_reset();
268  }
269 
270  if (context_->active_fb != this || enabled_srgb_ != enabled_srgb) {
271  enabled_srgb_ = enabled_srgb;
272  if (enabled_srgb && srgb_) {
273  glEnable(GL_FRAMEBUFFER_SRGB);
274  }
275  else {
276  glDisable(GL_FRAMEBUFFER_SRGB);
277  }
278  GPU_shader_set_framebuffer_srgb_target(enabled_srgb && srgb_);
279  }
280 
281  if (context_->active_fb != this) {
282  context_->active_fb = this;
283  state_manager_->active_fb = this;
284  dirty_state_ = true;
285  }
286 }
287 
290 /* -------------------------------------------------------------------- */
295  const float clear_col[4],
296  float clear_depth,
297  uint clear_stencil)
298 {
299  BLI_assert(GLContext::get() == context_);
300  BLI_assert(context_->active_fb == this);
301 
302  /* Save and restore the state. */
303  eGPUWriteMask write_mask = GPU_write_mask_get();
304  uint stencil_mask = GPU_stencil_mask_get();
305  eGPUStencilTest stencil_test = GPU_stencil_test_get();
306 
307  if (buffers & GPU_COLOR_BIT) {
308  GPU_color_mask(true, true, true, true);
309  glClearColor(clear_col[0], clear_col[1], clear_col[2], clear_col[3]);
310  }
311  if (buffers & GPU_DEPTH_BIT) {
312  GPU_depth_mask(true);
313  glClearDepth(clear_depth);
314  }
315  if (buffers & GPU_STENCIL_BIT) {
318  glClearStencil(clear_stencil);
319  }
320 
321  context_->state_manager->apply_state();
322 
323  GLbitfield mask = to_gl(buffers);
324  glClear(mask);
325 
326  if (buffers & (GPU_COLOR_BIT | GPU_DEPTH_BIT)) {
327  GPU_write_mask(write_mask);
328  }
329  if (buffers & GPU_STENCIL_BIT) {
330  GPU_stencil_write_mask_set(stencil_mask);
331  GPU_stencil_test(stencil_test);
332  }
333 }
334 
336  eGPUDataFormat data_format,
337  const void *clear_value)
338 {
339  BLI_assert(GLContext::get() == context_);
340  BLI_assert(context_->active_fb == this);
341 
342  /* Save and restore the state. */
343  eGPUWriteMask write_mask = GPU_write_mask_get();
344  GPU_color_mask(true, true, true, true);
345 
346  context_->state_manager->apply_state();
347 
349  BLI_assert(data_format == GPU_DATA_UINT_24_8);
350  float depth = ((*(uint32_t *)clear_value) & 0x00FFFFFFu) / (float)0x00FFFFFFu;
351  int stencil = ((*(uint32_t *)clear_value) >> 24);
352  glClearBufferfi(GL_DEPTH_STENCIL, 0, depth, stencil);
353  }
354  else if (type == GPU_FB_DEPTH_ATTACHMENT) {
355  if (data_format == GPU_DATA_FLOAT) {
356  glClearBufferfv(GL_DEPTH, 0, (GLfloat *)clear_value);
357  }
358  else if (data_format == GPU_DATA_UINT) {
359  float depth = *(uint32_t *)clear_value / (float)0xFFFFFFFFu;
360  glClearBufferfv(GL_DEPTH, 0, &depth);
361  }
362  else {
363  BLI_assert_msg(0, "Unhandled data format");
364  }
365  }
366  else {
367  int slot = type - GPU_FB_COLOR_ATTACHMENT0;
368  switch (data_format) {
369  case GPU_DATA_FLOAT:
370  glClearBufferfv(GL_COLOR, slot, (GLfloat *)clear_value);
371  break;
372  case GPU_DATA_UINT:
373  glClearBufferuiv(GL_COLOR, slot, (GLuint *)clear_value);
374  break;
375  case GPU_DATA_INT:
376  glClearBufferiv(GL_COLOR, slot, (GLint *)clear_value);
377  break;
378  default:
379  BLI_assert_msg(0, "Unhandled data format");
380  break;
381  }
382  }
383 
384  GPU_write_mask(write_mask);
385 }
386 
387 void GLFrameBuffer::clear_multi(const float (*clear_cols)[4])
388 {
389  /* WATCH: This can easily access clear_cols out of bounds it clear_cols is not big enough for
390  * all attachments.
391  * TODO(fclem): fix this insecurity? */
393  for (int i = 0; type < GPU_FB_MAX_ATTACHMENT; i++, type++) {
394  if (attachments_[type].tex != nullptr) {
395  this->clear_attachment(GPU_FB_COLOR_ATTACHMENT0 + i, GPU_DATA_FLOAT, clear_cols[i]);
396  }
397  }
398 }
399 
401  eGPUDataFormat data_format,
402  const int area[4],
403  int channel_len,
404  int slot,
405  void *r_data)
406 {
407  GLenum format, type, mode;
408  mode = gl_attachments_[slot];
409  type = to_gl(data_format);
410 
411  switch (plane) {
412  case GPU_DEPTH_BIT:
413  format = GL_DEPTH_COMPONENT;
415  this->attachments_[GPU_FB_DEPTH_ATTACHMENT].tex != nullptr ||
417  "GPUFramebuffer: Error: Trying to read depth without a depth buffer attached.");
418  break;
419  case GPU_COLOR_BIT:
421  mode != GL_NONE,
422  "GPUFramebuffer: Error: Trying to read a color slot without valid attachment.");
423  format = channel_len_to_gl(channel_len);
424  /* TODO: needed for selection buffers to work properly, this should be handled better. */
425  if (format == GL_RED && type == GL_UNSIGNED_INT) {
426  format = GL_RED_INTEGER;
427  }
428  break;
429  case GPU_STENCIL_BIT:
430  fprintf(stderr, "GPUFramebuffer: Error: Trying to read stencil bit. Unsupported.");
431  return;
432  default:
433  fprintf(stderr, "GPUFramebuffer: Error: Trying to read more than one frame-buffer plane.");
434  return;
435  }
436 
437  glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo_id_);
438  glReadBuffer(mode);
439  glReadPixels(UNPACK4(area), format, type, r_data);
440 }
441 
443  eGPUFrameBufferBits planes, int src_slot, FrameBuffer *dst_, int dst_slot, int x, int y)
444 {
445  GLFrameBuffer *src = this;
446  GLFrameBuffer *dst = static_cast<GLFrameBuffer *>(dst_);
447 
448  /* Frame-buffers must be up to date. This simplify this function. */
449  if (src->dirty_attachments_) {
450  src->bind(true);
451  }
452  if (dst->dirty_attachments_) {
453  dst->bind(true);
454  }
455 
456  glBindFramebuffer(GL_READ_FRAMEBUFFER, src->fbo_id_);
457  glBindFramebuffer(GL_DRAW_FRAMEBUFFER, dst->fbo_id_);
458 
459  if (planes & GPU_COLOR_BIT) {
460  BLI_assert(src->immutable_ == false || src_slot == 0);
461  BLI_assert(dst->immutable_ == false || dst_slot == 0);
462  BLI_assert(src->gl_attachments_[src_slot] != GL_NONE);
463  BLI_assert(dst->gl_attachments_[dst_slot] != GL_NONE);
464  glReadBuffer(src->gl_attachments_[src_slot]);
465  glDrawBuffer(dst->gl_attachments_[dst_slot]);
466  }
467 
468  context_->state_manager->apply_state();
469 
470  int w = src->width_;
471  int h = src->height_;
472  GLbitfield mask = to_gl(planes);
473  glBlitFramebuffer(0, 0, w, h, x, y, x + w, y + h, mask, GL_NEAREST);
474 
475  if (!dst->immutable_) {
476  /* Restore the draw buffers. */
477  glDrawBuffers(ARRAY_SIZE(dst->gl_attachments_), dst->gl_attachments_);
478  }
479  /* Ensure previous buffer is restored. */
480  context_->active_fb = dst;
481 }
482 
485 } // namespace blender::gpu
@ G_DEBUG_GPU
Definition: BKE_global.h:193
#define BLI_assert(a)
Definition: BLI_assert.h:46
#define BLI_assert_msg(a, msg)
Definition: BLI_assert.h:53
size_t BLI_snprintf(char *__restrict dst, size_t maxncpy, const char *__restrict format,...) ATTR_NONNULL(1
unsigned int uint
Definition: BLI_sys_types.h:67
#define UNPACK4(a)
#define ARRAY_SIZE(arr)
void GPU_framebuffer_restore(void)
eGPUFrameBufferBits
@ GPU_DEPTH_BIT
@ GPU_STENCIL_BIT
@ GPU_COLOR_BIT
#define glEnable
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint y
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum type
#define glDisable
void GPU_shader_set_framebuffer_srgb_target(int use_srgb_to_linear)
Definition: gpu_shader.cc:753
void GPU_write_mask(eGPUWriteMask mask)
Definition: gpu_state.cc:90
eGPUWriteMask
Definition: GPU_state.h:11
uint GPU_stencil_mask_get(void)
Definition: gpu_state.cc:230
void GPU_depth_mask(bool depth)
Definition: gpu_state.cc:107
void GPU_stencil_test(eGPUStencilTest test)
Definition: gpu_state.cc:70
void GPU_stencil_write_mask_set(uint write_mask)
Definition: gpu_state.cc:202
void GPU_color_mask(bool r, bool g, bool b, bool a)
Definition: gpu_state.cc:95
eGPUWriteMask GPU_write_mask_get(void)
Definition: gpu_state.cc:224
eGPUStencilTest GPU_stencil_test_get(void)
Definition: gpu_state.cc:242
eGPUStencilTest
Definition: GPU_state.h:92
@ GPU_STENCIL_ALWAYS
Definition: GPU_state.h:94
bool GPU_texture_cube(const GPUTexture *tex)
Definition: gpu_texture.cc:659
eGPUDataFormat
Definition: GPU_texture.h:170
@ GPU_DATA_UINT_24_8
Definition: GPU_texture.h:175
@ GPU_DATA_INT
Definition: GPU_texture.h:172
@ GPU_DATA_UINT
Definition: GPU_texture.h:173
@ GPU_DATA_FLOAT
Definition: GPU_texture.h:171
bool GPU_texture_array(const GPUTexture *tex)
Definition: gpu_texture.cc:664
void GPU_texture_get_mipmap_size(GPUTexture *tex, int lvl, int *size)
Definition: gpu_texture.cc:688
@ GPU_SRGB8_A8
Definition: GPU_texture.h:121
eGPUTextureFormat GPU_texture_format(const GPUTexture *tex)
Definition: gpu_texture.cc:639
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition: btDbvt.cpp:52
SIMD_FORCE_INLINE const btScalar & w() const
Return the w value.
Definition: btQuadWord.h:119
static Context * get()
Definition: gpu_context.cc:82
void size_set(int width, int height)
GPUAttachment attachments_[GPU_FB_MAX_ATTACHMENT]
static GLContext * get()
Definition: gl_context.hh:117
static bool unused_fb_slot_workaround
Definition: gl_context.hh:76
void fbo_free(GLuint fbo_id)
Definition: gl_context.cc:240
void clear(eGPUFrameBufferBits buffers, const float clear_col[4], float clear_depth, uint clear_stencil) override
bool check(char err_out[256]) override
void read(eGPUFrameBufferBits planes, eGPUDataFormat format, const int area[4], int channel_len, int slot, void *r_data) override
void clear_multi(const float(*clear_cols)[4]) override
GLFrameBuffer(const char *name)
void bind(bool enabled_srgb) override
void clear_attachment(GPUAttachmentType type, eGPUDataFormat data_format, const void *clear_value) override
void blit_to(eGPUFrameBufferBits planes, int src_slot, FrameBuffer *dst, int dst_slot, int dst_offset_x, int dst_offset_y) override
GLFrameBuffer * active_fb
Definition: gl_state.hh:31
virtual void apply_state()=0
SyclQueue void void * src
#define FORMAT_STATUS(X)
@ GPU_FB_DEPTH_STENCIL_ATTACHMENT
@ GPU_FB_MAX_ATTACHMENT
@ GPU_FB_COLOR_ATTACHMENT0
@ GPU_FB_DEPTH_ATTACHMENT
format
Definition: logImageCore.h:38
ccl_device_inline float4 mask(const int4 &mask, const float4 &a)
Definition: math_float4.h:513
#define G(x, y, z)
static void area(int d1, int d2, int e1, int e2, float weights[2])
void object_label(GLenum type, GLuint object, const char *name)
Definition: gl_debug.cc:328
static Context * unwrap(GPUContext *ctx)
GLenum channel_len_to_gl(int channel_len)
Definition: gl_texture.hh:368
static GLenum to_gl(const GPUAttachmentType type)
unsigned int uint32_t
Definition: stdint.h:80
struct GPUTexture * tex
static FT_Error err