Blender  V2.93
gl_framebuffer.cc
Go to the documentation of this file.
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  *
16  * The Original Code is Copyright (C) 2020 Blender Foundation.
17  * All rights reserved.
18  */
19 
24 #include "BKE_global.h"
25 
26 #include "GPU_capabilities.h"
27 
28 #include "gl_backend.hh"
29 #include "gl_debug.hh"
30 #include "gl_state.hh"
31 #include "gl_texture.hh"
32 
33 #include "gl_framebuffer.hh"
34 
35 namespace blender::gpu {
36 
37 /* -------------------------------------------------------------------- */
41 GLFrameBuffer::GLFrameBuffer(const char *name) : FrameBuffer(name)
42 {
43  /* Just-In-Time init. See #GLFrameBuffer::init(). */
44  immutable_ = false;
45  fbo_id_ = 0;
46 }
47 
49  const char *name, GLContext *ctx, GLenum target, GLuint fbo, int w, int h)
50  : FrameBuffer(name)
51 {
52  context_ = ctx;
53  state_manager_ = static_cast<GLStateManager *>(ctx->state_manager);
54  immutable_ = true;
55  fbo_id_ = fbo;
56  gl_attachments_[0] = target;
57  /* Never update an internal frame-buffer. */
58  dirty_attachments_ = false;
59  width_ = w;
60  height_ = h;
61  srgb_ = false;
62 
63  viewport_[0] = scissor_[0] = 0;
64  viewport_[1] = scissor_[1] = 0;
65  viewport_[2] = scissor_[2] = w;
66  viewport_[3] = scissor_[3] = h;
67 
68  if (fbo_id_) {
69  debug::object_label(GL_FRAMEBUFFER, fbo_id_, name_);
70  }
71 }
72 
74 {
75  if (context_ == nullptr) {
76  return;
77  }
78 
79  /* Context might be partially freed. This happens when destroying the window frame-buffers. */
80  if (context_ == Context::get()) {
81  glDeleteFramebuffers(1, &fbo_id_);
82  }
83  else {
84  context_->fbo_free(fbo_id_);
85  }
86  /* Restore default frame-buffer if this frame-buffer was bound. */
87  if (context_->active_fb == this && context_->back_left != this) {
88  /* If this assert triggers it means the frame-buffer is being freed while in use by another
89  * context which, by the way, is TOTALLY UNSAFE!!! */
90  BLI_assert(context_ == Context::get());
92  }
93 }
94 
95 void GLFrameBuffer::init()
96 {
97  context_ = GLContext::get();
98  state_manager_ = static_cast<GLStateManager *>(context_->state_manager);
99  glGenFramebuffers(1, &fbo_id_);
100  /* Binding before setting the label is needed on some drivers.
101  * This is not an issue since we call this function only before binding. */
102  glBindFramebuffer(GL_FRAMEBUFFER, fbo_id_);
103 
104  debug::object_label(GL_FRAMEBUFFER, fbo_id_, name_);
105 }
106 
109 /* -------------------------------------------------------------------- */
113 /* This is a rather slow operation. Don't check in normal cases. */
114 bool GLFrameBuffer::check(char err_out[256])
115 {
116  this->bind(true);
117 
118  GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
119 
120 #define FORMAT_STATUS(X) \
121  case X: { \
122  err = #X; \
123  break; \
124  }
125 
126  const char *err;
127  switch (status) {
128  FORMAT_STATUS(GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT);
129  FORMAT_STATUS(GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT);
130  FORMAT_STATUS(GL_FRAMEBUFFER_UNSUPPORTED);
131  FORMAT_STATUS(GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER);
132  FORMAT_STATUS(GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER);
133  FORMAT_STATUS(GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE);
134  FORMAT_STATUS(GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS);
135  FORMAT_STATUS(GL_FRAMEBUFFER_UNDEFINED);
136  case GL_FRAMEBUFFER_COMPLETE:
137  return true;
138  default:
139  err = "unknown";
140  break;
141  }
142 
143 #undef FORMAT_STATUS
144 
145  const char *format = "GPUFrameBuffer: %s status %s\n";
146 
147  if (err_out) {
148  BLI_snprintf(err_out, 256, format, this->name_, err);
149  }
150  else {
151  fprintf(stderr, format, this->name_, err);
152  }
153 
154  return false;
155 }
156 
157 void GLFrameBuffer::update_attachments()
158 {
159  /* Default frame-buffers cannot have attachments. */
160  BLI_assert(immutable_ == false);
161 
162  /* First color texture OR the depth texture if no color is attached.
163  * Used to determine frame-buffer color-space and dimensions. */
164  GPUAttachmentType first_attachment = GPU_FB_MAX_ATTACHMENT;
165  /* NOTE: Inverse iteration to get the first color texture. */
166  for (GPUAttachmentType type = GPU_FB_MAX_ATTACHMENT - 1; type >= 0; --type) {
167  GPUAttachment &attach = attachments_[type];
168  GLenum gl_attachment = to_gl(type);
169 
171  gl_attachments_[type - GPU_FB_COLOR_ATTACHMENT0] = (attach.tex) ? gl_attachment : GL_NONE;
172  first_attachment = (attach.tex) ? type : first_attachment;
173  }
174  else if (first_attachment == GPU_FB_MAX_ATTACHMENT) {
175  /* Only use depth texture to get information if there is no color attachment. */
176  first_attachment = (attach.tex) ? type : first_attachment;
177  }
178 
179  if (attach.tex == nullptr) {
180  glFramebufferTexture(GL_FRAMEBUFFER, gl_attachment, 0, 0);
181  continue;
182  }
183  GLuint gl_tex = static_cast<GLTexture *>(unwrap(attach.tex))->tex_id_;
184  if (attach.layer > -1 && GPU_texture_cube(attach.tex) && !GPU_texture_array(attach.tex)) {
185  /* Could be avoided if ARB_direct_state_access is required. In this case
186  * #glFramebufferTextureLayer would bind the correct face. */
187  GLenum gl_target = GL_TEXTURE_CUBE_MAP_POSITIVE_X + attach.layer;
188  glFramebufferTexture2D(GL_FRAMEBUFFER, gl_attachment, gl_target, gl_tex, attach.mip);
189  }
190  else if (attach.layer > -1) {
191  glFramebufferTextureLayer(GL_FRAMEBUFFER, gl_attachment, gl_tex, attach.mip, attach.layer);
192  }
193  else {
194  /* The whole texture level is attached. The frame-buffer is potentially layered. */
195  glFramebufferTexture(GL_FRAMEBUFFER, gl_attachment, gl_tex, attach.mip);
196  }
197  /* We found one depth buffer type. Stop here, otherwise we would
198  * override it by setting GPU_FB_DEPTH_ATTACHMENT */
200  break;
201  }
202  }
203 
205  /* Fill normally un-occupied slots to avoid rendering artifacts on some hardware. */
206  GLuint gl_tex = 0;
207  /* NOTE: Inverse iteration to get the first color texture. */
208  for (int i = ARRAY_SIZE(gl_attachments_) - 1; i >= 0; --i) {
210  GPUAttachment &attach = attachments_[type];
211  if (attach.tex != nullptr) {
212  gl_tex = static_cast<GLTexture *>(unwrap(attach.tex))->tex_id_;
213  }
214  else if (gl_tex != 0) {
215  GLenum gl_attachment = to_gl(type);
216  gl_attachments_[i] = gl_attachment;
217  glFramebufferTexture(GL_FRAMEBUFFER, gl_attachment, gl_tex, 0);
218  }
219  }
220  }
221 
222  if (first_attachment != GPU_FB_MAX_ATTACHMENT) {
223  GPUAttachment &attach = attachments_[first_attachment];
224  int size[3];
225  GPU_texture_get_mipmap_size(attach.tex, attach.mip, size);
226  this->size_set(size[0], size[1]);
227  srgb_ = (GPU_texture_format(attach.tex) == GPU_SRGB8_A8);
228  }
229 
230  dirty_attachments_ = false;
231 
232  glDrawBuffers(ARRAY_SIZE(gl_attachments_), gl_attachments_);
233 
234  if (G.debug & G_DEBUG_GPU) {
235  BLI_assert(this->check(nullptr));
236  }
237 }
238 
240 {
241  if (dirty_state_ == false) {
242  return;
243  }
244 
245  glViewport(UNPACK4(viewport_));
246  glScissor(UNPACK4(scissor_));
247 
248  if (scissor_test_) {
249  glEnable(GL_SCISSOR_TEST);
250  }
251  else {
252  glDisable(GL_SCISSOR_TEST);
253  }
254 
255  dirty_state_ = false;
256 }
257 
260 /* -------------------------------------------------------------------- */
264 void GLFrameBuffer::bind(bool enabled_srgb)
265 {
266  if (!immutable_ && fbo_id_ == 0) {
267  this->init();
268  }
269 
270  if (context_ != GLContext::get()) {
271  BLI_assert(!"Trying to use the same frame-buffer in multiple context");
272  return;
273  }
274 
275  if (context_->active_fb != this) {
276  glBindFramebuffer(GL_FRAMEBUFFER, fbo_id_);
277  /* Internal frame-buffers have only one color output and needs to be set every time. */
278  if (immutable_ && fbo_id_ == 0) {
279  glDrawBuffer(gl_attachments_[0]);
280  }
281  }
282 
283  if (dirty_attachments_) {
284  this->update_attachments();
285  this->viewport_reset();
286  this->scissor_reset();
287  }
288 
289  if (context_->active_fb != this || enabled_srgb_ != enabled_srgb) {
290  enabled_srgb_ = enabled_srgb;
291  if (enabled_srgb && srgb_) {
292  glEnable(GL_FRAMEBUFFER_SRGB);
293  }
294  else {
295  glDisable(GL_FRAMEBUFFER_SRGB);
296  }
297  GPU_shader_set_framebuffer_srgb_target(enabled_srgb && srgb_);
298  }
299 
300  if (context_->active_fb != this) {
301  context_->active_fb = this;
302  state_manager_->active_fb = this;
303  dirty_state_ = true;
304  }
305 }
306 
309 /* -------------------------------------------------------------------- */
314  const float clear_col[4],
315  float clear_depth,
316  uint clear_stencil)
317 {
318  BLI_assert(GLContext::get() == context_);
319  BLI_assert(context_->active_fb == this);
320 
321  /* Save and restore the state. */
322  eGPUWriteMask write_mask = GPU_write_mask_get();
323  uint stencil_mask = GPU_stencil_mask_get();
324  eGPUStencilTest stencil_test = GPU_stencil_test_get();
325 
326  if (buffers & GPU_COLOR_BIT) {
327  GPU_color_mask(true, true, true, true);
328  glClearColor(clear_col[0], clear_col[1], clear_col[2], clear_col[3]);
329  }
330  if (buffers & GPU_DEPTH_BIT) {
331  GPU_depth_mask(true);
332  glClearDepth(clear_depth);
333  }
334  if (buffers & GPU_STENCIL_BIT) {
337  glClearStencil(clear_stencil);
338  }
339 
340  context_->state_manager->apply_state();
341 
342  GLbitfield mask = to_gl(buffers);
343  glClear(mask);
344 
345  if (buffers & (GPU_COLOR_BIT | GPU_DEPTH_BIT)) {
346  GPU_write_mask(write_mask);
347  }
348  if (buffers & GPU_STENCIL_BIT) {
349  GPU_stencil_write_mask_set(stencil_mask);
350  GPU_stencil_test(stencil_test);
351  }
352 }
353 
355  eGPUDataFormat data_format,
356  const void *clear_value)
357 {
358  BLI_assert(GLContext::get() == context_);
359  BLI_assert(context_->active_fb == this);
360 
361  /* Save and restore the state. */
362  eGPUWriteMask write_mask = GPU_write_mask_get();
363  GPU_color_mask(true, true, true, true);
364 
365  context_->state_manager->apply_state();
366 
368  BLI_assert(data_format == GPU_DATA_UINT_24_8);
369  float depth = ((*(uint32_t *)clear_value) & 0x00FFFFFFu) / (float)0x00FFFFFFu;
370  int stencil = ((*(uint32_t *)clear_value) >> 24);
371  glClearBufferfi(GL_DEPTH_STENCIL, 0, depth, stencil);
372  }
373  else if (type == GPU_FB_DEPTH_ATTACHMENT) {
374  if (data_format == GPU_DATA_FLOAT) {
375  glClearBufferfv(GL_DEPTH, 0, (GLfloat *)clear_value);
376  }
377  else if (data_format == GPU_DATA_UINT) {
378  float depth = *(uint32_t *)clear_value / (float)0xFFFFFFFFu;
379  glClearBufferfv(GL_DEPTH, 0, &depth);
380  }
381  else {
382  BLI_assert(!"Unhandled data format");
383  }
384  }
385  else {
386  int slot = type - GPU_FB_COLOR_ATTACHMENT0;
387  switch (data_format) {
388  case GPU_DATA_FLOAT:
389  glClearBufferfv(GL_COLOR, slot, (GLfloat *)clear_value);
390  break;
391  case GPU_DATA_UINT:
392  glClearBufferuiv(GL_COLOR, slot, (GLuint *)clear_value);
393  break;
394  case GPU_DATA_INT:
395  glClearBufferiv(GL_COLOR, slot, (GLint *)clear_value);
396  break;
397  default:
398  BLI_assert(!"Unhandled data format");
399  break;
400  }
401  }
402 
403  GPU_write_mask(write_mask);
404 }
405 
406 void GLFrameBuffer::clear_multi(const float (*clear_cols)[4])
407 {
408  /* WATCH: This can easily access clear_cols out of bounds it clear_cols is not big enough for
409  * all attachments.
410  * TODO(fclem): fix this insecurity? */
412  for (int i = 0; type < GPU_FB_MAX_ATTACHMENT; i++, type++) {
413  if (attachments_[type].tex != nullptr) {
414  this->clear_attachment(GPU_FB_COLOR_ATTACHMENT0 + i, GPU_DATA_FLOAT, clear_cols[i]);
415  }
416  }
417 }
418 
420  eGPUDataFormat data_format,
421  const int area[4],
422  int channel_len,
423  int slot,
424  void *r_data)
425 {
426  GLenum format, type, mode;
427  mode = gl_attachments_[slot];
428  type = to_gl(data_format);
429 
430  switch (plane) {
431  case GPU_DEPTH_BIT:
432  format = GL_DEPTH_COMPONENT;
433  break;
434  case GPU_COLOR_BIT:
435  format = channel_len_to_gl(channel_len);
436  /* TODO: needed for selection buffers to work properly, this should be handled better. */
437  if (format == GL_RED && type == GL_UNSIGNED_INT) {
438  format = GL_RED_INTEGER;
439  }
440  break;
441  case GPU_STENCIL_BIT:
442  fprintf(stderr, "GPUFramebuffer: Error: Trying to read stencil bit. Unsupported.");
443  return;
444  default:
445  fprintf(stderr, "GPUFramebuffer: Error: Trying to read more than one frame-buffer plane.");
446  return;
447  }
448 
449  glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo_id_);
450  glReadBuffer(mode);
451  glReadPixels(UNPACK4(area), format, type, r_data);
452 }
453 
458  eGPUFrameBufferBits planes, int src_slot, FrameBuffer *dst_, int dst_slot, int x, int y)
459 {
460  GLFrameBuffer *src = this;
461  GLFrameBuffer *dst = static_cast<GLFrameBuffer *>(dst_);
462 
463  /* Frame-buffers must be up to date. This simplify this function. */
464  if (src->dirty_attachments_) {
465  src->bind(true);
466  }
467  if (dst->dirty_attachments_) {
468  dst->bind(true);
469  }
470 
471  glBindFramebuffer(GL_READ_FRAMEBUFFER, src->fbo_id_);
472  glBindFramebuffer(GL_DRAW_FRAMEBUFFER, dst->fbo_id_);
473 
474  if (planes & GPU_COLOR_BIT) {
475  BLI_assert(src->immutable_ == false || src_slot == 0);
476  BLI_assert(dst->immutable_ == false || dst_slot == 0);
477  BLI_assert(src->gl_attachments_[src_slot] != GL_NONE);
478  BLI_assert(dst->gl_attachments_[dst_slot] != GL_NONE);
479  glReadBuffer(src->gl_attachments_[src_slot]);
480  glDrawBuffer(dst->gl_attachments_[dst_slot]);
481  }
482 
483  context_->state_manager->apply_state();
484 
485  int w = src->width_;
486  int h = src->height_;
487  GLbitfield mask = to_gl(planes);
488  glBlitFramebuffer(0, 0, w, h, x, y, x + w, y + h, mask, GL_NEAREST);
489 
490  if (!dst->immutable_) {
491  /* Restore the draw buffers. */
492  glDrawBuffers(ARRAY_SIZE(dst->gl_attachments_), dst->gl_attachments_);
493  }
494  /* Ensure previous buffer is restored. */
495  context_->active_fb = dst;
496 }
497 
500 } // namespace blender::gpu
@ G_DEBUG_GPU
Definition: BKE_global.h:151
#define BLI_assert(a)
Definition: BLI_assert.h:58
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:83
#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 type
_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
#define glDisable
void GPU_shader_set_framebuffer_srgb_target(int use_srgb_to_linear)
Definition: gpu_shader.cc:740
void GPU_write_mask(eGPUWriteMask mask)
Definition: gpu_state.cc:100
eGPUWriteMask
Definition: GPU_state.h:25
uint GPU_stencil_mask_get(void)
Definition: gpu_state.cc:249
void GPU_depth_mask(bool depth)
Definition: gpu_state.cc:117
void GPU_stencil_test(eGPUStencilTest test)
Definition: gpu_state.cc:80
void GPU_stencil_write_mask_set(uint write_mask)
Definition: gpu_state.cc:221
void GPU_color_mask(bool r, bool g, bool b, bool a)
Definition: gpu_state.cc:105
eGPUWriteMask GPU_write_mask_get(void)
Definition: gpu_state.cc:243
eGPUStencilTest GPU_stencil_test_get(void)
Definition: gpu_state.cc:261
eGPUStencilTest
Definition: GPU_state.h:87
@ GPU_STENCIL_ALWAYS
Definition: GPU_state.h:89
bool GPU_texture_cube(const GPUTexture *tex)
Definition: gpu_texture.cc:574
eGPUDataFormat
Definition: GPU_texture.h:171
@ GPU_DATA_UINT_24_8
Definition: GPU_texture.h:176
@ GPU_DATA_INT
Definition: GPU_texture.h:173
@ GPU_DATA_UINT
Definition: GPU_texture.h:174
@ GPU_DATA_FLOAT
Definition: GPU_texture.h:172
bool GPU_texture_array(const GPUTexture *tex)
Definition: gpu_texture.cc:579
void GPU_texture_get_mipmap_size(GPUTexture *tex, int lvl, int *size)
Definition: gpu_texture.cc:590
@ GPU_SRGB8_A8
Definition: GPU_texture.h:122
eGPUTextureFormat GPU_texture_format(const GPUTexture *tex)
Definition: gpu_texture.cc:554
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(void)
Definition: gpu_context.cc:88
void size_set(int width, int height)
GPUAttachment attachments_[GPU_FB_MAX_ATTACHMENT]
static GLContext * get()
Definition: gl_context.hh:118
static bool unused_fb_slot_workaround
Definition: gl_context.hh:79
void fbo_free(GLuint fbo_id)
Definition: gl_context.cc:247
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:46
virtual void apply_state(void)=0
static FT_Error err
Definition: freetypefont.c:52
#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:47
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:335
static Context * unwrap(GPUContext *ctx)
GLenum channel_len_to_gl(int channel_len)
Definition: gl_texture.hh:370
static GLenum to_gl(const GPUAttachmentType type)
unsigned int uint32_t
Definition: stdint.h:83
struct GPUTexture * tex
ccl_device_inline float4 mask(const int4 &mask, const float4 &a)
#define G(x, y, z)