Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorClément Foucault <foucault.clem@gmail.com>2020-08-29 02:13:54 +0300
committerClément Foucault <foucault.clem@gmail.com>2020-08-30 14:11:02 +0300
commitf3a65a1b4aa3c7da221acdbeee20afb7ebe3b221 (patch)
tree1b7b8c90ef0ecb891b35c8fa89cf25873035d784 /source/blender/gpu/intern/gpu_framebuffer.cc
parent0850afb34e21c073eb2a4c7475eeab2684f30e43 (diff)
GPUFrameBuffer: GL backend isolation
This is related to the Vulkan port T68990. This is a full cleanup of the Framebuffer module and a separation of OpenGL related functions. There is some changes with how the default framebuffers are handled. Now the default framebuffers are individually wrapped inside special GLFrameBuffers. This make it easier to keep track of the currently bound framebuffer state and have some specificity for operations on these framebuffers. Another change is dropping the optimisation of only configuring the changed attachements during framebuffers update. This does not give any benefits and add some complexity to the code. This might be brought back if it has a performance impact on some systems. This also adds support for naming framebuffers but it is currently not used.
Diffstat (limited to 'source/blender/gpu/intern/gpu_framebuffer.cc')
-rw-r--r--source/blender/gpu/intern/gpu_framebuffer.cc987
1 files changed, 286 insertions, 701 deletions
diff --git a/source/blender/gpu/intern/gpu_framebuffer.cc b/source/blender/gpu/intern/gpu_framebuffer.cc
index 5a575f9e5f5..3390b47b1b1 100644
--- a/source/blender/gpu/intern/gpu_framebuffer.cc
+++ b/source/blender/gpu/intern/gpu_framebuffer.cc
@@ -32,518 +32,313 @@
#include "GPU_shader.h"
#include "GPU_texture.h"
+#include "gpu_backend.hh"
#include "gpu_context_private.hh"
#include "gpu_private.h"
+#include "gpu_texture_private.hh"
#include "gpu_framebuffer_private.hh"
-using namespace blender::gpu;
+namespace blender::gpu {
-static GLenum convert_attachment_type_to_gl(GPUAttachmentType type)
-{
-#define ATTACHMENT(type) \
- case GPU_FB_##type: { \
- return GL_##type; \
- } \
- ((void)0)
-
- switch (type) {
- ATTACHMENT(DEPTH_ATTACHMENT);
- ATTACHMENT(DEPTH_STENCIL_ATTACHMENT);
- ATTACHMENT(COLOR_ATTACHMENT0);
- ATTACHMENT(COLOR_ATTACHMENT1);
- ATTACHMENT(COLOR_ATTACHMENT2);
- ATTACHMENT(COLOR_ATTACHMENT3);
- ATTACHMENT(COLOR_ATTACHMENT4);
- ATTACHMENT(COLOR_ATTACHMENT5);
- default:
- BLI_assert(0);
- return GL_COLOR_ATTACHMENT0;
- }
-}
+/* -------------------------------------------------------------------- */
+/** \name Constructor / Destructor
+ * \{ */
-static GPUAttachmentType attachment_type_from_tex(GPUTexture *tex, int slot)
+FrameBuffer::FrameBuffer(const char *name)
{
- switch (GPU_texture_format(tex)) {
- case GPU_DEPTH_COMPONENT32F:
- case GPU_DEPTH_COMPONENT24:
- case GPU_DEPTH_COMPONENT16:
- return GPU_FB_DEPTH_ATTACHMENT;
- case GPU_DEPTH24_STENCIL8:
- case GPU_DEPTH32F_STENCIL8:
- return GPU_FB_DEPTH_STENCIL_ATTACHMENT;
- default:
- return static_cast<GPUAttachmentType>(GPU_FB_COLOR_ATTACHMENT0 + slot);
+ if (name) {
+ BLI_strncpy(name_, name, sizeof(name_));
}
-}
-
-static GLenum convert_buffer_bits_to_gl(eGPUFrameBufferBits bits)
-{
- GLbitfield mask = 0;
- mask |= (bits & GPU_DEPTH_BIT) ? GL_DEPTH_BUFFER_BIT : 0;
- mask |= (bits & GPU_STENCIL_BIT) ? GL_STENCIL_BUFFER_BIT : 0;
- mask |= (bits & GPU_COLOR_BIT) ? GL_COLOR_BUFFER_BIT : 0;
- return mask;
-}
-
-static void gpu_print_framebuffer_error(GLenum status, char err_out[256])
-{
- const char *format = "GPUFrameBuffer: framebuffer status %s\n";
- const char *err = "unknown";
-
-#define FORMAT_STATUS(X) \
- case GL_FRAMEBUFFER_##X: { \
- err = "GL_FRAMEBUFFER_" #X; \
- break; \
- } \
- ((void)0)
-
- switch (status) {
- /* success */
- FORMAT_STATUS(COMPLETE);
- /* errors shared by OpenGL desktop & ES */
- FORMAT_STATUS(INCOMPLETE_ATTACHMENT);
- FORMAT_STATUS(INCOMPLETE_MISSING_ATTACHMENT);
- FORMAT_STATUS(UNSUPPORTED);
-#if 0 /* for OpenGL ES only */
- FORMAT_STATUS(INCOMPLETE_DIMENSIONS);
-#else /* for desktop GL only */
- FORMAT_STATUS(INCOMPLETE_DRAW_BUFFER);
- FORMAT_STATUS(INCOMPLETE_READ_BUFFER);
- FORMAT_STATUS(INCOMPLETE_MULTISAMPLE);
- FORMAT_STATUS(UNDEFINED);
-#endif
+ else {
+ name_[0] = '\0';
}
+ /* Force config on first use. */
+ dirty_attachments_ = true;
-#undef FORMAT_STATUS
-
- if (err_out) {
- BLI_snprintf(err_out, 256, format, err);
- }
- else {
- fprintf(stderr, format, err);
+ for (int i = 0; i < ARRAY_SIZE(attachments_); i++) {
+ attachments_[i].tex = NULL;
+ attachments_[i].mip = -1;
+ attachments_[i].layer = -1;
}
}
-GPUFrameBuffer *GPU_framebuffer_active_get(void)
+FrameBuffer::~FrameBuffer()
{
- GPUContext *ctx = GPU_context_active_get();
- return reinterpret_cast<GPUFrameBuffer *>(ctx ? ctx->active_fb : NULL);
+ GPUFrameBuffer *gpu_fb = reinterpret_cast<GPUFrameBuffer *>(this);
+ for (int i = 0; i < ARRAY_SIZE(attachments_); i++) {
+ if (attachments_[i].tex != NULL) {
+ GPU_texture_detach_framebuffer(attachments_[i].tex, gpu_fb);
+ }
+ }
}
-/* GPUFrameBuffer */
+/** \} */
-GPUFrameBuffer *GPU_framebuffer_create(void)
-{
- /* We generate the FB object later at first use in order to
- * create the framebuffer in the right opengl context. */
- return (GPUFrameBuffer *)new FrameBuffer();
-}
-
-static void gpu_framebuffer_init(FrameBuffer *fb)
-{
- fb->object = GPU_fbo_alloc();
- fb->ctx = GPU_context_active_get();
- /* Not really needed for now. */
- // gpu_context_add_framebuffer(fb->ctx, fb);
-}
+/* -------------------------------------------------------------------- */
+/** \name Attachments managment
+ * \{ */
-void GPU_framebuffer_free(GPUFrameBuffer *gpu_fb)
+void FrameBuffer::attachment_set(GPUAttachmentType type, const GPUAttachment &new_attachment)
{
- FrameBuffer *fb = reinterpret_cast<FrameBuffer *>(gpu_fb);
- for (int i_type = 0; i_type < GPU_FB_MAX_ATTACHEMENT; i_type++) {
- GPUAttachmentType type = static_cast<GPUAttachmentType>(i_type);
- if (fb->attachments[type].tex != NULL) {
- GPU_framebuffer_texture_detach(gpu_fb, fb->attachments[type].tex);
- }
- }
-
- if (fb->object != 0) {
- /* This restores the framebuffer if it was bound */
- GPU_fbo_free(fb->object, fb->ctx);
- /* Not really needed for now. */
- // gpu_context_remove_framebuffer(fb->ctx, fb);
- }
-
- /* TODO(fclem) check if bound in its associated context context. */
- if (GPU_framebuffer_active_get() == gpu_fb) {
- GPU_context_active_get()->active_fb = NULL;
+ if (new_attachment.mip == -1) {
+ return; /* GPU_ATTACHMENT_LEAVE */
}
- delete fb;
-}
-
-/* ---------- Attach ----------- */
-
-static void gpu_framebuffer_texture_attach_ex(
- FrameBuffer *fb, GPUTexture *tex, int slot, int layer, int mip)
-{
- if (slot >= GPU_FB_MAX_COLOR_ATTACHMENT) {
+ if (type >= GPU_FB_MAX_ATTACHEMENT) {
fprintf(stderr,
- "Attaching to index %d framebuffer slot unsupported. "
- "Use at most %d\n",
- slot,
+ "GPUFramebuffer: Error: Trying to attach texture to type %d but maximum slot is %d.\n",
+ type - GPU_FB_COLOR_ATTACHMENT0,
GPU_FB_MAX_COLOR_ATTACHMENT);
return;
}
- GPUFrameBuffer *gpufb = reinterpret_cast<GPUFrameBuffer *>(fb);
- GPUAttachmentType type = attachment_type_from_tex(tex, slot);
- GPUAttachment *attachment = &fb->attachments[type];
+ if (new_attachment.tex) {
+ if (new_attachment.layer > 0) {
+ BLI_assert(ELEM(GPU_texture_target(new_attachment.tex),
+ GL_TEXTURE_2D_ARRAY,
+ GL_TEXTURE_CUBE_MAP,
+ GL_TEXTURE_CUBE_MAP_ARRAY_ARB));
+ }
+ if (GPU_texture_stencil(new_attachment.tex)) {
+ BLI_assert(ELEM(type, GPU_FB_DEPTH_STENCIL_ATTACHMENT));
+ }
+ else if (GPU_texture_depth(new_attachment.tex)) {
+ BLI_assert(ELEM(type, GPU_FB_DEPTH_ATTACHMENT));
+ }
+ }
+
+ GPUAttachment &attachment = attachments_[type];
- if ((attachment->tex == tex) && (attachment->mip == mip) && (attachment->layer == layer)) {
+ if (attachment.tex == new_attachment.tex && attachment.layer == new_attachment.layer &&
+ attachment.mip == new_attachment.mip) {
return; /* Exact same texture already bound here. */
}
- if (attachment->tex != NULL) {
- GPU_framebuffer_texture_detach(gpufb, attachment->tex);
- }
-
- if (attachment->tex == NULL) {
- GPU_texture_attach_framebuffer(tex, gpufb, type);
+ /* Unbind previous and bind new. */
+ /* TODO(fclem) cleanup the casts. */
+ if (attachment.tex) {
+ GPU_texture_detach_framebuffer(attachment.tex, reinterpret_cast<GPUFrameBuffer *>(this));
}
- attachment->tex = tex;
- attachment->mip = mip;
- attachment->layer = layer;
- GPU_FB_ATTACHEMENT_SET_DIRTY(fb->dirty_flag, type);
-}
+ attachment = new_attachment;
-void GPU_framebuffer_texture_attach(GPUFrameBuffer *gpu_fb, GPUTexture *tex, int slot, int mip)
-{
- FrameBuffer *fb = reinterpret_cast<FrameBuffer *>(gpu_fb);
- gpu_framebuffer_texture_attach_ex(fb, tex, slot, -1, mip);
-}
+ /* Might be null if this is for unbinding. */
+ if (attachment.tex) {
+ GPU_texture_attach_framebuffer(attachment.tex, reinterpret_cast<GPUFrameBuffer *>(this), type);
+ }
+ else {
+ /* GPU_ATTACHMENT_NONE */
+ }
-void GPU_framebuffer_texture_layer_attach(
- GPUFrameBuffer *gpu_fb, GPUTexture *tex, int slot, int layer, int mip)
-{
- FrameBuffer *fb = reinterpret_cast<FrameBuffer *>(gpu_fb);
- /* NOTE: We could support 1D ARRAY texture. */
- BLI_assert(GPU_texture_target(tex) == GL_TEXTURE_2D_ARRAY);
- gpu_framebuffer_texture_attach_ex(fb, tex, slot, layer, mip);
+ dirty_attachments_ = true;
}
-void GPU_framebuffer_texture_cubeface_attach(
- GPUFrameBuffer *gpu_fb, GPUTexture *tex, int slot, int face, int mip)
+void FrameBuffer::recursive_downsample(int max_lvl,
+ void (*callback)(void *userData, int level),
+ void *userData)
{
- FrameBuffer *fb = reinterpret_cast<FrameBuffer *>(gpu_fb);
- BLI_assert(GPU_texture_cube(tex));
- gpu_framebuffer_texture_attach_ex(fb, tex, slot, face, mip);
-}
-
-/* ---------- Detach ----------- */
-
-void GPU_framebuffer_texture_detach_slot(GPUFrameBuffer *gpu_fb, GPUTexture *tex, int type)
-{
- FrameBuffer *fb = reinterpret_cast<FrameBuffer *>(gpu_fb);
- GPUAttachment *attachment = &fb->attachments[type];
+ GPUContext *ctx = GPU_context_active_get();
+ /* Bind to make sure the framebuffer is up to date. */
+ this->bind(true);
- if (attachment->tex != tex) {
- fprintf(stderr,
- "Warning, attempting to detach Texture %p from framebuffer %p "
- "but texture is not attached.\n",
- tex,
- fb);
+ if (width_ == 1 && height_ == 1) {
return;
}
+ /* HACK: Make the framebuffer appear not bound to avoid assert in GPU_texture_bind. */
+ ctx->active_fb = NULL;
- attachment->tex = NULL;
- GPU_FB_ATTACHEMENT_SET_DIRTY(fb->dirty_flag, type);
-}
-
-void GPU_framebuffer_texture_detach(GPUFrameBuffer *gpu_fb, GPUTexture *tex)
-{
- GPUAttachmentType type = (GPUAttachmentType)GPU_texture_detach_framebuffer(tex, gpu_fb);
- GPU_framebuffer_texture_detach_slot(gpu_fb, tex, type);
-}
-
-/* ---------- Config (Attach & Detach) ----------- */
-
-/**
- * First GPUAttachment in *config is always the depth/depth_stencil buffer.
- * Following GPUAttachments are color buffers.
- * Setting GPUAttachment.mip to -1 will leave the texture in this slot.
- * Setting GPUAttachment.tex to NULL will detach the texture in this slot.
- */
-void GPU_framebuffer_config_array(GPUFrameBuffer *gpu_fb,
- const GPUAttachment *config,
- int config_len)
-{
- FrameBuffer *fb = reinterpret_cast<FrameBuffer *>(gpu_fb);
- if (config[0].tex) {
- BLI_assert(GPU_texture_depth(config[0].tex));
- gpu_framebuffer_texture_attach_ex(fb, config[0].tex, 0, config[0].layer, config[0].mip);
- }
- else if (config[0].mip == -1) {
- /* Leave texture attached */
- }
- else if (fb->attachments[GPU_FB_DEPTH_ATTACHMENT].tex != NULL) {
- GPU_framebuffer_texture_detach(gpu_fb, fb->attachments[GPU_FB_DEPTH_ATTACHMENT].tex);
- }
- else if (fb->attachments[GPU_FB_DEPTH_STENCIL_ATTACHMENT].tex != NULL) {
- GPU_framebuffer_texture_detach(gpu_fb, fb->attachments[GPU_FB_DEPTH_STENCIL_ATTACHMENT].tex);
- }
+ int levels = floor(log2(max_ii(width_, height_)));
+ max_lvl = min_ii(max_lvl, levels);
- int slot = 0;
- for (int i = 1; i < config_len; i++, slot++) {
- if (config[i].tex != NULL) {
- BLI_assert(GPU_texture_depth(config[i].tex) == false);
- gpu_framebuffer_texture_attach_ex(fb, config[i].tex, slot, config[i].layer, config[i].mip);
- }
- else if (config[i].mip != -1) {
- GPUTexture *tex = fb->color_tex(slot);
+ int current_dim[2] = {width_, height_};
+ int mip_lvl;
+ for (mip_lvl = 1; mip_lvl < max_lvl + 1; mip_lvl++) {
+ /* calculate next viewport size */
+ current_dim[0] = max_ii(current_dim[0] / 2, 1);
+ current_dim[1] = max_ii(current_dim[1] / 2, 1);
+ /* Replace attaached miplevel for each attachement. */
+ for (int att = 0; att < ARRAY_SIZE(attachments_); att++) {
+ GPUTexture *tex = attachments_[att].tex;
if (tex != NULL) {
- GPU_framebuffer_texture_detach(gpu_fb, tex);
+ /* Some Intel HDXXX have issue with rendering to a mipmap that is below
+ * the texture GL_TEXTURE_MAX_LEVEL. So even if it not correct, in this case
+ * we allow GL_TEXTURE_MAX_LEVEL to be one level lower. In practice it does work! */
+ int map_lvl = (GPU_mip_render_workaround()) ? mip_lvl : (mip_lvl - 1);
+ /* Restrict fetches only to previous level. */
+ GPU_texture_bind(tex, 0);
+ glTexParameteri(GPU_texture_target(tex), GL_TEXTURE_BASE_LEVEL, mip_lvl - 1);
+ glTexParameteri(GPU_texture_target(tex), GL_TEXTURE_MAX_LEVEL, map_lvl);
+ GPU_texture_unbind(tex);
+ /* Bind next level. */
+ attachments_[att].mip = mip_lvl;
}
}
- }
-}
+ /* Update the internal attachments and viewport size. */
+ dirty_attachments_ = true;
+ this->bind(true);
+ /* HACK: Make the framebuffer appear not bound to avoid assert in GPU_texture_bind. */
+ ctx->active_fb = NULL;
-/* ---------- Bind / Restore ----------- */
+ callback(userData, mip_lvl);
-static void gpu_framebuffer_attachment_attach(GPUAttachment *attach, GPUAttachmentType attach_type)
-{
- int tex_bind = GPU_texture_opengl_bindcode(attach->tex);
- GLenum gl_attachment = convert_attachment_type_to_gl(attach_type);
-
- if (attach->layer > -1) {
- if (GPU_texture_cube(attach->tex)) {
- glFramebufferTexture2D(GL_FRAMEBUFFER,
- gl_attachment,
- GL_TEXTURE_CUBE_MAP_POSITIVE_X + attach->layer,
- tex_bind,
- attach->mip);
- }
- else {
- glFramebufferTextureLayer(
- GL_FRAMEBUFFER, gl_attachment, tex_bind, attach->mip, attach->layer);
+ /* This is the last mipmap level. Exit loop without incrementing mip_lvl. */
+ if (current_dim[0] == 1 && current_dim[1] == 1) {
+ break;
}
}
- else {
- glFramebufferTexture(GL_FRAMEBUFFER, gl_attachment, tex_bind, attach->mip);
- }
-}
-
-static void gpu_framebuffer_attachment_detach(GPUAttachment *UNUSED(attachment),
- GPUAttachmentType attach_type)
-{
- GLenum gl_attachment = convert_attachment_type_to_gl(attach_type);
- glFramebufferTexture(GL_FRAMEBUFFER, gl_attachment, 0, 0);
-}
-static void gpu_framebuffer_update_attachments(FrameBuffer *fb)
-{
- GLenum gl_attachments[GPU_FB_MAX_COLOR_ATTACHMENT];
- int numslots = 0;
-
- BLI_assert(GPU_context_active_get()->active_fb == fb);
-
- /* Update attachments */
- FOREACH_ATTACHMENT_RANGE(type, 0, GPU_FB_MAX_ATTACHEMENT)
- {
- if (type >= GPU_FB_COLOR_ATTACHMENT0) {
- if (fb->attachments[type].tex) {
- gl_attachments[numslots] = convert_attachment_type_to_gl(type);
- }
- else {
- gl_attachments[numslots] = GL_NONE;
- }
- numslots++;
- }
-
- if (GPU_FB_ATTACHEMENT_IS_DIRTY(fb->dirty_flag, type) == false) {
- continue;
- }
- if (fb->attachments[type].tex != NULL) {
- gpu_framebuffer_attachment_attach(&fb->attachments[type], type);
-
- fb->multisample = (GPU_texture_samples(fb->attachments[type].tex) > 0);
- fb->width = GPU_texture_width(fb->attachments[type].tex);
- fb->height = GPU_texture_height(fb->attachments[type].tex);
- }
- else {
- gpu_framebuffer_attachment_detach(&fb->attachments[type], type);
+ for (int att = 0; att < ARRAY_SIZE(attachments_); att++) {
+ if (attachments_[att].tex != NULL) {
+ /* Reset mipmap level range. */
+ GPUTexture *tex = attachments_[att].tex;
+ GPU_texture_bind(tex, 0);
+ glTexParameteri(GPU_texture_target(tex), GL_TEXTURE_BASE_LEVEL, 0);
+ glTexParameteri(GPU_texture_target(tex), GL_TEXTURE_MAX_LEVEL, mip_lvl);
+ GPU_texture_unbind(tex);
+ /* Reset base level. NOTE: might not be the one bound at the start of this function. */
+ attachments_[att].mip = 0;
}
}
- fb->dirty_flag = 0;
-
- /* Update draw buffers (color targets)
- * This state is saved in the FBO */
- if (numslots) {
- glDrawBuffers(numslots, gl_attachments);
- }
- else {
- glDrawBuffer(GL_NONE);
- }
+ /* Reattach base level textures. */
+ this->bind(true);
}
-/**
- * Hack to solve the problem of some bugged AMD GPUs (see `GPU_unused_fb_slot_workaround`).
- * If there is an empty color slot between the color slots,
- * all textures after this slot are apparently skipped/discarded.
- */
-static void gpu_framebuffer_update_attachments_and_fill_empty_slots(FrameBuffer *fb)
-{
- GLenum gl_attachments[GPU_FB_MAX_COLOR_ATTACHMENT];
- int dummy_tex = 0;
+/** \} */
- BLI_assert(GPU_context_active_get()->active_fb == fb);
+} // namespace blender::gpu
- /* Update attachments */
- for (int i_type = GPU_FB_MAX_ATTACHEMENT - 1; i_type >= 0; --i_type) {
- GPUAttachmentType type = static_cast<GPUAttachmentType>(i_type);
- GPUTexture *tex = fb->attachments[type].tex;
+/* -------------------------------------------------------------------- */
+/** \name C-API
+ * \{ */
- if (type >= GPU_FB_COLOR_ATTACHMENT0) {
- int slot = type - GPU_FB_COLOR_ATTACHMENT0;
- if (tex != NULL || (dummy_tex != 0)) {
- gl_attachments[slot] = convert_attachment_type_to_gl(type);
-
- if (dummy_tex == 0) {
- dummy_tex = GPU_texture_opengl_bindcode(tex);
- }
- }
- else {
- gl_attachments[slot] = GL_NONE;
- }
- }
- else {
- dummy_tex = 0;
- }
-
- if ((dummy_tex != 0) && tex == NULL) {
- /* Fill empty slot */
- glFramebufferTexture(GL_FRAMEBUFFER, convert_attachment_type_to_gl(type), dummy_tex, 0);
- }
- else if (GPU_FB_ATTACHEMENT_IS_DIRTY(fb->dirty_flag, type)) {
- if (tex != NULL) {
- gpu_framebuffer_attachment_attach(&fb->attachments[type], type);
-
- fb->multisample = (GPU_texture_samples(tex) > 0);
- fb->width = GPU_texture_width(tex);
- fb->height = GPU_texture_height(tex);
- }
- else {
- gpu_framebuffer_attachment_detach(&fb->attachments[type], type);
- }
- }
- }
- fb->dirty_flag = 0;
-
- /* Update draw buffers (color targets)
- * This state is saved in the FBO */
- glDrawBuffers(GPU_FB_MAX_COLOR_ATTACHMENT, gl_attachments);
-}
-
-#define FRAMEBUFFER_STACK_DEPTH 16
-
-static struct {
- GPUFrameBuffer *framebuffers[FRAMEBUFFER_STACK_DEPTH];
- uint top;
-} FrameBufferStack = {{0}};
+using namespace blender;
+using namespace blender::gpu;
-static void gpuPushFrameBuffer(GPUFrameBuffer *fb)
+GPUFrameBuffer *GPU_framebuffer_create()
{
- BLI_assert(FrameBufferStack.top < FRAMEBUFFER_STACK_DEPTH);
- FrameBufferStack.framebuffers[FrameBufferStack.top] = fb;
- FrameBufferStack.top++;
+ /* We generate the FB object later at first use in order to
+ * create the framebuffer in the right opengl context. */
+ return (GPUFrameBuffer *)GPUBackend::get()->framebuffer_alloc("FB");
}
-static GPUFrameBuffer *gpuPopFrameBuffer(void)
+void GPU_framebuffer_free(GPUFrameBuffer *gpu_fb)
{
- BLI_assert(FrameBufferStack.top > 0);
- FrameBufferStack.top--;
- return FrameBufferStack.framebuffers[FrameBufferStack.top];
+ delete reinterpret_cast<FrameBuffer *>(gpu_fb);
}
-#undef FRAMEBUFFER_STACK_DEPTH
+/* ---------- Binding ----------- */
void GPU_framebuffer_bind(GPUFrameBuffer *gpu_fb)
{
FrameBuffer *fb = reinterpret_cast<FrameBuffer *>(gpu_fb);
+ const bool enable_srgb = true;
+ fb->bind(enable_srgb);
+}
- if (fb->object == 0) {
- gpu_framebuffer_init(fb);
- }
+/* Workaround for binding a srgb framebuffer without doing the srgb transform. */
+void GPU_framebuffer_bind_no_srgb(GPUFrameBuffer *gpu_fb)
+{
+ FrameBuffer *fb = reinterpret_cast<FrameBuffer *>(gpu_fb);
+ const bool enable_srgb = false;
+ fb->bind(enable_srgb);
+}
- if (GPU_framebuffer_active_get() != gpu_fb) {
- glBindFramebuffer(GL_FRAMEBUFFER, fb->object);
- glEnable(GL_FRAMEBUFFER_SRGB);
+/* For stereo rendering. */
+void GPU_backbuffer_bind(eGPUBackBuffer buffer)
+{
+ GPUContext *ctx = GPU_context_active_get();
- GPUTexture *first_target = fb->attachments[GPU_FB_COLOR_ATTACHMENT0].tex;
- const bool is_srgb_target = (first_target &&
- (GPU_texture_format(first_target) == GPU_SRGB8_A8));
- GPU_shader_set_framebuffer_srgb_target(is_srgb_target);
+ if (buffer == GPU_BACKBUFFER_LEFT) {
+ ctx->back_left->bind(false);
}
-
- GPU_context_active_get()->active_fb = fb;
-
- if (fb->dirty_flag != 0) {
- if (GPU_unused_fb_slot_workaround()) {
- /* XXX: Please AMD, fix this. */
- gpu_framebuffer_update_attachments_and_fill_empty_slots(fb);
- }
- else {
- gpu_framebuffer_update_attachments(fb);
- }
+ else {
+ ctx->back_right->bind(false);
}
+}
- /* TODO manually check for errors? */
-#if 0
- char err_out[256];
- if (!GPU_framebuffer_check_valid(fb, err_out)) {
- printf("Invalid %s\n", err_out);
- }
-#endif
+void GPU_framebuffer_restore(void)
+{
+ GPU_context_active_get()->back_left->bind(false);
+}
- GPU_viewport(0, 0, fb->width, fb->height);
+GPUFrameBuffer *GPU_framebuffer_active_get(void)
+{
+ GPUContext *ctx = GPU_context_active_get();
+ return reinterpret_cast<GPUFrameBuffer *>(ctx ? ctx->active_fb : NULL);
}
-/* Workaround for binding a srgb framebuffer without doing the srgb transform. */
-void GPU_framebuffer_bind_no_srgb(GPUFrameBuffer *gpu_fb)
+/* Returns the default framebuffer. Will always exists even if it's just a dummy. */
+GPUFrameBuffer *GPU_framebuffer_back_get(void)
{
- FrameBuffer *fb = reinterpret_cast<FrameBuffer *>(gpu_fb);
+ GPUContext *ctx = GPU_context_active_get();
+ return reinterpret_cast<GPUFrameBuffer *>(ctx ? ctx->back_left : NULL);
+}
- GPU_framebuffer_bind(gpu_fb);
+bool GPU_framebuffer_bound(GPUFrameBuffer *gpu_fb)
+{
+ return (gpu_fb == GPU_framebuffer_active_get());
+}
- glDisable(GL_FRAMEBUFFER_SRGB);
+/* ---------- Attachment Management ----------- */
- GPUTexture *first_target = fb->attachments[GPU_FB_COLOR_ATTACHMENT0].tex;
- const bool is_srgb_target = (first_target && (GPU_texture_format(first_target) == GPU_SRGB8_A8));
- GPU_shader_set_framebuffer_srgb_target(!is_srgb_target);
+bool GPU_framebuffer_check_valid(GPUFrameBuffer *gpu_fb, char err_out[256])
+{
+ return reinterpret_cast<FrameBuffer *>(gpu_fb)->check(err_out);
}
-void GPU_framebuffer_restore(void)
+void GPU_framebuffer_texture_attach_ex(GPUFrameBuffer *gpu_fb, GPUAttachment attachement, int slot)
{
- if (GPU_framebuffer_active_get() != NULL) {
- glBindFramebuffer(GL_FRAMEBUFFER, GPU_framebuffer_default());
- GPU_context_active_get()->active_fb = NULL;
- glDisable(GL_FRAMEBUFFER_SRGB);
- GPU_shader_set_framebuffer_srgb_target(false);
- }
+ GPUAttachmentType type = blender::gpu::Texture::attachment_type(attachement.tex, slot);
+ reinterpret_cast<FrameBuffer *>(gpu_fb)->attachment_set(type, attachement);
}
-bool GPU_framebuffer_bound(GPUFrameBuffer *gpu_fb)
+void GPU_framebuffer_texture_detach(GPUFrameBuffer *gpu_fb, GPUTexture *tex)
{
- FrameBuffer *fb = reinterpret_cast<FrameBuffer *>(gpu_fb);
- return (gpu_fb == GPU_framebuffer_active_get()) && (fb->object != 0);
+ GPUAttachment attachement = GPU_ATTACHMENT_NONE;
+ int type = GPU_texture_framebuffer_attachement_get(tex, gpu_fb);
+ if (type != -1) {
+ reinterpret_cast<FrameBuffer *>(gpu_fb)->attachment_set((GPUAttachmentType)type, attachement);
+ }
+ else {
+ BLI_assert(!"Error: Texture: Framebuffer is not attached");
+ }
}
-bool GPU_framebuffer_check_valid(GPUFrameBuffer *gpu_fb, char err_out[256])
+/**
+ * First GPUAttachment in *config is always the depth/depth_stencil buffer.
+ * Following GPUAttachments are color buffers.
+ * Setting GPUAttachment.mip to -1 will leave the texture in this slot.
+ * Setting GPUAttachment.tex to NULL will detach the texture in this slot.
+ */
+void GPU_framebuffer_config_array(GPUFrameBuffer *gpu_fb,
+ const GPUAttachment *config,
+ int config_len)
{
- if (!GPU_framebuffer_bound(gpu_fb)) {
- GPU_framebuffer_bind(gpu_fb);
- }
+ FrameBuffer *fb = reinterpret_cast<FrameBuffer *>(gpu_fb);
- GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
+ const GPUAttachment &depth_attachement = config[0];
+ Span<GPUAttachment> color_attachments(config + 1, config_len - 1);
- if (status != GL_FRAMEBUFFER_COMPLETE) {
- GPU_framebuffer_restore();
- gpu_print_framebuffer_error(status, err_out);
- return false;
+ if (depth_attachement.mip == -1) {
+ /* GPU_ATTACHMENT_LEAVE */
+ }
+ else if (depth_attachement.tex == NULL) {
+ /* GPU_ATTACHMENT_NONE: Need to clear both targets. */
+ fb->attachment_set(GPU_FB_DEPTH_STENCIL_ATTACHMENT, depth_attachement);
+ fb->attachment_set(GPU_FB_DEPTH_ATTACHMENT, depth_attachement);
+ }
+ else {
+ GPUAttachmentType type = GPU_texture_stencil(depth_attachement.tex) ?
+ GPU_FB_DEPTH_STENCIL_ATTACHMENT :
+ GPU_FB_DEPTH_ATTACHMENT;
+ fb->attachment_set(type, depth_attachement);
}
- return true;
+ GPUAttachmentType type = GPU_FB_COLOR_ATTACHMENT0;
+ for (const GPUAttachment &attachement : color_attachments) {
+ fb->attachment_set(type, attachement);
+ ++type;
+ }
}
/* ---------- Framebuffer Operations ----------- */
@@ -567,121 +362,31 @@ void GPU_framebuffer_clear(GPUFrameBuffer *gpu_fb,
float clear_depth,
uint clear_stencil)
{
- CHECK_FRAMEBUFFER_IS_BOUND(gpu_fb);
-
- /* Save and restore the state. */
- eGPUWriteMask write_mask = GPU_write_mask_get();
- uint stencil_mask = GPU_stencil_mask_get();
- eGPUStencilTest stencil_test = GPU_stencil_test_get();
-
- if (buffers & GPU_COLOR_BIT) {
- GPU_color_mask(true, true, true, true);
- glClearColor(clear_col[0], clear_col[1], clear_col[2], clear_col[3]);
- }
- if (buffers & GPU_DEPTH_BIT) {
- GPU_depth_mask(true);
- glClearDepth(clear_depth);
- }
- if (buffers & GPU_STENCIL_BIT) {
- GPU_stencil_write_mask_set(0xFFu);
- GPU_stencil_test(GPU_STENCIL_ALWAYS);
- glClearStencil(clear_stencil);
- }
-
- GPU_context_active_get()->state_manager->apply_state();
-
- GLbitfield mask = convert_buffer_bits_to_gl(buffers);
- glClear(mask);
-
- if (buffers & (GPU_COLOR_BIT | GPU_DEPTH_BIT)) {
- GPU_write_mask(write_mask);
- }
- if (buffers & GPU_STENCIL_BIT) {
- GPU_stencil_write_mask_set(stencil_mask);
- GPU_stencil_test(stencil_test);
- }
+ reinterpret_cast<FrameBuffer *>(gpu_fb)->clear(buffers, clear_col, clear_depth, clear_stencil);
}
-/* Clear all textures bound to this framebuffer with a different color. */
+/* Clear all textures attached to this framebuffer with a different color. */
void GPU_framebuffer_multi_clear(GPUFrameBuffer *gpu_fb, const float (*clear_cols)[4])
{
- CHECK_FRAMEBUFFER_IS_BOUND(gpu_fb);
-
- FrameBuffer *fb = reinterpret_cast<FrameBuffer *>(gpu_fb);
-
- /* Save and restore the state. */
- eGPUWriteMask write_mask = GPU_write_mask_get();
- GPU_color_mask(true, true, true, true);
-
- int i_type = GPU_FB_COLOR_ATTACHMENT0;
- for (int i = 0; i_type < GPU_FB_MAX_ATTACHEMENT; i++, i_type++) {
- GPUAttachmentType type = static_cast<GPUAttachmentType>(i_type);
- if (fb->attachments[type].tex != NULL) {
- glClearBufferfv(GL_COLOR, i, clear_cols[i]);
- }
- }
-
- GPU_write_mask(write_mask);
-}
-
-void GPU_framebuffer_read_depth(GPUFrameBuffer *gpu_fb, int x, int y, int w, int h, float *data)
-{
- CHECK_FRAMEBUFFER_IS_BOUND(gpu_fb);
-
- GLenum type = GL_DEPTH_COMPONENT;
- glReadBuffer(GL_COLOR_ATTACHMENT0); /* This is OK! */
- glReadPixels(x, y, w, h, type, GL_FLOAT, data);
+ reinterpret_cast<FrameBuffer *>(gpu_fb)->clear_multi(clear_cols);
}
-static GLenum gpu_get_gl_datatype(eGPUDataFormat format)
+void GPU_clear_color(float red, float green, float blue, float alpha)
{
- switch (format) {
- case GPU_DATA_FLOAT:
- return GL_FLOAT;
- case GPU_DATA_INT:
- return GL_INT;
- case GPU_DATA_UNSIGNED_INT:
- return GL_UNSIGNED_INT;
- case GPU_DATA_UNSIGNED_BYTE:
- return GL_UNSIGNED_BYTE;
- case GPU_DATA_UNSIGNED_INT_24_8:
- return GL_UNSIGNED_INT_24_8;
- case GPU_DATA_10_11_11_REV:
- return GL_UNSIGNED_INT_10F_11F_11F_REV;
- default:
- BLI_assert(!"Unhandled data format");
- return GL_FLOAT;
- }
+ float clear_col[4] = {red, green, blue, alpha};
+ GPU_context_active_get()->active_fb->clear(GPU_COLOR_BIT, clear_col, 0.0f, 0x0);
}
-static GLenum gpu_get_gl_channel_type(int channels)
+void GPU_clear_depth(float depth)
{
- switch (channels) {
- case 1:
- return GL_RED;
- case 2:
- return GL_RG;
- case 3:
- return GL_RGB;
- case 4:
- return GL_RGBA;
- default:
- BLI_assert(!"Wrong number of read channels");
- return GL_RED;
- }
+ float clear_col[4] = {0};
+ GPU_context_active_get()->active_fb->clear(GPU_DEPTH_BIT, clear_col, depth, 0x0);
}
-static void gpu_framebuffer_read_color_ex(
- int x, int y, int w, int h, int channels, GLenum readfb, eGPUDataFormat format, float *data)
+void GPU_framebuffer_read_depth(GPUFrameBuffer *gpu_fb, int x, int y, int w, int h, float *data)
{
- GLenum type = gpu_get_gl_channel_type(channels);
- GLenum gl_format = gpu_get_gl_datatype(format);
- /* TODO: needed for selection buffers to work properly, this should be handled better. */
- if (type == GL_RED && gl_format == GL_UNSIGNED_INT) {
- type = GL_RED_INTEGER;
- }
- glReadBuffer(readfb);
- glReadPixels(x, y, w, h, type, gl_format, data);
+ int rect[4] = {x, y, w, h};
+ reinterpret_cast<FrameBuffer *>(gpu_fb)->read(GPU_DEPTH_BIT, GPU_DATA_FLOAT, rect, 1, 1, data);
}
void GPU_framebuffer_read_color(GPUFrameBuffer *gpu_fb,
@@ -694,12 +399,20 @@ void GPU_framebuffer_read_color(GPUFrameBuffer *gpu_fb,
eGPUDataFormat format,
void *data)
{
- CHECK_FRAMEBUFFER_IS_BOUND(gpu_fb);
- gpu_framebuffer_read_color_ex(
- x, y, w, h, channels, GL_COLOR_ATTACHMENT0 + slot, format, (float *)data);
+ int rect[4] = {x, y, w, h};
+ reinterpret_cast<FrameBuffer *>(gpu_fb)->read(GPU_COLOR_BIT, format, rect, channels, slot, data);
+}
+
+/* TODO(fclem) rename to read_color. */
+void GPU_frontbuffer_read_pixels(
+ int x, int y, int w, int h, int channels, eGPUDataFormat format, void *data)
+{
+ int rect[4] = {x, y, w, h};
+ GPU_context_active_get()->front_left->read(GPU_COLOR_BIT, format, rect, channels, 0, data);
}
/* read_slot and write_slot are only used for color buffers. */
+/* TODO(fclem) port as texture operation. */
void GPU_framebuffer_blit(GPUFrameBuffer *gpufb_read,
int read_slot,
GPUFrameBuffer *gpufb_write,
@@ -712,74 +425,36 @@ void GPU_framebuffer_blit(GPUFrameBuffer *gpufb_read,
FrameBuffer *prev_fb = GPU_context_active_get()->active_fb;
- /* Framebuffers must be up to date. This simplify this function. */
- if (fb_read->dirty_flag != 0 || fb_read->object == 0) {
- GPU_framebuffer_bind(gpufb_read);
+#ifndef NDEBUG
+ GPUTexture *read_tex, *write_tex;
+ if (blit_buffers & (GPU_DEPTH_BIT | GPU_STENCIL_BIT)) {
+ read_tex = fb_read->depth_tex();
+ write_tex = fb_write->depth_tex();
}
- if (fb_write->dirty_flag != 0 || fb_write->object == 0) {
- GPU_framebuffer_bind(gpufb_write);
+ else {
+ read_tex = fb_read->color_tex(read_slot);
+ write_tex = fb_write->color_tex(write_slot);
}
- const bool do_color = (blit_buffers & GPU_COLOR_BIT);
- const bool do_depth = (blit_buffers & GPU_DEPTH_BIT);
- const bool do_stencil = (blit_buffers & GPU_STENCIL_BIT);
-
- GPUTexture *read_tex = ((do_depth || do_stencil) ? fb_read->depth_tex() :
- fb_read->color_tex(read_slot));
- GPUTexture *write_tex = ((do_depth || do_stencil) ? fb_write->depth_tex() :
- fb_write->color_tex(read_slot));
-
- if (do_depth) {
+ if (blit_buffers & GPU_DEPTH_BIT) {
BLI_assert(GPU_texture_depth(read_tex) && GPU_texture_depth(write_tex));
BLI_assert(GPU_texture_format(read_tex) == GPU_texture_format(write_tex));
}
- if (do_stencil) {
+ if (blit_buffers & GPU_STENCIL_BIT) {
BLI_assert(GPU_texture_stencil(read_tex) && GPU_texture_stencil(write_tex));
BLI_assert(GPU_texture_format(read_tex) == GPU_texture_format(write_tex));
}
if (GPU_texture_samples(write_tex) != 0 || GPU_texture_samples(read_tex) != 0) {
/* Can only blit multisample textures to another texture of the same size. */
- BLI_assert((fb_read->width == fb_write->width) && (fb_read->height == fb_write->height));
- }
-
- glBindFramebuffer(GL_READ_FRAMEBUFFER, fb_read->object);
- glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fb_write->object);
-
- if (do_color) {
- glReadBuffer(GL_COLOR_ATTACHMENT0 + read_slot);
- glDrawBuffer(GL_COLOR_ATTACHMENT0 + write_slot);
- /* XXX we messed with the glDrawBuffer, this will reset the
- * glDrawBuffers the next time we bind fb_write. */
- fb_write->dirty_flag = GPU_FB_DIRTY_DRAWBUFFER;
+ BLI_assert((GPU_texture_width(write_tex) == GPU_texture_width(read_tex)) &&
+ (GPU_texture_height(write_tex) == GPU_texture_height(read_tex)));
}
+#endif
- GLbitfield mask = convert_buffer_bits_to_gl(blit_buffers);
-
- GPU_context_active_get()->state_manager->apply_state();
-
- glBlitFramebuffer(0,
- 0,
- fb_read->width,
- fb_read->height,
- 0,
- 0,
- fb_write->width,
- fb_write->height,
- mask,
- GL_NEAREST);
+ fb_read->blit_to(blit_buffers, read_slot, fb_write, write_slot, 0, 0);
- /* Restore previous framebuffer */
- if (fb_write == prev_fb) {
- GPU_framebuffer_bind(gpufb_write); /* To update drawbuffers */
- }
- else if (prev_fb) {
- glBindFramebuffer(GL_FRAMEBUFFER, prev_fb->object);
- GPU_context_active_get()->active_fb = prev_fb;
- }
- else {
- glBindFramebuffer(GL_FRAMEBUFFER, GPU_framebuffer_default());
- GPU_context_active_get()->active_fb = NULL;
- }
+ /* FIXME(fclem) sRGB is not saved. */
+ prev_fb->bind(true);
}
/**
@@ -792,77 +467,40 @@ void GPU_framebuffer_recursive_downsample(GPUFrameBuffer *gpu_fb,
void (*callback)(void *userData, int level),
void *userData)
{
- GPUContext *ctx = GPU_context_active_get();
- FrameBuffer *fb = reinterpret_cast<FrameBuffer *>(gpu_fb);
- /* Framebuffer must be up to date and bound. This simplify this function. */
- if (ctx->active_fb != fb || fb->dirty_flag != 0 || fb->object == 0) {
- GPU_framebuffer_bind(gpu_fb);
- }
- /* HACK: We make the framebuffer appear not bound in order to
- * not trigger any error in GPU_texture_bind(). */
- FrameBuffer *prev_fb = ctx->active_fb;
- ctx->active_fb = NULL;
-
- int levels = floor(log2(max_ii(fb->width, fb->height)));
- max_lvl = min_ii(max_lvl, levels);
+ reinterpret_cast<FrameBuffer *>(gpu_fb)->recursive_downsample(max_lvl, callback, userData);
+}
- int i;
- int current_dim[2] = {fb->width, fb->height};
- for (i = 1; i < max_lvl + 1; i++) {
- /* calculate next viewport size */
- current_dim[0] = max_ii(current_dim[0] / 2, 1);
- current_dim[1] = max_ii(current_dim[1] / 2, 1);
+/** \} */
- for (int i_type = 0; i_type < GPU_FB_MAX_ATTACHEMENT; i_type++) {
- GPUAttachmentType type = static_cast<GPUAttachmentType>(i_type);
- if (fb->attachments[type].tex != NULL) {
- /* Some Intel HDXXX have issue with rendering to a mipmap that is below
- * the texture GL_TEXTURE_MAX_LEVEL. So even if it not correct, in this case
- * we allow GL_TEXTURE_MAX_LEVEL to be one level lower. In practice it does work! */
- int next_lvl = (GPU_mip_render_workaround()) ? i : i - 1;
- /* bind next level for rendering but first restrict fetches only to previous level */
- GPUTexture *tex = fb->attachments[type].tex;
- GPU_texture_bind(tex, 0);
- glTexParameteri(GPU_texture_target(tex), GL_TEXTURE_BASE_LEVEL, i - 1);
- glTexParameteri(GPU_texture_target(tex), GL_TEXTURE_MAX_LEVEL, next_lvl);
- GPU_texture_unbind(tex);
- /* copy attachment and replace miplevel. */
- GPUAttachment attachment = fb->attachments[type];
- attachment.mip = i;
- gpu_framebuffer_attachment_attach(&attachment, type);
- }
- }
-
- BLI_assert(GL_FRAMEBUFFER_COMPLETE == glCheckFramebufferStatus(GL_FRAMEBUFFER));
+/* -------------------------------------------------------------------- */
+/** \name GPUOffScreen
+ *
+ * Container that holds a framebuffer and its textures.
+ * Might be bound to multiple contexts.
+ * \{ */
- GPU_viewport(0, 0, current_dim[0], current_dim[1]);
- callback(userData, i);
+#define FRAMEBUFFER_STACK_DEPTH 16
- if (current_dim[0] == 1 && current_dim[1] == 1) {
- break;
- }
- }
+static struct {
+ GPUFrameBuffer *framebuffers[FRAMEBUFFER_STACK_DEPTH];
+ uint top;
+} FrameBufferStack = {{0}};
- for (int i_type = 0; i_type < GPU_FB_MAX_ATTACHEMENT; i_type++) {
- GPUAttachmentType type = static_cast<GPUAttachmentType>(i_type);
- if (fb->attachments[type].tex != NULL) {
- /* reset mipmap level range */
- GPUTexture *tex = fb->attachments[type].tex;
- GPU_texture_bind(tex, 0);
- glTexParameteri(GPU_texture_target(tex), GL_TEXTURE_BASE_LEVEL, 0);
- glTexParameteri(GPU_texture_target(tex), GL_TEXTURE_MAX_LEVEL, i - 1);
- GPU_texture_unbind(tex);
- /* Reattach original level */
- /* NOTE: This is not necessary but this makes the FBO config
- * remain in sync with the GPUFrameBuffer config. */
- gpu_framebuffer_attachment_attach(&fb->attachments[type], type);
- }
- }
+static void gpuPushFrameBuffer(GPUFrameBuffer *fb)
+{
+ BLI_assert(FrameBufferStack.top < FRAMEBUFFER_STACK_DEPTH);
+ FrameBufferStack.framebuffers[FrameBufferStack.top] = fb;
+ FrameBufferStack.top++;
+}
- ctx->active_fb = prev_fb;
+static GPUFrameBuffer *gpuPopFrameBuffer(void)
+{
+ BLI_assert(FrameBufferStack.top > 0);
+ FrameBufferStack.top--;
+ return FrameBufferStack.framebuffers[FrameBufferStack.top];
}
-/* GPUOffScreen */
+#undef FRAMEBUFFER_STACK_DEPTH
#define MAX_CTX_FB_LEN 3
@@ -1013,35 +651,20 @@ void GPU_offscreen_unbind(GPUOffScreen *ofs, bool restore)
void GPU_offscreen_draw_to_screen(GPUOffScreen *ofs, int x, int y)
{
- const int w = GPU_texture_width(ofs->color);
- const int h = GPU_texture_height(ofs->color);
-
- GPU_context_active_get()->state_manager->apply_state();
-
+ GPUContext *ctx = GPU_context_active_get();
FrameBuffer *ofs_fb = reinterpret_cast<FrameBuffer *>(gpu_offscreen_fb_get(ofs));
-
- glBindFramebuffer(GL_READ_FRAMEBUFFER, ofs_fb->object);
- GLenum status = glCheckFramebufferStatus(GL_READ_FRAMEBUFFER);
-
- if (status == GL_FRAMEBUFFER_COMPLETE) {
- glBlitFramebuffer(0, 0, w, h, x, y, x + w, y + h, GL_COLOR_BUFFER_BIT, GL_NEAREST);
- }
- else {
- gpu_print_framebuffer_error(status, NULL);
- }
-
- glBindFramebuffer(GL_READ_FRAMEBUFFER, GPU_framebuffer_default());
+ ofs_fb->blit_to(GPU_COLOR_BIT, 0, ctx->active_fb, 0, x, y);
}
-void GPU_offscreen_read_pixels(GPUOffScreen *ofs, eGPUDataFormat type, void *pixels)
+void GPU_offscreen_read_pixels(GPUOffScreen *ofs, eGPUDataFormat format, void *pixels)
{
+ BLI_assert(ELEM(format, GPU_DATA_UNSIGNED_BYTE, GPU_DATA_FLOAT));
+
const int w = GPU_texture_width(ofs->color);
const int h = GPU_texture_height(ofs->color);
- BLI_assert(ELEM(type, GPU_DATA_UNSIGNED_BYTE, GPU_DATA_FLOAT));
- GLenum gl_type = (type == GPU_DATA_FLOAT) ? GL_FLOAT : GL_UNSIGNED_BYTE;
-
- glReadPixels(0, 0, w, h, GL_RGBA, gl_type, pixels);
+ GPUFrameBuffer *ofs_fb = gpu_offscreen_fb_get(ofs);
+ GPU_framebuffer_read_color(ofs_fb, 0, 0, w, h, 4, 0, format, pixels);
}
int GPU_offscreen_width(const GPUOffScreen *ofs)
@@ -1070,42 +693,4 @@ void GPU_offscreen_viewport_data_get(GPUOffScreen *ofs,
*r_depth = ofs->depth;
}
-void GPU_clear_color(float red, float green, float blue, float alpha)
-{
- BLI_assert((GPU_write_mask_get() & GPU_WRITE_COLOR) != 0);
-
- GPU_context_active_get()->state_manager->apply_state();
-
- glClearColor(red, green, blue, alpha);
- glClear(GL_COLOR_BUFFER_BIT);
-}
-
-void GPU_clear_depth(float depth)
-{
- BLI_assert((GPU_write_mask_get() & GPU_WRITE_DEPTH) != 0);
-
- GPU_context_active_get()->state_manager->apply_state();
-
- glClearDepth(depth);
- glClear(GL_DEPTH_BUFFER_BIT);
-}
-
-void GPU_frontbuffer_read_pixels(
- int x, int y, int w, int h, int channels, eGPUDataFormat format, void *data)
-{
- gpu_framebuffer_read_color_ex(x, y, w, h, channels, GL_FRONT, format, (float *)data);
-}
-
-/* For stereo rendering. */
-void GPU_backbuffer_bind(eGPUBackBuffer buffer)
-{
- if (buffer == GPU_BACKBUFFER) {
- glDrawBuffer(GL_BACK);
- }
- else if (buffer == GPU_BACKBUFFER_LEFT) {
- glDrawBuffer(GL_BACK_LEFT);
- }
- else if (buffer == GPU_BACKBUFFER_RIGHT) {
- glDrawBuffer(GL_BACK_RIGHT);
- }
-} \ No newline at end of file
+/** \} */ \ No newline at end of file