diff options
author | Clément Foucault <foucault.clem@gmail.com> | 2017-06-22 03:01:58 +0300 |
---|---|---|
committer | Clément Foucault <foucault.clem@gmail.com> | 2017-06-22 04:51:06 +0300 |
commit | ed59d03bfcac7e0b21c82febe6b6f2f786b62034 (patch) | |
tree | e7eb885586baf7cf6a3921efa5d04a1cd6072440 /source | |
parent | fe2ff3fc89332ddf8374b72e2f05f3f7015f8cbd (diff) |
GPUFramebuffer: Add recursive downsampling function.
This special case function enables rendering to a miplevel while using the miplevels above as texture input.
This is needed for some algorithm (i.e. creating a min-max depth pyramid texture).
Diffstat (limited to 'source')
-rw-r--r-- | source/blender/draw/intern/DRW_render.h | 3 | ||||
-rw-r--r-- | source/blender/draw/intern/draw_manager.c | 6 | ||||
-rw-r--r-- | source/blender/gpu/GPU_framebuffer.h | 4 | ||||
-rw-r--r-- | source/blender/gpu/intern/gpu_framebuffer.c | 75 |
4 files changed, 70 insertions, 18 deletions
diff --git a/source/blender/draw/intern/DRW_render.h b/source/blender/draw/intern/DRW_render.h index aa6b836be17..07e9abcbd47 100644 --- a/source/blender/draw/intern/DRW_render.h +++ b/source/blender/draw/intern/DRW_render.h @@ -202,6 +202,9 @@ void DRW_framebuffer_texture_layer_attach(struct GPUFrameBuffer *fb, struct GPUT void DRW_framebuffer_cubeface_attach(struct GPUFrameBuffer *fb, struct GPUTexture *tex, int slot, int face, int mip); void DRW_framebuffer_texture_detach(struct GPUTexture *tex); void DRW_framebuffer_blit(struct GPUFrameBuffer *fb_read, struct GPUFrameBuffer *fb_write, bool depth); +void DRW_framebuffer_recursive_downsample( + struct GPUFrameBuffer *fb, struct GPUTexture *tex, int num_iter, + void (*callback)(void *userData, int level), void *userData); void DRW_framebuffer_viewport_size(struct GPUFrameBuffer *fb_read, int x, int y, int w, int h); void DRW_framebuffer_free(struct GPUFrameBuffer *fb); #define DRW_FRAMEBUFFER_FREE_SAFE(fb) do { \ diff --git a/source/blender/draw/intern/draw_manager.c b/source/blender/draw/intern/draw_manager.c index d01f7f5823e..e390ab33c69 100644 --- a/source/blender/draw/intern/draw_manager.c +++ b/source/blender/draw/intern/draw_manager.c @@ -2137,6 +2137,12 @@ void DRW_framebuffer_blit(struct GPUFrameBuffer *fb_read, struct GPUFrameBuffer GPU_framebuffer_blit(fb_read, 0, fb_write, 0, depth); } +void DRW_framebuffer_recursive_downsample( + struct GPUFrameBuffer *fb, struct GPUTexture *tex, int num_iter, + void (*callback)(void *userData, int level), void *userData) +{ + GPU_framebuffer_recursive_downsample(fb, tex, num_iter, callback, userData); +} void DRW_framebuffer_viewport_size(struct GPUFrameBuffer *UNUSED(fb_read), int x, int y, int w, int h) { glViewport(x, y, w, h); diff --git a/source/blender/gpu/GPU_framebuffer.h b/source/blender/gpu/GPU_framebuffer.h index 6778930f61c..a079d12b469 100644 --- a/source/blender/gpu/GPU_framebuffer.h +++ b/source/blender/gpu/GPU_framebuffer.h @@ -75,6 +75,10 @@ void GPU_framebuffer_blit( GPUFrameBuffer *fb_read, int read_slot, GPUFrameBuffer *fb_write, int write_slot, bool use_depth); +void GPU_framebuffer_recursive_downsample( + GPUFrameBuffer *fb, struct GPUTexture *tex, int num_iter, + void (*callback)(void *userData, int level), void *userData); + /* GPU OffScreen * - wrapper around framebuffer and texture for simple offscreen drawing * - changes size if graphics card can't support it */ diff --git a/source/blender/gpu/intern/gpu_framebuffer.c b/source/blender/gpu/intern/gpu_framebuffer.c index d791f839e20..ddf0e83309c 100644 --- a/source/blender/gpu/intern/gpu_framebuffer.c +++ b/source/blender/gpu/intern/gpu_framebuffer.c @@ -142,16 +142,7 @@ bool GPU_framebuffer_texture_attach(GPUFrameBuffer *fb, GPUTexture *tex, int slo else attachment = GL_COLOR_ATTACHMENT0 + slot; -#if defined(WITH_GL_PROFILE_COMPAT) - /* Workaround for Mac & Mesa compatibility profile, remove after we switch to core profile */ - /* glFramebufferTexture was introduced in 3.2. It is *not* available in the ARB FBO extension */ - if (GLEW_VERSION_3_2) - glFramebufferTexture(GL_FRAMEBUFFER, attachment, GPU_texture_opengl_bindcode(tex), mip); /* normal core call, same as below */ - else - glFramebufferTexture2D(GL_FRAMEBUFFER, attachment, GPU_texture_target(tex), GPU_texture_opengl_bindcode(tex), mip); -#else glFramebufferTexture(GL_FRAMEBUFFER, attachment, GPU_texture_opengl_bindcode(tex), mip); -#endif if (GPU_texture_depth(tex)) fb->depthtex = tex; @@ -250,16 +241,7 @@ void GPU_framebuffer_texture_detach(GPUTexture *tex) attachment = GL_COLOR_ATTACHMENT0 + fb_attachment; } -#if defined(WITH_GL_PROFILE_COMPAT) - /* Workaround for Mac & Mesa compatibility profile, remove after we switch to core profile */ - /* glFramebufferTexture was introduced in 3.2. It is *not* available in the ARB FBO extension */ - if (GLEW_VERSION_3_2) - glFramebufferTexture(GL_FRAMEBUFFER, attachment, 0, 0); /* normal core call, same as below */ - else - glFramebufferTexture2D(GL_FRAMEBUFFER, attachment, GPU_texture_target(tex), 0, 0); -#else glFramebufferTexture(GL_FRAMEBUFFER, attachment, 0, 0); -#endif GPU_texture_framebuffer_set(tex, NULL, -1); } @@ -554,6 +536,63 @@ void GPU_framebuffer_blit(GPUFrameBuffer *fb_read, int read_slot, GPUFrameBuffer glDrawBuffer(GL_COLOR_ATTACHMENT0); } +/** + * 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. + **/ +void GPU_framebuffer_recursive_downsample( + GPUFrameBuffer *fb, GPUTexture *tex, int num_iter, void (*callback)(void *userData, int level), void *userData) +{ + int current_dim[2] = {GPU_texture_width(tex), GPU_texture_height(tex)}; + GLenum attachment; + + /* Manually setup framebuffer to not use GPU_texture_framebuffer_set() */ + glBindFramebuffer(GL_FRAMEBUFFER, fb->object); + GG.currentfb = fb->object; + + if (GPU_texture_stencil(tex) && GPU_texture_depth(tex)) + attachment = GL_DEPTH_STENCIL_ATTACHMENT; + else if (GPU_texture_depth(tex)) + attachment = GL_DEPTH_ATTACHMENT; + else + attachment = GL_COLOR_ATTACHMENT0; + + /* last bound prevails here, better allow explicit control here too */ + glDrawBuffer(GL_COLOR_ATTACHMENT0); + glReadBuffer(GL_COLOR_ATTACHMENT0); + + for (int i=1; i < num_iter+1 && (current_dim[0] > 1 && current_dim[1] > 1); i++) { + + /* calculate next viewport size */ + current_dim[0] /= 2; + current_dim[1] /= 2; + + /* ensure that the viewport size is always at least 1x1 */ + CLAMP_MIN(current_dim[0], 1); + CLAMP_MIN(current_dim[1], 1); + + glViewport(0, 0, current_dim[0], current_dim[1]); + + /* bind next level for rendering but first restrict fetches only to previous level */ + GPU_texture_bind(tex, 0); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, i-1); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, i-1); + GPU_texture_unbind(tex); + + glFramebufferTexture2D(GL_FRAMEBUFFER, attachment, GL_TEXTURE_2D, GPU_texture_opengl_bindcode(tex), i); + + callback(userData, i); + } + + glFramebufferTexture(GL_FRAMEBUFFER, attachment, 0, 0); + + /* reset mipmap level range for the depth image */ + GPU_texture_bind(tex, 0); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, num_iter - 1); + GPU_texture_unbind(tex); +} + /* GPUOffScreen */ struct GPUOffScreen { |