Blender V4.5
gpu_framebuffer.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2005 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9#include "MEM_guardedalloc.h"
10
11#include "BLI_math_base.h"
12#include "BLI_string.h"
13#include "BLI_utildefines.h"
14
15#include "GPU_capabilities.hh"
16#include "GPU_texture.hh"
17
18#include "gpu_backend.hh"
21
23
24namespace blender::gpu {
25
26/* -------------------------------------------------------------------- */
29
30FrameBuffer::FrameBuffer(const char *name)
31{
32 if (name) {
33 STRNCPY(name_, name);
34 }
35 else {
36 name_[0] = '\0';
37 }
38 /* Force config on first use. */
39 dirty_attachments_ = true;
40 dirty_state_ = true;
41
42 for (GPUAttachment &attachment : attachments_) {
43 attachment.tex = nullptr;
44 attachment.mip = -1;
45 attachment.layer = -1;
46 }
47}
48
50{
51 for (GPUAttachment &attachment : attachments_) {
52 if (attachment.tex != nullptr) {
53 reinterpret_cast<Texture *>(attachment.tex)->detach_from(this);
54 }
55 }
56
57#ifndef GPU_NO_USE_PY_REFERENCES
58 if (this->py_ref) {
59 *this->py_ref = nullptr;
60 }
61#endif
62}
63
65
66/* -------------------------------------------------------------------- */
69
71{
72 if (new_attachment.mip == -1) {
73 return; /* GPU_ATTACHMENT_LEAVE */
74 }
75
76 if (type >= GPU_FB_MAX_ATTACHMENT) {
77 fprintf(stderr,
78 "GPUFramebuffer: Error: Trying to attach texture to type %d but maximum slot is %d.\n",
81 return;
82 }
83
84 if (new_attachment.tex) {
85 if (new_attachment.layer > 0) {
86 BLI_assert(GPU_texture_is_cube(new_attachment.tex) ||
87 GPU_texture_is_array(new_attachment.tex));
88 }
89 if (GPU_texture_has_stencil_format(new_attachment.tex)) {
91 }
92 else if (GPU_texture_has_depth_format(new_attachment.tex)) {
94 }
95 }
96
97 GPUAttachment &attachment = attachments_[type];
98
99 set_color_attachment_bit(type, new_attachment.tex != nullptr);
100
101 if (attachment.tex == new_attachment.tex && attachment.layer == new_attachment.layer &&
102 attachment.mip == new_attachment.mip)
103 {
104 return; /* Exact same texture already bound here. */
105 }
106 /* Unbind previous and bind new. */
107 /* TODO(fclem): cleanup the casts. */
108 if (attachment.tex) {
109 reinterpret_cast<Texture *>(attachment.tex)->detach_from(this);
110 }
111
112 /* Might be null if this is for unbinding. */
113 if (new_attachment.tex) {
114 reinterpret_cast<Texture *>(new_attachment.tex)->attach_to(this, type);
115 }
116 else {
117 /* GPU_ATTACHMENT_NONE */
118 }
119
120 attachment = new_attachment;
121 dirty_attachments_ = true;
122}
123
130
131void FrameBuffer::subpass_transition(const GPUAttachmentState depth_attachment_state,
132 Span<GPUAttachmentState> color_attachment_states)
133{
134 /* NOTE: Depth is not supported as input attachment because the Metal API doesn't support it and
135 * because depth is not compatible with the framebuffer fetch implementation. */
136 BLI_assert(depth_attachment_state != GPU_ATTACHMENT_READ);
137
140 {
141 BLI_assert(depth_attachment_state == GPU_ATTACHMENT_IGNORE);
142 }
143
144 BLI_assert(color_attachment_states.size() <= GPU_FB_MAX_COLOR_ATTACHMENT);
147 if (this->attachments_[type].tex) {
148 BLI_assert(i < color_attachment_states.size());
149 set_color_attachment_bit(type, color_attachment_states[i] == GPU_ATTACHMENT_WRITE);
150 }
151 else {
152 BLI_assert(i >= color_attachment_states.size() ||
153 color_attachment_states[i] == GPU_ATTACHMENT_IGNORE);
154 }
155 }
156
157 subpass_transition_impl(depth_attachment_state, color_attachment_states);
158}
159
160void FrameBuffer::load_store_config_array(const GPULoadStore *load_store_actions, uint actions_len)
161{
162 /* Follows attachment structure of GPU_framebuffer_config_array/GPU_framebuffer_ensure_config */
163 const GPULoadStore &depth_action = load_store_actions[0];
164 Span<GPULoadStore> color_attachment_actions(load_store_actions + 1, actions_len - 1);
165 BLI_assert(color_attachment_actions.size() <= GPU_FB_MAX_COLOR_ATTACHMENT);
166
169 {
172 }
173
176 }
177
178 if (this->attachments_[GPU_FB_DEPTH_ATTACHMENT].tex) {
180 }
181
184 if (this->attachments_[type].tex) {
185 BLI_assert(i < color_attachment_actions.size());
186 this->attachment_set_loadstore_op(type, color_attachment_actions[i]);
187 }
188 else {
189 BLI_assert(i >= color_attachment_actions.size() ||
190 (color_attachment_actions[i].load_action == GPU_LOADACTION_DONT_CARE &&
191 color_attachment_actions[i].store_action == GPU_STOREACTION_DONT_CARE));
192 }
193 }
194}
195
197{
198 uint total_bits = 0;
199 for (GPUAttachment &attachment : attachments_) {
200 Texture *tex = reinterpret_cast<Texture *>(attachment.tex);
201 if (tex != nullptr) {
202 int bits = to_bytesize(tex->format_get()) * to_component_len(tex->format_get());
203 total_bits += bits;
204 }
205 }
206 return total_bits;
207}
208
210 void (*callback)(void *user_data, int level),
211 void *user_data)
212{
213 /* Bind to make sure the frame-buffer is up to date. */
214 this->bind(true);
215
216 /* FIXME(fclem): This assumes all mips are defined which may not be the case. */
217 max_lvl = min_ii(max_lvl, floor(log2(max_ii(width_, height_))));
218
219 for (int mip_lvl = 1; mip_lvl <= max_lvl; mip_lvl++) {
220 /* Replace attached mip-level for each attachment. */
221 for (GPUAttachment &attachment : attachments_) {
222 Texture *tex = reinterpret_cast<Texture *>(attachment.tex);
223 if (tex != nullptr) {
224 /* Some Intel HDXXX have issue with rendering to a mipmap that is below
225 * the texture GL_TEXTURE_MAX_LEVEL. So even if it not correct, in this case
226 * we allow GL_TEXTURE_MAX_LEVEL to be one level lower. In practice it does work! */
227 int mip_max = GPU_mip_render_workaround() ? mip_lvl : (mip_lvl - 1);
228 /* Restrict fetches only to previous level. */
229 tex->mip_range_set(mip_lvl - 1, mip_max);
230 /* Bind next level. */
231 attachment.mip = mip_lvl;
232 }
233 }
234
235 /* Update the internal attachments and viewport size. */
236 dirty_attachments_ = true;
237 this->bind(true);
238
239 /* Optimize load-store state. */
241 for (GPUAttachment &attachment : attachments_) {
242 Texture *tex = reinterpret_cast<Texture *>(attachment.tex);
243 if (tex != nullptr) {
246 }
247 ++type;
248 }
249
250 callback(user_data, mip_lvl);
251 }
252
253 for (GPUAttachment &attachment : attachments_) {
254 if (attachment.tex != nullptr) {
255 /* Reset mipmap level range. */
256 reinterpret_cast<Texture *>(attachment.tex)->mip_range_set(0, max_lvl);
257 /* Reset base level. NOTE: might not be the one bound at the start of this function. */
258 attachment.mip = 0;
259 }
260 }
261 dirty_attachments_ = true;
262}
263
265
266} // namespace blender::gpu
267
268/* -------------------------------------------------------------------- */
271
272using namespace blender;
273using namespace blender::gpu;
274
275GPUFrameBuffer *GPU_framebuffer_create(const char *name)
276{
277 /* We generate the FB object later at first use in order to
278 * create the frame-buffer in the right opengl context. */
279 return wrap(GPUBackend::get()->framebuffer_alloc(name));
280}
281
282void GPU_framebuffer_free(GPUFrameBuffer *fb)
283{
284 delete unwrap(fb);
285}
286
287const char *GPU_framebuffer_get_name(GPUFrameBuffer *fb)
288{
289 return unwrap(fb)->name_get();
290}
291
292/* ---------- Binding ----------- */
293
294void GPU_framebuffer_bind(GPUFrameBuffer *fb)
295{
296 const bool enable_srgb = true;
297 /* Disable custom loadstore and bind. */
298 unwrap(fb)->set_use_explicit_loadstore(false);
299 unwrap(fb)->bind(enable_srgb);
300}
301
303 const GPULoadStore *load_store_actions,
304 uint actions_len)
305{
306 const bool enable_srgb = true;
307 /* Bind with explicit loadstore state */
308 unwrap(fb)->set_use_explicit_loadstore(true);
309 unwrap(fb)->bind(enable_srgb);
310
311 /* Update load store */
312 unwrap(fb)->load_store_config_array(load_store_actions, actions_len);
313}
314
316 const GPUAttachmentState *attachment_states,
317 uint attachment_len)
318{
319 unwrap(fb)->subpass_transition(
320 attachment_states[0], Span<GPUAttachmentState>(attachment_states + 1, attachment_len - 1));
321}
322
323void GPU_framebuffer_bind_no_srgb(GPUFrameBuffer *fb)
324{
325 const bool enable_srgb = false;
326 unwrap(fb)->bind(enable_srgb);
327}
328
330{
331 Context *ctx = Context::get();
332
333 if (back_buffer_type == GPU_BACKBUFFER_LEFT) {
334 ctx->back_left->bind(false);
335 }
336 else {
337 ctx->back_right->bind(false);
338 }
339}
340
342{
343 Context::get()->back_left->bind(false);
344}
345
347{
348 Context *ctx = Context::get();
349 return wrap(ctx ? ctx->active_fb : nullptr);
350}
351
353{
354 Context *ctx = Context::get();
355 return wrap(ctx ? ctx->back_left : nullptr);
356}
357
358bool GPU_framebuffer_bound(GPUFrameBuffer *gpu_fb)
359{
360 return (gpu_fb == GPU_framebuffer_active_get());
361}
362
363/* ---------- Attachment Management ----------- */
364
365bool GPU_framebuffer_check_valid(GPUFrameBuffer *gpu_fb, char err_out[256])
366{
367 return unwrap(gpu_fb)->check(err_out);
368}
369
370static void gpu_framebuffer_texture_attach_ex(GPUFrameBuffer *gpu_fb,
371 GPUAttachment attachment,
372 int slot)
373{
374 Texture *tex = reinterpret_cast<Texture *>(attachment.tex);
375 GPUAttachmentType type = tex->attachment_type(slot);
376 unwrap(gpu_fb)->attachment_set(type, attachment);
377}
378
379void GPU_framebuffer_texture_attach(GPUFrameBuffer *fb, GPUTexture *tex, int slot, int mip)
380{
381 GPUAttachment attachment = GPU_ATTACHMENT_TEXTURE_MIP(tex, mip);
382 gpu_framebuffer_texture_attach_ex(fb, attachment, slot);
383}
384
386 GPUFrameBuffer *fb, GPUTexture *tex, int slot, int layer, int mip)
387{
388 GPUAttachment attachment = GPU_ATTACHMENT_TEXTURE_LAYER_MIP(tex, layer, mip);
389 gpu_framebuffer_texture_attach_ex(fb, attachment, slot);
390}
391
393 GPUFrameBuffer *fb, GPUTexture *tex, int slot, int face, int mip)
394{
395 GPUAttachment attachment = GPU_ATTACHMENT_TEXTURE_CUBEFACE_MIP(tex, face, mip);
396 gpu_framebuffer_texture_attach_ex(fb, attachment, slot);
397}
398
399void GPU_framebuffer_texture_detach(GPUFrameBuffer *fb, GPUTexture *tex)
400{
401 unwrap(tex)->detach_from(unwrap(fb));
402}
403
404void GPU_framebuffer_config_array(GPUFrameBuffer *gpu_fb,
405 const GPUAttachment *config,
406 int config_len)
407{
408 FrameBuffer *fb = unwrap(gpu_fb);
409
410 const GPUAttachment &depth_attachment = config[0];
411 Span<GPUAttachment> color_attachments(config + 1, config_len - 1);
412
413 if (depth_attachment.mip == -1) {
414 /* GPU_ATTACHMENT_LEAVE */
415 }
416 else if (depth_attachment.tex == nullptr) {
417 /* GPU_ATTACHMENT_NONE: Need to clear both targets. */
418 fb->attachment_set(GPU_FB_DEPTH_STENCIL_ATTACHMENT, depth_attachment);
419 fb->attachment_set(GPU_FB_DEPTH_ATTACHMENT, depth_attachment);
420 }
421 else {
422 GPUAttachmentType type = GPU_texture_has_stencil_format(depth_attachment.tex) ?
425 fb->attachment_set(type, depth_attachment);
426 }
427
429 for (const GPUAttachment &attachment : color_attachments) {
430 fb->attachment_set(type, attachment);
431 ++type;
432 }
433}
434
435void GPU_framebuffer_default_size(GPUFrameBuffer *gpu_fb, int width, int height)
436{
437 unwrap(gpu_fb)->default_size_set(width, height);
438}
439
440/* ---------- Viewport & Scissor Region ----------- */
441
442void GPU_framebuffer_viewport_set(GPUFrameBuffer *gpu_fb, int x, int y, int width, int height)
443{
444 int viewport_rect[4] = {x, y, width, height};
445 unwrap(gpu_fb)->viewport_set(viewport_rect);
446}
447
448void GPU_framebuffer_multi_viewports_set(GPUFrameBuffer *gpu_fb,
449 const int viewport_rects[GPU_MAX_VIEWPORTS][4])
450{
451 unwrap(gpu_fb)->viewport_multi_set(viewport_rects);
452}
453
454void GPU_framebuffer_viewport_get(GPUFrameBuffer *gpu_fb, int r_viewport[4])
455{
456 unwrap(gpu_fb)->viewport_get(r_viewport);
457}
458
459void GPU_framebuffer_viewport_reset(GPUFrameBuffer *gpu_fb)
460{
461 unwrap(gpu_fb)->viewport_reset();
462}
463
464/* ---------- Frame-buffer Operations ----------- */
465
466void GPU_framebuffer_clear(GPUFrameBuffer *gpu_fb,
468 const float clear_col[4],
469 float clear_depth,
470 uint clear_stencil)
471{
472 BLI_assert_msg(unwrap(gpu_fb)->get_use_explicit_loadstore() == false,
473 "Using GPU_framebuffer_clear_* functions in conjunction with custom load-store "
474 "state via GPU_framebuffer_bind_ex is invalid.");
475 unwrap(gpu_fb)->clear(buffers, clear_col, clear_depth, clear_stencil);
476}
477
478void GPU_framebuffer_clear_color(GPUFrameBuffer *fb, const float clear_col[4])
479{
480 GPU_framebuffer_clear(fb, GPU_COLOR_BIT, clear_col, 0.0f, 0x00);
481}
482
483void GPU_framebuffer_clear_depth(GPUFrameBuffer *fb, float clear_depth)
484{
485 GPU_framebuffer_clear(fb, GPU_DEPTH_BIT, nullptr, clear_depth, 0x00);
486}
487
489 const float clear_col[4],
490 float clear_depth)
491{
492 GPU_framebuffer_clear(fb, GPU_COLOR_BIT | GPU_DEPTH_BIT, clear_col, clear_depth, 0x00);
493}
494
495void GPU_framebuffer_clear_stencil(GPUFrameBuffer *fb, uint clear_stencil)
496{
497 GPU_framebuffer_clear(fb, GPU_STENCIL_BIT, nullptr, 0.0f, clear_stencil);
498}
499
500void GPU_framebuffer_clear_depth_stencil(GPUFrameBuffer *fb, float clear_depth, uint clear_stencil)
501{
502 GPU_framebuffer_clear(fb, GPU_DEPTH_BIT | GPU_STENCIL_BIT, nullptr, clear_depth, clear_stencil);
503}
504
506 const float clear_col[4],
507 float clear_depth,
508 uint clear_stencil)
509{
511 fb, GPU_COLOR_BIT | GPU_DEPTH_BIT | GPU_STENCIL_BIT, clear_col, clear_depth, clear_stencil);
512}
513
514void GPU_framebuffer_multi_clear(GPUFrameBuffer *fb, const float (*clear_colors)[4])
515{
516 BLI_assert_msg(unwrap(fb)->get_use_explicit_loadstore() == false,
517 "Using GPU_framebuffer_clear_* functions in conjunction with custom load-store "
518 "state via GPU_framebuffer_bind_ex is invalid.");
519 unwrap(fb)->clear_multi(clear_colors);
520}
521
522void GPU_clear_color(float red, float green, float blue, float alpha)
523{
524 BLI_assert_msg(Context::get()->active_fb->get_use_explicit_loadstore() == false,
525 "Using GPU_framebuffer_clear_* functions in conjunction with custom load-store "
526 "state via GPU_framebuffer_bind_ex is invalid.");
527 float clear_col[4] = {red, green, blue, alpha};
528 Context::get()->active_fb->clear(GPU_COLOR_BIT, clear_col, 0.0f, 0x0);
529}
530
531void GPU_clear_depth(float depth)
532{
533 BLI_assert_msg(Context::get()->active_fb->get_use_explicit_loadstore() == false,
534 "Using GPU_framebuffer_clear_* functions in conjunction with custom load-store "
535 "state via GPU_framebuffer_bind_ex is invalid.");
536 float clear_col[4] = {0};
537 Context::get()->active_fb->clear(GPU_DEPTH_BIT, clear_col, depth, 0x0);
538}
539
541 GPUFrameBuffer *fb, int x, int y, int w, int h, eGPUDataFormat format, void *data)
542{
543 int rect[4] = {x, y, w, h};
544 unwrap(fb)->read(GPU_DEPTH_BIT, format, rect, 1, 1, data);
545}
546
547void GPU_framebuffer_read_color(GPUFrameBuffer *fb,
548 int x,
549 int y,
550 int w,
551 int h,
552 int channels,
553 int slot,
555 void *data)
556{
557 int rect[4] = {x, y, w, h};
558 unwrap(fb)->read(GPU_COLOR_BIT, format, rect, channels, slot, data);
559}
560
562 int x, int y, int w, int h, int channels, eGPUDataFormat format, void *data)
563{
564 int rect[4] = {x, y, w, h};
565 Context::get()->front_left->read(GPU_COLOR_BIT, format, rect, channels, 0, data);
566}
567
568/* TODO(fclem): port as texture operation. */
569void GPU_framebuffer_blit(GPUFrameBuffer *gpu_fb_read,
570 int read_slot,
571 GPUFrameBuffer *gpu_fb_write,
572 int write_slot,
573 eGPUFrameBufferBits blit_buffers)
574{
575 FrameBuffer *fb_read = unwrap(gpu_fb_read);
576 FrameBuffer *fb_write = unwrap(gpu_fb_write);
577 BLI_assert(blit_buffers != 0);
578
579 FrameBuffer *prev_fb = Context::get()->active_fb;
580
581#ifndef NDEBUG
582 GPUTexture *read_tex, *write_tex;
583 if (blit_buffers & (GPU_DEPTH_BIT | GPU_STENCIL_BIT)) {
584 read_tex = fb_read->depth_tex();
585 write_tex = fb_write->depth_tex();
586 }
587 else {
588 read_tex = fb_read->color_tex(read_slot);
589 write_tex = fb_write->color_tex(write_slot);
590 }
591
592 if (blit_buffers & GPU_DEPTH_BIT) {
594 BLI_assert(GPU_texture_format(read_tex) == GPU_texture_format(write_tex));
595 }
596 if (blit_buffers & GPU_STENCIL_BIT) {
599 BLI_assert(GPU_texture_format(read_tex) == GPU_texture_format(write_tex));
600 }
601#endif
602
603 fb_read->blit_to(blit_buffers, read_slot, fb_write, write_slot, 0, 0);
604
605 /* FIXME(@fclem): sRGB is not saved. */
606 prev_fb->bind(true);
607}
608
610 int max_level,
611 void (*per_level_callback)(void *user_data, int level),
612 void *user_data)
613{
614 unwrap(fb)->recursive_downsample(max_level, per_level_callback, user_data);
615}
616
617#ifndef GPU_NO_USE_PY_REFERENCES
619{
620 return unwrap(fb)->py_ref;
621}
622
623void GPU_framebuffer_py_reference_set(GPUFrameBuffer *fb, void **py_ref)
624{
625 BLI_assert(py_ref == nullptr || unwrap(fb)->py_ref == nullptr);
626 unwrap(fb)->py_ref = py_ref;
627}
628#endif
629
631
632/* -------------------------------------------------------------------- */
637
638#define FRAMEBUFFER_STACK_DEPTH 16
639
640static struct {
643} FrameBufferStack = {{nullptr}};
644
645void GPU_framebuffer_push(GPUFrameBuffer *fb)
646{
648 FrameBufferStack.framebuffers[FrameBufferStack.top] = fb;
649 FrameBufferStack.top++;
650}
651
652GPUFrameBuffer *GPU_framebuffer_pop()
653{
655 FrameBufferStack.top--;
656 return FrameBufferStack.framebuffers[FrameBufferStack.top];
657}
658
663
664#undef FRAMEBUFFER_STACK_DEPTH
665
667
668/* -------------------------------------------------------------------- */
674
676 constexpr static int MAX_CTX_FB_LEN = 3;
677
678 struct {
680 GPUFrameBuffer *fb;
681 } framebuffers[MAX_CTX_FB_LEN];
682
683 GPUTexture *color;
684 GPUTexture *depth;
685};
686
690static GPUFrameBuffer *gpu_offscreen_fb_get(GPUOffScreen *ofs)
691{
692 Context *ctx = Context::get();
693 BLI_assert(ctx);
694
695 for (auto &framebuffer : ofs->framebuffers) {
696 if (framebuffer.fb == nullptr) {
697 framebuffer.ctx = ctx;
698 GPU_framebuffer_ensure_config(&framebuffer.fb,
699 {
700 GPU_ATTACHMENT_TEXTURE(ofs->depth),
701 GPU_ATTACHMENT_TEXTURE(ofs->color),
702 });
703 }
704
705 if (framebuffer.ctx == ctx) {
706 return framebuffer.fb;
707 }
708 }
709
710 /* List is full, this should never happen or
711 * it might just slow things down if it happens
712 * regularly. In this case we just empty the list
713 * and start over. This is most likely never going
714 * to happen under normal usage. */
715 BLI_assert(0);
716 printf(
717 "Warning: GPUOffscreen used in more than 3 GPUContext. "
718 "This may create performance drop.\n");
719
720 for (auto &framebuffer : ofs->framebuffers) {
721 GPU_framebuffer_free(framebuffer.fb);
722 framebuffer.fb = nullptr;
723 }
724
725 return gpu_offscreen_fb_get(ofs);
726}
727
729 int height,
730 bool with_depth_buffer,
732 eGPUTextureUsage usage,
733 bool clear,
734 char err_out[256])
735{
737
738 /* Sometimes areas can have 0 height or width and this will
739 * create a 1D texture which we don't want. */
740 height = max_ii(1, height);
741 width = max_ii(1, width);
742
743 /* Always add GPU_TEXTURE_USAGE_ATTACHMENT for convenience. */
745
746 ofs->color = GPU_texture_create_2d("ofs_color", width, height, 1, format, usage, nullptr);
747
748 if (with_depth_buffer) {
749 /* Format view flag is needed by Workbench Volumes to read the stencil view. */
752 "ofs_depth", width, height, 1, GPU_DEPTH24_STENCIL8, depth_usage, nullptr);
753 }
754
755 if ((with_depth_buffer && !ofs->depth) || !ofs->color) {
756 const char error[] = "GPUTexture: Texture allocation failed.";
757 if (err_out) {
758 BLI_strncpy(err_out, error, 256);
759 }
760 else {
761 fprintf(stderr, "%s", error);
762 }
764 return nullptr;
765 }
766
767 GPUFrameBuffer *fb = gpu_offscreen_fb_get(ofs);
768
769 /* check validity at the very end! */
770 if (!GPU_framebuffer_check_valid(fb, err_out)) {
772 return nullptr;
773 }
774
775 if (clear) {
776 float const clear_color[4] = {0.0f, 0.0f, 0.0f, 0.0f};
777 float clear_depth = 0.0f;
779 if (with_depth_buffer) {
780 GPU_framebuffer_clear_color_depth(fb, clear_color, clear_depth);
781 }
782 else {
783 GPU_framebuffer_clear_color(fb, clear_color);
784 }
785 }
786
788 return ofs;
789}
790
792{
793 for (auto &framebuffer : offscreen->framebuffers) {
794 if (framebuffer.fb) {
795 GPU_framebuffer_free(framebuffer.fb);
796 }
797 }
798 if (offscreen->color) {
799 GPU_texture_free(offscreen->color);
800 }
801 if (offscreen->depth) {
802 GPU_texture_free(offscreen->depth);
803 }
804
805 MEM_freeN(offscreen);
806}
807
808void GPU_offscreen_bind(GPUOffScreen *offscreen, bool save)
809{
810 if (save) {
811 GPUFrameBuffer *fb = GPU_framebuffer_active_get();
813 }
814 unwrap(gpu_offscreen_fb_get(offscreen))->bind(false);
815}
816
817void GPU_offscreen_unbind(GPUOffScreen * /*offscreen*/, bool restore)
818{
819 GPUFrameBuffer *fb = nullptr;
820 if (restore) {
822 }
823
824 if (fb) {
826 }
827 else {
829 }
830}
831
833{
834 Context *ctx = Context::get();
835 FrameBuffer *ofs_fb = unwrap(gpu_offscreen_fb_get(offscreen));
836 ofs_fb->blit_to(GPU_COLOR_BIT, 0, ctx->active_fb, 0, x, y);
837}
838
840 GPUOffScreen *offscreen, eGPUDataFormat format, int x, int y, int w, int h, void *r_data)
841{
843 BLI_assert(x >= 0 && y >= 0 && w > 0 && h > 0);
844 BLI_assert(x + w <= GPU_texture_width(offscreen->color));
845 BLI_assert(y + h <= GPU_texture_height(offscreen->color));
846
847 GPUFrameBuffer *ofs_fb = gpu_offscreen_fb_get(offscreen);
848 GPU_framebuffer_read_color(ofs_fb, x, y, w, h, 4, 0, format, r_data);
849}
850
852{
854
855 const int w = GPU_texture_width(offscreen->color);
856 const int h = GPU_texture_height(offscreen->color);
857
858 GPU_offscreen_read_color_region(offscreen, format, 0, 0, w, h, r_data);
859}
860
862{
863 return GPU_texture_width(offscreen->color);
864}
865
867{
868 return GPU_texture_height(offscreen->color);
869}
870
871GPUTexture *GPU_offscreen_color_texture(const GPUOffScreen *offscreen)
872{
873 return offscreen->color;
874}
875
877{
878 return GPU_texture_format(offscreen->color);
879}
880
882 GPUFrameBuffer **r_fb,
883 GPUTexture **r_color,
884 GPUTexture **r_depth)
885{
886 *r_fb = gpu_offscreen_fb_get(offscreen);
887 *r_color = offscreen->color;
888 *r_depth = offscreen->depth;
889}
890
#define BLI_assert(a)
Definition BLI_assert.h:46
#define BLI_assert_msg(a, msg)
Definition BLI_assert.h:53
MINLINE int min_ii(int a, int b)
MINLINE int max_ii(int a, int b)
char * STRNCPY(char(&dst)[N], const char *src)
Definition BLI_string.h:688
char * BLI_strncpy(char *__restrict dst, const char *__restrict src, size_t dst_maxncpy) ATTR_NONNULL(1
unsigned int uint
#define ELEM(...)
bool GPU_mip_render_workaround()
@ GPU_LOADACTION_DONT_CARE
@ GPU_STOREACTION_STORE
@ GPU_STOREACTION_DONT_CARE
GPUAttachmentState
@ GPU_ATTACHMENT_WRITE
@ GPU_ATTACHMENT_READ
@ GPU_ATTACHMENT_IGNORE
void GPU_framebuffer_multi_viewports_set(GPUFrameBuffer *gpu_fb, const int viewport_rects[GPU_MAX_VIEWPORTS][4])
void GPU_framebuffer_read_color(GPUFrameBuffer *fb, int x, int y, int width, int height, int channels, int slot, eGPUDataFormat data_format, void *r_data)
void GPU_framebuffer_viewport_get(GPUFrameBuffer *fb, int r_viewport[4])
void GPU_offscreen_draw_to_screen(GPUOffScreen *offscreen, int x, int y)
const char * GPU_framebuffer_get_name(GPUFrameBuffer *fb)
void GPU_framebuffer_bind_no_srgb(GPUFrameBuffer *fb)
GPUFrameBuffer * GPU_framebuffer_create(const char *name)
GPUFrameBuffer * GPU_framebuffer_active_get()
int GPU_offscreen_width(const GPUOffScreen *offscreen)
bool GPU_framebuffer_check_valid(GPUFrameBuffer *fb, char err_out[256])
void GPU_framebuffer_viewport_set(GPUFrameBuffer *fb, int x, int y, int width, int height)
void GPU_framebuffer_viewport_reset(GPUFrameBuffer *fb)
void GPU_offscreen_bind(GPUOffScreen *offscreen, bool save)
void GPU_offscreen_viewport_data_get(GPUOffScreen *offscreen, GPUFrameBuffer **r_fb, GPUTexture **r_color, GPUTexture **r_depth)
void GPU_framebuffer_texture_cubeface_attach(GPUFrameBuffer *fb, GPUTexture *texture, int slot, int face, int mip)
void GPU_framebuffer_clear_color_depth_stencil(GPUFrameBuffer *fb, const float clear_col[4], float clear_depth, uint clear_stencil)
void GPU_framebuffer_restore()
eGPUFrameBufferBits
@ GPU_DEPTH_BIT
@ GPU_STENCIL_BIT
@ GPU_COLOR_BIT
void GPU_framebuffer_clear_stencil(GPUFrameBuffer *fb, uint clear_stencil)
void GPU_framebuffer_texture_detach(GPUFrameBuffer *fb, GPUTexture *texture)
void GPU_framebuffer_clear_depth_stencil(GPUFrameBuffer *fb, float clear_depth, uint clear_stencil)
static constexpr int GPU_MAX_VIEWPORTS
void GPU_frontbuffer_read_color(int x, int y, int width, int height, int channels, eGPUDataFormat data_format, void *r_data)
void ** GPU_framebuffer_py_reference_get(GPUFrameBuffer *fb)
void GPU_framebuffer_read_depth(GPUFrameBuffer *fb, int x, int y, int width, int height, eGPUDataFormat data_format, void *r_data)
#define GPU_ATTACHMENT_NONE
void GPU_framebuffer_clear_color_depth(GPUFrameBuffer *fb, const float clear_col[4], float clear_depth)
uint GPU_framebuffer_stack_level_get()
void GPU_framebuffer_subpass_transition_array(GPUFrameBuffer *fb, const GPUAttachmentState *attachment_states, uint attachment_len)
#define GPU_ATTACHMENT_TEXTURE_MIP(_texture, _mip)
void GPU_framebuffer_bind_loadstore(GPUFrameBuffer *fb, const GPULoadStore *load_store_actions, uint load_store_actions_len)
int GPU_offscreen_height(const GPUOffScreen *offscreen)
GPUOffScreen * GPU_offscreen_create(int width, int height, bool with_depth_buffer, eGPUTextureFormat format, eGPUTextureUsage usage, bool clear, char err_out[256])
void GPU_framebuffer_py_reference_set(GPUFrameBuffer *fb, void **py_ref)
void GPU_framebuffer_free(GPUFrameBuffer *fb)
void GPU_framebuffer_bind(GPUFrameBuffer *fb)
eGPUBackBuffer
@ GPU_BACKBUFFER_LEFT
void GPU_framebuffer_multi_clear(GPUFrameBuffer *fb, const float(*clear_colors)[4])
GPUTexture * GPU_offscreen_color_texture(const GPUOffScreen *offscreen)
void GPU_clear_color(float red, float green, float blue, float alpha)
void GPU_framebuffer_config_array(GPUFrameBuffer *fb, const GPUAttachment *config, int config_len)
void GPU_offscreen_read_color_region(GPUOffScreen *offscreen, eGPUDataFormat data_format, int x, int y, int w, int h, void *r_data)
void GPU_framebuffer_texture_layer_attach(GPUFrameBuffer *fb, GPUTexture *texture, int slot, int layer, int mip)
void GPU_offscreen_free(GPUOffScreen *offscreen)
void GPU_backbuffer_bind(eGPUBackBuffer back_buffer_type)
eGPUTextureFormat GPU_offscreen_format(const GPUOffScreen *offscreen)
void GPU_framebuffer_push(GPUFrameBuffer *fb)
#define NULL_ATTACHMENT_COLOR
void GPU_clear_depth(float depth)
void GPU_framebuffer_default_size(GPUFrameBuffer *fb, int width, int height)
void GPU_framebuffer_recursive_downsample(GPUFrameBuffer *fb, int max_level, void(*per_level_callback)(void *user_data, int level), void *user_data)
void GPU_framebuffer_clear_color(GPUFrameBuffer *fb, const float clear_col[4])
#define GPU_framebuffer_ensure_config(_fb,...)
void GPU_offscreen_read_color(GPUOffScreen *offscreen, eGPUDataFormat data_format, void *r_data)
GPUFrameBuffer * GPU_framebuffer_pop()
#define GPU_ATTACHMENT_TEXTURE_LAYER_MIP(_texture, _layer, _mip)
void GPU_framebuffer_clear(GPUFrameBuffer *fb, eGPUFrameBufferBits buffers, const float clear_col[4], float clear_depth, unsigned int clear_stencil)
void GPU_framebuffer_clear_depth(GPUFrameBuffer *fb, float clear_depth)
bool GPU_framebuffer_bound(GPUFrameBuffer *fb)
GPUFrameBuffer * GPU_framebuffer_back_get()
void GPU_offscreen_unbind(GPUOffScreen *offscreen, bool restore)
#define GPU_ATTACHMENT_TEXTURE_CUBEFACE_MIP(_texture, _face, _mip)
void GPU_framebuffer_texture_attach(GPUFrameBuffer *fb, GPUTexture *texture, int slot, int mip)
void GPU_framebuffer_blit(GPUFrameBuffer *fb_read, int read_slot, GPUFrameBuffer *fb_write, int write_slot, eGPUFrameBufferBits blit_buffers)
int GPU_texture_height(const GPUTexture *texture)
GPUTexture * GPU_texture_create_2d(const char *name, int width, int height, int mip_len, eGPUTextureFormat format, eGPUTextureUsage usage, const float *data)
void GPU_texture_free(GPUTexture *texture)
int GPU_texture_width(const GPUTexture *texture)
bool GPU_texture_is_cube(const GPUTexture *texture)
eGPUDataFormat
@ GPU_DATA_UBYTE
@ GPU_DATA_FLOAT
bool GPU_texture_is_array(const GPUTexture *texture)
eGPUTextureUsage
@ GPU_TEXTURE_USAGE_ATTACHMENT
@ GPU_TEXTURE_USAGE_FORMAT_VIEW
bool GPU_texture_has_stencil_format(const GPUTexture *texture)
eGPUTextureFormat
@ GPU_DEPTH24_STENCIL8
bool GPU_texture_has_depth_format(const GPUTexture *texture)
eGPUTextureFormat GPU_texture_format(const GPUTexture *texture)
Read Guarded memory(de)allocation.
BMesh const char void * data
SIMD_FORCE_INLINE const btScalar & w() const
Return the w value.
Definition btQuadWord.h:119
constexpr int64_t size() const
Definition BLI_span.hh:252
static Context * get()
void attachment_remove(GPUAttachmentType type)
virtual void subpass_transition_impl(const GPUAttachmentState depth_attachment_state, Span< GPUAttachmentState > color_attachment_states)=0
virtual void attachment_set_loadstore_op(GPUAttachmentType type, GPULoadStore ls)=0
virtual void read(eGPUFrameBufferBits planes, eGPUDataFormat format, const int area[4], int channel_len, int slot, void *r_data)=0
void set_color_attachment_bit(GPUAttachmentType type, bool value)
virtual void bind(bool enabled_srgb)=0
void subpass_transition(const GPUAttachmentState depth_attachment_state, Span< GPUAttachmentState > color_attachment_states)
GPUTexture * color_tex(int slot) const
FrameBuffer(const char *name)
virtual void clear(eGPUFrameBufferBits buffers, const float clear_col[4], float clear_depth, uint clear_stencil)=0
GPUAttachment attachments_[GPU_FB_MAX_ATTACHMENT]
void load_store_config_array(const GPULoadStore *load_store_actions, uint actions_len)
virtual void blit_to(eGPUFrameBufferBits planes, int src_slot, FrameBuffer *dst, int dst_slot, int dst_offset_x, int dst_offset_y)=0
void recursive_downsample(int max_lvl, void(*callback)(void *user_data, int level), void *user_data)
void attachment_set(GPUAttachmentType type, const GPUAttachment &new_attachment)
static GPUBackend * get()
virtual void mip_range_set(int min, int max)=0
eGPUTextureFormat format_get() const
GPUAttachmentType attachment_type(int slot) const
#define FRAMEBUFFER_STACK_DEPTH
static struct @333043062060075056321126220274031331233357063275 FrameBufferStack
GPUFrameBuffer * framebuffers[FRAMEBUFFER_STACK_DEPTH]
uint top
static void gpu_framebuffer_texture_attach_ex(GPUFrameBuffer *gpu_fb, GPUAttachment attachment, int slot)
static GPUFrameBuffer * gpu_offscreen_fb_get(GPUOffScreen *ofs)
@ GPU_FB_DEPTH_STENCIL_ATTACHMENT
@ GPU_FB_MAX_ATTACHMENT
@ GPU_FB_COLOR_ATTACHMENT0
@ GPU_FB_DEPTH_ATTACHMENT
#define GPU_FB_MAX_COLOR_ATTACHMENT
#define log2
#define floor
#define printf(...)
BLI_INLINE float fb(float length, float L)
format
void * MEM_callocN(size_t len, const char *str)
Definition mallocn.cc:118
void MEM_freeN(void *vmemh)
Definition mallocn.cc:113
static void error(const char *str)
static void clear(Message &msg)
Definition msgfmt.cc:213
static Context * unwrap(GPUContext *ctx)
static GPUContext * wrap(Context *ctx)
int to_bytesize(const DataFormat format)
int to_component_len(eGPUTextureFormat format)
GPUTexture * tex
eGPULoadOp load_action
eGPUStoreOp store_action
static constexpr int MAX_CTX_FB_LEN
GPUTexture * color
GPUTexture * depth
struct GPUOffScreen::@307216123000113114306375037052221210375313104050 framebuffers[MAX_CTX_FB_LEN]
GPUFrameBuffer * fb
i
Definition text_draw.cc:230
char * buffers[2]