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:
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