Blender V4.3
gl_framebuffer.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2020 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
9#include "BLI_string.h"
10
11#include "BKE_global.hh"
12
13#include "gl_backend.hh"
14#include "gl_debug.hh"
15#include "gl_state.hh"
16#include "gl_texture.hh"
17
18#include "gl_framebuffer.hh"
19
20namespace blender::gpu {
21
22/* -------------------------------------------------------------------- */
27{
28 /* Just-In-Time init. See #GLFrameBuffer::init(). */
29 immutable_ = false;
30 fbo_id_ = 0;
31}
32
34 const char *name, GLContext *ctx, GLenum target, GLuint fbo, int w, int h)
35 : FrameBuffer(name)
36{
37 context_ = ctx;
38 state_manager_ = static_cast<GLStateManager *>(ctx->state_manager);
39 immutable_ = true;
40 fbo_id_ = fbo;
41 gl_attachments_[0] = target;
42 /* Never update an internal frame-buffer. */
43 dirty_attachments_ = false;
44 width_ = w;
45 height_ = h;
46 srgb_ = false;
47
48 viewport_[0][0] = scissor_[0] = 0;
49 viewport_[0][1] = scissor_[1] = 0;
50 viewport_[0][2] = scissor_[2] = w;
51 viewport_[0][3] = scissor_[3] = h;
52
53 if (fbo_id_) {
54 debug::object_label(GL_FRAMEBUFFER, fbo_id_, name_);
55 }
56}
57
59{
60 if (context_ == nullptr) {
61 return;
62 }
63
64 /* Context might be partially freed. This happens when destroying the window frame-buffers. */
65 if (context_ == Context::get()) {
66 glDeleteFramebuffers(1, &fbo_id_);
67 }
68 else {
69 context_->fbo_free(fbo_id_);
70 }
71 /* Restore default frame-buffer if this frame-buffer was bound. */
72 if (context_->active_fb == this && context_->back_left != this) {
73 /* If this assert triggers it means the frame-buffer is being freed while in use by another
74 * context which, by the way, is TOTALLY UNSAFE! */
75 BLI_assert(context_ == Context::get());
77 }
78}
79
80void GLFrameBuffer::init()
81{
82 context_ = GLContext::get();
83 state_manager_ = static_cast<GLStateManager *>(context_->state_manager);
84 glGenFramebuffers(1, &fbo_id_);
85 /* Binding before setting the label is needed on some drivers.
86 * This is not an issue since we call this function only before binding. */
87 glBindFramebuffer(GL_FRAMEBUFFER, fbo_id_);
88
89 debug::object_label(GL_FRAMEBUFFER, fbo_id_, name_);
90}
91
94/* -------------------------------------------------------------------- */
98bool GLFrameBuffer::check(char err_out[256])
99{
100 this->bind(true);
101
102 GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
103
104#define FORMAT_STATUS(X) \
105 case X: { \
106 err = #X; \
107 break; \
108 }
109
110 const char *err;
111 switch (status) {
112 FORMAT_STATUS(GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT);
113 FORMAT_STATUS(GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT);
114 FORMAT_STATUS(GL_FRAMEBUFFER_UNSUPPORTED);
115 FORMAT_STATUS(GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER);
116 FORMAT_STATUS(GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER);
117 FORMAT_STATUS(GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE);
118 FORMAT_STATUS(GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS);
119 FORMAT_STATUS(GL_FRAMEBUFFER_UNDEFINED);
120 case GL_FRAMEBUFFER_COMPLETE:
121 return true;
122 default:
123 err = "unknown";
124 break;
125 }
126
127#undef FORMAT_STATUS
128
129 const char *format = "GPUFrameBuffer: %s status %s\n";
130
131 if (err_out) {
132 BLI_snprintf(err_out, 256, format, this->name_, err);
133 }
134 else {
135 fprintf(stderr, format, this->name_, err);
136 }
137
138 return false;
139}
140
141void GLFrameBuffer::update_attachments()
142{
143 /* Default frame-buffers cannot have attachments. */
144 BLI_assert(immutable_ == false);
145
146 /* First color texture OR the depth texture if no color is attached.
147 * Used to determine frame-buffer color-space and dimensions. */
148 GPUAttachmentType first_attachment = GPU_FB_MAX_ATTACHMENT;
149 /* NOTE: Inverse iteration to get the first color texture. */
150 for (GPUAttachmentType type = GPU_FB_MAX_ATTACHMENT - 1; type >= 0; --type) {
151 GPUAttachment &attach = attachments_[type];
152 GLenum gl_attachment = to_gl(type);
153
154 if (type >= GPU_FB_COLOR_ATTACHMENT0) {
155 gl_attachments_[type - GPU_FB_COLOR_ATTACHMENT0] = (attach.tex) ? gl_attachment : GL_NONE;
156 first_attachment = (attach.tex) ? type : first_attachment;
157 }
158 else if (first_attachment == GPU_FB_MAX_ATTACHMENT) {
159 /* Only use depth texture to get information if there is no color attachment. */
160 first_attachment = (attach.tex) ? type : first_attachment;
161 }
162
163 if (attach.tex == nullptr) {
164 glFramebufferTexture(GL_FRAMEBUFFER, gl_attachment, 0, 0);
165 continue;
166 }
167 GLuint gl_tex = static_cast<GLTexture *>(unwrap(attach.tex))->tex_id_;
168 if (attach.layer > -1 && GPU_texture_is_cube(attach.tex) && !GPU_texture_is_array(attach.tex))
169 {
170 /* Could be avoided if ARB_direct_state_access is required. In this case
171 * #glFramebufferTextureLayer would bind the correct face. */
172 GLenum gl_target = GL_TEXTURE_CUBE_MAP_POSITIVE_X + attach.layer;
173 glFramebufferTexture2D(GL_FRAMEBUFFER, gl_attachment, gl_target, gl_tex, attach.mip);
174 }
175 else if (attach.layer > -1) {
176 glFramebufferTextureLayer(GL_FRAMEBUFFER, gl_attachment, gl_tex, attach.mip, attach.layer);
177 }
178 else {
179 /* The whole texture level is attached. The frame-buffer is potentially layered. */
180 glFramebufferTexture(GL_FRAMEBUFFER, gl_attachment, gl_tex, attach.mip);
181 }
182 /* We found one depth buffer type. Stop here, otherwise we would
183 * override it by setting GPU_FB_DEPTH_ATTACHMENT */
185 break;
186 }
187 }
188
190 /* Fill normally un-occupied slots to avoid rendering artifacts on some hardware. */
191 GLuint gl_tex = 0;
192 /* NOTE: Inverse iteration to get the first color texture. */
193 for (int i = ARRAY_SIZE(gl_attachments_) - 1; i >= 0; --i) {
195 GPUAttachment &attach = attachments_[type];
196 if (attach.tex != nullptr) {
197 gl_tex = static_cast<GLTexture *>(unwrap(attach.tex))->tex_id_;
198 }
199 else if (gl_tex != 0) {
200 GLenum gl_attachment = to_gl(type);
201 gl_attachments_[i] = gl_attachment;
202 glFramebufferTexture(GL_FRAMEBUFFER, gl_attachment, gl_tex, 0);
203 }
204 }
205 }
206
207 if (first_attachment != GPU_FB_MAX_ATTACHMENT) {
208 GPUAttachment &attach = attachments_[first_attachment];
209 int size[3];
210 GPU_texture_get_mipmap_size(attach.tex, attach.mip, size);
211 this->size_set(size[0], size[1]);
212 srgb_ = (GPU_texture_format(attach.tex) == GPU_SRGB8_A8);
213 }
214 else {
215 /* Empty frame-buffer. */
216 glFramebufferParameteri(GL_FRAMEBUFFER, GL_FRAMEBUFFER_DEFAULT_WIDTH, width_);
217 glFramebufferParameteri(GL_FRAMEBUFFER, GL_FRAMEBUFFER_DEFAULT_HEIGHT, height_);
218 }
219
220 dirty_attachments_ = false;
221
222 glDrawBuffers(ARRAY_SIZE(gl_attachments_), gl_attachments_);
223
224 if (G.debug & G_DEBUG_GPU) {
225 BLI_assert(this->check(nullptr));
226 }
227}
228
230 Span<GPUAttachmentState> color_attachment_states)
231{
232 GPU_depth_mask(depth_attachment_state == GPU_ATTACHMENT_WRITE);
233
234 bool any_read = false;
235 for (auto attachment : color_attachment_states.index_range()) {
236 if (attachment == GPU_ATTACHMENT_READ) {
237 any_read = true;
238 break;
239 }
240 }
241
243 if (any_read) {
244 glFramebufferFetchBarrierEXT();
245 }
246 }
248 if (any_read) {
249 glTextureBarrier();
250 }
251
252 GLenum attachments[GPU_FB_MAX_COLOR_ATTACHMENT] = {GL_NONE};
253 for (int i : color_attachment_states.index_range()) {
255 GPUTexture *attach_tex = this->attachments_[type].tex;
256 if (color_attachment_states[i] == GPU_ATTACHMENT_READ) {
257 tmp_detached_[type] = this->attachments_[type]; /* Bypass feedback loop check. */
259 }
260 else {
261 tmp_detached_[type] = GPU_ATTACHMENT_NONE;
262 }
263 bool attach_write = color_attachment_states[i] == GPU_ATTACHMENT_WRITE;
264 attachments[i] = (attach_tex && attach_write) ? to_gl(type) : GL_NONE;
265 }
266 /* We have to use `glDrawBuffers` instead of `glColorMaski` because the later is overwritten
267 * by the `GLStateManager`. */
268 /* WATCH(fclem): This modifies the frame-buffer state without setting `dirty_attachments_`. */
269 glDrawBuffers(ARRAY_SIZE(attachments), attachments);
270 }
271 else {
272 /* The only way to have correct visibility without extensions and ensure defined behavior, is
273 * to unbind the textures and update the frame-buffer. This is a slow operation but that's all
274 * we can do to emulate the sub-pass input. */
275 /* TODO(@fclem): Could avoid the frame-buffer reconfiguration by creating multiple
276 * frame-buffers internally. */
277 for (int i : color_attachment_states.index_range()) {
279
280 if (color_attachment_states[i] == GPU_ATTACHMENT_WRITE) {
281 if (tmp_detached_[type].tex != nullptr) {
282 /* Re-attach previous read attachments. */
283 this->attachment_set(type, tmp_detached_[type]);
284 tmp_detached_[type] = GPU_ATTACHMENT_NONE;
285 }
286 }
287 else if (color_attachment_states[i] == GPU_ATTACHMENT_READ) {
288 tmp_detached_[type] = this->attachments_[type];
289 unwrap(tmp_detached_[type].tex)->detach_from(this);
291 }
292 }
293 if (dirty_attachments_) {
294 this->update_attachments();
295 }
296 }
297}
298
300{
301 BLI_assert(context_->active_fb == this);
302
303 /* TODO(fclem): Add support for other ops. */
305 if (tmp_detached_[type].tex != nullptr) {
306 /* #GPULoadStore is used to define the frame-buffer before it is used for rendering.
307 * Binding back unattached attachment makes its state undefined. This is described by the
308 * documentation and the user-land code should specify a sub-pass at the start of the drawing
309 * to explicitly set attachment state. */
311 /* NOOP. */
312 }
314 /* Reset default attachment state. */
315 for (int i : IndexRange(ARRAY_SIZE(tmp_detached_))) {
316 tmp_detached_[i] = GPU_ATTACHMENT_NONE;
317 }
318 glDrawBuffers(ARRAY_SIZE(gl_attachments_), gl_attachments_);
319 }
320 else {
321 tmp_detached_[type] = GPU_ATTACHMENT_NONE;
322 this->attachment_set(type, tmp_detached_[type]);
323 this->update_attachments();
324 }
325 }
327 }
328}
329
331{
332 if (dirty_state_ == false) {
333 return;
334 }
335
336 if (multi_viewport_ == false) {
337 glViewport(UNPACK4(viewport_[0]));
338 }
339 else {
340 /* Great API you have there! You have to convert to float values for setting int viewport
341 * values. **Audible Facepalm** */
342 float viewports_f[GPU_MAX_VIEWPORTS][4];
343 for (int i = 0; i < GPU_MAX_VIEWPORTS; i++) {
344 for (int j = 0; j < 4; j++) {
345 viewports_f[i][j] = viewport_[i][j];
346 }
347 }
348 glViewportArrayv(0, GPU_MAX_VIEWPORTS, viewports_f[0]);
349 }
350 glScissor(UNPACK4(scissor_));
351
352 if (scissor_test_) {
353 glEnable(GL_SCISSOR_TEST);
354 }
355 else {
356 glDisable(GL_SCISSOR_TEST);
357 }
358
359 dirty_state_ = false;
360}
361
364/* -------------------------------------------------------------------- */
368void GLFrameBuffer::bind(bool enabled_srgb)
369{
370 if (!immutable_ && fbo_id_ == 0) {
371 this->init();
372 }
373
374 if (context_ != GLContext::get()) {
375 BLI_assert_msg(0, "Trying to use the same frame-buffer in multiple context");
376 return;
377 }
378
379 if (context_->active_fb != this) {
380 glBindFramebuffer(GL_FRAMEBUFFER, fbo_id_);
381 /* Internal frame-buffers have only one color output and needs to be set every time. */
382 if (immutable_ && fbo_id_ == 0) {
383 glDrawBuffer(gl_attachments_[0]);
384 }
385 }
386
388 for (int index : IndexRange(GPU_FB_MAX_ATTACHMENT)) {
389 tmp_detached_[index] = GPU_ATTACHMENT_NONE;
390 }
391 }
392
393 if (dirty_attachments_) {
394 this->update_attachments();
395 this->viewport_reset();
396 this->scissor_reset();
397 }
398
399 if (context_->active_fb != this || enabled_srgb_ != enabled_srgb) {
400 enabled_srgb_ = enabled_srgb;
401 if (enabled_srgb && srgb_) {
402 glEnable(GL_FRAMEBUFFER_SRGB);
403 }
404 else {
405 glDisable(GL_FRAMEBUFFER_SRGB);
406 }
407 Shader::set_framebuffer_srgb_target(enabled_srgb && srgb_);
408 }
409
410 if (context_->active_fb != this) {
411 context_->active_fb = this;
412 state_manager_->active_fb = this;
413 dirty_state_ = true;
414 }
415}
416
419/* -------------------------------------------------------------------- */
424 const float clear_col[4],
425 float clear_depth,
426 uint clear_stencil)
427{
428 BLI_assert(GLContext::get() == context_);
429 BLI_assert(context_->active_fb == this);
430
431 /* Save and restore the state. */
432 eGPUWriteMask write_mask = GPU_write_mask_get();
433 uint stencil_mask = GPU_stencil_mask_get();
434 eGPUStencilTest stencil_test = GPU_stencil_test_get();
435
436 if (buffers & GPU_COLOR_BIT) {
437 GPU_color_mask(true, true, true, true);
438 glClearColor(clear_col[0], clear_col[1], clear_col[2], clear_col[3]);
439 }
440 if (buffers & GPU_DEPTH_BIT) {
441 GPU_depth_mask(true);
442 glClearDepth(clear_depth);
443 }
444 if (buffers & GPU_STENCIL_BIT) {
447 glClearStencil(clear_stencil);
448 }
449
450 context_->state_manager->apply_state();
451
452 GLbitfield mask = to_gl(buffers);
453 glClear(mask);
454
456 GPU_write_mask(write_mask);
457 }
458 if (buffers & GPU_STENCIL_BIT) {
459 GPU_stencil_write_mask_set(stencil_mask);
460 GPU_stencil_test(stencil_test);
461 }
462}
463
465 eGPUDataFormat data_format,
466 const void *clear_value)
467{
468 BLI_assert(GLContext::get() == context_);
469 BLI_assert(context_->active_fb == this);
470
471 /* Save and restore the state. */
472 eGPUWriteMask write_mask = GPU_write_mask_get();
473 GPU_color_mask(true, true, true, true);
474 bool depth_mask = GPU_depth_mask_get();
475 GPU_depth_mask(true);
476
477 context_->state_manager->apply_state();
478
480 BLI_assert(data_format == GPU_DATA_UINT_24_8);
481 float depth = ((*(uint32_t *)clear_value) & 0x00FFFFFFu) / float(0x00FFFFFFu);
482 int stencil = ((*(uint32_t *)clear_value) >> 24);
483 glClearBufferfi(GL_DEPTH_STENCIL, 0, depth, stencil);
484 }
485 else if (type == GPU_FB_DEPTH_ATTACHMENT) {
486 if (data_format == GPU_DATA_FLOAT) {
487 glClearBufferfv(GL_DEPTH, 0, (GLfloat *)clear_value);
488 }
489 else if (data_format == GPU_DATA_UINT) {
490 float depth = *(uint32_t *)clear_value / float(0xFFFFFFFFu);
491 glClearBufferfv(GL_DEPTH, 0, &depth);
492 }
493 else {
494 BLI_assert_msg(0, "Unhandled data format");
495 }
496 }
497 else {
498 int slot = type - GPU_FB_COLOR_ATTACHMENT0;
499 switch (data_format) {
500 case GPU_DATA_FLOAT:
501 glClearBufferfv(GL_COLOR, slot, (GLfloat *)clear_value);
502 break;
503 case GPU_DATA_UINT:
504 glClearBufferuiv(GL_COLOR, slot, (GLuint *)clear_value);
505 break;
506 case GPU_DATA_INT:
507 glClearBufferiv(GL_COLOR, slot, (GLint *)clear_value);
508 break;
509 default:
510 BLI_assert_msg(0, "Unhandled data format");
511 break;
512 }
513 }
514
515 GPU_write_mask(write_mask);
516 GPU_depth_mask(depth_mask);
517}
518
519void GLFrameBuffer::clear_multi(const float (*clear_cols)[4])
520{
521 /* WATCH: This can easily access clear_cols out of bounds it clear_cols is not big enough for
522 * all attachments.
523 * TODO(fclem): fix this insecurity? */
524 int type = GPU_FB_COLOR_ATTACHMENT0;
525 for (int i = 0; type < GPU_FB_MAX_ATTACHMENT; i++, type++) {
526 if (attachments_[type].tex != nullptr) {
528 }
529 }
530}
531
533 eGPUDataFormat data_format,
534 const int area[4],
535 int channel_len,
536 int slot,
537 void *r_data)
538{
539 GLenum format, type, mode;
540 mode = gl_attachments_[slot];
541 type = to_gl(data_format);
542
543 switch (plane) {
544 case GPU_DEPTH_BIT:
545 format = GL_DEPTH_COMPONENT;
547 this->attachments_[GPU_FB_DEPTH_ATTACHMENT].tex != nullptr ||
549 "GPUFramebuffer: Error: Trying to read depth without a depth buffer attached.");
550 break;
551 case GPU_COLOR_BIT:
553 mode != GL_NONE,
554 "GPUFramebuffer: Error: Trying to read a color slot without valid attachment.");
555 format = channel_len_to_gl(channel_len);
556 /* TODO: needed for selection buffers to work properly, this should be handled better. */
557 if (format == GL_RED && type == GL_UNSIGNED_INT) {
558 format = GL_RED_INTEGER;
559 }
560 break;
561 case GPU_STENCIL_BIT:
562 fprintf(stderr, "GPUFramebuffer: Error: Trying to read stencil bit. Unsupported.");
563 return;
564 default:
565 fprintf(stderr, "GPUFramebuffer: Error: Trying to read more than one frame-buffer plane.");
566 return;
567 }
568
569 glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo_id_);
570 glReadBuffer(mode);
571 glReadPixels(UNPACK4(area), format, type, r_data);
572}
573
575 eGPUFrameBufferBits planes, int src_slot, FrameBuffer *dst_, int dst_slot, int x, int y)
576{
577 GLFrameBuffer *src = this;
578 GLFrameBuffer *dst = static_cast<GLFrameBuffer *>(dst_);
579
580 /* Frame-buffers must be up to date. This simplify this function. */
581 if (src->dirty_attachments_) {
582 src->bind(true);
583 }
584 if (dst->dirty_attachments_) {
585 dst->bind(true);
586 }
587
588 glBindFramebuffer(GL_READ_FRAMEBUFFER, src->fbo_id_);
589 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, dst->fbo_id_);
590
591 if (planes & GPU_COLOR_BIT) {
592 BLI_assert(src->immutable_ == false || src_slot == 0);
593 BLI_assert(dst->immutable_ == false || dst_slot == 0);
594 BLI_assert(src->gl_attachments_[src_slot] != GL_NONE);
595 BLI_assert(dst->gl_attachments_[dst_slot] != GL_NONE);
596 glReadBuffer(src->gl_attachments_[src_slot]);
597 glDrawBuffer(dst->gl_attachments_[dst_slot]);
598 }
599
600 context_->state_manager->apply_state();
601
602 int w = src->width_;
603 int h = src->height_;
604 GLbitfield mask = to_gl(planes);
605 glBlitFramebuffer(0, 0, w, h, x, y, x + w, y + h, mask, GL_NEAREST);
606
607 if (!dst->immutable_) {
608 /* Restore the draw buffers. */
609 glDrawBuffers(ARRAY_SIZE(dst->gl_attachments_), dst->gl_attachments_);
610 }
611 /* Ensure previous buffer is restored. */
612 context_->active_fb = dst;
613}
614
617} // namespace blender::gpu
@ G_DEBUG_GPU
#define BLI_assert(a)
Definition BLI_assert.h:50
#define BLI_assert_msg(a, msg)
Definition BLI_assert.h:57
size_t BLI_snprintf(char *__restrict dst, size_t dst_maxncpy, const char *__restrict format,...) ATTR_NONNULL(1
unsigned int uint
#define UNPACK4(a)
#define ARRAY_SIZE(arr)
@ GPU_LOADACTION_CLEAR
GPUAttachmentState
@ GPU_ATTACHMENT_WRITE
@ GPU_ATTACHMENT_READ
void GPU_framebuffer_restore()
eGPUFrameBufferBits
@ GPU_DEPTH_BIT
@ GPU_STENCIL_BIT
@ GPU_COLOR_BIT
#define GPU_ATTACHMENT_NONE
#define GPU_MAX_VIEWPORTS
void GPU_write_mask(eGPUWriteMask mask)
Definition gpu_state.cc:93
eGPUWriteMask
Definition GPU_state.hh:16
void GPU_depth_mask(bool depth)
Definition gpu_state.cc:110
void GPU_stencil_test(eGPUStencilTest test)
Definition gpu_state.cc:73
void GPU_stencil_write_mask_set(uint write_mask)
Definition gpu_state.cc:205
void GPU_color_mask(bool r, bool g, bool b, bool a)
Definition gpu_state.cc:98
eGPUWriteMask GPU_write_mask_get()
Definition gpu_state.cc:227
eGPUStencilTest GPU_stencil_test_get()
Definition gpu_state.cc:245
uint GPU_stencil_mask_get()
Definition gpu_state.cc:233
eGPUStencilTest
Definition GPU_state.hh:117
@ GPU_STENCIL_ALWAYS
Definition GPU_state.hh:119
bool GPU_depth_mask_get()
Definition gpu_state.cc:276
void GPU_texture_bind_ex(GPUTexture *texture, GPUSamplerState state, int unit)
bool GPU_texture_is_cube(const GPUTexture *texture)
eGPUDataFormat
@ GPU_DATA_UINT_24_8
@ GPU_DATA_INT
@ GPU_DATA_UINT
@ GPU_DATA_FLOAT
bool GPU_texture_is_array(const GPUTexture *texture)
@ GPU_SRGB8_A8
void GPU_texture_get_mipmap_size(GPUTexture *texture, int mip_level, int *r_size)
eGPUTextureFormat GPU_texture_format(const GPUTexture *texture)
SIMD_FORCE_INLINE const btScalar & w() const
Return the w value.
Definition btQuadWord.h:119
constexpr IndexRange index_range() const
Definition BLI_span.hh:402
static Context * get()
void size_set(int width, int height)
GPUAttachment attachments_[GPU_FB_MAX_ATTACHMENT]
int viewport_[GPU_MAX_VIEWPORTS][4]
void attachment_set(GPUAttachmentType type, const GPUAttachment &new_attachment)
static bool framebuffer_fetch_support
Definition gl_context.hh:54
static GLContext * get()
static bool unused_fb_slot_workaround
Definition gl_context.hh:68
static bool texture_barrier_support
Definition gl_context.hh:62
void fbo_free(GLuint fbo_id)
void clear(eGPUFrameBufferBits buffers, const float clear_col[4], float clear_depth, uint clear_stencil) override
bool check(char err_out[256]) override
void attachment_set_loadstore_op(GPUAttachmentType type, GPULoadStore ls) 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
void subpass_transition_impl(const GPUAttachmentState depth_attachment_state, Span< GPUAttachmentState > color_attachment_states) 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:32
static void set_framebuffer_srgb_target(int use_srgb_to_linear)
virtual void apply_state()=0
#define FORMAT_STATUS(X)
@ GPU_FB_DEPTH_STENCIL_ATTACHMENT
@ GPU_FB_MAX_ATTACHMENT
@ GPU_FB_COLOR_ATTACHMENT0
@ GPU_FB_DEPTH_ATTACHMENT
#define GPU_FB_MAX_COLOR_ATTACHMENT
format
#define G(x, y, z)
void object_label(GLenum type, GLuint object, const char *name)
Definition gl_debug.cc:344
static Context * unwrap(GPUContext *ctx)
GLenum channel_len_to_gl(int channel_len)
static GLenum to_gl(const GPUAttachmentType type)
unsigned int uint32_t
Definition stdint.h:80
GPUTexture * tex
eGPULoadOp load_action
static constexpr GPUSamplerState default_sampler()
char * buffers[2]