2023-08-16 00:20:26 +10:00
|
|
|
/* SPDX-FileCopyrightText: 2005 Blender Authors
|
2023-05-31 16:19:06 +02:00
|
|
|
*
|
|
|
|
|
* SPDX-License-Identifier: GPL-2.0-or-later */
|
2015-12-06 21:20:19 +01:00
|
|
|
|
2019-02-18 11:23:17 +11:00
|
|
|
/** \file
|
|
|
|
|
* \ingroup gpu
|
|
|
|
|
*/
|
|
|
|
|
|
2015-12-06 21:20:19 +01:00
|
|
|
#include "MEM_guardedalloc.h"
|
|
|
|
|
|
2018-03-25 17:46:48 +02:00
|
|
|
#include "BLI_math_base.h"
|
Cleanup: fewer iostreams related includes from BLI/BKE headers
Including <iostream> or similar headers is quite expensive, since it
also pulls in things like <locale> and so on. In many BLI headers,
iostreams are only used to implement some sort of "debug print",
or an operator<< for ostream.
Change some of the commonly used places to instead include <iosfwd>,
which is the standard way of forward-declaring iostreams related
classes, and move the actual debug-print / operator<< implementations
into .cc files.
This is not done for templated classes though (it would be possible
to provide explicit operator<< instantiations somewhere in the
source file, but that would lead to hard-to-figure-out linker error
whenever someone would add a different template type). There, where
possible, I changed from full <iostream> include to only the needed
<ostream> part.
For Span<T>, I just removed print_as_lines since it's not used by
anything. It could be moved into a .cc file using a similar approach
as above if needed.
Doing full blender build changes include counts this way:
- <iostream> 1986 -> 978
- <sstream> 2880 -> 925
It does not affect the total build time much though, mostly because
towards the end of it there's just several CPU cores finishing
compiling OpenVDB related source files.
Pull Request: https://projects.blender.org/blender/blender/pulls/111046
2023-08-11 12:27:56 +03:00
|
|
|
#include "BLI_string.h"
|
2020-03-19 09:33:03 +01:00
|
|
|
#include "BLI_utildefines.h"
|
2015-12-06 21:20:19 +01:00
|
|
|
|
2024-03-23 01:24:18 +01:00
|
|
|
#include "GPU_capabilities.hh"
|
|
|
|
|
#include "GPU_texture.hh"
|
2015-12-06 21:20:19 +01:00
|
|
|
|
2020-08-29 01:13:54 +02:00
|
|
|
#include "gpu_backend.hh"
|
2020-08-08 03:01:45 +02:00
|
|
|
#include "gpu_context_private.hh"
|
2020-08-29 01:13:54 +02:00
|
|
|
#include "gpu_texture_private.hh"
|
2018-06-11 20:50:14 +02:00
|
|
|
|
2020-08-25 23:27:40 +02:00
|
|
|
#include "gpu_framebuffer_private.hh"
|
|
|
|
|
|
2020-08-29 01:13:54 +02:00
|
|
|
namespace blender::gpu {
|
2015-12-06 21:20:19 +01:00
|
|
|
|
2020-08-29 01:13:54 +02:00
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
|
/** \name Constructor / Destructor
|
|
|
|
|
* \{ */
|
2018-03-25 17:46:48 +02:00
|
|
|
|
2020-08-29 01:13:54 +02:00
|
|
|
FrameBuffer::FrameBuffer(const char *name)
|
2018-03-25 17:46:48 +02:00
|
|
|
{
|
2020-08-29 01:13:54 +02:00
|
|
|
if (name) {
|
2023-05-09 12:50:37 +10:00
|
|
|
STRNCPY(name_, name);
|
2018-03-25 17:46:48 +02:00
|
|
|
}
|
2020-08-29 01:13:54 +02:00
|
|
|
else {
|
|
|
|
|
name_[0] = '\0';
|
2015-12-06 21:20:19 +01:00
|
|
|
}
|
2020-08-29 01:13:54 +02:00
|
|
|
/* Force config on first use. */
|
|
|
|
|
dirty_attachments_ = true;
|
2020-08-29 15:17:13 +02:00
|
|
|
dirty_state_ = true;
|
2015-12-06 21:20:19 +01:00
|
|
|
|
2020-12-07 12:21:11 +01:00
|
|
|
for (GPUAttachment &attachment : attachments_) {
|
|
|
|
|
attachment.tex = nullptr;
|
|
|
|
|
attachment.mip = -1;
|
|
|
|
|
attachment.layer = -1;
|
2015-12-06 21:20:19 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-08-29 01:13:54 +02:00
|
|
|
FrameBuffer::~FrameBuffer()
|
2018-06-11 20:50:14 +02:00
|
|
|
{
|
2020-12-07 12:21:11 +01:00
|
|
|
for (GPUAttachment &attachment : attachments_) {
|
|
|
|
|
if (attachment.tex != nullptr) {
|
|
|
|
|
reinterpret_cast<Texture *>(attachment.tex)->detach_from(this);
|
2020-08-29 01:13:54 +02:00
|
|
|
}
|
|
|
|
|
}
|
2021-04-29 14:48:59 -03:00
|
|
|
|
2021-04-30 11:20:39 -03:00
|
|
|
#ifndef GPU_NO_USE_PY_REFERENCES
|
2021-04-29 14:48:59 -03:00
|
|
|
if (this->py_ref) {
|
|
|
|
|
*this->py_ref = nullptr;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
2018-06-11 20:50:14 +02:00
|
|
|
}
|
|
|
|
|
|
2020-08-29 01:13:54 +02:00
|
|
|
/** \} */
|
2015-12-06 21:20:19 +01:00
|
|
|
|
2020-08-29 01:13:54 +02:00
|
|
|
/* -------------------------------------------------------------------- */
|
2020-09-02 09:58:26 +10:00
|
|
|
/** \name Attachments Management
|
2020-08-29 01:13:54 +02:00
|
|
|
* \{ */
|
2015-12-06 21:20:19 +01:00
|
|
|
|
2020-08-29 01:13:54 +02:00
|
|
|
void FrameBuffer::attachment_set(GPUAttachmentType type, const GPUAttachment &new_attachment)
|
2015-12-06 21:20:19 +01:00
|
|
|
{
|
2020-08-29 01:13:54 +02:00
|
|
|
if (new_attachment.mip == -1) {
|
|
|
|
|
return; /* GPU_ATTACHMENT_LEAVE */
|
2018-03-25 17:46:48 +02:00
|
|
|
}
|
2015-12-06 21:20:19 +01:00
|
|
|
|
2020-09-02 10:04:50 +10:00
|
|
|
if (type >= GPU_FB_MAX_ATTACHMENT) {
|
2017-06-08 20:12:58 +02:00
|
|
|
fprintf(stderr,
|
2020-08-29 01:13:54 +02:00
|
|
|
"GPUFramebuffer: Error: Trying to attach texture to type %d but maximum slot is %d.\n",
|
|
|
|
|
type - GPU_FB_COLOR_ATTACHMENT0,
|
2018-03-25 17:46:48 +02:00
|
|
|
GPU_FB_MAX_COLOR_ATTACHMENT);
|
|
|
|
|
return;
|
2017-06-08 20:12:58 +02:00
|
|
|
}
|
|
|
|
|
|
2020-08-29 01:13:54 +02:00
|
|
|
if (new_attachment.tex) {
|
|
|
|
|
if (new_attachment.layer > 0) {
|
2023-02-25 01:04:35 +01:00
|
|
|
BLI_assert(GPU_texture_is_cube(new_attachment.tex) ||
|
|
|
|
|
GPU_texture_is_array(new_attachment.tex));
|
2020-08-29 01:13:54 +02:00
|
|
|
}
|
2023-02-25 01:04:35 +01:00
|
|
|
if (GPU_texture_has_stencil_format(new_attachment.tex)) {
|
2020-08-29 01:13:54 +02:00
|
|
|
BLI_assert(ELEM(type, GPU_FB_DEPTH_STENCIL_ATTACHMENT));
|
|
|
|
|
}
|
2023-02-25 01:04:35 +01:00
|
|
|
else if (GPU_texture_has_depth_format(new_attachment.tex)) {
|
2020-08-29 01:13:54 +02:00
|
|
|
BLI_assert(ELEM(type, GPU_FB_DEPTH_ATTACHMENT));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
GPUAttachment &attachment = attachments_[type];
|
2017-06-08 20:12:58 +02:00
|
|
|
|
2024-12-10 17:13:06 +01:00
|
|
|
set_color_attachment_bit(type, new_attachment.tex != nullptr);
|
|
|
|
|
|
2020-08-29 01:13:54 +02:00
|
|
|
if (attachment.tex == new_attachment.tex && attachment.layer == new_attachment.layer &&
|
|
|
|
|
attachment.mip == new_attachment.mip)
|
|
|
|
|
{
|
2018-03-25 17:46:48 +02:00
|
|
|
return; /* Exact same texture already bound here. */
|
2017-06-16 13:25:22 +02:00
|
|
|
}
|
2020-08-29 01:13:54 +02:00
|
|
|
/* Unbind previous and bind new. */
|
2020-09-19 14:32:41 +10:00
|
|
|
/* TODO(fclem): cleanup the casts. */
|
2020-08-29 01:13:54 +02:00
|
|
|
if (attachment.tex) {
|
2020-09-05 17:37:01 +02:00
|
|
|
reinterpret_cast<Texture *>(attachment.tex)->detach_from(this);
|
2018-03-25 17:46:48 +02:00
|
|
|
}
|
2017-06-08 20:12:58 +02:00
|
|
|
|
2020-08-29 01:13:54 +02:00
|
|
|
/* Might be null if this is for unbinding. */
|
2023-08-29 15:49:32 +02:00
|
|
|
if (new_attachment.tex) {
|
|
|
|
|
reinterpret_cast<Texture *>(new_attachment.tex)->attach_to(this, type);
|
2020-08-29 01:13:54 +02:00
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
/* GPU_ATTACHMENT_NONE */
|
|
|
|
|
}
|
2017-06-16 13:25:22 +02:00
|
|
|
|
2023-08-29 15:49:32 +02:00
|
|
|
attachment = new_attachment;
|
2020-08-29 01:13:54 +02:00
|
|
|
dirty_attachments_ = true;
|
2017-06-16 13:25:22 +02:00
|
|
|
}
|
|
|
|
|
|
2020-09-05 17:37:01 +02:00
|
|
|
void FrameBuffer::attachment_remove(GPUAttachmentType type)
|
|
|
|
|
{
|
|
|
|
|
attachments_[type] = GPU_ATTACHMENT_NONE;
|
|
|
|
|
dirty_attachments_ = true;
|
2024-12-10 17:13:06 +01:00
|
|
|
set_color_attachment_bit(type, false);
|
2020-09-05 17:37:01 +02:00
|
|
|
}
|
|
|
|
|
|
2024-01-15 13:25:20 +01:00
|
|
|
void FrameBuffer::subpass_transition(const GPUAttachmentState depth_attachment_state,
|
|
|
|
|
Span<GPUAttachmentState> color_attachment_states)
|
|
|
|
|
{
|
|
|
|
|
/* NOTE: Depth is not supported as input attachment because the Metal API doesn't support it and
|
|
|
|
|
* because depth is not compatible with the framebuffer fetch implementation. */
|
2024-06-10 09:57:15 +02:00
|
|
|
BLI_assert(depth_attachment_state != GPU_ATTACHMENT_READ);
|
2024-01-15 13:25:20 +01:00
|
|
|
|
|
|
|
|
if (!attachments_[GPU_FB_DEPTH_ATTACHMENT].tex &&
|
|
|
|
|
!attachments_[GPU_FB_DEPTH_STENCIL_ATTACHMENT].tex)
|
|
|
|
|
{
|
2024-06-10 09:57:15 +02:00
|
|
|
BLI_assert(depth_attachment_state == GPU_ATTACHMENT_IGNORE);
|
2024-01-15 13:25:20 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
BLI_assert(color_attachment_states.size() <= GPU_FB_MAX_COLOR_ATTACHMENT);
|
|
|
|
|
for (int i : IndexRange(GPU_FB_MAX_COLOR_ATTACHMENT)) {
|
|
|
|
|
GPUAttachmentType type = GPU_FB_COLOR_ATTACHMENT0 + i;
|
|
|
|
|
if (this->attachments_[type].tex) {
|
|
|
|
|
BLI_assert(i < color_attachment_states.size());
|
2024-12-10 17:13:06 +01:00
|
|
|
set_color_attachment_bit(type, color_attachment_states[i] == GPU_ATTACHMENT_WRITE);
|
2024-01-15 13:25:20 +01:00
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
BLI_assert(i >= color_attachment_states.size() ||
|
2024-06-10 09:57:15 +02:00
|
|
|
color_attachment_states[i] == GPU_ATTACHMENT_IGNORE);
|
2024-01-15 13:25:20 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
subpass_transition_impl(depth_attachment_state, color_attachment_states);
|
|
|
|
|
}
|
|
|
|
|
|
2022-06-27 11:41:04 +02:00
|
|
|
void FrameBuffer::load_store_config_array(const GPULoadStore *load_store_actions, uint actions_len)
|
|
|
|
|
{
|
|
|
|
|
/* Follows attachment structure of GPU_framebuffer_config_array/GPU_framebuffer_ensure_config */
|
|
|
|
|
const GPULoadStore &depth_action = load_store_actions[0];
|
2023-09-04 18:30:54 +02:00
|
|
|
Span<GPULoadStore> color_attachment_actions(load_store_actions + 1, actions_len - 1);
|
2024-01-15 13:25:20 +01:00
|
|
|
BLI_assert(color_attachment_actions.size() <= GPU_FB_MAX_COLOR_ATTACHMENT);
|
|
|
|
|
|
|
|
|
|
if (!attachments_[GPU_FB_DEPTH_ATTACHMENT].tex &&
|
|
|
|
|
!attachments_[GPU_FB_DEPTH_STENCIL_ATTACHMENT].tex)
|
|
|
|
|
{
|
|
|
|
|
BLI_assert(depth_action.load_action == GPU_LOADACTION_DONT_CARE &&
|
|
|
|
|
depth_action.store_action == GPU_STOREACTION_DONT_CARE);
|
|
|
|
|
}
|
2022-06-27 11:41:04 +02:00
|
|
|
|
|
|
|
|
if (this->attachments_[GPU_FB_DEPTH_STENCIL_ATTACHMENT].tex) {
|
2023-09-04 18:30:54 +02:00
|
|
|
this->attachment_set_loadstore_op(GPU_FB_DEPTH_STENCIL_ATTACHMENT, depth_action);
|
2022-06-27 11:41:04 +02:00
|
|
|
}
|
2024-01-15 13:25:20 +01:00
|
|
|
|
2022-06-27 11:41:04 +02:00
|
|
|
if (this->attachments_[GPU_FB_DEPTH_ATTACHMENT].tex) {
|
2023-09-04 18:30:54 +02:00
|
|
|
this->attachment_set_loadstore_op(GPU_FB_DEPTH_ATTACHMENT, depth_action);
|
2022-06-27 11:41:04 +02:00
|
|
|
}
|
|
|
|
|
|
2024-01-15 13:25:20 +01:00
|
|
|
for (int i : IndexRange(GPU_FB_MAX_COLOR_ATTACHMENT)) {
|
|
|
|
|
GPUAttachmentType type = GPU_FB_COLOR_ATTACHMENT0 + i;
|
2022-06-27 11:41:04 +02:00
|
|
|
if (this->attachments_[type].tex) {
|
2024-01-15 13:25:20 +01:00
|
|
|
BLI_assert(i < color_attachment_actions.size());
|
|
|
|
|
this->attachment_set_loadstore_op(type, color_attachment_actions[i]);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
BLI_assert(i >= color_attachment_actions.size() ||
|
|
|
|
|
(color_attachment_actions[i].load_action == GPU_LOADACTION_DONT_CARE &&
|
|
|
|
|
color_attachment_actions[i].store_action == GPU_STOREACTION_DONT_CARE));
|
2022-06-27 11:41:04 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-09-25 17:04:52 +10:00
|
|
|
uint FrameBuffer::get_bits_per_pixel()
|
2022-06-27 11:41:04 +02:00
|
|
|
{
|
2022-09-25 17:04:52 +10:00
|
|
|
uint total_bits = 0;
|
2022-06-27 11:41:04 +02:00
|
|
|
for (GPUAttachment &attachment : attachments_) {
|
|
|
|
|
Texture *tex = reinterpret_cast<Texture *>(attachment.tex);
|
|
|
|
|
if (tex != nullptr) {
|
|
|
|
|
int bits = to_bytesize(tex->format_get()) * to_component_len(tex->format_get());
|
|
|
|
|
total_bits += bits;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return total_bits;
|
|
|
|
|
}
|
|
|
|
|
|
2020-08-29 01:13:54 +02:00
|
|
|
/** \} */
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-08-29 01:13:54 +02:00
|
|
|
} // namespace blender::gpu
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-08-29 01:13:54 +02:00
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
|
/** \name C-API
|
|
|
|
|
* \{ */
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-08-29 01:13:54 +02:00
|
|
|
using namespace blender;
|
|
|
|
|
using namespace blender::gpu;
|
2018-11-06 15:24:13 +01:00
|
|
|
|
2025-09-16 17:50:48 +02:00
|
|
|
gpu::FrameBuffer *GPU_framebuffer_create(const char *name)
|
2018-11-06 15:24:13 +01:00
|
|
|
{
|
2020-08-29 01:13:54 +02:00
|
|
|
/* We generate the FB object later at first use in order to
|
2020-09-02 09:58:26 +10:00
|
|
|
* create the frame-buffer in the right opengl context. */
|
2025-09-16 17:50:48 +02:00
|
|
|
return GPUBackend::get()->framebuffer_alloc(name);
|
2018-11-06 15:24:13 +01:00
|
|
|
}
|
|
|
|
|
|
2025-09-16 17:50:48 +02:00
|
|
|
void GPU_framebuffer_free(gpu::FrameBuffer *fb)
|
2018-11-06 15:24:13 +01:00
|
|
|
{
|
2025-09-16 17:50:48 +02:00
|
|
|
delete fb;
|
2018-11-06 15:24:13 +01:00
|
|
|
}
|
|
|
|
|
|
2025-09-16 17:50:48 +02:00
|
|
|
const char *GPU_framebuffer_get_name(gpu::FrameBuffer *fb)
|
2022-10-30 14:56:54 +01:00
|
|
|
{
|
2025-09-16 17:50:48 +02:00
|
|
|
return fb->name_get();
|
2022-10-30 14:56:54 +01:00
|
|
|
}
|
|
|
|
|
|
2020-08-29 01:13:54 +02:00
|
|
|
/* ---------- Binding ----------- */
|
2018-11-06 15:24:13 +01:00
|
|
|
|
2025-09-16 17:50:48 +02:00
|
|
|
void GPU_framebuffer_bind(gpu::FrameBuffer *fb)
|
2017-02-07 11:20:15 +01:00
|
|
|
{
|
2020-08-29 01:13:54 +02:00
|
|
|
const bool enable_srgb = true;
|
2023-12-04 17:32:28 +01:00
|
|
|
/* Disable custom loadstore and bind. */
|
2025-09-16 17:50:48 +02:00
|
|
|
fb->set_use_explicit_loadstore(false);
|
|
|
|
|
fb->bind(enable_srgb);
|
2020-08-29 01:13:54 +02:00
|
|
|
}
|
2020-08-25 23:27:40 +02:00
|
|
|
|
2025-09-16 17:50:48 +02:00
|
|
|
void GPU_framebuffer_bind_loadstore(gpu::FrameBuffer *fb,
|
2022-06-27 11:41:04 +02:00
|
|
|
const GPULoadStore *load_store_actions,
|
|
|
|
|
uint actions_len)
|
|
|
|
|
{
|
2023-12-04 17:32:28 +01:00
|
|
|
const bool enable_srgb = true;
|
|
|
|
|
/* Bind with explicit loadstore state */
|
2025-09-16 17:50:48 +02:00
|
|
|
fb->set_use_explicit_loadstore(true);
|
|
|
|
|
fb->bind(enable_srgb);
|
2022-06-27 11:41:04 +02:00
|
|
|
|
|
|
|
|
/* Update load store */
|
2025-09-16 17:50:48 +02:00
|
|
|
fb->load_store_config_array(load_store_actions, actions_len);
|
2022-06-27 11:41:04 +02:00
|
|
|
}
|
|
|
|
|
|
2025-09-16 17:50:48 +02:00
|
|
|
void GPU_framebuffer_subpass_transition_array(gpu::FrameBuffer *fb,
|
2023-10-01 15:27:21 +02:00
|
|
|
const GPUAttachmentState *attachment_states,
|
|
|
|
|
uint attachment_len)
|
|
|
|
|
{
|
2025-09-16 17:50:48 +02:00
|
|
|
fb->subpass_transition(attachment_states[0],
|
|
|
|
|
Span<GPUAttachmentState>(attachment_states + 1, attachment_len - 1));
|
2023-10-01 15:27:21 +02:00
|
|
|
}
|
|
|
|
|
|
2025-09-16 17:50:48 +02:00
|
|
|
void GPU_framebuffer_bind_no_srgb(gpu::FrameBuffer *fb)
|
2020-08-29 01:13:54 +02:00
|
|
|
{
|
|
|
|
|
const bool enable_srgb = false;
|
2025-09-16 17:50:48 +02:00
|
|
|
fb->bind(enable_srgb);
|
2020-08-29 01:13:54 +02:00
|
|
|
}
|
2017-02-07 11:20:15 +01:00
|
|
|
|
2025-09-15 15:11:02 +02:00
|
|
|
void GPU_backbuffer_bind(GPUBackBuffer back_buffer_type)
|
2020-08-29 01:13:54 +02:00
|
|
|
{
|
2020-09-08 04:12:12 +02:00
|
|
|
Context *ctx = Context::get();
|
2020-04-14 20:44:45 +02:00
|
|
|
|
2024-10-31 15:18:29 +01:00
|
|
|
if (back_buffer_type == GPU_BACKBUFFER_LEFT) {
|
2020-08-29 01:13:54 +02:00
|
|
|
ctx->back_left->bind(false);
|
2019-04-22 09:32:37 +10:00
|
|
|
}
|
2020-08-29 01:13:54 +02:00
|
|
|
else {
|
|
|
|
|
ctx->back_right->bind(false);
|
2018-12-05 20:59:22 -02:00
|
|
|
}
|
2020-08-29 01:13:54 +02:00
|
|
|
}
|
2017-02-07 11:20:15 +01:00
|
|
|
|
2021-12-08 00:31:20 -05:00
|
|
|
void GPU_framebuffer_restore()
|
2020-08-29 01:13:54 +02:00
|
|
|
{
|
2020-09-08 04:12:12 +02:00
|
|
|
Context::get()->back_left->bind(false);
|
2020-08-29 01:13:54 +02:00
|
|
|
}
|
2017-02-07 11:20:15 +01:00
|
|
|
|
2025-09-16 17:50:48 +02:00
|
|
|
gpu::FrameBuffer *GPU_framebuffer_active_get()
|
2020-08-29 01:13:54 +02:00
|
|
|
{
|
2020-09-08 04:12:12 +02:00
|
|
|
Context *ctx = Context::get();
|
2025-09-16 17:50:48 +02:00
|
|
|
return ctx ? ctx->active_fb : nullptr;
|
2017-02-07 11:20:15 +01:00
|
|
|
}
|
|
|
|
|
|
2025-09-16 17:50:48 +02:00
|
|
|
gpu::FrameBuffer *GPU_framebuffer_back_get()
|
2020-08-18 14:43:18 +02:00
|
|
|
{
|
2020-09-08 04:12:12 +02:00
|
|
|
Context *ctx = Context::get();
|
2025-09-16 17:50:48 +02:00
|
|
|
return ctx ? ctx->back_left : nullptr;
|
2020-08-29 01:13:54 +02:00
|
|
|
}
|
2020-08-25 23:27:40 +02:00
|
|
|
|
2025-09-16 17:50:48 +02:00
|
|
|
bool GPU_framebuffer_bound(gpu::FrameBuffer *gpu_fb)
|
2020-08-29 01:13:54 +02:00
|
|
|
{
|
|
|
|
|
return (gpu_fb == GPU_framebuffer_active_get());
|
|
|
|
|
}
|
2020-08-18 14:43:18 +02:00
|
|
|
|
2020-08-29 01:13:54 +02:00
|
|
|
/* ---------- Attachment Management ----------- */
|
2020-08-18 14:43:18 +02:00
|
|
|
|
2025-09-16 17:50:48 +02:00
|
|
|
bool GPU_framebuffer_check_valid(gpu::FrameBuffer *gpu_fb, char err_out[256])
|
2020-08-29 01:13:54 +02:00
|
|
|
{
|
2025-09-16 17:50:48 +02:00
|
|
|
return gpu_fb->check(err_out);
|
2020-08-18 14:43:18 +02:00
|
|
|
}
|
|
|
|
|
|
2025-09-16 17:50:48 +02:00
|
|
|
static void gpu_framebuffer_texture_attach_ex(gpu::FrameBuffer *gpu_fb,
|
2023-03-05 16:31:28 +01:00
|
|
|
GPUAttachment attachment,
|
|
|
|
|
int slot)
|
2015-12-06 21:20:19 +01:00
|
|
|
{
|
2020-09-02 01:25:32 +02:00
|
|
|
Texture *tex = reinterpret_cast<Texture *>(attachment.tex);
|
|
|
|
|
GPUAttachmentType type = tex->attachment_type(slot);
|
2025-09-16 17:50:48 +02:00
|
|
|
gpu_fb->attachment_set(type, attachment);
|
2015-12-06 21:20:19 +01:00
|
|
|
}
|
|
|
|
|
|
2025-09-16 17:50:48 +02:00
|
|
|
void GPU_framebuffer_texture_attach(gpu::FrameBuffer *fb,
|
2025-07-22 09:48:10 +02:00
|
|
|
blender::gpu::Texture *tex,
|
|
|
|
|
int slot,
|
|
|
|
|
int mip)
|
2020-08-30 19:07:49 +02:00
|
|
|
{
|
2020-09-02 10:04:50 +10:00
|
|
|
GPUAttachment attachment = GPU_ATTACHMENT_TEXTURE_MIP(tex, mip);
|
2023-03-05 16:31:28 +01:00
|
|
|
gpu_framebuffer_texture_attach_ex(fb, attachment, slot);
|
2020-08-30 19:07:49 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void GPU_framebuffer_texture_layer_attach(
|
2025-09-16 17:50:48 +02:00
|
|
|
gpu::FrameBuffer *fb, blender::gpu::Texture *tex, int slot, int layer, int mip)
|
2020-08-30 19:07:49 +02:00
|
|
|
{
|
2020-09-02 10:04:50 +10:00
|
|
|
GPUAttachment attachment = GPU_ATTACHMENT_TEXTURE_LAYER_MIP(tex, layer, mip);
|
2023-03-05 16:31:28 +01:00
|
|
|
gpu_framebuffer_texture_attach_ex(fb, attachment, slot);
|
2020-08-30 19:07:49 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void GPU_framebuffer_texture_cubeface_attach(
|
2025-09-16 17:50:48 +02:00
|
|
|
gpu::FrameBuffer *fb, blender::gpu::Texture *tex, int slot, int face, int mip)
|
2020-08-30 19:07:49 +02:00
|
|
|
{
|
2020-09-02 10:04:50 +10:00
|
|
|
GPUAttachment attachment = GPU_ATTACHMENT_TEXTURE_CUBEFACE_MIP(tex, face, mip);
|
2023-03-05 16:31:28 +01:00
|
|
|
gpu_framebuffer_texture_attach_ex(fb, attachment, slot);
|
2020-08-30 19:07:49 +02:00
|
|
|
}
|
|
|
|
|
|
2025-09-16 17:50:48 +02:00
|
|
|
void GPU_framebuffer_texture_detach(gpu::FrameBuffer *fb, blender::gpu::Texture *tex)
|
2015-12-06 21:20:19 +01:00
|
|
|
{
|
2025-09-16 17:50:48 +02:00
|
|
|
tex->detach_from(fb);
|
2015-12-06 21:20:19 +01:00
|
|
|
}
|
|
|
|
|
|
2025-09-16 17:50:48 +02:00
|
|
|
void GPU_framebuffer_config_array(gpu::FrameBuffer *fb,
|
2020-08-29 01:13:54 +02:00
|
|
|
const GPUAttachment *config,
|
|
|
|
|
int config_len)
|
2015-12-06 21:20:19 +01:00
|
|
|
{
|
2020-09-02 10:04:50 +10:00
|
|
|
const GPUAttachment &depth_attachment = config[0];
|
2020-08-29 01:13:54 +02:00
|
|
|
Span<GPUAttachment> color_attachments(config + 1, config_len - 1);
|
2016-08-19 00:52:52 -04:00
|
|
|
|
2020-09-02 10:04:50 +10:00
|
|
|
if (depth_attachment.mip == -1) {
|
2020-08-29 01:13:54 +02:00
|
|
|
/* GPU_ATTACHMENT_LEAVE */
|
|
|
|
|
}
|
2020-11-06 17:49:09 +01:00
|
|
|
else if (depth_attachment.tex == nullptr) {
|
2020-08-29 01:13:54 +02:00
|
|
|
/* GPU_ATTACHMENT_NONE: Need to clear both targets. */
|
2020-09-02 10:04:50 +10:00
|
|
|
fb->attachment_set(GPU_FB_DEPTH_STENCIL_ATTACHMENT, depth_attachment);
|
|
|
|
|
fb->attachment_set(GPU_FB_DEPTH_ATTACHMENT, depth_attachment);
|
2020-08-29 01:13:54 +02:00
|
|
|
}
|
|
|
|
|
else {
|
2023-02-25 01:04:35 +01:00
|
|
|
GPUAttachmentType type = GPU_texture_has_stencil_format(depth_attachment.tex) ?
|
2020-08-29 01:13:54 +02:00
|
|
|
GPU_FB_DEPTH_STENCIL_ATTACHMENT :
|
|
|
|
|
GPU_FB_DEPTH_ATTACHMENT;
|
2020-09-02 10:04:50 +10:00
|
|
|
fb->attachment_set(type, depth_attachment);
|
2015-12-06 21:20:19 +01:00
|
|
|
}
|
2016-08-19 00:52:52 -04:00
|
|
|
|
2020-08-29 01:13:54 +02:00
|
|
|
GPUAttachmentType type = GPU_FB_COLOR_ATTACHMENT0;
|
2020-09-02 10:04:50 +10:00
|
|
|
for (const GPUAttachment &attachment : color_attachments) {
|
|
|
|
|
fb->attachment_set(type, attachment);
|
2020-08-29 01:13:54 +02:00
|
|
|
++type;
|
|
|
|
|
}
|
2015-12-06 21:20:19 +01:00
|
|
|
}
|
|
|
|
|
|
2025-09-16 17:50:48 +02:00
|
|
|
void GPU_framebuffer_default_size(gpu::FrameBuffer *gpu_fb, int width, int height)
|
2022-09-17 10:17:38 +02:00
|
|
|
{
|
2025-09-16 17:50:48 +02:00
|
|
|
gpu_fb->default_size_set(width, height);
|
2022-09-17 10:17:38 +02:00
|
|
|
}
|
|
|
|
|
|
2020-08-29 15:17:13 +02:00
|
|
|
/* ---------- Viewport & Scissor Region ----------- */
|
2015-12-06 21:20:19 +01:00
|
|
|
|
2025-09-16 17:50:48 +02:00
|
|
|
void GPU_framebuffer_viewport_set(gpu::FrameBuffer *gpu_fb, int x, int y, int width, int height)
|
2020-08-29 15:17:13 +02:00
|
|
|
{
|
|
|
|
|
int viewport_rect[4] = {x, y, width, height};
|
2025-09-16 17:50:48 +02:00
|
|
|
gpu_fb->viewport_set(viewport_rect);
|
2020-08-29 15:17:13 +02:00
|
|
|
}
|
2018-03-25 14:18:39 +02:00
|
|
|
|
2025-09-16 17:50:48 +02:00
|
|
|
void GPU_framebuffer_multi_viewports_set(gpu::FrameBuffer *gpu_fb,
|
2023-08-08 17:12:49 +02:00
|
|
|
const int viewport_rects[GPU_MAX_VIEWPORTS][4])
|
|
|
|
|
{
|
2025-09-16 17:50:48 +02:00
|
|
|
gpu_fb->viewport_multi_set(viewport_rects);
|
2023-08-08 17:12:49 +02:00
|
|
|
}
|
|
|
|
|
|
2025-09-16 17:50:48 +02:00
|
|
|
void GPU_framebuffer_viewport_get(gpu::FrameBuffer *gpu_fb, int r_viewport[4])
|
2018-03-25 14:18:39 +02:00
|
|
|
{
|
2025-09-16 17:50:48 +02:00
|
|
|
gpu_fb->viewport_get(r_viewport);
|
2020-08-29 15:17:13 +02:00
|
|
|
}
|
2018-03-25 14:18:39 +02:00
|
|
|
|
2025-09-16 17:50:48 +02:00
|
|
|
void GPU_framebuffer_viewport_reset(gpu::FrameBuffer *gpu_fb)
|
2020-08-29 15:17:13 +02:00
|
|
|
{
|
2025-09-16 17:50:48 +02:00
|
|
|
gpu_fb->viewport_reset();
|
2018-03-25 14:18:39 +02:00
|
|
|
}
|
|
|
|
|
|
2021-02-05 16:23:34 +11:00
|
|
|
/* ---------- Frame-buffer Operations ----------- */
|
2020-08-29 15:17:13 +02:00
|
|
|
|
2025-09-16 17:50:48 +02:00
|
|
|
void GPU_framebuffer_clear(gpu::FrameBuffer *gpu_fb,
|
2025-09-15 15:11:02 +02:00
|
|
|
GPUFrameBufferBits buffers,
|
2018-09-12 12:18:35 +10:00
|
|
|
const float clear_col[4],
|
|
|
|
|
float clear_depth,
|
|
|
|
|
uint clear_stencil)
|
2018-03-25 14:18:39 +02:00
|
|
|
{
|
2025-09-16 17:50:48 +02:00
|
|
|
BLI_assert_msg(gpu_fb->get_use_explicit_loadstore() == false,
|
2023-12-04 17:32:28 +01:00
|
|
|
"Using GPU_framebuffer_clear_* functions in conjunction with custom load-store "
|
|
|
|
|
"state via GPU_framebuffer_bind_ex is invalid.");
|
2025-09-16 17:50:48 +02:00
|
|
|
gpu_fb->clear(buffers, clear_col, clear_depth, clear_stencil);
|
2023-03-05 16:31:28 +01:00
|
|
|
}
|
|
|
|
|
|
2025-09-16 17:50:48 +02:00
|
|
|
void GPU_framebuffer_clear_color(gpu::FrameBuffer *fb, const float clear_col[4])
|
2023-03-05 16:31:28 +01:00
|
|
|
{
|
|
|
|
|
GPU_framebuffer_clear(fb, GPU_COLOR_BIT, clear_col, 0.0f, 0x00);
|
|
|
|
|
}
|
|
|
|
|
|
2025-09-16 17:50:48 +02:00
|
|
|
void GPU_framebuffer_clear_depth(gpu::FrameBuffer *fb, float clear_depth)
|
2023-03-05 16:31:28 +01:00
|
|
|
{
|
2023-03-07 15:59:14 +11:00
|
|
|
GPU_framebuffer_clear(fb, GPU_DEPTH_BIT, nullptr, clear_depth, 0x00);
|
2023-03-05 16:31:28 +01:00
|
|
|
}
|
|
|
|
|
|
2025-09-16 17:50:48 +02:00
|
|
|
void GPU_framebuffer_clear_color_depth(gpu::FrameBuffer *fb,
|
2023-03-05 16:31:28 +01:00
|
|
|
const float clear_col[4],
|
|
|
|
|
float clear_depth)
|
|
|
|
|
{
|
|
|
|
|
GPU_framebuffer_clear(fb, GPU_COLOR_BIT | GPU_DEPTH_BIT, clear_col, clear_depth, 0x00);
|
|
|
|
|
}
|
|
|
|
|
|
2025-09-16 17:50:48 +02:00
|
|
|
void GPU_framebuffer_clear_stencil(gpu::FrameBuffer *fb, uint clear_stencil)
|
2023-03-05 16:31:28 +01:00
|
|
|
{
|
2023-03-07 15:59:14 +11:00
|
|
|
GPU_framebuffer_clear(fb, GPU_STENCIL_BIT, nullptr, 0.0f, clear_stencil);
|
2023-03-05 16:31:28 +01:00
|
|
|
}
|
|
|
|
|
|
2025-09-16 17:50:48 +02:00
|
|
|
void GPU_framebuffer_clear_depth_stencil(gpu::FrameBuffer *fb,
|
|
|
|
|
float clear_depth,
|
|
|
|
|
uint clear_stencil)
|
2023-03-05 16:31:28 +01:00
|
|
|
{
|
2023-03-07 15:59:14 +11:00
|
|
|
GPU_framebuffer_clear(fb, GPU_DEPTH_BIT | GPU_STENCIL_BIT, nullptr, clear_depth, clear_stencil);
|
2023-03-05 16:31:28 +01:00
|
|
|
}
|
|
|
|
|
|
2025-09-16 17:50:48 +02:00
|
|
|
void GPU_framebuffer_clear_color_depth_stencil(gpu::FrameBuffer *fb,
|
2023-03-05 16:31:28 +01:00
|
|
|
const float clear_col[4],
|
|
|
|
|
float clear_depth,
|
|
|
|
|
uint clear_stencil)
|
|
|
|
|
{
|
|
|
|
|
GPU_framebuffer_clear(
|
|
|
|
|
fb, GPU_COLOR_BIT | GPU_DEPTH_BIT | GPU_STENCIL_BIT, clear_col, clear_depth, clear_stencil);
|
2018-03-25 14:18:39 +02:00
|
|
|
}
|
|
|
|
|
|
2025-09-16 17:50:48 +02:00
|
|
|
void GPU_framebuffer_multi_clear(gpu::FrameBuffer *fb, const float (*clear_colors)[4])
|
2020-03-09 16:27:24 +01:00
|
|
|
{
|
2025-09-16 17:50:48 +02:00
|
|
|
BLI_assert_msg(fb->get_use_explicit_loadstore() == false,
|
2023-12-04 17:32:28 +01:00
|
|
|
"Using GPU_framebuffer_clear_* functions in conjunction with custom load-store "
|
|
|
|
|
"state via GPU_framebuffer_bind_ex is invalid.");
|
2025-09-16 17:50:48 +02:00
|
|
|
fb->clear_multi(clear_colors);
|
2018-03-25 17:46:48 +02:00
|
|
|
}
|
|
|
|
|
|
2020-08-29 01:13:54 +02:00
|
|
|
void GPU_clear_color(float red, float green, float blue, float alpha)
|
2018-03-25 17:46:48 +02:00
|
|
|
{
|
2023-12-04 17:32:28 +01:00
|
|
|
BLI_assert_msg(Context::get()->active_fb->get_use_explicit_loadstore() == false,
|
|
|
|
|
"Using GPU_framebuffer_clear_* functions in conjunction with custom load-store "
|
|
|
|
|
"state via GPU_framebuffer_bind_ex is invalid.");
|
2020-08-29 01:13:54 +02:00
|
|
|
float clear_col[4] = {red, green, blue, alpha};
|
2020-09-08 04:12:12 +02:00
|
|
|
Context::get()->active_fb->clear(GPU_COLOR_BIT, clear_col, 0.0f, 0x0);
|
2020-07-16 02:50:55 +02:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-08-29 01:13:54 +02:00
|
|
|
void GPU_clear_depth(float depth)
|
2020-07-16 02:50:55 +02:00
|
|
|
{
|
2023-12-04 17:32:28 +01:00
|
|
|
BLI_assert_msg(Context::get()->active_fb->get_use_explicit_loadstore() == false,
|
|
|
|
|
"Using GPU_framebuffer_clear_* functions in conjunction with custom load-store "
|
|
|
|
|
"state via GPU_framebuffer_bind_ex is invalid.");
|
2020-08-29 01:13:54 +02:00
|
|
|
float clear_col[4] = {0};
|
2020-09-08 04:12:12 +02:00
|
|
|
Context::get()->active_fb->clear(GPU_DEPTH_BIT, clear_col, depth, 0x0);
|
2020-07-16 02:50:55 +02:00
|
|
|
}
|
|
|
|
|
|
2020-09-07 21:08:31 +02:00
|
|
|
void GPU_framebuffer_read_depth(
|
2025-09-16 17:50:48 +02:00
|
|
|
gpu::FrameBuffer *fb, int x, int y, int w, int h, eGPUDataFormat format, void *data)
|
2020-07-16 02:50:55 +02:00
|
|
|
{
|
2020-08-29 01:13:54 +02:00
|
|
|
int rect[4] = {x, y, w, h};
|
2025-09-16 17:50:48 +02:00
|
|
|
fb->read(GPU_DEPTH_BIT, format, rect, 1, 1, data);
|
2020-07-16 02:50:55 +02:00
|
|
|
}
|
|
|
|
|
|
2025-09-16 17:50:48 +02:00
|
|
|
void GPU_framebuffer_read_color(gpu::FrameBuffer *fb,
|
2020-07-16 02:50:55 +02:00
|
|
|
int x,
|
|
|
|
|
int y,
|
|
|
|
|
int w,
|
|
|
|
|
int h,
|
|
|
|
|
int channels,
|
|
|
|
|
int slot,
|
|
|
|
|
eGPUDataFormat format,
|
|
|
|
|
void *data)
|
|
|
|
|
{
|
2020-08-29 01:13:54 +02:00
|
|
|
int rect[4] = {x, y, w, h};
|
2025-09-16 17:50:48 +02:00
|
|
|
fb->read(GPU_COLOR_BIT, format, rect, channels, slot, data);
|
2020-08-29 01:13:54 +02:00
|
|
|
}
|
|
|
|
|
|
2023-04-16 20:38:19 +10:00
|
|
|
void GPU_frontbuffer_read_color(
|
2020-08-29 01:13:54 +02:00
|
|
|
int x, int y, int w, int h, int channels, eGPUDataFormat format, void *data)
|
|
|
|
|
{
|
|
|
|
|
int rect[4] = {x, y, w, h};
|
2020-09-08 04:12:12 +02:00
|
|
|
Context::get()->front_left->read(GPU_COLOR_BIT, format, rect, channels, 0, data);
|
2018-03-25 17:46:48 +02:00
|
|
|
}
|
|
|
|
|
|
2020-09-19 14:32:41 +10:00
|
|
|
/* TODO(fclem): port as texture operation. */
|
2025-09-16 17:50:48 +02:00
|
|
|
void GPU_framebuffer_blit(gpu::FrameBuffer *fb_read,
|
2018-03-25 17:46:48 +02:00
|
|
|
int read_slot,
|
2025-09-16 17:50:48 +02:00
|
|
|
gpu::FrameBuffer *fb_write,
|
2018-03-25 17:46:48 +02:00
|
|
|
int write_slot,
|
2025-09-15 15:11:02 +02:00
|
|
|
GPUFrameBufferBits blit_buffers)
|
2018-03-25 17:46:48 +02:00
|
|
|
{
|
|
|
|
|
BLI_assert(blit_buffers != 0);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-09-08 04:12:12 +02:00
|
|
|
FrameBuffer *prev_fb = Context::get()->active_fb;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-08-29 01:13:54 +02:00
|
|
|
#ifndef NDEBUG
|
2025-07-22 09:48:10 +02:00
|
|
|
blender::gpu::Texture *read_tex, *write_tex;
|
2020-08-29 01:13:54 +02:00
|
|
|
if (blit_buffers & (GPU_DEPTH_BIT | GPU_STENCIL_BIT)) {
|
|
|
|
|
read_tex = fb_read->depth_tex();
|
|
|
|
|
write_tex = fb_write->depth_tex();
|
2018-03-25 17:46:48 +02:00
|
|
|
}
|
2020-08-29 01:13:54 +02:00
|
|
|
else {
|
|
|
|
|
read_tex = fb_read->color_tex(read_slot);
|
|
|
|
|
write_tex = fb_write->color_tex(write_slot);
|
2018-03-25 17:46:48 +02:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-08-29 01:13:54 +02:00
|
|
|
if (blit_buffers & GPU_DEPTH_BIT) {
|
2023-02-25 01:04:35 +01:00
|
|
|
BLI_assert(GPU_texture_has_depth_format(read_tex) && GPU_texture_has_depth_format(write_tex));
|
2017-11-14 20:49:13 +01:00
|
|
|
BLI_assert(GPU_texture_format(read_tex) == GPU_texture_format(write_tex));
|
2017-11-10 23:36:05 +01:00
|
|
|
}
|
2020-08-29 01:13:54 +02:00
|
|
|
if (blit_buffers & GPU_STENCIL_BIT) {
|
2023-02-25 01:04:35 +01:00
|
|
|
BLI_assert(GPU_texture_has_stencil_format(read_tex) &&
|
|
|
|
|
GPU_texture_has_stencil_format(write_tex));
|
2017-11-14 20:49:13 +01:00
|
|
|
BLI_assert(GPU_texture_format(read_tex) == GPU_texture_format(write_tex));
|
2017-11-10 23:36:05 +01:00
|
|
|
}
|
2020-08-29 01:13:54 +02:00
|
|
|
#endif
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-08-29 01:13:54 +02:00
|
|
|
fb_read->blit_to(blit_buffers, read_slot, fb_write, write_slot, 0, 0);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2022-01-31 10:29:46 +11:00
|
|
|
/* FIXME(@fclem): sRGB is not saved. */
|
2020-08-29 01:13:54 +02:00
|
|
|
prev_fb->bind(true);
|
2017-02-15 15:15:42 +01:00
|
|
|
}
|
|
|
|
|
|
2021-04-30 11:20:39 -03:00
|
|
|
#ifndef GPU_NO_USE_PY_REFERENCES
|
2025-09-16 17:50:48 +02:00
|
|
|
void **GPU_framebuffer_py_reference_get(gpu::FrameBuffer *fb)
|
2021-04-29 14:48:59 -03:00
|
|
|
{
|
2025-09-16 17:50:48 +02:00
|
|
|
return fb->py_ref;
|
2021-04-29 14:48:59 -03:00
|
|
|
}
|
|
|
|
|
|
2025-09-16 17:50:48 +02:00
|
|
|
void GPU_framebuffer_py_reference_set(gpu::FrameBuffer *fb, void **py_ref)
|
2021-04-29 14:48:59 -03:00
|
|
|
{
|
2025-09-16 17:50:48 +02:00
|
|
|
BLI_assert(py_ref == nullptr || fb->py_ref == nullptr);
|
|
|
|
|
fb->py_ref = py_ref;
|
2021-04-29 14:48:59 -03:00
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
2020-08-29 01:13:54 +02:00
|
|
|
/** \} */
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-08-29 01:13:54 +02:00
|
|
|
/* -------------------------------------------------------------------- */
|
2021-07-23 16:56:00 +10:00
|
|
|
/** \name Frame-Buffer Stack
|
2020-08-29 01:13:54 +02:00
|
|
|
*
|
2021-02-18 13:26:39 +11:00
|
|
|
* Keeps track of frame-buffer binding operation to restore previously bound frame-buffers.
|
2020-08-29 01:13:54 +02:00
|
|
|
* \{ */
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-08-29 01:13:54 +02:00
|
|
|
#define FRAMEBUFFER_STACK_DEPTH 16
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-08-29 01:13:54 +02:00
|
|
|
static struct {
|
2025-09-16 17:50:48 +02:00
|
|
|
gpu::FrameBuffer *framebuffers[FRAMEBUFFER_STACK_DEPTH];
|
2020-08-29 01:13:54 +02:00
|
|
|
uint top;
|
2020-11-06 17:49:09 +01:00
|
|
|
} FrameBufferStack = {{nullptr}};
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2025-09-16 17:50:48 +02:00
|
|
|
void GPU_framebuffer_push(gpu::FrameBuffer *fb)
|
2020-08-29 01:13:54 +02:00
|
|
|
{
|
|
|
|
|
BLI_assert(FrameBufferStack.top < FRAMEBUFFER_STACK_DEPTH);
|
|
|
|
|
FrameBufferStack.framebuffers[FrameBufferStack.top] = fb;
|
|
|
|
|
FrameBufferStack.top++;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2025-09-16 17:50:48 +02:00
|
|
|
gpu::FrameBuffer *GPU_framebuffer_pop()
|
2020-08-29 01:13:54 +02:00
|
|
|
{
|
|
|
|
|
BLI_assert(FrameBufferStack.top > 0);
|
|
|
|
|
FrameBufferStack.top--;
|
|
|
|
|
return FrameBufferStack.framebuffers[FrameBufferStack.top];
|
2017-06-22 02:01:58 +02:00
|
|
|
}
|
|
|
|
|
|
2021-12-08 00:31:20 -05:00
|
|
|
uint GPU_framebuffer_stack_level_get()
|
Python: gpu module: add new submodules and types
This commit extends the gpu python API with:
```
gpu.types.Buffer #"__init__", "to_list"
gpu.types.GPUTexture #"__init__", "clear", "read", "format"
gpu.types.GPUFrameBuffer #"__init__", "bind", "clear", "is_bound", "viewport", ("__enter__", "__exit__" with "GPUFrameBufferStackContext")
gpu.types.GPUUniformBuf #"__init__", "update"
gpu.state #"blend_set", "blend_get", "depth_test_set", "depth_test_get", "depth_mask_set", "depth_mask_get", "viewport_set", "viewport_get", "line_width_set", "line_width_get", "point_size_set", "color_mask_set", "face_culling_set", "front_facing_set", "program_point_size_set"
```
Add these methods to existing objects:
```
gpu.types.GPUShader #"uniform_sample", "uniform_buffer"
```
Maniphest Tasks: T80481
Differential Revision: https://developer.blender.org/D8826
2021-02-17 10:48:08 -03:00
|
|
|
{
|
|
|
|
|
return FrameBufferStack.top;
|
|
|
|
|
}
|
|
|
|
|
|
2020-08-29 01:13:54 +02:00
|
|
|
#undef FRAMEBUFFER_STACK_DEPTH
|
2015-12-06 21:20:19 +01:00
|
|
|
|
Python: gpu module: add new submodules and types
This commit extends the gpu python API with:
```
gpu.types.Buffer #"__init__", "to_list"
gpu.types.GPUTexture #"__init__", "clear", "read", "format"
gpu.types.GPUFrameBuffer #"__init__", "bind", "clear", "is_bound", "viewport", ("__enter__", "__exit__" with "GPUFrameBufferStackContext")
gpu.types.GPUUniformBuf #"__init__", "update"
gpu.state #"blend_set", "blend_get", "depth_test_set", "depth_test_get", "depth_mask_set", "depth_mask_get", "viewport_set", "viewport_get", "line_width_set", "line_width_get", "point_size_set", "color_mask_set", "face_culling_set", "front_facing_set", "program_point_size_set"
```
Add these methods to existing objects:
```
gpu.types.GPUShader #"uniform_sample", "uniform_buffer"
```
Maniphest Tasks: T80481
Differential Revision: https://developer.blender.org/D8826
2021-02-17 10:48:08 -03:00
|
|
|
/** \} */
|
|
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
|
/** \name GPUOffScreen
|
|
|
|
|
*
|
|
|
|
|
* Container that holds a frame-buffer and its textures.
|
|
|
|
|
* Might be bound to multiple contexts.
|
|
|
|
|
* \{ */
|
|
|
|
|
|
2015-12-06 21:20:19 +01:00
|
|
|
struct GPUOffScreen {
|
2024-10-31 15:18:29 +01:00
|
|
|
constexpr static int MAX_CTX_FB_LEN = 3;
|
|
|
|
|
|
2019-06-13 21:31:46 +02:00
|
|
|
struct {
|
2020-09-08 04:12:12 +02:00
|
|
|
Context *ctx;
|
2025-09-16 17:50:48 +02:00
|
|
|
gpu::FrameBuffer *fb;
|
2019-06-13 21:31:46 +02:00
|
|
|
} framebuffers[MAX_CTX_FB_LEN];
|
|
|
|
|
|
2025-07-22 09:48:10 +02:00
|
|
|
blender::gpu::Texture *color;
|
|
|
|
|
blender::gpu::Texture *depth;
|
2015-12-06 21:20:19 +01:00
|
|
|
};
|
|
|
|
|
|
2020-09-02 09:58:26 +10:00
|
|
|
/**
|
|
|
|
|
* Returns the correct frame-buffer for the current context.
|
|
|
|
|
*/
|
2025-09-16 17:50:48 +02:00
|
|
|
static gpu::FrameBuffer *gpu_offscreen_fb_get(GPUOffScreen *ofs)
|
2019-06-13 21:31:46 +02:00
|
|
|
{
|
2020-09-08 04:12:12 +02:00
|
|
|
Context *ctx = Context::get();
|
2019-06-13 21:31:46 +02:00
|
|
|
BLI_assert(ctx);
|
|
|
|
|
|
2020-12-07 12:21:11 +01:00
|
|
|
for (auto &framebuffer : ofs->framebuffers) {
|
|
|
|
|
if (framebuffer.fb == nullptr) {
|
|
|
|
|
framebuffer.ctx = ctx;
|
|
|
|
|
GPU_framebuffer_ensure_config(&framebuffer.fb,
|
2020-07-25 18:40:19 +02:00
|
|
|
{
|
|
|
|
|
GPU_ATTACHMENT_TEXTURE(ofs->depth),
|
|
|
|
|
GPU_ATTACHMENT_TEXTURE(ofs->color),
|
|
|
|
|
});
|
2019-06-13 21:31:46 +02:00
|
|
|
}
|
|
|
|
|
|
2020-12-07 12:21:11 +01:00
|
|
|
if (framebuffer.ctx == ctx) {
|
|
|
|
|
return framebuffer.fb;
|
2019-06-13 21:31:46 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* List is full, this should never happen or
|
|
|
|
|
* it might just slow things down if it happens
|
2019-07-07 15:38:41 +10:00
|
|
|
* regularly. In this case we just empty the list
|
2019-06-13 21:31:46 +02:00
|
|
|
* and start over. This is most likely never going
|
|
|
|
|
* to happen under normal usage. */
|
|
|
|
|
BLI_assert(0);
|
|
|
|
|
printf(
|
|
|
|
|
"Warning: GPUOffscreen used in more than 3 GPUContext. "
|
|
|
|
|
"This may create performance drop.\n");
|
|
|
|
|
|
2020-12-07 12:21:11 +01:00
|
|
|
for (auto &framebuffer : ofs->framebuffers) {
|
|
|
|
|
GPU_framebuffer_free(framebuffer.fb);
|
|
|
|
|
framebuffer.fb = nullptr;
|
2019-06-13 21:31:46 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return gpu_offscreen_fb_get(ofs);
|
|
|
|
|
}
|
|
|
|
|
|
2023-04-14 22:02:51 +02:00
|
|
|
GPUOffScreen *GPU_offscreen_create(int width,
|
|
|
|
|
int height,
|
2024-10-31 15:18:29 +01:00
|
|
|
bool with_depth_buffer,
|
2025-07-22 14:58:54 +02:00
|
|
|
blender::gpu::TextureFormat format,
|
2023-04-14 22:02:51 +02:00
|
|
|
eGPUTextureUsage usage,
|
2025-05-28 13:17:37 +02:00
|
|
|
bool clear,
|
2023-04-14 22:02:51 +02:00
|
|
|
char err_out[256])
|
2015-12-06 21:20:19 +01:00
|
|
|
{
|
2025-03-05 16:35:09 +01:00
|
|
|
GPUOffScreen *ofs = MEM_callocN<GPUOffScreen>(__func__);
|
2015-12-06 21:20:19 +01:00
|
|
|
|
2019-01-22 16:30:17 +01:00
|
|
|
/* Sometimes areas can have 0 height or width and this will
|
|
|
|
|
* create a 1D texture which we don't want. */
|
|
|
|
|
height = max_ii(1, height);
|
|
|
|
|
width = max_ii(1, width);
|
|
|
|
|
|
2023-04-14 22:02:51 +02:00
|
|
|
/* Always add GPU_TEXTURE_USAGE_ATTACHMENT for convenience. */
|
|
|
|
|
usage |= GPU_TEXTURE_USAGE_ATTACHMENT;
|
|
|
|
|
|
2023-02-25 01:52:27 +01:00
|
|
|
ofs->color = GPU_texture_create_2d("ofs_color", width, height, 1, format, usage, nullptr);
|
2015-12-06 21:20:19 +01:00
|
|
|
|
2024-10-31 15:18:29 +01:00
|
|
|
if (with_depth_buffer) {
|
2023-11-24 16:52:21 +01:00
|
|
|
/* Format view flag is needed by Workbench Volumes to read the stencil view. */
|
|
|
|
|
eGPUTextureUsage depth_usage = usage | GPU_TEXTURE_USAGE_FORMAT_VIEW;
|
2025-07-22 14:58:54 +02:00
|
|
|
ofs->depth = GPU_texture_create_2d("ofs_depth",
|
|
|
|
|
width,
|
|
|
|
|
height,
|
|
|
|
|
1,
|
|
|
|
|
blender::gpu::TextureFormat::SFLOAT_32_DEPTH_UINT_8,
|
|
|
|
|
depth_usage,
|
|
|
|
|
nullptr);
|
2015-12-06 21:20:19 +01:00
|
|
|
}
|
|
|
|
|
|
2024-10-31 15:18:29 +01:00
|
|
|
if ((with_depth_buffer && !ofs->depth) || !ofs->color) {
|
2025-07-22 09:48:10 +02:00
|
|
|
const char error[] = "blender::gpu::Texture: Texture allocation failed.";
|
2021-07-14 20:38:18 -03:00
|
|
|
if (err_out) {
|
2023-05-09 12:59:07 +10:00
|
|
|
BLI_strncpy(err_out, error, 256);
|
2021-07-14 20:38:18 -03:00
|
|
|
}
|
|
|
|
|
else {
|
2023-05-09 12:59:07 +10:00
|
|
|
fprintf(stderr, "%s", error);
|
2021-07-14 20:38:18 -03:00
|
|
|
}
|
2015-12-06 21:20:19 +01:00
|
|
|
GPU_offscreen_free(ofs);
|
2020-11-06 17:49:09 +01:00
|
|
|
return nullptr;
|
2015-12-06 21:20:19 +01:00
|
|
|
}
|
2018-04-20 20:51:54 +02:00
|
|
|
|
2025-09-16 17:50:48 +02:00
|
|
|
gpu::FrameBuffer *fb = gpu_offscreen_fb_get(ofs);
|
2018-03-25 17:46:48 +02:00
|
|
|
|
2015-12-06 21:20:19 +01:00
|
|
|
/* check validity at the very end! */
|
2019-06-13 21:31:46 +02:00
|
|
|
if (!GPU_framebuffer_check_valid(fb, err_out)) {
|
2015-12-06 21:20:19 +01:00
|
|
|
GPU_offscreen_free(ofs);
|
2020-11-06 17:49:09 +01:00
|
|
|
return nullptr;
|
2015-12-06 21:20:19 +01:00
|
|
|
}
|
2025-05-28 13:17:37 +02:00
|
|
|
|
|
|
|
|
if (clear) {
|
|
|
|
|
float const clear_color[4] = {0.0f, 0.0f, 0.0f, 0.0f};
|
|
|
|
|
float clear_depth = 0.0f;
|
|
|
|
|
GPU_framebuffer_bind(fb);
|
|
|
|
|
if (with_depth_buffer) {
|
|
|
|
|
GPU_framebuffer_clear_color_depth(fb, clear_color, clear_depth);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
GPU_framebuffer_clear_color(fb, clear_color);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-12-06 21:20:19 +01:00
|
|
|
GPU_framebuffer_restore();
|
|
|
|
|
return ofs;
|
|
|
|
|
}
|
|
|
|
|
|
2024-10-31 15:18:29 +01:00
|
|
|
void GPU_offscreen_free(GPUOffScreen *offscreen)
|
2015-12-06 21:20:19 +01:00
|
|
|
{
|
2024-10-31 15:18:29 +01:00
|
|
|
for (auto &framebuffer : offscreen->framebuffers) {
|
2020-12-07 12:21:11 +01:00
|
|
|
if (framebuffer.fb) {
|
|
|
|
|
GPU_framebuffer_free(framebuffer.fb);
|
2019-06-13 21:31:46 +02:00
|
|
|
}
|
2019-04-22 09:32:37 +10:00
|
|
|
}
|
2024-10-31 15:18:29 +01:00
|
|
|
if (offscreen->color) {
|
|
|
|
|
GPU_texture_free(offscreen->color);
|
2019-04-22 09:32:37 +10:00
|
|
|
}
|
2024-10-31 15:18:29 +01:00
|
|
|
if (offscreen->depth) {
|
|
|
|
|
GPU_texture_free(offscreen->depth);
|
2019-04-22 09:32:37 +10:00
|
|
|
}
|
2018-06-04 09:09:12 +02:00
|
|
|
|
2024-10-31 15:18:29 +01:00
|
|
|
MEM_freeN(offscreen);
|
2015-12-06 21:20:19 +01:00
|
|
|
}
|
|
|
|
|
|
2024-10-31 15:18:29 +01:00
|
|
|
void GPU_offscreen_bind(GPUOffScreen *offscreen, bool save)
|
2015-12-06 21:20:19 +01:00
|
|
|
{
|
2018-03-25 17:46:48 +02:00
|
|
|
if (save) {
|
2025-09-16 17:50:48 +02:00
|
|
|
gpu::FrameBuffer *fb = GPU_framebuffer_active_get();
|
Python: gpu module: add new submodules and types
This commit extends the gpu python API with:
```
gpu.types.Buffer #"__init__", "to_list"
gpu.types.GPUTexture #"__init__", "clear", "read", "format"
gpu.types.GPUFrameBuffer #"__init__", "bind", "clear", "is_bound", "viewport", ("__enter__", "__exit__" with "GPUFrameBufferStackContext")
gpu.types.GPUUniformBuf #"__init__", "update"
gpu.state #"blend_set", "blend_get", "depth_test_set", "depth_test_get", "depth_mask_set", "depth_mask_get", "viewport_set", "viewport_get", "line_width_set", "line_width_get", "point_size_set", "color_mask_set", "face_culling_set", "front_facing_set", "program_point_size_set"
```
Add these methods to existing objects:
```
gpu.types.GPUShader #"uniform_sample", "uniform_buffer"
```
Maniphest Tasks: T80481
Differential Revision: https://developer.blender.org/D8826
2021-02-17 10:48:08 -03:00
|
|
|
GPU_framebuffer_push(fb);
|
2015-12-06 21:20:19 +01:00
|
|
|
}
|
2025-09-16 17:50:48 +02:00
|
|
|
gpu_offscreen_fb_get(offscreen)->bind(false);
|
2015-12-06 21:20:19 +01:00
|
|
|
}
|
|
|
|
|
|
2024-10-31 15:18:29 +01:00
|
|
|
void GPU_offscreen_unbind(GPUOffScreen * /*offscreen*/, bool restore)
|
2015-12-06 21:20:19 +01:00
|
|
|
{
|
2025-09-16 17:50:48 +02:00
|
|
|
gpu::FrameBuffer *fb = nullptr;
|
2018-03-25 17:46:48 +02:00
|
|
|
if (restore) {
|
Python: gpu module: add new submodules and types
This commit extends the gpu python API with:
```
gpu.types.Buffer #"__init__", "to_list"
gpu.types.GPUTexture #"__init__", "clear", "read", "format"
gpu.types.GPUFrameBuffer #"__init__", "bind", "clear", "is_bound", "viewport", ("__enter__", "__exit__" with "GPUFrameBufferStackContext")
gpu.types.GPUUniformBuf #"__init__", "update"
gpu.state #"blend_set", "blend_get", "depth_test_set", "depth_test_get", "depth_mask_set", "depth_mask_get", "viewport_set", "viewport_get", "line_width_set", "line_width_get", "point_size_set", "color_mask_set", "face_culling_set", "front_facing_set", "program_point_size_set"
```
Add these methods to existing objects:
```
gpu.types.GPUShader #"uniform_sample", "uniform_buffer"
```
Maniphest Tasks: T80481
Differential Revision: https://developer.blender.org/D8826
2021-02-17 10:48:08 -03:00
|
|
|
fb = GPU_framebuffer_pop();
|
2018-11-06 15:24:13 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (fb) {
|
|
|
|
|
GPU_framebuffer_bind(fb);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
GPU_framebuffer_restore();
|
2018-03-25 17:46:48 +02:00
|
|
|
}
|
2015-12-06 21:20:19 +01:00
|
|
|
}
|
|
|
|
|
|
2024-10-31 15:18:29 +01:00
|
|
|
void GPU_offscreen_draw_to_screen(GPUOffScreen *offscreen, int x, int y)
|
2018-04-27 10:22:37 +02:00
|
|
|
{
|
2020-09-08 04:12:12 +02:00
|
|
|
Context *ctx = Context::get();
|
2025-09-16 17:50:48 +02:00
|
|
|
FrameBuffer *ofs_fb = gpu_offscreen_fb_get(offscreen);
|
2020-08-29 01:13:54 +02:00
|
|
|
ofs_fb->blit_to(GPU_COLOR_BIT, 0, ctx->active_fb, 0, x, y);
|
2018-04-27 10:22:37 +02:00
|
|
|
}
|
|
|
|
|
|
2023-04-16 20:38:19 +10:00
|
|
|
void GPU_offscreen_read_color_region(
|
2024-10-31 15:18:29 +01:00
|
|
|
GPUOffScreen *offscreen, eGPUDataFormat format, int x, int y, int w, int h, void *r_data)
|
2023-04-16 20:08:32 +10:00
|
|
|
{
|
|
|
|
|
BLI_assert(ELEM(format, GPU_DATA_UBYTE, GPU_DATA_FLOAT));
|
|
|
|
|
BLI_assert(x >= 0 && y >= 0 && w > 0 && h > 0);
|
2024-10-31 15:18:29 +01:00
|
|
|
BLI_assert(x + w <= GPU_texture_width(offscreen->color));
|
|
|
|
|
BLI_assert(y + h <= GPU_texture_height(offscreen->color));
|
2023-04-16 20:08:32 +10:00
|
|
|
|
2025-09-16 17:50:48 +02:00
|
|
|
gpu::FrameBuffer *ofs_fb = gpu_offscreen_fb_get(offscreen);
|
2023-04-16 20:38:19 +10:00
|
|
|
GPU_framebuffer_read_color(ofs_fb, x, y, w, h, 4, 0, format, r_data);
|
2023-04-16 20:08:32 +10:00
|
|
|
}
|
|
|
|
|
|
2024-10-31 15:18:29 +01:00
|
|
|
void GPU_offscreen_read_color(GPUOffScreen *offscreen, eGPUDataFormat format, void *r_data)
|
2015-12-06 21:20:19 +01:00
|
|
|
{
|
2021-02-17 12:38:21 -03:00
|
|
|
BLI_assert(ELEM(format, GPU_DATA_UBYTE, GPU_DATA_FLOAT));
|
2020-08-29 01:13:54 +02:00
|
|
|
|
2024-10-31 15:18:29 +01:00
|
|
|
const int w = GPU_texture_width(offscreen->color);
|
|
|
|
|
const int h = GPU_texture_height(offscreen->color);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2024-10-31 15:18:29 +01:00
|
|
|
GPU_offscreen_read_color_region(offscreen, format, 0, 0, w, h, r_data);
|
2015-12-06 21:20:19 +01:00
|
|
|
}
|
|
|
|
|
|
2024-10-31 15:18:29 +01:00
|
|
|
int GPU_offscreen_width(const GPUOffScreen *offscreen)
|
2015-12-06 21:20:19 +01:00
|
|
|
{
|
2024-10-31 15:18:29 +01:00
|
|
|
return GPU_texture_width(offscreen->color);
|
2015-12-06 21:20:19 +01:00
|
|
|
}
|
|
|
|
|
|
2024-10-31 15:18:29 +01:00
|
|
|
int GPU_offscreen_height(const GPUOffScreen *offscreen)
|
2015-12-06 21:20:19 +01:00
|
|
|
{
|
2024-10-31 15:18:29 +01:00
|
|
|
return GPU_texture_height(offscreen->color);
|
2015-12-06 21:20:19 +01:00
|
|
|
}
|
|
|
|
|
|
2025-07-22 09:48:10 +02:00
|
|
|
blender::gpu::Texture *GPU_offscreen_color_texture(const GPUOffScreen *offscreen)
|
2015-12-06 21:20:19 +01:00
|
|
|
{
|
2024-10-31 15:18:29 +01:00
|
|
|
return offscreen->color;
|
2015-12-06 21:20:19 +01:00
|
|
|
}
|
|
|
|
|
|
2025-07-22 14:58:54 +02:00
|
|
|
blender::gpu::TextureFormat GPU_offscreen_format(const GPUOffScreen *offscreen)
|
2023-08-09 14:25:15 +02:00
|
|
|
{
|
|
|
|
|
return GPU_texture_format(offscreen->color);
|
|
|
|
|
}
|
|
|
|
|
|
2024-10-31 15:18:29 +01:00
|
|
|
void GPU_offscreen_viewport_data_get(GPUOffScreen *offscreen,
|
2025-09-16 17:50:48 +02:00
|
|
|
gpu::FrameBuffer **r_fb,
|
2025-07-22 09:48:10 +02:00
|
|
|
blender::gpu::Texture **r_color,
|
|
|
|
|
blender::gpu::Texture **r_depth)
|
2017-05-03 02:50:29 +10:00
|
|
|
{
|
2024-10-31 15:18:29 +01:00
|
|
|
*r_fb = gpu_offscreen_fb_get(offscreen);
|
|
|
|
|
*r_color = offscreen->color;
|
|
|
|
|
*r_depth = offscreen->depth;
|
2017-05-09 15:09:39 +02:00
|
|
|
}
|
2018-06-26 15:17:31 -06:00
|
|
|
|
2020-09-02 09:58:26 +10:00
|
|
|
/** \} */
|