Changeset View
Changeset View
Standalone View
Standalone View
source/blender/gpu/intern/gpu_framebuffer.c
| Show All 36 Lines | |||||
| #include "GPU_batch.h" | #include "GPU_batch.h" | ||||
| #include "GPU_draw.h" | #include "GPU_draw.h" | ||||
| #include "GPU_extensions.h" | #include "GPU_extensions.h" | ||||
| #include "GPU_framebuffer.h" | #include "GPU_framebuffer.h" | ||||
| #include "GPU_matrix.h" | #include "GPU_matrix.h" | ||||
| #include "GPU_shader.h" | #include "GPU_shader.h" | ||||
| #include "GPU_texture.h" | #include "GPU_texture.h" | ||||
| static ThreadLocal(GLuint) g_currentfb; | #include "intern/gpu_private.h" | ||||
| static ThreadLocal(void*) g_currentfb; | |||||
| typedef enum { | typedef enum { | ||||
| GPU_FB_DEPTH_ATTACHMENT = 0, | GPU_FB_DEPTH_ATTACHMENT = 0, | ||||
| GPU_FB_DEPTH_STENCIL_ATTACHMENT, | GPU_FB_DEPTH_STENCIL_ATTACHMENT, | ||||
| GPU_FB_COLOR_ATTACHMENT0, | GPU_FB_COLOR_ATTACHMENT0, | ||||
| GPU_FB_COLOR_ATTACHMENT1, | GPU_FB_COLOR_ATTACHMENT1, | ||||
| GPU_FB_COLOR_ATTACHMENT2, | GPU_FB_COLOR_ATTACHMENT2, | ||||
| GPU_FB_COLOR_ATTACHMENT3, | GPU_FB_COLOR_ATTACHMENT3, | ||||
| ▲ Show 20 Lines • Show All 104 Lines • ▼ Show 20 Lines | #undef format_status | ||||
| if (err_out) { | if (err_out) { | ||||
| BLI_snprintf(err_out, 256, format, err); | BLI_snprintf(err_out, 256, format, err); | ||||
| } | } | ||||
| else { | else { | ||||
| fprintf(stderr, format, err); | fprintf(stderr, format, err); | ||||
| } | } | ||||
| } | } | ||||
| void gpu_framebuffer_module_init(void) | |||||
| { | |||||
| BLI_thread_local_create(g_currentfb); | |||||
| } | |||||
| void gpu_framebuffer_module_exit(void) | |||||
| { | |||||
| BLI_thread_local_delete(g_currentfb); | |||||
| } | |||||
| static uint gpu_framebuffer_current_get() | |||||
| { | |||||
| return GET_UINT_FROM_POINTER(BLI_thread_local_get(g_currentfb)); | |||||
| } | |||||
| static void gpu_framebuffer_current_set(uint object) | |||||
| { | |||||
| BLI_thread_local_set(g_currentfb, SET_UINT_IN_POINTER(object)); | |||||
| } | |||||
| /* GPUFrameBuffer */ | /* GPUFrameBuffer */ | ||||
| GPUFrameBuffer *GPU_framebuffer_create(void) | GPUFrameBuffer *GPU_framebuffer_create(void) | ||||
| { | { | ||||
| /* We generate the FB object later at first use in order to | /* We generate the FB object later at first use in order to | ||||
| * create the framebuffer in the right opengl context. */ | * create the framebuffer in the right opengl context. */ | ||||
| return MEM_callocN(sizeof(GPUFrameBuffer), "GPUFrameBuffer");; | return MEM_callocN(sizeof(GPUFrameBuffer), "GPUFrameBuffer");; | ||||
| } | } | ||||
| Show All 9 Lines | for (GPUAttachmentType type = 0; type < GPU_FB_MAX_ATTACHEMENT; type++) { | ||||
| if (fb->attachments[type].tex != NULL) { | if (fb->attachments[type].tex != NULL) { | ||||
| GPU_framebuffer_texture_detach(fb, fb->attachments[type].tex); | GPU_framebuffer_texture_detach(fb, fb->attachments[type].tex); | ||||
| } | } | ||||
| } | } | ||||
| /* This restores the framebuffer if it was bound */ | /* This restores the framebuffer if it was bound */ | ||||
| glDeleteFramebuffers(1, &fb->object); | glDeleteFramebuffers(1, &fb->object); | ||||
| if (g_currentfb == fb->object) { | if (gpu_framebuffer_current_get() == fb->object) { | ||||
| g_currentfb = 0; | gpu_framebuffer_current_set(0); | ||||
| } | } | ||||
| MEM_freeN(fb); | MEM_freeN(fb); | ||||
| } | } | ||||
| /* ---------- Attach ----------- */ | /* ---------- Attach ----------- */ | ||||
| static void gpu_framebuffer_texture_attach_ex(GPUFrameBuffer *fb, GPUTexture *tex, int slot, int layer, int mip) | static void gpu_framebuffer_texture_attach_ex(GPUFrameBuffer *fb, GPUTexture *tex, int slot, int layer, int mip) | ||||
| ▲ Show 20 Lines • Show All 135 Lines • ▼ Show 20 Lines | static void gpu_framebuffer_attachment_detach(GPUAttachment *UNUSED(attachment), GPUAttachmentType attach_type) | ||||
| glFramebufferTexture(GL_FRAMEBUFFER, gl_attachment, 0, 0); | glFramebufferTexture(GL_FRAMEBUFFER, gl_attachment, 0, 0); | ||||
| } | } | ||||
| static void gpu_framebuffer_update_attachments(GPUFrameBuffer *fb) | static void gpu_framebuffer_update_attachments(GPUFrameBuffer *fb) | ||||
| { | { | ||||
| GLenum gl_attachments[GPU_FB_MAX_COLOR_ATTACHMENT]; | GLenum gl_attachments[GPU_FB_MAX_COLOR_ATTACHMENT]; | ||||
| int numslots = 0; | int numslots = 0; | ||||
| BLI_assert(g_currentfb == fb->object); | BLI_assert(gpu_framebuffer_current_get() == fb->object); | ||||
| /* Update attachments */ | /* Update attachments */ | ||||
| for (GPUAttachmentType type = 0; type < GPU_FB_MAX_ATTACHEMENT; ++type) { | for (GPUAttachmentType type = 0; type < GPU_FB_MAX_ATTACHEMENT; ++type) { | ||||
| if (type >= GPU_FB_COLOR_ATTACHMENT0) { | if (type >= GPU_FB_COLOR_ATTACHMENT0) { | ||||
| if (fb->attachments[type].tex) { | if (fb->attachments[type].tex) { | ||||
| gl_attachments[numslots] = convert_attachment_type_to_gl(type); | gl_attachments[numslots] = convert_attachment_type_to_gl(type); | ||||
| } | } | ||||
| Show All 27 Lines | else | ||||
| glDrawBuffer(GL_NONE); | glDrawBuffer(GL_NONE); | ||||
| } | } | ||||
| void GPU_framebuffer_bind(GPUFrameBuffer *fb) | void GPU_framebuffer_bind(GPUFrameBuffer *fb) | ||||
| { | { | ||||
| if (fb->object == 0) | if (fb->object == 0) | ||||
| gpu_framebuffer_init(fb); | gpu_framebuffer_init(fb); | ||||
| if (g_currentfb != fb->object) | if (gpu_framebuffer_current_get() != fb->object) | ||||
| glBindFramebuffer(GL_FRAMEBUFFER, fb->object); | glBindFramebuffer(GL_FRAMEBUFFER, fb->object); | ||||
| g_currentfb = fb->object; | gpu_framebuffer_current_set(fb->object); | ||||
| if (fb->dirty_flag != 0) | if (fb->dirty_flag != 0) | ||||
| gpu_framebuffer_update_attachments(fb); | gpu_framebuffer_update_attachments(fb); | ||||
| /* TODO manually check for errors? */ | /* TODO manually check for errors? */ | ||||
| #if 0 | #if 0 | ||||
| char err_out[256]; | char err_out[256]; | ||||
| if (!GPU_framebuffer_check_valid(fb, err_out)) { | if (!GPU_framebuffer_check_valid(fb, err_out)) { | ||||
| printf("Invalid %s\n", err_out); | printf("Invalid %s\n", err_out); | ||||
| } | } | ||||
| #endif | #endif | ||||
| if (fb->multisample) | if (fb->multisample) | ||||
| glEnable(GL_MULTISAMPLE); | glEnable(GL_MULTISAMPLE); | ||||
| glViewport(0, 0, fb->width, fb->height); | glViewport(0, 0, fb->width, fb->height); | ||||
| } | } | ||||
| void GPU_framebuffer_restore(void) | void GPU_framebuffer_restore(void) | ||||
| { | { | ||||
| if (g_currentfb != 0) { | if (gpu_framebuffer_current_get() != 0) { | ||||
| glBindFramebuffer(GL_FRAMEBUFFER, 0); | glBindFramebuffer(GL_FRAMEBUFFER, 0); | ||||
| g_currentfb = 0; | gpu_framebuffer_current_set(0); | ||||
| } | } | ||||
| } | } | ||||
| bool GPU_framebuffer_bound(GPUFrameBuffer *fb) | bool GPU_framebuffer_bound(GPUFrameBuffer *fb) | ||||
| { | { | ||||
| return (fb->object == g_currentfb) && (fb->object != 0); | return (fb->object == gpu_framebuffer_current_get()) && (fb->object != 0); | ||||
| } | } | ||||
| unsigned int GPU_framebuffer_current_get(void) | unsigned int GPU_framebuffer_current_get(void) | ||||
| { | { | ||||
| return g_currentfb; | return gpu_framebuffer_current_get(); | ||||
| } | } | ||||
| bool GPU_framebuffer_check_valid(GPUFrameBuffer *fb, char err_out[256]) | bool GPU_framebuffer_check_valid(GPUFrameBuffer *fb, char err_out[256]) | ||||
| { | { | ||||
| if (!GPU_framebuffer_bound(fb)) | if (!GPU_framebuffer_bound(fb)) | ||||
| GPU_framebuffer_bind(fb); | GPU_framebuffer_bind(fb); | ||||
| GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); | GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); | ||||
| ▲ Show 20 Lines • Show All 74 Lines • ▼ Show 20 Lines | |||||
| /* read_slot and write_slot are only used for color buffers. */ | /* read_slot and write_slot are only used for color buffers. */ | ||||
| void GPU_framebuffer_blit( | void GPU_framebuffer_blit( | ||||
| GPUFrameBuffer *fb_read, int read_slot, | GPUFrameBuffer *fb_read, int read_slot, | ||||
| GPUFrameBuffer *fb_write, int write_slot, | GPUFrameBuffer *fb_write, int write_slot, | ||||
| GPUFrameBufferBits blit_buffers) | GPUFrameBufferBits blit_buffers) | ||||
| { | { | ||||
| BLI_assert(blit_buffers != 0); | BLI_assert(blit_buffers != 0); | ||||
| GLuint prev_fb = g_currentfb; | GLuint prev_fb = gpu_framebuffer_current_get(); | ||||
| /* Framebuffers must be up to date. This simplify this function. */ | /* Framebuffers must be up to date. This simplify this function. */ | ||||
| if (fb_read->dirty_flag != 0 || fb_read->object == 0) { | if (fb_read->dirty_flag != 0 || fb_read->object == 0) { | ||||
| GPU_framebuffer_bind(fb_read); | GPU_framebuffer_bind(fb_read); | ||||
| } | } | ||||
| if (fb_write->dirty_flag != 0 || fb_write->object == 0) { | if (fb_write->dirty_flag != 0 || fb_write->object == 0) { | ||||
| GPU_framebuffer_bind(fb_write); | GPU_framebuffer_bind(fb_write); | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 43 Lines • ▼ Show 20 Lines | glBlitFramebuffer(0, 0, fb_read->width, fb_read->height, | ||||
| mask, GL_NEAREST); | mask, GL_NEAREST); | ||||
| /* Restore previous framebuffer */ | /* Restore previous framebuffer */ | ||||
| if (fb_write->object == prev_fb) { | if (fb_write->object == prev_fb) { | ||||
| GPU_framebuffer_bind(fb_write); /* To update drawbuffers */ | GPU_framebuffer_bind(fb_write); /* To update drawbuffers */ | ||||
| } | } | ||||
| else { | else { | ||||
| glBindFramebuffer(GL_FRAMEBUFFER, prev_fb); | glBindFramebuffer(GL_FRAMEBUFFER, prev_fb); | ||||
| g_currentfb = prev_fb; | gpu_framebuffer_current_set(prev_fb); | ||||
| } | } | ||||
| } | } | ||||
| /** | /** | ||||
| * Use this if you need to custom downsample your texture and use the previous mip level as input. | * Use this if you need to custom downsample your texture and use the previous mip level as input. | ||||
| * This function only takes care of the correct texture handling. It execute the callback for each texture level. | * This function only takes care of the correct texture handling. It execute the callback for each texture level. | ||||
| **/ | **/ | ||||
| void GPU_framebuffer_recursive_downsample( | void GPU_framebuffer_recursive_downsample( | ||||
| GPUFrameBuffer *fb, int max_lvl, | GPUFrameBuffer *fb, int max_lvl, | ||||
| void (*callback)(void *userData, int level), void *userData) | void (*callback)(void *userData, int level), void *userData) | ||||
| { | { | ||||
| /* Framebuffer must be up to date and bound. This simplify this function. */ | /* Framebuffer must be up to date and bound. This simplify this function. */ | ||||
| if (g_currentfb != fb->object || fb->dirty_flag != 0 || fb->object == 0) { | if (gpu_framebuffer_current_get() != fb->object || fb->dirty_flag != 0 || fb->object == 0) { | ||||
| GPU_framebuffer_bind(fb); | GPU_framebuffer_bind(fb); | ||||
| } | } | ||||
| /* HACK: We make the framebuffer appear not bound in order to | /* HACK: We make the framebuffer appear not bound in order to | ||||
| * not trigger any error in GPU_texture_bind(). */ | * not trigger any error in GPU_texture_bind(). */ | ||||
| GLuint prev_fb = g_currentfb; | GLuint prev_fb = gpu_framebuffer_current_get(); | ||||
| g_currentfb = 0; | gpu_framebuffer_current_set(0); | ||||
| int i; | int i; | ||||
| int current_dim[2] = {fb->width, fb->height}; | int current_dim[2] = {fb->width, fb->height}; | ||||
| for (i = 1; i < max_lvl + 1; i++) { | for (i = 1; i < max_lvl + 1; i++) { | ||||
| /* calculate next viewport size */ | /* calculate next viewport size */ | ||||
| current_dim[0] = max_ii(current_dim[0] / 2, 1); | current_dim[0] = max_ii(current_dim[0] / 2, 1); | ||||
| current_dim[1] = max_ii(current_dim[1] / 2, 1); | current_dim[1] = max_ii(current_dim[1] / 2, 1); | ||||
| Show All 31 Lines | if (fb->attachments[type].tex != NULL) { | ||||
| GPU_texture_unbind(tex); | GPU_texture_unbind(tex); | ||||
| /* Reattach original level */ | /* Reattach original level */ | ||||
| /* NOTE: This is not necessary but this makes the FBO config | /* NOTE: This is not necessary but this makes the FBO config | ||||
| * remain in sync with the GPUFrameBuffer config. */ | * remain in sync with the GPUFrameBuffer config. */ | ||||
| gpu_framebuffer_attachment_attach(&fb->attachments[type], type); | gpu_framebuffer_attachment_attach(&fb->attachments[type], type); | ||||
| } | } | ||||
| } | } | ||||
| g_currentfb = prev_fb; | gpu_framebuffer_current_set(prev_fb); | ||||
| } | } | ||||
| /* GPUOffScreen */ | /* GPUOffScreen */ | ||||
| struct GPUOffScreen { | struct GPUOffScreen { | ||||
| GPUFrameBuffer *fb; | GPUFrameBuffer *fb; | ||||
| GPUTexture *color; | GPUTexture *color; | ||||
| GPUTexture *depth; | GPUTexture *depth; | ||||
| ▲ Show 20 Lines • Show All 163 Lines • Show Last 20 Lines | |||||