diff options
author | Lukas Tönne <lukas.toenne@gmail.com> | 2018-04-15 13:16:55 +0300 |
---|---|---|
committer | Lukas Tönne <lukas.toenne@gmail.com> | 2018-04-15 13:16:55 +0300 |
commit | 7e1832c8d546ec13e752b7bd42ce13e3fc10ae86 (patch) | |
tree | 0fff9d878db69b288f909ff9a0f8aefe31ab8d80 /source/blender/gpu | |
parent | c0c8df3f2cf3ab03cec1f660619b0fe2290caf2a (diff) | |
parent | 94959dba1b53640e2a36cf9b5ca46aaf49c5c74a (diff) |
Merge branch 'blender2.8' into hair_guides
Diffstat (limited to 'source/blender/gpu')
50 files changed, 2467 insertions, 3177 deletions
diff --git a/source/blender/gpu/CMakeLists.txt b/source/blender/gpu/CMakeLists.txt index 0ac842d90a0..bf0e6ea3368 100644 --- a/source/blender/gpu/CMakeLists.txt +++ b/source/blender/gpu/CMakeLists.txt @@ -55,7 +55,6 @@ set(SRC intern/gpu_batch_presets.c intern/gpu_buffers.c intern/gpu_codegen.c - intern/gpu_compositing.c intern/gpu_debug.c intern/gpu_draw.c intern/gpu_extensions.c @@ -81,7 +80,6 @@ set(SRC shaders/gpu_shader_fx_dof_hq_frag.glsl shaders/gpu_shader_fx_dof_hq_vert.glsl shaders/gpu_shader_fx_dof_hq_geo.glsl - shaders/gpu_shader_fullscreen_vert.glsl shaders/gpu_shader_material.glsl shaders/gpu_shader_sep_gaussian_blur_frag.glsl shaders/gpu_shader_sep_gaussian_blur_vert.glsl @@ -99,7 +97,6 @@ set(SRC GPU_basic_shader.h GPU_batch.h GPU_buffers.h - GPU_compositing.h GPU_debug.h GPU_draw.h GPU_extensions.h @@ -135,6 +132,12 @@ data_to_c_simple(shaders/gpu_shader_simple_lighting_smooth_color_alpha_frag.glsl data_to_c_simple(shaders/gpu_shader_flat_color_frag.glsl SRC) data_to_c_simple(shaders/gpu_shader_flat_color_alpha_test_0_frag.glsl SRC) data_to_c_simple(shaders/gpu_shader_2D_vert.glsl SRC) +data_to_c_simple(shaders/gpu_shader_2D_widget_base_vert.glsl SRC) +data_to_c_simple(shaders/gpu_shader_2D_widget_base_frag.glsl SRC) +data_to_c_simple(shaders/gpu_shader_2D_widget_shadow_vert.glsl SRC) +data_to_c_simple(shaders/gpu_shader_2D_widget_shadow_frag.glsl SRC) +data_to_c_simple(shaders/gpu_shader_2D_nodelink_frag.glsl SRC) +data_to_c_simple(shaders/gpu_shader_2D_nodelink_vert.glsl SRC) data_to_c_simple(shaders/gpu_shader_2D_flat_color_vert.glsl SRC) data_to_c_simple(shaders/gpu_shader_2D_line_dashed_uniform_color_vert.glsl SRC) data_to_c_simple(shaders/gpu_shader_2D_line_dashed_frag.glsl SRC) @@ -142,14 +145,18 @@ data_to_c_simple(shaders/gpu_shader_2D_line_dashed_geom.glsl SRC) data_to_c_simple(shaders/gpu_shader_2D_smooth_color_vert.glsl SRC) data_to_c_simple(shaders/gpu_shader_2D_smooth_color_frag.glsl SRC) data_to_c_simple(shaders/gpu_shader_2D_image_vert.glsl SRC) +data_to_c_simple(shaders/gpu_shader_2D_image_rect_vert.glsl SRC) +data_to_c_simple(shaders/gpu_shader_2D_image_multi_rect_vert.glsl SRC) +data_to_c_simple(shaders/gpu_shader_image_frag.glsl SRC) data_to_c_simple(shaders/gpu_shader_image_linear_frag.glsl SRC) data_to_c_simple(shaders/gpu_shader_image_shuffle_color_frag.glsl SRC) data_to_c_simple(shaders/gpu_shader_image_mask_uniform_color_frag.glsl SRC) data_to_c_simple(shaders/gpu_shader_image_modulate_alpha_frag.glsl SRC) data_to_c_simple(shaders/gpu_shader_image_alpha_color_frag.glsl SRC) data_to_c_simple(shaders/gpu_shader_image_color_frag.glsl SRC) -data_to_c_simple(shaders/gpu_shader_image_rect_modulate_alpha_frag.glsl SRC) +data_to_c_simple(shaders/gpu_shader_image_varying_color_frag.glsl SRC) data_to_c_simple(shaders/gpu_shader_image_depth_linear_frag.glsl SRC) +data_to_c_simple(shaders/gpu_shader_image_depth_copy_frag.glsl SRC) data_to_c_simple(shaders/gpu_shader_image_interlace_frag.glsl SRC) data_to_c_simple(shaders/gpu_shader_3D_image_vert.glsl SRC) data_to_c_simple(shaders/gpu_shader_3D_vert.glsl SRC) @@ -174,7 +181,7 @@ data_to_c_simple(shaders/gpu_shader_instance_edges_variying_color_geom.glsl SRC) data_to_c_simple(shaders/gpu_shader_instance_edges_variying_color_vert.glsl SRC) data_to_c_simple(shaders/gpu_shader_instance_bone_envelope_solid_vert.glsl SRC) data_to_c_simple(shaders/gpu_shader_instance_bone_envelope_wire_vert.glsl SRC) -data_to_c_simple(shaders/gpu_shader_instance_mball_helpers_vert.glsl SRC) +data_to_c_simple(shaders/gpu_shader_instance_mball_handles_vert.glsl SRC) data_to_c_simple(shaders/gpu_shader_3D_groundline_geom.glsl SRC) data_to_c_simple(shaders/gpu_shader_3D_groundpoint_vert.glsl SRC) @@ -202,7 +209,10 @@ data_to_c_simple(shaders/gpu_shader_edges_overlay_vert.glsl SRC) data_to_c_simple(shaders/gpu_shader_edges_overlay_geom.glsl SRC) data_to_c_simple(shaders/gpu_shader_edges_overlay_simple_geom.glsl SRC) data_to_c_simple(shaders/gpu_shader_edges_overlay_frag.glsl SRC) +data_to_c_simple(shaders/gpu_shader_text_simple_vert.glsl SRC) +data_to_c_simple(shaders/gpu_shader_text_simple_geom.glsl SRC) data_to_c_simple(shaders/gpu_shader_text_vert.glsl SRC) +data_to_c_simple(shaders/gpu_shader_text_geom.glsl SRC) data_to_c_simple(shaders/gpu_shader_text_frag.glsl SRC) data_to_c_simple(shaders/gpu_shader_keyframe_diamond_vert.glsl SRC) data_to_c_simple(shaders/gpu_shader_keyframe_diamond_frag.glsl SRC) @@ -221,15 +231,6 @@ data_to_c_simple(shaders/gpu_shader_vertex.glsl SRC) data_to_c_simple(shaders/gpu_shader_vertex_world.glsl SRC) data_to_c_simple(shaders/gpu_shader_vsm_store_frag.glsl SRC) data_to_c_simple(shaders/gpu_shader_vsm_store_vert.glsl SRC) -data_to_c_simple(shaders/gpu_shader_fullscreen_vert.glsl SRC) -data_to_c_simple(shaders/gpu_shader_fx_ssao_frag.glsl SRC) -data_to_c_simple(shaders/gpu_shader_fx_dof_frag.glsl SRC) -data_to_c_simple(shaders/gpu_shader_fx_dof_vert.glsl SRC) -data_to_c_simple(shaders/gpu_shader_fx_dof_hq_frag.glsl SRC) -data_to_c_simple(shaders/gpu_shader_fx_dof_hq_vert.glsl SRC) -data_to_c_simple(shaders/gpu_shader_fx_dof_hq_geo.glsl SRC) -data_to_c_simple(shaders/gpu_shader_fx_depth_resolve.glsl SRC) -data_to_c_simple(shaders/gpu_shader_fx_lib.glsl SRC) if(WITH_GAMEENGINE) add_definitions(-DWITH_GAMEENGINE) diff --git a/source/blender/gpu/GPU_batch.h b/source/blender/gpu/GPU_batch.h index d2f3409dc07..760faeff7b1 100644 --- a/source/blender/gpu/GPU_batch.h +++ b/source/blender/gpu/GPU_batch.h @@ -32,6 +32,7 @@ #define __GPU_BATCH_H__ #include "../../../intern/gawain/gawain/gwn_batch.h" +#include "../../../intern/gawain/gawain/gwn_batch_private.h" struct rctf; @@ -39,6 +40,7 @@ struct rctf; // #include "gawain/batch.h" #include "BLI_compiler_attrs.h" +#include "BLI_sys_types.h" #include "GPU_shader.h" @@ -58,11 +60,15 @@ void gpu_batch_init(void); void gpu_batch_exit(void); /* gpu_batch_presets.c */ +/* Only use by draw manager. Use the presets function instead for interface. */ +Gwn_Batch *gpu_batch_sphere(int lat_res, int lon_res) ATTR_WARN_UNUSED_RESULT; /* Replacement for gluSphere */ Gwn_Batch *GPU_batch_preset_sphere(int lod) ATTR_WARN_UNUSED_RESULT; Gwn_Batch *GPU_batch_preset_sphere_wire(int lod) ATTR_WARN_UNUSED_RESULT; void gpu_batch_presets_init(void); +void gpu_batch_presets_register(Gwn_Batch *preset_batch); +void gpu_batch_presets_reset(void); void gpu_batch_presets_exit(void); #endif /* __GPU_BATCH_H__ */ diff --git a/source/blender/gpu/GPU_compositing.h b/source/blender/gpu/GPU_compositing.h deleted file mode 100644 index d506d91a9aa..00000000000 --- a/source/blender/gpu/GPU_compositing.h +++ /dev/null @@ -1,106 +0,0 @@ -/* - * ***** BEGIN GPL LICENSE BLOCK ***** - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2005 Blender Foundation. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): Antony Riakiotakis. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file GPU_compositing.h - * \ingroup gpu - */ - -#ifndef __GPU_COMPOSITING_H__ -#define __GPU_COMPOSITING_H__ - -#ifdef __cplusplus -extern "C" { -#endif - -/* opaque handle for framebuffer compositing effects (defined in gpu_compositing.c )*/ -typedef struct GPUFX GPUFX; -struct GPUDOFSettings; -struct GPUSSAOSettings; -struct GPUOffScreen; -struct GPUFXSettings; -struct rcti; -struct Scene; -struct GPUShader; -enum eGPUFXFlags; - -/**** Public API *****/ - -typedef enum GPUFXShaderEffect { - /* Screen space ambient occlusion shader */ - GPU_SHADER_FX_SSAO = 1, - - /* depth of field passes. Yep, quite a complex effect */ - GPU_SHADER_FX_DEPTH_OF_FIELD_PASS_ONE = 2, - GPU_SHADER_FX_DEPTH_OF_FIELD_PASS_TWO = 3, - GPU_SHADER_FX_DEPTH_OF_FIELD_PASS_THREE = 4, - GPU_SHADER_FX_DEPTH_OF_FIELD_PASS_FOUR = 5, - GPU_SHADER_FX_DEPTH_OF_FIELD_PASS_FIVE = 6, - - /* high quality */ - GPU_SHADER_FX_DEPTH_OF_FIELD_HQ_PASS_ONE = 7, - GPU_SHADER_FX_DEPTH_OF_FIELD_HQ_PASS_TWO = 8, - GPU_SHADER_FX_DEPTH_OF_FIELD_HQ_PASS_THREE = 9, - - GPU_SHADER_FX_DEPTH_RESOLVE = 10, -} GPUFXShaderEffect; - -/* keep in synch with enum above! */ -#define MAX_FX_SHADERS 11 - -/* generate a new FX compositor */ -GPUFX *GPU_fx_compositor_create(void); - -/* destroy a text compositor */ -void GPU_fx_compositor_destroy(GPUFX *fx); - -/* initialize a framebuffer with size taken from the viewport */ -bool GPU_fx_compositor_initialize_passes( - GPUFX *fx, const struct rcti *rect, const struct rcti *scissor_rect, - const struct GPUFXSettings *fx_settings); - -/* do compositing on the fx passes that have been initialized */ -bool GPU_fx_do_composite_pass( - GPUFX *fx, float projmat[4][4], bool is_persp, - struct Scene *scene, struct GPUOffScreen *ofs); - -/* bind new depth buffer for XRay pass */ -void GPU_fx_compositor_setup_XRay_pass(GPUFX *fx, bool do_xray); - -/* resolve a final depth buffer by compositing the XRay and normal depth buffers */ -void GPU_fx_compositor_XRay_resolve(GPUFX *fx); - -void GPU_fx_compositor_init_dof_settings(struct GPUDOFSettings *dof); -void GPU_fx_compositor_init_ssao_settings(struct GPUSSAOSettings *ssao); - - -/* initialize and cache the shader unform interface for effects */ -void GPU_fx_shader_init_interface(struct GPUShader *shader, GPUFXShaderEffect effect); -#ifdef __cplusplus -} -#endif - -#endif // __GPU_COMPOSITING_H__ diff --git a/source/blender/gpu/GPU_draw.h b/source/blender/gpu/GPU_draw.h index 8d29632fc71..9bbf46b2a1f 100644 --- a/source/blender/gpu/GPU_draw.h +++ b/source/blender/gpu/GPU_draw.h @@ -47,6 +47,8 @@ struct RegionView3D; struct SmokeModifierData; struct DupliObject; +#include "DNA_object_enums.h" + /* OpenGL drawing functions related to shading. These are also * shared with the game engine, where there were previously * duplicates of some of these functions. */ @@ -73,9 +75,10 @@ void GPU_disable_program_point_size(void); * GPU_object_material_bind returns 0 if drawing should be skipped * - after drawing, the material must be disabled again */ -void GPU_begin_object_materials(struct View3D *v3d, struct RegionView3D *rv3d, - struct Scene *scene, struct ViewLayer *view_layer, - struct Object *ob, bool glsl, bool *do_alpha_after); +void GPU_begin_object_materials( + struct View3D *v3d, struct RegionView3D *rv3d, + struct Scene *scene, struct ViewLayer *view_layer, + struct Object *ob, bool glsl, bool *do_alpha_after); void GPU_end_object_materials(void); bool GPU_object_materials_check(void); diff --git a/source/blender/gpu/GPU_extensions.h b/source/blender/gpu/GPU_extensions.h index d860431b04f..d36b0ea15be 100644 --- a/source/blender/gpu/GPU_extensions.h +++ b/source/blender/gpu/GPU_extensions.h @@ -64,7 +64,6 @@ typedef enum GPUDeviceType { GPU_DEVICE_INTEL = (1 << 2), GPU_DEVICE_SOFTWARE = (1 << 3), GPU_DEVICE_UNKNOWN = (1 << 4), - GPU_DEVICE_AMD_VEGA = (1 << 5), GPU_DEVICE_ANY = (0xff) } GPUDeviceType; diff --git a/source/blender/gpu/GPU_framebuffer.h b/source/blender/gpu/GPU_framebuffer.h index c58d98c201e..0ab15a4ea47 100644 --- a/source/blender/gpu/GPU_framebuffer.h +++ b/source/blender/gpu/GPU_framebuffer.h @@ -36,61 +36,158 @@ extern "C" { #endif +struct GPUTexture; + +typedef struct GPUAttachment { + struct GPUTexture *tex; + int mip, layer; +} GPUAttachment; + +typedef enum GPUFrameBufferBits{ + GPU_COLOR_BIT = (1 << 0), + GPU_DEPTH_BIT = (1 << 1), + GPU_STENCIL_BIT = (1 << 2), +} GPUFrameBufferBits; + typedef struct GPUFrameBuffer GPUFrameBuffer; typedef struct GPUOffScreen GPUOffScreen; -struct GPUTexture; /* GPU Framebuffer * - this is a wrapper for an OpenGL framebuffer object (FBO). in practice * multiple FBO's may be created, to get around limitations on the number * of attached textures and the dimension requirements. - * - after any of the GPU_framebuffer_* functions, GPU_framebuffer_restore must - * be called before rendering to the window framebuffer again */ - -void GPU_texture_bind_as_framebuffer(struct GPUTexture *tex); + * - actual FBO creation & config is deferred until GPU_framebuffer_bind or + * GPU_framebuffer_check_valid to allow creation & config while another + * opengl context is bound (since FBOs are not shared between ogl contexts). + */ GPUFrameBuffer *GPU_framebuffer_create(void); -bool GPU_framebuffer_texture_attach(GPUFrameBuffer *fb, struct GPUTexture *tex, int slot, int mip); -bool GPU_framebuffer_texture_layer_attach( - GPUFrameBuffer *fb, struct GPUTexture *tex, int slot, int layer, int mip); -bool GPU_framebuffer_texture_cubeface_attach( - GPUFrameBuffer *fb, struct GPUTexture *tex, int slot, int face, int mip); -void GPU_framebuffer_texture_detach(struct GPUTexture *tex); -void GPU_framebuffer_bind(GPUFrameBuffer *fb); -void GPU_framebuffer_slots_bind(GPUFrameBuffer *fb, int slot); -void GPU_framebuffer_texture_unbind(GPUFrameBuffer *fb, struct GPUTexture *tex); void GPU_framebuffer_free(GPUFrameBuffer *fb); +void GPU_framebuffer_bind(GPUFrameBuffer *fb); +void GPU_framebuffer_restore(void); + +bool GPU_framebuffer_bound(GPUFrameBuffer *fb); bool GPU_framebuffer_check_valid(GPUFrameBuffer *fb, char err_out[256]); -void GPU_framebuffer_bind_no_save(GPUFrameBuffer *fb, int slot); +/* internal use only */ +unsigned int GPU_framebuffer_current_get(void); -bool GPU_framebuffer_bound(GPUFrameBuffer *fb); +#define GPU_FRAMEBUFFER_FREE_SAFE(fb) do { \ + if (fb != NULL) { \ + GPU_framebuffer_free(fb); \ + fb = NULL; \ + } \ +} while (0) -void GPU_framebuffer_restore(void); -void GPU_framebuffer_blur( - GPUFrameBuffer *fb, struct GPUTexture *tex, - GPUFrameBuffer *blurfb, struct GPUTexture *blurtex); +/* Framebuffer setup : You need to call GPU_framebuffer_bind for theses + * to be effective. */ + +void GPU_framebuffer_texture_attach( + GPUFrameBuffer *fb, struct GPUTexture *tex, int slot, int mip); +void GPU_framebuffer_texture_layer_attach( + GPUFrameBuffer *fb, struct GPUTexture *tex, int slot, int layer, int mip); +void GPU_framebuffer_texture_cubeface_attach( + GPUFrameBuffer *fb, struct GPUTexture *tex, int slot, int face, int mip); +void GPU_framebuffer_texture_detach(GPUFrameBuffer *fb, struct GPUTexture *tex); +void GPU_framebuffer_texture_detach_slot( + GPUFrameBuffer *fb, struct GPUTexture *tex, int type); + +/** + * How to use GPU_framebuffer_ensure_config(). + * + * Example : + * GPU_framebuffer_ensure_config(&fb, { + * GPU_ATTACHMENT_TEXTURE(depth), // must be depth buffer + * GPU_ATTACHMENT_TEXTURE(tex1), + * GPU_ATTACHMENT_TEXTURE_CUBEFACE(tex2, 0), + * GPU_ATTACHMENT_TEXTURE_LAYER_MIP(tex2, 0, 0) + * }) + * + * Note : Unspecified attachements (i.e: those beyond the last + * GPU_ATTACHMENT_* in GPU_framebuffer_ensure_config list) + * are left unchanged. + * Note : Make sure that the dimensions of your textures matches + * otherwise you will have an invalid framebuffer error. + **/ +#define GPU_framebuffer_ensure_config(_fb, ...) do { \ + if (*(_fb) == NULL) { \ + *(_fb) = GPU_framebuffer_create(); \ + } \ + GPUAttachment config[] = __VA_ARGS__; \ + GPU_framebuffer_config_array(*(_fb), config, (sizeof(config) / sizeof(GPUAttachment))); \ +} while (0) + +void GPU_framebuffer_config_array(GPUFrameBuffer *fb, const GPUAttachment *config, int config_ct); + +#define GPU_ATTACHMENT_NONE \ + {.tex = NULL, .layer = -1, .mip = 0} +#define GPU_ATTACHMENT_LEAVE \ + {.tex = NULL, .layer = -1, .mip = -1} +#define GPU_ATTACHMENT_TEXTURE(_tex) \ + {.tex = _tex, .layer = -1, .mip = 0} +#define GPU_ATTACHMENT_TEXTURE_MIP(_tex, _mip) \ + {.tex = _tex, .layer = -1, .mip = _mip} +#define GPU_ATTACHMENT_TEXTURE_LAYER(_tex, _layer) \ + {.tex = _tex, .layer = _layer, .mip = 0} +#define GPU_ATTACHMENT_TEXTURE_LAYER_MIP(_tex, _layer, _mip) \ + {.tex = _tex, .layer = _layer, .mip = _mip} +#define GPU_ATTACHMENT_TEXTURE_CUBEFACE(_tex, _face) \ + {.tex = _tex, .layer = _face, .mip = 0} +#define GPU_ATTACHMENT_TEXTURE_CUBEFACE_MIP(_tex, _face, _mip) \ + {.tex = _tex, .layer = _face, .mip = _mip} + +/* Framebuffer operations */ + +void GPU_framebuffer_viewport_set(GPUFrameBuffer *fb, int x, int y, int w, int h); + +void GPU_framebuffer_clear( + GPUFrameBuffer *fb, GPUFrameBufferBits buffers, + const float clear_col[4], float clear_depth, unsigned int clear_stencil); + +#define GPU_framebuffer_clear_color(fb, col) \ + GPU_framebuffer_clear(fb, GPU_COLOR_BIT, col, 0.0f, 0x00) + +#define GPU_framebuffer_clear_depth(fb, depth) \ + GPU_framebuffer_clear(fb, GPU_DEPTH_BIT, NULL, depth, 0x00) + +#define GPU_framebuffer_clear_color_depth(fb, col, depth) \ + GPU_framebuffer_clear(fb, GPU_COLOR_BIT | GPU_DEPTH_BIT, col, depth, 0x00) + +#define GPU_framebuffer_clear_stencil(fb, stencil) \ + GPU_framebuffer_clear(fb, GPU_STENCIL_BIT, NULL, 0.0f, stencil) + +#define GPU_framebuffer_clear_depth_stencil(fb, depth, stencil) \ + GPU_framebuffer_clear(fb, GPU_DEPTH_BIT | GPU_STENCIL_BIT, NULL, depth, stencil) + +#define GPU_framebuffer_clear_color_depth_stencil(fb, col, depth, stencil) \ + GPU_framebuffer_clear(fb, GPU_COLOR_BIT | GPU_DEPTH_BIT | GPU_STENCIL_BIT, col, depth, stencil) + +void GPU_framebuffer_read_depth(GPUFrameBuffer *fb, int x, int y, int w, int h, float *data); +void GPU_framebuffer_read_color( + GPUFrameBuffer *fb, int x, int y, int w, int h, int channels, int slot, float *data); void GPU_framebuffer_blit( GPUFrameBuffer *fb_read, int read_slot, - GPUFrameBuffer *fb_write, int write_slot, bool use_depth, bool use_stencil); + GPUFrameBuffer *fb_write, int write_slot, + GPUFrameBufferBits blit_buffers); void GPU_framebuffer_recursive_downsample( - GPUFrameBuffer *fb, struct GPUTexture *tex, int num_iter, + GPUFrameBuffer *fb, int max_lvl, 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 */ + */ -GPUOffScreen *GPU_offscreen_create(int width, int height, int samples, bool high_bitdepth, char err_out[256]); +GPUOffScreen *GPU_offscreen_create(int width, int height, int samples, + bool depth, bool high_bitdepth, char err_out[256]); void GPU_offscreen_free(GPUOffScreen *ofs); void GPU_offscreen_bind(GPUOffScreen *ofs, bool save); void GPU_offscreen_unbind(GPUOffScreen *ofs, bool restore); void GPU_offscreen_read_pixels(GPUOffScreen *ofs, int type, void *pixels); int GPU_offscreen_width(const GPUOffScreen *ofs); int GPU_offscreen_height(const GPUOffScreen *ofs); -int GPU_offscreen_color_texture(const GPUOffScreen *ofs); +struct GPUTexture *GPU_offscreen_color_texture(const GPUOffScreen *ofs); void GPU_offscreen_viewport_data_get( GPUOffScreen *ofs, diff --git a/source/blender/gpu/GPU_material.h b/source/blender/gpu/GPU_material.h index 698f3ada2a3..1d2b234e7f3 100644 --- a/source/blender/gpu/GPU_material.h +++ b/source/blender/gpu/GPU_material.h @@ -110,7 +110,8 @@ typedef enum GPUBuiltin { GPU_INVERSE_LOC_TO_VIEW_MATRIX = (1 << 14), GPU_OBJECT_INFO = (1 << 15), GPU_VOLUME_DENSITY = (1 << 16), - GPU_VOLUME_FLAME = (1 << 17) + GPU_VOLUME_FLAME = (1 << 17), + GPU_VOLUME_TEMPERATURE = (1 << 18) } GPUBuiltin; typedef enum GPUOpenGLBuiltin { @@ -135,14 +136,19 @@ typedef enum GPUBlendMode { typedef struct GPUNodeStack { GPUType type; - const char *name; float vec[4]; struct GPUNodeLink *link; bool hasinput; bool hasoutput; short sockettype; + bool end; } GPUNodeStack; +typedef enum GPUMaterialStatus { + GPU_MAT_FAILED = 0, + GPU_MAT_QUEUED, + GPU_MAT_SUCCESS, +} GPUMaterialStatus; #define GPU_DYNAMIC_GROUP_FROM_TYPE(f) ((f) & 0xFFFF0000) @@ -244,9 +250,11 @@ GPUMaterial *GPU_material_from_nodetree_find( struct ListBase *gpumaterials, const void *engine_type, int options); GPUMaterial *GPU_material_from_nodetree( struct Scene *scene, struct bNodeTree *ntree, struct ListBase *gpumaterials, const void *engine_type, int options, - const char *vert_code, const char *geom_code, const char *frag_lib, const char *defines); + const char *vert_code, const char *geom_code, const char *frag_lib, const char *defines, bool deferred); GPUMaterial *GPU_material_from_blender(struct Scene *scene, struct Material *ma, bool use_opensubdiv); GPUMaterial *GPU_material_matcap(struct Scene *scene, struct Material *ma, bool use_opensubdiv); +void GPU_material_generate_pass( + GPUMaterial *mat, const char *vert_code, const char *geom_code, const char *frag_lib, const char *defines); void GPU_material_free(struct ListBase *gpumaterial); void GPU_materials_free(void); @@ -262,6 +270,8 @@ bool GPU_material_bound(GPUMaterial *material); struct Scene *GPU_material_scene(GPUMaterial *material); GPUMatType GPU_Material_get_type(GPUMaterial *material); struct GPUPass *GPU_material_get_pass(GPUMaterial *material); +struct ListBase *GPU_material_get_inputs(GPUMaterial *material); +GPUMaterialStatus GPU_material_status(GPUMaterial *mat); struct GPUUniformBuffer *GPU_material_get_uniform_buffer(GPUMaterial *material); void GPU_material_create_uniform_buffer(GPUMaterial *material, struct ListBase *inputs); @@ -357,10 +367,9 @@ void GPU_zenith_update_color(float color[3]); struct GPUParticleInfo { float scalprops[4]; - float location[3]; + float location[4]; float velocity[3]; float angular_velocity[3]; - int random_id; }; #ifdef WITH_OPENSUBDIV @@ -369,6 +378,9 @@ void GPU_material_update_fvar_offset(GPUMaterial *gpu_material, struct DerivedMesh *dm); #endif +void GPU_pass_cache_garbage_collect(void); +void GPU_pass_cache_free(void); + #ifdef __cplusplus } #endif diff --git a/source/blender/gpu/GPU_select.h b/source/blender/gpu/GPU_select.h index 0617d58f3b6..f1342a1f6b8 100644 --- a/source/blender/gpu/GPU_select.h +++ b/source/blender/gpu/GPU_select.h @@ -47,6 +47,7 @@ enum { void GPU_select_begin(unsigned int *buffer, unsigned int bufsize, const struct rcti *input, char mode, int oldhits); bool GPU_select_load_id(unsigned int id); +void GPU_select_finalize(void); unsigned int GPU_select_end(void); bool GPU_select_query_check_active(void); diff --git a/source/blender/gpu/GPU_shader.h b/source/blender/gpu/GPU_shader.h index f2119a117e5..b33df9fdb20 100644 --- a/source/blender/gpu/GPU_shader.h +++ b/source/blender/gpu/GPU_shader.h @@ -72,9 +72,6 @@ int GPU_shader_get_program(GPUShader *shader); void *GPU_shader_get_interface(GPUShader *shader); -void *GPU_fx_shader_get_interface(GPUShader *shader); -void GPU_fx_shader_set_interface(GPUShader *shader, void *interface); - int GPU_shader_get_uniform(GPUShader *shader, const char *name); int GPU_shader_get_builtin_uniform(GPUShader *shader, int builtin); int GPU_shader_get_uniform_block(GPUShader *shader, const char *name); @@ -100,6 +97,7 @@ typedef enum GPUBuiltinShader { /* specialized drawing */ GPU_SHADER_TEXT, + GPU_SHADER_TEXT_SIMPLE, GPU_SHADER_EDGES_FRONT_BACK_PERSP, GPU_SHADER_EDGES_FRONT_BACK_ORTHO, GPU_SHADER_EDGES_OVERLAY_SIMPLE, @@ -113,8 +111,12 @@ typedef enum GPUBuiltinShader { GPU_SHADER_2D_UNIFORM_COLOR, GPU_SHADER_2D_FLAT_COLOR, GPU_SHADER_2D_SMOOTH_COLOR, + GPU_SHADER_2D_IMAGE, GPU_SHADER_2D_IMAGE_COLOR, GPU_SHADER_2D_IMAGE_ALPHA_COLOR, + GPU_SHADER_2D_IMAGE_ALPHA, + GPU_SHADER_2D_IMAGE_RECT_COLOR, + GPU_SHADER_2D_IMAGE_MULTI_RECT_COLOR, GPU_SHADER_2D_CHECKER, GPU_SHADER_2D_DIAG_STRIPES, /* for simple 3D drawing */ @@ -131,8 +133,8 @@ typedef enum GPUBuiltinShader { GPU_SHADER_2D_IMAGE_SHUFFLE_COLOR, GPU_SHADER_2D_IMAGE_MASK_UNIFORM_COLOR, GPU_SHADER_3D_IMAGE_MODULATE_ALPHA, - GPU_SHADER_3D_IMAGE_RECT_MODULATE_ALPHA, GPU_SHADER_3D_IMAGE_DEPTH, + GPU_SHADER_3D_IMAGE_DEPTH_COPY, /* stereo 3d */ GPU_SHADER_2D_IMAGE_INTERLACE, /* points */ @@ -169,11 +171,17 @@ typedef enum GPUBuiltinShader { GPU_SHADER_INSTANCE_VARIYING_COLOR_VARIYING_SIZE, /* Uniformly scaled */ GPU_SHADER_INSTANCE_VARIYING_COLOR_VARIYING_SCALE, GPU_SHADER_INSTANCE_EDGES_VARIYING_COLOR, + /* specialized for UI drawing */ + GPU_SHADER_2D_WIDGET_BASE, + GPU_SHADER_2D_WIDGET_BASE_INST, + GPU_SHADER_2D_WIDGET_SHADOW, + GPU_SHADER_2D_NODELINK, + GPU_SHADER_2D_NODELINK_INST, GPU_SHADER_3D_INSTANCE_BONE_ENVELOPE_SOLID, GPU_SHADER_3D_INSTANCE_BONE_ENVELOPE_WIRE, - GPU_SHADER_3D_INSTANCE_MBALL_HELPERS, + GPU_SHADER_3D_INSTANCE_MBALL_HANDLES, GPU_NUM_BUILTIN_SHADERS /* (not an actual shader) */ } GPUBuiltinShader; @@ -189,7 +197,6 @@ typedef enum GPUInterlaceShader { } GPUInterlaceShader; GPUShader *GPU_shader_get_builtin_shader(GPUBuiltinShader shader); -GPUShader *GPU_shader_get_builtin_fx_shader(int effects, bool persp); void GPU_shader_free_builtin_shaders(void); diff --git a/source/blender/gpu/GPU_texture.h b/source/blender/gpu/GPU_texture.h index e74d9a3291d..7c33153ee01 100644 --- a/source/blender/gpu/GPU_texture.h +++ b/source/blender/gpu/GPU_texture.h @@ -70,6 +70,7 @@ typedef enum GPUTextureFormat { GPU_RG16I, GPU_R32F, GPU_R16F, + GPU_R16I, GPU_RG8, GPU_R8, #if 0 @@ -88,7 +89,6 @@ typedef enum GPUTextureFormat { GPU_RG8UI, GPU_R32I, GPU_R32UI, - GPU_R16I, GPU_R16UI, GPU_R16, GPU_R8I, @@ -189,16 +189,18 @@ void GPU_texture_filter_mode(GPUTexture *tex, bool use_filter); void GPU_texture_mipmap_mode(GPUTexture *tex, bool use_mipmap, bool use_filter); void GPU_texture_wrap_mode(GPUTexture *tex, bool use_repeat); -struct GPUFrameBuffer *GPU_texture_framebuffer(GPUTexture *tex); -int GPU_texture_framebuffer_attachment(GPUTexture *tex); -void GPU_texture_framebuffer_set(GPUTexture *tex, struct GPUFrameBuffer *fb, int attachment); +void GPU_texture_attach_framebuffer(GPUTexture *tex, struct GPUFrameBuffer *fb, int attachment); +int GPU_texture_detach_framebuffer(GPUTexture *tex, struct GPUFrameBuffer *fb); int GPU_texture_target(const GPUTexture *tex); int GPU_texture_width(const GPUTexture *tex); int GPU_texture_height(const GPUTexture *tex); -int GPU_texture_format(const GPUTexture *tex); +GPUTextureFormat GPU_texture_format(const GPUTexture *tex); +int GPU_texture_samples(const GPUTexture *tex); +bool GPU_texture_cube(const GPUTexture *tex); bool GPU_texture_depth(const GPUTexture *tex); bool GPU_texture_stencil(const GPUTexture *tex); +bool GPU_texture_integer(const GPUTexture *tex); int GPU_texture_opengl_bindcode(const GPUTexture *tex); #ifdef __cplusplus diff --git a/source/blender/gpu/GPU_viewport.h b/source/blender/gpu/GPU_viewport.h index 580ff64befb..ca7d5ae7ceb 100644 --- a/source/blender/gpu/GPU_viewport.h +++ b/source/blender/gpu/GPU_viewport.h @@ -46,7 +46,7 @@ typedef struct GPUViewport GPUViewport; /* Contains memory pools informations */ typedef struct ViewportMemoryPool { struct BLI_mempool *calls; - struct BLI_mempool *calls_generate; + struct BLI_mempool *states; struct BLI_mempool *shgroups; struct BLI_mempool *uniforms; struct BLI_mempool *passes; @@ -83,7 +83,6 @@ typedef struct ViewportEngineData { /* Profiling data */ double init_time; - double cache_time; double render_time; double background_time; } ViewportEngineData; @@ -98,6 +97,7 @@ typedef struct ViewportEngineData_Info { GPUViewport *GPU_viewport_create(void); void GPU_viewport_bind(GPUViewport *viewport, const rcti *rect); void GPU_viewport_unbind(GPUViewport *viewport); +void GPU_viewport_draw_to_screen(GPUViewport *viewport, const rcti *rect); void GPU_viewport_free(GPUViewport *viewport); GPUViewport *GPU_viewport_create_from_offscreen(struct GPUOffScreen *ofs); @@ -113,6 +113,9 @@ void *GPU_viewport_texture_list_get(GPUViewport *viewport); void GPU_viewport_size_get(const GPUViewport *viewport, int size[2]); void GPU_viewport_size_set(GPUViewport *viewport, const int size[2]); +/* Profiling */ +double *GPU_viewport_cache_time_get(GPUViewport *viewport); + void GPU_viewport_tag_update(GPUViewport *viewport); bool GPU_viewport_do_update(GPUViewport *viewport); @@ -122,13 +125,4 @@ GPUTexture *GPU_viewport_texture_pool_query(GPUViewport *viewport, void *engine, bool GPU_viewport_engines_data_validate(GPUViewport *viewport, unsigned int hash); void GPU_viewport_cache_release(GPUViewport *viewport); -/* debug */ -bool GPU_viewport_debug_depth_create(GPUViewport *viewport, int width, int height, char err_out[256]); -void GPU_viewport_debug_depth_free(GPUViewport *viewport); -void GPU_viewport_debug_depth_store(GPUViewport *viewport, const int x, const int y); -void GPU_viewport_debug_depth_draw(GPUViewport *viewport, const float znear, const float zfar); -bool GPU_viewport_debug_depth_is_valid(GPUViewport *viewport); -int GPU_viewport_debug_depth_width(const GPUViewport *viewport); -int GPU_viewport_debug_depth_height(const GPUViewport *viewport); - #endif // __GPU_VIEWPORT_H__ diff --git a/source/blender/gpu/intern/gpu_batch.c b/source/blender/gpu/intern/gpu_batch.c index 0400fc1025b..332102aca46 100644 --- a/source/blender/gpu/intern/gpu_batch.c +++ b/source/blender/gpu/intern/gpu_batch.c @@ -34,7 +34,7 @@ #include "BLI_utildefines.h" #include "BLI_rect.h" #include "BLI_math.h" -#include "BLI_polyfill2d.h" +#include "BLI_polyfill_2d.h" #include "BLI_sort_utils.h" diff --git a/source/blender/gpu/intern/gpu_batch_presets.c b/source/blender/gpu/intern/gpu_batch_presets.c index 9db04832a51..10cbd16490b 100644 --- a/source/blender/gpu/intern/gpu_batch_presets.c +++ b/source/blender/gpu/intern/gpu_batch_presets.c @@ -31,6 +31,11 @@ #include "BLI_utildefines.h" #include "BLI_math.h" +#include "BLI_threads.h" +#include "BLI_listbase.h" +#include "MEM_guardedalloc.h" + +#include "UI_interface.h" #include "GPU_batch.h" #include "gpu_shader_private.h" @@ -50,14 +55,24 @@ static struct { struct { uint pos, nor; } attr_id; -} g_presets_3d = {0}; +} g_presets_3d = {{0}}; -/* We may want 2D presets later. */ +static ListBase presets_list = {NULL, NULL}; /* -------------------------------------------------------------------- */ /** \name 3D Primitives * \{ */ +static Gwn_VertFormat *preset_3D_format(void) +{ + if (g_presets_3d.format.attrib_ct == 0) { + Gwn_VertFormat *format = &g_presets_3d.format; + g_presets_3d.attr_id.pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT); + g_presets_3d.attr_id.nor = GWN_vertformat_attr_add(format, "nor", GWN_COMP_F32, 3, GWN_FETCH_FLOAT); + } + return &g_presets_3d.format; +} + static void batch_sphere_lat_lon_vert( Gwn_VertBufRaw *pos_step, Gwn_VertBufRaw *nor_step, float lat, float lon) @@ -71,13 +86,13 @@ static void batch_sphere_lat_lon_vert( } /* Replacement for gluSphere */ -static Gwn_Batch *batch_sphere(int lat_res, int lon_res) +Gwn_Batch *gpu_batch_sphere(int lat_res, int lon_res) { const float lon_inc = 2 * M_PI / lon_res; const float lat_inc = M_PI / lat_res; float lon, lat; - Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&g_presets_3d.format); + Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(preset_3D_format()); const uint vbo_len = (lat_res - 1) * lon_res * 6; GWN_vertbuf_data_alloc(vbo, vbo_len); @@ -115,7 +130,7 @@ static Gwn_Batch *batch_sphere_wire(int lat_res, int lon_res) const float lat_inc = M_PI / lat_res; float lon, lat; - Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&g_presets_3d.format); + Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(preset_3D_format()); const uint vbo_len = (lat_res * lon_res * 2) + ((lat_res - 1) * lon_res * 2); GWN_vertbuf_data_alloc(vbo, vbo_len); @@ -146,6 +161,7 @@ static Gwn_Batch *batch_sphere_wire(int lat_res, int lon_res) Gwn_Batch *GPU_batch_preset_sphere(int lod) { BLI_assert(lod >= 0 && lod <= 2); + BLI_assert(BLI_thread_is_main()); if (lod == 0) { return g_presets_3d.batch.sphere_low; @@ -161,6 +177,7 @@ Gwn_Batch *GPU_batch_preset_sphere(int lod) Gwn_Batch *GPU_batch_preset_sphere_wire(int lod) { BLI_assert(lod >= 0 && lod <= 1); + BLI_assert(BLI_thread_is_main()); if (lod == 0) { return g_presets_3d.batch.sphere_wire_low; @@ -175,26 +192,45 @@ Gwn_Batch *GPU_batch_preset_sphere_wire(int lod) void gpu_batch_presets_init(void) { - if (g_presets_3d.format.attrib_ct == 0) { - Gwn_VertFormat *format = &g_presets_3d.format; - g_presets_3d.attr_id.pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT); - g_presets_3d.attr_id.nor = GWN_vertformat_attr_add(format, "nor", GWN_COMP_F32, 3, GWN_FETCH_FLOAT); - } - /* Hard coded resolution */ - g_presets_3d.batch.sphere_low = batch_sphere(8, 16); - g_presets_3d.batch.sphere_med = batch_sphere(16, 10); - g_presets_3d.batch.sphere_high = batch_sphere(32, 24); + g_presets_3d.batch.sphere_low = gpu_batch_sphere(8, 16); + gpu_batch_presets_register(g_presets_3d.batch.sphere_low); + + g_presets_3d.batch.sphere_med = gpu_batch_sphere(16, 10); + gpu_batch_presets_register(g_presets_3d.batch.sphere_med); + + g_presets_3d.batch.sphere_high = gpu_batch_sphere(32, 24); + gpu_batch_presets_register(g_presets_3d.batch.sphere_high); g_presets_3d.batch.sphere_wire_low = batch_sphere_wire(6, 8); + gpu_batch_presets_register(g_presets_3d.batch.sphere_wire_low); + g_presets_3d.batch.sphere_wire_med = batch_sphere_wire(8, 16); + gpu_batch_presets_register(g_presets_3d.batch.sphere_wire_med); +} + +void gpu_batch_presets_register(Gwn_Batch *preset_batch) +{ + BLI_addtail(&presets_list, BLI_genericNodeN(preset_batch)); +} + +void gpu_batch_presets_reset(void) +{ + /* Reset vao caches for these every time we switch opengl context. + * This way they will draw correctly for each window. */ + LinkData *link = presets_list.first; + for (link = presets_list.first; link; link = link->next) { + Gwn_Batch *preset = link->data; + gwn_batch_vao_cache_clear(preset); + } } void gpu_batch_presets_exit(void) { - GWN_batch_discard(g_presets_3d.batch.sphere_low); - GWN_batch_discard(g_presets_3d.batch.sphere_med); - GWN_batch_discard(g_presets_3d.batch.sphere_high); - GWN_batch_discard(g_presets_3d.batch.sphere_wire_low); - GWN_batch_discard(g_presets_3d.batch.sphere_wire_med); + LinkData *link; + while ((link = BLI_pophead(&presets_list))) { + Gwn_Batch *preset = link->data; + GWN_batch_discard(preset); + MEM_freeN(link); + } } diff --git a/source/blender/gpu/intern/gpu_buffers.c b/source/blender/gpu/intern/gpu_buffers.c index d0efee79ab0..3367a568bc5 100644 --- a/source/blender/gpu/intern/gpu_buffers.c +++ b/source/blender/gpu/intern/gpu_buffers.c @@ -986,15 +986,37 @@ struct GPU_PBVH_Buffers { float diffuse_color[4]; }; -typedef struct { +static struct { uint pos, nor, col; -} VertexBufferAttrID; +} g_vbo_id = {0}; -static void gpu_pbvh_vert_format_init__gwn(Gwn_VertFormat *format, VertexBufferAttrID *vbo_id) +/* Allocates a non-initialized buffer to be sent to GPU. + * Return is false it indicates that the memory map failed. */ +static bool gpu_pbvh_vert_buf_data_set(GPU_PBVH_Buffers *buffers, unsigned int vert_ct) { - vbo_id->pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT); - vbo_id->nor = GWN_vertformat_attr_add(format, "nor", GWN_COMP_I16, 3, GWN_FETCH_INT_TO_FLOAT_UNIT); - vbo_id->col = GWN_vertformat_attr_add(format, "color", GWN_COMP_U8, 3, GWN_FETCH_INT_TO_FLOAT_UNIT); + if (buffers->vert_buf == NULL) { + /* Initialize vertex buffer */ + /* match 'VertexBufferFormat' */ + + static Gwn_VertFormat format = {0}; + if (format.attrib_ct == 0) { + g_vbo_id.pos = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT); + g_vbo_id.nor = GWN_vertformat_attr_add(&format, "nor", GWN_COMP_I16, 3, GWN_FETCH_INT_TO_FLOAT_UNIT); + g_vbo_id.col = GWN_vertformat_attr_add(&format, "color", GWN_COMP_U8, 3, GWN_FETCH_INT_TO_FLOAT_UNIT); + } +#if 0 + buffers->vert_buf = GWN_vertbuf_create_with_format_ex(&format, GWN_USAGE_DYNAMIC); + GWN_vertbuf_data_alloc(buffers->vert_buf, vert_ct); + } + else if (vert_ct != buffers->vert_buf->vertex_ct) { + GWN_vertbuf_data_resize(buffers->vert_buf, vert_ct); + } +#else + buffers->vert_buf = GWN_vertbuf_create_with_format_ex(&format, GWN_USAGE_STATIC); + } + GWN_vertbuf_data_alloc(buffers->vert_buf, vert_ct); +#endif + return buffers->vert_buf->data != NULL; } static void gpu_pbvh_batch_init(GPU_PBVH_Buffers *buffers) @@ -1004,14 +1026,14 @@ static void gpu_pbvh_batch_init(GPU_PBVH_Buffers *buffers) GWN_vertbuf_use(buffers->vert_buf); } - GWN_BATCH_DISCARD_SAFE(buffers->triangles); - buffers->triangles = GWN_batch_create( - GWN_PRIM_TRIS, buffers->vert_buf, - /* can be NULL */ - buffers->index_buf); + if (buffers->triangles == NULL) { + buffers->triangles = GWN_batch_create( + GWN_PRIM_TRIS, buffers->vert_buf, + /* can be NULL */ + buffers->index_buf); + } - GWN_BATCH_DISCARD_SAFE(buffers->triangles_fast); - if (buffers->index_buf_fast) { + if ((buffers->triangles_fast == NULL) && buffers->index_buf_fast) { buffers->triangles_fast = GWN_batch_create( GWN_PRIM_TRIS, buffers->vert_buf, /* can be NULL */ @@ -1085,25 +1107,15 @@ void GPU_pbvh_mesh_buffers_update( rgba_float_to_uchar(diffuse_color_ub, diffuse_color); /* Build VBO */ - GWN_VERTBUF_DISCARD_SAFE(buffers->vert_buf); - - /* match 'VertexBufferFormat' */ - Gwn_VertFormat format = {0}; - VertexBufferAttrID vbo_id; - gpu_pbvh_vert_format_init__gwn(&format, &vbo_id); - - buffers->vert_buf = GWN_vertbuf_create_with_format(&format); - GWN_vertbuf_data_alloc(buffers->vert_buf, totelem); - - if (buffers->vert_buf->data) { + if (gpu_pbvh_vert_buf_data_set(buffers, totelem)) { /* Vertex data is shared if smooth-shaded, but separate * copies are made for flat shading because normals * shouldn't be shared. */ if (buffers->smooth) { for (uint i = 0; i < totvert; ++i) { const MVert *v = &mvert[vert_indices[i]]; - GWN_vertbuf_attr_set(buffers->vert_buf, vbo_id.pos, i, v->co); - GWN_vertbuf_attr_set(buffers->vert_buf, vbo_id.nor, i, v->no); + GWN_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.pos, i, v->co); + GWN_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.nor, i, v->no); } for (uint i = 0; i < buffers->face_indices_len; i++) { @@ -1114,10 +1126,10 @@ void GPU_pbvh_mesh_buffers_update( int v_index = buffers->mloop[lt->tri[j]].v; uchar color_ub[3]; gpu_color_from_mask_copy(vmask[v_index], diffuse_color, color_ub); - GWN_vertbuf_attr_set(buffers->vert_buf, vbo_id.col, vidx, color_ub); + GWN_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.col, vidx, color_ub); } else { - GWN_vertbuf_attr_set(buffers->vert_buf, vbo_id.col, vidx, diffuse_color_ub); + GWN_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.col, vidx, diffuse_color_ub); } } } @@ -1160,9 +1172,9 @@ void GPU_pbvh_mesh_buffers_update( for (uint j = 0; j < 3; j++) { const MVert *v = &mvert[vtri[j]]; - GWN_vertbuf_attr_set(buffers->vert_buf, vbo_id.pos, vbo_index, v->co); - GWN_vertbuf_attr_set(buffers->vert_buf, vbo_id.nor, vbo_index, no); - GWN_vertbuf_attr_set(buffers->vert_buf, vbo_id.col, vbo_index, color_ub); + GWN_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.pos, vbo_index, v->co); + GWN_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.nor, vbo_index, no); + GWN_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.col, vbo_index, color_ub); vbo_index++; } @@ -1171,9 +1183,6 @@ void GPU_pbvh_mesh_buffers_update( gpu_pbvh_batch_init(buffers); } - else { - GWN_VERTBUF_DISCARD_SAFE(buffers->vert_buf); - } } buffers->mvert = mvert; @@ -1293,17 +1302,9 @@ void GPU_pbvh_grid_buffers_update( copy_v4_v4(buffers->diffuse_color, diffuse_color); - Gwn_VertFormat format = {0}; - VertexBufferAttrID vbo_id; - gpu_pbvh_vert_format_init__gwn(&format, &vbo_id); - - /* Build coord/normal VBO */ - GWN_VERTBUF_DISCARD_SAFE(buffers->vert_buf); - buffers->vert_buf = GWN_vertbuf_create_with_format(&format); - GWN_vertbuf_data_alloc(buffers->vert_buf, totgrid * key->grid_area); - uint vbo_index_offset = 0; - if (buffers->vert_buf->data) { + /* Build VBO */ + if (gpu_pbvh_vert_buf_data_set(buffers, totgrid * key->grid_area)) { for (i = 0; i < totgrid; ++i) { CCGElem *grid = grids[grid_indices[i]]; int vbo_index = vbo_index_offset; @@ -1311,12 +1312,12 @@ void GPU_pbvh_grid_buffers_update( for (y = 0; y < key->grid_size; y++) { for (x = 0; x < key->grid_size; x++) { CCGElem *elem = CCG_grid_elem(key, grid, x, y); - GWN_vertbuf_attr_set(buffers->vert_buf, vbo_id.pos, vbo_index, CCG_elem_co(key, elem)); + GWN_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.pos, vbo_index, CCG_elem_co(key, elem)); if (buffers->smooth) { short no_short[3]; normal_float_to_short_v3(no_short, CCG_elem_no(key, elem)); - GWN_vertbuf_attr_set(buffers->vert_buf, vbo_id.nor, vbo_index, no_short); + GWN_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.nor, vbo_index, no_short); if (has_mask) { uchar color_ub[3]; @@ -1327,7 +1328,7 @@ void GPU_pbvh_grid_buffers_update( else { F3TOCHAR3(diffuse_color, color_ub); } - GWN_vertbuf_attr_set(buffers->vert_buf, vbo_id.col, vbo_index, color_ub); + GWN_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.col, vbo_index, color_ub); } } vbo_index += 1; @@ -1354,7 +1355,7 @@ void GPU_pbvh_grid_buffers_update( vbo_index = vbo_index_offset + ((j + 1) * key->grid_size + k); short no_short[3]; normal_float_to_short_v3(no_short, fno); - GWN_vertbuf_attr_set(buffers->vert_buf, vbo_id.nor, vbo_index, no_short); + GWN_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.nor, vbo_index, no_short); if (has_mask) { uchar color_ub[3]; @@ -1370,7 +1371,7 @@ void GPU_pbvh_grid_buffers_update( else { F3TOCHAR3(diffuse_color, color_ub); } - GWN_vertbuf_attr_set(buffers->vert_buf, vbo_id.col, vbo_index, color_ub); + GWN_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.col, vbo_index, color_ub); } } } @@ -1381,9 +1382,6 @@ void GPU_pbvh_grid_buffers_update( gpu_pbvh_batch_init(buffers); } - else { - GWN_VERTBUF_DISCARD_SAFE(buffers->vert_buf); - } } buffers->grids = grids; @@ -1562,7 +1560,6 @@ GPU_PBVH_Buffers *GPU_pbvh_grid_buffers_build( static void gpu_bmesh_vert_to_buffer_copy__gwn( BMVert *v, Gwn_VertBuf *vert_buf, - const VertexBufferAttrID *vbo_id, int *v_index, const float fno[3], const float *fmask, @@ -1573,12 +1570,12 @@ static void gpu_bmesh_vert_to_buffer_copy__gwn( if (!BM_elem_flag_test(v, BM_ELEM_HIDDEN)) { /* Set coord, normal, and mask */ - GWN_vertbuf_attr_set(vert_buf, vbo_id->pos, *v_index, v->co); + GWN_vertbuf_attr_set(vert_buf, g_vbo_id.pos, *v_index, v->co); { short no_short[3]; normal_float_to_short_v3(no_short, fno ? fno : v->no); - GWN_vertbuf_attr_set(vert_buf, vbo_id->nor, *v_index, no_short); + GWN_vertbuf_attr_set(vert_buf, g_vbo_id.nor, *v_index, no_short); } { @@ -1596,7 +1593,7 @@ static void gpu_bmesh_vert_to_buffer_copy__gwn( effective_mask, diffuse_color, color_ub); - GWN_vertbuf_attr_set(vert_buf, vbo_id->col, *v_index, color_ub); + GWN_vertbuf_attr_set(vert_buf, g_vbo_id.col, *v_index, color_ub); } /* Assign index for use in the triangle index buffer */ @@ -1694,18 +1691,8 @@ void GPU_pbvh_bmesh_buffers_update( copy_v4_v4(buffers->diffuse_color, diffuse_color); - /* Initialize vertex buffer */ - GWN_VERTBUF_DISCARD_SAFE(buffers->vert_buf); - /* match 'VertexBufferFormat' */ - Gwn_VertFormat format = {0}; - VertexBufferAttrID vbo_id; - gpu_pbvh_vert_format_init__gwn(&format, &vbo_id); - - buffers->vert_buf = GWN_vertbuf_create_with_format(&format); - GWN_vertbuf_data_alloc(buffers->vert_buf, totvert); - /* Fill vertex buffer */ - if (buffers->vert_buf->data) { + if (gpu_pbvh_vert_buf_data_set(buffers, totvert)) { int v_index = 0; if (buffers->smooth) { @@ -1718,7 +1705,7 @@ void GPU_pbvh_bmesh_buffers_update( GSET_ITER (gs_iter, bm_unique_verts) { gpu_bmesh_vert_to_buffer_copy__gwn( BLI_gsetIterator_getKey(&gs_iter), - buffers->vert_buf, &vbo_id, &v_index, NULL, NULL, + buffers->vert_buf, &v_index, NULL, NULL, cd_vert_mask_offset, diffuse_color, show_mask); } @@ -1726,7 +1713,7 @@ void GPU_pbvh_bmesh_buffers_update( GSET_ITER (gs_iter, bm_other_verts) { gpu_bmesh_vert_to_buffer_copy__gwn( BLI_gsetIterator_getKey(&gs_iter), - buffers->vert_buf, &vbo_id, &v_index, NULL, NULL, + buffers->vert_buf, &v_index, NULL, NULL, cd_vert_mask_offset, diffuse_color, show_mask); } @@ -1759,7 +1746,7 @@ void GPU_pbvh_bmesh_buffers_update( for (i = 0; i < 3; i++) { gpu_bmesh_vert_to_buffer_copy__gwn( - v[i], buffers->vert_buf, &vbo_id, + v[i], buffers->vert_buf, &v_index, f->no, &fmask, cd_vert_mask_offset, diffuse_color, show_mask); @@ -1774,7 +1761,6 @@ void GPU_pbvh_bmesh_buffers_update( bm->elem_index_dirty |= BM_VERT; } else { - GWN_VERTBUF_DISCARD_SAFE(buffers->vert_buf); /* Memory map failed */ return; } @@ -1786,9 +1772,6 @@ void GPU_pbvh_bmesh_buffers_update( GWN_indexbuf_init(&elb, GWN_PRIM_TRIS, tottri, maxvert); /* Initialize triangle index buffer */ - if (buffers->triangles && !buffers->is_index_buf_global) { - GWN_BATCH_DISCARD_SAFE(buffers->triangles); - } buffers->is_index_buf_global = false; /* Fill triangle index buffer */ @@ -1812,7 +1795,12 @@ void GPU_pbvh_bmesh_buffers_update( buffers->tot_tri = tottri; - buffers->index_buf = GWN_indexbuf_build(&elb); + if (buffers->index_buf == NULL) { + buffers->index_buf = GWN_indexbuf_build(&elb); + } + else { + GWN_indexbuf_build_in_place(&elb, buffers->index_buf); + } } } else if (buffers->index_buf) { @@ -1901,7 +1889,7 @@ bool GPU_pbvh_buffers_diffuse_changed(GPU_PBVH_Buffers *buffers, GSet *bm_faces, } else if (buffers->use_bmesh) { /* due to dynamic nature of dyntopo, only get first material */ - if (BLI_gset_size(bm_faces) > 0) { + if (BLI_gset_len(bm_faces) > 0) { GSetIterator gs_iter; BMFace *f; diff --git a/source/blender/gpu/intern/gpu_codegen.c b/source/blender/gpu/intern/gpu_codegen.c index 9e4daa2a036..b245c9a161f 100644 --- a/source/blender/gpu/intern/gpu_codegen.c +++ b/source/blender/gpu/intern/gpu_codegen.c @@ -39,10 +39,14 @@ #include "DNA_node_types.h" #include "BLI_blenlib.h" +#include "BLI_hash_mm2a.h" +#include "BLI_linklist.h" #include "BLI_utildefines.h" #include "BLI_dynstr.h" #include "BLI_ghash.h" +#include "PIL_time.h" + #include "GPU_extensions.h" #include "GPU_glew.h" #include "GPU_material.h" @@ -64,6 +68,50 @@ extern char datatoc_gpu_shader_geometry_glsl[]; static char *glsl_material_library = NULL; +/* -------------------- GPUPass Cache ------------------ */ +/** + * Internal shader cache: This prevent the shader recompilation / stall when + * using undo/redo AND also allows for GPUPass reuse if the Shader code is the + * same for 2 different Materials. Unused GPUPasses are free by Garbage collection. + **/ + +static LinkNode *pass_cache = NULL; /* GPUPass */ + +static uint32_t gpu_pass_hash(const char *vert, const char *geom, const char *frag, const char *defs) +{ + BLI_HashMurmur2A hm2a; + BLI_hash_mm2a_init(&hm2a, 0); + BLI_hash_mm2a_add(&hm2a, (unsigned char *)frag, strlen(frag)); + BLI_hash_mm2a_add(&hm2a, (unsigned char *)vert, strlen(vert)); + if (defs) + BLI_hash_mm2a_add(&hm2a, (unsigned char *)defs, strlen(defs)); + if (geom) + BLI_hash_mm2a_add(&hm2a, (unsigned char *)geom, strlen(geom)); + + return BLI_hash_mm2a_end(&hm2a); +} + +/* Search by hash then by exact string match. */ +static GPUPass *gpu_pass_cache_lookup( + const char *vert, const char *geom, const char *frag, const char *defs, uint32_t hash) +{ + for (LinkNode *ln = pass_cache; ln; ln = ln->next) { + GPUPass *pass = (GPUPass *)ln->link; + if (pass->hash == hash) { + /* Note: Could be made faster if that becomes a real bottleneck. */ + if ((defs != NULL) && (strcmp(pass->defines, defs) != 0)) { /* Pass */ } + else if ((geom != NULL) && (strcmp(pass->geometrycode, geom) != 0)) { /* Pass */ } + else if ((strcmp(pass->fragmentcode, frag) == 0) && + (strcmp(pass->vertexcode, vert) == 0)) + { + return pass; + } + } + } + return NULL; +} + +/* -------------------- GPU Codegen ------------------ */ /* type definitions and constants */ @@ -427,6 +475,8 @@ const char *GPU_builtin_name(GPUBuiltin builtin) return "sampdensity"; else if (builtin == GPU_VOLUME_FLAME) return "sampflame"; + else if (builtin == GPU_VOLUME_TEMPERATURE) + return "unftemperature"; else return ""; } @@ -1173,15 +1223,13 @@ GPUShader *GPU_pass_shader(GPUPass *pass) return pass->shader; } -static void gpu_nodes_extract_dynamic_inputs_new(GPUPass *pass, ListBase *nodes) +static void gpu_nodes_extract_dynamic_inputs_new(GPUShader *shader, ListBase *inputs, ListBase *nodes) { - GPUShader *shader = pass->shader; GPUNode *node; GPUInput *next, *input; - ListBase *inputs = &pass->inputs; int extract, z; - memset(inputs, 0, sizeof(*inputs)); + BLI_listbase_clear(inputs); if (!shader) return; @@ -1234,15 +1282,13 @@ static void gpu_nodes_extract_dynamic_inputs_new(GPUPass *pass, ListBase *nodes) GPU_shader_unbind(); } -static void gpu_nodes_extract_dynamic_inputs(GPUPass *pass, ListBase *nodes) +static void gpu_nodes_extract_dynamic_inputs(GPUShader *shader, ListBase *inputs, ListBase *nodes) { - GPUShader *shader = pass->shader; GPUNode *node; GPUInput *next, *input; - ListBase *inputs = &pass->inputs; int extract, z; - memset(inputs, 0, sizeof(*inputs)); + BLI_listbase_clear(inputs); if (!shader) return; @@ -1320,11 +1366,10 @@ static void gpu_nodes_extract_dynamic_inputs(GPUPass *pass, ListBase *nodes) GPU_shader_unbind(); } -void GPU_pass_bind(GPUPass *pass, double time, int mipmap) +void GPU_pass_bind(GPUPass *pass, ListBase *inputs, double time, int mipmap) { GPUInput *input; GPUShader *shader = pass->shader; - ListBase *inputs = &pass->inputs; if (!shader) return; @@ -1349,11 +1394,10 @@ void GPU_pass_bind(GPUPass *pass, double time, int mipmap) } } -void GPU_pass_update_uniforms(GPUPass *pass) +void GPU_pass_update_uniforms(GPUPass *pass, ListBase *inputs) { GPUInput *input; GPUShader *shader = pass->shader; - ListBase *inputs = &pass->inputs; if (!shader) return; @@ -1374,11 +1418,10 @@ void GPU_pass_update_uniforms(GPUPass *pass) } } -void GPU_pass_unbind(GPUPass *pass) +void GPU_pass_unbind(GPUPass *pass, ListBase *inputs) { GPUInput *input; GPUShader *shader = pass->shader; - ListBase *inputs = &pass->inputs; if (!shader) return; @@ -1677,7 +1720,7 @@ static void gpu_node_output(GPUNode *node, const GPUType type, GPUNodeLink **lin BLI_addtail(&node->outputs, output); } -static void gpu_inputs_free(ListBase *inputs) +void GPU_inputs_free(ListBase *inputs) { GPUInput *input; @@ -1695,7 +1738,7 @@ static void gpu_node_free(GPUNode *node) { GPUOutput *output; - gpu_inputs_free(&node->inputs); + GPU_inputs_free(&node->inputs); for (output = node->outputs.first; output; output = output->next) if (output->link) { @@ -1718,7 +1761,7 @@ static void gpu_nodes_free(ListBase *nodes) /* vertex attributes */ -static void gpu_nodes_get_vertex_attributes(ListBase *nodes, GPUVertexAttribs *attribs) +void GPU_nodes_get_vertex_attributes(ListBase *nodes, GPUVertexAttribs *attribs) { GPUNode *node; GPUInput *input; @@ -1958,16 +2001,20 @@ bool GPU_stack_link(GPUMaterial *material, bNode *bnode, const char *name, GPUNo totout = 0; if (in) { - for (i = 0; in[i].type != GPU_NONE; i++) { - gpu_node_input_socket(material, bnode, node, &in[i], i); - totin++; + for (i = 0; !in[i].end; i++) { + if (in[i].type != GPU_NONE) { + gpu_node_input_socket(material, bnode, node, &in[i], i); + totin++; + } } } if (out) { - for (i = 0; out[i].type != GPU_NONE; i++) { - gpu_node_output(node, out[i].type, &out[i].link); - totout++; + for (i = 0; !out[i].end; i++) { + if (out[i].type != GPU_NONE) { + gpu_node_output(node, out[i].type, &out[i].link); + totout++; + } } } @@ -2046,7 +2093,7 @@ static void gpu_nodes_tag(GPUNodeLink *link) gpu_nodes_tag(input->link); } -static void gpu_nodes_prune(ListBase *nodes, GPUNodeLink *outlink) +void GPU_nodes_prune(ListBase *nodes, GPUNodeLink *outlink) { GPUNode *node, *next; @@ -2066,79 +2113,83 @@ static void gpu_nodes_prune(ListBase *nodes, GPUNodeLink *outlink) } GPUPass *GPU_generate_pass_new( - struct GPUMaterial *material, - ListBase *nodes, struct GPUNodeLink *frag_outlink, - GPUVertexAttribs *attribs, + GPUMaterial *material, + GPUNodeLink *frag_outlink, struct GPUVertexAttribs *attribs, + ListBase *nodes, ListBase *inputs, const char *vert_code, const char *geom_code, const char *frag_lib, const char *defines) { + char *vertexcode, *geometrycode, *fragmentcode; GPUShader *shader; GPUPass *pass; - char *vertexgen, *fragmentgen, *tmp; - char *vertexcode, *geometrycode, *fragmentcode; /* prune unused nodes */ - gpu_nodes_prune(nodes, frag_outlink); + GPU_nodes_prune(nodes, frag_outlink); - gpu_nodes_get_vertex_attributes(nodes, attribs); + GPU_nodes_get_vertex_attributes(nodes, attribs); - /* generate code and compile with opengl */ - fragmentgen = code_generate_fragment(material, nodes, frag_outlink->output, true); - vertexgen = code_generate_vertex_new(nodes, vert_code, (geom_code != NULL)); + /* generate code */ + char *fragmentgen = code_generate_fragment(material, nodes, frag_outlink->output, true); + char *tmp = BLI_strdupcat(frag_lib, glsl_material_library); - tmp = BLI_strdupcat(frag_lib, glsl_material_library); + vertexcode = code_generate_vertex_new(nodes, vert_code, (geom_code != NULL)); + geometrycode = (geom_code) ? code_generate_geometry_new(nodes, geom_code) : NULL; fragmentcode = BLI_strdupcat(tmp, fragmentgen); - vertexcode = BLI_strdup(vertexgen); - - if (geom_code) { - geometrycode = code_generate_geometry_new(nodes, geom_code); - } - else { - geometrycode = NULL; - } - - shader = GPU_shader_create(vertexcode, - fragmentcode, - geometrycode, - NULL, - defines); + MEM_freeN(fragmentgen); MEM_freeN(tmp); - /* failed? */ + /* Cache lookup: Reuse shaders already compiled */ + uint32_t hash = gpu_pass_hash(vertexcode, geometrycode, fragmentcode, defines); + pass = gpu_pass_cache_lookup(vertexcode, geometrycode, fragmentcode, defines, hash); + if (pass) { + /* Cache hit. Reuse the same GPUPass and GPUShader. */ + shader = pass->shader; + pass->refcount += 1; + + MEM_SAFE_FREE(vertexcode); + MEM_SAFE_FREE(fragmentcode); + MEM_SAFE_FREE(geometrycode); + } + else { + /* Cache miss. (Re)compile the shader. */ + shader = GPU_shader_create(vertexcode, + fragmentcode, + geometrycode, + NULL, + defines); + + /* We still create a pass even if shader compilation + * fails to avoid trying to compile again and again. */ + pass = MEM_callocN(sizeof(GPUPass), "GPUPass"); + pass->shader = shader; + pass->refcount = 1; + pass->hash = hash; + pass->vertexcode = vertexcode; + pass->fragmentcode = fragmentcode; + pass->geometrycode = geometrycode; + pass->libcode = glsl_material_library; + pass->defines = (defines) ? BLI_strdup(defines) : NULL; + + BLI_linklist_prepend(&pass_cache, pass); + } + + /* did compilation failed ? */ if (!shader) { - if (fragmentcode) - MEM_freeN(fragmentcode); - if (vertexcode) - MEM_freeN(vertexcode); - if (geometrycode) - MEM_freeN(geometrycode); - MEM_freeN(fragmentgen); - MEM_freeN(vertexgen); gpu_nodes_free(nodes); + /* Pass will not be used. Don't increment refcount. */ + pass->refcount--; return NULL; } - - /* create pass */ - pass = MEM_callocN(sizeof(GPUPass), "GPUPass"); - pass->shader = shader; - pass->fragmentcode = fragmentcode; - pass->geometrycode = geometrycode; - pass->vertexcode = vertexcode; - pass->libcode = glsl_material_library; - - /* extract dynamic inputs and throw away nodes */ - gpu_nodes_extract_dynamic_inputs_new(pass, nodes); - gpu_nodes_free(nodes); - - MEM_freeN(fragmentgen); - MEM_freeN(vertexgen); - - return pass; + else { + gpu_nodes_extract_dynamic_inputs_new(shader, inputs, nodes); + return pass; + } } +/* TODO(fclem) Remove for 2.8 */ GPUPass *GPU_generate_pass( - ListBase *nodes, GPUNodeLink *outlink, + ListBase *nodes, ListBase *inputs, GPUNodeLink *outlink, GPUVertexAttribs *attribs, int *builtins, const GPUMatType type, const char *UNUSED(name), const bool use_opensubdiv, @@ -2156,9 +2207,9 @@ GPUPass *GPU_generate_pass( #endif /* prune unused nodes */ - gpu_nodes_prune(nodes, outlink); + GPU_nodes_prune(nodes, outlink); - gpu_nodes_get_vertex_attributes(nodes, attribs); + GPU_nodes_get_vertex_attributes(nodes, attribs); gpu_nodes_get_builtin_flag(nodes, builtins); /* generate code and compile with opengl */ @@ -2194,30 +2245,38 @@ GPUPass *GPU_generate_pass( /* create pass */ pass = MEM_callocN(sizeof(GPUPass), "GPUPass"); - + pass->refcount = 1; pass->shader = shader; pass->fragmentcode = fragmentcode; pass->geometrycode = geometrycode; pass->vertexcode = vertexcode; pass->libcode = glsl_material_library; + BLI_linklist_prepend(&pass_cache, pass); + /* extract dynamic inputs and throw away nodes */ - gpu_nodes_extract_dynamic_inputs(pass, nodes); + gpu_nodes_extract_dynamic_inputs(shader, inputs, nodes); gpu_nodes_free(nodes); return pass; } -void GPU_pass_free(GPUPass *pass) +void GPU_pass_release(GPUPass *pass) +{ + BLI_assert(pass->refcount > 0); + pass->refcount--; +} + +static void gpu_pass_free(GPUPass *pass) { - GPU_shader_free(pass->shader); - gpu_inputs_free(&pass->inputs); - if (pass->fragmentcode) - MEM_freeN(pass->fragmentcode); - if (pass->geometrycode) - MEM_freeN(pass->geometrycode); - if (pass->vertexcode) - MEM_freeN(pass->vertexcode); + BLI_assert(pass->refcount == 0); + if (pass->shader) { + GPU_shader_free(pass->shader); + } + MEM_SAFE_FREE(pass->fragmentcode); + MEM_SAFE_FREE(pass->geometrycode); + MEM_SAFE_FREE(pass->vertexcode); + MEM_SAFE_FREE(pass->defines); MEM_freeN(pass); } @@ -2226,3 +2285,34 @@ void GPU_pass_free_nodes(ListBase *nodes) gpu_nodes_free(nodes); } +void GPU_pass_cache_garbage_collect(void) +{ + static int lasttime = 0; + const int shadercollectrate = 60; /* hardcoded for now. */ + int ctime = (int)PIL_check_seconds_timer(); + + if (ctime < shadercollectrate + lasttime) + return; + + lasttime = ctime; + + LinkNode *next, **prev_ln = &pass_cache; + for (LinkNode *ln = pass_cache; ln; ln = next) { + GPUPass *pass = (GPUPass *)ln->link; + next = ln->next; + if (pass->refcount == 0) { + gpu_pass_free(pass); + /* Remove from list */ + MEM_freeN(ln); + *prev_ln = next; + } + else { + prev_ln = &ln->next; + } + } +} + +void GPU_pass_cache_free(void) +{ + BLI_linklist_free(pass_cache, (LinkNodeFreeFP)gpu_pass_free); +} diff --git a/source/blender/gpu/intern/gpu_codegen.h b/source/blender/gpu/intern/gpu_codegen.h index 14e07a6e012..dab0bc3f8b1 100644 --- a/source/blender/gpu/intern/gpu_codegen.h +++ b/source/blender/gpu/intern/gpu_codegen.h @@ -157,25 +157,27 @@ typedef struct GPUInput { } GPUInput; struct GPUPass { - ListBase inputs; struct GPUShader *shader; char *fragmentcode; char *geometrycode; char *vertexcode; + char *defines; const char *libcode; + unsigned int refcount; /* Orphaned GPUPasses gets freed by the garbage collector. */ + uint32_t hash; /* Identity hash generated from all GLSL code. */ }; typedef struct GPUPass GPUPass; GPUPass *GPU_generate_pass_new( - struct GPUMaterial *material, - ListBase *nodes, struct GPUNodeLink *frag_outlink, - struct GPUVertexAttribs *attribs, + GPUMaterial *material, + GPUNodeLink *frag_outlink, struct GPUVertexAttribs *attribs, + ListBase *nodes, ListBase *inputs, const char *vert_code, const char *geom_code, const char *frag_lib, const char *defines); GPUPass *GPU_generate_pass( - ListBase *nodes, struct GPUNodeLink *outlink, + ListBase *nodes, ListBase *inputs, struct GPUNodeLink *outlink, struct GPUVertexAttribs *attribs, int *builtin, const GPUMatType type, const char *name, const bool use_opensubdiv, @@ -183,13 +185,18 @@ GPUPass *GPU_generate_pass( struct GPUShader *GPU_pass_shader(GPUPass *pass); -void GPU_pass_bind(GPUPass *pass, double time, int mipmap); -void GPU_pass_update_uniforms(GPUPass *pass); -void GPU_pass_unbind(GPUPass *pass); +void GPU_nodes_get_vertex_attributes(ListBase *nodes, struct GPUVertexAttribs *attribs); +void GPU_nodes_prune(ListBase *nodes, struct GPUNodeLink *outlink); + +void GPU_pass_bind(GPUPass *pass, ListBase *inputs, double time, int mipmap); +void GPU_pass_update_uniforms(GPUPass *pass, ListBase *inputs); +void GPU_pass_unbind(GPUPass *pass, ListBase *inputs); -void GPU_pass_free(GPUPass *pass); +void GPU_pass_release(GPUPass *pass); void GPU_pass_free_nodes(ListBase *nodes); +void GPU_inputs_free(ListBase *inputs); + void gpu_codegen_init(void); void gpu_codegen_exit(void); diff --git a/source/blender/gpu/intern/gpu_compositing.c b/source/blender/gpu/intern/gpu_compositing.c deleted file mode 100644 index 3de363cc76e..00000000000 --- a/source/blender/gpu/intern/gpu_compositing.c +++ /dev/null @@ -1,1494 +0,0 @@ -/* - * ***** BEGIN GPL LICENSE BLOCK ***** - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2006 Blender Foundation. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): Antony Riakiotakis. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file blender/gpu/intern/gpu_compositing.c - * \ingroup gpu - * - * System that manages framebuffer compositing. - */ - -#include "BLI_sys_types.h" -#include "BLI_rect.h" -#include "BLI_math.h" - -#include "BLI_rand.h" - -#include "DNA_vec_types.h" -#include "DNA_scene_types.h" -#include "DNA_gpu_types.h" - -#include "GPU_compositing.h" -#include "GPU_draw.h" -#include "GPU_extensions.h" -#include "GPU_framebuffer.h" -#include "GPU_glew.h" -#include "GPU_shader.h" -#include "GPU_texture.h" -#include "GPU_batch.h" - -#include "MEM_guardedalloc.h" - -static const float fullscreencos[4][2] = {{-1.0f, -1.0f}, {1.0f, -1.0f}, {-1.0f, 1.0f}, {1.0f, 1.0f}}; -static const float fullscreenuvs[4][2] = {{0.0f, 0.0f}, {1.0f, 0.0f}, {0.0f, 1.0f}, {1.0f, 1.0f}}; - - -/* shader interfaces (legacy GL 2 style, without uniform buffer objects) */ - -typedef struct { - int ssao_uniform; - int ssao_color_uniform; - int color_uniform; - int depth_uniform; - int viewvecs_uniform; - int ssao_sample_params_uniform; - int ssao_concentric_tex; - int ssao_jitter_uniform; -} GPUSSAOShaderInterface; - -typedef struct { - int invrendertargetdim_uniform; - int color_uniform; - int dof_uniform; - int depth_uniform; - int viewvecs_uniform; -} GPUDOFHQPassOneInterface; - -typedef struct { - int rendertargetdim_uniform; - int color_uniform; - int coc_uniform; - int select_uniform; - int dof_uniform; -} GPUDOFHQPassTwoInterface; - -typedef struct { - int dof_uniform; - int invrendertargetdim_uniform; - int color_uniform; - int far_uniform; - int near_uniform; - int viewvecs_uniform; - int depth_uniform; -} GPUDOFHQPassThreeInterface; - -typedef struct { - int dof_uniform; - int invrendertargetdim_uniform; - int color_uniform; - int depth_uniform; - int viewvecs_uniform; -} GPUDOFPassOneInterface; - -typedef struct { - int dof_uniform; - int invrendertargetdim_uniform; - int color_uniform; - int depth_uniform; - int viewvecs_uniform; -} GPUDOFPassTwoInterface; - -typedef struct { - int near_coc_downsampled; - int near_coc_blurred; -} GPUDOFPassThreeInterface; - -typedef struct { - int near_coc_downsampled; - int invrendertargetdim_uniform; -} GPUDOFPassFourInterface; - -typedef struct { - int medium_blurred_uniform; - int high_blurred_uniform; - int dof_uniform; - int invrendertargetdim_uniform; - int original_uniform; - int depth_uniform; - int viewvecs_uniform; -} GPUDOFPassFiveInterface; - -typedef struct { - int depth_uniform; -} GPUDepthResolveInterface; - - -struct GPUFX { - /* we borrow the term gbuffer from deferred rendering however this is just a regular - * depth/color framebuffer. Could be extended later though */ - GPUFrameBuffer *gbuffer; - - /* dimensions of the gbuffer */ - int gbuffer_dim[2]; - - /* texture bound to the first color attachment of the gbuffer */ - GPUTexture *color_buffer; - - /* second texture used for ping-pong compositing */ - GPUTexture *color_buffer_sec; - /* texture bound to the depth attachment of the gbuffer */ - GPUTexture *depth_buffer; - GPUTexture *depth_buffer_xray; - - /* texture used for jittering for various effects */ - GPUTexture *jitter_buffer; - - /* all those buffers below have to coexist. - * Fortunately they are all quarter sized (1/16th of memory) of original framebuffer */ - int dof_downsampled_w; - int dof_downsampled_h; - - /* texture used for near coc and color blurring calculation */ - GPUTexture *dof_near_coc_buffer; - /* blurred near coc buffer. */ - GPUTexture *dof_near_coc_blurred_buffer; - /* final near coc buffer. */ - GPUTexture *dof_near_coc_final_buffer; - - /* half size blur buffer */ - GPUTexture *dof_half_downsampled_near; - GPUTexture *dof_half_downsampled_far; - /* high quality dof texture downsamplers. 6 levels means 64 pixels wide - should be enough */ - GPUTexture *dof_nearfar_coc; - GPUTexture *dof_near_blur; - GPUTexture *dof_far_blur; - - /* for high quality we use again a spiral texture with radius adapted */ - bool dof_high_quality; - - /* texture used for ssao */ - int ssao_sample_count_cache; - GPUTexture *ssao_spiral_samples_tex; - - - GPUFXSettings settings; - - /* or-ed flags of enabled effects */ - int effects; - - /* number of passes, needed to detect if ping pong buffer allocation is needed */ - int num_passes; - - /* we have a stencil, restore the previous state */ - bool restore_stencil; - - Gwn_Batch *quad_batch; - Gwn_Batch *point_batch; -}; - -#if 0 -/* concentric mapping, see "A Low Distortion Map Between Disk and Square" and - * http://psgraphics.blogspot.nl/2011/01/improved-code-for-concentric-map.html */ -static GPUTexture * create_concentric_sample_texture(int side) -{ - GPUTexture *tex; - float midpoint = 0.5f * (side - 1); - float *texels = (float *)MEM_mallocN(sizeof(float) * 2 * side * side, "concentric_tex"); - int i, j; - - for (i = 0; i < side; i++) { - for (j = 0; j < side; j++) { - int index = (i * side + j) * 2; - float a = 1.0f - i / midpoint; - float b = 1.0f - j / midpoint; - float phi, r; - if (a * a > b * b) { - r = a; - phi = (M_PI_4) * (b / a); - } - else { - r = b; - phi = M_PI_2 - (M_PI_4) * (a / b); - } - texels[index] = r * cos(phi); - texels[index + 1] = r * sin(phi); - } - } - - tex = GPU_texture_create_1D_custom(side * side, 2, GPU_RG16F, (float *)texels, NULL); - - /* Set parameters */ - GPU_texture_bind(tex, 0); - GPU_texture_filter_mode(tex, false); - GPU_texture_unbind(tex); - - MEM_freeN(texels); - return tex; -} -#endif - -static GPUTexture *create_spiral_sample_texture(int numsaples) -{ - GPUTexture *tex; - float (*texels)[2] = MEM_mallocN(sizeof(float[2]) * numsaples, "concentric_tex"); - const float numsaples_inv = 1.0f / numsaples; - int i; - /* arbitrary number to ensure we don't get conciding samples every circle */ - const float spirals = 7.357; - - for (i = 0; i < numsaples; i++) { - float r = (i + 0.5f) * numsaples_inv; - float phi = r * spirals * (float)(2.0 * M_PI); - texels[i][0] = r * cosf(phi); - texels[i][1] = r * sinf(phi); - } - - tex = GPU_texture_create_1D_custom(numsaples, 2, GPU_RG16F, (float *)texels, NULL); - - /* Set parameters */ - GPU_texture_bind(tex, 0); - GPU_texture_filter_mode(tex, false); - GPU_texture_unbind(tex); - - MEM_freeN(texels); - return tex; -} - -/* generate a new FX compositor */ -GPUFX *GPU_fx_compositor_create(void) -{ - GPUFX *fx = MEM_callocN(sizeof(GPUFX), "GPUFX compositor"); - - /* Quad buffer */ - static Gwn_VertFormat format = {0}; - static unsigned int pos, uvs; - if (format.attrib_ct == 0) { - pos = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT); - uvs = GWN_vertformat_attr_add(&format, "uvs", GWN_COMP_F32, 2, GWN_FETCH_FLOAT); - } - Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&format); - GWN_vertbuf_data_alloc(vbo, 4); - for (int i = 0; i < 4; ++i) { - GWN_vertbuf_attr_set(vbo, pos, i, fullscreencos[i]); - GWN_vertbuf_attr_set(vbo, uvs, i, fullscreenuvs[i]); - } - fx->quad_batch = GWN_batch_create_ex(GWN_PRIM_TRI_STRIP, vbo, NULL, GWN_BATCH_OWNS_VBO); - - /* Point Buffer */ - static Gwn_VertFormat format_point = {0}; - static unsigned int dummy_attrib; - if (format_point.attrib_ct == 0) { - dummy_attrib = GWN_vertformat_attr_add(&format_point, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT); - } - float dummy[2] = {0.0f, 0.0f}; - Gwn_VertBuf *vbo_point = GWN_vertbuf_create_with_format(&format_point); - GWN_vertbuf_data_alloc(vbo_point, 1); - GWN_vertbuf_attr_set(vbo_point, dummy_attrib, 0, &dummy); - fx->point_batch = GWN_batch_create_ex(GWN_PRIM_POINTS, vbo_point, NULL, GWN_BATCH_OWNS_VBO); - - return fx; -} - -static void cleanup_fx_dof_buffers(GPUFX *fx) -{ - if (fx->dof_near_coc_blurred_buffer) { - GPU_texture_free(fx->dof_near_coc_blurred_buffer); - fx->dof_near_coc_blurred_buffer = NULL; - } - if (fx->dof_near_coc_buffer) { - GPU_texture_free(fx->dof_near_coc_buffer); - fx->dof_near_coc_buffer = NULL; - } - if (fx->dof_near_coc_final_buffer) { - GPU_texture_free(fx->dof_near_coc_final_buffer); - fx->dof_near_coc_final_buffer = NULL; - } - - if (fx->dof_half_downsampled_near) { - GPU_texture_free(fx->dof_half_downsampled_near); - fx->dof_half_downsampled_near = NULL; - } - if (fx->dof_half_downsampled_far) { - GPU_texture_free(fx->dof_half_downsampled_far); - fx->dof_half_downsampled_far = NULL; - } - if (fx->dof_nearfar_coc) { - GPU_texture_free(fx->dof_nearfar_coc); - fx->dof_nearfar_coc = NULL; - } - if (fx->dof_near_blur) { - GPU_texture_free(fx->dof_near_blur); - fx->dof_near_blur = NULL; - } - if (fx->dof_far_blur) { - GPU_texture_free(fx->dof_far_blur); - fx->dof_far_blur = NULL; - } -} - -static void cleanup_fx_gl_data(GPUFX *fx, bool do_fbo) -{ - if (fx->color_buffer) { - GPU_framebuffer_texture_detach(fx->color_buffer); - GPU_texture_free(fx->color_buffer); - fx->color_buffer = NULL; - } - - if (fx->color_buffer_sec) { - GPU_framebuffer_texture_detach(fx->color_buffer_sec); - GPU_texture_free(fx->color_buffer_sec); - fx->color_buffer_sec = NULL; - } - - if (fx->depth_buffer) { - GPU_framebuffer_texture_detach(fx->depth_buffer); - GPU_texture_free(fx->depth_buffer); - fx->depth_buffer = NULL; - } - - if (fx->depth_buffer_xray) { - GPU_framebuffer_texture_detach(fx->depth_buffer_xray); - GPU_texture_free(fx->depth_buffer_xray); - fx->depth_buffer_xray = NULL; - } - - cleanup_fx_dof_buffers(fx); - - if (fx->ssao_spiral_samples_tex) { - GPU_texture_free(fx->ssao_spiral_samples_tex); - fx->ssao_spiral_samples_tex = NULL; - } - - if (fx->jitter_buffer && do_fbo) { - GPU_texture_free(fx->jitter_buffer); - fx->jitter_buffer = NULL; - } - - if (fx->gbuffer && do_fbo) { - GPU_framebuffer_free(fx->gbuffer); - fx->gbuffer = NULL; - } -} - -/* destroy a text compositor */ -void GPU_fx_compositor_destroy(GPUFX *fx) -{ - cleanup_fx_gl_data(fx, true); - GWN_batch_discard(fx->quad_batch); - GWN_batch_discard(fx->point_batch); - MEM_freeN(fx); -} - -static GPUTexture * create_jitter_texture(void) -{ - GPUTexture *tex; - float jitter[64 * 64][2]; - int i; - - for (i = 0; i < 64 * 64; i++) { - jitter[i][0] = 2.0f * BLI_frand() - 1.0f; - jitter[i][1] = 2.0f * BLI_frand() - 1.0f; - normalize_v2(jitter[i]); - } - - tex = GPU_texture_create_2D_custom(64, 64, 2, GPU_RG16F, &jitter[0][0], NULL); - - /* Set parameters */ - GPU_texture_bind(tex, 0); - GPU_texture_filter_mode(tex, false); - GPU_texture_wrap_mode(tex, true); - GPU_texture_unbind(tex); - - return tex; -} - - -bool GPU_fx_compositor_initialize_passes( - GPUFX *fx, const rcti *rect, const rcti *scissor_rect, - const GPUFXSettings *fx_settings) -{ - int w = BLI_rcti_size_x(rect), h = BLI_rcti_size_y(rect); - char err_out[256]; - int num_passes = 0; - char fx_flag; - - fx->effects = 0; - - if (!fx_settings) { - cleanup_fx_gl_data(fx, true); - return false; - } - - fx_flag = fx_settings->fx_flag; - - /* disable effects if no options passed for them */ - if (!fx_settings->dof) { - fx_flag &= ~GPU_FX_FLAG_DOF; - } - if (!fx_settings->ssao || fx_settings->ssao->samples < 1) { - fx_flag &= ~GPU_FX_FLAG_SSAO; - } - - if (!fx_flag) { - cleanup_fx_gl_data(fx, true); - return false; - } - - /* scissor is missing when drawing offscreen, in that case, dimensions match exactly. In opposite case - * add one to match viewport dimensions */ - if (scissor_rect) { - w++; - h++; - } - - fx->num_passes = 0; - /* dof really needs a ping-pong buffer to work */ - if (fx_flag & GPU_FX_FLAG_DOF) - num_passes++; - - if (fx_flag & GPU_FX_FLAG_SSAO) - num_passes++; - - if (!fx->gbuffer) { - fx->gbuffer = GPU_framebuffer_create(); - - if (!fx->gbuffer) { - return false; - } - } - - /* try creating the jitter texture */ - if (!fx->jitter_buffer) - fx->jitter_buffer = create_jitter_texture(); - - /* check if color buffers need recreation */ - if (!fx->color_buffer || !fx->depth_buffer || w != fx->gbuffer_dim[0] || h != fx->gbuffer_dim[1]) { - cleanup_fx_gl_data(fx, false); - - if (!(fx->color_buffer = GPU_texture_create_2D(w, h, NULL, err_out))) { - printf(".256%s\n", err_out); - cleanup_fx_gl_data(fx, true); - return false; - } - - if (!(fx->depth_buffer = GPU_texture_create_depth(w, h, err_out))) { - printf("%.256s\n", err_out); - cleanup_fx_gl_data(fx, true); - return false; - } - } - - if (fx_flag & GPU_FX_FLAG_SSAO) { - if (fx_settings->ssao->samples != fx->ssao_sample_count_cache || !fx->ssao_spiral_samples_tex) { - if (fx_settings->ssao->samples < 1) - fx_settings->ssao->samples = 1; - - fx->ssao_sample_count_cache = fx_settings->ssao->samples; - - if (fx->ssao_spiral_samples_tex) { - GPU_texture_free(fx->ssao_spiral_samples_tex); - } - - fx->ssao_spiral_samples_tex = create_spiral_sample_texture(fx_settings->ssao->samples); - } - } - else { - if (fx->ssao_spiral_samples_tex) { - GPU_texture_free(fx->ssao_spiral_samples_tex); - fx->ssao_spiral_samples_tex = NULL; - } - } - - /* create textures for dof effect */ - if (fx_flag & GPU_FX_FLAG_DOF) { - bool dof_high_quality = (fx_settings->dof->high_quality != 0); - - /* cleanup buffers if quality setting has changed (no need to keep more buffers around than necessary ) */ - if (dof_high_quality != fx->dof_high_quality) - cleanup_fx_dof_buffers(fx); - - if (dof_high_quality) { - fx->dof_downsampled_w = w / 2; - fx->dof_downsampled_h = h / 2; - - if (!fx->dof_half_downsampled_near || !fx->dof_nearfar_coc || !fx->dof_near_blur || - !fx->dof_far_blur || !fx->dof_half_downsampled_far) - { - - if (!(fx->dof_half_downsampled_near = GPU_texture_create_2D( - fx->dof_downsampled_w, fx->dof_downsampled_h, NULL, err_out))) - { - printf("%.256s\n", err_out); - cleanup_fx_gl_data(fx, true); - return false; - } - if (!(fx->dof_half_downsampled_far = GPU_texture_create_2D( - fx->dof_downsampled_w, fx->dof_downsampled_h, NULL, err_out))) - { - printf("%.256s\n", err_out); - cleanup_fx_gl_data(fx, true); - return false; - } - - if (!(fx->dof_nearfar_coc = GPU_texture_create_2D_custom( - fx->dof_downsampled_w, fx->dof_downsampled_h, 2, GPU_RG16F, NULL, err_out))) - { - printf("%.256s\n", err_out); - cleanup_fx_gl_data(fx, true); - return false; - } - GPU_texture_bind(fx->dof_nearfar_coc, 0); - GPU_texture_filter_mode(fx->dof_nearfar_coc, false); - GPU_texture_wrap_mode(fx->dof_nearfar_coc, false); - GPU_texture_unbind(fx->dof_nearfar_coc); - - if (!(fx->dof_near_blur = GPU_texture_create_2D_custom( - fx->dof_downsampled_w, fx->dof_downsampled_h, 4, GPU_RGBA16F, NULL, err_out))) - { - printf("%.256s\n", err_out); - cleanup_fx_gl_data(fx, true); - return false; - } - - if (!(fx->dof_far_blur = GPU_texture_create_2D_custom( - fx->dof_downsampled_w, fx->dof_downsampled_h, 4, GPU_RGBA16F, NULL, err_out))) - { - printf("%.256s\n", err_out); - cleanup_fx_gl_data(fx, true); - return false; - } - } - } - else { - fx->dof_downsampled_w = w / 4; - fx->dof_downsampled_h = h / 4; - - if (!fx->dof_near_coc_buffer || !fx->dof_near_coc_blurred_buffer || !fx->dof_near_coc_final_buffer) { - - if (!(fx->dof_near_coc_buffer = GPU_texture_create_2D( - fx->dof_downsampled_w, fx->dof_downsampled_h, NULL, err_out))) - { - printf("%.256s\n", err_out); - cleanup_fx_gl_data(fx, true); - return false; - } - if (!(fx->dof_near_coc_blurred_buffer = GPU_texture_create_2D( - fx->dof_downsampled_w, fx->dof_downsampled_h, NULL, err_out))) - { - printf("%.256s\n", err_out); - cleanup_fx_gl_data(fx, true); - return false; - } - if (!(fx->dof_near_coc_final_buffer = GPU_texture_create_2D( - fx->dof_downsampled_w, fx->dof_downsampled_h, NULL, err_out))) - { - printf("%.256s\n", err_out); - cleanup_fx_gl_data(fx, true); - return false; - } - } - } - - fx->dof_high_quality = dof_high_quality; - } - else { - /* cleanup unnecessary buffers */ - cleanup_fx_dof_buffers(fx); - } - - /* we need to pass data between shader stages, allocate an extra color buffer */ - if (num_passes > 1) { - if (!fx->color_buffer_sec) { - if (!(fx->color_buffer_sec = GPU_texture_create_2D(w, h, NULL, err_out))) { - printf(".256%s\n", err_out); - cleanup_fx_gl_data(fx, true); - return false; - } - } - } - else { - if (fx->color_buffer_sec) { - GPU_framebuffer_texture_detach(fx->color_buffer_sec); - GPU_texture_free(fx->color_buffer_sec); - fx->color_buffer_sec = NULL; - } - } - - /* bind the buffers */ - - /* first depth buffer, because system assumes read/write buffers */ - GPU_framebuffer_texture_attach(fx->gbuffer, fx->depth_buffer, 0, 0); - GPU_framebuffer_texture_attach(fx->gbuffer, fx->color_buffer, 0, 0); - - if (!GPU_framebuffer_check_valid(fx->gbuffer, err_out)) - printf("%.256s\n", err_out); - - GPU_texture_bind_as_framebuffer(fx->color_buffer); - - /* enable scissor test. It's needed to ensure sculpting works correctly */ - if (scissor_rect) { - int w_sc = BLI_rcti_size_x(scissor_rect) + 1; - int h_sc = BLI_rcti_size_y(scissor_rect) + 1; - gpuPushAttrib(GPU_SCISSOR_BIT); - glEnable(GL_SCISSOR_TEST); - glScissor(scissor_rect->xmin - rect->xmin, scissor_rect->ymin - rect->ymin, - w_sc, h_sc); - fx->restore_stencil = true; - } - else { - fx->restore_stencil = false; - } - - fx->effects = fx_flag; - - if (fx_settings) - fx->settings = *fx_settings; - fx->gbuffer_dim[0] = w; - fx->gbuffer_dim[1] = h; - - fx->num_passes = num_passes; - - return true; -} - -static void gpu_fx_bind_render_target(int *passes_left, GPUFX *fx, struct GPUOffScreen *ofs, GPUTexture *target) -{ - if ((*passes_left)-- == 1) { - GPU_framebuffer_texture_unbind(fx->gbuffer, NULL); - if (ofs) { - GPU_offscreen_bind(ofs, false); - } - else - GPU_framebuffer_restore(); - } - else { - /* bind the ping buffer to the color buffer */ - GPU_framebuffer_texture_attach(fx->gbuffer, target, 0, 0); - } -} - -void GPU_fx_compositor_setup_XRay_pass(GPUFX *fx, bool do_xray) -{ - char err_out[256]; - - if (do_xray) { - if (!fx->depth_buffer_xray && - !(fx->depth_buffer_xray = GPU_texture_create_depth(fx->gbuffer_dim[0], fx->gbuffer_dim[1], err_out))) - { - printf("%.256s\n", err_out); - cleanup_fx_gl_data(fx, true); - return; - } - } - else { - if (fx->depth_buffer_xray) { - GPU_framebuffer_texture_detach(fx->depth_buffer_xray); - GPU_texture_free(fx->depth_buffer_xray); - fx->depth_buffer_xray = NULL; - } - return; - } - - GPU_framebuffer_texture_detach(fx->depth_buffer); - - /* first depth buffer, because system assumes read/write buffers */ - GPU_framebuffer_texture_attach(fx->gbuffer, fx->depth_buffer_xray, 0, 0); -} - - -void GPU_fx_compositor_XRay_resolve(GPUFX *fx) -{ - GPUShader *depth_resolve_shader; - GPU_framebuffer_texture_detach(fx->depth_buffer_xray); - - /* attach regular framebuffer */ - GPU_framebuffer_texture_attach(fx->gbuffer, fx->depth_buffer, 0, 0); - - /* full screen quad where we will always write to depth buffer */ - gpuPushAttrib(GPU_DEPTH_BUFFER_BIT | GPU_SCISSOR_BIT); - glDepthFunc(GL_ALWAYS); - /* disable scissor from sculpt if any */ - glDisable(GL_SCISSOR_TEST); - /* disable writing to color buffer, it's depth only pass */ - glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); - - depth_resolve_shader = GPU_shader_get_builtin_fx_shader(GPU_SHADER_FX_DEPTH_RESOLVE, false); - - if (depth_resolve_shader) { - GPUDepthResolveInterface *interface = GPU_fx_shader_get_interface(depth_resolve_shader); - - /* set up quad buffer */ - GWN_batch_program_set(fx->quad_batch, GPU_shader_get_program(depth_resolve_shader), GPU_shader_get_interface(depth_resolve_shader)); - - GPU_texture_bind(fx->depth_buffer_xray, 0); - GPU_texture_compare_mode(fx->depth_buffer_xray, false); - GPU_texture_filter_mode(fx->depth_buffer_xray, true); - GPU_shader_uniform_texture(depth_resolve_shader, interface->depth_uniform, fx->depth_buffer_xray); - - /* draw */ - GWN_batch_draw(fx->quad_batch); - - /* disable bindings */ - GPU_texture_compare_mode(fx->depth_buffer_xray, true); - GPU_texture_filter_mode(fx->depth_buffer_xray, false); - GPU_texture_unbind(fx->depth_buffer_xray); - - GPU_shader_unbind(); - } - - glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); - - gpuPopAttrib(); -} - - -bool GPU_fx_do_composite_pass( - GPUFX *fx, float projmat[4][4], bool is_persp, - struct Scene *scene, struct GPUOffScreen *ofs) -{ - GPUTexture *src, *target; - int numslots = 0; - float invproj[4][4]; - int i; - float dfdyfac[2]; - /* number of passes left. when there are no more passes, the result is passed to the frambuffer */ - int passes_left = fx->num_passes; - /* view vectors for the corners of the view frustum. Can be used to recreate the world space position easily */ - float viewvecs[3][4] = { - {-1.0f, -1.0f, -1.0f, 1.0f}, - {1.0f, -1.0f, -1.0f, 1.0f}, - {-1.0f, 1.0f, -1.0f, 1.0f} - }; - - if (fx->effects == 0) - return false; - - GPU_get_dfdy_factors(dfdyfac); - /* first, unbind the render-to-texture framebuffer */ - GPU_framebuffer_texture_detach(fx->color_buffer); - GPU_framebuffer_texture_detach(fx->depth_buffer); - - if (fx->restore_stencil) { - gpuPopAttrib(); - } - - src = fx->color_buffer; - target = fx->color_buffer_sec; - - /* full screen FX pass */ - - /* invert the view matrix */ - invert_m4_m4(invproj, projmat); - - /* convert the view vectors to view space */ - for (i = 0; i < 3; i++) { - mul_m4_v4(invproj, viewvecs[i]); - /* normalized trick see http://www.derschmale.com/2014/01/26/reconstructing-positions-from-the-depth-buffer */ - mul_v3_fl(viewvecs[i], 1.0f / viewvecs[i][3]); - if (is_persp) - mul_v3_fl(viewvecs[i], 1.0f / viewvecs[i][2]); - viewvecs[i][3] = 1.0; - } - - /* we need to store the differences */ - viewvecs[1][0] -= viewvecs[0][0]; - viewvecs[1][1] = viewvecs[2][1] - viewvecs[0][1]; - - /* calculate a depth offset as well */ - if (!is_persp) { - float vec_far[] = {-1.0f, -1.0f, 1.0f, 1.0f}; - mul_m4_v4(invproj, vec_far); - mul_v3_fl(vec_far, 1.0f / vec_far[3]); - viewvecs[1][2] = vec_far[2] - viewvecs[0][2]; - } - - glDisable(GL_DEPTH_TEST); - - /* ssao pass */ - if (fx->effects & GPU_FX_FLAG_SSAO) { - GPUShader *ssao_shader; - ssao_shader = GPU_shader_get_builtin_fx_shader(GPU_SHADER_FX_SSAO, is_persp); - if (ssao_shader) { - const GPUSSAOSettings *fx_ssao = fx->settings.ssao; - /* adjust attenuation to be scale invariant */ - float attenuation = fx_ssao->attenuation / (fx_ssao->distance_max * fx_ssao->distance_max); - float ssao_params[4] = {fx_ssao->distance_max, fx_ssao->factor, attenuation, 0.0f}; - float sample_params[3]; - - sample_params[0] = fx->ssao_sample_count_cache; - /* multiplier so we tile the random texture on screen */ - sample_params[1] = fx->gbuffer_dim[0] / 64.0; - sample_params[2] = fx->gbuffer_dim[1] / 64.0; - - ssao_params[3] = (passes_left == 1 && !ofs) ? dfdyfac[0] : dfdyfac[1]; - - GPUSSAOShaderInterface *interface = GPU_fx_shader_get_interface(ssao_shader); - - GWN_batch_program_set(fx->quad_batch, GPU_shader_get_program(ssao_shader), GPU_shader_get_interface(ssao_shader)); - - GPU_shader_uniform_vector(ssao_shader, interface->ssao_uniform, 4, 1, ssao_params); - GPU_shader_uniform_vector(ssao_shader, interface->ssao_color_uniform, 4, 1, fx_ssao->color); - GPU_shader_uniform_vector(ssao_shader, interface->viewvecs_uniform, 4, 3, viewvecs[0]); - GPU_shader_uniform_vector(ssao_shader, interface->ssao_sample_params_uniform, 3, 1, sample_params); - - GPU_texture_bind(src, numslots++); - GPU_shader_uniform_texture(ssao_shader, interface->color_uniform, src); - - GPU_texture_bind(fx->depth_buffer, numslots++); - GPU_texture_compare_mode(fx->depth_buffer, false); - GPU_texture_filter_mode(fx->depth_buffer, true); - GPU_shader_uniform_texture(ssao_shader, interface->depth_uniform, fx->depth_buffer); - - GPU_texture_bind(fx->jitter_buffer, numslots++); - GPU_shader_uniform_texture(ssao_shader, interface->ssao_jitter_uniform, fx->jitter_buffer); - - GPU_texture_bind(fx->ssao_spiral_samples_tex, numslots++); - GPU_shader_uniform_texture(ssao_shader, interface->ssao_concentric_tex, fx->ssao_spiral_samples_tex); - - /* draw */ - gpu_fx_bind_render_target(&passes_left, fx, ofs, target); - - GWN_batch_draw(fx->quad_batch); - - /* disable bindings */ - GPU_texture_unbind(src); - GPU_texture_compare_mode(fx->depth_buffer, true); - GPU_texture_filter_mode(fx->depth_buffer, false); - GPU_texture_unbind(fx->depth_buffer); - GPU_texture_unbind(fx->jitter_buffer); - GPU_texture_unbind(fx->ssao_spiral_samples_tex); - - /* may not be attached, in that case this just returns */ - if (target) { - GPU_framebuffer_texture_detach(target); - if (ofs) { - GPU_offscreen_bind(ofs, false); - } - else { - GPU_framebuffer_restore(); - } - } - - /* swap here, after src/target have been unbound */ - SWAP(GPUTexture *, target, src); - numslots = 0; - } - } - - /* second pass, dof */ - if (fx->effects & GPU_FX_FLAG_DOF) { - const GPUDOFSettings *fx_dof = fx->settings.dof; - float dof_params[4]; - float scale = scene->unit.system ? scene->unit.scale_length : 1.0f; - /* this is factor that converts to the scene scale. focal length and sensor are expressed in mm - * unit.scale_length is how many meters per blender unit we have. We want to convert to blender units though - * because the shader reads coordinates in world space, which is in blender units. - * Note however that focus_distance is already in blender units and shall not be scaled here (see T48157). */ - float scale_camera = 0.001f / scale; - /* we want radius here for the aperture number */ - float aperture = 0.5f * scale_camera * fx_dof->focal_length / fx_dof->fstop; - - dof_params[0] = aperture * fabsf(scale_camera * fx_dof->focal_length / - (fx_dof->focus_distance - scale_camera * fx_dof->focal_length)); - dof_params[1] = fx_dof->focus_distance; - dof_params[2] = fx->gbuffer_dim[0] / (scale_camera * fx_dof->sensor); - dof_params[3] = fx_dof->num_blades; - - if (fx->dof_high_quality) { - GPUShader *dof_shader_pass1, *dof_shader_pass2, *dof_shader_pass3; - - /* custom shaders close to the effect described in CryEngine 3 Graphics Gems */ - dof_shader_pass1 = GPU_shader_get_builtin_fx_shader(GPU_SHADER_FX_DEPTH_OF_FIELD_HQ_PASS_ONE, is_persp); - dof_shader_pass2 = GPU_shader_get_builtin_fx_shader(GPU_SHADER_FX_DEPTH_OF_FIELD_HQ_PASS_TWO, is_persp); - dof_shader_pass3 = GPU_shader_get_builtin_fx_shader(GPU_SHADER_FX_DEPTH_OF_FIELD_HQ_PASS_THREE, is_persp); - - /* error occured, restore framebuffers and return */ - if (!(dof_shader_pass1 && dof_shader_pass2 && dof_shader_pass3)) { - GPU_framebuffer_texture_unbind(fx->gbuffer, NULL); - GPU_framebuffer_restore(); - - GPU_shader_unbind(); - return false; - } - - /* pass first, downsample the color buffer to near/far targets and calculate coc texture */ - { - float invrendertargetdim[2] = {1.0f / fx->dof_downsampled_w, 1.0f / fx->dof_downsampled_h}; - - GPUDOFHQPassOneInterface *interface = GPU_fx_shader_get_interface(dof_shader_pass1); - - GWN_batch_program_set(fx->quad_batch, GPU_shader_get_program(dof_shader_pass1), GPU_shader_get_interface(dof_shader_pass1)); - - GPU_shader_uniform_vector(dof_shader_pass1, interface->dof_uniform, 4, 1, dof_params); - GPU_shader_uniform_vector(dof_shader_pass1, interface->invrendertargetdim_uniform, 2, 1, invrendertargetdim); - GPU_shader_uniform_vector(dof_shader_pass1, interface->viewvecs_uniform, 4, 3, viewvecs[0]); - - GPU_shader_uniform_vector(dof_shader_pass1, interface->invrendertargetdim_uniform, 2, 1, invrendertargetdim); - - GPU_texture_bind(fx->depth_buffer, numslots++); - GPU_texture_compare_mode(fx->depth_buffer, false); - GPU_texture_filter_mode(fx->depth_buffer, false); - GPU_shader_uniform_texture(dof_shader_pass1, interface->depth_uniform, fx->depth_buffer); - - GPU_texture_bind(src, numslots++); - /* disable filtering for the texture so custom downsample can do the right thing */ - GPU_texture_filter_mode(src, false); - GPU_shader_uniform_texture(dof_shader_pass2, interface->color_uniform, src); - - /* target is the downsampled coc buffer */ - GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_half_downsampled_near, 0, 0); - GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_half_downsampled_far, 1, 0); - GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_nearfar_coc, 2, 0); - /* binding takes care of setting the viewport to the downsampled size */ - GPU_framebuffer_slots_bind(fx->gbuffer, 0); - - GPU_framebuffer_check_valid(fx->gbuffer, NULL); - - GWN_batch_draw(fx->quad_batch); - - /* disable bindings */ - GPU_texture_filter_mode(src, true); - GPU_texture_unbind(src); - GPU_texture_compare_mode(fx->depth_buffer, true); - GPU_texture_filter_mode(fx->depth_buffer, false); - GPU_texture_unbind(fx->depth_buffer); - - GPU_framebuffer_texture_detach(fx->dof_half_downsampled_near); - GPU_framebuffer_texture_detach(fx->dof_half_downsampled_far); - GPU_framebuffer_texture_detach(fx->dof_nearfar_coc); - GPU_framebuffer_texture_unbind(fx->gbuffer, fx->dof_half_downsampled_near); - - numslots = 0; - } - - /* second pass, shoot quads for every pixel in the downsampled buffers, scaling according - * to circle of confusion */ - { - int rendertargetdim[2] = {fx->dof_downsampled_w, fx->dof_downsampled_h}; - float selection[2] = {0.0f, 1.0f}; - - GPUDOFHQPassTwoInterface *interface = GPU_fx_shader_get_interface(dof_shader_pass2); - - GWN_batch_program_set(fx->point_batch, GPU_shader_get_program(dof_shader_pass2), GPU_shader_get_interface(dof_shader_pass2)); - - GPU_texture_bind(fx->dof_nearfar_coc, numslots++); - GPU_texture_bind(fx->dof_half_downsampled_far, numslots++); - GPU_texture_bind(fx->dof_half_downsampled_near, numslots++); - - GPU_shader_uniform_vector(dof_shader_pass2, interface->dof_uniform, 4, 1, dof_params); - GPU_shader_uniform_vector_int(dof_shader_pass2, interface->rendertargetdim_uniform, 2, 1, rendertargetdim); - GPU_shader_uniform_vector(dof_shader_pass2, interface->select_uniform, 2, 1, selection); - GPU_shader_uniform_texture(dof_shader_pass2, interface->coc_uniform, fx->dof_nearfar_coc); - GPU_shader_uniform_texture(dof_shader_pass2, interface->color_uniform, fx->dof_half_downsampled_far); - GPU_texture_filter_mode(fx->dof_half_downsampled_far, false); - - /* target is the downsampled coc buffer */ - GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_far_blur, 0, 0); - GPU_texture_bind_as_framebuffer(fx->dof_far_blur); - - glDisable(GL_DEPTH_TEST); - glEnable(GL_BLEND); - glBlendFunc(GL_ONE, GL_ONE); - glPointSize(1.0f); - /* have to clear the buffer unfortunately */ - glClearColor(0.0, 0.0, 0.0, 0.0); - glClear(GL_COLOR_BUFFER_BIT); - /* the draw call we all waited for, draw a point per pixel, scaled per circle of confusion */ - GWN_batch_draw_stupid_instanced(fx->point_batch, 0, fx->dof_downsampled_w * fx->dof_downsampled_h, 0, 0, 0, NULL, NULL); - - GPU_texture_unbind(fx->dof_half_downsampled_far); - GPU_framebuffer_texture_detach(fx->dof_far_blur); - - selection[0] = 1.0f; - selection[1] = 0.0f; - - GPU_shader_uniform_vector(dof_shader_pass2, interface->select_uniform, 2, 1, selection); - GPU_shader_uniform_texture(dof_shader_pass2, interface->color_uniform, fx->dof_half_downsampled_near); - GPU_texture_filter_mode(fx->dof_half_downsampled_near, false); - - GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_near_blur, 0, 0); - /* have to clear the buffer unfortunately */ - glClear(GL_COLOR_BUFFER_BIT); - /* the draw call we all waited for, draw a point per pixel, scaled per circle of confusion */ - GWN_batch_draw_stupid_instanced(fx->point_batch, 0, fx->dof_downsampled_w * fx->dof_downsampled_h, 0, 0, 0, NULL, NULL); - GWN_batch_program_use_end(fx->point_batch); - - /* disable bindings */ - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glDisable(GL_BLEND); - - GPU_framebuffer_texture_detach(fx->dof_near_blur); - - GPU_texture_unbind(fx->dof_half_downsampled_near); - GPU_texture_unbind(fx->dof_nearfar_coc); - - GPU_framebuffer_texture_unbind(fx->gbuffer, fx->dof_far_blur); - numslots = 0; - } - - /* third pass, accumulate the near/far blur fields */ - { - float invrendertargetdim[2] = {1.0f / fx->dof_downsampled_w, 1.0f / fx->dof_downsampled_h}; - - GPUDOFHQPassThreeInterface *interface = GPU_fx_shader_get_interface(dof_shader_pass3); - - GWN_batch_program_set(fx->quad_batch, GPU_shader_get_program(dof_shader_pass3), GPU_shader_get_interface(dof_shader_pass3)); - - GPU_shader_uniform_vector(dof_shader_pass3, interface->dof_uniform, 4, 1, dof_params); - - GPU_shader_uniform_vector(dof_shader_pass3, interface->invrendertargetdim_uniform, 2, 1, invrendertargetdim); - GPU_shader_uniform_vector(dof_shader_pass3, interface->viewvecs_uniform, 4, 3, viewvecs[0]); - - GPU_texture_bind(fx->dof_near_blur, numslots++); - GPU_shader_uniform_texture(dof_shader_pass3, interface->near_uniform, fx->dof_near_blur); - GPU_texture_filter_mode(fx->dof_near_blur, true); - - GPU_texture_bind(fx->dof_far_blur, numslots++); - GPU_shader_uniform_texture(dof_shader_pass3, interface->far_uniform, fx->dof_far_blur); - GPU_texture_filter_mode(fx->dof_far_blur, true); - - GPU_texture_bind(fx->depth_buffer, numslots++); - GPU_texture_compare_mode(fx->depth_buffer, false); - GPU_texture_filter_mode(fx->depth_buffer, false); - GPU_shader_uniform_texture(dof_shader_pass3, interface->depth_uniform, fx->depth_buffer); - - GPU_texture_bind(src, numslots++); - GPU_shader_uniform_texture(dof_shader_pass3, interface->color_uniform, src); - - /* if this is the last pass, prepare for rendering on the frambuffer */ - gpu_fx_bind_render_target(&passes_left, fx, ofs, target); - - GWN_batch_draw(fx->quad_batch); - - /* disable bindings */ - GPU_texture_unbind(fx->dof_near_blur); - GPU_texture_unbind(fx->dof_far_blur); - GPU_texture_unbind(src); - GPU_texture_compare_mode(fx->depth_buffer, true); - GPU_texture_unbind(fx->depth_buffer); - - /* may not be attached, in that case this just returns */ - if (target) { - GPU_framebuffer_texture_detach(target); - if (ofs) { - GPU_offscreen_bind(ofs, false); - } - else { - GPU_framebuffer_restore(); - } - } - - numslots = 0; - } - } - else { - GPUShader *dof_shader_pass1, *dof_shader_pass2, *dof_shader_pass3, *dof_shader_pass4, *dof_shader_pass5; - - /* DOF effect has many passes but most of them are performed - * on a texture whose dimensions are 4 times less than the original - * (16 times lower than original screen resolution). - * Technique used is not very exact but should be fast enough and is based - * on "Practical Post-Process Depth of Field" - * see http://http.developer.nvidia.com/GPUGems3/gpugems3_ch28.html */ - dof_shader_pass1 = GPU_shader_get_builtin_fx_shader(GPU_SHADER_FX_DEPTH_OF_FIELD_PASS_ONE, is_persp); - dof_shader_pass2 = GPU_shader_get_builtin_fx_shader(GPU_SHADER_FX_DEPTH_OF_FIELD_PASS_TWO, is_persp); - dof_shader_pass3 = GPU_shader_get_builtin_fx_shader(GPU_SHADER_FX_DEPTH_OF_FIELD_PASS_THREE, is_persp); - dof_shader_pass4 = GPU_shader_get_builtin_fx_shader(GPU_SHADER_FX_DEPTH_OF_FIELD_PASS_FOUR, is_persp); - dof_shader_pass5 = GPU_shader_get_builtin_fx_shader(GPU_SHADER_FX_DEPTH_OF_FIELD_PASS_FIVE, is_persp); - - /* error occured, restore framebuffers and return */ - if (!(dof_shader_pass1 && dof_shader_pass2 && dof_shader_pass3 && dof_shader_pass4 && dof_shader_pass5)) { - GPU_framebuffer_texture_unbind(fx->gbuffer, NULL); - GPU_framebuffer_restore(); - - GPU_shader_unbind(); - return false; - } - - /* pass first, first level of blur in low res buffer */ - { - float invrendertargetdim[2] = {1.0f / fx->gbuffer_dim[0], 1.0f / fx->gbuffer_dim[1]}; - - GPUDOFPassOneInterface *interface = GPU_fx_shader_get_interface(dof_shader_pass1); - - GWN_batch_program_set(fx->quad_batch, GPU_shader_get_program(dof_shader_pass1), GPU_shader_get_interface(dof_shader_pass1)); - - GPU_shader_uniform_vector(dof_shader_pass1, interface->dof_uniform, 4, 1, dof_params); - GPU_shader_uniform_vector(dof_shader_pass1, interface->invrendertargetdim_uniform, 2, 1, invrendertargetdim); - GPU_shader_uniform_vector(dof_shader_pass1, interface->viewvecs_uniform, 4, 3, viewvecs[0]); - - GPU_texture_bind(src, numslots++); - GPU_shader_uniform_texture(dof_shader_pass1, interface->color_uniform, src); - - GPU_texture_bind(fx->depth_buffer, numslots++); - GPU_texture_compare_mode(fx->depth_buffer, false); - GPU_texture_filter_mode(fx->depth_buffer, true); - GPU_shader_uniform_texture(dof_shader_pass1, interface->depth_uniform, fx->depth_buffer); - - /* target is the downsampled coc buffer */ - GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_near_coc_buffer, 0, 0); - /* binding takes care of setting the viewport to the downsampled size */ - GPU_texture_bind_as_framebuffer(fx->dof_near_coc_buffer); - - GWN_batch_draw(fx->quad_batch); - /* disable bindings */ - GPU_texture_unbind(src); - GPU_texture_compare_mode(fx->depth_buffer, true); - GPU_texture_filter_mode(fx->depth_buffer, false); - GPU_texture_unbind(fx->depth_buffer); - - GPU_framebuffer_texture_detach(fx->dof_near_coc_buffer); - numslots = 0; - } - - /* second pass, gaussian blur the downsampled image */ - { - float invrendertargetdim[2] = {1.0f / GPU_texture_width(fx->dof_near_coc_blurred_buffer), - 1.0f / GPU_texture_height(fx->dof_near_coc_blurred_buffer)}; - float tmp = invrendertargetdim[0]; - invrendertargetdim[0] = 0.0f; - - GPUDOFPassTwoInterface *interface = GPU_fx_shader_get_interface(dof_shader_pass2); - - dof_params[2] = GPU_texture_width(fx->dof_near_coc_blurred_buffer) / (scale_camera * fx_dof->sensor); - - /* Blurring vertically */ - GWN_batch_program_set(fx->quad_batch, GPU_shader_get_program(dof_shader_pass2), GPU_shader_get_interface(dof_shader_pass2)); - - GPU_shader_uniform_vector(dof_shader_pass2, interface->dof_uniform, 4, 1, dof_params); - GPU_shader_uniform_vector(dof_shader_pass2, interface->invrendertargetdim_uniform, 2, 1, invrendertargetdim); - GPU_shader_uniform_vector(dof_shader_pass2, interface->viewvecs_uniform, 4, 3, viewvecs[0]); - - GPU_texture_bind(fx->depth_buffer, numslots++); - GPU_texture_compare_mode(fx->depth_buffer, false); - GPU_texture_filter_mode(fx->depth_buffer, true); - GPU_shader_uniform_texture(dof_shader_pass2, interface->depth_uniform, fx->depth_buffer); - - GPU_texture_bind(fx->dof_near_coc_buffer, numslots++); - GPU_shader_uniform_texture(dof_shader_pass2, interface->color_uniform, fx->dof_near_coc_buffer); - - /* use final buffer as a temp here */ - GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_near_coc_final_buffer, 0, 0); - - /* Drawing quad */ - GWN_batch_draw(fx->quad_batch); - - /* Rebind Shader */ - GWN_batch_program_set(fx->quad_batch, GPU_shader_get_program(dof_shader_pass2), GPU_shader_get_interface(dof_shader_pass2)); - - /* *unbind/detach */ - GPU_texture_unbind(fx->dof_near_coc_buffer); - - GPU_framebuffer_texture_detach(fx->dof_near_coc_final_buffer); - - /* Blurring horizontally */ - invrendertargetdim[0] = tmp; - invrendertargetdim[1] = 0.0f; - GPU_shader_uniform_vector(dof_shader_pass2, interface->invrendertargetdim_uniform, 2, 1, invrendertargetdim); - - GPU_texture_bind(fx->dof_near_coc_final_buffer, numslots++); - GPU_shader_uniform_texture(dof_shader_pass2, interface->color_uniform, fx->dof_near_coc_final_buffer); - - GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_near_coc_blurred_buffer, 0, 0); - - GWN_batch_draw(fx->quad_batch); - - /* *unbind/detach */ - GPU_texture_compare_mode(fx->depth_buffer, true); - GPU_texture_filter_mode(fx->depth_buffer, false); - GPU_texture_unbind(fx->depth_buffer); - - GPU_texture_unbind(fx->dof_near_coc_final_buffer); - GPU_framebuffer_texture_detach(fx->dof_near_coc_blurred_buffer); - - dof_params[2] = fx->gbuffer_dim[0] / (scale_camera * fx_dof->sensor); - - numslots = 0; - } - - /* third pass, calculate near coc */ - { - GPUDOFPassThreeInterface *interface = GPU_fx_shader_get_interface(dof_shader_pass3); - - GWN_batch_program_set(fx->quad_batch, GPU_shader_get_program(dof_shader_pass3), GPU_shader_get_interface(dof_shader_pass3)); - - GPU_texture_bind(fx->dof_near_coc_buffer, numslots++); - GPU_shader_uniform_texture(dof_shader_pass3, interface->near_coc_downsampled, fx->dof_near_coc_buffer); - - GPU_texture_bind(fx->dof_near_coc_blurred_buffer, numslots++); - GPU_shader_uniform_texture(dof_shader_pass3, interface->near_coc_blurred, fx->dof_near_coc_blurred_buffer); - - GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_near_coc_final_buffer, 0, 0); - - GWN_batch_draw(fx->quad_batch); - /* disable bindings */ - GPU_texture_unbind(fx->dof_near_coc_buffer); - GPU_texture_unbind(fx->dof_near_coc_blurred_buffer); - - /* unbinding here restores the size to the original */ - GPU_framebuffer_texture_detach(fx->dof_near_coc_final_buffer); - - numslots = 0; - } - - /* fourth pass blur final coc once to eliminate discontinuities */ - { - float invrendertargetdim[2] = {1.0f / GPU_texture_width(fx->dof_near_coc_blurred_buffer), - 1.0f / GPU_texture_height(fx->dof_near_coc_blurred_buffer)}; - - GPUDOFPassFourInterface *interface = GPU_fx_shader_get_interface(dof_shader_pass4); - - GWN_batch_program_set(fx->quad_batch, GPU_shader_get_program(dof_shader_pass4), GPU_shader_get_interface(dof_shader_pass4)); - - GPU_texture_bind(fx->dof_near_coc_final_buffer, numslots++); - GPU_shader_uniform_texture(dof_shader_pass4, interface->near_coc_downsampled, fx->dof_near_coc_final_buffer); - GPU_shader_uniform_vector(dof_shader_pass4, interface->invrendertargetdim_uniform, 2, 1, invrendertargetdim); - - GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_near_coc_buffer, 0, 0); - - GWN_batch_draw(fx->quad_batch); - /* disable bindings */ - GPU_texture_unbind(fx->dof_near_coc_final_buffer); - - /* unbinding here restores the size to the original */ - GPU_framebuffer_texture_unbind(fx->gbuffer, fx->dof_near_coc_buffer); - GPU_framebuffer_texture_detach(fx->dof_near_coc_buffer); - - numslots = 0; - } - - /* final pass, merge blurred layers according to final calculated coc */ - { - float invrendertargetdim[2] = {1.0f / fx->gbuffer_dim[0], 1.0f / fx->gbuffer_dim[1]}; - - GPUDOFPassFiveInterface *interface = GPU_fx_shader_get_interface(dof_shader_pass5); - - GWN_batch_program_set(fx->quad_batch, GPU_shader_get_program(dof_shader_pass5), GPU_shader_get_interface(dof_shader_pass5)); - - GPU_shader_uniform_vector(dof_shader_pass5, interface->dof_uniform, 4, 1, dof_params); - GPU_shader_uniform_vector(dof_shader_pass5, interface->invrendertargetdim_uniform, 2, 1, invrendertargetdim); - GPU_shader_uniform_vector(dof_shader_pass5, interface->viewvecs_uniform, 4, 3, viewvecs[0]); - - GPU_texture_bind(src, numslots++); - GPU_shader_uniform_texture(dof_shader_pass5, interface->original_uniform, src); - - GPU_texture_bind(fx->dof_near_coc_blurred_buffer, numslots++); - GPU_shader_uniform_texture(dof_shader_pass5, interface->high_blurred_uniform, fx->dof_near_coc_blurred_buffer); - - GPU_texture_bind(fx->dof_near_coc_buffer, numslots++); - GPU_shader_uniform_texture(dof_shader_pass5, interface->medium_blurred_uniform, fx->dof_near_coc_buffer); - - GPU_texture_bind(fx->depth_buffer, numslots++); - GPU_texture_compare_mode(fx->depth_buffer, false); - GPU_texture_filter_mode(fx->depth_buffer, true); - GPU_shader_uniform_texture(dof_shader_pass5, interface->depth_uniform, fx->depth_buffer); - - /* if this is the last pass, prepare for rendering on the frambuffer */ - gpu_fx_bind_render_target(&passes_left, fx, ofs, target); - - GWN_batch_draw(fx->quad_batch); - /* disable bindings */ - GPU_texture_unbind(fx->dof_near_coc_buffer); - GPU_texture_unbind(fx->dof_near_coc_blurred_buffer); - GPU_texture_unbind(src); - GPU_texture_compare_mode(fx->depth_buffer, true); - GPU_texture_filter_mode(fx->depth_buffer, false); - GPU_texture_unbind(fx->depth_buffer); - - /* may not be attached, in that case this just returns */ - if (target) { - GPU_framebuffer_texture_detach(target); - if (ofs) { - GPU_offscreen_bind(ofs, false); - } - else { - GPU_framebuffer_restore(); - } - } - - SWAP(GPUTexture *, target, src); - numslots = 0; - } - } - } - - GPU_shader_unbind(); - - return true; -} - -void GPU_fx_compositor_init_dof_settings(GPUDOFSettings *fx_dof) -{ - fx_dof->fstop = 128.0f; - fx_dof->focal_length = 1.0f; - fx_dof->focus_distance = 1.0f; - fx_dof->sensor = 1.0f; - fx_dof->num_blades = 6; - fx_dof->ratio = 1.0f; -} - -void GPU_fx_compositor_init_ssao_settings(GPUSSAOSettings *fx_ssao) -{ - fx_ssao->factor = 1.0f; - fx_ssao->distance_max = 0.2f; - fx_ssao->attenuation = 1.0f; - fx_ssao->samples = 20; -} - -void GPU_fx_shader_init_interface(GPUShader *shader, GPUFXShaderEffect effect) -{ - if (!shader) - return; - - switch (effect) { - case GPU_SHADER_FX_SSAO: - { - GPUSSAOShaderInterface *interface = MEM_mallocN(sizeof(GPUSSAOShaderInterface), "GPUSSAOShaderInterface"); - - interface->ssao_uniform = GPU_shader_get_uniform(shader, "ssao_params"); - interface->ssao_color_uniform = GPU_shader_get_uniform(shader, "ssao_color"); - interface->color_uniform = GPU_shader_get_uniform(shader, "colorbuffer"); - interface->depth_uniform = GPU_shader_get_uniform(shader, "depthbuffer"); - interface->viewvecs_uniform = GPU_shader_get_uniform(shader, "viewvecs"); - interface->ssao_sample_params_uniform = GPU_shader_get_uniform(shader, "ssao_sample_params"); - interface->ssao_concentric_tex = GPU_shader_get_uniform(shader, "ssao_concentric_tex"); - interface->ssao_jitter_uniform = GPU_shader_get_uniform(shader, "jitter_tex"); - - GPU_fx_shader_set_interface(shader, interface); - break; - } - - case GPU_SHADER_FX_DEPTH_OF_FIELD_HQ_PASS_ONE: - { - GPUDOFHQPassOneInterface *interface = MEM_mallocN(sizeof(GPUDOFHQPassOneInterface), "GPUDOFHQPassOneInterface"); - - interface->invrendertargetdim_uniform = GPU_shader_get_uniform(shader, "invrendertargetdim"); - interface->color_uniform = GPU_shader_get_uniform(shader, "colorbuffer"); - interface->dof_uniform = GPU_shader_get_uniform(shader, "dof_params"); - interface->depth_uniform = GPU_shader_get_uniform(shader, "depthbuffer"); - interface->viewvecs_uniform = GPU_shader_get_uniform(shader, "viewvecs"); - - GPU_fx_shader_set_interface(shader, interface); - break; - } - - case GPU_SHADER_FX_DEPTH_OF_FIELD_HQ_PASS_TWO: - { - GPUDOFHQPassTwoInterface *interface = MEM_mallocN(sizeof(GPUDOFHQPassTwoInterface), "GPUDOFHQPassTwoInterface"); - - interface->rendertargetdim_uniform = GPU_shader_get_uniform(shader, "rendertargetdim"); - interface->color_uniform = GPU_shader_get_uniform(shader, "colorbuffer"); - interface->coc_uniform = GPU_shader_get_uniform(shader, "cocbuffer"); - interface->select_uniform = GPU_shader_get_uniform(shader, "layerselection"); - interface->dof_uniform = GPU_shader_get_uniform(shader, "dof_params"); - - GPU_fx_shader_set_interface(shader, interface); - break; - } - - case GPU_SHADER_FX_DEPTH_OF_FIELD_HQ_PASS_THREE: - { - GPUDOFHQPassThreeInterface *interface = MEM_mallocN(sizeof(GPUDOFHQPassThreeInterface), "GPUDOFHQPassThreeInterface"); - - interface->dof_uniform = GPU_shader_get_uniform(shader, "dof_params"); - interface->invrendertargetdim_uniform = GPU_shader_get_uniform(shader, "invrendertargetdim"); - interface->color_uniform = GPU_shader_get_uniform(shader, "colorbuffer"); - interface->far_uniform = GPU_shader_get_uniform(shader, "farbuffer"); - interface->near_uniform = GPU_shader_get_uniform(shader, "nearbuffer"); - interface->viewvecs_uniform = GPU_shader_get_uniform(shader, "viewvecs"); - interface->depth_uniform = GPU_shader_get_uniform(shader, "depthbuffer"); - - GPU_fx_shader_set_interface(shader, interface); - break; - } - - case GPU_SHADER_FX_DEPTH_OF_FIELD_PASS_ONE: - { - GPUDOFPassOneInterface *interface = MEM_mallocN(sizeof(GPUDOFPassOneInterface), "GPUDOFPassOneInterface"); - - interface->dof_uniform = GPU_shader_get_uniform(shader, "dof_params"); - interface->invrendertargetdim_uniform = GPU_shader_get_uniform(shader, "invrendertargetdim"); - interface->color_uniform = GPU_shader_get_uniform(shader, "colorbuffer"); - interface->depth_uniform = GPU_shader_get_uniform(shader, "depthbuffer"); - interface->viewvecs_uniform = GPU_shader_get_uniform(shader, "viewvecs"); - - GPU_fx_shader_set_interface(shader, interface); - break; - } - case GPU_SHADER_FX_DEPTH_OF_FIELD_PASS_TWO: - { - GPUDOFPassTwoInterface *interface = MEM_mallocN(sizeof(GPUDOFPassTwoInterface), "GPUDOFPassTwoInterface"); - - interface->dof_uniform = GPU_shader_get_uniform(shader, "dof_params"); - interface->invrendertargetdim_uniform = GPU_shader_get_uniform(shader, "invrendertargetdim"); - interface->color_uniform = GPU_shader_get_uniform(shader, "colorbuffer"); - interface->depth_uniform = GPU_shader_get_uniform(shader, "depthbuffer"); - interface->viewvecs_uniform = GPU_shader_get_uniform(shader, "viewvecs"); - - GPU_fx_shader_set_interface(shader, interface); - break; - } - case GPU_SHADER_FX_DEPTH_OF_FIELD_PASS_THREE: - { - GPUDOFPassThreeInterface *interface = MEM_mallocN(sizeof(GPUDOFPassThreeInterface), "GPUDOFPassThreeInterface"); - - interface->near_coc_downsampled = GPU_shader_get_uniform(shader, "colorbuffer"); - interface->near_coc_blurred = GPU_shader_get_uniform(shader, "blurredcolorbuffer"); - - GPU_fx_shader_set_interface(shader, interface); - break; - } - case GPU_SHADER_FX_DEPTH_OF_FIELD_PASS_FOUR: - { - GPUDOFPassFourInterface *interface = MEM_mallocN(sizeof(GPUDOFPassFourInterface), "GPUDOFPassFourInterface"); - - interface->near_coc_downsampled = GPU_shader_get_uniform(shader, "colorbuffer"); - interface->invrendertargetdim_uniform = GPU_shader_get_uniform(shader, "invrendertargetdim"); - - GPU_fx_shader_set_interface(shader, interface); - break; - } - case GPU_SHADER_FX_DEPTH_OF_FIELD_PASS_FIVE: - { - GPUDOFPassFiveInterface *interface = MEM_mallocN(sizeof(GPUDOFPassFiveInterface), "GPUDOFPassFiveInterface"); - - interface->medium_blurred_uniform = GPU_shader_get_uniform(shader, "mblurredcolorbuffer"); - interface->high_blurred_uniform = GPU_shader_get_uniform(shader, "blurredcolorbuffer"); - interface->dof_uniform = GPU_shader_get_uniform(shader, "dof_params"); - interface->invrendertargetdim_uniform = GPU_shader_get_uniform(shader, "invrendertargetdim"); - interface->original_uniform = GPU_shader_get_uniform(shader, "colorbuffer"); - interface->depth_uniform = GPU_shader_get_uniform(shader, "depthbuffer"); - interface->viewvecs_uniform = GPU_shader_get_uniform(shader, "viewvecs"); - - GPU_fx_shader_set_interface(shader, interface); - break; - } - - case GPU_SHADER_FX_DEPTH_RESOLVE: - { - GPUDepthResolveInterface *interface = MEM_mallocN(sizeof(GPUDepthResolveInterface), "GPUDepthResolveInterface"); - - interface->depth_uniform = GPU_shader_get_uniform(shader, "depthbuffer"); - - GPU_fx_shader_set_interface(shader, interface); - break; - } - - default: - break; - } -} - diff --git a/source/blender/gpu/intern/gpu_draw.c b/source/blender/gpu/intern/gpu_draw.c index f9cf3235ac1..8b344716a9c 100644 --- a/source/blender/gpu/intern/gpu_draw.c +++ b/source/blender/gpu/intern/gpu_draw.c @@ -39,11 +39,11 @@ #include <string.h> #include "BLI_blenlib.h" +#include "BLI_hash.h" #include "BLI_linklist.h" #include "BLI_math.h" #include "BLI_threads.h" #include "BLI_utildefines.h" -#include "BLI_hash.h" #include "DNA_lamp_types.h" #include "DNA_material_types.h" @@ -398,7 +398,7 @@ static void gpu_set_alpha_blend(GPUBlendMode alphablend) if (alphablend == GPU_BLEND_SOLID) { glDisable(GL_BLEND); glDisable(GL_SAMPLE_ALPHA_TO_COVERAGE); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); } else if (alphablend == GPU_BLEND_ADD) { glEnable(GL_BLEND); @@ -1319,9 +1319,9 @@ static LinkNode *image_free_queue = NULL; static void gpu_queue_image_for_free(Image *ima) { - BLI_lock_thread(LOCK_OPENGL); + BLI_thread_lock(LOCK_OPENGL); BLI_linklist_prepend(&image_free_queue, ima); - BLI_unlock_thread(LOCK_OPENGL); + BLI_thread_unlock(LOCK_OPENGL); } void GPU_free_unused_buffers(void) @@ -1329,7 +1329,7 @@ void GPU_free_unused_buffers(void) if (!BLI_thread_is_main()) return; - BLI_lock_thread(LOCK_OPENGL); + BLI_thread_lock(LOCK_OPENGL); /* images */ for (LinkNode *node = image_free_queue; node; node = node->next) { @@ -1346,7 +1346,7 @@ void GPU_free_unused_buffers(void) /* vbo buffers */ GPU_global_buffer_pool_free_unused(); - BLI_unlock_thread(LOCK_OPENGL); + BLI_thread_unlock(LOCK_OPENGL); } void GPU_free_image(Image *ima) @@ -1734,6 +1734,8 @@ static int gpu_get_particle_info(GPUParticleInfo *pi) pi->scalprops[3] = p->size; copy_v3_v3(pi->location, p->state.co); + pi->location[3] = BLI_hash_int_01(ind); + copy_v3_v3(pi->velocity, p->state.vel); copy_v3_v3(pi->angular_velocity, p->state.ave); return 1; @@ -2093,7 +2095,7 @@ int GPU_scene_object_lights(ViewLayer *view_layer, float viewmat[4][4], int orth return count; } -static void gpu_multisample(bool enable) +static void gpu_disable_multisample(void) { #ifdef __linux__ /* changing multisample from the default (enabled) causes problems on some @@ -2109,16 +2111,10 @@ static void gpu_multisample(bool enable) } if (toggle_ok) { - if (enable) - glEnable(GL_MULTISAMPLE); - else - glDisable(GL_MULTISAMPLE); + glDisable(GL_MULTISAMPLE); } #else - if (enable) - glEnable(GL_MULTISAMPLE); - else - glDisable(GL_MULTISAMPLE); + glDisable(GL_MULTISAMPLE); #endif } @@ -2150,7 +2146,7 @@ void GPU_state_init(void) glCullFace(GL_BACK); glDisable(GL_CULL_FACE); - gpu_multisample(false); + gpu_disable_multisample(); } void GPU_enable_program_point_size(void) @@ -2385,7 +2381,7 @@ static GPUAttribStack state = { }; #define AttribStack state -#define Gwn_VertAttr state.attrib_stack[state.top] +#define Attrib state.attrib_stack[state.top] /** * Replacement for glPush/PopAttributes @@ -2395,48 +2391,48 @@ static GPUAttribStack state = { */ void gpuPushAttrib(eGPUAttribMask mask) { - Gwn_VertAttr.mask = mask; + Attrib.mask = mask; if ((mask & GPU_DEPTH_BUFFER_BIT) != 0) { - Gwn_VertAttr.is_depth_test = glIsEnabled(GL_DEPTH_TEST); - glGetIntegerv(GL_DEPTH_FUNC, &Gwn_VertAttr.depth_func); - glGetDoublev(GL_DEPTH_CLEAR_VALUE, &Gwn_VertAttr.depth_clear_value); - glGetBooleanv(GL_DEPTH_WRITEMASK, (GLboolean *)&Gwn_VertAttr.depth_write_mask); + Attrib.is_depth_test = glIsEnabled(GL_DEPTH_TEST); + glGetIntegerv(GL_DEPTH_FUNC, &Attrib.depth_func); + glGetDoublev(GL_DEPTH_CLEAR_VALUE, &Attrib.depth_clear_value); + glGetBooleanv(GL_DEPTH_WRITEMASK, (GLboolean *)&Attrib.depth_write_mask); } if ((mask & GPU_ENABLE_BIT) != 0) { - Gwn_VertAttr.is_blend = glIsEnabled(GL_BLEND); + Attrib.is_blend = glIsEnabled(GL_BLEND); for (int i = 0; i < 6; i++) { - Gwn_VertAttr.is_clip_plane[i] = glIsEnabled(GL_CLIP_PLANE0 + i); + Attrib.is_clip_plane[i] = glIsEnabled(GL_CLIP_PLANE0 + i); } - Gwn_VertAttr.is_cull_face = glIsEnabled(GL_CULL_FACE); - Gwn_VertAttr.is_depth_test = glIsEnabled(GL_DEPTH_TEST); - Gwn_VertAttr.is_dither = glIsEnabled(GL_DITHER); - Gwn_VertAttr.is_line_smooth = glIsEnabled(GL_LINE_SMOOTH); - Gwn_VertAttr.is_color_logic_op = glIsEnabled(GL_COLOR_LOGIC_OP); - Gwn_VertAttr.is_multisample = glIsEnabled(GL_MULTISAMPLE); - Gwn_VertAttr.is_polygon_offset_line = glIsEnabled(GL_POLYGON_OFFSET_LINE); - Gwn_VertAttr.is_polygon_offset_fill = glIsEnabled(GL_POLYGON_OFFSET_FILL); - Gwn_VertAttr.is_polygon_smooth = glIsEnabled(GL_POLYGON_SMOOTH); - Gwn_VertAttr.is_sample_alpha_to_coverage = glIsEnabled(GL_SAMPLE_ALPHA_TO_COVERAGE); - Gwn_VertAttr.is_scissor_test = glIsEnabled(GL_SCISSOR_TEST); - Gwn_VertAttr.is_stencil_test = glIsEnabled(GL_STENCIL_TEST); + Attrib.is_cull_face = glIsEnabled(GL_CULL_FACE); + Attrib.is_depth_test = glIsEnabled(GL_DEPTH_TEST); + Attrib.is_dither = glIsEnabled(GL_DITHER); + Attrib.is_line_smooth = glIsEnabled(GL_LINE_SMOOTH); + Attrib.is_color_logic_op = glIsEnabled(GL_COLOR_LOGIC_OP); + Attrib.is_multisample = glIsEnabled(GL_MULTISAMPLE); + Attrib.is_polygon_offset_line = glIsEnabled(GL_POLYGON_OFFSET_LINE); + Attrib.is_polygon_offset_fill = glIsEnabled(GL_POLYGON_OFFSET_FILL); + Attrib.is_polygon_smooth = glIsEnabled(GL_POLYGON_SMOOTH); + Attrib.is_sample_alpha_to_coverage = glIsEnabled(GL_SAMPLE_ALPHA_TO_COVERAGE); + Attrib.is_scissor_test = glIsEnabled(GL_SCISSOR_TEST); + Attrib.is_stencil_test = glIsEnabled(GL_STENCIL_TEST); } if ((mask & GPU_SCISSOR_BIT) != 0) { - Gwn_VertAttr.is_scissor_test = glIsEnabled(GL_SCISSOR_TEST); - glGetIntegerv(GL_SCISSOR_BOX, (GLint *)&Gwn_VertAttr.scissor_box); + Attrib.is_scissor_test = glIsEnabled(GL_SCISSOR_TEST); + glGetIntegerv(GL_SCISSOR_BOX, (GLint *)&Attrib.scissor_box); } if ((mask & GPU_VIEWPORT_BIT) != 0) { - glGetDoublev(GL_DEPTH_RANGE, (GLdouble *)&Gwn_VertAttr.near_far); - glGetIntegerv(GL_VIEWPORT, (GLint *)&Gwn_VertAttr.viewport); + glGetDoublev(GL_DEPTH_RANGE, (GLdouble *)&Attrib.near_far); + glGetIntegerv(GL_VIEWPORT, (GLint *)&Attrib.viewport); } if ((mask & GPU_BLEND_BIT) != 0) { - Gwn_VertAttr.is_blend = glIsEnabled(GL_BLEND); + Attrib.is_blend = glIsEnabled(GL_BLEND); } BLI_assert(AttribStack.top < STATE_STACK_DEPTH); @@ -2458,52 +2454,52 @@ void gpuPopAttrib(void) BLI_assert(AttribStack.top > 0); AttribStack.top--; - GLint mask = Gwn_VertAttr.mask; + GLint mask = Attrib.mask; if ((mask & GPU_DEPTH_BUFFER_BIT) != 0) { - restore_mask(GL_DEPTH_TEST, Gwn_VertAttr.is_depth_test); - glDepthFunc(Gwn_VertAttr.depth_func); - glClearDepth(Gwn_VertAttr.depth_clear_value); - glDepthMask(Gwn_VertAttr.depth_write_mask); + restore_mask(GL_DEPTH_TEST, Attrib.is_depth_test); + glDepthFunc(Attrib.depth_func); + glClearDepth(Attrib.depth_clear_value); + glDepthMask(Attrib.depth_write_mask); } if ((mask & GPU_ENABLE_BIT) != 0) { - restore_mask(GL_BLEND, Gwn_VertAttr.is_blend); + restore_mask(GL_BLEND, Attrib.is_blend); for (int i = 0; i < 6; i++) { - restore_mask(GL_CLIP_PLANE0 + i, Gwn_VertAttr.is_clip_plane[i]); + restore_mask(GL_CLIP_PLANE0 + i, Attrib.is_clip_plane[i]); } - restore_mask(GL_CULL_FACE, Gwn_VertAttr.is_cull_face); - restore_mask(GL_DEPTH_TEST, Gwn_VertAttr.is_depth_test); - restore_mask(GL_DITHER, Gwn_VertAttr.is_dither); - restore_mask(GL_LINE_SMOOTH, Gwn_VertAttr.is_line_smooth); - restore_mask(GL_COLOR_LOGIC_OP, Gwn_VertAttr.is_color_logic_op); - restore_mask(GL_MULTISAMPLE, Gwn_VertAttr.is_multisample); - restore_mask(GL_POLYGON_OFFSET_LINE, Gwn_VertAttr.is_polygon_offset_line); - restore_mask(GL_POLYGON_OFFSET_FILL, Gwn_VertAttr.is_polygon_offset_fill); - restore_mask(GL_POLYGON_SMOOTH, Gwn_VertAttr.is_polygon_smooth); - restore_mask(GL_SAMPLE_ALPHA_TO_COVERAGE, Gwn_VertAttr.is_sample_alpha_to_coverage); - restore_mask(GL_SCISSOR_TEST, Gwn_VertAttr.is_scissor_test); - restore_mask(GL_STENCIL_TEST, Gwn_VertAttr.is_stencil_test); + restore_mask(GL_CULL_FACE, Attrib.is_cull_face); + restore_mask(GL_DEPTH_TEST, Attrib.is_depth_test); + restore_mask(GL_DITHER, Attrib.is_dither); + restore_mask(GL_LINE_SMOOTH, Attrib.is_line_smooth); + restore_mask(GL_COLOR_LOGIC_OP, Attrib.is_color_logic_op); + restore_mask(GL_MULTISAMPLE, Attrib.is_multisample); + restore_mask(GL_POLYGON_OFFSET_LINE, Attrib.is_polygon_offset_line); + restore_mask(GL_POLYGON_OFFSET_FILL, Attrib.is_polygon_offset_fill); + restore_mask(GL_POLYGON_SMOOTH, Attrib.is_polygon_smooth); + restore_mask(GL_SAMPLE_ALPHA_TO_COVERAGE, Attrib.is_sample_alpha_to_coverage); + restore_mask(GL_SCISSOR_TEST, Attrib.is_scissor_test); + restore_mask(GL_STENCIL_TEST, Attrib.is_stencil_test); } if ((mask & GPU_VIEWPORT_BIT) != 0) { - glViewport(Gwn_VertAttr.viewport[0], Gwn_VertAttr.viewport[1], Gwn_VertAttr.viewport[2], Gwn_VertAttr.viewport[3]); - glDepthRange(Gwn_VertAttr.near_far[0], Gwn_VertAttr.near_far[1]); + glViewport(Attrib.viewport[0], Attrib.viewport[1], Attrib.viewport[2], Attrib.viewport[3]); + glDepthRange(Attrib.near_far[0], Attrib.near_far[1]); } if ((mask & GPU_SCISSOR_BIT) != 0) { - restore_mask(GL_SCISSOR_TEST, Gwn_VertAttr.is_scissor_test); - glScissor(Gwn_VertAttr.scissor_box[0], Gwn_VertAttr.scissor_box[1], Gwn_VertAttr.scissor_box[2], Gwn_VertAttr.scissor_box[3]); + restore_mask(GL_SCISSOR_TEST, Attrib.is_scissor_test); + glScissor(Attrib.scissor_box[0], Attrib.scissor_box[1], Attrib.scissor_box[2], Attrib.scissor_box[3]); } if ((mask & GPU_BLEND_BIT) != 0) { - restore_mask(GL_BLEND, Gwn_VertAttr.is_blend); + restore_mask(GL_BLEND, Attrib.is_blend); } } -#undef Gwn_VertAttr +#undef Attrib #undef AttribStack /** \} */ diff --git a/source/blender/gpu/intern/gpu_extensions.c b/source/blender/gpu/intern/gpu_extensions.c index 57df877bf18..73e86c1b391 100644 --- a/source/blender/gpu/intern/gpu_extensions.c +++ b/source/blender/gpu/intern/gpu_extensions.c @@ -149,7 +149,7 @@ void gpu_extensions_init(void) else GG.max_anisotropy = 1.0f; - glGetIntegerv(GL_MAX_UNIFORM_BUFFER_BINDINGS, &GG.maxubobinds); + glGetIntegerv(GL_MAX_FRAGMENT_UNIFORM_BLOCKS, &GG.maxubobinds); glGetIntegerv(GL_MAX_UNIFORM_BLOCK_SIZE, &GG.maxubosize); #ifndef NDEBUG @@ -178,14 +178,6 @@ void gpu_extensions_init(void) GG.device = GPU_DEVICE_ATI; GG.driver = GPU_DRIVER_OFFICIAL; } - /* XXX : TODO : Remove this once this sampling mipmap problem is gone. - * https://github.com/dfelinto/opengl-sandbox/blob/downsample/README.md */ - else if (strstr(renderer, "AMD VEGA") && - strstr(vendor, "X.Org")) - { - GG.device = GPU_DEVICE_AMD_VEGA; - GG.driver = GPU_DRIVER_OPENSOURCE; - } else if (strstr(vendor, "NVIDIA")) { GG.device = GPU_DEVICE_NVIDIA; GG.driver = GPU_DRIVER_OFFICIAL; diff --git a/source/blender/gpu/intern/gpu_framebuffer.c b/source/blender/gpu/intern/gpu_framebuffer.c index 09013cd29bd..8d8fb50d9b9 100644 --- a/source/blender/gpu/intern/gpu_framebuffer.c +++ b/source/blender/gpu/intern/gpu_framebuffer.c @@ -28,7 +28,9 @@ #include "MEM_guardedalloc.h" #include "BLI_blenlib.h" +#include "BLI_threads.h" #include "BLI_utildefines.h" +#include "BLI_math_base.h" #include "BKE_global.h" @@ -40,20 +42,91 @@ #include "GPU_shader.h" #include "GPU_texture.h" -static struct GPUFrameBufferGlobal { - GLuint currentfb; -} GG = {0}; +static ThreadLocal(GLuint) g_currentfb; -/* Number of maximum output slots. - * We support 5 outputs for now (usually we wouldn't need more to preserve fill rate) */ -#define GPU_FB_MAX_SLOTS 5 +typedef enum { + GPU_FB_DEPTH_ATTACHMENT = 0, + GPU_FB_DEPTH_STENCIL_ATTACHMENT, + GPU_FB_COLOR_ATTACHMENT0, + GPU_FB_COLOR_ATTACHMENT1, + GPU_FB_COLOR_ATTACHMENT2, + GPU_FB_COLOR_ATTACHMENT3, + GPU_FB_COLOR_ATTACHMENT4, + /* Number of maximum output slots. + * We support 5 outputs for now (usually we wouldn't need more to preserve fill rate). */ + /* Keep in mind that GL max is GL_MAX_DRAW_BUFFERS and is at least 8, corresponding to + * the maximum number of COLOR attachments specified by glDrawBuffers. */ + GPU_FB_MAX_ATTACHEMENT +} GPUAttachmentType; + +#define GPU_FB_MAX_COLOR_ATTACHMENT (GPU_FB_MAX_ATTACHEMENT - GPU_FB_COLOR_ATTACHMENT0) + +#define GPU_FB_DIRTY_DRAWBUFFER (1 << 15) + +#define GPU_FB_ATTACHEMENT_IS_DIRTY(flag, type) ((flag & (1 << type)) != 0) +#define GPU_FB_ATTACHEMENT_SET_DIRTY(flag, type) (flag |= (1 << type)) struct GPUFrameBuffer { GLuint object; - GPUTexture *colortex[GPU_FB_MAX_SLOTS]; - GPUTexture *depthtex; + GPUAttachment attachments[GPU_FB_MAX_ATTACHEMENT]; + uint16_t dirty_flag; + int width, height; + bool multisample; + /* TODO Check that we always use the right context when binding + * (FBOs are not shared accross ogl contexts). */ + // void *ctx; }; +static GLenum convert_attachment_type_to_gl(GPUAttachmentType type) +{ + static const GLenum table[] = { + [GPU_FB_DEPTH_ATTACHMENT] = GL_DEPTH_ATTACHMENT, + [GPU_FB_DEPTH_STENCIL_ATTACHMENT] = GL_DEPTH_STENCIL_ATTACHMENT, + [GPU_FB_COLOR_ATTACHMENT0] = GL_COLOR_ATTACHMENT0, + [GPU_FB_COLOR_ATTACHMENT1] = GL_COLOR_ATTACHMENT1, + [GPU_FB_COLOR_ATTACHMENT2] = GL_COLOR_ATTACHMENT2, + [GPU_FB_COLOR_ATTACHMENT3] = GL_COLOR_ATTACHMENT3, + [GPU_FB_COLOR_ATTACHMENT4] = GL_COLOR_ATTACHMENT4 + }; + return table[type]; +} + +static GPUAttachmentType attachment_type_from_tex(GPUTexture *tex, int slot) +{ + 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: + return GPU_FB_DEPTH_STENCIL_ATTACHMENT; + default: + return GPU_FB_COLOR_ATTACHMENT0 + slot; + } +} + +static GLenum convert_buffer_bits_to_gl(GPUFrameBufferBits 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 GPUTexture *framebuffer_get_depth_tex(GPUFrameBuffer *fb) +{ + if (fb->attachments[GPU_FB_DEPTH_ATTACHMENT].tex) + return fb->attachments[GPU_FB_DEPTH_ATTACHMENT].tex; + else + return fb->attachments[GPU_FB_DEPTH_STENCIL_ATTACHMENT].tex;; +} + +static GPUTexture *framebuffer_get_color_tex(GPUFrameBuffer *fb, int slot) +{ + return fb->attachments[GPU_FB_COLOR_ATTACHMENT0 + slot].tex; +} + static void gpu_print_framebuffer_error(GLenum status, char err_out[256]) { const char *format = "GPUFrameBuffer: framebuffer status %s\n"; @@ -94,296 +167,268 @@ static void gpu_print_framebuffer_error(GLenum status, char err_out[256]) GPUFrameBuffer *GPU_framebuffer_create(void) { - GPUFrameBuffer *fb; + /* We generate the FB object later at first use in order to + * create the framebuffer in the right opengl context. */ + return MEM_callocN(sizeof(GPUFrameBuffer), "GPUFrameBuffer");; +} - fb = MEM_callocN(sizeof(GPUFrameBuffer), "GPUFrameBuffer"); +static void gpu_framebuffer_init(GPUFrameBuffer *fb) +{ glGenFramebuffers(1, &fb->object); - - if (!fb->object) { - fprintf(stderr, "GPUFFrameBuffer: framebuffer gen failed.\n"); - GPU_framebuffer_free(fb); - return NULL; - } - - /* make sure no read buffer is enabled, so completeness check will not fail. We set those at binding time */ - glBindFramebuffer(GL_FRAMEBUFFER, fb->object); - glReadBuffer(GL_NONE); - glDrawBuffer(GL_NONE); - glBindFramebuffer(GL_FRAMEBUFFER, 0); - - return fb; } -bool GPU_framebuffer_texture_attach(GPUFrameBuffer *fb, GPUTexture *tex, int slot, int mip) +void GPU_framebuffer_free(GPUFrameBuffer *fb) { - GLenum attachment; - - if (slot >= GPU_FB_MAX_SLOTS) { - fprintf(stderr, - "Attaching to index %d framebuffer slot unsupported. " - "Use at most %d\n", slot, GPU_FB_MAX_SLOTS); - return false; - } - - if ((G.debug & G_DEBUG)) { - if (GPU_texture_bound_number(tex) != -1) { - fprintf(stderr, - "Feedback loop warning!: " - "Attempting to attach texture to framebuffer while still bound to texture unit for drawing!\n"); + for (GPUAttachmentType type = 0; type < GPU_FB_MAX_ATTACHEMENT; type++) { + if (fb->attachments[type].tex != NULL) { + GPU_framebuffer_texture_detach(fb, fb->attachments[type].tex); } } - 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 + slot; - - glFramebufferTexture(GL_FRAMEBUFFER, attachment, GPU_texture_opengl_bindcode(tex), mip); + /* This restores the framebuffer if it was bound */ + glDeleteFramebuffers(1, &fb->object); - if (GPU_texture_depth(tex)) - fb->depthtex = tex; - else - fb->colortex[slot] = tex; - - GPU_texture_framebuffer_set(tex, fb, slot); + if (g_currentfb == fb->object) { + g_currentfb = 0; + } - return true; + MEM_freeN(fb); } -static bool gpu_framebuffer_texture_layer_attach_ex(GPUFrameBuffer *fb, GPUTexture *tex, int slot, int layer, int mip, bool cubemap) -{ - GLenum attachment; - GLenum facetarget; +/* ---------- Attach ----------- */ - if (slot >= GPU_FB_MAX_SLOTS) { +static void gpu_framebuffer_texture_attach_ex(GPUFrameBuffer *fb, GPUTexture *tex, int slot, int layer, int mip) +{ + if (slot >= GPU_FB_MAX_COLOR_ATTACHMENT) { fprintf(stderr, "Attaching to index %d framebuffer slot unsupported. " - "Use at most %d\n", slot, GPU_FB_MAX_SLOTS); - return false; - } - - if ((G.debug & G_DEBUG)) { - if (GPU_texture_bound_number(tex) != -1) { - fprintf(stderr, - "Feedback loop warning!: " - "Attempting to attach texture to framebuffer while still bound to texture unit for drawing!\n"); - } + "Use at most %d\n", slot, GPU_FB_MAX_COLOR_ATTACHMENT); + return; } - 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 + slot; + GPUAttachmentType type = attachment_type_from_tex(tex, slot); + GPUAttachment *attachment = &fb->attachments[type]; - if (cubemap) { - facetarget = GL_TEXTURE_CUBE_MAP_POSITIVE_X + layer; - glFramebufferTexture2D(GL_FRAMEBUFFER, attachment, facetarget, GPU_texture_opengl_bindcode(tex), mip); + if ((attachment->tex == tex) && + (attachment->mip == mip) && + (attachment->layer == layer)) + { + return; /* Exact same texture already bound here. */ } - else { - glFramebufferTextureLayer(GL_FRAMEBUFFER, attachment, GPU_texture_opengl_bindcode(tex), mip, layer); + else if (attachment->tex != NULL) { + GPU_framebuffer_texture_detach(fb, attachment->tex); } - if (GPU_texture_depth(tex)) - fb->depthtex = tex; - else - fb->colortex[slot] = tex; - - GPU_texture_framebuffer_set(tex, fb, slot); + if (attachment->tex == NULL) { + GPU_texture_attach_framebuffer(tex, fb, type); + } - return true; + attachment->tex = tex; + attachment->mip = mip; + attachment->layer = layer; + GPU_FB_ATTACHEMENT_SET_DIRTY(fb->dirty_flag, type); } -bool GPU_framebuffer_texture_layer_attach(GPUFrameBuffer *fb, GPUTexture *tex, int slot, int layer, int mip) +void GPU_framebuffer_texture_attach(GPUFrameBuffer *fb, GPUTexture *tex, int slot, int mip) { - return gpu_framebuffer_texture_layer_attach_ex(fb, tex, slot, layer, mip, false); + gpu_framebuffer_texture_attach_ex(fb, tex, slot, -1, mip); } -bool GPU_framebuffer_texture_cubeface_attach(GPUFrameBuffer *fb, GPUTexture *tex, int slot, int face, int mip) +void GPU_framebuffer_texture_layer_attach(GPUFrameBuffer *fb, GPUTexture *tex, int slot, int layer, int mip) { - BLI_assert(GPU_texture_target(tex) == GL_TEXTURE_CUBE_MAP); - return gpu_framebuffer_texture_layer_attach_ex(fb, tex, slot, face, mip, true); + /* 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); } -void GPU_framebuffer_texture_detach(GPUTexture *tex) +void GPU_framebuffer_texture_cubeface_attach(GPUFrameBuffer *fb, GPUTexture *tex, int slot, int face, int mip) { - GLenum attachment; - GPUFrameBuffer *fb = GPU_texture_framebuffer(tex); - int fb_attachment = GPU_texture_framebuffer_attachment(tex); + BLI_assert(GPU_texture_cube(tex)); + gpu_framebuffer_texture_attach_ex(fb, tex, slot, face, mip); +} - if (!fb) - return; +/* ---------- Detach ----------- */ - if (GG.currentfb != fb->object) { - glBindFramebuffer(GL_FRAMEBUFFER, fb->object); - GG.currentfb = fb->object; - } +void GPU_framebuffer_texture_detach_slot(GPUFrameBuffer *fb, GPUTexture *tex, int type) +{ + GPUAttachment *attachment = &fb->attachments[type]; - if (GPU_texture_stencil(tex) && GPU_texture_depth(tex)) { - fb->depthtex = NULL; - attachment = GL_DEPTH_STENCIL_ATTACHMENT; - } - else if (GPU_texture_depth(tex)) { - fb->depthtex = NULL; - attachment = GL_DEPTH_ATTACHMENT; - } - else { - BLI_assert(fb->colortex[fb_attachment] == tex); - fb->colortex[fb_attachment] = NULL; - attachment = GL_COLOR_ATTACHMENT0 + fb_attachment; + if (attachment->tex != tex) { + fprintf(stderr, + "Warning, attempting to detach Texture %p from framebuffer %p " + "but texture is not attached.\n", tex, fb); + return; } - glFramebufferTexture(GL_FRAMEBUFFER, attachment, 0, 0); + attachment->tex = NULL; + GPU_FB_ATTACHEMENT_SET_DIRTY(fb->dirty_flag, type); +} - GPU_texture_framebuffer_set(tex, NULL, -1); +void GPU_framebuffer_texture_detach(GPUFrameBuffer *fb, GPUTexture *tex) +{ + GPUAttachmentType type = GPU_texture_detach_framebuffer(tex, fb); + GPU_framebuffer_texture_detach_slot(fb, tex, type); } -void GPU_texture_bind_as_framebuffer(GPUTexture *tex) +/* ---------- 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 *fb, const GPUAttachment *config, int config_ct) { - GPUFrameBuffer *fb = GPU_texture_framebuffer(tex); - int fb_attachment = GPU_texture_framebuffer_attachment(tex); + 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(fb, fb->attachments[GPU_FB_DEPTH_ATTACHMENT].tex); + } + else if (fb->attachments[GPU_FB_DEPTH_STENCIL_ATTACHMENT].tex != NULL) { + GPU_framebuffer_texture_detach(fb, fb->attachments[GPU_FB_DEPTH_STENCIL_ATTACHMENT].tex); + } - if (!fb) { - fprintf(stderr, "Error, texture not bound to framebuffer!\n"); - return; + int slot = 0; + for (int i = 1; i < config_ct; ++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 = framebuffer_get_color_tex(fb, slot); + if (tex != NULL) { + GPU_framebuffer_texture_detach(fb, tex); + } + } } +} - /* push attributes */ - gpuPushAttrib(GPU_ENABLE_BIT | GPU_VIEWPORT_BIT); - glDisable(GL_SCISSOR_TEST); +/* ---------- Bind / Restore ----------- */ - /* bind framebuffer */ - glBindFramebuffer(GL_FRAMEBUFFER, fb->object); +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 (GPU_texture_depth(tex)) { - glDrawBuffer(GL_NONE); - glReadBuffer(GL_NONE); + 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); + } } else { - /* last bound prevails here, better allow explicit control here too */ - glDrawBuffer(GL_COLOR_ATTACHMENT0 + fb_attachment); - glReadBuffer(GL_COLOR_ATTACHMENT0 + fb_attachment); - } - - if (GPU_texture_target(tex) == GL_TEXTURE_2D_MULTISAMPLE) { - glEnable(GL_MULTISAMPLE); + glFramebufferTexture(GL_FRAMEBUFFER, gl_attachment, tex_bind, attach->mip); } +} - /* set default viewport */ - glViewport(0, 0, GPU_texture_width(tex), GPU_texture_height(tex)); - GG.currentfb = fb->object; +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); } -void GPU_framebuffer_slots_bind(GPUFrameBuffer *fb, int slot) +static void gpu_framebuffer_update_attachments(GPUFrameBuffer *fb) { - int numslots = 0, i; - GLenum attachments[GPU_FB_MAX_SLOTS]; - - if (!fb->colortex[slot]) { - fprintf(stderr, "Error, framebuffer slot empty!\n"); - return; - } - - for (i = 0; i < GPU_FB_MAX_SLOTS; i++) { - if (fb->colortex[i]) { - attachments[numslots] = GL_COLOR_ATTACHMENT0 + i; + GLenum gl_attachments[GPU_FB_MAX_COLOR_ATTACHMENT]; + int numslots = 0; + + BLI_assert(g_currentfb == fb->object); + + /* Update attachments */ + for (GPUAttachmentType type = 0; type < GPU_FB_MAX_ATTACHEMENT; ++type) { + + 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++; } - } - - /* push attributes */ - gpuPushAttrib(GPU_ENABLE_BIT | GPU_VIEWPORT_BIT); - glDisable(GL_SCISSOR_TEST); - /* bind framebuffer */ - glBindFramebuffer(GL_FRAMEBUFFER, fb->object); + if (GPU_FB_ATTACHEMENT_IS_DIRTY(fb->dirty_flag, type) == false) { + continue; + } + else if (fb->attachments[type].tex != NULL) { + gpu_framebuffer_attachment_attach(&fb->attachments[type], type); - /* last bound prevails here, better allow explicit control here too */ - glDrawBuffers(numslots, attachments); - glReadBuffer(GL_COLOR_ATTACHMENT0 + slot); + 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); + } + } + fb->dirty_flag = 0; - /* set default viewport */ - glViewport(0, 0, GPU_texture_width(fb->colortex[slot]), GPU_texture_height(fb->colortex[slot])); - GG.currentfb = fb->object; + /* Update draw buffers (color targets) + * This state is saved in the FBO */ + if (numslots) + glDrawBuffers(numslots, gl_attachments); + else + glDrawBuffer(GL_NONE); } void GPU_framebuffer_bind(GPUFrameBuffer *fb) { - int numslots = 0, i; - GLenum attachments[GPU_FB_MAX_SLOTS]; - GLenum readattachement = 0; - GPUTexture *tex; + if (fb->object == 0) + gpu_framebuffer_init(fb); - for (i = 0; i < GPU_FB_MAX_SLOTS; i++) { - if (fb->colortex[i]) { - attachments[numslots] = GL_COLOR_ATTACHMENT0 + i; - tex = fb->colortex[i]; + if (g_currentfb != fb->object) + glBindFramebuffer(GL_FRAMEBUFFER, fb->object); - if (!readattachement) - readattachement = GL_COLOR_ATTACHMENT0 + i; + g_currentfb = fb->object; - numslots++; - } - } - - /* bind framebuffer */ - glBindFramebuffer(GL_FRAMEBUFFER, fb->object); + if (fb->dirty_flag != 0) + gpu_framebuffer_update_attachments(fb); - if (numslots == 0) { - glDrawBuffer(GL_NONE); - glReadBuffer(GL_NONE); - tex = fb->depthtex; - } - else { - /* last bound prevails here, better allow explicit control here too */ - glDrawBuffers(numslots, attachments); - glReadBuffer(readattachement); + /* 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 - if (GPU_texture_target(tex) == GL_TEXTURE_2D_MULTISAMPLE) { + if (fb->multisample) glEnable(GL_MULTISAMPLE); - } - glViewport(0, 0, GPU_texture_width(tex), GPU_texture_height(tex)); - GG.currentfb = fb->object; + glViewport(0, 0, fb->width, fb->height); } -void GPU_framebuffer_texture_unbind(GPUFrameBuffer *UNUSED(fb), GPUTexture *UNUSED(tex)) +void GPU_framebuffer_restore(void) { - /* Restore attributes. */ - gpuPopAttrib(); + if (g_currentfb != 0) { + glBindFramebuffer(GL_FRAMEBUFFER, 0); + g_currentfb = 0; + } } -void GPU_framebuffer_bind_no_save(GPUFrameBuffer *fb, int slot) +bool GPU_framebuffer_bound(GPUFrameBuffer *fb) { - glBindFramebuffer(GL_FRAMEBUFFER, fb->object); - /* last bound prevails here, better allow explicit control here too */ - glDrawBuffer(GL_COLOR_ATTACHMENT0 + slot); - glReadBuffer(GL_COLOR_ATTACHMENT0 + slot); - - /* push matrices and set default viewport and matrix */ - glViewport(0, 0, GPU_texture_width(fb->colortex[slot]), GPU_texture_height(fb->colortex[slot])); - GG.currentfb = fb->object; + return (fb->object == g_currentfb) && (fb->object != 0); } -bool GPU_framebuffer_bound(GPUFrameBuffer *fb) +unsigned int GPU_framebuffer_current_get(void) { - return fb->object == GG.currentfb; + return g_currentfb; } bool GPU_framebuffer_check_valid(GPUFrameBuffer *fb, char err_out[256]) { - glBindFramebuffer(GL_FRAMEBUFFER, fb->object); - GG.currentfb = fb->object; + if (!GPU_framebuffer_bound(fb)) + GPU_framebuffer_bind(fb); GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); @@ -396,172 +441,140 @@ bool GPU_framebuffer_check_valid(GPUFrameBuffer *fb, char err_out[256]) return true; } -void GPU_framebuffer_free(GPUFrameBuffer *fb) -{ - int i; - if (fb->depthtex) - GPU_framebuffer_texture_detach(fb->depthtex); - - for (i = 0; i < GPU_FB_MAX_SLOTS; i++) { - if (fb->colortex[i]) { - GPU_framebuffer_texture_detach(fb->colortex[i]); - } - } +/* ---------- Framebuffer Operations ----------- */ - if (fb->object) { - glDeleteFramebuffers(1, &fb->object); +#define CHECK_FRAMEBUFFER_IS_BOUND(_fb) \ + BLI_assert(GPU_framebuffer_bound(_fb)); \ + UNUSED_VARS_NDEBUG(_fb); - if (GG.currentfb == fb->object) { - glBindFramebuffer(GL_FRAMEBUFFER, 0); - GG.currentfb = 0; - } - } +/* Needs to be done after binding. */ +void GPU_framebuffer_viewport_set(GPUFrameBuffer *fb, int x, int y, int w, int h) +{ + CHECK_FRAMEBUFFER_IS_BOUND(fb); - MEM_freeN(fb); + glViewport(x, y, w, h); } -void GPU_framebuffer_restore(void) +void GPU_framebuffer_clear( + GPUFrameBuffer *fb, GPUFrameBufferBits buffers, + const float clear_col[4], float clear_depth, unsigned int clear_stencil) { - if (GG.currentfb != 0) { - glBindFramebuffer(GL_FRAMEBUFFER, 0); - GG.currentfb = 0; + CHECK_FRAMEBUFFER_IS_BOUND(fb); + + if (buffers & GPU_COLOR_BIT) { + glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); + glClearColor(clear_col[0], clear_col[1], clear_col[2], clear_col[3]); + } + if (buffers & GPU_DEPTH_BIT) { + glDepthMask(GL_TRUE); + glClearDepth(clear_depth); } + if (buffers & GPU_STENCIL_BIT) { + glStencilMask(clear_stencil); + } + + GLbitfield mask = convert_buffer_bits_to_gl(buffers); + glClear(mask); } -void GPU_framebuffer_blur( - GPUFrameBuffer *fb, GPUTexture *tex, - GPUFrameBuffer *blurfb, GPUTexture *blurtex) +void GPU_framebuffer_read_depth(GPUFrameBuffer *fb, int x, int y, int w, int h, float *data) { - const float fullscreencos[4][2] = {{-1.0f, -1.0f}, {1.0f, -1.0f}, {-1.0f, 1.0f}, {1.0f, 1.0f}}; - const float fullscreenuvs[4][2] = {{0.0f, 0.0f}, {1.0f, 0.0f}, {0.0f, 1.0f}, {1.0f, 1.0f}}; - - static Gwn_VertFormat format = {0}; - static Gwn_VertBuf vbo = {{0}}; - static Gwn_Batch batch = {{0}}; - - const float scaleh[2] = {1.0f / GPU_texture_width(blurtex), 0.0f}; - const float scalev[2] = {0.0f, 1.0f / GPU_texture_height(tex)}; - - GPUShader *blur_shader = GPU_shader_get_builtin_shader(GPU_SHADER_SEP_GAUSSIAN_BLUR); + CHECK_FRAMEBUFFER_IS_BOUND(fb); - if (!blur_shader) - return; - - /* Preparing to draw quad */ - if (format.attrib_ct == 0) { - unsigned int i = 0; - /* Vertex format */ - unsigned int pos = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT); - unsigned int uvs = GWN_vertformat_attr_add(&format, "uvs", GWN_COMP_F32, 2, GWN_FETCH_FLOAT); - - /* Vertices */ - GWN_vertbuf_init_with_format(&vbo, &format); - GWN_vertbuf_data_alloc(&vbo, 36); - - for (int j = 0; j < 3; ++j) { - GWN_vertbuf_attr_set(&vbo, uvs, i, fullscreenuvs[j]); - GWN_vertbuf_attr_set(&vbo, pos, i++, fullscreencos[j]); - } - for (int j = 1; j < 4; ++j) { - GWN_vertbuf_attr_set(&vbo, uvs, i, fullscreenuvs[j]); - GWN_vertbuf_attr_set(&vbo, pos, i++, fullscreencos[j]); - } + GLenum type = GL_DEPTH_COMPONENT; + glReadBuffer(GL_COLOR_ATTACHMENT0); /* This is OK! */ + glReadPixels(x, y, w, h, type, GL_FLOAT, data); +} - GWN_batch_init(&batch, GL_TRIANGLES, &vbo, NULL); +void GPU_framebuffer_read_color( + GPUFrameBuffer *fb, int x, int y, int w, int h, int channels, int slot, float *data) +{ + CHECK_FRAMEBUFFER_IS_BOUND(fb); + + GLenum type; + switch (channels) { + case 1: type = GL_RED; break; + case 2: type = GL_RG; break; + case 3: type = GL_RGB; break; + case 4: type = GL_RGBA; break; + default: + BLI_assert(false && "wrong number of read channels"); + return; } - - glDisable(GL_DEPTH_TEST); - - /* Blurring horizontally */ - /* We do the bind ourselves rather than using GPU_framebuffer_texture_bind() to avoid - * pushing unnecessary matrices onto the OpenGL stack. */ - glBindFramebuffer(GL_FRAMEBUFFER, blurfb->object); - glDrawBuffer(GL_COLOR_ATTACHMENT0); - - /* avoid warnings from texture binding */ - GG.currentfb = blurfb->object; - - glViewport(0, 0, GPU_texture_width(blurtex), GPU_texture_height(blurtex)); + glReadBuffer(GL_COLOR_ATTACHMENT0 + slot); + glReadPixels(x, y, w, h, type, GL_FLOAT, data); +} - GPU_texture_bind(tex, 0); +/* read_slot and write_slot are only used for color buffers. */ +void GPU_framebuffer_blit( + GPUFrameBuffer *fb_read, int read_slot, + GPUFrameBuffer *fb_write, int write_slot, + GPUFrameBufferBits blit_buffers) +{ + BLI_assert(blit_buffers != 0); - GWN_batch_program_set_builtin(&batch, GPU_SHADER_SEP_GAUSSIAN_BLUR); - GWN_batch_uniform_2f(&batch, "ScaleU", scaleh[0], scaleh[1]); - GWN_batch_uniform_1i(&batch, "textureSource", GL_TEXTURE0); - GWN_batch_draw(&batch); + GLuint prev_fb = g_currentfb; - /* Blurring vertically */ - glBindFramebuffer(GL_FRAMEBUFFER, fb->object); - glDrawBuffer(GL_COLOR_ATTACHMENT0); - - GG.currentfb = fb->object; - - glViewport(0, 0, GPU_texture_width(tex), GPU_texture_height(tex)); + /* Framebuffers must be up to date. This simplify this function. */ + if (fb_read->dirty_flag != 0 || fb_read->object == 0) { + GPU_framebuffer_bind(fb_read); + } + if (fb_write->dirty_flag != 0 || fb_write->object == 0) { + GPU_framebuffer_bind(fb_write); + } - GPU_texture_bind(blurtex, 0); + 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); - /* Hack to make the following uniform stick */ - GWN_batch_program_set_builtin(&batch, GPU_SHADER_SEP_GAUSSIAN_BLUR); - GWN_batch_uniform_2f(&batch, "ScaleU", scalev[0], scalev[1]); - GWN_batch_uniform_1i(&batch, "textureSource", GL_TEXTURE0); - GWN_batch_draw(&batch); -} + GPUTexture *read_tex = (do_depth || do_stencil) + ? framebuffer_get_depth_tex(fb_read) + : framebuffer_get_color_tex(fb_read, read_slot); + GPUTexture *write_tex = (do_depth || do_stencil) + ? framebuffer_get_depth_tex(fb_write) + : framebuffer_get_color_tex(fb_write, read_slot); -void GPU_framebuffer_blit( - GPUFrameBuffer *fb_read, int read_slot, GPUFrameBuffer *fb_write, - int write_slot, bool use_depth, bool use_stencil) -{ - GPUTexture *read_tex = (use_depth || use_stencil) ? fb_read->depthtex : fb_read->colortex[read_slot]; - GPUTexture *write_tex = (use_depth || use_stencil) ? fb_write->depthtex : fb_write->colortex[write_slot]; - int read_attach = (use_depth) ? GL_DEPTH_ATTACHMENT : - (use_stencil) ? GL_DEPTH_STENCIL_ATTACHMENT : - GL_COLOR_ATTACHMENT0 + GPU_texture_framebuffer_attachment(read_tex); - int write_attach = (use_depth) ? GL_DEPTH_ATTACHMENT : - (use_stencil) ? GL_DEPTH_STENCIL_ATTACHMENT : - GL_COLOR_ATTACHMENT0 + GPU_texture_framebuffer_attachment(write_tex); - int read_bind = GPU_texture_opengl_bindcode(read_tex); - int write_bind = GPU_texture_opengl_bindcode(write_tex); - const int read_w = GPU_texture_width(read_tex); - const int read_h = GPU_texture_height(read_tex); - const int write_w = GPU_texture_width(write_tex); - const int write_h = GPU_texture_height(write_tex); - - - /* Never both! */ - BLI_assert(!(use_depth && use_stencil)); - - if (use_depth) { + if (do_depth) { BLI_assert(GPU_texture_depth(read_tex) && GPU_texture_depth(write_tex)); BLI_assert(GPU_texture_format(read_tex) == GPU_texture_format(write_tex)); } - else if (use_stencil) { + if (do_stencil) { 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)); + } - /* read from multi-sample buffer */ glBindFramebuffer(GL_READ_FRAMEBUFFER, fb_read->object); - glFramebufferTexture2D( - GL_READ_FRAMEBUFFER, read_attach, - GPU_texture_target(read_tex), read_bind, 0); - BLI_assert(glCheckFramebufferStatus(GL_READ_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE); - - /* write into new single-sample buffer */ glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fb_write->object); - glFramebufferTexture2D( - GL_DRAW_FRAMEBUFFER, write_attach, - GPU_texture_target(write_tex), write_bind, 0); - BLI_assert(glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE); - glDrawBuffer((use_depth || use_stencil) ? GL_COLOR_ATTACHMENT0 : read_attach); - glBlitFramebuffer(0, 0, read_w, read_h, 0, 0, write_w, write_h, - (use_depth) ? GL_DEPTH_BUFFER_BIT : - (use_stencil) ? GL_STENCIL_BUFFER_BIT : - GL_COLOR_BUFFER_BIT, GL_NEAREST); + 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; + } + + GLbitfield mask = convert_buffer_bits_to_gl(blit_buffers); + + glBlitFramebuffer(0, 0, fb_read->width, fb_read->height, + 0, 0, fb_write->width, fb_write->height, + mask, GL_NEAREST); /* Restore previous framebuffer */ - glBindFramebuffer(GL_FRAMEBUFFER, GG.currentfb); - glDrawBuffer(GL_COLOR_ATTACHMENT0); + if (fb_write->object == prev_fb) { + GPU_framebuffer_bind(fb_write); /* To update drawbuffers */ + } + else { + glBindFramebuffer(GL_FRAMEBUFFER, prev_fb); + g_currentfb = prev_fb; + } } /** @@ -569,77 +582,65 @@ void GPU_framebuffer_blit( * 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) + GPUFrameBuffer *fb, int max_lvl, + void (*callback)(void *userData, int level), void *userData) { - int i; - 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 */ - if (GPU_texture_depth(tex)) { - glDrawBuffer(GL_NONE); - glReadBuffer(GL_NONE); - } - else { - glDrawBuffer(GL_COLOR_ATTACHMENT0); - glReadBuffer(GL_COLOR_ATTACHMENT0); + /* Framebuffer must be up to date and bound. This simplify this function. */ + if (g_currentfb != fb->object || fb->dirty_flag != 0 || fb->object == 0) { + GPU_framebuffer_bind(fb); } + /* HACK: We make the framebuffer appear not bound in order to + * not trigger any error in GPU_texture_bind(). */ + GLuint prev_fb = g_currentfb; + g_currentfb = 0; - for (i = 1; i < num_iter + 1; i++) { - + 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] /= 2; - current_dim[1] /= 2; - - if (GPU_type_matches(GPU_DEVICE_AMD_VEGA, GPU_OS_UNIX, GPU_DRIVER_OPENSOURCE)) { - /* NOTE : here 16 is because of a bug on AMD Vega GPU + non-pro drivers, that prevents us - * from sampling mipmaps that are smaller or equal to 16px. (9) */ - if (current_dim[0] <= 16 && current_dim[1] <= 16) { - break; - } - } - else { - if (current_dim[0] <= 2 && current_dim[1] <= 2) { - /* Cannot reduce further. */ - break; + current_dim[0] = max_ii(current_dim[0] / 2, 1); + current_dim[1] = max_ii(current_dim[1] / 2, 1); + + for (GPUAttachmentType type = 0; type < GPU_FB_MAX_ATTACHEMENT; ++type) { + if (fb->attachments[type].tex != NULL) { + /* 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, i - 1); + GPU_texture_unbind(tex); + /* copy attachment and replace miplevel. */ + GPUAttachment attachment = fb->attachments[type]; + attachment.mip = i; + gpu_framebuffer_attachment_attach(&attachment, type); } } - /* ensure that the viewport size is always at least 1x1 */ - CLAMP_MIN(current_dim[0], 1); - CLAMP_MIN(current_dim[1], 1); + BLI_assert(GL_FRAMEBUFFER_COMPLETE == glCheckFramebufferStatus(GL_FRAMEBUFFER)); 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(GPU_texture_target(tex), GL_TEXTURE_BASE_LEVEL, i - 1); - glTexParameteri(GPU_texture_target(tex), GL_TEXTURE_MAX_LEVEL, i - 1); - GPU_texture_unbind(tex); - - glFramebufferTexture(GL_FRAMEBUFFER, attachment, GPU_texture_opengl_bindcode(tex), i); - callback(userData, i); - } - glFramebufferTexture(GL_FRAMEBUFFER, attachment, 0, 0); + if (current_dim[0] == 1 && current_dim[1] == 1) + break; + } + + for (GPUAttachmentType type = 0; type < GPU_FB_MAX_ATTACHEMENT; ++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); + } + } - /* reset mipmap level range for the depth image */ - 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); + g_currentfb = prev_fb; } /* GPUOffScreen */ @@ -650,55 +651,29 @@ struct GPUOffScreen { GPUTexture *depth; }; -GPUOffScreen *GPU_offscreen_create(int width, int height, int samples, bool high_bitdepth, char err_out[256]) +GPUOffScreen *GPU_offscreen_create(int width, int height, int samples, bool depth, bool high_bitdepth, char err_out[256]) { GPUOffScreen *ofs; ofs = MEM_callocN(sizeof(GPUOffScreen), "GPUOffScreen"); - ofs->fb = GPU_framebuffer_create(); - if (!ofs->fb) { - GPU_offscreen_free(ofs); - return NULL; - } - - if (samples) { - if (!GLEW_ARB_texture_multisample || - /* This is required when blitting from a multi-sampled buffers, - * even though we're not scaling. */ - !GLEW_EXT_framebuffer_multisample_blit_scaled) - { - samples = 0; - } - } - - ofs->depth = GPU_texture_create_depth_with_stencil_multisample(width, height, samples, err_out); - if (!ofs->depth) { - GPU_offscreen_free(ofs); - return NULL; - } - - if (!GPU_framebuffer_texture_attach(ofs->fb, ofs->depth, 0, 0)) { - GPU_offscreen_free(ofs); - return NULL; - } + ofs->color = GPU_texture_create_2D_custom_multisample(width, height, 4, + (high_bitdepth) ? GPU_RGBA16F : GPU_RGBA8, NULL, samples, err_out); - if (high_bitdepth) { - ofs->color = GPU_texture_create_2D_custom_multisample(width, height, 4, GPU_RGBA16F, NULL, samples, err_out); - } - else { - ofs->color = GPU_texture_create_2D_multisample(width, height, NULL, samples, err_out); - } - if (!ofs->color) { - GPU_offscreen_free(ofs); - return NULL; + if (depth) { + ofs->depth = GPU_texture_create_depth_with_stencil_multisample(width, height, samples, err_out); } - if (!GPU_framebuffer_texture_attach(ofs->fb, ofs->color, 0, 0)) { + if (!ofs->depth || !ofs->color) { GPU_offscreen_free(ofs); return NULL; } + GPU_framebuffer_ensure_config(&ofs->fb, { + GPU_ATTACHMENT_TEXTURE(ofs->depth), + GPU_ATTACHMENT_TEXTURE(ofs->color) + }); + /* check validity at the very end! */ if (!GPU_framebuffer_check_valid(ofs->fb, err_out)) { GPU_offscreen_free(ofs); @@ -724,20 +699,19 @@ void GPU_offscreen_free(GPUOffScreen *ofs) void GPU_offscreen_bind(GPUOffScreen *ofs, bool save) { - glDisable(GL_SCISSOR_TEST); - if (save) - GPU_texture_bind_as_framebuffer(ofs->color); - else { - GPU_framebuffer_bind_no_save(ofs->fb, 0); + if (save) { + gpuPushAttrib(GPU_SCISSOR_BIT | GPU_VIEWPORT_BIT); } + glDisable(GL_SCISSOR_TEST); + GPU_framebuffer_bind(ofs->fb); } -void GPU_offscreen_unbind(GPUOffScreen *ofs, bool restore) +void GPU_offscreen_unbind(GPUOffScreen *UNUSED(ofs), bool restore) { - if (restore) - GPU_framebuffer_texture_unbind(ofs->fb, ofs->color); GPU_framebuffer_restore(); - glEnable(GL_SCISSOR_TEST); + if (restore) { + gpuPopAttrib(); + } } void GPU_offscreen_read_pixels(GPUOffScreen *ofs, int type, void *pixels) @@ -745,46 +719,28 @@ void GPU_offscreen_read_pixels(GPUOffScreen *ofs, int type, void *pixels) const int w = GPU_texture_width(ofs->color); const int h = GPU_texture_height(ofs->color); + BLI_assert(type == GL_UNSIGNED_BYTE || type == GL_FLOAT); + if (GPU_texture_target(ofs->color) == GL_TEXTURE_2D_MULTISAMPLE) { /* For a multi-sample texture, * we need to create an intermediate buffer to blit to, * before its copied using 'glReadPixels' */ - - /* not needed since 'ofs' needs to be bound to the framebuffer already */ -// #define USE_FBO_CTX_SWITCH - GLuint fbo_blit = 0; GLuint tex_blit = 0; - GLenum status; /* create texture for new 'fbo_blit' */ glGenTextures(1, &tex_blit); - if (!tex_blit) { - goto finally; - } - glBindTexture(GL_TEXTURE_2D, tex_blit); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, w, h, 0, GL_RGBA, type, 0); - -#ifdef USE_FBO_CTX_SWITCH - /* read from multi-sample buffer */ - glBindFramebuffer(GL_READ_FRAMEBUFFER, ofs->color->fb->object); - glFramebufferTexture2D( - GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + ofs->color->fb_attachment, - GL_TEXTURE_2D_MULTISAMPLE, ofs->color->bindcode, 0); - status = glCheckFramebufferStatus(GL_READ_FRAMEBUFFER); - if (status != GL_FRAMEBUFFER_COMPLETE) { - goto finally; - } -#endif + glTexImage2D(GL_TEXTURE_2D, 0, (type == GL_FLOAT) ? GL_RGBA16F : GL_RGBA8, + w, h, 0, GL_RGBA, type, 0); /* write into new single-sample buffer */ glGenFramebuffers(1, &fbo_blit); glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo_blit); - glFramebufferTexture2D( - GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, - GL_TEXTURE_2D, tex_blit, 0); - status = glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER); + glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, + GL_TEXTURE_2D, tex_blit, 0); + + GLenum status = glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER); if (status != GL_FRAMEBUFFER_COMPLETE) { goto finally; } @@ -796,21 +752,13 @@ void GPU_offscreen_read_pixels(GPUOffScreen *ofs, int type, void *pixels) glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo_blit); glReadPixels(0, 0, w, h, GL_RGBA, type, pixels); -#ifdef USE_FBO_CTX_SWITCH /* restore the original frame-bufer */ - glBindFramebuffer(GL_FRAMEBUFFER, ofs->color->fb->object); -#undef USE_FBO_CTX_SWITCH -#endif - + glBindFramebuffer(GL_FRAMEBUFFER, ofs->fb->object); finally: /* cleanup */ - if (tex_blit) { - glDeleteTextures(1, &tex_blit); - } - if (fbo_blit) { - glDeleteFramebuffers(1, &fbo_blit); - } + glDeleteTextures(1, &tex_blit); + glDeleteFramebuffers(1, &fbo_blit); } else { glReadPixels(0, 0, w, h, GL_RGBA, type, pixels); @@ -827,9 +775,9 @@ int GPU_offscreen_height(const GPUOffScreen *ofs) return GPU_texture_height(ofs->color); } -int GPU_offscreen_color_texture(const GPUOffScreen *ofs) +GPUTexture *GPU_offscreen_color_texture(const GPUOffScreen *ofs) { - return GPU_texture_opengl_bindcode(ofs->color); + return ofs->color; } /* only to be used by viewport code! */ diff --git a/source/blender/gpu/intern/gpu_lamp.c b/source/blender/gpu/intern/gpu_lamp.c index 3c49c057b49..8968521060d 100644 --- a/source/blender/gpu/intern/gpu_lamp.c +++ b/source/blender/gpu/intern/gpu_lamp.c @@ -49,6 +49,7 @@ #include "GPU_material.h" #include "GPU_shader.h" #include "GPU_texture.h" +#include "GPU_batch.h" #include "gpu_lamp_private.h" @@ -266,90 +267,35 @@ GPULamp *GPU_lamp_from_blender(Scene *scene, Object *ob, Object *par) if ((la->type == LA_SPOT && (la->mode & (LA_SHAD_BUF | LA_SHAD_RAY))) || (la->type == LA_SUN && (la->mode & LA_SHAD_RAY))) { - /* opengl */ - lamp->fb = GPU_framebuffer_create(); - if (!lamp->fb) { - gpu_lamp_shadow_free(lamp); - return lamp; - } - if (lamp->la->shadowmap_type == LA_SHADMAP_VARIANCE) { - /* Shadow depth map */ lamp->depthtex = GPU_texture_create_depth(lamp->size, lamp->size, NULL); - if (!lamp->depthtex) { - gpu_lamp_shadow_free(lamp); - return lamp; - } - - GPU_texture_bind(lamp->depthtex, 0); - GPU_texture_compare_mode(lamp->depthtex, true); - GPU_texture_unbind(lamp->depthtex); - - if (!GPU_framebuffer_texture_attach(lamp->fb, lamp->depthtex, 0, 0)) { - gpu_lamp_shadow_free(lamp); - return lamp; - } - - /* Shadow color map */ lamp->tex = gpu_lamp_create_vsm_shadow_map(lamp->size); - if (!lamp->tex) { - gpu_lamp_shadow_free(lamp); - return lamp; - } - - if (!GPU_framebuffer_texture_attach(lamp->fb, lamp->tex, 0, 0)) { - gpu_lamp_shadow_free(lamp); - return lamp; - } - - if (!GPU_framebuffer_check_valid(lamp->fb, NULL)) { - gpu_lamp_shadow_free(lamp); - return lamp; - } - - /* FBO and texture for blurring */ - lamp->blurfb = GPU_framebuffer_create(); - if (!lamp->blurfb) { - gpu_lamp_shadow_free(lamp); - return lamp; - } - lamp->blurtex = gpu_lamp_create_vsm_shadow_map(lamp->size * 0.5); - if (!lamp->blurtex) { - gpu_lamp_shadow_free(lamp); - return lamp; - } - if (!GPU_framebuffer_texture_attach(lamp->blurfb, lamp->blurtex, 0, 0)) { - gpu_lamp_shadow_free(lamp); - return lamp; - } + lamp->fb = GPU_framebuffer_create(); + GPU_framebuffer_texture_attach(lamp->fb, lamp->depthtex, 0, 0); + GPU_framebuffer_texture_attach(lamp->fb, lamp->tex, 0, 0); - /* we need to properly bind to test for completeness */ - GPU_texture_bind_as_framebuffer(lamp->blurtex); + lamp->blurfb = GPU_framebuffer_create(); + GPU_framebuffer_texture_attach(lamp->blurfb, lamp->blurtex, 0, 0); - if (!GPU_framebuffer_check_valid(lamp->blurfb, NULL)) { + if (!GPU_framebuffer_check_valid(lamp->fb, NULL) || + !GPU_framebuffer_check_valid(lamp->blurfb, NULL)) + { gpu_lamp_shadow_free(lamp); return lamp; } - - GPU_framebuffer_texture_unbind(lamp->blurfb, lamp->blurtex); } else { lamp->tex = GPU_texture_create_depth(lamp->size, lamp->size, NULL); - if (!lamp->tex) { - gpu_lamp_shadow_free(lamp); - return lamp; - } GPU_texture_bind(lamp->tex, 0); GPU_texture_compare_mode(lamp->tex, true); + GPU_texture_filter_mode(lamp->tex, true); GPU_texture_unbind(lamp->tex); - if (!GPU_framebuffer_texture_attach(lamp->fb, lamp->tex, 0, 0)) { - gpu_lamp_shadow_free(lamp); - return lamp; - } + lamp->fb = GPU_framebuffer_create(); + GPU_framebuffer_texture_attach(lamp->fb, lamp->tex, 0, 0); if (!GPU_framebuffer_check_valid(lamp->fb, NULL)) { gpu_lamp_shadow_free(lamp); @@ -437,7 +383,7 @@ void GPU_lamp_shadow_buffer_bind(GPULamp *lamp, float viewmat[4][4], int *winsiz /* opengl */ glDisable(GL_SCISSOR_TEST); - GPU_texture_bind_as_framebuffer(lamp->tex); + GPU_framebuffer_bind(lamp->fb); if (lamp->la->shadowmap_type == LA_SHADMAP_VARIANCE) GPU_shader_bind(GPU_shader_get_builtin_shader(GPU_SHADER_VSM_STORE)); @@ -447,14 +393,45 @@ void GPU_lamp_shadow_buffer_bind(GPULamp *lamp, float viewmat[4][4], int *winsiz *winsize = lamp->size; } +static void gpu_lamp_shadow_blur(GPULamp *lamp) +{ + const float scaleh[2] = {1.0f / GPU_texture_width(lamp->blurtex), 0.0f}; + const float scalev[2] = {0.0f, 1.0f / GPU_texture_height(lamp->tex)}; + + GPUShader *blur_shader = GPU_shader_get_builtin_shader(GPU_SHADER_SEP_GAUSSIAN_BLUR); + + if (!blur_shader) + return; + + int tex_loc = GPU_shader_get_uniform(blur_shader, "textureSource"); + int scale_loc = GPU_shader_get_uniform(blur_shader, "ScaleU"); + + glDisable(GL_DEPTH_TEST); + + GPU_shader_bind(blur_shader); + + /* Blurring horizontally */ + GPU_framebuffer_bind(lamp->blurfb); + GPU_texture_bind(lamp->tex, 0); + GPU_shader_uniform_vector(blur_shader, scale_loc, 2, 1, scaleh); + GPU_shader_uniform_texture(blur_shader, tex_loc, lamp->tex); + GWN_draw_primitive(GL_TRIANGLES, 3); + + /* Blurring vertically */ + GPU_framebuffer_bind(lamp->fb); + GPU_texture_bind(lamp->blurtex, 0); + GPU_shader_uniform_vector(blur_shader, scale_loc, 2, 1, scalev); + GPU_shader_uniform_texture(blur_shader, tex_loc, lamp->blurtex); + GWN_draw_primitive(GL_TRIANGLES, 3); +} + void GPU_lamp_shadow_buffer_unbind(GPULamp *lamp) { if (lamp->la->shadowmap_type == LA_SHADMAP_VARIANCE) { GPU_shader_unbind(); - GPU_framebuffer_blur(lamp->fb, lamp->tex, lamp->blurfb, lamp->blurtex); + gpu_lamp_shadow_blur(lamp); } - GPU_framebuffer_texture_unbind(lamp->fb, lamp->tex); GPU_framebuffer_restore(); glEnable(GL_SCISSOR_TEST); } diff --git a/source/blender/gpu/intern/gpu_material.c b/source/blender/gpu/intern/gpu_material.c index 2e6c1cbf9df..a408a41513a 100644 --- a/source/blender/gpu/intern/gpu_material.c +++ b/source/blender/gpu/intern/gpu_material.c @@ -68,6 +68,8 @@ #include "GPU_texture.h" #include "GPU_uniformbuffer.h" +#include "DRW_engine.h" + #include "gpu_codegen.h" #include "gpu_lamp_private.h" @@ -103,6 +105,7 @@ struct GPUMaterial { /* material for mesh surface, worlds or something else. * some code generation is done differently depending on the use case */ int type; /* DEPRECATED */ + GPUMaterialStatus status; const void *engine_type; /* attached engine type */ int options; /* to identify shader variations (shadow, probe, world background...) */ @@ -113,6 +116,7 @@ struct GPUMaterial { /* for binding the material */ GPUPass *pass; + ListBase inputs; /* GPUInput */ GPUVertexAttribs attribs; int builtins; int alpha, obcolalpha; @@ -142,7 +146,10 @@ struct GPUMaterial { */ int domain; + /* Used by 2.8 pipeline */ GPUUniformBuffer *ubo; /* UBOs for shader uniforms. */ + + /* Eevee SSS */ GPUUniformBuffer *sss_profile; /* UBO containing SSS profile. */ GPUTexture *sss_tex_profile; /* Texture containing SSS profile. */ float *sss_radii; /* UBO containing SSS profile. */ @@ -215,12 +222,14 @@ static int gpu_material_construct_end(GPUMaterial *material, const char *passnam { if (material->outlink) { GPUNodeLink *outlink = material->outlink; - material->pass = GPU_generate_pass(&material->nodes, outlink, + material->pass = GPU_generate_pass(&material->nodes, &material->inputs, outlink, &material->attribs, &material->builtins, material->type, passname, material->is_opensubdiv, GPU_material_use_new_shading_nodes(material)); + material->status = (material->pass) ? GPU_MAT_SUCCESS : GPU_MAT_FAILED; + if (!material->pass) return 0; @@ -270,8 +279,14 @@ void GPU_material_free(ListBase *gpumaterial) for (LinkData *link = gpumaterial->first; link; link = link->next) { GPUMaterial *material = link->data; + /* Cancel / wait any pending lazy compilation. */ + DRW_deferred_shader_remove(material); + + GPU_pass_free_nodes(&material->nodes); + GPU_inputs_free(&material->inputs); + if (material->pass) - GPU_pass_free(material->pass); + GPU_pass_release(material->pass); if (material->ubo != NULL) { GPU_uniformbuffer_free(material->ubo); @@ -343,7 +358,7 @@ void GPU_material_bind( } /* note material must be bound before setting uniforms */ - GPU_pass_bind(material->pass, time, mipmap); + GPU_pass_bind(material->pass, &material->inputs, time, mipmap); /* handle per material built-ins */ if (material->builtins & GPU_VIEW_MATRIX) { @@ -363,7 +378,7 @@ void GPU_material_bind( } } - GPU_pass_update_uniforms(material->pass); + GPU_pass_update_uniforms(material->pass, &material->inputs); material->bound = 1; } @@ -417,7 +432,7 @@ void GPU_material_bind_uniforms( GPU_shader_uniform_vector(shader, material->partscalarpropsloc, 4, 1, pi->scalprops); } if (material->builtins & GPU_PARTICLE_LOCATION) { - GPU_shader_uniform_vector(shader, material->partcoloc, 3, 1, pi->location); + GPU_shader_uniform_vector(shader, material->partcoloc, 4, 1, pi->location); } if (material->builtins & GPU_PARTICLE_VELOCITY) { GPU_shader_uniform_vector(shader, material->partvel, 3, 1, pi->velocity); @@ -436,7 +451,7 @@ void GPU_material_unbind(GPUMaterial *material) { if (material->pass) { material->bound = 0; - GPU_pass_unbind(material->pass); + GPU_pass_unbind(material->pass, &material->inputs); } } @@ -460,6 +475,11 @@ GPUPass *GPU_material_get_pass(GPUMaterial *material) return material->pass; } +ListBase *GPU_material_get_inputs(GPUMaterial *material) +{ + return &material->inputs; +} + GPUUniformBuffer *GPU_material_get_uniform_buffer(GPUMaterial *material) { return material->ubo; @@ -557,7 +577,9 @@ static float eval_profile(float r, short falloff_type, float sharpness, float pa { r = fabsf(r); - if (falloff_type == SHD_SUBSURFACE_BURLEY) { + if (falloff_type == SHD_SUBSURFACE_BURLEY || + falloff_type == SHD_SUBSURFACE_RANDOM_WALK) + { return burley_profile(r, param) / BURLEY_TRUNCATE_CDF; } else if (falloff_type == SHD_SUBSURFACE_CUBIC) { @@ -598,7 +620,9 @@ static void compute_sss_kernel( /* Christensen-Burley fitting */ float l[3], d[3]; - if (falloff_type == SHD_SUBSURFACE_BURLEY) { + if (falloff_type == SHD_SUBSURFACE_BURLEY || + falloff_type == SHD_SUBSURFACE_RANDOM_WALK) + { mul_v3_v3fl(l, rad, 0.25f * M_1_PI); const float A = 1.0f; const float s = 1.9f - A + 3.5f * (A - 0.8f) * (A - 0.8f); @@ -825,6 +849,12 @@ void gpu_material_add_node(GPUMaterial *material, GPUNode *node) BLI_addtail(&material->nodes, node); } +/* Return true if the material compilation has not yet begin or begin. */ +GPUMaterialStatus GPU_material_status(GPUMaterial *mat) +{ + return mat->status; +} + /* Code generation */ bool GPU_material_do_color_management(GPUMaterial *mat) @@ -2486,10 +2516,8 @@ GPUMaterial *GPU_material_from_nodetree_find( */ GPUMaterial *GPU_material_from_nodetree( Scene *scene, struct bNodeTree *ntree, ListBase *gpumaterials, const void *engine_type, int options, - const char *vert_code, const char *geom_code, const char *frag_lib, const char *defines) + const char *vert_code, const char *geom_code, const char *frag_lib, const char *defines, bool deferred) { - GPUMaterial *mat; - GPUNodeLink *outlink; LinkData *link; bool has_volume_output, has_surface_output; @@ -2497,7 +2525,7 @@ GPUMaterial *GPU_material_from_nodetree( BLI_assert(GPU_material_from_nodetree_find(gpumaterials, engine_type, options) == NULL); /* allocate material */ - mat = GPU_material_construct_begin(NULL); /* TODO remove GPU_material_construct_begin */ + GPUMaterial *mat = MEM_callocN(sizeof(GPUMaterial), "GPUMaterial");; mat->scene = scene; mat->engine_type = engine_type; mat->options = options; @@ -2512,11 +2540,15 @@ GPUMaterial *GPU_material_from_nodetree( mat->domain |= GPU_DOMAIN_VOLUME; } - /* Let Draw manager finish the construction. */ - if (mat->outlink) { - outlink = mat->outlink; - mat->pass = GPU_generate_pass_new( - mat, &mat->nodes, outlink, &mat->attribs, vert_code, geom_code, frag_lib, defines); + if (!deferred) { + GPU_material_generate_pass(mat, vert_code, geom_code, frag_lib, defines); + } + else if (mat->outlink) { + /* Prune the unused nodes and extract attribs before compiling so the + * generated VBOs are ready to accept the future shader. */ + GPU_nodes_prune(&mat->nodes, mat->outlink); + GPU_nodes_get_vertex_attributes(&mat->nodes, &mat->attribs); + mat->status = GPU_MAT_QUEUED; } /* note that even if building the shader fails in some way, we still keep @@ -2530,6 +2562,21 @@ GPUMaterial *GPU_material_from_nodetree( return mat; } +/* Calls this function if /a mat was created with deferred compilation. */ +void GPU_material_generate_pass( + GPUMaterial *mat, const char *vert_code, const char *geom_code, const char *frag_lib, const char *defines) +{ + BLI_assert(mat->pass == NULL); /* Only run once! */ + if (mat->outlink) { + mat->pass = GPU_generate_pass_new( + mat, mat->outlink, &mat->attribs, &mat->nodes, &mat->inputs, vert_code, geom_code, frag_lib, defines); + mat->status = (mat->pass) ? GPU_MAT_SUCCESS : GPU_MAT_FAILED; + } + else { + mat->status = GPU_MAT_FAILED; + } +} + GPUMaterial *GPU_material_from_blender(Scene *scene, Material *ma, bool use_opensubdiv) { GPUMaterial *mat; @@ -2692,7 +2739,7 @@ GPUShaderExport *GPU_shader_export(struct Scene *scene, struct Material *ma) if (pass && pass->fragmentcode && pass->vertexcode) { shader = MEM_callocN(sizeof(GPUShaderExport), "GPUShaderExport"); - for (input = pass->inputs.first; input; input = input->next) { + for (input = mat->inputs.first; input; input = input->next) { GPUInputUniform *uniform = MEM_callocN(sizeof(GPUInputUniform), "GPUInputUniform"); if (input->ima) { @@ -2869,7 +2916,7 @@ void GPU_material_update_fvar_offset(GPUMaterial *gpu_material, { GPUPass *pass = gpu_material->pass; GPUShader *shader = (pass != NULL ? pass->shader : NULL); - ListBase *inputs = (pass != NULL ? &pass->inputs : NULL); + ListBase *inputs = (pass != NULL ? &gpu_material->inputs : NULL); GPUInput *input; if (shader == NULL) { diff --git a/source/blender/gpu/intern/gpu_select.c b/source/blender/gpu/intern/gpu_select.c index 153cf5f1e97..7023e44d289 100644 --- a/source/blender/gpu/intern/gpu_select.c +++ b/source/blender/gpu/intern/gpu_select.c @@ -73,7 +73,7 @@ static GPUSelectState g_select_state = {0}; /** * initialize and provide buffer for results */ -void GPU_select_begin(unsigned int *buffer, unsigned int bufsize, const rcti *input, char mode, int oldhits) +void GPU_select_begin(uint *buffer, uint bufsize, const rcti *input, char mode, int oldhits) { if (mode == GPU_SELECT_NEAREST_SECOND_PASS) { /* In the case hits was '-1', don't start the second pass since it's not going to give useful results. @@ -108,12 +108,12 @@ void GPU_select_begin(unsigned int *buffer, unsigned int bufsize, const rcti *in case ALGO_GL_QUERY: { g_select_state.use_cache = false; - gpu_select_query_begin((unsigned int (*)[4])buffer, bufsize / 4, input, mode, oldhits); + gpu_select_query_begin((uint (*)[4])buffer, bufsize / 4, input, mode, oldhits); break; } default: /* ALGO_GL_PICK */ { - gpu_select_pick_begin((unsigned int (*)[4])buffer, bufsize / 4, input, mode); + gpu_select_pick_begin((uint (*)[4])buffer, bufsize / 4, input, mode); break; } } @@ -126,7 +126,7 @@ void GPU_select_begin(unsigned int *buffer, unsigned int bufsize, const rcti *in * * \warning We rely on the order of object rendering on passes to be the same for this to work. */ -bool GPU_select_load_id(unsigned int id) +bool GPU_select_load_id(uint id) { /* if no selection mode active, ignore */ if (!g_select_state.select_is_active) @@ -154,9 +154,9 @@ bool GPU_select_load_id(unsigned int id) * Return number of hits and hits in buffer. * if \a dopass is true, we will do a second pass with occlusion queries to get the closest hit. */ -unsigned int GPU_select_end(void) +uint GPU_select_end(void) { - unsigned int hits = 0; + uint hits = 0; switch (g_select_state.algorithm) { case ALGO_GL_LEGACY: diff --git a/source/blender/gpu/intern/gpu_select_pick.c b/source/blender/gpu/intern/gpu_select_pick.c index f1d311890e6..4aef80934ad 100644 --- a/source/blender/gpu/intern/gpu_select_pick.c +++ b/source/blender/gpu/intern/gpu_select_pick.c @@ -62,14 +62,14 @@ /* For looping over a sub-region of a rect, could be moved into 'rct.c'*/ typedef struct SubRectStride { - unsigned int start; /* start here */ - unsigned int span; /* read these */ - unsigned int span_len; /* len times (read span 'len' times). */ - unsigned int skip; /* skip those */ + uint start; /* start here */ + uint span; /* read these */ + uint span_len; /* len times (read span 'len' times). */ + uint skip; /* skip those */ } SubRectStride; /* we may want to change back to float if uint isn't well supported */ -typedef unsigned int depth_t; +typedef uint depth_t; /** * Calculate values needed for looping over a sub-region (smaller buffer within a larger buffer). @@ -89,10 +89,10 @@ static void rect_subregion_stride_calc(const rcti *src, const rcti *dst, SubRect src->ymax >= dst->ymax && src->ymax >= dst->ymax); BLI_assert(x >= 0 && y >= 0); - r_sub->start = (unsigned int)((src_x * y) + x); - r_sub->span = (unsigned int)dst_x; - r_sub->span_len = (unsigned int)dst_y; - r_sub->skip = (unsigned int)(src_x - dst_x); + r_sub->start = (uint)((src_x * y) + x); + r_sub->span = (uint)dst_x; + r_sub->span_len = (uint)dst_y; + r_sub->skip = (uint)(src_x - dst_x); } /** @@ -114,11 +114,11 @@ BLI_INLINE bool depth_is_filled(const depth_t *prev, const depth_t *curr) /* store result of glReadPixels */ typedef struct DepthBufCache { struct DepthBufCache *next, *prev; - unsigned int id; + uint id; depth_t buf[0]; } DepthBufCache; -static DepthBufCache *depth_buf_malloc(unsigned int rect_len) +static DepthBufCache *depth_buf_malloc(uint rect_len) { DepthBufCache *rect = MEM_mallocN(sizeof(DepthBufCache) + sizeof(depth_t) * rect_len, __func__); rect->id = SELECT_ID_NONE; @@ -127,10 +127,10 @@ static DepthBufCache *depth_buf_malloc(unsigned int rect_len) static bool depth_buf_rect_depth_any( const DepthBufCache *rect_depth, - unsigned int rect_len) + uint rect_len) { const depth_t *curr = rect_depth->buf; - for (unsigned int i = 0; i < rect_len; i++, curr++) { + for (uint i = 0; i < rect_len; i++, curr++) { if (*curr != DEPTH_MAX) { return true; } @@ -143,7 +143,7 @@ static bool depth_buf_subrect_depth_any( const SubRectStride *sub_rect) { const depth_t *curr = rect_depth->buf + sub_rect->start; - for (unsigned int i = 0; i < sub_rect->span_len; i++) { + for (uint i = 0; i < sub_rect->span_len; i++) { const depth_t *curr_end = curr + sub_rect->span; for (; curr < curr_end; curr++, curr++) { if (*curr != DEPTH_MAX) { @@ -157,14 +157,14 @@ static bool depth_buf_subrect_depth_any( static bool depth_buf_rect_depth_any_filled( const DepthBufCache *rect_prev, const DepthBufCache *rect_curr, - unsigned int rect_len) + uint rect_len) { #if 0 return memcmp(rect_depth_a->buf, rect_depth_b->buf, rect_len * sizeof(depth_t)) != 0; #else const depth_t *prev = rect_prev->buf; const depth_t *curr = rect_curr->buf; - for (unsigned int i = 0; i < rect_len; i++, curr++, prev++) { + for (uint i = 0; i < rect_len; i++, curr++, prev++) { if (depth_is_filled(prev, curr)) { return true; } @@ -183,7 +183,7 @@ static bool depth_buf_subrect_depth_any_filled( /* same as above but different rect sizes */ const depth_t *prev = rect_src->buf + sub_rect->start; const depth_t *curr = rect_dst->buf + sub_rect->start; - for (unsigned int i = 0; i < sub_rect->span_len; i++) { + for (uint i = 0; i < sub_rect->span_len; i++) { const depth_t *curr_end = curr + sub_rect->span; for (; curr < curr_end; prev++, curr++) { if (depth_is_filled(prev, curr)) { @@ -203,7 +203,7 @@ static bool depth_buf_subrect_depth_any_filled( */ typedef struct DepthID { - unsigned int id; + uint id; depth_t depth; } DepthID; @@ -238,10 +238,10 @@ static int depth_cmp(const void *v1, const void *v2) /* depth sorting */ typedef struct GPUPickState { /* cache on initialization */ - unsigned int (*buffer)[4]; + uint (*buffer)[4]; /* buffer size (stores number of integers, for actual size multiply by sizeof integer)*/ - unsigned int bufsize; + uint bufsize; /* mode of operation */ char mode; @@ -257,14 +257,14 @@ typedef struct GPUPickState { /* Set after first draw */ bool is_init; - unsigned int prev_id; + uint prev_id; } gl; /* src: data stored in 'cache' and 'gl', * dst: use when cached region is smaller (where src -> dst isn't 1:1) */ struct { rcti clip_rect; - unsigned int rect_len; + uint rect_len; } src, dst; /* Store cache between `GPU_select_cache_begin/end` */ @@ -284,13 +284,13 @@ typedef struct GPUPickState { /* GPU_SELECT_PICK_ALL */ struct { DepthID *hits; - unsigned int hits_len; - unsigned int hits_len_alloc; + uint hits_len; + uint hits_len_alloc; } all; /* GPU_SELECT_PICK_NEAREST */ struct { - unsigned int *rect_id; + uint *rect_id; } nearest; }; } GPUPickState; @@ -299,7 +299,7 @@ typedef struct GPUPickState { static GPUPickState g_pick_state = {0}; void gpu_select_pick_begin( - unsigned int (*buffer)[4], unsigned int bufsize, + uint (*buffer)[4], uint bufsize, const rcti *input, char mode) { GPUPickState *ps = &g_pick_state; @@ -312,7 +312,7 @@ void gpu_select_pick_begin( ps->buffer = buffer; ps->mode = mode; - const unsigned int rect_len = (unsigned int)(BLI_rcti_size_x(input) * BLI_rcti_size_y(input)); + const uint rect_len = (uint)(BLI_rcti_size_x(input) * BLI_rcti_size_y(input)); ps->dst.clip_rect = *input; ps->dst.rect_len = rect_len; @@ -327,6 +327,9 @@ void gpu_select_pick_begin( glDepthMask(GL_TRUE); if (mode == GPU_SELECT_PICK_ALL) { + /* Note that other depth settings (such as #GL_LEQUAL) work too, + * since the depth is always cleared. + * Noting this for cases when depth picking is used where drawing calls change depth settings. */ glDepthFunc(GL_ALWAYS); } else { @@ -358,7 +361,7 @@ void gpu_select_pick_begin( #if 0 glReadPixels(UNPACK4(ps->gl.clip_readpixels), GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, ps->gl.rect_depth->buf); #else - for (unsigned int i = 0; i < rect_len; i++) { + for (uint i = 0; i < rect_len; i++) { ps->gl.rect_depth->buf[i] = DEPTH_MAX; } #endif @@ -381,8 +384,8 @@ void gpu_select_pick_begin( } else { /* Set to 0xff for SELECT_ID_NONE */ - ps->nearest.rect_id = MEM_mallocN(sizeof(unsigned int) * ps->dst.rect_len, __func__); - memset(ps->nearest.rect_id, 0xff, sizeof(unsigned int) * ps->dst.rect_len); + ps->nearest.rect_id = MEM_mallocN(sizeof(uint) * ps->dst.rect_len, __func__); + memset(ps->nearest.rect_id, 0xff, sizeof(uint) * ps->dst.rect_len); } } @@ -393,7 +396,7 @@ void gpu_select_pick_begin( static void gpu_select_load_id_pass_all(const DepthBufCache *rect_curr) { GPUPickState *ps = &g_pick_state; - const unsigned int id = rect_curr->id; + const uint id = rect_curr->id; /* find the best depth for this pass and store in 'all.hits' */ depth_t depth_best = DEPTH_MAX; @@ -405,15 +408,15 @@ static void gpu_select_load_id_pass_all(const DepthBufCache *rect_curr) if (ps->is_cached == false) { const depth_t *curr = rect_curr->buf; BLI_assert(ps->src.rect_len == ps->dst.rect_len); - const unsigned int rect_len = ps->src.rect_len; - for (unsigned int i = 0; i < rect_len; i++, curr++) { + const uint rect_len = ps->src.rect_len; + for (uint i = 0; i < rect_len; i++, curr++) { EVAL_TEST(); } } else { /* same as above but different rect sizes */ const depth_t *curr = rect_curr->buf + ps->cache.sub_rect.start; - for (unsigned int i = 0; i < ps->cache.sub_rect.span_len; i++) { + for (uint i = 0; i < ps->cache.sub_rect.span_len; i++) { const depth_t *curr_end = curr + ps->cache.sub_rect.span; for (; curr < curr_end; curr++) { EVAL_TEST(); @@ -437,10 +440,10 @@ static void gpu_select_load_id_pass_all(const DepthBufCache *rect_curr) static void gpu_select_load_id_pass_nearest(const DepthBufCache *rect_prev, const DepthBufCache *rect_curr) { GPUPickState *ps = &g_pick_state; - const unsigned int id = rect_curr->id; + const uint id = rect_curr->id; /* keep track each pixels ID in 'nearest.rect_id' */ if (id != SELECT_ID_NONE) { - unsigned int *id_ptr = ps->nearest.rect_id; + uint *id_ptr = ps->nearest.rect_id; /* Check against DEPTH_MAX because XRAY will clear the buffer, * so previously set values will become unset. @@ -454,8 +457,8 @@ static void gpu_select_load_id_pass_nearest(const DepthBufCache *rect_prev, cons const depth_t *prev = rect_prev->buf; const depth_t *curr = rect_curr->buf; BLI_assert(ps->src.rect_len == ps->dst.rect_len); - const unsigned int rect_len = ps->src.rect_len; - for (unsigned int i = 0; i < rect_len; i++, curr++, prev++, id_ptr++) { + const uint rect_len = ps->src.rect_len; + for (uint i = 0; i < rect_len; i++, curr++, prev++, id_ptr++) { EVAL_TEST(); } } @@ -463,7 +466,7 @@ static void gpu_select_load_id_pass_nearest(const DepthBufCache *rect_prev, cons /* same as above but different rect sizes */ const depth_t *prev = rect_prev->buf + ps->cache.sub_rect.start; const depth_t *curr = rect_curr->buf + ps->cache.sub_rect.start; - for (unsigned int i = 0; i < ps->cache.sub_rect.span_len; i++) { + for (uint i = 0; i < ps->cache.sub_rect.span_len; i++) { const depth_t *curr_end = curr + ps->cache.sub_rect.span; for (; curr < curr_end; prev++, curr++, id_ptr++) { EVAL_TEST(); @@ -478,11 +481,11 @@ static void gpu_select_load_id_pass_nearest(const DepthBufCache *rect_prev, cons } -bool gpu_select_pick_load_id(unsigned int id) +bool gpu_select_pick_load_id(uint id) { GPUPickState *ps = &g_pick_state; if (ps->gl.is_init) { - const unsigned int rect_len = ps->src.rect_len; + const uint rect_len = ps->src.rect_len; glReadPixels(UNPACK4(ps->gl.clip_readpixels), GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, ps->gl.rect_depth_test->buf); /* perform initial check since most cases the array remains unchanged */ @@ -524,7 +527,7 @@ bool gpu_select_pick_load_id(unsigned int id) return true; } -unsigned int gpu_select_pick_end(void) +uint gpu_select_pick_end(void) { GPUPickState *ps = &g_pick_state; @@ -537,7 +540,6 @@ unsigned int gpu_select_pick_end(void) /* force finishing last pass */ gpu_select_pick_load_id(ps->gl.prev_id); } - gpuPopAttrib(); glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); } @@ -559,9 +561,9 @@ unsigned int gpu_select_pick_end(void) rect_depth_final = ps->gl.rect_depth; } - unsigned int maxhits = g_pick_state.bufsize; + uint maxhits = g_pick_state.bufsize; DepthID *depth_data; - unsigned int depth_data_len = 0; + uint depth_data_len = 0; if (g_pick_state.mode == GPU_SELECT_PICK_ALL) { depth_data = ps->all.hits; @@ -575,7 +577,7 @@ unsigned int gpu_select_pick_end(void) /* GPU_SELECT_PICK_NEAREST */ /* Over alloc (unlikely we have as many depths as pixels) */ - unsigned int depth_data_len_first_pass = 0; + uint depth_data_len_first_pass = 0; depth_data = MEM_mallocN(ps->dst.rect_len * sizeof(*depth_data), __func__); /* Partially de-duplicating copy, @@ -584,7 +586,7 @@ unsigned int gpu_select_pick_end(void) #define EVAL_TEST(i_src, i_dst) \ { \ - const unsigned int id = ps->nearest.rect_id[i_dst]; \ + const uint id = ps->nearest.rect_id[i_dst]; \ if (id != SELECT_ID_NONE) { \ const depth_t depth = rect_depth_final->buf[i_src]; \ if (depth_last == NULL || depth_last->id != id) { \ @@ -601,15 +603,15 @@ unsigned int gpu_select_pick_end(void) { DepthID *depth_last = NULL; if (ps->is_cached == false) { - for (unsigned int i = 0; i < ps->src.rect_len; i++) { + for (uint i = 0; i < ps->src.rect_len; i++) { EVAL_TEST(i, i); } } else { /* same as above but different rect sizes */ - unsigned int i_src = ps->cache.sub_rect.start, i_dst = 0; - for (unsigned int j = 0; j < ps->cache.sub_rect.span_len; j++) { - const unsigned int i_src_end = i_src + ps->cache.sub_rect.span; + uint i_src = ps->cache.sub_rect.start, i_dst = 0; + for (uint j = 0; j < ps->cache.sub_rect.span_len; j++) { + const uint i_src_end = i_src + ps->cache.sub_rect.span; for (; i_src < i_src_end; i_src++, i_dst++) { EVAL_TEST(i_src, i_dst); } @@ -626,7 +628,7 @@ unsigned int gpu_select_pick_end(void) depth_data_len = 0; { DepthID *depth_last = NULL; - for (unsigned int i = 0; i < depth_data_len_first_pass; i++) { + for (uint i = 0; i < depth_data_len_first_pass; i++) { if (depth_last == NULL || depth_last->id != depth_data[i].id) { depth_last = &depth_data[depth_data_len++]; *depth_last = depth_data[i]; @@ -640,16 +642,16 @@ unsigned int gpu_select_pick_end(void) /* Finally sort each unique (id, depth) pair by depth * so the final hit-list is sorted by depth (nearest first) */ - unsigned int hits = 0; + uint hits = 0; if (depth_data_len > maxhits) { - hits = (unsigned int)-1; + hits = (uint)-1; } else { /* leave sorting up to the caller */ qsort(depth_data, depth_data_len, sizeof(DepthID), depth_cmp); - for (unsigned int i = 0; i < depth_data_len; i++) { + for (uint i = 0; i < depth_data_len; i++) { #ifdef DEBUG_PRINT printf(" hit: %u: depth %u\n", depth_data[i].id, depth_data[i].depth); #endif diff --git a/source/blender/gpu/intern/gpu_select_sample_query.c b/source/blender/gpu/intern/gpu_select_sample_query.c index e3bd20f3776..12390e5cdb0 100644 --- a/source/blender/gpu/intern/gpu_select_sample_query.c +++ b/source/blender/gpu/intern/gpu_select_sample_query.c @@ -44,6 +44,8 @@ #include "BLI_utildefines.h" +#include "PIL_time.h" + #include "gpu_select_private.h" @@ -54,20 +56,20 @@ typedef struct GPUQueryState { /* Tracks whether a query has been issued so that gpu_load_id can end the previous one */ bool query_issued; /* array holding the OpenGL query identifiers */ - unsigned int *queries; + uint *queries; /* array holding the id corresponding to each query */ - unsigned int *id; + uint *id; /* number of queries in *queries and *id */ - unsigned int num_of_queries; + uint num_of_queries; /* index to the next query to start */ - unsigned int active_query; + uint active_query; /* cache on initialization */ - unsigned int (*buffer)[4]; + uint (*buffer)[4]; /* buffer size (stores number of integers, for actual size multiply by sizeof integer)*/ - unsigned int bufsize; + uint bufsize; /* mode of operation */ char mode; - unsigned int index; + uint index; int oldhits; } GPUQueryState; @@ -75,7 +77,7 @@ static GPUQueryState g_query_state = {0}; void gpu_select_query_begin( - unsigned int (*buffer)[4], unsigned int bufsize, + uint (*buffer)[4], uint bufsize, const rcti *input, char mode, int oldhits) { @@ -96,7 +98,7 @@ void gpu_select_query_begin( g_query_state.id = MEM_mallocN(g_query_state.num_of_queries * sizeof(*g_query_state.id), "gpu selection ids"); glGenQueries(g_query_state.num_of_queries, g_query_state.queries); - gpuPushAttrib(GPU_DEPTH_BUFFER_BIT | GPU_VIEWPORT_BIT); + gpuPushAttrib(GPU_DEPTH_BUFFER_BIT | GPU_VIEWPORT_BIT | GPU_SCISSOR_BIT); /* disable writing to the framebuffer */ glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); @@ -114,6 +116,7 @@ void gpu_select_query_begin( glDepthMask(GL_FALSE); } else if (mode == GPU_SELECT_NEAREST_FIRST_PASS) { + glDisable(GL_SCISSOR_TEST); /* allows fast clear */ glClear(GL_DEPTH_BUFFER_BIT); glEnable(GL_DEPTH_TEST); glDepthMask(GL_TRUE); @@ -126,7 +129,7 @@ void gpu_select_query_begin( } } -bool gpu_select_query_load_id(unsigned int id) +bool gpu_select_query_load_id(uint id) { if (g_query_state.query_issued) { glEndQuery(GL_SAMPLES_PASSED); @@ -161,19 +164,28 @@ bool gpu_select_query_load_id(unsigned int id) return true; } -unsigned int gpu_select_query_end(void) +uint gpu_select_query_end(void) { int i; - unsigned int hits = 0; - const unsigned int maxhits = g_query_state.bufsize; + uint hits = 0; + const uint maxhits = g_query_state.bufsize; if (g_query_state.query_issued) { glEndQuery(GL_SAMPLES_PASSED); } for (i = 0; i < g_query_state.active_query; i++) { - unsigned int result; + uint result = 0; + /* Wait until the result is available. */ + while (result == 0) { + glGetQueryObjectuiv(g_query_state.queries[i], GL_QUERY_RESULT_AVAILABLE, &result); + if (result == 0) { + /* (fclem) Not sure if this is better than calling + * glGetQueryObjectuiv() indefinitely. */ + PIL_sleep_ms(1); + } + } glGetQueryObjectuiv(g_query_state.queries[i], GL_QUERY_RESULT, &result); if (result > 0) { if (g_query_state.mode != GPU_SELECT_NEAREST_SECOND_PASS) { diff --git a/source/blender/gpu/intern/gpu_shader.c b/source/blender/gpu/intern/gpu_shader.c index 598722d372b..e0b11edb197 100644 --- a/source/blender/gpu/intern/gpu_shader.c +++ b/source/blender/gpu/intern/gpu_shader.c @@ -37,7 +37,6 @@ #include "DNA_space_types.h" -#include "GPU_compositing.h" #include "GPU_extensions.h" #include "GPU_matrix.h" #include "GPU_shader.h" @@ -66,17 +65,27 @@ extern char datatoc_gpu_shader_2D_flat_color_vert_glsl[]; extern char datatoc_gpu_shader_2D_smooth_color_vert_glsl[]; extern char datatoc_gpu_shader_2D_smooth_color_frag_glsl[]; extern char datatoc_gpu_shader_2D_image_vert_glsl[]; +extern char datatoc_gpu_shader_2D_image_rect_vert_glsl[]; +extern char datatoc_gpu_shader_2D_image_multi_rect_vert_glsl[]; +extern char datatoc_gpu_shader_2D_widget_base_vert_glsl[]; +extern char datatoc_gpu_shader_2D_widget_base_frag_glsl[]; +extern char datatoc_gpu_shader_2D_widget_shadow_vert_glsl[]; +extern char datatoc_gpu_shader_2D_widget_shadow_frag_glsl[]; +extern char datatoc_gpu_shader_2D_nodelink_frag_glsl[]; +extern char datatoc_gpu_shader_2D_nodelink_vert_glsl[]; extern char datatoc_gpu_shader_3D_image_vert_glsl[]; +extern char datatoc_gpu_shader_image_frag_glsl[]; extern char datatoc_gpu_shader_image_linear_frag_glsl[]; extern char datatoc_gpu_shader_image_color_frag_glsl[]; +extern char datatoc_gpu_shader_image_varying_color_frag_glsl[]; extern char datatoc_gpu_shader_image_alpha_color_frag_glsl[]; extern char datatoc_gpu_shader_image_shuffle_color_frag_glsl[]; extern char datatoc_gpu_shader_image_interlace_frag_glsl[]; extern char datatoc_gpu_shader_image_mask_uniform_color_frag_glsl[]; extern char datatoc_gpu_shader_image_modulate_alpha_frag_glsl[]; -extern char datatoc_gpu_shader_image_rect_modulate_alpha_frag_glsl[]; extern char datatoc_gpu_shader_image_depth_linear_frag_glsl[]; +extern char datatoc_gpu_shader_image_depth_copy_frag_glsl[]; extern char datatoc_gpu_shader_3D_vert_glsl[]; extern char datatoc_gpu_shader_3D_normal_vert_glsl[]; extern char datatoc_gpu_shader_3D_flat_color_vert_glsl[]; @@ -98,7 +107,7 @@ extern char datatoc_gpu_shader_instance_edges_variying_color_geom_glsl[]; extern char datatoc_gpu_shader_instance_edges_variying_color_vert_glsl[]; extern char datatoc_gpu_shader_instance_bone_envelope_solid_vert_glsl[]; extern char datatoc_gpu_shader_instance_bone_envelope_wire_vert_glsl[]; -extern char datatoc_gpu_shader_instance_mball_helpers_vert_glsl[]; +extern char datatoc_gpu_shader_instance_mball_handles_vert_glsl[]; extern char datatoc_gpu_shader_3D_groundpoint_vert_glsl[]; extern char datatoc_gpu_shader_3D_groundline_geom_glsl[]; @@ -133,7 +142,10 @@ extern char datatoc_gpu_shader_edges_overlay_geom_glsl[]; extern char datatoc_gpu_shader_edges_overlay_simple_geom_glsl[]; extern char datatoc_gpu_shader_edges_overlay_frag_glsl[]; extern char datatoc_gpu_shader_text_vert_glsl[]; +extern char datatoc_gpu_shader_text_geom_glsl[]; extern char datatoc_gpu_shader_text_frag_glsl[]; +extern char datatoc_gpu_shader_text_simple_vert_glsl[]; +extern char datatoc_gpu_shader_text_simple_geom_glsl[]; extern char datatoc_gpu_shader_keyframe_diamond_vert_glsl[]; extern char datatoc_gpu_shader_keyframe_diamond_frag_glsl[]; @@ -144,22 +156,10 @@ extern char datatoc_gpu_shader_vsm_store_vert_glsl[]; extern char datatoc_gpu_shader_vsm_store_frag_glsl[]; extern char datatoc_gpu_shader_sep_gaussian_blur_vert_glsl[]; extern char datatoc_gpu_shader_sep_gaussian_blur_frag_glsl[]; -extern char datatoc_gpu_shader_fullscreen_vert_glsl[]; -extern char datatoc_gpu_shader_fx_ssao_frag_glsl[]; -extern char datatoc_gpu_shader_fx_dof_frag_glsl[]; -extern char datatoc_gpu_shader_fx_dof_vert_glsl[]; -extern char datatoc_gpu_shader_fx_dof_hq_frag_glsl[]; -extern char datatoc_gpu_shader_fx_dof_hq_vert_glsl[]; -extern char datatoc_gpu_shader_fx_dof_hq_geo_glsl[]; -extern char datatoc_gpu_shader_fx_depth_resolve_glsl[]; -extern char datatoc_gpu_shader_fx_lib_glsl[]; /* cache of built-in shaders (each is created on first use) */ static GPUShader *builtin_shaders[GPU_NUM_BUILTIN_SHADERS] = { NULL }; -/* cache for shader fx. Those can exist in combinations so store them here */ -static GPUShader *fx_shaders[MAX_FX_SHADERS * 2] = { NULL }; - typedef struct { const char *vert; const char *frag; @@ -542,9 +542,6 @@ void GPU_shader_free(GPUShader *shader) if (shader->program) glDeleteProgram(shader->program); - if (shader->uniform_interface) - MEM_freeN(shader->uniform_interface); - if (shader->interface) GWN_shaderinterface_discard(shader->interface); @@ -573,11 +570,6 @@ int GPU_shader_get_uniform_block(GPUShader *shader, const char *name) return ubo ? ubo->location : -1; } -void *GPU_fx_shader_get_interface(GPUShader *shader) -{ - return shader->uniform_interface; -} - void *GPU_shader_get_interface(GPUShader *shader) { return shader->interface; @@ -589,11 +581,6 @@ int GPU_shader_get_program(GPUShader *shader) return (int)shader->program; } -void GPU_fx_shader_set_interface(GPUShader *shader, void *interface) -{ - shader->uniform_interface = interface; -} - void GPU_shader_uniform_vector(GPUShader *UNUSED(shader), int location, int length, int arraysize, const float *value) { if (location == -1 || value == NULL) @@ -640,32 +627,17 @@ void GPU_shader_uniform_buffer(GPUShader *shader, int location, GPUUniformBuffer void GPU_shader_uniform_texture(GPUShader *UNUSED(shader), int location, GPUTexture *tex) { int number = GPU_texture_bound_number(tex); - int bindcode = GPU_texture_opengl_bindcode(tex); - int target = GPU_texture_target(tex); - if (number >= GPU_max_textures()) { - fprintf(stderr, "Not enough texture slots.\n"); + if (number == -1) { + fprintf(stderr, "Texture is not bound.\n"); + BLI_assert(0); return; } - - if (number == -1) - return; if (location == -1) return; - if (number != 0) - glActiveTexture(GL_TEXTURE0 + number); - - if (bindcode != 0) - glBindTexture(target, bindcode); - else - GPU_invalid_tex_bind(target); - glUniform1i(location, number); - - if (number != 0) - glActiveTexture(GL_TEXTURE0); } int GPU_shader_get_attribute(GPUShader *shader, const char *name) @@ -687,7 +659,12 @@ GPUShader *GPU_shader_get_builtin_shader(GPUBuiltinShader shader) [GPU_SHADER_SMOKE_FIRE] = { datatoc_gpu_shader_smoke_vert_glsl, datatoc_gpu_shader_smoke_frag_glsl }, [GPU_SHADER_SMOKE_COBA] = { datatoc_gpu_shader_smoke_vert_glsl, datatoc_gpu_shader_smoke_frag_glsl }, - [GPU_SHADER_TEXT] = { datatoc_gpu_shader_text_vert_glsl, datatoc_gpu_shader_text_frag_glsl }, + [GPU_SHADER_TEXT] = { datatoc_gpu_shader_text_vert_glsl, + datatoc_gpu_shader_text_frag_glsl, + datatoc_gpu_shader_text_geom_glsl }, + [GPU_SHADER_TEXT_SIMPLE] = { datatoc_gpu_shader_text_simple_vert_glsl, + datatoc_gpu_shader_text_frag_glsl, + datatoc_gpu_shader_text_simple_geom_glsl }, [GPU_SHADER_KEYFRAME_DIAMOND] = { datatoc_gpu_shader_keyframe_diamond_vert_glsl, datatoc_gpu_shader_keyframe_diamond_frag_glsl }, [GPU_SHADER_EDGES_FRONT_BACK_PERSP] = { datatoc_gpu_shader_edges_front_back_persp_vert_glsl, @@ -710,10 +687,10 @@ GPUShader *GPU_shader_get_builtin_shader(GPUBuiltinShader shader) datatoc_gpu_shader_image_mask_uniform_color_frag_glsl }, [GPU_SHADER_3D_IMAGE_MODULATE_ALPHA] = { datatoc_gpu_shader_3D_image_vert_glsl, datatoc_gpu_shader_image_modulate_alpha_frag_glsl }, - [GPU_SHADER_3D_IMAGE_RECT_MODULATE_ALPHA] = { datatoc_gpu_shader_3D_image_vert_glsl, - datatoc_gpu_shader_image_rect_modulate_alpha_frag_glsl }, [GPU_SHADER_3D_IMAGE_DEPTH] = { datatoc_gpu_shader_3D_image_vert_glsl, datatoc_gpu_shader_image_depth_linear_frag_glsl }, + [GPU_SHADER_3D_IMAGE_DEPTH_COPY] = { datatoc_gpu_shader_3D_image_vert_glsl, + datatoc_gpu_shader_image_depth_copy_frag_glsl }, [GPU_SHADER_2D_IMAGE_INTERLACE] = { datatoc_gpu_shader_2D_image_vert_glsl, datatoc_gpu_shader_image_interlace_frag_glsl }, @@ -728,12 +705,21 @@ GPUShader *GPU_shader_get_builtin_shader(GPUBuiltinShader shader) datatoc_gpu_shader_2D_smooth_color_frag_glsl }, [GPU_SHADER_2D_IMAGE_LINEAR_TO_SRGB] = { datatoc_gpu_shader_2D_image_vert_glsl, datatoc_gpu_shader_image_linear_frag_glsl }, + [GPU_SHADER_2D_IMAGE] = { datatoc_gpu_shader_2D_image_vert_glsl, + datatoc_gpu_shader_image_frag_glsl }, [GPU_SHADER_2D_IMAGE_COLOR] = { datatoc_gpu_shader_2D_image_vert_glsl, datatoc_gpu_shader_image_color_frag_glsl }, [GPU_SHADER_2D_IMAGE_ALPHA_COLOR] = { datatoc_gpu_shader_2D_image_vert_glsl, datatoc_gpu_shader_image_alpha_color_frag_glsl }, + [GPU_SHADER_2D_IMAGE_ALPHA] = { datatoc_gpu_shader_2D_image_vert_glsl, + datatoc_gpu_shader_image_modulate_alpha_frag_glsl }, [GPU_SHADER_2D_IMAGE_SHUFFLE_COLOR] = { datatoc_gpu_shader_2D_image_vert_glsl, datatoc_gpu_shader_image_shuffle_color_frag_glsl }, + [GPU_SHADER_2D_IMAGE_RECT_COLOR] = { datatoc_gpu_shader_2D_image_rect_vert_glsl, + datatoc_gpu_shader_image_color_frag_glsl }, + [GPU_SHADER_2D_IMAGE_MULTI_RECT_COLOR] = { datatoc_gpu_shader_2D_image_multi_rect_vert_glsl, + datatoc_gpu_shader_image_varying_color_frag_glsl }, + [GPU_SHADER_3D_UNIFORM_COLOR] = { datatoc_gpu_shader_3D_vert_glsl, datatoc_gpu_shader_uniform_color_frag_glsl }, [GPU_SHADER_3D_UNIFORM_COLOR_U32] = { datatoc_gpu_shader_3D_vert_glsl, datatoc_gpu_shader_uniform_color_frag_glsl }, [GPU_SHADER_3D_FLAT_COLOR] = { datatoc_gpu_shader_3D_flat_color_vert_glsl, @@ -816,12 +802,23 @@ GPUShader *GPU_shader_get_builtin_shader(GPUBuiltinShader shader) datatoc_gpu_shader_flat_color_frag_glsl, datatoc_gpu_shader_instance_edges_variying_color_geom_glsl}, + [GPU_SHADER_2D_WIDGET_BASE] = { datatoc_gpu_shader_2D_widget_base_vert_glsl, + datatoc_gpu_shader_2D_widget_base_frag_glsl}, + [GPU_SHADER_2D_WIDGET_BASE_INST] = { datatoc_gpu_shader_2D_widget_base_vert_glsl, + datatoc_gpu_shader_2D_widget_base_frag_glsl}, + [GPU_SHADER_2D_WIDGET_SHADOW] = { datatoc_gpu_shader_2D_widget_shadow_vert_glsl, + datatoc_gpu_shader_2D_widget_shadow_frag_glsl }, + [GPU_SHADER_2D_NODELINK] = { datatoc_gpu_shader_2D_nodelink_vert_glsl, + datatoc_gpu_shader_2D_nodelink_frag_glsl }, + [GPU_SHADER_2D_NODELINK_INST] = { datatoc_gpu_shader_2D_nodelink_vert_glsl, + datatoc_gpu_shader_2D_nodelink_frag_glsl }, + [GPU_SHADER_3D_INSTANCE_BONE_ENVELOPE_SOLID] = { datatoc_gpu_shader_instance_bone_envelope_solid_vert_glsl, datatoc_gpu_shader_simple_lighting_frag_glsl }, [GPU_SHADER_3D_INSTANCE_BONE_ENVELOPE_WIRE] = { datatoc_gpu_shader_instance_bone_envelope_wire_vert_glsl, datatoc_gpu_shader_flat_color_frag_glsl }, - [GPU_SHADER_3D_INSTANCE_MBALL_HELPERS] = { datatoc_gpu_shader_instance_mball_helpers_vert_glsl, + [GPU_SHADER_3D_INSTANCE_MBALL_HANDLES] = { datatoc_gpu_shader_instance_mball_handles_vert_glsl, datatoc_gpu_shader_flat_color_frag_glsl }, }; @@ -829,25 +826,29 @@ GPUShader *GPU_shader_get_builtin_shader(GPUBuiltinShader shader) /* just a few special cases */ const char *defines = NULL; switch (shader) { + case GPU_SHADER_2D_WIDGET_BASE_INST: + case GPU_SHADER_2D_NODELINK_INST: + defines = "#define USE_INSTANCE\n"; + break; case GPU_SHADER_SMOKE_COBA: - defines = "#define USE_COBA;\n"; + defines = "#define USE_COBA\n"; break; case GPU_SHADER_INSTANCE_VARIYING_COLOR_VARIYING_SIZE: - defines = "#define UNIFORM_SCALE;\n"; + defines = "#define UNIFORM_SCALE\n"; break; case GPU_SHADER_3D_INSTANCE_SCREEN_ALIGNED_AXIS: - defines = "#define AXIS_NAME;\n"; + defines = "#define AXIS_NAME\n"; break; case GPU_SHADER_3D_OBJECTSPACE_SIMPLE_LIGHTING_VARIYING_COLOR: case GPU_SHADER_3D_INSTANCE_BONE_ENVELOPE_SOLID: - defines = "#define USE_INSTANCE_COLOR;\n"; + defines = "#define USE_INSTANCE_COLOR\n"; break; case GPU_SHADER_3D_FLAT_COLOR_U32: case GPU_SHADER_3D_UNIFORM_COLOR_U32: - defines = "#define USE_COLOR_U32;\n"; + defines = "#define USE_COLOR_U32\n"; break; case GPU_SHADER_SIMPLE_LIGHTING_FLAT_COLOR: - defines = "#define USE_FLAT_NORMAL;\n"; + defines = "#define USE_FLAT_NORMAL\n"; break; default: break; @@ -880,82 +881,6 @@ GPUShader *GPU_shader_get_builtin_shader(GPUBuiltinShader shader) #define MAX_DEFINES 100 -GPUShader *GPU_shader_get_builtin_fx_shader(int effect, bool persp) -{ - int offset; - char defines[MAX_DEFINES] = ""; - /* avoid shaders out of range */ - if (effect >= MAX_FX_SHADERS) - return NULL; - - offset = 2 * effect; - - if (persp) { - offset += 1; - strcat(defines, "#define PERSP_MATRIX\n"); - } - - if (!fx_shaders[offset]) { - GPUShader *shader = NULL; - - switch (effect) { - case GPU_SHADER_FX_SSAO: - shader = GPU_shader_create(datatoc_gpu_shader_fullscreen_vert_glsl, datatoc_gpu_shader_fx_ssao_frag_glsl, NULL, datatoc_gpu_shader_fx_lib_glsl, defines); - break; - - case GPU_SHADER_FX_DEPTH_OF_FIELD_PASS_ONE: - strcat(defines, "#define FIRST_PASS\n"); - shader = GPU_shader_create(datatoc_gpu_shader_fx_dof_vert_glsl, datatoc_gpu_shader_fx_dof_frag_glsl, NULL, datatoc_gpu_shader_fx_lib_glsl, defines); - break; - - case GPU_SHADER_FX_DEPTH_OF_FIELD_PASS_TWO: - strcat(defines, "#define SECOND_PASS\n"); - shader = GPU_shader_create(datatoc_gpu_shader_fx_dof_vert_glsl, datatoc_gpu_shader_fx_dof_frag_glsl, NULL, datatoc_gpu_shader_fx_lib_glsl, defines); - break; - - case GPU_SHADER_FX_DEPTH_OF_FIELD_PASS_THREE: - strcat(defines, "#define THIRD_PASS\n"); - shader = GPU_shader_create(datatoc_gpu_shader_fx_dof_vert_glsl, datatoc_gpu_shader_fx_dof_frag_glsl, NULL, datatoc_gpu_shader_fx_lib_glsl, defines); - break; - - case GPU_SHADER_FX_DEPTH_OF_FIELD_PASS_FOUR: - strcat(defines, "#define FOURTH_PASS\n"); - shader = GPU_shader_create(datatoc_gpu_shader_fx_dof_vert_glsl, datatoc_gpu_shader_fx_dof_frag_glsl, NULL, datatoc_gpu_shader_fx_lib_glsl, defines); - break; - - case GPU_SHADER_FX_DEPTH_OF_FIELD_PASS_FIVE: - strcat(defines, "#define FIFTH_PASS\n"); - shader = GPU_shader_create(datatoc_gpu_shader_fx_dof_vert_glsl, datatoc_gpu_shader_fx_dof_frag_glsl, NULL, datatoc_gpu_shader_fx_lib_glsl, defines); - break; - - case GPU_SHADER_FX_DEPTH_OF_FIELD_HQ_PASS_ONE: - strcat(defines, "#define FIRST_PASS\n"); - shader = GPU_shader_create(datatoc_gpu_shader_fx_dof_hq_vert_glsl, datatoc_gpu_shader_fx_dof_hq_frag_glsl, NULL, datatoc_gpu_shader_fx_lib_glsl, defines); - break; - - case GPU_SHADER_FX_DEPTH_OF_FIELD_HQ_PASS_TWO: - strcat(defines, "#define SECOND_PASS\n"); - shader = GPU_shader_create(datatoc_gpu_shader_fx_dof_hq_vert_glsl, datatoc_gpu_shader_fx_dof_hq_frag_glsl, datatoc_gpu_shader_fx_dof_hq_geo_glsl, datatoc_gpu_shader_fx_lib_glsl, defines); - break; - - case GPU_SHADER_FX_DEPTH_OF_FIELD_HQ_PASS_THREE: - strcat(defines, "#define THIRD_PASS\n"); - shader = GPU_shader_create(datatoc_gpu_shader_fx_dof_hq_vert_glsl, datatoc_gpu_shader_fx_dof_hq_frag_glsl, NULL, datatoc_gpu_shader_fx_lib_glsl, defines); - break; - - case GPU_SHADER_FX_DEPTH_RESOLVE: - shader = GPU_shader_create(datatoc_gpu_shader_fullscreen_vert_glsl, datatoc_gpu_shader_fx_depth_resolve_glsl, NULL, NULL, defines); - break; - } - - fx_shaders[offset] = shader; - GPU_fx_shader_init_interface(shader, effect); - } - - return fx_shaders[offset]; -} - - void GPU_shader_free_builtin_shaders(void) { for (int i = 0; i < GPU_NUM_BUILTIN_SHADERS; ++i) { @@ -964,11 +889,4 @@ void GPU_shader_free_builtin_shaders(void) builtin_shaders[i] = NULL; } } - - for (int i = 0; i < 2 * MAX_FX_SHADERS; ++i) { - if (fx_shaders[i]) { - GPU_shader_free(fx_shaders[i]); - fx_shaders[i] = NULL; - } - } } diff --git a/source/blender/gpu/intern/gpu_shader_private.h b/source/blender/gpu/intern/gpu_shader_private.h index f883773df17..67d8c6e6213 100644 --- a/source/blender/gpu/intern/gpu_shader_private.h +++ b/source/blender/gpu/intern/gpu_shader_private.h @@ -35,9 +35,6 @@ struct GPUShader { GLuint geometry; /* handle for geometry shader */ GLuint fragment; /* handle for fragment shader */ - void *uniform_interface; /* cached uniform interface for shader. Data depends on shader */ - /* NOTE: ^-- only FX compositing shaders use this */ - Gwn_ShaderInterface *interface; /* cached uniform & attrib interface for shader */ }; diff --git a/source/blender/gpu/intern/gpu_texture.c b/source/blender/gpu/intern/gpu_texture.c index d6b641af225..75830f60f03 100644 --- a/source/blender/gpu/intern/gpu_texture.c +++ b/source/blender/gpu/intern/gpu_texture.c @@ -48,6 +48,22 @@ static struct GPUTextureGlobal { GPUTexture *invalid_tex_3D; } GG = {NULL, NULL, NULL}; +/* Maximum number of FBOs a texture can be attached to. */ +#define GPU_TEX_MAX_FBO_ATTACHED 8 + +typedef enum GPUTextureFormatFlag{ + GPU_FORMAT_DEPTH = (1 << 0), + GPU_FORMAT_STENCIL = (1 << 1), + GPU_FORMAT_INTEGER = (1 << 2), + GPU_FORMAT_FLOAT = (1 << 3), + + GPU_FORMAT_1D = (1 << 10), + GPU_FORMAT_2D = (1 << 11), + GPU_FORMAT_3D = (1 << 12), + GPU_FORMAT_CUBE = (1 << 13), + GPU_FORMAT_ARRAY = (1 << 14), +} GPUTextureFormatFlag; + /* GPUTexture */ struct GPUTexture { int w, h, d; /* width/height/depth */ @@ -59,14 +75,15 @@ struct GPUTexture { GLuint bindcode; /* opengl identifier for texture */ int fromblender; /* we got the texture from Blender */ - GPUFrameBuffer *fb; /* GPUFramebuffer this texture is attached to */ - int fb_attachment; /* slot the texture is attached to */ - bool depth; /* is a depth texture? */ - bool stencil; /* is a stencil texture? */ + GPUTextureFormat format; + GPUTextureFormatFlag format_flag; unsigned int bytesize; /* number of byte for one pixel */ - int format; /* GPUTextureFormat */ int components; /* number of color/alpha channels */ + int samples; /* number of samples for multisamples textures. 0 if not multisample target */ + + int fb_attachment[GPU_TEX_MAX_FBO_ATTACHED]; + GPUFrameBuffer *fb[GPU_TEX_MAX_FBO_ATTACHED]; }; /* ------ Memory Management ------- */ @@ -113,30 +130,26 @@ unsigned int GPU_texture_memory_usage_get(void) static GLenum gpu_texture_get_format( int components, GPUTextureFormat data_type, - GLenum *format, GLenum *data_format, bool *is_depth, bool *is_stencil, unsigned int *bytesize) + GLenum *format, GLenum *data_format, GPUTextureFormatFlag *format_flag, unsigned int *bytesize) { if (ELEM(data_type, GPU_DEPTH_COMPONENT24, GPU_DEPTH_COMPONENT16, GPU_DEPTH_COMPONENT32F)) { - *is_depth = true; - *is_stencil = false; + *format_flag |= GPU_FORMAT_DEPTH; *data_format = GL_FLOAT; *format = GL_DEPTH_COMPONENT; } else if (data_type == GPU_DEPTH24_STENCIL8) { - *is_depth = true; - *is_stencil = true; + *format_flag |= GPU_FORMAT_DEPTH | GPU_FORMAT_STENCIL; *data_format = GL_UNSIGNED_INT_24_8; *format = GL_DEPTH_STENCIL; } else { - *is_depth = false; - *is_stencil = false; - /* Integer formats */ - if (ELEM(data_type, GPU_RG16I)) { + if (ELEM(data_type, GPU_RG16I, GPU_R16I)) { *data_format = GL_INT; + *format_flag |= GPU_FORMAT_INTEGER; switch (components) { case 1: *format = GL_RED_INTEGER; break; @@ -148,6 +161,7 @@ static GLenum gpu_texture_get_format( } else { *data_format = GL_FLOAT; + *format_flag |= GPU_FORMAT_FLOAT; switch (components) { case 1: *format = GL_RED; break; @@ -184,6 +198,7 @@ static GLenum gpu_texture_get_format( break; case GPU_DEPTH_COMPONENT16: case GPU_R16F: + case GPU_R16I: case GPU_RG8: *bytesize = 2; break; @@ -208,6 +223,7 @@ static GLenum gpu_texture_get_format( case GPU_RGBA8: return GL_RGBA8; case GPU_R32F: return GL_R32F; case GPU_R16F: return GL_R16F; + case GPU_R16I: return GL_R16I; case GPU_RG8: return GL_RG8; case GPU_R8: return GL_R8; /* Special formats texture & renderbuffer */ @@ -340,11 +356,12 @@ static GPUTexture *GPU_texture_create_nD( tex->w = w; tex->h = h; tex->d = d; + tex->samples = samples; tex->number = -1; tex->refcount = 1; - tex->fb_attachment = -1; tex->format = data_type; tex->components = components; + tex->format_flag = 0; if (n == 2) { if (d == 0) @@ -371,7 +388,8 @@ static GPUTexture *GPU_texture_create_nD( tex->target = GL_TEXTURE_2D_MULTISAMPLE; GLenum format, internalformat, data_format; - internalformat = gpu_texture_get_format(components, data_type, &format, &data_format, &tex->depth, &tex->stencil, &tex->bytesize); + internalformat = gpu_texture_get_format(components, data_type, &format, &data_format, + &tex->format_flag, &tex->bytesize); gpu_texture_memory_footprint_add(tex); @@ -387,7 +405,6 @@ static GPUTexture *GPU_texture_create_nD( return NULL; } - tex->number = 0; glBindTexture(tex->target, tex->bindcode); /* Check if texture fit in VRAM */ @@ -446,17 +463,23 @@ static GPUTexture *GPU_texture_create_nD( MEM_freeN(rescaled_fpixels); /* Texture Parameters */ - if (tex->depth) { + if (GPU_texture_stencil(tex) || /* Does not support filtering */ + GPU_texture_integer(tex) || /* Does not support filtering */ + GPU_texture_depth(tex)) + { glTexParameteri(tex->target_base, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(tex->target_base, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(tex->target_base, GL_TEXTURE_COMPARE_MODE, GL_NONE); - glTexParameteri(tex->target_base, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL); + glTexParameteri(tex->target_base, GL_TEXTURE_MAG_FILTER, GL_NEAREST); } else { glTexParameteri(tex->target_base, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(tex->target_base, GL_TEXTURE_MAG_FILTER, GL_LINEAR); } + if (GPU_texture_depth(tex)) { + glTexParameteri(tex->target_base, GL_TEXTURE_COMPARE_MODE, GL_NONE); + glTexParameteri(tex->target_base, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL); + } + glTexParameteri(tex->target_base, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); if (n > 1) { glTexParameteri(tex->target_base, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); @@ -465,7 +488,7 @@ static GPUTexture *GPU_texture_create_nD( glTexParameteri(tex->target_base, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); } - GPU_texture_unbind(tex); + glBindTexture(tex->target, 0); return tex; } @@ -483,11 +506,12 @@ static GPUTexture *GPU_texture_cube_create( tex->w = w; tex->h = w; tex->d = d; + tex->samples = 0; tex->number = -1; tex->refcount = 1; - tex->fb_attachment = -1; tex->format = data_type; tex->components = components; + tex->format_flag = GPU_FORMAT_CUBE; if (d == 0) { tex->target_base = tex->target = GL_TEXTURE_CUBE_MAP; @@ -497,7 +521,8 @@ static GPUTexture *GPU_texture_cube_create( // tex->target_base = tex->target = GL_TEXTURE_CUBE_MAP_ARRAY; } - internalformat = gpu_texture_get_format(components, data_type, &format, &data_format, &tex->depth, &tex->stencil, &tex->bytesize); + internalformat = gpu_texture_get_format(components, data_type, &format, &data_format, + &tex->format_flag, &tex->bytesize); gpu_texture_memory_footprint_add(tex); @@ -513,7 +538,6 @@ static GPUTexture *GPU_texture_cube_create( return NULL; } - tex->number = 0; glBindTexture(tex->target, tex->bindcode); /* Upload Texture */ @@ -525,22 +549,28 @@ static GPUTexture *GPU_texture_cube_create( glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, 0, internalformat, tex->w, tex->h, 0, format, data_format, fpixels_nz); /* Texture Parameters */ - if (tex->depth) { + if (GPU_texture_stencil(tex) || /* Does not support filtering */ + GPU_texture_integer(tex) || /* Does not support filtering */ + GPU_texture_depth(tex)) + { glTexParameteri(tex->target_base, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(tex->target_base, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(tex->target_base, GL_TEXTURE_COMPARE_MODE, GL_NONE); - glTexParameteri(tex->target_base, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL); + glTexParameteri(tex->target_base, GL_TEXTURE_MAG_FILTER, GL_NEAREST); } else { glTexParameteri(tex->target_base, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(tex->target_base, GL_TEXTURE_MAG_FILTER, GL_LINEAR); } + if (GPU_texture_depth(tex)) { + glTexParameteri(tex->target_base, GL_TEXTURE_COMPARE_MODE, GL_NONE); + glTexParameteri(tex->target_base, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL); + } + glTexParameteri(tex->target_base, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(tex->target_base, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(tex->target_base, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); - GPU_texture_unbind(tex); + glBindTexture(tex->target, 0); return tex; } @@ -576,6 +606,7 @@ GPUTexture *GPU_texture_from_blender(Image *ima, ImageUser *iuser, int textarget tex->fromblender = 1; tex->format = -1; tex->components = -1; + tex->samples = 0; ima->gputexture[gputt] = tex; @@ -686,7 +717,8 @@ GPUTexture *GPU_texture_create_2D_custom_multisample( return GPU_texture_create_nD(w, h, 0, 2, pixels, data_type, channels, samples, false, err_out); } -GPUTexture *GPU_texture_create_2D_array_custom(int w, int h, int d, int channels, GPUTextureFormat data_type, const float *pixels, char err_out[256]) +GPUTexture *GPU_texture_create_2D_array_custom( + int w, int h, int d, int channels, GPUTextureFormat data_type, const float *pixels, char err_out[256]) { return GPU_texture_create_nD(w, h, d, 2, pixels, data_type, channels, 0, false, err_out); } @@ -696,11 +728,13 @@ GPUTexture *GPU_texture_create_3D(int w, int h, int d, const float *pixels, char return GPU_texture_create_nD(w, h, d, 3, pixels, GPU_RGBA8, 4, 0, true, err_out); } -GPUTexture *GPU_texture_create_3D_custom(int w, int h, int d, int channels, GPUTextureFormat data_type, const float *pixels, char err_out[256]) +GPUTexture *GPU_texture_create_3D_custom( + int w, int h, int d, int channels, GPUTextureFormat data_type, const float *pixels, char err_out[256]) { return GPU_texture_create_nD(w, h, d, 3, pixels, data_type, channels, 0, true, err_out); } -GPUTexture *GPU_texture_create_cube_custom(int w, int channels, GPUTextureFormat data_type, const float *fpixels, char err_out[256]) +GPUTexture *GPU_texture_create_cube_custom( + int w, int channels, GPUTextureFormat data_type, const float *fpixels, char err_out[256]) { const float *fpixels_px, *fpixels_py, *fpixels_pz, *fpixels_nx, *fpixels_ny, *fpixels_nz; @@ -716,7 +750,8 @@ GPUTexture *GPU_texture_create_cube_custom(int w, int channels, GPUTextureFormat fpixels_px = fpixels_py = fpixels_pz = fpixels_nx = fpixels_ny = fpixels_nz = NULL; } - return GPU_texture_cube_create(w, 0, fpixels_px, fpixels_py, fpixels_pz, fpixels_nx, fpixels_ny, fpixels_nz, data_type, channels, err_out); + return GPU_texture_cube_create(w, 0, fpixels_px, fpixels_py, fpixels_pz, fpixels_nx, fpixels_ny, fpixels_nz, + data_type, channels, err_out); } GPUTexture *GPU_texture_create_depth(int w, int h, char err_out[256]) @@ -745,7 +780,8 @@ void GPU_texture_update(GPUTexture *tex, const float *pixels) BLI_assert(tex->components > -1); GLenum format, data_format; - gpu_texture_get_format(tex->components, tex->format, &format, &data_format, &tex->depth, &tex->stencil, &tex->bytesize); + gpu_texture_get_format(tex->components, tex->format, &format, &data_format, + &tex->format_flag, &tex->bytesize); glBindTexture(tex->target, tex->bindcode); @@ -803,55 +839,44 @@ void GPU_invalid_tex_free(void) GPU_texture_free(GG.invalid_tex_3D); } - void GPU_texture_bind(GPUTexture *tex, int number) { + BLI_assert(number >= 0); + if (number >= GPU_max_textures()) { fprintf(stderr, "Not enough texture slots.\n"); return; } if ((G.debug & G_DEBUG)) { - if (tex->fb && GPU_framebuffer_bound(tex->fb)) { - fprintf(stderr, "Feedback loop warning!: Attempting to bind texture attached to current framebuffer!\n"); + for (int i = 0; i < GPU_TEX_MAX_FBO_ATTACHED; ++i) { + if (tex->fb[i] && GPU_framebuffer_bound(tex->fb[i])) { + fprintf(stderr, "Feedback loop warning!: Attempting to bind " + "texture attached to current framebuffer!\n"); + BLI_assert(0); /* Should never happen! */ + break; + } } } - if (number < 0) - return; - - if (number != 0) - glActiveTexture(GL_TEXTURE0 + number); + glActiveTexture(GL_TEXTURE0 + number); if (tex->bindcode != 0) glBindTexture(tex->target, tex->bindcode); else GPU_invalid_tex_bind(tex->target_base); - if (number != 0) - glActiveTexture(GL_TEXTURE0); - tex->number = number; } void GPU_texture_unbind(GPUTexture *tex) { - if (tex->number >= GPU_max_textures()) { - fprintf(stderr, "Not enough texture slots.\n"); - return; - } - if (tex->number == -1) return; - if (tex->number != 0) - glActiveTexture(GL_TEXTURE0 + tex->number); - + glActiveTexture(GL_TEXTURE0 + tex->number); glBindTexture(tex->target, 0); - if (tex->number != 0) - glActiveTexture(GL_TEXTURE0); - tex->number = -1; } @@ -860,114 +885,79 @@ int GPU_texture_bound_number(GPUTexture *tex) return tex->number; } +#define WARN_NOT_BOUND(_tex) do { \ + if (_tex->number == -1) { \ + fprintf(stderr, "Warning : Trying to set parameter on a texture not bound.\n"); \ + BLI_assert(0); \ + return; \ + } \ +} while (0); + void GPU_texture_generate_mipmap(GPUTexture *tex) { - if (tex->number >= GPU_max_textures()) { - fprintf(stderr, "Not enough texture slots.\n"); - return; - } - - if (tex->number == -1) - return; - - if (tex->number != 0) - glActiveTexture(GL_TEXTURE0 + tex->number); + WARN_NOT_BOUND(tex); + glActiveTexture(GL_TEXTURE0 + tex->number); glGenerateMipmap(tex->target_base); - - if (tex->number != 0) - glActiveTexture(GL_TEXTURE0); } void GPU_texture_compare_mode(GPUTexture *tex, bool use_compare) { - if (tex->number >= GPU_max_textures()) { - fprintf(stderr, "Not enough texture slots.\n"); - return; - } + WARN_NOT_BOUND(tex); - if (tex->number == -1) + /* Could become an assertion ? (fclem) */ + if (!GPU_texture_depth(tex)) return; - if (tex->number != 0) - glActiveTexture(GL_TEXTURE0 + tex->number); - - /* TODO viewport: use GL_COMPARE_REF_TO_TEXTURE after we switch to core profile */ - if (tex->depth) - glTexParameteri(tex->target_base, GL_TEXTURE_COMPARE_MODE, use_compare ? GL_COMPARE_R_TO_TEXTURE : GL_NONE); + GLenum mode = (use_compare) ? GL_COMPARE_REF_TO_TEXTURE : GL_NONE; - if (tex->number != 0) - glActiveTexture(GL_TEXTURE0); + glActiveTexture(GL_TEXTURE0 + tex->number); + glTexParameteri(tex->target_base, GL_TEXTURE_COMPARE_MODE, mode); } void GPU_texture_filter_mode(GPUTexture *tex, bool use_filter) { - if (tex->number >= GPU_max_textures()) { - fprintf(stderr, "Not enough texture slots.\n"); - return; - } + WARN_NOT_BOUND(tex); - if (tex->number == -1) - return; + /* Stencil and integer format does not support filtering. */ + BLI_assert(!use_filter || !(GPU_texture_stencil(tex) || GPU_texture_integer(tex))); - if (tex->number != 0) - glActiveTexture(GL_TEXTURE0 + tex->number); + GLenum filter = (use_filter) ? GL_LINEAR : GL_NEAREST; - GLenum filter = use_filter ? GL_LINEAR : GL_NEAREST; + glActiveTexture(GL_TEXTURE0 + tex->number); glTexParameteri(tex->target_base, GL_TEXTURE_MAG_FILTER, filter); glTexParameteri(tex->target_base, GL_TEXTURE_MIN_FILTER, filter); - - if (tex->number != 0) - glActiveTexture(GL_TEXTURE0); } void GPU_texture_mipmap_mode(GPUTexture *tex, bool use_mipmap, bool use_filter) { - if (tex->number >= GPU_max_textures()) { - fprintf(stderr, "Not enough texture slots.\n"); - return; - } - - if (tex->number == -1) - return; + WARN_NOT_BOUND(tex); - if (tex->number != 0) - glActiveTexture(GL_TEXTURE0 + tex->number); + /* Stencil and integer format does not support filtering. */ + BLI_assert((!use_filter && !use_mipmap) || !(GPU_texture_stencil(tex) || GPU_texture_integer(tex))); + GLenum filter = (use_filter) ? GL_LINEAR : GL_NEAREST; GLenum mipmap = (use_filter) - ? use_mipmap ? GL_LINEAR_MIPMAP_LINEAR : GL_LINEAR - : use_mipmap ? GL_NEAREST_MIPMAP_LINEAR : GL_NEAREST; - glTexParameteri(tex->target_base, GL_TEXTURE_MIN_FILTER, mipmap); + ? (use_mipmap) ? GL_LINEAR_MIPMAP_LINEAR : GL_LINEAR + : (use_mipmap) ? GL_NEAREST_MIPMAP_LINEAR : GL_NEAREST; - GLenum filter = use_filter ? GL_LINEAR : GL_NEAREST; + glActiveTexture(GL_TEXTURE0 + tex->number); + glTexParameteri(tex->target_base, GL_TEXTURE_MIN_FILTER, mipmap); glTexParameteri(tex->target_base, GL_TEXTURE_MAG_FILTER, filter); - - if (tex->number != 0) - glActiveTexture(GL_TEXTURE0); } void GPU_texture_wrap_mode(GPUTexture *tex, bool use_repeat) { - if (tex->number >= GPU_max_textures()) { - fprintf(stderr, "Not enough texture slots.\n"); - return; - } + WARN_NOT_BOUND(tex); - if (tex->number == -1) - return; - - if (tex->number != 0) - glActiveTexture(GL_TEXTURE0 + tex->number); + GLenum repeat = (use_repeat) ? GL_REPEAT : GL_CLAMP_TO_EDGE; - GLenum repeat = use_repeat ? GL_REPEAT : GL_CLAMP_TO_EDGE; + glActiveTexture(GL_TEXTURE0 + tex->number); glTexParameteri(tex->target_base, GL_TEXTURE_WRAP_S, repeat); if (tex->target_base != GL_TEXTURE_1D) glTexParameteri(tex->target_base, GL_TEXTURE_WRAP_T, repeat); if (tex->target_base == GL_TEXTURE_3D) glTexParameteri(tex->target_base, GL_TEXTURE_WRAP_R, repeat); - - if (tex->number != 0) - glActiveTexture(GL_TEXTURE0); } void GPU_texture_free(GPUTexture *tex) @@ -978,8 +968,12 @@ void GPU_texture_free(GPUTexture *tex) fprintf(stderr, "GPUTexture: negative refcount\n"); if (tex->refcount == 0) { - if (tex->fb) - GPU_framebuffer_texture_detach(tex); + for (int i = 0; i < GPU_TEX_MAX_FBO_ATTACHED; ++i) { + if (tex->fb[i] != NULL) { + GPU_framebuffer_texture_detach_slot(tex->fb[i], tex, tex->fb_attachment[i]); + } + } + if (tex->bindcode && !tex->fromblender) glDeleteTextures(1, &tex->bindcode); @@ -1009,39 +1003,64 @@ int GPU_texture_height(const GPUTexture *tex) return tex->h; } -int GPU_texture_format(const GPUTexture *tex) +GPUTextureFormat GPU_texture_format(const GPUTexture *tex) { return tex->format; } +int GPU_texture_samples(const GPUTexture *tex) +{ + return tex->samples; +} + bool GPU_texture_depth(const GPUTexture *tex) { - return tex->depth; + return (tex->format_flag & GPU_FORMAT_DEPTH) != 0; } bool GPU_texture_stencil(const GPUTexture *tex) { - return tex->stencil; + return (tex->format_flag & GPU_FORMAT_STENCIL) != 0; } -int GPU_texture_opengl_bindcode(const GPUTexture *tex) +bool GPU_texture_integer(const GPUTexture *tex) { - return tex->bindcode; + return (tex->format_flag & GPU_FORMAT_INTEGER) != 0; } -GPUFrameBuffer *GPU_texture_framebuffer(GPUTexture *tex) +bool GPU_texture_cube(const GPUTexture *tex) { - return tex->fb; + return (tex->format_flag & GPU_FORMAT_CUBE) != 0; } -int GPU_texture_framebuffer_attachment(GPUTexture *tex) +int GPU_texture_opengl_bindcode(const GPUTexture *tex) { - return tex->fb_attachment; + return tex->bindcode; } -void GPU_texture_framebuffer_set(GPUTexture *tex, GPUFrameBuffer *fb, int attachment) +void GPU_texture_attach_framebuffer(GPUTexture *tex, GPUFrameBuffer *fb, int attachment) { - tex->fb = fb; - tex->fb_attachment = attachment; + for (int i = 0; i < GPU_TEX_MAX_FBO_ATTACHED; ++i) { + if (tex->fb[i] == NULL) { + tex->fb[i] = fb; + tex->fb_attachment[i] = attachment; + return; + } + } + + BLI_assert(!"Error: Texture: Not enough Framebuffer slots"); } +/* Return previous attachment point */ +int GPU_texture_detach_framebuffer(GPUTexture *tex, GPUFrameBuffer *fb) +{ + for (int i = 0; i < GPU_TEX_MAX_FBO_ATTACHED; ++i) { + if (tex->fb[i] == fb) { + tex->fb[i] = NULL; + return tex->fb_attachment[i]; + } + } + + BLI_assert(!"Error: Texture: Framebuffer is not attached"); + return 0; +} diff --git a/source/blender/gpu/intern/gpu_viewport.c b/source/blender/gpu/intern/gpu_viewport.c index 3ef53b3a6c3..5d89bd59277 100644 --- a/source/blender/gpu/intern/gpu_viewport.c +++ b/source/blender/gpu/intern/gpu_viewport.c @@ -48,6 +48,7 @@ #include "GPU_immediate.h" #include "GPU_texture.h" #include "GPU_viewport.h" +#include "GPU_draw.h" #include "DRW_engine.h" @@ -68,12 +69,7 @@ typedef struct ViewportTempTexture { } ViewportTempTexture; struct GPUViewport { - float pad[4]; - - /* debug */ - GPUTexture *debug_depth; int size[2]; - int samples; int flag; @@ -87,6 +83,9 @@ struct GPUViewport { struct DRWInstanceDataList *idatalist; /* Used for rendering data structure. */ ListBase tex_pool; /* ViewportTempTexture list : Temporary textures shared across draw engines */ + + /* Profiling data */ + double cache_time; }; enum { @@ -97,6 +96,7 @@ static void gpu_viewport_buffers_free(FramebufferList *fbl, int fbl_len, Texture static void gpu_viewport_storage_free(StorageList *stl, int stl_len); static void gpu_viewport_passes_free(PassList *psl, int psl_len); static void gpu_viewport_texture_pool_free(GPUViewport *viewport); +static void gpu_viewport_default_fb_create(GPUViewport *viewport); void GPU_viewport_tag_update(GPUViewport *viewport) { @@ -125,9 +125,33 @@ GPUViewport *GPU_viewport_create(void) GPUViewport *GPU_viewport_create_from_offscreen(struct GPUOffScreen *ofs) { GPUViewport *viewport = GPU_viewport_create(); - GPU_offscreen_viewport_data_get(ofs, &viewport->fbl->default_fb, &viewport->txl->color, &viewport->txl->depth); + GPUTexture *color, *depth; + GPUFrameBuffer *fb; viewport->size[0] = GPU_offscreen_width(ofs); viewport->size[1] = GPU_offscreen_height(ofs); + + GPU_offscreen_viewport_data_get(ofs, &fb, &color, &depth); + + if (GPU_texture_samples(color)) { + viewport->txl->multisample_color = color; + viewport->txl->multisample_depth = depth; + viewport->fbl->multisample_fb = fb; + gpu_viewport_default_fb_create(viewport); + } + else { + viewport->fbl->default_fb = fb; + viewport->txl->color = color; + viewport->txl->depth = depth; + GPU_framebuffer_ensure_config(&viewport->fbl->color_only_fb, { + GPU_ATTACHMENT_NONE, + GPU_ATTACHMENT_TEXTURE(viewport->txl->color) + }); + GPU_framebuffer_ensure_config(&viewport->fbl->depth_only_fb, { + GPU_ATTACHMENT_TEXTURE(viewport->txl->depth), + GPU_ATTACHMENT_NONE + }); + } + return viewport; } /** @@ -135,9 +159,22 @@ GPUViewport *GPU_viewport_create_from_offscreen(struct GPUOffScreen *ofs) */ void GPU_viewport_clear_from_offscreen(GPUViewport *viewport) { - viewport->fbl->default_fb = NULL; - viewport->txl->color = NULL; - viewport->txl->depth = NULL; + DefaultFramebufferList *dfbl = viewport->fbl; + DefaultTextureList *dtxl = viewport->txl; + + if (dfbl->multisample_fb) { + /* GPUViewport expect the final result to be in default_fb but + * GPUOffscreen wants it in its multisample_fb, so we sync it back. */ + GPU_framebuffer_blit(dfbl->default_fb, 0, dfbl->multisample_fb, 0, GPU_COLOR_BIT | GPU_DEPTH_BIT); + dfbl->multisample_fb = NULL; + dtxl->multisample_color = NULL; + dtxl->multisample_depth = NULL; + } + else { + viewport->fbl->default_fb = NULL; + dtxl->color = NULL; + dtxl->depth = NULL; + } } void *GPU_viewport_engine_data_create(GPUViewport *viewport, void *engine_type) @@ -243,6 +280,11 @@ void GPU_viewport_size_set(GPUViewport *viewport, const int size[2]) viewport->size[1] = size[1]; } +double *GPU_viewport_cache_time_get(GPUViewport *viewport) +{ + return &viewport->cache_time; +} + /** * Try to find a texture coresponding to params into the texture pool. * If no texture was found, create one and add it to the pool. @@ -252,9 +294,9 @@ GPUTexture *GPU_viewport_texture_pool_query(GPUViewport *viewport, void *engine, GPUTexture *tex; for (ViewportTempTexture *tmp_tex = viewport->tex_pool.first; tmp_tex; tmp_tex = tmp_tex->next) { - if ((GPU_texture_width(tmp_tex->texture) == width) && - (GPU_texture_height(tmp_tex->texture) == height) && - (GPU_texture_format(tmp_tex->texture) == format)) + if ((GPU_texture_format(tmp_tex->texture) == format) && + (GPU_texture_width(tmp_tex->texture) == width) && + (GPU_texture_height(tmp_tex->texture) == height)) { /* Search if the engine is not already using this texture */ for (int i = 0; i < MAX_ENGINE_BUFFER_SHARING; ++i) { @@ -271,11 +313,16 @@ GPUTexture *GPU_viewport_texture_pool_query(GPUViewport *viewport, void *engine, } tex = GPU_texture_create_2D_custom(width, height, channels, format, NULL, NULL); + GPU_texture_bind(tex, 0); + /* Doing filtering for depth does not make sense when not doing shadow mapping, + * and enabling texture filtering on integer texture make them unreadable. */ + bool do_filter = !GPU_texture_depth(tex) && !GPU_texture_integer(tex); + GPU_texture_filter_mode(tex, do_filter); + GPU_texture_unbind(tex); ViewportTempTexture *tmp_tex = MEM_callocN(sizeof(ViewportTempTexture), "ViewportTempTexture"); tmp_tex->texture = tex; tmp_tex->user[0] = engine; - BLI_addtail(&viewport->tex_pool, tmp_tex); return tex; @@ -335,16 +382,94 @@ void GPU_viewport_cache_release(GPUViewport *viewport) } } -void GPU_viewport_bind(GPUViewport *viewport, const rcti *rect) +static void gpu_viewport_default_fb_create(GPUViewport *viewport) +{ + DefaultFramebufferList *dfbl = viewport->fbl; + DefaultTextureList *dtxl = viewport->txl; + int *size = viewport->size; + bool ok = true; + + dtxl->color = GPU_texture_create_2D(size[0], size[1], NULL, NULL); + dtxl->depth = GPU_texture_create_depth_with_stencil(size[0], size[1], NULL); + + if (!(dtxl->depth && dtxl->color)) { + ok = false; + goto cleanup; + } + + GPU_framebuffer_ensure_config(&dfbl->default_fb, { + GPU_ATTACHMENT_TEXTURE(dtxl->depth), + GPU_ATTACHMENT_TEXTURE(dtxl->color) + }); + + GPU_framebuffer_ensure_config(&dfbl->depth_only_fb, { + GPU_ATTACHMENT_TEXTURE(dtxl->depth), + GPU_ATTACHMENT_NONE + }); + + GPU_framebuffer_ensure_config(&dfbl->color_only_fb, { + GPU_ATTACHMENT_NONE, + GPU_ATTACHMENT_TEXTURE(dtxl->color) + }); + + ok = ok && GPU_framebuffer_check_valid(dfbl->default_fb, NULL); + ok = ok && GPU_framebuffer_check_valid(dfbl->color_only_fb, NULL); + ok = ok && GPU_framebuffer_check_valid(dfbl->depth_only_fb, NULL); + +cleanup: + if (!ok) { + GPU_viewport_free(viewport); + DRW_opengl_context_disable(); + return; + } + + GPU_framebuffer_restore(); +} + +static void gpu_viewport_default_multisample_fb_create(GPUViewport *viewport) { DefaultFramebufferList *dfbl = viewport->fbl; DefaultTextureList *dtxl = viewport->txl; + int *size = viewport->size; + int samples = viewport->samples; + bool ok = true; + + dtxl->multisample_color = GPU_texture_create_2D_multisample(size[0], size[1], NULL, samples, NULL); + dtxl->multisample_depth = GPU_texture_create_depth_with_stencil_multisample(size[0], size[1], samples, NULL); + + if (!(dtxl->multisample_depth && dtxl->multisample_color)) { + ok = false; + goto cleanup; + } + + GPU_framebuffer_ensure_config(&dfbl->multisample_fb, { + GPU_ATTACHMENT_TEXTURE(dtxl->multisample_depth), + GPU_ATTACHMENT_TEXTURE(dtxl->multisample_color) + }); + + ok = ok && GPU_framebuffer_check_valid(dfbl->multisample_fb, NULL); + +cleanup: + if (!ok) { + GPU_viewport_free(viewport); + DRW_opengl_context_disable(); + return; + } + + GPU_framebuffer_restore(); +} + +void GPU_viewport_bind(GPUViewport *viewport, const rcti *rect) +{ + DefaultFramebufferList *dfbl = viewport->fbl; int fbl_len, txl_len; /* add one pixel because of scissor test */ int rect_w = BLI_rcti_size_x(rect) + 1; int rect_h = BLI_rcti_size_y(rect) + 1; + DRW_opengl_context_enable(); + if (dfbl->default_fb) { if (rect_w != viewport->size[0] || rect_h != viewport->size[1] || U.ogl_multisamples != viewport->samples) { gpu_viewport_buffers_free( @@ -361,121 +486,31 @@ void GPU_viewport_bind(GPUViewport *viewport, const rcti *rect) } } + viewport->size[0] = rect_w; + viewport->size[1] = rect_h; + viewport->samples = U.ogl_multisamples; + gpu_viewport_texture_pool_clear_users(viewport); /* Multisample Buffer */ - if (U.ogl_multisamples > 0) { + if (viewport->samples > 0) { if (!dfbl->default_fb) { - bool ok = true; - viewport->samples = U.ogl_multisamples; - - dfbl->multisample_fb = GPU_framebuffer_create(); - if (!dfbl->multisample_fb) { - ok = false; - goto cleanup_multisample; - } - - /* Color */ - dtxl->multisample_color = GPU_texture_create_2D_multisample(rect_w, rect_h, NULL, U.ogl_multisamples, NULL); - if (!dtxl->multisample_color) { - ok = false; - goto cleanup_multisample; - } - - if (!GPU_framebuffer_texture_attach(dfbl->multisample_fb, dtxl->multisample_color, 0, 0)) { - ok = false; - goto cleanup_multisample; - } - - /* Depth */ - dtxl->multisample_depth = GPU_texture_create_depth_with_stencil_multisample(rect_w, rect_h, - U.ogl_multisamples, NULL); - - if (!dtxl->multisample_depth) { - ok = false; - goto cleanup_multisample; - } - - if (!GPU_framebuffer_texture_attach(dfbl->multisample_fb, dtxl->multisample_depth, 0, 0)) { - ok = false; - goto cleanup_multisample; - } - else if (!GPU_framebuffer_check_valid(dfbl->multisample_fb, NULL)) { - ok = false; - goto cleanup_multisample; - } - -cleanup_multisample: - if (!ok) { - GPU_viewport_free(viewport); - MEM_freeN(viewport); - return; - } + gpu_viewport_default_multisample_fb_create(viewport); } } if (!dfbl->default_fb) { - bool ok = true; - viewport->size[0] = rect_w; - viewport->size[1] = rect_h; - - dfbl->default_fb = GPU_framebuffer_create(); - if (!dfbl->default_fb) { - ok = false; - goto cleanup; - } - - /* Color */ - dtxl->color = GPU_texture_create_2D(rect_w, rect_h, NULL, NULL); - if (!dtxl->color) { - ok = false; - goto cleanup; - } - - if (!GPU_framebuffer_texture_attach(dfbl->default_fb, dtxl->color, 0, 0)) { - ok = false; - goto cleanup; - } - - /* Depth */ - dtxl->depth = GPU_texture_create_depth_with_stencil(rect_w, rect_h, NULL); - - if (dtxl->depth) { - /* Define texture parameters */ - GPU_texture_bind(dtxl->depth, 0); - GPU_texture_compare_mode(dtxl->depth, false); - GPU_texture_filter_mode(dtxl->depth, true); - GPU_texture_unbind(dtxl->depth); - } - else { - ok = false; - goto cleanup; - } - - if (!GPU_framebuffer_texture_attach(dfbl->default_fb, dtxl->depth, 0, 0)) { - ok = false; - goto cleanup; - } - else if (!GPU_framebuffer_check_valid(dfbl->default_fb, NULL)) { - ok = false; - goto cleanup; - } - -cleanup: - if (!ok) { - GPU_viewport_free(viewport); - MEM_freeN(viewport); - return; - } - - GPU_framebuffer_restore(); + gpu_viewport_default_fb_create(viewport); } - - GPU_framebuffer_slots_bind(dfbl->default_fb, 0); } -static void draw_ofs_to_screen(GPUViewport *viewport) +void GPU_viewport_draw_to_screen(GPUViewport *viewport, const rcti *rect) { + DefaultFramebufferList *dfbl = viewport->fbl; + + if (dfbl->default_fb == NULL) + return; + DefaultTextureList *dtxl = viewport->txl; GPUTexture *color = dtxl->color; @@ -483,50 +518,31 @@ static void draw_ofs_to_screen(GPUViewport *viewport) const float w = (float)GPU_texture_width(color); const float h = (float)GPU_texture_height(color); - Gwn_VertFormat *format = immVertexFormat(); - unsigned int texcoord = GWN_vertformat_attr_add(format, "texCoord", GWN_COMP_F32, 2, GWN_FETCH_FLOAT); - unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT); - - immBindBuiltinProgram(GPU_SHADER_3D_IMAGE_MODULATE_ALPHA); - GPU_texture_bind(color, 0); - - immUniform1i("image", 0); /* default GL_TEXTURE0 unit */ - - immBegin(GWN_PRIM_TRI_STRIP, 4); + BLI_assert(w == BLI_rcti_size_x(rect) + 1); + BLI_assert(h == BLI_rcti_size_y(rect) + 1); - immAttrib2f(texcoord, 0.0f, 0.0f); - immVertex2f(pos, 0.0f, 0.0f); + float x1 = rect->xmin; + float x2 = rect->xmin + w; + float y1 = rect->ymin; + float y2 = rect->ymin + h; - immAttrib2f(texcoord, 1.0f, 0.0f); - immVertex2f(pos, w, 0.0f); + GPUShader *shader = GPU_shader_get_builtin_shader(GPU_SHADER_2D_IMAGE_RECT_COLOR); + GPU_shader_bind(shader); - immAttrib2f(texcoord, 0.0f, 1.0f); - immVertex2f(pos, 0.0f, h); - - immAttrib2f(texcoord, 1.0f, 1.0f); - immVertex2f(pos, w, h); + GPU_texture_bind(color, 0); + glUniform1i(GPU_shader_get_uniform(shader, "image"), 0); + glUniform4f(GPU_shader_get_uniform(shader, "rect_icon"), 0.0f, 0.0f, 1.0f, 1.0f); + glUniform4f(GPU_shader_get_uniform(shader, "rect_geom"), x1, y1, x2, y2); + glUniform4f(GPU_shader_get_builtin_uniform(shader, GWN_UNIFORM_COLOR), 1.0f, 1.0f, 1.0f, 1.0f); - immEnd(); + GWN_draw_primitive(GWN_PRIM_TRI_STRIP, 4); GPU_texture_unbind(color); - - immUnbindProgram(); } -void GPU_viewport_unbind(GPUViewport *viewport) +void GPU_viewport_unbind(GPUViewport *UNUSED(viewport)) { - DefaultFramebufferList *dfbl = viewport->fbl; - - if (dfbl->default_fb) { - GPU_framebuffer_texture_unbind(NULL, NULL); - GPU_framebuffer_restore(); - - glEnable(GL_SCISSOR_TEST); - glDisable(GL_DEPTH_TEST); - - /* This might be bandwidth limiting */ - draw_ofs_to_screen(viewport); - } + DRW_opengl_context_disable(); } static void gpu_viewport_buffers_free( @@ -571,6 +587,7 @@ static void gpu_viewport_passes_free(PassList *psl, int psl_len) } } +/* Must be executed inside Drawmanager Opengl Context. */ void GPU_viewport_free(GPUViewport *viewport) { gpu_viewport_engines_data_free(viewport); @@ -587,8 +604,8 @@ void GPU_viewport_free(GPUViewport *viewport) if (viewport->vmempool.calls != NULL) { BLI_mempool_destroy(viewport->vmempool.calls); } - if (viewport->vmempool.calls_generate != NULL) { - BLI_mempool_destroy(viewport->vmempool.calls_generate); + if (viewport->vmempool.states != NULL) { + BLI_mempool_destroy(viewport->vmempool.states); } if (viewport->vmempool.shgroups != NULL) { BLI_mempool_destroy(viewport->vmempool.shgroups); @@ -603,84 +620,5 @@ void GPU_viewport_free(GPUViewport *viewport) DRW_instance_data_list_free(viewport->idatalist); MEM_freeN(viewport->idatalist); - GPU_viewport_debug_depth_free(viewport); -} - -/****************** debug ********************/ - -bool GPU_viewport_debug_depth_create(GPUViewport *viewport, int width, int height, char err_out[256]) -{ - viewport->debug_depth = GPU_texture_create_2D_custom(width, height, 4, GPU_RGBA16F, NULL, err_out); - return (viewport->debug_depth != NULL); -} - -void GPU_viewport_debug_depth_free(GPUViewport *viewport) -{ - if (viewport->debug_depth != NULL) { - MEM_freeN(viewport->debug_depth); - viewport->debug_depth = NULL; - } -} - -void GPU_viewport_debug_depth_store(GPUViewport *viewport, const int x, const int y) -{ - const int w = GPU_texture_width(viewport->debug_depth); - const int h = GPU_texture_height(viewport->debug_depth); - - GPU_texture_bind(viewport->debug_depth, 0); - glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT24, x, y, w, h, 0); - GPU_texture_unbind(viewport->debug_depth); -} - -void GPU_viewport_debug_depth_draw(GPUViewport *viewport, const float znear, const float zfar) -{ - const float w = (float)GPU_texture_width(viewport->debug_depth); - const float h = (float)GPU_texture_height(viewport->debug_depth); - - Gwn_VertFormat *format = immVertexFormat(); - unsigned int texcoord = GWN_vertformat_attr_add(format, "texCoord", GWN_COMP_F32, 2, GWN_FETCH_FLOAT); - unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT); - - immBindBuiltinProgram(GPU_SHADER_3D_IMAGE_DEPTH); - - GPU_texture_bind(viewport->debug_depth, 0); - - immUniform1f("znear", znear); - immUniform1f("zfar", zfar); - immUniform1i("image", 0); /* default GL_TEXTURE0 unit */ - - immBegin(GWN_PRIM_TRI_STRIP, 4); - - immAttrib2f(texcoord, 0.0f, 0.0f); - immVertex2f(pos, 0.0f, 0.0f); - - immAttrib2f(texcoord, 1.0f, 0.0f); - immVertex2f(pos, w, 0.0f); - - immAttrib2f(texcoord, 0.0f, 1.0f); - immVertex2f(pos, 0.0f, h); - - immAttrib2f(texcoord, 1.0f, 1.0f); - immVertex2f(pos, w, h); - - immEnd(); - - GPU_texture_unbind(viewport->debug_depth); - - immUnbindProgram(); -} - -int GPU_viewport_debug_depth_width(const GPUViewport *viewport) -{ - return GPU_texture_width(viewport->debug_depth); -} - -int GPU_viewport_debug_depth_height(const GPUViewport *viewport) -{ - return GPU_texture_height(viewport->debug_depth); -} - -bool GPU_viewport_debug_depth_is_valid(GPUViewport *viewport) -{ - return viewport->debug_depth != NULL; + MEM_freeN(viewport); } diff --git a/source/blender/gpu/shaders/gpu_shader_2D_image_multi_rect_vert.glsl b/source/blender/gpu/shaders/gpu_shader_2D_image_multi_rect_vert.glsl new file mode 100644 index 00000000000..9fdf8ececc5 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_2D_image_multi_rect_vert.glsl @@ -0,0 +1,48 @@ +/** + * Simple shader that just draw multiple icons at the specified locations + * does not need any vertex input (producing less call to immBegin/End) + **/ + +/* Same as ICON_DRAW_CACHE_SIZE */ +#define MAX_CALLS 16 + +uniform vec4 calls_data[MAX_CALLS * 3]; + +out vec2 texCoord_interp; +flat out vec4 finalColor; + +void main() +{ + /* Rendering 2 triangle per icon. */ + int i = gl_VertexID / 6; + int v = gl_VertexID % 6; + + vec4 pos = calls_data[i*3]; + vec4 tex = calls_data[i*3+1]; + finalColor = calls_data[i*3+2]; + + /* TODO Remove this */ + if (v == 2) v = 4; + else if (v == 3) v = 0; + else if (v == 5) v = 2; + + if (v == 0) { + pos.xy = pos.xw; + tex.xy = tex.xw; + } + else if (v == 1) { + pos.xy = pos.xz; + tex.xy = tex.xz; + } + else if (v == 2) { + pos.xy = pos.yw; + tex.xy = tex.yw; + } + else { + pos.xy = pos.yz; + tex.xy = tex.yz; + } + + gl_Position = vec4(pos.xy, 0.0f, 1.0f); + texCoord_interp = tex.xy; +} diff --git a/source/blender/gpu/shaders/gpu_shader_2D_image_rect_vert.glsl b/source/blender/gpu/shaders/gpu_shader_2D_image_rect_vert.glsl new file mode 100644 index 00000000000..118f4e3b187 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_2D_image_rect_vert.glsl @@ -0,0 +1,35 @@ +/** + * Simple shader that just draw one icon at the specified location + * does not need any vertex input (producing less call to immBegin/End) + **/ + +uniform mat4 ModelViewProjectionMatrix; +uniform vec4 rect_icon; +uniform vec4 rect_geom; + +out vec2 texCoord_interp; + +void main() +{ + vec2 uv; + vec2 co; + if (gl_VertexID == 0) { + co = rect_geom.xw; + uv = rect_icon.xw; + } + else if (gl_VertexID == 1) { + co = rect_geom.xy; + uv = rect_icon.xy; + } + else if (gl_VertexID == 2) { + co = rect_geom.zw; + uv = rect_icon.zw; + } + else { + co = rect_geom.zy; + uv = rect_icon.zy; + } + + gl_Position = ModelViewProjectionMatrix * vec4(co, 0.0f, 1.0f); + texCoord_interp = uv; +} diff --git a/source/blender/gpu/shaders/gpu_shader_2D_nodelink_frag.glsl b/source/blender/gpu/shaders/gpu_shader_2D_nodelink_frag.glsl new file mode 100644 index 00000000000..8dda575107a --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_2D_nodelink_frag.glsl @@ -0,0 +1,10 @@ + +in float colorGradient; +in vec4 finalColor; + +out vec4 fragColor; + +void main() { + fragColor = finalColor; + fragColor.a *= smoothstep(1.0, 0.1, abs(colorGradient)); +}
\ No newline at end of file diff --git a/source/blender/gpu/shaders/gpu_shader_2D_nodelink_vert.glsl b/source/blender/gpu/shaders/gpu_shader_2D_nodelink_vert.glsl new file mode 100644 index 00000000000..4c295fcd72a --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_2D_nodelink_vert.glsl @@ -0,0 +1,107 @@ +/** + * 2D Quadratic Bezier thick line drawing + **/ + +#define MID_VERTEX 57 + +/* u is position along the curve, defining the tangent space. + * v is "signed" distance (compressed to [0..1] range) from the pos in expand direction */ +in vec2 uv; +in vec2 pos; /* verts position in the curve tangent space */ +in vec2 expand; + +#ifdef USE_INSTANCE +/* Instance attrib */ +in vec2 P0; +in vec2 P1; +in vec2 P2; +in vec2 P3; +in ivec4 colid_doarrow; + +uniform vec4 colors[6]; + +#define colStart colors[colid_doarrow[0]] +#define colEnd colors[colid_doarrow[1]] +#define colShadow colors[colid_doarrow[2]] +#define doArrow (colid_doarrow[3] != 0) + +#else +/* Single curve drawcall, use uniform. */ +uniform vec2 bezierPts[4]; + +#define P0 bezierPts[0] +#define P1 bezierPts[1] +#define P2 bezierPts[2] +#define P3 bezierPts[3] + +uniform vec4 colors[3]; +uniform bool doArrow; + +#define colShadow colors[0] +#define colStart colors[1] +#define colEnd colors[2] + +#endif + +uniform float expandSize; +uniform float arrowSize; +uniform mat4 ModelViewProjectionMatrix; + +out float colorGradient; +out vec4 finalColor; + +void main(void) +{ + float t = uv.x; + float t2 = t * t; + float t2_3 = 3.0 * t2; + float one_minus_t = 1.0 - t; + float one_minus_t2 = one_minus_t * one_minus_t; + float one_minus_t2_3 = 3.0 * one_minus_t2; + + vec2 point = (P0 * one_minus_t2 * one_minus_t + + P1 * one_minus_t2_3 * t + + P2 * t2_3 * one_minus_t + + P3 * t2 * t); + + vec2 tangent = ((P1 - P0) * one_minus_t2_3 + + (P2 - P1) * 6.0 * (t - t2) + + (P3 - P2) * t2_3); + + /* tangent space at t */ + tangent = normalize(tangent); + vec2 normal = tangent.yx * vec2(-1.0, 1.0); + + /* Position vertex on the curve tangent space */ + point += (pos.x * tangent + pos.y * normal) * arrowSize; + + gl_Position = ModelViewProjectionMatrix * vec4(point, 0.0, 1.0); + + vec2 exp_axis = expand.x * tangent + expand.y * normal; + + /* rotate & scale the expand axis */ + exp_axis = ModelViewProjectionMatrix[0].xy * exp_axis.xx + + ModelViewProjectionMatrix[1].xy * exp_axis.yy; + + + float expand_dist = (uv.y * 2.0 - 1.0); + colorGradient = expand_dist; + + if (gl_VertexID < MID_VERTEX) { + /* Shadow pass */ + finalColor = colShadow; + } + else { + /* Second pass */ + finalColor = mix(colStart, colEnd, uv.x); + expand_dist *= 0.5; + } + + /* Expand into a line */ + gl_Position.xy += exp_axis * expandSize * expand_dist; + + /* if arrow */ + if (expand.y != 1.0 && !doArrow) { + gl_Position.xy *= 0.0; + } +}
\ No newline at end of file diff --git a/source/blender/gpu/shaders/gpu_shader_2D_widget_base_frag.glsl b/source/blender/gpu/shaders/gpu_shader_2D_widget_base_frag.glsl new file mode 100644 index 00000000000..f660cae8d12 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_2D_widget_base_frag.glsl @@ -0,0 +1,35 @@ +uniform vec3 checkerColorAndSize; + +noperspective in vec4 finalColor; +noperspective in float butCo; + +out vec4 fragColor; + +vec4 do_checkerboard() +{ + float size = checkerColorAndSize.z; + vec2 phase = mod(gl_FragCoord.xy, size * 2.0); + + if ((phase.x > size && phase.y < size) || + (phase.x < size && phase.y > size)) + { + return vec4(checkerColorAndSize.xxx, 1.0); + } + else { + return vec4(checkerColorAndSize.yyy, 1.0); + } +} + +void main() +{ + fragColor = finalColor; + + if (butCo > 0.5) { + vec4 checker = do_checkerboard(); + fragColor = mix(checker, fragColor, fragColor.a); + } + + if (butCo > 0.0) { + fragColor.a = 1.0; + } +}
\ No newline at end of file diff --git a/source/blender/gpu/shaders/gpu_shader_2D_widget_base_vert.glsl b/source/blender/gpu/shaders/gpu_shader_2D_widget_base_vert.glsl new file mode 100644 index 00000000000..0c351a3bce4 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_2D_widget_base_vert.glsl @@ -0,0 +1,186 @@ +#define BIT_RANGE(x) uint((1 << x) - 1) + +/* 2 bits for corner */ +/* Attention! Not the same order as in UI_interface.h! + * Ordered by drawing order. */ +#define BOTTOM_LEFT 0u +#define BOTTOM_RIGHT 1u +#define TOP_RIGHT 2u +#define TOP_LEFT 3u +#define CNR_FLAG_RANGE BIT_RANGE(2) + +/* 4bits for corner id */ +#define CORNER_VEC_OFS 2u +#define CORNER_VEC_RANGE BIT_RANGE(4) +const vec2 cornervec[36] = vec2[36]( + vec2(0.0, 1.0), vec2(0.02, 0.805), vec2(0.067, 0.617), vec2(0.169, 0.45), vec2(0.293, 0.293), vec2(0.45, 0.169), vec2(0.617, 0.076), vec2(0.805, 0.02), vec2(1.0, 0.0), + vec2(-1.0, 0.0), vec2(-0.805, 0.02), vec2(-0.617, 0.067), vec2(-0.45, 0.169), vec2(-0.293, 0.293), vec2(-0.169, 0.45), vec2(-0.076, 0.617), vec2(-0.02, 0.805), vec2(0.0, 1.0), + vec2(0.0, -1.0), vec2(-0.02, -0.805), vec2(-0.067, -0.617), vec2(-0.169, -0.45), vec2(-0.293, -0.293), vec2(-0.45, -0.169), vec2(-0.617, -0.076), vec2(-0.805, -0.02), vec2(-1.0, 0.0), + vec2(1.0, 0.0), vec2(0.805, -0.02), vec2(0.617, -0.067), vec2(0.45, -0.169), vec2(0.293, -0.293), vec2(0.169, -0.45), vec2(0.076, -0.617), vec2(0.02, -0.805), vec2(0.0, -1.0) +); + +/* 4bits for jitter id */ +#define JIT_OFS 6u +#define JIT_RANGE BIT_RANGE(4) +const vec2 jit[9] = vec2[9]( + vec2( 0.468813, -0.481430), vec2(-0.155755, -0.352820), + vec2( 0.219306, -0.238501), vec2(-0.393286, -0.110949), + vec2(-0.024699, 0.013908), vec2( 0.343805, 0.147431), + vec2(-0.272855, 0.269918), vec2( 0.095909, 0.388710), + vec2( 0.0, 0.0) +); + +/* 2bits for other flags */ +#define INNER_FLAG uint(1 << 10) /* is inner vert */ +#define EMBOSS_FLAG uint(1 << 11) /* is emboss vert */ + +/* 2bits for color */ +#define COLOR_OFS 12u +#define COLOR_RANGE BIT_RANGE(2) +#define COLOR_INNER 0u +#define COLOR_EDGE 1u +#define COLOR_EMBOSS 2u + +/* 2bits for trias type */ +#define TRIA_FLAG uint(1 << 14) /* is tria vert */ +#define TRIA_FIRST INNER_FLAG /* is first tria (reuse INNER_FLAG) */ + +/* We can reuse the CORNER_* bits for tria */ +#define TRIA_VEC_RANGE BIT_RANGE(6) +const vec2 triavec[34] = vec2[34]( + /* horizontal tria */ + vec2(-0.352077, 0.532607), vec2(-0.352077, -0.549313), vec2( 0.330000, -0.008353), + vec2( 0.352077, 0.532607), vec2( 0.352077, -0.549313), vec2(-0.330000, -0.008353), + /* circle tria (triangle strip) */ + vec2(0.000000, 1.000000), + vec2(0.382684, 0.923879), vec2(-0.382683, 0.923880), + vec2(0.707107, 0.707107), vec2(-0.707107, 0.707107), + vec2(0.923879, 0.382684), vec2(-0.923879, 0.382684), + vec2(1.000000, 0.000000), vec2(-1.000000, 0.000000), + vec2(0.923879, -0.382684), vec2(-0.923879, -0.382684), + vec2(0.707107, -0.707107), vec2(-0.707107, -0.707107), + vec2(0.382684, -0.923879), vec2(-0.382683, -0.923880), + vec2(0.000000, -1.000000), + /* menu arrow */ + vec2(-0.33, 0.16), vec2(0.33, 0.16), vec2(0.0, 0.82), + vec2(0.0, -0.82), vec2(-0.33, -0.16), vec2(0.33, -0.16), + /* check mark */ + vec2(-0.578579, 0.253369), vec2(-0.392773, 0.412794), vec2(-0.004241, -0.328551), + vec2(-0.003001, 0.034320), vec2(1.055313, 0.864744), vec2(0.866408, 1.026895) +); + +uniform mat4 ModelViewProjectionMatrix; + +#ifdef USE_INSTANCE +#define MAX_INSTANCE 6 +uniform vec4 parameters[11 * MAX_INSTANCE]; +#else +uniform vec4 parameters[11]; +#endif + +/* gl_InstanceID is 0 if not drawing instances. */ +#define recti parameters[gl_InstanceID * 11 + 0] +#define rect parameters[gl_InstanceID * 11 + 1] +#define radsi parameters[gl_InstanceID * 11 + 2].x +#define rads parameters[gl_InstanceID * 11 + 2].y +#define faci parameters[gl_InstanceID * 11 + 2].zw +#define roundCorners parameters[gl_InstanceID * 11 + 3] +#define colorInner1 parameters[gl_InstanceID * 11 + 4] +#define colorInner2 parameters[gl_InstanceID * 11 + 5] +#define colorEdge parameters[gl_InstanceID * 11 + 6] +#define colorEmboss parameters[gl_InstanceID * 11 + 7] +#define colorTria parameters[gl_InstanceID * 11 + 8] +#define tria1Center parameters[gl_InstanceID * 11 + 9].xy +#define tria2Center parameters[gl_InstanceID * 11 + 9].zw +#define tria1Size parameters[gl_InstanceID * 11 + 10].x +#define tria2Size parameters[gl_InstanceID * 11 + 10].y +#define shadeDir parameters[gl_InstanceID * 11 + 10].z +#define doAlphaCheck parameters[gl_InstanceID * 11 + 10].w + +in uint vflag; + +noperspective out vec4 finalColor; +noperspective out float butCo; + +vec2 do_widget(void) +{ + uint cflag = vflag & CNR_FLAG_RANGE; + uint vofs = (vflag >> CORNER_VEC_OFS) & CORNER_VEC_RANGE; + + vec2 v = cornervec[cflag * 9u + vofs]; + + bool is_inner = (vflag & INNER_FLAG) != 0u; + + /* Scale by corner radius */ + v *= roundCorners[cflag] * ((is_inner) ? radsi : rads); + + /* Position to corner */ + vec4 rct = (is_inner) ? recti : rect; + if (cflag == BOTTOM_LEFT) + v += rct.xz; + else if (cflag == BOTTOM_RIGHT) + v += rct.yz; + else if (cflag == TOP_RIGHT) + v += rct.yw; + else /* (cflag == TOP_LEFT) */ + v += rct.xw; + + /* compute uv and color gradient */ + uint color_id = (vflag >> COLOR_OFS) & COLOR_RANGE; + if (color_id == COLOR_INNER) { + vec2 uv = faci * (v - recti.xz); + float fac = clamp((shadeDir > 0.0) ? uv.y : uv.x, 0.0, 1.0); + if (doAlphaCheck != 0.0) { + finalColor = colorInner1; + butCo = uv.x; + } + else { + finalColor = mix(colorInner2, colorInner1, fac); + butCo = -1.0; + } + } + else if (color_id == COLOR_EDGE) { + finalColor = colorEdge; + butCo = -1.0; + } + else /* (color_id == COLOR_EMBOSS) */ { + finalColor = colorEmboss; + butCo = -1.0; + } + + bool is_emboss = (vflag & EMBOSS_FLAG) != 0u; + v.y -= (is_emboss) ? 1.0f : 0.0; + + return v; +} + +vec2 do_tria() +{ + uint vofs = vflag & TRIA_VEC_RANGE; + + vec2 v = triavec[vofs]; + + finalColor = colorTria; + butCo = -1.0; + + bool is_tria_first = (vflag & TRIA_FIRST) != 0u; + + if (is_tria_first) + v = v * tria1Size + tria1Center; + else + v = v * tria2Size + tria2Center; + + return v; +} + +void main() +{ + bool is_tria = (vflag & TRIA_FLAG) != 0u; + + vec2 v = (is_tria) ? do_tria() : do_widget(); + + /* Antialiasing offset */ + v += jit[(vflag >> JIT_OFS) & JIT_RANGE]; + + gl_Position = ModelViewProjectionMatrix * vec4(v, 0.0, 1.0); +}
\ No newline at end of file diff --git a/source/blender/gpu/shaders/gpu_shader_2D_widget_shadow_frag.glsl b/source/blender/gpu/shaders/gpu_shader_2D_widget_shadow_frag.glsl new file mode 100644 index 00000000000..7587b2fc18a --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_2D_widget_shadow_frag.glsl @@ -0,0 +1,13 @@ + +in float shadowFalloff; + +out vec4 fragColor; + +uniform float alpha; + +void main() +{ + fragColor = vec4(0.0); + /* Manual curve fit of the falloff curve of previous drawing method. */ + fragColor.a = alpha * (shadowFalloff * shadowFalloff * 0.722 + shadowFalloff * 0.277); +}
\ No newline at end of file diff --git a/source/blender/gpu/shaders/gpu_shader_2D_widget_shadow_vert.glsl b/source/blender/gpu/shaders/gpu_shader_2D_widget_shadow_vert.glsl new file mode 100644 index 00000000000..2f5353a7c86 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_2D_widget_shadow_vert.glsl @@ -0,0 +1,64 @@ +#define BIT_RANGE(x) uint((1 << x) - 1) + +/* 2 bits for corner */ +/* Attention! Not the same order as in UI_interface.h! + * Ordered by drawing order. */ +#define BOTTOM_LEFT 0u +#define BOTTOM_RIGHT 1u +#define TOP_RIGHT 2u +#define TOP_LEFT 3u +#define CNR_FLAG_RANGE BIT_RANGE(2) + +/* 4bits for corner id */ +#define CORNER_VEC_OFS 2u +#define CORNER_VEC_RANGE BIT_RANGE(4) +const vec2 cornervec[36] = vec2[36]( + vec2(0.0, 1.0), vec2(0.02, 0.805), vec2(0.067, 0.617), vec2(0.169, 0.45), vec2(0.293, 0.293), vec2(0.45, 0.169), vec2(0.617, 0.076), vec2(0.805, 0.02), vec2(1.0, 0.0), + vec2(-1.0, 0.0), vec2(-0.805, 0.02), vec2(-0.617, 0.067), vec2(-0.45, 0.169), vec2(-0.293, 0.293), vec2(-0.169, 0.45), vec2(-0.076, 0.617), vec2(-0.02, 0.805), vec2(0.0, 1.0), + vec2(0.0, -1.0), vec2(-0.02, -0.805), vec2(-0.067, -0.617), vec2(-0.169, -0.45), vec2(-0.293, -0.293), vec2(-0.45, -0.169), vec2(-0.617, -0.076), vec2(-0.805, -0.02), vec2(-1.0, 0.0), + vec2(1.0, 0.0), vec2(0.805, -0.02), vec2(0.617, -0.067), vec2(0.45, -0.169), vec2(0.293, -0.293), vec2(0.169, -0.45), vec2(0.076, -0.617), vec2(0.02, -0.805), vec2(0.0, -1.0) +); + +#define INNER_FLAG uint(1 << 10) /* is inner vert */ + +uniform mat4 ModelViewProjectionMatrix; + +uniform vec4 parameters[4]; +/* radi and rad per corner */ +#define recti parameters[0] +#define rect parameters[1] +#define radsi parameters[2].x +#define rads parameters[2].y +#define roundCorners parameters[3] + +in uint vflag; + +out float shadowFalloff; + +void main() +{ + uint cflag = vflag & CNR_FLAG_RANGE; + uint vofs = (vflag >> CORNER_VEC_OFS) & CORNER_VEC_RANGE; + + vec2 v = cornervec[cflag * 9u + vofs]; + + bool is_inner = (vflag & INNER_FLAG) != 0u; + + shadowFalloff = (is_inner) ? 1.0 : 0.0; + + /* Scale by corner radius */ + v *= roundCorners[cflag] * ((is_inner) ? radsi : rads); + + /* Position to corner */ + vec4 rct = (is_inner) ? recti : rect; + if (cflag == BOTTOM_LEFT) + v += rct.xz; + else if (cflag == BOTTOM_RIGHT) + v += rct.yz; + else if (cflag == TOP_RIGHT) + v += rct.yw; + else /* (cflag == TOP_LEFT) */ + v += rct.xw; + + gl_Position = ModelViewProjectionMatrix * vec4(v, 0.0, 1.0); +}
\ No newline at end of file diff --git a/source/blender/gpu/shaders/gpu_shader_fullscreen_vert.glsl b/source/blender/gpu/shaders/gpu_shader_fullscreen_vert.glsl deleted file mode 100644 index fc5cc1cdcc3..00000000000 --- a/source/blender/gpu/shaders/gpu_shader_fullscreen_vert.glsl +++ /dev/null @@ -1,10 +0,0 @@ - -in vec2 pos; -in vec2 uvs; -out vec4 uvcoordsvar; - -void main() -{ - uvcoordsvar = vec4(uvs, 0.0, 0.0); - gl_Position = vec4(pos, 0.0, 1.0); -} diff --git a/source/blender/gpu/shaders/gpu_shader_image_depth_copy_frag.glsl b/source/blender/gpu/shaders/gpu_shader_image_depth_copy_frag.glsl new file mode 100644 index 00000000000..10f4dfd5a87 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_image_depth_copy_frag.glsl @@ -0,0 +1,12 @@ + +in vec2 texCoord_interp; +out vec4 fragColor; + +uniform sampler2D image; + +void main() +{ + float depth = texture(image, texCoord_interp).r; + fragColor = vec4(depth); + gl_FragDepth = depth; +} diff --git a/source/blender/gpu/shaders/gpu_shader_image_rect_modulate_alpha_frag.glsl b/source/blender/gpu/shaders/gpu_shader_image_frag.glsl index 7d9ce9d2003..6eeab8ca7e8 100644 --- a/source/blender/gpu/shaders/gpu_shader_image_rect_modulate_alpha_frag.glsl +++ b/source/blender/gpu/shaders/gpu_shader_image_frag.glsl @@ -2,11 +2,9 @@ in vec2 texCoord_interp; out vec4 fragColor; -uniform float alpha; -uniform sampler2DRect image; +uniform sampler2D image; void main() { fragColor = texture(image, texCoord_interp); - fragColor.a *= alpha; } diff --git a/source/blender/gpu/shaders/gpu_shader_image_interlace_frag.glsl b/source/blender/gpu/shaders/gpu_shader_image_interlace_frag.glsl index 7f3e7df40ac..d95645f58e5 100644 --- a/source/blender/gpu/shaders/gpu_shader_image_interlace_frag.glsl +++ b/source/blender/gpu/shaders/gpu_shader_image_interlace_frag.glsl @@ -8,8 +8,8 @@ in vec2 texCoord_interp; out vec4 fragColor; uniform int interlace_id; -uniform sampler2DRect image_a; -uniform sampler2DRect image_b; +uniform sampler2D image_a; +uniform sampler2D image_b; bool interlace() { diff --git a/source/blender/gpu/shaders/gpu_shader_image_varying_color_frag.glsl b/source/blender/gpu/shaders/gpu_shader_image_varying_color_frag.glsl new file mode 100644 index 00000000000..37686092700 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_image_varying_color_frag.glsl @@ -0,0 +1,11 @@ + +in vec2 texCoord_interp; +flat in vec4 finalColor; +out vec4 fragColor; + +uniform sampler2D image; + +void main() +{ + fragColor = texture(image, texCoord_interp) * finalColor; +} diff --git a/source/blender/gpu/shaders/gpu_shader_instance_mball_helpers_vert.glsl b/source/blender/gpu/shaders/gpu_shader_instance_mball_handles_vert.glsl index 819199c26c7..819199c26c7 100644 --- a/source/blender/gpu/shaders/gpu_shader_instance_mball_helpers_vert.glsl +++ b/source/blender/gpu/shaders/gpu_shader_instance_mball_handles_vert.glsl diff --git a/source/blender/gpu/shaders/gpu_shader_material.glsl b/source/blender/gpu/shaders/gpu_shader_material.glsl index 780f4f59fb9..d3bc1f0ef8e 100644 --- a/source/blender/gpu/shaders/gpu_shader_material.glsl +++ b/source/blender/gpu/shaders/gpu_shader_material.glsl @@ -1,16 +1,9 @@ -uniform mat4 ModelViewMatrix; -#ifndef EEVEE_ENGINE -uniform mat4 ProjectionMatrix; -uniform mat4 ViewMatrixInverse; -uniform mat4 ViewMatrix; -#endif uniform mat4 ModelMatrix; uniform mat4 ModelMatrixInverse; +uniform mat4 ModelViewMatrix; uniform mat4 ModelViewMatrixInverse; -uniform mat4 ProjectionMatrixInverse; uniform mat3 NormalMatrix; -uniform vec4 CameraTexCoFactors; /* Old glsl mode compat. */ @@ -238,16 +231,18 @@ void geom( } void particle_info( - vec4 sprops, vec3 loc, vec3 vel, vec3 avel, - out float index, out float age, out float life_time, out vec3 location, + vec4 sprops, vec4 loc, vec3 vel, vec3 avel, + out float index, out float random, out float age, + out float life_time, out vec3 location, out float size, out vec3 velocity, out vec3 angular_velocity) { index = sprops.x; + random = loc.w; age = sprops.y; life_time = sprops.z; size = sprops.w; - location = loc; + location = loc.xyz; velocity = vel; angular_velocity = avel; } @@ -2533,8 +2528,7 @@ uint hash(int kx, int ky, int kz) float bits_to_01(uint bits) { - float x = float(bits) * (1.0 / float(0xffffffffu)); - return x; + return (float(bits) / 4294967295.0); } float cellnoise(vec3 p) @@ -2696,7 +2690,6 @@ void node_bsdf_glossy(vec4 color, float roughness, vec3 N, float ssr_id, out Clo { #ifdef EEVEE_ENGINE vec3 out_spec, ssr_spec; - roughness = sqrt(roughness); eevee_closure_glossy(N, vec3(1.0), int(ssr_id), roughness, 1.0, out_spec, ssr_spec); vec3 vN = normalize(mat3(ViewMatrix) * N); result = CLOSURE_DEFAULT; @@ -2718,7 +2711,8 @@ void node_bsdf_glossy(vec4 color, float roughness, vec3 N, float ssr_id, out Clo vec3 light_specular = glLightSource[i].specular.rgb; /* we mix in some diffuse so low roughness still shows up */ - float bsdf = 0.5 * pow(max(dot(N, H), 0.0), 1.0 / roughness); + float r2 = roughness * roughness; + float bsdf = 0.5 * pow(max(dot(N, H), 0.0), 1.0 / r2); bsdf += 0.5 * max(dot(N, light_position), 0.0); L += light_specular * bsdf; } @@ -2738,7 +2732,6 @@ void node_bsdf_glass(vec4 color, float roughness, float ior, vec3 N, float ssr_i { #ifdef EEVEE_ENGINE vec3 out_spec, out_refr, ssr_spec; - roughness = sqrt(roughness); vec3 refr_color = (refractionDepth > 0.0) ? color.rgb * color.rgb : color.rgb; /* Simulate 2 transmission event */ eevee_closure_glass(N, vec3(1.0), int(ssr_id), roughness, 1.0, ior, out_spec, out_refr, ssr_spec); out_refr *= refr_color; @@ -2977,9 +2970,10 @@ void node_bsdf_refraction(vec4 color, float roughness, float ior, vec3 N, out Cl #ifdef EEVEE_ENGINE vec3 out_refr; color.rgb *= (refractionDepth > 0.0) ? color.rgb : vec3(1.0); /* Simulate 2 absorption event. */ - roughness = sqrt(roughness); eevee_closure_refraction(N, roughness, ior, out_refr); + vec3 vN = normalize(mat3(ViewMatrix) * N); result = CLOSURE_DEFAULT; + result.ssr_normal = normal_encode(vN, viewCameraVec); result.radiance = out_refr * color.rgb; result.ssr_id = REFRACT_CLOSURE_FLAG; #else @@ -3004,7 +2998,7 @@ void node_ambient_occlusion(vec4 color, out Closure result) /* emission */ -void node_emission(vec4 color, float strength, vec3 N, out Closure result) +void node_emission(vec4 color, float strength, vec3 vN, out Closure result) { #ifndef VOLUMETRICS color *= strength; @@ -3012,7 +3006,7 @@ void node_emission(vec4 color, float strength, vec3 N, out Closure result) result = CLOSURE_DEFAULT; result.radiance = color.rgb; result.opacity = color.a; - result.ssr_normal = normal_encode(N, viewCameraVec); + result.ssr_normal = normal_encode(vN, viewCameraVec); #else result = Closure(color.rgb, color.a); #endif @@ -3072,6 +3066,86 @@ void node_volume_absorption(vec4 color, float density, out Closure result) #endif } +void node_blackbody(float temperature, sampler2D spectrummap, out vec4 color) +{ + if(temperature >= 12000.0) { + color = vec4(0.826270103, 0.994478524, 1.56626022, 1.0); + } + else if(temperature < 965.0) { + color = vec4(4.70366907, 0.0, 0.0, 1.0); + } + else { + float t = (temperature - 965.0) / (12000.0 - 965.0); + color = vec4(texture(spectrummap, vec2(t, 0.0)).rgb, 1.0); + } +} + +void node_volume_principled( + vec4 color, + float density, + float anisotropy, + vec4 absorption_color, + float emission_strength, + vec4 emission_color, + float blackbody_intensity, + vec4 blackbody_tint, + float temperature, + float density_attribute, + vec4 color_attribute, + float temperature_attribute, + sampler2D spectrummap, + out Closure result) +{ +#ifdef VOLUMETRICS + vec3 absorption_coeff = vec3(0.0); + vec3 scatter_coeff = vec3(0.0); + vec3 emission_coeff = vec3(0.0); + + /* Compute density. */ + density = max(density, 0.0); + + if(density > 1e-5) { + density = max(density * density_attribute, 0.0); + } + + if(density > 1e-5) { + /* Compute scattering and absorption coefficients. */ + vec3 scatter_color = color.rgb * color_attribute.rgb; + + scatter_coeff = scatter_color * density; + absorption_color.rgb = sqrt(max(absorption_color.rgb, 0.0)); + absorption_coeff = max(1.0 - scatter_color, 0.0) * max(1.0 - absorption_color.rgb, 0.0) * density; + } + + /* Compute emission. */ + emission_strength = max(emission_strength, 0.0); + + if(emission_strength > 1e-5) { + emission_coeff += emission_strength * emission_color.rgb; + } + + if(blackbody_intensity > 1e-3) { + /* Add temperature from attribute. */ + float T = max(temperature * max(temperature_attribute, 0.0), 0.0); + + /* Stefan-Boltzman law. */ + float T4 = (T * T) * (T * T); + float sigma = 5.670373e-8 * 1e-6 / M_PI; + float intensity = sigma * mix(1.0, T4, blackbody_intensity); + + if(intensity > 1e-5) { + vec4 bb; + node_blackbody(T, spectrummap, bb); + emission_coeff += bb.rgb * blackbody_tint.rgb * intensity; + } + } + + result = Closure(absorption_coeff, scatter_coeff, emission_coeff, anisotropy); +#else + result = CLOSURE_DEFAULT; +#endif +} + /* closures */ void node_mix_shader(float fac, Closure shader1, Closure shader2, out Closure shader) @@ -3150,7 +3224,13 @@ void node_attribute_volume_color(sampler3D tex, out vec4 outcol, out vec3 outvec #else vec3 cos = vec3(0.0); #endif - outvec = texture(tex, cos).rgb; + + vec4 value = texture(tex, cos).rgba; + /* Density is premultiplied for interpolation, divide it out here. */ + if (value.a > 1e-8) + value.rgb /= value.a; + + outvec = value.rgb; outcol = vec4(outvec, 1.0); outf = dot(vec3(1.0 / 3.0), outvec); } @@ -3162,9 +3242,23 @@ void node_attribute_volume_flame(sampler3D tex, out vec4 outcol, out vec3 outvec #else vec3 cos = vec3(0.0); #endif - outvec = texture(tex, cos).rrr; - outcol = vec4(outvec, 1.0); - outf = dot(vec3(1.0 / 3.0), outvec); + outf = texture(tex, cos).r; + outvec = vec3(outf, outf, outf); + outcol = vec4(outf, outf, outf, 1.0); +} + +void node_attribute_volume_temperature(sampler3D tex, vec2 temperature, out vec4 outcol, out vec3 outvec, out float outf) +{ +#if defined(EEVEE_ENGINE) && defined(MESH_SHADER) && defined(VOLUMETRICS) + vec3 cos = volumeObjectLocalCoord; +#else + vec3 cos = vec3(0.0); +#endif + float flame = texture(tex, cos).r; + + outf = (flame > 0.01) ? temperature.x + flame * (temperature.y - temperature.x): 0.0; + outvec = vec3(outf, outf, outf); + outcol = vec4(outf, outf, outf, 1.0); } void node_attribute(vec3 attr, out vec4 outcol, out vec3 outvec, out float outf) @@ -3657,17 +3751,29 @@ float noise_perlin(float x, float y, float z) float v = noise_fade(fy); float w = noise_fade(fz); - float result; + float noise_u[2], noise_v[2]; + + noise_u[0] = noise_nerp(u, + noise_grad(hash(X, Y, Z), fx, fy, fz), + noise_grad(hash(X + 1, Y, Z), fx - 1.0, fy, fz)); + + noise_u[1] = noise_nerp(u, + noise_grad(hash(X, Y + 1, Z), fx, fy - 1.0, fz), + noise_grad(hash(X + 1, Y + 1, Z), fx - 1.0, fy - 1.0, fz)); + + noise_v[0] = noise_nerp(v, noise_u[0], noise_u[1]); - result = noise_nerp(w, noise_nerp(v, noise_nerp(u, noise_grad(hash(X, Y, Z), fx, fy, fz), - noise_grad(hash(X + 1, Y, Z), fx - 1.0, fy, fz)), - noise_nerp(u, noise_grad(hash(X, Y + 1, Z), fx, fy - 1.0, fz), - noise_grad(hash(X + 1, Y + 1, Z), fx - 1.0, fy - 1.0, fz))), - noise_nerp(v, noise_nerp(u, noise_grad(hash(X, Y, Z + 1), fx, fy, fz - 1.0), - noise_grad(hash(X + 1, Y, Z + 1), fx - 1.0, fy, fz - 1.0)), - noise_nerp(u, noise_grad(hash(X, Y + 1, Z + 1), fx, fy - 1.0, fz - 1.0), - noise_grad(hash(X + 1, Y + 1, Z + 1), fx - 1.0, fy - 1.0, fz - 1.0)))); - return noise_scale3(result); + noise_u[0] = noise_nerp(u, + noise_grad(hash(X, Y, Z + 1), fx, fy, fz - 1.0), + noise_grad(hash(X + 1, Y, Z + 1), fx - 1.0, fy, fz - 1.0)); + + noise_u[1] = noise_nerp(u, + noise_grad(hash(X, Y + 1, Z + 1), fx, fy - 1.0, fz - 1.0), + noise_grad(hash(X + 1, Y + 1, Z + 1), fx - 1.0, fy - 1.0, fz - 1.0)); + + noise_v[1] = noise_nerp(v, noise_u[0], noise_u[1]); + + return noise_scale3(noise_nerp(w, noise_v[0], noise_v[1])); } float noise(vec3 p) @@ -4135,9 +4241,38 @@ void node_bevel(float radius, vec3 N, out vec3 result) result = N; } -void node_displacement(float height, float dist, vec3 N, out vec3 result) +void node_displacement_object(float height, float midlevel, float scale, vec3 N, mat4 obmat, out vec3 result) +{ + N = (vec4(N, 0.0) * obmat).xyz; + result = (height - midlevel) * scale * normalize(N); + result = (obmat * vec4(result, 0.0)).xyz; +} + +void node_displacement_world(float height, float midlevel, float scale, vec3 N, out vec3 result) +{ + result = (height - midlevel) * scale * normalize(N); +} + +void node_vector_displacement_tangent(vec4 vector, float midlevel, float scale, vec4 tangent, vec3 normal, mat4 obmat, mat4 viewmat, out vec3 result) +{ + vec3 N_object = normalize(((vec4(normal, 0.0) * viewmat) * obmat).xyz); + vec3 T_object = normalize(((vec4(tangent.xyz, 0.0) * viewmat) * obmat).xyz); + vec3 B_object = tangent.w * normalize(cross(N_object, T_object)); + + vec3 offset = (vector.xyz - vec3(midlevel)) * scale; + result = offset.x * T_object + offset.y * N_object + offset.z * B_object; + result = (obmat * vec4(result, 0.0)).xyz; +} + +void node_vector_displacement_object(vec4 vector, float midlevel, float scale, mat4 obmat, out vec3 result) +{ + result = (vector.xyz - vec3(midlevel)) * scale; + result = (obmat * vec4(result, 0.0)).xyz; +} + +void node_vector_displacement_world(vec4 vector, float midlevel, float scale, out vec3 result) { - result = height * dist * N; + result = (vector.xyz - vec3(midlevel)) * scale; } /* output */ diff --git a/source/blender/gpu/shaders/gpu_shader_sep_gaussian_blur_vert.glsl b/source/blender/gpu/shaders/gpu_shader_sep_gaussian_blur_vert.glsl index 1319e386c65..fca39852c2a 100644 --- a/source/blender/gpu/shaders/gpu_shader_sep_gaussian_blur_vert.glsl +++ b/source/blender/gpu/shaders/gpu_shader_sep_gaussian_blur_vert.glsl @@ -1,12 +1,14 @@ -uniform mat4 ModelViewProjectionMatrix; - -in vec2 pos; -in vec2 uvs; out vec2 texCoord_interp; void main() { - gl_Position = ModelViewProjectionMatrix * vec4(pos, 0.0, 1.0); - texCoord_interp = uvs; + const vec4 vert[3] = vec4[3]( + vec3(-1.0, -1.0, 0.0, 0.0), + vec3( 3.0, -1.0, 2.0, 0.0), + vec3(-1.0, 3.0, 0.0, 2.0) + ); + + gl_Position = vec4(vert[gl_VertexID].xy, 0.0, 1.0); + texCoord_interp = vert[gl_VertexID].zw; } diff --git a/source/blender/gpu/shaders/gpu_shader_text_frag.glsl b/source/blender/gpu/shaders/gpu_shader_text_frag.glsl index 7ff90ad4f21..fbfa4cfcc9d 100644 --- a/source/blender/gpu/shaders/gpu_shader_text_frag.glsl +++ b/source/blender/gpu/shaders/gpu_shader_text_frag.glsl @@ -1,15 +1,74 @@ flat in vec4 color_flat; +flat in vec4 texCoord_rect; noperspective in vec2 texCoord_interp; out vec4 fragColor; uniform sampler2D glyph; +const vec2 offsets4[4] = vec2[4]( + vec2(-0.5, 0.5), vec2( 0.5, 0.5), + vec2(-0.5, -0.5), vec2(-0.5, -0.5) +); + +const vec2 offsets16[16] = vec2[16]( + vec2(-1.5, 1.5), vec2(-0.5, 1.5), vec2( 0.5, 1.5), vec2( 1.5, 1.5), + vec2(-1.5, 0.5), vec2(-0.5, 0.5), vec2( 0.5, 0.5), vec2( 1.5, 0.5), + vec2(-1.5, -0.5), vec2(-0.5, -0.5), vec2( 0.5, -0.5), vec2( 1.5, -0.5), + vec2(-1.5, -1.5), vec2(-0.5, -1.5), vec2( 0.5, -1.5), vec2( 1.5, -1.5) +); + +#define sample_glyph_offset(texco, texel, ofs) texture(glyph, texco + ofs * texel).r + void main() { // input color replaces texture color fragColor.rgb = color_flat.rgb; + vec2 texel = 1.0 / vec2(textureSize(glyph, 0)); + vec2 texco = mix(abs(texCoord_rect.xy), abs(texCoord_rect.zw), texCoord_interp); + // modulate input alpha & texture alpha - fragColor.a = color_flat.a * texture(glyph, texCoord_interp).r; + if (texCoord_rect.x > 0) { + fragColor.a = texture(glyph, texco).r; + } + else { + fragColor.a = 0.0; + + if (texCoord_rect.w > 0) { + /* 3x3 blur */ + /* Manual unroll for perf. (stupid glsl compiler) */ + fragColor.a += sample_glyph_offset(texco, texel, offsets4[0]); + fragColor.a += sample_glyph_offset(texco, texel, offsets4[1]); + fragColor.a += sample_glyph_offset(texco, texel, offsets4[2]); + fragColor.a += sample_glyph_offset(texco, texel, offsets4[3]); + fragColor.a *= (1.0 / 4.0); + } + else { + /* 5x5 blur */ + /* Manual unroll for perf. (stupid glsl compiler) */ + fragColor.a += sample_glyph_offset(texco, texel, offsets16[ 0]); + fragColor.a += sample_glyph_offset(texco, texel, offsets16[ 1]); + fragColor.a += sample_glyph_offset(texco, texel, offsets16[ 2]); + fragColor.a += sample_glyph_offset(texco, texel, offsets16[ 3]); + + fragColor.a += sample_glyph_offset(texco, texel, offsets16[ 4]); + fragColor.a += sample_glyph_offset(texco, texel, offsets16[ 5]) * 2.0; + fragColor.a += sample_glyph_offset(texco, texel, offsets16[ 6]) * 2.0; + fragColor.a += sample_glyph_offset(texco, texel, offsets16[ 7]); + + fragColor.a += sample_glyph_offset(texco, texel, offsets16[ 8]); + fragColor.a += sample_glyph_offset(texco, texel, offsets16[ 9]) * 2.0; + fragColor.a += sample_glyph_offset(texco, texel, offsets16[10]) * 2.0; + fragColor.a += sample_glyph_offset(texco, texel, offsets16[11]); + + fragColor.a += sample_glyph_offset(texco, texel, offsets16[12]); + fragColor.a += sample_glyph_offset(texco, texel, offsets16[13]); + fragColor.a += sample_glyph_offset(texco, texel, offsets16[14]); + fragColor.a += sample_glyph_offset(texco, texel, offsets16[15]); + fragColor.a *= (1.0 / 20.0); + } + } + + fragColor.a *= color_flat.a; } diff --git a/source/blender/gpu/shaders/gpu_shader_text_geom.glsl b/source/blender/gpu/shaders/gpu_shader_text_geom.glsl new file mode 100644 index 00000000000..0acd2106f7a --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_text_geom.glsl @@ -0,0 +1,37 @@ + +uniform mat4 ModelViewProjectionMatrix; + +layout(points) in; +layout(triangle_strip, max_vertices = 4) out; + +in vec4 pos_rect[]; +in vec4 tex_rect[]; +in vec4 color[]; + +flat out vec4 color_flat; +flat out vec4 texCoord_rect; +noperspective out vec2 texCoord_interp; + +void main() +{ + color_flat = color[0]; + texCoord_rect = tex_rect[0]; + + gl_Position = (ModelViewProjectionMatrix * vec4(pos_rect[0].xy, 0.0, 1.0)); + texCoord_interp = vec2(0.0, 0.0); + EmitVertex(); + + gl_Position = (ModelViewProjectionMatrix * vec4(pos_rect[0].zy, 0.0, 1.0)); + texCoord_interp = vec2(1.0, 0.0); + EmitVertex(); + + gl_Position = (ModelViewProjectionMatrix * vec4(pos_rect[0].xw, 0.0, 1.0)); + texCoord_interp = vec2(0.0, 1.0); + EmitVertex(); + + gl_Position = (ModelViewProjectionMatrix * vec4(pos_rect[0].zw, 0.0, 1.0)); + texCoord_interp = vec2(1.0, 1.0); + EmitVertex(); + + EndPrimitive(); +} diff --git a/source/blender/gpu/shaders/gpu_shader_text_simple_geom.glsl b/source/blender/gpu/shaders/gpu_shader_text_simple_geom.glsl new file mode 100644 index 00000000000..8903fd1df57 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_text_simple_geom.glsl @@ -0,0 +1,36 @@ + +layout(points) in; +layout(triangle_strip, max_vertices = 4) out; + +in vec4 pos_rect[]; +in vec4 tex_rect[]; +in vec4 color[]; + +flat out vec4 color_flat; +flat out vec4 texCoord_rect; +noperspective out vec2 texCoord_interp; + +void main() +{ + color_flat = color[0]; + texCoord_rect = tex_rect[0]; + gl_Position.zw = vec2(0.0, 1.0); + + gl_Position.xy = pos_rect[0].xy; + texCoord_interp = vec2(0.0, 0.0); + EmitVertex(); + + gl_Position.xy = pos_rect[0].zy; + texCoord_interp = vec2(1.0, 0.0); + EmitVertex(); + + gl_Position.xy = pos_rect[0].xw; + texCoord_interp = vec2(0.0, 1.0); + EmitVertex(); + + gl_Position.xy = pos_rect[0].zw; + texCoord_interp = vec2(1.0, 1.0); + EmitVertex(); + + EndPrimitive(); +} diff --git a/source/blender/gpu/shaders/gpu_shader_text_simple_vert.glsl b/source/blender/gpu/shaders/gpu_shader_text_simple_vert.glsl new file mode 100644 index 00000000000..4a2cde71e07 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_text_simple_vert.glsl @@ -0,0 +1,22 @@ + +/* Simpler version of gpu_shader_text_vert that supports only 2D translation. */ + +uniform mat4 ModelViewProjectionMatrix; + +in vec4 pos; /* rect */ +in vec4 tex; /* rect */ +in vec4 col; + +out vec4 pos_rect; +out vec4 tex_rect; +out vec4 color; + +void main() +{ + /* Manual mat4*vec2 */ + pos_rect = ModelViewProjectionMatrix[0].xyxy * pos.xxzz; + pos_rect += ModelViewProjectionMatrix[1].xyxy * pos.yyww; + pos_rect += ModelViewProjectionMatrix[3].xyxy; + tex_rect = tex; + color = col; +} diff --git a/source/blender/gpu/shaders/gpu_shader_text_vert.glsl b/source/blender/gpu/shaders/gpu_shader_text_vert.glsl index 6129f49ce22..338156f5b68 100644 --- a/source/blender/gpu/shaders/gpu_shader_text_vert.glsl +++ b/source/blender/gpu/shaders/gpu_shader_text_vert.glsl @@ -1,16 +1,17 @@ uniform mat4 ModelViewProjectionMatrix; -in vec2 pos; -in vec2 texCoord; -in vec4 color; -flat out vec4 color_flat; -noperspective out vec2 texCoord_interp; +in vec4 pos; /* rect */ +in vec4 tex; /* rect */ +in vec4 col; + +out vec4 pos_rect; +out vec4 tex_rect; +out vec4 color; void main() { - gl_Position = ModelViewProjectionMatrix * vec4(pos, 0.0, 1.0); - - color_flat = color; - texCoord_interp = texCoord; + pos_rect = pos; + tex_rect = tex; + color = col; } |