Blender V4.3
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
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_batch.hh"
16#include "GPU_capabilities.hh"
17#include "GPU_shader.hh"
18#include "GPU_texture.hh"
19
20#include "gpu_backend.hh"
23
25
26namespace blender::gpu {
27
28/* -------------------------------------------------------------------- */
32FrameBuffer::FrameBuffer(const char *name)
33{
34 if (name) {
35 STRNCPY(name_, name);
36 }
37 else {
38 name_[0] = '\0';
39 }
40 /* Force config on first use. */
41 dirty_attachments_ = true;
42 dirty_state_ = true;
43
44 for (GPUAttachment &attachment : attachments_) {
45 attachment.tex = nullptr;
46 attachment.mip = -1;
47 attachment.layer = -1;
48 }
49}
50
52{
53 for (GPUAttachment &attachment : attachments_) {
54 if (attachment.tex != nullptr) {
55 reinterpret_cast<Texture *>(attachment.tex)->detach_from(this);
56 }
57 }
58
59#ifndef GPU_NO_USE_PY_REFERENCES
60 if (this->py_ref) {
61 *this->py_ref = nullptr;
62 }
63#endif
64}
65
68/* -------------------------------------------------------------------- */
73{
74 if (new_attachment.mip == -1) {
75 return; /* GPU_ATTACHMENT_LEAVE */
76 }
77
78 if (type >= GPU_FB_MAX_ATTACHMENT) {
79 fprintf(stderr,
80 "GPUFramebuffer: Error: Trying to attach texture to type %d but maximum slot is %d.\n",
83 return;
84 }
85
86 if (new_attachment.tex) {
87 if (new_attachment.layer > 0) {
88 BLI_assert(GPU_texture_is_cube(new_attachment.tex) ||
89 GPU_texture_is_array(new_attachment.tex));
90 }
91 if (GPU_texture_has_stencil_format(new_attachment.tex)) {
93 }
94 else if (GPU_texture_has_depth_format(new_attachment.tex)) {
96 }
97 }
98
99 GPUAttachment &attachment = attachments_[type];
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
129
130void FrameBuffer::subpass_transition(const GPUAttachmentState depth_attachment_state,
131 Span<GPUAttachmentState> color_attachment_states)
132{
133 /* NOTE: Depth is not supported as input attachment because the Metal API doesn't support it and
134 * because depth is not compatible with the framebuffer fetch implementation. */
135 BLI_assert(depth_attachment_state != GPU_ATTACHMENT_READ);
136
139 {
140 BLI_assert(depth_attachment_state == GPU_ATTACHMENT_IGNORE);
141 }
142
143 BLI_assert(color_attachment_states.size() <= GPU_FB_MAX_COLOR_ATTACHMENT);
146 if (this->attachments_[type].tex) {
147 BLI_assert(i < color_attachment_states.size());
148 }
149 else {
150 BLI_assert(i >= color_attachment_states.size() ||
151 color_attachment_states[i] == GPU_ATTACHMENT_IGNORE);
152 }
153 }
154
155 subpass_transition_impl(depth_attachment_state, color_attachment_states);
156}
157
158void FrameBuffer::load_store_config_array(const GPULoadStore *load_store_actions, uint actions_len)
159{
160 /* Follows attachment structure of GPU_framebuffer_config_array/GPU_framebuffer_ensure_config */
161 const GPULoadStore &depth_action = load_store_actions[0];
162 Span<GPULoadStore> color_attachment_actions(load_store_actions + 1, actions_len - 1);
163 BLI_assert(color_attachment_actions.size() <= GPU_FB_MAX_COLOR_ATTACHMENT);
164
167 {
170 }
171
174 }
175
176 if (this->attachments_[GPU_FB_DEPTH_ATTACHMENT].tex) {
178 }
179
182 if (this->attachments_[type].tex) {
183 BLI_assert(i < color_attachment_actions.size());
184 this->attachment_set_loadstore_op(type, color_attachment_actions[i]);
185 }
186 else {
187 BLI_assert(i >= color_attachment_actions.size() ||
188 (color_attachment_actions[i].load_action == GPU_LOADACTION_DONT_CARE &&
189 color_attachment_actions[i].store_action == GPU_STOREACTION_DONT_CARE));
190 }
191 }
192}
193
195{
196 uint total_bits = 0;
197 for (GPUAttachment &attachment : attachments_) {
198 Texture *tex = reinterpret_cast<Texture *>(attachment.tex);
199 if (tex != nullptr) {
200 int bits = to_bytesize(tex->format_get()) * to_component_len(tex->format_get());
201 total_bits += bits;
202 }
203 }
204 return total_bits;
205}
206
208 void (*callback)(void *user_data, int level),
209 void *user_data)
210{
211 /* Bind to make sure the frame-buffer is up to date. */
212 this->bind(true);
213
214 /* FIXME(fclem): This assumes all mips are defined which may not be the case. */
215 max_lvl = min_ii(max_lvl, floor(log2(max_ii(width_, height_))));
216
217 for (int mip_lvl = 1; mip_lvl <= max_lvl; mip_lvl++) {
218 /* Replace attached mip-level for each attachment. */
219 for (GPUAttachment &attachment : attachments_) {
220 Texture *tex = reinterpret_cast<Texture *>(attachment.tex);
221 if (tex != nullptr) {
222 /* Some Intel HDXXX have issue with rendering to a mipmap that is below
223 * the texture GL_TEXTURE_MAX_LEVEL. So even if it not correct, in this case
224 * we allow GL_TEXTURE_MAX_LEVEL to be one level lower. In practice it does work! */
225 int mip_max = GPU_mip_render_workaround() ? mip_lvl : (mip_lvl - 1);
226 /* Restrict fetches only to previous level. */
227 tex->mip_range_set(mip_lvl - 1, mip_max);
228 /* Bind next level. */
229 attachment.mip = mip_lvl;
230 }
231 }
232
233 /* Update the internal attachments and viewport size. */
234 dirty_attachments_ = true;
235 this->bind(true);
236
237 /* Optimize load-store state. */
239 for (GPUAttachment &attachment : attachments_) {
240 Texture *tex = reinterpret_cast<Texture *>(attachment.tex);
241 if (tex != nullptr) {
244 }
245 ++type;
246 }
247
248 callback(user_data, mip_lvl);
249 }
250
251 for (GPUAttachment &attachment : attachments_) {
252 if (attachment.tex != nullptr) {
253 /* Reset mipmap level range. */
254 reinterpret_cast<Texture *>(attachment.tex)->mip_range_set(0, max_lvl);
255 /* Reset base level. NOTE: might not be the one bound at the start of this function. */
256 attachment.mip = 0;
257 }
258 }
259 dirty_attachments_ = true;
260}
261
264} // namespace blender::gpu
265
266/* -------------------------------------------------------------------- */
270using namespace blender;
271using namespace blender::gpu;
272
273GPUFrameBuffer *GPU_framebuffer_create(const char *name)
274{
275 /* We generate the FB object later at first use in order to
276 * create the frame-buffer in the right opengl context. */
277 return wrap(GPUBackend::get()->framebuffer_alloc(name));
278}
279
280void GPU_framebuffer_free(GPUFrameBuffer *gpu_fb)
281{
282 delete unwrap(gpu_fb);
283}
284
285const char *GPU_framebuffer_get_name(GPUFrameBuffer *gpu_fb)
286{
287 return unwrap(gpu_fb)->name_get();
288}
289
290/* ---------- Binding ----------- */
291
292void GPU_framebuffer_bind(GPUFrameBuffer *gpu_fb)
293{
294 const bool enable_srgb = true;
295 /* Disable custom loadstore and bind. */
296 unwrap(gpu_fb)->set_use_explicit_loadstore(false);
297 unwrap(gpu_fb)->bind(enable_srgb);
298}
299
300void GPU_framebuffer_bind_loadstore(GPUFrameBuffer *gpu_fb,
301 const GPULoadStore *load_store_actions,
302 uint actions_len)
303{
304 const bool enable_srgb = true;
305 /* Bind with explicit loadstore state */
306 unwrap(gpu_fb)->set_use_explicit_loadstore(true);
307 unwrap(gpu_fb)->bind(enable_srgb);
308
309 /* Update load store */
310 FrameBuffer *fb = unwrap(gpu_fb);
311 fb->load_store_config_array(load_store_actions, actions_len);
312}
313
315 const GPUAttachmentState *attachment_states,
316 uint attachment_len)
317{
318 unwrap(gpu_fb)->subpass_transition(
319 attachment_states[0], Span<GPUAttachmentState>(attachment_states + 1, attachment_len - 1));
320}
321
322void GPU_framebuffer_bind_no_srgb(GPUFrameBuffer *gpu_fb)
323{
324 const bool enable_srgb = false;
325 unwrap(gpu_fb)->bind(enable_srgb);
326}
327
329{
330 Context *ctx = Context::get();
331
332 if (buffer == GPU_BACKBUFFER_LEFT) {
333 ctx->back_left->bind(false);
334 }
335 else {
336 ctx->back_right->bind(false);
337 }
338}
339
341{
342 Context::get()->back_left->bind(false);
343}
344
346{
347 Context *ctx = Context::get();
348 return wrap(ctx ? ctx->active_fb : nullptr);
349}
350
352{
353 Context *ctx = Context::get();
354 return wrap(ctx ? ctx->back_left : nullptr);
355}
356
357bool GPU_framebuffer_bound(GPUFrameBuffer *gpu_fb)
358{
359 return (gpu_fb == GPU_framebuffer_active_get());
360}
361
362/* ---------- Attachment Management ----------- */
363
364bool GPU_framebuffer_check_valid(GPUFrameBuffer *gpu_fb, char err_out[256])
365{
366 return unwrap(gpu_fb)->check(err_out);
367}
368
369static void gpu_framebuffer_texture_attach_ex(GPUFrameBuffer *gpu_fb,
370 GPUAttachment attachment,
371 int slot)
372{
373 Texture *tex = reinterpret_cast<Texture *>(attachment.tex);
374 GPUAttachmentType type = tex->attachment_type(slot);
375 unwrap(gpu_fb)->attachment_set(type, attachment);
376}
377
378void GPU_framebuffer_texture_attach(GPUFrameBuffer *fb, GPUTexture *tex, int slot, int mip)
379{
381 gpu_framebuffer_texture_attach_ex(fb, attachment, slot);
382}
383
385 GPUFrameBuffer *fb, GPUTexture *tex, int slot, int layer, int mip)
386{
387 GPUAttachment attachment = GPU_ATTACHMENT_TEXTURE_LAYER_MIP(tex, layer, mip);
388 gpu_framebuffer_texture_attach_ex(fb, attachment, slot);
389}
390
392 GPUFrameBuffer *fb, GPUTexture *tex, int slot, int face, int mip)
393{
395 gpu_framebuffer_texture_attach_ex(fb, attachment, slot);
396}
397
398void GPU_framebuffer_texture_detach(GPUFrameBuffer *fb, GPUTexture *tex)
399{
400 unwrap(tex)->detach_from(unwrap(fb));
401}
402
403void GPU_framebuffer_config_array(GPUFrameBuffer *gpu_fb,
404 const GPUAttachment *config,
405 int config_len)
406{
407 FrameBuffer *fb = unwrap(gpu_fb);
408
409 const GPUAttachment &depth_attachment = config[0];
410 Span<GPUAttachment> color_attachments(config + 1, config_len - 1);
411
412 if (depth_attachment.mip == -1) {
413 /* GPU_ATTACHMENT_LEAVE */
414 }
415 else if (depth_attachment.tex == nullptr) {
416 /* GPU_ATTACHMENT_NONE: Need to clear both targets. */
417 fb->attachment_set(GPU_FB_DEPTH_STENCIL_ATTACHMENT, depth_attachment);
418 fb->attachment_set(GPU_FB_DEPTH_ATTACHMENT, depth_attachment);
419 }
420 else {
421 GPUAttachmentType type = GPU_texture_has_stencil_format(depth_attachment.tex) ?
424 fb->attachment_set(type, depth_attachment);
425 }
426
428 for (const GPUAttachment &attachment : color_attachments) {
429 fb->attachment_set(type, attachment);
430 ++type;
431 }
432}
433
434void GPU_framebuffer_default_size(GPUFrameBuffer *gpu_fb, int width, int height)
435{
436 unwrap(gpu_fb)->default_size_set(width, height);
437}
438
439/* ---------- Viewport & Scissor Region ----------- */
440
441void GPU_framebuffer_viewport_set(GPUFrameBuffer *gpu_fb, int x, int y, int width, int height)
442{
443 int viewport_rect[4] = {x, y, width, height};
444 unwrap(gpu_fb)->viewport_set(viewport_rect);
445}
446
447void GPU_framebuffer_multi_viewports_set(GPUFrameBuffer *gpu_fb,
448 const int viewport_rects[GPU_MAX_VIEWPORTS][4])
449{
450 unwrap(gpu_fb)->viewport_multi_set(viewport_rects);
451}
452
453void GPU_framebuffer_viewport_get(GPUFrameBuffer *gpu_fb, int r_viewport[4])
454{
455 unwrap(gpu_fb)->viewport_get(r_viewport);
456}
457
458void GPU_framebuffer_viewport_reset(GPUFrameBuffer *gpu_fb)
459{
460 unwrap(gpu_fb)->viewport_reset();
461}
462
463/* ---------- Frame-buffer Operations ----------- */
464
465void GPU_framebuffer_clear(GPUFrameBuffer *gpu_fb,
467 const float clear_col[4],
468 float clear_depth,
469 uint clear_stencil)
470{
471 BLI_assert_msg(unwrap(gpu_fb)->get_use_explicit_loadstore() == false,
472 "Using GPU_framebuffer_clear_* functions in conjunction with custom load-store "
473 "state via GPU_framebuffer_bind_ex is invalid.");
474 unwrap(gpu_fb)->clear(buffers, clear_col, clear_depth, clear_stencil);
475}
476
477void GPU_framebuffer_clear_color(GPUFrameBuffer *fb, const float clear_col[4])
478{
479 GPU_framebuffer_clear(fb, GPU_COLOR_BIT, clear_col, 0.0f, 0x00);
480}
481
482void GPU_framebuffer_clear_depth(GPUFrameBuffer *fb, float clear_depth)
483{
484 GPU_framebuffer_clear(fb, GPU_DEPTH_BIT, nullptr, clear_depth, 0x00);
485}
486
488 const float clear_col[4],
489 float clear_depth)
490{
491 GPU_framebuffer_clear(fb, GPU_COLOR_BIT | GPU_DEPTH_BIT, clear_col, clear_depth, 0x00);
492}
493
494void GPU_framebuffer_clear_stencil(GPUFrameBuffer *fb, uint clear_stencil)
495{
496 GPU_framebuffer_clear(fb, GPU_STENCIL_BIT, nullptr, 0.0f, clear_stencil);
497}
498
499void GPU_framebuffer_clear_depth_stencil(GPUFrameBuffer *fb, float clear_depth, uint clear_stencil)
500{
501 GPU_framebuffer_clear(fb, GPU_DEPTH_BIT | GPU_STENCIL_BIT, nullptr, clear_depth, clear_stencil);
502}
503
505 const float clear_col[4],
506 float clear_depth,
507 uint clear_stencil)
508{
510 fb, GPU_COLOR_BIT | GPU_DEPTH_BIT | GPU_STENCIL_BIT, clear_col, clear_depth, clear_stencil);
511}
512
513void GPU_framebuffer_multi_clear(GPUFrameBuffer *gpu_fb, const float (*clear_cols)[4])
514{
515 BLI_assert_msg(unwrap(gpu_fb)->get_use_explicit_loadstore() == false,
516 "Using GPU_framebuffer_clear_* functions in conjunction with custom load-store "
517 "state via GPU_framebuffer_bind_ex is invalid.");
518 unwrap(gpu_fb)->clear_multi(clear_cols);
519}
520
521void GPU_clear_color(float red, float green, float blue, float alpha)
522{
523 BLI_assert_msg(Context::get()->active_fb->get_use_explicit_loadstore() == false,
524 "Using GPU_framebuffer_clear_* functions in conjunction with custom load-store "
525 "state via GPU_framebuffer_bind_ex is invalid.");
526 float clear_col[4] = {red, green, blue, alpha};
527 Context::get()->active_fb->clear(GPU_COLOR_BIT, clear_col, 0.0f, 0x0);
528}
529
530void GPU_clear_depth(float depth)
531{
532 BLI_assert_msg(Context::get()->active_fb->get_use_explicit_loadstore() == false,
533 "Using GPU_framebuffer_clear_* functions in conjunction with custom load-store "
534 "state via GPU_framebuffer_bind_ex is invalid.");
535 float clear_col[4] = {0};
536 Context::get()->active_fb->clear(GPU_DEPTH_BIT, clear_col, depth, 0x0);
537}
538
540 GPUFrameBuffer *gpu_fb, int x, int y, int w, int h, eGPUDataFormat format, void *data)
541{
542 int rect[4] = {x, y, w, h};
543 unwrap(gpu_fb)->read(GPU_DEPTH_BIT, format, rect, 1, 1, data);
544}
545
546void GPU_framebuffer_read_color(GPUFrameBuffer *gpu_fb,
547 int x,
548 int y,
549 int w,
550 int h,
551 int channels,
552 int slot,
554 void *data)
555{
556 int rect[4] = {x, y, w, h};
557 unwrap(gpu_fb)->read(GPU_COLOR_BIT, format, rect, channels, slot, data);
558}
559
561 int x, int y, int w, int h, int channels, eGPUDataFormat format, void *data)
562{
563 int rect[4] = {x, y, w, h};
564 Context::get()->front_left->read(GPU_COLOR_BIT, format, rect, channels, 0, data);
565}
566
567/* TODO(fclem): port as texture operation. */
568void GPU_framebuffer_blit(GPUFrameBuffer *gpufb_read,
569 int read_slot,
570 GPUFrameBuffer *gpufb_write,
571 int write_slot,
572 eGPUFrameBufferBits blit_buffers)
573{
574 FrameBuffer *fb_read = unwrap(gpufb_read);
575 FrameBuffer *fb_write = unwrap(gpufb_write);
576 BLI_assert(blit_buffers != 0);
577
578 FrameBuffer *prev_fb = Context::get()->active_fb;
579
580#ifndef NDEBUG
581 GPUTexture *read_tex, *write_tex;
582 if (blit_buffers & (GPU_DEPTH_BIT | GPU_STENCIL_BIT)) {
583 read_tex = fb_read->depth_tex();
584 write_tex = fb_write->depth_tex();
585 }
586 else {
587 read_tex = fb_read->color_tex(read_slot);
588 write_tex = fb_write->color_tex(write_slot);
589 }
590
591 if (blit_buffers & GPU_DEPTH_BIT) {
593 BLI_assert(GPU_texture_format(read_tex) == GPU_texture_format(write_tex));
594 }
595 if (blit_buffers & GPU_STENCIL_BIT) {
598 BLI_assert(GPU_texture_format(read_tex) == GPU_texture_format(write_tex));
599 }
600#endif
601
602 fb_read->blit_to(blit_buffers, read_slot, fb_write, write_slot, 0, 0);
603
604 /* FIXME(@fclem): sRGB is not saved. */
605 prev_fb->bind(true);
606}
607
608void GPU_framebuffer_recursive_downsample(GPUFrameBuffer *gpu_fb,
609 int max_lvl,
610 void (*callback)(void *user_data, int level),
611 void *user_data)
612{
613 unwrap(gpu_fb)->recursive_downsample(max_lvl, callback, user_data);
614}
615
616#ifndef GPU_NO_USE_PY_REFERENCES
617void **GPU_framebuffer_py_reference_get(GPUFrameBuffer *gpu_fb)
618{
619 return unwrap(gpu_fb)->py_ref;
620}
621
622void GPU_framebuffer_py_reference_set(GPUFrameBuffer *gpu_fb, void **py_ref)
623{
624 BLI_assert(py_ref == nullptr || unwrap(gpu_fb)->py_ref == nullptr);
625 unwrap(gpu_fb)->py_ref = py_ref;
626}
627#endif
628
631/* -------------------------------------------------------------------- */
637#define FRAMEBUFFER_STACK_DEPTH 16
638
639static struct {
642} FrameBufferStack = {{nullptr}};
643
644void GPU_framebuffer_push(GPUFrameBuffer *fb)
645{
647 FrameBufferStack.framebuffers[FrameBufferStack.top] = fb;
648 FrameBufferStack.top++;
649}
650
651GPUFrameBuffer *GPU_framebuffer_pop()
652{
654 FrameBufferStack.top--;
655 return FrameBufferStack.framebuffers[FrameBufferStack.top];
656}
657
662
663#undef FRAMEBUFFER_STACK_DEPTH
664
667/* -------------------------------------------------------------------- */
674#define MAX_CTX_FB_LEN 3
675
677 struct {
679 GPUFrameBuffer *fb;
681
682 GPUTexture *color;
683 GPUTexture *depth;
684};
685
689static GPUFrameBuffer *gpu_offscreen_fb_get(GPUOffScreen *ofs)
690{
691 Context *ctx = Context::get();
692 BLI_assert(ctx);
693
694 for (auto &framebuffer : ofs->framebuffers) {
695 if (framebuffer.fb == nullptr) {
696 framebuffer.ctx = ctx;
697 GPU_framebuffer_ensure_config(&framebuffer.fb,
698 {
699 GPU_ATTACHMENT_TEXTURE(ofs->depth),
700 GPU_ATTACHMENT_TEXTURE(ofs->color),
701 });
702 }
703
704 if (framebuffer.ctx == ctx) {
705 return framebuffer.fb;
706 }
707 }
708
709 /* List is full, this should never happen or
710 * it might just slow things down if it happens
711 * regularly. In this case we just empty the list
712 * and start over. This is most likely never going
713 * to happen under normal usage. */
714 BLI_assert(0);
715 printf(
716 "Warning: GPUOffscreen used in more than 3 GPUContext. "
717 "This may create performance drop.\n");
718
719 for (auto &framebuffer : ofs->framebuffers) {
720 GPU_framebuffer_free(framebuffer.fb);
721 framebuffer.fb = nullptr;
722 }
723
724 return gpu_offscreen_fb_get(ofs);
725}
726
728 int height,
729 bool depth,
731 eGPUTextureUsage usage,
732 char err_out[256])
733{
734 GPUOffScreen *ofs = MEM_cnew<GPUOffScreen>(__func__);
735
736 /* Sometimes areas can have 0 height or width and this will
737 * create a 1D texture which we don't want. */
738 height = max_ii(1, height);
739 width = max_ii(1, width);
740
741 /* Always add GPU_TEXTURE_USAGE_ATTACHMENT for convenience. */
743
744 ofs->color = GPU_texture_create_2d("ofs_color", width, height, 1, format, usage, nullptr);
745
746 if (depth) {
747 /* Format view flag is needed by Workbench Volumes to read the stencil view. */
750 "ofs_depth", width, height, 1, GPU_DEPTH24_STENCIL8, depth_usage, nullptr);
751 }
752
753 if ((depth && !ofs->depth) || !ofs->color) {
754 const char error[] = "GPUTexture: Texture allocation failed.";
755 if (err_out) {
756 BLI_strncpy(err_out, error, 256);
757 }
758 else {
759 fprintf(stderr, "%s", error);
760 }
762 return nullptr;
763 }
764
765 GPUFrameBuffer *fb = gpu_offscreen_fb_get(ofs);
766
767 /* check validity at the very end! */
768 if (!GPU_framebuffer_check_valid(fb, err_out)) {
770 return nullptr;
771 }
773 return ofs;
774}
775
777{
778 for (auto &framebuffer : ofs->framebuffers) {
779 if (framebuffer.fb) {
780 GPU_framebuffer_free(framebuffer.fb);
781 }
782 }
783 if (ofs->color) {
785 }
786 if (ofs->depth) {
788 }
789
790 MEM_freeN(ofs);
791}
792
793void GPU_offscreen_bind(GPUOffScreen *ofs, bool save)
794{
795 if (save) {
796 GPUFrameBuffer *fb = GPU_framebuffer_active_get();
798 }
799 unwrap(gpu_offscreen_fb_get(ofs))->bind(false);
800}
801
802void GPU_offscreen_unbind(GPUOffScreen * /*ofs*/, bool restore)
803{
804 GPUFrameBuffer *fb = nullptr;
805 if (restore) {
807 }
808
809 if (fb) {
811 }
812 else {
814 }
815}
816
818{
819 Context *ctx = Context::get();
821 ofs_fb->blit_to(GPU_COLOR_BIT, 0, ctx->active_fb, 0, x, y);
822}
823
825 GPUOffScreen *ofs, eGPUDataFormat format, int x, int y, int w, int h, void *r_data)
826{
828 BLI_assert(x >= 0 && y >= 0 && w > 0 && h > 0);
829 BLI_assert(x + w <= GPU_texture_width(ofs->color));
830 BLI_assert(y + h <= GPU_texture_height(ofs->color));
831
832 GPUFrameBuffer *ofs_fb = gpu_offscreen_fb_get(ofs);
833 GPU_framebuffer_read_color(ofs_fb, x, y, w, h, 4, 0, format, r_data);
834}
835
837{
839
840 const int w = GPU_texture_width(ofs->color);
841 const int h = GPU_texture_height(ofs->color);
842
843 GPU_offscreen_read_color_region(ofs, format, 0, 0, w, h, r_data);
844}
845
847{
848 return GPU_texture_width(ofs->color);
849}
850
852{
853 return GPU_texture_height(ofs->color);
854}
855
857{
858 return ofs->color;
859}
860
862{
863 return GPU_texture_format(offscreen->color);
864}
865
867 GPUFrameBuffer **r_fb,
868 GPUTexture **r_color,
869 GPUTexture **r_depth)
870{
871 *r_fb = gpu_offscreen_fb_get(ofs);
872 *r_color = ofs->color;
873 *r_depth = ofs->depth;
874}
875
#define BLI_assert(a)
Definition BLI_assert.h:50
#define BLI_assert_msg(a, msg)
Definition BLI_assert.h:57
MINLINE int min_ii(int a, int b)
MINLINE int max_ii(int a, int b)
#define STRNCPY(dst, src)
Definition BLI_string.h:593
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_READ
@ GPU_ATTACHMENT_IGNORE
void GPU_framebuffer_multi_viewports_set(GPUFrameBuffer *gpu_fb, const int viewport_rects[GPU_MAX_VIEWPORTS][4])
bool GPU_framebuffer_check_valid(GPUFrameBuffer *framebuffer, char err_out[256])
void GPU_offscreen_draw_to_screen(GPUOffScreen *offscreen, int x, int y)
GPUOffScreen * GPU_offscreen_create(int width, int height, bool with_depth_buffer, eGPUTextureFormat format, eGPUTextureUsage usage, char err_out[256])
GPUFrameBuffer * GPU_framebuffer_create(const char *name)
const char * GPU_framebuffer_get_name(GPUFrameBuffer *framebuffer)
void GPU_framebuffer_push(GPUFrameBuffer *framebuffer)
void GPU_framebuffer_default_size(GPUFrameBuffer *framebuffer, int width, int height)
void GPU_framebuffer_config_array(GPUFrameBuffer *framebuffer, const GPUAttachment *config, int config_len)
GPUFrameBuffer * GPU_framebuffer_active_get()
int GPU_offscreen_width(const GPUOffScreen *offscreen)
void GPU_framebuffer_viewport_get(GPUFrameBuffer *framebuffer, int r_viewport[4])
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_detach(GPUFrameBuffer *framebuffer, GPUTexture *texture)
void GPU_framebuffer_clear_color_depth_stencil(GPUFrameBuffer *fb, const float clear_col[4], float clear_depth, uint clear_stencil)
void GPU_framebuffer_texture_cubeface_attach(GPUFrameBuffer *framebuffer, GPUTexture *texture, int slot, int face, int mip)
void GPU_framebuffer_restore()
eGPUFrameBufferBits
@ GPU_DEPTH_BIT
@ GPU_STENCIL_BIT
@ GPU_COLOR_BIT
void GPU_framebuffer_clear_stencil(GPUFrameBuffer *fb, uint clear_stencil)
bool GPU_framebuffer_bound(GPUFrameBuffer *framebuffer)
void GPU_framebuffer_clear_depth_stencil(GPUFrameBuffer *fb, float clear_depth, uint clear_stencil)
void GPU_framebuffer_py_reference_set(GPUFrameBuffer *framebuffer, void **py_ref)
void ** GPU_framebuffer_py_reference_get(GPUFrameBuffer *framebuffer)
void GPU_frontbuffer_read_color(int x, int y, int width, int height, int channels, eGPUDataFormat data_format, void *r_data)
void GPU_framebuffer_read_depth(GPUFrameBuffer *framebuffer, int x, int y, int width, int height, eGPUDataFormat data_format, void *r_data)
#define GPU_ATTACHMENT_NONE
void GPU_framebuffer_viewport_reset(GPUFrameBuffer *framebuffer)
void GPU_framebuffer_clear_color_depth(GPUFrameBuffer *fb, const float clear_col[4], float clear_depth)
uint GPU_framebuffer_stack_level_get()
#define GPU_ATTACHMENT_TEXTURE_MIP(_texture, _mip)
void GPU_framebuffer_texture_layer_attach(GPUFrameBuffer *framebuffer, GPUTexture *texture, int slot, int layer, int mip)
int GPU_offscreen_height(const GPUOffScreen *offscreen)
void GPU_framebuffer_recursive_downsample(GPUFrameBuffer *framebuffer, int max_level, void(*per_level_callback)(void *user_data, int level), void *user_data)
void GPU_framebuffer_bind_no_srgb(GPUFrameBuffer *framebuffer)
eGPUBackBuffer
@ GPU_BACKBUFFER_LEFT
void GPU_framebuffer_clear(GPUFrameBuffer *framebuffer, eGPUFrameBufferBits buffers, const float clear_col[4], float clear_depth, unsigned int clear_stencil)
GPUTexture * GPU_offscreen_color_texture(const GPUOffScreen *offscreen)
void GPU_clear_color(float red, float green, float blue, float alpha)
void GPU_framebuffer_multi_clear(GPUFrameBuffer *framebuffer, const float(*clear_colors)[4])
void GPU_offscreen_read_color_region(GPUOffScreen *offscreen, eGPUDataFormat data_format, int x, int y, int w, int h, void *r_data)
void GPU_offscreen_free(GPUOffScreen *offscreen)
void GPU_framebuffer_bind(GPUFrameBuffer *framebuffer)
void GPU_framebuffer_subpass_transition_array(GPUFrameBuffer *framebuffer, const GPUAttachmentState *attachment_states, uint attachment_len)
void GPU_backbuffer_bind(eGPUBackBuffer back_buffer_type)
eGPUTextureFormat GPU_offscreen_format(const GPUOffScreen *offscreen)
#define NULL_ATTACHMENT_COLOR
void GPU_clear_depth(float depth)
void GPU_framebuffer_read_color(GPUFrameBuffer *framebuffer, int x, int y, int width, int height, int channels, int slot, eGPUDataFormat data_format, void *r_data)
void GPU_framebuffer_clear_color(GPUFrameBuffer *fb, const float clear_col[4])
void GPU_framebuffer_viewport_set(GPUFrameBuffer *framebuffer, int x, int y, int width, int height)
#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_MAX_VIEWPORTS
#define GPU_ATTACHMENT_TEXTURE_LAYER_MIP(_texture, _layer, _mip)
void GPU_framebuffer_clear_depth(GPUFrameBuffer *fb, float clear_depth)
void GPU_framebuffer_free(GPUFrameBuffer *framebuffer)
GPUFrameBuffer * GPU_framebuffer_back_get()
void GPU_framebuffer_texture_attach(GPUFrameBuffer *framebuffer, GPUTexture *texture, int slot, int mip)
void GPU_offscreen_unbind(GPUOffScreen *offscreen, bool restore)
#define GPU_ATTACHMENT_TEXTURE_CUBEFACE_MIP(_texture, _face, _mip)
void GPU_framebuffer_blit(GPUFrameBuffer *fb_read, int read_slot, GPUFrameBuffer *fb_write, int write_slot, eGPUFrameBufferBits blit_buffers)
void GPU_framebuffer_bind_loadstore(GPUFrameBuffer *framebuffer, const GPULoadStore *load_store_actions, uint load_store_actions_len)
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.
Group Output data from inside of a node group A color picker Mix two input colors RGB to Convert a color s luminance to a grayscale value Generate a normal vector and a dot product Brightness Control the brightness and contrast of the input color Vector Map input vector components with curves Camera Retrieve information about the camera and how it relates to the current shading point s position Clamp a value between a minimum and a maximum Vector Perform vector math operation Invert Invert a producing a negative Combine Generate a color from its red
Group Output data from inside of a node group A color picker Mix two input colors RGB to Convert a color s luminance to a grayscale value Generate a normal vector and a dot product Brightness Control the brightness and contrast of the input color Vector Map input vector components with curves Camera Retrieve information about the camera and how it relates to the current shading point s position Clamp a value between a minimum and a maximum Vector Perform vector math operation Invert Invert a producing a negative Combine Generate a color from its green
SIMD_FORCE_INLINE const btScalar & w() const
Return the w value.
Definition btQuadWord.h:119
constexpr int64_t size() const
Definition BLI_span.hh:253
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
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()
#define printf
DEGForeachIDComponentCallback callback
#define FRAMEBUFFER_STACK_DEPTH
static struct @626 FrameBufferStack
#define MAX_CTX_FB_LEN
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
BLI_INLINE float fb(float length, float L)
format
void MEM_freeN(void *vmemh)
Definition mallocn.cc:105
ccl_device_inline float2 floor(const float2 a)
static void error(const char *str)
static Context * unwrap(GPUContext *ctx)
static GPUContext * wrap(Context *ctx)
size_t to_bytesize(GPUIndexBufType type)
int to_component_len(eGPUTextureFormat format)
GPUTexture * tex
eGPULoadOp load_action
eGPUStoreOp store_action
GPUTexture * color
GPUTexture * depth
struct GPUOffScreen::@627 framebuffers[MAX_CTX_FB_LEN]
GPUFrameBuffer * fb
char * buffers[2]