diff options
Diffstat (limited to 'source/blender/gpu')
160 files changed, 11610 insertions, 11983 deletions
diff --git a/source/blender/gpu/CMakeLists.txt b/source/blender/gpu/CMakeLists.txt index 885ff2ff159..481133ba984 100644 --- a/source/blender/gpu/CMakeLists.txt +++ b/source/blender/gpu/CMakeLists.txt @@ -31,6 +31,9 @@ set(INC ../imbuf ../makesdna ../makesrna + ../draw + + ../editors/include # For node muting stuff... ../nodes @@ -39,6 +42,7 @@ set(INC ../../../intern/glew-mx ../../../intern/guardedalloc ../../../intern/smoke/extern + ../../../intern/gawain ) set(INC_SYS @@ -47,20 +51,26 @@ set(INC_SYS set(SRC intern/gpu_basic_shader.c + intern/gpu_batch.c + 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 intern/gpu_framebuffer.c + intern/gpu_immediate.c + intern/gpu_immediate_util.c intern/gpu_init_exit.c intern/gpu_material.c + intern/gpu_matrix.c intern/gpu_select.c intern/gpu_select_pick.c intern/gpu_select_sample_query.c intern/gpu_shader.c intern/gpu_texture.c + intern/gpu_uniformbuffer.c + intern/gpu_viewport.c shaders/gpu_shader_fx_lib.glsl shaders/gpu_shader_fx_ssao_frag.glsl @@ -69,7 +79,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_fx_vert.glsl shaders/gpu_shader_material.glsl shaders/gpu_shader_sep_gaussian_blur_frag.glsl shaders/gpu_shader_sep_gaussian_blur_vert.glsl @@ -85,23 +94,128 @@ set(SRC shaders/gpu_shader_smoke_vert.glsl GPU_basic_shader.h + GPU_batch.h GPU_buffers.h - GPU_compositing.h GPU_debug.h GPU_draw.h GPU_extensions.h GPU_framebuffer.h GPU_glew.h + GPU_immediate.h + GPU_immediate_util.h GPU_init_exit.h + GPU_legacy_stubs.h GPU_material.h + GPU_matrix.h GPU_select.h GPU_shader.h GPU_texture.h + GPU_uniformbuffer.h + GPU_viewport.h + intern/gpu_codegen.h intern/gpu_private.h intern/gpu_select_private.h + intern/gpu_shader_private.h ) +data_to_c_simple(shaders/gpu_shader_depth_only_frag.glsl SRC) +data_to_c_simple(shaders/gpu_shader_uniform_color_frag.glsl SRC) +data_to_c_simple(shaders/gpu_shader_checker_frag.glsl SRC) +data_to_c_simple(shaders/gpu_shader_diag_stripes_frag.glsl SRC) +data_to_c_simple(shaders/gpu_shader_simple_lighting_frag.glsl SRC) +data_to_c_simple(shaders/gpu_shader_simple_lighting_smooth_color_frag.glsl SRC) +data_to_c_simple(shaders/gpu_shader_simple_lighting_smooth_color_alpha_frag.glsl SRC) +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_flat_id_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) +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_smooth_color_dithered_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_desaturate_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_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_image_multisample_resolve_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) +data_to_c_simple(shaders/gpu_shader_3D_normal_vert.glsl SRC) +data_to_c_simple(shaders/gpu_shader_3D_flat_color_vert.glsl SRC) +data_to_c_simple(shaders/gpu_shader_3D_line_dashed_uniform_color_legacy_vert.glsl SRC) +data_to_c_simple(shaders/gpu_shader_3D_line_dashed_uniform_color_vert.glsl SRC) +data_to_c_simple(shaders/gpu_shader_3D_smooth_color_vert.glsl SRC) +data_to_c_simple(shaders/gpu_shader_3D_normal_smooth_color_vert.glsl SRC) +data_to_c_simple(shaders/gpu_shader_3D_smooth_color_frag.glsl SRC) +data_to_c_simple(shaders/gpu_shader_3D_passthrough_vert.glsl SRC) +data_to_c_simple(shaders/gpu_shader_3D_clipped_uniform_color_vert.glsl SRC) + +data_to_c_simple(shaders/gpu_shader_instance_vert.glsl SRC) +data_to_c_simple(shaders/gpu_shader_instance_variying_size_variying_color_vert.glsl SRC) +data_to_c_simple(shaders/gpu_shader_instance_variying_size_variying_id_vert.glsl SRC) +data_to_c_simple(shaders/gpu_shader_instance_objectspace_variying_color_vert.glsl SRC) +data_to_c_simple(shaders/gpu_shader_instance_screenspace_variying_color_vert.glsl SRC) +data_to_c_simple(shaders/gpu_shader_instance_screen_aligned_vert.glsl SRC) +data_to_c_simple(shaders/gpu_shader_instance_camera_vert.glsl SRC) +data_to_c_simple(shaders/gpu_shader_instance_distance_line_vert.glsl SRC) +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_3D_groundline_geom.glsl SRC) +data_to_c_simple(shaders/gpu_shader_3D_groundpoint_vert.glsl SRC) + +data_to_c_simple(shaders/gpu_shader_point_uniform_color_frag.glsl SRC) +data_to_c_simple(shaders/gpu_shader_point_uniform_color_aa_frag.glsl SRC) +data_to_c_simple(shaders/gpu_shader_point_uniform_color_outline_aa_frag.glsl SRC) +data_to_c_simple(shaders/gpu_shader_point_varying_color_outline_aa_frag.glsl SRC) +data_to_c_simple(shaders/gpu_shader_point_varying_color_frag.glsl SRC) +data_to_c_simple(shaders/gpu_shader_3D_point_fixed_size_varying_color_vert.glsl SRC) +data_to_c_simple(shaders/gpu_shader_3D_point_varying_size_vert.glsl SRC) +data_to_c_simple(shaders/gpu_shader_3D_point_varying_size_varying_color_vert.glsl SRC) +data_to_c_simple(shaders/gpu_shader_3D_point_uniform_size_aa_vert.glsl SRC) +data_to_c_simple(shaders/gpu_shader_3D_point_uniform_size_outline_aa_vert.glsl SRC) +data_to_c_simple(shaders/gpu_shader_2D_point_varying_size_varying_color_vert.glsl SRC) +data_to_c_simple(shaders/gpu_shader_2D_point_uniform_size_aa_vert.glsl SRC) +data_to_c_simple(shaders/gpu_shader_2D_point_uniform_size_outline_aa_vert.glsl SRC) +data_to_c_simple(shaders/gpu_shader_2D_point_uniform_size_varying_color_outline_aa_vert.glsl SRC) + +data_to_c_simple(shaders/gpu_shader_edges_front_back_persp_vert.glsl SRC) +data_to_c_simple(shaders/gpu_shader_edges_front_back_persp_geom.glsl SRC) +data_to_c_simple(shaders/gpu_shader_edges_front_back_persp_legacy_vert.glsl SRC) +data_to_c_simple(shaders/gpu_shader_edges_front_back_ortho_vert.glsl SRC) +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) + data_to_c_simple(shaders/gpu_shader_geometry.glsl SRC) data_to_c_simple(shaders/gpu_shader_fire_frag.glsl SRC) data_to_c_simple(shaders/gpu_shader_smoke_frag.glsl SRC) @@ -116,19 +230,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_fx_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) -endif() if(WITH_MOD_SMOKE) add_definitions(-DWITH_SMOKE) diff --git a/source/blender/gpu/GPU_basic_shader.h b/source/blender/gpu/GPU_basic_shader.h index d9bf3d1ced3..dc378927e79 100644 --- a/source/blender/gpu/GPU_basic_shader.h +++ b/source/blender/gpu/GPU_basic_shader.h @@ -64,12 +64,6 @@ typedef enum GPUBasicShaderStipple { GPU_SHADER_STIPPLE_HEXAGON = 3, GPU_SHADER_STIPPLE_DIAG_STRIPES = 4, GPU_SHADER_STIPPLE_DIAG_STRIPES_SWAP = 5, - GPU_SHADER_STIPPLE_S3D_INTERLACE_ROW = 6, - GPU_SHADER_STIPPLE_S3D_INTERLACE_ROW_SWAP = 7, - GPU_SHADER_STIPPLE_S3D_INTERLACE_COLUMN = 8, - GPU_SHADER_STIPPLE_S3D_INTERLACE_COLUMN_SWAP = 9, - GPU_SHADER_STIPPLE_S3D_INTERLACE_CHECKER = 10, - GPU_SHADER_STIPPLE_S3D_INTERLACE_CHECKER_SWAP = 11 } GPUBasicShaderStipple; void GPU_basic_shaders_init(void); @@ -132,9 +126,6 @@ void GPU_basic_shader_stipple(GPUBasicShaderStipple stipple_id); void GPU_basic_shader_line_stipple(GLint stipple_factor, GLushort stipple_pattern); void GPU_basic_shader_line_width(float line_width); -bool GPU_basic_shader_use_glsl_get(void); -void GPU_basic_shader_use_glsl_set(bool enabled); - #ifdef __cplusplus } #endif diff --git a/source/blender/gpu/GPU_batch.h b/source/blender/gpu/GPU_batch.h new file mode 100644 index 00000000000..b706bdbf189 --- /dev/null +++ b/source/blender/gpu/GPU_batch.h @@ -0,0 +1,74 @@ +/* + * ***** 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) 2016 Blender Foundation. + * All rights reserved. + * + * + * Contributor(s): Mike Erwin + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/* Batched geometry rendering is powered by the Gawain library. + * This file contains any additions or modifications specific to Blender. + */ + +#ifndef __GPU_BATCH_H__ +#define __GPU_BATCH_H__ + +#include "../../../intern/gawain/gawain/gwn_batch.h" +#include "../../../intern/gawain/gawain/gwn_batch_private.h" + +struct rctf; + +// TODO: CMake magic to do this: +// #include "gawain/batch.h" + +#include "BLI_compiler_attrs.h" +#include "BLI_sys_types.h" + +#include "GPU_shader.h" + +/* Extend GWN_batch_program_set to use Blender’s library of built-in shader programs. */ + +/* gpu_batch.c */ +void GWN_batch_program_set_builtin(Gwn_Batch *batch, GPUBuiltinShader shader_id) ATTR_NONNULL(1); + +Gwn_Batch *GPU_batch_tris_from_poly_2d_encoded( + const uchar *polys_flat, uint polys_flat_len, const struct rctf *rect + ) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1); +Gwn_Batch *GPU_batch_wire_from_poly_2d_encoded( + const uchar *polys_flat, uint polys_flat_len, const struct rctf *rect + ) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1); + +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_buffers.h b/source/blender/gpu/GPU_buffers.h index 6ffaa29ead6..f496c92f283 100644 --- a/source/blender/gpu/GPU_buffers.h +++ b/source/blender/gpu/GPU_buffers.h @@ -32,191 +32,19 @@ #ifndef __GPU_BUFFERS_H__ #define __GPU_BUFFERS_H__ -#ifdef DEBUG -/* #define DEBUG_VBO(X) printf(X)*/ -# define DEBUG_VBO(X) -#else -# define DEBUG_VBO(X) -#endif - #include <stddef.h> struct BMesh; struct CCGElem; struct CCGKey; struct DMFlagMat; -struct DerivedMesh; -struct GSet; -struct GPUVertPointLink; -struct GPUDrawObject; struct GridCommonGPUBuffer; -struct PBVH; +struct GSet; +struct MLoop; +struct MLoopTri; +struct MPoly; struct MVert; - -typedef struct GPUBuffer { - size_t size; /* in bytes */ - unsigned int id; /* used with vertex buffer objects */ -} GPUBuffer; - -typedef struct GPUBufferMaterial { - /* range of points used for this material */ - unsigned int start; - unsigned int totelements; - unsigned int totloops; - unsigned int *polys; /* array of polygons for this material */ - unsigned int totpolys; /* total polygons in polys */ - unsigned int totvisiblepolys; /* total visible polygons */ - - /* original material index */ - short mat_nr; -} GPUBufferMaterial; - -void GPU_buffer_material_finalize(struct GPUDrawObject *gdo, GPUBufferMaterial *matinfo, int totmat); - -/* meshes are split up by material since changing materials requires - * GL state changes that can't occur in the middle of drawing an - * array. - * - * some simplifying assumptions are made: - * - all quads are treated as two triangles. - * - no vertex sharing is used; each triangle gets its own copy of the - * vertices it uses (this makes it easy to deal with a vertex used - * by faces with different properties, such as smooth/solid shading, - * different MCols, etc.) - * - * to avoid confusion between the original MVert vertices and the - * arrays of OpenGL vertices, the latter are referred to here and in - * the source as `points'. similarly, the OpenGL triangles generated - * for MFaces are referred to as triangles rather than faces. - */ -typedef struct GPUDrawObject { - GPUBuffer *points; - GPUBuffer *normals; - GPUBuffer *uv; - GPUBuffer *uv_tex; - GPUBuffer *colors; - GPUBuffer *edges; - GPUBuffer *uvedges; - GPUBuffer *triangles; /* triangle index buffer */ - - /* for each original vertex, the list of related points */ - struct GPUVertPointLink *vert_points; - - /* see: USE_GPU_POINT_LINK define */ -#if 0 - /* storage for the vert_points lists */ - struct GPUVertPointLink *vert_points_mem; - int vert_points_usage; -#endif - - int colType; - - GPUBufferMaterial *materials; - int totmaterial; - - unsigned int tot_triangle_point; - unsigned int tot_loose_point; - /* different than total loops since ngons get tesselated still */ - unsigned int tot_loop_verts; - - /* caches of the original DerivedMesh values */ - unsigned int totvert; - unsigned int totedge; - - unsigned int loose_edge_offset; - unsigned int tot_loose_edge_drawn; - unsigned int tot_edge_drawn; - - /* for subsurf, offset where drawing of interior edges starts */ - unsigned int interior_offset; - unsigned int totinterior; -} GPUDrawObject; - -/* currently unused */ -// #define USE_GPU_POINT_LINK - -typedef struct GPUVertPointLink { -#ifdef USE_GPU_POINT_LINK - struct GPUVertPointLink *next; -#endif - /* -1 means uninitialized */ - int point_index; -} GPUVertPointLink; - - - -/* used for GLSL materials */ -typedef struct GPUAttrib { - int index; - int info_index; - int size; - int type; -} GPUAttrib; - -void GPU_global_buffer_pool_free(void); -void GPU_global_buffer_pool_free_unused(void); - -GPUBuffer *GPU_buffer_alloc(size_t size); -void GPU_buffer_free(GPUBuffer *buffer); - -void GPU_drawobject_free(struct DerivedMesh *dm); - -/* flag that controls data type to fill buffer with, a modifier will prepare. */ -typedef enum { - GPU_BUFFER_VERTEX = 0, - GPU_BUFFER_NORMAL, - GPU_BUFFER_COLOR, - GPU_BUFFER_UV, - GPU_BUFFER_UV_TEXPAINT, - GPU_BUFFER_EDGE, - GPU_BUFFER_UVEDGE, - GPU_BUFFER_TRIANGLES -} GPUBufferType; - -typedef enum { - GPU_BINDING_ARRAY = 0, - GPU_BINDING_INDEX = 1, -} GPUBindingType; - -typedef enum { - GPU_ATTR_INFO_SRGB = (1 << 0), -} GPUAttrInfo; - -/* called before drawing */ -void GPU_vertex_setup(struct DerivedMesh *dm); -void GPU_normal_setup(struct DerivedMesh *dm); -void GPU_uv_setup(struct DerivedMesh *dm); -void GPU_texpaint_uv_setup(struct DerivedMesh *dm); -/* colType is the cddata MCol type to use! */ -void GPU_color_setup(struct DerivedMesh *dm, int colType); -void GPU_buffer_bind_as_color(GPUBuffer *buffer); -void GPU_edge_setup(struct DerivedMesh *dm); /* does not mix with other data */ -void GPU_uvedge_setup(struct DerivedMesh *dm); - -void GPU_triangle_setup(struct DerivedMesh *dm); - -int GPU_attrib_element_size(GPUAttrib data[], int numdata); -void GPU_interleaved_attrib_setup(GPUBuffer *buffer, GPUAttrib data[], int numdata, int element_size); - -void GPU_buffer_bind(GPUBuffer *buffer, GPUBindingType binding); -void GPU_buffer_unbind(GPUBuffer *buffer, GPUBindingType binding); - -/* can't lock more than one buffer at once */ -void *GPU_buffer_lock(GPUBuffer *buffer, GPUBindingType binding); -void *GPU_buffer_lock_stream(GPUBuffer *buffer, GPUBindingType binding); -void GPU_buffer_unlock(GPUBuffer *buffer, GPUBindingType binding); - -/* switch color rendering on=1/off=0 */ -void GPU_color_switch(int mode); - -/* used for drawing edges */ -void GPU_buffer_draw_elements(GPUBuffer *elements, unsigned int mode, int start, int count); - -/* called after drawing */ -void GPU_buffers_unbind(void); - -/* only unbind interleaved data */ -void GPU_interleaved_attrib_unbind(void); +struct PBVH; /* Buffers for non-DerivedMesh drawing */ typedef struct GPU_PBVH_Buffers GPU_PBVH_Buffers; @@ -263,14 +91,10 @@ void GPU_pbvh_grid_buffers_update( const int update_flags); /* draw */ -void GPU_pbvh_buffers_draw( - GPU_PBVH_Buffers *buffers, DMSetMaterial setMaterial, - bool wireframe, bool fast); +struct Gwn_Batch *GPU_pbvh_buffers_batch_get(GPU_PBVH_Buffers *buffers, bool fast); -/* debug PBVH draw*/ -void GPU_pbvh_BB_draw(float min[3], float max[3], bool leaf); -void GPU_pbvh_BB_draw_init(void); -void GPU_pbvh_BB_draw_end(void); +/* debug PBVH draw */ +void GPU_pbvh_BB_draw(float min[3], float max[3], bool leaf, unsigned int pos); bool GPU_pbvh_buffers_diffuse_changed(GPU_PBVH_Buffers *buffers, struct GSet *bm_faces, bool show_diffuse_color); bool GPU_pbvh_buffers_mask_changed(GPU_PBVH_Buffers *buffers, bool show_mask); @@ -278,4 +102,6 @@ bool GPU_pbvh_buffers_mask_changed(GPU_PBVH_Buffers *buffers, bool show_mask); void GPU_pbvh_buffers_free(GPU_PBVH_Buffers *buffers); void GPU_pbvh_multires_buffers_free(struct GridCommonGPUBuffer **grid_common_gpu_buffer); +void GPU_pbvh_fix_linking(void); + #endif 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_debug.h b/source/blender/gpu/GPU_debug.h index 61b2bc591ce..c7a99d33654 100644 --- a/source/blender/gpu/GPU_debug.h +++ b/source/blender/gpu/GPU_debug.h @@ -41,24 +41,6 @@ extern "C" { /* prints something if debug mode is active only */ void GPU_print_error_debug(const char *str); -/* replacement for gluErrorString */ -const char *gpuErrorString(GLenum err); - -/* prints current OpenGL state */ -void GPU_state_print(void); - -void GPU_assert_no_gl_errors(const char *file, int line, const char *str); - -# define GPU_ASSERT_NO_GL_ERRORS(str) GPU_assert_no_gl_errors(__FILE__, __LINE__, (str)) - -# define GPU_CHECK_ERRORS_AROUND(glProcCall) \ - ( \ - GPU_ASSERT_NO_GL_ERRORS("Pre: " #glProcCall), \ - (glProcCall), \ - GPU_ASSERT_NO_GL_ERRORS("Post: " #glProcCall) \ - ) - - /* inserts a debug marker message for the debug context messaging system */ void GPU_string_marker(const char *str); diff --git a/source/blender/gpu/GPU_draw.h b/source/blender/gpu/GPU_draw.h index 90b65af87c8..e26d973142b 100644 --- a/source/blender/gpu/GPU_draw.h +++ b/source/blender/gpu/GPU_draw.h @@ -39,76 +39,31 @@ extern "C" { struct ImBuf; struct Image; struct ImageUser; -struct MTexPoly; struct Object; struct Scene; +struct ViewLayer; struct View3D; struct RegionView3D; struct SmokeModifierData; struct DupliObject; -/* OpenGL drawing functions related to shading. These are also - * shared with the game engine, where there were previously - * duplicates of some of these functions. */ +#include "DNA_object_enums.h" + +/* OpenGL drawing functions related to shading. */ /* Initialize * - sets the default Blender opengl state, if in doubt, check * the contents of this function - * - this is called when starting Blender, for opengl rendering, - * and for switching back from the game engine for example. */ + * - this is called when starting Blender, for opengl rendering. */ void GPU_state_init(void); -/* Material drawing - * - first the state is initialized by a particular object and - * it's materials - * - after this, materials can be quickly enabled by their number, - * 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 Object *ob, bool glsl, bool *do_alpha_after); -void GPU_end_object_materials(void); -bool GPU_object_materials_check(void); - -int GPU_object_material_bind(int nr, void *attribs); -void GPU_object_material_unbind(void); -int GPU_object_material_visible(int nr, void *attribs); - -void GPU_begin_dupli_object(struct DupliObject *dob); -void GPU_end_dupli_object(void); - -void GPU_material_diffuse_get(int nr, float diff[4]); -bool GPU_material_use_matcaps_get(void); - -void GPU_set_material_alpha_blend(int alphablend); -int GPU_get_material_alpha_blend(void); - -/* TexFace drawing - * - this is mutually exclusive with material drawing, a mesh should - * be drawn using one or the other - * - passing NULL clears the state again */ - -int GPU_set_tpage(struct MTexPoly *mtexpoly, int mipmap, int transp); -void GPU_clear_tpage(bool force); +/* Programmable point size + * - shaders set their own point size when enabled + * - use glPointSize when disabled */ -/* Lights - * - returns how many lights were enabled - * - this affects fixed functions materials and texface, not glsl */ - -int GPU_default_lights(void); -int GPU_scene_object_lights( - struct Scene *scene, struct Object *ob, - int lay, float viewmat[4][4], int ortho); - -/* Text render - * - based on moving uv coordinates */ - -void GPU_render_text( - struct MTexPoly *mtexpoly, int mode, - const char *textstr, int textlen, unsigned int *col, - const float *v_quad[4], const float *uv_quad[4], - int glattrib); +void GPU_enable_program_point_size(void); +void GPU_disable_program_point_size(void); /* Mipmap settings * - these will free textures on changes */ @@ -131,11 +86,9 @@ void GPU_set_gpu_mipmapping(int gpu_mipmap); * - these deal with images bound as opengl textures */ void GPU_paint_update_image(struct Image *ima, struct ImageUser *iuser, int x, int y, int w, int h); -void GPU_update_images_framechange(void); -int GPU_update_image_time(struct Image *ima, double time); int GPU_verify_image( struct Image *ima, struct ImageUser *iuser, - int textarget, int tftile, bool compare, bool mipmap, bool is_data); + int textarget, bool compare, bool mipmap, bool is_data); void GPU_create_gl_tex( unsigned int *bind, unsigned int *rect, float *frect, int rectw, int recth, int textarget, bool mipmap, bool use_hight_bit_depth, struct Image *ima); @@ -155,17 +108,23 @@ void GPU_create_smoke(struct SmokeModifierData *smd, int highres); /* Delayed free of OpenGL buffers by main thread */ void GPU_free_unused_buffers(void); -#ifdef WITH_OPENSUBDIV -struct DerivedMesh; -void GPU_draw_update_fvar_offset(struct DerivedMesh *dm); -#endif - /* utilities */ void GPU_select_index_set(int index); void GPU_select_index_get(int index, int *r_col); int GPU_select_to_index(unsigned int col); void GPU_select_to_index_array(unsigned int *col, const unsigned int size); +typedef enum eGPUAttribMask { + GPU_DEPTH_BUFFER_BIT = (1 << 0), + GPU_ENABLE_BIT = (1 << 1), + GPU_SCISSOR_BIT = (1 << 2), + GPU_VIEWPORT_BIT = (1 << 3), + GPU_BLEND_BIT = (1 << 4), +} eGPUAttribMask; + +void gpuPushAttrib(eGPUAttribMask mask); +void gpuPopAttrib(void); + #ifdef __cplusplus } #endif diff --git a/source/blender/gpu/GPU_extensions.h b/source/blender/gpu/GPU_extensions.h index 31ad8243c4b..d36b0ea15be 100644 --- a/source/blender/gpu/GPU_extensions.h +++ b/source/blender/gpu/GPU_extensions.h @@ -38,21 +38,16 @@ extern "C" { /* GPU extensions support */ -void GPU_extensions_disable(void); - -bool GPU_legacy_support(void); bool GPU_full_non_power_of_two_support(void); -bool GPU_display_list_support(void); bool GPU_bicubic_bump_support(void); -bool GPU_geometry_shader_support(void); -bool GPU_geometry_shader_support_via_extension(void); -bool GPU_instanced_drawing_support(void); int GPU_max_texture_size(void); int GPU_max_textures(void); float GPU_max_texture_anisotropy(void); int GPU_max_color_texture_samples(void); int GPU_max_cube_map_size(void); +int GPU_max_ubo_binds(void); +int GPU_max_ubo_size(void); int GPU_color_depth(void); void GPU_get_dfdy_factors(float fac[2]); diff --git a/source/blender/gpu/GPU_framebuffer.h b/source/blender/gpu/GPU_framebuffer.h index 2719b8fa6a8..61dd899f3d9 100644 --- a/source/blender/gpu/GPU_framebuffer.h +++ b/source/blender/gpu/GPU_framebuffer.h @@ -36,48 +36,163 @@ 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); -int GPU_framebuffer_texture_attach(GPUFrameBuffer *fb, struct GPUTexture *tex, int slot, char err_out[256]); -void GPU_framebuffer_texture_detach(struct GPUTexture *tex); -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, + GPUFrameBufferBits blit_buffers); + +void GPU_framebuffer_recursive_downsample( + 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, 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); +void GPU_offscreen_draw_to_screen(GPUOffScreen *ofs, int x, int y); 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, + GPUFrameBuffer **r_fb, struct GPUTexture **r_color, struct GPUTexture **r_depth); #ifdef __cplusplus } diff --git a/source/blender/gpu/GPU_glew.h b/source/blender/gpu/GPU_glew.h index 94217863fd6..afe1c9763ad 100644 --- a/source/blender/gpu/GPU_glew.h +++ b/source/blender/gpu/GPU_glew.h @@ -34,4 +34,8 @@ #include "glew-mx.h" +#ifndef WITH_LEGACY_OPENGL +#include "GPU_legacy_stubs.h" +#endif + #endif /* __GPU_GLEW_H__ */ diff --git a/source/blender/gpu/GPU_immediate.h b/source/blender/gpu/GPU_immediate.h new file mode 100644 index 00000000000..2a2692e6baf --- /dev/null +++ b/source/blender/gpu/GPU_immediate.h @@ -0,0 +1,58 @@ +/* + * ***** 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) 2016 Blender Foundation. + * All rights reserved. + * + * + * Contributor(s): Mike Erwin + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/* Immediate mode rendering is powered by the Gawain library. + * This file contains any additions or modifications specific to Blender. + */ + +#ifndef __GPU_IMMEDIATE_H__ +#define __GPU_IMMEDIATE_H__ + +#include "../../../intern/gawain/gawain/gwn_immediate.h" +#include "../../../intern/gawain/gawain/gwn_imm_util.h" + +// TODO: CMake magic to do this: +// #include "gawain/gwn_immediate.h" +// #include "gawain/gwn_imm_util.h" + +#include "GPU_shader.h" + +/* Extend immBindProgram to use Blender’s library of built-in shader programs. + * Use immUnbindProgram() when done. */ +void immBindBuiltinProgram(GPUBuiltinShader shader_id); + +/* + * Extend immUniformColor to take Blender's themes + */ +void immUniformThemeColor(int color_id); +void immUniformThemeColor3(int color_id); +void immUniformThemeColorShade(int color_id, int offset); +void immUniformThemeColorShadeAlpha(int color_id, int color_offset, int alpha_offset); +void immUniformThemeColorBlendShade(int color_id1, int color_id2, float fac, int offset); +void immUniformThemeColorBlend(int color_id1, int color_id2, float fac); +void immThemeColorShadeAlpha(int colorid, int coloffset, int alphaoffset); + +#endif /* __GPU_IMMEDIATE_H__ */ diff --git a/source/blender/gpu/GPU_immediate_util.h b/source/blender/gpu/GPU_immediate_util.h new file mode 100644 index 00000000000..c31d477ff5b --- /dev/null +++ b/source/blender/gpu/GPU_immediate_util.h @@ -0,0 +1,64 @@ +/* + * ***** 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. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file GPU_immediate_util.h + * \ingroup gpu + * + * Utility drawing functions (rough equivalent to OpenGL's GLU) + */ + +#ifndef __GPU_IMMEDIATE_UTIL_H__ +#define __GPU_IMMEDIATE_UTIL_H__ + +void imm_cpack(uint x); + +void imm_draw_circle_wire_2d(uint shdr_pos, float x, float y, float radius, int nsegments); +void imm_draw_circle_fill_2d(uint shdr_pos, float x, float y, float radius, int nsegments); + +void imm_draw_circle_wire_aspect_2d(uint shdr_pos, float x, float y, float radius_x, float radius_y, int nsegments); +void imm_draw_circle_fill_aspect_2d(uint shdr_pos, float x, float y, float radius_x, float radius_y, int nsegments); + +/* use this version when Gwn_VertFormat has a vec3 position */ +void imm_draw_circle_wire_3d(uint pos, float x, float y, float radius, int nsegments); +void imm_draw_circle_fill_3d(uint pos, float x, float y, float radius, int nsegments); + +void imm_draw_disk_partial_fill_2d( + uint pos, float x, float y, + float radius_inner, float radius_outer, int nsegments, float start, float sweep); + +void imm_draw_box_wire_2d(uint pos, float x1, float y1, float x2, float y2); +void imm_draw_box_wire_3d(uint pos, float x1, float y1, float x2, float y2); + +void imm_draw_box_checker_2d(float x1, float y1, float x2, float y2); + +void imm_draw_cube_fill_3d(uint pos, const float co[3], const float aspect[3]); +void imm_draw_cube_wire_3d(uint pos, const float co[3], const float aspect[3]); + +void imm_draw_cylinder_fill_normal_3d( + uint pos, uint nor, float base, float top, float height, + int slices, int stacks); +void imm_draw_cylinder_wire_3d( + uint pos, float base, float top, float height, + int slices, int stacks); +void imm_draw_cylinder_fill_3d( + uint pos, float base, float top, float height, + int slices, int stacks); + +#endif /* __GPU_IMMEDIATE_UTIL_H__ */ diff --git a/source/blender/gpu/GPU_legacy_stubs.h b/source/blender/gpu/GPU_legacy_stubs.h new file mode 100644 index 00000000000..a195eac9eec --- /dev/null +++ b/source/blender/gpu/GPU_legacy_stubs.h @@ -0,0 +1,457 @@ +/* + * ***** 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) 2017 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Blender Foundation, Dalai Felinto. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file GPU_legacy_stubs.h + * \ingroup gpu + * + * This is to mark the transition to OpenGL core profile + * The idea is to allow Blender 2.8 to be built with OpenGL 3.3 even if it means breaking things + * + * This file should be removed in the future + */ + +#ifndef __GPU_LEGACY_STUBS_H__ +#define __GPU_LEGACY_STUBS_H__ + +#if defined(__GNUC__) +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wunused-parameter" +# pragma GCC diagnostic ignored "-Wunused-function" +#endif + +#include <stdlib.h> /* for abort(). */ + +#include "BLI_utildefines.h" + +/** + * Empty function, use for breakpoint when a depreacated + * OpenGL function is called. + */ +static void gl_deprecated(void) +{ + BLI_assert(true); +} + +#define _GL_BOOL BLI_INLINE GLboolean +#define _GL_BOOL_RET { \ + gl_deprecated(); \ + return false; \ +} + +#define _GL_ENUM BLI_INLINE GLenum +#define _GL_ENUM_RET { \ + gl_deprecated(); \ + return 0; \ +} + +#define _GL_INT BLI_INLINE GLint +#define _GL_INT_RET { \ + gl_deprecated(); \ + return 0; \ +} + + +#define _GL_UINT BLI_INLINE GLuint +#define _GL_UINT_RET { \ + gl_deprecated(); \ + return 0; \ +} + +#define _GL_VOID BLI_INLINE void +#define _GL_VOID_RET { \ + gl_deprecated(); \ +} + +static bool disable_enable_check(GLenum cap) +{ + const bool is_deprecated = \ + ELEM( + cap, + GL_ALPHA_TEST, + GL_LINE_STIPPLE, + GL_POINT_SPRITE, + GL_TEXTURE_1D, + GL_TEXTURE_2D, + GL_TEXTURE_GEN_S, + GL_TEXTURE_GEN_T, + -1 + ); + + if (is_deprecated) { + gl_deprecated(); + } + + return is_deprecated; +} + +_GL_VOID USE_CAREFULLY_glDisable (GLenum cap) +{ + if (!disable_enable_check(cap)) { + glDisable(cap); + } +} +#define glDisable USE_CAREFULLY_glDisable + +_GL_VOID USE_CAREFULLY_glEnable (GLenum cap) +{ + if (!disable_enable_check(cap)) { + glEnable(cap); + } +} +#define glEnable USE_CAREFULLY_glEnable + +/** + * Hand written cases + */ + +_GL_VOID DO_NOT_USE_glClientActiveTexture (GLenum texture) _GL_VOID_RET + + +/** + * List automatically generated from `gl-deprecated.h` and `glew.h` + */ + +/** + * ENUM values + */ +#define DO_NOT_USE_GL_CURRENT_FOG_COORDINATE 0 +#define DO_NOT_USE_GL_FOG_COORDINATE 0 +#define DO_NOT_USE_GL_FOG_COORDINATE_ARRAY 0 +#define DO_NOT_USE_GL_FOG_COORDINATE_ARRAY_BUFFER_BINDING 0 +#define DO_NOT_USE_GL_FOG_COORDINATE_ARRAY_POINTER 0 +#define DO_NOT_USE_GL_FOG_COORDINATE_ARRAY_STRIDE 0 +#define DO_NOT_USE_GL_FOG_COORDINATE_ARRAY_TYPE 0 +#define DO_NOT_USE_GL_FOG_COORDINATE_SOURCE 0 +#define DO_NOT_USE_GL_POINT_SIZE_GRANULARITY 0 +#define DO_NOT_USE_GL_POINT_SIZE_RANGE 0 +#define DO_NOT_USE_GL_SOURCE0_ALPHA 0 +#define DO_NOT_USE_GL_SOURCE0_RGB 0 +#define DO_NOT_USE_GL_SOURCE1_ALPHA 0 +#define DO_NOT_USE_GL_SOURCE1_RGB 0 +#define DO_NOT_USE_GL_SOURCE2_ALPHA 0 +#define DO_NOT_USE_GL_SOURCE2_RGB 0 + +/** + * Functions + */ +_GL_VOID DO_NOT_USE_glAccum (GLenum op, GLfloat value) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glAlphaFunc (GLenum func, GLclampf ref) _GL_VOID_RET +_GL_BOOL DO_NOT_USE_glAreTexturesResident (GLsizei n, const GLuint *textures, GLboolean *residences) _GL_BOOL_RET +_GL_VOID DO_NOT_USE_glArrayElement (GLint i) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glBegin (GLenum mode) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glBitmap (GLsizei width, GLsizei height, GLfloat xorig, GLfloat yorig, GLfloat xmove, GLfloat ymove, const GLubyte *bitmap) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glCallList (GLuint list) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glCallLists (GLsizei n, GLenum type, const void *lists) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glClearAccum (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glClearIndex (GLfloat c) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glClipPlane (GLenum plane, const GLdouble *equation) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glColor3b (GLbyte red, GLbyte green, GLbyte blue) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glColor3bv (const GLbyte *v) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glColor3d (GLdouble red, GLdouble green, GLdouble blue) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glColor3dv (const GLdouble *v) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glColor3f (GLfloat red, GLfloat green, GLfloat blue) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glColor3fv (const GLfloat *v) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glColor3i (GLint red, GLint green, GLint blue) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glColor3iv (const GLint *v) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glColor3s (GLshort red, GLshort green, GLshort blue) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glColor3sv (const GLshort *v) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glColor3ub (GLubyte red, GLubyte green, GLubyte blue) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glColor3ubv (const GLubyte *v) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glColor3ui (GLuint red, GLuint green, GLuint blue) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glColor3uiv (const GLuint *v) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glColor3us (GLushort red, GLushort green, GLushort blue) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glColor3usv (const GLushort *v) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glColor4b (GLbyte red, GLbyte green, GLbyte blue, GLbyte alpha) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glColor4bv (const GLbyte *v) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glColor4d (GLdouble red, GLdouble green, GLdouble blue, GLdouble alpha) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glColor4dv (const GLdouble *v) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glColor4f (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glColor4fv (const GLfloat *v) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glColor4i (GLint red, GLint green, GLint blue, GLint alpha) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glColor4iv (const GLint *v) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glColor4s (GLshort red, GLshort green, GLshort blue, GLshort alpha) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glColor4sv (const GLshort *v) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glColor4ub (GLubyte red, GLubyte green, GLubyte blue, GLubyte alpha) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glColor4ubv (const GLubyte *v) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glColor4ui (GLuint red, GLuint green, GLuint blue, GLuint alpha) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glColor4uiv (const GLuint *v) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glColor4us (GLushort red, GLushort green, GLushort blue, GLushort alpha) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glColor4usv (const GLushort *v) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glColorMaterial (GLenum face, GLenum mode) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glColorPointer (GLint size, GLenum type, GLsizei stride, const void *pointer) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glCopyPixels (GLint x, GLint y, GLsizei width, GLsizei height, GLenum type) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glDeleteLists (GLuint list, GLsizei range) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glDisableClientState (GLenum array) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glDrawPixels (GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glEdgeFlag (GLboolean flag) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glEdgeFlagPointer (GLsizei stride, const void *pointer) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glEdgeFlagv (const GLboolean *flag) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glEnableClientState (GLenum array) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glEnd (void) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glEndList (void) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glEvalCoord1d (GLdouble u) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glEvalCoord1dv (const GLdouble *u) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glEvalCoord1f (GLfloat u) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glEvalCoord1fv (const GLfloat *u) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glEvalCoord2d (GLdouble u, GLdouble v) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glEvalCoord2dv (const GLdouble *u) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glEvalCoord2f (GLfloat u, GLfloat v) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glEvalCoord2fv (const GLfloat *u) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glEvalMesh1 (GLenum mode, GLint i1, GLint i2) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glEvalMesh2 (GLenum mode, GLint i1, GLint i2, GLint j1, GLint j2) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glEvalPoint1 (GLint i) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glEvalPoint2 (GLint i, GLint j) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glFeedbackBuffer (GLsizei size, GLenum type, GLfloat *buffer) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glFogf (GLenum pname, GLfloat param) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glFogfv (GLenum pname, const GLfloat *params) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glFogi (GLenum pname, GLint param) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glFogiv (GLenum pname, const GLint *params) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glFrustum (GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar) _GL_VOID_RET +_GL_UINT DO_NOT_USE_glGenLists (GLsizei range) _GL_UINT_RET +_GL_VOID DO_NOT_USE_glGetClipPlane (GLenum plane, GLdouble *equation) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glGetLightfv (GLenum light, GLenum pname, GLfloat *params) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glGetLightiv (GLenum light, GLenum pname, GLint *params) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glGetMapdv (GLenum target, GLenum query, GLdouble *v) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glGetMapfv (GLenum target, GLenum query, GLfloat *v) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glGetMapiv (GLenum target, GLenum query, GLint *v) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glGetMaterialfv (GLenum face, GLenum pname, GLfloat *params) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glGetMaterialiv (GLenum face, GLenum pname, GLint *params) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glGetPixelMapfv (GLenum map, GLfloat *values) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glGetPixelMapuiv (GLenum map, GLuint *values) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glGetPixelMapusv (GLenum map, GLushort *values) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glGetPolygonStipple (GLubyte *mask) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glGetTexEnvfv (GLenum target, GLenum pname, GLfloat *params) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glGetTexEnviv (GLenum target, GLenum pname, GLint *params) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glGetTexGendv (GLenum coord, GLenum pname, GLdouble *params) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glGetTexGenfv (GLenum coord, GLenum pname, GLfloat *params) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glGetTexGeniv (GLenum coord, GLenum pname, GLint *params) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glIndexMask (GLuint mask) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glIndexPointer (GLenum type, GLsizei stride, const void *pointer) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glIndexd (GLdouble c) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glIndexdv (const GLdouble *c) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glIndexf (GLfloat c) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glIndexfv (const GLfloat *c) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glIndexi (GLint c) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glIndexiv (const GLint *c) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glIndexs (GLshort c) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glIndexsv (const GLshort *c) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glIndexub (GLubyte c) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glIndexubv (const GLubyte *c) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glInitNames (void) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glInterleavedArrays (GLenum format, GLsizei stride, const void *pointer) _GL_VOID_RET +_GL_BOOL DO_NOT_USE_glIsList (GLuint list) _GL_BOOL_RET +_GL_VOID DO_NOT_USE_glLightModelf (GLenum pname, GLfloat param) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glLightModelfv (GLenum pname, const GLfloat *params) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glLightModeli (GLenum pname, GLint param) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glLightModeliv (GLenum pname, const GLint *params) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glLightf (GLenum light, GLenum pname, GLfloat param) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glLightfv (GLenum light, GLenum pname, const GLfloat *params) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glLighti (GLenum light, GLenum pname, GLint param) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glLightiv (GLenum light, GLenum pname, const GLint *params) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glLineStipple (GLint factor, GLushort pattern) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glListBase (GLuint base) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glLoadIdentity (void) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glLoadMatrixd (const GLdouble *m) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glLoadMatrixf (const GLfloat *m) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glLoadName (GLuint name) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glMap1d (GLenum target, GLdouble u1, GLdouble u2, GLint stride, GLint order, const GLdouble *points) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glMap1f (GLenum target, GLfloat u1, GLfloat u2, GLint stride, GLint order, const GLfloat *points) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glMap2d (GLenum target, GLdouble u1, GLdouble u2, GLint ustride, GLint uorder, GLdouble v1, GLdouble v2, GLint vstride, GLint vorder, const GLdouble *points) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glMap2f (GLenum target, GLfloat u1, GLfloat u2, GLint ustride, GLint uorder, GLfloat v1, GLfloat v2, GLint vstride, GLint vorder, const GLfloat *points) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glMapGrid1d (GLint un, GLdouble u1, GLdouble u2) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glMapGrid1f (GLint un, GLfloat u1, GLfloat u2) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glMapGrid2d (GLint un, GLdouble u1, GLdouble u2, GLint vn, GLdouble v1, GLdouble v2) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glMapGrid2f (GLint un, GLfloat u1, GLfloat u2, GLint vn, GLfloat v1, GLfloat v2) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glMaterialf (GLenum face, GLenum pname, GLfloat param) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glMaterialfv (GLenum face, GLenum pname, const GLfloat *params) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glMateriali (GLenum face, GLenum pname, GLint param) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glMaterialiv (GLenum face, GLenum pname, const GLint *params) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glMatrixMode (GLenum mode) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glMultMatrixd (const GLdouble *m) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glMultMatrixf (const GLfloat *m) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glNewList (GLuint list, GLenum mode) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glNormal3b (GLbyte nx, GLbyte ny, GLbyte nz) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glNormal3bv (const GLbyte *v) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glNormal3d (GLdouble nx, GLdouble ny, GLdouble nz) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glNormal3dv (const GLdouble *v) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glNormal3f (GLfloat nx, GLfloat ny, GLfloat nz) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glNormal3fv (const GLfloat *v) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glNormal3i (GLint nx, GLint ny, GLint nz) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glNormal3iv (const GLint *v) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glNormal3s (GLshort nx, GLshort ny, GLshort nz) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glNormal3sv (const GLshort *v) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glNormalPointer (GLenum type, GLsizei stride, const void *pointer) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glOrtho (GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glPassThrough (GLfloat token) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glPixelMapfv (GLenum map, GLsizei mapsize, const GLfloat *values) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glPixelMapuiv (GLenum map, GLsizei mapsize, const GLuint *values) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glPixelMapusv (GLenum map, GLsizei mapsize, const GLushort *values) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glPixelTransferf (GLenum pname, GLfloat param) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glPixelTransferi (GLenum pname, GLint param) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glPixelZoom (GLfloat xfactor, GLfloat yfactor) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glPolygonStipple (const GLubyte *mask) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glPopAttrib (void) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glPopClientAttrib (void) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glPopMatrix (void) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glPopName (void) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glPrioritizeTextures (GLsizei n, const GLuint *textures, const GLclampf *priorities) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glPushAttrib (GLbitfield mask) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glPushClientAttrib (GLbitfield mask) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glPushMatrix (void) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glPushName (GLuint name) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glRasterPos2d (GLdouble x, GLdouble y) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glRasterPos2dv (const GLdouble *v) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glRasterPos2f (GLfloat x, GLfloat y) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glRasterPos2fv (const GLfloat *v) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glRasterPos2i (GLint x, GLint y) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glRasterPos2iv (const GLint *v) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glRasterPos2s (GLshort x, GLshort y) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glRasterPos2sv (const GLshort *v) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glRasterPos3d (GLdouble x, GLdouble y, GLdouble z) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glRasterPos3dv (const GLdouble *v) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glRasterPos3f (GLfloat x, GLfloat y, GLfloat z) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glRasterPos3fv (const GLfloat *v) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glRasterPos3i (GLint x, GLint y, GLint z) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glRasterPos3iv (const GLint *v) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glRasterPos3s (GLshort x, GLshort y, GLshort z) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glRasterPos3sv (const GLshort *v) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glRasterPos4d (GLdouble x, GLdouble y, GLdouble z, GLdouble w) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glRasterPos4dv (const GLdouble *v) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glRasterPos4f (GLfloat x, GLfloat y, GLfloat z, GLfloat w) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glRasterPos4fv (const GLfloat *v) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glRasterPos4i (GLint x, GLint y, GLint z, GLint w) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glRasterPos4iv (const GLint *v) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glRasterPos4s (GLshort x, GLshort y, GLshort z, GLshort w) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glRasterPos4sv (const GLshort *v) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glRectd (GLdouble x1, GLdouble y1, GLdouble x2, GLdouble y2) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glRectdv (const GLdouble *v1, const GLdouble *v2) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glRectf (GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glRectfv (const GLfloat *v1, const GLfloat *v2) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glRecti (GLint x1, GLint y1, GLint x2, GLint y2) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glRectiv (const GLint *v1, const GLint *v2) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glRects (GLshort x1, GLshort y1, GLshort x2, GLshort y2) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glRectsv (const GLshort *v1, const GLshort *v2) _GL_VOID_RET +_GL_INT DO_NOT_USE_glRenderMode (GLenum mode) _GL_INT_RET +_GL_VOID DO_NOT_USE_glRotated (GLdouble angle, GLdouble x, GLdouble y, GLdouble z) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glRotatef (GLfloat angle, GLfloat x, GLfloat y, GLfloat z) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glScaled (GLdouble x, GLdouble y, GLdouble z) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glScalef (GLfloat x, GLfloat y, GLfloat z) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glSelectBuffer (GLsizei size, GLuint *buffer) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glShadeModel (GLenum mode) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glTexCoord1d (GLdouble s) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glTexCoord1dv (const GLdouble *v) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glTexCoord1f (GLfloat s) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glTexCoord1fv (const GLfloat *v) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glTexCoord1i (GLint s) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glTexCoord1iv (const GLint *v) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glTexCoord1s (GLshort s) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glTexCoord1sv (const GLshort *v) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glTexCoord2d (GLdouble s, GLdouble t) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glTexCoord2dv (const GLdouble *v) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glTexCoord2f (GLfloat s, GLfloat t) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glTexCoord2fv (const GLfloat *v) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glTexCoord2i (GLint s, GLint t) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glTexCoord2iv (const GLint *v) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glTexCoord2s (GLshort s, GLshort t) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glTexCoord2sv (const GLshort *v) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glTexCoord3d (GLdouble s, GLdouble t, GLdouble r) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glTexCoord3dv (const GLdouble *v) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glTexCoord3f (GLfloat s, GLfloat t, GLfloat r) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glTexCoord3fv (const GLfloat *v) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glTexCoord3i (GLint s, GLint t, GLint r) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glTexCoord3iv (const GLint *v) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glTexCoord3s (GLshort s, GLshort t, GLshort r) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glTexCoord3sv (const GLshort *v) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glTexCoord4d (GLdouble s, GLdouble t, GLdouble r, GLdouble q) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glTexCoord4dv (const GLdouble *v) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glTexCoord4f (GLfloat s, GLfloat t, GLfloat r, GLfloat q) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glTexCoord4fv (const GLfloat *v) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glTexCoord4i (GLint s, GLint t, GLint r, GLint q) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glTexCoord4iv (const GLint *v) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glTexCoord4s (GLshort s, GLshort t, GLshort r, GLshort q) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glTexCoord4sv (const GLshort *v) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glTexCoordPointer (GLint size, GLenum type, GLsizei stride, const void *pointer) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glTexEnvf (GLenum target, GLenum pname, GLfloat param) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glTexEnvfv (GLenum target, GLenum pname, const GLfloat *params) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glTexEnvi (GLenum target, GLenum pname, GLint param) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glTexEnviv (GLenum target, GLenum pname, const GLint *params) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glTexGend (GLenum coord, GLenum pname, GLdouble param) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glTexGendv (GLenum coord, GLenum pname, const GLdouble *params) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glTexGenf (GLenum coord, GLenum pname, GLfloat param) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glTexGenfv (GLenum coord, GLenum pname, const GLfloat *params) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glTexGeni (GLenum coord, GLenum pname, GLint param) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glTexGeniv (GLenum coord, GLenum pname, const GLint *params) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glTranslated (GLdouble x, GLdouble y, GLdouble z) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glTranslatef (GLfloat x, GLfloat y, GLfloat z) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glVertex2d (GLdouble x, GLdouble y) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glVertex2dv (const GLdouble *v) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glVertex2f (GLfloat x, GLfloat y) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glVertex2fv (const GLfloat *v) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glVertex2i (GLint x, GLint y) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glVertex2iv (const GLint *v) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glVertex2s (GLshort x, GLshort y) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glVertex2sv (const GLshort *v) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glVertex3d (GLdouble x, GLdouble y, GLdouble z) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glVertex3dv (const GLdouble *v) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glVertex3f (GLfloat x, GLfloat y, GLfloat z) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glVertex3fv (const GLfloat *v) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glVertex3i (GLint x, GLint y, GLint z) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glVertex3iv (const GLint *v) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glVertex3s (GLshort x, GLshort y, GLshort z) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glVertex3sv (const GLshort *v) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glVertex4d (GLdouble x, GLdouble y, GLdouble z, GLdouble w) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glVertex4dv (const GLdouble *v) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glVertex4f (GLfloat x, GLfloat y, GLfloat z, GLfloat w) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glVertex4fv (const GLfloat *v) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glVertex4i (GLint x, GLint y, GLint z, GLint w) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glVertex4iv (const GLint *v) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glVertex4s (GLshort x, GLshort y, GLshort z, GLshort w) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glVertex4sv (const GLshort *v) _GL_VOID_RET +_GL_VOID DO_NOT_USE_glVertexPointer (GLint size, GLenum type, GLsizei stride, const void *pointer) _GL_VOID_RET + +/** + * End of automatically generated list + */ + + + +#undef _GL_BOOL +#undef _GL_BOOL_RET +#undef _GL_ENUM +#undef _GL_ENUM_RET +#undef _GL_INT +#undef _GL_INT_RET +#undef _GL_UINT +#undef _GL_UINT_RET +#undef _GL_VOID +#undef _GL_VOID_RET + +#if defined(__GNUC__) +# pragma GCC diagnostic pop +#endif + +#endif /* __GPU_LEGACY_STUBS_H__ */ diff --git a/source/blender/gpu/GPU_material.h b/source/blender/gpu/GPU_material.h index e229afd3323..95492016f25 100644 --- a/source/blender/gpu/GPU_material.h +++ b/source/blender/gpu/GPU_material.h @@ -43,30 +43,33 @@ extern "C" { struct Image; struct ImageUser; +struct ListBase; struct Material; struct Object; -struct Image; struct Scene; -struct SceneRenderLayer; struct GPUVertexAttribs; struct GPUNode; struct GPUNodeLink; struct GPUNodeStack; struct GPUMaterial; struct GPUTexture; +struct GPUUniformBuffer; struct GPULamp; struct PreviewImage; struct World; +struct bNode; +struct bNodeTree; typedef struct GPUNode GPUNode; typedef struct GPUNodeLink GPUNodeLink; typedef struct GPUMaterial GPUMaterial; -typedef struct GPULamp GPULamp; + typedef struct GPUParticleInfo GPUParticleInfo; /* Functions to create GPU Materials nodes */ typedef enum GPUType { + /* Keep in sync with GPU_DATATYPE_STR */ /* The value indicates the number of elements in each type */ GPU_NONE = 0, GPU_FLOAT = 1, @@ -76,9 +79,16 @@ typedef enum GPUType { GPU_MAT3 = 9, GPU_MAT4 = 16, + /* Values not in GPU_DATATYPE_STR */ GPU_TEX2D = 1002, - GPU_SHADOW2D = 1003, - GPU_TEXCUBE = 1004, + GPU_TEX3D = 1003, + GPU_SHADOW2D = 1004, + GPU_TEXCUBE = 1005, + + /* GLSL Struct types */ + GPU_CLOSURE = 1006, + + /* Opengl Attributes */ GPU_ATTRIB = 3001 } GPUType; @@ -98,7 +108,10 @@ typedef enum GPUBuiltin { GPU_PARTICLE_ANG_VELOCITY = (1 << 12), GPU_LOC_TO_VIEW_MATRIX = (1 << 13), GPU_INVERSE_LOC_TO_VIEW_MATRIX = (1 << 14), - GPU_OBJECT_INFO = (1 << 15) + GPU_OBJECT_INFO = (1 << 15), + GPU_VOLUME_DENSITY = (1 << 16), + GPU_VOLUME_FLAME = (1 << 17), + GPU_VOLUME_TEMPERATURE = (1 << 18) } GPUBuiltin; typedef enum GPUOpenGLBuiltin { @@ -123,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) @@ -141,6 +159,7 @@ typedef struct GPUNodeStack { #define GPU_DYNAMIC_GROUP_MIST 0x00050000 #define GPU_DYNAMIC_GROUP_WORLD 0x00060000 #define GPU_DYNAMIC_GROUP_MAT 0x00070000 +#define GPU_DYNAMIC_UBO 0x00080000 typedef enum GPUDynamicType { @@ -200,6 +219,7 @@ typedef enum GPUDynamicType { GPUNodeLink *GPU_attribute(CustomDataType type, const char *name); GPUNodeLink *GPU_uniform(float *num); GPUNodeLink *GPU_dynamic_uniform(float *num, GPUDynamicType dynamictype, void *data); +GPUNodeLink *GPU_uniform_buffer(float *num, GPUType gputype); GPUNodeLink *GPU_image(struct Image *ima, struct ImageUser *iuser, bool is_data); GPUNodeLink *GPU_cube_map(struct Image *ima, struct ImageUser *iuser, bool is_data); GPUNodeLink *GPU_image_preview(struct PreviewImage *prv); @@ -210,150 +230,48 @@ GPUNodeLink *GPU_opengl_builtin(GPUOpenGLBuiltin builtin); void GPU_node_link_set_type(GPUNodeLink *link, GPUType type); bool GPU_link(GPUMaterial *mat, const char *name, ...); -bool GPU_stack_link(GPUMaterial *mat, const char *name, GPUNodeStack *in, GPUNodeStack *out, ...); +bool GPU_stack_link(GPUMaterial *mat, struct bNode *node, const char *name, GPUNodeStack *in, GPUNodeStack *out, ...); +GPUNodeLink *GPU_uniformbuffer_link_out( + struct GPUMaterial *mat, struct bNode *node, + struct GPUNodeStack *stack, const int index); void GPU_material_output_link(GPUMaterial *material, GPUNodeLink *link); -void GPU_material_enable_alpha(GPUMaterial *material); GPUBuiltin GPU_get_material_builtins(GPUMaterial *material); -GPUBlendMode GPU_material_alpha_blend(GPUMaterial *material, float obcol[4]); -/* High level functions to create and use GPU materials */ -GPUMaterial *GPU_material_world(struct Scene *scene, struct World *wo); +void GPU_material_sss_profile_create(GPUMaterial *material, float *radii, short *falloff_type, float *sharpness); +struct GPUUniformBuffer *GPU_material_sss_profile_get( + GPUMaterial *material, int sample_ct, struct GPUTexture **tex_profile); -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); +/* High level functions to create and use GPU materials */ +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); +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); -bool GPU_lamp_visible(GPULamp *lamp, struct SceneRenderLayer *srl, struct Material *ma); -void GPU_material_bind( - GPUMaterial *material, int oblay, int viewlay, double time, int mipmap, - float viewmat[4][4], float viewinv[4][4], float cameraborder[4], bool scenelock); -void GPU_material_bind_uniforms( - GPUMaterial *material, float obmat[4][4], float viewmat[4][4], float obcol[4], - float autobumpscale, GPUParticleInfo *pi, float object_info[3]); -void GPU_material_unbind(GPUMaterial *material); -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); +void GPU_material_uniform_buffer_tag_dirty(struct ListBase *gpumaterials); void GPU_material_vertex_attributes(GPUMaterial *material, struct GPUVertexAttribs *attrib); bool GPU_material_do_color_management(GPUMaterial *mat); -bool GPU_material_use_new_shading_nodes(GPUMaterial *mat); -bool GPU_material_use_world_space_shading(GPUMaterial *mat); - -/* Exported shading */ - -typedef struct GPUShadeInput { - GPUMaterial *gpumat; - struct Material *mat; - - GPUNodeLink *rgb, *specrgb, *vn, *view, *vcol, *ref; - GPUNodeLink *alpha, *refl, *spec, *emit, *har, *amb; - GPUNodeLink *spectra, *mir, *refcol; -} GPUShadeInput; - -typedef struct GPUShadeResult { - GPUNodeLink *diff, *spec, *combined, *alpha; -} GPUShadeResult; - -void GPU_shadeinput_set(GPUMaterial *mat, struct Material *ma, GPUShadeInput *shi); -void GPU_shaderesult_set(GPUShadeInput *shi, GPUShadeResult *shr); - -/* Export GLSL shader */ - -typedef enum GPUDataType { - GPU_DATA_NONE = 0, - GPU_DATA_1I = 1, /* 1 integer */ - GPU_DATA_1F = 2, - GPU_DATA_2F = 3, - GPU_DATA_3F = 4, - GPU_DATA_4F = 5, - GPU_DATA_9F = 6, - GPU_DATA_16F = 7, - GPU_DATA_4UB = 8, -} GPUDataType; - -/* this structure gives information of each uniform found in the shader */ -typedef struct GPUInputUniform { - struct GPUInputUniform *next, *prev; - char varname[32]; /* name of uniform in shader */ - GPUDynamicType type; /* type of uniform, data format and calculation derive from it */ - GPUDataType datatype; /* type of uniform data */ - struct Object *lamp; /* when type=GPU_DYNAMIC_LAMP_... or GPU_DYNAMIC_SAMPLER_2DSHADOW */ - struct Image *image; /* when type=GPU_DYNAMIC_SAMPLER_2DIMAGE */ - struct Material *material;/* when type=GPU_DYNAMIC_MAT_... */ - int texnumber; /* when type=GPU_DYNAMIC_SAMPLER, texture number: 0.. */ - unsigned char *texpixels; /* for internally generated texture, pixel data in RGBA format */ - int texsize; /* size in pixel of the texture in texpixels buffer: - * for 2D textures, this is S and T size (square texture) */ -} GPUInputUniform; - -typedef struct GPUInputAttribute { - struct GPUInputAttribute *next, *prev; - char varname[32]; /* name of attribute in shader */ - int type; /* from CustomData.type, data type derives from it */ - GPUDataType datatype; /* type of attribute data */ - const char *name; /* layer name */ - int number; /* generic attribute number */ -} GPUInputAttribute; - -typedef struct GPUShaderExport { - ListBase uniforms; - ListBase attributes; - char *vertex; - char *fragment; -} GPUShaderExport; - -GPUShaderExport *GPU_shader_export(struct Scene *scene, struct Material *ma); -void GPU_free_shader_export(GPUShaderExport *shader); - -/* Lamps */ - -GPULamp *GPU_lamp_from_blender(struct Scene *scene, struct Object *ob, struct Object *par); -void GPU_lamp_free(struct Object *ob); - -bool GPU_lamp_has_shadow_buffer(GPULamp *lamp); -void GPU_lamp_update_buffer_mats(GPULamp *lamp); -void GPU_lamp_shadow_buffer_bind(GPULamp *lamp, float viewmat[4][4], int *winsize, float winmat[4][4]); -void GPU_lamp_shadow_buffer_unbind(GPULamp *lamp); -int GPU_lamp_shadow_buffer_type(GPULamp *lamp); -int GPU_lamp_shadow_bind_code(GPULamp *lamp); -float *GPU_lamp_dynpersmat(GPULamp *lamp); - -void GPU_lamp_update(GPULamp *lamp, int lay, int hide, float obmat[4][4]); -void GPU_lamp_update_colors(GPULamp *lamp, float r, float g, float b, float energy); -void GPU_lamp_update_distance(GPULamp *lamp, float distance, float att1, float att2, - float coeff_const, float coeff_lin, float coeff_quad); -void GPU_lamp_update_spot(GPULamp *lamp, float spotsize, float spotblend); -int GPU_lamp_shadow_layer(GPULamp *lamp); -GPUNodeLink *GPU_lamp_get_data( - GPUMaterial *mat, GPULamp *lamp, - GPUNodeLink **r_col, GPUNodeLink **r_lv, GPUNodeLink **r_dist, GPUNodeLink **r_shadow, GPUNodeLink **r_energy); - -/* World */ -void GPU_mist_update_enable(short enable); -void GPU_mist_update_values(int type, float start, float dist, float inten, float color[3]); -void GPU_horizon_update_color(float color[3]); -void GPU_ambient_update_color(float color[3]); -void GPU_zenith_update_color(float color[3]); - -struct GPUParticleInfo -{ - float scalprops[4]; - float location[4]; - float velocity[3]; - float angular_velocity[3]; -}; - -#ifdef WITH_OPENSUBDIV -struct DerivedMesh; -void GPU_material_update_fvar_offset(GPUMaterial *gpu_material, - struct DerivedMesh *dm); -#endif +bool GPU_material_use_domain_surface(GPUMaterial *mat); +bool GPU_material_use_domain_volume(GPUMaterial *mat); + +void GPU_pass_cache_garbage_collect(void); +void GPU_pass_cache_free(void); #ifdef __cplusplus } diff --git a/source/blender/gpu/GPU_matrix.h b/source/blender/gpu/GPU_matrix.h new file mode 100644 index 00000000000..f22c0cd5c4d --- /dev/null +++ b/source/blender/gpu/GPU_matrix.h @@ -0,0 +1,190 @@ +/* + * ***** 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) 2012 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Alexandr Kuznetsov, Jason Wilkins, Mike Erwin + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file source/blender/gpu/GPU_matrix.h + * \ingroup gpu + */ + +#ifndef __GPU_MATRIX_H__ +#define __GPU_MATRIX_H__ + +#include "BLI_sys_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct Gwn_ShaderInterface; + +void gpuMatrixReset(void); /* to Identity transform & empty stack */ + +/* ModelView Matrix (2D or 3D) */ + +void gpuPushMatrix(void); /* TODO: PushCopy vs PushIdentity? */ +void gpuPopMatrix(void); + +void gpuLoadIdentity(void); + +void gpuScaleUniform(float factor); + + +/* 3D ModelView Matrix */ + +void gpuLoadMatrix(const float m[4][4]); +void gpuMultMatrix(const float m[4][4]); + +void gpuTranslate3f(float x, float y, float z); +void gpuTranslate3fv(const float vec[3]); +void gpuScale3f(float x, float y, float z); +void gpuScale3fv(const float vec[3]); +void gpuRotate3f(float deg, float x, float y, float z); /* axis of rotation should be a unit vector */ +void gpuRotate3fv(float deg, const float axis[3]); /* axis of rotation should be a unit vector */ +void gpuRotateAxis(float deg, char axis); /* TODO: enum for axis? */ + +void gpuLookAt(float eyeX, float eyeY, float eyeZ, float centerX, float centerY, float centerZ, float upX, float upY, float upZ); +/* TODO: variant that takes eye[3], center[3], up[3] */ + + +/* 2D ModelView Matrix */ + +void gpuTranslate2f(float x, float y); +void gpuTranslate2fv(const float vec[2]); +void gpuScale2f(float x, float y); +void gpuScale2fv(const float vec[2]); +void gpuRotate2D(float deg); + +/* Projection Matrix (2D or 3D) */ + +void gpuPushProjectionMatrix(void); +void gpuPopProjectionMatrix(void); + +/* 3D Projection Matrix */ + +void gpuLoadIdentityProjectionMatrix(void); +void gpuLoadProjectionMatrix(const float m[4][4]); + +void gpuOrtho(float left, float right, float bottom, float top, float near, float far); +void gpuFrustum(float left, float right, float bottom, float top, float near, float far); +void gpuPerspective(float fovy, float aspect, float near, float far); + +/* 3D Projection between Window and World Space */ + +void gpuProject(const float world[3], const float model[4][4], const float proj[4][4], const int view[4], float win[3]); +bool gpuUnProject(const float win[3], const float model[4][4], const float proj[4][4], const int view[4], float world[3]); + +/* 2D Projection Matrix */ + +void gpuOrtho2D(float left, float right, float bottom, float top); + + +/* functions to get matrix values */ +const float (*gpuGetModelViewMatrix(float m[4][4]))[4]; +const float (*gpuGetProjectionMatrix(float m[4][4]))[4]; +const float (*gpuGetModelViewProjectionMatrix(float m[4][4]))[4]; + +const float (*gpuGetNormalMatrix(float m[3][3]))[3]; +const float (*gpuGetNormalMatrixInverse(float m[3][3]))[3]; + + +/* set uniform values for currently bound shader */ +void gpuBindMatrices(const struct Gwn_ShaderInterface *); +bool gpuMatricesDirty(void); /* since last bind */ + + +/* Python API needs to be able to inspect the stack so errors raise exceptions instead of crashing. */ +#ifdef USE_GPU_PY_MATRIX_API +int GPU_matrix_stack_level_get_model_view(void); +int GPU_matrix_stack_level_get_projection(void); +/* static assert ensures this doesn't change! */ +#define GPU_PY_MATRIX_STACK_LEN 31 +#endif /* USE_GPU_PY_MATRIX_API */ + + +#ifdef __cplusplus +} +#endif + +#ifndef SUPPRESS_GENERIC_MATRIX_API + +#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L) +#define _GPU_MAT3_CONST_CAST(x) (_Generic((x), \ + void *: (const float (*)[3])(x), \ + float *: (const float (*)[3])(x), \ + float [9]: (const float (*)[3])(x), \ + float (*)[4]: (const float (*)[3])(x), \ + float [4][4]: (const float (*)[3])(x), \ + const void *: (const float (*)[3])(x), \ + const float *: (const float (*)[3])(x), \ + const float [9]: (const float (*)[3])(x), \ + const float (*)[3]: (const float (*)[3])(x), \ + const float [3][3]: (const float (*)[3])(x)) \ +) +#define _GPU_MAT3_CAST(x) (_Generic((x), \ + void *: (float (*)[3])(x), \ + float *: (float (*)[3])(x), \ + float [9]: (float (*)[3])(x), \ + float (*)[3]: (float (*)[3])(x), \ + float [3][3]: (float (*)[3])(x)) \ +) +#define _GPU_MAT4_CONST_CAST(x) (_Generic((x), \ + void *: (const float (*)[4])(x), \ + float *: (const float (*)[4])(x), \ + float [16]: (const float (*)[4])(x), \ + float (*)[4]: (const float (*)[4])(x), \ + float [4][4]: (const float (*)[4])(x), \ + const void *: (const float (*)[4])(x), \ + const float *: (const float (*)[4])(x), \ + const float [16]: (const float (*)[4])(x), \ + const float (*)[4]: (const float (*)[4])(x), \ + const float [4][4]: (const float (*)[4])(x)) \ +) +#define _GPU_MAT4_CAST(x) (_Generic((x), \ + void *: (float (*)[4])(x), \ + float *: (float (*)[4])(x), \ + float [16]: (float (*)[4])(x), \ + float (*)[4]: (float (*)[4])(x), \ + float [4][4]: (float (*)[4])(x)) \ +) +#else +# define _GPU_MAT3_CONST_CAST(x) (const float (*)[3])(x) +# define _GPU_MAT3_CAST(x) (float (*)[3])(x) +# define _GPU_MAT4_CONST_CAST(x) (const float (*)[4])(x) +# define _GPU_MAT4_CAST(x) (float (*)[4])(x) +#endif /* C11 */ + +/* make matrix inputs generic, to avoid warnings */ +# define gpuMultMatrix(x) gpuMultMatrix(_GPU_MAT4_CONST_CAST(x)) +# define gpuLoadMatrix(x) gpuLoadMatrix(_GPU_MAT4_CONST_CAST(x)) +# define gpuLoadProjectionMatrix(x) gpuLoadProjectionMatrix(_GPU_MAT4_CONST_CAST(x)) +# define gpuGetModelViewMatrix(x) gpuGetModelViewMatrix(_GPU_MAT4_CAST(x)) +# define gpuGetProjectionMatrix(x) gpuGetProjectionMatrix(_GPU_MAT4_CAST(x)) +# define gpuGetModelViewProjectionMatrix(x) gpuGetModelViewProjectionMatrix(_GPU_MAT4_CAST(x)) +# define gpuGetNormalMatrix(x) gpuGetNormalMatrix(_GPU_MAT3_CAST(x)) +# define gpuGetNormalMatrixInverse(x) gpuGetNormalMatrixInverse(_GPU_MAT3_CAST(x)) +#endif /* SUPPRESS_GENERIC_MATRIX_API */ + +#endif /* __GPU_MATRIX_H__ */ diff --git a/source/blender/gpu/GPU_select.h b/source/blender/gpu/GPU_select.h index 53f480bccd7..f1342a1f6b8 100644 --- a/source/blender/gpu/GPU_select.h +++ b/source/blender/gpu/GPU_select.h @@ -57,4 +57,7 @@ void GPU_select_cache_begin(void); void GPU_select_cache_load_id(void); void GPU_select_cache_end(void); +/* utilities */ +const uint *GPU_select_buffer_near(const uint *buffer, int hits); + #endif diff --git a/source/blender/gpu/GPU_shader.h b/source/blender/gpu/GPU_shader.h index 5b94db6e120..f831d495ad0 100644 --- a/source/blender/gpu/GPU_shader.h +++ b/source/blender/gpu/GPU_shader.h @@ -38,6 +38,7 @@ extern "C" { typedef struct GPUShader GPUShader; struct GPUTexture; +struct GPUUniformBuffer; /* GPU Shader * - only for fragment shaders now @@ -49,34 +50,51 @@ enum { GPU_SHADER_FLAGS_NEW_SHADING = (1 << 1), }; +typedef enum GPUShaderTFBType { + GPU_SHADER_TFB_NONE = 0, /* Transform feedback unsupported. */ + GPU_SHADER_TFB_POINTS = 1, + GPU_SHADER_TFB_LINES = 2, + GPU_SHADER_TFB_TRIANGLES = 3, +} GPUShaderTFBType; + GPUShader *GPU_shader_create( const char *vertexcode, const char *fragcode, const char *geocode, const char *libcode, - const char *defines, - int input, int output, int number); + const char *defines); GPUShader *GPU_shader_create_ex( const char *vertexcode, const char *fragcode, const char *geocode, const char *libcode, const char *defines, - int input, int output, int number, - const int flags); + const int flags, + const GPUShaderTFBType tf_type, + const char **tf_names, + const int tf_count); void GPU_shader_free(GPUShader *shader); void GPU_shader_bind(GPUShader *shader); void GPU_shader_unbind(void); +/* Returns true if transform feedback was succesfully enabled. */ +bool GPU_shader_transform_feedback_enable(GPUShader *shader, unsigned int vbo_id); +void GPU_shader_transform_feedback_disable(GPUShader *shader); + +int GPU_shader_get_program(GPUShader *shader); + void *GPU_shader_get_interface(GPUShader *shader); -void GPU_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); void GPU_shader_uniform_vector(GPUShader *shader, int location, int length, int arraysize, const float *value); void GPU_shader_uniform_vector_int(GPUShader *shader, int location, int length, int arraysize, const int *value); +void GPU_shader_uniform_buffer(GPUShader *shader, int location, struct GPUUniformBuffer *ubo); void GPU_shader_uniform_texture(GPUShader *shader, int location, struct GPUTexture *tex); void GPU_shader_uniform_int(GPUShader *shader, int location, int value); void GPU_shader_geometry_stage_primitive_io(GPUShader *shader, int input, int output, int number); @@ -85,15 +103,264 @@ int GPU_shader_get_attribute(GPUShader *shader, const char *name); /* Builtin/Non-generated shaders */ typedef enum GPUBuiltinShader { - GPU_SHADER_VSM_STORE = 0, - GPU_SHADER_SEP_GAUSSIAN_BLUR = 1, - GPU_SHADER_SMOKE = 2, - GPU_SHADER_SMOKE_FIRE = 3, - GPU_SHADER_SMOKE_COBA = 4, + GPU_SHADER_VSM_STORE, + GPU_SHADER_SEP_GAUSSIAN_BLUR, + GPU_SHADER_SMOKE, + GPU_SHADER_SMOKE_FIRE, + GPU_SHADER_SMOKE_COBA, + + /* 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, + GPU_SHADER_EDGES_OVERLAY, + GPU_SHADER_KEYFRAME_DIAMOND, + GPU_SHADER_SIMPLE_LIGHTING, + GPU_SHADER_SIMPLE_LIGHTING_FLAT_COLOR, + GPU_SHADER_SIMPLE_LIGHTING_SMOOTH_COLOR, + GPU_SHADER_SIMPLE_LIGHTING_SMOOTH_COLOR_ALPHA, + + /* for simple 2D drawing */ + /** + * Take a single color for all the vertices and a 2D position for each vertex. + * + * \param color: uniform vec4 + * \param pos: in vec2 + */ + GPU_SHADER_2D_UNIFORM_COLOR, + /** + * Take a 2D position and color for each vertex without color interpolation. + * + * \param color: in vec4 + * \param pos: in vec2 + */ + GPU_SHADER_2D_FLAT_COLOR, + /** + * Take a 2D position and color for each vertex with linear interpolation in window space. + * + * \param color: in vec4 + * \param pos: in vec2 + */ + GPU_SHADER_2D_SMOOTH_COLOR, + GPU_SHADER_2D_SMOOTH_COLOR_DITHER, + GPU_SHADER_2D_IMAGE, + GPU_SHADER_2D_IMAGE_COLOR, + GPU_SHADER_2D_IMAGE_DESATURATE_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_IMAGE_MULTISAMPLE_2, + GPU_SHADER_2D_IMAGE_MULTISAMPLE_4, + GPU_SHADER_2D_IMAGE_MULTISAMPLE_8, + GPU_SHADER_2D_IMAGE_MULTISAMPLE_16, + GPU_SHADER_2D_CHECKER, + GPU_SHADER_2D_DIAG_STRIPES, + /* for simple 3D drawing */ + /** + * Take a single color for all the vertices and a 3D position for each vertex. + * + * \param color: uniform vec4 + * \param pos: in vec3 + */ + GPU_SHADER_3D_UNIFORM_COLOR, + GPU_SHADER_3D_UNIFORM_COLOR_U32, + GPU_SHADER_3D_UNIFORM_COLOR_INSTANCE, + /** + * Take a 3D position and color for each vertex without color interpolation. + * + * \param color: in vec4 + * \param pos: in vec3 + */ + GPU_SHADER_3D_FLAT_COLOR, + GPU_SHADER_3D_FLAT_COLOR_U32, /* use for select-id's */ + /** + * Take a 3D position and color for each vertex with perspective correct interpolation. + * + * \param color: in vec4 + * \param pos: in vec3 + */ + GPU_SHADER_3D_SMOOTH_COLOR, + /** + * Take a 3D position for each vertex and output only depth. + * + * \param pos: in vec3 + */ + GPU_SHADER_3D_DEPTH_ONLY, + GPU_SHADER_3D_CLIPPED_UNIFORM_COLOR, + /* basic image drawing */ + GPU_SHADER_2D_IMAGE_LINEAR_TO_SRGB, + GPU_SHADER_2D_IMAGE_SHUFFLE_COLOR, + GPU_SHADER_2D_IMAGE_MASK_UNIFORM_COLOR, + /** + * Draw texture with alpha. Take a 3D positon and a 2D texture coordinate for each vertex. + * + * \param alpha: uniform float + * \param image: uniform sampler2D + * \param texCoord: in vec2 + * \param pos: in vec3 + */ + GPU_SHADER_3D_IMAGE_MODULATE_ALPHA, + /** + * Draw linearized depth texture relate to near and far distances. + * Take a 3D positon and a 2D texture coordinate for each vertex. + * + * \param znear: uniform float + * \param zfar: uniform float + * \param image: uniform sampler2D + * \param texCoord: in vec2 + * \param pos: in vec3 + */ + GPU_SHADER_3D_IMAGE_DEPTH, + GPU_SHADER_3D_IMAGE_DEPTH_COPY, + /* stereo 3d */ + GPU_SHADER_2D_IMAGE_INTERLACE, + /* points */ + /** + * Draw round points with a hardcoded size. + * Take a single color for all the vertices and a 2D position for each vertex. + * + * \param color: uniform vec4 + * \param pos: in vec2 + */ + GPU_SHADER_2D_POINT_FIXED_SIZE_UNIFORM_COLOR, + /** + * Draw round points with a constant size. + * Take a single color for all the vertices and a 2D position for each vertex. + * + * \param size: uniform float + * \param color: uniform vec4 + * \param pos: in vec2 + */ + GPU_SHADER_2D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_AA, + /** + * Draw round points with a constant size and an outline. + * Take a single color for all the vertices and a 2D position for each vertex. + * + * \param size: uniform float + * \param outlineWidth: uniform float + * \param color: uniform vec4 + * \param outlineColor: uniform vec4 + * \param pos: in vec2 + */ + GPU_SHADER_2D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_OUTLINE_AA, + /** + * Draw round points with a constant size and an outline. Take a 2D position and a color for each vertex. + * + * \param size: uniform float + * \param outlineWidth: uniform float + * \param outlineColor: uniform vec4 + * \param color: in vec4 + * \param pos: in vec2 + */ + GPU_SHADER_2D_POINT_UNIFORM_SIZE_VARYING_COLOR_OUTLINE_AA, + /** + * Draw round points with a constant size and an outline. Take a 2D position and a color for each vertex. + * + * \param size: in float + * \param color: in vec4 + * \param pos: in vec2 + */ + GPU_SHADER_2D_POINT_VARYING_SIZE_VARYING_COLOR, + /** + * Draw round points with a hardcoded size. + * Take a single color for all the vertices and a 3D position for each vertex. + * + * \param color: uniform vec4 + * \param pos: in vec3 + */ + GPU_SHADER_3D_POINT_FIXED_SIZE_UNIFORM_COLOR, + /** + * Draw round points with a hardcoded size. + * Take a single color for all the vertices and a 3D position for each vertex. + * + * \param color: uniform vec4 + * \param pos: in vec3 + */ + GPU_SHADER_3D_POINT_FIXED_SIZE_VARYING_COLOR, + /** + * Draw round points with a constant size. + * Take a single color for all the vertices and a 3D position for each vertex. + * + * \param size: uniform float + * \param color: uniform vec4 + * \param pos: in vec3 + */ + GPU_SHADER_3D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_AA, + /** + * Draw round points with a constant size and an outline. + * Take a single color for all the vertices and a 3D position for each vertex. + * + * \param size: uniform float + * \param outlineWidth: uniform float + * \param color: uniform vec4 + * \param outlineColor: uniform vec4 + * \param pos: in vec3 + */ + GPU_SHADER_3D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_OUTLINE_AA, + /** + * Draw round points with a constant size and an outline. + * Take a single color for all the vertices and a 3D position for each vertex. + * + * \param color: uniform vec4 + * \param size: in float + * \param pos: in vec3 + */ + GPU_SHADER_3D_POINT_VARYING_SIZE_UNIFORM_COLOR, + /** + * Draw round points with a constant size and an outline. Take a 3D position and a color for each vertex. + * + * \param size: in float + * \param color: in vec4 + * \param pos: in vec3 + */ + GPU_SHADER_3D_POINT_VARYING_SIZE_VARYING_COLOR, + /* lines */ + GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR, + GPU_SHADER_3D_LINE_DASHED_UNIFORM_COLOR, + /* lamp drawing */ + GPU_SHADER_3D_GROUNDPOINT, + GPU_SHADER_3D_GROUNDLINE, + GPU_SHADER_3D_SCREENSPACE_VARIYING_COLOR, + /* bone drawing */ + GPU_SHADER_3D_OBJECTSPACE_VARIYING_COLOR, + GPU_SHADER_3D_OBJECTSPACE_SIMPLE_LIGHTING_VARIYING_COLOR, + /* camera drawing */ + GPU_SHADER_CAMERA, + /* distance in front of objects */ + GPU_SHADER_DISTANCE_LINES, + /* axis name */ + GPU_SHADER_3D_INSTANCE_SCREEN_ALIGNED_AXIS, + GPU_SHADER_3D_INSTANCE_SCREEN_ALIGNED, + /* instance */ + GPU_SHADER_INSTANCE_UNIFORM_COLOR, + GPU_SHADER_INSTANCE_VARIYING_ID_VARIYING_SIZE, /* Uniformly scaled */ + 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_NUM_BUILTIN_SHADERS /* (not an actual shader) */ } GPUBuiltinShader; +/* Keep these in sync with: + * gpu_shader_image_interlace_frag.glsl + * gpu_shader_image_rect_interlace_frag.glsl + **/ +typedef enum GPUInterlaceShader { + GPU_SHADER_INTERLACE_ROW = 0, + GPU_SHADER_INTERLACE_COLUMN = 1, + GPU_SHADER_INTERLACE_CHECKER = 2, +} 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 756fe79151b..cc66b5dbf9b 100644 --- a/source/blender/gpu/GPU_texture.h +++ b/source/blender/gpu/GPU_texture.h @@ -39,6 +39,7 @@ extern "C" { struct Image; struct ImageUser; struct PreviewImage; +struct Gwn_VertBuf; struct GPUFrameBuffer; typedef struct GPUTexture GPUTexture; @@ -55,25 +56,114 @@ typedef struct GPUTexture GPUTexture; * - if created with from_blender, will not free the texture */ -typedef enum GPUHDRType { - GPU_HDR_NONE = 0, - GPU_HDR_HALF_FLOAT = 1, - GPU_HDR_FULL_FLOAT = (1 << 1), -} GPUHDRType; - -GPUTexture *GPU_texture_create_1D(int w, const float *pixels, char err_out[256]); -GPUTexture *GPU_texture_create_2D(int w, int h, const float *pixels, GPUHDRType hdr, char err_out[256]); -GPUTexture *GPU_texture_create_3D(int w, int h, int depth, int channels, const float *fpixels); -GPUTexture *GPU_texture_create_depth(int w, int h, char err_out[256]); -GPUTexture *GPU_texture_create_vsm_shadow_map(int size, char err_out[256]); -GPUTexture *GPU_texture_create_2D_procedural(int w, int h, const float *pixels, bool repeat, char err_out[256]); -GPUTexture *GPU_texture_create_1D_procedural(int w, const float *pixels, char err_out[256]); +/* Wrapper to supported OpenGL/Vulkan texture internal storage + * If you need a type just uncomment it. Be aware that some formats + * are not supported by renderbuffers. All of the following formats + * are part of the OpenGL 3.3 core + * specification. */ +typedef enum GPUTextureFormat { + /* Formats texture & renderbuffer */ + GPU_RGBA8UI, + GPU_RGBA8I, + GPU_RGBA8, + GPU_RGBA32UI, + GPU_RGBA32I, + GPU_RGBA32F, + GPU_RGBA16UI, + GPU_RGBA16I, + GPU_RGBA16F, + GPU_RGBA16, + GPU_RG8UI, + GPU_RG8I, + GPU_RG8, + GPU_RG32UI, + GPU_RG32I, + GPU_RG32F, + GPU_RG16UI, + GPU_RG16I, + GPU_RG16F, + GPU_RG16, + GPU_R8UI, + GPU_R8I, + GPU_R8, + GPU_R32UI, + GPU_R32I, + GPU_R32F, + GPU_R16UI, + GPU_R16I, + GPU_R16F, + GPU_R16, /* Max texture buffer format. */ + + /* Special formats texture & renderbuffer */ +#if 0 + GPU_RGB10_A2, + GPU_RGB10_A2UI, + GPU_DEPTH32F_STENCIL8, +#endif + GPU_R11F_G11F_B10F, + GPU_DEPTH24_STENCIL8, + + /* Texture only format */ + GPU_RGB16F, +#if 0 + GPU_RGBA16_SNORM, + GPU_RGBA8_SNORM, + GPU_RGB32F, + GPU_RGB32I, + GPU_RGB32UI, + GPU_RGB16_SNORM, + GPU_RGB16I, + GPU_RGB16UI, + GPU_RGB16, + GPU_RGB8_SNORM, + GPU_RGB8, + GPU_RGB8I, + GPU_RGB8UI, + GPU_RG16_SNORM, + GPU_RG8_SNORM, + GPU_R16_SNORM, + GPU_R8_SNORM, +#endif + + /* Special formats texture only */ +#if 0 + GPU_SRGB8_A8, + GPU_SRGB8, + GPU_RGB9_E5, + GPU_COMPRESSED_RG_RGTC2, + GPU_COMPRESSED_SIGNED_RG_RGTC2, + GPU_COMPRESSED_RED_RGTC1, + GPU_COMPRESSED_SIGNED_RED_RGTC1, +#endif + + /* Depth Formats */ + GPU_DEPTH_COMPONENT32F, + GPU_DEPTH_COMPONENT24, + GPU_DEPTH_COMPONENT16, +} GPUTextureFormat; + +unsigned int GPU_texture_memory_usage_get(void); + +GPUTexture *GPU_texture_create_1D( + int w, GPUTextureFormat data_type, const float *pixels, char err_out[256]); +GPUTexture *GPU_texture_create_2D( + int w, int h, GPUTextureFormat data_type, const float *pixels, char err_out[256]); GPUTexture *GPU_texture_create_2D_multisample( - int w, int h, const float *pixels, GPUHDRType hdr, int samples, char err_out[256]); -GPUTexture *GPU_texture_create_depth_multisample(int w, int h, int samples, char err_out[256]); + int w, int h, GPUTextureFormat data_type, const float *pixels, int samples, char err_out[256]); +GPUTexture *GPU_texture_create_2D_array( + int w, int h, int d, GPUTextureFormat data_type, const float *pixels, char err_out[256]); +GPUTexture *GPU_texture_create_3D( + int w, int h, int d, GPUTextureFormat data_type, const float *pixels, char err_out[256]); +GPUTexture *GPU_texture_create_cube( + int w, GPUTextureFormat data_type, const float *pixels, char err_out[256]); +GPUTexture *GPU_texture_create_from_vertbuf(struct Gwn_VertBuf *vert); + GPUTexture *GPU_texture_from_blender( struct Image *ima, struct ImageUser *iuser, int textarget, bool is_data, double time, int mipmap); GPUTexture *GPU_texture_from_preview(struct PreviewImage *prv, int mipmap); + +void GPU_texture_update(GPUTexture *tex, const float *pixels); + void GPU_invalid_tex_init(void); void GPU_invalid_tex_bind(int mode); void GPU_invalid_tex_free(void); @@ -81,21 +171,28 @@ void GPU_invalid_tex_free(void); void GPU_texture_free(GPUTexture *tex); void GPU_texture_ref(GPUTexture *tex); - void GPU_texture_bind(GPUTexture *tex, int number); void GPU_texture_unbind(GPUTexture *tex); int GPU_texture_bound_number(GPUTexture *tex); -void GPU_texture_filter_mode(GPUTexture *tex, bool compare, bool use_filter); +void GPU_texture_generate_mipmap(GPUTexture *tex); +void GPU_texture_compare_mode(GPUTexture *tex, bool use_compare); +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_depth(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_uniformbuffer.h b/source/blender/gpu/GPU_uniformbuffer.h new file mode 100644 index 00000000000..c2480f8ba03 --- /dev/null +++ b/source/blender/gpu/GPU_uniformbuffer.h @@ -0,0 +1,59 @@ +/* + * ***** 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): Clement Foucault. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file GPU_uniformbuffer.h + * \ingroup gpu + */ + +#ifndef __GPU_UNIFORMBUFFER_H__ +#define __GPU_UNIFORMBUFFER_H__ + +struct ListBase; + +typedef struct GPUUniformBuffer GPUUniformBuffer; +typedef struct GPUUniformBufferDynamicItem GPUUniformBufferDynamicItem; + +GPUUniformBuffer *GPU_uniformbuffer_create(int size, const void *data, char err_out[256]); +GPUUniformBuffer *GPU_uniformbuffer_dynamic_create(struct ListBase *inputs, char err_out[256]); + +void GPU_uniformbuffer_free(GPUUniformBuffer *ubo); + +void GPU_uniformbuffer_update(GPUUniformBuffer *ubo, const void *data); +void GPU_uniformbuffer_dynamic_update(GPUUniformBuffer *ubo_); + +void GPU_uniformbuffer_bind(GPUUniformBuffer *ubo, int number); +void GPU_uniformbuffer_unbind(GPUUniformBuffer *ubo); + +int GPU_uniformbuffer_bindpoint(GPUUniformBuffer *ubo); + +bool GPU_uniformbuffer_is_empty(GPUUniformBuffer *ubo); +bool GPU_uniformbuffer_is_dirty(GPUUniformBuffer *ubo); +void GPU_uniformbuffer_tag_dirty(GPUUniformBuffer *ubo); + +#define GPU_UBO_BLOCK_NAME "nodeTree" + +#endif /* __GPU_UNIFORMBUFFER_H__ */ diff --git a/source/blender/gpu/GPU_viewport.h b/source/blender/gpu/GPU_viewport.h new file mode 100644 index 00000000000..921cd0e7369 --- /dev/null +++ b/source/blender/gpu/GPU_viewport.h @@ -0,0 +1,130 @@ +/* + * ***** 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): + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file GPU_viewport.h + * \ingroup gpu + */ + +#ifndef __GPU_VIEWPORT_H__ +#define __GPU_VIEWPORT_H__ + +#include <stdbool.h> + +#include "DNA_vec_types.h" + +#include "GPU_framebuffer.h" +#include "GPU_texture.h" + +#define GPU_INFO_SIZE 512 /* IMA_MAX_RENDER_TEXT */ + +typedef struct GPUViewport GPUViewport; + +/* Contains memory pools informations */ +typedef struct ViewportMemoryPool { + struct BLI_mempool *calls; + struct BLI_mempool *states; + struct BLI_mempool *shgroups; + struct BLI_mempool *uniforms; + struct BLI_mempool *passes; +} ViewportMemoryPool; + +/* All FramebufferLists are just the same pointers with different names */ +typedef struct FramebufferList { + struct GPUFrameBuffer *framebuffers[0]; +} FramebufferList; + +typedef struct TextureList { + struct GPUTexture *textures[0]; +} TextureList; + +typedef struct PassList { + struct DRWPass *passes[0]; +} PassList; + +typedef struct StorageList { + void *storage[0]; /* custom structs from the engine */ +} StorageList; + +typedef struct ViewportEngineData { + void *engine_type; + + FramebufferList *fbl; + TextureList *txl; + PassList *psl; + StorageList *stl; + char info[GPU_INFO_SIZE]; + + /* we may want to put this elsewhere */ + struct DRWTextStore *text_draw_cache; + + /* Profiling data */ + double init_time; + double render_time; + double background_time; +} ViewportEngineData; + +typedef struct ViewportEngineData_Info { + int fbl_len; + int txl_len; + int psl_len; + int stl_len; +} 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); +void GPU_viewport_clear_from_offscreen(GPUViewport *viewport); + +ViewportMemoryPool *GPU_viewport_mempool_get(GPUViewport *viewport); +struct DRWInstanceDataList *GPU_viewport_instance_data_list_get(GPUViewport *viewport); + +void *GPU_viewport_engine_data_create(GPUViewport *viewport, void *engine_type); +void *GPU_viewport_engine_data_get(GPUViewport *viewport, void *engine_type); +void *GPU_viewport_framebuffer_list_get(GPUViewport *viewport); +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); + +GPUTexture *GPU_viewport_color_texture(GPUViewport *viewport); + +/* Texture pool */ +GPUTexture *GPU_viewport_texture_pool_query(GPUViewport *viewport, void *engine, int width, int height, int format); + +bool GPU_viewport_engines_data_validate(GPUViewport *viewport, unsigned int hash); +void GPU_viewport_cache_release(GPUViewport *viewport); + +#endif // __GPU_VIEWPORT_H__ diff --git a/source/blender/gpu/intern/gpu_basic_shader.c b/source/blender/gpu/intern/gpu_basic_shader.c index 8505bd847a0..620a06ae606 100644 --- a/source/blender/gpu/intern/gpu_basic_shader.c +++ b/source/blender/gpu/intern/gpu_basic_shader.c @@ -140,114 +140,6 @@ const GLubyte stipple_checker_8px[128] = { 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255}; -const GLubyte stipple_interlace_row[128] = { - 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, - 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, - 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, - 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, - 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, - 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, - 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, - 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, - 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, - 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, - 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, - 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, - 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, - 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, - 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, - 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00}; - -const GLubyte stipple_interlace_row_swap[128] = { - 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff}; - -const GLubyte stipple_interlace_column[128] = { - 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, - 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, - 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, - 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, - 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, - 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, - 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, - 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, - 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, - 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, - 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, - 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, - 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, - 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, - 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, - 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55}; - -const GLubyte stipple_interlace_column_swap[128] = { - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa}; - -const GLubyte stipple_interlace_checker[128] = { - 0x55, 0x55, 0x55, 0x55, 0xaa, 0xaa, 0xaa, 0xaa, - 0x55, 0x55, 0x55, 0x55, 0xaa, 0xaa, 0xaa, 0xaa, - 0x55, 0x55, 0x55, 0x55, 0xaa, 0xaa, 0xaa, 0xaa, - 0x55, 0x55, 0x55, 0x55, 0xaa, 0xaa, 0xaa, 0xaa, - 0x55, 0x55, 0x55, 0x55, 0xaa, 0xaa, 0xaa, 0xaa, - 0x55, 0x55, 0x55, 0x55, 0xaa, 0xaa, 0xaa, 0xaa, - 0x55, 0x55, 0x55, 0x55, 0xaa, 0xaa, 0xaa, 0xaa, - 0x55, 0x55, 0x55, 0x55, 0xaa, 0xaa, 0xaa, 0xaa, - 0x55, 0x55, 0x55, 0x55, 0xaa, 0xaa, 0xaa, 0xaa, - 0x55, 0x55, 0x55, 0x55, 0xaa, 0xaa, 0xaa, 0xaa, - 0x55, 0x55, 0x55, 0x55, 0xaa, 0xaa, 0xaa, 0xaa, - 0x55, 0x55, 0x55, 0x55, 0xaa, 0xaa, 0xaa, 0xaa, - 0x55, 0x55, 0x55, 0x55, 0xaa, 0xaa, 0xaa, 0xaa, - 0x55, 0x55, 0x55, 0x55, 0xaa, 0xaa, 0xaa, 0xaa, - 0x55, 0x55, 0x55, 0x55, 0xaa, 0xaa, 0xaa, 0xaa, - 0x55, 0x55, 0x55, 0x55, 0xaa, 0xaa, 0xaa, 0xaa}; - -const GLubyte stipple_interlace_checker_swap[128] = { - 0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55, - 0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55, - 0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55, - 0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55, - 0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55, - 0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55, - 0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55, - 0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55, - 0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55, - 0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55, - 0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55, - 0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55, - 0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55, - 0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55, - 0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55, - 0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55}; - const GLubyte stipple_hexagon[128] = { 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, @@ -267,24 +159,6 @@ const GLubyte stipple_hexagon[128] = { 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22}; /* ********************************************* */ -/* GLSL State */ - -static bool USE_GLSL = false; - -/** - * \note this isn't part of the basic shader API, - * only set from the command line once on startup. - */ -void GPU_basic_shader_use_glsl_set(bool enabled) -{ - USE_GLSL = enabled; -} - -bool GPU_basic_shader_use_glsl_get(void) -{ - return USE_GLSL; -} - /* Init / exit */ void GPU_basic_shaders_init(void) @@ -316,31 +190,6 @@ static bool solid_compatible_lighting(void) return ((directional & enabled) == enabled); } -#if 0 -static int detect_options() -{ - GLint two_sided; - int options = 0; - - if (glIsEnabled(GL_TEXTURE_2D)) - options |= GPU_SHADER_TEXTURE_2D; - if (glIsEnabled(GL_TEXTURE_RECTANGLE)) - options |= GPU_SHADER_TEXTURE_RECT; - GPU_SHADER_TEXTURE_RECT - if (glIsEnabled(GL_COLOR_MATERIAL)) - options |= GPU_SHADER_USE_COLOR; - - if (glIsEnabled(GL_LIGHTING)) - options |= GPU_SHADER_LIGHTING; - - glGetIntegerv(GL_LIGHT_MODEL_TWO_SIDE, &two_sided); - if (two_sided == GL_TRUE) - options |= GPU_SHADER_TWO_SIDED; - - return options; -} -#endif - static GPUShader *gpu_basic_shader(int options) { /* glsl code */ @@ -388,7 +237,7 @@ static GPUShader *gpu_basic_shader(int options) datatoc_gpu_shader_basic_frag_glsl, geom_glsl, NULL, - defines, 0, 0, 0); + defines); if (shader) { /* set texture map to first texture unit */ @@ -420,102 +269,16 @@ static void gpu_basic_shader_uniform_autoset(GPUShader *shader, int options) void GPU_basic_shader_bind(int options) { - if (USE_GLSL) { - if (options) { - const int bound_options = GPU_MATERIAL_STATE.bound_options; - - /* texture options need to be set for basic shader too */ - if (options & GPU_SHADER_TEXTURE_2D) { - glEnable(GL_TEXTURE_2D); - } - else if (bound_options & GPU_SHADER_TEXTURE_2D) { - glDisable(GL_TEXTURE_2D); - } - - if (options & GPU_SHADER_TEXTURE_RECT) { - glEnable(GL_TEXTURE_RECTANGLE); - } - else if (bound_options & GPU_SHADER_TEXTURE_RECT) { - glDisable(GL_TEXTURE_RECTANGLE); - } - - GPUShader *shader = gpu_basic_shader(options); + if (options) { + GPUShader *shader = gpu_basic_shader(options); - if (shader) { - GPU_shader_bind(shader); - gpu_basic_shader_uniform_autoset(shader, options); - } - } - else { - GPU_shader_unbind(); + if (shader) { + GPU_shader_bind(shader); + gpu_basic_shader_uniform_autoset(shader, options); } } else { - const int bound_options = GPU_MATERIAL_STATE.bound_options; - - if (options & GPU_SHADER_LIGHTING) { - glEnable(GL_LIGHTING); - - if (options & GPU_SHADER_USE_COLOR) - glEnable(GL_COLOR_MATERIAL); - else - glDisable(GL_COLOR_MATERIAL); - - if (options & GPU_SHADER_TWO_SIDED) - glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE); - else - glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_FALSE); - } - else if (bound_options & GPU_SHADER_LIGHTING) { - glDisable(GL_LIGHTING); - glDisable(GL_COLOR_MATERIAL); - glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_FALSE); - } - - if (options & GPU_SHADER_TEXTURE_2D) { - GLint env_mode = (options & (GPU_SHADER_USE_COLOR | GPU_SHADER_LIGHTING)) ? GL_MODULATE : GL_REPLACE; - glEnable(GL_TEXTURE_2D); - glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, env_mode); - } - else if (bound_options & GPU_SHADER_TEXTURE_2D) { - if ((options & GPU_SHADER_TEXTURE_RECT) == 0) { - glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); - } - glDisable(GL_TEXTURE_2D); - } - - if (options & GPU_SHADER_TEXTURE_RECT) { - GLint env_mode = (options & (GPU_SHADER_USE_COLOR | GPU_SHADER_LIGHTING)) ? GL_MODULATE : GL_REPLACE; - glEnable(GL_TEXTURE_RECTANGLE); - glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, env_mode); - } - else if (bound_options & GPU_SHADER_TEXTURE_RECT) { - if ((options & GPU_SHADER_TEXTURE_2D) == 0) { - glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); - } - glDisable(GL_TEXTURE_RECTANGLE); - } - - if ((options & GPU_SHADER_LINE) && (options & GPU_SHADER_STIPPLE)) { - glEnable(GL_LINE_STIPPLE); - } - else if ((bound_options & GPU_SHADER_LINE) && (bound_options & GPU_SHADER_STIPPLE)) { - glDisable(GL_LINE_STIPPLE); - } - - if (((options & GPU_SHADER_LINE) == 0) && (options & GPU_SHADER_STIPPLE)) { - glEnable(GL_POLYGON_STIPPLE); - } - else if (((bound_options & GPU_SHADER_LINE) == 0) && (bound_options & GPU_SHADER_STIPPLE)) { - glDisable(GL_POLYGON_STIPPLE); - } - - if (options & GPU_SHADER_FLAT_NORMAL) { - glShadeModel(GL_FLAT); - } - else if (bound_options & GPU_SHADER_FLAT_NORMAL) { - glShadeModel(GL_SMOOTH); - } + GPU_shader_unbind(); } GPU_MATERIAL_STATE.bound_options = options; @@ -544,175 +307,37 @@ void GPU_basic_shader_colors( const float diffuse[3], const float specular[3], int shininess, float alpha) { - float gl_diffuse[4], gl_specular[4]; - - if (diffuse) - copy_v3_v3(gl_diffuse, diffuse); - else - zero_v3(gl_diffuse); - gl_diffuse[3] = alpha; - - if (specular) - copy_v3_v3(gl_specular, specular); - else - zero_v3(gl_specular); - gl_specular[3] = 1.0f; - - glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, gl_diffuse); - glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, gl_specular); - glMateriali(GL_FRONT_AND_BACK, GL_SHININESS, CLAMPIS(shininess, 1, 128)); + UNUSED_VARS(diffuse, specular, shininess, alpha); + return; } void GPU_basic_shader_light_set(int light_num, GPULightData *light) { - int light_bit = (1 << light_num); - - /* note that light position is affected by the current modelview matrix! */ - - GPU_MATERIAL_STATE.lights_enabled &= ~light_bit; - GPU_MATERIAL_STATE.lights_directional &= ~light_bit; - - if (light) { - float position[4], diffuse[4], specular[4]; - - glEnable(GL_LIGHT0 + light_num); - - /* position */ - if (light->type == GPU_LIGHT_SUN) { - copy_v3_v3(position, light->direction); - position[3] = 0.0f; - } - else { - copy_v3_v3(position, light->position); - position[3] = 1.0f; - } - glLightfv(GL_LIGHT0 + light_num, GL_POSITION, position); - - /* energy */ - copy_v3_v3(diffuse, light->diffuse); - copy_v3_v3(specular, light->specular); - diffuse[3] = 1.0f; - specular[3] = 1.0f; - glLightfv(GL_LIGHT0 + light_num, GL_DIFFUSE, diffuse); - glLightfv(GL_LIGHT0 + light_num, GL_SPECULAR, specular); - - /* attenuation */ - if (light->type == GPU_LIGHT_SUN) { - glLightf(GL_LIGHT0 + light_num, GL_CONSTANT_ATTENUATION, 1.0f); - glLightf(GL_LIGHT0 + light_num, GL_LINEAR_ATTENUATION, 0.0f); - glLightf(GL_LIGHT0 + light_num, GL_QUADRATIC_ATTENUATION, 0.0f); - } - else { - glLightf(GL_LIGHT0 + light_num, GL_CONSTANT_ATTENUATION, light->constant_attenuation); - glLightf(GL_LIGHT0 + light_num, GL_LINEAR_ATTENUATION, light->linear_attenuation); - glLightf(GL_LIGHT0 + light_num, GL_QUADRATIC_ATTENUATION, light->quadratic_attenuation); - } - - /* spot */ - glLightfv(GL_LIGHT0 + light_num, GL_SPOT_DIRECTION, light->direction); - if (light->type == GPU_LIGHT_SPOT) { - glLightf(GL_LIGHT0 + light_num, GL_SPOT_CUTOFF, light->spot_cutoff); - glLightf(GL_LIGHT0 + light_num, GL_SPOT_EXPONENT, light->spot_exponent); - } - else { - glLightf(GL_LIGHT0 + light_num, GL_SPOT_CUTOFF, 180.0f); - glLightf(GL_LIGHT0 + light_num, GL_SPOT_EXPONENT, 0.0f); - } - - GPU_MATERIAL_STATE.lights_enabled |= light_bit; - if (position[3] == 0.0f) - GPU_MATERIAL_STATE.lights_directional |= light_bit; - } - else { - /* TODO(sergey): Needs revisit. */ - if (USE_GLSL || true) { - /* glsl shader needs these zero to skip them */ - const float zero[4] = {0.0f, 0.0f, 0.0f, 0.0f}; - - glLightfv(GL_LIGHT0 + light_num, GL_POSITION, zero); - glLightfv(GL_LIGHT0 + light_num, GL_DIFFUSE, zero); - glLightfv(GL_LIGHT0 + light_num, GL_SPECULAR, zero); - } - - glDisable(GL_LIGHT0 + light_num); - } + UNUSED_VARS(light_num, light); + return; } void GPU_basic_shader_light_set_viewer(bool local) { - glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, (local) ? GL_TRUE: GL_FALSE); + UNUSED_VARS(local); + return; } void GPU_basic_shader_stipple(GPUBasicShaderStipple stipple_id) { - if (USE_GLSL) { - glUniform1i(GPU_shader_get_uniform(gpu_basic_shader(GPU_MATERIAL_STATE.bound_options), "stipple_id"), stipple_id); - } - else { - switch (stipple_id) { - case GPU_SHADER_STIPPLE_HALFTONE: - glPolygonStipple(stipple_halftone); - return; - case GPU_SHADER_STIPPLE_QUARTTONE: - glPolygonStipple(stipple_quarttone); - return; - case GPU_SHADER_STIPPLE_CHECKER_8PX: - glPolygonStipple(stipple_checker_8px); - return; - case GPU_SHADER_STIPPLE_HEXAGON: - glPolygonStipple(stipple_hexagon); - return; - case GPU_SHADER_STIPPLE_DIAG_STRIPES_SWAP: - glPolygonStipple(stipple_diag_stripes_neg); - return; - case GPU_SHADER_STIPPLE_DIAG_STRIPES: - glPolygonStipple(stipple_diag_stripes_pos); - return; - case GPU_SHADER_STIPPLE_S3D_INTERLACE_ROW: - glPolygonStipple(stipple_interlace_row); - return; - case GPU_SHADER_STIPPLE_S3D_INTERLACE_ROW_SWAP: - glPolygonStipple(stipple_interlace_row_swap); - return; - case GPU_SHADER_STIPPLE_S3D_INTERLACE_COLUMN: - glPolygonStipple(stipple_interlace_column); - return; - case GPU_SHADER_STIPPLE_S3D_INTERLACE_COLUMN_SWAP: - glPolygonStipple(stipple_interlace_column_swap); - return; - case GPU_SHADER_STIPPLE_S3D_INTERLACE_CHECKER: - glPolygonStipple(stipple_interlace_checker); - return; - case GPU_SHADER_STIPPLE_S3D_INTERLACE_CHECKER_SWAP: - glPolygonStipple(stipple_interlace_checker_swap); - return; - default: - glPolygonStipple(stipple_hexagon); - return; - } - } + glUniform1i(GPU_shader_get_uniform(gpu_basic_shader(GPU_MATERIAL_STATE.bound_options), "stipple_id"), stipple_id); } void GPU_basic_shader_line_width(float line_width) { - if (USE_GLSL) { - GPU_MATERIAL_STATE.line_width = line_width; - if (GPU_MATERIAL_STATE.bound_options & GPU_SHADER_LINE) { - glUniform1f(GPU_shader_get_uniform(gpu_basic_shader(GPU_MATERIAL_STATE.bound_options), "line_width"), line_width); - } - } - else { - glLineWidth(line_width); + GPU_MATERIAL_STATE.line_width = line_width; + if (GPU_MATERIAL_STATE.bound_options & GPU_SHADER_LINE) { + glUniform1f(GPU_shader_get_uniform(gpu_basic_shader(GPU_MATERIAL_STATE.bound_options), "line_width"), line_width); } } void GPU_basic_shader_line_stipple(GLint stipple_factor, GLushort stipple_pattern) { - if (USE_GLSL) { - glUniform1i(GPU_shader_get_uniform(gpu_basic_shader(GPU_MATERIAL_STATE.bound_options), "stipple_factor"), stipple_factor); - glUniform1i(GPU_shader_get_uniform(gpu_basic_shader(GPU_MATERIAL_STATE.bound_options), "stipple_pattern"), stipple_pattern); - } - else { - glLineStipple(stipple_factor, stipple_pattern); - } + glUniform1i(GPU_shader_get_uniform(gpu_basic_shader(GPU_MATERIAL_STATE.bound_options), "stipple_factor"), stipple_factor); + glUniform1i(GPU_shader_get_uniform(gpu_basic_shader(GPU_MATERIAL_STATE.bound_options), "stipple_pattern"), stipple_pattern); } diff --git a/source/blender/gpu/intern/gpu_batch.c b/source/blender/gpu/intern/gpu_batch.c new file mode 100644 index 00000000000..59d88e81822 --- /dev/null +++ b/source/blender/gpu/intern/gpu_batch.c @@ -0,0 +1,281 @@ +/* + * ***** 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) 2016 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Mike Erwin + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/gpu/intern/gpu_batch.c + * \ingroup gpu + */ + +#include "MEM_guardedalloc.h" + +#include "BLI_utildefines.h" +#include "BLI_rect.h" +#include "BLI_math.h" +#include "BLI_polyfill_2d.h" +#include "BLI_sort_utils.h" + + +#include "GPU_batch.h" /* own include */ +#include "gpu_shader_private.h" + +/* -------------------------------------------------------------------- */ +/** \name Utilities + * \{ */ + +void GWN_batch_program_set_builtin(Gwn_Batch *batch, GPUBuiltinShader shader_id) +{ + GPUShader *shader = GPU_shader_get_builtin_shader(shader_id); + GWN_batch_program_set(batch, shader->program, shader->interface); +} + +/** \} */ + + + +/* -------------------------------------------------------------------- */ +/** \name Batch Creation + * \{ */ + +/** + * Creates triangles from a byte-array of polygons. + * + * See 'make_shape_2d_from_blend.py' utility to create data to pass to this function. + * + * \param polys_flat: Pairs of X, Y coordinates (repeating to signify closing the polygon). + * \param polys_flat_len: Length of the array (must be an even number). + * \param rect: Optional region to map the byte 0..255 coords to. When not set use -1..1. + */ +Gwn_Batch *GPU_batch_tris_from_poly_2d_encoded( + const uchar *polys_flat, uint polys_flat_len, const rctf *rect) +{ + const uchar (*polys)[2] = (const void *)polys_flat; + const uint polys_len = polys_flat_len / 2; + BLI_assert(polys_flat_len == polys_len * 2); + + /* Over alloc in both cases */ + float (*verts)[2] = MEM_mallocN(sizeof(*verts) * polys_len, __func__); + float (*verts_step)[2] = verts; + uint (*tris)[3] = MEM_mallocN(sizeof(*tris) * polys_len, __func__); + uint (*tris_step)[3] = tris; + + const float range_uchar[2] = { + (rect ? (rect->xmax - rect->xmin) : 2.0f) / 255.0f, + (rect ? (rect->ymax - rect->ymin) : 2.0f) / 255.0f, + }; + const float min_uchar[2] = { + (rect ? rect->xmin : -1.0f), + (rect ? rect->ymin : -1.0f), + }; + + uint i_poly = 0; + uint i_vert = 0; + while (i_poly != polys_len) { + for (uint j = 0; j < 2; j++) { + verts[i_vert][j] = min_uchar[j] + ((float)polys[i_poly][j] * range_uchar[j]); + } + i_vert++; + i_poly++; + if (polys[i_poly - 1][0] == polys[i_poly][0] && + polys[i_poly - 1][1] == polys[i_poly][1]) + { + const uint verts_step_len = (&verts[i_vert]) - verts_step; + BLI_assert(verts_step_len >= 3); + const uint tris_len = (verts_step_len - 2); + BLI_polyfill_calc(verts_step, verts_step_len, -1, tris_step); + /* offset indices */ + if (verts_step != verts) { + uint *t = tris_step[0]; + const uint offset = (verts_step - verts); + uint tot = tris_len * 3; + while (tot--) { + *t += offset; + t++; + } + BLI_assert(t == tris_step[tris_len]); + } + verts_step += verts_step_len; + tris_step += tris_len; + i_poly++; + /* ignore the duplicate point */ + } + } + + /* We have vertices and tris, make a batch from this. */ + static Gwn_VertFormat format = {0}; + static struct { uint pos; } attr_id; + if (format.attrib_ct == 0) { + attr_id.pos = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT); + } + + const uint verts_len = (verts_step - verts); + const uint tris_len = (tris_step - tris); + Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&format); + GWN_vertbuf_data_alloc(vbo, verts_len); + + Gwn_VertBufRaw pos_step; + GWN_vertbuf_attr_get_raw_data(vbo, attr_id.pos, &pos_step); + + for (uint i = 0; i < verts_len; i++) { + copy_v2_v2(GWN_vertbuf_raw_step(&pos_step), verts[i]); + } + + Gwn_IndexBufBuilder elb; + GWN_indexbuf_init(&elb, GWN_PRIM_TRIS, tris_len, verts_len); + for (uint i = 0; i < tris_len; i++) { + GWN_indexbuf_add_tri_verts(&elb, UNPACK3(tris[i])); + } + Gwn_IndexBuf *indexbuf = GWN_indexbuf_build(&elb); + + MEM_freeN(tris); + MEM_freeN(verts); + + return GWN_batch_create_ex( + GWN_PRIM_TRIS, vbo, + indexbuf, + GWN_BATCH_OWNS_VBO | GWN_BATCH_OWNS_INDEX); +} + +Gwn_Batch *GPU_batch_wire_from_poly_2d_encoded( + const uchar *polys_flat, uint polys_flat_len, const rctf *rect) +{ + const uchar (*polys)[2] = (const void *)polys_flat; + const uint polys_len = polys_flat_len / 2; + BLI_assert(polys_flat_len == polys_len * 2); + + /* Over alloc */ + /* Lines are pairs of (x, y) byte locations packed into an int32_t. */ + int32_t *lines = MEM_mallocN(sizeof(*lines) * polys_len, __func__); + int32_t *lines_step = lines; + + const float range_uchar[2] = { + (rect ? (rect->xmax - rect->xmin) : 2.0f) / 255.0f, + (rect ? (rect->ymax - rect->ymin) : 2.0f) / 255.0f, + }; + const float min_uchar[2] = { + (rect ? rect->xmin : -1.0f), + (rect ? rect->ymin : -1.0f), + }; + + uint i_poly_prev = 0; + uint i_poly = 0; + while (i_poly != polys_len) { + i_poly++; + if (polys[i_poly - 1][0] == polys[i_poly][0] && + polys[i_poly - 1][1] == polys[i_poly][1]) + { + const uchar (*polys_step)[2] = polys + i_poly_prev; + const uint polys_step_len = i_poly - i_poly_prev; + BLI_assert(polys_step_len >= 2); + for (uint i_prev = polys_step_len - 1, i = 0; i < polys_step_len; i_prev = i++) { + union { + uint8_t as_u8[4]; + uint16_t as_u16[2]; + uint32_t as_u32; + } data; + data.as_u16[0] = *((const uint16_t *)polys_step[i_prev]); + data.as_u16[1] = *((const uint16_t *)polys_step[i]); + if (data.as_u16[0] > data.as_u16[1]) { + SWAP(uint16_t, data.as_u16[0], data.as_u16[1]); + } + *lines_step = data.as_u32; + lines_step++; + } + i_poly++; + i_poly_prev = i_poly; + /* ignore the duplicate point */ + } + } + + uint lines_len = lines_step - lines; + + /* Hide Lines (we could make optional) */ + { + qsort(lines, lines_len, sizeof(int32_t), BLI_sortutil_cmp_int); + lines_step = lines; + + if (lines[0] != lines[1]) { + *lines_step++ = lines[0]; + } + for (uint i_prev = 0, i = 1; i < lines_len; i_prev = i++) { + if (lines[i] != lines[i_prev]) { + *lines_step++ = lines[i]; + } + } + lines_len = lines_step - lines; + } + + /* We have vertices and tris, make a batch from this. */ + static Gwn_VertFormat format = {0}; + static struct { uint pos; } attr_id; + if (format.attrib_ct == 0) { + attr_id.pos = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT); + } + + Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&format); + const uint vbo_len_capacity = lines_len * 2; + GWN_vertbuf_data_alloc(vbo, vbo_len_capacity); + + Gwn_VertBufRaw pos_step; + GWN_vertbuf_attr_get_raw_data(vbo, attr_id.pos, &pos_step); + + for (uint i = 0; i < lines_len; i++) { + union { + uint8_t as_u8_pair[2][2]; + uint32_t as_u32; + } data; + data.as_u32 = lines[i]; + for (uint k = 0; k < 2; k++) { + float *pos_v2 = GWN_vertbuf_raw_step(&pos_step); + for (uint j = 0; j < 2; j++) { + pos_v2[j] = min_uchar[j] + ((float)data.as_u8_pair[k][j] * range_uchar[j]); + } + } + } + BLI_assert(vbo_len_capacity == GWN_vertbuf_raw_used(&pos_step)); + MEM_freeN(lines); + return GWN_batch_create_ex( + GWN_PRIM_LINES, vbo, + NULL, + GWN_BATCH_OWNS_VBO); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Init/Exit + * \{ */ + +void gpu_batch_init(void) +{ + gpu_batch_presets_init(); +} + +void gpu_batch_exit(void) +{ + gpu_batch_presets_exit(); +} + +/** \} */ diff --git a/source/blender/gpu/intern/gpu_batch_presets.c b/source/blender/gpu/intern/gpu_batch_presets.c new file mode 100644 index 00000000000..10cbd16490b --- /dev/null +++ b/source/blender/gpu/intern/gpu_batch_presets.c @@ -0,0 +1,236 @@ +/* + * ***** 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) 2016 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Mike Erwin + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/gpu/intern/gpu_batch_presets.c + * \ingroup gpu + */ + +#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" + +/* Struct to store 3D Batches and their format */ +static struct { + struct { + Gwn_Batch *sphere_high; + Gwn_Batch *sphere_med; + Gwn_Batch *sphere_low; + Gwn_Batch *sphere_wire_low; + Gwn_Batch *sphere_wire_med; + } batch; + + Gwn_VertFormat format; + + struct { + uint pos, nor; + } attr_id; +} g_presets_3d = {{0}}; + +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) +{ + float pos[3]; + pos[0] = sinf(lat) * cosf(lon); + pos[1] = cosf(lat); + pos[2] = sinf(lat) * sinf(lon); + copy_v3_v3(GWN_vertbuf_raw_step(pos_step), pos); + copy_v3_v3(GWN_vertbuf_raw_step(nor_step), pos); +} + +/* Replacement for gluSphere */ +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(preset_3D_format()); + const uint vbo_len = (lat_res - 1) * lon_res * 6; + GWN_vertbuf_data_alloc(vbo, vbo_len); + + Gwn_VertBufRaw pos_step, nor_step; + GWN_vertbuf_attr_get_raw_data(vbo, g_presets_3d.attr_id.pos, &pos_step); + GWN_vertbuf_attr_get_raw_data(vbo, g_presets_3d.attr_id.nor, &nor_step); + + lon = 0.0f; + for (int i = 0; i < lon_res; i++, lon += lon_inc) { + lat = 0.0f; + for (int j = 0; j < lat_res; j++, lat += lat_inc) { + if (j != lat_res - 1) { /* Pole */ + batch_sphere_lat_lon_vert(&pos_step, &nor_step, lat + lat_inc, lon + lon_inc); + batch_sphere_lat_lon_vert(&pos_step, &nor_step, lat + lat_inc, lon); + batch_sphere_lat_lon_vert(&pos_step, &nor_step, lat, lon); + } + + if (j != 0) { /* Pole */ + batch_sphere_lat_lon_vert(&pos_step, &nor_step, lat, lon + lon_inc); + batch_sphere_lat_lon_vert(&pos_step, &nor_step, lat + lat_inc, lon + lon_inc); + batch_sphere_lat_lon_vert(&pos_step, &nor_step, lat, lon); + } + } + } + + BLI_assert(vbo_len == GWN_vertbuf_raw_used(&pos_step)); + BLI_assert(vbo_len == GWN_vertbuf_raw_used(&nor_step)); + + return GWN_batch_create_ex(GWN_PRIM_TRIS, vbo, NULL, GWN_BATCH_OWNS_VBO); +} + +static Gwn_Batch *batch_sphere_wire(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(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); + + Gwn_VertBufRaw pos_step, nor_step; + GWN_vertbuf_attr_get_raw_data(vbo, g_presets_3d.attr_id.pos, &pos_step); + GWN_vertbuf_attr_get_raw_data(vbo, g_presets_3d.attr_id.nor, &nor_step); + + lon = 0.0f; + for (int i = 0; i < lon_res; i++, lon += lon_inc) { + lat = 0.0f; + for (int j = 0; j < lat_res; j++, lat += lat_inc) { + batch_sphere_lat_lon_vert(&pos_step, &nor_step, lat + lat_inc, lon); + batch_sphere_lat_lon_vert(&pos_step, &nor_step, lat, lon); + + if (j != lat_res - 1) { /* Pole */ + batch_sphere_lat_lon_vert(&pos_step, &nor_step, lat + lat_inc, lon + lon_inc); + batch_sphere_lat_lon_vert(&pos_step, &nor_step, lat + lat_inc, lon); + } + } + } + + BLI_assert(vbo_len == GWN_vertbuf_raw_used(&pos_step)); + BLI_assert(vbo_len == GWN_vertbuf_raw_used(&nor_step)); + + return GWN_batch_create_ex(GWN_PRIM_LINES, vbo, NULL, GWN_BATCH_OWNS_VBO); +} + +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; + } + else if (lod == 1) { + return g_presets_3d.batch.sphere_med; + } + else { + return g_presets_3d.batch.sphere_high; + } +} + +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; + } + else { + return g_presets_3d.batch.sphere_wire_med; + } +} + +/** \} */ + + +void gpu_batch_presets_init(void) +{ + /* Hard coded resolution */ + 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) +{ + 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 38e847da967..9d2a0ceef4d 100644 --- a/source/blender/gpu/intern/gpu_buffers.c +++ b/source/blender/gpu/intern/gpu_buffers.c @@ -35,8 +35,6 @@ #include <stddef.h> #include <string.h> -#include "GPU_glew.h" - #include "MEM_guardedalloc.h" #include "BLI_bitmap.h" @@ -55,914 +53,29 @@ #include "GPU_buffers.h" #include "GPU_draw.h" -#include "GPU_basic_shader.h" +#include "GPU_immediate.h" +#include "GPU_batch.h" #include "bmesh.h" -typedef enum { - GPU_BUFFER_VERTEX_STATE = (1 << 0), - GPU_BUFFER_NORMAL_STATE = (1 << 1), - GPU_BUFFER_TEXCOORD_UNIT_0_STATE = (1 << 2), - GPU_BUFFER_TEXCOORD_UNIT_2_STATE = (1 << 3), - GPU_BUFFER_COLOR_STATE = (1 << 4), - GPU_BUFFER_ELEMENT_STATE = (1 << 5), -} GPUBufferState; - -typedef struct { - GLenum gl_buffer_type; - int num_components; /* number of data components for one vertex */ -} GPUBufferTypeSettings; - - -static size_t gpu_buffer_size_from_type(DerivedMesh *dm, GPUBufferType type); - -static const GPUBufferTypeSettings gpu_buffer_type_settings[] = { - /* vertex */ - {GL_ARRAY_BUFFER, 3}, - /* normal */ - {GL_ARRAY_BUFFER, 4}, /* we copy 3 shorts per normal but we add a fourth for alignment */ - /* mcol */ - {GL_ARRAY_BUFFER, 4}, - /* uv */ - {GL_ARRAY_BUFFER, 2}, - /* uv for texpaint */ - {GL_ARRAY_BUFFER, 4}, - /* edge */ - {GL_ELEMENT_ARRAY_BUFFER, 2}, - /* uv edge */ - {GL_ELEMENT_ARRAY_BUFFER, 4}, - /* triangles, 1 point since we are allocating from tottriangle points, which account for all points */ - {GL_ELEMENT_ARRAY_BUFFER, 1}, -}; - -#define MAX_GPU_ATTRIB_DATA 32 - -#define BUFFER_OFFSET(n) ((GLubyte *)NULL + (n)) - -static GPUBufferState GLStates = 0; -static GPUAttrib attribData[MAX_GPU_ATTRIB_DATA] = { { -1, 0, 0 } }; - static ThreadMutex buffer_mutex = BLI_MUTEX_INITIALIZER; /* multires global buffer, can be used for many grids having the same grid size */ typedef struct GridCommonGPUBuffer { - GPUBuffer *mres_buffer; + Gwn_IndexBuf *mres_buffer; int mres_prev_gridsize; - GLenum mres_prev_index_type; unsigned mres_prev_totquad; } GridCommonGPUBuffer; -void GPU_buffer_material_finalize(GPUDrawObject *gdo, GPUBufferMaterial *matinfo, int totmat) -{ - int i, curmat, curelement; - - /* count the number of materials used by this DerivedMesh */ - for (i = 0; i < totmat; i++) { - if (matinfo[i].totelements > 0) - gdo->totmaterial++; - } - - /* allocate an array of materials used by this DerivedMesh */ - gdo->materials = MEM_mallocN(sizeof(GPUBufferMaterial) * gdo->totmaterial, - "GPUDrawObject.materials"); - - /* initialize the materials array */ - for (i = 0, curmat = 0, curelement = 0; i < totmat; i++) { - if (matinfo[i].totelements > 0) { - gdo->materials[curmat] = matinfo[i]; - gdo->materials[curmat].start = curelement; - gdo->materials[curmat].mat_nr = i; - gdo->materials[curmat].polys = MEM_mallocN(sizeof(int) * matinfo[i].totpolys, "GPUBufferMaterial.polys"); - - curelement += matinfo[i].totelements; - curmat++; - } - } - - MEM_freeN(matinfo); -} - - -/* stores recently-deleted buffers so that new buffers won't have to - * be recreated as often - * - * only one instance of this pool is created, stored in - * gpu_buffer_pool - * - * note that the number of buffers in the pool is usually limited to - * MAX_FREE_GPU_BUFFERS, but this limit may be exceeded temporarily - * when a GPUBuffer is released outside the main thread; due to OpenGL - * restrictions it cannot be immediately released - */ -typedef struct GPUBufferPool { - /* number of allocated buffers stored */ - int totbuf; - /* actual allocated length of the arrays */ - int maxsize; - GPUBuffer **buffers; -} GPUBufferPool; -#define MAX_FREE_GPU_BUFFERS 8 - -/* create a new GPUBufferPool */ -static GPUBufferPool *gpu_buffer_pool_new(void) -{ - GPUBufferPool *pool; - - pool = MEM_callocN(sizeof(GPUBufferPool), "GPUBuffer_Pool"); - - pool->maxsize = MAX_FREE_GPU_BUFFERS; - pool->buffers = MEM_mallocN(sizeof(*pool->buffers) * pool->maxsize, - "GPUBufferPool.buffers"); - return pool; -} - -/* remove a GPUBuffer from the pool (does not free the GPUBuffer) */ -static void gpu_buffer_pool_remove_index(GPUBufferPool *pool, int index) -{ - int i; - - if (!pool || index < 0 || index >= pool->totbuf) - return; - - /* shift entries down, overwriting the buffer at `index' */ - for (i = index; i < pool->totbuf - 1; i++) - pool->buffers[i] = pool->buffers[i + 1]; - - /* clear the last entry */ - if (pool->totbuf > 0) - pool->buffers[pool->totbuf - 1] = NULL; - - pool->totbuf--; -} - -/* delete the last entry in the pool */ -static void gpu_buffer_pool_delete_last(GPUBufferPool *pool) -{ - GPUBuffer *last; - - if (pool->totbuf <= 0) - return; - - /* get the last entry */ - if (!(last = pool->buffers[pool->totbuf - 1])) - return; - - /* delete the buffer's data */ - glDeleteBuffers(1, &last->id); - - /* delete the buffer and remove from pool */ - MEM_freeN(last); - pool->totbuf--; - pool->buffers[pool->totbuf] = NULL; -} - -/* free a GPUBufferPool; also frees the data in the pool's - * GPUBuffers */ -static void gpu_buffer_pool_free(GPUBufferPool *pool) -{ - if (!pool) - return; - - while (pool->totbuf) - gpu_buffer_pool_delete_last(pool); - - MEM_freeN(pool->buffers); - MEM_freeN(pool); -} - -static void gpu_buffer_pool_free_unused(GPUBufferPool *pool) -{ - if (!pool) - return; - - BLI_mutex_lock(&buffer_mutex); - - while (pool->totbuf) - gpu_buffer_pool_delete_last(pool); - - BLI_mutex_unlock(&buffer_mutex); -} - -static GPUBufferPool *gpu_buffer_pool = NULL; -static GPUBufferPool *gpu_get_global_buffer_pool(void) -{ - /* initialize the pool */ - if (!gpu_buffer_pool) - gpu_buffer_pool = gpu_buffer_pool_new(); - - return gpu_buffer_pool; -} - -void GPU_global_buffer_pool_free(void) -{ - gpu_buffer_pool_free(gpu_buffer_pool); - gpu_buffer_pool = NULL; -} - -void GPU_global_buffer_pool_free_unused(void) -{ - gpu_buffer_pool_free_unused(gpu_buffer_pool); -} - -/* get a GPUBuffer of at least `size' bytes; uses one from the buffer - * pool if possible, otherwise creates a new one - * - * Thread-unsafe version for internal usage only. - */ -static GPUBuffer *gpu_buffer_alloc_intern(size_t size) -{ - GPUBufferPool *pool; - GPUBuffer *buf; - int i, bestfit = -1; - size_t bufsize; - - /* bad case, leads to leak of buf since buf->pointer will allocate - * NULL, leading to return without cleanup. In any case better detect early - * psy-fi */ - if (size == 0) - return NULL; - - pool = gpu_get_global_buffer_pool(); - - /* not sure if this buffer pool code has been profiled much, - * seems to me that the graphics driver and system memory - * management might do this stuff anyway. --nicholas - */ - - /* check the global buffer pool for a recently-deleted buffer - * that is at least as big as the request, but not more than - * twice as big */ - for (i = 0; i < pool->totbuf; i++) { - bufsize = pool->buffers[i]->size; - - /* check for an exact size match */ - if (bufsize == size) { - bestfit = i; - break; - } - /* smaller buffers won't fit data and buffers at least - * twice as big are a waste of memory */ - else if (bufsize > size && size > (bufsize / 2)) { - /* is it closer to the required size than the - * last appropriate buffer found. try to save - * memory */ - if (bestfit == -1 || pool->buffers[bestfit]->size > bufsize) { - bestfit = i; - } - } - } - - /* if an acceptable buffer was found in the pool, remove it - * from the pool and return it */ - if (bestfit != -1) { - buf = pool->buffers[bestfit]; - gpu_buffer_pool_remove_index(pool, bestfit); - return buf; - } - - /* no acceptable buffer found in the pool, create a new one */ - buf = MEM_callocN(sizeof(GPUBuffer), "GPUBuffer"); - buf->size = size; - - glGenBuffers(1, &buf->id); - glBindBuffer(GL_ARRAY_BUFFER, buf->id); - glBufferData(GL_ARRAY_BUFFER, size, NULL, GL_STATIC_DRAW); - glBindBuffer(GL_ARRAY_BUFFER, 0); - - return buf; -} - -/* Same as above, but safe for threading. */ -GPUBuffer *GPU_buffer_alloc(size_t size) -{ - GPUBuffer *buffer; - - if (size == 0) { - /* Early out, no lock needed in this case. */ - return NULL; - } - - BLI_mutex_lock(&buffer_mutex); - buffer = gpu_buffer_alloc_intern(size); - BLI_mutex_unlock(&buffer_mutex); - - return buffer; -} - -/* release a GPUBuffer; does not free the actual buffer or its data, - * but rather moves it to the pool of recently-freed buffers for - * possible re-use - * - * Thread-unsafe version for internal usage only. - */ -static void gpu_buffer_free_intern(GPUBuffer *buffer) -{ - GPUBufferPool *pool; - int i; - - if (!buffer) - return; - - pool = gpu_get_global_buffer_pool(); - - /* free the last used buffer in the queue if no more space, but only - * if we are in the main thread. for e.g. rendering or baking it can - * happen that we are in other thread and can't call OpenGL, in that - * case cleanup will be done GPU_buffer_pool_free_unused */ - if (BLI_thread_is_main()) { - /* in main thread, safe to decrease size of pool back - * down to MAX_FREE_GPU_BUFFERS */ - while (pool->totbuf >= MAX_FREE_GPU_BUFFERS) - gpu_buffer_pool_delete_last(pool); - } - else { - /* outside of main thread, can't safely delete the - * buffer, so increase pool size */ - if (pool->maxsize == pool->totbuf) { - pool->maxsize += MAX_FREE_GPU_BUFFERS; - pool->buffers = MEM_reallocN(pool->buffers, - sizeof(GPUBuffer *) * pool->maxsize); - } - } - - /* shift pool entries up by one */ - for (i = pool->totbuf; i > 0; i--) - pool->buffers[i] = pool->buffers[i - 1]; - - /* insert the buffer into the beginning of the pool */ - pool->buffers[0] = buffer; - pool->totbuf++; -} - -/* Same as above, but safe for threading. */ -void GPU_buffer_free(GPUBuffer *buffer) -{ - if (!buffer) { - /* Early output, no need to lock in this case, */ - return; - } - - BLI_mutex_lock(&buffer_mutex); - gpu_buffer_free_intern(buffer); - BLI_mutex_unlock(&buffer_mutex); -} - -void GPU_drawobject_free(DerivedMesh *dm) -{ - GPUDrawObject *gdo; - int i; - - if (!dm || !(gdo = dm->drawObject)) - return; - - for (i = 0; i < gdo->totmaterial; i++) { - if (gdo->materials[i].polys) - MEM_freeN(gdo->materials[i].polys); - } - - MEM_freeN(gdo->materials); - if (gdo->vert_points) - MEM_freeN(gdo->vert_points); -#ifdef USE_GPU_POINT_LINK - MEM_freeN(gdo->vert_points_mem); -#endif - GPU_buffer_free(gdo->points); - GPU_buffer_free(gdo->normals); - GPU_buffer_free(gdo->uv); - GPU_buffer_free(gdo->uv_tex); - GPU_buffer_free(gdo->colors); - GPU_buffer_free(gdo->edges); - GPU_buffer_free(gdo->uvedges); - GPU_buffer_free(gdo->triangles); - - MEM_freeN(gdo); - dm->drawObject = NULL; -} - -static GPUBuffer *gpu_try_realloc(GPUBufferPool *pool, GPUBuffer *buffer, size_t size) -{ - /* try freeing an entry from the pool - * and reallocating the buffer */ - gpu_buffer_free_intern(buffer); - - buffer = NULL; - - while (pool->totbuf && !buffer) { - gpu_buffer_pool_delete_last(pool); - buffer = gpu_buffer_alloc_intern(size); - } - - return buffer; -} - -static GPUBuffer *gpu_buffer_setup(DerivedMesh *dm, GPUDrawObject *object, - int type, void *user, GPUBuffer *buffer) -{ - GPUBufferPool *pool; - float *varray; - int *mat_orig_to_new; - int i; - const GPUBufferTypeSettings *ts = &gpu_buffer_type_settings[type]; - GLenum target = ts->gl_buffer_type; - size_t size = gpu_buffer_size_from_type(dm, type); - GLboolean uploaded; - - pool = gpu_get_global_buffer_pool(); - - BLI_mutex_lock(&buffer_mutex); - - /* alloc a GPUBuffer; fall back to legacy mode on failure */ - if (!buffer) { - if (!(buffer = gpu_buffer_alloc_intern(size))) { - BLI_mutex_unlock(&buffer_mutex); - return NULL; - } - } - - mat_orig_to_new = MEM_mallocN(sizeof(*mat_orig_to_new) * dm->totmat, - "GPU_buffer_setup.mat_orig_to_new"); - for (i = 0; i < object->totmaterial; i++) { - /* map from original material index to new - * GPUBufferMaterial index */ - mat_orig_to_new[object->materials[i].mat_nr] = i; - } - - /* bind the buffer and discard previous data, - * avoids stalling gpu */ - glBindBuffer(target, buffer->id); - glBufferData(target, buffer->size, NULL, GL_STATIC_DRAW); - - /* attempt to map the buffer */ - if (!(varray = glMapBuffer(target, GL_WRITE_ONLY))) { - buffer = gpu_try_realloc(pool, buffer, size); - - /* allocation still failed; unfortunately we need to exit */ - if (!(buffer && (varray = glMapBuffer(target, GL_WRITE_ONLY)))) { - if (buffer) - gpu_buffer_free_intern(buffer); - BLI_mutex_unlock(&buffer_mutex); - return NULL; - } - } - - uploaded = GL_FALSE; - - /* attempt to upload the data to the VBO */ - while (uploaded == GL_FALSE) { - dm->copy_gpu_data(dm, type, varray, mat_orig_to_new, user); - /* glUnmapBuffer returns GL_FALSE if - * the data store is corrupted; retry - * in that case */ - uploaded = glUnmapBuffer(target); - } - glBindBuffer(target, 0); - - MEM_freeN(mat_orig_to_new); - - BLI_mutex_unlock(&buffer_mutex); - - return buffer; -} - -/* get the GPUDrawObject buffer associated with a type */ -static GPUBuffer **gpu_drawobject_buffer_from_type(GPUDrawObject *gdo, GPUBufferType type) -{ - switch (type) { - case GPU_BUFFER_VERTEX: - return &gdo->points; - case GPU_BUFFER_NORMAL: - return &gdo->normals; - case GPU_BUFFER_COLOR: - return &gdo->colors; - case GPU_BUFFER_UV: - return &gdo->uv; - case GPU_BUFFER_UV_TEXPAINT: - return &gdo->uv_tex; - case GPU_BUFFER_EDGE: - return &gdo->edges; - case GPU_BUFFER_UVEDGE: - return &gdo->uvedges; - case GPU_BUFFER_TRIANGLES: - return &gdo->triangles; - default: - return NULL; - } -} - -/* get the amount of space to allocate for a buffer of a particular type */ -static size_t gpu_buffer_size_from_type(DerivedMesh *dm, GPUBufferType type) -{ - const int components = gpu_buffer_type_settings[type].num_components; - switch (type) { - case GPU_BUFFER_VERTEX: - return sizeof(float) * components * (dm->drawObject->tot_loop_verts + dm->drawObject->tot_loose_point); - case GPU_BUFFER_NORMAL: - return sizeof(short) * components * dm->drawObject->tot_loop_verts; - case GPU_BUFFER_COLOR: - return sizeof(char) * components * dm->drawObject->tot_loop_verts; - case GPU_BUFFER_UV: - return sizeof(float) * components * dm->drawObject->tot_loop_verts; - case GPU_BUFFER_UV_TEXPAINT: - return sizeof(float) * components * dm->drawObject->tot_loop_verts; - case GPU_BUFFER_EDGE: - return sizeof(int) * components * dm->drawObject->totedge; - case GPU_BUFFER_UVEDGE: - return sizeof(int) * components * dm->drawObject->tot_loop_verts; - case GPU_BUFFER_TRIANGLES: - return sizeof(int) * components * dm->drawObject->tot_triangle_point; - default: - return -1; - } -} - -/* call gpu_buffer_setup with settings for a particular type of buffer */ -static GPUBuffer *gpu_buffer_setup_type(DerivedMesh *dm, GPUBufferType type, GPUBuffer *buf) -{ - void *user_data = NULL; - - /* special handling for MCol and UV buffers */ - if (type == GPU_BUFFER_COLOR) { - if (!(user_data = DM_get_loop_data_layer(dm, dm->drawObject->colType))) - return NULL; - } - else if (ELEM(type, GPU_BUFFER_UV, GPU_BUFFER_UV_TEXPAINT)) { - if (!DM_get_loop_data_layer(dm, CD_MLOOPUV)) - return NULL; - } - - buf = gpu_buffer_setup(dm, dm->drawObject, type, user_data, buf); - - return buf; -} - -/* get the buffer of `type', initializing the GPUDrawObject and - * buffer if needed */ -static GPUBuffer *gpu_buffer_setup_common(DerivedMesh *dm, GPUBufferType type, bool update) -{ - GPUBuffer **buf; - - if (!dm->drawObject) - dm->drawObject = dm->gpuObjectNew(dm); - - buf = gpu_drawobject_buffer_from_type(dm->drawObject, type); - if (!(*buf)) - *buf = gpu_buffer_setup_type(dm, type, NULL); - else if (update) - *buf = gpu_buffer_setup_type(dm, type, *buf); - - return *buf; -} - -void GPU_vertex_setup(DerivedMesh *dm) -{ - if (!gpu_buffer_setup_common(dm, GPU_BUFFER_VERTEX, false)) - return; - - glEnableClientState(GL_VERTEX_ARRAY); - glBindBuffer(GL_ARRAY_BUFFER, dm->drawObject->points->id); - glVertexPointer(3, GL_FLOAT, 0, 0); - - GLStates |= GPU_BUFFER_VERTEX_STATE; -} - -void GPU_normal_setup(DerivedMesh *dm) -{ - if (!gpu_buffer_setup_common(dm, GPU_BUFFER_NORMAL, false)) - return; - - glEnableClientState(GL_NORMAL_ARRAY); - glBindBuffer(GL_ARRAY_BUFFER, dm->drawObject->normals->id); - glNormalPointer(GL_SHORT, 4 * sizeof(short), 0); - - GLStates |= GPU_BUFFER_NORMAL_STATE; -} - -void GPU_uv_setup(DerivedMesh *dm) -{ - if (!gpu_buffer_setup_common(dm, GPU_BUFFER_UV, false)) - return; - - glEnableClientState(GL_TEXTURE_COORD_ARRAY); - glBindBuffer(GL_ARRAY_BUFFER, dm->drawObject->uv->id); - glTexCoordPointer(2, GL_FLOAT, 0, 0); - - GLStates |= GPU_BUFFER_TEXCOORD_UNIT_0_STATE; -} - -void GPU_texpaint_uv_setup(DerivedMesh *dm) -{ - if (!gpu_buffer_setup_common(dm, GPU_BUFFER_UV_TEXPAINT, false)) - return; - - glEnableClientState(GL_TEXTURE_COORD_ARRAY); - glBindBuffer(GL_ARRAY_BUFFER, dm->drawObject->uv_tex->id); - glTexCoordPointer(2, GL_FLOAT, 4 * sizeof(float), 0); - glClientActiveTexture(GL_TEXTURE2); - glEnableClientState(GL_TEXTURE_COORD_ARRAY); - glTexCoordPointer(2, GL_FLOAT, 4 * sizeof(float), BUFFER_OFFSET(2 * sizeof(float))); - glClientActiveTexture(GL_TEXTURE0); - - GLStates |= GPU_BUFFER_TEXCOORD_UNIT_0_STATE | GPU_BUFFER_TEXCOORD_UNIT_2_STATE; -} - - -void GPU_color_setup(DerivedMesh *dm, int colType) -{ - bool update = false; - - if (!dm->drawObject) { - /* XXX Not really nice, but we need a valid gpu draw object to set the colType... - * Else we would have to add a new param to gpu_buffer_setup_common. */ - dm->drawObject = dm->gpuObjectNew(dm); - dm->dirty &= ~DM_DIRTY_MCOL_UPDATE_DRAW; - dm->drawObject->colType = colType; - } - /* In paint mode, dm may stay the same during stroke, however we still want to update colors! - * Also check in case we changed color type (i.e. which MCol cdlayer we use). */ - else if ((dm->dirty & DM_DIRTY_MCOL_UPDATE_DRAW) || (colType != dm->drawObject->colType)) { - update = true; - dm->dirty &= ~DM_DIRTY_MCOL_UPDATE_DRAW; - dm->drawObject->colType = colType; - } - - if (!gpu_buffer_setup_common(dm, GPU_BUFFER_COLOR, update)) - return; - - glEnableClientState(GL_COLOR_ARRAY); - glBindBuffer(GL_ARRAY_BUFFER, dm->drawObject->colors->id); - glColorPointer(4, GL_UNSIGNED_BYTE, 0, 0); - - GLStates |= GPU_BUFFER_COLOR_STATE; -} - -void GPU_buffer_bind_as_color(GPUBuffer *buffer) -{ - glEnableClientState(GL_COLOR_ARRAY); - glBindBuffer(GL_ARRAY_BUFFER, buffer->id); - glColorPointer(4, GL_UNSIGNED_BYTE, 0, 0); - - GLStates |= GPU_BUFFER_COLOR_STATE; -} - - -void GPU_edge_setup(DerivedMesh *dm) -{ - if (!gpu_buffer_setup_common(dm, GPU_BUFFER_EDGE, false)) - return; - - if (!gpu_buffer_setup_common(dm, GPU_BUFFER_VERTEX, false)) - return; - - glEnableClientState(GL_VERTEX_ARRAY); - glBindBuffer(GL_ARRAY_BUFFER, dm->drawObject->points->id); - glVertexPointer(3, GL_FLOAT, 0, 0); - - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, dm->drawObject->edges->id); - - GLStates |= (GPU_BUFFER_VERTEX_STATE | GPU_BUFFER_ELEMENT_STATE); -} - -void GPU_uvedge_setup(DerivedMesh *dm) -{ - if (!gpu_buffer_setup_common(dm, GPU_BUFFER_UVEDGE, false)) - return; - - glEnableClientState(GL_VERTEX_ARRAY); - glBindBuffer(GL_ARRAY_BUFFER, dm->drawObject->uvedges->id); - glVertexPointer(2, GL_FLOAT, 0, 0); - - GLStates |= GPU_BUFFER_VERTEX_STATE; -} - -void GPU_triangle_setup(struct DerivedMesh *dm) -{ - if (!gpu_buffer_setup_common(dm, GPU_BUFFER_TRIANGLES, false)) - return; - - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, dm->drawObject->triangles->id); - GLStates |= GPU_BUFFER_ELEMENT_STATE; -} - -static int gpu_typesize(int type) -{ - switch (type) { - case GL_FLOAT: - return sizeof(float); - case GL_INT: - return sizeof(int); - case GL_UNSIGNED_INT: - return sizeof(unsigned int); - case GL_BYTE: - return sizeof(char); - case GL_UNSIGNED_BYTE: - return sizeof(unsigned char); - default: - return 0; - } -} - -int GPU_attrib_element_size(GPUAttrib data[], int numdata) -{ - int i, elementsize = 0; - - for (i = 0; i < numdata; i++) { - int typesize = gpu_typesize(data[i].type); - if (typesize != 0) - elementsize += typesize * data[i].size; - } - return elementsize; -} - -void GPU_interleaved_attrib_setup(GPUBuffer *buffer, GPUAttrib data[], int numdata, int element_size) -{ - int i; - int elementsize; - size_t offset = 0; - - for (i = 0; i < MAX_GPU_ATTRIB_DATA; i++) { - if (attribData[i].index != -1) { - glDisableVertexAttribArray(attribData[i].index); - } - else - break; - } - if (element_size == 0) - elementsize = GPU_attrib_element_size(data, numdata); - else - elementsize = element_size; - - glBindBuffer(GL_ARRAY_BUFFER, buffer->id); - - for (i = 0; i < numdata; i++) { - glEnableVertexAttribArray(data[i].index); - int info = 0; - if (data[i].type == GL_UNSIGNED_BYTE) { - info |= GPU_ATTR_INFO_SRGB; - } - glUniform1i(data[i].info_index, info); - - glVertexAttribPointer(data[i].index, data[i].size, data[i].type, - GL_TRUE, elementsize, BUFFER_OFFSET(offset)); - offset += data[i].size * gpu_typesize(data[i].type); - - attribData[i].index = data[i].index; - attribData[i].size = data[i].size; - attribData[i].type = data[i].type; - } - - attribData[numdata].index = -1; -} - -void GPU_interleaved_attrib_unbind(void) -{ - int i; - for (i = 0; i < MAX_GPU_ATTRIB_DATA; i++) { - if (attribData[i].index != -1) { - glDisableVertexAttribArray(attribData[i].index); - } - else - break; - } - attribData[0].index = -1; -} - -void GPU_buffers_unbind(void) -{ - int i; - - if (GLStates & GPU_BUFFER_VERTEX_STATE) - glDisableClientState(GL_VERTEX_ARRAY); - if (GLStates & GPU_BUFFER_NORMAL_STATE) - glDisableClientState(GL_NORMAL_ARRAY); - if (GLStates & GPU_BUFFER_TEXCOORD_UNIT_0_STATE) - glDisableClientState(GL_TEXTURE_COORD_ARRAY); - if (GLStates & GPU_BUFFER_TEXCOORD_UNIT_2_STATE) { - glClientActiveTexture(GL_TEXTURE2); - glDisableClientState(GL_TEXTURE_COORD_ARRAY); - glClientActiveTexture(GL_TEXTURE0); - } - if (GLStates & GPU_BUFFER_COLOR_STATE) - glDisableClientState(GL_COLOR_ARRAY); - if (GLStates & GPU_BUFFER_ELEMENT_STATE) - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); - - GLStates &= ~(GPU_BUFFER_VERTEX_STATE | GPU_BUFFER_NORMAL_STATE | - GPU_BUFFER_TEXCOORD_UNIT_0_STATE | GPU_BUFFER_TEXCOORD_UNIT_2_STATE | - GPU_BUFFER_COLOR_STATE | GPU_BUFFER_ELEMENT_STATE); - - for (i = 0; i < MAX_GPU_ATTRIB_DATA; i++) { - if (attribData[i].index != -1) { - glDisableVertexAttribArray(attribData[i].index); - } - else - break; - } - attribData[0].index = -1; - - glBindBuffer(GL_ARRAY_BUFFER, 0); -} - -void GPU_color_switch(int mode) -{ - if (mode) { - if (!(GLStates & GPU_BUFFER_COLOR_STATE)) - glEnableClientState(GL_COLOR_ARRAY); - GLStates |= GPU_BUFFER_COLOR_STATE; - } - else { - if (GLStates & GPU_BUFFER_COLOR_STATE) - glDisableClientState(GL_COLOR_ARRAY); - GLStates &= ~GPU_BUFFER_COLOR_STATE; - } -} - -static int gpu_binding_type_gl[] = -{ - GL_ARRAY_BUFFER, - GL_ELEMENT_ARRAY_BUFFER -}; - -void *GPU_buffer_lock(GPUBuffer *buffer, GPUBindingType binding) -{ - float *varray; - int bindtypegl; - - if (!buffer) - return 0; - - bindtypegl = gpu_binding_type_gl[binding]; - glBindBuffer(bindtypegl, buffer->id); - varray = glMapBuffer(bindtypegl, GL_WRITE_ONLY); - return varray; -} - -void *GPU_buffer_lock_stream(GPUBuffer *buffer, GPUBindingType binding) -{ - float *varray; - int bindtypegl; - - if (!buffer) - return 0; - - bindtypegl = gpu_binding_type_gl[binding]; - glBindBuffer(bindtypegl, buffer->id); - /* discard previous data, avoid stalling gpu */ - glBufferData(bindtypegl, buffer->size, 0, GL_STREAM_DRAW); - varray = glMapBuffer(bindtypegl, GL_WRITE_ONLY); - return varray; -} - -void GPU_buffer_unlock(GPUBuffer *UNUSED(buffer), GPUBindingType binding) -{ - int bindtypegl = gpu_binding_type_gl[binding]; - /* note: this operation can fail, could return - * an error code from this function? */ - glUnmapBuffer(bindtypegl); - glBindBuffer(bindtypegl, 0); -} - -void GPU_buffer_bind(GPUBuffer *buffer, GPUBindingType binding) -{ - int bindtypegl = gpu_binding_type_gl[binding]; - glBindBuffer(bindtypegl, buffer->id); -} - -void GPU_buffer_unbind(GPUBuffer *UNUSED(buffer), GPUBindingType binding) -{ - int bindtypegl = gpu_binding_type_gl[binding]; - glBindBuffer(bindtypegl, 0); -} - -/* used for drawing edges */ -void GPU_buffer_draw_elements(GPUBuffer *UNUSED(elements), unsigned int mode, int start, int count) -{ - glDrawElements(mode, count, GL_UNSIGNED_INT, BUFFER_OFFSET(start * sizeof(unsigned int))); -} - - /* XXX: the rest of the code in this file is used for optimized PBVH * drawing and doesn't interact at all with the buffer code above */ -/* Convenience struct for building the VBO. */ -typedef struct { - float co[3]; - short no[3]; - - /* inserting this to align the 'color' field to a four-byte - * boundary; drastically increases viewport performance on my - * drivers (Gallium/Radeon) --nicholasbishop */ - char pad[2]; - - unsigned char color[3]; -} VertexBufferFormat; - struct GPU_PBVH_Buffers { - /* opengl buffer handles */ - GPUBuffer *vert_buf, *index_buf, *index_buf_fast; - GLenum index_type; + Gwn_IndexBuf *index_buf, *index_buf_fast; + Gwn_VertBuf *vert_buf; - int *baseelemarray; - void **baseindex; + Gwn_Batch *triangles; + Gwn_Batch *triangles_fast; /* mesh pointers in case buffer allocation fails */ const MPoly *mpoly; @@ -995,10 +108,73 @@ struct GPU_PBVH_Buffers { bool show_diffuse_color; bool show_mask; - bool use_matcaps; float diffuse_color[4]; }; +static struct { + uint pos, nor, col; +} g_vbo_id = {0}; + +static void gpu_material_diffuse_get(int UNUSED(nr), float diff[4]) +{ + /* TODO: sculpt diffuse color option not supported in 2.8 yet. */ + diff[0] = 0.8f; + diff[1] = 0.8f; + diff[2] = 0.8f; + diff[3] = 1.0f; +} + +/* 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) +{ + 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) +{ + /* force flushing to the GPU */ + if (buffers->vert_buf->data) { + GWN_vertbuf_use(buffers->vert_buf); + } + + if (buffers->triangles == NULL) { + buffers->triangles = GWN_batch_create( + GWN_PRIM_TRIS, buffers->vert_buf, + /* can be NULL */ + buffers->index_buf); + } + + if ((buffers->triangles_fast == NULL) && buffers->index_buf_fast) { + buffers->triangles_fast = GWN_batch_create( + GWN_PRIM_TRIS, buffers->vert_buf, + /* can be NULL */ + buffers->index_buf_fast); + } +} + static float gpu_color_from_mask(float mask) { return 1.0f - mask * 0.75f; @@ -1040,25 +216,20 @@ void GPU_pbvh_mesh_buffers_update( { const bool show_diffuse_color = (update_flags & GPU_PBVH_BUFFERS_SHOW_DIFFUSE_COLOR) != 0; const bool show_mask = (update_flags & GPU_PBVH_BUFFERS_SHOW_MASK) != 0; - VertexBufferFormat *vert_data; - int i; buffers->vmask = vmask; buffers->show_diffuse_color = show_diffuse_color; buffers->show_mask = show_mask; - buffers->use_matcaps = GPU_material_use_matcaps_get(); { int totelem = (buffers->smooth ? totvert : (buffers->tot_tri * 3)); float diffuse_color[4] = {0.8f, 0.8f, 0.8f, 0.8f}; - if (buffers->use_matcaps) - diffuse_color[0] = diffuse_color[1] = diffuse_color[2] = 1.0; - else if (show_diffuse_color) { + if (show_diffuse_color) { const MLoopTri *lt = &buffers->looptri[buffers->face_indices[0]]; const MPoly *mp = &buffers->mpoly[lt->poly]; - GPU_material_diffuse_get(mp->mat_nr + 1, diffuse_color); + gpu_material_diffuse_get(mp->mat_nr + 1, diffuse_color); } copy_v4_v4(buffers->diffuse_color, diffuse_color); @@ -1067,35 +238,29 @@ void GPU_pbvh_mesh_buffers_update( rgba_float_to_uchar(diffuse_color_ub, diffuse_color); /* Build VBO */ - if (buffers->vert_buf) - GPU_buffer_free(buffers->vert_buf); - buffers->vert_buf = GPU_buffer_alloc(sizeof(VertexBufferFormat) * totelem); - vert_data = GPU_buffer_lock(buffers->vert_buf, GPU_BINDING_ARRAY); - - if (vert_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 (i = 0; i < totvert; ++i) { + for (uint i = 0; i < totvert; ++i) { const MVert *v = &mvert[vert_indices[i]]; - VertexBufferFormat *out = vert_data + i; - - copy_v3_v3(out->co, v->co); - memcpy(out->no, v->no, sizeof(short) * 3); + 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 (i = 0; i < buffers->face_indices_len; i++) { + for (uint i = 0; i < buffers->face_indices_len; i++) { const MLoopTri *lt = &buffers->looptri[buffers->face_indices[i]]; for (uint j = 0; j < 3; j++) { - VertexBufferFormat *out = vert_data + face_vert_indices[i][j]; - + int vidx = face_vert_indices[i][j]; if (vmask && show_mask) { - uint v_index = buffers->mloop[lt->tri[j]].v; - gpu_color_from_mask_copy(vmask[v_index], diffuse_color, out->color); + 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, g_vbo_id.col, vidx, color_ub); } else { - copy_v3_v3_uchar(out->color, diffuse_color_ub); + GWN_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.col, vidx, diffuse_color_ub); } } } @@ -1104,8 +269,9 @@ void GPU_pbvh_mesh_buffers_update( /* calculate normal for each polygon only once */ unsigned int mpoly_prev = UINT_MAX; short no[3]; + int vbo_index = 0; - for (i = 0; i < buffers->face_indices_len; ++i) { + for (uint i = 0; i < buffers->face_indices_len; i++) { const MLoopTri *lt = &buffers->looptri[buffers->face_indices[i]]; const unsigned int vtri[3] = { buffers->mloop[lt->tri[0]].v, @@ -1136,22 +302,17 @@ void GPU_pbvh_mesh_buffers_update( for (uint j = 0; j < 3; j++) { const MVert *v = &mvert[vtri[j]]; - VertexBufferFormat *out = vert_data; - copy_v3_v3(out->co, v->co); - copy_v3_v3_short(out->no, no); - copy_v3_v3_uchar(out->color, 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); - vert_data++; + vbo_index++; } } } - GPU_buffer_unlock(buffers->vert_buf, GPU_BINDING_ARRAY); - } - else { - GPU_buffer_free(buffers->vert_buf); - buffers->vert_buf = NULL; + gpu_pbvh_batch_init(buffers); } } @@ -1166,16 +327,20 @@ GPU_PBVH_Buffers *GPU_pbvh_mesh_buffers_build( const int face_indices_len) { GPU_PBVH_Buffers *buffers; - unsigned short *tri_data; - int i, j, tottri; + int i, tottri; buffers = MEM_callocN(sizeof(GPU_PBVH_Buffers), "GPU_Buffers"); - buffers->index_type = GL_UNSIGNED_SHORT; + + /* smooth or flat for all */ +#if 0 buffers->smooth = mpoly[looptri[face_indices[0]].poly].flag & ME_SMOOTH; +#else + /* for DrawManager we dont support mixed smooth/flat */ + buffers->smooth = (mpoly[0].flag & ME_SMOOTH) != 0; +#endif buffers->show_diffuse_color = false; buffers->show_mask = true; - buffers->use_matcaps = false; /* Count the number of visible triangles */ for (i = 0, tottri = 0; i < face_indices_len; ++i) { @@ -1200,35 +365,28 @@ GPU_PBVH_Buffers *GPU_pbvh_mesh_buffers_build( * shading requires separate vertex normals so an index buffer is * can't be used there. */ if (buffers->smooth) { - buffers->index_buf = GPU_buffer_alloc(sizeof(unsigned short) * tottri * 3); - buffers->is_index_buf_global = false; - } - - if (buffers->index_buf) { /* Fill the triangle buffer */ - tri_data = GPU_buffer_lock(buffers->index_buf, GPU_BINDING_INDEX); - if (tri_data) { - for (i = 0; i < face_indices_len; ++i) { - const MLoopTri *lt = &looptri[face_indices[i]]; - - /* Skip hidden faces */ - if (paint_is_face_hidden(lt, mvert, mloop)) - continue; - - for (j = 0; j < 3; ++j) { - *tri_data = face_vert_indices[i][j]; - tri_data++; - } - } - GPU_buffer_unlock(buffers->index_buf, GPU_BINDING_INDEX); + buffers->index_buf = NULL; + Gwn_IndexBufBuilder elb; + GWN_indexbuf_init(&elb, GWN_PRIM_TRIS, tottri, INT_MAX); + + for (i = 0; i < face_indices_len; ++i) { + const MLoopTri *lt = &looptri[face_indices[i]]; + + /* Skip hidden faces */ + if (paint_is_face_hidden(lt, mvert, mloop)) + continue; + + GWN_indexbuf_add_tri_verts(&elb, UNPACK3(face_vert_indices[i])); } - else { - if (!buffers->is_index_buf_global) { - GPU_buffer_free(buffers->index_buf); - } - buffers->index_buf = NULL; - buffers->is_index_buf_global = false; + buffers->index_buf = GWN_indexbuf_build(&elb); + } + else { + if (!buffers->is_index_buf_global) { + GWN_INDEXBUF_DISCARD_SAFE(buffers->index_buf); } + buffers->index_buf = NULL; + buffers->is_index_buf_global = false; } buffers->tot_tri = tottri; @@ -1251,61 +409,59 @@ void GPU_pbvh_grid_buffers_update( { const bool show_diffuse_color = (update_flags & GPU_PBVH_BUFFERS_SHOW_DIFFUSE_COLOR) != 0; const bool show_mask = (update_flags & GPU_PBVH_BUFFERS_SHOW_MASK) != 0; - VertexBufferFormat *vert_data; int i, j, k, x, y; buffers->show_diffuse_color = show_diffuse_color; buffers->show_mask = show_mask; - buffers->use_matcaps = GPU_material_use_matcaps_get(); buffers->smooth = grid_flag_mats[grid_indices[0]].flag & ME_SMOOTH; /* Build VBO */ - if (buffers->vert_buf) { + if (buffers->index_buf) { const int has_mask = key->has_mask; float diffuse_color[4] = {0.8f, 0.8f, 0.8f, 1.0f}; - if (buffers->use_matcaps) - diffuse_color[0] = diffuse_color[1] = diffuse_color[2] = 1.0; - else if (show_diffuse_color) { + if (show_diffuse_color) { const DMFlagMat *flags = &grid_flag_mats[grid_indices[0]]; - GPU_material_diffuse_get(flags->mat_nr + 1, diffuse_color); + gpu_material_diffuse_get(flags->mat_nr + 1, diffuse_color); } copy_v4_v4(buffers->diffuse_color, diffuse_color); - vert_data = GPU_buffer_lock_stream(buffers->vert_buf, GPU_BINDING_ARRAY); - if (vert_data) { + uint vbo_index_offset = 0; + /* Build VBO */ + if (gpu_pbvh_vert_buf_data_set(buffers, totgrid * key->grid_area)) { for (i = 0; i < totgrid; ++i) { - VertexBufferFormat *vd = vert_data; CCGElem *grid = grids[grid_indices[i]]; + int vbo_index = vbo_index_offset; 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); - - copy_v3_v3(vd->co, 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) { - normal_float_to_short_v3(vd->no, CCG_elem_no(key, elem)); + short no_short[3]; + normal_float_to_short_v3(no_short, CCG_elem_no(key, elem)); + GWN_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.nor, vbo_index, no_short); if (has_mask) { + uchar color_ub[3]; if (show_mask) { gpu_color_from_mask_copy(*CCG_elem_mask(key, elem), - diffuse_color, vd->color); + diffuse_color, color_ub); } else { - unit_float_to_uchar_clamp_v3(vd->color, diffuse_color); + unit_float_to_uchar_clamp_v3(color_ub, diffuse_color); } + GWN_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.col, vbo_index, color_ub); } } - vd++; + vbo_index += 1; } } if (!buffers->smooth) { - /* for flat shading, recalc normals and set the last vertex of - * each triangle in the index buffer to have the flat normal as - * that is what opengl will use */ for (j = 0; j < key->grid_size - 1; j++) { for (k = 0; k < key->grid_size - 1; k++) { CCGElem *elems[4] = { @@ -1322,10 +478,13 @@ void GPU_pbvh_grid_buffers_update( CCG_elem_co(key, elems[2]), CCG_elem_co(key, elems[3])); - vd = vert_data + (j + 1) * key->grid_size + k; - normal_float_to_short_v3(vd->no, fno); + 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, g_vbo_id.nor, vbo_index, no_short); if (has_mask) { + uchar color_ub[3]; if (show_mask) { gpu_color_from_mask_quad_copy(key, elems[0], @@ -1333,24 +492,21 @@ void GPU_pbvh_grid_buffers_update( elems[2], elems[3], diffuse_color, - vd->color); + color_ub); } else { - unit_float_to_uchar_clamp_v3(vd->color, diffuse_color); + unit_float_to_uchar_clamp_v3(color_ub, diffuse_color); } + GWN_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.col, vbo_index, color_ub); } } } } - vert_data += key->grid_area; + vbo_index_offset += key->grid_area; } - GPU_buffer_unlock(buffers->vert_buf, GPU_BINDING_ARRAY); - } - else { - GPU_buffer_free(buffers->vert_buf); - buffers->vert_buf = NULL; + gpu_pbvh_batch_init(buffers); } } @@ -1365,57 +521,54 @@ void GPU_pbvh_grid_buffers_update( /* Build the element array buffer of grid indices using either * unsigned shorts or unsigned ints. */ -#define FILL_QUAD_BUFFER(type_, tot_quad_, buffer_) \ +#define FILL_QUAD_BUFFER(max_vert_, tot_quad_, buffer_) \ { \ - type_ *tri_data; \ int offset = 0; \ int i, j, k; \ - buffer_ = GPU_buffer_alloc(sizeof(type_) * (tot_quad_) * 6); \ + \ + Gwn_IndexBufBuilder elb; \ + GWN_indexbuf_init( \ + &elb, GWN_PRIM_TRIS, tot_quad_ * 2, max_vert_); \ \ /* Fill the buffer */ \ - tri_data = GPU_buffer_lock(buffer_, GPU_BINDING_INDEX); \ - if (tri_data) { \ - for (i = 0; i < totgrid; ++i) { \ - BLI_bitmap *gh = NULL; \ - if (grid_hidden) \ - gh = grid_hidden[(grid_indices)[i]]; \ + for (i = 0; i < totgrid; ++i) { \ + BLI_bitmap *gh = NULL; \ + if (grid_hidden) \ + gh = grid_hidden[(grid_indices)[i]]; \ \ - for (j = 0; j < gridsize - 1; ++j) { \ - for (k = 0; k < gridsize - 1; ++k) { \ - /* Skip hidden grid face */ \ - if (gh && \ - paint_is_grid_face_hidden(gh, \ - gridsize, k, j)) \ - continue; \ - \ - *(tri_data++) = offset + j * gridsize + k + 1; \ - *(tri_data++) = offset + j * gridsize + k; \ - *(tri_data++) = offset + (j + 1) * gridsize + k; \ - \ - *(tri_data++) = offset + (j + 1) * gridsize + k + 1; \ - *(tri_data++) = offset + j * gridsize + k + 1; \ - *(tri_data++) = offset + (j + 1) * gridsize + k; \ - } \ - } \ - \ - offset += gridsize * gridsize; \ + for (j = 0; j < gridsize - 1; ++j) { \ + for (k = 0; k < gridsize - 1; ++k) { \ + /* Skip hidden grid face */ \ + if (gh && paint_is_grid_face_hidden( \ + gh, gridsize, k, j)) \ + { \ + continue; \ + } \ + GWN_indexbuf_add_generic_vert(&elb, offset + j * gridsize + k + 1); \ + GWN_indexbuf_add_generic_vert(&elb, offset + j * gridsize + k); \ + GWN_indexbuf_add_generic_vert(&elb, offset + (j + 1) * gridsize + k); \ + \ + GWN_indexbuf_add_generic_vert(&elb, offset + (j + 1) * gridsize + k + 1); \ + GWN_indexbuf_add_generic_vert(&elb, offset + j * gridsize + k + 1); \ + GWN_indexbuf_add_generic_vert(&elb, offset + (j + 1) * gridsize + k); \ + } \ } \ - GPU_buffer_unlock(buffer_, GPU_BINDING_INDEX); \ - } \ - else { \ - GPU_buffer_free(buffer_); \ - (buffer_) = NULL; \ + \ + offset += gridsize * gridsize; \ } \ + buffer_ = GWN_indexbuf_build(&elb); \ } (void)0 /* end FILL_QUAD_BUFFER */ -static GPUBuffer *gpu_get_grid_buffer( - int gridsize, GLenum *index_type, unsigned *totquad, GridCommonGPUBuffer **grid_common_gpu_buffer) +static Gwn_IndexBuf *gpu_get_grid_buffer( + int gridsize, unsigned *totquad, GridCommonGPUBuffer **grid_common_gpu_buffer, + /* remove this arg when gawain gets base-vertex support! */ + int totgrid) { /* used in the FILL_QUAD_BUFFER macro */ BLI_bitmap * const *grid_hidden = NULL; const int *grid_indices = NULL; - int totgrid = 1; + // int totgrid = 1; GridCommonGPUBuffer *gridbuff = *grid_common_gpu_buffer; @@ -1423,65 +576,48 @@ static GPUBuffer *gpu_get_grid_buffer( *grid_common_gpu_buffer = gridbuff = MEM_mallocN(sizeof(GridCommonGPUBuffer), __func__); gridbuff->mres_buffer = NULL; gridbuff->mres_prev_gridsize = -1; - gridbuff->mres_prev_index_type = 0; gridbuff->mres_prev_totquad = 0; } /* VBO is already built */ if (gridbuff->mres_buffer && gridbuff->mres_prev_gridsize == gridsize) { - *index_type = gridbuff->mres_prev_index_type; *totquad = gridbuff->mres_prev_totquad; return gridbuff->mres_buffer; } /* we can't reuse old, delete the existing buffer */ else if (gridbuff->mres_buffer) { - GPU_buffer_free(gridbuff->mres_buffer); + GWN_indexbuf_discard(gridbuff->mres_buffer); + gridbuff->mres_buffer = NULL; } /* Build new VBO */ - *totquad = (gridsize - 1) * (gridsize - 1); + *totquad = (gridsize - 1) * (gridsize - 1) * totgrid; + int max_vert = gridsize * gridsize * totgrid; - if (gridsize * gridsize < USHRT_MAX) { - *index_type = GL_UNSIGNED_SHORT; - FILL_QUAD_BUFFER(unsigned short, *totquad, gridbuff->mres_buffer); - } - else { - *index_type = GL_UNSIGNED_INT; - FILL_QUAD_BUFFER(unsigned int, *totquad, gridbuff->mres_buffer); - } + FILL_QUAD_BUFFER(max_vert, *totquad, gridbuff->mres_buffer); gridbuff->mres_prev_gridsize = gridsize; - gridbuff->mres_prev_index_type = *index_type; gridbuff->mres_prev_totquad = *totquad; return gridbuff->mres_buffer; } -#define FILL_FAST_BUFFER(type_) \ +#define FILL_FAST_BUFFER() \ { \ - type_ *buffer; \ - buffers->index_buf_fast = GPU_buffer_alloc(sizeof(type_) * 6 * totgrid); \ - buffer = GPU_buffer_lock(buffers->index_buf_fast, GPU_BINDING_INDEX); \ - if (buffer) { \ - int i; \ - for (i = 0; i < totgrid; i++) { \ - int currentquad = i * 6; \ - buffer[currentquad] = i * gridsize * gridsize + gridsize - 1; \ - buffer[currentquad + 1] = i * gridsize * gridsize; \ - buffer[currentquad + 2] = (i + 1) * gridsize * gridsize - gridsize; \ - buffer[currentquad + 3] = (i + 1) * gridsize * gridsize - 1; \ - buffer[currentquad + 4] = i * gridsize * gridsize + gridsize - 1; \ - buffer[currentquad + 5] = (i + 1) * gridsize * gridsize - gridsize; \ - } \ - GPU_buffer_unlock(buffers->index_buf_fast, GPU_BINDING_INDEX); \ - } \ - else { \ - GPU_buffer_free(buffers->index_buf_fast); \ - buffers->index_buf_fast = NULL; \ + Gwn_IndexBufBuilder elb; \ + GWN_indexbuf_init(&elb, GWN_PRIM_TRIS, 6 * totgrid, INT_MAX); \ + for (int i = 0; i < totgrid; i++) { \ + GWN_indexbuf_add_generic_vert(&elb, i * gridsize * gridsize + gridsize - 1); \ + GWN_indexbuf_add_generic_vert(&elb, i * gridsize * gridsize); \ + GWN_indexbuf_add_generic_vert(&elb, (i + 1) * gridsize * gridsize - gridsize); \ + GWN_indexbuf_add_generic_vert(&elb, (i + 1) * gridsize * gridsize - 1); \ + GWN_indexbuf_add_generic_vert(&elb, i * gridsize * gridsize + gridsize - 1); \ + GWN_indexbuf_add_generic_vert(&elb, (i + 1) * gridsize * gridsize - gridsize); \ } \ + buffers->index_buf_fast = GWN_indexbuf_build(&elb); \ } (void)0 GPU_PBVH_Buffers *GPU_pbvh_grid_buffers_build( - int *grid_indices, int totgrid, BLI_bitmap **grid_hidden, int gridsize, const CCGKey *key, + int *grid_indices, int totgrid, BLI_bitmap **grid_hidden, int gridsize, const CCGKey *UNUSED(key), GridCommonGPUBuffer **grid_common_gpu_buffer) { GPU_PBVH_Buffers *buffers; @@ -1494,7 +630,6 @@ GPU_PBVH_Buffers *GPU_pbvh_grid_buffers_build( buffers->show_diffuse_color = false; buffers->show_mask = true; - buffers->use_matcaps = false; /* Count the number of quads */ totquad = BKE_pbvh_count_grid_quads(grid_hidden, grid_indices, totgrid, gridsize); @@ -1504,39 +639,26 @@ GPU_PBVH_Buffers *GPU_pbvh_grid_buffers_build( return buffers; /* create and fill indices of the fast buffer too */ - if (totgrid * gridsize * gridsize < USHRT_MAX) { - FILL_FAST_BUFFER(unsigned short); - } - else { - FILL_FAST_BUFFER(unsigned int); - } + FILL_FAST_BUFFER(); if (totquad == fully_visible_totquad) { buffers->index_buf = gpu_get_grid_buffer( - gridsize, &buffers->index_type, &buffers->tot_quad, grid_common_gpu_buffer); + gridsize, &buffers->tot_quad, grid_common_gpu_buffer, totgrid); buffers->has_hidden = false; buffers->is_index_buf_global = true; } else { + uint max_vert = totgrid * gridsize * gridsize; buffers->tot_quad = totquad; - if (totgrid * gridsize * gridsize < USHRT_MAX) { - buffers->index_type = GL_UNSIGNED_SHORT; - FILL_QUAD_BUFFER(unsigned short, totquad, buffers->index_buf); - } - else { - buffers->index_type = GL_UNSIGNED_INT; - FILL_QUAD_BUFFER(unsigned int, totquad, buffers->index_buf); - } + FILL_QUAD_BUFFER(max_vert, totquad, buffers->index_buf); - buffers->has_hidden = true; + buffers->has_hidden = false; buffers->is_index_buf_global = false; } +#ifdef USE_BASE_ELEM /* Build coord/normal VBO */ - if (buffers->index_buf) - buffers->vert_buf = GPU_buffer_alloc(sizeof(VertexBufferFormat) * totgrid * key->grid_area); - if (GLEW_ARB_draw_elements_base_vertex /* 3.2 */) { int i; buffers->baseelemarray = MEM_mallocN(sizeof(int) * totgrid * 2, "GPU_PBVH_Buffers.baseelemarray"); @@ -1547,6 +669,7 @@ GPU_PBVH_Buffers *GPU_pbvh_grid_buffers_build( buffers->baseindex[i] = NULL; } } +#endif return buffers; } @@ -1559,32 +682,44 @@ GPU_PBVH_Buffers *GPU_pbvh_grid_buffers_build( * index '*v_index' in the 'vert_data' array and '*v_index' is * incremented. */ -static void gpu_bmesh_vert_to_buffer_copy(BMVert *v, - VertexBufferFormat *vert_data, - int *v_index, - const float fno[3], - const float *fmask, - const int cd_vert_mask_offset, - const float diffuse_color[4], - const bool show_mask) +static void gpu_bmesh_vert_to_buffer_copy__gwn( + BMVert *v, + Gwn_VertBuf *vert_buf, + int *v_index, + const float fno[3], + const float *fmask, + const int cd_vert_mask_offset, + const float diffuse_color[4], + const bool show_mask) { if (!BM_elem_flag_test(v, BM_ELEM_HIDDEN)) { - VertexBufferFormat *vd = &vert_data[*v_index]; /* Set coord, normal, and mask */ - copy_v3_v3(vd->co, v->co); - normal_float_to_short_v3(vd->no, fno ? fno : v->no); + GWN_vertbuf_attr_set(vert_buf, g_vbo_id.pos, *v_index, v->co); - float effective_mask; - if (show_mask) { - effective_mask = fmask ? *fmask - : BM_ELEM_CD_GET_FLOAT(v, cd_vert_mask_offset); - } - else { - effective_mask = 0.0f; + { + short no_short[3]; + normal_float_to_short_v3(no_short, fno ? fno : v->no); + GWN_vertbuf_attr_set(vert_buf, g_vbo_id.nor, *v_index, no_short); } - gpu_color_from_mask_copy(effective_mask, diffuse_color, vd->color); + { + uchar color_ub[3]; + float effective_mask; + if (show_mask) { + effective_mask = fmask ? *fmask + : BM_ELEM_CD_GET_FLOAT(v, cd_vert_mask_offset); + } + else { + effective_mask = 0.0f; + } + + gpu_color_from_mask_copy( + effective_mask, + diffuse_color, + 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 */ /* note: caller must set: bm->elem_index_dirty |= BM_VERT; */ @@ -1643,8 +778,6 @@ void GPU_pbvh_bmesh_buffers_update( { const bool show_diffuse_color = (update_flags & GPU_PBVH_BUFFERS_SHOW_DIFFUSE_COLOR) != 0; const bool show_mask = (update_flags & GPU_PBVH_BUFFERS_SHOW_MASK) != 0; - VertexBufferFormat *vert_data; - void *tri_data; int tottri, totvert, maxvert = 0; float diffuse_color[4] = {0.8f, 0.8f, 0.8f, 1.0f}; @@ -1653,7 +786,6 @@ void GPU_pbvh_bmesh_buffers_update( buffers->show_diffuse_color = show_diffuse_color; buffers->show_mask = show_mask; - buffers->use_matcaps = GPU_material_use_matcaps_get(); /* Count visible triangles */ tottri = gpu_bmesh_face_visible_count(bm_faces); @@ -1670,27 +802,19 @@ void GPU_pbvh_bmesh_buffers_update( return; } - if (buffers->use_matcaps) - diffuse_color[0] = diffuse_color[1] = diffuse_color[2] = 1.0; - else if (show_diffuse_color) { + if (show_diffuse_color) { /* due to dynamic nature of dyntopo, only get first material */ GSetIterator gs_iter; BMFace *f; BLI_gsetIterator_init(&gs_iter, bm_faces); f = BLI_gsetIterator_getKey(&gs_iter); - GPU_material_diffuse_get(f->mat_nr + 1, diffuse_color); + gpu_material_diffuse_get(f->mat_nr + 1, diffuse_color); } copy_v4_v4(buffers->diffuse_color, diffuse_color); - /* Initialize vertex buffer */ - if (buffers->vert_buf) - GPU_buffer_free(buffers->vert_buf); - buffers->vert_buf = GPU_buffer_alloc(sizeof(VertexBufferFormat) * totvert); - /* Fill vertex buffer */ - vert_data = GPU_buffer_lock(buffers->vert_buf, GPU_BINDING_ARRAY); - if (vert_data) { + if (gpu_pbvh_vert_buf_data_set(buffers, totvert)) { int v_index = 0; if (buffers->smooth) { @@ -1701,17 +825,19 @@ void GPU_pbvh_bmesh_buffers_update( bm->elem_index_dirty |= BM_VERT; GSET_ITER (gs_iter, bm_unique_verts) { - gpu_bmesh_vert_to_buffer_copy(BLI_gsetIterator_getKey(&gs_iter), - vert_data, &v_index, NULL, NULL, - cd_vert_mask_offset, diffuse_color, - show_mask); + gpu_bmesh_vert_to_buffer_copy__gwn( + BLI_gsetIterator_getKey(&gs_iter), + buffers->vert_buf, &v_index, NULL, NULL, + cd_vert_mask_offset, diffuse_color, + show_mask); } GSET_ITER (gs_iter, bm_other_verts) { - gpu_bmesh_vert_to_buffer_copy(BLI_gsetIterator_getKey(&gs_iter), - vert_data, &v_index, NULL, NULL, - cd_vert_mask_offset, diffuse_color, - show_mask); + gpu_bmesh_vert_to_buffer_copy__gwn( + BLI_gsetIterator_getKey(&gs_iter), + buffers->vert_buf, &v_index, NULL, NULL, + cd_vert_mask_offset, diffuse_color, + show_mask); } maxvert = v_index; @@ -1741,10 +867,11 @@ void GPU_pbvh_bmesh_buffers_update( fmask /= 3.0f; for (i = 0; i < 3; i++) { - gpu_bmesh_vert_to_buffer_copy(v[i], vert_data, - &v_index, f->no, &fmask, - cd_vert_mask_offset, diffuse_color, - show_mask); + gpu_bmesh_vert_to_buffer_copy__gwn( + v[i], buffers->vert_buf, + &v_index, f->no, &fmask, + cd_vert_mask_offset, diffuse_color, + show_mask); } } } @@ -1752,32 +879,26 @@ void GPU_pbvh_bmesh_buffers_update( buffers->tot_tri = tottri; } - GPU_buffer_unlock(buffers->vert_buf, GPU_BINDING_ARRAY); - /* gpu_bmesh_vert_to_buffer_copy sets dirty index values */ bm->elem_index_dirty |= BM_VERT; } else { /* Memory map failed */ - GPU_buffer_free(buffers->vert_buf); - buffers->vert_buf = NULL; return; } if (buffers->smooth) { - const int use_short = (maxvert < USHRT_MAX); + /* Fill the triangle buffer */ + buffers->index_buf = NULL; + Gwn_IndexBufBuilder elb; + GWN_indexbuf_init(&elb, GWN_PRIM_TRIS, tottri, maxvert); /* Initialize triangle index buffer */ - if (buffers->index_buf && !buffers->is_index_buf_global) - GPU_buffer_free(buffers->index_buf); buffers->is_index_buf_global = false; - buffers->index_buf = GPU_buffer_alloc((use_short ? - sizeof(unsigned short) : - sizeof(unsigned int)) * 3 * tottri); /* Fill triangle index buffer */ - tri_data = GPU_buffer_lock(buffers->index_buf, GPU_BINDING_INDEX); - if (tri_data) { + + { GSetIterator gs_iter; GSET_ITER (gs_iter, bm_faces) { @@ -1789,46 +910,30 @@ void GPU_pbvh_bmesh_buffers_update( l_iter = l_first = BM_FACE_FIRST_LOOP(f); do { - BMVert *v = l_iter->v; - if (use_short) { - unsigned short *elem = tri_data; - (*elem) = BM_elem_index_get(v); - elem++; - tri_data = elem; - } - else { - unsigned int *elem = tri_data; - (*elem) = BM_elem_index_get(v); - elem++; - tri_data = elem; - } + GWN_indexbuf_add_generic_vert(&elb, BM_elem_index_get(l_iter->v)); } while ((l_iter = l_iter->next) != l_first); } } - GPU_buffer_unlock(buffers->index_buf, GPU_BINDING_INDEX); - buffers->tot_tri = tottri; - buffers->index_type = (use_short ? - GL_UNSIGNED_SHORT : - GL_UNSIGNED_INT); - } - else { - /* Memory map failed */ - if (!buffers->is_index_buf_global) { - GPU_buffer_free(buffers->index_buf); + + if (buffers->index_buf == NULL) { + buffers->index_buf = GWN_indexbuf_build(&elb); + } + else { + GWN_indexbuf_build_in_place(&elb, buffers->index_buf); } - buffers->index_buf = NULL; - buffers->is_index_buf_global = false; } } else if (buffers->index_buf) { if (!buffers->is_index_buf_global) { - GPU_buffer_free(buffers->index_buf); + GWN_INDEXBUF_DISCARD_SAFE(buffers->index_buf); } buffers->index_buf = NULL; buffers->is_index_buf_global = false; } + + gpu_pbvh_batch_init(buffers); } GPU_PBVH_Buffers *GPU_pbvh_bmesh_buffers_build(bool smooth_shading) @@ -1840,172 +945,31 @@ GPU_PBVH_Buffers *GPU_pbvh_bmesh_buffers_build(bool smooth_shading) buffers->smooth = smooth_shading; buffers->show_diffuse_color = false; buffers->show_mask = true; - buffers->use_matcaps = false; return buffers; } -void GPU_pbvh_buffers_draw( - GPU_PBVH_Buffers *buffers, DMSetMaterial setMaterial, - bool wireframe, bool fast) +Gwn_Batch *GPU_pbvh_buffers_batch_get(GPU_PBVH_Buffers *buffers, bool fast) { - bool do_fast = fast && buffers->index_buf_fast; - /* sets material from the first face, to solve properly face would need to - * be sorted in buckets by materials */ - if (setMaterial) { - if (buffers->face_indices_len) { - const MLoopTri *lt = &buffers->looptri[buffers->face_indices[0]]; - const MPoly *mp = &buffers->mpoly[lt->poly]; - if (!setMaterial(mp->mat_nr + 1, NULL)) - return; - } - else if (buffers->totgrid) { - const DMFlagMat *f = &buffers->grid_flag_mats[buffers->grid_indices[0]]; - if (!setMaterial(f->mat_nr + 1, NULL)) - return; - } - else { - if (!setMaterial(1, NULL)) - return; - } - } - - if (buffers->vert_buf) { - char *base = NULL; - char *index_base = NULL; - /* weak inspection of bound options, should not be necessary ideally */ - const int bound_options_old = GPU_basic_shader_bound_options(); - int bound_options_new = 0; - glEnableClientState(GL_VERTEX_ARRAY); - if (!wireframe) { - glEnableClientState(GL_NORMAL_ARRAY); - glEnableClientState(GL_COLOR_ARRAY); - - bound_options_new |= GPU_SHADER_USE_COLOR; - } - - GPU_buffer_bind(buffers->vert_buf, GPU_BINDING_ARRAY); - - if (do_fast) { - GPU_buffer_bind(buffers->index_buf_fast, GPU_BINDING_INDEX); - } - else if (buffers->index_buf) { - GPU_buffer_bind(buffers->index_buf, GPU_BINDING_INDEX); - } - - if (wireframe) { - glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); - } - else { - if ((buffers->smooth == false) && (buffers->face_indices_len == 0)) { - bound_options_new |= GPU_SHADER_FLAT_NORMAL; - } - } - - if (bound_options_new & ~bound_options_old) { - GPU_basic_shader_bind(bound_options_old | bound_options_new); - } - - if (buffers->tot_quad) { - const char *offset = base; - const bool drawall = !(buffers->has_hidden || do_fast); - - if (GLEW_ARB_draw_elements_base_vertex && drawall) { - - glVertexPointer(3, GL_FLOAT, sizeof(VertexBufferFormat), - offset + offsetof(VertexBufferFormat, co)); - if (!wireframe) { - glNormalPointer(GL_SHORT, sizeof(VertexBufferFormat), - offset + offsetof(VertexBufferFormat, no)); - glColorPointer(3, GL_UNSIGNED_BYTE, sizeof(VertexBufferFormat), - offset + offsetof(VertexBufferFormat, color)); - } - - glMultiDrawElementsBaseVertex(GL_TRIANGLES, buffers->baseelemarray, buffers->index_type, - (const void * const *)buffers->baseindex, - buffers->totgrid, &buffers->baseelemarray[buffers->totgrid]); - } - else { - int i, last = drawall ? buffers->totgrid : 1; - - /* we could optimize this to one draw call, but it would need more memory */ - for (i = 0; i < last; i++) { - glVertexPointer(3, GL_FLOAT, sizeof(VertexBufferFormat), - offset + offsetof(VertexBufferFormat, co)); - if (!wireframe) { - glNormalPointer(GL_SHORT, sizeof(VertexBufferFormat), - offset + offsetof(VertexBufferFormat, no)); - glColorPointer(3, GL_UNSIGNED_BYTE, sizeof(VertexBufferFormat), - offset + offsetof(VertexBufferFormat, color)); - } - - if (do_fast) - glDrawElements(GL_TRIANGLES, buffers->totgrid * 6, buffers->index_type, index_base); - else - glDrawElements(GL_TRIANGLES, buffers->tot_quad * 6, buffers->index_type, index_base); - - offset += buffers->gridkey.grid_area * sizeof(VertexBufferFormat); - } - } - } - else if (buffers->tot_tri) { - int totelem = buffers->tot_tri * 3; - - glVertexPointer(3, GL_FLOAT, sizeof(VertexBufferFormat), - (void *)(base + offsetof(VertexBufferFormat, co))); - - if (!wireframe) { - glNormalPointer(GL_SHORT, sizeof(VertexBufferFormat), - (void *)(base + offsetof(VertexBufferFormat, no))); - glColorPointer(3, GL_UNSIGNED_BYTE, sizeof(VertexBufferFormat), - (void *)(base + offsetof(VertexBufferFormat, color))); - } - - if (buffers->index_buf) - glDrawElements(GL_TRIANGLES, totelem, buffers->index_type, index_base); - else - glDrawArrays(GL_TRIANGLES, 0, totelem); - } - - if (wireframe) - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); - - GPU_buffer_unbind(buffers->vert_buf, GPU_BINDING_ARRAY); - if (buffers->index_buf || do_fast) - GPU_buffer_unbind(do_fast ? buffers->index_buf_fast : buffers->index_buf, GPU_BINDING_INDEX); - - glDisableClientState(GL_VERTEX_ARRAY); - if (!wireframe) { - glDisableClientState(GL_NORMAL_ARRAY); - glDisableClientState(GL_COLOR_ARRAY); - } - - if (bound_options_new & ~bound_options_old) { - GPU_basic_shader_bind(bound_options_old); - } - } + return (fast && buffers->triangles_fast) ? + buffers->triangles_fast : buffers->triangles; } -bool GPU_pbvh_buffers_diffuse_changed( - GPU_PBVH_Buffers *buffers, GSet *bm_faces, bool show_diffuse_color) +bool GPU_pbvh_buffers_diffuse_changed(GPU_PBVH_Buffers *buffers, GSet *bm_faces, bool show_diffuse_color) { float diffuse_color[4]; - bool use_matcaps = GPU_material_use_matcaps_get(); if (buffers->show_diffuse_color != show_diffuse_color) return true; - if (buffers->use_matcaps != use_matcaps) - return true; - - if ((buffers->show_diffuse_color == false) || use_matcaps) + if (buffers->show_diffuse_color == false) return false; if (buffers->looptri) { const MLoopTri *lt = &buffers->looptri[buffers->face_indices[0]]; const MPoly *mp = &buffers->mpoly[lt->poly]; - GPU_material_diffuse_get(mp->mat_nr + 1, diffuse_color); + gpu_material_diffuse_get(mp->mat_nr + 1, diffuse_color); } else if (buffers->use_bmesh) { /* due to dynamic nature of dyntopo, only get first material */ @@ -2015,7 +979,7 @@ bool GPU_pbvh_buffers_diffuse_changed( BLI_gsetIterator_init(&gs_iter, bm_faces); f = BLI_gsetIterator_getKey(&gs_iter); - GPU_material_diffuse_get(f->mat_nr + 1, diffuse_color); + gpu_material_diffuse_get(f->mat_nr + 1, diffuse_color); } else { return false; @@ -2024,7 +988,7 @@ bool GPU_pbvh_buffers_diffuse_changed( else { const DMFlagMat *flags = &buffers->grid_flag_mats[buffers->grid_indices[0]]; - GPU_material_diffuse_get(flags->mat_nr + 1, diffuse_color); + gpu_material_diffuse_get(flags->mat_nr + 1, diffuse_color); } return !equals_v3v3(diffuse_color, buffers->diffuse_color); @@ -2038,16 +1002,20 @@ bool GPU_pbvh_buffers_mask_changed(GPU_PBVH_Buffers *buffers, bool show_mask) void GPU_pbvh_buffers_free(GPU_PBVH_Buffers *buffers) { if (buffers) { - if (buffers->vert_buf) - GPU_buffer_free(buffers->vert_buf); - if (buffers->index_buf && !buffers->is_index_buf_global) - GPU_buffer_free(buffers->index_buf); - if (buffers->index_buf_fast) - GPU_buffer_free(buffers->index_buf_fast); + GWN_BATCH_DISCARD_SAFE(buffers->triangles); + GWN_BATCH_DISCARD_SAFE(buffers->triangles_fast); + if (!buffers->is_index_buf_global) { + GWN_INDEXBUF_DISCARD_SAFE(buffers->index_buf); + } + GWN_INDEXBUF_DISCARD_SAFE(buffers->index_buf_fast); + GWN_VERTBUF_DISCARD_SAFE(buffers->vert_buf); + +#ifdef USE_BASE_ELEM if (buffers->baseelemarray) MEM_freeN(buffers->baseelemarray); if (buffers->baseindex) MEM_freeN(buffers->baseindex); +#endif MEM_freeN(buffers); } @@ -2060,7 +1028,7 @@ void GPU_pbvh_multires_buffers_free(GridCommonGPUBuffer **grid_common_gpu_buffer if (gridbuff) { if (gridbuff->mres_buffer) { BLI_mutex_lock(&buffer_mutex); - gpu_buffer_free_intern(gridbuff->mres_buffer); + GWN_INDEXBUF_DISCARD_SAFE(gridbuff->mres_buffer); BLI_mutex_unlock(&buffer_mutex); } MEM_freeN(gridbuff); @@ -2069,59 +1037,61 @@ void GPU_pbvh_multires_buffers_free(GridCommonGPUBuffer **grid_common_gpu_buffer } /* debug function, draws the pbvh BB */ -void GPU_pbvh_BB_draw(float min[3], float max[3], bool leaf) +void GPU_pbvh_BB_draw(float min[3], float max[3], bool leaf, unsigned int pos) { - const float quads[4][4][3] = { - { - {min[0], min[1], min[2]}, - {max[0], min[1], min[2]}, - {max[0], min[1], max[2]}, - {min[0], min[1], max[2]} - }, + if (leaf) + immUniformColor4f(0.0, 1.0, 0.0, 0.5); + else + immUniformColor4f(1.0, 0.0, 0.0, 0.5); - { - {min[0], min[1], min[2]}, - {min[0], max[1], min[2]}, - {min[0], max[1], max[2]}, - {min[0], min[1], max[2]} - }, + /* TODO(merwin): revisit this after we have mutable VertexBuffers + * could keep a static batch & index buffer, change the VBO contents per draw + */ - { - {max[0], max[1], min[2]}, - {max[0], min[1], min[2]}, - {max[0], min[1], max[2]}, - {max[0], max[1], max[2]} - }, + immBegin(GWN_PRIM_LINES, 24); - { - {max[0], max[1], min[2]}, - {min[0], max[1], min[2]}, - {min[0], max[1], max[2]}, - {max[0], max[1], max[2]} - }, - }; + /* top */ + immVertex3f(pos, min[0], min[1], max[2]); + immVertex3f(pos, min[0], max[1], max[2]); - if (leaf) - glColor4f(0.0, 1.0, 0.0, 0.5); - else - glColor4f(1.0, 0.0, 0.0, 0.5); + immVertex3f(pos, min[0], max[1], max[2]); + immVertex3f(pos, max[0], max[1], max[2]); - glVertexPointer(3, GL_FLOAT, 0, &quads[0][0][0]); - glDrawArrays(GL_QUADS, 0, 16); -} + immVertex3f(pos, max[0], max[1], max[2]); + immVertex3f(pos, max[0], min[1], max[2]); -void GPU_pbvh_BB_draw_init(void) -{ - glPushAttrib(GL_ENABLE_BIT); - glDisable(GL_CULL_FACE); - glEnableClientState(GL_VERTEX_ARRAY); - glDisableClientState(GL_COLOR_ARRAY); - glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); - glEnable(GL_BLEND); + immVertex3f(pos, max[0], min[1], max[2]); + immVertex3f(pos, min[0], min[1], max[2]); + + /* bottom */ + immVertex3f(pos, min[0], min[1], min[2]); + immVertex3f(pos, min[0], max[1], min[2]); + + immVertex3f(pos, min[0], max[1], min[2]); + immVertex3f(pos, max[0], max[1], min[2]); + + immVertex3f(pos, max[0], max[1], min[2]); + immVertex3f(pos, max[0], min[1], min[2]); + + immVertex3f(pos, max[0], min[1], min[2]); + immVertex3f(pos, min[0], min[1], min[2]); + + /* sides */ + immVertex3f(pos, min[0], min[1], min[2]); + immVertex3f(pos, min[0], min[1], max[2]); + + immVertex3f(pos, min[0], max[1], min[2]); + immVertex3f(pos, min[0], max[1], max[2]); + + immVertex3f(pos, max[0], max[1], min[2]); + immVertex3f(pos, max[0], max[1], max[2]); + + immVertex3f(pos, max[0], min[1], min[2]); + immVertex3f(pos, max[0], min[1], max[2]); + + immEnd(); } -void GPU_pbvh_BB_draw_end(void) +void GPU_pbvh_fix_linking() { - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); - glPopAttrib(); } diff --git a/source/blender/gpu/intern/gpu_codegen.c b/source/blender/gpu/intern/gpu_codegen.c index b5512aa108d..f182f08f4a9 100644 --- a/source/blender/gpu/intern/gpu_codegen.c +++ b/source/blender/gpu/intern/gpu_codegen.c @@ -36,17 +36,23 @@ #include "DNA_customdata_types.h" #include "DNA_image_types.h" #include "DNA_material_types.h" +#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" #include "GPU_shader.h" #include "GPU_texture.h" +#include "GPU_uniformbuffer.h" #include "BLI_sys_types.h" /* for intptr_t support */ @@ -62,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 */ @@ -88,7 +138,7 @@ typedef struct GPUFunction { /* Indices match the GPUType enum */ static const char *GPU_DATATYPE_STR[17] = { "", "float", "vec2", "vec3", "vec4", - NULL, NULL, NULL, NULL, "mat3", NULL, NULL, NULL, NULL, NULL, NULL, "mat4", + NULL, NULL, NULL, NULL, "mat3", NULL, NULL, NULL, NULL, NULL, NULL, "mat4" }; /* GLSL code parsing for finding function definitions. @@ -172,7 +222,7 @@ static void gpu_parse_functions_string(GHash *hash, char *code) /* test for type */ type = GPU_NONE; - for (i = 1; i <= 16; i++) { + for (i = 1; i < ARRAY_SIZE(GPU_DATATYPE_STR); i++) { if (GPU_DATATYPE_STR[i] && gpu_str_prefix(code, GPU_DATATYPE_STR[i])) { type = i; break; @@ -188,6 +238,13 @@ static void gpu_parse_functions_string(GHash *hash, char *code) if (!type && gpu_str_prefix(code, "sampler2D")) { type = GPU_TEX2D; } + if (!type && gpu_str_prefix(code, "sampler3D")) { + type = GPU_TEX3D; + } + + if (!type && gpu_str_prefix(code, "Closure")) { + type = GPU_CLOSURE; + } if (type) { /* add parameter */ @@ -350,6 +407,8 @@ static void codegen_convert_datatype(DynStr *ds, int from, int to, const char *t BLI_dynstr_appendf(ds, "vec4(%s.r, %s.r, %s.r, %s.g)", name, name, name, name); else if (from == GPU_FLOAT) BLI_dynstr_appendf(ds, "vec4(%s, %s, %s, 1.0)", name, name, name); + else /* can happen with closure */ + BLI_dynstr_append(ds, name); } } @@ -412,6 +471,12 @@ const char *GPU_builtin_name(GPUBuiltin builtin) return "unfparticleangvel"; else if (builtin == GPU_OBJECT_INFO) return "unfobjectinfo"; + else if (builtin == GPU_VOLUME_DENSITY) + return "sampdensity"; + else if (builtin == GPU_VOLUME_FLAME) + return "sampflame"; + else if (builtin == GPU_VOLUME_TEMPERATURE) + return "unftemperature"; else return ""; } @@ -500,12 +565,16 @@ static void codegen_set_unique_ids(ListBase *nodes) BLI_ghash_free(definehash, NULL, NULL); } -static int codegen_print_uniforms_functions(DynStr *ds, ListBase *nodes) +/** + * It will create an UBO for GPUMaterial if there is any GPU_DYNAMIC_UBO. + */ +static int codegen_process_uniforms_functions(GPUMaterial *material, DynStr *ds, ListBase *nodes) { GPUNode *node; GPUInput *input; const char *name; int builtins = 0; + ListBase ubo_inputs = {NULL, NULL}; /* print uniforms */ for (node = nodes->first; node; node = node->next) { @@ -525,7 +594,14 @@ static int codegen_print_uniforms_functions(DynStr *ds, ListBase *nodes) builtins |= input->builtin; name = GPU_builtin_name(input->builtin); - if (gpu_str_prefix(name, "unf")) { + if (gpu_str_prefix(name, "samp")) { + if ((input->builtin == GPU_VOLUME_DENSITY) || + (input->builtin == GPU_VOLUME_FLAME)) + { + BLI_dynstr_appendf(ds, "uniform sampler3D %s;\n", name); + } + } + else if (gpu_str_prefix(name, "unf")) { BLI_dynstr_appendf(ds, "uniform %s %s;\n", GPU_DATATYPE_STR[input->type], name); } @@ -536,14 +612,23 @@ static int codegen_print_uniforms_functions(DynStr *ds, ListBase *nodes) } } } + else if (input->source == GPU_SOURCE_STRUCT) { + /* Add other struct here if needed. */ + BLI_dynstr_appendf(ds, "Closure strct%d = CLOSURE_DEFAULT;\n", input->id); + } else if (input->source == GPU_SOURCE_VEC_UNIFORM) { - if (input->dynamicvec) { + if (input->dynamictype == GPU_DYNAMIC_UBO) { + if (!input->link) { + /* We handle the UBOuniforms separately. */ + BLI_addtail(&ubo_inputs, BLI_genericNodeN(input)); + } + } + else if (input->dynamicvec) { /* only create uniforms for dynamic vectors */ BLI_dynstr_appendf(ds, "uniform %s unf%d;\n", GPU_DATATYPE_STR[input->type], input->id); } else { - /* for others use const so the compiler can do folding */ BLI_dynstr_appendf(ds, "const %s cons%d = ", GPU_DATATYPE_STR[input->type], input->id); codegen_print_datatype(ds, input->type, input->vec); @@ -569,6 +654,22 @@ static int codegen_print_uniforms_functions(DynStr *ds, ListBase *nodes) } } + /* Handle the UBO block separately. */ + if ((material != NULL) && !BLI_listbase_is_empty(&ubo_inputs)) { + GPU_material_create_uniform_buffer(material, &ubo_inputs); + + /* Inputs are sorted */ + BLI_dynstr_appendf(ds, "\nlayout (std140) uniform %s {\n", GPU_UBO_BLOCK_NAME); + + for (LinkData *link = ubo_inputs.first; link; link = link->next) { + input = link->data; + BLI_dynstr_appendf(ds, "\t%s unf%d;\n", + GPU_DATATYPE_STR[input->type], input->id); + } + BLI_dynstr_append(ds, "};\n"); + BLI_freelistN(&ubo_inputs); + } + BLI_dynstr_append(ds, "\n"); return builtins; @@ -594,8 +695,13 @@ static void codegen_declare_tmps(DynStr *ds, ListBase *nodes) /* declare temporary variables for node output storage */ for (output = node->outputs.first; output; output = output->next) { - BLI_dynstr_appendf(ds, "\t%s tmp%d;\n", - GPU_DATATYPE_STR[output->type], output->id); + if (output->type == GPU_CLOSURE) { + BLI_dynstr_appendf(ds, "\tClosure tmp%d;\n", output->id); + } + else { + BLI_dynstr_appendf(ds, "\t%s tmp%d;\n", + GPU_DATATYPE_STR[output->type], output->id); + } } } @@ -622,11 +728,26 @@ static void codegen_call_functions(DynStr *ds, ListBase *nodes, GPUOutput *final "tmp", input->link->output->id); } else if (input->source == GPU_SOURCE_BUILTIN) { - if (input->builtin == GPU_VIEW_NORMAL) + if (input->builtin == GPU_INVERSE_VIEW_MATRIX) + BLI_dynstr_append(ds, "viewinv"); + else if (input->builtin == GPU_VIEW_MATRIX) + BLI_dynstr_append(ds, "viewmat"); + else if (input->builtin == GPU_CAMERA_TEXCO_FACTORS) + BLI_dynstr_append(ds, "camtexfac"); + else if (input->builtin == GPU_OBJECT_MATRIX) + BLI_dynstr_append(ds, "objmat"); + else if (input->builtin == GPU_INVERSE_OBJECT_MATRIX) + BLI_dynstr_append(ds, "objinv"); + else if (input->builtin == GPU_VIEW_POSITION) + BLI_dynstr_append(ds, "viewposition"); + else if (input->builtin == GPU_VIEW_NORMAL) BLI_dynstr_append(ds, "facingnormal"); else BLI_dynstr_append(ds, GPU_builtin_name(input->builtin)); } + else if (input->source == GPU_SOURCE_STRUCT) { + BLI_dynstr_appendf(ds, "strct%d", input->id); + } else if (input->source == GPU_SOURCE_VEC_UNIFORM) { if (input->dynamicvec) BLI_dynstr_appendf(ds, "unf%d", input->id); @@ -655,12 +776,11 @@ static void codegen_call_functions(DynStr *ds, ListBase *nodes, GPUOutput *final BLI_dynstr_append(ds, ");\n"); } - BLI_dynstr_append(ds, "\n\tgl_FragColor = "); - codegen_convert_datatype(ds, finaloutput->type, GPU_VEC4, "tmp", finaloutput->id); + BLI_dynstr_appendf(ds, "\n\treturn tmp%d", finaloutput->id); BLI_dynstr_append(ds, ";\n"); } -static char *code_generate_fragment(ListBase *nodes, GPUOutput *output) +static char *code_generate_fragment(GPUMaterial *material, ListBase *nodes, GPUOutput *output) { DynStr *ds = BLI_dynstr_new(); char *code; @@ -677,17 +797,29 @@ static char *code_generate_fragment(ListBase *nodes, GPUOutput *output) #endif codegen_set_unique_ids(nodes); - builtins = codegen_print_uniforms_functions(ds, nodes); + builtins = codegen_process_uniforms_functions(material, ds, nodes); #if 0 if (G.debug & G_DEBUG) BLI_dynstr_appendf(ds, "/* %s */\n", name); #endif - BLI_dynstr_append(ds, "void main()\n{\n"); - + BLI_dynstr_append(ds, "Closure nodetree_exec(void)\n{\n"); + + if (builtins & GPU_VIEW_MATRIX) + BLI_dynstr_append(ds, "\tmat4 viewmat = ViewMatrix;\n"); + if (builtins & GPU_CAMERA_TEXCO_FACTORS) + BLI_dynstr_append(ds, "\tvec4 camtexfac = CameraTexCoFactors;\n"); + if (builtins & GPU_OBJECT_MATRIX) + BLI_dynstr_append(ds, "\tmat4 objmat = ModelMatrix;\n"); + if (builtins & GPU_INVERSE_OBJECT_MATRIX) + BLI_dynstr_append(ds, "\tmat4 objinv = ModelMatrixInverse;\n"); + if (builtins & GPU_INVERSE_VIEW_MATRIX) + BLI_dynstr_append(ds, "\tmat4 viewinv = ViewMatrixInverse;\n"); if (builtins & GPU_VIEW_NORMAL) - BLI_dynstr_append(ds, "\tvec3 facingnormal = gl_FrontFacing? varnormal: -varnormal;\n"); + BLI_dynstr_append(ds, "\tvec3 facingnormal = gl_FrontFacing? viewNormal: -viewNormal;\n"); + if (builtins & GPU_VIEW_POSITION) + BLI_dynstr_append(ds, "\tvec3 viewposition = viewPosition;\n"); /* Calculate tangent space. */ #ifdef WITH_OPENSUBDIV @@ -722,6 +854,17 @@ static char *code_generate_fragment(ListBase *nodes, GPUOutput *output) BLI_dynstr_append(ds, "}\n"); + /* XXX This cannot go into gpu_shader_material.glsl because main() would be parsed and generate error */ + /* Old glsl mode compat. */ + BLI_dynstr_append(ds, "#ifndef NODETREE_EXEC\n"); + BLI_dynstr_append(ds, "out vec4 fragColor;\n"); + BLI_dynstr_append(ds, "void main()\n"); + BLI_dynstr_append(ds, "{\n"); + BLI_dynstr_append(ds, "\tClosure cl = nodetree_exec();\n"); + BLI_dynstr_append(ds, "\tfragColor = vec4(cl.radiance, cl.opacity);\n"); + BLI_dynstr_append(ds, "}\n"); + BLI_dynstr_append(ds, "#endif\n\n"); + /* create shader */ code = BLI_dynstr_get_cstring(ds); BLI_dynstr_free(ds); @@ -733,103 +876,152 @@ static char *code_generate_fragment(ListBase *nodes, GPUOutput *output) return code; } -static char *code_generate_vertex(ListBase *nodes, const GPUMatType type) +static const char *attrib_prefix_get(CustomDataType type) +{ + switch (type) { + case CD_ORCO: return "orco"; + case CD_MTFACE: return "u"; + case CD_TANGENT: return "t"; + case CD_MCOL: return "c"; + case CD_AUTO_FROM_NAME: return "a"; + default: BLI_assert(false && "Gwn_VertAttr Prefix type not found : This should not happen!"); return ""; + } +} + +static char *code_generate_vertex(ListBase *nodes, const char *vert_code, bool use_geom) { DynStr *ds = BLI_dynstr_new(); GPUNode *node; GPUInput *input; char *code; - char *vertcode = NULL; - + + /* Hairs uv and col attribs are passed by bufferTextures. */ + BLI_dynstr_append(ds, + "#ifdef HAIR_SHADER\n" + "#define DEFINE_ATTRIB(type, attr) uniform samplerBuffer attr\n" + "#else\n" + "#define DEFINE_ATTRIB(type, attr) in type attr\n" + "#endif\n" + ); + for (node = nodes->first; node; node = node->next) { for (input = node->inputs.first; input; input = input->next) { if (input->source == GPU_SOURCE_ATTRIB && input->attribfirst) { -#ifdef WITH_OPENSUBDIV - bool skip_opensubdiv = ELEM(input->attribtype, CD_MTFACE, CD_TANGENT); - if (skip_opensubdiv) { - BLI_dynstr_appendf(ds, "#ifndef USE_OPENSUBDIV\n"); + /* XXX FIXME : see notes in mesh_render_data_create() */ + /* NOTE : Replicate changes to mesh_render_data_create() in draw_cache_impl_mesh.c */ + if (input->attribtype == CD_ORCO) { + /* orco is computed from local positions, see bellow */ + BLI_dynstr_appendf(ds, "uniform vec3 OrcoTexCoFactors[2];\n"); } -#endif - BLI_dynstr_appendf(ds, "%s %s att%d;\n", - GLEW_VERSION_3_0 ? "in" : "attribute", - GPU_DATATYPE_STR[input->type], input->attribid); - BLI_dynstr_appendf(ds, "uniform int att%d_info;\n", input->attribid); - BLI_dynstr_appendf(ds, "%s %s var%d;\n", - GLEW_VERSION_3_0 ? "out" : "varying", - GPU_DATATYPE_STR[input->type], input->attribid); -#ifdef WITH_OPENSUBDIV - if (skip_opensubdiv) { - BLI_dynstr_appendf(ds, "#endif\n"); + else if (input->attribname[0] == '\0') { + BLI_dynstr_appendf(ds, "DEFINE_ATTRIB(%s, %s);\n", GPU_DATATYPE_STR[input->type], attrib_prefix_get(input->attribtype)); + BLI_dynstr_appendf(ds, "#define att%d %s\n", input->attribid, attrib_prefix_get(input->attribtype)); } -#endif + else { + unsigned int hash = BLI_ghashutil_strhash_p(input->attribname); + BLI_dynstr_appendf(ds, "DEFINE_ATTRIB(%s, %s%u);\n", + GPU_DATATYPE_STR[input->type], attrib_prefix_get(input->attribtype), hash); + BLI_dynstr_appendf(ds, "#define att%d %s%u\n", + input->attribid, attrib_prefix_get(input->attribtype), hash); + /* Auto attrib can be vertex color byte buffer. + * We need to know and convert them to linear space in VS. */ + if (!use_geom && input->attribtype == CD_AUTO_FROM_NAME) { + BLI_dynstr_appendf(ds, "uniform bool ba%u;\n", hash); + BLI_dynstr_appendf(ds, "#define att%d_is_srgb ba%u\n", input->attribid, hash); + } + } + BLI_dynstr_appendf(ds, "out %s var%d%s;\n", + GPU_DATATYPE_STR[input->type], input->attribid, use_geom ? "g" : ""); } } } BLI_dynstr_append(ds, "\n"); - switch (type) { - case GPU_MATERIAL_TYPE_MESH: - vertcode = datatoc_gpu_shader_vertex_glsl; - break; - case GPU_MATERIAL_TYPE_WORLD: - vertcode = datatoc_gpu_shader_vertex_world_glsl; - break; - default: - fprintf(stderr, "invalid material type, set one after GPU_material_construct_begin\n"); - break; + BLI_dynstr_append(ds, + "#define ATTRIB\n" + "uniform mat3 NormalMatrix;\n" + "uniform mat4 ModelMatrixInverse;\n" + "vec3 srgb_to_linear_attrib(vec3 c) {\n" + "\tc = max(c, vec3(0.0));\n" + "\tvec3 c1 = c * (1.0 / 12.92);\n" + "\tvec3 c2 = pow((c + 0.055) * (1.0 / 1.055), vec3(2.4));\n" + "\treturn mix(c1, c2, step(vec3(0.04045), c));\n" + "}\n\n" + ); + + /* Prototype because defined later. */ + BLI_dynstr_append(ds, + "vec2 hair_get_customdata_vec2(const samplerBuffer);\n" + "vec3 hair_get_customdata_vec3(const samplerBuffer);\n" + "vec4 hair_get_customdata_vec4(const samplerBuffer);\n" + "vec3 hair_get_strand_pos(void);\n" + "\n" + ); + + BLI_dynstr_append(ds, "void pass_attrib(in vec3 position) {\n"); + + BLI_dynstr_append(ds, "#ifdef HAIR_SHADER\n"); + + for (node = nodes->first; node; node = node->next) { + for (input = node->inputs.first; input; input = input->next) { + if (input->source == GPU_SOURCE_ATTRIB && input->attribfirst) { + if (input->attribtype == CD_TANGENT) { + /* Not supported by hairs */ + BLI_dynstr_appendf(ds, "\tvar%d%s = vec4(0.0);\n", + input->attribid, use_geom ? "g" : ""); + } + else if (input->attribtype == CD_ORCO) { + BLI_dynstr_appendf(ds, "\tvar%d%s = OrcoTexCoFactors[0] + (ModelMatrixInverse * vec4(hair_get_strand_pos(), 1.0)).xyz * OrcoTexCoFactors[1];\n", + input->attribid, use_geom ? "g" : ""); + } + else { + BLI_dynstr_appendf(ds, "\tvar%d%s = hair_get_customdata_%s(att%d);\n", + input->attribid, use_geom ? "g" : "", GPU_DATATYPE_STR[input->type], input->attribid); + } + } + } } - BLI_dynstr_append(ds, vertcode); - - for (node = nodes->first; node; node = node->next) - for (input = node->inputs.first; input; input = input->next) + BLI_dynstr_append(ds, "#else /* MESH_SHADER */\n"); + + for (node = nodes->first; node; node = node->next) { + for (input = node->inputs.first; input; input = input->next) { if (input->source == GPU_SOURCE_ATTRIB && input->attribfirst) { if (input->attribtype == CD_TANGENT) { /* silly exception */ -#ifdef WITH_OPENSUBDIV - BLI_dynstr_appendf(ds, "#ifndef USE_OPENSUBDIV\n"); -#endif BLI_dynstr_appendf( - ds, "\tvar%d.xyz = normalize(gl_NormalMatrix * att%d.xyz);\n", - input->attribid, input->attribid); + ds, "\tvar%d%s.xyz = normalize(NormalMatrix * att%d.xyz);\n", + input->attribid, use_geom ? "g" : "", input->attribid); BLI_dynstr_appendf( - ds, "\tvar%d.w = att%d.w;\n", - input->attribid, input->attribid); -#ifdef WITH_OPENSUBDIV - BLI_dynstr_appendf(ds, "#endif\n"); -#endif + ds, "\tvar%d%s.w = att%d.w;\n", + input->attribid, use_geom ? "g" : "", input->attribid); } - else { -#ifdef WITH_OPENSUBDIV - bool is_mtface = input->attribtype == CD_MTFACE; - if (is_mtface) { - BLI_dynstr_appendf(ds, "#ifndef USE_OPENSUBDIV\n"); - } -#endif - BLI_dynstr_appendf(ds, "\tset_var_from_attr(att%d, att%d_info, var%d);\n", - input->attribid, input->attribid, input->attribid); -#ifdef WITH_OPENSUBDIV - if (is_mtface) { - BLI_dynstr_appendf(ds, "#endif\n"); - } -#endif + else if (input->attribtype == CD_ORCO) { + BLI_dynstr_appendf(ds, "\tvar%d%s = OrcoTexCoFactors[0] + position * OrcoTexCoFactors[1];\n", + input->attribid, use_geom ? "g" : ""); } - } - /* unfortunately special handling is needed here because we abuse gl_Color/gl_SecondaryColor flat shading */ - else if (input->source == GPU_SOURCE_OPENGL_BUILTIN) { - if (input->oglbuiltin == GPU_MATCAP_NORMAL) { - /* remap to 0.0 - 1.0 range. This is done because OpenGL 2.0 clamps colors - * between shader stages and we want the full range of the normal */ - BLI_dynstr_appendf(ds, "\tvec3 matcapcol = vec3(0.5) * varnormal + vec3(0.5);\n"); - BLI_dynstr_appendf(ds, "\tgl_FrontSecondaryColor = vec4(matcapcol, 1.0);\n"); + else if (input->attribtype == CD_MCOL) { + BLI_dynstr_appendf(ds, "\tvar%d%s = srgb_to_linear_attrib(att%d);\n", + input->attribid, use_geom ? "g" : "", input->attribid); } - else if (input->oglbuiltin == GPU_COLOR) { - BLI_dynstr_appendf(ds, "\tgl_FrontColor = gl_Color;\n"); + else if (input->attribtype == CD_AUTO_FROM_NAME) { + BLI_dynstr_appendf(ds, "\tvar%d%s = (att%d_is_srgb) ? srgb_to_linear_attrib(att%d) : att%d;\n", + input->attribid, use_geom ? "g" : "", + input->attribid, input->attribid, input->attribid); + } + else { + BLI_dynstr_appendf(ds, "\tvar%d%s = att%d;\n", + input->attribid, use_geom ? "g" : "", input->attribid); } } + } + } + BLI_dynstr_append(ds, "#endif /* HAIR_SHADER */\n"); BLI_dynstr_append(ds, "}\n"); + BLI_dynstr_append(ds, vert_code); + code = BLI_dynstr_get_cstring(ds); BLI_dynstr_free(ds); @@ -841,65 +1033,49 @@ static char *code_generate_vertex(ListBase *nodes, const GPUMatType type) return code; } -static char *code_generate_geometry(ListBase *nodes, bool use_opensubdiv) +static char *code_generate_geometry(ListBase *nodes, const char *geom_code) { -#ifdef WITH_OPENSUBDIV - if (use_opensubdiv) { - DynStr *ds = BLI_dynstr_new(); - GPUNode *node; - GPUInput *input; - char *code; + DynStr *ds = BLI_dynstr_new(); + GPUNode *node; + GPUInput *input; + char *code; - /* Generate varying declarations. */ - for (node = nodes->first; node; node = node->next) { - for (input = node->inputs.first; input; input = input->next) { - if (input->source == GPU_SOURCE_ATTRIB && input->attribfirst) { - if (input->attribtype == CD_MTFACE) { - /* NOTE: For now we are using varying on purpose, - * otherwise we are not able to write to the varying. - */ - BLI_dynstr_appendf(ds, "%s %s var%d%s;\n", - "varying", - GPU_DATATYPE_STR[input->type], - input->attribid, - ""); - BLI_dynstr_appendf(ds, "uniform int fvar%d_offset;\n", - input->attribid); - } - } - } - } + /* Create prototype because attributes cannot be declared before layout. */ + BLI_dynstr_appendf(ds, "void pass_attrib(in int vert);\n"); + BLI_dynstr_append(ds, "#define ATTRIB\n"); - BLI_dynstr_append(ds, datatoc_gpu_shader_geometry_glsl); + BLI_dynstr_append(ds, geom_code); - /* Generate varying assignments. */ - for (node = nodes->first; node; node = node->next) { - for (input = node->inputs.first; input; input = input->next) { - if (input->source == GPU_SOURCE_ATTRIB && input->attribfirst) { - if (input->attribtype == CD_MTFACE) { - BLI_dynstr_appendf( - ds, - "\tINTERP_FACE_VARYING_ATT_2(var%d, " - "int(texelFetch(FVarDataOffsetBuffer, fvar%d_offset).r), st);\n", - input->attribid, - input->attribid); - } - } + /* Generate varying declarations. */ + for (node = nodes->first; node; node = node->next) { + for (input = node->inputs.first; input; input = input->next) { + if (input->source == GPU_SOURCE_ATTRIB && input->attribfirst) { + BLI_dynstr_appendf(ds, "in %s var%dg[];\n", + GPU_DATATYPE_STR[input->type], + input->attribid); + BLI_dynstr_appendf(ds, "out %s var%d;\n", + GPU_DATATYPE_STR[input->type], + input->attribid); } } + } - BLI_dynstr_append(ds, "}\n"); - code = BLI_dynstr_get_cstring(ds); - BLI_dynstr_free(ds); + /* Generate varying assignments. */ + BLI_dynstr_appendf(ds, "void pass_attrib(in int vert) {\n"); + for (node = nodes->first; node; node = node->next) { + for (input = node->inputs.first; input; input = input->next) { + if (input->source == GPU_SOURCE_ATTRIB && input->attribfirst) { + /* TODO let shader choose what to do depending on what the attrib is. */ + BLI_dynstr_appendf(ds, "\tvar%d = var%dg[vert];\n", input->attribid, input->attribid); + } + } + } + BLI_dynstr_append(ds, "}\n"); - //if (G.debug & G_DEBUG) printf("%s\n", code); + code = BLI_dynstr_get_cstring(ds); + BLI_dynstr_free(ds); - return code; - } -#else - UNUSED_VARS(nodes, use_opensubdiv); -#endif - return NULL; + return code; } void GPU_code_generate_glsl_lib(void) @@ -928,15 +1104,13 @@ GPUShader *GPU_pass_shader(GPUPass *pass) return pass->shader; } -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; @@ -951,26 +1125,9 @@ static void gpu_nodes_extract_dynamic_inputs(GPUPass *pass, ListBase *nodes) /* attributes don't need to be bound, they already have * an id that the drawing functions will use */ if (input->source == GPU_SOURCE_ATTRIB) { -#ifdef WITH_OPENSUBDIV - /* We do need mtface attributes for later, so we can - * update face-varuing variables offset in the texture - * buffer for proper sampling from the shader. - * - * We don't do anything about attribute itself, we - * only use it to learn which uniform name is to be - * updated. - * - * TODO(sergey): We can add ad extra uniform input - * for the offset, which will be purely internal and - * which would avoid having such an exceptions. - */ - if (input->attribtype != CD_MTFACE) { - continue; - } -#else continue; -#endif } + if (input->source == GPU_SOURCE_BUILTIN || input->source == GPU_SOURCE_OPENGL_BUILTIN) { @@ -995,14 +1152,6 @@ static void gpu_nodes_extract_dynamic_inputs(GPUPass *pass, ListBase *nodes) if (extract) input->shaderloc = GPU_shader_get_uniform(shader, input->shadername); -#ifdef WITH_OPENSUBDIV - if (input->source == GPU_SOURCE_ATTRIB && - input->attribtype == CD_MTFACE) - { - extract = 1; - } -#endif - /* extract nodes */ if (extract) { BLI_remlink(&node->inputs, input); @@ -1014,11 +1163,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; @@ -1043,11 +1191,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; @@ -1068,11 +1215,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; @@ -1135,7 +1281,7 @@ static void gpu_node_input_link(GPUNode *node, GPUNodeLink *link, const GPUType name = outnode->name; input = outnode->inputs.first; - if ((STREQ(name, "set_value") || STREQ(name, "set_rgb")) && + if ((STREQ(name, "set_value") || STREQ(name, "set_rgb") || STREQ(name, "set_rgba")) && (input->type == type)) { input = MEM_dupallocN(outnode->inputs.first); @@ -1194,7 +1340,7 @@ static void gpu_node_input_link(GPUNode *node, GPUNodeLink *link, const GPUType #if 0 input->tex = GPU_texture_create_2D(link->texturesize, link->texturesize, link->ptr2, NULL); #endif - input->tex = GPU_texture_create_2D(link->texturesize, 1, link->ptr1, GPU_HDR_NONE, NULL); + input->tex = GPU_texture_create_2D(link->texturesize, 1, GPU_RGBA8, link->ptr1, NULL); input->textarget = GL_TEXTURE_2D; MEM_freeN(link->ptr1); @@ -1235,6 +1381,12 @@ static void gpu_node_input_link(GPUNode *node, GPUNodeLink *link, const GPUType BLI_strncpy(input->attribname, link->attribname, sizeof(input->attribname)); MEM_freeN(link); } + else if (type == GPU_CLOSURE) { + input->type = type; + input->source = GPU_SOURCE_STRUCT; + + MEM_freeN(link); + } else { /* uniform vector */ input->type = type; @@ -1246,21 +1398,100 @@ static void gpu_node_input_link(GPUNode *node, GPUNodeLink *link, const GPUType input->dynamictype = link->dynamictype; input->dynamicdata = link->ptr2; } + MEM_freeN(link); } BLI_addtail(&node->inputs, input); } -static void gpu_node_input_socket(GPUNode *node, GPUNodeStack *sock) + +static const char *gpu_uniform_set_function_from_type(eNodeSocketDatatype type) +{ + switch (type) { + case SOCK_FLOAT: + return "set_value"; + case SOCK_VECTOR: + return "set_rgb"; + case SOCK_RGBA: + return "set_rgba"; + default: + BLI_assert(!"No gpu function for non-supported eNodeSocketDatatype"); + return NULL; + } +} + +/** + * Link stack uniform buffer. + * This is called for the input/output sockets that are note connected. + */ +static GPUNodeLink *gpu_uniformbuffer_link( + GPUMaterial *mat, bNode *node, GPUNodeStack *stack, const int index, const eNodeSocketInOut in_out) { - GPUNodeLink *link; + bNodeSocket *socket; + + /* Some nodes can have been create on the fly and does + * not have an original to point to. (i.e. the bump from + * ntree_shader_relink_displacement). In this case just + * revert to static constant folding. */ + if (node->original == NULL) { + return NULL; + } + + if (in_out == SOCK_IN) { + socket = BLI_findlink(&node->original->inputs, index); + } + else { + socket = BLI_findlink(&node->original->outputs, index); + } + + BLI_assert(socket != NULL); + BLI_assert(socket->in_out == in_out); + + if ((socket->flag & SOCK_HIDE_VALUE) == 0) { + GPUNodeLink *link; + switch (socket->type) { + case SOCK_FLOAT: + { + bNodeSocketValueFloat *socket_data = socket->default_value; + link = GPU_uniform_buffer(&socket_data->value, GPU_FLOAT); + break; + } + case SOCK_VECTOR: + { + bNodeSocketValueRGBA *socket_data = socket->default_value; + link = GPU_uniform_buffer(socket_data->value, GPU_VEC3); + break; + } + case SOCK_RGBA: + { + bNodeSocketValueRGBA *socket_data = socket->default_value; + link = GPU_uniform_buffer(socket_data->value, GPU_VEC4); + break; + } + default: + return NULL; + break; + } + + if (in_out == SOCK_IN) { + GPU_link(mat, gpu_uniform_set_function_from_type(socket->type), link, &stack->link); + } + return link; + } + return NULL; +} +static void gpu_node_input_socket(GPUMaterial *material, bNode *bnode, GPUNode *node, GPUNodeStack *sock, const int index) +{ if (sock->link) { gpu_node_input_link(node, sock->link, sock->type); } + else if ((material != NULL) && (gpu_uniformbuffer_link(material, bnode, sock, index, SOCK_IN) != NULL)) { + gpu_node_input_link(node, sock->link, sock->type); + } else { - link = GPU_node_link_create(); + GPUNodeLink *link = GPU_node_link_create(); link->ptr1 = sock->vec; gpu_node_input_link(node, link, sock->type); } @@ -1286,7 +1517,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; @@ -1304,7 +1535,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) { @@ -1327,7 +1558,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; @@ -1368,26 +1599,20 @@ static void gpu_nodes_get_vertex_attributes(ListBase *nodes, GPUVertexAttribs *a } } -static void gpu_nodes_get_builtin_flag(ListBase *nodes, int *builtin) -{ - GPUNode *node; - GPUInput *input; - - *builtin = 0; - - for (node = nodes->first; node; node = node->next) - for (input = node->inputs.first; input; input = input->next) - if (input->source == GPU_SOURCE_BUILTIN) - *builtin |= input->builtin; -} - /* varargs linking */ GPUNodeLink *GPU_attribute(const CustomDataType type, const char *name) { GPUNodeLink *link = GPU_node_link_create(); - link->attribtype = type; + /* Fall back to the UV layer, which matches old behavior. */ + if (type == CD_AUTO_FROM_NAME && name[0] == '\0') { + link->attribtype = CD_MTFACE; + } + else { + link->attribtype = type; + } + link->attribname = name; return link; @@ -1416,6 +1641,21 @@ GPUNodeLink *GPU_dynamic_uniform(float *num, GPUDynamicType dynamictype, void *d return link; } +/** + * Add uniform to UBO struct of GPUMaterial. + */ +GPUNodeLink *GPU_uniform_buffer(float *num, GPUType gputype) +{ + GPUNodeLink *link = GPU_node_link_create(); + link->ptr1 = num; + link->ptr2 = NULL; + link->dynamic = true; + link->dynamictype = GPU_DYNAMIC_UBO; + link->type = gputype; + + return link; +} + GPUNodeLink *GPU_image(Image *ima, ImageUser *iuser, bool is_data) { GPUNodeLink *link = GPU_node_link_create(); @@ -1526,7 +1766,7 @@ bool GPU_link(GPUMaterial *mat, const char *name, ...) return true; } -bool GPU_stack_link(GPUMaterial *mat, const char *name, GPUNodeStack *in, GPUNodeStack *out, ...) +bool GPU_stack_link(GPUMaterial *material, bNode *bnode, const char *name, GPUNodeStack *in, GPUNodeStack *out, ...) { GPUNode *node; GPUFunction *function; @@ -1545,16 +1785,20 @@ bool GPU_stack_link(GPUMaterial *mat, const char *name, GPUNodeStack *in, GPUNod totout = 0; if (in) { - for (i = 0; in[i].type != GPU_NONE; i++) { - gpu_node_input_socket(node, &in[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++; + } } } @@ -1572,7 +1816,7 @@ bool GPU_stack_link(GPUMaterial *mat, const char *name, GPUNodeStack *in, GPUNod if (totin == 0) { link = va_arg(params, GPUNodeLink *); if (link->socket) - gpu_node_input_socket(node, link->socket); + gpu_node_input_socket(NULL, NULL, node, link->socket, -1); else gpu_node_input_link(node, link, function->paramtype[i]); } @@ -1582,8 +1826,8 @@ bool GPU_stack_link(GPUMaterial *mat, const char *name, GPUNodeStack *in, GPUNod } va_end(params); - gpu_material_add_node(mat, node); - + gpu_material_add_node(material, node); + return true; } @@ -1608,6 +1852,11 @@ int GPU_link_changed(GPUNodeLink *link) return 0; } +GPUNodeLink *GPU_uniformbuffer_link_out(GPUMaterial *mat, bNode *node, GPUNodeStack *stack, const int index) +{ + return gpu_uniformbuffer_link(mat, node, stack, index, SOCK_OUT); +} + /* Pass create/free */ static void gpu_nodes_tag(GPUNodeLink *link) @@ -1628,7 +1877,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; @@ -1647,91 +1896,97 @@ static void gpu_nodes_prune(ListBase *nodes, GPUNodeLink *outlink) } } -GPUPass *GPU_generate_pass( - ListBase *nodes, GPUNodeLink *outlink, - GPUVertexAttribs *attribs, int *builtins, - const GPUMatType type, const char *UNUSED(name), - const bool use_opensubdiv, - const bool use_new_shading) +GPUPass *GPU_generate_pass_new( + 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 *vertexcode, *geometrycode, *fragmentcode; -#if 0 - if (!FUNCTION_LIB) { - GPU_nodes_free(nodes); - return NULL; + /* prune unused nodes */ + GPU_nodes_prune(nodes, frag_outlink); + + GPU_nodes_get_vertex_attributes(nodes, attribs); + + /* generate code */ + char *fragmentgen = code_generate_fragment(material, nodes, frag_outlink->output); + char *tmp = BLI_strdupcat(frag_lib, glsl_material_library); + + vertexcode = code_generate_vertex(nodes, vert_code, (geom_code != NULL)); + geometrycode = (geom_code) ? code_generate_geometry(nodes, geom_code) : NULL; + fragmentcode = BLI_strdupcat(tmp, fragmentgen); + + MEM_freeN(fragmentgen); + MEM_freeN(tmp); + + /* 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); } -#endif - /* prune unused nodes */ - gpu_nodes_prune(nodes, outlink); - - gpu_nodes_get_vertex_attributes(nodes, attribs); - gpu_nodes_get_builtin_flag(nodes, builtins); - - /* generate code and compile with opengl */ - fragmentcode = code_generate_fragment(nodes, outlink->output); - vertexcode = code_generate_vertex(nodes, type); - geometrycode = code_generate_geometry(nodes, use_opensubdiv); - - int flags = GPU_SHADER_FLAGS_NONE; - if (use_opensubdiv) { - flags |= GPU_SHADER_FLAGS_SPECIAL_OPENSUBDIV; - } - if (use_new_shading) { - flags |= GPU_SHADER_FLAGS_NEW_SHADING; - } - shader = GPU_shader_create_ex(vertexcode, - fragmentcode, - geometrycode, - glsl_material_library, - NULL, - 0, - 0, - 0, - flags); - - /* failed? */ + /* did compilation failed ? */ if (!shader) { - if (fragmentcode) - MEM_freeN(fragmentcode); - if (vertexcode) - MEM_freeN(vertexcode); - memset(attribs, 0, sizeof(*attribs)); - memset(builtins, 0, sizeof(*builtins)); 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->output = outlink->output; - 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(pass, nodes); - gpu_nodes_free(nodes); + else { + gpu_nodes_extract_dynamic_inputs(shader, inputs, nodes); + return pass; + } +} - return pass; +void GPU_pass_release(GPUPass *pass) +{ + BLI_assert(pass->refcount > 0); + pass->refcount--; } -void GPU_pass_free(GPUPass *pass) +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); } @@ -1740,3 +1995,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 7af17f9122d..328da36c3de 100644 --- a/source/blender/gpu/intern/gpu_codegen.h +++ b/source/blender/gpu/intern/gpu_codegen.h @@ -57,7 +57,8 @@ typedef enum GPUDataSource { GPU_SOURCE_OPENGL_BUILTIN, GPU_SOURCE_TEX_PIXEL, GPU_SOURCE_TEX, - GPU_SOURCE_ATTRIB + GPU_SOURCE_ATTRIB, + GPU_SOURCE_STRUCT } GPUDataSource; typedef enum { @@ -156,35 +157,45 @@ typedef struct GPUInput { } GPUInput; struct GPUPass { - struct GPUPass *next, *prev; - - ListBase inputs; - struct GPUOutput *output; 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(ListBase *nodes, struct GPUNodeLink *outlink, - struct GPUVertexAttribs *attribs, int *builtin, - const GPUMatType type, const char *name, - const bool use_opensubdiv, - const bool use_new_shading); +GPUPass *GPU_generate_pass_new( + 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, ListBase *inputs, struct GPUNodeLink *outlink, + struct GPUVertexAttribs *attribs, int *builtin, + const GPUMatType type, const char *name, + const bool use_opensubdiv); 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_free(GPUPass *pass); +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_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 2f2a16f9e1d..00000000000 --- a/source/blender/gpu/intern/gpu_compositing.c +++ /dev/null @@ -1,1461 +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_extensions.h" -#include "GPU_framebuffer.h" -#include "GPU_glew.h" -#include "GPU_shader.h" -#include "GPU_texture.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; - - unsigned int vbuffer; -}; - -#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_procedural(side * side, texels, NULL); - 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_procedural(numsaples, (float *)texels, NULL); - MEM_freeN(texels); - return tex; -} - -/* generate a new FX compositor */ -GPUFX *GPU_fx_compositor_create(void) -{ - GPUFX *fx = MEM_callocN(sizeof(GPUFX), "GPUFX compositor"); - - glGenBuffers(1, &fx->vbuffer); - glBindBuffer(GL_ARRAY_BUFFER, fx->vbuffer); - glBufferData(GL_ARRAY_BUFFER, 16 * sizeof(float), NULL, GL_STATIC_DRAW); - glBufferSubData(GL_ARRAY_BUFFER, 0, 8 * sizeof(float), fullscreencos); - glBufferSubData(GL_ARRAY_BUFFER, 8 * sizeof(float), 8 * sizeof(float), fullscreenuvs); - glBindBuffer(GL_ARRAY_BUFFER, 0); - - 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); - glDeleteBuffers(1, &fx->vbuffer); - MEM_freeN(fx); -} - -static GPUTexture * create_jitter_texture(void) -{ - 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]); - } - - return GPU_texture_create_2D_procedural(64, 64, &jitter[0][0], true, NULL); -} - - -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 (!GLEW_EXT_framebuffer_object) - return false; - - 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, GPU_HDR_NONE, 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) && - GPU_geometry_shader_support() && GPU_instanced_drawing_support(); - - /* 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, GPU_HDR_NONE, 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, GPU_HDR_NONE, err_out))) - { - printf("%.256s\n", err_out); - cleanup_fx_gl_data(fx, true); - return false; - } - if (!(fx->dof_nearfar_coc = GPU_texture_create_2D_procedural( - fx->dof_downsampled_w, fx->dof_downsampled_h, NULL, false, err_out))) - { - printf("%.256s\n", err_out); - cleanup_fx_gl_data(fx, true); - return false; - } - - - if (!(fx->dof_near_blur = GPU_texture_create_2D( - fx->dof_downsampled_w, fx->dof_downsampled_h, NULL, GPU_HDR_HALF_FLOAT, err_out))) - { - printf("%.256s\n", err_out); - cleanup_fx_gl_data(fx, true); - return false; - } - - if (!(fx->dof_far_blur = GPU_texture_create_2D( - fx->dof_downsampled_w, fx->dof_downsampled_h, NULL, GPU_HDR_HALF_FLOAT, 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, GPU_HDR_NONE, 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, GPU_HDR_NONE, 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, GPU_HDR_NONE, 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, GPU_HDR_NONE, 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 */ - if (!GPU_framebuffer_texture_attach(fx->gbuffer, fx->depth_buffer, 0, err_out)) - printf("%.256s\n", err_out); - - if (!GPU_framebuffer_texture_attach(fx->gbuffer, fx->color_buffer, 0, err_out)) - printf("%.256s\n", err_out); - - 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; - glPushAttrib(GL_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, NULL); - } -} - -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 */ - if (!GPU_framebuffer_texture_attach(fx->gbuffer, fx->depth_buffer_xray, 0, err_out)) - printf("%.256s\n", err_out); -} - - -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, NULL); - - /* full screen quad where we will always write to depth buffer */ - glPushAttrib(GL_DEPTH_BUFFER_BIT | GL_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); - - /* set up quad buffer */ - glBindBuffer(GL_ARRAY_BUFFER, fx->vbuffer); - glVertexPointer(2, GL_FLOAT, 0, NULL); - glTexCoordPointer(2, GL_FLOAT, 0, ((GLubyte *)NULL + 8 * sizeof(float))); - glEnableClientState(GL_VERTEX_ARRAY); - glEnableClientState(GL_TEXTURE_COORD_ARRAY); - - depth_resolve_shader = GPU_shader_get_builtin_fx_shader(GPU_SHADER_FX_DEPTH_RESOLVE, false); - - if (depth_resolve_shader) { - GPUDepthResolveInterface *interface = GPU_shader_get_interface(depth_resolve_shader); - - GPU_shader_bind(depth_resolve_shader); - - GPU_texture_bind(fx->depth_buffer_xray, 0); - GPU_texture_filter_mode(fx->depth_buffer_xray, false, true); - GPU_shader_uniform_texture(depth_resolve_shader, interface->depth_uniform, fx->depth_buffer_xray); - - /* draw */ - glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); - - /* disable bindings */ - GPU_texture_filter_mode(fx->depth_buffer_xray, true, false); - GPU_texture_unbind(fx->depth_buffer_xray); - - GPU_shader_unbind(); - } - - glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); - - glBindBuffer(GL_ARRAY_BUFFER, 0); - glDisableClientState(GL_VERTEX_ARRAY); - glDisableClientState(GL_TEXTURE_COORD_ARRAY); - - glPopAttrib(); -} - - -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) - glPopAttrib(); - - src = fx->color_buffer; - target = fx->color_buffer_sec; - - /* set up quad buffer */ - glBindBuffer(GL_ARRAY_BUFFER, fx->vbuffer); - glVertexPointer(2, GL_FLOAT, 0, NULL); - glTexCoordPointer(2, GL_FLOAT, 0, ((GLubyte *)NULL + 8 * sizeof(float))); - glEnableClientState(GL_VERTEX_ARRAY); - glEnableClientState(GL_TEXTURE_COORD_ARRAY); - - /* 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]; - } - - /* set invalid color in case shader fails */ - glColor3f(1.0, 0.0, 1.0); - 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_shader_get_interface(ssao_shader); - - GPU_shader_bind(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_filter_mode(fx->depth_buffer, false, 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); - - glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); - - /* disable bindings */ - GPU_texture_unbind(src); - GPU_texture_filter_mode(fx->depth_buffer, true, 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(); - glDisableClientState(GL_VERTEX_ARRAY); - glDisableClientState(GL_TEXTURE_COORD_ARRAY); - - GPU_shader_unbind(); - glBindBuffer(GL_ARRAY_BUFFER, 0); - 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_shader_get_interface(dof_shader_pass1); - - GPU_shader_bind(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_filter_mode(fx->depth_buffer, false, 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, 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, NULL); - GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_half_downsampled_far, 1, NULL); - GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_nearfar_coc, 2, NULL); - /* 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); - - glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); - /* disable bindings */ - GPU_texture_filter_mode(src, false, true); - GPU_texture_unbind(src); - GPU_texture_filter_mode(fx->depth_buffer, true, 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_shader_get_interface(dof_shader_pass2); - - GPU_shader_bind(dof_shader_pass2); - - 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_texture_bind(fx->dof_nearfar_coc, numslots++); - GPU_shader_uniform_texture(dof_shader_pass2, interface->coc_uniform, fx->dof_nearfar_coc); - - GPU_texture_bind(fx->dof_half_downsampled_far, numslots++); - GPU_texture_bind(fx->dof_half_downsampled_near, numslots++); - 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, false); - - /* target is the downsampled coc buffer */ - GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_far_blur, 0, NULL); - 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 */ - glDrawArraysInstancedARB(GL_POINTS, 0, 1, fx->dof_downsampled_w * fx->dof_downsampled_h); - - GPU_texture_unbind(fx->dof_half_downsampled_far); - GPU_framebuffer_texture_detach(fx->dof_far_blur); - - 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, false); - - selection[0] = 1.0f; - selection[1] = 0.0f; - - GPU_shader_uniform_vector(dof_shader_pass2, interface->select_uniform, 2, 1, selection); - - GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_near_blur, 0, NULL); - /* 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 */ - glDrawArraysInstancedARB(GL_POINTS, 0, 1, fx->dof_downsampled_w * fx->dof_downsampled_h); - - /* 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); - } - - /* 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_shader_get_interface(dof_shader_pass3); - - GPU_shader_bind(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, false, 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, false, true); - - GPU_texture_bind(fx->depth_buffer, numslots++); - GPU_texture_filter_mode(fx->depth_buffer, false, 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); - - glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); - - /* disable bindings */ - GPU_texture_unbind(fx->dof_near_blur); - GPU_texture_unbind(fx->dof_far_blur); - GPU_texture_unbind(src); - GPU_texture_filter_mode(fx->depth_buffer, true, 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(); - } - } - - 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(); - glDisableClientState(GL_VERTEX_ARRAY); - glDisableClientState(GL_TEXTURE_COORD_ARRAY); - - GPU_shader_unbind(); - glBindBuffer(GL_ARRAY_BUFFER, 0); - 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_shader_get_interface(dof_shader_pass1); - - GPU_shader_bind(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_filter_mode(fx->depth_buffer, false, 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, NULL); - /* binding takes care of setting the viewport to the downsampled size */ - GPU_texture_bind_as_framebuffer(fx->dof_near_coc_buffer); - - glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); - /* disable bindings */ - GPU_texture_unbind(src); - GPU_texture_filter_mode(fx->depth_buffer, true, 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_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 */ - GPU_shader_bind(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_filter_mode(fx->depth_buffer, false, 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, NULL); - - /* Drawing quad */ - glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); - - /* *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, NULL); - glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); - - /* *unbind/detach */ - GPU_texture_filter_mode(fx->depth_buffer, true, 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_shader_get_interface(dof_shader_pass3); - - GPU_shader_bind(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, NULL); - - glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); - /* 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_shader_get_interface(dof_shader_pass4); - - GPU_shader_bind(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, NULL); - - glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); - /* 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_shader_get_interface(dof_shader_pass5); - - GPU_shader_bind(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_filter_mode(fx->depth_buffer, false, 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); - - glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); - /* 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_filter_mode(fx->depth_buffer, true, 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; - } - } - } - - glDisableClientState(GL_VERTEX_ARRAY); - glDisableClientState(GL_TEXTURE_COORD_ARRAY); - glBindBuffer(GL_ARRAY_BUFFER, 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; -} - -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(struct 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_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_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_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_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_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_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_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_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_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_shader_set_interface(shader, interface); - break; - } - - default: - break; - } -} - diff --git a/source/blender/gpu/intern/gpu_debug.c b/source/blender/gpu/intern/gpu_debug.c index 859aab9565f..8aea87ef659 100644 --- a/source/blender/gpu/intern/gpu_debug.c +++ b/source/blender/gpu/intern/gpu_debug.c @@ -20,7 +20,7 @@ * * The Original Code is: all of this file. * - * Contributor(s): Brecht Van Lommel, Jason Wilkins. + * Contributor(s): Brecht Van Lommel, Jason Wilkins, Mike Erwin. * * ***** END GPL LICENSE BLOCK ***** */ @@ -44,122 +44,18 @@ #include <stdlib.h> #include <string.h> -#define CASE_CODE_RETURN_STR(code) case code: return #code; +#ifndef __APPLE__ /* only non-Apple systems implement OpenGL debug callbacks */ -static const char *gpu_gl_error_symbol(GLenum err) -{ - switch (err) { - CASE_CODE_RETURN_STR(GL_NO_ERROR) - CASE_CODE_RETURN_STR(GL_INVALID_ENUM) - CASE_CODE_RETURN_STR(GL_INVALID_VALUE) - CASE_CODE_RETURN_STR(GL_INVALID_OPERATION) - CASE_CODE_RETURN_STR(GL_STACK_OVERFLOW) - CASE_CODE_RETURN_STR(GL_STACK_UNDERFLOW) - CASE_CODE_RETURN_STR(GL_OUT_OF_MEMORY) - -#if GL_ARB_imaging - CASE_CODE_RETURN_STR(GL_TABLE_TOO_LARGE) -#endif - -#if defined(WITH_GLU) - CASE_CODE_RETURN_STR(GLU_INVALID_ENUM) - CASE_CODE_RETURN_STR(GLU_INVALID_VALUE) - CASE_CODE_RETURN_STR(GLU_OUT_OF_MEMORY) -#endif +/* control whether we use older AMD_debug_output extension + * some supported GPU + OS combos do not have the newer extensions */ +# define LEGACY_DEBUG 1 - default: - return "<unknown error>"; - } -} - -#undef CASE_CODE_RETURN_STR - - -static bool gpu_report_gl_errors(const char *file, int line, const char *str) -{ - GLenum gl_error = glGetError(); - - if (gl_error == GL_NO_ERROR) { - return true; - } - else { - /* glGetError should have cleared the error flag, so if we get the - * same flag twice that means glGetError itself probably triggered - * the error. This happens on Windows if the GL context is invalid. - */ - { - GLenum new_error = glGetError(); - if (gl_error == new_error) { - fprintf(stderr, "GL: Possible context invalidation issue\n"); - return false; - } - } - - fprintf(stderr, - "%s:%d: ``%s'' -> GL Error (0x%04X - %s): %s\n", - file, line, str, gl_error, - gpu_gl_error_symbol(gl_error), - gpuErrorString(gl_error)); - - return false; - } -} - - -const char *gpuErrorString(GLenum err) -{ - switch (err) { - case GL_NO_ERROR: - return "No Error"; - - case GL_INVALID_ENUM: - return "Invalid Enumeration"; - - case GL_INVALID_VALUE: - return "Invalid Value"; - - case GL_INVALID_OPERATION: - return "Invalid Operation"; - - case GL_STACK_OVERFLOW: - return "Stack Overflow"; - - case GL_STACK_UNDERFLOW: - return "Stack Underflow"; - - case GL_OUT_OF_MEMORY: - return "Out of Memory"; - -#if GL_ARB_imaging - case GL_TABLE_TOO_LARGE: - return "Table Too Large"; -#endif - -#if defined(WITH_GLU) - case GLU_INVALID_ENUM: - return "Invalid Enum (GLU)"; - - case GLU_INVALID_VALUE: - return "Invalid Value (GLU)"; - - case GLU_OUT_OF_MEMORY: - return "Out of Memory (GLU)"; -#endif - - default: - return "<unknown error>"; - } -} - - -/* Debug callbacks need the same calling convention as OpenGL functions. - */ -#if defined(_WIN32) && !defined(_WIN32_WCE) && !defined(__SCITECH_SNAP__) - /* Win32 but not WinCE */ -# define APIENTRY __stdcall -#else -# define APIENTRY -#endif +/* Debug callbacks need the same calling convention as OpenGL functions. */ +# if defined(_WIN32) +# define APIENTRY __stdcall +# else +# define APIENTRY +# endif static const char *source_name(GLenum source) @@ -189,32 +85,11 @@ static const char *message_type_name(GLenum message) } } -static const char *category_name_amd(GLenum category) -{ - switch (category) { - case GL_DEBUG_CATEGORY_API_ERROR_AMD: return "API error"; - case GL_DEBUG_CATEGORY_WINDOW_SYSTEM_AMD: return "window system"; - case GL_DEBUG_CATEGORY_DEPRECATION_AMD: return "deprecated behavior"; - case GL_DEBUG_CATEGORY_UNDEFINED_BEHAVIOR_AMD: return "undefined behavior"; - case GL_DEBUG_CATEGORY_PERFORMANCE_AMD: return "performance"; - case GL_DEBUG_CATEGORY_SHADER_COMPILER_AMD: return "shader compiler"; - case GL_DEBUG_CATEGORY_APPLICATION_AMD: return "application"; - case GL_DEBUG_CATEGORY_OTHER_AMD: return "other"; - default: return "???"; - } -} - - static void APIENTRY gpu_debug_proc( GLenum source, GLenum type, GLuint UNUSED(id), GLenum severity, GLsizei UNUSED(length), const GLchar *message, const GLvoid *UNUSED(userParm)) { - if (type == GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR) { - /* Blender 2.7x uses OpenGL 2.1, we don't care if features are deprecated */ - return; - } - bool backtrace = false; switch (severity) { @@ -233,18 +108,28 @@ static void APIENTRY gpu_debug_proc( } } +# if LEGACY_DEBUG + +static const char *category_name_amd(GLenum category) +{ + switch (category) { + case GL_DEBUG_CATEGORY_API_ERROR_AMD: return "API error"; + case GL_DEBUG_CATEGORY_WINDOW_SYSTEM_AMD: return "window system"; + case GL_DEBUG_CATEGORY_DEPRECATION_AMD: return "deprecated behavior"; + case GL_DEBUG_CATEGORY_UNDEFINED_BEHAVIOR_AMD: return "undefined behavior"; + case GL_DEBUG_CATEGORY_PERFORMANCE_AMD: return "performance"; + case GL_DEBUG_CATEGORY_SHADER_COMPILER_AMD: return "shader compiler"; + case GL_DEBUG_CATEGORY_APPLICATION_AMD: return "application"; + case GL_DEBUG_CATEGORY_OTHER_AMD: return "other"; + default: return "???"; + } +} -#ifndef GLEW_ES_ONLY static void APIENTRY gpu_debug_proc_amd( GLuint UNUSED(id), GLenum category, GLenum severity, GLsizei UNUSED(length), const GLchar *message, GLvoid *UNUSED(userParm)) { - if (category == GL_DEBUG_CATEGORY_DEPRECATION_AMD) { - /* Blender 2.7x uses OpenGL 2.1, we don't care if features are deprecated */ - return; - } - bool backtrace = false; switch (severity) { @@ -261,148 +146,88 @@ static void APIENTRY gpu_debug_proc_amd( fflush(stderr); } } -#endif +# endif /* LEGACY_DEBUG */ - -#undef APIENTRY +# undef APIENTRY +#endif /* not Apple */ void gpu_debug_init(void) { +#ifdef __APPLE__ + fprintf(stderr, "OpenGL debug callback is not available on Apple.\n"); +#else /* not Apple */ const char success[] = "Successfully hooked OpenGL debug callback."; -#if !defined(WITH_GLEW_ES) && !defined(GLEW_ES_ONLY) - if (GLEW_VERSION_4_3) { - fprintf(stderr, "Using OpenGL 4.3 debug facilities\n"); - glEnable(GL_DEBUG_OUTPUT); - glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS); - glDebugMessageCallback((GLDEBUGPROC)gpu_debug_proc, mxGetCurrentContext()); - glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, NULL, GL_TRUE); - GPU_string_marker(success); - return; - } -#endif - - if (GLEW_KHR_debug) { -#ifndef GLEW_ES_ONLY - fprintf(stderr, "Using KHR_debug extension\n"); + if (GLEW_VERSION_4_3 || GLEW_KHR_debug) { + fprintf(stderr, "Using %s\n", GLEW_VERSION_4_3 ? "OpenGL 4.3 debug facilities" : "KHR_debug extension"); glEnable(GL_DEBUG_OUTPUT); glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS); - glDebugMessageCallback((GLDEBUGPROC)gpu_debug_proc, mxGetCurrentContext()); + glDebugMessageCallback((GLDEBUGPROC)gpu_debug_proc, NULL); glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, NULL, GL_TRUE); GPU_string_marker(success); -#endif - return; } - -#ifndef GLEW_ES_ONLY - if (GLEW_ARB_debug_output) { + else if (GLEW_ARB_debug_output) { fprintf(stderr, "Using ARB_debug_output extension\n"); glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS); - glDebugMessageCallbackARB((GLDEBUGPROCARB)gpu_debug_proc, mxGetCurrentContext()); + glDebugMessageCallbackARB((GLDEBUGPROCARB)gpu_debug_proc, NULL); glDebugMessageControlARB(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, NULL, GL_TRUE); GPU_string_marker(success); - - return; } - - if (GLEW_AMD_debug_output) { +# if LEGACY_DEBUG + else if (GLEW_AMD_debug_output) { fprintf(stderr, "Using AMD_debug_output extension\n"); - glDebugMessageCallbackAMD(gpu_debug_proc_amd, mxGetCurrentContext()); + glDebugMessageCallbackAMD(gpu_debug_proc_amd, NULL); glDebugMessageEnableAMD(GL_DONT_CARE, GL_DONT_CARE, 0, NULL, GL_TRUE); GPU_string_marker(success); - - return; } -#endif - - fprintf(stderr, "Failed to hook OpenGL debug callback.\n"); - - return; +# endif + else { + fprintf(stderr, "Failed to hook OpenGL debug callback.\n"); + } +#endif /* not Apple */ } void gpu_debug_exit(void) { -#ifndef WITH_GLEW_ES -#ifndef GLEW_ES_ONLY - if (GLEW_VERSION_4_3) { - glDebugMessageCallback(NULL, NULL); - - return; - } -#endif -#endif - - if (GLEW_KHR_debug) { -#ifndef GLEW_ES_ONLY +#ifndef __APPLE__ + if (GLEW_VERSION_4_3 || GLEW_KHR_debug) { glDebugMessageCallback(NULL, NULL); -#endif - return; } - -#ifndef GLEW_ES_ONLY - if (GLEW_ARB_debug_output) { + else if (GLEW_ARB_debug_output) { glDebugMessageCallbackARB(NULL, NULL); - - return; } - - if (GLEW_AMD_debug_output) { +# if LEGACY_DEBUG + else if (GLEW_AMD_debug_output) { glDebugMessageCallbackAMD(NULL, NULL); - - return; } +# endif #endif - - return; } void GPU_string_marker(const char *buf) { -#ifndef WITH_GLEW_ES -#ifndef GLEW_ES_ONLY - if (GLEW_VERSION_4_3) { - glDebugMessageInsert( - GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_MARKER, 0, - GL_DEBUG_SEVERITY_NOTIFICATION, -1, buf); - - return; - } -#endif -#endif - - if (GLEW_KHR_debug) { -#ifndef GLEW_ES_ONLY +#ifdef __APPLE__ + UNUSED_VARS(buf); +#else /* not Apple */ + if (GLEW_VERSION_4_3 || GLEW_KHR_debug) { glDebugMessageInsert( GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_MARKER, 0, GL_DEBUG_SEVERITY_NOTIFICATION, -1, buf); -#endif - return; } - -#ifndef GLEW_ES_ONLY - if (GLEW_ARB_debug_output) { + else if (GLEW_ARB_debug_output) { glDebugMessageInsertARB( GL_DEBUG_SOURCE_APPLICATION_ARB, GL_DEBUG_TYPE_OTHER_ARB, 0, GL_DEBUG_SEVERITY_LOW_ARB, -1, buf); - - return; } - - if (GLEW_AMD_debug_output) { +# if LEGACY_DEBUG + else if (GLEW_AMD_debug_output) { glDebugMessageInsertAMD( GL_DEBUG_CATEGORY_APPLICATION_AMD, GL_DEBUG_SEVERITY_LOW_AMD, 0, 0, buf); - - return; } - - if (GLEW_GREMEDY_string_marker) { - glStringMarkerGREMEDY(0, buf); - - return; - } -#endif +# endif +#endif /* not Apple */ } void GPU_print_error_debug(const char *str) @@ -410,406 +235,3 @@ void GPU_print_error_debug(const char *str) if (G.debug & G_DEBUG) fprintf(stderr, "GPU: %s\n", str); } - - -void GPU_assert_no_gl_errors(const char *file, int line, const char *str) -{ - if (G.debug) { - GLboolean gl_ok = gpu_report_gl_errors(file, line, str); - - BLI_assert(gl_ok); - (void) gl_ok; - } -} - - -static void gpu_state_print_fl_ex(const char *name, GLenum type) -{ -#define MAX_ARRAY_SIZE 64 - - const unsigned char err_mark[4] = {0xff, 0xff, 0xff, 0xff}; - - float value[MAX_ARRAY_SIZE]; - int a; - - memset(value, 0xff, sizeof(value)); - glGetFloatv(type, value); - - if (glGetError() == GL_NO_ERROR) { - printf("%s: ", name); - for (a = 0; a < MAX_ARRAY_SIZE; a++) { - if (memcmp(&value[a], err_mark, sizeof(value[a])) == 0) { - break; - } - printf("%.2f ", value[a]); - } - printf("\n"); - } - -#undef MAX_ARRAY_SIZE -} - -#define gpu_state_print_fl(val) gpu_state_print_fl_ex(#val, val) - -void GPU_state_print(void) -{ - GPU_ASSERT_NO_GL_ERRORS("GPU_state_print"); /* clear any errors */ - - gpu_state_print_fl(GL_ACCUM_ALPHA_BITS); - gpu_state_print_fl(GL_ACCUM_BLUE_BITS); - gpu_state_print_fl(GL_ACCUM_CLEAR_VALUE); - gpu_state_print_fl(GL_ACCUM_GREEN_BITS); - gpu_state_print_fl(GL_ACCUM_RED_BITS); - gpu_state_print_fl(GL_ACTIVE_TEXTURE); - gpu_state_print_fl(GL_ALIASED_LINE_WIDTH_RANGE); - gpu_state_print_fl(GL_ALIASED_POINT_SIZE_RANGE); - gpu_state_print_fl(GL_ALPHA_BIAS); - gpu_state_print_fl(GL_ALPHA_BITS); - gpu_state_print_fl(GL_ALPHA_SCALE); - gpu_state_print_fl(GL_ALPHA_TEST); - gpu_state_print_fl(GL_ALPHA_TEST_FUNC); - gpu_state_print_fl(GL_ALPHA_TEST_REF); - gpu_state_print_fl(GL_ARRAY_BUFFER_BINDING); - gpu_state_print_fl(GL_ATTRIB_STACK_DEPTH); - gpu_state_print_fl(GL_AUTO_NORMAL); - gpu_state_print_fl(GL_AUX_BUFFERS); - gpu_state_print_fl(GL_BLEND); - gpu_state_print_fl(GL_BLEND_COLOR); - gpu_state_print_fl(GL_BLEND_DST_ALPHA); - gpu_state_print_fl(GL_BLEND_DST_RGB); - gpu_state_print_fl(GL_BLEND_EQUATION_ALPHA); - gpu_state_print_fl(GL_BLEND_EQUATION_RGB); - gpu_state_print_fl(GL_BLEND_SRC_ALPHA); - gpu_state_print_fl(GL_BLEND_SRC_RGB); - gpu_state_print_fl(GL_BLUE_BIAS); - gpu_state_print_fl(GL_BLUE_BITS); - gpu_state_print_fl(GL_BLUE_SCALE); - gpu_state_print_fl(GL_CLIENT_ACTIVE_TEXTURE); - gpu_state_print_fl(GL_CLIENT_ATTRIB_STACK_DEPTH); - gpu_state_print_fl(GL_CLIP_PLANE0); - gpu_state_print_fl(GL_COLOR_ARRAY); - gpu_state_print_fl(GL_COLOR_ARRAY_BUFFER_BINDING); - gpu_state_print_fl(GL_COLOR_ARRAY_SIZE); - gpu_state_print_fl(GL_COLOR_ARRAY_STRIDE); - gpu_state_print_fl(GL_COLOR_ARRAY_TYPE); - gpu_state_print_fl(GL_COLOR_CLEAR_VALUE); - gpu_state_print_fl(GL_COLOR_LOGIC_OP); - gpu_state_print_fl(GL_COLOR_MATERIAL); - gpu_state_print_fl(GL_COLOR_MATERIAL_FACE); - gpu_state_print_fl(GL_COLOR_MATERIAL_PARAMETER); - gpu_state_print_fl(GL_COLOR_MATRIX); - gpu_state_print_fl(GL_COLOR_MATRIX_STACK_DEPTH); - gpu_state_print_fl(GL_COLOR_SUM); - gpu_state_print_fl(GL_COLOR_TABLE); - gpu_state_print_fl(GL_COLOR_WRITEMASK); - gpu_state_print_fl(GL_NUM_COMPRESSED_TEXTURE_FORMATS); - gpu_state_print_fl(GL_COMPRESSED_TEXTURE_FORMATS); - gpu_state_print_fl(GL_CONVOLUTION_1D); - gpu_state_print_fl(GL_CONVOLUTION_2D); - gpu_state_print_fl(GL_CULL_FACE); - gpu_state_print_fl(GL_CULL_FACE_MODE); - gpu_state_print_fl(GL_CURRENT_COLOR); - gpu_state_print_fl(GL_CURRENT_FOG_COORD); - gpu_state_print_fl(GL_CURRENT_INDEX); - gpu_state_print_fl(GL_CURRENT_NORMAL); - gpu_state_print_fl(GL_CURRENT_PROGRAM); - gpu_state_print_fl(GL_CURRENT_RASTER_COLOR); - gpu_state_print_fl(GL_CURRENT_RASTER_DISTANCE); - gpu_state_print_fl(GL_CURRENT_RASTER_INDEX); - gpu_state_print_fl(GL_CURRENT_RASTER_POSITION); - gpu_state_print_fl(GL_CURRENT_RASTER_POSITION_VALID); - gpu_state_print_fl(GL_CURRENT_RASTER_SECONDARY_COLOR); - gpu_state_print_fl(GL_CURRENT_RASTER_TEXTURE_COORDS); - gpu_state_print_fl(GL_CURRENT_SECONDARY_COLOR); - gpu_state_print_fl(GL_CURRENT_TEXTURE_COORDS); - gpu_state_print_fl(GL_DEPTH_BIAS); - gpu_state_print_fl(GL_DEPTH_BITS); - gpu_state_print_fl(GL_DEPTH_CLEAR_VALUE); - gpu_state_print_fl(GL_DEPTH_FUNC); - gpu_state_print_fl(GL_DEPTH_RANGE); - gpu_state_print_fl(GL_DEPTH_SCALE); - gpu_state_print_fl(GL_DEPTH_TEST); - gpu_state_print_fl(GL_DEPTH_WRITEMASK); - gpu_state_print_fl(GL_DITHER); - gpu_state_print_fl(GL_DOUBLEBUFFER); - gpu_state_print_fl(GL_DRAW_BUFFER); - gpu_state_print_fl(GL_DRAW_BUFFER0); - gpu_state_print_fl(GL_EDGE_FLAG); - gpu_state_print_fl(GL_EDGE_FLAG_ARRAY); - gpu_state_print_fl(GL_EDGE_FLAG_ARRAY_BUFFER_BINDING); - gpu_state_print_fl(GL_EDGE_FLAG_ARRAY_STRIDE); - gpu_state_print_fl(GL_ELEMENT_ARRAY_BUFFER_BINDING); - gpu_state_print_fl(GL_FEEDBACK_BUFFER_SIZE); - gpu_state_print_fl(GL_FEEDBACK_BUFFER_TYPE); - gpu_state_print_fl(GL_FOG); - gpu_state_print_fl(GL_FOG_COLOR); - gpu_state_print_fl(GL_FOG_COORD_ARRAY); - gpu_state_print_fl(GL_FOG_COORD_ARRAY_BUFFER_BINDING); - gpu_state_print_fl(GL_FOG_COORD_ARRAY_STRIDE); - gpu_state_print_fl(GL_FOG_COORD_ARRAY_TYPE); - gpu_state_print_fl(GL_FOG_COORD_SRC); - gpu_state_print_fl(GL_FOG_DENSITY); - gpu_state_print_fl(GL_FOG_END); - gpu_state_print_fl(GL_FOG_HINT); - gpu_state_print_fl(GL_FOG_INDEX); - gpu_state_print_fl(GL_FOG_MODE); - gpu_state_print_fl(GL_FOG_START); - gpu_state_print_fl(GL_FRAGMENT_PROGRAM_ARB); /* TODO: remove ARB program support */ - gpu_state_print_fl(GL_FRAGMENT_SHADER_DERIVATIVE_HINT); - gpu_state_print_fl(GL_FRONT_FACE); - gpu_state_print_fl(GL_GENERATE_MIPMAP_HINT); - gpu_state_print_fl(GL_GREEN_BIAS); - gpu_state_print_fl(GL_GREEN_BITS); - gpu_state_print_fl(GL_GREEN_SCALE); - gpu_state_print_fl(GL_HISTOGRAM); - gpu_state_print_fl(GL_INDEX_ARRAY); - gpu_state_print_fl(GL_INDEX_ARRAY_BUFFER_BINDING); - gpu_state_print_fl(GL_INDEX_ARRAY_STRIDE); - gpu_state_print_fl(GL_INDEX_ARRAY_TYPE); - gpu_state_print_fl(GL_INDEX_BITS); - gpu_state_print_fl(GL_INDEX_CLEAR_VALUE); - gpu_state_print_fl(GL_INDEX_LOGIC_OP); - gpu_state_print_fl(GL_INDEX_MODE); - gpu_state_print_fl(GL_INDEX_OFFSET); - gpu_state_print_fl(GL_INDEX_SHIFT); - gpu_state_print_fl(GL_INDEX_WRITEMASK); - gpu_state_print_fl(GL_LIGHT0); - gpu_state_print_fl(GL_LIGHT1); - gpu_state_print_fl(GL_LIGHT2); - gpu_state_print_fl(GL_LIGHT3); - gpu_state_print_fl(GL_LIGHT4); - gpu_state_print_fl(GL_LIGHT5); - gpu_state_print_fl(GL_LIGHT6); - gpu_state_print_fl(GL_LIGHT7); - gpu_state_print_fl(GL_LIGHTING); - gpu_state_print_fl(GL_LIGHT_MODEL_AMBIENT); - gpu_state_print_fl(GL_LIGHT_MODEL_COLOR_CONTROL); - gpu_state_print_fl(GL_LIGHT_MODEL_LOCAL_VIEWER); - gpu_state_print_fl(GL_LIGHT_MODEL_TWO_SIDE); - gpu_state_print_fl(GL_LINE_SMOOTH); - gpu_state_print_fl(GL_LINE_SMOOTH_HINT); - gpu_state_print_fl(GL_LINE_STIPPLE); - gpu_state_print_fl(GL_LINE_STIPPLE_PATTERN); - gpu_state_print_fl(GL_LINE_STIPPLE_REPEAT); - gpu_state_print_fl(GL_LINE_WIDTH); - gpu_state_print_fl(GL_LINE_WIDTH_GRANULARITY); - gpu_state_print_fl(GL_LINE_WIDTH_RANGE); - gpu_state_print_fl(GL_LIST_BASE); - gpu_state_print_fl(GL_LIST_INDEX); - gpu_state_print_fl(GL_LIST_MODE); - gpu_state_print_fl(GL_LOGIC_OP); - gpu_state_print_fl(GL_LOGIC_OP_MODE); - gpu_state_print_fl(GL_MAP1_COLOR_4); - gpu_state_print_fl(GL_MAP1_GRID_DOMAIN); - gpu_state_print_fl(GL_MAP1_GRID_SEGMENTS); - gpu_state_print_fl(GL_MAP1_INDEX); - gpu_state_print_fl(GL_MAP1_NORMAL); - gpu_state_print_fl(GL_MAP1_TEXTURE_COORD_1); - gpu_state_print_fl(GL_MAP1_TEXTURE_COORD_2); - gpu_state_print_fl(GL_MAP1_TEXTURE_COORD_3); - gpu_state_print_fl(GL_MAP1_TEXTURE_COORD_4); - gpu_state_print_fl(GL_MAP1_VERTEX_3); - gpu_state_print_fl(GL_MAP1_VERTEX_4); - gpu_state_print_fl(GL_MAP2_COLOR_4); - gpu_state_print_fl(GL_MAP2_GRID_DOMAIN); - gpu_state_print_fl(GL_MAP2_GRID_SEGMENTS); - gpu_state_print_fl(GL_MAP2_INDEX); - gpu_state_print_fl(GL_MAP2_NORMAL); - gpu_state_print_fl(GL_MAP2_TEXTURE_COORD_1); - gpu_state_print_fl(GL_MAP2_TEXTURE_COORD_2); - gpu_state_print_fl(GL_MAP2_TEXTURE_COORD_3); - gpu_state_print_fl(GL_MAP2_TEXTURE_COORD_4); - gpu_state_print_fl(GL_MAP2_VERTEX_3); - gpu_state_print_fl(GL_MAP2_VERTEX_4); - gpu_state_print_fl(GL_MAP_COLOR); - gpu_state_print_fl(GL_MAP_STENCIL); - gpu_state_print_fl(GL_MATRIX_MODE); - gpu_state_print_fl(GL_MAX_3D_TEXTURE_SIZE); - gpu_state_print_fl(GL_MAX_ATTRIB_STACK_DEPTH); - gpu_state_print_fl(GL_MAX_CLIENT_ATTRIB_STACK_DEPTH); - gpu_state_print_fl(GL_MAX_CLIP_PLANES); - gpu_state_print_fl(GL_MAX_COLOR_MATRIX_STACK_DEPTH); - gpu_state_print_fl(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS); - gpu_state_print_fl(GL_MAX_CUBE_MAP_TEXTURE_SIZE); - gpu_state_print_fl(GL_MAX_DRAW_BUFFERS); - gpu_state_print_fl(GL_MAX_ELEMENTS_INDICES); - gpu_state_print_fl(GL_MAX_ELEMENTS_VERTICES); - gpu_state_print_fl(GL_MAX_EVAL_ORDER); - gpu_state_print_fl(GL_MAX_FRAGMENT_UNIFORM_COMPONENTS); - gpu_state_print_fl(GL_MAX_LIGHTS); - gpu_state_print_fl(GL_MAX_LIST_NESTING); - gpu_state_print_fl(GL_MAX_MODELVIEW_STACK_DEPTH); - gpu_state_print_fl(GL_MAX_NAME_STACK_DEPTH); - gpu_state_print_fl(GL_MAX_PIXEL_MAP_TABLE); - gpu_state_print_fl(GL_MAX_PROJECTION_STACK_DEPTH); - gpu_state_print_fl(GL_MAX_TEXTURE_COORDS); - gpu_state_print_fl(GL_MAX_TEXTURE_IMAGE_UNITS); - gpu_state_print_fl(GL_MAX_TEXTURE_LOD_BIAS); - gpu_state_print_fl(GL_MAX_TEXTURE_SIZE); - gpu_state_print_fl(GL_MAX_TEXTURE_STACK_DEPTH); - gpu_state_print_fl(GL_MAX_TEXTURE_UNITS); - gpu_state_print_fl(GL_MAX_VARYING_FLOATS); - gpu_state_print_fl(GL_MAX_VERTEX_ATTRIBS); - gpu_state_print_fl(GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS); - gpu_state_print_fl(GL_MAX_VERTEX_UNIFORM_COMPONENTS); - gpu_state_print_fl(GL_MAX_VIEWPORT_DIMS); - gpu_state_print_fl(GL_MINMAX); - gpu_state_print_fl(GL_MODELVIEW_MATRIX); - gpu_state_print_fl(GL_MODELVIEW_STACK_DEPTH); - gpu_state_print_fl(GL_MULTISAMPLE); - gpu_state_print_fl(GL_NAME_STACK_DEPTH); - gpu_state_print_fl(GL_NORMALIZE); - gpu_state_print_fl(GL_NORMAL_ARRAY); - gpu_state_print_fl(GL_NORMAL_ARRAY_BUFFER_BINDING); - gpu_state_print_fl(GL_NORMAL_ARRAY_STRIDE); - gpu_state_print_fl(GL_NORMAL_ARRAY_TYPE); - gpu_state_print_fl(GL_NUM_COMPRESSED_TEXTURE_FORMATS); - gpu_state_print_fl(GL_PACK_ALIGNMENT); - gpu_state_print_fl(GL_PACK_IMAGE_HEIGHT); - gpu_state_print_fl(GL_PACK_LSB_FIRST); - gpu_state_print_fl(GL_PACK_ROW_LENGTH); - gpu_state_print_fl(GL_PACK_SKIP_IMAGES); - gpu_state_print_fl(GL_PACK_SKIP_PIXELS); - gpu_state_print_fl(GL_PACK_SKIP_ROWS); - gpu_state_print_fl(GL_PACK_SWAP_BYTES); - gpu_state_print_fl(GL_PERSPECTIVE_CORRECTION_HINT); - gpu_state_print_fl(GL_PIXEL_MAP_A_TO_A_SIZE); - gpu_state_print_fl(GL_PIXEL_MAP_B_TO_B_SIZE); - gpu_state_print_fl(GL_PIXEL_MAP_G_TO_G_SIZE); - gpu_state_print_fl(GL_PIXEL_MAP_I_TO_A_SIZE); - gpu_state_print_fl(GL_PIXEL_MAP_I_TO_B_SIZE); - gpu_state_print_fl(GL_PIXEL_MAP_I_TO_G_SIZE); - gpu_state_print_fl(GL_PIXEL_MAP_I_TO_I_SIZE); - gpu_state_print_fl(GL_PIXEL_MAP_I_TO_R_SIZE); - gpu_state_print_fl(GL_PIXEL_MAP_R_TO_R_SIZE); - gpu_state_print_fl(GL_PIXEL_MAP_S_TO_S_SIZE); - gpu_state_print_fl(GL_PIXEL_PACK_BUFFER_BINDING); - gpu_state_print_fl(GL_PIXEL_UNPACK_BUFFER_BINDING); - gpu_state_print_fl(GL_POINT_DISTANCE_ATTENUATION); - gpu_state_print_fl(GL_POINT_FADE_THRESHOLD_SIZE); - gpu_state_print_fl(GL_POINT_SIZE); - gpu_state_print_fl(GL_POINT_SIZE_GRANULARITY); - gpu_state_print_fl(GL_POINT_SIZE_MAX); - gpu_state_print_fl(GL_POINT_SIZE_MIN); - gpu_state_print_fl(GL_POINT_SIZE_RANGE); - gpu_state_print_fl(GL_POINT_SMOOTH); - gpu_state_print_fl(GL_POINT_SMOOTH_HINT); - gpu_state_print_fl(GL_POINT_SPRITE); - gpu_state_print_fl(GL_POLYGON_MODE); - gpu_state_print_fl(GL_POLYGON_OFFSET_FACTOR); - gpu_state_print_fl(GL_POLYGON_OFFSET_FILL); - gpu_state_print_fl(GL_POLYGON_OFFSET_LINE); - gpu_state_print_fl(GL_POLYGON_OFFSET_POINT); - gpu_state_print_fl(GL_POLYGON_OFFSET_UNITS); - gpu_state_print_fl(GL_POLYGON_SMOOTH); - gpu_state_print_fl(GL_POLYGON_SMOOTH_HINT); - gpu_state_print_fl(GL_POLYGON_STIPPLE); - gpu_state_print_fl(GL_POST_COLOR_MATRIX_ALPHA_BIAS); - gpu_state_print_fl(GL_POST_COLOR_MATRIX_ALPHA_SCALE); - gpu_state_print_fl(GL_POST_COLOR_MATRIX_BLUE_BIAS); - gpu_state_print_fl(GL_POST_COLOR_MATRIX_BLUE_SCALE); - gpu_state_print_fl(GL_POST_COLOR_MATRIX_COLOR_TABLE); - gpu_state_print_fl(GL_POST_COLOR_MATRIX_GREEN_BIAS); - gpu_state_print_fl(GL_POST_COLOR_MATRIX_GREEN_SCALE); - gpu_state_print_fl(GL_POST_COLOR_MATRIX_RED_BIAS); - gpu_state_print_fl(GL_POST_COLOR_MATRIX_RED_SCALE); - gpu_state_print_fl(GL_POST_CONVOLUTION_ALPHA_BIAS); - gpu_state_print_fl(GL_POST_CONVOLUTION_ALPHA_SCALE); - gpu_state_print_fl(GL_POST_CONVOLUTION_BLUE_BIAS); - gpu_state_print_fl(GL_POST_CONVOLUTION_BLUE_SCALE); - gpu_state_print_fl(GL_POST_CONVOLUTION_COLOR_TABLE); - gpu_state_print_fl(GL_POST_CONVOLUTION_GREEN_BIAS); - gpu_state_print_fl(GL_POST_CONVOLUTION_GREEN_SCALE); - gpu_state_print_fl(GL_POST_CONVOLUTION_RED_BIAS); - gpu_state_print_fl(GL_POST_CONVOLUTION_RED_SCALE); - gpu_state_print_fl(GL_PROJECTION_MATRIX); - gpu_state_print_fl(GL_PROJECTION_STACK_DEPTH); - gpu_state_print_fl(GL_READ_BUFFER); - gpu_state_print_fl(GL_RED_BIAS); - gpu_state_print_fl(GL_RED_BITS); - gpu_state_print_fl(GL_RED_SCALE); - gpu_state_print_fl(GL_RENDER_MODE); - gpu_state_print_fl(GL_RESCALE_NORMAL); - gpu_state_print_fl(GL_RGBA_MODE); - gpu_state_print_fl(GL_SAMPLES); - gpu_state_print_fl(GL_SAMPLE_BUFFERS); - gpu_state_print_fl(GL_SAMPLE_COVERAGE_INVERT); - gpu_state_print_fl(GL_SAMPLE_COVERAGE_VALUE); - gpu_state_print_fl(GL_SCISSOR_BOX); - gpu_state_print_fl(GL_SCISSOR_TEST); - gpu_state_print_fl(GL_SECONDARY_COLOR_ARRAY); - gpu_state_print_fl(GL_SECONDARY_COLOR_ARRAY_BUFFER_BINDING); - gpu_state_print_fl(GL_SECONDARY_COLOR_ARRAY_SIZE); - gpu_state_print_fl(GL_SECONDARY_COLOR_ARRAY_STRIDE); - gpu_state_print_fl(GL_SECONDARY_COLOR_ARRAY_TYPE); - gpu_state_print_fl(GL_SELECTION_BUFFER_SIZE); - gpu_state_print_fl(GL_SEPARABLE_2D); - gpu_state_print_fl(GL_SHADE_MODEL); - gpu_state_print_fl(GL_SMOOTH_LINE_WIDTH_GRANULARITY); - gpu_state_print_fl(GL_SMOOTH_LINE_WIDTH_RANGE); - gpu_state_print_fl(GL_SMOOTH_POINT_SIZE_GRANULARITY); - gpu_state_print_fl(GL_SMOOTH_POINT_SIZE_RANGE); - gpu_state_print_fl(GL_STENCIL_BACK_FAIL); - gpu_state_print_fl(GL_STENCIL_BACK_FUNC); - gpu_state_print_fl(GL_STENCIL_BACK_PASS_DEPTH_FAIL); - gpu_state_print_fl(GL_STENCIL_BACK_PASS_DEPTH_PASS); - gpu_state_print_fl(GL_STENCIL_BACK_REF); - gpu_state_print_fl(GL_STENCIL_BACK_VALUE_MASK); - gpu_state_print_fl(GL_STENCIL_BACK_WRITEMASK); - gpu_state_print_fl(GL_STENCIL_BITS); - gpu_state_print_fl(GL_STENCIL_CLEAR_VALUE); - gpu_state_print_fl(GL_STENCIL_FAIL); - gpu_state_print_fl(GL_STENCIL_FUNC); - gpu_state_print_fl(GL_STENCIL_PASS_DEPTH_FAIL); - gpu_state_print_fl(GL_STENCIL_PASS_DEPTH_PASS); - gpu_state_print_fl(GL_STENCIL_REF); - gpu_state_print_fl(GL_STENCIL_TEST); - gpu_state_print_fl(GL_STENCIL_VALUE_MASK); - gpu_state_print_fl(GL_STENCIL_WRITEMASK); - gpu_state_print_fl(GL_STEREO); - gpu_state_print_fl(GL_SUBPIXEL_BITS); - gpu_state_print_fl(GL_TEXTURE_1D); - gpu_state_print_fl(GL_TEXTURE_2D); - gpu_state_print_fl(GL_TEXTURE_3D); - gpu_state_print_fl(GL_TEXTURE_BINDING_1D); - gpu_state_print_fl(GL_TEXTURE_BINDING_2D); - gpu_state_print_fl(GL_TEXTURE_BINDING_3D); - gpu_state_print_fl(GL_TEXTURE_BINDING_CUBE_MAP); - gpu_state_print_fl(GL_TEXTURE_COMPRESSION_HINT); - gpu_state_print_fl(GL_TEXTURE_COORD_ARRAY); - gpu_state_print_fl(GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING); - gpu_state_print_fl(GL_TEXTURE_COORD_ARRAY_SIZE); - gpu_state_print_fl(GL_TEXTURE_COORD_ARRAY_STRIDE); - gpu_state_print_fl(GL_TEXTURE_COORD_ARRAY_TYPE); - gpu_state_print_fl(GL_TEXTURE_CUBE_MAP); - gpu_state_print_fl(GL_TEXTURE_GEN_Q); - gpu_state_print_fl(GL_TEXTURE_GEN_R); - gpu_state_print_fl(GL_TEXTURE_GEN_S); - gpu_state_print_fl(GL_TEXTURE_GEN_T); - gpu_state_print_fl(GL_TEXTURE_MATRIX); - gpu_state_print_fl(GL_TEXTURE_STACK_DEPTH); - gpu_state_print_fl(GL_TRANSPOSE_COLOR_MATRIX); - gpu_state_print_fl(GL_TRANSPOSE_MODELVIEW_MATRIX); - gpu_state_print_fl(GL_TRANSPOSE_PROJECTION_MATRIX); - gpu_state_print_fl(GL_TRANSPOSE_TEXTURE_MATRIX); - gpu_state_print_fl(GL_UNPACK_ALIGNMENT); - gpu_state_print_fl(GL_UNPACK_IMAGE_HEIGHT); - gpu_state_print_fl(GL_UNPACK_LSB_FIRST); - gpu_state_print_fl(GL_UNPACK_ROW_LENGTH); - gpu_state_print_fl(GL_UNPACK_SKIP_IMAGES); - gpu_state_print_fl(GL_UNPACK_SKIP_PIXELS); - gpu_state_print_fl(GL_UNPACK_SKIP_ROWS); - gpu_state_print_fl(GL_UNPACK_SWAP_BYTES); - gpu_state_print_fl(GL_VERTEX_ARRAY); - gpu_state_print_fl(GL_VERTEX_ARRAY_BUFFER_BINDING); - gpu_state_print_fl(GL_VERTEX_ARRAY_SIZE); - gpu_state_print_fl(GL_VERTEX_ARRAY_STRIDE); - gpu_state_print_fl(GL_VERTEX_ARRAY_TYPE); - gpu_state_print_fl(GL_VERTEX_PROGRAM_POINT_SIZE); - gpu_state_print_fl(GL_VERTEX_PROGRAM_TWO_SIDE); - gpu_state_print_fl(GL_VIEWPORT); - gpu_state_print_fl(GL_ZOOM_X); - gpu_state_print_fl(GL_ZOOM_Y); -} - -#undef gpu_state_print_fl diff --git a/source/blender/gpu/intern/gpu_draw.c b/source/blender/gpu/intern/gpu_draw.c index 514f2f71bd7..7bfebb702a1 100644 --- a/source/blender/gpu/intern/gpu_draw.c +++ b/source/blender/gpu/intern/gpu_draw.c @@ -31,15 +31,13 @@ * Utility functions for dealing with OpenGL texture & material context, * mipmap generation and light objects. * - * These are some obscure rendering functions shared between the - * game engine and the blender, in this module to avoid duplication + * These are some obscure rendering functions shared between the game engine (not anymore) + * and the blender, in this module to avoid duplication * and abstract them away from the rest a bit. */ #include <string.h> -#include "GPU_glew.h" - #include "BLI_blenlib.h" #include "BLI_hash.h" #include "BLI_linklist.h" @@ -72,15 +70,12 @@ #include "BKE_node.h" #include "BKE_scene.h" #include "BKE_DerivedMesh.h" -#ifdef WITH_GAMEENGINE -# include "BKE_object.h" -#endif #include "GPU_basic_shader.h" -#include "GPU_buffers.h" #include "GPU_draw.h" #include "GPU_extensions.h" #include "GPU_material.h" +#include "GPU_matrix.h" #include "GPU_shader.h" #include "GPU_texture.h" @@ -99,141 +94,20 @@ extern Material defmaterial; /* from material.c */ -/* Text Rendering */ - -static void gpu_mcol(unsigned int ucol) -{ - /* mcol order is swapped */ - const char *cp = (char *)&ucol; - glColor3ub(cp[3], cp[2], cp[1]); -} - -void GPU_render_text( - MTexPoly *mtexpoly, int mode, - const char *textstr, int textlen, unsigned int *col, - const float *v_quad[4], const float *uv_quad[4], - int glattrib) -{ - if ((mode & GEMAT_TEXT) && (textlen > 0) && mtexpoly->tpage) { - const float *v1 = v_quad[0]; - const float *v2 = v_quad[1]; - const float *v3 = v_quad[2]; - const float *v4 = v_quad[3]; - Image *ima = (Image *)mtexpoly->tpage; - const size_t textlen_st = textlen; - float centerx, centery, sizex, sizey, transx, transy, movex, movey, advance; - - /* multiline */ - float line_start = 0.0f, line_height; - - if (v4) - line_height = max_ffff(v1[1], v2[1], v3[1], v4[2]) - min_ffff(v1[1], v2[1], v3[1], v4[2]); - else - line_height = max_fff(v1[1], v2[1], v3[1]) - min_fff(v1[1], v2[1], v3[1]); - line_height *= 1.2f; /* could be an option? */ - /* end multiline */ - - - /* color has been set */ - if (mtexpoly->mode & TF_OBCOL) - col = NULL; - else if (!col) - glColor3f(1.0f, 1.0f, 1.0f); - - glPushMatrix(); - - /* get the tab width */ - ImBuf *first_ibuf = BKE_image_get_first_ibuf(ima); - matrixGlyph(first_ibuf, ' ', ¢erx, ¢ery, - &sizex, &sizey, &transx, &transy, &movex, &movey, &advance); - - float advance_tab = advance * 4; /* tab width could also be an option */ - - - for (size_t index = 0; index < textlen_st; ) { - unsigned int character; - float uv[4][2]; - - /* lets calculate offset stuff */ - character = BLI_str_utf8_as_unicode_and_size_safe(textstr + index, &index); - - if (character == '\n') { - glTranslatef(line_start, -line_height, 0.0f); - line_start = 0.0f; - continue; - } - else if (character == '\t') { - glTranslatef(advance_tab, 0.0f, 0.0f); - line_start -= advance_tab; /* so we can go back to the start of the line */ - continue; - - } - else if (character > USHRT_MAX) { - /* not much we can do here bmfonts take ushort */ - character = '?'; - } - - /* space starts at offset 1 */ - /* character = character - ' ' + 1; */ - matrixGlyph(first_ibuf, character, & centerx, ¢ery, - &sizex, &sizey, &transx, &transy, &movex, &movey, &advance); - - uv[0][0] = (uv_quad[0][0] - centerx) * sizex + transx; - uv[0][1] = (uv_quad[0][1] - centery) * sizey + transy; - uv[1][0] = (uv_quad[1][0] - centerx) * sizex + transx; - uv[1][1] = (uv_quad[1][1] - centery) * sizey + transy; - uv[2][0] = (uv_quad[2][0] - centerx) * sizex + transx; - uv[2][1] = (uv_quad[2][1] - centery) * sizey + transy; - - glBegin(GL_POLYGON); - if (glattrib >= 0) glVertexAttrib2fv(glattrib, uv[0]); - else glTexCoord2fv(uv[0]); - if (col) gpu_mcol(col[0]); - glVertex3f(sizex * v1[0] + movex, sizey * v1[1] + movey, v1[2]); - - if (glattrib >= 0) glVertexAttrib2fv(glattrib, uv[1]); - else glTexCoord2fv(uv[1]); - if (col) gpu_mcol(col[1]); - glVertex3f(sizex * v2[0] + movex, sizey * v2[1] + movey, v2[2]); - - if (glattrib >= 0) glVertexAttrib2fv(glattrib, uv[2]); - else glTexCoord2fv(uv[2]); - if (col) gpu_mcol(col[2]); - glVertex3f(sizex * v3[0] + movex, sizey * v3[1] + movey, v3[2]); - - if (v4) { - uv[3][0] = (uv_quad[3][0] - centerx) * sizex + transx; - uv[3][1] = (uv_quad[3][1] - centery) * sizey + transy; - - if (glattrib >= 0) glVertexAttrib2fv(glattrib, uv[3]); - else glTexCoord2fv(uv[3]); - if (col) gpu_mcol(col[3]); - glVertex3f(sizex * v4[0] + movex, sizey * v4[1] + movey, v4[2]); - } - glEnd(); - - glTranslatef(advance, 0.0f, 0.0f); - line_start -= advance; /* so we can go back to the start of the line */ - } - glPopMatrix(); - - BKE_image_release_ibuf(ima, first_ibuf, NULL); - } -} - -/* Checking powers of two for images since OpenGL ES requires it */ - +//* Checking powers of two for images since OpenGL ES requires it */ +#ifdef WITH_DDS static bool is_power_of_2_resolution(int w, int h) { return is_power_of_2_i(w) && is_power_of_2_i(h); } +#endif static bool is_over_resolution_limit(GLenum textarget, int w, int h) { int size = (textarget == GL_TEXTURE_2D) ? GPU_max_texture_size() : GPU_max_cube_map_size(); int reslimit = (U.glreslimit != 0) ? - min_ii(U.glreslimit, size) : size; + min_ii(U.glreslimit, size) : size; return (w > reslimit || h > reslimit); } @@ -253,10 +127,6 @@ static int smaller_power_of_2_limit(int num) /* Current OpenGL state caching for GPU_set_tpage */ static struct GPUTextureState { - int curtile, tile; - int curtilemode, tilemode; - int curtileXRep, tileXRep; - int curtileYRep, tileYRep; Image *ima, *curima; /* also controls min/mag filtering */ @@ -269,8 +139,7 @@ static struct GPUTextureState { int alphablend; float anisotropic; int gpu_mipmap; - MTexPoly *lasttface; -} GTS = {0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, 1, 0, 0, -1, 1.0f, 0, NULL}; +} GTS = {NULL, NULL, 1, 0, 0, -1, 1.0f, 0}; /* Mipmap settings */ @@ -279,36 +148,13 @@ void GPU_set_gpu_mipmapping(int gpu_mipmap) int old_value = GTS.gpu_mipmap; /* only actually enable if it's supported */ - GTS.gpu_mipmap = gpu_mipmap && GLEW_EXT_framebuffer_object; + GTS.gpu_mipmap = gpu_mipmap; if (old_value != GTS.gpu_mipmap) { GPU_free_images(); } } -static void gpu_generate_mipmap(GLenum target) -{ - const bool is_ati = GPU_type_matches(GPU_DEVICE_ATI, GPU_OS_ANY, GPU_DRIVER_ANY); - int target_enabled = 0; - - /* work around bug in ATI driver, need to have GL_TEXTURE_2D enabled - * http://www.opengl.org/wiki/Common_Mistakes#Automatic_mipmap_generation */ - if (is_ati) { - target_enabled = glIsEnabled(target); - if (!target_enabled) - glEnable(target); - } - - /* TODO: simplify when we transition to GL >= 3 */ - if (GLEW_VERSION_3_0 || GLEW_ARB_framebuffer_object) - glGenerateMipmap(target); - else if (GLEW_EXT_framebuffer_object) - glGenerateMipmapEXT(target); - - if (is_ati && !target_enabled) - glDisable(target); -} - void GPU_set_mipmap(bool mipmap) { if (GTS.domipmap != mipmap) { @@ -381,28 +227,6 @@ float GPU_get_anisotropic(void) /* Set OpenGL state for an MTFace */ -static void gpu_make_repbind(Image *ima) -{ - ImBuf *ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL); - if (ibuf == NULL) - return; - - if (ima->repbind) { - glDeleteTextures(ima->totbind, (GLuint *)ima->repbind); - MEM_freeN(ima->repbind); - ima->repbind = NULL; - ima->tpageflag &= ~IMA_MIPMAP_COMPLETE; - } - - ima->totbind = ima->xrep * ima->yrep; - - if (ima->totbind > 1) { - ima->repbind = MEM_callocN(sizeof(int) * ima->totbind, "repbind"); - } - - BKE_image_release_ibuf(ima, ibuf, NULL); -} - static unsigned int *gpu_get_image_bindcode(Image *ima, GLenum textarget) { unsigned int *bind = 0; @@ -415,104 +239,6 @@ static unsigned int *gpu_get_image_bindcode(Image *ima, GLenum textarget) return bind; } -void GPU_clear_tpage(bool force) -{ - if (GTS.lasttface == NULL && !force) - return; - - GTS.lasttface = NULL; - GTS.curtile = 0; - GTS.curima = NULL; - if (GTS.curtilemode != 0) { - glMatrixMode(GL_TEXTURE); - glLoadIdentity(); - glMatrixMode(GL_MODELVIEW); - } - GTS.curtilemode = 0; - GTS.curtileXRep = 0; - GTS.curtileYRep = 0; - GTS.alphablend = -1; - - glDisable(GL_BLEND); - glDisable(GL_TEXTURE_2D); - glDisable(GL_TEXTURE_GEN_S); - glDisable(GL_TEXTURE_GEN_T); - glDisable(GL_ALPHA_TEST); -} - -static void gpu_set_alpha_blend(GPUBlendMode alphablend) -{ - if (alphablend == GPU_BLEND_SOLID) { - glDisable(GL_BLEND); - glDisable(GL_ALPHA_TEST); - glDisable(GL_SAMPLE_ALPHA_TO_COVERAGE); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - } - else if (alphablend == GPU_BLEND_ADD) { - glEnable(GL_BLEND); - glBlendFunc(GL_ONE, GL_ONE); - glDisable(GL_ALPHA_TEST); - glDisable(GL_SAMPLE_ALPHA_TO_COVERAGE); - } - else if (ELEM(alphablend, GPU_BLEND_ALPHA, GPU_BLEND_ALPHA_SORT)) { - glEnable(GL_BLEND); - glDisable(GL_SAMPLE_ALPHA_TO_COVERAGE); - - /* for OpenGL render we use the alpha channel, this makes alpha blend correct */ - glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); - - /* if U.glalphaclip == 1.0, some cards go bonkers... - * turn off alpha test in this case */ - - /* added after 2.45 to clip alpha */ - if (U.glalphaclip == 1.0f) { - glDisable(GL_ALPHA_TEST); - } - else { - glEnable(GL_ALPHA_TEST); - glAlphaFunc(GL_GREATER, U.glalphaclip); - } - } - else if (alphablend == GPU_BLEND_CLIP) { - glDisable(GL_BLEND); - glDisable(GL_SAMPLE_ALPHA_TO_COVERAGE); - glEnable(GL_ALPHA_TEST); - glAlphaFunc(GL_GREATER, 0.5f); - } - else if (alphablend == GPU_BLEND_ALPHA_TO_COVERAGE) { - glEnable(GL_ALPHA_TEST); - glAlphaFunc(GL_GREATER, U.glalphaclip); - glEnable(GL_SAMPLE_ALPHA_TO_COVERAGE); - } -} - -static void gpu_verify_alpha_blend(int alphablend) -{ - /* verify alpha blending modes */ - if (GTS.alphablend == alphablend) - return; - - gpu_set_alpha_blend(alphablend); - GTS.alphablend = alphablend; -} - -static void gpu_verify_reflection(Image *ima) -{ - if (ima && (ima->flag & IMA_REFLECT)) { - /* enable reflection mapping */ - glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP); - glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP); - - glEnable(GL_TEXTURE_GEN_S); - glEnable(GL_TEXTURE_GEN_T); - } - else { - /* disable reflection mapping */ - glDisable(GL_TEXTURE_GEN_S); - glDisable(GL_TEXTURE_GEN_T); - } -} - typedef struct VerifyThreadData { ImBuf *ibuf; float *srgb_frect; @@ -534,8 +260,6 @@ static void gpu_verify_high_bit_srgb_buffer_slice(float *srgb_frect, ibuf->x, height, ibuf->x, ibuf->x); IMB_buffer_float_unpremultiply(current_srgb_frect, ibuf->x, height); - /* Clamp buffer colors to 1.0 to avoid artifacts due to glu for hdr images. */ - IMB_buffer_float_clamp(current_srgb_frect, ibuf->x, height); } static void verify_thread_do(void *data_v, @@ -567,7 +291,7 @@ static void gpu_verify_high_bit_srgb_buffer(float *srgb_frect, int GPU_verify_image( Image *ima, ImageUser *iuser, - int textarget, int tftile, bool compare, bool mipmap, bool is_data) + int textarget, bool compare, bool mipmap, bool is_data) { unsigned int *bind = NULL; int tpx = 0, tpy = 0; @@ -577,46 +301,12 @@ int GPU_verify_image( /* flag to determine whether deep format is used */ bool use_high_bit_depth = false, do_color_management = false; - /* initialize tile mode and number of repeats */ GTS.ima = ima; - GTS.tilemode = (ima && (ima->tpageflag & (IMA_TILES | IMA_TWINANIM))); - GTS.tileXRep = 0; - GTS.tileYRep = 0; - - /* setting current tile according to frame */ - if (ima && (ima->tpageflag & IMA_TWINANIM)) - GTS.tile = ima->lastframe; - else - GTS.tile = tftile; - - GTS.tile = MAX2(0, GTS.tile); - - if (ima) { - GTS.tileXRep = ima->xrep; - GTS.tileYRep = ima->yrep; - } - /* if same image & tile, we're done */ - if (compare && ima == GTS.curima && GTS.curtile == GTS.tile && - GTS.tilemode == GTS.curtilemode && GTS.curtileXRep == GTS.tileXRep && - GTS.curtileYRep == GTS.tileYRep) - { + if (compare && ima == GTS.curima) { return (ima != NULL); } - /* if tiling mode or repeat changed, change texture matrix to fit */ - if (GTS.tilemode != GTS.curtilemode || GTS.curtileXRep != GTS.tileXRep || - GTS.curtileYRep != GTS.tileYRep) - { - glMatrixMode(GL_TEXTURE); - glLoadIdentity(); - - if (ima && (ima->tpageflag & IMA_TILES)) - glScalef(ima->xrep, ima->yrep, 1.0f); - - glMatrixMode(GL_MODELVIEW); - } - /* check if we have a valid image */ if (ima == NULL || ima->ok == 0) return 0; @@ -652,48 +342,8 @@ int GPU_verify_image( GPU_free_image(ima); ima->tpageflag &= ~IMA_TPAGE_REFRESH; } - - if (GTS.tilemode) { - /* tiled mode */ - if (ima->repbind == NULL) gpu_make_repbind(ima); - if (GTS.tile >= ima->totbind) GTS.tile = 0; - - /* this happens when you change repeat buttons */ - if (ima->repbind && textarget == GL_TEXTURE_2D) bind = &ima->repbind[GTS.tile]; - else bind = gpu_get_image_bindcode(ima, textarget); - - if (*bind == 0) { - short texwindx = ibuf->x / ima->xrep; - short texwindy = ibuf->y / ima->yrep; - - if (GTS.tile >= ima->xrep * ima->yrep) - GTS.tile = ima->xrep * ima->yrep - 1; - - short texwinsy = GTS.tile / ima->xrep; - short texwinsx = GTS.tile - texwinsy * ima->xrep; - - texwinsx *= texwindx; - texwinsy *= texwindy; - - tpx = texwindx; - tpy = texwindy; - if (use_high_bit_depth) { - if (do_color_management) { - srgb_frect = MEM_mallocN(ibuf->x * ibuf->y * sizeof(float) * 4, "floar_buf_col_cor"); - gpu_verify_high_bit_srgb_buffer(srgb_frect, ibuf); - frect = srgb_frect + (4 * (texwinsy * ibuf->x + texwinsx)); - } - else { - frect = ibuf->rect_float + (ibuf->channels * (texwinsy * ibuf->x + texwinsx)); - } - } - else { - rect = ibuf->rect + texwinsy * ibuf->x + texwinsx; - } - } - } - else { + { /* regular image mode */ bind = gpu_get_image_bindcode(ima, textarget); @@ -722,57 +372,22 @@ int GPU_verify_image( const int rectw = tpx; const int recth = tpy; - unsigned *tilerect = NULL; - float *ftilerect = NULL; - - /* for tiles, copy only part of image into buffer */ - if (GTS.tilemode) { - if (use_high_bit_depth) { - ftilerect = MEM_mallocN(rectw * recth * sizeof(*ftilerect), "tilerect"); - - for (int y = 0; y < recth; y++) { - const float *frectrow = &frect[y * ibuf->x]; - float *ftilerectrow = &ftilerect[y * rectw]; - - memcpy(ftilerectrow, frectrow, tpx * sizeof(*frectrow)); - } - - frect = ftilerect; - } - else { - tilerect = MEM_mallocN(rectw * recth * sizeof(*tilerect), "tilerect"); - - for (int y = 0; y < recth; y++) { - const unsigned *rectrow = &rect[y * ibuf->x]; - unsigned *tilerectrow = &tilerect[y * rectw]; - - memcpy(tilerectrow, rectrow, tpx * sizeof(*rectrow)); - } - - rect = tilerect; - } - } - #ifdef WITH_DDS if (ibuf->ftype == IMB_FTYPE_DDS) GPU_create_gl_tex_compressed(bind, rect, rectw, recth, textarget, mipmap, ima, ibuf); else #endif GPU_create_gl_tex(bind, rect, frect, rectw, recth, textarget, mipmap, use_high_bit_depth, ima); - + /* mark as non-color data texture */ if (*bind) { if (is_data) - ima->tpageflag |= IMA_GLBIND_IS_DATA; + ima->tpageflag |= IMA_GLBIND_IS_DATA; else - ima->tpageflag &= ~IMA_GLBIND_IS_DATA; + ima->tpageflag &= ~IMA_GLBIND_IS_DATA; } /* clean up */ - if (tilerect) - MEM_freeN(tilerect); - if (ftilerect) - MEM_freeN(ftilerect); if (srgb_frect) MEM_freeN(srgb_frect); @@ -858,30 +473,6 @@ void GPU_create_gl_tex( int tpx = rectw; int tpy = recth; - /* scale if not a power of two. this is not strictly necessary for newer - * GPUs (OpenGL version >= 2.0) since they support non-power-of-two-textures - * Then don't bother scaling for hardware that supports NPOT textures! */ - if (textarget == GL_TEXTURE_2D && - ((!GPU_full_non_power_of_two_support() && !is_power_of_2_resolution(rectw, recth)) || - is_over_resolution_limit(textarget, rectw, recth))) - { - rectw = smaller_power_of_2_limit(rectw); - recth = smaller_power_of_2_limit(recth); - - if (use_high_bit_depth) { - ibuf = IMB_allocFromBuffer(NULL, frect, tpx, tpy); - IMB_scaleImBuf(ibuf, rectw, recth); - - frect = ibuf->rect_float; - } - else { - ibuf = IMB_allocFromBuffer(rect, NULL, tpx, tpy); - IMB_scaleImBuf(ibuf, rectw, recth); - - rect = ibuf->rect; - } - } - /* create image */ glGenTextures(1, (GLuint *)bind); glBindTexture(textarget, *bind); @@ -889,7 +480,7 @@ void GPU_create_gl_tex( if (textarget == GL_TEXTURE_2D) { if (use_high_bit_depth) { if (GLEW_ARB_texture_float) - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F_ARB, rectw, recth, 0, GL_RGBA, GL_FLOAT, frect); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, rectw, recth, 0, GL_RGBA, GL_FLOAT, frect); else glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16, rectw, recth, 0, GL_RGBA, GL_FLOAT, frect); } @@ -900,7 +491,7 @@ void GPU_create_gl_tex( if (GPU_get_mipmap() && mipmap) { if (GTS.gpu_mipmap) { - gpu_generate_mipmap(GL_TEXTURE_2D); + glGenerateMipmap(GL_TEXTURE_2D); } else { int i; @@ -918,7 +509,7 @@ void GPU_create_gl_tex( ImBuf *mip = ibuf->mipmap[i - 1]; if (use_high_bit_depth) { if (GLEW_ARB_texture_float) - glTexImage2D(GL_TEXTURE_2D, i, GL_RGBA16F_ARB, mip->x, mip->y, 0, GL_RGBA, GL_FLOAT, mip->rect_float); + glTexImage2D(GL_TEXTURE_2D, i, GL_RGBA16F, mip->x, mip->y, 0, GL_RGBA, GL_FLOAT, mip->rect_float); else glTexImage2D(GL_TEXTURE_2D, i, GL_RGBA16, mip->x, mip->y, 0, GL_RGBA, GL_FLOAT, mip->rect_float); } @@ -940,7 +531,7 @@ void GPU_create_gl_tex( if (h == w && is_power_of_2_i(h) && !is_over_resolution_limit(textarget, h, w)) { void **cube_map = gpu_gen_cube_map(rect, frect, rectw, recth, use_high_bit_depth); - GLenum informat = use_high_bit_depth ? (GLEW_ARB_texture_float ? GL_RGBA16F_ARB : GL_RGBA16) : GL_RGBA8; + GLenum informat = use_high_bit_depth ? (GLEW_ARB_texture_float ? GL_RGBA16F : GL_RGBA16) : GL_RGBA8; GLenum type = use_high_bit_depth ? GL_FLOAT : GL_UNSIGNED_BYTE; if (cube_map) @@ -951,7 +542,7 @@ void GPU_create_gl_tex( if (GPU_get_mipmap() && mipmap) { if (GTS.gpu_mipmap) { - gpu_generate_mipmap(GL_TEXTURE_CUBE_MAP); + glGenerateMipmap(GL_TEXTURE_CUBE_MAP); } else { if (!ibuf) { @@ -975,7 +566,7 @@ void GPU_create_gl_tex( if (mip_cube_map) { for (int j = 0; j < 6; j++) { glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + j, i, - informat, mipw, miph, 0, GL_RGBA, type, mip_cube_map[j]); + informat, mipw, miph, 0, GL_RGBA, type, mip_cube_map[j]); } } gpu_del_cube_map(mip_cube_map); @@ -1056,7 +647,7 @@ bool GPU_upload_dxt_texture(ImBuf *ibuf) size = ((width + 3) / 4) * ((height + 3) / 4) * blocksize; glCompressedTexImage2D(GL_TEXTURE_2D, i, format, width, height, - 0, size, ibuf->dds_data.data + offset); + 0, size, ibuf->dds_data.data + offset); offset += size; width >>= 1; @@ -1091,62 +682,6 @@ void GPU_create_gl_tex_compressed( } #endif } -static void gpu_verify_repeat(Image *ima) -{ - /* set either clamp or repeat in X/Y */ - if (ima->tpageflag & IMA_CLAMP_U) - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - else - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); - - if (ima->tpageflag & IMA_CLAMP_V) - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - else - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); -} - -int GPU_set_tpage(MTexPoly *mtexpoly, int mipmap, int alphablend) -{ - /* check if we need to clear the state */ - if (mtexpoly == NULL) { - GPU_clear_tpage(false); - return 0; - } - - Image *ima = mtexpoly->tpage; - GTS.lasttface = mtexpoly; - - gpu_verify_alpha_blend(alphablend); - gpu_verify_reflection(ima); - - if (GPU_verify_image(ima, NULL, GL_TEXTURE_2D, mtexpoly->tile, 1, mipmap, false)) { - GTS.curtile = GTS.tile; - GTS.curima = GTS.ima; - GTS.curtilemode = GTS.tilemode; - GTS.curtileXRep = GTS.tileXRep; - GTS.curtileYRep = GTS.tileYRep; - - glEnable(GL_TEXTURE_2D); - } - else { - glDisable(GL_TEXTURE_2D); - - GTS.curtile = 0; - GTS.curima = NULL; - GTS.curtilemode = 0; - GTS.curtileXRep = 0; - GTS.curtileYRep = 0; - - return 0; - } - - gpu_verify_repeat(ima); - - /* Did this get lost in the image recode? */ - /* BKE_image_tag_time(ima);*/ - - return 1; -} /* these two functions are called on entering and exiting texture paint mode, * temporary disabling/enabling mipmapping on all images for quick texture @@ -1206,9 +741,7 @@ void GPU_paint_set_mipmap(bool mipmap) /* check if image has been downscaled and do scaled partial update */ static bool gpu_check_scaled_image(ImBuf *ibuf, Image *ima, float *frect, int x, int y, int w, int h) { - if ((!GPU_full_non_power_of_two_support() && !is_power_of_2_resolution(ibuf->x, ibuf->y)) || - is_over_resolution_limit(GL_TEXTURE_2D, ibuf->x, ibuf->y)) - { + if (is_over_resolution_limit(GL_TEXTURE_2D, ibuf->x, ibuf->y)) { int x_limit = smaller_power_of_2_limit(ibuf->x); int y_limit = smaller_power_of_2_limit(ibuf->y); @@ -1261,7 +794,7 @@ static bool gpu_check_scaled_image(ImBuf *ibuf, Image *ima, float *frect, int x, } if (GPU_get_mipmap()) { - gpu_generate_mipmap(GL_TEXTURE_2D); + glGenerateMipmap(GL_TEXTURE_2D); } else { ima->tpageflag &= ~IMA_MIPMAP_COMPLETE; @@ -1277,8 +810,7 @@ void GPU_paint_update_image(Image *ima, ImageUser *iuser, int x, int y, int w, i { ImBuf *ibuf = BKE_image_acquire_ibuf(ima, iuser, NULL); - if (ima->repbind || - (!GTS.gpu_mipmap && GPU_get_mipmap()) || + if ((!GTS.gpu_mipmap && GPU_get_mipmap()) || (ima->bindcode[TEXTARGET_TEXTURE_2D] == 0) || (ibuf == NULL) || (w == 0) || (h == 0)) @@ -1296,7 +828,7 @@ void GPU_paint_update_image(Image *ima, ImageUser *iuser, int x, int y, int w, i float *buffer = MEM_mallocN(w * h * sizeof(float) * 4, "temp_texpaint_float_buf"); bool is_data = (ima->tpageflag & IMA_GLBIND_IS_DATA) != 0; IMB_partial_rect_from_float(ibuf, buffer, x, y, w, h, is_data); - + if (gpu_check_scaled_image(ibuf, ima, buffer, x, y, w, h)) { MEM_freeN(buffer); BKE_image_release_ibuf(ima, ibuf, NULL); @@ -1311,7 +843,7 @@ void GPU_paint_update_image(Image *ima, ImageUser *iuser, int x, int y, int w, i /* we have already accounted for the case where GTS.gpu_mipmap is false * so we will be using GPU mipmap generation here */ if (GPU_get_mipmap()) { - gpu_generate_mipmap(GL_TEXTURE_2D); + glGenerateMipmap(GL_TEXTURE_2D); } else { ima->tpageflag &= ~IMA_MIPMAP_COMPLETE; @@ -1337,7 +869,7 @@ void GPU_paint_update_image(Image *ima, ImageUser *iuser, int x, int y, int w, i glPixelStorei(GL_UNPACK_SKIP_ROWS, y); glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, w, h, GL_RGBA, - GL_UNSIGNED_BYTE, ibuf->rect); + GL_UNSIGNED_BYTE, ibuf->rect); glPixelStorei(GL_UNPACK_ROW_LENGTH, row_length); glPixelStorei(GL_UNPACK_SKIP_PIXELS, skip_pixels); @@ -1345,7 +877,7 @@ void GPU_paint_update_image(Image *ima, ImageUser *iuser, int x, int y, int w, i /* see comment above as to why we are using gpu mipmap generation here */ if (GPU_get_mipmap()) { - gpu_generate_mipmap(GL_TEXTURE_2D); + glGenerateMipmap(GL_TEXTURE_2D); } else { ima->tpageflag &= ~IMA_MIPMAP_COMPLETE; @@ -1355,61 +887,6 @@ void GPU_paint_update_image(Image *ima, ImageUser *iuser, int x, int y, int w, i BKE_image_release_ibuf(ima, ibuf, NULL); } -void GPU_update_images_framechange(void) -{ - for (Image *ima = G.main->image.first; ima; ima = ima->id.next) { - if (ima->tpageflag & IMA_TWINANIM) { - if (ima->twend >= ima->xrep * ima->yrep) - ima->twend = ima->xrep * ima->yrep - 1; - - /* check: is bindcode not in the array? free. (to do) */ - - ima->lastframe++; - if (ima->lastframe > ima->twend) - ima->lastframe = ima->twsta; - } - } -} - -int GPU_update_image_time(Image *ima, double time) -{ - if (!ima) - return 0; - - if (ima->lastupdate < 0) - ima->lastupdate = 0; - - if (ima->lastupdate > (float)time) - ima->lastupdate = (float)time; - - int inc = 0; - - if (ima->tpageflag & IMA_TWINANIM) { - if (ima->twend >= ima->xrep * ima->yrep) ima->twend = ima->xrep * ima->yrep - 1; - - /* check: is the bindcode not in the array? Then free. (still to do) */ - - float diff = (float)((float)time - ima->lastupdate); - inc = (int)(diff * (float)ima->animspeed); - - ima->lastupdate += ((float)inc / (float)ima->animspeed); - - int newframe = ima->lastframe + inc; - - if (newframe > (int)ima->twend) { - if (ima->twend - ima->twsta != 0) - newframe = (int)ima->twsta - 1 + (newframe - ima->twend) % (ima->twend - ima->twsta); - else - newframe = ima->twsta; - } - - ima->lastframe = newframe; - } - - return inc; -} - - void GPU_free_smoke(SmokeModifierData *smd) { if (smd->type & MOD_SMOKE_TYPE_DOMAIN && smd->domain) { @@ -1437,31 +914,60 @@ void GPU_create_smoke(SmokeModifierData *smd, int highres) if (smoke_has_colors(sds->fluid)) { float *data = MEM_callocN(sizeof(float) * sds->total_cells * 4, "smokeColorTexture"); smoke_get_rgba(sds->fluid, data, 0); - sds->tex = GPU_texture_create_3D(sds->res[0], sds->res[1], sds->res[2], 4, data); + sds->tex = GPU_texture_create_3D(sds->res[0], sds->res[1], sds->res[2], GPU_RGBA8, data, NULL); MEM_freeN(data); } /* density only */ else { - sds->tex = GPU_texture_create_3D(sds->res[0], sds->res[1], sds->res[2], 1, smoke_get_density(sds->fluid)); + sds->tex = GPU_texture_create_3D(sds->res[0], sds->res[1], sds->res[2], + GPU_R8, smoke_get_density(sds->fluid), NULL); + + /* Swizzle the RGBA components to read the Red channel so + * that the shader stay the same for colored and non color + * density textures. */ + GPU_texture_bind(sds->tex, 0); + glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_SWIZZLE_R, GL_RED); + glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_SWIZZLE_G, GL_RED); + glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_SWIZZLE_B, GL_RED); + glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_SWIZZLE_A, GL_RED); + GPU_texture_unbind(sds->tex); } - sds->tex_flame = (smoke_has_fuel(sds->fluid)) ? GPU_texture_create_3D(sds->res[0], sds->res[1], sds->res[2], 1, smoke_get_flame(sds->fluid)) : NULL; + sds->tex_flame = (smoke_has_fuel(sds->fluid)) ? + GPU_texture_create_3D(sds->res[0], sds->res[1], sds->res[2], + GPU_R8, smoke_get_flame(sds->fluid), NULL) : + NULL; } else if (!sds->tex && highres) { /* rgba texture for color + density */ if (smoke_turbulence_has_colors(sds->wt)) { float *data = MEM_callocN(sizeof(float) * smoke_turbulence_get_cells(sds->wt) * 4, "smokeColorTexture"); smoke_turbulence_get_rgba(sds->wt, data, 0); - sds->tex = GPU_texture_create_3D(sds->res_wt[0], sds->res_wt[1], sds->res_wt[2], 4, data); + sds->tex = GPU_texture_create_3D(sds->res_wt[0], sds->res_wt[1], sds->res_wt[2], GPU_RGBA8, data, NULL); MEM_freeN(data); } /* density only */ else { - sds->tex = GPU_texture_create_3D(sds->res_wt[0], sds->res_wt[1], sds->res_wt[2], 1, smoke_turbulence_get_density(sds->wt)); + sds->tex = GPU_texture_create_3D(sds->res_wt[0], sds->res_wt[1], sds->res_wt[2], + GPU_R8, smoke_turbulence_get_density(sds->wt), NULL); + + /* Swizzle the RGBA components to read the Red channel so + * that the shader stay the same for colored and non color + * density textures. */ + GPU_texture_bind(sds->tex, 0); + glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_SWIZZLE_R, GL_RED); + glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_SWIZZLE_G, GL_RED); + glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_SWIZZLE_B, GL_RED); + glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_SWIZZLE_A, GL_RED); + GPU_texture_unbind(sds->tex); } - sds->tex_flame = (smoke_turbulence_has_fuel(sds->wt)) ? GPU_texture_create_3D(sds->res_wt[0], sds->res_wt[1], sds->res_wt[2], 1, smoke_turbulence_get_flame(sds->wt)) : NULL; + sds->tex_flame = (smoke_turbulence_has_fuel(sds->wt)) ? + GPU_texture_create_3D(sds->res_wt[0], sds->res_wt[1], sds->res_wt[2], + GPU_R8, smoke_turbulence_get_flame(sds->wt), NULL) : + NULL; } - sds->tex_shadow = GPU_texture_create_3D(sds->res[0], sds->res[1], sds->res[2], 1, sds->shadow); + sds->tex_shadow = GPU_texture_create_3D(sds->res[0], sds->res[1], sds->res[2], + GPU_R8, sds->shadow, NULL); } #else // WITH_SMOKE (void)highres; @@ -1499,9 +1005,6 @@ void GPU_free_unused_buffers(void) BLI_linklist_free(image_free_queue, NULL); image_free_queue = NULL; - /* vbo buffers */ - GPU_global_buffer_pool_free_unused(); - BLI_thread_unlock(LOCK_OPENGL); } @@ -1525,14 +1028,6 @@ void GPU_free_image(Image *ima) } } - /* free repeated image binding */ - if (ima->repbind) { - glDeleteTextures(ima->totbind, (GLuint *)ima->repbind); - - MEM_freeN(ima->repbind); - ima->repbind = NULL; - } - ima->tpageflag &= ~(IMA_MIPMAP_COMPLETE | IMA_GLBIND_IS_DATA); } @@ -1576,7 +1071,7 @@ void GPU_free_images_old(void) if ((ima->flag & IMA_NOCOLLECT) == 0 && ctime - ima->lastused > U.textimeout) { /* If it's in GL memory, deallocate and set time tag to current time * This gives textures a "second chance" to be used before dying. */ - if (BKE_image_has_bindcode(ima) || ima->repbind) { + if (BKE_image_has_bindcode(ima)) { GPU_free_image(ima); ima->lastused = ctime; } @@ -1589,679 +1084,7 @@ void GPU_free_images_old(void) } } - -/* OpenGL Materials */ - -#define FIXEDMAT 8 - -/* OpenGL state caching for materials */ - -typedef struct GPUMaterialFixed { - float diff[3]; - float spec[3]; - int hard; - float alpha; -} GPUMaterialFixed; - -static struct GPUMaterialState { - GPUMaterialFixed (*matbuf); - GPUMaterialFixed matbuf_fixed[FIXEDMAT]; - int totmat; - - /* set when called inside GPU_begin_object_materials / GPU_end_object_materials - * otherwise calling GPU_object_material_bind returns zero */ - bool is_enabled; - - Material **gmatbuf; - Material *gmatbuf_fixed[FIXEDMAT]; - Material *gboundmat; - Object *gob; - DupliObject *dob; - Scene *gscene; - int glay; - bool gscenelock; - float (*gviewmat)[4]; - float (*gviewinv)[4]; - float (*gviewcamtexcofac); - - bool backface_culling; - bool two_sided_lighting; - - GPUBlendMode *alphablend; - GPUBlendMode alphablend_fixed[FIXEDMAT]; - bool use_alpha_pass, is_alpha_pass; - bool use_matcaps; - - int lastmatnr, lastretval; - GPUBlendMode lastalphablend; - bool is_opensubdiv; -} GMS = {NULL}; - -/* fixed function material, alpha handed by caller */ -static void gpu_material_to_fixed( - GPUMaterialFixed *smat, const Material *bmat, const int gamma, const Object *ob, - const int new_shading_nodes, const bool dimdown) -{ - if (bmat->mode & MA_SHLESS) { - copy_v3_v3(smat->diff, &bmat->r); - - if (gamma) - linearrgb_to_srgb_v3_v3(smat->diff, smat->diff); - - zero_v3(smat->spec); - smat->alpha = 1.0f; - smat->hard = 0; - } - else if (new_shading_nodes) { - copy_v3_v3(smat->diff, &bmat->r); - copy_v3_v3(smat->spec, &bmat->specr); - smat->alpha = 1.0f; - smat->hard = CLAMPIS(bmat->har, 0, 128); - - if (dimdown) { - mul_v3_fl(smat->diff, 0.8f); - mul_v3_fl(smat->spec, 0.5f); - } - - if (gamma) { - linearrgb_to_srgb_v3_v3(smat->diff, smat->diff); - linearrgb_to_srgb_v3_v3(smat->spec, smat->spec); - } - } - else { - mul_v3_v3fl(smat->diff, &bmat->r, bmat->ref + bmat->emit); - - if (bmat->shade_flag & MA_OBCOLOR) - mul_v3_v3(smat->diff, ob->col); - - mul_v3_v3fl(smat->spec, &bmat->specr, bmat->spec); - smat->hard = CLAMPIS(bmat->har, 1, 128); - smat->alpha = 1.0f; - - if (gamma) { - linearrgb_to_srgb_v3_v3(smat->diff, smat->diff); - linearrgb_to_srgb_v3_v3(smat->spec, smat->spec); - } - } -} - -static Material *gpu_active_node_material(Material *ma) -{ - if (ma && ma->use_nodes && ma->nodetree) { - bNode *node = nodeGetActiveID(ma->nodetree, ID_MA); - - if (node) - return (Material *)node->id; - else - return NULL; - } - - return ma; -} - -void GPU_begin_dupli_object(DupliObject *dob) -{ - GMS.dob = dob; -} - -void GPU_end_dupli_object(void) -{ - GMS.dob = NULL; -} - -void GPU_begin_object_materials( - View3D *v3d, RegionView3D *rv3d, Scene *scene, Object *ob, - bool glsl, bool *do_alpha_after) -{ - Material *ma; - GPUMaterial *gpumat; - GPUBlendMode alphablend; - DupliObject *dob; - int a; - const bool gamma = BKE_scene_check_color_management_enabled(scene); - const bool new_shading_nodes = BKE_scene_use_new_shading_nodes(scene); - const bool use_matcap = (v3d->flag2 & V3D_SHOW_SOLID_MATCAP) != 0; /* assumes v3d->defmaterial->preview is set */ - bool use_opensubdiv = false; - -#ifdef WITH_OPENSUBDIV - { - DerivedMesh *derivedFinal = NULL; - if (ob->type == OB_MESH) { - Mesh *me = ob->data; - BMEditMesh *em = me->edit_btmesh; - if (em != NULL) { - derivedFinal = em->derivedFinal; - } - else { - derivedFinal = ob->derivedFinal; - } - } - else { - derivedFinal = ob->derivedFinal; - } - - if (derivedFinal != NULL && derivedFinal->type == DM_TYPE_CCGDM) { - CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) derivedFinal; - use_opensubdiv = ccgdm->useGpuBackend; - } - } -#endif - -#ifdef WITH_GAMEENGINE - if (rv3d->rflag & RV3D_IS_GAME_ENGINE) { - ob = BKE_object_lod_matob_get(ob, scene); - } -#endif - - /* initialize state */ - /* DupliObject must be restored */ - dob = GMS.dob; - memset(&GMS, 0, sizeof(GMS)); - GMS.is_enabled = true; - GMS.dob = dob; - GMS.lastmatnr = -1; - GMS.lastretval = -1; - GMS.lastalphablend = GPU_BLEND_SOLID; - GMS.use_matcaps = use_matcap; - - GMS.backface_culling = (v3d->flag2 & V3D_BACKFACE_CULLING) != 0; - - GMS.two_sided_lighting = false; - if (ob && ob->type == OB_MESH) - GMS.two_sided_lighting = (((Mesh *)ob->data)->flag & ME_TWOSIDED) != 0; - - GMS.gob = ob; - GMS.gscene = scene; - GMS.is_opensubdiv = use_opensubdiv; - GMS.totmat = use_matcap ? 1 : ob->totcol + 1; /* materials start from 1, default material is 0 */ - GMS.glay = (v3d->localvd) ? v3d->localvd->lay : v3d->lay; /* keep lamps visible in local view */ - GMS.gscenelock = (v3d->scenelock != 0); - GMS.gviewmat = rv3d->viewmat; - GMS.gviewinv = rv3d->viewinv; - GMS.gviewcamtexcofac = rv3d->viewcamtexcofac; - - /* alpha pass setup. there's various cases to handle here: - * - object transparency on: only solid materials draw in the first pass, - * and only transparent in the second 'alpha' pass. - * - object transparency off: for glsl we draw both in a single pass, and - * for solid we don't use transparency at all. */ - GMS.use_alpha_pass = (do_alpha_after != NULL); - GMS.is_alpha_pass = (v3d->transp != false); - if (GMS.use_alpha_pass) - *do_alpha_after = false; - - if (GMS.totmat > FIXEDMAT) { - GMS.matbuf = MEM_callocN(sizeof(GPUMaterialFixed) * GMS.totmat, "GMS.matbuf"); - GMS.gmatbuf = MEM_callocN(sizeof(*GMS.gmatbuf) * GMS.totmat, "GMS.matbuf"); - GMS.alphablend = MEM_callocN(sizeof(*GMS.alphablend) * GMS.totmat, "GMS.matbuf"); - } - else { - GMS.matbuf = GMS.matbuf_fixed; - GMS.gmatbuf = GMS.gmatbuf_fixed; - GMS.alphablend = GMS.alphablend_fixed; - } - - /* viewport material, setup in space_view3d, defaults to matcap using ma->preview now */ - if (use_matcap) { - GMS.gmatbuf[0] = v3d->defmaterial; - GPU_material_matcap(scene, v3d->defmaterial, use_opensubdiv); - - /* do material 1 too, for displists! */ - memcpy(&GMS.matbuf[1], &GMS.matbuf[0], sizeof(GPUMaterialFixed)); - - GMS.alphablend[0] = GPU_BLEND_SOLID; - } - else { - - /* no materials assigned? */ - if (ob->totcol == 0) { - gpu_material_to_fixed(&GMS.matbuf[0], &defmaterial, 0, ob, new_shading_nodes, true); - - /* do material 1 too, for displists! */ - memcpy(&GMS.matbuf[1], &GMS.matbuf[0], sizeof(GPUMaterialFixed)); - - if (glsl) { - GMS.gmatbuf[0] = &defmaterial; - GPU_material_from_blender(GMS.gscene, &defmaterial, GMS.is_opensubdiv); - } - - GMS.alphablend[0] = GPU_BLEND_SOLID; - } - - /* setup materials */ - for (a = 1; a <= ob->totcol; a++) { - /* find a suitable material */ - ma = give_current_material(ob, a); - if (!glsl && !new_shading_nodes) ma = gpu_active_node_material(ma); - if (ma == NULL) ma = &defmaterial; - - /* create glsl material if requested */ - gpumat = glsl ? GPU_material_from_blender(GMS.gscene, ma, GMS.is_opensubdiv) : NULL; - - if (gpumat) { - /* do glsl only if creating it succeed, else fallback */ - GMS.gmatbuf[a] = ma; - alphablend = GPU_material_alpha_blend(gpumat, ob->col); - } - else { - /* fixed function opengl materials */ - gpu_material_to_fixed(&GMS.matbuf[a], ma, gamma, ob, new_shading_nodes, false); - - if (GMS.use_alpha_pass && ((ma->mode & MA_TRANSP) || (new_shading_nodes && ma->alpha != 1.0f))) { - GMS.matbuf[a].alpha = ma->alpha; - alphablend = (ma->alpha == 1.0f) ? GPU_BLEND_SOLID: GPU_BLEND_ALPHA; - } - else { - GMS.matbuf[a].alpha = 1.0f; - alphablend = GPU_BLEND_SOLID; - } - } - - /* setting 'do_alpha_after = true' indicates this object needs to be - * drawn in a second alpha pass for improved blending */ - if (do_alpha_after && !GMS.is_alpha_pass) - if (ELEM(alphablend, GPU_BLEND_ALPHA, GPU_BLEND_ADD, GPU_BLEND_ALPHA_SORT)) - *do_alpha_after = true; - - GMS.alphablend[a] = alphablend; - } - } - - /* let's start with a clean state */ - GPU_object_material_unbind(); -} - -static int gpu_get_particle_info(GPUParticleInfo *pi) -{ - DupliObject *dob = GMS.dob; - if (dob->particle_system) { - int ind; - if (dob->persistent_id[0] < dob->particle_system->totpart) - ind = dob->persistent_id[0]; - else { - ind = dob->particle_system->child[dob->persistent_id[0] - dob->particle_system->totpart].parent; - } - if (ind >= 0) { - ParticleData *p = &dob->particle_system->particles[ind]; - - pi->scalprops[0] = ind; - pi->scalprops[1] = GMS.gscene->r.cfra - p->time; - pi->scalprops[2] = p->lifetime; - 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; - } - else return 0; - } - else - return 0; -} - -static void GPU_get_object_info(float oi[3], Material *mat) -{ - Object *ob = GMS.gob; - oi[0] = ob->index; - oi[1] = mat->index; - unsigned int random; - if (GMS.dob) { - random = GMS.dob->random_id; - } - else { - random = BLI_hash_int_2d(BLI_hash_string(GMS.gob->id.name + 2), 0); - } - oi[2] = random * (1.0f / (float)0xFFFFFFFF); -} - -int GPU_object_material_bind(int nr, void *attribs) -{ - GPUVertexAttribs *gattribs = attribs; - - /* no GPU_begin_object_materials, use default material */ - if (!GMS.matbuf) { - memset(&GMS, 0, sizeof(GMS)); - - float diffuse[3], specular[3]; - mul_v3_v3fl(diffuse, &defmaterial.r, defmaterial.ref + defmaterial.emit); - mul_v3_v3fl(specular, &defmaterial.specr, defmaterial.spec); - GPU_basic_shader_colors(diffuse, specular, 35, 1.0f); - - if (GMS.two_sided_lighting) - GPU_basic_shader_bind(GPU_SHADER_LIGHTING | GPU_SHADER_TWO_SIDED); - else - GPU_basic_shader_bind(GPU_SHADER_LIGHTING); - - return 0; - } - - /* prevent index to use un-initialized array items */ - if (nr >= GMS.totmat) - nr = 0; - - if (gattribs) - memset(gattribs, 0, sizeof(*gattribs)); - - /* keep current material */ - if (nr == GMS.lastmatnr) - return GMS.lastretval; - - /* unbind glsl material */ - if (GMS.gboundmat) { - if (GMS.is_alpha_pass) glDepthMask(0); - GPU_material_unbind(GPU_material_from_blender(GMS.gscene, GMS.gboundmat, GMS.is_opensubdiv)); - GMS.gboundmat = NULL; - } - - /* draw materials with alpha in alpha pass */ - GMS.lastmatnr = nr; - GMS.lastretval = 1; - - if (GMS.use_alpha_pass) { - GMS.lastretval = ELEM(GMS.alphablend[nr], GPU_BLEND_SOLID, GPU_BLEND_CLIP); - if (GMS.is_alpha_pass) - GMS.lastretval = !GMS.lastretval; - } - else - GMS.lastretval = !GMS.is_alpha_pass; - - if (GMS.lastretval) { - /* for alpha pass, use alpha blend */ - GPUBlendMode alphablend = GMS.alphablend[nr]; - - if (gattribs && GMS.gmatbuf[nr]) { - /* bind glsl material and get attributes */ - Material *mat = GMS.gmatbuf[nr]; - GPUParticleInfo partile_info; - float object_info[3] = {0}; - - float auto_bump_scale; - - GPUMaterial *gpumat = GPU_material_from_blender(GMS.gscene, mat, GMS.is_opensubdiv); - GPU_material_vertex_attributes(gpumat, gattribs); - - if (GMS.dob) { - gpu_get_particle_info(&partile_info); - } - - if (GPU_get_material_builtins(gpumat) & GPU_OBJECT_INFO) { - GPU_get_object_info(object_info, mat); - } - - GPU_material_bind( - gpumat, GMS.gob->lay, GMS.glay, 1.0, !(GMS.gob->mode & OB_MODE_TEXTURE_PAINT), - GMS.gviewmat, GMS.gviewinv, GMS.gviewcamtexcofac, GMS.gscenelock); - - auto_bump_scale = GMS.gob->derivedFinal != NULL ? GMS.gob->derivedFinal->auto_bump_scale : 1.0f; - GPU_material_bind_uniforms(gpumat, GMS.gob->obmat, GMS.gviewmat, GMS.gob->col, auto_bump_scale, &partile_info, object_info); - GMS.gboundmat = mat; - - /* for glsl use alpha blend mode, unless it's set to solid and - * we are already drawing in an alpha pass */ - if (mat->game.alpha_blend != GPU_BLEND_SOLID) - alphablend = mat->game.alpha_blend; - - if (GMS.is_alpha_pass) glDepthMask(1); - - if (GMS.backface_culling) { - if (mat->game.flag) - glEnable(GL_CULL_FACE); - else - glDisable(GL_CULL_FACE); - } - - if (GMS.use_matcaps) - glColor3f(1.0f, 1.0f, 1.0f); - } - else { - /* or do fixed function opengl material */ - GPU_basic_shader_colors( - GMS.matbuf[nr].diff, - GMS.matbuf[nr].spec, GMS.matbuf[nr].hard, GMS.matbuf[nr].alpha); - - if (GMS.two_sided_lighting) - GPU_basic_shader_bind(GPU_SHADER_LIGHTING | GPU_SHADER_TWO_SIDED); - else - GPU_basic_shader_bind(GPU_SHADER_LIGHTING); - } - - /* set (alpha) blending mode */ - GPU_set_material_alpha_blend(alphablend); - } - - return GMS.lastretval; -} - -int GPU_object_material_visible(int nr, void *attribs) -{ - GPUVertexAttribs *gattribs = attribs; - int visible; - - if (!GMS.matbuf) - return 0; - - if (gattribs) - memset(gattribs, 0, sizeof(*gattribs)); - - if (nr >= GMS.totmat) - nr = 0; - - if (GMS.use_alpha_pass) { - visible = ELEM(GMS.alphablend[nr], GPU_BLEND_SOLID, GPU_BLEND_CLIP); - if (GMS.is_alpha_pass) - visible = !visible; - } - else - visible = !GMS.is_alpha_pass; - - return visible; -} - -void GPU_set_material_alpha_blend(int alphablend) -{ - if (GMS.lastalphablend == alphablend) - return; - - gpu_set_alpha_blend(alphablend); - GMS.lastalphablend = alphablend; -} - -int GPU_get_material_alpha_blend(void) -{ - return GMS.lastalphablend; -} - -void GPU_object_material_unbind(void) -{ - GMS.lastmatnr = -1; - GMS.lastretval = 1; - - if (GMS.gboundmat) { - if (GMS.backface_culling) - glDisable(GL_CULL_FACE); - - if (GMS.is_alpha_pass) glDepthMask(0); - GPU_material_unbind(GPU_material_from_blender(GMS.gscene, GMS.gboundmat, GMS.is_opensubdiv)); - GMS.gboundmat = NULL; - } - else - GPU_basic_shader_bind(GPU_SHADER_USE_COLOR); - - GPU_set_material_alpha_blend(GPU_BLEND_SOLID); -} - -void GPU_material_diffuse_get(int nr, float diff[4]) -{ - /* prevent index to use un-initialized array items */ - if (nr >= GMS.totmat) - nr = 0; - - /* no GPU_begin_object_materials, use default material */ - if (!GMS.matbuf) { - mul_v3_v3fl(diff, &defmaterial.r, defmaterial.ref + defmaterial.emit); - } - else { - copy_v3_v3(diff, GMS.matbuf[nr].diff); - diff[3] = GMS.matbuf[nr].alpha; - } -} - -bool GPU_material_use_matcaps_get(void) -{ - return GMS.use_matcaps; -} - -bool GPU_object_materials_check(void) -{ - return GMS.is_enabled; -} - -void GPU_end_object_materials(void) -{ - GPU_object_material_unbind(); - - GMS.is_enabled = false; - - if (GMS.matbuf && GMS.matbuf != GMS.matbuf_fixed) { - MEM_freeN(GMS.matbuf); - MEM_freeN(GMS.gmatbuf); - MEM_freeN(GMS.alphablend); - } - - GMS.matbuf = NULL; - GMS.gmatbuf = NULL; - GMS.alphablend = NULL; - GMS.two_sided_lighting = false; - - /* resetting the texture matrix after the scaling needed for tiled textures */ - if (GTS.tilemode) { - glMatrixMode(GL_TEXTURE); - glLoadIdentity(); - glMatrixMode(GL_MODELVIEW); - } -} - -/* Lights */ - -int GPU_default_lights(void) -{ - /* initialize */ - if (U.light[0].flag == 0 && U.light[1].flag == 0 && U.light[2].flag == 0) { - U.light[0].flag = 1; - U.light[0].vec[0] = -0.3; U.light[0].vec[1] = 0.3; U.light[0].vec[2] = 0.9; - U.light[0].col[0] = 0.8; U.light[0].col[1] = 0.8; U.light[0].col[2] = 0.8; - U.light[0].spec[0] = 0.5; U.light[0].spec[1] = 0.5; U.light[0].spec[2] = 0.5; - U.light[0].spec[3] = 1.0; - - U.light[1].flag = 0; - U.light[1].vec[0] = 0.5; U.light[1].vec[1] = 0.5; U.light[1].vec[2] = 0.1; - U.light[1].col[0] = 0.4; U.light[1].col[1] = 0.4; U.light[1].col[2] = 0.8; - U.light[1].spec[0] = 0.3; U.light[1].spec[1] = 0.3; U.light[1].spec[2] = 0.5; - U.light[1].spec[3] = 1.0; - - U.light[2].flag = 0; - U.light[2].vec[0] = 0.3; U.light[2].vec[1] = -0.3; U.light[2].vec[2] = -0.2; - U.light[2].col[0] = 0.8; U.light[2].col[1] = 0.5; U.light[2].col[2] = 0.4; - U.light[2].spec[0] = 0.5; U.light[2].spec[1] = 0.4; U.light[2].spec[2] = 0.3; - U.light[2].spec[3] = 1.0; - } - - GPU_basic_shader_light_set_viewer(false); - - int count = 0; - - for (int a = 0; a < 8; a++) { - if (a < 3 && U.light[a].flag) { - GPULightData light = {0}; - - light.type = GPU_LIGHT_SUN; - - normalize_v3_v3(light.direction, U.light[a].vec); - copy_v3_v3(light.diffuse, U.light[a].col); - copy_v3_v3(light.specular, U.light[a].spec); - - GPU_basic_shader_light_set(a, &light); - - count++; - } - else - GPU_basic_shader_light_set(a, NULL); - } - - return count; -} - -int GPU_scene_object_lights(Scene *scene, Object *ob, int lay, float viewmat[4][4], int ortho) -{ - /* disable all lights */ - for (int count = 0; count < 8; count++) - GPU_basic_shader_light_set(count, NULL); - - /* view direction for specular is not computed correct by default in - * opengl, so we set the settings ourselves */ - GPU_basic_shader_light_set_viewer(!ortho); - - int count = 0; - - for (Base *base = scene->base.first; base; base = base->next) { - if (base->object->type != OB_LAMP) - continue; - - if (!(base->lay & lay) || !(base->lay & ob->lay)) - continue; - - Lamp *la = base->object->data; - - /* setup lamp transform */ - glPushMatrix(); - glLoadMatrixf((float *)viewmat); - - /* setup light */ - GPULightData light = {0}; - - mul_v3_v3fl(light.diffuse, &la->r, la->energy); - mul_v3_v3fl(light.specular, &la->r, la->energy); - - if (la->type == LA_SUN) { - /* directional sun light */ - light.type = GPU_LIGHT_SUN; - normalize_v3_v3(light.direction, base->object->obmat[2]); - } - else { - /* other lamps with position attenuation */ - copy_v3_v3(light.position, base->object->obmat[3]); - - light.constant_attenuation = 1.0f; - light.linear_attenuation = la->att1 / la->dist; - light.quadratic_attenuation = la->att2 / (la->dist * la->dist); - - if (la->type == LA_SPOT) { - light.type = GPU_LIGHT_SPOT; - negate_v3_v3(light.direction, base->object->obmat[2]); - normalize_v3(light.direction); - light.spot_cutoff = RAD2DEGF(la->spotsize * 0.5f); - light.spot_exponent = 128.0f * la->spotblend; - } - else - light.type = GPU_LIGHT_POINT; - } - - GPU_basic_shader_light_set(count, &light); - - glPopMatrix(); - - count++; - if (count == 8) - break; - } - - 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 @@ -2277,115 +1100,51 @@ 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 } /* Default OpenGL State * - * This is called on startup, for opengl offscreen render and to restore state - * for the game engine. Generally we should always return to this state when + * This is called on startup, for opengl offscreen render. + * Generally we should always return to this state when * temporarily modifying the state for drawing, though that are (undocumented) * exceptions that we should try to get rid of. */ void GPU_state_init(void) { - float mat_ambient[] = { 0.0, 0.0, 0.0, 0.0 }; - float mat_specular[] = { 0.5, 0.5, 0.5, 1.0 }; - - glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, mat_ambient); - glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mat_specular); - glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, mat_specular); - glMateriali(GL_FRONT_AND_BACK, GL_SHININESS, 35); - glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE); - - GPU_default_lights(); - + GPU_disable_program_point_size(); + + glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS); + glDepthFunc(GL_LEQUAL); - /* scaling matrices */ - glEnable(GL_NORMALIZE); - glDisable(GL_ALPHA_TEST); glDisable(GL_BLEND); glDisable(GL_DEPTH_TEST); - glDisable(GL_FOG); - glDisable(GL_LIGHTING); - glDisable(GL_COLOR_MATERIAL); - glDisable(GL_LOGIC_OP); + glDisable(GL_COLOR_LOGIC_OP); glDisable(GL_STENCIL_TEST); - glDisable(GL_TEXTURE_1D); - glDisable(GL_TEXTURE_2D); - glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); - - /* default disabled, enable should be local per function */ - glDisableClientState(GL_VERTEX_ARRAY); - glDisableClientState(GL_NORMAL_ARRAY); - glDisableClientState(GL_COLOR_ARRAY); - glDisableClientState(GL_TEXTURE_COORD_ARRAY); - - glPixelTransferi(GL_MAP_COLOR, GL_FALSE); - glPixelTransferi(GL_RED_SCALE, 1); - glPixelTransferi(GL_RED_BIAS, 0); - glPixelTransferi(GL_GREEN_SCALE, 1); - glPixelTransferi(GL_GREEN_BIAS, 0); - glPixelTransferi(GL_BLUE_SCALE, 1); - glPixelTransferi(GL_BLUE_BIAS, 0); - glPixelTransferi(GL_ALPHA_SCALE, 1); - glPixelTransferi(GL_ALPHA_BIAS, 0); - - glPixelTransferi(GL_DEPTH_BIAS, 0); - glPixelTransferi(GL_DEPTH_SCALE, 1); - glDepthRange(0.0, 1.0); - glMatrixMode(GL_TEXTURE); - glLoadIdentity(); - glMatrixMode(GL_MODELVIEW); + glDepthRange(0.0, 1.0); glFrontFace(GL_CCW); glCullFace(GL_BACK); glDisable(GL_CULL_FACE); - gpu_multisample(false); - - GPU_basic_shader_bind(GPU_SHADER_USE_COLOR); + gpu_disable_multisample(); } -#ifdef WITH_OPENSUBDIV -/* Update face-varying variables offset which might be - * different from mesh to mesh sharing the same material. - */ -void GPU_draw_update_fvar_offset(DerivedMesh *dm) +void GPU_enable_program_point_size(void) { - /* Sanity check to be sure we only do this for OpenSubdiv draw. */ - BLI_assert(dm->type == DM_TYPE_CCGDM); - BLI_assert(GMS.is_opensubdiv); - - for (int i = 0; i < GMS.totmat; ++i) { - Material *material = GMS.gmatbuf[i]; - GPUMaterial *gpu_material; - - if (material == NULL) { - continue; - } - - gpu_material = GPU_material_from_blender(GMS.gscene, - material, - GMS.is_opensubdiv); - - GPU_material_update_fvar_offset(gpu_material, dm); - } + glEnable(GL_PROGRAM_POINT_SIZE); } -#endif +void GPU_disable_program_point_size(void) +{ + glDisable(GL_PROGRAM_POINT_SIZE); +} /** \name Framebuffer color depth, for selection codes * \{ */ @@ -2502,10 +1261,10 @@ void GPU_select_to_index_array(unsigned int *col, const unsigned int size) { #define INDEX_BUF_ARRAY(INDEX_FROM_BUF_BITS) \ for (i = size; i--; col++) { \ - if ((c = *col)) { \ - *col = INDEX_FROM_BUF_BITS(c); \ - } \ - } ((void)0) + if ((c = *col)) { \ + *col = INDEX_FROM_BUF_BITS(c); \ + } \ + } ((void)0) if (size > 0) { unsigned int i, c; @@ -2533,4 +1292,173 @@ void GPU_select_to_index_array(unsigned int *col, const unsigned int size) #undef INDEX_BUF_ARRAY } +#define STATE_STACK_DEPTH 16 + +typedef struct { + eGPUAttribMask mask; + + /* GL_ENABLE_BIT */ + unsigned int is_blend : 1; + unsigned int is_cull_face : 1; + unsigned int is_depth_test : 1; + unsigned int is_dither : 1; + unsigned int is_lighting : 1; + unsigned int is_line_smooth : 1; + unsigned int is_color_logic_op : 1; + unsigned int is_multisample : 1; + unsigned int is_polygon_offset_line : 1; + unsigned int is_polygon_offset_fill : 1; + unsigned int is_polygon_smooth : 1; + unsigned int is_sample_alpha_to_coverage : 1; + unsigned int is_scissor_test : 1; + unsigned int is_stencil_test : 1; + + bool is_clip_plane[6]; + + /* GL_DEPTH_BUFFER_BIT */ + /* unsigned int is_depth_test : 1; */ + int depth_func; + double depth_clear_value; + bool depth_write_mask; + + /* GL_SCISSOR_BIT */ + int scissor_box[4]; + /* unsigned int is_scissor_test : 1; */ + + /* GL_VIEWPORT_BIT */ + int viewport[4]; + double near_far[2]; +} GPUAttribValues; + +typedef struct { + GPUAttribValues attrib_stack[STATE_STACK_DEPTH]; + unsigned int top; +} GPUAttribStack; + +static GPUAttribStack state = { + .top = 0 +}; + +#define AttribStack state +#define Attrib state.attrib_stack[state.top] + +/** + * Replacement for glPush/PopAttributes + * + * We don't need to cover all the options of legacy OpenGL + * but simply the ones used by Blender. + */ +void gpuPushAttrib(eGPUAttribMask mask) +{ + Attrib.mask = mask; + + if ((mask & GPU_DEPTH_BUFFER_BIT) != 0) { + 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) { + Attrib.is_blend = glIsEnabled(GL_BLEND); + + for (int i = 0; i < 6; i++) { + Attrib.is_clip_plane[i] = glIsEnabled(GL_CLIP_PLANE0 + i); + } + + 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) { + 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 *)&Attrib.near_far); + glGetIntegerv(GL_VIEWPORT, (GLint *)&Attrib.viewport); + } + + if ((mask & GPU_BLEND_BIT) != 0) { + Attrib.is_blend = glIsEnabled(GL_BLEND); + } + + BLI_assert(AttribStack.top < STATE_STACK_DEPTH); + AttribStack.top++; +} + +static void restore_mask(GLenum cap, const bool value) +{ + if (value) { + glEnable(cap); + } + else { + glDisable(cap); + } +} + +void gpuPopAttrib(void) +{ + BLI_assert(AttribStack.top > 0); + AttribStack.top--; + + GLint mask = Attrib.mask; + + if ((mask & GPU_DEPTH_BUFFER_BIT) != 0) { + 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, Attrib.is_blend); + + for (int i = 0; i < 6; i++) { + restore_mask(GL_CLIP_PLANE0 + i, Attrib.is_clip_plane[i]); + } + + 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(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, 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, Attrib.is_blend); + } +} + +#undef Attrib +#undef AttribStack + /** \} */ diff --git a/source/blender/gpu/intern/gpu_extensions.c b/source/blender/gpu/intern/gpu_extensions.c index e0ce87d0e68..73e86c1b391 100644 --- a/source/blender/gpu/intern/gpu_extensions.c +++ b/source/blender/gpu/intern/gpu_extensions.c @@ -56,14 +56,11 @@ /* Extensions support */ /* -- extension: version of GL that absorbs it + * EXT_gpu_shader4: 3.0 * ARB_framebuffer object: 3.0 - * EXT_framebuffer_object: 3.0 - * EXT_framebuffer_blit: 3.0 - * EXT_framebuffer_multisample: 3.0 * EXT_framebuffer_multisample_blit_scaled: ??? * ARB_draw_instanced: 3.1 * ARB_texture_multisample: 3.2 - * EXT_geometry_shader4: 3.2 * ARB_texture_query_lod: 4.0 */ @@ -71,7 +68,8 @@ static struct GPUGlobal { GLint maxtexsize; GLint maxcubemapsize; GLint maxtextures; - bool extdisabled; + GLint maxubosize; + GLint maxubobinds; int colordepth; int samples_color_texture_max; GPUDeviceType device; @@ -93,11 +91,6 @@ bool GPU_type_matches(GPUDeviceType device, GPUOSType os, GPUDriverType driver) /* GPU Extensions */ -void GPU_extensions_disable(void) -{ - GG.extdisabled = true; -} - int GPU_max_texture_size(void) { return GG.maxtexsize; @@ -123,6 +116,16 @@ int GPU_max_cube_map_size(void) return GG.maxcubemapsize; } +int GPU_max_ubo_binds(void) +{ + return GG.maxubobinds; +} + +int GPU_max_ubo_size(void) +{ + return GG.maxubosize; +} + void GPU_get_dfdy_factors(float fac[2]) { copy_v2_v2(fac, GG.dfdyfactors); @@ -130,8 +133,11 @@ void GPU_get_dfdy_factors(float fac[2]) void gpu_extensions_init(void) { - /* BLI_assert(GLEW_VERSION_2_1); */ - /* ^-- maybe a bit extreme? */ + /* during 2.8 development each platform has its own OpenGL minimum requirements + * final 2.8 release will be unified on OpenGL 3.3 core profile, no required extensions + * see developer.blender.org/T49012 for details + */ + BLI_assert(GLEW_VERSION_3_3); glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &GG.maxtextures); @@ -143,11 +149,22 @@ void gpu_extensions_init(void) else GG.max_anisotropy = 1.0f; + glGetIntegerv(GL_MAX_FRAGMENT_UNIFORM_BLOCKS, &GG.maxubobinds); + glGetIntegerv(GL_MAX_UNIFORM_BLOCK_SIZE, &GG.maxubosize); + +#ifndef NDEBUG + GLint ret; + glBindFramebuffer(GL_FRAMEBUFFER, 0); + glGetFramebufferAttachmentParameteriv(GL_FRAMEBUFFER, GL_FRONT_LEFT, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE, &ret); + /* We expect FRONT_LEFT to be the default buffer. */ + BLI_assert(ret == GL_FRAMEBUFFER_DEFAULT); +#endif + GLint r, g, b; - glGetIntegerv(GL_RED_BITS, &r); - glGetIntegerv(GL_GREEN_BITS, &g); - glGetIntegerv(GL_BLUE_BITS, &b); - GG.colordepth = r + g + b; /* assumes same depth for RGB */ + glGetFramebufferAttachmentParameteriv(GL_FRAMEBUFFER, GL_FRONT_LEFT, GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE, &r); + glGetFramebufferAttachmentParameteriv(GL_FRAMEBUFFER, GL_FRONT_LEFT, GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE, &g); + glGetFramebufferAttachmentParameteriv(GL_FRAMEBUFFER, GL_FRONT_LEFT, GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE, &b); + GG.colordepth = r + g + b; /* Assumes same depth for RGB. */ if (GLEW_VERSION_3_2 || GLEW_ARB_texture_multisample) { glGetIntegerv(GL_MAX_COLOR_TEXTURE_SAMPLES, &GG.samples_color_texture_max); @@ -201,10 +218,6 @@ void gpu_extensions_init(void) GG.driver = GPU_DRIVER_ANY; } - /* make sure double side isn't used by default and only getting enabled in places where it's - * really needed to prevent different unexpected behaviors like with intel gme965 card (sergey) */ - glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_FALSE); - #ifdef _WIN32 GG.os = GPU_OS_WIN; #elif defined(__APPLE__) @@ -246,43 +259,6 @@ void gpu_extensions_exit(void) GPU_invalid_tex_free(); } -bool GPU_legacy_support(void) -{ - /* return whether or not current GL context is compatible with legacy OpenGL */ - static bool checked = false; - static bool support = true; - - if (!checked) { - if (GLEW_VERSION_3_2) { - GLint profile; - glGetIntegerv(GL_CONTEXT_PROFILE_MASK, &profile); - - if (G.debug & G_DEBUG_GPU) { - printf("GL_CONTEXT_PROFILE_MASK = %#x (%s profile)\n", (unsigned int)profile, - (profile & GL_CONTEXT_COMPATIBILITY_PROFILE_BIT) ? "compatibility" : - (profile & GL_CONTEXT_CORE_PROFILE_BIT) ? "core" : "unknown"); - } - - if (profile == 0) { - /* workaround for nVidia's Linux driver */ - support = GLEW_ARB_compatibility; - } - else { - support = profile & GL_CONTEXT_COMPATIBILITY_PROFILE_BIT; - } - } - else if (GLEW_VERSION_3_1) { - support = GLEW_ARB_compatibility; - } - - /* any OpenGL version <= 3.0 is legacy, so support remains true */ - - checked = true; - } - - return support; -} - bool GPU_full_non_power_of_two_support(void) { /* always supported on full GL but still relevant for OpenGL ES 2.0 where @@ -290,39 +266,11 @@ bool GPU_full_non_power_of_two_support(void) return true; } -bool GPU_display_list_support(void) -{ - /* deprecated in GL 3 - * supported on older GL and compatibility profile - * still queried by game engine - */ - return true; -} - bool GPU_bicubic_bump_support(void) { return GLEW_VERSION_4_0 || (GLEW_ARB_texture_query_lod && GLEW_VERSION_3_0); } -bool GPU_geometry_shader_support(void) -{ - /* in GL 3.2 geometry shaders are fully supported - * core profile clashes with our other shaders so accept compatibility only - * other GL versions can use EXT_geometry_shader4 if available - */ - return (GLEW_VERSION_3_2 && GPU_legacy_support()) || GLEW_EXT_geometry_shader4; -} - -bool GPU_geometry_shader_support_via_extension(void) -{ - return GLEW_EXT_geometry_shader4 && !(GLEW_VERSION_3_2 && GPU_legacy_support()); -} - -bool GPU_instanced_drawing_support(void) -{ - return GLEW_VERSION_3_1 || GLEW_ARB_draw_instanced; -} - int GPU_color_depth(void) { return GG.colordepth; @@ -330,12 +278,14 @@ int GPU_color_depth(void) bool GPU_mem_stats_supported(void) { - return (GLEW_NVX_gpu_memory_info || (GLEW_ATI_meminfo)) && (G.debug & G_DEBUG_GPU_MEM); + return (GLEW_NVX_gpu_memory_info || GLEW_ATI_meminfo) && (G.debug & G_DEBUG_GPU_MEM); } void GPU_mem_stats_get(int *totalmem, int *freemem) { + /* TODO(merwin): use Apple's platform API to get this info */ + if (GLEW_NVX_gpu_memory_info) { /* returned value in Kb */ glGetIntegerv(GL_GPU_MEMORY_INFO_TOTAL_AVAILABLE_MEMORY_NVX, totalmem); diff --git a/source/blender/gpu/intern/gpu_framebuffer.c b/source/blender/gpu/intern/gpu_framebuffer.c index e7a8beae5cc..75576c35f51 100644 --- a/source/blender/gpu/intern/gpu_framebuffer.c +++ b/source/blender/gpu/intern/gpu_framebuffer.c @@ -28,70 +28,138 @@ #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" -#include "GPU_debug.h" -#include "GPU_glew.h" +#include "GPU_batch.h" +#include "GPU_draw.h" +#include "GPU_extensions.h" #include "GPU_framebuffer.h" +#include "GPU_matrix.h" #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 4 outputs for now (usually we wouldn't need more to preserve fill rate) */ -#define GPU_FB_MAX_SLOTS 4 +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"; const char *err = "unknown"; +#define format_status(X) \ + case GL_FRAMEBUFFER_##X: err = "GL_FRAMEBUFFER_"#X; \ + break; + switch (status) { - case GL_FRAMEBUFFER_COMPLETE_EXT: - break; - case GL_INVALID_OPERATION: - err = "Invalid operation"; - break; - case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT: - err = "Incomplete attachment"; - break; - case GL_FRAMEBUFFER_UNSUPPORTED_EXT: - err = "Unsupported framebuffer format"; - break; - case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT: - err = "Missing attachment"; - break; - case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT: - err = "Attached images must have same dimensions"; - break; - case GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT: - err = "Attached images must have same format"; - break; - case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT: - err = "Missing draw buffer"; - break; - case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT: - err = "Missing read buffer"; - break; + /* success */ + format_status(COMPLETE) + /* errors shared by OpenGL desktop & ES */ + format_status(INCOMPLETE_ATTACHMENT) + format_status(INCOMPLETE_MISSING_ATTACHMENT) + format_status(UNSUPPORTED) +#if 0 /* for OpenGL ES only */ + format_status(INCOMPLETE_DIMENSIONS) +#else /* for desktop GL only */ + format_status(INCOMPLETE_DRAW_BUFFER) + format_status(INCOMPLETE_READ_BUFFER) + format_status(INCOMPLETE_MULTISAMPLE) + format_status(UNDEFINED) +#endif } +#undef format_status + if (err_out) { - BLI_snprintf(err_out, 256, "GPUFrameBuffer: framebuffer incomplete error %d '%s'", - (int)status, err); + BLI_snprintf(err_out, 256, format, err); } else { - fprintf(stderr, "GPUFrameBuffer: framebuffer incomplete error %d '%s'\n", - (int)status, err); + fprintf(stderr, format, err); } } @@ -99,348 +167,480 @@ 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");; +} - if (!(GLEW_VERSION_3_0 || GLEW_ARB_framebuffer_object || - (GLEW_EXT_framebuffer_object && GLEW_EXT_framebuffer_blit))) - { - return NULL; +static void gpu_framebuffer_init(GPUFrameBuffer *fb) +{ + glGenFramebuffers(1, &fb->object); +} + +void GPU_framebuffer_free(GPUFrameBuffer *fb) +{ + 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); + } } - - fb = MEM_callocN(sizeof(GPUFrameBuffer), "GPUFrameBuffer"); - glGenFramebuffersEXT(1, &fb->object); - if (!fb->object) { - fprintf(stderr, "GPUFFrameBuffer: framebuffer gen failed. %d\n", - (int)glGetError()); - GPU_framebuffer_free(fb); - return NULL; + /* This restores the framebuffer if it was bound */ + glDeleteFramebuffers(1, &fb->object); + + if (g_currentfb == fb->object) { + g_currentfb = 0; } - /* make sure no read buffer is enabled, so completeness check will not fail. We set those at binding time */ - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb->object); - glReadBuffer(GL_NONE); - glDrawBuffer(GL_NONE); - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); - - return fb; + MEM_freeN(fb); } -int GPU_framebuffer_texture_attach(GPUFrameBuffer *fb, GPUTexture *tex, int slot, char err_out[256]) -{ - GLenum attachment; - GLenum error; +/* ---------- 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 0; - } - - 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; } - if (GPU_texture_depth(tex)) - attachment = GL_DEPTH_ATTACHMENT_EXT; - else - attachment = GL_COLOR_ATTACHMENT0_EXT + slot; - - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb->object); - GG.currentfb = fb->object; + GPUAttachmentType type = attachment_type_from_tex(tex, slot); + GPUAttachment *attachment = &fb->attachments[type]; - /* Clean glError buffer. */ - while (glGetError() != GL_NO_ERROR) {} - - glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, attachment, - GPU_texture_target(tex), GPU_texture_opengl_bindcode(tex), 0); - - error = glGetError(); + if ((attachment->tex == tex) && + (attachment->mip == mip) && + (attachment->layer == layer)) + { + return; /* Exact same texture already bound here. */ + } + else if (attachment->tex != NULL) { + GPU_framebuffer_texture_detach(fb, attachment->tex); + } - if (error == GL_INVALID_OPERATION) { - GPU_framebuffer_restore(); - gpu_print_framebuffer_error(error, err_out); - return 0; + if (attachment->tex == NULL) { + GPU_texture_attach_framebuffer(tex, fb, type); } - if (GPU_texture_depth(tex)) - fb->depthtex = tex; - else - fb->colortex[slot] = tex; + attachment->tex = tex; + attachment->mip = mip; + attachment->layer = layer; + GPU_FB_ATTACHEMENT_SET_DIRTY(fb->dirty_flag, type); +} - GPU_texture_framebuffer_set(tex, fb, slot); +void GPU_framebuffer_texture_attach(GPUFrameBuffer *fb, GPUTexture *tex, int slot, int mip) +{ + gpu_framebuffer_texture_attach_ex(fb, tex, slot, -1, mip); +} - return 1; +void GPU_framebuffer_texture_layer_attach(GPUFrameBuffer *fb, GPUTexture *tex, int slot, int layer, int mip) +{ + /* 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) { - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 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_depth(tex)) { - fb->depthtex = NULL; - attachment = GL_DEPTH_ATTACHMENT_EXT; - } - else { - BLI_assert(fb->colortex[fb_attachment] == tex); - fb->colortex[fb_attachment] = NULL; - attachment = GL_COLOR_ATTACHMENT0_EXT + 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; } - glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, attachment, GPU_texture_target(tex), 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 */ - glPushAttrib(GL_ENABLE_BIT | GL_VIEWPORT_BIT); - glDisable(GL_SCISSOR_TEST); +/* ---------- Bind / Restore ----------- */ - /* bind framebuffer */ - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 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_EXT + fb_attachment); - glReadBuffer(GL_COLOR_ATTACHMENT0_EXT + fb_attachment); - } - - if (GPU_texture_target(tex) == GL_TEXTURE_2D_MULTISAMPLE) { - glEnable(GL_MULTISAMPLE); + glFramebufferTexture(GL_FRAMEBUFFER, gl_attachment, tex_bind, attach->mip); } +} - /* push matrices and set default viewport and matrix */ - glViewport(0, 0, GPU_texture_width(tex), GPU_texture_height(tex)); - GG.currentfb = fb->object; - - glMatrixMode(GL_PROJECTION); - glPushMatrix(); - glMatrixMode(GL_MODELVIEW); - glPushMatrix(); +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[4]; - - if (!fb->colortex[slot]) { - fprintf(stderr, "Error, framebuffer slot empty!\n"); - return; - } - - for (i = 0; i < 4; i++) { - if (fb->colortex[i]) { - attachments[numslots] = GL_COLOR_ATTACHMENT0_EXT + 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++; } + + 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); + + 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); + } } - - /* push attributes */ - glPushAttrib(GL_ENABLE_BIT | GL_VIEWPORT_BIT); - glDisable(GL_SCISSOR_TEST); + fb->dirty_flag = 0; - /* bind framebuffer */ - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb->object); + /* Update draw buffers (color targets) + * This state is saved in the FBO */ + if (numslots) + glDrawBuffers(numslots, gl_attachments); + else + glDrawBuffer(GL_NONE); +} - /* last bound prevails here, better allow explicit control here too */ - glDrawBuffers(numslots, attachments); - glReadBuffer(GL_COLOR_ATTACHMENT0_EXT + slot); +void GPU_framebuffer_bind(GPUFrameBuffer *fb) +{ + if (fb->object == 0) + gpu_framebuffer_init(fb); - /* 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; + if (g_currentfb != fb->object) + glBindFramebuffer(GL_FRAMEBUFFER, fb->object); - glMatrixMode(GL_PROJECTION); - glPushMatrix(); - glMatrixMode(GL_MODELVIEW); - glPushMatrix(); -} + g_currentfb = fb->object; + if (fb->dirty_flag != 0) + gpu_framebuffer_update_attachments(fb); -void GPU_framebuffer_texture_unbind(GPUFrameBuffer *UNUSED(fb), GPUTexture *UNUSED(tex)) -{ - /* restore matrix */ - glMatrixMode(GL_PROJECTION); - glPopMatrix(); - glMatrixMode(GL_MODELVIEW); - glPopMatrix(); + /* 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 (fb->multisample) + glEnable(GL_MULTISAMPLE); - /* restore attributes */ - glPopAttrib(); + glViewport(0, 0, fb->width, fb->height); } -void GPU_framebuffer_bind_no_save(GPUFrameBuffer *fb, int slot) +void GPU_framebuffer_restore(void) { - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb->object); - /* last bound prevails here, better allow explicit control here too */ - glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT + slot); - glReadBuffer(GL_COLOR_ATTACHMENT0_EXT + 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; - GG.currentfb = fb->object; + if (g_currentfb != 0) { + glBindFramebuffer(GL_FRAMEBUFFER, 0); + g_currentfb = 0; + } } bool GPU_framebuffer_bound(GPUFrameBuffer *fb) { - return fb->object == GG.currentfb; + return (fb->object == g_currentfb) && (fb->object != 0); +} + +unsigned int GPU_framebuffer_current_get(void) +{ + return g_currentfb; } bool GPU_framebuffer_check_valid(GPUFrameBuffer *fb, char err_out[256]) { - GLenum status; - - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb->object); - GG.currentfb = fb->object; - - /* Clean glError buffer. */ - while (glGetError() != GL_NO_ERROR) {} - - status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); - - if (status != GL_FRAMEBUFFER_COMPLETE_EXT) { + if (!GPU_framebuffer_bound(fb)) + GPU_framebuffer_bind(fb); + + GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); + + if (status != GL_FRAMEBUFFER_COMPLETE) { GPU_framebuffer_restore(); gpu_print_framebuffer_error(status, err_out); return false; } - + return true; } -void GPU_framebuffer_free(GPUFrameBuffer *fb) +/* ---------- Framebuffer Operations ----------- */ + +#define CHECK_FRAMEBUFFER_IS_BOUND(_fb) \ + BLI_assert(GPU_framebuffer_bound(_fb)); \ + UNUSED_VARS_NDEBUG(_fb); + +/* Needs to be done after binding. */ +void GPU_framebuffer_viewport_set(GPUFrameBuffer *fb, int x, int y, int w, int h) { - int i; - if (fb->depthtex) - GPU_framebuffer_texture_detach(fb->depthtex); + CHECK_FRAMEBUFFER_IS_BOUND(fb); - for (i = 0; i < GPU_FB_MAX_SLOTS; i++) { - if (fb->colortex[i]) { - GPU_framebuffer_texture_detach(fb->colortex[i]); - } - } + glViewport(x, y, w, h); +} - if (fb->object) { - glDeleteFramebuffersEXT(1, &fb->object); +void GPU_framebuffer_clear( + GPUFrameBuffer *fb, GPUFrameBufferBits buffers, + const float clear_col[4], float clear_depth, unsigned int clear_stencil) +{ + CHECK_FRAMEBUFFER_IS_BOUND(fb); - if (GG.currentfb == fb->object) { - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); - GG.currentfb = 0; - } + 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); } - MEM_freeN(fb); + GLbitfield mask = convert_buffer_bits_to_gl(buffers); + glClear(mask); } -void GPU_framebuffer_restore(void) +void GPU_framebuffer_read_depth(GPUFrameBuffer *fb, int x, int y, int w, int h, float *data) +{ + CHECK_FRAMEBUFFER_IS_BOUND(fb); + + GLenum type = GL_DEPTH_COMPONENT; + glReadBuffer(GL_COLOR_ATTACHMENT0); /* This is OK! */ + glReadPixels(x, y, w, h, type, GL_FLOAT, data); +} + +void GPU_framebuffer_read_color( + GPUFrameBuffer *fb, int x, int y, int w, int h, int channels, int slot, float *data) { - if (GG.currentfb != 0) { - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); - GG.currentfb = 0; + 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; } + glReadBuffer(GL_COLOR_ATTACHMENT0 + slot); + glReadPixels(x, y, w, h, type, GL_FLOAT, data); } -void GPU_framebuffer_blur( - GPUFrameBuffer *fb, GPUTexture *tex, - GPUFrameBuffer *blurfb, GPUTexture *blurtex) +/* 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) { - const float scaleh[2] = {1.0f / GPU_texture_width(blurtex), 0.0f}; - const float scalev[2] = {0.0f, 1.0f / GPU_texture_height(tex)}; + BLI_assert(blit_buffers != 0); - GPUShader *blur_shader = GPU_shader_get_builtin_shader(GPU_SHADER_SEP_GAUSSIAN_BLUR); - int scale_uniform, texture_source_uniform; + GLuint prev_fb = g_currentfb; - if (!blur_shader) - return; + /* 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); + } - scale_uniform = GPU_shader_get_uniform(blur_shader, "ScaleU"); - texture_source_uniform = GPU_shader_get_uniform(blur_shader, "textureSource"); - - /* Blurring horizontally */ + 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); - /* We do the bind ourselves rather than using GPU_framebuffer_texture_bind() to avoid - * pushing unnecessary matrices onto the OpenGL stack. */ - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, blurfb->object); - glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT); - - /* avoid warnings from texture binding */ - GG.currentfb = blurfb->object; - - GPU_shader_bind(blur_shader); - GPU_shader_uniform_vector(blur_shader, scale_uniform, 2, 1, scaleh); - GPU_shader_uniform_texture(blur_shader, texture_source_uniform, tex); - glViewport(0, 0, GPU_texture_width(blurtex), GPU_texture_height(blurtex)); - - /* Preparing to draw quad */ - glMatrixMode(GL_TEXTURE); - glLoadIdentity(); - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); - - glDisable(GL_DEPTH_TEST); - - GPU_texture_bind(tex, 0); - - /* Drawing quad */ - glBegin(GL_QUADS); - glTexCoord2d(0, 0); glVertex2f(1, 1); - glTexCoord2d(1, 0); glVertex2f(-1, 1); - glTexCoord2d(1, 1); glVertex2f(-1, -1); - glTexCoord2d(0, 1); glVertex2f(1, -1); - glEnd(); - - /* Blurring vertically */ - - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb->object); - glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT); - - GG.currentfb = fb->object; - - glViewport(0, 0, GPU_texture_width(tex), GPU_texture_height(tex)); - GPU_shader_uniform_vector(blur_shader, scale_uniform, 2, 1, scalev); - GPU_shader_uniform_texture(blur_shader, texture_source_uniform, blurtex); - GPU_texture_bind(blurtex, 0); + 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); + + 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)); + } + 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)); + } + + glBindFramebuffer(GL_READ_FRAMEBUFFER, fb_read->object); + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fb_write->object); + + if (do_color) { + glReadBuffer(GL_COLOR_ATTACHMENT0 + read_slot); + glDrawBuffer(GL_COLOR_ATTACHMENT0 + write_slot); + /* XXX we messed with the glDrawBuffer, this will reset the + * glDrawBuffers the next time we bind fb_write. */ + fb_write->dirty_flag = GPU_FB_DIRTY_DRAWBUFFER; + } + + 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 */ + if (fb_write->object == prev_fb) { + GPU_framebuffer_bind(fb_write); /* To update drawbuffers */ + } + else { + glBindFramebuffer(GL_FRAMEBUFFER, prev_fb); + g_currentfb = prev_fb; + } +} + +/** + * Use this if you need to custom downsample your texture and use the previous mip level as input. + * This function only takes care of the correct texture handling. It execute the callback for each texture level. + **/ +void GPU_framebuffer_recursive_downsample( + GPUFrameBuffer *fb, int max_lvl, + void (*callback)(void *userData, int level), void *userData) +{ + /* 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; + + int i; + int current_dim[2] = {fb->width, fb->height}; + for (i = 1; i < max_lvl + 1; i++) { + /* calculate next viewport size */ + current_dim[0] = max_ii(current_dim[0] / 2, 1); + current_dim[1] = max_ii(current_dim[1] / 2, 1); + + for (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); + } + } - glBegin(GL_QUADS); - glTexCoord2d(0, 0); glVertex2f(1, 1); - glTexCoord2d(1, 0); glVertex2f(-1, 1); - glTexCoord2d(1, 1); glVertex2f(-1, -1); - glTexCoord2d(0, 1); glVertex2f(1, -1); - glEnd(); + BLI_assert(GL_FRAMEBUFFER_COMPLETE == glCheckFramebufferStatus(GL_FRAMEBUFFER)); + + glViewport(0, 0, current_dim[0], current_dim[1]); + callback(userData, i); + + if (current_dim[0] == 1 && current_dim[1] == 1) + break; + } - GPU_shader_unbind(); + 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); + } + } + + g_currentfb = prev_fb; } /* GPUOffScreen */ @@ -451,63 +651,42 @@ struct GPUOffScreen { GPUTexture *depth; }; -GPUOffScreen *GPU_offscreen_create(int width, int height, int samples, 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; - } + ofs->color = GPU_texture_create_2D_multisample(width, height, + (high_bitdepth) ? GPU_RGBA16F : GPU_RGBA8, NULL, samples, err_out); - if (samples) { - if (!GLEW_EXT_framebuffer_multisample || - !GLEW_ARB_texture_multisample || - /* Only needed for GPU_offscreen_read_pixels. - * We could add an arg if we intend to use multi-sample - * offscreen buffers w/o reading their pixels */ - !GLEW_EXT_framebuffer_blit || - /* This is required when blitting from a multi-sampled buffers, - * even though we're not scaling. */ - !GLEW_EXT_framebuffer_multisample_blit_scaled) - { - samples = 0; - } + if (depth) { + ofs->depth = GPU_texture_create_2D_multisample(width, height, GPU_DEPTH24_STENCIL8, NULL, samples, err_out); } - ofs->depth = GPU_texture_create_depth_multisample(width, height, samples, err_out); - if (!ofs->depth) { + if ((depth && !ofs->depth) || !ofs->color) { GPU_offscreen_free(ofs); return NULL; } - if (!GPU_framebuffer_texture_attach(ofs->fb, ofs->depth, 0, err_out)) { - GPU_offscreen_free(ofs); - return NULL; - } + gpuPushAttrib(GPU_VIEWPORT_BIT); - ofs->color = GPU_texture_create_2D_multisample(width, height, NULL, GPU_HDR_NONE, samples, err_out); - if (!ofs->color) { - GPU_offscreen_free(ofs); - return NULL; - } + GPU_framebuffer_ensure_config(&ofs->fb, { + GPU_ATTACHMENT_TEXTURE(ofs->depth), + GPU_ATTACHMENT_TEXTURE(ofs->color) + }); - if (!GPU_framebuffer_texture_attach(ofs->fb, ofs->color, 0, err_out)) { - GPU_offscreen_free(ofs); - return NULL; - } - /* check validity at the very end! */ if (!GPU_framebuffer_check_valid(ofs->fb, err_out)) { GPU_offscreen_free(ofs); + gpuPopAttrib(); return NULL; } GPU_framebuffer_restore(); + gpuPopAttrib(); + return ofs; } @@ -525,20 +704,37 @@ 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_draw_to_screen(GPUOffScreen *ofs, int x, int y) +{ + const int w = GPU_texture_width(ofs->color); + const int h = GPU_texture_height(ofs->color); + + glBindFramebuffer(GL_READ_FRAMEBUFFER, ofs->fb->object); + GLenum status = glCheckFramebufferStatus(GL_READ_FRAMEBUFFER); + + if (status == GL_FRAMEBUFFER_COMPLETE) { + glBlitFramebuffer(0, 0, w, h, x, y, x + w, y + h, GL_COLOR_BUFFER_BIT, GL_NEAREST); + } + else { + gpu_print_framebuffer_error(status, NULL); + } + + glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); } void GPU_offscreen_read_pixels(GPUOffScreen *ofs, int type, void *pixels) @@ -546,74 +742,46 @@ 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 */ - glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, ofs->color->fb->object); - glFramebufferTexture2DEXT( - GL_READ_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + ofs->color->fb_attachment, - GL_TEXTURE_2D_MULTISAMPLE, ofs->color->bindcode, 0); - status = glCheckFramebufferStatusEXT(GL_READ_FRAMEBUFFER_EXT); - if (status != GL_FRAMEBUFFER_COMPLETE_EXT) { - 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 */ - glGenFramebuffersEXT(1, &fbo_blit); - glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, fbo_blit); - glFramebufferTexture2DEXT( - GL_DRAW_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, - GL_TEXTURE_2D, tex_blit, 0); - status = glCheckFramebufferStatusEXT(GL_DRAW_FRAMEBUFFER_EXT); - if (status != GL_FRAMEBUFFER_COMPLETE_EXT) { + glGenFramebuffers(1, &fbo_blit); + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo_blit); + 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; } /* perform the copy */ - glBlitFramebufferEXT(0, 0, w, h, 0, 0, w, h, GL_COLOR_BUFFER_BIT, GL_NEAREST); + glBlitFramebuffer(0, 0, w, h, 0, 0, w, h, GL_COLOR_BUFFER_BIT, GL_NEAREST); /* read the results */ - glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, fbo_blit); + 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 */ - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 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) { - glDeleteFramebuffersEXT(1, &fbo_blit); - } - - GPU_ASSERT_NO_GL_ERRORS("Read Multi-Sample Pixels"); + glDeleteTextures(1, &tex_blit); + glDeleteFramebuffers(1, &fbo_blit); } else { glReadPixels(0, 0, w, h, GL_RGBA, type, pixels); @@ -630,8 +798,17 @@ 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! */ +void GPU_offscreen_viewport_data_get( + GPUOffScreen *ofs, + GPUFrameBuffer **r_fb, GPUTexture **r_color, GPUTexture **r_depth) +{ + *r_fb = ofs->fb; + *r_color = ofs->color; + *r_depth = ofs->depth; +} diff --git a/source/blender/gpu/intern/gpu_immediate.c b/source/blender/gpu/intern/gpu_immediate.c new file mode 100644 index 00000000000..5f22b7f9279 --- /dev/null +++ b/source/blender/gpu/intern/gpu_immediate.c @@ -0,0 +1,88 @@ +/* + * ***** 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) 2016 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Mike Erwin + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include "GPU_immediate.h" +#include "GPU_matrix.h" +#include "UI_resources.h" +#include "BLI_utildefines.h" + +#include "gpu_shader_private.h" + +void immBindBuiltinProgram(GPUBuiltinShader shader_id) +{ + GPUShader *shader = GPU_shader_get_builtin_shader(shader_id); + immBindProgram(shader->program, shader->interface); +} + +void immUniformThemeColor(int color_id) +{ + float color[4]; + UI_GetThemeColor4fv(color_id, color); + immUniformColor4fv(color); +} + +void immUniformThemeColor3(int color_id) +{ + float color[3]; + UI_GetThemeColor3fv(color_id, color); + immUniformColor3fv(color); +} + +void immUniformThemeColorShade(int color_id, int offset) +{ + float color[4]; + UI_GetThemeColorShade4fv(color_id, offset, color); + immUniformColor4fv(color); +} + +void immUniformThemeColorShadeAlpha(int color_id, int color_offset, int alpha_offset) +{ + float color[4]; + UI_GetThemeColorShadeAlpha4fv(color_id, color_offset, alpha_offset, color); + immUniformColor4fv(color); +} + +void immUniformThemeColorBlendShade(int color_id1, int color_id2, float fac, int offset) +{ + float color[4]; + UI_GetThemeColorBlendShade4fv(color_id1, color_id2, fac, offset, color); + immUniformColor4fv(color); +} + +void immUniformThemeColorBlend(int color_id1, int color_id2, float fac) +{ + uint8_t color[3]; + UI_GetThemeColorBlend3ubv(color_id1, color_id2, fac, color); + immUniformColor3ubv(color); +} + +void immThemeColorShadeAlpha(int colorid, int coloffset, int alphaoffset) +{ + unsigned char col[4]; + UI_GetThemeColorShadeAlpha4ubv(colorid, coloffset, alphaoffset, col); + immUniformColor4ub(col[0], col[1], col[2], col[3]); +} diff --git a/source/blender/gpu/intern/gpu_immediate_util.c b/source/blender/gpu/intern/gpu_immediate_util.c new file mode 100644 index 00000000000..bad878ef4bf --- /dev/null +++ b/source/blender/gpu/intern/gpu_immediate_util.c @@ -0,0 +1,424 @@ +/* + * ***** 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. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file source/blender/gpu/intern/gpu_immediate_util.c + * \ingroup gpu + */ + +#include <stdio.h> +#include <string.h> + +#include "BLI_utildefines.h" +#include "BLI_math.h" + +#include "GPU_basic_shader.h" +#include "GPU_immediate.h" +#include "GPU_immediate_util.h" +#include "GPU_matrix.h" + +static const float cube_coords[8][3] = { + {-1, -1, -1}, + {-1, -1, +1}, + {-1, +1, -1}, + {-1, +1, +1}, + {+1, -1, -1}, + {+1, -1, +1}, + {+1, +1, -1}, + {+1, +1, +1}, +}; +static const int cube_quad_index[6][4] = { + {0, 1, 3, 2}, + {0, 2, 6, 4}, + {0, 4, 5, 1}, + {1, 5, 7, 3}, + {2, 3, 7, 6}, + {4, 6, 7, 5}, +}; +static const int cube_line_index[12][2] = { + {0, 1}, + {0, 2}, + {0, 4}, + {1, 3}, + {1, 5}, + {2, 3}, + {2, 6}, + {3, 7}, + {4, 5}, + {4, 6}, + {5, 7}, + {6, 7}, +}; + +/** + * Pack color into 3 bytes + * + * This define converts a numerical value to the equivalent 24-bit + * color, while not being endian-sensitive. On little-endians, this + * is the same as doing a 'naive' indexing, on big-endian, it is not! + * + * \note BGR format (i.e. 0xBBGGRR)... + * + * \param x color. + */ +void imm_cpack(unsigned int x) +{ + immUniformColor3ub(((x) & 0xFF), + (((x) >> 8) & 0xFF), + (((x) >> 16) & 0xFF)); +} + +static void imm_draw_circle( + Gwn_PrimType prim_type, const uint shdr_pos, float x, float y, float rad_x, float rad_y, int nsegments) +{ + immBegin(prim_type, nsegments); + for (int i = 0; i < nsegments; ++i) { + const float angle = (float)(2 * M_PI) * ((float)i / (float)nsegments); + immVertex2f(shdr_pos, x + (rad_x * cosf(angle)), y + (rad_y * sinf(angle))); + } + immEnd(); +} + +/** + * Draw a circle outline with the given \a radius. + * The circle is centered at \a x, \a y and drawn in the XY plane. + * + * \param shdr_pos The vertex attribute number for position. + * \param x Horizontal center. + * \param y Vertical center. + * \param radius The circle's radius. + * \param nsegments The number of segments to use in drawing (more = smoother). + */ +void imm_draw_circle_wire_2d(uint shdr_pos, float x, float y, float rad, int nsegments) +{ + imm_draw_circle(GWN_PRIM_LINE_LOOP, shdr_pos, x, y, rad, rad, nsegments); +} + +/** + * Draw a filled circle with the given \a radius. + * The circle is centered at \a x, \a y and drawn in the XY plane. + * + * \param shdr_pos The vertex attribute number for position. + * \param x Horizontal center. + * \param y Vertical center. + * \param radius The circle's radius. + * \param nsegments The number of segments to use in drawing (more = smoother). + */ +void imm_draw_circle_fill_2d(uint shdr_pos, float x, float y, float rad, int nsegments) +{ + imm_draw_circle(GWN_PRIM_TRI_FAN, shdr_pos, x, y, rad, rad, nsegments); +} + +void imm_draw_circle_wire_aspect_2d(uint shdr_pos, float x, float y, float rad_x, float rad_y, int nsegments) +{ + imm_draw_circle(GWN_PRIM_LINE_LOOP, shdr_pos, x, y, rad_x, rad_y, nsegments); +} +void imm_draw_circle_fill_aspect_2d(uint shdr_pos, float x, float y, float rad_x, float rad_y, int nsegments) +{ + imm_draw_circle(GWN_PRIM_TRI_FAN, shdr_pos, x, y, rad_x, rad_y, nsegments); +} + +/** + * \note We could have `imm_draw_lined_disk_partial` but currently there is no need. + */ +static void imm_draw_disk_partial( + Gwn_PrimType prim_type, unsigned pos, float x, float y, + float rad_inner, float rad_outer, int nsegments, float start, float sweep) +{ + /* shift & reverse angle, increase 'nsegments' to match gluPartialDisk */ + const float angle_start = -(DEG2RADF(start)) + (float)(M_PI / 2); + const float angle_end = -(DEG2RADF(sweep) - angle_start); + nsegments += 1; + immBegin(prim_type, nsegments * 2); + for (int i = 0; i < nsegments; ++i) { + const float angle = interpf(angle_start, angle_end, ((float)i / (float)(nsegments - 1))); + const float angle_sin = sinf(angle); + const float angle_cos = cosf(angle); + immVertex2f(pos, x + rad_inner * angle_cos, y + rad_inner * angle_sin); + immVertex2f(pos, x + rad_outer * angle_cos, y + rad_outer * angle_sin); + } + immEnd(); +} + +/** + * Draw a filled arc with the given inner and outer radius. + * The circle is centered at \a x, \a y and drawn in the XY plane. + * + * \note Arguments are `gluPartialDisk` compatible. + * + * \param pos: The vertex attribute number for position. + * \param x: Horizontal center. + * \param y: Vertical center. + * \param radius_inner: The inner circle's radius. + * \param radius_outer: The outer circle's radius (can be zero). + * \param nsegments: The number of segments to use in drawing (more = smoother). + * \param start: Specifies the starting angle, in degrees, of the disk portion. + * \param sweep: Specifies the sweep angle, in degrees, of the disk portion. + */ +void imm_draw_disk_partial_fill_2d( + unsigned pos, float x, float y, + float rad_inner, float rad_outer, int nsegments, float start, float sweep) +{ + imm_draw_disk_partial(GWN_PRIM_TRI_STRIP, pos, x, y, rad_inner, rad_outer, nsegments, start, sweep); +} + +static void imm_draw_circle_3D( + Gwn_PrimType prim_type, unsigned pos, float x, float y, + float rad, int nsegments) +{ + immBegin(prim_type, nsegments); + for (int i = 0; i < nsegments; ++i) { + float angle = (float)(2 * M_PI) * ((float)i / (float)nsegments); + immVertex3f(pos, x + rad * cosf(angle), y + rad * sinf(angle), 0.0f); + } + immEnd(); +} + +void imm_draw_circle_wire_3d(unsigned pos, float x, float y, float rad, int nsegments) +{ + imm_draw_circle_3D(GWN_PRIM_LINE_LOOP, pos, x, y, rad, nsegments); +} + +void imm_draw_circle_fill_3d(unsigned pos, float x, float y, float rad, int nsegments) +{ + imm_draw_circle_3D(GWN_PRIM_TRI_FAN, pos, x, y, rad, nsegments); +} + +/** +* Draw a lined box. +* +* \param pos The vertex attribute number for position. +* \param x1 left. +* \param y1 bottom. +* \param x2 right. +* \param y2 top. +*/ +void imm_draw_box_wire_2d(unsigned pos, float x1, float y1, float x2, float y2) +{ + immBegin(GWN_PRIM_LINE_LOOP, 4); + immVertex2f(pos, x1, y1); + immVertex2f(pos, x1, y2); + immVertex2f(pos, x2, y2); + immVertex2f(pos, x2, y1); + immEnd(); +} + +void imm_draw_box_wire_3d(unsigned pos, float x1, float y1, float x2, float y2) +{ + /* use this version when Gwn_VertFormat has a vec3 position */ + immBegin(GWN_PRIM_LINE_LOOP, 4); + immVertex3f(pos, x1, y1, 0.0f); + immVertex3f(pos, x1, y2, 0.0f); + immVertex3f(pos, x2, y2, 0.0f); + immVertex3f(pos, x2, y1, 0.0f); + immEnd(); +} + +/** + * Draw a standard checkerboard to indicate transparent backgrounds. + */ +void imm_draw_box_checker_2d(float x1, float y1, float x2, float y2) +{ + unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT); + immBindBuiltinProgram(GPU_SHADER_2D_CHECKER); + + immUniform4f("color1", 0.15f, 0.15f, 0.15f, 1.0f); + immUniform4f("color2", 0.2f, 0.2f, 0.2f, 1.0f); + immUniform1i("size", 8); + + immRectf(pos, x1, y1, x2, y2); + + immUnbindProgram(); +} + +void imm_draw_cube_fill_3d(uint pos, const float co[3], const float aspect[3]) +{ + float coords[ARRAY_SIZE(cube_coords)][3]; + + for (int i = 0; i < ARRAY_SIZE(cube_coords); i++) { + madd_v3_v3v3v3(coords[i], co, cube_coords[i], aspect); + } + + immBegin(GWN_PRIM_TRIS, ARRAY_SIZE(cube_quad_index) * 3 * 2); + for (int i = 0; i < ARRAY_SIZE(cube_quad_index); i++) { + immVertex3fv(pos, coords[cube_quad_index[i][0]]); + immVertex3fv(pos, coords[cube_quad_index[i][1]]); + immVertex3fv(pos, coords[cube_quad_index[i][2]]); + + immVertex3fv(pos, coords[cube_quad_index[i][0]]); + immVertex3fv(pos, coords[cube_quad_index[i][2]]); + immVertex3fv(pos, coords[cube_quad_index[i][3]]); + } + immEnd(); +} + +void imm_draw_cube_wire_3d(uint pos, const float co[3], const float aspect[3]) +{ + float coords[ARRAY_SIZE(cube_coords)][3]; + + for (int i = 0; i < ARRAY_SIZE(cube_coords); i++) { + madd_v3_v3v3v3(coords[i], co, cube_coords[i], aspect); + } + + immBegin(GWN_PRIM_LINES, ARRAY_SIZE(cube_line_index) * 2); + for (int i = 0; i < ARRAY_SIZE(cube_line_index); i++) { + immVertex3fv(pos, coords[cube_line_index[i][0]]); + immVertex3fv(pos, coords[cube_line_index[i][1]]); + } + immEnd(); +} + +/** +* Draw a cylinder. Replacement for gluCylinder. +* _warning_ : Slow, better use it only if you no other choices. +* +* \param pos The vertex attribute number for position. +* \param nor The vertex attribute number for normal. +* \param base Specifies the radius of the cylinder at z = 0. +* \param top Specifies the radius of the cylinder at z = height. +* \param height Specifies the height of the cylinder. +* \param slices Specifies the number of subdivisions around the z axis. +* \param stacks Specifies the number of subdivisions along the z axis. +*/ +void imm_draw_cylinder_fill_normal_3d( + unsigned int pos, unsigned int nor, float base, float top, float height, int slices, int stacks) +{ + immBegin(GWN_PRIM_TRIS, 6 * slices * stacks); + for (int i = 0; i < slices; ++i) { + const float angle1 = (float)(2 * M_PI) * ((float)i / (float)slices); + const float angle2 = (float)(2 * M_PI) * ((float)(i + 1) / (float)slices); + const float cos1 = cosf(angle1); + const float sin1 = sinf(angle1); + const float cos2 = cosf(angle2); + const float sin2 = sinf(angle2); + + for (int j = 0; j < stacks; ++j) { + float fac1 = (float)j / (float)stacks; + float fac2 = (float)(j + 1) / (float)stacks; + float r1 = base * (1.f - fac1) + top * fac1; + float r2 = base * (1.f - fac2) + top * fac2; + float h1 = height * ((float)j / (float)stacks); + float h2 = height * ((float)(j + 1) / (float)stacks); + + float v1[3] = {r1 *cos2, r1 * sin2, h1}; + float v2[3] = {r2 *cos2, r2 * sin2, h2}; + float v3[3] = {r2 *cos1, r2 * sin1, h2}; + float v4[3] = {r1 *cos1, r1 * sin1, h1}; + float n1[3], n2[3]; + + /* calc normals */ + sub_v3_v3v3(n1, v2, v1); + normalize_v3(n1); + n1[0] = cos1; n1[1] = sin1; n1[2] = 1 - n1[2]; + + sub_v3_v3v3(n2, v3, v4); + normalize_v3(n2); + n2[0] = cos2; n2[1] = sin2; n2[2] = 1 - n2[2]; + + /* first tri */ + immAttrib3fv(nor, n2); + immVertex3fv(pos, v1); + immVertex3fv(pos, v2); + immAttrib3fv(nor, n1); + immVertex3fv(pos, v3); + + /* second tri */ + immVertex3fv(pos, v3); + immVertex3fv(pos, v4); + immAttrib3fv(nor, n2); + immVertex3fv(pos, v1); + } + } + immEnd(); +} + +void imm_draw_cylinder_wire_3d(unsigned int pos, float base, float top, float height, int slices, int stacks) +{ + immBegin(GWN_PRIM_LINES, 6 * slices * stacks); + for (int i = 0; i < slices; ++i) { + const float angle1 = (float)(2 * M_PI) * ((float)i / (float)slices); + const float angle2 = (float)(2 * M_PI) * ((float)(i + 1) / (float)slices); + const float cos1 = cosf(angle1); + const float sin1 = sinf(angle1); + const float cos2 = cosf(angle2); + const float sin2 = sinf(angle2); + + for (int j = 0; j < stacks; ++j) { + float fac1 = (float)j / (float)stacks; + float fac2 = (float)(j + 1) / (float)stacks; + float r1 = base * (1.f - fac1) + top * fac1; + float r2 = base * (1.f - fac2) + top * fac2; + float h1 = height * ((float)j / (float)stacks); + float h2 = height * ((float)(j + 1) / (float)stacks); + + float v1[3] = {r1 * cos2, r1 * sin2, h1}; + float v2[3] = {r2 * cos2, r2 * sin2, h2}; + float v3[3] = {r2 * cos1, r2 * sin1, h2}; + float v4[3] = {r1 * cos1, r1 * sin1, h1}; + + immVertex3fv(pos, v1); + immVertex3fv(pos, v2); + + immVertex3fv(pos, v2); + immVertex3fv(pos, v3); + + immVertex3fv(pos, v1); + immVertex3fv(pos, v4); + } + } + immEnd(); +} + +void imm_draw_cylinder_fill_3d(unsigned int pos, float base, float top, float height, int slices, int stacks) +{ + immBegin(GWN_PRIM_TRIS, 6 * slices * stacks); + for (int i = 0; i < slices; ++i) { + const float angle1 = (float)(2 * M_PI) * ((float)i / (float)slices); + const float angle2 = (float)(2 * M_PI) * ((float)(i + 1) / (float)slices); + const float cos1 = cosf(angle1); + const float sin1 = sinf(angle1); + const float cos2 = cosf(angle2); + const float sin2 = sinf(angle2); + + for (int j = 0; j < stacks; ++j) { + float fac1 = (float)j / (float)stacks; + float fac2 = (float)(j + 1) / (float)stacks; + float r1 = base * (1.f - fac1) + top * fac1; + float r2 = base * (1.f - fac2) + top * fac2; + float h1 = height * ((float)j / (float)stacks); + float h2 = height * ((float)(j + 1) / (float)stacks); + + float v1[3] = {r1 * cos2, r1 * sin2, h1}; + float v2[3] = {r2 * cos2, r2 * sin2, h2}; + float v3[3] = {r2 * cos1, r2 * sin1, h2}; + float v4[3] = {r1 * cos1, r1 * sin1, h1}; + + /* first tri */ + immVertex3fv(pos, v1); + immVertex3fv(pos, v2); + immVertex3fv(pos, v3); + + /* second tri */ + immVertex3fv(pos, v3); + immVertex3fv(pos, v4); + immVertex3fv(pos, v1); + } + } + immEnd(); +} diff --git a/source/blender/gpu/intern/gpu_init_exit.c b/source/blender/gpu/intern/gpu_init_exit.c index c72c83b6b07..c2f14687ff5 100644 --- a/source/blender/gpu/intern/gpu_init_exit.c +++ b/source/blender/gpu/intern/gpu_init_exit.c @@ -30,8 +30,10 @@ */ #include "BLI_sys_types.h" +#include "GPU_buffers.h" #include "GPU_init_exit.h" /* interface */ - +#include "GPU_immediate.h" +#include "GPU_batch.h" #include "BKE_global.h" #include "intern/gpu_codegen.h" @@ -59,14 +61,28 @@ void GPU_init(void) if (G.debug & G_DEBUG_GPU) gpu_debug_init(); + gpu_batch_init(); + + if (!G.background) { + immInit(); + } + + GPU_pbvh_fix_linking(); } void GPU_exit(void) { + if (!G.background) { + immDestroy(); + } + + gpu_batch_exit(); + if (G.debug & G_DEBUG_GPU) gpu_debug_exit(); + gpu_codegen_exit(); gpu_extensions_exit(); /* must come last */ diff --git a/source/blender/gpu/intern/gpu_material.c b/source/blender/gpu/intern/gpu_material.c index edb6c9a29f9..769c60f8e61 100644 --- a/source/blender/gpu/intern/gpu_material.c +++ b/source/blender/gpu/intern/gpu_material.c @@ -45,16 +45,17 @@ #include "BLI_math.h" #include "BLI_blenlib.h" #include "BLI_utildefines.h" +#include "BLI_rand.h" #include "BKE_anim.h" #include "BKE_colorband.h" #include "BKE_colortools.h" #include "BKE_global.h" #include "BKE_image.h" +#include "BKE_layer.h" #include "BKE_main.h" #include "BKE_node.h" #include "BKE_scene.h" -#include "BKE_group.h" #include "IMB_imbuf_types.h" @@ -63,6 +64,9 @@ #include "GPU_material.h" #include "GPU_shader.h" #include "GPU_texture.h" +#include "GPU_uniformbuffer.h" + +#include "DRW_engine.h" #include "gpu_codegen.h" @@ -72,32 +76,17 @@ /* Structs */ -typedef enum DynMatProperty { - DYN_LAMP_CO = 1, - DYN_LAMP_VEC = 2, - DYN_LAMP_IMAT = 4, - DYN_LAMP_PERSMAT = 8, -} DynMatProperty; - -static struct GPUWorld { - float mistenabled; - float mistype; - float miststart; - float mistdistance; - float mistintensity; - float mistcol[4]; - float horicol[3]; - float ambcol[4]; - float zencol[3]; -} GPUWorld; - struct GPUMaterial { - Scene *scene; + Scene *scene; /* DEPRECATED was only usefull for lamps */ Material *ma; /* material for mesh surface, worlds or something else. * some code generation is done differently depending on the use case */ - int type; + int type; /* DEPRECATED */ + GPUMaterialStatus status; + + const void *engine_type; /* attached engine type */ + int options; /* to identify shader variations (shadow, probe, world background...) */ /* for creating the material */ ListBase nodes; @@ -105,6 +94,7 @@ struct GPUMaterial { /* for binding the material */ GPUPass *pass; + ListBase inputs; /* GPUInput */ GPUVertexAttribs attribs; int builtins; int alpha, obcolalpha; @@ -124,360 +114,69 @@ struct GPUMaterial { int objectinfoloc; - ListBase lamps; - bool bound; - bool is_opensubdiv; -}; - -struct GPULamp { - Scene *scene; - Object *ob; - Object *par; - Lamp *la; - - int type, mode, lay, hide; - - float dynenergy, dyncol[3]; - float energy, col[3]; - - float co[3], vec[3]; - float dynco[3], dynvec[3]; - float obmat[4][4]; - float imat[4][4]; - float dynimat[4][4]; - float spotsi, spotbl, k; - float spotvec[2]; - float dyndist, dynatt1, dynatt2; - float dist, att1, att2; - float coeff_const, coeff_lin, coeff_quad; - float shadow_color[3]; - - float bias, d, clipend; - int size; - - int falloff_type; - struct CurveMapping *curfalloff; - - float winmat[4][4]; - float viewmat[4][4]; - float persmat[4][4]; - float dynpersmat[4][4]; - - GPUFrameBuffer *fb; - GPUFrameBuffer *blurfb; - GPUTexture *tex; - GPUTexture *depthtex; - GPUTexture *blurtex; - - ListBase materials; + /* XXX: Should be in Material. But it depends on the output node + * used and since the output selection is difference for 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. */ + int sss_samples; + short int *sss_falloff; + float *sss_sharpness; + bool sss_dirty; }; -/* Forward declaration so shade_light_textures() can use this, while still keeping the code somewhat organized */ -static void texture_rgb_blend( - GPUMaterial *mat, GPUNodeLink *tex, GPUNodeLink *out, GPUNodeLink *fact, GPUNodeLink *facg, - int blendtype, GPUNodeLink **in); +enum { + GPU_DOMAIN_SURFACE = (1 << 0), + GPU_DOMAIN_VOLUME = (1 << 1), + GPU_DOMAIN_SSS = (1 << 2) +}; /* Functions */ -static GPUMaterial *GPU_material_construct_begin(Material *ma) -{ - GPUMaterial *material = MEM_callocN(sizeof(GPUMaterial), "GPUMaterial"); - - material->ma = ma; - - return material; -} - -static void gpu_material_set_attrib_id(GPUMaterial *material) -{ - GPUVertexAttribs *attribs = &material->attribs; - GPUPass *pass = material->pass; - if (!pass) { - attribs->totlayer = 0; - return; - } - - GPUShader *shader = GPU_pass_shader(pass); - if (!shader) { - attribs->totlayer = 0; - return; - } - - /* convert from attribute number to the actual id assigned by opengl, - * in case the attrib does not get a valid index back, it was probably - * removed by the glsl compiler by dead code elimination */ - - int b = 0; - for (int a = 0; a < attribs->totlayer; a++) { - char name[32]; - BLI_snprintf(name, sizeof(name), "att%d", attribs->layer[a].attribid); - attribs->layer[a].glindex = GPU_shader_get_attribute(shader, name); - - BLI_snprintf(name, sizeof(name), "att%d_info", attribs->layer[a].attribid); - attribs->layer[a].glinfoindoex = GPU_shader_get_uniform(shader, name); - - if (attribs->layer[a].glindex >= 0) { - attribs->layer[b] = attribs->layer[a]; - b++; - } - } - - attribs->totlayer = b; -} - -static int gpu_material_construct_end(GPUMaterial *material, const char *passname) -{ - if (material->outlink) { - GPUNodeLink *outlink = material->outlink; - material->pass = GPU_generate_pass(&material->nodes, outlink, - &material->attribs, &material->builtins, material->type, - passname, - material->is_opensubdiv, - GPU_material_use_new_shading_nodes(material)); - - if (!material->pass) - return 0; - - gpu_material_set_attrib_id(material); - - GPUShader *shader = GPU_pass_shader(material->pass); - - if (material->builtins & GPU_VIEW_MATRIX) - material->viewmatloc = GPU_shader_get_uniform(shader, GPU_builtin_name(GPU_VIEW_MATRIX)); - if (material->builtins & GPU_INVERSE_VIEW_MATRIX) - material->invviewmatloc = GPU_shader_get_uniform(shader, GPU_builtin_name(GPU_INVERSE_VIEW_MATRIX)); - if (material->builtins & GPU_OBJECT_MATRIX) - material->obmatloc = GPU_shader_get_uniform(shader, GPU_builtin_name(GPU_OBJECT_MATRIX)); - if (material->builtins & GPU_INVERSE_OBJECT_MATRIX) - material->invobmatloc = GPU_shader_get_uniform(shader, GPU_builtin_name(GPU_INVERSE_OBJECT_MATRIX)); - if (material->builtins & GPU_LOC_TO_VIEW_MATRIX) - material->localtoviewmatloc = GPU_shader_get_uniform(shader, GPU_builtin_name(GPU_LOC_TO_VIEW_MATRIX)); - if (material->builtins & GPU_INVERSE_LOC_TO_VIEW_MATRIX) - material->invlocaltoviewmatloc = GPU_shader_get_uniform(shader, GPU_builtin_name(GPU_INVERSE_LOC_TO_VIEW_MATRIX)); - if (material->builtins & GPU_OBCOLOR) - material->obcolloc = GPU_shader_get_uniform(shader, GPU_builtin_name(GPU_OBCOLOR)); - if (material->builtins & GPU_AUTO_BUMPSCALE) - material->obautobumpscaleloc = GPU_shader_get_uniform(shader, GPU_builtin_name(GPU_AUTO_BUMPSCALE)); - if (material->builtins & GPU_CAMERA_TEXCO_FACTORS) - material->cameratexcofacloc = GPU_shader_get_uniform(shader, GPU_builtin_name(GPU_CAMERA_TEXCO_FACTORS)); - if (material->builtins & GPU_PARTICLE_SCALAR_PROPS) - material->partscalarpropsloc = GPU_shader_get_uniform(shader, GPU_builtin_name(GPU_PARTICLE_SCALAR_PROPS)); - if (material->builtins & GPU_PARTICLE_LOCATION) - material->partcoloc = GPU_shader_get_uniform(shader, GPU_builtin_name(GPU_PARTICLE_LOCATION)); - if (material->builtins & GPU_PARTICLE_VELOCITY) - material->partvel = GPU_shader_get_uniform(shader, GPU_builtin_name(GPU_PARTICLE_VELOCITY)); - if (material->builtins & GPU_PARTICLE_ANG_VELOCITY) - material->partangvel = GPU_shader_get_uniform(shader, GPU_builtin_name(GPU_PARTICLE_ANG_VELOCITY)); - if (material->builtins & GPU_OBJECT_INFO) - material->objectinfoloc = GPU_shader_get_uniform(shader, GPU_builtin_name(GPU_OBJECT_INFO)); - return 1; - } - else { - GPU_pass_free_nodes(&material->nodes); - } - - return 0; -} - void GPU_material_free(ListBase *gpumaterial) { for (LinkData *link = gpumaterial->first; link; link = link->next) { GPUMaterial *material = link->data; - if (material->pass) - GPU_pass_free(material->pass); - - for (LinkData *nlink = material->lamps.first; nlink; nlink = nlink->next) { - GPULamp *lamp = nlink->data; - - if (material->ma) { - Material *ma = material->ma; - - LinkData *next = NULL; - for (LinkData *mlink = lamp->materials.first; mlink; mlink = next) { - next = mlink->next; - if (mlink->data == ma) - BLI_freelinkN(&lamp->materials, mlink); - } - } - } - - BLI_freelistN(&material->lamps); - - MEM_freeN(material); - } + /* Cancel / wait any pending lazy compilation. */ + DRW_deferred_shader_remove(material); - BLI_freelistN(gpumaterial); -} + GPU_pass_free_nodes(&material->nodes); + GPU_inputs_free(&material->inputs); -bool GPU_lamp_visible(GPULamp *lamp, SceneRenderLayer *srl, Material *ma) -{ - if (lamp->hide) - return false; - else if (srl && srl->light_override) - return BKE_group_object_exists(srl->light_override, lamp->ob); - else if (ma && ma->group) - return BKE_group_object_exists(ma->group, lamp->ob); - else - return true; -} + if (material->pass) + GPU_pass_release(material->pass); -void GPU_material_bind( - GPUMaterial *material, int oblay, int viewlay, double time, int mipmap, - float viewmat[4][4], float viewinv[4][4], float camerafactors[4], bool scenelock) -{ - if (material->pass) { - GPUShader *shader = GPU_pass_shader(material->pass); - SceneRenderLayer *srl = scenelock ? BLI_findlink(&material->scene->r.layers, material->scene->r.actlay) : NULL; - - if (srl) - viewlay &= srl->lay; - - /* handle layer lamps */ - if (material->type == GPU_MATERIAL_TYPE_MESH) { - for (LinkData *nlink = material->lamps.first; nlink; nlink = nlink->next) { - GPULamp *lamp = nlink->data; - - if ((lamp->lay & viewlay) && (!(lamp->mode & LA_LAYER) || (lamp->lay & oblay)) && - GPU_lamp_visible(lamp, srl, material->ma)) - { - lamp->dynenergy = lamp->energy; - copy_v3_v3(lamp->dyncol, lamp->col); - } - else { - lamp->dynenergy = 0.0f; - lamp->dyncol[0] = lamp->dyncol[1] = lamp->dyncol[2] = 0.0f; - } - - if (material->dynproperty & DYN_LAMP_VEC) { - copy_v3_v3(lamp->dynvec, lamp->vec); - normalize_v3(lamp->dynvec); - negate_v3(lamp->dynvec); - mul_mat3_m4_v3(viewmat, lamp->dynvec); - } - - if (material->dynproperty & DYN_LAMP_CO) { - copy_v3_v3(lamp->dynco, lamp->co); - mul_m4_v3(viewmat, lamp->dynco); - } - - if (material->dynproperty & DYN_LAMP_IMAT) { - mul_m4_m4m4(lamp->dynimat, lamp->imat, viewinv); - } - - if (material->dynproperty & DYN_LAMP_PERSMAT) { - /* The lamp matrices are already updated if we're using shadow buffers */ - if (!GPU_lamp_has_shadow_buffer(lamp)) { - GPU_lamp_update_buffer_mats(lamp); - } - mul_m4_m4m4(lamp->dynpersmat, lamp->persmat, viewinv); - } - } + if (material->ubo != NULL) { + GPU_uniformbuffer_free(material->ubo); } - - /* note material must be bound before setting uniforms */ - GPU_pass_bind(material->pass, time, mipmap); - /* handle per material built-ins */ - if (material->builtins & GPU_VIEW_MATRIX) { - GPU_shader_uniform_vector(shader, material->viewmatloc, 16, 1, (float *)viewmat); - } - if (material->builtins & GPU_INVERSE_VIEW_MATRIX) { - GPU_shader_uniform_vector(shader, material->invviewmatloc, 16, 1, (float *)viewinv); - } - if (material->builtins & GPU_CAMERA_TEXCO_FACTORS) { - if (camerafactors) { - GPU_shader_uniform_vector(shader, material->cameratexcofacloc, 4, 1, (float *)camerafactors); - } - else { - /* use default, no scaling no offset */ - float borders[4] = {1.0f, 1.0f, 0.0f, 0.0f}; - GPU_shader_uniform_vector(shader, material->cameratexcofacloc, 4, 1, (float *)borders); - } + if (material->sss_tex_profile != NULL) { + GPU_texture_free(material->sss_tex_profile); } - GPU_pass_update_uniforms(material->pass); - - material->bound = 1; - } -} - -GPUBuiltin GPU_get_material_builtins(GPUMaterial *material) -{ - return material->builtins; -} - -void GPU_material_bind_uniforms( - GPUMaterial *material, float obmat[4][4], float viewmat[4][4], float obcol[4], - float autobumpscale, GPUParticleInfo *pi, float object_info[3]) -{ - if (material->pass) { - GPUShader *shader = GPU_pass_shader(material->pass); - float invmat[4][4], col[4]; - float localtoviewmat[4][4]; - float invlocaltoviewmat[4][4]; - - /* handle per object builtins */ - if (material->builtins & GPU_OBJECT_MATRIX) { - GPU_shader_uniform_vector(shader, material->obmatloc, 16, 1, (float *)obmat); - } - if (material->builtins & GPU_INVERSE_OBJECT_MATRIX) { - invert_m4_m4(invmat, obmat); - GPU_shader_uniform_vector(shader, material->invobmatloc, 16, 1, (float *)invmat); - } - if (material->builtins & GPU_LOC_TO_VIEW_MATRIX) { - if (viewmat) { - mul_m4_m4m4(localtoviewmat, viewmat, obmat); - GPU_shader_uniform_vector(shader, material->localtoviewmatloc, 16, 1, (float *)localtoviewmat); - } - } - if (material->builtins & GPU_INVERSE_LOC_TO_VIEW_MATRIX) { - if (viewmat) { - mul_m4_m4m4(localtoviewmat, viewmat, obmat); - invert_m4_m4(invlocaltoviewmat, localtoviewmat); - GPU_shader_uniform_vector(shader, material->invlocaltoviewmatloc, 16, 1, (float *)invlocaltoviewmat); - } - } - if (material->builtins & GPU_OBCOLOR) { - copy_v4_v4(col, obcol); - CLAMP(col[3], 0.0f, 1.0f); - GPU_shader_uniform_vector(shader, material->obcolloc, 4, 1, col); - } - if (material->builtins & GPU_AUTO_BUMPSCALE) { - GPU_shader_uniform_vector(shader, material->obautobumpscaleloc, 1, 1, &autobumpscale); - } - if (material->builtins & GPU_PARTICLE_SCALAR_PROPS) { - GPU_shader_uniform_vector(shader, material->partscalarpropsloc, 4, 1, pi->scalprops); - } - if (material->builtins & GPU_PARTICLE_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); - } - if (material->builtins & GPU_PARTICLE_ANG_VELOCITY) { - GPU_shader_uniform_vector(shader, material->partangvel, 3, 1, pi->angular_velocity); - } - if (material->builtins & GPU_OBJECT_INFO) { - GPU_shader_uniform_vector(shader, material->objectinfoloc, 3, 1, object_info); + if (material->sss_profile != NULL) { + GPU_uniformbuffer_free(material->sss_profile); } + MEM_freeN(material); } -} -void GPU_material_unbind(GPUMaterial *material) -{ - if (material->pass) { - material->bound = 0; - GPU_pass_unbind(material->pass); - } + BLI_freelistN(gpumaterial); } -bool GPU_material_bound(GPUMaterial *material) +GPUBuiltin GPU_get_material_builtins(GPUMaterial *material) { - return material->bound; + return material->builtins; } Scene *GPU_material_scene(GPUMaterial *material) @@ -490,1735 +189,478 @@ GPUMatType GPU_Material_get_type(GPUMaterial *material) return material->type; } - -void GPU_material_vertex_attributes(GPUMaterial *material, GPUVertexAttribs *attribs) +GPUPass *GPU_material_get_pass(GPUMaterial *material) { - *attribs = material->attribs; + return material->pass; } -void GPU_material_output_link(GPUMaterial *material, GPUNodeLink *link) +ListBase *GPU_material_get_inputs(GPUMaterial *material) { - if (!material->outlink) - material->outlink = link; + return &material->inputs; } -void GPU_material_enable_alpha(GPUMaterial *material) +GPUUniformBuffer *GPU_material_get_uniform_buffer(GPUMaterial *material) { - material->alpha = 1; + return material->ubo; } -GPUBlendMode GPU_material_alpha_blend(GPUMaterial *material, float obcol[4]) +/** + * Create dynamic UBO from parameters + * \param ListBase of BLI_genericNodeN(GPUInput) + */ +void GPU_material_create_uniform_buffer(GPUMaterial *material, ListBase *inputs) { - if (material->alpha || (material->obcolalpha && obcol[3] < 1.0f)) - return GPU_BLEND_ALPHA; - else - return GPU_BLEND_SOLID; + material->ubo = GPU_uniformbuffer_dynamic_create(inputs, NULL); } -void gpu_material_add_node(GPUMaterial *material, GPUNode *node) +void GPU_material_uniform_buffer_tag_dirty(ListBase *gpumaterials) { - BLI_addtail(&material->nodes, node); + for (LinkData *link = gpumaterials->first; link; link = link->next) { + GPUMaterial *material = link->data; + if (material->ubo != NULL) { + GPU_uniformbuffer_tag_dirty(material->ubo); + } + if (material->sss_profile != NULL) { + material->sss_dirty = true; + } + } } -/* Code generation */ +/* Eevee Subsurface scattering. */ +/* Based on Separable SSS. by Jorge Jimenez and Diego Gutierrez */ -bool GPU_material_do_color_management(GPUMaterial *mat) -{ - if (!BKE_scene_check_color_management_enabled(mat->scene)) - return false; +#define SSS_SAMPLES 65 +#define SSS_EXPONENT 2.0f /* Importance sampling exponent */ - return true; -} +typedef struct GPUSssKernelData { + float kernel[SSS_SAMPLES][4]; + float param[3], max_radius; + int samples; +} GPUSssKernelData; -bool GPU_material_use_new_shading_nodes(GPUMaterial *mat) +static void sss_calculate_offsets(GPUSssKernelData *kd, int count, float exponent) { - return BKE_scene_use_new_shading_nodes(mat->scene); -} - -bool GPU_material_use_world_space_shading(GPUMaterial *mat) -{ - return BKE_scene_use_world_space_shading(mat->scene); + float step = 2.0f / (float)(count - 1); + for (int i = 0; i < count; i++) { + float o = ((float)i) * step - 1.0f; + float sign = (o < 0.0f) ? -1.0f : 1.0f; + float ofs = sign * fabsf(powf(o, exponent)); + kd->kernel[i][3] = ofs; + } } -static GPUNodeLink *lamp_get_visibility(GPUMaterial *mat, GPULamp *lamp, GPUNodeLink **lv, GPUNodeLink **dist) +#define GAUSS_TRUNCATE 12.46f +static float gaussian_profile(float r, float radius) { - GPUNodeLink *visifac; - - /* from get_lamp_visibility */ - if (lamp->type == LA_SUN || lamp->type == LA_HEMI) { - mat->dynproperty |= DYN_LAMP_VEC; - GPU_link(mat, "lamp_visibility_sun_hemi", - GPU_dynamic_uniform(lamp->dynvec, GPU_DYNAMIC_LAMP_DYNVEC, lamp->ob), lv, dist, &visifac); - return visifac; - } - else { - mat->dynproperty |= DYN_LAMP_CO; - GPU_link(mat, "lamp_visibility_other", - GPU_builtin(GPU_VIEW_POSITION), - GPU_dynamic_uniform(lamp->dynco, GPU_DYNAMIC_LAMP_DYNCO, lamp->ob), lv, dist, &visifac); - - if (lamp->type == LA_AREA) - return visifac; - - switch (lamp->falloff_type) { - case LA_FALLOFF_CONSTANT: - break; - case LA_FALLOFF_INVLINEAR: - GPU_link(mat, "lamp_falloff_invlinear", - GPU_dynamic_uniform(&lamp->dist, GPU_DYNAMIC_LAMP_DISTANCE, lamp->ob), *dist, &visifac); - break; - case LA_FALLOFF_INVSQUARE: - GPU_link(mat, "lamp_falloff_invsquare", - GPU_dynamic_uniform(&lamp->dist, GPU_DYNAMIC_LAMP_DISTANCE, lamp->ob), *dist, &visifac); - break; - case LA_FALLOFF_SLIDERS: - GPU_link(mat, "lamp_falloff_sliders", - GPU_dynamic_uniform(&lamp->dist, GPU_DYNAMIC_LAMP_DISTANCE, lamp->ob), - GPU_dynamic_uniform(&lamp->att1, GPU_DYNAMIC_LAMP_ATT1, lamp->ob), - GPU_dynamic_uniform(&lamp->att2, GPU_DYNAMIC_LAMP_ATT2, lamp->ob), *dist, &visifac); - break; - case LA_FALLOFF_INVCOEFFICIENTS: - GPU_link(mat, "lamp_falloff_invcoefficients", - GPU_dynamic_uniform(&lamp->coeff_const, GPU_DYNAMIC_LAMP_COEFFCONST, lamp->ob), - GPU_dynamic_uniform(&lamp->coeff_lin, GPU_DYNAMIC_LAMP_COEFFLIN, lamp->ob), - GPU_dynamic_uniform(&lamp->coeff_quad, GPU_DYNAMIC_LAMP_COEFFQUAD, lamp->ob), *dist, &visifac); - break; - case LA_FALLOFF_CURVE: - { - float *array; - int size; - - curvemapping_initialize(lamp->curfalloff); - curvemapping_table_RGBA(lamp->curfalloff, &array, &size); - GPU_link(mat, "lamp_falloff_curve", - GPU_dynamic_uniform(&lamp->dist, GPU_DYNAMIC_LAMP_DISTANCE, lamp->ob), - GPU_texture(size, array), *dist, &visifac); - - break; - } - } - - if (lamp->mode & LA_SPHERE) - GPU_link(mat, "lamp_visibility_sphere", - GPU_dynamic_uniform(&lamp->dist, GPU_DYNAMIC_LAMP_DISTANCE, lamp->ob), - *dist, visifac, &visifac); - - if (lamp->type == LA_SPOT) { - GPUNodeLink *inpr; + const float v = radius * radius * (0.25f * 0.25f); + const float Rm = sqrtf(v * GAUSS_TRUNCATE); - if (lamp->mode & LA_SQUARE) { - mat->dynproperty |= DYN_LAMP_VEC | DYN_LAMP_IMAT; - GPU_link(mat, "lamp_visibility_spot_square", - GPU_dynamic_uniform(lamp->dynvec, GPU_DYNAMIC_LAMP_DYNVEC, lamp->ob), - GPU_dynamic_uniform((float *)lamp->dynimat, GPU_DYNAMIC_LAMP_DYNIMAT, lamp->ob), - GPU_dynamic_uniform((float *)lamp->spotvec, GPU_DYNAMIC_LAMP_SPOTSCALE, lamp->ob), *lv, &inpr); - } - else { - mat->dynproperty |= DYN_LAMP_VEC | DYN_LAMP_IMAT; - GPU_link(mat, "lamp_visibility_spot_circle", - GPU_dynamic_uniform(lamp->dynvec, GPU_DYNAMIC_LAMP_DYNVEC, lamp->ob), - GPU_dynamic_uniform((float *)lamp->dynimat, GPU_DYNAMIC_LAMP_DYNIMAT, lamp->ob), - GPU_dynamic_uniform((float *)lamp->spotvec, GPU_DYNAMIC_LAMP_SPOTSCALE, lamp->ob), *lv, &inpr); - } - - GPU_link(mat, "lamp_visibility_spot", - GPU_dynamic_uniform(&lamp->spotsi, GPU_DYNAMIC_LAMP_SPOTSIZE, lamp->ob), - GPU_dynamic_uniform(&lamp->spotbl, GPU_DYNAMIC_LAMP_SPOTBLEND, lamp->ob), - inpr, visifac, &visifac); - } - - GPU_link(mat, "lamp_visibility_clamp", visifac, &visifac); - - return visifac; + if (r >= Rm) { + return 0.0f; } + return expf(-r * r / (2.0f * v)) / (2.0f * M_PI * v); } -#if 0 -static void area_lamp_vectors(LampRen *lar) +#define BURLEY_TRUNCATE 16.0f +#define BURLEY_TRUNCATE_CDF 0.9963790093708328f // cdf(BURLEY_TRUNCATE) +static float burley_profile(float r, float d) { - float xsize = 0.5f * lar->area_size, ysize = 0.5f * lar->area_sizey; - - /* make it smaller, so area light can be multisampled */ - float multifac = 1.0f / sqrtf((float)lar->ray_totsamp); - xsize *= multifac; - ysize *= multifac; - - /* corner vectors */ - lar->area[0][0] = lar->co[0] - xsize * lar->mat[0][0] - ysize * lar->mat[1][0]; - lar->area[0][1] = lar->co[1] - xsize * lar->mat[0][1] - ysize * lar->mat[1][1]; - lar->area[0][2] = lar->co[2] - xsize * lar->mat[0][2] - ysize * lar->mat[1][2]; - - /* corner vectors */ - lar->area[1][0] = lar->co[0] - xsize * lar->mat[0][0] + ysize * lar->mat[1][0]; - lar->area[1][1] = lar->co[1] - xsize * lar->mat[0][1] + ysize * lar->mat[1][1]; - lar->area[1][2] = lar->co[2] - xsize * lar->mat[0][2] + ysize * lar->mat[1][2]; - - /* corner vectors */ - lar->area[2][0] = lar->co[0] + xsize * lar->mat[0][0] + ysize * lar->mat[1][0]; - lar->area[2][1] = lar->co[1] + xsize * lar->mat[0][1] + ysize * lar->mat[1][1]; - lar->area[2][2] = lar->co[2] + xsize * lar->mat[0][2] + ysize * lar->mat[1][2]; - - /* corner vectors */ - lar->area[3][0] = lar->co[0] + xsize * lar->mat[0][0] - ysize * lar->mat[1][0]; - lar->area[3][1] = lar->co[1] + xsize * lar->mat[0][1] - ysize * lar->mat[1][1]; - lar->area[3][2] = lar->co[2] + xsize * lar->mat[0][2] - ysize * lar->mat[1][2]; - /* only for correction button size, matrix size works on energy */ - lar->areasize = lar->dist * lar->dist / (4.0f * xsize * ysize); + float exp_r_3_d = expf(-r / (3.0f * d)); + float exp_r_d = exp_r_3_d * exp_r_3_d * exp_r_3_d; + return (exp_r_d + exp_r_3_d) / (4.0f * d); } -#endif -static void ramp_blend( - GPUMaterial *mat, GPUNodeLink *fac, GPUNodeLink *col1, GPUNodeLink *col2, int type, - GPUNodeLink **r_col) +static float cubic_profile(float r, float radius, float sharpness) { - static const char *names[] = {"mix_blend", "mix_add", "mix_mult", "mix_sub", - "mix_screen", "mix_div", "mix_diff", "mix_dark", "mix_light", - "mix_overlay", "mix_dodge", "mix_burn", "mix_hue", "mix_sat", - "mix_val", "mix_color", "mix_soft", "mix_linear"}; - - GPU_link(mat, names[type], fac, col1, col2, r_col); -} + float Rm = radius * (1.0f + sharpness); -static void BKE_colorband_eval_blend( - GPUMaterial *mat, ColorBand *coba, GPUNodeLink *fac, float rampfac, int type, - GPUNodeLink *incol, GPUNodeLink **r_col) -{ - GPUNodeLink *tmp, *alpha, *col; - float *array; - int size; - - /* do colorband */ - BKE_colorband_evaluate_table_rgba(coba, &array, &size); - GPU_link(mat, "valtorgb", fac, GPU_texture(size, array), &col, &tmp); - - /* use alpha in fac */ - GPU_link(mat, "mtex_alpha_from_col", col, &alpha); - GPU_link(mat, "math_multiply", alpha, GPU_uniform(&rampfac), &fac); - - /* blending method */ - ramp_blend(mat, fac, incol, col, type, r_col); -} - -static void ramp_diffuse_result(GPUShadeInput *shi, GPUNodeLink **diff) -{ - Material *ma = shi->mat; - GPUMaterial *mat = shi->gpumat; - - if (!(mat->scene->gm.flag & GAME_GLSL_NO_RAMPS)) { - if (ma->ramp_col) { - if (ma->rampin_col == MA_RAMP_IN_RESULT) { - GPUNodeLink *fac; - GPU_link(mat, "ramp_rgbtobw", *diff, &fac); - - /* colorband + blend */ - BKE_colorband_eval_blend(mat, ma->ramp_col, fac, ma->rampfac_col, ma->rampblend_col, *diff, diff); - } - } + if (r >= Rm) { + return 0.0f; } -} + /* custom variation with extra sharpness, to match the previous code */ + const float y = 1.0f / (1.0f + sharpness); + float Rmy, ry, ryinv; -static void add_to_diffuse( - GPUMaterial *mat, Material *ma, GPUShadeInput *shi, GPUNodeLink *is, GPUNodeLink *rgb, - GPUNodeLink **r_diff) -{ - GPUNodeLink *fac, *tmp, *addcol; - - if (!(mat->scene->gm.flag & GAME_GLSL_NO_RAMPS) && - ma->ramp_col && (ma->mode & MA_RAMP_COL)) - { - /* MA_RAMP_IN_RESULT is exceptional */ - if (ma->rampin_col == MA_RAMP_IN_RESULT) { - addcol = shi->rgb; - } - else { - /* input */ - switch (ma->rampin_col) { - case MA_RAMP_IN_ENERGY: - GPU_link(mat, "ramp_rgbtobw", rgb, &fac); - break; - case MA_RAMP_IN_SHADER: - fac = is; - break; - case MA_RAMP_IN_NOR: - GPU_link(mat, "vec_math_dot", shi->view, shi->vn, &tmp, &fac); - break; - default: - GPU_link(mat, "set_value_zero", &fac); - break; - } + Rmy = powf(Rm, y); + ry = powf(r, y); + ryinv = (r > 0.0f) ? powf(r, y - 1.0f) : 0.0f; - /* colorband + blend */ - BKE_colorband_eval_blend(mat, ma->ramp_col, fac, ma->rampfac_col, ma->rampblend_col, shi->rgb, &addcol); - } - } - else - addcol = shi->rgb; + const float Rmy5 = (Rmy * Rmy) * (Rmy * Rmy) * Rmy; + const float f = Rmy - ry; + const float num = f * (f * f) * (y * ryinv); - /* output to */ - GPU_link(mat, "shade_madd", *r_diff, rgb, addcol, r_diff); + return (10.0f * num) / (Rmy5 * M_PI); } -static void ramp_spec_result(GPUShadeInput *shi, GPUNodeLink **spec) +static float eval_profile(float r, short falloff_type, float sharpness, float param) { - Material *ma = shi->mat; - GPUMaterial *mat = shi->gpumat; + r = fabsf(r); - if (!(mat->scene->gm.flag & GAME_GLSL_NO_RAMPS) && - ma->ramp_spec && ma->rampin_spec == MA_RAMP_IN_RESULT) + if (falloff_type == SHD_SUBSURFACE_BURLEY || + falloff_type == SHD_SUBSURFACE_RANDOM_WALK) { - GPUNodeLink *fac; - GPU_link(mat, "ramp_rgbtobw", *spec, &fac); - - /* colorband + blend */ - BKE_colorband_eval_blend(mat, ma->ramp_spec, fac, ma->rampfac_spec, ma->rampblend_spec, *spec, spec); + return burley_profile(r, param) / BURLEY_TRUNCATE_CDF; } -} - -static void do_specular_ramp(GPUShadeInput *shi, GPUNodeLink *is, GPUNodeLink *t, GPUNodeLink **spec) -{ - Material *ma = shi->mat; - GPUMaterial *mat = shi->gpumat; - GPUNodeLink *fac, *tmp; - - *spec = shi->specrgb; - - /* MA_RAMP_IN_RESULT is exception */ - if (ma->ramp_spec && (ma->rampin_spec != MA_RAMP_IN_RESULT)) { - - /* input */ - switch (ma->rampin_spec) { - case MA_RAMP_IN_ENERGY: - fac = t; - break; - case MA_RAMP_IN_SHADER: - fac = is; - break; - case MA_RAMP_IN_NOR: - GPU_link(mat, "vec_math_dot", shi->view, shi->vn, &tmp, &fac); - break; - default: - GPU_link(mat, "set_value_zero", &fac); - break; - } - - /* colorband + blend */ - BKE_colorband_eval_blend(mat, ma->ramp_spec, fac, ma->rampfac_spec, ma->rampblend_spec, *spec, spec); + else if (falloff_type == SHD_SUBSURFACE_CUBIC) { + return cubic_profile(r, param, sharpness); + } + else { + return gaussian_profile(r, param); } } -static void add_user_list(ListBase *list, void *data) -{ - LinkData *link = MEM_callocN(sizeof(LinkData), "GPULinkData"); - link->data = data; - BLI_addtail(list, link); -} - -static void shade_light_textures(GPUMaterial *mat, GPULamp *lamp, GPUNodeLink **rgb) +/* Resolution for each sample of the precomputed kernel profile */ +#define INTEGRAL_RESOLUTION 32 +static float eval_integral(float x0, float x1, short falloff_type, float sharpness, float param) { - for (int i = 0; i < MAX_MTEX; ++i) { - MTex *mtex = lamp->la->mtex[i]; - - if (mtex && mtex->tex && (mtex->tex->type & TEX_IMAGE) && mtex->tex->ima) { - mat->dynproperty |= DYN_LAMP_PERSMAT; - - float one = 1.0f; - GPUNodeLink *tex_rgb; + const float range = x1 - x0; + const float step = range / INTEGRAL_RESOLUTION; + float integral = 0.0f; - GPU_link(mat, "shade_light_texture", - GPU_builtin(GPU_VIEW_POSITION), - GPU_image(mtex->tex->ima, &mtex->tex->iuser, false), - GPU_dynamic_uniform((float *)lamp->dynpersmat, GPU_DYNAMIC_LAMP_DYNPERSMAT, lamp->ob), - &tex_rgb); - texture_rgb_blend(mat, tex_rgb, *rgb, GPU_uniform(&one), GPU_uniform(&mtex->colfac), mtex->blendtype, rgb); - } + for (int i = 0; i < INTEGRAL_RESOLUTION; ++i) { + float x = x0 + range * ((float)i + 0.5f) / (float)INTEGRAL_RESOLUTION; + float y = eval_profile(x, falloff_type, sharpness, param); + integral += y * step; } + + return integral; } +#undef INTEGRAL_RESOLUTION -static void shade_one_light(GPUShadeInput *shi, GPUShadeResult *shr, GPULamp *lamp) +static void compute_sss_kernel( + GPUSssKernelData *kd, float *radii, int sample_ct, int falloff_type, float sharpness) { - Material *ma = shi->mat; - GPUMaterial *mat = shi->gpumat; - GPUNodeLink *lv, *dist, *is, *inp, *i; - GPUNodeLink *outcol, *specfac, *t, *shadfac = NULL, *lcol; - float one = 1.0f; - - if ((lamp->mode & LA_ONLYSHADOW) && !(ma->mode & MA_SHADOW)) - return; - - GPUNodeLink *vn = shi->vn; - GPUNodeLink *view = shi->view; + float rad[3]; + /* Minimum radius */ + rad[0] = MAX2(radii[0], 1e-15f); + rad[1] = MAX2(radii[1], 1e-15f); + rad[2] = MAX2(radii[2], 1e-15f); - GPUNodeLink *visifac = lamp_get_visibility(mat, lamp, &lv, &dist); + /* Christensen-Burley fitting */ + float l[3], d[3]; -#if 0 - if (ma->mode & MA_TANGENT_V) - GPU_link(mat, "shade_tangent_v", lv, GPU_attribute(CD_TANGENT, ""), &vn); -#endif - - GPU_link(mat, "shade_inp", vn, lv, &inp); + 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); + /* XXX 0.6f Out of nowhere to match cycles! Empirical! Can be tweak better. */ + mul_v3_v3fl(d, l, 0.6f / s); + mul_v3_v3fl(rad, d, BURLEY_TRUNCATE); + kd->max_radius = MAX3(rad[0], rad[1], rad[2]); - if (lamp->mode & LA_NO_DIFF) { - GPU_link(mat, "shade_is_no_diffuse", &is); + copy_v3_v3(kd->param, d); } - else if (lamp->type == LA_HEMI) { - GPU_link(mat, "shade_is_hemi", inp, &is); + else if (falloff_type == SHD_SUBSURFACE_CUBIC) { + copy_v3_v3(kd->param, rad); + mul_v3_fl(rad, 1.0f + sharpness); + kd->max_radius = MAX3(rad[0], rad[1], rad[2]); } else { - if (lamp->type == LA_AREA) { - float area[4][4] = {{0.0f}}, areasize = 0.0f; - - mat->dynproperty |= DYN_LAMP_VEC | DYN_LAMP_CO; - GPU_link(mat, "shade_inp_area", - GPU_builtin(GPU_VIEW_POSITION), - GPU_dynamic_uniform(lamp->dynco, GPU_DYNAMIC_LAMP_DYNCO, lamp->ob), - GPU_dynamic_uniform(lamp->dynvec, GPU_DYNAMIC_LAMP_DYNVEC, lamp->ob), vn, - GPU_uniform((float *)area), - GPU_uniform(&areasize), - GPU_uniform(&lamp->k), &inp); - } + kd->max_radius = MAX3(rad[0], rad[1], rad[2]); - is = inp; /* Lambert */ - - if (!(mat->scene->gm.flag & GAME_GLSL_NO_SHADERS)) { - if (ma->diff_shader == MA_DIFF_ORENNAYAR) - GPU_link(mat, "shade_diffuse_oren_nayer", inp, vn, lv, view, - GPU_uniform(&ma->roughness), &is); - else if (ma->diff_shader == MA_DIFF_TOON) - GPU_link(mat, "shade_diffuse_toon", vn, lv, view, - GPU_uniform(&ma->param[0]), GPU_uniform(&ma->param[1]), &is); - else if (ma->diff_shader == MA_DIFF_MINNAERT) - GPU_link(mat, "shade_diffuse_minnaert", inp, vn, view, - GPU_uniform(&ma->darkness), &is); - else if (ma->diff_shader == MA_DIFF_FRESNEL) - GPU_link(mat, "shade_diffuse_fresnel", vn, lv, view, - GPU_uniform(&ma->param[0]), GPU_uniform(&ma->param[1]), &is); - } + copy_v3_v3(kd->param, rad); } - if (!(mat->scene->gm.flag & GAME_GLSL_NO_SHADERS)) - if (ma->shade_flag & MA_CUBIC) - GPU_link(mat, "shade_cubic", is, &is); - - i = is; - GPU_link(mat, "shade_visifac", i, visifac, shi->refl, &i); - - GPU_link(mat, "set_rgb", GPU_dynamic_uniform(lamp->dyncol, GPU_DYNAMIC_LAMP_DYNCOL, lamp->ob), &lcol); - shade_light_textures(mat, lamp, &lcol); - GPU_link(mat, "shade_mul_value_v3", - GPU_dynamic_uniform(&lamp->dynenergy, GPU_DYNAMIC_LAMP_DYNENERGY, lamp->ob), lcol, &lcol); - -#if 0 - if (ma->mode & MA_TANGENT_VN) - GPU_link(mat, "shade_tangent_v_spec", GPU_attribute(CD_TANGENT, ""), &vn); -#endif + /* Compute samples locations on the 1d kernel [-1..1] */ + sss_calculate_offsets(kd, sample_ct, SSS_EXPONENT); - /* this replaces if (i > 0.0) conditional until that is supported */ - /* done in shade_visifac now, GPU_link(mat, "mtex_value_clamp_positive", i, &i); */ - - if ((ma->mode & MA_SHADOW) && GPU_lamp_has_shadow_buffer(lamp)) { - if (!(mat->scene->gm.flag & GAME_GLSL_NO_SHADOWS)) { - mat->dynproperty |= DYN_LAMP_PERSMAT; - - if (lamp->la->shadowmap_type == LA_SHADMAP_VARIANCE) { - GPU_link(mat, "test_shadowbuf_vsm", - GPU_builtin(GPU_VIEW_POSITION), - GPU_dynamic_texture(lamp->tex, GPU_DYNAMIC_SAMPLER_2DSHADOW, lamp->ob), - GPU_dynamic_uniform((float *)lamp->dynpersmat, GPU_DYNAMIC_LAMP_DYNPERSMAT, lamp->ob), - GPU_uniform(&lamp->bias), GPU_uniform(&lamp->la->bleedbias), inp, &shadfac); - } - else { - GPU_link(mat, "test_shadowbuf", - GPU_builtin(GPU_VIEW_POSITION), - GPU_dynamic_texture(lamp->tex, GPU_DYNAMIC_SAMPLER_2DSHADOW, lamp->ob), - GPU_dynamic_uniform((float *)lamp->dynpersmat, GPU_DYNAMIC_LAMP_DYNPERSMAT, lamp->ob), - GPU_uniform(&lamp->bias), inp, &shadfac); - } - - if (lamp->mode & LA_ONLYSHADOW) { - GPUNodeLink *shadrgb; - GPU_link(mat, "shade_only_shadow", i, shadfac, - GPU_dynamic_uniform(&lamp->dynenergy, GPU_DYNAMIC_LAMP_DYNENERGY, lamp->ob), - GPU_uniform(lamp->shadow_color), &shadrgb); - - if (!(lamp->mode & LA_NO_DIFF)) { - GPU_link(mat, "shade_only_shadow_diffuse", shadrgb, shi->rgb, - shr->diff, &shr->diff); - } - - if (!(lamp->mode & LA_NO_SPEC)) { - GPU_link(mat, "shade_only_shadow_specular", shadrgb, shi->specrgb, - shr->spec, &shr->spec); - } - - add_user_list(&mat->lamps, lamp); - add_user_list(&lamp->materials, shi->gpumat->ma); - return; - } - } - } - else if ((mat->scene->gm.flag & GAME_GLSL_NO_SHADOWS) && (lamp->mode & LA_ONLYSHADOW)) { - add_user_list(&mat->lamps, lamp); - add_user_list(&lamp->materials, shi->gpumat->ma); - return; - } - else - GPU_link(mat, "set_value", GPU_uniform(&one), &shadfac); - - if (GPU_link_changed(shi->refl) || ma->ref != 0.0f) { - if (!(lamp->mode & LA_NO_DIFF)) { - GPUNodeLink *rgb; - GPU_link(mat, "shade_mul_value", i, lcol, &rgb); - GPU_link(mat, "mtex_value_invert", shadfac, &shadfac); - GPU_link(mat, "mix_mult", shadfac, rgb, GPU_uniform(lamp->shadow_color), &rgb); - GPU_link(mat, "mtex_value_invert", shadfac, &shadfac); - add_to_diffuse(mat, ma, shi, is, rgb, &shr->diff); - } - } + /* Weights sum for normalization */ + float sum[3] = {0.0f, 0.0f, 0.0f}; - if (mat->scene->gm.flag & GAME_GLSL_NO_SHADERS) { - /* pass */ - } - else if (!(lamp->mode & LA_NO_SPEC) && !(lamp->mode & LA_ONLYSHADOW) && - (GPU_link_changed(shi->spec) || ma->spec != 0.0f)) - { - if (lamp->type == LA_HEMI) { - GPU_link(mat, "shade_hemi_spec", vn, lv, view, GPU_uniform(&ma->spec), shi->har, visifac, &t); - GPU_link(mat, "shade_add_spec", t, lcol, shi->specrgb, &outcol); - GPU_link(mat, "shade_add_clamped", shr->spec, outcol, &shr->spec); + /* Compute integral of each sample footprint */ + for (int i = 0; i < sample_ct; i++) { + float x0, x1; + + if (i == 0) { + x0 = kd->kernel[0][3] - fabsf(kd->kernel[0][3] - kd->kernel[1][3]) / 2.0f; } else { - if (ma->spec_shader == MA_SPEC_PHONG) { - GPU_link(mat, "shade_phong_spec", vn, lv, view, shi->har, &specfac); - } - else if (ma->spec_shader == MA_SPEC_COOKTORR) { - GPU_link(mat, "shade_cooktorr_spec", vn, lv, view, shi->har, &specfac); - } - else if (ma->spec_shader == MA_SPEC_BLINN) { - GPU_link(mat, "shade_blinn_spec", vn, lv, view, - GPU_uniform(&ma->refrac), shi->har, &specfac); - } - else if (ma->spec_shader == MA_SPEC_WARDISO) { - GPU_link(mat, "shade_wardiso_spec", vn, lv, view, - GPU_uniform(&ma->rms), &specfac); - } - else { - GPU_link(mat, "shade_toon_spec", vn, lv, view, - GPU_uniform(&ma->param[2]), GPU_uniform(&ma->param[3]), &specfac); - } - - if (lamp->type == LA_AREA) - GPU_link(mat, "shade_spec_area_inp", specfac, inp, &specfac); - - GPU_link(mat, "shade_spec_t", shadfac, shi->spec, visifac, specfac, &t); - - if (ma->mode & MA_RAMP_SPEC) { - GPUNodeLink *spec; - do_specular_ramp(shi, specfac, t, &spec); - GPU_link(mat, "shade_add_spec", t, lcol, spec, &outcol); - GPU_link(mat, "shade_add_clamped", shr->spec, outcol, &shr->spec); - } - else { - GPU_link(mat, "shade_add_spec", t, lcol, shi->specrgb, &outcol); - GPU_link(mat, "shade_add_clamped", shr->spec, outcol, &shr->spec); - } + x0 = (kd->kernel[i - 1][3] + kd->kernel[i][3]) / 2.0f; } - } - add_user_list(&mat->lamps, lamp); - add_user_list(&lamp->materials, shi->gpumat->ma); -} - -static void material_lights(GPUShadeInput *shi, GPUShadeResult *shr) -{ - Base *base; - Scene *sce_iter; - - for (SETLOOPER(shi->gpumat->scene, sce_iter, base)) { - Object *ob = base->object; - - if (ob->type == OB_LAMP) { - GPULamp *lamp = GPU_lamp_from_blender(shi->gpumat->scene, ob, NULL); - if (lamp) - shade_one_light(shi, shr, lamp); + if (i == sample_ct - 1) { + x1 = kd->kernel[sample_ct - 1][3] + fabsf(kd->kernel[sample_ct - 2][3] - kd->kernel[sample_ct - 1][3]) / 2.0f; + } + else { + x1 = (kd->kernel[i][3] + kd->kernel[i + 1][3]) / 2.0f; } - if (ob->transflag & OB_DUPLI) { - ListBase *lb = object_duplilist(G.main->eval_ctx, shi->gpumat->scene, ob); - - for (DupliObject *dob = lb->first; dob; dob = dob->next) { - Object *ob_iter = dob->ob; + x0 *= kd->max_radius; + x1 *= kd->max_radius; - if (ob_iter->type == OB_LAMP) { - float omat[4][4]; - copy_m4_m4(omat, ob_iter->obmat); - copy_m4_m4(ob_iter->obmat, dob->mat); + kd->kernel[i][0] = eval_integral(x0, x1, falloff_type, sharpness, kd->param[0]); + kd->kernel[i][1] = eval_integral(x0, x1, falloff_type, sharpness, kd->param[1]); + kd->kernel[i][2] = eval_integral(x0, x1, falloff_type, sharpness, kd->param[2]); - GPULamp *lamp = GPU_lamp_from_blender(shi->gpumat->scene, ob_iter, ob); - if (lamp) - shade_one_light(shi, shr, lamp); + sum[0] += kd->kernel[i][0]; + sum[1] += kd->kernel[i][1]; + sum[2] += kd->kernel[i][2]; + } - copy_m4_m4(ob_iter->obmat, omat); - } + for (int i = 0; i < 3; ++i) { + if (sum[i] > 0.0f) { + /* Normalize */ + for (int j = 0; j < sample_ct; j++) { + kd->kernel[j][i] /= sum[i]; } - - free_object_duplilist(lb); + } + else { + /* Avoid 0 kernel sum. */ + kd->kernel[sample_ct / 2][i] = 1.0f; } } - /* prevent only shadow lamps from producing negative colors.*/ - GPU_link(shi->gpumat, "shade_clamp_positive", shr->spec, &shr->spec); - GPU_link(shi->gpumat, "shade_clamp_positive", shr->diff, &shr->diff); -} - -static void texture_rgb_blend( - GPUMaterial *mat, GPUNodeLink *tex, GPUNodeLink *out, GPUNodeLink *fact, GPUNodeLink *facg, - int blendtype, GPUNodeLink **in) -{ - switch (blendtype) { - case MTEX_BLEND: - GPU_link(mat, "mtex_rgb_blend", out, tex, fact, facg, in); - break; - case MTEX_MUL: - GPU_link(mat, "mtex_rgb_mul", out, tex, fact, facg, in); - break; - case MTEX_SCREEN: - GPU_link(mat, "mtex_rgb_screen", out, tex, fact, facg, in); - break; - case MTEX_OVERLAY: - GPU_link(mat, "mtex_rgb_overlay", out, tex, fact, facg, in); - break; - case MTEX_SUB: - GPU_link(mat, "mtex_rgb_sub", out, tex, fact, facg, in); - break; - case MTEX_ADD: - GPU_link(mat, "mtex_rgb_add", out, tex, fact, facg, in); - break; - case MTEX_DIV: - GPU_link(mat, "mtex_rgb_div", out, tex, fact, facg, in); - break; - case MTEX_DIFF: - GPU_link(mat, "mtex_rgb_diff", out, tex, fact, facg, in); - break; - case MTEX_DARK: - GPU_link(mat, "mtex_rgb_dark", out, tex, fact, facg, in); - break; - case MTEX_LIGHT: - GPU_link(mat, "mtex_rgb_light", out, tex, fact, facg, in); - break; - case MTEX_BLEND_HUE: - GPU_link(mat, "mtex_rgb_hue", out, tex, fact, facg, in); - break; - case MTEX_BLEND_SAT: - GPU_link(mat, "mtex_rgb_sat", out, tex, fact, facg, in); - break; - case MTEX_BLEND_VAL: - GPU_link(mat, "mtex_rgb_val", out, tex, fact, facg, in); - break; - case MTEX_BLEND_COLOR: - GPU_link(mat, "mtex_rgb_color", out, tex, fact, facg, in); - break; - case MTEX_SOFT_LIGHT: - GPU_link(mat, "mtex_rgb_soft", out, tex, fact, facg, in); - break; - case MTEX_LIN_LIGHT: - GPU_link(mat, "mtex_rgb_linear", out, tex, fact, facg, in); - break; - default: - GPU_link(mat, "set_rgb_zero", &in); - break; + /* Put center sample at the start of the array (to sample first) */ + float tmpv[4]; + copy_v4_v4(tmpv, kd->kernel[sample_ct / 2]); + for (int i = sample_ct / 2; i > 0; i--) { + copy_v4_v4(kd->kernel[i], kd->kernel[i - 1]); } -} + copy_v4_v4(kd->kernel[0], tmpv); -static void texture_value_blend( - GPUMaterial *mat, GPUNodeLink *tex, GPUNodeLink *out, GPUNodeLink *fact, GPUNodeLink *facg, - int blendtype, GPUNodeLink **in) -{ - switch (blendtype) { - case MTEX_BLEND: - GPU_link(mat, "mtex_value_blend", out, tex, fact, facg, in); - break; - case MTEX_MUL: - GPU_link(mat, "mtex_value_mul", out, tex, fact, facg, in); - break; - case MTEX_SCREEN: - GPU_link(mat, "mtex_value_screen", out, tex, fact, facg, in); - break; - case MTEX_SUB: - GPU_link(mat, "mtex_value_sub", out, tex, fact, facg, in); - break; - case MTEX_ADD: - GPU_link(mat, "mtex_value_add", out, tex, fact, facg, in); - break; - case MTEX_DIV: - GPU_link(mat, "mtex_value_div", out, tex, fact, facg, in); - break; - case MTEX_DIFF: - GPU_link(mat, "mtex_value_diff", out, tex, fact, facg, in); - break; - case MTEX_DARK: - GPU_link(mat, "mtex_value_dark", out, tex, fact, facg, in); - break; - case MTEX_LIGHT: - GPU_link(mat, "mtex_value_light", out, tex, fact, facg, in); - break; - default: - GPU_link(mat, "set_value_zero", &in); - break; - } + kd->samples = sample_ct; } -static void do_material_tex(GPUShadeInput *shi) +#define INTEGRAL_RESOLUTION 512 +static void compute_sss_translucence_kernel( + const GPUSssKernelData *kd, int resolution, short falloff_type, float sharpness, float **output) { - Material *ma = shi->mat; - GPUMaterial *mat = shi->gpumat; - MTex *mtex; - Tex *tex; - GPUNodeLink *texco, *tin, *trgb, *tnor, *tcol, *stencil, *tnorfac; - GPUNodeLink *texco_norm, *texco_orco, *texco_object; - GPUNodeLink *texco_global, *texco_uv = NULL; - GPUNodeLink *newnor, *orn; - float one = 1.0f; - int rgbnor, talpha; - bool init_done = false; - int iBumpSpacePrev = 0; /* Not necessary, quieting gcc warning. */ - GPUNodeLink *vNorg, *vNacc, *fPrevMagnitude; - int iFirstTimeNMap = 1; - bool found_deriv_map = false; - - GPU_link(mat, "set_value", GPU_uniform(&one), &stencil); - - GPU_link(mat, "texco_norm", GPU_builtin(GPU_VIEW_NORMAL), &texco_norm); - GPU_link(mat, "texco_orco", GPU_attribute(CD_ORCO, ""), &texco_orco); - GPU_link(mat, "texco_object", GPU_builtin(GPU_INVERSE_VIEW_MATRIX), - GPU_builtin(GPU_INVERSE_OBJECT_MATRIX), - GPU_builtin(GPU_VIEW_POSITION), &texco_object); -#if 0 - GPU_link(mat, "texco_tangent", GPU_attribute(CD_TANGENT, ""), &texco_tangent); -#endif - GPU_link(mat, "texco_global", GPU_builtin(GPU_INVERSE_VIEW_MATRIX), - GPU_builtin(GPU_VIEW_POSITION), &texco_global); - - orn = texco_norm; - - /* go over texture slots */ - for (int tex_nr = 0; tex_nr < MAX_MTEX; tex_nr++) { - /* separate tex switching */ - if (ma->septex & (1 << tex_nr)) continue; - - if (ma->mtex[tex_nr]) { - mtex = ma->mtex[tex_nr]; - - tex = mtex->tex; - if (tex == NULL) continue; - - /* which coords */ - if (mtex->texco == TEXCO_ORCO) - texco = texco_orco; - else if (mtex->texco == TEXCO_OBJECT) - texco = texco_object; - else if (mtex->texco == TEXCO_NORM) - texco = orn; - else if (mtex->texco == TEXCO_TANGENT) - texco = texco_object; - else if (mtex->texco == TEXCO_GLOB) - texco = texco_global; - else if (mtex->texco == TEXCO_REFL) { - GPU_link(mat, "texco_refl", shi->vn, shi->view, &shi->ref); - texco = shi->ref; - } - else if (mtex->texco == TEXCO_UV) { - if (1) { //!(texco_uv && strcmp(mtex->uvname, lastuvname) == 0)) { - GPU_link(mat, "texco_uv", GPU_attribute(CD_MTFACE, mtex->uvname), &texco_uv); - /*lastuvname = mtex->uvname;*/ /*UNUSED*/ - } - texco = texco_uv; - } - else - continue; - - /* in case of uv, this would just undo a multiplication in texco_uv */ - if (mtex->texco != TEXCO_UV) - GPU_link(mat, "mtex_2d_mapping", texco, &texco); - - if (mtex->size[0] != 1.0f || mtex->size[1] != 1.0f || mtex->size[2] != 1.0f) - GPU_link(mat, "mtex_mapping_size", texco, GPU_uniform(mtex->size), &texco); - - float ofs[3] = { - mtex->ofs[0] + 0.5f - 0.5f * mtex->size[0], - mtex->ofs[1] + 0.5f - 0.5f * mtex->size[1], - 0.0f - }; - - if (ofs[0] != 0.0f || ofs[1] != 0.0f || ofs[2] != 0.0f) - GPU_link(mat, "mtex_mapping_ofs", texco, GPU_uniform(ofs), &texco); - - talpha = 0; - - if (tex && tex->ima && - ((tex->type == TEX_IMAGE) || - ((tex->type == TEX_ENVMAP) && (mtex->texco == TEXCO_REFL)))) - { - if (tex->type == TEX_IMAGE) { - GPU_link(mat, "mtex_image", texco, GPU_image(tex->ima, &tex->iuser, false), &tin, &trgb); - } - else { - GPU_link(mat, "mtex_cube_map_refl", - GPU_cube_map(tex->ima, &tex->iuser, false), shi->view, shi->vn, - GPU_builtin(GPU_INVERSE_VIEW_MATRIX), - GPU_builtin(GPU_VIEW_MATRIX), &tin, &trgb); - } - rgbnor = TEX_RGB; - - talpha = ((tex->imaflag & TEX_USEALPHA) && tex->ima && (tex->ima->flag & IMA_IGNORE_ALPHA) == 0); - } - else { - continue; - } + float (*texels)[4]; + texels = MEM_callocN(sizeof(float) * 4 * resolution, "compute_sss_translucence_kernel"); + *output = (float *)texels; - /* texture output */ - if ((rgbnor & TEX_RGB) && (mtex->texflag & MTEX_RGBTOINT)) { - GPU_link(mat, "mtex_rgbtoint", trgb, &tin); - rgbnor -= TEX_RGB; - } + /* Last texel should be black, hence the - 1. */ + for (int i = 0; i < resolution - 1; ++i) { + /* Distance from surface. */ + float d = kd->max_radius * ((float)i + 0.00001f) / ((float)resolution); - if (mtex->texflag & MTEX_NEGATIVE) { - if (rgbnor & TEX_RGB) - GPU_link(mat, "mtex_rgb_invert", trgb, &trgb); - else - GPU_link(mat, "mtex_value_invert", tin, &tin); - } + /* For each distance d we compute the radiance incomming from an hypothetic parallel plane. */ + /* Compute radius of the footprint on the hypothetic plane */ + float r_fp = sqrtf(kd->max_radius * kd->max_radius - d * d); + float r_step = r_fp / INTEGRAL_RESOLUTION; + float area_accum = 0.0f; + for (float r = 0.0f; r < r_fp; r += r_step) { + /* Compute distance to the "shading" point through the medium. */ + /* r_step * 0.5f to put sample between the area borders */ + float dist = hypotf(r + r_step * 0.5f, d); - if (mtex->texflag & MTEX_STENCIL) { - if (rgbnor & TEX_RGB) - GPU_link(mat, "mtex_rgb_stencil", stencil, trgb, &stencil, &trgb); - else - GPU_link(mat, "mtex_value_stencil", stencil, tin, &stencil, &tin); - } + float profile[3]; + profile[0] = eval_profile(dist, falloff_type, sharpness, kd->param[0]); + profile[1] = eval_profile(dist, falloff_type, sharpness, kd->param[1]); + profile[2] = eval_profile(dist, falloff_type, sharpness, kd->param[2]); - /* mapping */ - if (mtex->mapto & (MAP_COL | MAP_COLSPEC | MAP_COLMIR)) { - /* stencil maps on the texture control slider, not texture intensity value */ - if ((rgbnor & TEX_RGB) == 0) { - GPU_link(mat, "set_rgb", GPU_uniform(&mtex->r), &tcol); - } - else { - GPU_link(mat, "set_rgba", trgb, &tcol); - - if (mtex->mapto & MAP_ALPHA) - GPU_link(mat, "set_value", stencil, &tin); - else if (talpha) - GPU_link(mat, "mtex_alpha_from_col", trgb, &tin); - else - GPU_link(mat, "set_value_one", &tin); - } - - if ((tex->type == TEX_IMAGE) || - ((tex->type == TEX_ENVMAP) && (mtex->texco == TEXCO_REFL))) - { - if (GPU_material_do_color_management(mat)) { - GPU_link(mat, "srgb_to_linearrgb", tcol, &tcol); - } - } - - if (mtex->mapto & MAP_COL) { - GPUNodeLink *colfac; - - if (mtex->colfac == 1.0f) colfac = stencil; - else GPU_link(mat, "math_multiply", GPU_uniform(&mtex->colfac), stencil, &colfac); - - texture_rgb_blend(mat, tcol, shi->rgb, tin, colfac, mtex->blendtype, &shi->rgb); - } - - if (!(mat->scene->gm.flag & GAME_GLSL_NO_EXTRA_TEX) && (mtex->mapto & MAP_COLSPEC)) { - GPUNodeLink *colspecfac; - - if (mtex->colspecfac == 1.0f) colspecfac = stencil; - else GPU_link(mat, "math_multiply", GPU_uniform(&mtex->colspecfac), stencil, &colspecfac); - - texture_rgb_blend(mat, tcol, shi->specrgb, tin, colspecfac, mtex->blendtype, &shi->specrgb); - } - - if (mtex->mapto & MAP_COLMIR) { - GPUNodeLink *colmirfac; - - if (mtex->mirrfac == 1.0f) colmirfac = stencil; - else GPU_link(mat, "math_multiply", GPU_uniform(&mtex->mirrfac), stencil, &colmirfac); - - /* exception for envmap only */ - if (tex->type == TEX_ENVMAP && mtex->blendtype == MTEX_BLEND) { - GPU_link(mat, "mtex_mirror", tcol, shi->refcol, tin, colmirfac, &shi->refcol); - } - else - texture_rgb_blend(mat, tcol, shi->mir, tin, colmirfac, mtex->blendtype, &shi->mir); - } - } - - if (!(mat->scene->gm.flag & GAME_GLSL_NO_EXTRA_TEX) && (mtex->mapto & MAP_NORM)) { - if (tex->type == TEX_IMAGE) { - found_deriv_map = tex->imaflag & TEX_DERIVATIVEMAP; - - if (tex->imaflag & TEX_NORMALMAP) { - /* normalmap image */ - GPU_link(mat, "mtex_normal", texco, GPU_image(tex->ima, &tex->iuser, true), &tnor); - - if (mtex->norfac < 0.0f) - GPU_link(mat, "mtex_negate_texnormal", tnor, &tnor); - - if (mtex->normapspace == MTEX_NSPACE_TANGENT) { - if (iFirstTimeNMap != 0) { - // use unnormalized normal (this is how we bake it - closer to gamedev) - GPUNodeLink *vNegNorm; - GPU_link(mat, "vec_math_negate", - GPU_builtin(GPU_VIEW_NORMAL), &vNegNorm); - GPU_link(mat, "mtex_nspace_tangent", - GPU_attribute(CD_TANGENT, ""), vNegNorm, tnor, &newnor); - iFirstTimeNMap = 0; - } - else { /* otherwise use accumulated perturbations */ - GPU_link(mat, "mtex_nspace_tangent", - GPU_attribute(CD_TANGENT, ""), shi->vn, tnor, &newnor); - } - } - else if (mtex->normapspace == MTEX_NSPACE_OBJECT) { - /* transform normal by object then view matrix */ - GPU_link(mat, "mtex_nspace_object", tnor, &newnor); - } - else if (mtex->normapspace == MTEX_NSPACE_WORLD) { - /* transform normal by view matrix */ - GPU_link(mat, "mtex_nspace_world", GPU_builtin(GPU_VIEW_MATRIX), tnor, &newnor); - } - else { - /* no transform, normal in camera space */ - newnor = tnor; - } - - float norfac = min_ff(fabsf(mtex->norfac), 1.0f); - - if (norfac == 1.0f && !GPU_link_changed(stencil)) { - shi->vn = newnor; - } - else { - tnorfac = GPU_uniform(&norfac); - - if (GPU_link_changed(stencil)) - GPU_link(mat, "math_multiply", tnorfac, stencil, &tnorfac); - - GPU_link(mat, "mtex_blend_normal", tnorfac, shi->vn, newnor, &shi->vn); - } - - } - else if (found_deriv_map || - (mtex->texflag & (MTEX_3TAP_BUMP | MTEX_5TAP_BUMP | MTEX_BICUBIC_BUMP))) - { - /* ntap bumpmap image */ - int iBumpSpace; - float ima_x, ima_y; - - float imag_tspace_dimension_x = 1024.0f; /* only used for texture space variant */ - float aspect = 1.0f; - - GPUNodeLink *vR1, *vR2; - GPUNodeLink *dBs, *dBt, *fDet; - - float hScale = 0.1f; /* compatibility adjustment factor for all bumpspace types */ - if (mtex->texflag & MTEX_BUMP_TEXTURESPACE) - hScale = 13.0f; /* factor for scaling texspace bumps */ - else if (found_deriv_map) - hScale = 1.0f; - - /* resolve texture resolution */ - if ((mtex->texflag & MTEX_BUMP_TEXTURESPACE) || found_deriv_map) { - ImBuf *ibuf = BKE_image_acquire_ibuf(tex->ima, &tex->iuser, NULL); - ima_x = 512.0f; ima_y = 512.0f; /* prevent calling textureSize, glsl 1.3 only */ - if (ibuf) { - ima_x = ibuf->x; - ima_y = ibuf->y; - aspect = (float)ima_y / ima_x; - } - BKE_image_release_ibuf(tex->ima, ibuf, NULL); - } - - /* The negate on norfac is done because the - * normal in the renderer points inward which corresponds - * to inverting the bump map. Should this ever change - * this negate must be removed. */ - float norfac = -hScale * mtex->norfac; - if (found_deriv_map) { - float fVirtDim = sqrtf(fabsf(ima_x * mtex->size[0] * ima_y * mtex->size[1])); - norfac /= MAX2(fVirtDim, FLT_EPSILON); - } - - tnorfac = GPU_uniform(&norfac); - - if (found_deriv_map) - GPU_link(mat, "math_multiply", tnorfac, GPU_builtin(GPU_AUTO_BUMPSCALE), &tnorfac); - - if (GPU_link_changed(stencil)) - GPU_link(mat, "math_multiply", tnorfac, stencil, &tnorfac); - - if (!init_done) { - /* copy shi->vn to vNorg and vNacc, set magnitude to 1 */ - GPU_link(mat, "mtex_bump_normals_init", shi->vn, &vNorg, &vNacc, &fPrevMagnitude); - iBumpSpacePrev = 0; - init_done = true; - } - - // find current bump space - if (mtex->texflag & MTEX_BUMP_OBJECTSPACE) - iBumpSpace = 1; - else if (mtex->texflag & MTEX_BUMP_TEXTURESPACE) - iBumpSpace = 2; - else - iBumpSpace = 4; /* ViewSpace */ - - /* re-initialize if bump space changed */ - if (iBumpSpacePrev != iBumpSpace) { - GPUNodeLink *surf_pos = GPU_builtin(GPU_VIEW_POSITION); - - if (mtex->texflag & MTEX_BUMP_OBJECTSPACE) - GPU_link(mat, "mtex_bump_init_objspace", - surf_pos, vNorg, - GPU_builtin(GPU_VIEW_MATRIX), - GPU_builtin(GPU_INVERSE_VIEW_MATRIX), - GPU_builtin(GPU_OBJECT_MATRIX), - GPU_builtin(GPU_INVERSE_OBJECT_MATRIX), - fPrevMagnitude, vNacc, - &fPrevMagnitude, &vNacc, - &vR1, &vR2, &fDet); - - else if (mtex->texflag & MTEX_BUMP_TEXTURESPACE) - GPU_link(mat, "mtex_bump_init_texturespace", - surf_pos, vNorg, - fPrevMagnitude, vNacc, - &fPrevMagnitude, &vNacc, - &vR1, &vR2, &fDet); - - else - GPU_link(mat, "mtex_bump_init_viewspace", - surf_pos, vNorg, - fPrevMagnitude, vNacc, - &fPrevMagnitude, &vNacc, - &vR1, &vR2, &fDet); - - iBumpSpacePrev = iBumpSpace; - } - - - if (found_deriv_map) { - GPU_link(mat, "mtex_bump_deriv", - texco, GPU_image(tex->ima, &tex->iuser, true), - GPU_uniform(&ima_x), GPU_uniform(&ima_y), tnorfac, - &dBs, &dBt); - } - else if (mtex->texflag & MTEX_3TAP_BUMP) - GPU_link(mat, "mtex_bump_tap3", - texco, GPU_image(tex->ima, &tex->iuser, true), tnorfac, - &dBs, &dBt); - else if (mtex->texflag & MTEX_5TAP_BUMP) - GPU_link(mat, "mtex_bump_tap5", - texco, GPU_image(tex->ima, &tex->iuser, true), tnorfac, - &dBs, &dBt); - else if (mtex->texflag & MTEX_BICUBIC_BUMP) { - if (GPU_bicubic_bump_support()) { - GPU_link(mat, "mtex_bump_bicubic", - texco, GPU_image(tex->ima, &tex->iuser, true), tnorfac, - &dBs, &dBt); - } - else { - GPU_link(mat, "mtex_bump_tap5", - texco, GPU_image(tex->ima, &tex->iuser, true), tnorfac, - &dBs, &dBt); - } - } - - - if (mtex->texflag & MTEX_BUMP_TEXTURESPACE) { - float imag_tspace_dimension_y = aspect * imag_tspace_dimension_x; - GPU_link(mat, "mtex_bump_apply_texspace", - fDet, dBs, dBt, vR1, vR2, - GPU_image(tex->ima, &tex->iuser, true), texco, - GPU_uniform(&imag_tspace_dimension_x), - GPU_uniform(&imag_tspace_dimension_y), vNacc, - &vNacc, &shi->vn); - } - else - GPU_link(mat, "mtex_bump_apply", - fDet, dBs, dBt, vR1, vR2, vNacc, - &vNacc, &shi->vn); - - } - } - - GPU_link(mat, "vec_math_negate", shi->vn, &orn); - } + /* Since the profile and configuration are radially symetrical we + * can just evaluate it once and weight it accordingly */ + float r_next = r + r_step; + float disk_area = (M_PI * r_next * r_next) - (M_PI * r * r); - if ((mtex->mapto & MAP_VARS)) { - if (rgbnor & TEX_RGB) { - if (talpha) - GPU_link(mat, "mtex_alpha_from_col", trgb, &tin); - else - GPU_link(mat, "mtex_rgbtoint", trgb, &tin); - } - - if (!(mat->scene->gm.flag & GAME_GLSL_NO_EXTRA_TEX) && mtex->mapto & MAP_REF) { - GPUNodeLink *difffac; - - if (mtex->difffac == 1.0f) difffac = stencil; - else GPU_link(mat, "math_multiply", GPU_uniform(&mtex->difffac), stencil, &difffac); - - texture_value_blend( - mat, GPU_uniform(&mtex->def_var), shi->refl, tin, difffac, - mtex->blendtype, &shi->refl); - GPU_link(mat, "mtex_value_clamp_positive", shi->refl, &shi->refl); - } - if (!(mat->scene->gm.flag & GAME_GLSL_NO_EXTRA_TEX) && mtex->mapto & MAP_SPEC) { - GPUNodeLink *specfac; - - if (mtex->specfac == 1.0f) specfac = stencil; - else GPU_link(mat, "math_multiply", GPU_uniform(&mtex->specfac), stencil, &specfac); - - texture_value_blend( - mat, GPU_uniform(&mtex->def_var), shi->spec, tin, specfac, - mtex->blendtype, &shi->spec); - GPU_link(mat, "mtex_value_clamp_positive", shi->spec, &shi->spec); - } - if (!(mat->scene->gm.flag & GAME_GLSL_NO_EXTRA_TEX) && mtex->mapto & MAP_EMIT) { - GPUNodeLink *emitfac; - - if (mtex->emitfac == 1.0f) emitfac = stencil; - else GPU_link(mat, "math_multiply", GPU_uniform(&mtex->emitfac), stencil, &emitfac); - - texture_value_blend( - mat, GPU_uniform(&mtex->def_var), shi->emit, tin, emitfac, - mtex->blendtype, &shi->emit); - GPU_link(mat, "mtex_value_clamp_positive", shi->emit, &shi->emit); - } - if (!(mat->scene->gm.flag & GAME_GLSL_NO_EXTRA_TEX) && mtex->mapto & MAP_HAR) { - GPUNodeLink *hardfac; - - if (mtex->hardfac == 1.0f) hardfac = stencil; - else GPU_link(mat, "math_multiply", GPU_uniform(&mtex->hardfac), stencil, &hardfac); - - GPU_link(mat, "mtex_har_divide", shi->har, &shi->har); - texture_value_blend( - mat, GPU_uniform(&mtex->def_var), shi->har, tin, hardfac, - mtex->blendtype, &shi->har); - GPU_link(mat, "mtex_har_multiply_clamp", shi->har, &shi->har); - } - if (mtex->mapto & MAP_ALPHA) { - GPUNodeLink *alphafac; - - if (mtex->alphafac == 1.0f) alphafac = stencil; - else GPU_link(mat, "math_multiply", GPU_uniform(&mtex->alphafac), stencil, &alphafac); - - texture_value_blend( - mat, GPU_uniform(&mtex->def_var), shi->alpha, tin, alphafac, - mtex->blendtype, &shi->alpha); - GPU_link(mat, "mtex_value_clamp", shi->alpha, &shi->alpha); - } - if (!(mat->scene->gm.flag & GAME_GLSL_NO_EXTRA_TEX) && mtex->mapto & MAP_AMB) { - GPUNodeLink *ambfac; - - if (mtex->ambfac == 1.0f) ambfac = stencil; - else GPU_link(mat, "math_multiply", GPU_uniform(&mtex->ambfac), stencil, &ambfac); - - texture_value_blend( - mat, GPU_uniform(&mtex->def_var), shi->amb, tin, ambfac, - mtex->blendtype, &shi->amb); - GPU_link(mat, "mtex_value_clamp", shi->amb, &shi->amb); - } - } + mul_v3_fl(profile, disk_area); + add_v3_v3(texels[i], profile); + area_accum += disk_area; } + /* Normalize over the disk. */ + mul_v3_fl(texels[i], 1.0f / (area_accum)); } -} - -void GPU_shadeinput_set(GPUMaterial *mat, Material *ma, GPUShadeInput *shi) -{ - float one = 1.0f; - - memset(shi, 0, sizeof(*shi)); - - shi->gpumat = mat; - shi->mat = ma; - - GPU_link(mat, "set_rgb", GPU_dynamic_uniform(&ma->r, GPU_DYNAMIC_MAT_DIFFRGB, ma), &shi->rgb); - GPU_link(mat, "set_rgb", GPU_dynamic_uniform(&ma->specr, GPU_DYNAMIC_MAT_SPECRGB, ma), &shi->specrgb); - GPU_link(mat, "set_rgb", GPU_dynamic_uniform(&ma->mirr, GPU_DYNAMIC_MAT_MIR, ma), &shi->mir); - GPU_link(mat, "set_rgba_zero", &shi->refcol); - GPU_link(mat, "shade_norm", GPU_builtin(GPU_VIEW_NORMAL), &shi->vn); - - if (mat->alpha) - GPU_link(mat, "set_value", GPU_dynamic_uniform(&ma->alpha, GPU_DYNAMIC_MAT_ALPHA, ma), &shi->alpha); - else - GPU_link(mat, "set_value", GPU_uniform(&one), &shi->alpha); - - GPU_link(mat, "set_value", GPU_dynamic_uniform(&ma->ref, GPU_DYNAMIC_MAT_REF, ma), &shi->refl); - GPU_link(mat, "set_value", GPU_dynamic_uniform(&ma->spec, GPU_DYNAMIC_MAT_SPEC, ma), &shi->spec); - GPU_link(mat, "set_value", GPU_dynamic_uniform(&ma->emit, GPU_DYNAMIC_MAT_EMIT, ma), &shi->emit); - GPU_link(mat, "set_value", GPU_dynamic_uniform((float *)&ma->har, GPU_DYNAMIC_MAT_HARD, ma), &shi->har); - GPU_link(mat, "set_value", GPU_dynamic_uniform(&ma->amb, GPU_DYNAMIC_MAT_AMB, ma), &shi->amb); - GPU_link(mat, "set_value", GPU_uniform(&ma->spectra), &shi->spectra); - GPU_link(mat, "shade_view", GPU_builtin(GPU_VIEW_POSITION), &shi->view); - GPU_link(mat, "vcol_attribute", GPU_attribute(CD_MCOL, ""), &shi->vcol); - if (GPU_material_do_color_management(mat)) - GPU_link(mat, "srgb_to_linearrgb", shi->vcol, &shi->vcol); - GPU_link(mat, "texco_refl", shi->vn, shi->view, &shi->ref); -} -void GPU_mist_update_enable(short enable) -{ - GPUWorld.mistenabled = (float)enable; -} + /* Normalize */ + for (int j = resolution - 2; j > 0; j--) { + texels[j][0] /= (texels[0][0] > 0.0f) ? texels[0][0] : 1.0f; + texels[j][1] /= (texels[0][1] > 0.0f) ? texels[0][1] : 1.0f; + texels[j][2] /= (texels[0][2] > 0.0f) ? texels[0][2] : 1.0f; + } -void GPU_mist_update_values(int type, float start, float dist, float inten, float color[3]) -{ - GPUWorld.mistype = (float)type; - GPUWorld.miststart = start; - GPUWorld.mistdistance = dist; - GPUWorld.mistintensity = inten; - copy_v3_v3(GPUWorld.mistcol, color); - GPUWorld.mistcol[3] = 1.0f; -} + /* First texel should be white */ + texels[0][0] = (texels[0][0] > 0.0f) ? 1.0f : 0.0f; + texels[0][1] = (texels[0][1] > 0.0f) ? 1.0f : 0.0f; + texels[0][2] = (texels[0][2] > 0.0f) ? 1.0f : 0.0f; -void GPU_horizon_update_color(float color[3]) -{ - copy_v3_v3(GPUWorld.horicol, color); + /* dim the last few texels for smoother transition */ + mul_v3_fl(texels[resolution - 2], 0.25f); + mul_v3_fl(texels[resolution - 3], 0.5f); + mul_v3_fl(texels[resolution - 4], 0.75f); } +#undef INTEGRAL_RESOLUTION -void GPU_ambient_update_color(float color[3]) +void GPU_material_sss_profile_create(GPUMaterial *material, float *radii, short *falloff_type, float *sharpness) { - copy_v3_v3(GPUWorld.ambcol, color); - GPUWorld.ambcol[3] = 1.0f; -} + material->sss_radii = radii; + material->sss_falloff = falloff_type; + material->sss_sharpness = sharpness; + material->sss_dirty = true; -void GPU_zenith_update_color(float color[3]) -{ - copy_v3_v3(GPUWorld.zencol, color); + /* Update / Create UBO */ + if (material->sss_profile == NULL) { + material->sss_profile = GPU_uniformbuffer_create(sizeof(GPUSssKernelData), NULL, NULL); + } } -void GPU_shaderesult_set(GPUShadeInput *shi, GPUShadeResult *shr) +struct GPUUniformBuffer *GPU_material_sss_profile_get(GPUMaterial *material, int sample_ct, GPUTexture **tex_profile) { - GPUMaterial *mat = shi->gpumat; - GPUNodeLink *emit, *ulinfac, *ulogfac, *mistfac; - Material *ma = shi->mat; - World *world = mat->scene->world; - float linfac, logfac; - - memset(shr, 0, sizeof(*shr)); - - if (ma->mode & MA_VERTEXCOLP) - shi->rgb = shi->vcol; - - do_material_tex(shi); - - if ((mat->scene->gm.flag & GAME_GLSL_NO_LIGHTS) || (ma->mode & MA_SHLESS)) { - GPU_link(mat, "set_rgb", shi->rgb, &shr->diff); - GPU_link(mat, "set_rgb_zero", &shr->spec); - GPU_link(mat, "set_value", shi->alpha, &shr->alpha); - shr->combined = shr->diff; - } - else { - if (GPU_link_changed(shi->emit) || ma->emit != 0.0f) { - if ((ma->mode & (MA_VERTEXCOL | MA_VERTEXCOLP)) == MA_VERTEXCOL) { - GPU_link(mat, "shade_add", shi->emit, shi->vcol, &emit); - GPU_link(mat, "shade_mul", emit, shi->rgb, &shr->diff); - } - else - GPU_link(mat, "shade_mul_value", shi->emit, shi->rgb, &shr->diff); - } - else - GPU_link(mat, "set_rgb_zero", &shr->diff); + if (material->sss_radii == NULL) + return NULL; - GPU_link(mat, "set_rgb_zero", &shr->spec); + if (material->sss_dirty || (material->sss_samples != sample_ct)) { + GPUSssKernelData kd; - material_lights(shi, shr); + float sharpness = (material->sss_sharpness != NULL) ? *material->sss_sharpness : 0.0f; - shr->combined = shr->diff; + /* XXX Black magic but it seems to fit. Maybe because we integrate -1..1 */ + sharpness *= 0.5f; - GPU_link(mat, "set_value", shi->alpha, &shr->alpha); + compute_sss_kernel(&kd, material->sss_radii, sample_ct, *material->sss_falloff, sharpness); - if (world) { - /* exposure correction */ - if (world->exp != 0.0f || world->range != 1.0f) { - linfac = 1.0f + powf((2.0f * world->exp + 0.5f), -10); - logfac = logf((linfac - 1.0f) / linfac) / world->range; + /* Update / Create UBO */ + GPU_uniformbuffer_update(material->sss_profile, &kd); - GPU_link(mat, "set_value", GPU_uniform(&linfac), &ulinfac); - GPU_link(mat, "set_value", GPU_uniform(&logfac), &ulogfac); + /* Update / Create Tex */ + float *translucence_profile; + compute_sss_translucence_kernel(&kd, 64, *material->sss_falloff, sharpness, &translucence_profile); - GPU_link(mat, "shade_exposure_correct", shr->combined, - ulinfac, ulogfac, &shr->combined); - GPU_link(mat, "shade_exposure_correct", shr->spec, - ulinfac, ulogfac, &shr->spec); - } - - /* environment lighting */ - if (!(mat->scene->gm.flag & GAME_GLSL_NO_ENV_LIGHTING) && - (world->mode & WO_ENV_LIGHT) && - (mat->scene->r.mode & R_SHADOW) && - !BKE_scene_use_new_shading_nodes(mat->scene)) - { - if ((world->ao_env_energy != 0.0f) && (GPU_link_changed(shi->amb) || ma->amb != 0.0f) && - (GPU_link_changed(shi->refl) || ma->ref != 0.0f)) - { - if (world->aocolor != WO_AOPLAIN) { - if (!(is_zero_v3(&world->horr) & is_zero_v3(&world->zenr))) { - GPUNodeLink *fcol, *f; - GPU_link(mat, "math_multiply", shi->amb, shi->refl, &f); - GPU_link(mat, "math_multiply", f, GPU_uniform(&world->ao_env_energy), &f); - GPU_link(mat, "shade_mul_value", f, shi->rgb, &fcol); - GPU_link(mat, "env_apply", shr->combined, - GPU_dynamic_uniform(GPUWorld.horicol, GPU_DYNAMIC_HORIZON_COLOR, NULL), - GPU_dynamic_uniform(GPUWorld.zencol, GPU_DYNAMIC_ZENITH_COLOR, NULL), fcol, - GPU_builtin(GPU_VIEW_MATRIX), shi->vn, &shr->combined); - } - } - else { - GPUNodeLink *f; - GPU_link(mat, "math_multiply", shi->amb, shi->refl, &f); - GPU_link(mat, "math_multiply", f, GPU_uniform(&world->ao_env_energy), &f); - GPU_link(mat, "shade_maddf", shr->combined, f, shi->rgb, &shr->combined); - } - } - } - - /* ambient color */ - if (GPU_link_changed(shi->amb) || ma->amb != 0.0f) { - GPU_link(mat, "shade_maddf", shr->combined, GPU_uniform(&ma->amb), - GPU_dynamic_uniform(GPUWorld.ambcol, GPU_DYNAMIC_AMBIENT_COLOR, NULL), - &shr->combined); - } + if (material->sss_tex_profile != NULL) { + GPU_texture_free(material->sss_tex_profile); } - if (ma->mode & MA_TRANSP && (ma->mode & (MA_ZTRANSP | MA_RAYTRANSP))) { - if (GPU_link_changed(shi->spectra) || ma->spectra != 0.0f) { - GPU_link(mat, "alpha_spec_correction", shr->spec, shi->spectra, - shi->alpha, &shr->alpha); - } - } + material->sss_tex_profile = GPU_texture_create_1D(64, GPU_RGBA16F, translucence_profile, NULL); - if (ma->mode & MA_RAMP_COL) ramp_diffuse_result(shi, &shr->combined); - if (ma->mode & MA_RAMP_SPEC) ramp_spec_result(shi, &shr->spec); + MEM_freeN(translucence_profile); - if (GPU_link_changed(shi->refcol)) - GPU_link(mat, "shade_add_mirror", shi->mir, shi->refcol, shr->combined, &shr->combined); - - if (GPU_link_changed(shi->spec) || ma->spec != 0.0f) - GPU_link(mat, "shade_add", shr->combined, shr->spec, &shr->combined); + material->sss_samples = sample_ct; + material->sss_dirty = false; } - GPU_link(mat, "mtex_alpha_to_col", shr->combined, shr->alpha, &shr->combined); - - if (ma->shade_flag & MA_OBCOLOR) - GPU_link(mat, "shade_obcolor", shr->combined, GPU_builtin(GPU_OBCOLOR), &shr->combined); - - if (!(ma->mode & MA_NOMIST)) { - GPU_link(mat, "shade_mist_factor", GPU_builtin(GPU_VIEW_POSITION), - GPU_dynamic_uniform(&GPUWorld.mistenabled, GPU_DYNAMIC_MIST_ENABLE, NULL), - GPU_dynamic_uniform(&GPUWorld.miststart, GPU_DYNAMIC_MIST_START, NULL), - GPU_dynamic_uniform(&GPUWorld.mistdistance, GPU_DYNAMIC_MIST_DISTANCE, NULL), - GPU_dynamic_uniform(&GPUWorld.mistype, GPU_DYNAMIC_MIST_TYPE, NULL), - GPU_dynamic_uniform(&GPUWorld.mistintensity, GPU_DYNAMIC_MIST_INTENSITY, NULL), &mistfac); - - GPU_link(mat, "mix_blend", mistfac, shr->combined, - GPU_dynamic_uniform(GPUWorld.mistcol, GPU_DYNAMIC_MIST_COLOR, NULL), &shr->combined); + if (tex_profile != NULL) { + *tex_profile = material->sss_tex_profile; } + return material->sss_profile; +} - if (!mat->alpha) { - if (world && (GPU_link_changed(shr->alpha) || ma->alpha != 1.0f)) - GPU_link(mat, "shade_world_mix", GPU_dynamic_uniform(GPUWorld.horicol, GPU_DYNAMIC_HORIZON_COLOR, NULL), - shr->combined, &shr->combined); - - GPU_link(mat, "shade_alpha_opaque", shr->combined, &shr->combined); - } +#undef SSS_EXPONENT +#undef SSS_SAMPLES - if (ma->shade_flag & MA_OBCOLOR) { - mat->obcolalpha = 1; - GPU_link(mat, "shade_alpha_obcolor", shr->combined, GPU_builtin(GPU_OBCOLOR), &shr->combined); - } +void GPU_material_vertex_attributes(GPUMaterial *material, GPUVertexAttribs *attribs) +{ + *attribs = material->attribs; } -static GPUNodeLink *GPU_blender_material(GPUMaterial *mat, Material *ma) +void GPU_material_output_link(GPUMaterial *material, GPUNodeLink *link) { - GPUShadeInput shi; - GPUShadeResult shr; - - GPU_shadeinput_set(mat, ma, &shi); - GPU_shaderesult_set(&shi, &shr); - - return shr.combined; + if (!material->outlink) + material->outlink = link; } -static GPUNodeLink *gpu_material_diffuse_bsdf(GPUMaterial *mat, Material *ma) +void gpu_material_add_node(GPUMaterial *material, GPUNode *node) { - static float roughness = 0.0f; - GPUNodeLink *outlink; - - GPU_link(mat, "node_bsdf_diffuse", - GPU_uniform(&ma->r), GPU_uniform(&roughness), GPU_builtin(GPU_VIEW_NORMAL), &outlink); - - return outlink; + BLI_addtail(&material->nodes, node); } -static GPUNodeLink *gpu_material_preview_matcap(GPUMaterial *mat, Material *ma) +/* Return true if the material compilation has not yet begin or begin. */ +GPUMaterialStatus GPU_material_status(GPUMaterial *mat) { - GPUNodeLink *outlink; - - /* some explanations here: - * matcap normal holds the normal remapped to the 0.0 - 1.0 range. To take advantage of flat shading, we abuse - * the built in secondary color of opengl. Color is just the regular color, which should include mask value too. - * This also needs flat shading so we use the primary opengl color built-in */ - GPU_link(mat, "material_preview_matcap", GPU_uniform(&ma->r), GPU_image_preview(ma->preview), - GPU_opengl_builtin(GPU_MATCAP_NORMAL), GPU_opengl_builtin(GPU_COLOR), &outlink); - - return outlink; + return mat->status; } -/* new solid draw mode with glsl matcaps */ -GPUMaterial *GPU_material_matcap(Scene *scene, Material *ma, bool use_opensubdiv) -{ - GPUMaterial *mat; - GPUNodeLink *outlink; - LinkData *link; - - for (link = ma->gpumaterial.first; link; link = link->next) { - GPUMaterial *current_material = (GPUMaterial *)link->data; - if (current_material->scene == scene && - current_material->is_opensubdiv == use_opensubdiv) - { - return current_material; - } - } - - /* allocate material */ - mat = GPU_material_construct_begin(ma); - mat->scene = scene; - mat->type = GPU_MATERIAL_TYPE_MESH; - mat->is_opensubdiv = use_opensubdiv; +/* Code generation */ - if (ma->preview && ma->preview->rect[0]) { - outlink = gpu_material_preview_matcap(mat, ma); - } - else { - outlink = gpu_material_diffuse_bsdf(mat, ma); - } - - GPU_material_output_link(mat, outlink); +bool GPU_material_do_color_management(GPUMaterial *mat) +{ + if (!BKE_scene_check_color_management_enabled(mat->scene)) + return false; - gpu_material_construct_end(mat, "matcap_pass"); - - /* note that even if building the shader fails in some way, we still keep - * it to avoid trying to compile again and again, and simple do not use - * the actual shader on drawing */ - - link = MEM_callocN(sizeof(LinkData), "GPUMaterialLink"); - link->data = mat; - BLI_addtail(&ma->gpumaterial, link); - - return mat; + return true; } -static void do_world_tex(GPUShadeInput *shi, struct World *wo, GPUNodeLink **hor, GPUNodeLink **zen, GPUNodeLink **blend) +bool GPU_material_use_domain_surface(GPUMaterial *mat) { - GPUMaterial *mat = shi->gpumat; - GPUNodeLink *texco, *tin, *trgb, *stencil, *tcol, *zenfac; - MTex *mtex; - Tex *tex; - float ofs[3], zero = 0.0f; - int tex_nr, rgbnor; - - GPU_link(mat, "set_value_one", &stencil); - /* go over texture slots */ - for (tex_nr = 0; tex_nr < MAX_MTEX; tex_nr++) { - if (wo->mtex[tex_nr]) { - mtex = wo->mtex[tex_nr]; - tex = mtex->tex; - if (tex == NULL || !tex->ima || (tex->type != TEX_IMAGE && tex->type != TEX_ENVMAP)) - continue; - /* which coords */ - if (mtex->texco == TEXCO_VIEW || mtex->texco == TEXCO_GLOB) { - if (tex->type == TEX_IMAGE) - texco = GPU_builtin(GPU_VIEW_POSITION); - else if (tex->type == TEX_ENVMAP) - GPU_link(mat, "background_transform_to_world", GPU_builtin(GPU_VIEW_POSITION), &texco); - } - else if (mtex->texco == TEXCO_EQUIRECTMAP || mtex->texco == TEXCO_ANGMAP) { - if ((tex->type == TEX_IMAGE && wo->skytype & WO_SKYREAL) || tex->type == TEX_ENVMAP) - GPU_link(mat, "background_transform_to_world", GPU_builtin(GPU_VIEW_POSITION), &texco); - else - texco = GPU_builtin(GPU_VIEW_POSITION); - } - else - continue; - GPU_link(mat, "texco_norm", texco, &texco); - if (tex->type == TEX_IMAGE && !(wo->skytype & WO_SKYREAL)) { - GPU_link(mat, "mtex_2d_mapping", texco, &texco); - } - if (mtex->size[0] != 1.0f || mtex->size[1] != 1.0f || mtex->size[2] != 1.0f) { - float size[3] = { mtex->size[0], mtex->size[1], mtex->size[2] }; - if (tex->type == TEX_ENVMAP) { - size[1] = mtex->size[2]; - size[2] = mtex->size[1]; - } - GPU_link(mat, "mtex_mapping_size", texco, GPU_uniform(size), &texco); - } - ofs[0] = mtex->ofs[0] + 0.5f - 0.5f * mtex->size[0]; - if (tex->type == TEX_ENVMAP) { - ofs[1] = -mtex->ofs[2] + 0.5f - 0.5f * mtex->size[2]; - ofs[2] = mtex->ofs[1] + 0.5f - 0.5f * mtex->size[1]; - } - else { - ofs[1] = mtex->ofs[1] + 0.5f - 0.5f * mtex->size[1]; - ofs[2] = 0.0; - } - if (ofs[0] != 0.0f || ofs[1] != 0.0f || ofs[2] != 0.0f) - GPU_link(mat, "mtex_mapping_ofs", texco, GPU_uniform(ofs), &texco); - if (mtex->texco == TEXCO_EQUIRECTMAP) { - GPU_link(mat, "node_tex_environment_equirectangular", texco, GPU_image(tex->ima, &tex->iuser, false), &trgb); - } - else if (mtex->texco == TEXCO_ANGMAP) { - GPU_link(mat, "node_tex_environment_mirror_ball", texco, GPU_image(tex->ima, &tex->iuser, false), &trgb); - } - else { - if (tex->type == TEX_ENVMAP) - GPU_link(mat, "mtex_cube_map", texco, GPU_cube_map(tex->ima, &tex->iuser, false), &tin, &trgb); - else if (tex->type == TEX_IMAGE) - GPU_link(mat, "mtex_image", texco, GPU_image(tex->ima, &tex->iuser, false), &tin, &trgb); - } - rgbnor = TEX_RGB; - if (tex->type == TEX_IMAGE || tex->type == TEX_ENVMAP) - if (GPU_material_do_color_management(mat)) - GPU_link(mat, "srgb_to_linearrgb", trgb, &trgb); - /* texture output */ - if ((rgbnor & TEX_RGB) && (mtex->texflag & MTEX_RGBTOINT)) { - GPU_link(mat, "mtex_rgbtoint", trgb, &tin); - rgbnor -= TEX_RGB; - } - if (mtex->texflag & MTEX_NEGATIVE) { - if (rgbnor & TEX_RGB) - GPU_link(mat, "mtex_rgb_invert", trgb, &trgb); - else - GPU_link(mat, "mtex_value_invert", tin, &tin); - } - if (mtex->texflag & MTEX_STENCIL) { - if (rgbnor & TEX_RGB) - GPU_link(mat, "mtex_rgb_stencil", stencil, trgb, &stencil, &trgb); - else - GPU_link(mat, "mtex_value_stencil", stencil, tin, &stencil, &tin); - } - else { - if (rgbnor & TEX_RGB) - GPU_link(mat, "mtex_alpha_multiply_value", trgb, stencil, &trgb); - else - GPU_link(mat, "math_multiply", stencil, tin, &tin); - } - /* color mapping */ - if (mtex->mapto & (WOMAP_HORIZ + WOMAP_ZENUP + WOMAP_ZENDOWN)) { - if ((rgbnor & TEX_RGB) == 0) - GPU_link(mat, "set_rgb", GPU_uniform(&mtex->r), &trgb); - else - GPU_link(mat, "mtex_alpha_from_col", trgb, &tin); - GPU_link(mat, "set_rgb", trgb, &tcol); - if (mtex->mapto & WOMAP_HORIZ) { - texture_rgb_blend(mat, tcol, *hor, tin, GPU_uniform(&mtex->colfac), mtex->blendtype, hor); - } - if (mtex->mapto & (WOMAP_ZENUP + WOMAP_ZENDOWN)) { - GPU_link(mat, "set_value_zero", &zenfac); - if (wo->skytype & WO_SKYREAL) { - if (mtex->mapto & WOMAP_ZENUP) { - if (mtex->mapto & WOMAP_ZENDOWN) { - GPU_link(mat, "world_zen_mapping", shi->view, GPU_uniform(&mtex->zenupfac), - GPU_uniform(&mtex->zendownfac), &zenfac); - } - else { - GPU_link(mat, "world_zen_mapping", shi->view, GPU_uniform(&mtex->zenupfac), - GPU_uniform(&zero), &zenfac); - } - } - else if (mtex->mapto & WOMAP_ZENDOWN) { - GPU_link(mat, "world_zen_mapping", shi->view, GPU_uniform(&zero), - GPU_uniform(&mtex->zendownfac), &zenfac); - } - } - else { - if (mtex->mapto & WOMAP_ZENUP) - GPU_link(mat, "set_value", GPU_uniform(&mtex->zenupfac), &zenfac); - else if (mtex->mapto & WOMAP_ZENDOWN) - GPU_link(mat, "set_value", GPU_uniform(&mtex->zendownfac), &zenfac); - } - texture_rgb_blend(mat, tcol, *zen, tin, zenfac, mtex->blendtype, zen); - } - } - if (mtex->mapto & WOMAP_BLEND && wo->skytype & WO_SKYBLEND) { - if (rgbnor & TEX_RGB) - GPU_link(mat, "mtex_rgbtoint", trgb, &tin); - texture_value_blend(mat, GPU_uniform(&mtex->def_var), *blend, tin, GPU_uniform(&mtex->blendfac), mtex->blendtype, blend); - } - } - } + return (mat->domain & GPU_DOMAIN_SURFACE); } -static void gpu_material_old_world(struct GPUMaterial *mat, struct World *wo) +bool GPU_material_use_domain_volume(GPUMaterial *mat) { - GPUShadeInput shi; - GPUShadeResult shr; - GPUNodeLink *hor, *zen, *ray, *blend; - - shi.gpumat = mat; + return (mat->domain & GPU_DOMAIN_VOLUME); +} - for (int i = 0; i < MAX_MTEX; i++) { - if (wo->mtex[i] && wo->mtex[i]->tex) { - wo->skytype |= WO_SKYTEX; - break; - } - } - if ((wo->skytype & (WO_SKYBLEND + WO_SKYTEX)) == 0) { - GPU_link(mat, "set_rgb", GPU_dynamic_uniform(&wo->horr, GPU_DYNAMIC_HORIZON_COLOR, NULL), &shr.combined); - } - else { - GPU_link(mat, "set_rgb_zero", &shi.rgb); - GPU_link(mat, "background_transform_to_world", GPU_builtin(GPU_VIEW_POSITION), &ray); - if (wo->skytype & WO_SKYPAPER) - GPU_link(mat, "world_paper_view", GPU_builtin(GPU_VIEW_POSITION), &shi.view); - else - GPU_link(mat, "shade_view", ray, &shi.view); - if (wo->skytype & WO_SKYBLEND) { - if (wo->skytype & WO_SKYPAPER) { - if (wo->skytype & WO_SKYREAL) - GPU_link(mat, "world_blend_paper_real", GPU_builtin(GPU_VIEW_POSITION), &blend); - else - GPU_link(mat, "world_blend_paper", GPU_builtin(GPU_VIEW_POSITION), &blend); - } - else { - if (wo->skytype & WO_SKYREAL) - GPU_link(mat, "world_blend_real", ray, &blend); - else - GPU_link(mat, "world_blend", ray, &blend); - } - } - else { - GPU_link(mat, "set_value_zero", &blend); +GPUMaterial *GPU_material_from_nodetree_find( + ListBase *gpumaterials, const void *engine_type, int options) +{ + for (LinkData *link = gpumaterials->first; link; link = link->next) { + GPUMaterial *current_material = (GPUMaterial *)link->data; + if (current_material->engine_type == engine_type && + current_material->options == options) + { + return current_material; } - GPU_link(mat, "set_rgb", GPU_dynamic_uniform(&wo->horr, GPU_DYNAMIC_HORIZON_COLOR, NULL), &hor); - GPU_link(mat, "set_rgb", GPU_dynamic_uniform(&wo->zenr, GPU_DYNAMIC_ZENITH_COLOR, NULL), &zen); - do_world_tex(&shi, wo, &hor, &zen, &blend); - if (wo->skytype & WO_SKYBLEND) - GPU_link(mat, "node_mix_shader", blend, hor, zen, &shi.rgb); - else - GPU_link(mat, "set_rgb", hor, &shi.rgb); - GPU_link(mat, "set_rgb", shi.rgb, &shr.combined); } - GPU_material_output_link(mat, shr.combined); + + return NULL; } -GPUMaterial *GPU_material_world(struct Scene *scene, struct World *wo) +/** + * \note Caller must use #GPU_material_from_nodetree_find to re-use existing materials, + * This is enforced since constructing other arguments to this function may be expensive + * so only do this when they are needed. + */ +GPUMaterial *GPU_material_from_nodetree( + Scene *scene, struct bNodeTree *ntree, ListBase *gpumaterials, const void *engine_type, int options) { LinkData *link; - GPUMaterial *mat; + bool has_volume_output, has_surface_output; - for (link = wo->gpumaterial.first; link; link = link->next) - if (((GPUMaterial *)link->data)->scene == scene) - return link->data; + /* Caller must re-use materials. */ + BLI_assert(GPU_material_from_nodetree_find(gpumaterials, engine_type, options) == NULL); /* allocate material */ - mat = GPU_material_construct_begin(NULL); + GPUMaterial *mat = MEM_callocN(sizeof(GPUMaterial), "GPUMaterial");; mat->scene = scene; - mat->type = GPU_MATERIAL_TYPE_WORLD; - - /* create nodes */ - if (BKE_scene_use_new_shading_nodes(scene) && wo->nodetree && wo->use_nodes) { - ntreeGPUMaterialNodes(wo->nodetree, mat, NODE_NEW_SHADING); + mat->engine_type = engine_type; + mat->options = options; + + ntreeGPUMaterialNodes(ntree, mat, NODE_NEW_SHADING | NODE_NEWER_SHADING); + ntreeGPUMaterialDomain(ntree, &has_surface_output, &has_volume_output); + + if (has_surface_output) { + mat->domain |= GPU_DOMAIN_SURFACE; } - else { - gpu_material_old_world(mat, wo); + if (has_volume_output) { + mat->domain |= GPU_DOMAIN_VOLUME; } - if (GPU_material_do_color_management(mat)) - if (mat->outlink) - GPU_link(mat, "linearrgb_to_srgb", mat->outlink, &mat->outlink); + 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; + } - gpu_material_construct_end(mat, wo->id.name); - /* note that even if building the shader fails in some way, we still keep * it to avoid trying to compile again and again, and simple do not use * the actual shader on drawing */ link = MEM_callocN(sizeof(LinkData), "GPUMaterialLink"); link->data = mat; - BLI_addtail(&wo->gpumaterial, link); + BLI_addtail(gpumaterials, link); return mat; } - -GPUMaterial *GPU_material_from_blender(Scene *scene, 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) { - GPUMaterial *mat; - GPUNodeLink *outlink; - LinkData *link; - - for (link = ma->gpumaterial.first; link; link = link->next) { - GPUMaterial *current_material = (GPUMaterial *)link->data; - if (current_material->scene == scene && - current_material->is_opensubdiv == use_opensubdiv) - { - return current_material; - } - } - - /* allocate material */ - mat = GPU_material_construct_begin(ma); - mat->scene = scene; - mat->type = GPU_MATERIAL_TYPE_MESH; - mat->is_opensubdiv = use_opensubdiv; - - /* render pipeline option */ - bool new_shading_nodes = BKE_scene_use_new_shading_nodes(scene); - if (!new_shading_nodes && (ma->mode & MA_TRANSP)) - GPU_material_enable_alpha(mat); - else if (new_shading_nodes && ma->alpha < 1.0f) - GPU_material_enable_alpha(mat); - - if (!(scene->gm.flag & GAME_GLSL_NO_NODES) && ma->nodetree && ma->use_nodes) { - /* create nodes */ - if (new_shading_nodes) - ntreeGPUMaterialNodes(ma->nodetree, mat, NODE_NEW_SHADING); - else - ntreeGPUMaterialNodes(ma->nodetree, mat, NODE_OLD_SHADING); + 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 { - if (new_shading_nodes) { - /* create simple diffuse material instead of nodes */ - outlink = gpu_material_diffuse_bsdf(mat, ma); - } - else { - /* create blender material */ - outlink = GPU_blender_material(mat, ma); - } - - GPU_material_output_link(mat, outlink); + mat->status = GPU_MAT_FAILED; } - - if (GPU_material_do_color_management(mat)) - if (mat->outlink) - GPU_link(mat, "linearrgb_to_srgb", mat->outlink, &mat->outlink); - - gpu_material_construct_end(mat, ma->id.name); - - /* note that even if building the shader fails in some way, we still keep - * it to avoid trying to compile again and again, and simple do not use - * the actual shader on drawing */ - - link = MEM_callocN(sizeof(LinkData), "GPUMaterialLink"); - link->data = mat; - BLI_addtail(&ma->gpumaterial, link); - - return mat; } void GPU_materials_free(void) { - Object *ob; Material *ma; World *wo; extern Material defmaterial; @@ -2230,684 +672,4 @@ void GPU_materials_free(void) GPU_material_free(&wo->gpumaterial); GPU_material_free(&defmaterial.gpumaterial); - - for (ob = G.main->object.first; ob; ob = ob->id.next) - GPU_lamp_free(ob); -} - -/* Lamps and shadow buffers */ - -static void gpu_lamp_calc_winmat(GPULamp *lamp) -{ - float temp, angle, pixsize, wsize; - - if (lamp->type == LA_SUN) { - wsize = lamp->la->shadow_frustum_size; - orthographic_m4(lamp->winmat, -wsize, wsize, -wsize, wsize, lamp->d, lamp->clipend); - } - else if (lamp->type == LA_SPOT) { - angle = saacos(lamp->spotsi); - temp = 0.5f * lamp->size * cosf(angle) / sinf(angle); - pixsize = lamp->d / temp; - wsize = pixsize * 0.5f * lamp->size; - /* compute shadows according to X and Y scaling factors */ - perspective_m4( - lamp->winmat, - -wsize * lamp->spotvec[0], wsize * lamp->spotvec[0], - -wsize * lamp->spotvec[1], wsize * lamp->spotvec[1], - lamp->d, lamp->clipend); - } -} - -void GPU_lamp_update(GPULamp *lamp, int lay, int hide, float obmat[4][4]) -{ - float mat[4][4]; - float obmat_scale[3]; - - lamp->lay = lay; - lamp->hide = hide; - - normalize_m4_m4_ex(mat, obmat, obmat_scale); - - copy_v3_v3(lamp->vec, mat[2]); - copy_v3_v3(lamp->co, mat[3]); - copy_m4_m4(lamp->obmat, mat); - invert_m4_m4(lamp->imat, mat); - - if (lamp->type == LA_SPOT) { - /* update spotlamp scale on X and Y axis */ - lamp->spotvec[0] = obmat_scale[0] / obmat_scale[2]; - lamp->spotvec[1] = obmat_scale[1] / obmat_scale[2]; - } - - if (GPU_lamp_has_shadow_buffer(lamp)) { - /* makeshadowbuf */ - gpu_lamp_calc_winmat(lamp); - } -} - -void GPU_lamp_update_colors(GPULamp *lamp, float r, float g, float b, float energy) -{ - lamp->energy = energy; - if (lamp->mode & LA_NEG) lamp->energy = -lamp->energy; - - lamp->col[0] = r; - lamp->col[1] = g; - lamp->col[2] = b; -} - -void GPU_lamp_update_distance(GPULamp *lamp, float distance, float att1, float att2, - float coeff_const, float coeff_lin, float coeff_quad) -{ - lamp->dist = distance; - lamp->att1 = att1; - lamp->att2 = att2; - lamp->coeff_const = coeff_const; - lamp->coeff_lin = coeff_lin; - lamp->coeff_quad = coeff_quad; } - -void GPU_lamp_update_spot(GPULamp *lamp, float spotsize, float spotblend) -{ - lamp->spotsi = cosf(spotsize * 0.5f); - lamp->spotbl = (1.0f - lamp->spotsi) * spotblend; -} - -static void gpu_lamp_from_blender(Scene *scene, Object *ob, Object *par, Lamp *la, GPULamp *lamp) -{ - lamp->scene = scene; - lamp->ob = ob; - lamp->par = par; - lamp->la = la; - - /* add_render_lamp */ - lamp->mode = la->mode; - lamp->type = la->type; - - lamp->energy = la->energy; - if (lamp->mode & LA_NEG) lamp->energy = -lamp->energy; - - lamp->col[0] = la->r; - lamp->col[1] = la->g; - lamp->col[2] = la->b; - - GPU_lamp_update(lamp, ob->lay, (ob->restrictflag & OB_RESTRICT_RENDER), ob->obmat); - - lamp->spotsi = la->spotsize; - if (lamp->mode & LA_HALO) - if (lamp->spotsi > DEG2RADF(170.0f)) - lamp->spotsi = DEG2RADF(170.0f); - lamp->spotsi = cosf(lamp->spotsi * 0.5f); - lamp->spotbl = (1.0f - lamp->spotsi) * la->spotblend; - lamp->k = la->k; - - lamp->dist = la->dist; - lamp->falloff_type = la->falloff_type; - lamp->att1 = la->att1; - lamp->att2 = la->att2; - lamp->coeff_const = la->coeff_const; - lamp->coeff_lin = la->coeff_lin; - lamp->coeff_quad = la->coeff_quad; - lamp->curfalloff = la->curfalloff; - - /* initshadowbuf */ - lamp->bias = 0.02f * la->bias; - lamp->size = la->bufsize; - lamp->d = la->clipsta; - lamp->clipend = la->clipend; - - /* arbitrary correction for the fact we do no soft transition */ - lamp->bias *= 0.25f; -} - -static void gpu_lamp_shadow_free(GPULamp *lamp) -{ - if (lamp->tex) { - GPU_texture_free(lamp->tex); - lamp->tex = NULL; - } - if (lamp->depthtex) { - GPU_texture_free(lamp->depthtex); - lamp->depthtex = NULL; - } - if (lamp->fb) { - GPU_framebuffer_free(lamp->fb); - lamp->fb = NULL; - } - if (lamp->blurtex) { - GPU_texture_free(lamp->blurtex); - lamp->blurtex = NULL; - } - if (lamp->blurfb) { - GPU_framebuffer_free(lamp->blurfb); - lamp->blurfb = NULL; - } -} - -GPULamp *GPU_lamp_from_blender(Scene *scene, Object *ob, Object *par) -{ - Lamp *la; - GPULamp *lamp; - LinkData *link; - - for (link = ob->gpulamp.first; link; link = link->next) { - lamp = (GPULamp *)link->data; - - if (lamp->par == par && lamp->scene == scene) - return link->data; - } - - lamp = MEM_callocN(sizeof(GPULamp), "GPULamp"); - - link = MEM_callocN(sizeof(LinkData), "GPULampLink"); - link->data = lamp; - BLI_addtail(&ob->gpulamp, link); - - la = ob->data; - gpu_lamp_from_blender(scene, ob, par, la, lamp); - - 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; - } - - if (!GPU_framebuffer_texture_attach(lamp->fb, lamp->depthtex, 0, NULL)) { - gpu_lamp_shadow_free(lamp); - return lamp; - } - - /* Shadow color map */ - lamp->tex = GPU_texture_create_vsm_shadow_map(lamp->size, NULL); - if (!lamp->tex) { - gpu_lamp_shadow_free(lamp); - return lamp; - } - - if (!GPU_framebuffer_texture_attach(lamp->fb, lamp->tex, 0, NULL)) { - 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_texture_create_vsm_shadow_map(lamp->size * 0.5, NULL); - if (!lamp->blurtex) { - gpu_lamp_shadow_free(lamp); - return lamp; - } - - if (!GPU_framebuffer_texture_attach(lamp->blurfb, lamp->blurtex, 0, NULL)) { - gpu_lamp_shadow_free(lamp); - return lamp; - } - - /* we need to properly bind to test for completeness */ - GPU_texture_bind_as_framebuffer(lamp->blurtex); - - if (!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; - } - - if (!GPU_framebuffer_texture_attach(lamp->fb, lamp->tex, 0, NULL)) { - gpu_lamp_shadow_free(lamp); - return lamp; - } - - if (!GPU_framebuffer_check_valid(lamp->fb, NULL)) { - gpu_lamp_shadow_free(lamp); - return lamp; - } - } - - GPU_framebuffer_restore(); - - lamp->shadow_color[0] = la->shdwr; - lamp->shadow_color[1] = la->shdwg; - lamp->shadow_color[2] = la->shdwb; - } - else { - lamp->shadow_color[0] = 1.0; - lamp->shadow_color[1] = 1.0; - lamp->shadow_color[2] = 1.0; - } - - return lamp; -} - -void GPU_lamp_free(Object *ob) -{ - GPULamp *lamp; - LinkData *link; - LinkData *nlink; - Material *ma; - - for (link = ob->gpulamp.first; link; link = link->next) { - lamp = link->data; - - while (lamp->materials.first) { - nlink = lamp->materials.first; - ma = nlink->data; - BLI_freelinkN(&lamp->materials, nlink); - - if (ma->gpumaterial.first) - GPU_material_free(&ma->gpumaterial); - } - - gpu_lamp_shadow_free(lamp); - - MEM_freeN(lamp); - } - - BLI_freelistN(&ob->gpulamp); -} - -bool GPU_lamp_has_shadow_buffer(GPULamp *lamp) -{ - return (!(lamp->scene->gm.flag & GAME_GLSL_NO_SHADOWS) && - !(lamp->scene->gm.flag & GAME_GLSL_NO_LIGHTS) && - lamp->tex && lamp->fb); -} - -void GPU_lamp_update_buffer_mats(GPULamp *lamp) -{ - float rangemat[4][4], persmat[4][4]; - - /* initshadowbuf */ - invert_m4_m4(lamp->viewmat, lamp->obmat); - normalize_v3(lamp->viewmat[0]); - normalize_v3(lamp->viewmat[1]); - normalize_v3(lamp->viewmat[2]); - - /* makeshadowbuf */ - mul_m4_m4m4(persmat, lamp->winmat, lamp->viewmat); - - /* opengl depth buffer is range 0.0..1.0 instead of -1.0..1.0 in blender */ - unit_m4(rangemat); - rangemat[0][0] = 0.5f; - rangemat[1][1] = 0.5f; - rangemat[2][2] = 0.5f; - rangemat[3][0] = 0.5f; - rangemat[3][1] = 0.5f; - rangemat[3][2] = 0.5f; - - mul_m4_m4m4(lamp->persmat, rangemat, persmat); -} - -void GPU_lamp_shadow_buffer_bind(GPULamp *lamp, float viewmat[4][4], int *winsize, float winmat[4][4]) -{ - GPU_lamp_update_buffer_mats(lamp); - - /* opengl */ - glDisable(GL_SCISSOR_TEST); - GPU_texture_bind_as_framebuffer(lamp->tex); - if (lamp->la->shadowmap_type == LA_SHADMAP_VARIANCE) - GPU_shader_bind(GPU_shader_get_builtin_shader(GPU_SHADER_VSM_STORE)); - - /* set matrices */ - copy_m4_m4(viewmat, lamp->viewmat); - copy_m4_m4(winmat, lamp->winmat); - *winsize = lamp->size; -} - -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_framebuffer_texture_unbind(lamp->fb, lamp->tex); - GPU_framebuffer_restore(); - glEnable(GL_SCISSOR_TEST); -} - -int GPU_lamp_shadow_buffer_type(GPULamp *lamp) -{ - return lamp->la->shadowmap_type; -} - -int GPU_lamp_shadow_bind_code(GPULamp *lamp) -{ - return lamp->tex ? GPU_texture_opengl_bindcode(lamp->tex) : -1; -} - -float *GPU_lamp_dynpersmat(GPULamp *lamp) -{ - return &lamp->dynpersmat[0][0]; -} - -int GPU_lamp_shadow_layer(GPULamp *lamp) -{ - if (lamp->fb && lamp->tex && (lamp->mode & (LA_LAYER | LA_LAYER_SHADOW))) - return lamp->lay; - else - return -1; -} - -GPUNodeLink *GPU_lamp_get_data( - GPUMaterial *mat, GPULamp *lamp, - GPUNodeLink **r_col, GPUNodeLink **r_lv, GPUNodeLink **r_dist, GPUNodeLink **r_shadow, GPUNodeLink **r_energy) -{ - GPUNodeLink *visifac; - - *r_col = GPU_dynamic_uniform(lamp->dyncol, GPU_DYNAMIC_LAMP_DYNCOL, lamp->ob); - *r_energy = GPU_dynamic_uniform(&lamp->dynenergy, GPU_DYNAMIC_LAMP_DYNENERGY, lamp->ob); - visifac = lamp_get_visibility(mat, lamp, r_lv, r_dist); - - shade_light_textures(mat, lamp, r_col); - - if (GPU_lamp_has_shadow_buffer(lamp)) { - GPUNodeLink *vn, *inp; - - GPU_link(mat, "shade_norm", GPU_builtin(GPU_VIEW_NORMAL), &vn); - GPU_link(mat, "shade_inp", vn, *r_lv, &inp); - mat->dynproperty |= DYN_LAMP_PERSMAT; - - if (lamp->la->shadowmap_type == LA_SHADMAP_VARIANCE) { - GPU_link(mat, "shadows_only_vsm", - GPU_builtin(GPU_VIEW_POSITION), - GPU_dynamic_texture(lamp->tex, GPU_DYNAMIC_SAMPLER_2DSHADOW, lamp->ob), - GPU_dynamic_uniform((float *)lamp->dynpersmat, GPU_DYNAMIC_LAMP_DYNPERSMAT, lamp->ob), - GPU_uniform(&lamp->bias), GPU_uniform(&lamp->la->bleedbias), - GPU_uniform(lamp->shadow_color), inp, r_shadow); - } - else { - GPU_link(mat, "shadows_only", - GPU_builtin(GPU_VIEW_POSITION), - GPU_dynamic_texture(lamp->tex, GPU_DYNAMIC_SAMPLER_2DSHADOW, lamp->ob), - GPU_dynamic_uniform((float *)lamp->dynpersmat, GPU_DYNAMIC_LAMP_DYNPERSMAT, lamp->ob), - GPU_uniform(&lamp->bias), GPU_uniform(lamp->shadow_color), inp, r_shadow); - } - } - else { - GPU_link(mat, "set_rgb_one", r_shadow); - } - - /* ensure shadow buffer and lamp textures will be updated */ - add_user_list(&mat->lamps, lamp); - add_user_list(&lamp->materials, mat->ma); - - return visifac; -} - -/* export the GLSL shader */ - -GPUShaderExport *GPU_shader_export(struct Scene *scene, struct Material *ma) -{ - static struct { - GPUBuiltin gputype; - GPUDynamicType dynamictype; - GPUDataType datatype; - } builtins[] = { - { GPU_VIEW_MATRIX, GPU_DYNAMIC_OBJECT_VIEWMAT, GPU_DATA_16F }, - { GPU_INVERSE_VIEW_MATRIX, GPU_DYNAMIC_OBJECT_VIEWIMAT, GPU_DATA_16F }, - { GPU_OBJECT_MATRIX, GPU_DYNAMIC_OBJECT_MAT, GPU_DATA_16F }, - { GPU_INVERSE_OBJECT_MATRIX, GPU_DYNAMIC_OBJECT_IMAT, GPU_DATA_16F }, - { GPU_LOC_TO_VIEW_MATRIX, GPU_DYNAMIC_OBJECT_LOCTOVIEWMAT, GPU_DATA_16F }, - { GPU_INVERSE_LOC_TO_VIEW_MATRIX, GPU_DYNAMIC_OBJECT_LOCTOVIEWIMAT, GPU_DATA_16F }, - { GPU_OBCOLOR, GPU_DYNAMIC_OBJECT_COLOR, GPU_DATA_4F }, - { GPU_AUTO_BUMPSCALE, GPU_DYNAMIC_OBJECT_AUTOBUMPSCALE, GPU_DATA_1F }, - { 0 } - }; - - GPUShaderExport *shader = NULL; - GPUInput *input; - int liblen, fraglen; - - /* TODO(sergey): How to determine whether we need OSD or not here? */ - GPUMaterial *mat = GPU_material_from_blender(scene, ma, false); - GPUPass *pass = (mat) ? mat->pass : NULL; - - if (pass && pass->fragmentcode && pass->vertexcode) { - shader = MEM_callocN(sizeof(GPUShaderExport), "GPUShaderExport"); - - for (input = pass->inputs.first; input; input = input->next) { - GPUInputUniform *uniform = MEM_callocN(sizeof(GPUInputUniform), "GPUInputUniform"); - - if (input->ima) { - /* image sampler uniform */ - uniform->type = GPU_DYNAMIC_SAMPLER_2DIMAGE; - uniform->datatype = GPU_DATA_1I; - uniform->image = input->ima; - uniform->texnumber = input->texid; - BLI_strncpy(uniform->varname, input->shadername, sizeof(uniform->varname)); - } - else if (input->tex) { - /* generated buffer */ - uniform->texnumber = input->texid; - uniform->datatype = GPU_DATA_1I; - BLI_strncpy(uniform->varname, input->shadername, sizeof(uniform->varname)); - - switch (input->textype) { - case GPU_SHADOW2D: - uniform->type = GPU_DYNAMIC_SAMPLER_2DSHADOW; - uniform->lamp = input->dynamicdata; - break; - case GPU_TEX2D: - if (GPU_texture_opengl_bindcode(input->tex)) { - uniform->type = GPU_DYNAMIC_SAMPLER_2DBUFFER; - glBindTexture(GL_TEXTURE_2D, GPU_texture_opengl_bindcode(input->tex)); - uniform->texsize = GPU_texture_width(input->tex) * GPU_texture_height(input->tex); - uniform->texpixels = MEM_mallocN(uniform->texsize * 4, "RGBApixels"); - glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, uniform->texpixels); - glBindTexture(GL_TEXTURE_2D, 0); - } - break; - - case GPU_NONE: - case GPU_TEXCUBE: - case GPU_FLOAT: - case GPU_VEC2: - case GPU_VEC3: - case GPU_VEC4: - case GPU_MAT3: - case GPU_MAT4: - case GPU_ATTRIB: - break; - } - } - else { - uniform->type = input->dynamictype; - BLI_strncpy(uniform->varname, input->shadername, sizeof(uniform->varname)); - switch (input->type) { - case GPU_FLOAT: - uniform->datatype = GPU_DATA_1F; - break; - case GPU_VEC2: - uniform->datatype = GPU_DATA_2F; - break; - case GPU_VEC3: - uniform->datatype = GPU_DATA_3F; - break; - case GPU_VEC4: - uniform->datatype = GPU_DATA_4F; - break; - case GPU_MAT3: - uniform->datatype = GPU_DATA_9F; - break; - case GPU_MAT4: - uniform->datatype = GPU_DATA_16F; - break; - - case GPU_NONE: - case GPU_TEX2D: - case GPU_TEXCUBE: - case GPU_SHADOW2D: - case GPU_ATTRIB: - break; - } - - if (GPU_DYNAMIC_GROUP_FROM_TYPE(uniform->type) == GPU_DYNAMIC_GROUP_LAMP) - uniform->lamp = input->dynamicdata; - - if (GPU_DYNAMIC_GROUP_FROM_TYPE(uniform->type) == GPU_DYNAMIC_GROUP_MAT) - uniform->material = input->dynamicdata; - } - - if (uniform->type != GPU_DYNAMIC_NONE) - BLI_addtail(&shader->uniforms, uniform); - else - MEM_freeN(uniform); - } - - /* process builtin uniform */ - for (int i = 0; builtins[i].gputype; i++) { - if (mat->builtins & builtins[i].gputype) { - GPUInputUniform *uniform = MEM_callocN(sizeof(GPUInputUniform), "GPUInputUniform"); - uniform->type = builtins[i].dynamictype; - uniform->datatype = builtins[i].datatype; - BLI_strncpy(uniform->varname, GPU_builtin_name(builtins[i].gputype), sizeof(uniform->varname)); - BLI_addtail(&shader->uniforms, uniform); - } - } - - /* now link fragment shader with library shader */ - /* TBD: remove the function that are not used in the main function */ - liblen = (pass->libcode) ? strlen(pass->libcode) : 0; - fraglen = strlen(pass->fragmentcode); - shader->fragment = (char *)MEM_mallocN(liblen + fraglen + 1, "GPUFragShader"); - if (pass->libcode) - memcpy(shader->fragment, pass->libcode, liblen); - memcpy(&shader->fragment[liblen], pass->fragmentcode, fraglen); - shader->fragment[liblen + fraglen] = 0; - - // export the attribute - for (int i = 0; i < mat->attribs.totlayer; i++) { - GPUInputAttribute *attribute = MEM_callocN(sizeof(GPUInputAttribute), "GPUInputAttribute"); - attribute->type = mat->attribs.layer[i].type; - attribute->number = mat->attribs.layer[i].glindex; - BLI_snprintf(attribute->varname, sizeof(attribute->varname), "att%d", mat->attribs.layer[i].attribid); - - switch (attribute->type) { - case CD_TANGENT: - attribute->datatype = GPU_DATA_4F; - break; - case CD_MTFACE: - attribute->datatype = GPU_DATA_2F; - attribute->name = mat->attribs.layer[i].name; - break; - case CD_MCOL: - attribute->datatype = GPU_DATA_4UB; - attribute->name = mat->attribs.layer[i].name; - break; - case CD_ORCO: - attribute->datatype = GPU_DATA_3F; - break; - } - - if (attribute->datatype != GPU_DATA_NONE) - BLI_addtail(&shader->attributes, attribute); - else - MEM_freeN(attribute); - } - - /* export the vertex shader */ - shader->vertex = BLI_strdup(pass->vertexcode); - } - - return shader; -} - -void GPU_free_shader_export(GPUShaderExport *shader) -{ - if (shader == NULL) - return; - - for (GPUInputUniform *uniform = shader->uniforms.first; uniform; uniform = uniform->next) - if (uniform->texpixels) - MEM_freeN(uniform->texpixels); - - BLI_freelistN(&shader->uniforms); - BLI_freelistN(&shader->attributes); - - if (shader->vertex) - MEM_freeN(shader->vertex); - if (shader->fragment) - MEM_freeN(shader->fragment); - - MEM_freeN(shader); -} - -#ifdef WITH_OPENSUBDIV -void GPU_material_update_fvar_offset(GPUMaterial *gpu_material, - DerivedMesh *dm) -{ - GPUPass *pass = gpu_material->pass; - GPUShader *shader = (pass != NULL ? pass->shader : NULL); - ListBase *inputs = (pass != NULL ? &pass->inputs : NULL); - GPUInput *input; - - if (shader == NULL) { - return; - } - - GPU_shader_bind(shader); - - for (input = inputs->first; - input != NULL; - input = input->next) - { - if (input->source == GPU_SOURCE_ATTRIB && - input->attribtype == CD_MTFACE) - { - char name[64]; - /* TODO(sergey): This will work for until names are - * consistent, we'll need to solve this somehow in the future. - */ - int layer_index; - int location; - - if (input->attribname[0] != '\0') { - layer_index = CustomData_get_named_layer(&dm->loopData, - CD_MLOOPUV, - input->attribname); - } - else { - layer_index = CustomData_get_active_layer(&dm->loopData, - CD_MLOOPUV); - } - - BLI_snprintf(name, sizeof(name), - "fvar%d_offset", - input->attribid); - location = GPU_shader_get_uniform(shader, name); - GPU_shader_uniform_int(shader, location, layer_index); - } - } - - GPU_shader_unbind(); -} -#endif diff --git a/source/blender/gpu/intern/gpu_matrix.c b/source/blender/gpu/intern/gpu_matrix.c new file mode 100644 index 00000000000..b6214f2778b --- /dev/null +++ b/source/blender/gpu/intern/gpu_matrix.c @@ -0,0 +1,649 @@ +/* + * ***** 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 ipmlied 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) 2012 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Alexandr Kuznetsov, Jason Wilkins, Mike Erwin + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file source/blender/gpu/intern/gpu_matrix.c + * \ingroup gpu + */ + +#include "../../../intern/gawain/gawain/gwn_shader_interface.h" + +#define SUPPRESS_GENERIC_MATRIX_API +#define USE_GPU_PY_MATRIX_API /* only so values are declared */ +#include "GPU_matrix.h" +#undef USE_GPU_PY_MATRIX_API + +#include "BLI_math_matrix.h" +#include "BLI_math_rotation.h" +#include "BLI_math_vector.h" + + +#define DEBUG_MATRIX_BIND 0 + +#define MATRIX_STACK_DEPTH 32 + +typedef float Mat4[4][4]; +typedef float Mat3[3][3]; + +typedef struct MatrixStack { + Mat4 stack[MATRIX_STACK_DEPTH]; + unsigned int top; +} MatrixStack; + +typedef struct { + MatrixStack model_view_stack; + MatrixStack projection_stack; + + bool dirty; + + /* TODO: cache of derived matrices (Normal, MVP, inverse MVP, etc) + * generate as needed for shaders, invalidate when original matrices change + * + * TODO: separate Model from View transform? Batches/objects have model, + * camera/eye has view & projection + */ +} MatrixState; + +#define MATRIX_4X4_IDENTITY {{1.0f, 0.0f, 0.0f, 0.0f}, \ + {0.0f, 1.0f, 0.0f, 0.0f}, \ + {0.0f, 0.0f, 1.0f, 0.0f}, \ + {0.0f, 0.0f, 0.0f, 1.0f}} + +static MatrixState state = { + .model_view_stack = {{MATRIX_4X4_IDENTITY}, 0}, + .projection_stack = {{MATRIX_4X4_IDENTITY}, 0}, + .dirty = true +}; + +#undef MATRIX_4X4_IDENTITY + +#define ModelViewStack state.model_view_stack +#define ModelView ModelViewStack.stack[ModelViewStack.top] + +#define ProjectionStack state.projection_stack +#define Projection ProjectionStack.stack[ProjectionStack.top] + +void gpuMatrixReset(void) +{ + state.model_view_stack.top = 0; + state.projection_stack.top = 0; + unit_m4(ModelView); + unit_m4(Projection); + state.dirty = true; +} + +#ifdef WITH_GPU_SAFETY + +/* Check if matrix is numerically good */ +static void checkmat(cosnt float *m) +{ + const int n = 16; + for (int i = 0; i < n; i++) { +#if _MSC_VER + BLI_assert(_finite(m[i])); +#else + BLI_assert(!isinf(m[i])); +#endif + } +} + +#define CHECKMAT(m) checkmat((const float*)m) + +#else + +#define CHECKMAT(m) + +#endif + + +void gpuPushMatrix(void) +{ + BLI_assert(ModelViewStack.top + 1 < MATRIX_STACK_DEPTH); + ModelViewStack.top++; + copy_m4_m4(ModelView, ModelViewStack.stack[ModelViewStack.top - 1]); +} + +void gpuPopMatrix(void) +{ + BLI_assert(ModelViewStack.top > 0); + ModelViewStack.top--; + state.dirty = true; +} + +void gpuPushProjectionMatrix(void) +{ + BLI_assert(ProjectionStack.top + 1 < MATRIX_STACK_DEPTH); + ProjectionStack.top++; + copy_m4_m4(Projection, ProjectionStack.stack[ProjectionStack.top - 1]); +} + +void gpuPopProjectionMatrix(void) +{ + BLI_assert(ProjectionStack.top > 0); + ProjectionStack.top--; + state.dirty = true; +} + +void gpuLoadMatrix(const float m[4][4]) +{ + copy_m4_m4(ModelView, m); + CHECKMAT(ModelView3D); + state.dirty = true; +} + +void gpuLoadIdentityProjectionMatrix(void) +{ + unit_m4(Projection); + CHECKMAT(Projection3D); + state.dirty = true; +} + +void gpuLoadProjectionMatrix(const float m[4][4]) +{ + copy_m4_m4(Projection, m); + CHECKMAT(Projection3D); + state.dirty = true; +} + +void gpuLoadIdentity(void) +{ + unit_m4(ModelView); + state.dirty = true; +} + +void gpuTranslate2f(float x, float y) +{ + Mat4 m; + unit_m4(m); + m[3][0] = x; + m[3][1] = y; + gpuMultMatrix(m); +} + +void gpuTranslate2fv(const float vec[2]) +{ + gpuTranslate2f(vec[0], vec[1]); +} + +void gpuTranslate3f(float x, float y, float z) +{ +#if 1 + translate_m4(ModelView, x, y, z); + CHECKMAT(ModelView); +#else /* above works well in early testing, below is generic version */ + Mat4 m; + unit_m4(m); + m[3][0] = x; + m[3][1] = y; + m[3][2] = z; + gpuMultMatrix(m); +#endif + state.dirty = true; +} + +void gpuTranslate3fv(const float vec[3]) +{ + gpuTranslate3f(vec[0], vec[1], vec[2]); +} + +void gpuScaleUniform(float factor) +{ + Mat4 m; + scale_m4_fl(m, factor); + gpuMultMatrix(m); +} + +void gpuScale2f(float x, float y) +{ + Mat4 m = {{0.0f}}; + m[0][0] = x; + m[1][1] = y; + m[2][2] = 1.0f; + m[3][3] = 1.0f; + gpuMultMatrix(m); +} + +void gpuScale2fv(const float vec[2]) +{ + gpuScale2f(vec[0], vec[1]); +} + +void gpuScale3f(float x, float y, float z) +{ + Mat4 m = {{0.0f}}; + m[0][0] = x; + m[1][1] = y; + m[2][2] = z; + m[3][3] = 1.0f; + gpuMultMatrix(m); +} + +void gpuScale3fv(const float vec[3]) +{ + gpuScale3f(vec[0], vec[1], vec[2]); +} + +void gpuMultMatrix(const float m[4][4]) +{ + mul_m4_m4_post(ModelView, m); + CHECKMAT(ModelView); + state.dirty = true; +} + +void gpuRotate2D(float deg) +{ + /* essentially RotateAxis('Z') + * TODO: simpler math for 2D case + */ + rotate_m4(ModelView, 'Z', DEG2RADF(deg)); +} + +void gpuRotate3f(float deg, float x, float y, float z) +{ + const float axis[3] = {x, y, z}; + gpuRotate3fv(deg, axis); +} + +void gpuRotate3fv(float deg, const float axis[3]) +{ + Mat4 m; + axis_angle_to_mat4(m, axis, DEG2RADF(deg)); + gpuMultMatrix(m); +} + +void gpuRotateAxis(float deg, char axis) +{ + /* rotate_m4 works in place */ + rotate_m4(ModelView, axis, DEG2RADF(deg)); + CHECKMAT(ModelView); + state.dirty = true; +} + +static void mat4_ortho_set(float m[4][4], float left, float right, float bottom, float top, float near, float far) +{ + m[0][0] = 2.0f / (right - left); + m[1][0] = 0.0f; + m[2][0] = 0.0f; + m[3][0] = -(right + left) / (right - left); + + m[0][1] = 0.0f; + m[1][1] = 2.0f / (top - bottom); + m[2][1] = 0.0f; + m[3][1] = -(top + bottom) / (top - bottom); + + m[0][2] = 0.0f; + m[1][2] = 0.0f; + m[2][2] = -2.0f / (far - near); + m[3][2] = -(far + near) / (far - near); + + m[0][3] = 0.0f; + m[1][3] = 0.0f; + m[2][3] = 0.0f; + m[3][3] = 1.0f; + + state.dirty = true; +} + +static void mat4_frustum_set(float m[4][4], float left, float right, float bottom, float top, float near, float far) +{ + m[0][0] = 2.0f * near / (right - left); + m[1][0] = 0.0f; + m[2][0] = (right + left) / (right - left); + m[3][0] = 0.0f; + + m[0][1] = 0.0f; + m[1][1] = 2.0f * near / (top - bottom); + m[2][1] = (top + bottom) / (top - bottom); + m[3][1] = 0.0f; + + m[0][2] = 0.0f; + m[1][2] = 0.0f; + m[2][2] = -(far + near) / (far - near); + m[3][2] = -2.0f * far * near / (far - near); + + m[0][3] = 0.0f; + m[1][3] = 0.0f; + m[2][3] = -1.0f; + m[3][3] = 0.0f; + + state.dirty = true; +} + +static void mat4_look_from_origin(float m[4][4], float lookdir[3], float camup[3]) +{ +/* This function is loosely based on Mesa implementation. + * + * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) + * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice including the dates of first publication and + * either this permission notice or a reference to + * http://oss.sgi.com/projects/FreeB/ + * shall be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF + * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * Except as contained in this notice, the name of Silicon Graphics, Inc. + * shall not be used in advertising or otherwise to promote the sale, use or + * other dealings in this Software without prior written authorization from + * Silicon Graphics, Inc. + */ + + float side[3]; + + normalize_v3(lookdir); + + cross_v3_v3v3(side, lookdir, camup); + + normalize_v3(side); + + cross_v3_v3v3(camup, side, lookdir); + + m[0][0] = side[0]; + m[1][0] = side[1]; + m[2][0] = side[2]; + m[3][0] = 0.0f; + + m[0][1] = camup[0]; + m[1][1] = camup[1]; + m[2][1] = camup[2]; + m[3][1] = 0.0f; + + m[0][2] = -lookdir[0]; + m[1][2] = -lookdir[1]; + m[2][2] = -lookdir[2]; + m[3][2] = 0.0f; + + m[0][3] = 0.0f; + m[1][3] = 0.0f; + m[2][3] = 0.0f; + m[3][3] = 1.0f; + + state.dirty = true; +} + +void gpuOrtho(float left, float right, float bottom, float top, float near, float far) +{ + mat4_ortho_set(Projection, left, right, bottom, top, near, far); + CHECKMAT(Projection); + state.dirty = true; +} + +void gpuOrtho2D(float left, float right, float bottom, float top) +{ + Mat4 m; + mat4_ortho_set(m, left, right, bottom, top, -1.0f, 1.0f); + CHECKMAT(Projection2D); + state.dirty = true; +} + +void gpuFrustum(float left, float right, float bottom, float top, float near, float far) +{ + mat4_frustum_set(Projection, left, right, bottom, top, near, far); + CHECKMAT(Projection); + state.dirty = true; +} + +void gpuPerspective(float fovy, float aspect, float near, float far) +{ + float half_height = tanf(fovy * (float)(M_PI / 360.0)) * near; + float half_width = half_height * aspect; + gpuFrustum(-half_width, +half_width, -half_height, +half_height, near, far); +} + +void gpuLookAt(float eyeX, float eyeY, float eyeZ, float centerX, float centerY, float centerZ, float upX, float upY, float upZ) +{ + Mat4 cm; + float lookdir[3]; + float camup[3] = {upX, upY, upZ}; + + lookdir[0] = centerX - eyeX; + lookdir[1] = centerY - eyeY; + lookdir[2] = centerZ - eyeZ; + + mat4_look_from_origin(cm, lookdir, camup); + + gpuMultMatrix(cm); + gpuTranslate3f(-eyeX, -eyeY, -eyeZ); +} + +void gpuProject(const float world[3], const float model[4][4], const float proj[4][4], const int view[4], float win[3]) +{ + float v[4]; + + mul_v4_m4v3(v, model, world); + mul_m4_v4(proj, v); + + if (v[3] != 0.0f) { + mul_v3_fl(v, 1.0f / v[3]); + } + + win[0] = view[0] + (view[2] * (v[0] + 1)) * 0.5f; + win[1] = view[1] + (view[3] * (v[1] + 1)) * 0.5f; + win[2] = (v[2] + 1) * 0.5f; +} + +bool gpuUnProject(const float win[3], const float model[4][4], const float proj[4][4], const int view[4], float world[3]) +{ + float pm[4][4]; + float in[4]; + float out[4]; + + mul_m4_m4m4(pm, proj, model); + + if (!invert_m4(pm)) { + zero_v3(world); + return false; + } + + in[0] = win[0]; + in[1] = win[1]; + in[2] = win[2]; + in[3] = 1; + + /* Map x and y from window coordinates */ + in[0] = (in[0] - view[0]) / view[2]; + in[1] = (in[1] - view[1]) / view[3]; + + /* Map to range -1 to +1 */ + in[0] = 2 * in[0] - 1; + in[1] = 2 * in[1] - 1; + in[2] = 2 * in[2] - 1; + + mul_v4_m4v3(out, pm, in); + + if (out[3] == 0.0f) { + copy_v3_v3(world, out); + return false; + } + + mul_v3_v3fl(world, out, 1.0f / out[3]); + return true; +} + +const float (*gpuGetModelViewMatrix(float m[4][4]))[4] +{ + if (m) { + copy_m4_m4(m, ModelView); + return m; + } + else { + return ModelView; + } +} + +const float (*gpuGetProjectionMatrix(float m[4][4]))[4] +{ + if (m) { + copy_m4_m4(m, Projection); + return m; + } + else { + return Projection; + } +} + +const float (*gpuGetModelViewProjectionMatrix(float m[4][4]))[4] +{ + if (m == NULL) { + static Mat4 temp; + m = temp; + } + + mul_m4_m4m4(m, Projection, ModelView); + return m; +} + +const float (*gpuGetNormalMatrix(float m[3][3]))[3] +{ + if (m == NULL) { + static Mat3 temp3; + m = temp3; + } + + copy_m3_m4(m, (const float (*)[4])gpuGetModelViewMatrix(NULL)); + + invert_m3(m); + transpose_m3(m); + + return m; +} + +const float (*gpuGetNormalMatrixInverse(float m[3][3]))[3] +{ + if (m == NULL) { + static Mat3 temp3; + m = temp3; + } + + gpuGetNormalMatrix(m); + invert_m3(m); + + return m; +} + +void gpuBindMatrices(const Gwn_ShaderInterface *shaderface) +{ + /* set uniform values to matrix stack values + * call this before a draw call if desired matrices are dirty + * call glUseProgram before this, as glUniform expects program to be bound + */ + + const Gwn_ShaderInput *MV = GWN_shaderinterface_uniform_builtin(shaderface, GWN_UNIFORM_MODELVIEW); + const Gwn_ShaderInput *P = GWN_shaderinterface_uniform_builtin(shaderface, GWN_UNIFORM_PROJECTION); + const Gwn_ShaderInput *MVP = GWN_shaderinterface_uniform_builtin(shaderface, GWN_UNIFORM_MVP); + + const Gwn_ShaderInput *N = GWN_shaderinterface_uniform_builtin(shaderface, GWN_UNIFORM_NORMAL); + const Gwn_ShaderInput *MV_inv = GWN_shaderinterface_uniform_builtin(shaderface, GWN_UNIFORM_MODELVIEW_INV); + const Gwn_ShaderInput *P_inv = GWN_shaderinterface_uniform_builtin(shaderface, GWN_UNIFORM_PROJECTION_INV); + + if (MV) { +#if DEBUG_MATRIX_BIND + puts("setting MV matrix"); +#endif + + glUniformMatrix4fv(MV->location, 1, GL_FALSE, (const float *)gpuGetModelViewMatrix(NULL)); + } + + if (P) { +#if DEBUG_MATRIX_BIND + puts("setting P matrix"); +#endif + + glUniformMatrix4fv(P->location, 1, GL_FALSE, (const float *)gpuGetProjectionMatrix(NULL)); + } + + if (MVP) { +#if DEBUG_MATRIX_BIND + puts("setting MVP matrix"); +#endif + + glUniformMatrix4fv(MVP->location, 1, GL_FALSE, (const float *)gpuGetModelViewProjectionMatrix(NULL)); + } + + if (N) { +#if DEBUG_MATRIX_BIND + puts("setting normal matrix"); +#endif + + glUniformMatrix3fv(N->location, 1, GL_FALSE, (const float *)gpuGetNormalMatrix(NULL)); + } + + if (MV_inv) { + Mat4 m; + gpuGetModelViewMatrix(m); + invert_m4(m); + glUniformMatrix4fv(MV_inv->location, 1, GL_FALSE, (const float *)m); + } + + if (P_inv) { + Mat4 m; + gpuGetProjectionMatrix(m); + invert_m4(m); + glUniformMatrix4fv(P_inv->location, 1, GL_FALSE, (const float *)m); + } + + state.dirty = false; +} + +bool gpuMatricesDirty(void) +{ + return state.dirty; +} + + +/* -------------------------------------------------------------------- */ + +/** \name Python API Helpers + * \{ */ +BLI_STATIC_ASSERT(GPU_PY_MATRIX_STACK_LEN + 1 == MATRIX_STACK_DEPTH, "define mismatch"); + +/* Return int since caller is may subtract. */ + +int GPU_matrix_stack_level_get_model_view(void) +{ + return (int)state.model_view_stack.top; +} + +int GPU_matrix_stack_level_get_projection(void) +{ + return (int)state.projection_stack.top; +} + +/** \} */ diff --git a/source/blender/gpu/intern/gpu_select.c b/source/blender/gpu/intern/gpu_select.c index 291a552a041..7023e44d289 100644 --- a/source/blender/gpu/intern/gpu_select.c +++ b/source/blender/gpu/intern/gpu_select.c @@ -187,12 +187,7 @@ uint GPU_select_end(void) */ bool GPU_select_query_check_active(void) { - return ((U.gpu_select_method == USER_SELECT_USE_OCCLUSION_QUERY) || - ((U.gpu_select_method == USER_SELECT_AUTO) && - (GPU_type_matches(GPU_DEVICE_ATI, GPU_OS_ANY, GPU_DRIVER_ANY) || - /* unsupported by nouveau, gallium 0.4, see: T47940 */ - GPU_type_matches(GPU_DEVICE_NVIDIA, GPU_OS_UNIX, GPU_DRIVER_OPENSOURCE)))); - + return ELEM(U.gpu_select_method, USER_SELECT_USE_OCCLUSION_QUERY, USER_SELECT_AUTO); } /* ---------------------------------------------------------------------------- @@ -232,3 +227,29 @@ bool GPU_select_is_cached(void) { return g_select_state.use_cache && gpu_select_pick_is_cached(); } + + +/* ---------------------------------------------------------------------------- + * Utilities + */ + +/** + * Helper function, nothing special but avoids doing inline since hit's aren't sorted by depth + * and purpose of 4x buffer indices isn't so clear. + * + * Note that comparing depth as uint is fine. + */ +const uint *GPU_select_buffer_near(const uint *buffer, int hits) +{ + const uint *buffer_near = NULL; + uint depth_min = (uint)-1; + for (int i = 0; i < hits; i++) { + if (buffer[1] < depth_min) { + BLI_assert(buffer[3] != -1); + depth_min = buffer[1]; + buffer_near = buffer; + } + buffer += 4; + } + return buffer_near; +} diff --git a/source/blender/gpu/intern/gpu_select_pick.c b/source/blender/gpu/intern/gpu_select_pick.c index 3e65e2987e6..953f6daf805 100644 --- a/source/blender/gpu/intern/gpu_select_pick.c +++ b/source/blender/gpu/intern/gpu_select_pick.c @@ -31,6 +31,8 @@ #include <stdlib.h> #include <float.h> +#include "GPU_immediate.h" +#include "GPU_draw.h" #include "GPU_select.h" #include "GPU_extensions.h" #include "GPU_glew.h" @@ -316,8 +318,8 @@ void gpu_select_pick_begin( /* Restrict OpenGL operations for when we don't have cache */ if (ps->is_cached == false) { + gpuPushAttrib(GPU_DEPTH_BUFFER_BIT | GPU_VIEWPORT_BIT); - glPushAttrib(GL_DEPTH_BUFFER_BIT | GL_VIEWPORT_BIT); /* disable writing to the framebuffer */ glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); @@ -334,12 +336,8 @@ void gpu_select_pick_begin( glDepthFunc(GL_LEQUAL); } - /* set just in case */ - glPixelTransferf(GL_DEPTH_BIAS, 0.0); - glPixelTransferf(GL_DEPTH_SCALE, 1.0); - float viewport[4]; - glGetFloatv(GL_SCISSOR_BOX, viewport); + glGetFloatv(GL_VIEWPORT, viewport); ps->src.clip_rect = *input; ps->src.rect_len = rect_len; @@ -542,7 +540,7 @@ uint gpu_select_pick_end(void) /* force finishing last pass */ gpu_select_pick_load_id(ps->gl.prev_id); } - glPopAttrib(); + gpuPopAttrib(); glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); } diff --git a/source/blender/gpu/intern/gpu_select_sample_query.c b/source/blender/gpu/intern/gpu_select_sample_query.c index 9bb96ea67a2..919ccbea2e9 100644 --- a/source/blender/gpu/intern/gpu_select_sample_query.c +++ b/source/blender/gpu/intern/gpu_select_sample_query.c @@ -32,6 +32,8 @@ #include <stdlib.h> +#include "GPU_immediate.h" +#include "GPU_draw.h" #include "GPU_select.h" #include "GPU_extensions.h" #include "GPU_glew.h" @@ -42,6 +44,8 @@ #include "BLI_utildefines.h" +#include "PIL_time.h" + #include "gpu_select_private.h" @@ -94,15 +98,15 @@ 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); - glPushAttrib(GL_DEPTH_BUFFER_BIT | GL_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); /* In order to save some fill rate we minimize the viewport using rect. - * We need to get the region of the scissor so that our geometry doesn't + * We need to get the region of the viewport so that our geometry doesn't * get rejected before the depth test. Should probably cull rect against - * scissor for viewport but this is a rare case I think */ - glGetFloatv(GL_SCISSOR_BOX, viewport); + * the viewport but this is a rare case I think */ + glGetFloatv(GL_VIEWPORT, viewport); glViewport(viewport[0], viewport[1], BLI_rcti_size_x(input), BLI_rcti_size_y(input)); /* occlusion queries operates on fragments that pass tests and since we are interested on all @@ -171,7 +175,16 @@ uint gpu_select_query_end(void) } for (i = 0; i < g_query_state.active_query; i++) { - uint 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) { @@ -206,7 +219,7 @@ uint gpu_select_query_end(void) glDeleteQueries(g_query_state.num_of_queries, g_query_state.queries); MEM_freeN(g_query_state.queries); MEM_freeN(g_query_state.id); - glPopAttrib(); + gpuPopAttrib(); glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); return hits; diff --git a/source/blender/gpu/intern/gpu_shader.c b/source/blender/gpu/intern/gpu_shader.c index b579f87698c..2068c5a6a75 100644 --- a/source/blender/gpu/intern/gpu_shader.c +++ b/source/blender/gpu/intern/gpu_shader.c @@ -30,22 +30,129 @@ #include "BLI_utildefines.h" #include "BLI_math_base.h" #include "BLI_math_vector.h" +#include "BLI_path_util.h" +#include "BKE_appdir.h" #include "BKE_global.h" -#include "GPU_compositing.h" -#include "GPU_debug.h" +#include "DNA_space_types.h" + #include "GPU_extensions.h" -#include "GPU_glew.h" +#include "GPU_matrix.h" #include "GPU_shader.h" #include "GPU_texture.h" -#include "GPU_material.h" +#include "GPU_uniformbuffer.h" + +#include "gpu_shader_private.h" -/* TODO(sergey): Find better default values for this constants. */ -#define MAX_DEFINE_LENGTH 1024 -#define MAX_EXT_DEFINE_LENGTH 1024 +/* Adjust these constants as needed. */ +#define MAX_DEFINE_LENGTH 256 +#define MAX_EXT_DEFINE_LENGTH 256 /* Non-generated shaders */ +extern char datatoc_gpu_shader_depth_only_frag_glsl[]; +extern char datatoc_gpu_shader_uniform_color_frag_glsl[]; +extern char datatoc_gpu_shader_checker_frag_glsl[]; +extern char datatoc_gpu_shader_diag_stripes_frag_glsl[]; +extern char datatoc_gpu_shader_simple_lighting_frag_glsl[]; +extern char datatoc_gpu_shader_simple_lighting_flat_color_frag_glsl[]; +extern char datatoc_gpu_shader_simple_lighting_smooth_color_frag_glsl[]; +extern char datatoc_gpu_shader_simple_lighting_smooth_color_alpha_frag_glsl[]; +extern char datatoc_gpu_shader_flat_color_frag_glsl[]; +extern char datatoc_gpu_shader_flat_color_alpha_test_0_frag_glsl[]; +extern char datatoc_gpu_shader_flat_id_frag_glsl[]; +extern char datatoc_gpu_shader_2D_vert_glsl[]; +extern char datatoc_gpu_shader_2D_flat_color_vert_glsl[]; +extern char datatoc_gpu_shader_2D_smooth_color_uniform_alpha_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_smooth_color_dithered_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_desaturate_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_depth_linear_frag_glsl[]; +extern char datatoc_gpu_shader_image_depth_copy_frag_glsl[]; +extern char datatoc_gpu_shader_image_multisample_resolve_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[]; +extern char datatoc_gpu_shader_3D_smooth_color_vert_glsl[]; +extern char datatoc_gpu_shader_3D_normal_flat_color_vert_glsl[]; +extern char datatoc_gpu_shader_3D_normal_smooth_color_vert_glsl[]; +extern char datatoc_gpu_shader_3D_smooth_color_frag_glsl[]; +extern char datatoc_gpu_shader_3D_passthrough_vert_glsl[]; +extern char datatoc_gpu_shader_3D_clipped_uniform_color_vert_glsl[]; + +extern char datatoc_gpu_shader_instance_vert_glsl[]; +extern char datatoc_gpu_shader_instance_variying_size_variying_color_vert_glsl[]; +extern char datatoc_gpu_shader_instance_variying_size_variying_id_vert_glsl[]; +extern char datatoc_gpu_shader_instance_objectspace_variying_color_vert_glsl[]; +extern char datatoc_gpu_shader_instance_screenspace_variying_color_vert_glsl[]; +extern char datatoc_gpu_shader_instance_screen_aligned_vert_glsl[]; +extern char datatoc_gpu_shader_instance_camera_vert_glsl[]; +extern char datatoc_gpu_shader_instance_distance_line_vert_glsl[]; +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_mball_handles_vert_glsl[]; + +extern char datatoc_gpu_shader_3D_groundpoint_vert_glsl[]; +extern char datatoc_gpu_shader_3D_groundline_geom_glsl[]; + +extern char datatoc_gpu_shader_point_uniform_color_frag_glsl[]; +extern char datatoc_gpu_shader_point_uniform_color_aa_frag_glsl[]; +extern char datatoc_gpu_shader_point_uniform_color_outline_aa_frag_glsl[]; +extern char datatoc_gpu_shader_point_varying_color_outline_aa_frag_glsl[]; +extern char datatoc_gpu_shader_point_varying_color_frag_glsl[]; +extern char datatoc_gpu_shader_3D_point_fixed_size_varying_color_vert_glsl[]; +extern char datatoc_gpu_shader_3D_point_varying_size_vert_glsl[]; +extern char datatoc_gpu_shader_3D_point_varying_size_varying_color_vert_glsl[]; +extern char datatoc_gpu_shader_3D_point_uniform_size_aa_vert_glsl[]; +extern char datatoc_gpu_shader_3D_point_uniform_size_outline_aa_vert_glsl[]; +extern char datatoc_gpu_shader_2D_point_varying_size_varying_color_vert_glsl[]; +extern char datatoc_gpu_shader_2D_point_uniform_size_aa_vert_glsl[]; +extern char datatoc_gpu_shader_2D_point_uniform_size_outline_aa_vert_glsl[]; +extern char datatoc_gpu_shader_2D_point_uniform_size_varying_color_outline_aa_vert_glsl[]; + +extern char datatoc_gpu_shader_2D_line_dashed_uniform_color_vert_glsl[]; +extern char datatoc_gpu_shader_2D_line_dashed_frag_glsl[]; +extern char datatoc_gpu_shader_2D_line_dashed_geom_glsl[]; +extern char datatoc_gpu_shader_3D_line_dashed_uniform_color_legacy_vert_glsl[]; +extern char datatoc_gpu_shader_3D_line_dashed_uniform_color_vert_glsl[]; + +extern char datatoc_gpu_shader_edges_front_back_persp_vert_glsl[]; +extern char datatoc_gpu_shader_edges_front_back_persp_geom_glsl[]; +extern char datatoc_gpu_shader_edges_front_back_persp_legacy_vert_glsl[]; +extern char datatoc_gpu_shader_edges_front_back_ortho_vert_glsl[]; +extern char datatoc_gpu_shader_edges_overlay_vert_glsl[]; +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[]; + extern char datatoc_gpu_shader_fire_frag_glsl[]; extern char datatoc_gpu_shader_smoke_vert_glsl[]; extern char datatoc_gpu_shader_smoke_frag_glsl[]; @@ -53,51 +160,23 @@ 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_fx_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[]; - -static struct GPUShadersGlobal { - struct { - GPUShader *vsm_store; - GPUShader *sep_gaussian_blur; - GPUShader *smoke; - GPUShader *smoke_fire; - GPUShader *smoke_coba; - /* cache for shader fx. Those can exist in combinations so store them here */ - GPUShader *fx_shaders[MAX_FX_SHADERS * 2]; - } shaders; -} GG = {{NULL}}; - -/* GPUShader */ - -struct GPUShader { - GLuint program; /* handle for full program (links shader stages below) */ - - GLuint vertex; /* handle for vertex shader */ - GLuint geometry; /* handle for geometry shader */ - GLuint fragment; /* handle for fragment shader */ - - int totattrib; /* total number of attributes */ - int uniforms; /* required uniforms */ - - void *uniform_interface; /* cached uniform interface for shader. Data depends on shader */ -}; + +/* cache of built-in shaders (each is created on first use) */ +static GPUShader *builtin_shaders[GPU_NUM_BUILTIN_SHADERS] = { NULL }; + +typedef struct { + const char *vert; + const char *frag; + const char *geom; /* geometry stage runs between vert & frag, but is less common, so it goes last */ +} GPUShaderStages; static void shader_print_errors(const char *task, const char *log, const char **code, int totcode) { - int i; int line = 1; fprintf(stderr, "GPUShader: %s error:\n", task); - for (i = 0; i < totcode; i++) { + for (int i = 0; i < totcode; i++) { const char *c, *pos, *end = code[i] + strlen(code[i]); if (G.debug & G_DEBUG) { @@ -120,76 +199,23 @@ static void shader_print_errors(const char *task, const char *log, const char ** static const char *gpu_shader_version(void) { - if (GLEW_VERSION_3_2) { - if (GLEW_ARB_compatibility) { - return "#version 150 compatibility\n"; - /* highest version that is widely supported - * gives us native geometry shaders! - * use compatibility profile so we can continue using builtin shader input/output names - */ - } - else { - return "#version 130\n"; - /* latest version that is compatible with existing shaders */ - } - } - else if (GLEW_VERSION_3_1) { - if (GLEW_ARB_compatibility) { - return "#version 140\n"; - /* also need the ARB_compatibility extension, handled below */ - } - else { - return "#version 130\n"; - /* latest version that is compatible with existing shaders */ - } - } - else if (GLEW_VERSION_3_0) { - return "#version 130\n"; - /* GLSL 1.3 has modern syntax/keywords/datatypes so use if available - * older features are deprecated but still available without compatibility extension or profile - */ - } - else { - return "#version 120\n"; - /* minimum supported */ - } + return "#version 330\n"; } - -static void gpu_shader_standard_extensions(char defines[MAX_EXT_DEFINE_LENGTH], bool use_geometry_shader) +static void gpu_shader_standard_extensions(char defines[MAX_EXT_DEFINE_LENGTH]) { /* enable extensions for features that are not part of our base GLSL version * don't use an extension for something already available! */ if (GLEW_ARB_texture_query_lod) { - /* a #version 400 feature, but we use #version 150 maximum so use extension */ + /* a #version 400 feature, but we use #version 330 maximum so use extension */ strcat(defines, "#extension GL_ARB_texture_query_lod: enable\n"); } - - if (use_geometry_shader && GPU_geometry_shader_support_via_extension()) { - strcat(defines, "#extension GL_EXT_geometry_shader4: enable\n"); - } - - if (GLEW_VERSION_3_1 && !GLEW_VERSION_3_2 && GLEW_ARB_compatibility) { - strcat(defines, "#extension GL_ARB_compatibility: enable\n"); - } - - if (!GLEW_VERSION_3_1) { - if (GLEW_ARB_draw_instanced) { - strcat(defines, "#extension GL_ARB_draw_instanced: enable\n"); - } - - if (!GLEW_VERSION_3_0 && GLEW_EXT_gpu_shader4) { - strcat(defines, "#extension GL_EXT_gpu_shader4: enable\n"); - /* TODO: maybe require this? shaders become so much nicer */ - } - } } static void gpu_shader_standard_defines(char defines[MAX_DEFINE_LENGTH], - bool use_opensubdiv, - bool use_new_shading) + bool use_opensubdiv) { /* some useful defines to detect GPU type */ if (GPU_type_matches(GPU_DEVICE_ATI, GPU_OS_ANY, GPU_DRIVER_ANY)) { @@ -207,10 +233,6 @@ static void gpu_shader_standard_defines(char defines[MAX_DEFINE_LENGTH], if (GPU_bicubic_bump_support()) strcat(defines, "#define BUMP_BICUBIC\n"); - if (GLEW_VERSION_3_0) { - strcat(defines, "#define BIT_OPERATIONS\n"); - } - #ifdef WITH_OPENSUBDIV /* TODO(sergey): Check whether we actually compiling shader for * the OpenSubdiv mesh. @@ -232,10 +254,6 @@ static void gpu_shader_standard_defines(char defines[MAX_DEFINE_LENGTH], UNUSED_VARS(use_opensubdiv); #endif - if (use_new_shading) { - strcat(defines, "#define USE_NEW_SHADING\n"); - } - return; } @@ -243,20 +261,64 @@ GPUShader *GPU_shader_create(const char *vertexcode, const char *fragcode, const char *geocode, const char *libcode, - const char *defines, - int input, - int output, - int number) + const char *defines) { return GPU_shader_create_ex(vertexcode, fragcode, geocode, libcode, defines, - input, - output, - number, - GPU_SHADER_FLAGS_NONE); + GPU_SHADER_FLAGS_NONE, + GPU_SHADER_TFB_NONE, + NULL, + 0); +} + +#define DEBUG_SHADER_NONE "" +#define DEBUG_SHADER_VERTEX "vert" +#define DEBUG_SHADER_FRAGMENT "frag" +#define DEBUG_SHADER_GEOMETRY "geom" + +/** + * Dump GLSL shaders to disk + * + * This is used for profiling shader performance externally and debug if shader code is correct. + * If called with no code, it simply bumps the shader index, so different shaders for the same + * program share the same index. + */ +static void gpu_dump_shaders(const char **code, const int num_shaders, const char *extension) +{ + if ((G.debug & G_DEBUG_GPU_SHADERS) == 0) { + return; + } + + /* We use the same shader index for shaders in the same program. + * So we call this function once before calling for the invidual shaders. */ + static int shader_index = 0; + if (code == NULL) { + shader_index++; + BLI_assert(STREQ(DEBUG_SHADER_NONE, extension)); + return; + } + + /* Determine the full path of the new shader. */ + char shader_path[FILE_MAX]; + + char file_name[512] = {'\0'}; + sprintf(file_name, "%04d.%s", shader_index, extension); + + BLI_join_dirfile(shader_path, sizeof(shader_path), BKE_tempdir_session(), file_name); + + /* Write shader to disk. */ + FILE *f = fopen(shader_path, "w"); + if (f == NULL) { + printf("Error writing to file: %s\n", shader_path); + } + for (int j = 0; j < num_shaders; j++) { + fprintf(f, "%s", code[j]); + } + fclose(f); + printf("Shader file written to disk: %s\n", shader_path); } GPUShader *GPU_shader_create_ex(const char *vertexcode, @@ -264,16 +326,12 @@ GPUShader *GPU_shader_create_ex(const char *vertexcode, const char *geocode, const char *libcode, const char *defines, - int input, - int output, - int number, - const int flags) + const int flags, + const GPUShaderTFBType tf_type, + const char **tf_names, + const int tf_count) { #ifdef WITH_OPENSUBDIV - /* TODO(sergey): used to add #version 150 to the geometry shader. - * Could safely be renamed to "use_geometry_code" since it's very - * likely any of geometry code will want to use GLSL 1.5. - */ bool use_opensubdiv = (flags & GPU_SHADER_FLAGS_SPECIAL_OPENSUBDIV) != 0; #else UNUSED_VARS(flags); @@ -286,10 +344,8 @@ GPUShader *GPU_shader_create_ex(const char *vertexcode, char standard_defines[MAX_DEFINE_LENGTH] = ""; char standard_extensions[MAX_EXT_DEFINE_LENGTH] = ""; - if (geocode && !GPU_geometry_shader_support()) - return NULL; - shader = MEM_callocN(sizeof(GPUShader), "GPUShader"); + gpu_dump_shaders(NULL, 0, DEBUG_SHADER_NONE); if (vertexcode) shader->vertex = glCreateShader(GL_VERTEX_SHADER); @@ -311,9 +367,8 @@ GPUShader *GPU_shader_create_ex(const char *vertexcode, } gpu_shader_standard_defines(standard_defines, - use_opensubdiv, - (flags & GPU_SHADER_FLAGS_NEW_SHADING) != 0); - gpu_shader_standard_extensions(standard_extensions, geocode != NULL); + use_opensubdiv); + gpu_shader_standard_extensions(standard_extensions); if (vertexcode) { const char *source[5]; @@ -327,6 +382,8 @@ GPUShader *GPU_shader_create_ex(const char *vertexcode, if (defines) source[num_source++] = defines; source[num_source++] = vertexcode; + gpu_dump_shaders(source, num_source, DEBUG_SHADER_VERTEX); + glAttachShader(shader->program, shader->vertex); glShaderSource(shader->vertex, num_source, source, NULL); @@ -366,6 +423,8 @@ GPUShader *GPU_shader_create_ex(const char *vertexcode, if (libcode) source[num_source++] = libcode; source[num_source++] = fragcode; + gpu_dump_shaders(source, num_source, DEBUG_SHADER_FRAGMENT); + glAttachShader(shader->program, shader->fragment); glShaderSource(shader->fragment, num_source, source, NULL); @@ -392,6 +451,8 @@ GPUShader *GPU_shader_create_ex(const char *vertexcode, if (defines) source[num_source++] = defines; source[num_source++] = geocode; + gpu_dump_shaders(source, num_source, DEBUG_SHADER_GEOMETRY); + glAttachShader(shader->program, shader->geometry); glShaderSource(shader->geometry, num_source, source, NULL); @@ -405,23 +466,22 @@ GPUShader *GPU_shader_create_ex(const char *vertexcode, GPU_shader_free(shader); return NULL; } - - if (!use_opensubdiv) { - GPU_shader_geometry_stage_primitive_io(shader, input, output, number); - } } #ifdef WITH_OPENSUBDIV if (use_opensubdiv) { glBindAttribLocation(shader->program, 0, "position"); glBindAttribLocation(shader->program, 1, "normal"); - GPU_shader_geometry_stage_primitive_io(shader, - GL_LINES_ADJACENCY_EXT, - GL_TRIANGLE_STRIP, - 4); } #endif + if (tf_names != NULL) { + glTransformFeedbackVaryings(shader->program, tf_count, tf_names, GL_INTERLEAVED_ATTRIBS); + /* Primitive type must be setup */ + BLI_assert(tf_type != GPU_SHADER_TFB_NONE); + shader->feedback_transform_type = tf_type; + } + glLinkProgram(shader->program); glGetProgramiv(shader->program, GL_LINK_STATUS, &status); if (!status) { @@ -436,38 +496,75 @@ GPUShader *GPU_shader_create_ex(const char *vertexcode, return NULL; } + shader->interface = GWN_shaderinterface_create(shader->program); + #ifdef WITH_OPENSUBDIV /* TODO(sergey): Find a better place for this. */ - if (use_opensubdiv && GLEW_VERSION_4_1) { - glProgramUniform1i(shader->program, - glGetUniformLocation(shader->program, "FVarDataOffsetBuffer"), - 30); /* GL_TEXTURE30 */ - - glProgramUniform1i(shader->program, - glGetUniformLocation(shader->program, "FVarDataBuffer"), - 31); /* GL_TEXTURE31 */ + if (use_opensubdiv) { + if (GLEW_VERSION_4_1) { + glProgramUniform1i(shader->program, + GWN_shaderinterface_uniform(shader->interface, "FVarDataOffsetBuffer")->location, + 30); /* GL_TEXTURE30 */ + + glProgramUniform1i(shader->program, + GWN_shaderinterface_uniform(shader->interface, "FVarDataBuffer")->location, + 31); /* GL_TEXTURE31 */ + } + else { + glUseProgram(shader->program); + glUniform1i(GWN_shaderinterface_uniform(shader->interface, "FVarDataOffsetBuffer")->location, 30); + glUniform1i(GWN_shaderinterface_uniform(shader->interface, "FVarDataBuffer")->location, 31); + glUseProgram(0); + } } #endif return shader; } +#undef DEBUG_SHADER_GEOMETRY +#undef DEBUG_SHADER_FRAGMENT +#undef DEBUG_SHADER_VERTEX +#undef DEBUG_SHADER_NONE + void GPU_shader_bind(GPUShader *shader) { - GPU_ASSERT_NO_GL_ERRORS("Pre Shader Bind"); + BLI_assert(shader && shader->program); + glUseProgram(shader->program); - GPU_ASSERT_NO_GL_ERRORS("Post Shader Bind"); + gpuBindMatrices(shader->interface); } void GPU_shader_unbind(void) { - GPU_ASSERT_NO_GL_ERRORS("Pre Shader Unbind"); glUseProgram(0); - GPU_ASSERT_NO_GL_ERRORS("Post Shader Unbind"); +} + +bool GPU_shader_transform_feedback_enable(GPUShader *shader, unsigned int vbo_id) +{ + if (shader->feedback_transform_type == GPU_SHADER_TFB_NONE) { + return false; + } + + glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, vbo_id); + + switch (shader->feedback_transform_type) { + case GPU_SHADER_TFB_POINTS: glBeginTransformFeedback(GL_POINTS); return true; + case GPU_SHADER_TFB_LINES: glBeginTransformFeedback(GL_LINES); return true; + case GPU_SHADER_TFB_TRIANGLES: glBeginTransformFeedback(GL_TRIANGLES); return true; + default: return false; + } +} + +void GPU_shader_transform_feedback_disable(GPUShader *UNUSED(shader)) +{ + glEndTransformFeedback(); } void GPU_shader_free(GPUShader *shader) { + BLI_assert(shader); + if (shader->vertex) glDeleteShader(shader->vertex); if (shader->geometry) @@ -477,25 +574,43 @@ 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); MEM_freeN(shader); } int GPU_shader_get_uniform(GPUShader *shader, const char *name) { - return glGetUniformLocation(shader->program, name); + BLI_assert(shader && shader->program); + const Gwn_ShaderInput *uniform = GWN_shaderinterface_uniform(shader->interface, name); + return uniform ? uniform->location : -1; +} + +int GPU_shader_get_builtin_uniform(GPUShader *shader, int builtin) +{ + BLI_assert(shader && shader->program); + const Gwn_ShaderInput *uniform = GWN_shaderinterface_uniform_builtin(shader->interface, builtin); + return uniform ? uniform->location : -1; +} + +int GPU_shader_get_uniform_block(GPUShader *shader, const char *name) +{ + BLI_assert(shader && shader->program); + + const Gwn_ShaderInput *ubo = GWN_shaderinterface_ubo(shader->interface, name); + return ubo ? ubo->location : -1; } void *GPU_shader_get_interface(GPUShader *shader) { - return shader->uniform_interface; + return shader->interface; } -void GPU_shader_set_interface(GPUShader *shader, void *interface) +/* Clement : Temp */ +int GPU_shader_get_program(GPUShader *shader) { - shader->uniform_interface = interface; + return (int)shader->program; } void GPU_shader_uniform_vector(GPUShader *UNUSED(shader), int location, int length, int arraysize, const float *value) @@ -503,16 +618,12 @@ void GPU_shader_uniform_vector(GPUShader *UNUSED(shader), int location, int leng if (location == -1 || value == NULL) return; - GPU_ASSERT_NO_GL_ERRORS("Pre Uniform Vector"); - if (length == 1) glUniform1fv(location, arraysize, value); else if (length == 2) glUniform2fv(location, arraysize, value); else if (length == 3) glUniform3fv(location, arraysize, value); else if (length == 4) glUniform4fv(location, arraysize, value); else if (length == 9) glUniformMatrix3fv(location, arraysize, 0, value); else if (length == 16) glUniformMatrix4fv(location, arraysize, 0, value); - - GPU_ASSERT_NO_GL_ERRORS("Post Uniform Vector"); } void GPU_shader_uniform_vector_int(GPUShader *UNUSED(shader), int location, int length, int arraysize, const int *value) @@ -520,14 +631,10 @@ void GPU_shader_uniform_vector_int(GPUShader *UNUSED(shader), int location, int if (location == -1) return; - GPU_ASSERT_NO_GL_ERRORS("Pre Uniform Vector"); - if (length == 1) glUniform1iv(location, arraysize, value); else if (length == 2) glUniform2iv(location, arraysize, value); else if (length == 3) glUniform3iv(location, arraysize, value); else if (length == 4) glUniform4iv(location, arraysize, value); - - GPU_ASSERT_NO_GL_ERRORS("Post Uniform Vector"); } void GPU_shader_uniform_int(GPUShader *UNUSED(shader), int location, int value) @@ -535,225 +642,296 @@ void GPU_shader_uniform_int(GPUShader *UNUSED(shader), int location, int value) if (location == -1) return; - GPU_CHECK_ERRORS_AROUND(glUniform1i(location, value)); + glUniform1i(location, value); } -void GPU_shader_geometry_stage_primitive_io(GPUShader *shader, int input, int output, int number) +void GPU_shader_uniform_buffer(GPUShader *shader, int location, GPUUniformBuffer *ubo) { - if (GPU_geometry_shader_support_via_extension()) { - /* geometry shaders must provide this info themselves for #version 150 and up */ - glProgramParameteriEXT(shader->program, GL_GEOMETRY_INPUT_TYPE_EXT, input); - glProgramParameteriEXT(shader->program, GL_GEOMETRY_OUTPUT_TYPE_EXT, output); - glProgramParameteriEXT(shader->program, GL_GEOMETRY_VERTICES_OUT_EXT, number); + int bindpoint = GPU_uniformbuffer_bindpoint(ubo); + + if (location == -1) { + return; } + + glUniformBlockBinding(shader->program, location, bindpoint); } void GPU_shader_uniform_texture(GPUShader *UNUSED(shader), int location, GPUTexture *tex) { - GLenum arbnumber; 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; - GPU_ASSERT_NO_GL_ERRORS("Pre Uniform Texture"); - - arbnumber = (GLenum)((GLuint)GL_TEXTURE0 + number); - - if (number != 0) glActiveTexture(arbnumber); - if (bindcode != 0) - glBindTexture(target, bindcode); - else - GPU_invalid_tex_bind(target); glUniform1i(location, number); - glEnable(target); - if (number != 0) glActiveTexture(GL_TEXTURE0); - - GPU_ASSERT_NO_GL_ERRORS("Post Uniform Texture"); } int GPU_shader_get_attribute(GPUShader *shader, const char *name) { - int index; - - GPU_CHECK_ERRORS_AROUND(index = glGetAttribLocation(shader->program, name)); - - return index; + BLI_assert(shader && shader->program); + const Gwn_ShaderInput *attrib = GWN_shaderinterface_attr(shader->interface, name); + return attrib ? attrib->location : -1; } GPUShader *GPU_shader_get_builtin_shader(GPUBuiltinShader shader) { - GPUShader *retval = NULL; - - switch (shader) { - case GPU_SHADER_VSM_STORE: - if (!GG.shaders.vsm_store) - GG.shaders.vsm_store = GPU_shader_create( - datatoc_gpu_shader_vsm_store_vert_glsl, datatoc_gpu_shader_vsm_store_frag_glsl, - NULL, NULL, NULL, 0, 0, 0); - retval = GG.shaders.vsm_store; - break; - case GPU_SHADER_SEP_GAUSSIAN_BLUR: - if (!GG.shaders.sep_gaussian_blur) - GG.shaders.sep_gaussian_blur = GPU_shader_create( - datatoc_gpu_shader_sep_gaussian_blur_vert_glsl, - datatoc_gpu_shader_sep_gaussian_blur_frag_glsl, - NULL, NULL, NULL, 0, 0, 0); - retval = GG.shaders.sep_gaussian_blur; - break; - case GPU_SHADER_SMOKE: - if (!GG.shaders.smoke) - GG.shaders.smoke = GPU_shader_create( - datatoc_gpu_shader_smoke_vert_glsl, datatoc_gpu_shader_smoke_frag_glsl, - NULL, NULL, NULL, 0, 0, 0); - retval = GG.shaders.smoke; - break; - case GPU_SHADER_SMOKE_FIRE: - if (!GG.shaders.smoke_fire) - GG.shaders.smoke_fire = GPU_shader_create( - datatoc_gpu_shader_smoke_vert_glsl, datatoc_gpu_shader_fire_frag_glsl, - NULL, NULL, NULL, 0, 0, 0); - retval = GG.shaders.smoke_fire; - break; - case GPU_SHADER_SMOKE_COBA: - if (!GG.shaders.smoke_coba) - GG.shaders.smoke_coba = GPU_shader_create( - datatoc_gpu_shader_smoke_vert_glsl, datatoc_gpu_shader_smoke_frag_glsl, - NULL, NULL, "#define USE_COBA;\n", 0, 0, 0); - retval = GG.shaders.smoke_coba; - break; - } - - if (retval == NULL) - printf("Unable to create a GPUShader for builtin shader: %u\n", shader); - - return retval; -} - -#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 (!GG.shaders.fx_shaders[offset]) { - GPUShader *shader = NULL; - - switch (effect) { - case GPU_SHADER_FX_SSAO: - shader = GPU_shader_create(datatoc_gpu_shader_fx_vert_glsl, datatoc_gpu_shader_fx_ssao_frag_glsl, NULL, datatoc_gpu_shader_fx_lib_glsl, defines, 0, 0, 0); + BLI_assert(shader != GPU_NUM_BUILTIN_SHADERS); /* don't be a troll */ + + static const GPUShaderStages builtin_shader_stages[GPU_NUM_BUILTIN_SHADERS] = { + [GPU_SHADER_VSM_STORE] = { datatoc_gpu_shader_vsm_store_vert_glsl, datatoc_gpu_shader_vsm_store_frag_glsl }, + [GPU_SHADER_SEP_GAUSSIAN_BLUR] = { datatoc_gpu_shader_sep_gaussian_blur_vert_glsl, + datatoc_gpu_shader_sep_gaussian_blur_frag_glsl }, + [GPU_SHADER_SMOKE] = { datatoc_gpu_shader_smoke_vert_glsl, datatoc_gpu_shader_smoke_frag_glsl }, + [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, + 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, + /* this version is */ datatoc_gpu_shader_flat_color_frag_glsl, + /* magical but slooow */ datatoc_gpu_shader_edges_front_back_persp_geom_glsl }, + [GPU_SHADER_EDGES_FRONT_BACK_ORTHO] = { datatoc_gpu_shader_edges_front_back_ortho_vert_glsl, + datatoc_gpu_shader_flat_color_frag_glsl }, + [GPU_SHADER_EDGES_OVERLAY_SIMPLE] = { datatoc_gpu_shader_3D_vert_glsl, datatoc_gpu_shader_edges_overlay_frag_glsl, + datatoc_gpu_shader_edges_overlay_simple_geom_glsl }, + [GPU_SHADER_EDGES_OVERLAY] = { datatoc_gpu_shader_edges_overlay_vert_glsl, + datatoc_gpu_shader_edges_overlay_frag_glsl, + datatoc_gpu_shader_edges_overlay_geom_glsl }, + [GPU_SHADER_SIMPLE_LIGHTING] = { datatoc_gpu_shader_3D_normal_vert_glsl, datatoc_gpu_shader_simple_lighting_frag_glsl }, + /* Use 'USE_FLAT_NORMAL' to make flat shader from smooth */ + [GPU_SHADER_SIMPLE_LIGHTING_FLAT_COLOR] = { datatoc_gpu_shader_3D_normal_smooth_color_vert_glsl, datatoc_gpu_shader_simple_lighting_smooth_color_frag_glsl }, + [GPU_SHADER_SIMPLE_LIGHTING_SMOOTH_COLOR] = { datatoc_gpu_shader_3D_normal_smooth_color_vert_glsl, datatoc_gpu_shader_simple_lighting_smooth_color_frag_glsl }, + [GPU_SHADER_SIMPLE_LIGHTING_SMOOTH_COLOR_ALPHA] = { datatoc_gpu_shader_3D_normal_smooth_color_vert_glsl, datatoc_gpu_shader_simple_lighting_smooth_color_alpha_frag_glsl }, + + [GPU_SHADER_2D_IMAGE_MASK_UNIFORM_COLOR] = { datatoc_gpu_shader_3D_image_vert_glsl, + 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_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_MULTISAMPLE_2] = { datatoc_gpu_shader_2D_vert_glsl, datatoc_gpu_shader_image_multisample_resolve_frag_glsl }, + [GPU_SHADER_2D_IMAGE_MULTISAMPLE_4] = { datatoc_gpu_shader_2D_vert_glsl, datatoc_gpu_shader_image_multisample_resolve_frag_glsl }, + [GPU_SHADER_2D_IMAGE_MULTISAMPLE_8] = { datatoc_gpu_shader_2D_vert_glsl, datatoc_gpu_shader_image_multisample_resolve_frag_glsl }, + [GPU_SHADER_2D_IMAGE_MULTISAMPLE_16] = { datatoc_gpu_shader_2D_vert_glsl, datatoc_gpu_shader_image_multisample_resolve_frag_glsl }, + + [GPU_SHADER_2D_IMAGE_INTERLACE] = { datatoc_gpu_shader_2D_image_vert_glsl, + datatoc_gpu_shader_image_interlace_frag_glsl }, + [GPU_SHADER_2D_CHECKER] = { datatoc_gpu_shader_2D_vert_glsl, datatoc_gpu_shader_checker_frag_glsl }, + + [GPU_SHADER_2D_DIAG_STRIPES] = { datatoc_gpu_shader_2D_vert_glsl, datatoc_gpu_shader_diag_stripes_frag_glsl }, + + [GPU_SHADER_2D_UNIFORM_COLOR] = { datatoc_gpu_shader_2D_vert_glsl, datatoc_gpu_shader_uniform_color_frag_glsl }, + [GPU_SHADER_2D_FLAT_COLOR] = { datatoc_gpu_shader_2D_flat_color_vert_glsl, + datatoc_gpu_shader_flat_color_frag_glsl }, + [GPU_SHADER_2D_SMOOTH_COLOR] = { datatoc_gpu_shader_2D_smooth_color_vert_glsl, + datatoc_gpu_shader_2D_smooth_color_frag_glsl }, + [GPU_SHADER_2D_SMOOTH_COLOR_DITHER] = { datatoc_gpu_shader_2D_smooth_color_vert_glsl, + datatoc_gpu_shader_2D_smooth_color_dithered_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_DESATURATE_COLOR] = { datatoc_gpu_shader_2D_image_vert_glsl, + datatoc_gpu_shader_image_desaturate_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_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, + datatoc_gpu_shader_flat_color_frag_glsl }, + [GPU_SHADER_3D_FLAT_COLOR_U32] = { datatoc_gpu_shader_3D_flat_color_vert_glsl, + datatoc_gpu_shader_flat_color_frag_glsl }, + [GPU_SHADER_3D_SMOOTH_COLOR] = { datatoc_gpu_shader_3D_smooth_color_vert_glsl, + datatoc_gpu_shader_3D_smooth_color_frag_glsl }, + [GPU_SHADER_3D_DEPTH_ONLY] = { datatoc_gpu_shader_3D_vert_glsl, datatoc_gpu_shader_depth_only_frag_glsl }, + [GPU_SHADER_3D_CLIPPED_UNIFORM_COLOR] = { datatoc_gpu_shader_3D_clipped_uniform_color_vert_glsl, + datatoc_gpu_shader_uniform_color_frag_glsl }, + + [GPU_SHADER_3D_GROUNDPOINT] = { datatoc_gpu_shader_3D_groundpoint_vert_glsl, datatoc_gpu_shader_point_uniform_color_frag_glsl }, + [GPU_SHADER_3D_GROUNDLINE] = { datatoc_gpu_shader_3D_passthrough_vert_glsl, + datatoc_gpu_shader_uniform_color_frag_glsl, + datatoc_gpu_shader_3D_groundline_geom_glsl }, + + [GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR] = { datatoc_gpu_shader_2D_line_dashed_uniform_color_vert_glsl, + datatoc_gpu_shader_2D_line_dashed_frag_glsl, + datatoc_gpu_shader_2D_line_dashed_geom_glsl }, + [GPU_SHADER_3D_LINE_DASHED_UNIFORM_COLOR] = { datatoc_gpu_shader_3D_line_dashed_uniform_color_vert_glsl, + datatoc_gpu_shader_2D_line_dashed_frag_glsl, + datatoc_gpu_shader_2D_line_dashed_geom_glsl }, + + [GPU_SHADER_3D_OBJECTSPACE_SIMPLE_LIGHTING_VARIYING_COLOR] = + { datatoc_gpu_shader_instance_objectspace_variying_color_vert_glsl, + datatoc_gpu_shader_simple_lighting_frag_glsl}, + [GPU_SHADER_3D_OBJECTSPACE_VARIYING_COLOR] = { datatoc_gpu_shader_instance_objectspace_variying_color_vert_glsl, + datatoc_gpu_shader_flat_color_frag_glsl}, + [GPU_SHADER_3D_SCREENSPACE_VARIYING_COLOR] = { datatoc_gpu_shader_instance_screenspace_variying_color_vert_glsl, + datatoc_gpu_shader_flat_color_frag_glsl}, + [GPU_SHADER_3D_INSTANCE_SCREEN_ALIGNED_AXIS] = { datatoc_gpu_shader_instance_screen_aligned_vert_glsl, + datatoc_gpu_shader_flat_color_frag_glsl}, + [GPU_SHADER_3D_INSTANCE_SCREEN_ALIGNED] = { datatoc_gpu_shader_instance_screen_aligned_vert_glsl, + datatoc_gpu_shader_flat_color_frag_glsl}, + + [GPU_SHADER_CAMERA] = { datatoc_gpu_shader_instance_camera_vert_glsl, + datatoc_gpu_shader_flat_color_frag_glsl}, + [GPU_SHADER_DISTANCE_LINES] = { datatoc_gpu_shader_instance_distance_line_vert_glsl, + datatoc_gpu_shader_flat_color_frag_glsl}, + + [GPU_SHADER_2D_POINT_FIXED_SIZE_UNIFORM_COLOR] = + { datatoc_gpu_shader_2D_vert_glsl, datatoc_gpu_shader_point_uniform_color_frag_glsl }, + [GPU_SHADER_2D_POINT_VARYING_SIZE_VARYING_COLOR] = + { datatoc_gpu_shader_2D_point_varying_size_varying_color_vert_glsl, + datatoc_gpu_shader_point_varying_color_frag_glsl }, + [GPU_SHADER_2D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_AA] = + { datatoc_gpu_shader_2D_point_uniform_size_aa_vert_glsl, + datatoc_gpu_shader_point_uniform_color_aa_frag_glsl }, + [GPU_SHADER_2D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_OUTLINE_AA] = + { datatoc_gpu_shader_2D_point_uniform_size_outline_aa_vert_glsl, + datatoc_gpu_shader_point_uniform_color_outline_aa_frag_glsl }, + [GPU_SHADER_2D_POINT_UNIFORM_SIZE_VARYING_COLOR_OUTLINE_AA] = + { datatoc_gpu_shader_2D_point_uniform_size_varying_color_outline_aa_vert_glsl, + datatoc_gpu_shader_point_varying_color_outline_aa_frag_glsl }, + [GPU_SHADER_3D_POINT_FIXED_SIZE_UNIFORM_COLOR] = { datatoc_gpu_shader_3D_vert_glsl, + datatoc_gpu_shader_point_uniform_color_frag_glsl }, + [GPU_SHADER_3D_POINT_FIXED_SIZE_VARYING_COLOR] = { datatoc_gpu_shader_3D_point_fixed_size_varying_color_vert_glsl, + datatoc_gpu_shader_point_varying_color_frag_glsl }, + [GPU_SHADER_3D_POINT_VARYING_SIZE_UNIFORM_COLOR] = { datatoc_gpu_shader_3D_point_varying_size_vert_glsl, + datatoc_gpu_shader_point_uniform_color_frag_glsl }, + [GPU_SHADER_3D_POINT_VARYING_SIZE_VARYING_COLOR] = + { datatoc_gpu_shader_3D_point_varying_size_varying_color_vert_glsl, + datatoc_gpu_shader_point_varying_color_frag_glsl }, + [GPU_SHADER_3D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_AA] = + { datatoc_gpu_shader_3D_point_uniform_size_aa_vert_glsl, + datatoc_gpu_shader_point_uniform_color_aa_frag_glsl }, + [GPU_SHADER_3D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_OUTLINE_AA] = + { datatoc_gpu_shader_3D_point_uniform_size_outline_aa_vert_glsl, + datatoc_gpu_shader_point_uniform_color_outline_aa_frag_glsl }, + + [GPU_SHADER_INSTANCE_UNIFORM_COLOR] = { datatoc_gpu_shader_instance_vert_glsl, datatoc_gpu_shader_uniform_color_frag_glsl }, + [GPU_SHADER_INSTANCE_VARIYING_ID_VARIYING_SIZE] = + { datatoc_gpu_shader_instance_variying_size_variying_id_vert_glsl, + datatoc_gpu_shader_flat_id_frag_glsl }, + [GPU_SHADER_INSTANCE_VARIYING_COLOR_VARIYING_SIZE] = + { datatoc_gpu_shader_instance_variying_size_variying_color_vert_glsl, + datatoc_gpu_shader_flat_color_frag_glsl }, + [GPU_SHADER_INSTANCE_VARIYING_COLOR_VARIYING_SCALE] = + { datatoc_gpu_shader_instance_variying_size_variying_color_vert_glsl, + datatoc_gpu_shader_flat_color_frag_glsl }, + [GPU_SHADER_INSTANCE_EDGES_VARIYING_COLOR] = { datatoc_gpu_shader_instance_edges_variying_color_vert_glsl, + 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 }, + }; + + if (builtin_shaders[shader] == NULL) { + /* just a few special cases */ + const char *defines = NULL; + switch (shader) { + case GPU_SHADER_2D_IMAGE_MULTISAMPLE_2: + defines = "#define SAMPLES 2\n"; 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, 0, 0, 0); + case GPU_SHADER_2D_IMAGE_MULTISAMPLE_4: + defines = "#define SAMPLES 4\n"; 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, 0, 0, 0); + case GPU_SHADER_2D_IMAGE_MULTISAMPLE_8: + defines = "#define SAMPLES 8\n"; 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, 0, 0, 0); + case GPU_SHADER_2D_IMAGE_MULTISAMPLE_16: + defines = "#define SAMPLES 16\n"; 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, 0, 0, 0); + case GPU_SHADER_2D_WIDGET_BASE_INST: + case GPU_SHADER_2D_NODELINK_INST: + defines = "#define USE_INSTANCE\n"; 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, 0, 0, 0); + case GPU_SHADER_SMOKE_COBA: + defines = "#define USE_COBA\n"; 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, 0, 0, 0); + case GPU_SHADER_INSTANCE_VARIYING_ID_VARIYING_SIZE: + case GPU_SHADER_INSTANCE_VARIYING_COLOR_VARIYING_SIZE: + defines = "#define UNIFORM_SCALE\n"; 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, GL_POINTS, GL_TRIANGLE_STRIP, 4); + case GPU_SHADER_3D_INSTANCE_SCREEN_ALIGNED_AXIS: + defines = "#define AXIS_NAME\n"; 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, 0, 0, 0); + case GPU_SHADER_3D_OBJECTSPACE_SIMPLE_LIGHTING_VARIYING_COLOR: + defines = "#define USE_INSTANCE_COLOR\n"; break; - - case GPU_SHADER_FX_DEPTH_RESOLVE: - shader = GPU_shader_create(datatoc_gpu_shader_fx_vert_glsl, datatoc_gpu_shader_fx_depth_resolve_glsl, NULL, NULL, defines, 0, 0, 0); + case GPU_SHADER_3D_FLAT_COLOR_U32: + case GPU_SHADER_3D_UNIFORM_COLOR_U32: + defines = "#define USE_COLOR_U32\n"; + break; + case GPU_SHADER_SIMPLE_LIGHTING_FLAT_COLOR: + defines = "#define USE_FLAT_NORMAL\n"; + break; + default: break; } - GG.shaders.fx_shaders[offset] = shader; - GPU_fx_shader_init_interface(shader, effect); - } - - return GG.shaders.fx_shaders[offset]; -} - - -void GPU_shader_free_builtin_shaders(void) -{ - int i; + const GPUShaderStages *stages = builtin_shader_stages + shader; - if (GG.shaders.vsm_store) { - GPU_shader_free(GG.shaders.vsm_store); - GG.shaders.vsm_store = NULL; - } + if (shader == GPU_SHADER_EDGES_FRONT_BACK_PERSP && !GLEW_VERSION_3_2) { + /* TODO: remove after switch to core profile (maybe) */ + static const GPUShaderStages legacy_fancy_edges = + { datatoc_gpu_shader_edges_front_back_persp_legacy_vert_glsl, + datatoc_gpu_shader_flat_color_alpha_test_0_frag_glsl }; + stages = &legacy_fancy_edges; + } - if (GG.shaders.sep_gaussian_blur) { - GPU_shader_free(GG.shaders.sep_gaussian_blur); - GG.shaders.sep_gaussian_blur = NULL; - } + if (shader == GPU_SHADER_3D_LINE_DASHED_UNIFORM_COLOR && !GLEW_VERSION_3_2) { + /* Dashed need geometry shader, which are not supported by legacy OpenGL, fallback to solid lines. */ + /* TODO: remove after switch to core profile (maybe) */ + static const GPUShaderStages legacy_dashed_lines = { datatoc_gpu_shader_3D_line_dashed_uniform_color_legacy_vert_glsl, + datatoc_gpu_shader_2D_line_dashed_frag_glsl }; + stages = &legacy_dashed_lines; + } - if (GG.shaders.smoke) { - GPU_shader_free(GG.shaders.smoke); - GG.shaders.smoke = NULL; + /* common case */ + builtin_shaders[shader] = GPU_shader_create(stages->vert, stages->frag, stages->geom, NULL, defines); } - if (GG.shaders.smoke_fire) { - GPU_shader_free(GG.shaders.smoke_fire); - GG.shaders.smoke_fire = NULL; - } + return builtin_shaders[shader]; +} - if (GG.shaders.smoke_coba) { - GPU_shader_free(GG.shaders.smoke_coba); - GG.shaders.smoke_coba = NULL; - } +#define MAX_DEFINES 100 - for (i = 0; i < 2 * MAX_FX_SHADERS; ++i) { - if (GG.shaders.fx_shaders[i]) { - GPU_shader_free(GG.shaders.fx_shaders[i]); - GG.shaders.fx_shaders[i] = NULL; +void GPU_shader_free_builtin_shaders(void) +{ + for (int i = 0; i < GPU_NUM_BUILTIN_SHADERS; ++i) { + if (builtin_shaders[i]) { + GPU_shader_free(builtin_shaders[i]); + builtin_shaders[i] = NULL; } } } - - diff --git a/source/blender/gpu/intern/gpu_shader_private.h b/source/blender/gpu/intern/gpu_shader_private.h new file mode 100644 index 00000000000..d8ec6b5d6d1 --- /dev/null +++ b/source/blender/gpu/intern/gpu_shader_private.h @@ -0,0 +1,44 @@ +/* + * ***** 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. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file gpu_shader_private.h + * \ingroup gpu + */ + +#ifndef __GPU_SHADER_PRIVATE_H__ +#define __GPU_SHADER_PRIVATE_H__ + +#include "GPU_glew.h" +#include "gawain/gwn_shader_interface.h" + +struct GPUShader { + GLuint program; /* handle for full program (links shader stages below) */ + + GLuint vertex; /* handle for vertex shader */ + GLuint geometry; /* handle for geometry shader */ + GLuint fragment; /* handle for fragment shader */ + + Gwn_ShaderInterface *interface; /* cached uniform & attrib interface for shader */ + + int feedback_transform_type; +}; + +#endif /* __GPU_SHADER_PRIVATE_H__ */ + diff --git a/source/blender/gpu/intern/gpu_texture.c b/source/blender/gpu/intern/gpu_texture.c index f50465189b2..38b38736660 100644 --- a/source/blender/gpu/intern/gpu_texture.c +++ b/source/blender/gpu/intern/gpu_texture.c @@ -35,6 +35,7 @@ #include "BKE_global.h" +#include "GPU_batch.h" #include "GPU_debug.h" #include "GPU_draw.h" #include "GPU_extensions.h" @@ -48,10 +49,25 @@ static struct GPUTextureGlobal { GPUTexture *invalid_tex_3D; } GG = {NULL, NULL, NULL}; -/* GPUTexture */ +/* 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; /* width/height */ + int w, h, d; /* width/height/depth */ int number; /* number for multitexture binding */ int refcount; /* reference count */ GLenum target; /* GL_TEXTURE_* */ @@ -60,45 +76,318 @@ 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 */ - int depth; /* is a depth texture? if 3D how deep? */ + GPUTextureFormat format; + GPUTextureFormatFlag format_flag; + + unsigned int bytesize; /* number of byte for one pixel */ + 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]; }; -static unsigned char *GPU_texture_convert_pixels(int length, const float *fpixels) +/* ------ Memory Management ------- */ +/* Records every texture allocation / free + * to estimate the Texture Pool Memory consumption */ +static unsigned int memory_usage; + +static unsigned int gpu_texture_memory_footprint_compute(GPUTexture *tex) { - unsigned char *pixels, *p; - const float *fp = fpixels; - const int len = 4 * length; + int samp = max_ii(tex->samples, 1); + switch (tex->target) { + case GL_TEXTURE_1D: + return tex->bytesize * tex->w * samp; + case GL_TEXTURE_1D_ARRAY: + case GL_TEXTURE_2D: + return tex->bytesize * tex->w * tex->h * samp; + case GL_TEXTURE_2D_ARRAY: + case GL_TEXTURE_3D: + return tex->bytesize * tex->w * tex->h * tex->d * samp; + case GL_TEXTURE_CUBE_MAP: + return tex->bytesize * 6 * tex->w * tex->h * samp; + case GL_TEXTURE_CUBE_MAP_ARRAY: + return tex->bytesize * 6 * tex->w * tex->h * tex->d * samp; + default: + return 0; + } +} - p = pixels = MEM_callocN(sizeof(unsigned char) * len, "GPUTexturePixels"); +static void gpu_texture_memory_footprint_add(GPUTexture *tex) +{ + memory_usage += gpu_texture_memory_footprint_compute(tex); +} - for (int a = 0; a < len; a++, p++, fp++) - *p = unit_float_to_uchar_clamp((*fp)); +static void gpu_texture_memory_footprint_remove(GPUTexture *tex) +{ + memory_usage -= gpu_texture_memory_footprint_compute(tex); +} - return pixels; +unsigned int GPU_texture_memory_usage_get(void) +{ + return memory_usage; } -static void gpu_glTexSubImageEmpty(GLenum target, GLenum format, int x, int y, int w, int h) +/* -------------------------------- */ + +static GLenum gpu_texture_get_format( + int components, GPUTextureFormat data_type, + GLenum *format, GLenum *data_format, GPUTextureFormatFlag *format_flag, unsigned int *bytesize) { - void *pixels = MEM_callocN(sizeof(char) * 4 * w * h, "GPUTextureEmptyPixels"); + if (ELEM(data_type, GPU_DEPTH_COMPONENT24, + GPU_DEPTH_COMPONENT16, + GPU_DEPTH_COMPONENT32F)) + { + *format_flag |= GPU_FORMAT_DEPTH; + *data_format = GL_FLOAT; + *format = GL_DEPTH_COMPONENT; + } + else if (data_type == GPU_DEPTH24_STENCIL8) { + *format_flag |= GPU_FORMAT_DEPTH | GPU_FORMAT_STENCIL; + *data_format = GL_UNSIGNED_INT_24_8; + *format = GL_DEPTH_STENCIL; + } + else { + /* Integer formats */ + if (ELEM(data_type, GPU_RG16I, GPU_R16I, GPU_RG16UI, GPU_R16UI, GPU_R32UI)) { + if (ELEM(data_type, GPU_R16UI, GPU_RG16UI, GPU_R32UI)) { + *data_format = GL_UNSIGNED_INT; + } + else { + *data_format = GL_INT; + } - if (target == GL_TEXTURE_1D) - glTexSubImage1D(target, 0, x, w, format, GL_UNSIGNED_BYTE, pixels); - else - glTexSubImage2D(target, 0, x, y, w, h, format, GL_UNSIGNED_BYTE, pixels); - - MEM_freeN(pixels); + *format_flag |= GPU_FORMAT_INTEGER; + + switch (components) { + case 1: *format = GL_RED_INTEGER; break; + case 2: *format = GL_RG_INTEGER; break; + case 3: *format = GL_RGB_INTEGER; break; + case 4: *format = GL_RGBA_INTEGER; break; + default: break; + } + } + else { + *data_format = GL_FLOAT; + *format_flag |= GPU_FORMAT_FLOAT; + + switch (components) { + case 1: *format = GL_RED; break; + case 2: *format = GL_RG; break; + case 3: *format = GL_RGB; break; + case 4: *format = GL_RGBA; break; + default: break; + } + } + } + + switch (data_type) { + case GPU_RGBA32F: + *bytesize = 32; + break; + case GPU_RG32F: + case GPU_RGBA16F: + case GPU_RGBA16: + *bytesize = 16; + break; + case GPU_RGB16F: + *bytesize = 12; + break; + case GPU_RG16F: + case GPU_RG16I: + case GPU_RG16UI: + case GPU_RG16: + case GPU_DEPTH24_STENCIL8: + case GPU_DEPTH_COMPONENT32F: + case GPU_RGBA8: + case GPU_R11F_G11F_B10F: + case GPU_R32F: + case GPU_R32UI: + *bytesize = 4; + break; + case GPU_DEPTH_COMPONENT24: + *bytesize = 3; + break; + case GPU_DEPTH_COMPONENT16: + case GPU_R16F: + case GPU_R16I: + case GPU_RG8: + *bytesize = 2; + break; + case GPU_R8: + *bytesize = 1; + break; + default: + *bytesize = 0; + break; + } + + /* You can add any of the available type to this list + * For available types see GPU_texture.h */ + switch (data_type) { + /* Formats texture & renderbuffer */ + case GPU_RGBA32F: return GL_RGBA32F; + case GPU_RGBA16F: return GL_RGBA16F; + case GPU_RGBA16: return GL_RGBA16; + case GPU_RG32F: return GL_RG32F; + case GPU_RGB16F: return GL_RGB16F; + case GPU_RG16F: return GL_RG16F; + case GPU_RG16I: return GL_RG16I; + case GPU_RG16: return GL_RG16; + case GPU_RGBA8: return GL_RGBA8; + case GPU_R32F: return GL_R32F; + case GPU_R32UI: return GL_R32UI; + case GPU_R16F: return GL_R16F; + case GPU_R16I: return GL_R16I; + case GPU_R16UI: return GL_R16UI; + case GPU_RG8: return GL_RG8; + case GPU_RG16UI: return GL_RG16UI; + case GPU_R8: return GL_R8; + /* Special formats texture & renderbuffer */ + case GPU_R11F_G11F_B10F: return GL_R11F_G11F_B10F; + case GPU_DEPTH24_STENCIL8: return GL_DEPTH24_STENCIL8; + /* Texture only format */ + /* ** Add Format here **/ + /* Special formats texture only */ + /* ** Add Format here **/ + /* Depth Formats */ + case GPU_DEPTH_COMPONENT32F: return GL_DEPTH_COMPONENT32F; + case GPU_DEPTH_COMPONENT24: return GL_DEPTH_COMPONENT24; + case GPU_DEPTH_COMPONENT16: return GL_DEPTH_COMPONENT16; + default: + fprintf(stderr, "Texture format incorrect or unsupported\n"); + return 0; + } } -static GPUTexture *GPU_texture_create_nD( - int w, int h, int n, const float *fpixels, int depth, - GPUHDRType hdr_type, int components, int samples, - char err_out[256]) +static int gpu_texture_get_component_count(GPUTextureFormat format) +{ + switch (format) { + case GPU_RGBA8: + case GPU_RGBA16F: + case GPU_RGBA16: + case GPU_RGBA32F: + return 4; + case GPU_RGB16F: + case GPU_R11F_G11F_B10F: + return 3; + case GPU_RG8: + case GPU_RG16: + case GPU_RG16F: + case GPU_RG16I: + case GPU_RG16UI: + case GPU_RG32F: + return 2; + default: + return 1; + } +} + +static float *GPU_texture_3D_rescale(GPUTexture *tex, int w, int h, int d, int channels, const float *fpixels) { - GLenum type, format, internalformat; - void *pixels = NULL; + const unsigned int xf = w / tex->w, yf = h / tex->h, zf = d / tex->d; + float *nfpixels = MEM_mallocN(channels * sizeof(float) * tex->w * tex->h * tex->d, "GPUTexture Rescaled 3Dtex"); + + if (nfpixels) { + GPU_print_error_debug("You need to scale a 3D texture, feel the pain!"); + + for (unsigned k = 0; k < tex->d; k++) { + for (unsigned j = 0; j < tex->h; j++) { + for (unsigned i = 0; i < tex->w; i++) { + /* obviously doing nearest filtering here, + * it's going to be slow in any case, let's not make it worse */ + float xb = i * xf; + float yb = j * yf; + float zb = k * zf; + unsigned int offset = k * (tex->w * tex->h) + i * tex->h + j; + unsigned int offset_orig = (zb) * (w * h) + (xb) * h + (yb); + + if (channels == 4) { + nfpixels[offset * 4] = fpixels[offset_orig * 4]; + nfpixels[offset * 4 + 1] = fpixels[offset_orig * 4 + 1]; + nfpixels[offset * 4 + 2] = fpixels[offset_orig * 4 + 2]; + nfpixels[offset * 4 + 3] = fpixels[offset_orig * 4 + 3]; + } + else + nfpixels[offset] = fpixels[offset_orig]; + } + } + } + } + + return nfpixels; +} + +/* This tries to allocate video memory for a given texture + * If alloc fails, lower the resolution until it fits. */ +static bool gpu_texture_try_alloc( + GPUTexture *tex, GLenum proxy, GLenum internalformat, GLenum format, GLenum data_format, + int channels, bool try_rescale, const float *fpixels, float **rescaled_fpixels) +{ + int r_width; + + switch (proxy) { + case GL_PROXY_TEXTURE_1D: + glTexImage1D(proxy, 0, internalformat, tex->w, 0, format, data_format, NULL); + break; + case GL_PROXY_TEXTURE_1D_ARRAY: + case GL_PROXY_TEXTURE_2D: + glTexImage2D(proxy, 0, internalformat, tex->w, tex->h, 0, format, data_format, NULL); + break; + case GL_PROXY_TEXTURE_2D_ARRAY: + case GL_PROXY_TEXTURE_3D: + glTexImage3D(proxy, 0, internalformat, tex->w, tex->h, tex->d, 0, format, data_format, NULL); + break; + } + + glGetTexLevelParameteriv(proxy, 0, GL_TEXTURE_WIDTH, &r_width); + + if (r_width == 0 && try_rescale) { + const int w = tex->w, h = tex->h, d = tex->d; + + /* Find largest texture possible */ + while (r_width == 0) { + tex->w /= 2; + tex->h /= 2; + tex->d /= 2; + + /* really unlikely to happen but keep this just in case */ + if (tex->w == 0) break; + if (tex->h == 0 && proxy != GL_PROXY_TEXTURE_1D) break; + if (tex->d == 0 && proxy == GL_PROXY_TEXTURE_3D) break; + + if (proxy == GL_PROXY_TEXTURE_1D) + glTexImage1D(proxy, 0, internalformat, tex->w, 0, format, data_format, NULL); + else if (proxy == GL_PROXY_TEXTURE_2D) + glTexImage2D(proxy, 0, internalformat, tex->w, tex->h, 0, format, data_format, NULL); + else if (proxy == GL_PROXY_TEXTURE_3D) + glTexImage3D(proxy, 0, internalformat, tex->w, tex->h, tex->d, 0, format, data_format, NULL); + + glGetTexLevelParameteriv(GL_PROXY_TEXTURE_3D, 0, GL_TEXTURE_WIDTH, &r_width); + } + /* Rescale */ + if (r_width > 0) { + switch (proxy) { + case GL_PROXY_TEXTURE_1D: + case GL_PROXY_TEXTURE_2D: + /* Do nothing for now */ + return false; + case GL_PROXY_TEXTURE_3D: + *rescaled_fpixels = GPU_texture_3D_rescale(tex, w, h, d, channels, fpixels); + return (bool)*rescaled_fpixels; + } + } + } + + return (r_width > 0); +} + +static GPUTexture *GPU_texture_create_nD( + int w, int h, int d, int n, const float *fpixels, + GPUTextureFormat data_type, int samples, + const bool can_rescale, char err_out[256]) +{ if (samples) { CLAMP_MAX(samples, GPU_max_color_texture_samples()); } @@ -106,280 +395,287 @@ static GPUTexture *GPU_texture_create_nD( GPUTexture *tex = MEM_callocN(sizeof(GPUTexture), "GPUTexture"); tex->w = w; tex->h = h; + tex->d = d; + tex->samples = samples; tex->number = -1; tex->refcount = 1; - tex->target = (n == 1) ? GL_TEXTURE_1D : (samples ? GL_TEXTURE_2D_MULTISAMPLE : GL_TEXTURE_2D); - tex->target_base = (n == 1) ? GL_TEXTURE_1D : GL_TEXTURE_2D; - tex->depth = depth; - tex->fb_attachment = -1; + tex->format = data_type; + tex->components = gpu_texture_get_component_count(data_type); + tex->format_flag = 0; + + if (n == 2) { + if (d == 0) + tex->target_base = tex->target = GL_TEXTURE_2D; + else + tex->target_base = tex->target = GL_TEXTURE_2D_ARRAY; + } + else if (n == 1) { + if (h == 0) + tex->target_base = tex->target = GL_TEXTURE_1D; + else + tex->target_base = tex->target = GL_TEXTURE_1D_ARRAY; + } + else if (n == 3) { + tex->target_base = tex->target = GL_TEXTURE_3D; + } + else { + /* should never happen */ + MEM_freeN(tex); + return NULL; + } + + if (samples && n == 2 && d == 0) + tex->target = GL_TEXTURE_2D_MULTISAMPLE; + + GLenum format, internalformat, data_format; + internalformat = gpu_texture_get_format(tex->components, data_type, &format, &data_format, + &tex->format_flag, &tex->bytesize); + gpu_texture_memory_footprint_add(tex); + + /* Generate Texture object */ glGenTextures(1, &tex->bindcode); if (!tex->bindcode) { - if (err_out) { - BLI_snprintf(err_out, 256, "GPUTexture: texture create failed: %d", - (int)glGetError()); - } - else { - fprintf(stderr, "GPUTexture: texture create failed: %d\n", - (int)glGetError()); - } + if (err_out) + BLI_snprintf(err_out, 256, "GPUTexture: texture create failed"); + else + fprintf(stderr, "GPUTexture: texture create failed"); GPU_texture_free(tex); return NULL; } - if (!GPU_full_non_power_of_two_support()) { - tex->w = power_of_2_max_i(tex->w); - tex->h = power_of_2_max_i(tex->h); - } - - tex->number = 0; glBindTexture(tex->target, tex->bindcode); - if (depth) { - type = GL_UNSIGNED_BYTE; - format = GL_DEPTH_COMPONENT; - internalformat = GL_DEPTH_COMPONENT; - } - else { - type = GL_FLOAT; - - if (components == 4) { - format = GL_RGBA; - switch (hdr_type) { - case GPU_HDR_NONE: - internalformat = GL_RGBA8; - break; - /* the following formats rely on ARB_texture_float or OpenGL 3.0 */ - case GPU_HDR_HALF_FLOAT: - internalformat = GL_RGBA16F_ARB; - break; - case GPU_HDR_FULL_FLOAT: - internalformat = GL_RGBA32F_ARB; - break; - default: - break; - } - } - else if (components == 2) { - /* these formats rely on ARB_texture_rg or OpenGL 3.0 */ - format = GL_RG; - switch (hdr_type) { - case GPU_HDR_NONE: - internalformat = GL_RG8; - break; - case GPU_HDR_HALF_FLOAT: - internalformat = GL_RG16F; - break; - case GPU_HDR_FULL_FLOAT: - internalformat = GL_RG32F; - break; - default: - break; - } - } + /* Check if texture fit in VRAM */ + GLenum proxy = GL_PROXY_TEXTURE_2D; - if (fpixels && hdr_type == GPU_HDR_NONE) { - type = GL_UNSIGNED_BYTE; - pixels = GPU_texture_convert_pixels(w * h, fpixels); - } + if (n == 2) { + if (d > 0) + proxy = GL_PROXY_TEXTURE_2D_ARRAY; + } + else if (n == 1) { + if (h == 0) + proxy = GL_PROXY_TEXTURE_1D; + else + proxy = GL_PROXY_TEXTURE_1D_ARRAY; + } + else if (n == 3) { + proxy = GL_PROXY_TEXTURE_3D; } - if (tex->target == GL_TEXTURE_1D) { - glTexImage1D(tex->target, 0, internalformat, tex->w, 0, format, type, NULL); + float *rescaled_fpixels = NULL; + bool valid = gpu_texture_try_alloc(tex, proxy, internalformat, format, data_format, tex->components, can_rescale, + fpixels, &rescaled_fpixels); + if (!valid) { + if (err_out) + BLI_snprintf(err_out, 256, "GPUTexture: texture alloc failed"); + else + fprintf(stderr, "GPUTexture: texture alloc failed. Not enough Video Memory."); + GPU_texture_free(tex); + return NULL; + } - if (fpixels) { - glTexSubImage1D(tex->target, 0, 0, w, format, type, - pixels ? pixels : fpixels); + /* Upload Texture */ + const float *pix = (rescaled_fpixels) ? rescaled_fpixels : fpixels; - if (tex->w > w) { - gpu_glTexSubImageEmpty(tex->target, format, w, 0, tex->w - w, 1); - } - } - } - else { + if (tex->target == GL_TEXTURE_2D || + tex->target == GL_TEXTURE_2D_MULTISAMPLE || + tex->target == GL_TEXTURE_1D_ARRAY) + { if (samples) { glTexImage2DMultisample(tex->target, samples, internalformat, tex->w, tex->h, true); + if (pix) + glTexSubImage2D(tex->target, 0, 0, 0, tex->w, tex->h, format, data_format, pix); } else { - glTexImage2D(tex->target, 0, internalformat, tex->w, tex->h, 0, - format, type, NULL); - } - - if (fpixels) { - glTexSubImage2D(tex->target, 0, 0, 0, w, h, - format, type, pixels ? pixels : fpixels); - - if (tex->w > w) { - gpu_glTexSubImageEmpty(tex->target, format, w, 0, tex->w - w, tex->h); - } - if (tex->h > h) { - gpu_glTexSubImageEmpty(tex->target, format, 0, h, w, tex->h - h); - } + glTexImage2D(tex->target, 0, internalformat, tex->w, tex->h, 0, format, data_format, pix); } } + else if (tex->target == GL_TEXTURE_1D) { + glTexImage1D(tex->target, 0, internalformat, tex->w, 0, format, data_format, pix); + } + else { + glTexImage3D(tex->target, 0, internalformat, tex->w, tex->h, tex->d, 0, format, data_format, pix); + } - if (pixels) - MEM_freeN(pixels); + if (rescaled_fpixels) + MEM_freeN(rescaled_fpixels); - if (depth) { + /* Texture Parameters */ + 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_COMPARE_R_TO_TEXTURE); - glTexParameteri(tex->target_base, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL); - glTexParameteri(tex->target_base, GL_DEPTH_TEXTURE_MODE, GL_INTENSITY); + 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 (tex->target_base != GL_TEXTURE_1D) { - glTexParameteri(tex->target_base, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + 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); } - else - glTexParameteri(tex->target_base, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + if (n > 2) { + glTexParameteri(tex->target_base, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); + } + + glBindTexture(tex->target, 0); return tex; } - -GPUTexture *GPU_texture_create_3D(int w, int h, int depth, int channels, const float *fpixels) +static GPUTexture *GPU_texture_cube_create( + int w, int d, + const float *fpixels_px, const float *fpixels_py, const float *fpixels_pz, + const float *fpixels_nx, const float *fpixels_ny, const float *fpixels_nz, + GPUTextureFormat data_type, + char err_out[256]) { - GLenum type, format, internalformat; - void *pixels = NULL; + GLenum format, internalformat, data_format; GPUTexture *tex = MEM_callocN(sizeof(GPUTexture), "GPUTexture"); tex->w = w; - tex->h = h; - tex->depth = depth; + tex->h = w; + tex->d = d; + tex->samples = 0; tex->number = -1; tex->refcount = 1; - tex->target = GL_TEXTURE_3D; - tex->target_base = GL_TEXTURE_3D; + tex->format = data_type; + tex->components = gpu_texture_get_component_count(data_type); + tex->format_flag = GPU_FORMAT_CUBE; + if (d == 0) { + tex->target_base = tex->target = GL_TEXTURE_CUBE_MAP; + } + else { + BLI_assert(false && "Cubemap array Not implemented yet"); + // tex->target_base = tex->target = GL_TEXTURE_CUBE_MAP_ARRAY; + } + + internalformat = gpu_texture_get_format(tex->components, data_type, &format, &data_format, + &tex->format_flag, &tex->bytesize); + + gpu_texture_memory_footprint_add(tex); + + /* Generate Texture object */ glGenTextures(1, &tex->bindcode); if (!tex->bindcode) { - fprintf(stderr, "GPUTexture: texture create failed: %d\n", - (int)glGetError()); + if (err_out) + BLI_snprintf(err_out, 256, "GPUTexture: texture create failed"); + else + fprintf(stderr, "GPUTexture: texture create failed"); GPU_texture_free(tex); return NULL; } - tex->number = 0; glBindTexture(tex->target, tex->bindcode); - GPU_ASSERT_NO_GL_ERRORS("3D glBindTexture"); - - type = GL_FLOAT; - if (channels == 4) { - format = GL_RGBA; - internalformat = GL_RGBA8; + /* Upload Texture */ + glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0, internalformat, tex->w, tex->h, 0, format, data_format, fpixels_px); + glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Y, 0, internalformat, tex->w, tex->h, 0, format, data_format, fpixels_py); + glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Z, 0, internalformat, tex->w, tex->h, 0, format, data_format, fpixels_pz); + glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_X, 0, internalformat, tex->w, tex->h, 0, format, data_format, fpixels_nx); + glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, 0, internalformat, tex->w, tex->h, 0, format, data_format, fpixels_ny); + glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, 0, internalformat, tex->w, tex->h, 0, format, data_format, fpixels_nz); + + /* Texture Parameters */ + 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_NEAREST); } else { - format = GL_RED; - internalformat = GL_INTENSITY8; + glTexParameteri(tex->target_base, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(tex->target_base, GL_TEXTURE_MAG_FILTER, GL_LINEAR); } - /* 3D textures are quite heavy, test if it's possible to create them first */ - glTexImage3D(GL_PROXY_TEXTURE_3D, 0, internalformat, tex->w, tex->h, tex->depth, 0, format, type, NULL); - - bool rescale = false; - int r_width; - - glGetTexLevelParameteriv(GL_PROXY_TEXTURE_3D, 0, GL_TEXTURE_WIDTH, &r_width); - - while (r_width == 0) { - rescale = true; - tex->w /= 2; - tex->h /= 2; - tex->depth /= 2; - glTexImage3D(GL_PROXY_TEXTURE_3D, 0, internalformat, tex->w, tex->h, tex->depth, 0, format, type, NULL); - glGetTexLevelParameteriv(GL_PROXY_TEXTURE_3D, 0, GL_TEXTURE_WIDTH, &r_width); + 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); } - /* really unlikely to happen but keep this just in case */ - tex->w = max_ii(tex->w, 1); - tex->h = max_ii(tex->h, 1); - tex->depth = max_ii(tex->depth, 1); - -#if 0 - if (fpixels) - pixels = GPU_texture_convert_pixels(w*h*depth, fpixels); -#endif + 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_ASSERT_NO_GL_ERRORS("3D glTexImage3D"); - - /* hardcore stuff, 3D texture rescaling - warning, this is gonna hurt your performance a lot, but we need it - * for gooseberry */ - if (rescale && fpixels) { - /* FIXME: should these be floating point? */ - const unsigned int xf = w / tex->w, yf = h / tex->h, zf = depth / tex->depth; - float *tex3d = MEM_mallocN(channels * sizeof(float) * tex->w * tex->h * tex->depth, "tex3d"); - - GPU_print_error_debug("You need to scale a 3D texture, feel the pain!"); - - for (unsigned k = 0; k < tex->depth; k++) { - for (unsigned j = 0; j < tex->h; j++) { - for (unsigned i = 0; i < tex->w; i++) { - /* obviously doing nearest filtering here, - * it's going to be slow in any case, let's not make it worse */ - float xb = i * xf; - float yb = j * yf; - float zb = k * zf; - unsigned int offset = k * (tex->w * tex->h) + i * tex->h + j; - unsigned int offset_orig = (zb) * (w * h) + (xb) * h + (yb); + glBindTexture(tex->target, 0); - if (channels == 4) { - tex3d[offset * 4] = fpixels[offset_orig * 4]; - tex3d[offset * 4 + 1] = fpixels[offset_orig * 4 + 1]; - tex3d[offset * 4 + 2] = fpixels[offset_orig * 4 + 2]; - tex3d[offset * 4 + 3] = fpixels[offset_orig * 4 + 3]; - } - else - tex3d[offset] = fpixels[offset_orig]; - } - } - } - - glTexImage3D(tex->target, 0, internalformat, tex->w, tex->h, tex->depth, 0, format, type, tex3d); + return tex; +} - MEM_freeN(tex3d); - } - else { - if (fpixels) { - glTexImage3D(tex->target, 0, internalformat, tex->w, tex->h, tex->depth, 0, format, type, fpixels); - GPU_ASSERT_NO_GL_ERRORS("3D glTexSubImage3D"); - } +/* Special buffer textures. data_type must be compatible with the buffer content. */ +static GPUTexture *GPU_texture_create_buffer(GPUTextureFormat data_type, const GLuint buffer) +{ + GPUTexture *tex = MEM_callocN(sizeof(GPUTexture), "GPUTexture"); + tex->number = -1; + tex->refcount = 1; + tex->format = data_type; + tex->components = gpu_texture_get_component_count(data_type); + tex->format_flag = 0; + tex->target_base = tex->target = GL_TEXTURE_BUFFER; + + GLenum format, internalformat, data_format; + internalformat = gpu_texture_get_format(tex->components, data_type, &format, &data_format, + &tex->format_flag, &tex->bytesize); + + if (!(ELEM(data_type, GPU_R8, GPU_R16) || + ELEM(data_type, GPU_R16F, GPU_R32F) || + ELEM(data_type, GPU_R8I, GPU_R16I, GPU_R32I) || + ELEM(data_type, GPU_R8UI, GPU_R16UI, GPU_R32UI) || + ELEM(data_type, GPU_RG8, GPU_RG16) || + ELEM(data_type, GPU_RG16F, GPU_RG32F) || + ELEM(data_type, GPU_RG8I, GPU_RG16I, GPU_RG32I) || + ELEM(data_type, GPU_RG8UI, GPU_RG16UI, GPU_RG32UI) || + //ELEM(data_type, GPU_RGB32F, GPU_RGB32I, GPU_RGB32UI) || /* Not available until gl 4.0 */ + ELEM(data_type, GPU_RGBA8, GPU_RGBA16) || + ELEM(data_type, GPU_RGBA16F, GPU_RGBA32F) || + ELEM(data_type, GPU_RGBA8I, GPU_RGBA16I, GPU_RGBA32I) || + ELEM(data_type, GPU_RGBA8UI, GPU_RGBA16UI, GPU_RGBA32UI))) + { + fprintf(stderr, "GPUTexture: invalid format for texture buffer"); + GPU_texture_free(tex); + return NULL; } + /* Generate Texture object */ + glGenTextures(1, &tex->bindcode); - glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); - - if (pixels) - MEM_freeN(pixels); + if (!tex->bindcode) { + fprintf(stderr, "GPUTexture: texture create failed"); + GPU_texture_free(tex); + BLI_assert(0 && "glGenTextures failled: Are you sure a valid OGL context is active on this thread?"); + return NULL; + } - GPU_texture_unbind(tex); + glBindTexture(tex->target, tex->bindcode); + glTexBuffer(tex->target, internalformat, buffer); + glBindTexture(tex->target, 0); return tex; } -GPUTexture *GPU_texture_from_blender(Image *ima, ImageUser *iuser, int textarget, bool is_data, double time, int mipmap) +GPUTexture *GPU_texture_from_blender(Image *ima, ImageUser *iuser, int textarget, bool is_data, double UNUSED(time), int mipmap) { int gputt; /* this binds a texture, so that's why to restore it to 0 */ - GLint bindcode = GPU_verify_image(ima, iuser, textarget, 0, 0, mipmap, is_data); - GPU_update_image_time(ima, time); + GLint bindcode = GPU_verify_image(ima, iuser, textarget, 0, mipmap, is_data); /* see GPUInput::textarget: it can take two values - GL_TEXTURE_2D and GL_TEXTURE_CUBE_MAP * these values are correct for glDisable, so textarget can be safely used in * GPU_texture_bind/GPU_texture_unbind through tex->target_base */ + /* (is any of this obsolete now that we don't glEnable/Disable textures?) */ if (textarget == GL_TEXTURE_2D) gputt = TEXTARGET_TEXTURE_2D; else @@ -398,14 +694,17 @@ GPUTexture *GPU_texture_from_blender(Image *ima, ImageUser *iuser, int textarget tex->target = textarget; tex->target_base = textarget; tex->fromblender = 1; + tex->format = -1; + tex->components = -1; + tex->samples = 0; ima->gputexture[gputt] = tex; if (!glIsTexture(tex->bindcode)) { - GPU_ASSERT_NO_GL_ERRORS("Blender Texture Not Loaded"); + GPU_print_error_debug("Blender Texture Not Loaded"); } else { - GLint w, h, border; + GLint w, h; GLenum gettarget; @@ -417,10 +716,8 @@ GPUTexture *GPU_texture_from_blender(Image *ima, ImageUser *iuser, int textarget glBindTexture(textarget, tex->bindcode); glGetTexLevelParameteriv(gettarget, 0, GL_TEXTURE_WIDTH, &w); glGetTexLevelParameteriv(gettarget, 0, GL_TEXTURE_HEIGHT, &h); - glGetTexLevelParameteriv(gettarget, 0, GL_TEXTURE_BORDER, &border); - - tex->w = w - border; - tex->h = h - border; + tex->w = w; + tex->h = h; } glBindTexture(textarget, 0); @@ -452,11 +749,13 @@ GPUTexture *GPU_texture_from_preview(PreviewImage *prv, int mipmap) tex->refcount = 1; tex->target = GL_TEXTURE_2D; tex->target_base = GL_TEXTURE_2D; + tex->format = -1; + tex->components = -1; prv->gputexture[0] = tex; if (!glIsTexture(tex->bindcode)) { - GPU_ASSERT_NO_GL_ERRORS("Blender Texture Not Loaded"); + GPU_print_error_debug("Blender Texture Not Loaded"); } else { GLint w, h; @@ -475,114 +774,165 @@ GPUTexture *GPU_texture_from_preview(PreviewImage *prv, int mipmap) } -GPUTexture *GPU_texture_create_1D(int w, const float *fpixels, char err_out[256]) +GPUTexture *GPU_texture_create_1D( + int w, GPUTextureFormat data_type, const float *pixels, char err_out[256]) { - GPUTexture *tex = GPU_texture_create_nD(w, 1, 1, fpixels, 0, GPU_HDR_NONE, 4, 0, err_out); - - if (tex) - GPU_texture_unbind(tex); - - return tex; + return GPU_texture_create_nD(w, 0, 0, 1, pixels, data_type, 0, false, err_out); } -GPUTexture *GPU_texture_create_2D(int w, int h, const float *fpixels, GPUHDRType hdr, char err_out[256]) +GPUTexture *GPU_texture_create_2D( + int w, int h, GPUTextureFormat data_type, const float *pixels, char err_out[256]) { - GPUTexture *tex = GPU_texture_create_nD(w, h, 2, fpixels, 0, hdr, 4, 0, err_out); - - if (tex) - GPU_texture_unbind(tex); - - return tex; + return GPU_texture_create_nD(w, h, 0, 2, pixels, data_type, 0, false, err_out); } + GPUTexture *GPU_texture_create_2D_multisample( - int w, int h, const float *fpixels, GPUHDRType hdr, int samples, char err_out[256]) + int w, int h, GPUTextureFormat data_type, const float *pixels, int samples, char err_out[256]) { - GPUTexture *tex = GPU_texture_create_nD(w, h, 2, fpixels, 0, hdr, 4, samples, err_out); - - if (tex) - GPU_texture_unbind(tex); - - return tex; + return GPU_texture_create_nD(w, h, 0, 2, pixels, data_type, samples, false, err_out); } -GPUTexture *GPU_texture_create_depth(int w, int h, char err_out[256]) +GPUTexture *GPU_texture_create_2D_array( + int w, int h, int d, GPUTextureFormat data_type, const float *pixels, char err_out[256]) { - GPUTexture *tex = GPU_texture_create_nD(w, h, 2, NULL, 1, GPU_HDR_NONE, 1, 0, err_out); - - if (tex) - GPU_texture_unbind(tex); - - return tex; + return GPU_texture_create_nD(w, h, d, 2, pixels, data_type, 0, false, err_out); } -GPUTexture *GPU_texture_create_depth_multisample(int w, int h, int samples, char err_out[256]) -{ - GPUTexture *tex = GPU_texture_create_nD(w, h, 2, NULL, 1, GPU_HDR_NONE, 1, samples, err_out); - - if (tex) - GPU_texture_unbind(tex); - return tex; +GPUTexture *GPU_texture_create_3D( + int w, int h, int d, GPUTextureFormat data_type, const float *pixels, char err_out[256]) +{ + return GPU_texture_create_nD(w, h, d, 3, pixels, data_type, 0, true, err_out); } -/** - * A shadow map for VSM needs two components (depth and depth^2) - */ -GPUTexture *GPU_texture_create_vsm_shadow_map(int size, char err_out[256]) +GPUTexture *GPU_texture_create_cube( + int w, GPUTextureFormat data_type, const float *fpixels, char err_out[256]) { - GPUTexture *tex = GPU_texture_create_nD(size, size, 2, NULL, 0, GPU_HDR_FULL_FLOAT, 2, 0, err_out); - - if (tex) { - /* Now we tweak some of the settings */ - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - - GPU_texture_unbind(tex); + const float *fpixels_px, *fpixels_py, *fpixels_pz, *fpixels_nx, *fpixels_ny, *fpixels_nz; + const int channels = gpu_texture_get_component_count(data_type); + + if (fpixels) { + fpixels_px = fpixels + 0 * w * w * channels; + fpixels_nx = fpixels + 1 * w * w * channels; + fpixels_py = fpixels + 2 * w * w * channels; + fpixels_ny = fpixels + 3 * w * w * channels; + fpixels_pz = fpixels + 4 * w * w * channels; + fpixels_nz = fpixels + 5 * w * w * channels; + } + else { + fpixels_px = fpixels_py = fpixels_pz = fpixels_nx = fpixels_ny = fpixels_nz = NULL; } - return tex; + return GPU_texture_cube_create(w, 0, fpixels_px, fpixels_py, fpixels_pz, fpixels_nx, fpixels_ny, fpixels_nz, + data_type, err_out); } -GPUTexture *GPU_texture_create_2D_procedural(int w, int h, const float *pixels, bool repeat, char err_out[256]) +GPUTexture *GPU_texture_create_from_vertbuf(Gwn_VertBuf *vert) { - GPUTexture *tex = GPU_texture_create_nD(w, h, 2, pixels, 0, GPU_HDR_HALF_FLOAT, 2, 0, err_out); + Gwn_VertFormat *format = &vert->format; + Gwn_VertAttr *attr = &format->attribs[0]; - if (tex) { - /* Now we tweak some of the settings */ - if (repeat) { - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); - } - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + /* Detect incompatible cases (not supported by texture buffers) */ + BLI_assert(format->attrib_ct == 1 && vert->vbo_id != 0); + BLI_assert(attr->comp_ct != 3); /* Not until OGL 4.0 */ + BLI_assert(attr->comp_type != GWN_COMP_I10); + BLI_assert(attr->fetch_mode != GWN_FETCH_INT_TO_FLOAT); - GPU_texture_unbind(tex); + unsigned int byte_per_comp = attr->sz / attr->comp_ct; + bool is_uint = ELEM(attr->comp_type, GWN_COMP_U8, GWN_COMP_U16, GWN_COMP_U32); + + /* Cannot fetch signed int or 32bit ints as normalized float. */ + if (attr->fetch_mode == GWN_FETCH_INT_TO_FLOAT_UNIT) { + BLI_assert(is_uint || byte_per_comp <= 2); } - return tex; + GPUTextureFormat data_type; + switch (attr->fetch_mode) { + case GWN_FETCH_FLOAT: + switch (attr->comp_ct) { + case 1: data_type = GPU_R32F; break; + case 2: data_type = GPU_RG32F; break; + // case 3: data_type = GPU_RGB32F; break; /* Not supported */ + default: data_type = GPU_RGBA32F; break; + } + break; + case GWN_FETCH_INT: + switch (attr->comp_ct) { + case 1: + switch (byte_per_comp) { + case 1: data_type = (is_uint) ? GPU_R8UI : GPU_R8I; break; + case 2: data_type = (is_uint) ? GPU_R16UI : GPU_R16I; break; + default: data_type = (is_uint) ? GPU_R32UI : GPU_R32I; break; + } + break; + case 2: + switch (byte_per_comp) { + case 1: data_type = (is_uint) ? GPU_RG8UI : GPU_RG8I; break; + case 2: data_type = (is_uint) ? GPU_RG16UI : GPU_RG16I; break; + default: data_type = (is_uint) ? GPU_RG32UI : GPU_RG32I; break; + } + break; + default: + switch (byte_per_comp) { + case 1: data_type = (is_uint) ? GPU_RGBA8UI : GPU_RGBA8I; break; + case 2: data_type = (is_uint) ? GPU_RGBA16UI : GPU_RGBA16I; break; + default: data_type = (is_uint) ? GPU_RGBA32UI : GPU_RGBA32I; break; + } + break; + } + break; + case GWN_FETCH_INT_TO_FLOAT_UNIT: + switch (attr->comp_ct) { + case 1: data_type = (byte_per_comp == 1) ? GPU_R8 : GPU_R16; break; + case 2: data_type = (byte_per_comp == 1) ? GPU_RG8 : GPU_RG16; break; + default: data_type = (byte_per_comp == 1) ? GPU_RGBA8 : GPU_RGBA16; break; + } + break; + default: + BLI_assert(0); + return NULL; + } + + return GPU_texture_create_buffer(data_type, vert->vbo_id); } -GPUTexture *GPU_texture_create_1D_procedural(int w, const float *pixels, char err_out[256]) +void GPU_texture_update(GPUTexture *tex, const float *pixels) { - GPUTexture *tex = GPU_texture_create_nD(w, 0, 1, pixels, 0, GPU_HDR_HALF_FLOAT, 2, 0, err_out); + BLI_assert(tex->format > -1); + BLI_assert(tex->components > -1); - if (tex) { - /* Now we tweak some of the settings */ - glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_REPEAT); - glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + GLenum format, data_format; + gpu_texture_get_format(tex->components, tex->format, &format, &data_format, + &tex->format_flag, &tex->bytesize); - GPU_texture_unbind(tex); + glBindTexture(tex->target, tex->bindcode); + + switch (tex->target) { + case GL_TEXTURE_2D: + case GL_TEXTURE_2D_MULTISAMPLE: + case GL_TEXTURE_1D_ARRAY: + glTexSubImage2D(tex->target, 0, 0, 0, tex->w, tex->h, format, data_format, pixels); + break; + case GL_TEXTURE_1D: + glTexSubImage1D(tex->target, 0, 0, tex->w, format, data_format, pixels); + break; + case GL_TEXTURE_3D: + case GL_TEXTURE_2D_ARRAY: + glTexSubImage3D(tex->target, 0, 0, 0, 0, tex->w, tex->h, tex->d, format, data_format, pixels); + break; + default: + BLI_assert(!"tex->target mode not supported"); } - return tex; + glBindTexture(tex->target, 0); } void GPU_invalid_tex_init(void) { + memory_usage = 0; const float color[4] = {1.0f, 0.0f, 1.0f, 1.0f}; - GG.invalid_tex_1D = GPU_texture_create_1D(1, color, NULL); - GG.invalid_tex_2D = GPU_texture_create_2D(1, 1, color, GPU_HDR_NONE, NULL); - GG.invalid_tex_3D = GPU_texture_create_3D(1, 1, 1, 4, color); + GG.invalid_tex_1D = GPU_texture_create_1D(1, GPU_RGBA8, color, NULL); + GG.invalid_tex_2D = GPU_texture_create_2D(1, 1, GPU_RGBA8, color, NULL); + GG.invalid_tex_3D = GPU_texture_create_3D(1, 1, 1, GPU_RGBA8, color, NULL); } void GPU_invalid_tex_bind(int mode) @@ -610,61 +960,45 @@ 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; - - GPU_ASSERT_NO_GL_ERRORS("Pre Texture Bind"); + glActiveTexture(GL_TEXTURE0 + number); - GLenum arbnumber = (GLenum)((GLuint)GL_TEXTURE0 + number); - if (number != 0) glActiveTexture(arbnumber); - if (tex->bindcode != 0) { - glBindTexture(tex->target_base, tex->bindcode); - } + if (tex->bindcode != 0) + glBindTexture(tex->target, tex->bindcode); else GPU_invalid_tex_bind(tex->target_base); - glEnable(tex->target_base); - if (number != 0) glActiveTexture(GL_TEXTURE0); tex->number = number; - - GPU_ASSERT_NO_GL_ERRORS("Post Texture Bind"); } 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; - - GPU_ASSERT_NO_GL_ERRORS("Pre Texture Unbind"); - GLenum arbnumber = (GLenum)((GLuint)GL_TEXTURE0 + tex->number); - if (tex->number != 0) glActiveTexture(arbnumber); - glBindTexture(tex->target_base, 0); - glDisable(tex->target_base); - if (tex->number != 0) glActiveTexture(GL_TEXTURE0); + glActiveTexture(GL_TEXTURE0 + tex->number); + glBindTexture(tex->target, 0); tex->number = -1; - - GPU_ASSERT_NO_GL_ERRORS("Post Texture Unbind"); } int GPU_texture_bound_number(GPUTexture *tex) @@ -672,39 +1006,79 @@ int GPU_texture_bound_number(GPUTexture *tex) return tex->number; } -void GPU_texture_filter_mode(GPUTexture *tex, bool compare, bool use_filter) +#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; - } + WARN_NOT_BOUND(tex); - if (tex->number == -1) + glActiveTexture(GL_TEXTURE0 + tex->number); + glGenerateMipmap(tex->target_base); +} + +void GPU_texture_compare_mode(GPUTexture *tex, bool use_compare) +{ + WARN_NOT_BOUND(tex); + + /* Could become an assertion ? (fclem) */ + if (!GPU_texture_depth(tex)) return; - GPU_ASSERT_NO_GL_ERRORS("Pre Texture Unbind"); + GLenum mode = (use_compare) ? GL_COMPARE_REF_TO_TEXTURE : GL_NONE; + + glActiveTexture(GL_TEXTURE0 + tex->number); + glTexParameteri(tex->target_base, GL_TEXTURE_COMPARE_MODE, mode); +} - GLenum arbnumber = (GLenum)((GLuint)GL_TEXTURE0 + tex->number); - if (tex->number != 0) glActiveTexture(arbnumber); +void GPU_texture_filter_mode(GPUTexture *tex, bool use_filter) +{ + WARN_NOT_BOUND(tex); - if (tex->depth) { - if (compare) - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE); - else - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_NONE); - } + /* Stencil and integer format does not support filtering. */ + BLI_assert(!use_filter || !(GPU_texture_stencil(tex) || GPU_texture_integer(tex))); - if (use_filter) { - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - } - else { - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - } - if (tex->number != 0) glActiveTexture(GL_TEXTURE0); + 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); +} + +void GPU_texture_mipmap_mode(GPUTexture *tex, bool use_mipmap, bool use_filter) +{ + WARN_NOT_BOUND(tex); - GPU_ASSERT_NO_GL_ERRORS("Post Texture Unbind"); + /* 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; + + glActiveTexture(GL_TEXTURE0 + tex->number); + glTexParameteri(tex->target_base, GL_TEXTURE_MIN_FILTER, mipmap); + glTexParameteri(tex->target_base, GL_TEXTURE_MAG_FILTER, filter); +} + +void GPU_texture_wrap_mode(GPUTexture *tex, bool use_repeat) +{ + WARN_NOT_BOUND(tex); + + 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); } void GPU_texture_free(GPUTexture *tex) @@ -715,11 +1089,17 @@ 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); + gpu_texture_memory_footprint_remove(tex); + MEM_freeN(tex); } } @@ -744,29 +1124,64 @@ int GPU_texture_height(const GPUTexture *tex) return tex->h; } -int GPU_texture_depth(const GPUTexture *tex) +GPUTextureFormat GPU_texture_format(const GPUTexture *tex) { - return tex->depth; + return tex->format; } -int GPU_texture_opengl_bindcode(const GPUTexture *tex) +int GPU_texture_samples(const GPUTexture *tex) { - return tex->bindcode; + return tex->samples; +} + +bool GPU_texture_depth(const GPUTexture *tex) +{ + return (tex->format_flag & GPU_FORMAT_DEPTH) != 0; } -GPUFrameBuffer *GPU_texture_framebuffer(GPUTexture *tex) +bool GPU_texture_stencil(const GPUTexture *tex) { - return tex->fb; + return (tex->format_flag & GPU_FORMAT_STENCIL) != 0; } -int GPU_texture_framebuffer_attachment(GPUTexture *tex) +bool GPU_texture_integer(const GPUTexture *tex) { - return tex->fb_attachment; + return (tex->format_flag & GPU_FORMAT_INTEGER) != 0; } -void GPU_texture_framebuffer_set(GPUTexture *tex, GPUFrameBuffer *fb, int attachment) +bool GPU_texture_cube(const GPUTexture *tex) { - tex->fb = fb; - tex->fb_attachment = attachment; + return (tex->format_flag & GPU_FORMAT_CUBE) != 0; } +int GPU_texture_opengl_bindcode(const GPUTexture *tex) +{ + return tex->bindcode; +} + +void GPU_texture_attach_framebuffer(GPUTexture *tex, GPUFrameBuffer *fb, int 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_uniformbuffer.c b/source/blender/gpu/intern/gpu_uniformbuffer.c new file mode 100644 index 00000000000..afd43600d9b --- /dev/null +++ b/source/blender/gpu/intern/gpu_uniformbuffer.c @@ -0,0 +1,378 @@ +/* + * ***** 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): Clement Foucault. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file gpu_uniformbuffer.c + * \ingroup gpu + */ + +#include <string.h> +#include "MEM_guardedalloc.h" + +#include "BLI_blenlib.h" + +#include "gpu_codegen.h" + +#include "GPU_extensions.h" +#include "GPU_glew.h" +#include "GPU_material.h" +#include "GPU_uniformbuffer.h" + +typedef enum GPUUniformBufferFlag { + GPU_UBO_FLAG_INITIALIZED = (1 << 0), + GPU_UBO_FLAG_DIRTY = (1 << 1), +} GPUUniformBufferFlag; + +typedef enum GPUUniformBufferType { + GPU_UBO_STATIC = 0, + GPU_UBO_DYNAMIC = 1, +} GPUUniformBufferType; + +struct GPUUniformBuffer { + int size; /* in bytes */ + GLuint bindcode; /* opengl identifier for UBO */ + int bindpoint; /* current binding point */ + GPUUniformBufferType type; +}; + +#define GPUUniformBufferStatic GPUUniformBuffer + +typedef struct GPUUniformBufferDynamic { + GPUUniformBuffer buffer; + ListBase items; /* GPUUniformBufferDynamicItem */ + void *data; + char flag; +} GPUUniformBufferDynamic; + +struct GPUUniformBufferDynamicItem { + struct GPUUniformBufferDynamicItem *next, *prev; + GPUType gputype; + float *data; + int size; +}; + + +/* Prototypes */ +static GPUType get_padded_gpu_type(struct LinkData *link); +static void gpu_uniformbuffer_inputs_sort(struct ListBase *inputs); + +static GPUUniformBufferDynamicItem *gpu_uniformbuffer_populate( + GPUUniformBufferDynamic *ubo, const GPUType gputype, float *num); + +/* Only support up to this type, if you want to extend it, make sure the + * padding logic is correct for the new types. */ +#define MAX_UBO_GPU_TYPE GPU_VEC4 + +static void gpu_uniformbuffer_initialize(GPUUniformBuffer *ubo, const void *data) +{ + glBindBuffer(GL_UNIFORM_BUFFER, ubo->bindcode); + glBufferData(GL_UNIFORM_BUFFER, ubo->size, data, GL_DYNAMIC_DRAW); + glBindBuffer(GL_UNIFORM_BUFFER, 0); +} + +GPUUniformBuffer *GPU_uniformbuffer_create(int size, const void *data, char err_out[256]) +{ + GPUUniformBuffer *ubo = MEM_callocN(sizeof(GPUUniformBufferStatic), "GPUUniformBufferStatic"); + ubo->size = size; + ubo->bindpoint = -1; + + /* Generate Buffer object */ + glGenBuffers(1, &ubo->bindcode); + + if (!ubo->bindcode) { + if (err_out) + BLI_snprintf(err_out, 256, "GPUUniformBuffer: UBO create failed"); + GPU_uniformbuffer_free(ubo); + return NULL; + } + + if (ubo->size > GPU_max_ubo_size()) { + if (err_out) + BLI_snprintf(err_out, 256, "GPUUniformBuffer: UBO too big"); + GPU_uniformbuffer_free(ubo); + return NULL; + } + + gpu_uniformbuffer_initialize(ubo, data); + return ubo; +} + +/** + * Create dynamic UBO from parameters + * Return NULL if failed to create or if \param inputs is empty. + * + * \param inputs ListBase of BLI_genericNodeN(GPUInput) + */ +GPUUniformBuffer *GPU_uniformbuffer_dynamic_create(ListBase *inputs, char err_out[256]) +{ + /* There is no point on creating an UBO if there is no arguments. */ + if (BLI_listbase_is_empty(inputs)) { + return NULL; + } + + GPUUniformBufferDynamic *ubo = MEM_callocN(sizeof(GPUUniformBufferDynamic), "GPUUniformBufferDynamic"); + ubo->buffer.type = GPU_UBO_DYNAMIC; + ubo->buffer.bindpoint = -1; + ubo->flag = GPU_UBO_FLAG_DIRTY; + + /* Generate Buffer object. */ + glGenBuffers(1, &ubo->buffer.bindcode); + + if (!ubo->buffer.bindcode) { + if (err_out) + BLI_snprintf(err_out, 256, "GPUUniformBuffer: UBO create failed"); + GPU_uniformbuffer_free(&ubo->buffer); + return NULL; + } + + if (ubo->buffer.size > GPU_max_ubo_size()) { + if (err_out) + BLI_snprintf(err_out, 256, "GPUUniformBuffer: UBO too big"); + GPU_uniformbuffer_free(&ubo->buffer); + return NULL; + } + + /* Make sure we comply to the ubo alignment requirements. */ + gpu_uniformbuffer_inputs_sort(inputs); + + for (LinkData *link = inputs->first; link; link = link->next) { + GPUInput *input = link->data; + GPUType gputype = get_padded_gpu_type(link); + gpu_uniformbuffer_populate(ubo, gputype, input->dynamicvec); + } + + ubo->data = MEM_mallocN(ubo->buffer.size, __func__); + + /* Initialize buffer data. */ + GPU_uniformbuffer_dynamic_update(&ubo->buffer); + return &ubo->buffer; +} + +/** + * Free the data, and clean the items list. + */ +static void gpu_uniformbuffer_dynamic_reset(GPUUniformBufferDynamic *ubo) +{ + ubo->buffer.size = 0; + if (ubo->data) { + MEM_freeN(ubo->data); + } + BLI_freelistN(&ubo->items); +} + +void GPU_uniformbuffer_free(GPUUniformBuffer *ubo) +{ + if (ubo->type == GPU_UBO_DYNAMIC) { + gpu_uniformbuffer_dynamic_reset((GPUUniformBufferDynamic *)ubo); + } + + glDeleteBuffers(1, &ubo->bindcode); + MEM_freeN(ubo); +} + +static void gpu_uniformbuffer_update(GPUUniformBuffer *ubo, const void *data) +{ + glBindBuffer(GL_UNIFORM_BUFFER, ubo->bindcode); + glBufferSubData(GL_UNIFORM_BUFFER, 0, ubo->size, data); + glBindBuffer(GL_UNIFORM_BUFFER, 0); +} + +void GPU_uniformbuffer_update(GPUUniformBuffer *ubo, const void *data) +{ + BLI_assert(ubo->type == GPU_UBO_STATIC); + gpu_uniformbuffer_update(ubo, data); +} + +/** + * We need to recalculate the internal data, and re-generate it + * from its populated items. + */ +void GPU_uniformbuffer_dynamic_update(GPUUniformBuffer *ubo_) +{ + BLI_assert(ubo_->type == GPU_UBO_DYNAMIC); + GPUUniformBufferDynamic *ubo = (GPUUniformBufferDynamic *)ubo_; + + float *offset = ubo->data; + for (GPUUniformBufferDynamicItem *item = ubo->items.first; item; item = item->next) { + memcpy(offset, item->data, item->size); + offset += item->gputype; + } + + if (ubo->flag & GPU_UBO_FLAG_INITIALIZED) { + gpu_uniformbuffer_update(ubo_, ubo->data); + } + else { + ubo->flag |= GPU_UBO_FLAG_INITIALIZED; + gpu_uniformbuffer_initialize(ubo_, ubo->data); + } + + ubo->flag &= ~GPU_UBO_FLAG_DIRTY; +} + +/** + * We need to pad some data types (vec3) on the C side + * To match the GPU expected memory block alignment. + */ +static GPUType get_padded_gpu_type(LinkData *link) +{ + GPUInput *input = link->data; + GPUType gputype = input->type; + + /* Unless the vec3 is followed by a float we need to treat it as a vec4. */ + if (gputype == GPU_VEC3 && + (link->next != NULL) && + (((GPUInput *)link->next->data)->type != GPU_FLOAT)) + { + gputype = GPU_VEC4; + } + + return gputype; +} + +/** + * Returns 1 if the first item shold be after second item. + * We make sure the vec4 uniforms come first. + */ +static int inputs_cmp(const void *a, const void *b) +{ + const LinkData *link_a = a, *link_b = b; + const GPUInput *input_a = link_a->data, *input_b = link_b->data; + return input_a->type < input_b->type ? 1 : 0; +} + +/** + * Make sure we respect the expected alignment of UBOs. + * vec4, pad vec3 as vec4, then vec2, then floats. + */ +static void gpu_uniformbuffer_inputs_sort(ListBase *inputs) +{ + /* Order them as vec4, vec3, vec2, float. */ + BLI_listbase_sort(inputs, inputs_cmp); + + /* Creates a lookup table for the different types; */ + LinkData *inputs_lookup[MAX_UBO_GPU_TYPE + 1] = {NULL}; + GPUType cur_type = MAX_UBO_GPU_TYPE + 1; + + for (LinkData *link = inputs->first; link; link = link->next) { + GPUInput *input = link->data; + if (input->type == cur_type) { + continue; + } + else { + inputs_lookup[input->type] = link; + cur_type = input->type; + } + } + + /* If there is no GPU_VEC3 there is no need for alignment. */ + if (inputs_lookup[GPU_VEC3] == NULL) { + return; + } + + LinkData *link = inputs_lookup[GPU_VEC3]; + while (link != NULL && ((GPUInput *)link->data)->type == GPU_VEC3) { + LinkData *link_next = link->next; + + /* If GPU_VEC3 is followed by nothing or a GPU_FLOAT, no need for aligment. */ + if ((link_next == NULL) || + ((GPUInput *)link_next->data)->type == GPU_FLOAT) + { + break; + } + + /* If there is a float, move it next to current vec3. */ + if (inputs_lookup[GPU_FLOAT] != NULL) { + LinkData *float_input = inputs_lookup[GPU_FLOAT]; + inputs_lookup[GPU_FLOAT] = float_input->next; + + BLI_remlink(inputs, float_input); + BLI_insertlinkafter(inputs, link, float_input); + } + + link = link_next; + } +} + +/** + * This may now happen from the main thread, so we can't update the UBO + * We simply flag it as dirty + */ +static GPUUniformBufferDynamicItem *gpu_uniformbuffer_populate( + GPUUniformBufferDynamic *ubo, const GPUType gputype, float *num) +{ + BLI_assert(gputype <= MAX_UBO_GPU_TYPE); + GPUUniformBufferDynamicItem *item = MEM_callocN(sizeof(GPUUniformBufferDynamicItem), __func__); + + item->gputype = gputype; + item->data = num; + item->size = gputype * sizeof(float); + ubo->buffer.size += item->size; + + ubo->flag |= GPU_UBO_FLAG_DIRTY; + BLI_addtail(&ubo->items, item); + + return item; +} + +void GPU_uniformbuffer_bind(GPUUniformBuffer *ubo, int number) +{ + if (number >= GPU_max_ubo_binds()) { + fprintf(stderr, "Not enough UBO slots.\n"); + return; + } + + if (ubo->type == GPU_UBO_DYNAMIC) { + GPUUniformBufferDynamic *ubo_dynamic = (GPUUniformBufferDynamic *)ubo; + if (ubo_dynamic->flag & GPU_UBO_FLAG_DIRTY) { + GPU_uniformbuffer_dynamic_update(ubo); + } + } + + if (ubo->bindcode != 0) { + glBindBufferBase(GL_UNIFORM_BUFFER, number, ubo->bindcode); + } + + ubo->bindpoint = number; +} + +void GPU_uniformbuffer_unbind(GPUUniformBuffer *ubo) +{ + ubo->bindpoint = -1; +} + +int GPU_uniformbuffer_bindpoint(GPUUniformBuffer *ubo) +{ + return ubo->bindpoint; +} + +void GPU_uniformbuffer_tag_dirty(GPUUniformBuffer *ubo_) +{ + BLI_assert(ubo_->type == GPU_UBO_DYNAMIC); + GPUUniformBufferDynamic *ubo = (GPUUniformBufferDynamic *)ubo_; + ubo->flag |= GPU_UBO_FLAG_DIRTY; +} + +#undef MAX_UBO_GPU_TYPE diff --git a/source/blender/gpu/intern/gpu_viewport.c b/source/blender/gpu/intern/gpu_viewport.c new file mode 100644 index 00000000000..0bf215f31a8 --- /dev/null +++ b/source/blender/gpu/intern/gpu_viewport.c @@ -0,0 +1,644 @@ +/* + * ***** 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): + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/gpu/intern/gpu_viewport.c + * \ingroup gpu + * + * System that manages viewport drawing. + */ + +#include <string.h> + +#include "BLI_listbase.h" +#include "BLI_rect.h" +#include "BLI_string.h" +#include "BLI_mempool.h" + +#include "BIF_gl.h" + +#include "DNA_vec_types.h" +#include "DNA_userdef_types.h" + +#include "BKE_global.h" + +#include "GPU_framebuffer.h" +#include "GPU_glew.h" +#include "GPU_immediate.h" +#include "GPU_texture.h" +#include "GPU_viewport.h" +#include "GPU_draw.h" + +#include "DRW_engine.h" + +#include "MEM_guardedalloc.h" + +static const int default_fbl_len = (sizeof(DefaultFramebufferList)) / sizeof(void *); +static const int default_txl_len = (sizeof(DefaultTextureList)) / sizeof(void *); + +/* Maximum number of simultaneous engine enabled at the same time. + * Setting it lower than the real number will do lead to + * higher VRAM usage due to sub-efficient buffer reuse. */ +#define MAX_ENGINE_BUFFER_SHARING 5 + +typedef struct ViewportTempTexture { + struct ViewportTempTexture *next, *prev; + void *user[MAX_ENGINE_BUFFER_SHARING]; + GPUTexture *texture; +} ViewportTempTexture; + +struct GPUViewport { + int size[2]; + int samples; + int flag; + + ListBase data; /* ViewportEngineData wrapped in LinkData */ + unsigned int data_hash; /* If hash mismatch we free all ViewportEngineData in this viewport */ + + DefaultFramebufferList *fbl; + DefaultTextureList *txl; + + ViewportMemoryPool vmempool; /* Used for rendering data structure. */ + 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 { + DO_UPDATE = (1 << 0), +}; + +static void gpu_viewport_buffers_free(FramebufferList *fbl, int fbl_len, TextureList *txl, int txl_len); +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) +{ + viewport->flag |= DO_UPDATE; +} + +bool GPU_viewport_do_update(GPUViewport *viewport) +{ + bool ret = (viewport->flag & DO_UPDATE); + viewport->flag &= ~DO_UPDATE; + return ret; +} + +GPUViewport *GPU_viewport_create(void) +{ + GPUViewport *viewport = MEM_callocN(sizeof(GPUViewport), "GPUViewport"); + viewport->fbl = MEM_callocN(sizeof(DefaultFramebufferList), "FramebufferList"); + viewport->txl = MEM_callocN(sizeof(DefaultTextureList), "TextureList"); + viewport->idatalist = DRW_instance_data_list_create(); + + viewport->size[0] = viewport->size[1] = -1; + + return viewport; +} + +GPUViewport *GPU_viewport_create_from_offscreen(struct GPUOffScreen *ofs) +{ + GPUViewport *viewport = GPU_viewport_create(); + 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; +} +/** + * Clear vars assigned from offscreen, so we don't free data owned by `GPUOffScreen`. + */ +void GPU_viewport_clear_from_offscreen(GPUViewport *viewport) +{ + 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) +{ + LinkData *ld = MEM_callocN(sizeof(LinkData), "LinkData"); + ViewportEngineData *data = MEM_callocN(sizeof(ViewportEngineData), "ViewportEngineData"); + int fbl_len, txl_len, psl_len, stl_len; + + DRW_engine_viewport_data_size_get(engine_type, &fbl_len, &txl_len, &psl_len, &stl_len); + + data->engine_type = engine_type; + + data->fbl = MEM_callocN((sizeof(void *) * fbl_len) + sizeof(FramebufferList), "FramebufferList"); + data->txl = MEM_callocN((sizeof(void *) * txl_len) + sizeof(TextureList), "TextureList"); + data->psl = MEM_callocN((sizeof(void *) * psl_len) + sizeof(PassList), "PassList"); + data->stl = MEM_callocN((sizeof(void *) * stl_len) + sizeof(StorageList), "StorageList"); + + ld->data = data; + BLI_addtail(&viewport->data, ld); + + return data; +} + +static void gpu_viewport_engines_data_free(GPUViewport *viewport) +{ + int fbl_len, txl_len, psl_len, stl_len; + + LinkData *next; + for (LinkData *link = viewport->data.first; link; link = next) { + next = link->next; + ViewportEngineData *data = link->data; + DRW_engine_viewport_data_size_get(data->engine_type, &fbl_len, &txl_len, &psl_len, &stl_len); + + gpu_viewport_buffers_free(data->fbl, fbl_len, data->txl, txl_len); + gpu_viewport_passes_free(data->psl, psl_len); + gpu_viewport_storage_free(data->stl, stl_len); + + MEM_freeN(data->fbl); + MEM_freeN(data->txl); + MEM_freeN(data->psl); + MEM_freeN(data->stl); + + /* We could handle this in the DRW module */ + if (data->text_draw_cache) { + extern void DRW_text_cache_destroy(struct DRWTextStore *dt); + DRW_text_cache_destroy(data->text_draw_cache); + data->text_draw_cache = NULL; + } + + MEM_freeN(data); + + BLI_remlink(&viewport->data, link); + MEM_freeN(link); + } + + gpu_viewport_texture_pool_free(viewport); +} + +void *GPU_viewport_engine_data_get(GPUViewport *viewport, void *engine_type) +{ + for (LinkData *link = viewport->data.first; link; link = link->next) { + ViewportEngineData *vdata = link->data; + if (vdata->engine_type == engine_type) { + return vdata; + } + } + return NULL; +} + +ViewportMemoryPool *GPU_viewport_mempool_get(GPUViewport *viewport) +{ + return &viewport->vmempool; +} + +struct DRWInstanceDataList *GPU_viewport_instance_data_list_get(GPUViewport *viewport) +{ + return viewport->idatalist; +} + +void *GPU_viewport_framebuffer_list_get(GPUViewport *viewport) +{ + return viewport->fbl; +} + +void *GPU_viewport_texture_list_get(GPUViewport *viewport) +{ + return viewport->txl; +} + +void GPU_viewport_size_get(const GPUViewport *viewport, int size[2]) +{ + size[0] = viewport->size[0]; + size[1] = viewport->size[1]; +} + +/** + * Special case, this is needed for when we have a viewport without a frame-buffer output + * (occlusion queries for eg) but still need to set the size since it may be used for other calculations. + */ +void GPU_viewport_size_set(GPUViewport *viewport, const int size[2]) +{ + viewport->size[0] = size[0]; + 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. + */ +GPUTexture *GPU_viewport_texture_pool_query(GPUViewport *viewport, void *engine, int width, int height, int format) +{ + GPUTexture *tex; + + for (ViewportTempTexture *tmp_tex = viewport->tex_pool.first; tmp_tex; tmp_tex = tmp_tex->next) { + 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) { + if (tmp_tex->user[i] == engine) { + break; + } + + if (tmp_tex->user[i] == NULL) { + tmp_tex->user[i] = engine; + return tmp_tex->texture; + } + } + } + } + + tex = GPU_texture_create_2D(width, height, 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; +} + +static void gpu_viewport_texture_pool_clear_users(GPUViewport *viewport) +{ + ViewportTempTexture *tmp_tex_next; + + for (ViewportTempTexture *tmp_tex = viewport->tex_pool.first; tmp_tex; tmp_tex = tmp_tex_next) { + tmp_tex_next = tmp_tex->next; + bool no_user = true; + for (int i = 0; i < MAX_ENGINE_BUFFER_SHARING; ++i) { + if (tmp_tex->user[i] != NULL) { + tmp_tex->user[i] = NULL; + no_user = false; + } + } + + if (no_user) { + GPU_texture_free(tmp_tex->texture); + BLI_freelinkN(&viewport->tex_pool, tmp_tex); + } + } +} + +static void gpu_viewport_texture_pool_free(GPUViewport *viewport) +{ + for (ViewportTempTexture *tmp_tex = viewport->tex_pool.first; tmp_tex; tmp_tex = tmp_tex->next) { + GPU_texture_free(tmp_tex->texture); + } + + BLI_freelistN(&viewport->tex_pool); +} + +bool GPU_viewport_engines_data_validate(GPUViewport *viewport, unsigned int hash) +{ + bool dirty = false; + + if (viewport->data_hash != hash) { + gpu_viewport_engines_data_free(viewport); + dirty = true; + } + + viewport->data_hash = hash; + + return dirty; +} + +void GPU_viewport_cache_release(GPUViewport *viewport) +{ + for (LinkData *link = viewport->data.first; link; link = link->next) { + ViewportEngineData *data = link->data; + int psl_len; + DRW_engine_viewport_data_size_get(data->engine_type, NULL, NULL, &psl_len, NULL); + gpu_viewport_passes_free(data->psl, psl_len); + } +} + +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], GPU_RGBA8, NULL, NULL); + dtxl->depth = GPU_texture_create_2D(size[0], size[1], GPU_DEPTH24_STENCIL8, NULL, 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], GPU_RGBA8, NULL, samples, NULL); + dtxl->multisample_depth = GPU_texture_create_2D_multisample(size[0], size[1], GPU_DEPTH24_STENCIL8, NULL, 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( + (FramebufferList *)viewport->fbl, default_fbl_len, + (TextureList *)viewport->txl, default_txl_len); + + for (LinkData *link = viewport->data.first; link; link = link->next) { + ViewportEngineData *data = link->data; + DRW_engine_viewport_data_size_get(data->engine_type, &fbl_len, &txl_len, NULL, NULL); + gpu_viewport_buffers_free(data->fbl, fbl_len, data->txl, txl_len); + } + + gpu_viewport_texture_pool_free(viewport); + } + } + + 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 (viewport->samples > 0) { + if (!dfbl->default_fb) { + gpu_viewport_default_multisample_fb_create(viewport); + } + } + + if (!dfbl->default_fb) { + gpu_viewport_default_fb_create(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; + + const float w = (float)GPU_texture_width(color); + const float h = (float)GPU_texture_height(color); + + BLI_assert(w == BLI_rcti_size_x(rect) + 1); + BLI_assert(h == BLI_rcti_size_y(rect) + 1); + + /* wmOrtho for the screen has this same offset */ + const float halfx = GLA_PIXEL_OFS / w; + const float halfy = GLA_PIXEL_OFS / h; + + float x1 = rect->xmin; + float x2 = rect->xmin + w; + float y1 = rect->ymin; + float y2 = rect->ymin + h; + + GPUShader *shader = GPU_shader_get_builtin_shader(GPU_SHADER_2D_IMAGE_RECT_COLOR); + GPU_shader_bind(shader); + + GPU_texture_bind(color, 0); + glUniform1i(GPU_shader_get_uniform(shader, "image"), 0); + glUniform4f(GPU_shader_get_uniform(shader, "rect_icon"), halfx, halfy, 1.0f + halfx, 1.0f + halfy); + 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); + + GWN_draw_primitive(GWN_PRIM_TRI_STRIP, 4); + + GPU_texture_unbind(color); +} + +void GPU_viewport_unbind(GPUViewport *UNUSED(viewport)) +{ + GPU_framebuffer_restore(); + DRW_opengl_context_disable(); +} + + +GPUTexture *GPU_viewport_color_texture(GPUViewport *viewport) +{ + DefaultFramebufferList *dfbl = viewport->fbl; + + if (dfbl->default_fb) { + DefaultTextureList *dtxl = viewport->txl; + return dtxl->color; + } + + return NULL; +} + +static void gpu_viewport_buffers_free( + FramebufferList *fbl, int fbl_len, + TextureList *txl, int txl_len) +{ + for (int i = 0; i < fbl_len; i++) { + GPUFrameBuffer *fb = fbl->framebuffers[i]; + if (fb) { + GPU_framebuffer_free(fb); + fbl->framebuffers[i] = NULL; + } + } + for (int i = 0; i < txl_len; i++) { + GPUTexture *tex = txl->textures[i]; + if (tex) { + GPU_texture_free(tex); + txl->textures[i] = NULL; + } + } +} + +static void gpu_viewport_storage_free(StorageList *stl, int stl_len) +{ + for (int i = 0; i < stl_len; i++) { + void *storage = stl->storage[i]; + if (storage) { + MEM_freeN(storage); + stl->storage[i] = NULL; + } + } +} + +static void gpu_viewport_passes_free(PassList *psl, int psl_len) +{ + for (int i = 0; i < psl_len; i++) { + struct DRWPass *pass = psl->passes[i]; + if (pass) { + DRW_pass_free(pass); + psl->passes[i] = NULL; + } + } +} + +/* Must be executed inside Drawmanager Opengl Context. */ +void GPU_viewport_free(GPUViewport *viewport) +{ + gpu_viewport_engines_data_free(viewport); + + gpu_viewport_buffers_free( + (FramebufferList *)viewport->fbl, default_fbl_len, + (TextureList *)viewport->txl, default_txl_len); + + gpu_viewport_texture_pool_free(viewport); + + MEM_freeN(viewport->fbl); + MEM_freeN(viewport->txl); + + if (viewport->vmempool.calls != NULL) { + BLI_mempool_destroy(viewport->vmempool.calls); + } + if (viewport->vmempool.states != NULL) { + BLI_mempool_destroy(viewport->vmempool.states); + } + if (viewport->vmempool.shgroups != NULL) { + BLI_mempool_destroy(viewport->vmempool.shgroups); + } + if (viewport->vmempool.uniforms != NULL) { + BLI_mempool_destroy(viewport->vmempool.uniforms); + } + if (viewport->vmempool.passes != NULL) { + BLI_mempool_destroy(viewport->vmempool.passes); + } + + DRW_instance_data_list_free(viewport->idatalist); + MEM_freeN(viewport->idatalist); + + MEM_freeN(viewport); +} diff --git a/source/blender/gpu/shaders/gpu_shader_2D_flat_color_vert.glsl b/source/blender/gpu/shaders/gpu_shader_2D_flat_color_vert.glsl new file mode 100644 index 00000000000..769e2b0e37c --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_2D_flat_color_vert.glsl @@ -0,0 +1,13 @@ + +uniform mat4 ModelViewProjectionMatrix; + +in vec2 pos; +in vec4 color; + +flat out vec4 finalColor; + +void main() +{ + gl_Position = ModelViewProjectionMatrix * vec4(pos, 0.0, 1.0); + finalColor = color; +} 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_image_vert.glsl b/source/blender/gpu/shaders/gpu_shader_2D_image_vert.glsl new file mode 100644 index 00000000000..228f3f1da19 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_2D_image_vert.glsl @@ -0,0 +1,13 @@ + +uniform mat4 ModelViewProjectionMatrix; + +/* Keep in sync with intern/opencolorio/gpu_shader_display_transform_vertex.glsl */ +in vec2 texCoord; +in vec2 pos; +out vec2 texCoord_interp; + +void main() +{ + gl_Position = ModelViewProjectionMatrix * vec4(pos.xy, 0.0f, 1.0f); + texCoord_interp = texCoord; +} diff --git a/source/blender/gpu/shaders/gpu_shader_2D_line_dashed_frag.glsl b/source/blender/gpu/shaders/gpu_shader_2D_line_dashed_frag.glsl new file mode 100644 index 00000000000..7caf00f58fd --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_2D_line_dashed_frag.glsl @@ -0,0 +1,54 @@ + +/* + * Fragment Shader for dashed lines, with uniform multi-color(s), or any single-color, and any thickness. + * + * Dashed is performed in screen space. + */ + +uniform float dash_width; + +/* Simple mode, discarding non-dash parts (so no need for blending at all). */ +uniform float dash_factor; /* if > 1.0, solid line. */ + +/* More advanced mode, allowing for complex, multi-colored patterns. Enabled when num_colors > 0. */ +/* Note: max number of steps/colors in pattern is 32! */ +uniform int num_colors; /* Enabled if > 0, 1 for solid line. */ +uniform vec4 colors[32]; + +noperspective in float distance_along_line; +noperspective in vec4 color_geom; + +out vec4 fragColor; + +void main() +{ + /* Multi-color option. */ + if (num_colors > 0) { + /* Solid line case, simple. */ + if (num_colors == 1) { + fragColor = colors[0]; + } + /* Actually dashed line... */ + else { + float normalized_distance = fract(distance_along_line / dash_width); + fragColor = colors[int(normalized_distance * num_colors)]; + } + } + /* Single color option. */ + else { + /* Solid line case, simple. */ + if (dash_factor >= 1.0f) { + fragColor = color_geom; + } + /* Actually dashed line... */ + else { + float normalized_distance = fract(distance_along_line / dash_width); + if (normalized_distance <= dash_factor) { + fragColor = color_geom; + } + else { + discard; + } + } + } +} diff --git a/source/blender/gpu/shaders/gpu_shader_2D_line_dashed_geom.glsl b/source/blender/gpu/shaders/gpu_shader_2D_line_dashed_geom.glsl new file mode 100644 index 00000000000..db4bdf0a9f0 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_2D_line_dashed_geom.glsl @@ -0,0 +1,56 @@ + +/* + * Geometry Shader for dashed lines, with uniform multi-color(s), or any single-color, and unary thickness. + * + * Dashed is performed in screen space. + */ + + +/* Make to be used with dynamic batching so no Model Matrix needed */ +uniform mat4 ModelViewProjectionMatrix; +uniform vec2 viewport_size; + +/* Uniforms from fragment shader, used here to optimize out useless computation in case of solid line. */ +uniform float dash_factor; /* if > 1.0, solid line. */ +uniform int num_colors; /* Enabled if > 0, 1 for solid line. */ + +layout(lines) in; + +in vec4 color_vert[]; + +layout(line_strip, max_vertices = 2) out; +noperspective out float distance_along_line; +noperspective out vec4 color_geom; + +void main() +{ + vec4 v1 = gl_in[0].gl_Position; + vec4 v2 = gl_in[1].gl_Position; + + gl_Position = v1; + color_geom = color_vert[0]; + distance_along_line = 0.0f; + EmitVertex(); + + gl_Position = v2; + color_geom = color_vert[1]; + if ((num_colors == 1) || (dash_factor >= 1.0f)) { + /* Solid line, optimize out distance computation! */ + distance_along_line = 0.0f; + } + else { + vec2 p1 = (v1.xy / v1.w) * 0.5 + 0.5; // <- device coordinates in [0..1] range. + p1 = p1 * viewport_size; // <- 'virtual' screen coordinates. + + vec2 p2 = (v2.xy / v2.w) * 0.5 + 0.5; // <- device coordinates in [0..1] range. + p2 = p2 * viewport_size; // <- 'virtual' screen coordinates. + + distance_along_line = distance(p1, p2); + } + EmitVertex(); + + EndPrimitive(); + + /* Note: we could also use similar approach as diag_stripes_frag, but this would give us dashed 'anchored' + * to the screen, and not to one end of the line... */ +} diff --git a/source/blender/gpu/shaders/gpu_shader_2D_line_dashed_uniform_color_vert.glsl b/source/blender/gpu/shaders/gpu_shader_2D_line_dashed_uniform_color_vert.glsl new file mode 100644 index 00000000000..f5c611586aa --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_2D_line_dashed_uniform_color_vert.glsl @@ -0,0 +1,21 @@ + +/* + * Vertex Shader for dashed lines with 2D coordinates, with uniform multi-colors or uniform single-color, + * and unary thickness. + * + * Dashed is performed in screen space. + */ + +uniform mat4 ModelViewProjectionMatrix; + +uniform vec4 color; + +in vec2 pos; + +out vec4 color_vert; + +void main() +{ + gl_Position = ModelViewProjectionMatrix * vec4(pos, 0.0, 1.0); + color_vert = color; +} diff --git a/source/blender/gpu/shaders/gpu_shader_2D_line_dashed_width_geom.glsl b/source/blender/gpu/shaders/gpu_shader_2D_line_dashed_width_geom.glsl new file mode 100644 index 00000000000..20c72f4407d --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_2D_line_dashed_width_geom.glsl @@ -0,0 +1,59 @@ + +// Draw dashed lines, perforated in screen space, with non-unary width. + +/* Make to be used with dynamic batching so no Model Matrix needed */ +uniform mat4 ModelViewProjectionMatrix; +uniform vec2 viewport_size; + +/* Width of the generated 'line'. */ +uniform float width; /* in pixels, screen space. */ + +/* Uniforms from fragment shader, used here to optimize out useless computation in case of solid line. */ +uniform float dash_factor; /* if > 1.0, solid line. */ +uniform int num_colors; /* Enabled if > 0, 1 for solid line. */ + +layout(lines) in; + +layout(triangle_strip, max_vertices = 4) out; +noperspective out float distance_along_line; + +void main() +{ + vec4 v1 = gl_in[0].gl_Position; + vec4 v2 = gl_in[1].gl_Position; + + /* Width, from 2D screen space in pixels, to ModelViewProjection space of each input vertices. */ + float w1 = (width / viewport_size) * v1.w * 2.0; + float w2 = (width / viewport_size) * v2.w * 2.0; + + /* Normalized vector parallel to screen and orthogonal to line. */ + vec4 wdir = normalize(vec4(v1.y - v2.y, v2.x - v1.x, 0.0, 0.0)) + + distance_along_line = 0.0f; + gl_Position = v1 + (wdir * w1); + EmitVertex(); + + gl_Position = v1 - (wdir * w1); + EmitVertex(); + + if ((num_colors == 1) || (dash_factor >= 1.0f)) { + /* Solid line, optimize out distance computation! */ + distance_along_line = 0.0f; + } + else { + vec2 p1 = (v1.xy / v1.w) * 0.5 + 0.5; // <- device coordinates in [0..1] range. + p1 = p1 * viewport_size; // <- 'virtual' screen coordinates. + + vec2 p2 = (v2.xy / v2.w) * 0.5 + 0.5; // <- device coordinates in [0..1] range. + p2 = p2 * viewport_size; // <- 'virtual' screen coordinates. + + distance_along_line = distance(p1, p2); + } + gl_Position = v2 + (wdir * w2); + EmitVertex(); + + gl_Position = v2 - (wdir * w2); + EmitVertex(); + + EndPrimitive(); +} 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..1497f9eeeb1 --- /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)); +} 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..4a9f5f94321 --- /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; + } +} diff --git a/source/blender/gpu/shaders/gpu_shader_2D_point_uniform_size_aa_vert.glsl b/source/blender/gpu/shaders/gpu_shader_2D_point_uniform_size_aa_vert.glsl new file mode 100644 index 00000000000..1f833cfb7be --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_2D_point_uniform_size_aa_vert.glsl @@ -0,0 +1,21 @@ + +uniform mat4 ModelViewProjectionMatrix; +uniform float size; + +in vec2 pos; +out vec2 radii; + +void main() { + gl_Position = ModelViewProjectionMatrix * vec4(pos, 0.0, 1.0); + gl_PointSize = size; + + // calculate concentric radii in pixels + float radius = 0.5 * size; + + // start at the outside and progress toward the center + radii[0] = radius; + radii[1] = radius - 1.0; + + // convert to PointCoord units + radii /= size; +} diff --git a/source/blender/gpu/shaders/gpu_shader_2D_point_uniform_size_outline_aa_vert.glsl b/source/blender/gpu/shaders/gpu_shader_2D_point_uniform_size_outline_aa_vert.glsl new file mode 100644 index 00000000000..99bdeb22904 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_2D_point_uniform_size_outline_aa_vert.glsl @@ -0,0 +1,24 @@ + +uniform mat4 ModelViewProjectionMatrix; +uniform float size; +uniform float outlineWidth; + +in vec2 pos; +out vec4 radii; + +void main() { + gl_Position = ModelViewProjectionMatrix * vec4(pos, 0.0, 1.0); + gl_PointSize = size; + + // calculate concentric radii in pixels + float radius = 0.5 * size; + + // start at the outside and progress toward the center + radii[0] = radius; + radii[1] = radius - 1.0; + radii[2] = radius - outlineWidth; + radii[3] = radius - outlineWidth - 1.0; + + // convert to PointCoord units + radii /= size; +} diff --git a/source/blender/gpu/shaders/gpu_shader_2D_point_uniform_size_varying_color_outline_aa_vert.glsl b/source/blender/gpu/shaders/gpu_shader_2D_point_uniform_size_varying_color_outline_aa_vert.glsl new file mode 100644 index 00000000000..5fad95236df --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_2D_point_uniform_size_varying_color_outline_aa_vert.glsl @@ -0,0 +1,27 @@ + +uniform mat4 ModelViewProjectionMatrix; +uniform float size; +uniform float outlineWidth; + +in vec2 pos; +in vec4 color; +out vec4 radii; +out vec4 fillColor; + +void main() { + gl_Position = ModelViewProjectionMatrix * vec4(pos, 0.0, 1.0); + gl_PointSize = size; + fillColor = color; + + // calculate concentric radii in pixels + float radius = 0.5 * size; + + // start at the outside and progress toward the center + radii[0] = radius; + radii[1] = radius - 1.0; + radii[2] = radius - outlineWidth; + radii[3] = radius - outlineWidth - 1.0; + + // convert to PointCoord units + radii /= size; +} diff --git a/source/blender/gpu/shaders/gpu_shader_2D_point_varying_size_varying_color_vert.glsl b/source/blender/gpu/shaders/gpu_shader_2D_point_varying_size_varying_color_vert.glsl new file mode 100644 index 00000000000..d6aacf0cdc5 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_2D_point_varying_size_varying_color_vert.glsl @@ -0,0 +1,14 @@ + +uniform mat4 ModelViewProjectionMatrix; + +in vec2 pos; +in float size; +in vec4 color; +out vec4 finalColor; + +void main() +{ + gl_Position = ModelViewProjectionMatrix * vec4(pos, 0.0, 1.0); + gl_PointSize = size; + finalColor = color; +} diff --git a/source/blender/gpu/shaders/gpu_shader_2D_smooth_color_dithered_frag.glsl b/source/blender/gpu/shaders/gpu_shader_2D_smooth_color_dithered_frag.glsl new file mode 100644 index 00000000000..145ed16248a --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_2D_smooth_color_dithered_frag.glsl @@ -0,0 +1,20 @@ + +noperspective in vec4 finalColor; +out vec4 fragColor; + +/* 4x4 bayer matrix prepared for 8bit UNORM precision error. */ +#define P(x) (((x + 0.5) * (1.0 / 16.0) - 0.5) * (1.0 / 255.0)) +const vec4 dither_mat4x4[4] = vec4[4]( + vec4( P(0.0), P(8.0), P(2.0), P(10.0)), + vec4(P(12.0), P(4.0), P(14.0), P(6.0)), + vec4( P(3.0), P(11.0), P(1.0), P(9.0)), + vec4(P(15.0), P(7.0), P(13.0), P(5.0)) +); + +void main() +{ + ivec2 tx1 = ivec2(gl_FragCoord.xy) % 4; + ivec2 tx2 = ivec2(gl_FragCoord.xy) % 2; + float dither_noise = dither_mat4x4[tx1.x][tx1.y]; + fragColor = finalColor + dither_noise; +} diff --git a/source/blender/gpu/shaders/gpu_shader_2D_smooth_color_frag.glsl b/source/blender/gpu/shaders/gpu_shader_2D_smooth_color_frag.glsl new file mode 100644 index 00000000000..4a4bfb6a616 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_2D_smooth_color_frag.glsl @@ -0,0 +1,8 @@ + +noperspective in vec4 finalColor; +out vec4 fragColor; + +void main() +{ + fragColor = finalColor; +} diff --git a/source/blender/gpu/shaders/gpu_shader_2D_smooth_color_vert.glsl b/source/blender/gpu/shaders/gpu_shader_2D_smooth_color_vert.glsl new file mode 100644 index 00000000000..fe91f4d0902 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_2D_smooth_color_vert.glsl @@ -0,0 +1,13 @@ + +uniform mat4 ModelViewProjectionMatrix; + +in vec2 pos; +in vec4 color; + +noperspective out vec4 finalColor; + +void main() +{ + gl_Position = ModelViewProjectionMatrix * vec4(pos, 0.0, 1.0); + finalColor = color; +} diff --git a/source/blender/gpu/shaders/gpu_shader_2D_vert.glsl b/source/blender/gpu/shaders/gpu_shader_2D_vert.glsl new file mode 100644 index 00000000000..89e3c52f9f8 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_2D_vert.glsl @@ -0,0 +1,9 @@ + +uniform mat4 ModelViewProjectionMatrix; + +in vec2 pos; + +void main() +{ + gl_Position = ModelViewProjectionMatrix * vec4(pos, 0.0, 1.0); +} 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..a356014d025 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_2D_widget_base_frag.glsl @@ -0,0 +1,40 @@ +uniform vec3 checkerColorAndSize; + +noperspective in vec4 finalColor; +noperspective in float butCo; +flat in float discardFac; + +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() +{ + if (min(1.0, -butCo) > discardFac) { + discard; + } + + fragColor = finalColor; + + if (butCo > 0.5) { + vec4 checker = do_checkerboard(); + fragColor = mix(checker, fragColor, fragColor.a); + } + + if (butCo > 0.0) { + fragColor.a = 1.0; + } +} 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..dcd23413c77 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_2D_widget_base_vert.glsl @@ -0,0 +1,202 @@ +#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[37] = vec2[37]( + /* ROUNDBOX_TRIA_ARROWS */ + 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), + /* ROUNDBOX_TRIA_SCROLL - 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), + /* ROUNDBOX_TRIA_MENU - menu arrows */ + 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), + /* ROUNDBOX_TRIA_CHECK - 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), + /* ROUNDBOX_TRIA_HOLD_ACTION_ARROW - hold action arrows */ +#define OY (-0.2 / 2) +#define SC (0.35 * 2) +// vec2(-0.5 + SC, 1.0 + OY), vec2( 0.5, 1.0 + OY), vec2( 0.5, 0.0 + OY + SC), + vec2( 0.5 - SC, 1.0 + OY), vec2(-0.5, 1.0 + OY), vec2(-0.5, 0.0 + OY + SC) +#undef OY +#undef SC +); + +uniform mat4 ModelViewProjectionMatrix; + +#define MAX_PARAM 11 +#ifdef USE_INSTANCE +#define MAX_INSTANCE 6 +uniform vec4 parameters[MAX_PARAM * MAX_INSTANCE]; +#else +uniform vec4 parameters[MAX_PARAM]; +#endif + +/* gl_InstanceID is 0 if not drawing instances. */ +#define recti parameters[gl_InstanceID * MAX_PARAM + 0] +#define rect parameters[gl_InstanceID * MAX_PARAM + 1] +#define radsi parameters[gl_InstanceID * MAX_PARAM + 2].x +#define rads parameters[gl_InstanceID * MAX_PARAM + 2].y +#define faci parameters[gl_InstanceID * MAX_PARAM + 2].zw +#define roundCorners parameters[gl_InstanceID * MAX_PARAM + 3] +#define colorInner1 parameters[gl_InstanceID * MAX_PARAM + 4] +#define colorInner2 parameters[gl_InstanceID * MAX_PARAM + 5] +#define colorEdge parameters[gl_InstanceID * MAX_PARAM + 6] +#define colorEmboss parameters[gl_InstanceID * MAX_PARAM + 7] +#define colorTria parameters[gl_InstanceID * MAX_PARAM + 8] +#define tria1Center parameters[gl_InstanceID * MAX_PARAM + 9].xy +#define tria2Center parameters[gl_InstanceID * MAX_PARAM + 9].zw +#define tria1Size parameters[gl_InstanceID * MAX_PARAM + 10].x +#define tria2Size parameters[gl_InstanceID * MAX_PARAM + 10].y +#define shadeDir parameters[gl_InstanceID * MAX_PARAM + 10].z +#define alphaDiscard parameters[gl_InstanceID * MAX_PARAM + 10].w + +/* We encode alpha check and discard factor together. */ +#define doAlphaCheck (alphaDiscard < 0.0) +#define discardFactor abs(alphaDiscard) + +in uint vflag; + +noperspective out vec4 finalColor; +noperspective out float butCo; +flat out float discardFac; + +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; + + vec2 uv = faci * (v - recti.xz); + + /* compute uv and color gradient */ + uint color_id = (vflag >> COLOR_OFS) & COLOR_RANGE; + if (color_id == COLOR_INNER) { + float fac = clamp((shadeDir > 0.0) ? uv.y : uv.x, 0.0, 1.0); + + if (doAlphaCheck) { + finalColor = colorInner1; + butCo = uv.x; + } + else { + finalColor = mix(colorInner2, colorInner1, fac); + butCo = -abs(uv.x); + } + } + else if (color_id == COLOR_EDGE) { + finalColor = colorEdge; + butCo = -abs(uv.x); + } + else /* (color_id == COLOR_EMBOSS) */ { + finalColor = colorEmboss; + butCo = -abs(uv.x); + } + + 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() +{ + discardFac = discardFactor; + 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); +} 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..fc4d055a903 --- /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); +} 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..f6be496ac4f --- /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); +} diff --git a/source/blender/gpu/shaders/gpu_shader_3D_clipped_uniform_color_vert.glsl b/source/blender/gpu/shaders/gpu_shader_3D_clipped_uniform_color_vert.glsl new file mode 100644 index 00000000000..84e44837264 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_3D_clipped_uniform_color_vert.glsl @@ -0,0 +1,12 @@ + +uniform mat4 ModelViewProjectionMatrix; +uniform mat4 ModelMatrix; +uniform vec4 ClipPlane; + +in vec3 pos; + +void main() +{ + gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0); + gl_ClipDistance[0] = dot(ModelMatrix * vec4(pos, 1.0), ClipPlane); +} diff --git a/source/blender/gpu/shaders/gpu_shader_3D_flat_color_vert.glsl b/source/blender/gpu/shaders/gpu_shader_3D_flat_color_vert.glsl new file mode 100644 index 00000000000..7db7e28d8e6 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_3D_flat_color_vert.glsl @@ -0,0 +1,26 @@ + +uniform mat4 ModelViewProjectionMatrix; + +in vec3 pos; +#if defined(USE_COLOR_U32) +in uint color; +#else +in vec4 color; +#endif + +flat out vec4 finalColor; + +void main() +{ + gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0); + +#if defined(USE_COLOR_U32) + finalColor = vec4( + ((color ) & uint(0xFF)) * (1.0f / 255.0f), + ((color >> 8) & uint(0xFF)) * (1.0f / 255.0f), + ((color >> 16) & uint(0xFF)) * (1.0f / 255.0f), + ((color >> 24) ) * (1.0f / 255.0f)); +#else + finalColor = color; +#endif +} diff --git a/source/blender/gpu/shaders/gpu_shader_3D_groundline_geom.glsl b/source/blender/gpu/shaders/gpu_shader_3D_groundline_geom.glsl new file mode 100644 index 00000000000..f16fa21b342 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_3D_groundline_geom.glsl @@ -0,0 +1,16 @@ + +/* Make to be used with dynamic batching so no Model Matrix needed */ +uniform mat4 ViewProjectionMatrix; + +layout(points) in; +layout(line_strip, max_vertices = 2) out; + +void main() +{ + vec3 vert = gl_in[0].gl_Position.xyz; + gl_Position = ViewProjectionMatrix * vec4(vert.xyz, 1.0); + EmitVertex(); + gl_Position = ViewProjectionMatrix * vec4(vert.xy, 0.0, 1.0); + EmitVertex(); + EndPrimitive(); +} diff --git a/source/blender/gpu/shaders/gpu_shader_3D_groundpoint_vert.glsl b/source/blender/gpu/shaders/gpu_shader_3D_groundpoint_vert.glsl new file mode 100644 index 00000000000..55f410eb25d --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_3D_groundpoint_vert.glsl @@ -0,0 +1,11 @@ + +/* Made to be used with dynamic batching so no Model Matrix needed */ +uniform mat4 ViewProjectionMatrix; + +in vec3 pos; + +void main() +{ + gl_Position = ViewProjectionMatrix * vec4(pos.xy, 0.0, 1.0); + gl_PointSize = 2.0; +} diff --git a/source/blender/gpu/shaders/gpu_shader_3D_image_vert.glsl b/source/blender/gpu/shaders/gpu_shader_3D_image_vert.glsl new file mode 100644 index 00000000000..eb877ab20b6 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_3D_image_vert.glsl @@ -0,0 +1,12 @@ + +uniform mat4 ModelViewProjectionMatrix; + +in vec2 texCoord; +in vec3 pos; +out vec2 texCoord_interp; + +void main() +{ + gl_Position = ModelViewProjectionMatrix * vec4(pos.xyz, 1.0f); + texCoord_interp = texCoord; +} diff --git a/source/blender/gpu/shaders/gpu_shader_3D_line_dashed_uniform_color_legacy_vert.glsl b/source/blender/gpu/shaders/gpu_shader_3D_line_dashed_uniform_color_legacy_vert.glsl new file mode 100644 index 00000000000..84fbf977846 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_3D_line_dashed_uniform_color_legacy_vert.glsl @@ -0,0 +1,26 @@ + +/* + * Vertex Shader for dashed lines with 3D coordinates, with uniform multi-colors or uniform single-color, + * and unary thickness. + * + * Legacy version, without geometry shader support, always produce solid lines! + */ + +uniform mat4 ModelViewProjectionMatrix; +uniform vec2 viewport_size; + +uniform vec4 color; + +in vec3 pos; +noperspective out float distance_along_line; +noperspective out vec4 color_geom; + +void main() +{ + gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0); + + /* Hack - prevent stupid GLSL compiler to optimize out unused viewport_size uniform, which gives crash! */ + distance_along_line = viewport_size.x * 0.000001f - viewport_size.x * 0.0000009f; + + color_geom = color; +} diff --git a/source/blender/gpu/shaders/gpu_shader_3D_line_dashed_uniform_color_vert.glsl b/source/blender/gpu/shaders/gpu_shader_3D_line_dashed_uniform_color_vert.glsl new file mode 100644 index 00000000000..2fe08896585 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_3D_line_dashed_uniform_color_vert.glsl @@ -0,0 +1,21 @@ + +/* + * Vertex Shader for dashed lines with 3D coordinates, with uniform multi-colors or uniform single-color, + * and unary thickness. + * + * Dashed is performed in screen space. + */ + +uniform mat4 ModelViewProjectionMatrix; + +uniform vec4 color; + +in vec3 pos; + +out vec4 color_vert; + +void main() +{ + gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0); + color_vert = color; +} diff --git a/source/blender/gpu/shaders/gpu_shader_3D_normal_smooth_color_vert.glsl b/source/blender/gpu/shaders/gpu_shader_3D_normal_smooth_color_vert.glsl new file mode 100644 index 00000000000..e6b8fed7265 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_3D_normal_smooth_color_vert.glsl @@ -0,0 +1,22 @@ + +uniform mat4 ModelViewProjectionMatrix; +uniform mat3 NormalMatrix; + +in vec3 pos; +in vec3 nor; +in vec4 color; + +#ifdef USE_FLAT_NORMAL +flat out vec3 normal; +flat out vec4 finalColor; +#else +out vec3 normal; +out vec4 finalColor; +#endif + +void main() +{ + normal = normalize(NormalMatrix * nor); + gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0); + finalColor = color; +} diff --git a/source/blender/gpu/shaders/gpu_shader_3D_normal_vert.glsl b/source/blender/gpu/shaders/gpu_shader_3D_normal_vert.glsl new file mode 100644 index 00000000000..a3f447a85f9 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_3D_normal_vert.glsl @@ -0,0 +1,13 @@ + +uniform mat4 ModelViewProjectionMatrix; +uniform mat3 NormalMatrix; + +in vec3 pos; +in vec3 nor; +out vec3 normal; + +void main() +{ + normal = normalize(NormalMatrix * nor); + gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0); +} diff --git a/source/blender/gpu/shaders/gpu_shader_3D_passthrough_vert.glsl b/source/blender/gpu/shaders/gpu_shader_3D_passthrough_vert.glsl new file mode 100644 index 00000000000..60793bf56b6 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_3D_passthrough_vert.glsl @@ -0,0 +1,8 @@ + +/* Does Nothing */ +in vec3 pos; + +void main() +{ + gl_Position = vec4(pos, 1.0); +} diff --git a/source/blender/gpu/shaders/gpu_shader_3D_point_fixed_size_varying_color_vert.glsl b/source/blender/gpu/shaders/gpu_shader_3D_point_fixed_size_varying_color_vert.glsl new file mode 100644 index 00000000000..2fe9c0623fa --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_3D_point_fixed_size_varying_color_vert.glsl @@ -0,0 +1,12 @@ + +uniform mat4 ModelViewProjectionMatrix; + +in vec3 pos; +in vec4 color; +out vec4 finalColor; + +void main() +{ + gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0); + finalColor = color; +} diff --git a/source/blender/gpu/shaders/gpu_shader_3D_point_uniform_size_aa_vert.glsl b/source/blender/gpu/shaders/gpu_shader_3D_point_uniform_size_aa_vert.glsl new file mode 100644 index 00000000000..ebc945fcf35 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_3D_point_uniform_size_aa_vert.glsl @@ -0,0 +1,21 @@ + +uniform mat4 ModelViewProjectionMatrix; +uniform float size; + +in vec3 pos; +out vec2 radii; + +void main() { + gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0); + gl_PointSize = size; + + // calculate concentric radii in pixels + float radius = 0.5 * size; + + // start at the outside and progress toward the center + radii[0] = radius; + radii[1] = radius - 1.0; + + // convert to PointCoord units + radii /= size; +} diff --git a/source/blender/gpu/shaders/gpu_shader_3D_point_uniform_size_outline_aa_vert.glsl b/source/blender/gpu/shaders/gpu_shader_3D_point_uniform_size_outline_aa_vert.glsl new file mode 100644 index 00000000000..0d6b90cfba4 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_3D_point_uniform_size_outline_aa_vert.glsl @@ -0,0 +1,24 @@ + +uniform mat4 ModelViewProjectionMatrix; +uniform float size; +uniform float outlineWidth; + +in vec3 pos; +out vec4 radii; + +void main() { + gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0); + gl_PointSize = size; + + // calculate concentric radii in pixels + float radius = 0.5 * size; + + // start at the outside and progress toward the center + radii[0] = radius; + radii[1] = radius - 1.0; + radii[2] = radius - outlineWidth; + radii[3] = radius - outlineWidth - 1.0; + + // convert to PointCoord units + radii /= size; +} diff --git a/source/blender/gpu/shaders/gpu_shader_3D_point_varying_size_varying_color_vert.glsl b/source/blender/gpu/shaders/gpu_shader_3D_point_varying_size_varying_color_vert.glsl new file mode 100644 index 00000000000..e14b9535c89 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_3D_point_varying_size_varying_color_vert.glsl @@ -0,0 +1,14 @@ + +uniform mat4 ModelViewProjectionMatrix; + +in vec3 pos; +in float size; +in vec4 color; +out vec4 finalColor; + +void main() +{ + gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0); + gl_PointSize = size; + finalColor = color; +} diff --git a/source/blender/gpu/shaders/gpu_shader_3D_point_varying_size_vert.glsl b/source/blender/gpu/shaders/gpu_shader_3D_point_varying_size_vert.glsl new file mode 100644 index 00000000000..e4f173ab617 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_3D_point_varying_size_vert.glsl @@ -0,0 +1,11 @@ + +uniform mat4 ModelViewProjectionMatrix; + +in vec3 pos; +in float size; + +void main() +{ + gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0); + gl_PointSize = size; +} diff --git a/source/blender/gpu/shaders/gpu_shader_3D_smooth_color_frag.glsl b/source/blender/gpu/shaders/gpu_shader_3D_smooth_color_frag.glsl new file mode 100644 index 00000000000..41fdefd22e8 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_3D_smooth_color_frag.glsl @@ -0,0 +1,8 @@ + +in vec4 finalColor; +out vec4 fragColor; + +void main() +{ + fragColor = finalColor; +} diff --git a/source/blender/gpu/shaders/gpu_shader_3D_smooth_color_vert.glsl b/source/blender/gpu/shaders/gpu_shader_3D_smooth_color_vert.glsl new file mode 100644 index 00000000000..a1feb2f75b7 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_3D_smooth_color_vert.glsl @@ -0,0 +1,13 @@ + +uniform mat4 ModelViewProjectionMatrix; + +in vec3 pos; +in vec4 color; + +out vec4 finalColor; + +void main() +{ + gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0); + finalColor = color; +} diff --git a/source/blender/gpu/shaders/gpu_shader_3D_vert.glsl b/source/blender/gpu/shaders/gpu_shader_3D_vert.glsl new file mode 100644 index 00000000000..059473ebb74 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_3D_vert.glsl @@ -0,0 +1,9 @@ + +uniform mat4 ModelViewProjectionMatrix; + +in vec3 pos; + +void main() +{ + gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0); +} diff --git a/source/blender/gpu/shaders/gpu_shader_basic_frag.glsl b/source/blender/gpu/shaders/gpu_shader_basic_frag.glsl index 01a335af048..5f7455582cd 100644 --- a/source/blender/gpu/shaders/gpu_shader_basic_frag.glsl +++ b/source/blender/gpu/shaders/gpu_shader_basic_frag.glsl @@ -20,12 +20,10 @@ #define STIPPLE_HEXAGON 3 #define STIPPLE_DIAG_STRIPES 4 #define STIPPLE_DIAG_STRIPES_SWAP 5 -#define STIPPLE_S3D_INTERLACE_ROW 6 -#define STIPPLE_S3D_INTERLACE_ROW_SWAP 7 -#define STIPPLE_S3D_INTERLACE_COLUMN 8 -#define STIPPLE_S3D_INTERLACE_COLUMN_SWAP 9 -#define STIPPLE_S3D_INTERLACE_CHECKERBOARD 10 -#define STIPPLE_S3D_INTERLACE_CHECKERBOARD_SWAP 11 + +#ifndef NO_SPECULAR +uniform mat4 ProjectionMatrix; +#endif #if defined(USE_SOLID_LIGHTING) || defined(USE_SCENE_LIGHTING) #if defined(USE_FLAT_NORMAL) @@ -58,7 +56,7 @@ uniform sampler2D_default texture_map; #ifdef USE_STIPPLE uniform int stipple_id; #if defined(DRAW_LINE) -varying in float t; +varying float t; uniform int stipple_pattern; #endif #endif @@ -74,14 +72,9 @@ void main() /* We have to use mod function and integer casting. * This can be optimized further with the bitwise operations * when GLSL 1.3 is supported. */ - if (stipple_id == STIPPLE_HALFTONE || - stipple_id == STIPPLE_S3D_INTERLACE_CHECKERBOARD || - stipple_id == STIPPLE_S3D_INTERLACE_CHECKERBOARD_SWAP) - { + if (stipple_id == STIPPLE_HALFTONE) { int result = int(mod(gl_FragCoord.x + gl_FragCoord.y, 2)); bool dis = result == 0; - if (stipple_id == STIPPLE_S3D_INTERLACE_CHECKERBOARD_SWAP) - dis = !dis; if (dis) discard; } @@ -116,22 +109,6 @@ void main() if (!((16 - modx > mody && mody > 8 - modx) || mody > 24 - modx)) discard; } - else if (stipple_id == STIPPLE_S3D_INTERLACE_ROW || stipple_id == STIPPLE_S3D_INTERLACE_ROW_SWAP) { - int result = int(mod(gl_FragCoord.y, 2)); - bool dis = result == 0; - if (stipple_id == STIPPLE_S3D_INTERLACE_ROW_SWAP) - dis = !dis; - if (dis) - discard; - } - else if (stipple_id == STIPPLE_S3D_INTERLACE_COLUMN || stipple_id == STIPPLE_S3D_INTERLACE_COLUMN_SWAP) { - int result = int(mod(gl_FragCoord.x, 2)); - bool dis = result != 0; - if (stipple_id == STIPPLE_S3D_INTERLACE_COLUMN_SWAP) - dis = !dis; - if (dis) - discard; - } else if (stipple_id == STIPPLE_HEXAGON) { int mody = int(mod(gl_FragCoord.y, 2)); int modx = int(mod(gl_FragCoord.x, 4)); @@ -190,7 +167,7 @@ void main() #ifndef NO_SPECULAR /* view vector computation, depends on orthographics or perspective */ - vec3 V = (gl_ProjectionMatrix[3][3] == 0.0) ? normalize(varying_position) : vec3(0.0, 0.0, -1.0); + vec3 V = (ProjectionMatrix[3][3] == 0.0) ? normalize(varying_position) : vec3(0.0, 0.0, -1.0); #endif for (int i = 0; i < NUM_SCENE_LIGHTS; i++) { diff --git a/source/blender/gpu/shaders/gpu_shader_basic_geom.glsl b/source/blender/gpu/shaders/gpu_shader_basic_geom.glsl index a88681a5fd3..13f05b340bf 100644 --- a/source/blender/gpu/shaders/gpu_shader_basic_geom.glsl +++ b/source/blender/gpu/shaders/gpu_shader_basic_geom.glsl @@ -14,9 +14,9 @@ layout(line_strip, max_vertices = 10) out; layout(triangle_strip, max_vertices = 6) out; #endif -varying out float t; -varying in vec4 varying_vertex_color_line[]; -varying out vec4 varying_vertex_color; +out float t; +in vec4 varying_vertex_color_line[]; +out vec4 varying_vertex_color; uniform ivec4 viewport; uniform float line_width; diff --git a/source/blender/gpu/shaders/gpu_shader_basic_vert.glsl b/source/blender/gpu/shaders/gpu_shader_basic_vert.glsl index 42fbdadf1d1..dbf6c267f14 100644 --- a/source/blender/gpu/shaders/gpu_shader_basic_vert.glsl +++ b/source/blender/gpu/shaders/gpu_shader_basic_vert.glsl @@ -1,4 +1,8 @@ +uniform mat4 ModelViewMatrix; +uniform mat4 ProjectionMatrix; +uniform mat3 NormalMatrix; + #if defined(USE_SOLID_LIGHTING) || defined(USE_SCENE_LIGHTING) #if defined(USE_FLAT_NORMAL) varying vec3 eyespace_vert_pos; @@ -29,15 +33,15 @@ varying float gl_ClipDistance[6]; void main() { - vec4 co = gl_ModelViewMatrix * gl_Vertex; + vec4 co = ModelViewMatrix * gl_Vertex; #if defined(USE_SOLID_LIGHTING) || defined(USE_SCENE_LIGHTING) #if !defined(USE_FLAT_NORMAL) - varying_normal = normalize(gl_NormalMatrix * gl_Normal); + varying_normal = normalize(NormalMatrix * gl_Normal); #endif #if defined(USE_FLAT_NORMAL) /* transform vertex into eyespace */ - eyespace_vert_pos = (gl_ModelViewMatrix * gl_Vertex).xyz; + eyespace_vert_pos = (ModelViewMatrix * gl_Vertex).xyz; #endif #ifndef USE_SOLID_LIGHTING @@ -45,7 +49,7 @@ void main() #endif #endif - gl_Position = gl_ProjectionMatrix * co; + gl_Position = ProjectionMatrix * co; #ifdef CLIP_WORKAROUND int i; diff --git a/source/blender/gpu/shaders/gpu_shader_checker_frag.glsl b/source/blender/gpu/shaders/gpu_shader_checker_frag.glsl new file mode 100644 index 00000000000..545f6d19e21 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_checker_frag.glsl @@ -0,0 +1,20 @@ + +uniform vec4 color1; +uniform vec4 color2; +uniform int size; + +out vec4 fragColor; + +void main() +{ + vec2 phase = mod(gl_FragCoord.xy, (size*2)); + + if ((phase.x > size && phase.y < size) || + (phase.x < size && phase.y > size)) + { + fragColor = color1; + } + else { + fragColor = color2; + } +} diff --git a/source/blender/gpu/shaders/gpu_shader_depth_only_frag.glsl b/source/blender/gpu/shaders/gpu_shader_depth_only_frag.glsl new file mode 100644 index 00000000000..60e71e19004 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_depth_only_frag.glsl @@ -0,0 +1,6 @@ + +void main() +{ + // no color output, only depth (line below is implicit) + // gl_FragDepth = gl_FragCoord.z; +} diff --git a/source/blender/gpu/shaders/gpu_shader_diag_stripes_frag.glsl b/source/blender/gpu/shaders/gpu_shader_diag_stripes_frag.glsl new file mode 100644 index 00000000000..beb71c58100 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_diag_stripes_frag.glsl @@ -0,0 +1,20 @@ + +uniform vec4 color1; +uniform vec4 color2; +uniform int size1; +uniform int size2; + +out vec4 fragColor; + +void main() +{ + float phase = mod((gl_FragCoord.x + gl_FragCoord.y), (size1 + size2)); + + if (phase < size1) + { + fragColor = color1; + } + else { + fragColor = color2; + } +} diff --git a/source/blender/gpu/shaders/gpu_shader_edges_front_back_ortho_vert.glsl b/source/blender/gpu/shaders/gpu_shader_edges_front_back_ortho_vert.glsl new file mode 100644 index 00000000000..4ed7ed56c11 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_edges_front_back_ortho_vert.glsl @@ -0,0 +1,54 @@ + +// Draw "fancy" wireframe, displaying front-facing, back-facing and +// silhouette lines differently. +// Mike Erwin, April 2015 + +uniform bool drawFront = true; +uniform bool drawBack = true; +uniform bool drawSilhouette = true; + +uniform vec4 frontColor; +uniform vec4 backColor; +uniform vec4 silhouetteColor; + +uniform vec3 eye; // direction we are looking + +uniform mat4 ModelViewProjectionMatrix; + +in vec3 pos; + +// normals of faces this edge joins (object coords) +in vec3 N1; +in vec3 N2; + +flat out vec4 finalColor; + +// TODO: in float angle; // [-pi .. +pi], + peak, 0 flat, - valley + +// to discard an entire line, set both endpoints to nowhere +// and it won't produce any fragments +const vec4 nowhere = vec4(vec3(0.0), 1.0); + +void main() +{ + bool face_1_front = dot(N1, eye) > 0.0; + bool face_2_front = dot(N2, eye) > 0.0; + + vec4 position = ModelViewProjectionMatrix * vec4(pos, 1.0); + + if (face_1_front && face_2_front) { + // front-facing edge + gl_Position = drawFront ? position : nowhere; + finalColor = frontColor; + } + else if (face_1_front || face_2_front) { + // exactly one face is front-facing, silhouette edge + gl_Position = drawSilhouette ? position : nowhere; + finalColor = silhouetteColor; + } + else { + // back-facing edge + gl_Position = drawBack ? position : nowhere; + finalColor = backColor; + } +} diff --git a/source/blender/gpu/shaders/gpu_shader_edges_front_back_persp_geom.glsl b/source/blender/gpu/shaders/gpu_shader_edges_front_back_persp_geom.glsl new file mode 100644 index 00000000000..e7632fcad15 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_edges_front_back_persp_geom.glsl @@ -0,0 +1,60 @@ + +// Draw "fancy" wireframe, displaying front-facing, back-facing and +// silhouette lines differently. +// Mike Erwin, April 2015 + +// After working with this shader a while, convinced we should make +// separate shaders for perpective & ortho. (Oct 2016) + +// Due to perspective, the line segment's endpoints might disagree on +// whether the adjacent faces are front facing. This geometry shader +// decides which edge type to use if endpoints disagree. + +uniform mat4 ProjectionMatrix; + +uniform bool drawFront = true; +uniform bool drawBack = true; +uniform bool drawSilhouette = true; + +uniform vec4 frontColor; +uniform vec4 backColor; +uniform vec4 silhouetteColor; + +layout(lines) in; +layout(line_strip, max_vertices = 2) out; + +in vec4 MV_pos[]; +in float edgeClass[]; + +flat out vec4 finalColor; + +void emitLine(vec4 color) +{ + gl_Position = ProjectionMatrix * MV_pos[0]; + EmitVertex(); + gl_Position = ProjectionMatrix * MV_pos[1]; + finalColor = color; + EmitVertex(); + EndPrimitive(); +} + +void main() +{ + float finalEdgeClass = max(edgeClass[0], edgeClass[1]); + + if (finalEdgeClass > 0.0f) { + // front-facing edge + if (drawFront) + emitLine(frontColor); + } + else if (finalEdgeClass < 0.0f) { + // back-facing edge + if (drawBack) + emitLine(backColor); + } + else { + // exactly one face is front-facing, silhouette edge + if (drawSilhouette) + emitLine(silhouetteColor); + } +} diff --git a/source/blender/gpu/shaders/gpu_shader_edges_front_back_persp_legacy_vert.glsl b/source/blender/gpu/shaders/gpu_shader_edges_front_back_persp_legacy_vert.glsl new file mode 100644 index 00000000000..30b3bdb890d --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_edges_front_back_persp_legacy_vert.glsl @@ -0,0 +1,68 @@ + +// Draw "fancy" wireframe, displaying front-facing, back-facing and +// silhouette lines differently. +// Mike Erwin, April 2015 + +// After working with this shader a while, convinced we should make +// separate shaders for perpective & ortho. (Oct 2016) + +// This shader is an imperfect stepping stone until all platforms are +// ready for geometry shaders. + +// Due to perspective, the line segment's endpoints might disagree on +// whether the adjacent faces are front facing. Need to use a geometry +// shader or pass in an extra position attribute (the other endpoint) +// to do this properly. + +uniform bool drawFront = true; +uniform bool drawBack = true; +uniform bool drawSilhouette = true; + +uniform vec4 frontColor; +uniform vec4 backColor; +uniform vec4 silhouetteColor; + +uniform mat4 ModelViewMatrix; +uniform mat4 ModelViewProjectionMatrix; +uniform mat3 NormalMatrix; + +in vec3 pos; + +// normals of faces this edge joins (object coords) +in vec3 N1; +in vec3 N2; + +flat out vec4 finalColor; + +// TODO: in float angle; // [-pi .. +pi], + peak, 0 flat, - valley + +// to discard an entire line, set its color to invisible +// (must have GL_BLEND enabled, or discard in fragment shader) +const vec4 invisible = vec4(0.0); + +bool front(vec3 N) +{ + vec4 xformed = ModelViewMatrix * vec4(pos, 1.0); + return dot(NormalMatrix * N, normalize(-xformed.xyz)) > 0.0; +} + +void main() +{ + bool face_1_front = front(N1); + bool face_2_front = front(N2); + + gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0); + + if (face_1_front && face_2_front) { + // front-facing edge + finalColor = drawFront ? frontColor : invisible; + } + else if (face_1_front || face_2_front) { + // exactly one face is front-facing, silhouette edge + finalColor = drawSilhouette ? silhouetteColor : invisible; + } + else { + // back-facing edge + finalColor = drawBack ? backColor : invisible; + } +} diff --git a/source/blender/gpu/shaders/gpu_shader_edges_front_back_persp_vert.glsl b/source/blender/gpu/shaders/gpu_shader_edges_front_back_persp_vert.glsl new file mode 100644 index 00000000000..e1fb78dd1a9 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_edges_front_back_persp_vert.glsl @@ -0,0 +1,44 @@ + +// Draw "fancy" wireframe, displaying front-facing, back-facing and +// silhouette lines differently. +// Mike Erwin, April 2015 + +// After working with this shader a while, convinced we should make +// separate shaders for perpective & ortho. (Oct 2016) + +// Due to perspective, the line segment's endpoints might disagree on +// whether the adjacent faces are front facing. We use a geometry +// shader to resolve this properly. + +uniform mat4 ModelViewMatrix; +uniform mat3 NormalMatrix; + +in vec3 pos; +in vec3 N1, N2; // normals of faces this edge joins (object coords) + +out vec4 MV_pos; +out float edgeClass; + +// TODO: in float angle; // [-pi .. +pi], + peak, 0 flat, - valley + +bool front(vec3 N, vec3 eye) +{ + return dot(NormalMatrix * N, eye) > 0.0; +} + +void main() +{ + MV_pos = ModelViewMatrix * vec4(pos, 1.0); + + vec3 eye = normalize(-MV_pos.xyz); + + bool face_1_front = front(N1, eye); + bool face_2_front = front(N2, eye); + + if (face_1_front && face_2_front) + edgeClass = 1.0; // front-facing edge + else if (face_1_front || face_2_front) + edgeClass = 0.0; // exactly one face is front-facing, silhouette edge + else + edgeClass = -1.0; // back-facing edge +} diff --git a/source/blender/gpu/shaders/gpu_shader_edges_overlay_frag.glsl b/source/blender/gpu/shaders/gpu_shader_edges_overlay_frag.glsl new file mode 100644 index 00000000000..0538c037dcf --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_edges_overlay_frag.glsl @@ -0,0 +1,20 @@ + +#define SMOOTH 1 + +const float transitionWidth = 1.0; + +uniform vec4 fillColor = vec4(0); +uniform vec4 outlineColor = vec4(0,0,0,1); + +noperspective in vec3 distanceToOutline; + +out vec4 FragColor; + +void main() { + float edgeness = min(min(distanceToOutline.x, distanceToOutline.y), distanceToOutline.z); +#if SMOOTH + FragColor = mix(outlineColor, fillColor, smoothstep(0, transitionWidth, edgeness)); +#else + FragColor = (edgeness <= 0) ? outlineColor : fillColor; +#endif +} diff --git a/source/blender/gpu/shaders/gpu_shader_edges_overlay_geom.glsl b/source/blender/gpu/shaders/gpu_shader_edges_overlay_geom.glsl new file mode 100644 index 00000000000..ad0dccb6c81 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_edges_overlay_geom.glsl @@ -0,0 +1,67 @@ +layout(triangles) in; +layout(triangle_strip, max_vertices=3) out; + +uniform float outlineWidth = 1.0; +uniform vec2 viewportSize; + +in vec4 pos_xformed[]; +in float widthModulator[]; + +noperspective out vec3 distanceToOutline; + +// project to screen space +vec2 proj(int axis) { + vec4 pos = pos_xformed[axis]; + return (0.5 * (pos.xy / pos.w) + 0.5) * viewportSize; +} + +float dist(vec2 pos[3], int v) { + // current vertex position + vec2 vpos = pos[v]; + // endpoints of opposite edge + vec2 e1 = pos[(v + 1) % 3]; + vec2 e2 = pos[(v + 2) % 3]; + + float abs_det = length(cross(vec3(vpos - e1, 0), vec3(vpos - e2, 0))); // could simplify + return abs_det / distance(e2, e1); +} + +vec3 distance[3]; + +void clearEdge(int v) { + float distant = 10 * outlineWidth; + for (int i = 0; i < 3; ++i) + distance[i][v] += distant; +} + +void modulateEdge(int v) { + float offset = min(widthModulator[v],1) * outlineWidth; + for (int i = 0; i < 3; ++i) + distance[i][v] -= offset; +} + +void main() { + vec2 pos[3] = vec2[3](proj(0), proj(1), proj(2)); + + for (int v = 0; v < 3; ++v) + distance[v] = vec3(0); + + for (int v = 0; v < 3; ++v) { + if (widthModulator[v] > 0) { + distance[v][v] = dist(pos, v); + modulateEdge(v); + } + } + + for (int v = 0; v < 3; ++v) + if (widthModulator[v] <= 0) + clearEdge(v); + + for (int v = 0; v < 3; ++v) { + gl_Position = pos_xformed[v]; + distanceToOutline = distance[v]; + EmitVertex(); + } + + EndPrimitive(); +} diff --git a/source/blender/gpu/shaders/gpu_shader_edges_overlay_simple_geom.glsl b/source/blender/gpu/shaders/gpu_shader_edges_overlay_simple_geom.glsl new file mode 100644 index 00000000000..ec692e210c2 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_edges_overlay_simple_geom.glsl @@ -0,0 +1,52 @@ +layout(triangles) in; +layout(triangle_strip, max_vertices=3) out; + +uniform float outlineWidth = 1.0; +uniform vec2 viewportSize; + +noperspective out vec3 distanceToOutline; + +// project to screen space +vec2 proj(int axis) { + vec4 pos = gl_in[axis].gl_Position; + return (0.5 * (pos.xy / pos.w) + 0.5) * viewportSize; +} + +float dist(vec2 pos[3], int v) { + // current vertex position + vec2 vpos = pos[v]; + // endpoints of opposite edge + vec2 e1 = pos[(v + 1) % 3]; + vec2 e2 = pos[(v + 2) % 3]; + + float abs_det = length(cross(vec3(vpos - e1, 0), vec3(vpos - e2, 0))); // could simplify + return abs_det / distance(e2, e1); +} + +vec3 distance[3]; + +void modulateEdge(int v) { + float offset = 0.5 * outlineWidth; + for (int i = 0; i < 3; ++i) + distance[i][v] -= offset; +} + +void main() { + vec2 pos[3] = vec2[3](proj(0), proj(1), proj(2)); + + for (int v = 0; v < 3; ++v) + distance[v] = vec3(0); + + for (int v = 0; v < 3; ++v) { + distance[v][v] = dist(pos, v); + modulateEdge(v); + } + + for (int v = 0; v < 3; ++v) { + gl_Position = gl_in[v].gl_Position; + distanceToOutline = distance[v]; + EmitVertex(); + } + + EndPrimitive(); +} diff --git a/source/blender/gpu/shaders/gpu_shader_edges_overlay_vert.glsl b/source/blender/gpu/shaders/gpu_shader_edges_overlay_vert.glsl new file mode 100644 index 00000000000..fb1d0aafe05 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_edges_overlay_vert.glsl @@ -0,0 +1,13 @@ + +uniform mat4 ModelViewProjectionMatrix; + +in vec3 pos; +in float edgeWidthModulator; + +out vec4 pos_xformed; +out float widthModulator; + +void main() { + pos_xformed = ModelViewProjectionMatrix * vec4(pos, 1.0); + widthModulator = edgeWidthModulator; +} diff --git a/source/blender/gpu/shaders/gpu_shader_fire_frag.glsl b/source/blender/gpu/shaders/gpu_shader_fire_frag.glsl index 3819203bcd9..fc9cafb6b02 100644 --- a/source/blender/gpu/shaders/gpu_shader_fire_frag.glsl +++ b/source/blender/gpu/shaders/gpu_shader_fire_frag.glsl @@ -1,17 +1,15 @@ -varying vec3 coords; +in vec3 coords; +out vec4 fragColor; uniform sampler3D flame_texture; uniform sampler1D spectrum_texture; void main() { - float flame = texture3D(flame_texture, coords).r; - vec4 emission = texture1D(spectrum_texture, flame); + float flame = texture(flame_texture, coords).r; + vec4 emission = texture(spectrum_texture, flame); - vec4 color; - color.rgb = emission.a * emission.rgb; - color.a = emission.a; - - gl_FragColor = color; + fragColor.rgb = emission.a * emission.rgb; + fragColor.a = emission.a; } diff --git a/source/blender/gpu/shaders/gpu_shader_flat_color_alpha_test_0_frag.glsl b/source/blender/gpu/shaders/gpu_shader_flat_color_alpha_test_0_frag.glsl new file mode 100644 index 00000000000..cefae1021d2 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_flat_color_alpha_test_0_frag.glsl @@ -0,0 +1,11 @@ + +flat in vec4 finalColor; +out vec4 fragColor; + +void main() +{ + if (finalColor.a > 0.0) + fragColor = finalColor; + else + discard; +} diff --git a/source/blender/gpu/shaders/gpu_shader_flat_color_frag.glsl b/source/blender/gpu/shaders/gpu_shader_flat_color_frag.glsl new file mode 100644 index 00000000000..d738ed5ddb2 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_flat_color_frag.glsl @@ -0,0 +1,8 @@ + +flat in vec4 finalColor; +out vec4 fragColor; + +void main() +{ + fragColor = finalColor; +} diff --git a/source/blender/gpu/shaders/gpu_shader_flat_id_frag.glsl b/source/blender/gpu/shaders/gpu_shader_flat_id_frag.glsl new file mode 100644 index 00000000000..aa6f30531ae --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_flat_id_frag.glsl @@ -0,0 +1,8 @@ + +flat in uint finalId; +out uint fragId; + +void main() +{ + fragId = finalId; +} diff --git a/source/blender/gpu/shaders/gpu_shader_fx_depth_resolve.glsl b/source/blender/gpu/shaders/gpu_shader_fx_depth_resolve.glsl index e04cd7d3306..c4e7cff2b0b 100644 --- a/source/blender/gpu/shaders/gpu_shader_fx_depth_resolve.glsl +++ b/source/blender/gpu/shaders/gpu_shader_fx_depth_resolve.glsl @@ -1,9 +1,10 @@ uniform sampler2D depthbuffer; -varying vec4 uvcoordsvar; + +in vec4 uvcoordsvar; void main(void) { - float depth = texture2D(depthbuffer, uvcoordsvar.xy).r; + float depth = texture(depthbuffer, uvcoordsvar.xy).r; /* XRay background, discard */ if (depth >= 1.0) { diff --git a/source/blender/gpu/shaders/gpu_shader_fx_dof_frag.glsl b/source/blender/gpu/shaders/gpu_shader_fx_dof_frag.glsl index 338ef6d51a7..15d30e75969 100644 --- a/source/blender/gpu/shaders/gpu_shader_fx_dof_frag.glsl +++ b/source/blender/gpu/shaders/gpu_shader_fx_dof_frag.glsl @@ -17,17 +17,18 @@ uniform vec4 dof_params; uniform vec4 viewvecs[3]; // coordinates on framebuffer in normalized (0.0-1.0) uv space -varying vec4 uvcoordsvar; +in vec4 uvcoordsvar; /* color texture coordinates, offset by a small amount */ -varying vec2 color_uv1; -varying vec2 color_uv2; +in vec2 color_uv1; +in vec2 color_uv2; -varying vec2 depth_uv1; -varying vec2 depth_uv2; -varying vec2 depth_uv3; -varying vec2 depth_uv4; +in vec2 depth_uv1; +in vec2 depth_uv2; +in vec2 depth_uv3; +in vec2 depth_uv4; +out vec4 FragColor; float calculate_far_coc(in float zdepth) { @@ -63,85 +64,85 @@ void first_pass() offset_row[2] = 3.0 * offset_row[0]; /* heavily blur the image */ - vec4 color = texture2D(colorbuffer, color_uv1); - color += texture2D(colorbuffer, color_uv1 + offset_row[1]); - color += texture2D(colorbuffer, color_uv2); - color += texture2D(colorbuffer, color_uv2 + offset_row[1]); + vec4 color = texture(colorbuffer, color_uv1); + color += texture(colorbuffer, color_uv1 + offset_row[1]); + color += texture(colorbuffer, color_uv2); + color += texture(colorbuffer, color_uv2 + offset_row[1]); color /= 4.0; - depth.r = texture2D(depthbuffer, depth_uv1).r; - depth.g = texture2D(depthbuffer, depth_uv2).r; - depth.b = texture2D(depthbuffer, depth_uv3).r; - depth.a = texture2D(depthbuffer, depth_uv4).r; + depth.r = texture(depthbuffer, depth_uv1).r; + depth.g = texture(depthbuffer, depth_uv2).r; + depth.b = texture(depthbuffer, depth_uv3).r; + depth.a = texture(depthbuffer, depth_uv4).r; zdepth = get_view_space_z_from_depth(vec4(viewvecs[0].z), vec4(viewvecs[1].z), depth); coc = calculate_near_coc(zdepth); - depth.r = texture2D(depthbuffer, depth_uv1 + offset_row[0]).r; - depth.g = texture2D(depthbuffer, depth_uv2 + offset_row[0]).r; - depth.b = texture2D(depthbuffer, depth_uv3 + offset_row[0]).r; - depth.a = texture2D(depthbuffer, depth_uv4 + offset_row[0]).r; + depth.r = texture(depthbuffer, depth_uv1 + offset_row[0]).r; + depth.g = texture(depthbuffer, depth_uv2 + offset_row[0]).r; + depth.b = texture(depthbuffer, depth_uv3 + offset_row[0]).r; + depth.a = texture(depthbuffer, depth_uv4 + offset_row[0]).r; zdepth = get_view_space_z_from_depth(vec4(viewvecs[0].z), vec4(viewvecs[1].z), depth); coc = max(calculate_near_coc(zdepth), coc); - depth.r = texture2D(depthbuffer, depth_uv1 + offset_row[1]).r; - depth.g = texture2D(depthbuffer, depth_uv2 + offset_row[1]).r; - depth.b = texture2D(depthbuffer, depth_uv3 + offset_row[1]).r; - depth.a = texture2D(depthbuffer, depth_uv4 + offset_row[1]).r; + depth.r = texture(depthbuffer, depth_uv1 + offset_row[1]).r; + depth.g = texture(depthbuffer, depth_uv2 + offset_row[1]).r; + depth.b = texture(depthbuffer, depth_uv3 + offset_row[1]).r; + depth.a = texture(depthbuffer, depth_uv4 + offset_row[1]).r; zdepth = get_view_space_z_from_depth(vec4(viewvecs[0].z), vec4(viewvecs[1].z), depth); coc = max(calculate_near_coc(zdepth), coc); - depth.r = texture2D(depthbuffer, depth_uv1 + offset_row[2]).r; - depth.g = texture2D(depthbuffer, depth_uv2 + offset_row[2]).r; - depth.b = texture2D(depthbuffer, depth_uv3 + offset_row[2]).r; - depth.a = texture2D(depthbuffer, depth_uv4 + offset_row[2]).r; + depth.r = texture(depthbuffer, depth_uv1 + offset_row[2]).r; + depth.g = texture(depthbuffer, depth_uv2 + offset_row[2]).r; + depth.b = texture(depthbuffer, depth_uv3 + offset_row[2]).r; + depth.a = texture(depthbuffer, depth_uv4 + offset_row[2]).r; zdepth = get_view_space_z_from_depth(vec4(viewvecs[0].z), vec4(viewvecs[1].z), depth); coc = max(calculate_near_coc(zdepth), coc); final_coc = max(max(coc.x, coc.y), max(coc.z, coc.w)); - gl_FragColor = vec4(color.rgb, final_coc); + FragColor = vec4(color.rgb, final_coc); } /* second pass, gaussian blur the downsampled image */ void second_pass() { - vec4 depth = vec4(texture2D(depthbuffer, uvcoordsvar.xy).r); + vec4 depth = vec4(texture(depthbuffer, uvcoordsvar.xy).r); /* clever sampling to sample 2 pixels at once. Of course it's not real gaussian sampling this way */ - vec4 color = texture2D(colorbuffer, uvcoordsvar.xy) * 0.3125; - color += texture2D(colorbuffer, uvcoordsvar.xy + invrendertargetdim) * 0.234375; - color += texture2D(colorbuffer, uvcoordsvar.xy + 2.5 * invrendertargetdim) * 0.09375; - color += texture2D(colorbuffer, uvcoordsvar.xy + 4.5 * invrendertargetdim) * 0.015625; - color += texture2D(colorbuffer, uvcoordsvar.xy - invrendertargetdim) * 0.234375; - color += texture2D(colorbuffer, uvcoordsvar.xy - 2.5 * invrendertargetdim) * 0.09375; - color += texture2D(colorbuffer, uvcoordsvar.xy - 4.5 * invrendertargetdim) * 0.015625; - - gl_FragColor = color; + vec4 color = texture(colorbuffer, uvcoordsvar.xy) * 0.3125; + color += texture(colorbuffer, uvcoordsvar.xy + invrendertargetdim) * 0.234375; + color += texture(colorbuffer, uvcoordsvar.xy + 2.5 * invrendertargetdim) * 0.09375; + color += texture(colorbuffer, uvcoordsvar.xy + 4.5 * invrendertargetdim) * 0.015625; + color += texture(colorbuffer, uvcoordsvar.xy - invrendertargetdim) * 0.234375; + color += texture(colorbuffer, uvcoordsvar.xy - 2.5 * invrendertargetdim) * 0.09375; + color += texture(colorbuffer, uvcoordsvar.xy - 4.5 * invrendertargetdim) * 0.015625; + + FragColor = color; } /* third pass, calculate the final coc from blurred and unblurred images */ void third_pass() { - vec4 color = texture2D(colorbuffer, uvcoordsvar.xy); - vec4 color_blurred = texture2D(blurredcolorbuffer, uvcoordsvar.xy); + vec4 color = texture(colorbuffer, uvcoordsvar.xy); + vec4 color_blurred = texture(blurredcolorbuffer, uvcoordsvar.xy); float coc = 2.0 * max(color_blurred.a, color.a); -color.a; - gl_FragColor = vec4(color.rgb, coc); + FragColor = vec4(color.rgb, coc); } /* fourth pass, blur the final coc once to get rid of discontinuities */ void fourth_pass() { - vec4 color = texture2D(colorbuffer, uvcoordsvar.xz); - color += texture2D(colorbuffer, uvcoordsvar.yz); - color += texture2D(colorbuffer, uvcoordsvar.xw); - color += texture2D(colorbuffer, uvcoordsvar.yw); + vec4 color = texture(colorbuffer, uvcoordsvar.xz); + color += texture(colorbuffer, uvcoordsvar.yz); + color += texture(colorbuffer, uvcoordsvar.xw); + color += texture(colorbuffer, uvcoordsvar.yw); - gl_FragColor = color / 4.0; + FragColor = color / 4.0; } vec4 small_sample_blur(in sampler2D colorbuffer, in vec2 uv, in vec4 color) @@ -150,10 +151,10 @@ vec4 small_sample_blur(in sampler2D colorbuffer, in vec2 uv, in vec4 color) vec4 result = weight * color; weight *= 4.0; - result += weight * texture2D(colorbuffer, uv + color_uv1.xy); - result += weight * texture2D(colorbuffer, uv - color_uv1.xy); - result += weight * texture2D(colorbuffer, uv + color_uv1.yx); - result += weight * texture2D(colorbuffer, uv - color_uv1.yx); + result += weight * texture(colorbuffer, uv + color_uv1.xy); + result += weight * texture(colorbuffer, uv - color_uv1.xy); + result += weight * texture(colorbuffer, uv + color_uv1.yx); + result += weight * texture(colorbuffer, uv - color_uv1.yx); return result; } @@ -163,11 +164,11 @@ vec4 small_sample_blur(in sampler2D colorbuffer, in vec2 uv, in vec4 color) void fifth_pass() { vec4 factors; - vec4 color_orig = texture2D(colorbuffer, uvcoordsvar.xy); - vec4 highblurred = texture2D(blurredcolorbuffer, uvcoordsvar.xy); - vec4 mediumblurred = texture2D(mblurredcolorbuffer, uvcoordsvar.xy); + vec4 color_orig = texture(colorbuffer, uvcoordsvar.xy); + vec4 highblurred = texture(blurredcolorbuffer, uvcoordsvar.xy); + vec4 mediumblurred = texture(mblurredcolorbuffer, uvcoordsvar.xy); vec4 smallblurred = small_sample_blur(colorbuffer, uvcoordsvar.xy, color_orig); - float depth = texture2D(depthbuffer, uvcoordsvar.xy).r; + float depth = texture(depthbuffer, uvcoordsvar.xy).r; float zdepth = get_view_space_z_from_depth(vec4(viewvecs[0].z), vec4(viewvecs[1].z), vec4(depth)).r; float coc_far = clamp(calculate_far_coc(zdepth), 0.0, 1.0); @@ -188,7 +189,7 @@ void fifth_pass() color /= dot(factors, vec4(1.0)); /* using original color is not correct, but use that for now because alpha of * blurred buffers uses CoC instead */ - gl_FragColor = vec4(color.rgb, color_orig.a); + FragColor = vec4(color.rgb, color_orig.a); } diff --git a/source/blender/gpu/shaders/gpu_shader_fx_dof_hq_frag.glsl b/source/blender/gpu/shaders/gpu_shader_fx_dof_hq_frag.glsl index 182113367d3..c41c1d0820b 100644 --- a/source/blender/gpu/shaders/gpu_shader_fx_dof_hq_frag.glsl +++ b/source/blender/gpu/shaders/gpu_shader_fx_dof_hq_frag.glsl @@ -14,24 +14,28 @@ uniform sampler2D depthbuffer; uniform sampler2D cocbuffer; -/* this includes focal distance in x and aperture size in y */ +/* this includes aperture size in x and focal distance in y */ uniform vec4 dof_params; /* viewvectors for reconstruction of world space */ uniform vec4 viewvecs[3]; /* initial uv coordinate */ -varying vec2 uvcoord; +in vec2 uvcoord; /* coordinate used for calculating radius et al set in geometry shader */ -varying vec2 particlecoord; -varying vec4 color; +in vec2 particlecoord; +flat in vec4 color; /* downsampling coordinates */ -varying vec2 downsample1; -varying vec2 downsample2; -varying vec2 downsample3; -varying vec2 downsample4; +in vec2 downsample1; +in vec2 downsample2; +in vec2 downsample3; +in vec2 downsample4; + +layout(location = 0) out vec4 fragData0; +layout(location = 1) out vec4 fragData1; +layout(location = 2) out vec4 fragData2; #define M_PI 3.1415926535897932384626433832795 @@ -55,15 +59,15 @@ void downsample_pass() float far_coc, near_coc; /* custom downsampling. We need to be careful to sample nearest here to avoid leaks */ - vec4 color1 = texture2D(colorbuffer, downsample1); - vec4 color2 = texture2D(colorbuffer, downsample2); - vec4 color3 = texture2D(colorbuffer, downsample3); - vec4 color4 = texture2D(colorbuffer, downsample4); + vec4 color1 = texture(colorbuffer, downsample1); + vec4 color2 = texture(colorbuffer, downsample2); + vec4 color3 = texture(colorbuffer, downsample3); + vec4 color4 = texture(colorbuffer, downsample4); - depth.r = texture2D(depthbuffer, downsample1).r; - depth.g = texture2D(depthbuffer, downsample2).r; - depth.b = texture2D(depthbuffer, downsample3).r; - depth.a = texture2D(depthbuffer, downsample4).r; + depth.r = texture(depthbuffer, downsample1).r; + depth.g = texture(depthbuffer, downsample2).r; + depth.b = texture(depthbuffer, downsample3).r; + depth.a = texture(depthbuffer, downsample4).r; zdepth = get_view_space_z_from_depth(vec4(viewvecs[0].z), vec4(viewvecs[1].z), depth); coc = calculate_coc(zdepth); @@ -82,16 +86,16 @@ void downsample_pass() float norm_far = dot(far_weights, vec4(1.0)); /* now write output to weighted buffers. */ - gl_FragData[0] = color1 * near_weights.x + color2 * near_weights.y + color3 * near_weights.z + + fragData0 = color1 * near_weights.x + color2 * near_weights.y + color3 * near_weights.z + color4 * near_weights.w; - gl_FragData[1] = color1 * far_weights.x + color2 * far_weights.y + color3 * far_weights.z + + fragData1 = color1 * far_weights.x + color2 * far_weights.y + color3 * far_weights.z + color4 * far_weights.w; if (norm_near > 0.0) - gl_FragData[0] /= norm_near; + fragData0 /= norm_near; if (norm_far > 0.0) - gl_FragData[1] /= norm_far; - gl_FragData[2] = vec4(near_coc, far_coc, 0.0, 1.0); + fragData1 /= norm_far; + fragData2 = vec4(near_coc, far_coc, 0.0, 1.0); } /* accumulate color in the near/far blur buffers */ @@ -102,36 +106,36 @@ void accumulate_pass(void) { if (dof_params.w == 0.0) r = 1.0; else - r = cos(M_PI / dof_params.w) / - (cos(theta - (2.0 * M_PI / dof_params.w) * floor((dof_params.w * theta + M_PI) / (2.0 * M_PI)))); + r = cos(M_PI / dof_params.w) / + (cos(theta - (2.0 * M_PI / dof_params.w) * floor((dof_params.w * theta + M_PI) / (2.0 * M_PI)))); if (dot(particlecoord, particlecoord) > r * r) discard; - gl_FragData[0] = color; + fragData0 = color; } -#define MERGE_THRESHOLD 4.0 +#define MERGE_THRESHOLD 4.0 /* combine the passes, */ void final_pass(void) { vec4 finalcolor; float totalweight; - float depth = texture2D(depthbuffer, uvcoord).r; + float depth = texture(depthbuffer, uvcoord).r; vec4 zdepth = get_view_space_z_from_depth(vec4(viewvecs[0].z), vec4(viewvecs[1].z), vec4(depth)); float coc_near = calculate_coc(zdepth).r; float coc_far = max(-coc_near, 0.0); coc_near = max(coc_near, 0.0); - vec4 farcolor = texture2D(farbuffer, uvcoord); + vec4 farcolor = texture(farbuffer, uvcoord); float farweight = farcolor.a; if (farweight > 0.0) farcolor /= farweight; - vec4 nearcolor = texture2D(nearbuffer, uvcoord); + vec4 nearcolor = texture(nearbuffer, uvcoord); - vec4 srccolor = texture2D(colorbuffer, uvcoord); + vec4 srccolor = texture(colorbuffer, uvcoord); - vec4 coc = texture2D(cocbuffer, uvcoord); + vec4 coc = texture(cocbuffer, uvcoord); float mixfac = smoothstep(1.0, MERGE_THRESHOLD, coc_far); finalcolor = mix(srccolor, farcolor, mixfac); @@ -152,7 +156,9 @@ void final_pass(void) { finalcolor = mix(finalcolor, nearcolor, nearweight / totalweight); } - gl_FragData[0] = finalcolor; + fragData0 = finalcolor; + // fragData0 = vec4(nearweight, farweight, 0.0, 1.0); + // fragData0 = vec4(nearcolor.rgb, 1.0); } void main() diff --git a/source/blender/gpu/shaders/gpu_shader_fx_dof_hq_geo.glsl b/source/blender/gpu/shaders/gpu_shader_fx_dof_hq_geo.glsl index 4c650e7695f..52d0a9be499 100644 --- a/source/blender/gpu/shaders/gpu_shader_fx_dof_hq_geo.glsl +++ b/source/blender/gpu/shaders/gpu_shader_fx_dof_hq_geo.glsl @@ -5,27 +5,14 @@ uniform vec2 layerselection; uniform sampler2D cocbuffer; -#if __VERSION__ >= 150 - layout(points) in; - layout(triangle_strip, max_vertices = 4) out; - - #define POS gl_in[0].gl_Position -#else - /* use the EXT_geometry_shader4 way */ - #define POS gl_PositionIn[0] -#endif - -/* initial uv coordinate */ -#if __VERSION__ < 130 - varying in vec2 uvcoord[]; - varying out vec2 particlecoord; - varying out vec4 color; - #define textureLod texture2DLod -#else - in vec2 uvcoord[]; - out vec2 particlecoord; - out vec4 color; -#endif +layout(points) in; +layout(triangle_strip, max_vertices = 4) out; + +#define POS gl_in[0].gl_Position + +in vec2 uvcoord[]; +out vec2 particlecoord; +flat out vec4 color; #define M_PI 3.1415926535897932384626433832795 @@ -46,21 +33,23 @@ void main() vec2 offset_far = vec2(offset_val * 0.5) / vec2(rendertargetdim.x, rendertargetdim.y); - gl_Position = POS + vec4(-offset_far.x, -offset_far.y, 0.0, 0.0); color = colortex; + + gl_Position = POS + vec4(-offset_far.x, -offset_far.y, 0.0, 0.0); particlecoord = vec2(-1.0, -1.0); EmitVertex(); + gl_Position = POS + vec4(-offset_far.x, offset_far.y, 0.0, 0.0); particlecoord = vec2(-1.0, 1.0); - color = colortex; EmitVertex(); + gl_Position = POS + vec4(offset_far.x, -offset_far.y, 0.0, 0.0); particlecoord = vec2(1.0, -1.0); - color = colortex; EmitVertex(); + gl_Position = POS + vec4(offset_far.x, offset_far.y, 0.0, 0.0); particlecoord = vec2(1.0, 1.0); - color = colortex; EmitVertex(); + EndPrimitive(); } diff --git a/source/blender/gpu/shaders/gpu_shader_fx_dof_hq_vert.glsl b/source/blender/gpu/shaders/gpu_shader_fx_dof_hq_vert.glsl index 09a0c75facc..1dd5bf42b25 100644 --- a/source/blender/gpu/shaders/gpu_shader_fx_dof_hq_vert.glsl +++ b/source/blender/gpu/shaders/gpu_shader_fx_dof_hq_vert.glsl @@ -1,27 +1,31 @@ -uniform vec2 invrendertargetdim; -uniform ivec2 rendertargetdim; + +in vec2 pos; +in vec2 uvs; /* initial uv coordinate */ -varying vec2 uvcoord; +out vec2 uvcoord; /* coordinate used for calculating radius et al set in geometry shader */ -varying vec2 particlecoord; +out vec2 particlecoord; /* downsampling coordinates */ -varying vec2 downsample1; -varying vec2 downsample2; -varying vec2 downsample3; -varying vec2 downsample4; +out vec2 downsample1; +out vec2 downsample2; +out vec2 downsample3; +out vec2 downsample4; + +uniform vec2 invrendertargetdim; +uniform ivec2 rendertargetdim; void vert_dof_downsample() { /* gather pixels from neighbors. half dimensions means we offset half a pixel to * get this right though it's possible we may lose a pixel at some point */ - downsample1 = gl_MultiTexCoord0.xy + vec2(-0.5, -0.5) * invrendertargetdim; - downsample2 = gl_MultiTexCoord0.xy + vec2(-0.5, 0.5) * invrendertargetdim; - downsample3 = gl_MultiTexCoord0.xy + vec2(0.5, 0.5) * invrendertargetdim; - downsample4 = gl_MultiTexCoord0.xy + vec2(0.5, -0.5) * invrendertargetdim; + downsample1 = uvs.xy + vec2(-0.5, -0.5) * invrendertargetdim; + downsample2 = uvs.xy + vec2(-0.5, 0.5) * invrendertargetdim; + downsample3 = uvs.xy + vec2(0.5, 0.5) * invrendertargetdim; + downsample4 = uvs.xy + vec2(0.5, -0.5) * invrendertargetdim; - gl_Position = gl_Vertex; + gl_Position = vec4(pos, 0.0, 1.0); } /* geometry shading pass, calculate a texture coordinate based on the indexed id */ @@ -42,8 +46,8 @@ void vert_dof_coc_scatter_pass() void vert_dof_final() { - uvcoord = gl_MultiTexCoord0.xy; - gl_Position = gl_Vertex; + uvcoord = uvs; + gl_Position = vec4(pos, 0.0, 1.0); } void main() diff --git a/source/blender/gpu/shaders/gpu_shader_fx_dof_vert.glsl b/source/blender/gpu/shaders/gpu_shader_fx_dof_vert.glsl index 63b57d5775c..0fcab6302e4 100644 --- a/source/blender/gpu/shaders/gpu_shader_fx_dof_vert.glsl +++ b/source/blender/gpu/shaders/gpu_shader_fx_dof_vert.glsl @@ -1,51 +1,54 @@ uniform vec2 invrendertargetdim; -//texture coordinates for framebuffer read -varying vec4 uvcoordsvar; +in vec2 pos; +in vec2 uvs; + +/* texture coordinates for framebuffer read */ +out vec4 uvcoordsvar; /* color texture coordinates, offset by a small amount */ -varying vec2 color_uv1; -varying vec2 color_uv2; +out vec2 color_uv1; +out vec2 color_uv2; -varying vec2 depth_uv1; -varying vec2 depth_uv2; -varying vec2 depth_uv3; -varying vec2 depth_uv4; +out vec2 depth_uv1; +out vec2 depth_uv2; +out vec2 depth_uv3; +out vec2 depth_uv4; //very simple shader for gull screen FX, just pass values on void vert_generic() { - uvcoordsvar = gl_MultiTexCoord0; - gl_Position = gl_Vertex; + uvcoordsvar = vec4(uvs, 0.0, 0.0); + gl_Position = vec4(pos, 0.0, 1.0); } void vert_dof_first_pass() { /* we offset the texture coordinates by 1.5 pixel, * then we reuse that to sample the surrounding pixels */ - color_uv1 = gl_MultiTexCoord0.xy + vec2(-1.5, -1.5) * invrendertargetdim; - color_uv2 = gl_MultiTexCoord0.xy + vec2(0.5, -1.5) * invrendertargetdim; + color_uv1 = uvs.xy + vec2(-1.5, -1.5) * invrendertargetdim; + color_uv2 = uvs.xy + vec2(0.5, -1.5) * invrendertargetdim; - depth_uv1 = gl_MultiTexCoord0.xy + vec2(-1.5, -1.5) * invrendertargetdim; - depth_uv2 = gl_MultiTexCoord0.xy + vec2(-0.5, -1.5) * invrendertargetdim; - depth_uv3 = gl_MultiTexCoord0.xy + vec2(0.5, -1.5) * invrendertargetdim; - depth_uv4 = gl_MultiTexCoord0.xy + vec2(1.5, -1.5) * invrendertargetdim; + depth_uv1 = uvs.xy + vec2(-1.5, -1.5) * invrendertargetdim; + depth_uv2 = uvs.xy + vec2(-0.5, -1.5) * invrendertargetdim; + depth_uv3 = uvs.xy + vec2(0.5, -1.5) * invrendertargetdim; + depth_uv4 = uvs.xy + vec2(1.5, -1.5) * invrendertargetdim; - gl_Position = gl_Vertex; + gl_Position = vec4(pos, 0.0, 1.0); } void vert_dof_fourth_pass() { vec4 halfpixel = vec4(-0.5, 0.5, -0.5, 0.5); - uvcoordsvar = gl_MultiTexCoord0.xxyy + + uvcoordsvar = uvs.xxyy + halfpixel * vec4(invrendertargetdim.x, invrendertargetdim.x, invrendertargetdim.y, invrendertargetdim.y); - gl_Position = gl_Vertex; + gl_Position = vec4(pos, 0.0, 1.0); } void vert_dof_fifth_pass() @@ -53,8 +56,8 @@ void vert_dof_fifth_pass() vec4 halfpixel = vec4(-0.5, 0.5, -0.5, 0.5); color_uv1 = vec2(0.5, 1.5) * invrendertargetdim; - uvcoordsvar = gl_MultiTexCoord0; - gl_Position = gl_Vertex; + uvcoordsvar = vec4(uvs, 0.0, 0.0); + gl_Position = vec4(pos, 0.0, 1.0); } void main() diff --git a/source/blender/gpu/shaders/gpu_shader_fx_lib.glsl b/source/blender/gpu/shaders/gpu_shader_fx_lib.glsl index 1dc49b52be1..7aa6786d292 100644 --- a/source/blender/gpu/shaders/gpu_shader_fx_lib.glsl +++ b/source/blender/gpu/shaders/gpu_shader_fx_lib.glsl @@ -1,14 +1,17 @@ +uniform mat4 ProjectionMatrix; + /* simple depth reconstruction, see http://www.derschmale.com/2014/01/26/reconstructing-positions-from-the-depth-buffer * we change the factors from the article to fit the OpennGL model. */ #ifdef PERSP_MATRIX + /* perspective camera code */ vec3 get_view_space_from_depth(in vec2 uvcoords, in vec3 viewvec_origin, in vec3 viewvec_diff, in float depth) { float d = 2.0 * depth - 1.0; - float zview = -gl_ProjectionMatrix[3][2] / (d + gl_ProjectionMatrix[2][2]); + float zview = -ProjectionMatrix[3][2] / (d + ProjectionMatrix[2][2]); return zview * (viewvec_origin + vec3(uvcoords, 0.0) * viewvec_diff); } @@ -18,7 +21,7 @@ vec4 get_view_space_z_from_depth(in vec4 near, in vec4 range, in vec4 depth) vec4 d = 2.0 * depth - vec4(1.0); /* return positive value, so sign differs! */ - return vec4(gl_ProjectionMatrix[3][2]) / (d + vec4(gl_ProjectionMatrix[2][2])); + return vec4(ProjectionMatrix[3][2]) / (d + vec4(ProjectionMatrix[2][2])); } #else diff --git a/source/blender/gpu/shaders/gpu_shader_fx_ssao_frag.glsl b/source/blender/gpu/shaders/gpu_shader_fx_ssao_frag.glsl index f19ff4ec65a..4904010c841 100644 --- a/source/blender/gpu/shaders/gpu_shader_fx_ssao_frag.glsl +++ b/source/blender/gpu/shaders/gpu_shader_fx_ssao_frag.glsl @@ -1,3 +1,4 @@ + // color buffer uniform sampler2D colorbuffer; @@ -9,8 +10,10 @@ uniform sampler1D ssao_concentric_tex; // depth buffer uniform sampler2D depthbuffer; + // coordinates on framebuffer in normalized (0.0-1.0) uv space -varying vec4 uvcoordsvar; +in vec4 uvcoordsvar; +out vec4 FragColor; /* ssao_params.x : pixel scale for the ssao radious */ /* ssao_params.y : factor for the ssao darkening */ @@ -33,7 +36,7 @@ vec3 calculate_view_space_normal(in vec3 viewposition) float calculate_ssao_factor(float depth) { /* take the normalized ray direction here */ - vec2 rotX = texture2D(jitter_tex, uvcoordsvar.xy * ssao_sample_params.yz).rg; + vec2 rotX = texture(jitter_tex, uvcoordsvar.xy * ssao_sample_params.yz).rg; vec2 rotY = vec2(-rotX.y, rotX.x); /* occlusion is zero in full depth */ @@ -46,9 +49,9 @@ float calculate_ssao_factor(float depth) /* find the offset in screen space by multiplying a point * in camera space at the depth of the point by the projection matrix. */ vec2 offset; - float homcoord = gl_ProjectionMatrix[2][3] * position.z + gl_ProjectionMatrix[3][3]; - offset.x = gl_ProjectionMatrix[0][0] * ssao_params.x / homcoord; - offset.y = gl_ProjectionMatrix[1][1] * ssao_params.x / homcoord; + float homcoord = ProjectionMatrix[2][3] * position.z + ProjectionMatrix[3][3]; + offset.x = ProjectionMatrix[0][0] * ssao_params.x / homcoord; + offset.y = ProjectionMatrix[1][1] * ssao_params.x / homcoord; /* convert from -1.0...1.0 range to 0.0..1.0 for easy use with texture coordinates */ offset *= 0.5; @@ -57,7 +60,7 @@ float calculate_ssao_factor(float depth) int num_samples = int(ssao_sample_params.x); for (x = 0; x < num_samples; x++) { - vec2 dir_sample = texture1D(ssao_concentric_tex, (float(x) + 0.5) / ssao_sample_params.x).rg; + vec2 dir_sample = texture(ssao_concentric_tex, (float(x) + 0.5) / ssao_sample_params.x).rg; /* rotate with random direction to get jittered result */ vec2 dir_jittered = vec2(dot(dir_sample, rotX), dot(dir_sample, rotY)); @@ -67,7 +70,7 @@ float calculate_ssao_factor(float depth) if (uvcoords.x > 1.0 || uvcoords.x < 0.0 || uvcoords.y > 1.0 || uvcoords.y < 0.0) continue; - float depth_new = texture2D(depthbuffer, uvcoords).r; + float depth_new = texture(depthbuffer, uvcoords).r; if (depth_new != 1.0) { vec3 pos_new = get_view_space_from_depth(uvcoords, viewvecs[0].xyz, viewvecs[1].xyz, depth_new); vec3 dir = pos_new - position; @@ -87,8 +90,8 @@ float calculate_ssao_factor(float depth) void main() { - float depth = texture2D(depthbuffer, uvcoordsvar.xy).r; - vec4 scene_col = texture2D(colorbuffer, uvcoordsvar.xy); + float depth = texture(depthbuffer, uvcoordsvar.xy).r; + vec4 scene_col = texture(colorbuffer, uvcoordsvar.xy); vec3 final_color = mix(scene_col.rgb, ssao_color.rgb, calculate_ssao_factor(depth)); - gl_FragColor = vec4(final_color.rgb, scene_col.a); + FragColor = vec4(final_color.rgb, scene_col.a); } diff --git a/source/blender/gpu/shaders/gpu_shader_fx_vert.glsl b/source/blender/gpu/shaders/gpu_shader_fx_vert.glsl deleted file mode 100644 index 5194e414520..00000000000 --- a/source/blender/gpu/shaders/gpu_shader_fx_vert.glsl +++ /dev/null @@ -1,9 +0,0 @@ -varying vec4 uvcoordsvar; - -//very simple shader for full screen FX, just pass values on - -void main() -{ - uvcoordsvar = gl_MultiTexCoord0; - gl_Position = gl_Vertex; -} diff --git a/source/blender/gpu/shaders/gpu_shader_geometry.glsl b/source/blender/gpu/shaders/gpu_shader_geometry.glsl index fe630dbeddb..705b79cbf56 100644 --- a/source/blender/gpu/shaders/gpu_shader_geometry.glsl +++ b/source/blender/gpu/shaders/gpu_shader_geometry.glsl @@ -1,10 +1,11 @@ + +uniform mat4 ProjectionMatrix; + uniform int PrimitiveIdBase; uniform int osd_active_uv_offset; -#if __VERSION__ >= 150 - layout(lines_adjacency) in; - layout(triangle_strip, max_vertices = 4) out; -#endif +layout(lines_adjacency) in; +layout(triangle_strip, max_vertices = 4) out; in block { VertexData v; @@ -31,17 +32,12 @@ uniform int osd_fvar_count; tessCoord.t); \ } -#ifdef USE_NEW_SHADING # define INTERP_FACE_VARYING_ATT_2(result, fvarOffset, tessCoord) \ { \ vec2 tmp; \ INTERP_FACE_VARYING_2(tmp, fvarOffset, tessCoord); \ result = vec3(tmp, 0); \ } -#else -# define INTERP_FACE_VARYING_ATT_2(result, fvarOffset, tessCoord) \ - INTERP_FACE_VARYING_2(result, fvarOffset, tessCoord) -#endif uniform samplerBuffer FVarDataBuffer; uniform isamplerBuffer FVarDataOffsetBuffer; @@ -69,7 +65,7 @@ void emit_flat(int index, vec3 normal) set_mtface_vertex_attrs(st); - gl_Position = gl_ProjectionMatrix * inpt[index].v.position; + gl_Position = ProjectionMatrix * inpt[index].v.position; EmitVertex(); } @@ -90,7 +86,7 @@ void emit_smooth(int index) set_mtface_vertex_attrs(st); - gl_Position = gl_ProjectionMatrix * inpt[index].v.position; + gl_Position = ProjectionMatrix * inpt[index].v.position; EmitVertex(); } diff --git a/source/blender/gpu/shaders/gpu_shader_image_alpha_color_frag.glsl b/source/blender/gpu/shaders/gpu_shader_image_alpha_color_frag.glsl new file mode 100644 index 00000000000..727c3c0a832 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_image_alpha_color_frag.glsl @@ -0,0 +1,11 @@ + +in vec2 texCoord_interp; +out vec4 fragColor; + +uniform vec4 color; +uniform sampler2D image; + +void main() +{ + fragColor = texture(image, texCoord_interp).r * color; +} diff --git a/source/blender/gpu/shaders/gpu_shader_image_color_frag.glsl b/source/blender/gpu/shaders/gpu_shader_image_color_frag.glsl new file mode 100644 index 00000000000..ef8935cc7ba --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_image_color_frag.glsl @@ -0,0 +1,11 @@ + +in vec2 texCoord_interp; +out vec4 fragColor; + +uniform vec4 color; +uniform sampler2D image; + +void main() +{ + fragColor = texture(image, texCoord_interp) * color; +} 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_depth_linear_frag.glsl b/source/blender/gpu/shaders/gpu_shader_image_depth_linear_frag.glsl new file mode 100644 index 00000000000..bcbe1f577fd --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_image_depth_linear_frag.glsl @@ -0,0 +1,16 @@ + +in vec2 texCoord_interp; +out vec4 fragColor; + +uniform float znear; +uniform float zfar; +uniform sampler2D image; + +void main() +{ + float depth = texture(image, texCoord_interp).r; + + /* normalize */ + fragColor.rgb = vec3((2.0f * znear) / (zfar + znear - (depth * (zfar - znear)))); + fragColor.a = 1.0f; +} diff --git a/source/blender/gpu/shaders/gpu_shader_image_desaturate_frag.glsl b/source/blender/gpu/shaders/gpu_shader_image_desaturate_frag.glsl new file mode 100644 index 00000000000..1ac0d68b35f --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_image_desaturate_frag.glsl @@ -0,0 +1,14 @@ + +uniform float factor; +in vec2 texCoord_interp; +out vec4 fragColor; + +uniform vec4 color; +uniform sampler2D image; + +void main() +{ + vec4 tex = texture(image, texCoord_interp); + tex.rgb = ((0.3333333 * factor) * vec3(tex.r + tex.g + tex.b)) + (tex.rgb * (1.0 - factor)); + fragColor = tex * color; +} diff --git a/source/blender/gpu/shaders/gpu_shader_image_frag.glsl b/source/blender/gpu/shaders/gpu_shader_image_frag.glsl new file mode 100644 index 00000000000..6eeab8ca7e8 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_image_frag.glsl @@ -0,0 +1,10 @@ + +in vec2 texCoord_interp; +out vec4 fragColor; + +uniform sampler2D image; + +void main() +{ + fragColor = texture(image, texCoord_interp); +} diff --git a/source/blender/gpu/shaders/gpu_shader_image_interlace_frag.glsl b/source/blender/gpu/shaders/gpu_shader_image_interlace_frag.glsl new file mode 100644 index 00000000000..d95645f58e5 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_image_interlace_frag.glsl @@ -0,0 +1,34 @@ + +/* Keep these in sync with GPU_shader.h */ +#define INTERLACE_ROW 0 +#define INTERLACE_COLUMN 1 +#define INTERLACE_CHECKERBOARD 2 + +in vec2 texCoord_interp; +out vec4 fragColor; + +uniform int interlace_id; +uniform sampler2D image_a; +uniform sampler2D image_b; + +bool interlace() +{ + if (interlace_id == INTERLACE_CHECKERBOARD) { + return (int(gl_FragCoord.x + gl_FragCoord.y) & 1) != 0; + } + else if (interlace_id == INTERLACE_ROW) { + return (int(gl_FragCoord.y) & 1) != 0; + } + else if (interlace_id == INTERLACE_COLUMN) { + return (int(gl_FragCoord.x) & 1) != 0; + } +} + +void main() +{ + if (interlace()) { + fragColor = texture(image_a, texCoord_interp); + } else { + fragColor = texture(image_b, texCoord_interp); + } +} diff --git a/source/blender/gpu/shaders/gpu_shader_image_linear_frag.glsl b/source/blender/gpu/shaders/gpu_shader_image_linear_frag.glsl new file mode 100644 index 00000000000..97eb3afc177 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_image_linear_frag.glsl @@ -0,0 +1,30 @@ + +/* Display a linear image texture into sRGB space */ + +uniform sampler2D image; + +in vec2 texCoord_interp; + +out vec4 fragColor; + +float linearrgb_to_srgb(float c) +{ + if (c < 0.0031308) + return (c < 0.0) ? 0.0 : c * 12.92; + else + return 1.055 * pow(c, 1.0 / 2.4) - 0.055; +} + +void linearrgb_to_srgb(vec4 col_from, out vec4 col_to) +{ + col_to.r = linearrgb_to_srgb(col_from.r); + col_to.g = linearrgb_to_srgb(col_from.g); + col_to.b = linearrgb_to_srgb(col_from.b); + col_to.a = col_from.a; +} + +void main() { + fragColor = texture(image, texCoord_interp.st); + + linearrgb_to_srgb(fragColor, fragColor); +} diff --git a/source/blender/gpu/shaders/gpu_shader_image_mask_uniform_color_frag.glsl b/source/blender/gpu/shaders/gpu_shader_image_mask_uniform_color_frag.glsl new file mode 100644 index 00000000000..4a45d03175e --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_image_mask_uniform_color_frag.glsl @@ -0,0 +1,12 @@ + +in vec2 texCoord_interp; +out vec4 fragColor; + +uniform sampler2D image; +uniform vec4 color; + +void main() +{ + fragColor.a = texture(image, texCoord_interp).a * color.a; + fragColor.rgb = color.rgb; +} diff --git a/source/blender/gpu/shaders/gpu_shader_image_modulate_alpha_frag.glsl b/source/blender/gpu/shaders/gpu_shader_image_modulate_alpha_frag.glsl new file mode 100644 index 00000000000..51092d56e5e --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_image_modulate_alpha_frag.glsl @@ -0,0 +1,12 @@ + +in vec2 texCoord_interp; +out vec4 fragColor; + +uniform float alpha; +uniform sampler2D image; + +void main() +{ + fragColor = texture(image, texCoord_interp); + fragColor.a *= alpha; +} diff --git a/source/blender/gpu/shaders/gpu_shader_image_multisample_resolve_frag.glsl b/source/blender/gpu/shaders/gpu_shader_image_multisample_resolve_frag.glsl new file mode 100644 index 00000000000..57362c88320 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_image_multisample_resolve_frag.glsl @@ -0,0 +1,124 @@ + +uniform sampler2DMS depthMulti; +uniform sampler2DMS colorMulti; + +out vec4 fragColor; + +#if SAMPLES > 16 +#error "Too many samples" +#endif + +// #define USE_DEPTH_WEIGHTING + +void main() +{ + ivec2 texel = ivec2(gl_FragCoord.xy); + + bvec4 b1, b2, b3, b4; + vec4 w1, w2, w3, w4; + vec4 d1, d2, d3, d4; + vec4 c1, c2, c3, c4, c5, c6, c7, c8; + vec4 c9, c10, c11, c12, c13, c14, c15, c16; + d1 = d2 = d3 = d4 = vec4(1.0); + w1 = w2 = w3 = w4 = vec4(0.0); + c1 = c2 = c3 = c4 = c5 = c6 = c7 = c8 = vec4(0.0); + c9 = c10 = c11 = c12 = c13 = c14 = c15 = c16 = vec4(0.0); + + /* Depth */ + + d1.x = texelFetch(depthMulti, texel, 0).r; + d1.y = texelFetch(depthMulti, texel, 1).r; +#if SAMPLES > 2 + d1.z = texelFetch(depthMulti, texel, 2).r; + d1.w = texelFetch(depthMulti, texel, 3).r; +#endif +#if SAMPLES > 4 + d2.x = texelFetch(depthMulti, texel, 4).r; + d2.y = texelFetch(depthMulti, texel, 5).r; + d2.z = texelFetch(depthMulti, texel, 6).r; + d2.w = texelFetch(depthMulti, texel, 7).r; +#endif +#if SAMPLES > 8 + d3.x = texelFetch(depthMulti, texel, 8).r; + d3.y = texelFetch(depthMulti, texel, 9).r; + d3.z = texelFetch(depthMulti, texel, 10).r; + d3.w = texelFetch(depthMulti, texel, 11).r; + d4.x = texelFetch(depthMulti, texel, 12).r; + d4.y = texelFetch(depthMulti, texel, 13).r; + d4.z = texelFetch(depthMulti, texel, 14).r; + d4.w = texelFetch(depthMulti, texel, 15).r; +#endif + + /* COLOR */ + b1 = notEqual(d1, vec4(1.0)); + if (any(b1)) { + c1 = texelFetch(colorMulti, texel, 0); + c2 = texelFetch(colorMulti, texel, 1); +#if SAMPLES > 2 + c3 = texelFetch(colorMulti, texel, 2); + c4 = texelFetch(colorMulti, texel, 3); +#endif + w1 = vec4(b1); + } +#if SAMPLES > 4 + b2 = notEqual(d2, vec4(1.0)); + if (any(b2)) { + c5 = texelFetch(colorMulti, texel, 4); + c6 = texelFetch(colorMulti, texel, 5); + c7 = texelFetch(colorMulti, texel, 6); + c8 = texelFetch(colorMulti, texel, 7); + w2 = vec4(b2); + } +#endif +#if SAMPLES > 8 + b3 = notEqual(d3, vec4(1.0)); + if (any(b3)) { + c9 = texelFetch(colorMulti, texel, 8); + c10 = texelFetch(colorMulti, texel, 9); + c11 = texelFetch(colorMulti, texel, 10); + c12 = texelFetch(colorMulti, texel, 11); + w3 = vec4(b3); + } + b4 = notEqual(d4, vec4(1.0)); + if (any(b4)) { + c13 = texelFetch(colorMulti, texel, 12); + c14 = texelFetch(colorMulti, texel, 13); + c15 = texelFetch(colorMulti, texel, 14); + c16 = texelFetch(colorMulti, texel, 15); + w4 = vec4(b4); + } +#endif + +#if SAMPLES > 8 + d1 = min(d1, min(d3, d4)); +#endif +#if SAMPLES > 4 + d1 = min(d1, d2); +#endif +#if SAMPLES > 2 + d1.xy = min(d1.xy, d1.zw); +#endif + gl_FragDepth = min(d1.x, d1.y); + +#ifdef USE_DEPTH_WEIGHTING + c1 *= w1.x; c2 *= w1.y; c3 *= w1.z; c4 *= w1.w; + c5 *= w2.x; c6 *= w2.y; c7 *= w2.z; c8 *= w2.w; + c9 *= w3.x; c10 *= w3.y; c11 *= w3.z; c12 *= w3.w; + c13 *= w4.x; c14 *= w4.y; c15 *= w4.z; c16 *= w4.w; +#endif + + c1 = c1 + c2; +#if SAMPLES > 2 + c1 += c3 + c4; +#endif +#if SAMPLES > 4 + c1 += c5 + c6 + c7 + c8; +#endif +#if SAMPLES > 8 + c1 += c9 + c10 + c11 + c12 + c13 + c14 + c15 + c16; +#endif + + const float inv_samples = 1.0 / float(SAMPLES); + + fragColor = c1 * inv_samples; +} diff --git a/source/blender/gpu/shaders/gpu_shader_image_shuffle_color_frag.glsl b/source/blender/gpu/shaders/gpu_shader_image_shuffle_color_frag.glsl new file mode 100644 index 00000000000..64662247d69 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_image_shuffle_color_frag.glsl @@ -0,0 +1,16 @@ + +in vec2 texCoord_interp; +out vec4 fragColor; + +uniform sampler2D image; +uniform vec4 color; +uniform vec4 shuffle; + +void main() +{ + vec4 sample = texture(image, texCoord_interp); + fragColor = vec4(sample.r * shuffle.r + + sample.g * shuffle.g + + sample.b * shuffle.b + + sample.a * shuffle.a) * color; +} 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_camera_vert.glsl b/source/blender/gpu/shaders/gpu_shader_instance_camera_vert.glsl new file mode 100644 index 00000000000..aec8fd9b0a1 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_instance_camera_vert.glsl @@ -0,0 +1,50 @@ + +uniform mat4 ViewProjectionMatrix; + +/* ---- Instanciated Attribs ---- */ +in float pos; + +/* ---- Per instance Attribs ---- */ +in vec3 color; +in vec4 corners[2]; /* trouble fetching vec2 */ +in float depth; +in vec4 tria; +in mat4 InstanceModelMatrix; + +flat out vec4 finalColor; + +void main() +{ + vec3 pPos; + + if (pos == 1.0) { + pPos = vec3(corners[0].xy, depth); + } + else if (pos == 2.0) { + pPos = vec3(corners[0].zw, depth); + } + else if (pos == 3.0) { + pPos = vec3(corners[1].xy, depth); + } + else if (pos == 4.0) { + pPos = vec3(corners[1].zw, depth); + } + else if (pos == 5.0) { + pPos = vec3(tria.xy, depth); + } + else if (pos == 6.0) { + vec2 ofs = tria.xy - corners[0].xy; + ofs.x = -ofs.x; + pPos = vec3(corners[1].zw + ofs, depth); + } + else if (pos == 7.0) { + pPos = vec3(tria.zw, depth); + } + else { + pPos = vec3(0.0); + } + + gl_Position = ViewProjectionMatrix * InstanceModelMatrix * vec4(pPos, 1.0); + + finalColor = vec4(color, 1.0); +} diff --git a/source/blender/gpu/shaders/gpu_shader_instance_distance_line_vert.glsl b/source/blender/gpu/shaders/gpu_shader_instance_distance_line_vert.glsl new file mode 100644 index 00000000000..ced5bb7f684 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_instance_distance_line_vert.glsl @@ -0,0 +1,25 @@ + +uniform mat4 ViewProjectionMatrix; + +/* ---- Instanciated Attribs ---- */ +in vec3 pos; + +/* ---- Per instance Attribs ---- */ +in vec3 color; +in float start; +in float end; +in mat4 InstanceModelMatrix; + +uniform float size; + +flat out vec4 finalColor; + +void main() +{ + float len = end - start; + vec3 sta = vec3(0.0, 0.0, -start); + + gl_Position = ViewProjectionMatrix * InstanceModelMatrix * vec4(pos * -len + sta, 1.0); + gl_PointSize = size; + finalColor = vec4(color, 1.0); +} diff --git a/source/blender/gpu/shaders/gpu_shader_instance_edges_variying_color_geom.glsl b/source/blender/gpu/shaders/gpu_shader_instance_edges_variying_color_geom.glsl new file mode 100644 index 00000000000..e26f419b8cd --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_instance_edges_variying_color_geom.glsl @@ -0,0 +1,57 @@ + +// Draw "fancy" wireframe, displaying front-facing, back-facing and +// silhouette lines differently. +// Mike Erwin, April 2015 + +// After working with this shader a while, convinced we should make +// separate shaders for perpective & ortho. (Oct 2016) + +// Due to perspective, the line segment's endpoints might disagree on +// whether the adjacent faces are front facing. This geometry shader +// decides which edge type to use if endpoints disagree. + +uniform mat4 ProjectionMatrix; + +uniform bool drawFront = true; +uniform bool drawBack = true; +uniform bool drawSilhouette = true; + +layout(lines) in; +layout(line_strip, max_vertices = 2) out; + +in vec4 MV_pos[]; +in float edgeClass[]; +in vec3 fCol[]; + +flat out vec4 finalColor; + +void emitLine(vec4 color) +{ + gl_Position = ProjectionMatrix * MV_pos[0]; + EmitVertex(); + gl_Position = ProjectionMatrix * MV_pos[1]; + finalColor = color; + EmitVertex(); + EndPrimitive(); +} + +void main() +{ + float finalEdgeClass = max(edgeClass[0], edgeClass[1]); + + if (finalEdgeClass > 0.0f) { + // front-facing edge + if (drawFront) + emitLine(vec4(fCol[0], 0.75)); + } + else if (finalEdgeClass < 0.0f) { + // back-facing edge + if (drawBack) + emitLine(vec4(fCol[0], 0.5)); + } + else { + // exactly one face is front-facing, silhouette edge + if (drawSilhouette) + emitLine(vec4(fCol[0], 1.0)); + } +} diff --git a/source/blender/gpu/shaders/gpu_shader_instance_edges_variying_color_vert.glsl b/source/blender/gpu/shaders/gpu_shader_instance_edges_variying_color_vert.glsl new file mode 100644 index 00000000000..fa30c9fb1ed --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_instance_edges_variying_color_vert.glsl @@ -0,0 +1,63 @@ + +// Draw "fancy" wireframe, displaying front-facing, back-facing and +// silhouette lines differently. +// Mike Erwin, April 2015 + +// After working with this shader a while, convinced we should make +// separate shaders for perpective & ortho. (Oct 2016) + +// Due to perspective, the line segment's endpoints might disagree on +// whether the adjacent faces are front facing. We use a geometry +// shader to resolve this properly. + +uniform mat4 ViewMatrix; +uniform mat4 ProjectionMatrix; + +in vec3 pos; +in vec3 N1, N2; // normals of faces this edge joins (object coords) + +/* instance attrib */ +in vec3 color; +in mat4 InstanceModelMatrix; + +out vec4 MV_pos; +out float edgeClass; +out vec3 fCol; + +// TODO: in float angle; // [-pi .. +pi], + peak, 0 flat, - valley + +bool front(mat3 NormalMatrix, vec3 N, vec3 eye) +{ + return dot(NormalMatrix * N, eye) > 0.0; +} + +void main() +{ + vec3 eye; + + mat4 ModelViewMatrix = ViewMatrix * InstanceModelMatrix; + + MV_pos = ModelViewMatrix * vec4(pos, 1.0); + + mat3 NormalMatrix = transpose(inverse(mat3(ModelViewMatrix))); + + /* if persp */ + if (ProjectionMatrix[3][3] == 0.0) { + eye = normalize(-MV_pos.xyz); + } + else { + eye = vec3(0.0, 0.0, 1.0); + } + + bool face_1_front = front(NormalMatrix, N1, eye); + bool face_2_front = front(NormalMatrix, N2, eye); + + if (face_1_front && face_2_front) + edgeClass = 1.0; // front-facing edge + else if (face_1_front || face_2_front) + edgeClass = 0.0; // exactly one face is front-facing, silhouette edge + else + edgeClass = -1.0; // back-facing edge + + fCol = color; +} diff --git a/source/blender/gpu/shaders/gpu_shader_instance_objectspace_variying_color_vert.glsl b/source/blender/gpu/shaders/gpu_shader_instance_objectspace_variying_color_vert.glsl new file mode 100644 index 00000000000..9876717b297 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_instance_objectspace_variying_color_vert.glsl @@ -0,0 +1,27 @@ + +uniform mat4 ViewMatrix; +uniform mat4 ViewProjectionMatrix; + +/* ---- Instanciated Attribs ---- */ +in vec3 pos; +in vec3 nor; + +/* ---- Per instance Attribs ---- */ +in mat4 InstanceModelMatrix; +in vec4 color; + +out vec3 normal; +flat out vec4 finalColor; + +void main() +{ + mat4 ModelViewProjectionMatrix = ViewProjectionMatrix * InstanceModelMatrix; + /* This is slow and run per vertex, but it's still faster than + * doing it per instance on CPU and sending it on via instance attrib */ + mat3 NormalMatrix = transpose(inverse(mat3(ViewMatrix * InstanceModelMatrix))); + + gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0); + normal = NormalMatrix * nor; + + finalColor = color; +} diff --git a/source/blender/gpu/shaders/gpu_shader_instance_screen_aligned_vert.glsl b/source/blender/gpu/shaders/gpu_shader_instance_screen_aligned_vert.glsl new file mode 100644 index 00000000000..2ee74b3eae0 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_instance_screen_aligned_vert.glsl @@ -0,0 +1,32 @@ + +uniform mat4 ViewProjectionMatrix; +uniform vec3 screen_vecs[2]; + +/* ---- Instanciated Attribs ---- */ +in vec3 pos; /* using Z as axis id */ + +/* ---- Per instance Attribs ---- */ +in mat4 InstanceModelMatrix; +in vec3 color; +in float size; + +flat out vec4 finalColor; + +void main() +{ + vec3 offset = vec3(0.0); + +#ifdef AXIS_NAME + if (pos.z == 0.0) + offset = vec3(1.125, 0.0, 0.0); + else if (pos.z == 1.0) + offset = vec3(0.0, 1.125, 0.0); + else + offset = vec3(0.0, 0.0, 1.125); + offset *= size; +#endif + + vec3 screen_pos = screen_vecs[0].xyz * pos.x + screen_vecs[1].xyz * pos.y; + gl_Position = ViewProjectionMatrix * (InstanceModelMatrix * vec4(offset, 1.0) + vec4(screen_pos * size, 0.0)); + finalColor = vec4(color, 1.0); +} diff --git a/source/blender/gpu/shaders/gpu_shader_instance_screenspace_variying_color_vert.glsl b/source/blender/gpu/shaders/gpu_shader_instance_screenspace_variying_color_vert.glsl new file mode 100644 index 00000000000..ba0ac29fb79 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_instance_screenspace_variying_color_vert.glsl @@ -0,0 +1,29 @@ + +uniform mat4 ViewProjectionMatrix; +uniform vec3 screen_vecs[2]; +uniform float size; +uniform float pixel_size; + +/* ---- Instanciated Attribs ---- */ +in vec2 pos; + +/* ---- Per instance Attribs ---- */ +in vec3 world_pos; +in vec3 color; + +flat out vec4 finalColor; + +float mul_project_m4_v3_zfac(in vec3 co) +{ + return (ViewProjectionMatrix[0][3] * co.x) + + (ViewProjectionMatrix[1][3] * co.y) + + (ViewProjectionMatrix[2][3] * co.z) + ViewProjectionMatrix[3][3]; +} + +void main() +{ + float pix_size = mul_project_m4_v3_zfac(world_pos) * pixel_size; + vec3 screen_pos = screen_vecs[0].xyz * pos.x + screen_vecs[1].xyz * pos.y; + gl_Position = ViewProjectionMatrix * vec4(world_pos + screen_pos * size * pix_size, 1.0); + finalColor = vec4(color, 1.0); +} diff --git a/source/blender/gpu/shaders/gpu_shader_instance_variying_size_variying_color_vert.glsl b/source/blender/gpu/shaders/gpu_shader_instance_variying_size_variying_color_vert.glsl new file mode 100644 index 00000000000..10a2ba61a2c --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_instance_variying_size_variying_color_vert.glsl @@ -0,0 +1,22 @@ + +uniform mat4 ViewProjectionMatrix; + +/* ---- Instanciated Attribs ---- */ +in vec3 pos; + +/* ---- Per instance Attribs ---- */ +in mat4 InstanceModelMatrix; +in vec3 color; +#ifdef UNIFORM_SCALE +in float size; +#else +in vec3 size; +#endif + +flat out vec4 finalColor; + +void main() +{ + gl_Position = ViewProjectionMatrix * InstanceModelMatrix * vec4(pos * size, 1.0); + finalColor = vec4(color, 1.0); +} diff --git a/source/blender/gpu/shaders/gpu_shader_instance_variying_size_variying_id_vert.glsl b/source/blender/gpu/shaders/gpu_shader_instance_variying_size_variying_id_vert.glsl new file mode 100644 index 00000000000..49750dddb3c --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_instance_variying_size_variying_id_vert.glsl @@ -0,0 +1,23 @@ + +uniform mat4 ViewProjectionMatrix; +uniform int baseId; + +/* ---- Instanciated Attribs ---- */ +in vec3 pos; + +/* ---- Per instance Attribs ---- */ +in mat4 InstanceModelMatrix; +#ifdef UNIFORM_SCALE +in float size; +#else +in vec3 size; +#endif +in int callId; + +flat out uint finalId; + +void main() +{ + gl_Position = ViewProjectionMatrix * InstanceModelMatrix * vec4(pos * size, 1.0); + finalId = uint(baseId + callId); +} diff --git a/source/blender/gpu/shaders/gpu_shader_instance_vert.glsl b/source/blender/gpu/shaders/gpu_shader_instance_vert.glsl new file mode 100644 index 00000000000..eac167e8045 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_instance_vert.glsl @@ -0,0 +1,13 @@ + +uniform mat4 ViewProjectionMatrix; + +/* ---- Instanciated Attribs ---- */ +in vec3 pos; + +/* ---- Per instance Attribs ---- */ +in mat4 InstanceModelMatrix; + +void main() +{ + gl_Position = ViewProjectionMatrix * InstanceModelMatrix * vec4(pos, 1.0); +} diff --git a/source/blender/gpu/shaders/gpu_shader_keyframe_diamond_frag.glsl b/source/blender/gpu/shaders/gpu_shader_keyframe_diamond_frag.glsl new file mode 100644 index 00000000000..7f445369833 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_keyframe_diamond_frag.glsl @@ -0,0 +1,31 @@ + +in vec4 radii; +in vec4 finalColor; +in vec4 finalOutlineColor; +out vec4 fragColor; + +void main() { + vec2 quad = abs(gl_PointCoord - vec2(0.5)); + float dist = quad.x + quad.y; + +// transparent outside of point +// --- 0 --- +// smooth transition +// --- 1 --- +// pure outline color +// --- 2 --- +// smooth transition +// --- 3 --- +// pure point color +// ... +// dist = 0 at center of point + + float mid_stroke = 0.5 * (radii[1] + radii[2]); + + vec4 backgroundColor = vec4(finalOutlineColor.rgb, 0.0); + + if (dist > mid_stroke) + fragColor = mix(finalOutlineColor, backgroundColor, smoothstep(radii[1], radii[0], dist)); + else + fragColor = mix(finalColor, finalOutlineColor, smoothstep(radii[3], radii[2], dist)); +} diff --git a/source/blender/gpu/shaders/gpu_shader_keyframe_diamond_vert.glsl b/source/blender/gpu/shaders/gpu_shader_keyframe_diamond_vert.glsl new file mode 100644 index 00000000000..c49832bf9b4 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_keyframe_diamond_vert.glsl @@ -0,0 +1,34 @@ + +uniform mat4 ModelViewProjectionMatrix; + +const float pixel_fudge = sqrt(2.0); +const float outline_width = 1.15 * pixel_fudge; + +in vec2 pos; +in float size; +in vec4 color; +in vec4 outlineColor; +out vec4 finalColor; +out vec4 finalOutlineColor; +out vec4 radii; + +void main() { + gl_Position = ModelViewProjectionMatrix * vec4(pos, 0.0, 1.0); + + // pass through unchanged + gl_PointSize = size + pixel_fudge; // 0.5 pixel_fudge on either side + finalColor = color; + finalOutlineColor = outlineColor; + + // calculate concentric radii in pixels + float radius = 0.5 * gl_PointSize; + + // start at the outside and progress toward the center + radii[0] = radius; + radii[1] = radius - pixel_fudge; + radii[2] = radius - outline_width; + radii[3] = radius - outline_width - pixel_fudge; + + // convert to PointCoord units + radii /= size; +} diff --git a/source/blender/gpu/shaders/gpu_shader_material.glsl b/source/blender/gpu/shaders/gpu_shader_material.glsl index aace5e95169..795320df6b7 100644 --- a/source/blender/gpu/shaders/gpu_shader_material.glsl +++ b/source/blender/gpu/shaders/gpu_shader_material.glsl @@ -1,12 +1,50 @@ + +uniform mat4 ModelMatrix; +uniform mat4 ModelViewMatrix; +uniform mat4 ModelViewMatrixInverse; +uniform mat3 NormalMatrix; + +#ifndef ATTRIB +uniform mat4 ModelMatrixInverse; +#endif + +/* Old glsl mode compat. */ + +#ifndef CLOSURE_DEFAULT + +struct Closure { + vec3 radiance; + float opacity; +}; + +#define CLOSURE_DEFAULT Closure(vec3(0.0), 1.0) + +Closure closure_mix(Closure cl1, Closure cl2, float fac) +{ + Closure cl; + cl.radiance = mix(cl1.radiance, cl2.radiance, fac); + cl.opacity = mix(cl1.opacity, cl2.opacity, fac); + return cl; +} + +Closure closure_add(Closure cl1, Closure cl2) +{ + Closure cl; + cl.radiance = cl1.radiance + cl2.radiance; + cl.opacity = cl1.opacity + cl2.opacity; + return cl; +} + +Closure nodetree_exec(void); /* Prototype */ + +#endif /* CLOSURE_DEFAULT */ + + /* Converters */ float convert_rgba_to_float(vec4 color) { -#ifdef USE_NEW_SHADING - return color.r * 0.2126 + color.g * 0.7152 + color.b * 0.0722; -#else - return (color.r + color.g + color.b) / 3.0; -#endif + return dot(color.rgb, vec3(0.2126, 0.7152, 0.0722)); } float exp_blender(float f) @@ -53,7 +91,7 @@ void rgb_to_hsv(vec4 rgb, out vec4 outcol) h = 0.0; } else { - c = (vec3(cmax, cmax, cmax) - rgb.xyz) / cdelta; + c = (vec3(cmax) - rgb.xyz) / cdelta; if (rgb.x == cmax) h = c[2] - c[1]; else if (rgb.y == cmax) h = 2.0 + c[0] - c[2]; @@ -155,56 +193,15 @@ void color_to_blender_normal_new_shading(vec3 color, out vec3 normal) normal.y = -2.0 * ((color.g) - 0.5); normal.z = -2.0 * ((color.b) - 0.5); } - +#ifndef M_PI #define M_PI 3.14159265358979323846 -#define M_1_PI 0.31830988618379069 +#endif +#ifndef M_1_PI +#define M_1_PI 0.318309886183790671538 +#endif /*********** SHADER NODES ***************/ -void vcol_attribute(vec4 attvcol, out vec4 vcol) -{ - vcol = vec4(attvcol.x, attvcol.y, attvcol.z, 1.0); -} - -void uv_attribute(vec2 attuv, out vec3 uv) -{ - uv = vec3(attuv * 2.0 - vec2(1.0, 1.0), 0.0); -} - -void geom( - vec3 co, vec3 nor, mat4 viewinvmat, vec3 attorco, vec2 attuv, vec4 attvcol, - out vec3 global, out vec3 local, out vec3 view, out vec3 orco, out vec3 uv, - out vec3 normal, out vec4 vcol, out float vcol_alpha, out float frontback) -{ - local = co; - view = (gl_ProjectionMatrix[3][3] == 0.0) ? normalize(local) : vec3(0.0, 0.0, -1.0); - global = (viewinvmat * vec4(local, 1.0)).xyz; - orco = attorco; - uv_attribute(attuv, uv); - normal = -normalize(nor); /* blender render normal is negated */ - vcol_attribute(attvcol, vcol); - srgb_to_linearrgb(vcol, vcol); - vcol_alpha = attvcol.a; - frontback = (gl_FrontFacing) ? 1.0 : 0.0; -} - -void particle_info( - 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.xyz; - velocity = vel; - angular_velocity = avel; -} - void vect_normalize(vec3 vin, out vec3 vout) { vout = normalize(vin); @@ -272,17 +269,6 @@ void camera(vec3 co, out vec3 outview, out float outdepth, out float outdist) outview = normalize(co); } -void lamp( - vec4 col, float energy, vec3 lv, float dist, vec3 shadow, float visifac, - out vec4 outcol, out vec3 outlv, out float outdist, out vec4 outshadow, out float outvisifac) -{ - outcol = col * energy; - outlv = lv; - outdist = dist; - outshadow = vec4(shadow, 1.0); - outvisifac = visifac; -} - void math_add(float val1, float val2, out float outval) { outval = val1 + val2; @@ -426,13 +412,13 @@ void squeeze(float val, float width, float center, out float outval) void vec_math_add(vec3 v1, vec3 v2, out vec3 outvec, out float outval) { outvec = v1 + v2; - outval = (abs(outvec[0]) + abs(outvec[1]) + abs(outvec[2])) / 3.0; + outval = (abs(outvec[0]) + abs(outvec[1]) + abs(outvec[2])) * 0.333333; } void vec_math_sub(vec3 v1, vec3 v2, out vec3 outvec, out float outval) { outvec = v1 - v2; - outval = (abs(outvec[0]) + abs(outvec[1]) + abs(outvec[2])) / 3.0; + outval = (abs(outvec[0]) + abs(outvec[1]) + abs(outvec[2])) * 0.333333; } void vec_math_average(vec3 v1, vec3 v2, out vec3 outvec, out float outval) @@ -448,7 +434,7 @@ void vec_math_mix(float strength, vec3 v1, vec3 v2, out vec3 outvec) void vec_math_dot(vec3 v1, vec3 v2, out vec3 outvec, out float outval) { - outvec = vec3(0, 0, 0); + outvec = vec3(0); outval = dot(v1, v2); } @@ -490,9 +476,9 @@ void normal_new_shading(vec3 dir, vec3 nor, out vec3 outnor, out float outdot) void curves_vec(float fac, vec3 vec, sampler2D curvemap, out vec3 outvec) { - outvec.x = texture2D(curvemap, vec2((vec.x + 1.0) * 0.5, 0.0)).x; - outvec.y = texture2D(curvemap, vec2((vec.y + 1.0) * 0.5, 0.0)).y; - outvec.z = texture2D(curvemap, vec2((vec.z + 1.0) * 0.5, 0.0)).z; + outvec.x = texture(curvemap, vec2((vec.x + 1.0) * 0.5, 0.0)).x; + outvec.y = texture(curvemap, vec2((vec.y + 1.0) * 0.5, 0.0)).y; + outvec.z = texture(curvemap, vec2((vec.z + 1.0) * 0.5, 0.0)).z; if (fac != 1.0) outvec = (outvec * fac) + (vec * (1.0 - fac)); @@ -501,9 +487,9 @@ void curves_vec(float fac, vec3 vec, sampler2D curvemap, out vec3 outvec) void curves_rgb(float fac, vec4 col, sampler2D curvemap, out vec4 outcol) { - outcol.r = texture2D(curvemap, vec2(texture2D(curvemap, vec2(col.r, 0.0)).a, 0.0)).r; - outcol.g = texture2D(curvemap, vec2(texture2D(curvemap, vec2(col.g, 0.0)).a, 0.0)).g; - outcol.b = texture2D(curvemap, vec2(texture2D(curvemap, vec2(col.b, 0.0)).a, 0.0)).b; + outcol.r = texture(curvemap, vec2(texture(curvemap, vec2(col.r, 0.0)).a, 0.0)).r; + outcol.g = texture(curvemap, vec2(texture(curvemap, vec2(col.g, 0.0)).a, 0.0)).g; + outcol.b = texture(curvemap, vec2(texture(curvemap, vec2(col.b, 0.0)).a, 0.0)).b; if (fac != 1.0) outcol = (outcol * fac) + (col * (1.0 - fac)); @@ -823,22 +809,19 @@ void mix_linear(float fac, vec4 col1, vec4 col2, out vec4 outcol) void valtorgb(float fac, sampler2D colormap, out vec4 outcol, out float outalpha) { - outcol = texture2D(colormap, vec2(fac, 0.0)); + outcol = texture(colormap, vec2(fac, 0.0)); outalpha = outcol.a; } void rgbtobw(vec4 color, out float outval) { -#ifdef USE_NEW_SHADING - outval = color.r * 0.2126 + color.g * 0.7152 + color.b * 0.0722; -#else - outval = color.r * 0.35 + color.g * 0.45 + color.b * 0.2; /* keep these factors in sync with texture.h:RGBTOBW */ -#endif + vec3 factors = vec3(0.2126, 0.7152, 0.0722); + outval = dot(color.rgb, factors); } void invert(float fac, vec4 col, out vec4 outcol) { - outcol.xyz = mix(col.xyz, vec3(1.0, 1.0, 1.0) - col.xyz, fac); + outcol.xyz = mix(col.xyz, vec3(1.0) - col.xyz, fac); outcol.w = col.w; } @@ -916,56 +899,6 @@ void output_node(vec4 rgb, float alpha, out vec4 outrgb) /*********** TEXTURES ***************/ -void texture_flip_blend(vec3 vec, out vec3 outvec) -{ - outvec = vec.yxz; -} - -void texture_blend_lin(vec3 vec, out float outval) -{ - outval = (1.0 + vec.x) / 2.0; -} - -void texture_blend_quad(vec3 vec, out float outval) -{ - outval = max((1.0 + vec.x) / 2.0, 0.0); - outval *= outval; -} - -void texture_wood_sin(vec3 vec, out float value, out vec4 color, out vec3 normal) -{ - float a = sqrt(vec.x * vec.x + vec.y * vec.y + vec.z * vec.z) * 20.0; - float wi = 0.5 + 0.5 * sin(a); - - value = wi; - color = vec4(wi, wi, wi, 1.0); - normal = vec3(0.0, 0.0, 0.0); -} - -void texture_image(vec3 vec, sampler2D ima, out float value, out vec4 color, out vec3 normal) -{ - color = texture2D(ima, (vec.xy + vec2(1.0, 1.0)) * 0.5); - value = color.a; - - normal.x = 2.0 * (color.r - 0.5); - normal.y = 2.0 * (0.5 - color.g); - normal.z = 2.0 * (color.b - 0.5); -} - -/************* MTEX *****************/ - -void texco_orco(vec3 attorco, out vec3 orco) -{ - orco = attorco; -} - -void texco_uv(vec2 attuv, out vec3 uv) -{ - /* disabled for now, works together with leaving out mtex_2d_mapping */ - // uv = vec3(attuv*2.0 - vec2(1.0, 1.0), 0.0); */ - uv = vec3(attuv, 0.0); -} - void texco_norm(vec3 normal, out vec3 outnormal) { /* corresponds to shi->orn, which is negated so cancels @@ -973,436 +906,11 @@ void texco_norm(vec3 normal, out vec3 outnormal) outnormal = normalize(normal); } -void texco_tangent(vec4 tangent, out vec3 outtangent) -{ - outtangent = normalize(tangent.xyz); -} - -void texco_global(mat4 viewinvmat, vec3 co, out vec3 global) -{ - global = (viewinvmat * vec4(co, 1.0)).xyz; -} - -void texco_object(mat4 viewinvmat, mat4 obinvmat, vec3 co, out vec3 object) -{ - object = (obinvmat * (viewinvmat * vec4(co, 1.0))).xyz; -} - -void texco_refl(vec3 vn, vec3 view, out vec3 ref) -{ - ref = view - 2.0 * dot(vn, view) * vn; -} - -void shade_norm(vec3 normal, out vec3 outnormal) -{ - /* blender render normal is negated */ - outnormal = -normalize(normal); -} - -void mtex_mirror(vec3 tcol, vec4 refcol, float tin, float colmirfac, out vec4 outrefcol) -{ - outrefcol = mix(refcol, vec4(1.0, tcol), tin * colmirfac); -} - -void mtex_rgb_blend(vec3 outcol, vec3 texcol, float fact, float facg, out vec3 incol) -{ - float facm; - - fact *= facg; - facm = 1.0 - fact; - - incol = fact * texcol + facm * outcol; -} - -void mtex_rgb_mul(vec3 outcol, vec3 texcol, float fact, float facg, out vec3 incol) -{ - float facm; - - fact *= facg; - facm = 1.0 - fact; - - incol = (facm + fact * texcol) * outcol; -} - -void mtex_rgb_screen(vec3 outcol, vec3 texcol, float fact, float facg, out vec3 incol) -{ - float facm; - - fact *= facg; - facm = 1.0 - fact; - - incol = vec3(1.0) - (vec3(facm) + fact * (vec3(1.0) - texcol)) * (vec3(1.0) - outcol); -} - -void mtex_rgb_overlay(vec3 outcol, vec3 texcol, float fact, float facg, out vec3 incol) -{ - float facm; - - fact *= facg; - facm = 1.0 - fact; - - if (outcol.r < 0.5) - incol.r = outcol.r * (facm + 2.0 * fact * texcol.r); - else - incol.r = 1.0 - (facm + 2.0 * fact * (1.0 - texcol.r)) * (1.0 - outcol.r); - - if (outcol.g < 0.5) - incol.g = outcol.g * (facm + 2.0 * fact * texcol.g); - else - incol.g = 1.0 - (facm + 2.0 * fact * (1.0 - texcol.g)) * (1.0 - outcol.g); - - if (outcol.b < 0.5) - incol.b = outcol.b * (facm + 2.0 * fact * texcol.b); - else - incol.b = 1.0 - (facm + 2.0 * fact * (1.0 - texcol.b)) * (1.0 - outcol.b); -} - -void mtex_rgb_sub(vec3 outcol, vec3 texcol, float fact, float facg, out vec3 incol) -{ - incol = -fact * facg * texcol + outcol; -} - -void mtex_rgb_add(vec3 outcol, vec3 texcol, float fact, float facg, out vec3 incol) -{ - incol = fact * facg * texcol + outcol; -} - -void mtex_rgb_div(vec3 outcol, vec3 texcol, float fact, float facg, out vec3 incol) -{ - float facm; - - fact *= facg; - facm = 1.0 - fact; - - if (texcol.r != 0.0) incol.r = facm * outcol.r + fact * outcol.r / texcol.r; - if (texcol.g != 0.0) incol.g = facm * outcol.g + fact * outcol.g / texcol.g; - if (texcol.b != 0.0) incol.b = facm * outcol.b + fact * outcol.b / texcol.b; -} - -void mtex_rgb_diff(vec3 outcol, vec3 texcol, float fact, float facg, out vec3 incol) -{ - float facm; - - fact *= facg; - facm = 1.0 - fact; - - incol = facm * outcol + fact * abs(texcol - outcol); -} - -void mtex_rgb_dark(vec3 outcol, vec3 texcol, float fact, float facg, out vec3 incol) -{ - float facm, col; - - fact *= facg; - facm = 1.0 - fact; - - incol.r = min(outcol.r, texcol.r) * fact + outcol.r * facm; - incol.g = min(outcol.g, texcol.g) * fact + outcol.g * facm; - incol.b = min(outcol.b, texcol.b) * fact + outcol.b * facm; -} - -void mtex_rgb_light(vec3 outcol, vec3 texcol, float fact, float facg, out vec3 incol) -{ - float facm, col; - - fact *= facg; - - col = fact * texcol.r; - if (col > outcol.r) incol.r = col; else incol.r = outcol.r; - col = fact * texcol.g; - if (col > outcol.g) incol.g = col; else incol.g = outcol.g; - col = fact * texcol.b; - if (col > outcol.b) incol.b = col; else incol.b = outcol.b; -} - -void mtex_rgb_hue(vec3 outcol, vec3 texcol, float fact, float facg, out vec3 incol) -{ - vec4 col; - - mix_hue(fact * facg, vec4(outcol, 1.0), vec4(texcol, 1.0), col); - incol.rgb = col.rgb; -} - -void mtex_rgb_sat(vec3 outcol, vec3 texcol, float fact, float facg, out vec3 incol) -{ - vec4 col; - - mix_sat(fact * facg, vec4(outcol, 1.0), vec4(texcol, 1.0), col); - incol.rgb = col.rgb; -} - -void mtex_rgb_val(vec3 outcol, vec3 texcol, float fact, float facg, out vec3 incol) -{ - vec4 col; - - mix_val(fact * facg, vec4(outcol, 1.0), vec4(texcol, 1.0), col); - incol.rgb = col.rgb; -} - -void mtex_rgb_color(vec3 outcol, vec3 texcol, float fact, float facg, out vec3 incol) -{ - vec4 col; - - mix_color(fact * facg, vec4(outcol, 1.0), vec4(texcol, 1.0), col); - incol.rgb = col.rgb; -} - -void mtex_rgb_soft(vec3 outcol, vec3 texcol, float fact, float facg, out vec3 incol) -{ - vec4 col; - - mix_soft(fact * facg, vec4(outcol, 1.0), vec4(texcol, 1.0), col); - incol.rgb = col.rgb; -} - -void mtex_rgb_linear(vec3 outcol, vec3 texcol, float fact, float facg, out vec3 incol) -{ - fact *= facg; - - if (texcol.r > 0.5) - incol.r = outcol.r + fact * (2.0 * (texcol.r - 0.5)); - else - incol.r = outcol.r + fact * (2.0 * (texcol.r) - 1.0); - - if (texcol.g > 0.5) - incol.g = outcol.g + fact * (2.0 * (texcol.g - 0.5)); - else - incol.g = outcol.g + fact * (2.0 * (texcol.g) - 1.0); - - if (texcol.b > 0.5) - incol.b = outcol.b + fact * (2.0 * (texcol.b - 0.5)); - else - incol.b = outcol.b + fact * (2.0 * (texcol.b) - 1.0); -} - -void mtex_value_vars(inout float fact, float facg, out float facm) -{ - fact *= abs(facg); - facm = 1.0 - fact; - - if (facg < 0.0) { - float tmp = fact; - fact = facm; - facm = tmp; - } -} - -void mtex_value_blend(float outcol, float texcol, float fact, float facg, out float incol) -{ - float facm; - mtex_value_vars(fact, facg, facm); - - incol = fact * texcol + facm * outcol; -} - -void mtex_value_mul(float outcol, float texcol, float fact, float facg, out float incol) -{ - float facm; - mtex_value_vars(fact, facg, facm); - - facm = 1.0 - facg; - incol = (facm + fact * texcol) * outcol; -} - -void mtex_value_screen(float outcol, float texcol, float fact, float facg, out float incol) -{ - float facm; - mtex_value_vars(fact, facg, facm); - - facm = 1.0 - facg; - incol = 1.0 - (facm + fact * (1.0 - texcol)) * (1.0 - outcol); -} - -void mtex_value_sub(float outcol, float texcol, float fact, float facg, out float incol) -{ - float facm; - mtex_value_vars(fact, facg, facm); - - fact = -fact; - incol = fact * texcol + outcol; -} - -void mtex_value_add(float outcol, float texcol, float fact, float facg, out float incol) -{ - float facm; - mtex_value_vars(fact, facg, facm); - - fact = fact; - incol = fact * texcol + outcol; -} - -void mtex_value_div(float outcol, float texcol, float fact, float facg, out float incol) -{ - float facm; - mtex_value_vars(fact, facg, facm); - - if (texcol != 0.0) - incol = facm * outcol + fact * outcol / texcol; - else - incol = 0.0; -} - -void mtex_value_diff(float outcol, float texcol, float fact, float facg, out float incol) -{ - float facm; - mtex_value_vars(fact, facg, facm); - - incol = facm * outcol + fact * abs(texcol - outcol); -} - -void mtex_value_dark(float outcol, float texcol, float fact, float facg, out float incol) -{ - float facm; - mtex_value_vars(fact, facg, facm); - - incol = facm * outcol + fact * min(outcol, texcol); -} - -void mtex_value_light(float outcol, float texcol, float fact, float facg, out float incol) -{ - float facm; - mtex_value_vars(fact, facg, facm); - - float col = fact * texcol; - if (col > outcol) incol = col; else incol = outcol; -} - -void mtex_value_clamp_positive(float fac, out float outfac) -{ - outfac = max(fac, 0.0); -} - -void mtex_value_clamp(float fac, out float outfac) -{ - outfac = clamp(fac, 0.0, 1.0); -} - -void mtex_har_divide(float har, out float outhar) -{ - outhar = har / 128.0; -} - -void mtex_har_multiply_clamp(float har, out float outhar) -{ - har *= 128.0; - - if (har < 1.0) outhar = 1.0; - else if (har > 511.0) outhar = 511.0; - else outhar = har; -} - -void mtex_alpha_from_col(vec4 col, out float alpha) -{ - alpha = col.a; -} - -void mtex_alpha_to_col(vec4 col, float alpha, out vec4 outcol) -{ - outcol = vec4(col.rgb, alpha); -} - -void mtex_alpha_multiply_value(vec4 col, float value, out vec4 outcol) -{ - outcol = vec4(col.rgb, col.a * value); -} - -void mtex_rgbtoint(vec4 rgb, out float intensity) -{ - intensity = dot(vec3(0.35, 0.45, 0.2), rgb.rgb); -} - -void mtex_value_invert(float invalue, out float outvalue) -{ - outvalue = 1.0 - invalue; -} - -void mtex_rgb_invert(vec4 inrgb, out vec4 outrgb) -{ - outrgb = vec4(vec3(1.0) - inrgb.rgb, inrgb.a); -} - -void mtex_value_stencil(float stencil, float intensity, out float outstencil, out float outintensity) -{ - float fact = intensity; - outintensity = intensity * stencil; - outstencil = stencil * fact; -} - -void mtex_rgb_stencil(float stencil, vec4 rgb, out float outstencil, out vec4 outrgb) -{ - float fact = rgb.a; - outrgb = vec4(rgb.rgb, rgb.a * stencil); - outstencil = stencil * fact; -} - -void mtex_mapping_ofs(vec3 texco, vec3 ofs, out vec3 outtexco) -{ - outtexco = texco + ofs; -} - -void mtex_mapping_size(vec3 texco, vec3 size, out vec3 outtexco) -{ - outtexco = size * texco; -} - -void mtex_2d_mapping(vec3 vec, out vec3 outvec) -{ - outvec = vec3(vec.xy * 0.5 + vec2(0.5), vec.z); -} - vec3 mtex_2d_mapping(vec3 vec) { return vec3(vec.xy * 0.5 + vec2(0.5), vec.z); } -void mtex_cube_map(vec3 co, samplerCube ima, out float value, out vec4 color) -{ - color = textureCube(ima, co); - value = 1.0; -} - -void mtex_cube_map_refl_from_refldir( - samplerCube ima, vec3 reflecteddirection, out float value, out vec4 color) -{ - color = textureCube(ima, reflecteddirection); - value = color.a; -} - -void mtex_cube_map_refl( - samplerCube ima, vec3 vp, vec3 vn, mat4 viewmatrixinverse, mat4 viewmatrix, - out float value, out vec4 color) -{ - vec3 viewdirection = vec3(viewmatrixinverse * vec4(vp, 0.0)); - vec3 normaldirection = normalize(vec3(vec4(vn, 0.0) * viewmatrix)); - vec3 reflecteddirection = reflect(viewdirection, normaldirection); - color = textureCube(ima, reflecteddirection); - value = 1.0; -} - -void mtex_image(vec3 texco, sampler2D ima, out float value, out vec4 color) -{ - color = texture2D(ima, texco.xy); - value = 1.0; -} - -void mtex_normal(vec3 texco, sampler2D ima, out vec3 normal) -{ - // The invert of the red channel is to make - // the normal map compliant with the outside world. - // It needs to be done because in Blender - // the normal used points inward. - // Should this ever change this negate must be removed. - vec4 color = texture2D(ima, texco.xy); - normal = 2.0 * (vec3(-color.r, color.g, color.b) - vec3(-0.5, 0.5, 0.5)); -} - -void mtex_bump_normals_init(vec3 vN, out vec3 vNorg, out vec3 vNacc, out float fPrevMagnitude) -{ - vNorg = vN; - vNacc = vN; - fPrevMagnitude = 1.0; -} - /** helper method to extract the upper left 3x3 matrix from a 4x4 matrix */ mat3 to_mat3(mat4 m4) { @@ -1413,976 +921,6 @@ mat3 to_mat3(mat4 m4) return m3; } -void mtex_bump_init_objspace( - vec3 surf_pos, vec3 surf_norm, - mat4 mView, mat4 mViewInv, mat4 mObj, mat4 mObjInv, - float fPrevMagnitude_in, vec3 vNacc_in, - out float fPrevMagnitude_out, out vec3 vNacc_out, - out vec3 vR1, out vec3 vR2, out float fDet) -{ - mat3 obj2view = to_mat3(gl_ModelViewMatrix); - mat3 view2obj = to_mat3(gl_ModelViewMatrixInverse); - - vec3 vSigmaS = view2obj * dFdx(surf_pos); - vec3 vSigmaT = view2obj * dFdy(surf_pos); - vec3 vN = normalize(surf_norm * obj2view); - - vR1 = cross(vSigmaT, vN); - vR2 = cross(vN, vSigmaS); - fDet = dot(vSigmaS, vR1); - - /* pretransform vNacc (in mtex_bump_apply) using the inverse transposed */ - vR1 = vR1 * view2obj; - vR2 = vR2 * view2obj; - vN = vN * view2obj; - - float fMagnitude = abs(fDet) * length(vN); - vNacc_out = vNacc_in * (fMagnitude / fPrevMagnitude_in); - fPrevMagnitude_out = fMagnitude; -} - -void mtex_bump_init_texturespace( - vec3 surf_pos, vec3 surf_norm, - float fPrevMagnitude_in, vec3 vNacc_in, - out float fPrevMagnitude_out, out vec3 vNacc_out, - out vec3 vR1, out vec3 vR2, out float fDet) -{ - vec3 vSigmaS = dFdx(surf_pos); - vec3 vSigmaT = dFdy(surf_pos); - vec3 vN = surf_norm; /* normalized interpolated vertex normal */ - - vR1 = normalize(cross(vSigmaT, vN)); - vR2 = normalize(cross(vN, vSigmaS)); - fDet = sign(dot(vSigmaS, vR1)); - - float fMagnitude = abs(fDet); - vNacc_out = vNacc_in * (fMagnitude / fPrevMagnitude_in); - fPrevMagnitude_out = fMagnitude; -} - -void mtex_bump_init_viewspace( - vec3 surf_pos, vec3 surf_norm, - float fPrevMagnitude_in, vec3 vNacc_in, - out float fPrevMagnitude_out, out vec3 vNacc_out, - out vec3 vR1, out vec3 vR2, out float fDet) -{ - vec3 vSigmaS = dFdx(surf_pos); - vec3 vSigmaT = dFdy(surf_pos); - vec3 vN = surf_norm; /* normalized interpolated vertex normal */ - - vR1 = cross(vSigmaT, vN); - vR2 = cross(vN, vSigmaS); - fDet = dot(vSigmaS, vR1); - - float fMagnitude = abs(fDet); - vNacc_out = vNacc_in * (fMagnitude / fPrevMagnitude_in); - fPrevMagnitude_out = fMagnitude; -} - -void mtex_bump_tap3( - vec3 texco, sampler2D ima, float hScale, - out float dBs, out float dBt) -{ - vec2 STll = texco.xy; - vec2 STlr = texco.xy + dFdx(texco.xy); - vec2 STul = texco.xy + dFdy(texco.xy); - - float Hll, Hlr, Hul; - rgbtobw(texture2D(ima, STll), Hll); - rgbtobw(texture2D(ima, STlr), Hlr); - rgbtobw(texture2D(ima, STul), Hul); - - dBs = hScale * (Hlr - Hll); - dBt = hScale * (Hul - Hll); -} - -#ifdef BUMP_BICUBIC - -void mtex_bump_bicubic( - vec3 texco, sampler2D ima, float hScale, - out float dBs, out float dBt ) -{ - float Hl; - float Hr; - float Hd; - float Hu; - - vec2 TexDx = dFdx(texco.xy); - vec2 TexDy = dFdy(texco.xy); - - vec2 STl = texco.xy - 0.5 * TexDx; - vec2 STr = texco.xy + 0.5 * TexDx; - vec2 STd = texco.xy - 0.5 * TexDy; - vec2 STu = texco.xy + 0.5 * TexDy; - - rgbtobw(texture2D(ima, STl), Hl); - rgbtobw(texture2D(ima, STr), Hr); - rgbtobw(texture2D(ima, STd), Hd); - rgbtobw(texture2D(ima, STu), Hu); - - vec2 dHdxy = vec2(Hr - Hl, Hu - Hd); - float fBlend = clamp(1.0 - textureQueryLOD(ima, texco.xy).x, 0.0, 1.0); - if (fBlend != 0.0) { - // the derivative of the bicubic sampling of level 0 - ivec2 vDim; - vDim = textureSize(ima, 0); - - // taking the fract part of the texture coordinate is a hardcoded wrap mode. - // this is acceptable as textures use wrap mode exclusively in 3D view elsewhere in blender. - // this is done so that we can still get a valid texel with uvs outside the 0,1 range - // by texelFetch below, as coordinates are clamped when using this function. - vec2 fTexLoc = vDim * fract(texco.xy) - vec2(0.5, 0.5); - ivec2 iTexLoc = ivec2(floor(fTexLoc)); - vec2 t = clamp(fTexLoc - iTexLoc, 0.0, 1.0); // sat just to be pedantic - -/******************************************************************************************* - * This block will replace the one below when one channel textures are properly supported. * - ******************************************************************************************* - vec4 vSamplesUL = textureGather(ima, (iTexLoc+ivec2(-1,-1) + vec2(0.5,0.5))/vDim); - vec4 vSamplesUR = textureGather(ima, (iTexLoc+ivec2(1,-1) + vec2(0.5,0.5))/vDim); - vec4 vSamplesLL = textureGather(ima, (iTexLoc+ivec2(-1,1) + vec2(0.5,0.5))/vDim); - vec4 vSamplesLR = textureGather(ima, (iTexLoc+ivec2(1,1) + vec2(0.5,0.5))/vDim); - - mat4 H = mat4(vSamplesUL.w, vSamplesUL.x, vSamplesLL.w, vSamplesLL.x, - vSamplesUL.z, vSamplesUL.y, vSamplesLL.z, vSamplesLL.y, - vSamplesUR.w, vSamplesUR.x, vSamplesLR.w, vSamplesLR.x, - vSamplesUR.z, vSamplesUR.y, vSamplesLR.z, vSamplesLR.y); - */ - ivec2 iTexLocMod = iTexLoc + ivec2(-1, -1); - - mat4 H; - - for (int i = 0; i < 4; i++) { - for (int j = 0; j < 4; j++) { - ivec2 iTexTmp = iTexLocMod + ivec2(i, j); - - // wrap texture coordinates manually for texelFetch to work on uvs oitside the 0,1 range. - // this is guaranteed to work since we take the fractional part of the uv above. - iTexTmp.x = (iTexTmp.x < 0) ? iTexTmp.x + vDim.x : ((iTexTmp.x >= vDim.x) ? iTexTmp.x - vDim.x : iTexTmp.x); - iTexTmp.y = (iTexTmp.y < 0) ? iTexTmp.y + vDim.y : ((iTexTmp.y >= vDim.y) ? iTexTmp.y - vDim.y : iTexTmp.y); - - rgbtobw(texelFetch(ima, iTexTmp, 0), H[i][j]); - } - } - - float x = t.x, y = t.y; - float x2 = x * x, x3 = x2 * x, y2 = y * y, y3 = y2 * y; - - vec4 X = vec4(-0.5 * (x3 + x) + x2, 1.5 * x3 - 2.5 * x2 + 1, -1.5 * x3 + 2 * x2 + 0.5 * x, 0.5 * (x3 - x2)); - vec4 Y = vec4(-0.5 * (y3 + y) + y2, 1.5 * y3 - 2.5 * y2 + 1, -1.5 * y3 + 2 * y2 + 0.5 * y, 0.5 * (y3 - y2)); - vec4 dX = vec4(-1.5 * x2 + 2 * x - 0.5, 4.5 * x2 - 5 * x, -4.5 * x2 + 4 * x + 0.5, 1.5 * x2 - x); - vec4 dY = vec4(-1.5 * y2 + 2 * y - 0.5, 4.5 * y2 - 5 * y, -4.5 * y2 + 4 * y + 0.5, 1.5 * y2 - y); - - // complete derivative in normalized coordinates (mul by vDim) - vec2 dHdST = vDim * vec2(dot(Y, H * dX), dot(dY, H * X)); - - // transform derivative to screen-space - vec2 dHdxy_bicubic = vec2(dHdST.x * TexDx.x + dHdST.y * TexDx.y, - dHdST.x * TexDy.x + dHdST.y * TexDy.y); - - // blend between the two - dHdxy = dHdxy * (1 - fBlend) + dHdxy_bicubic * fBlend; - } - - dBs = hScale * dHdxy.x; - dBt = hScale * dHdxy.y; -} - -#endif - -void mtex_bump_tap5( - vec3 texco, sampler2D ima, float hScale, - out float dBs, out float dBt) -{ - vec2 TexDx = dFdx(texco.xy); - vec2 TexDy = dFdy(texco.xy); - - vec2 STc = texco.xy; - vec2 STl = texco.xy - 0.5 * TexDx; - vec2 STr = texco.xy + 0.5 * TexDx; - vec2 STd = texco.xy - 0.5 * TexDy; - vec2 STu = texco.xy + 0.5 * TexDy; - - float Hc, Hl, Hr, Hd, Hu; - rgbtobw(texture2D(ima, STc), Hc); - rgbtobw(texture2D(ima, STl), Hl); - rgbtobw(texture2D(ima, STr), Hr); - rgbtobw(texture2D(ima, STd), Hd); - rgbtobw(texture2D(ima, STu), Hu); - - dBs = hScale * (Hr - Hl); - dBt = hScale * (Hu - Hd); -} - -void mtex_bump_deriv( - vec3 texco, sampler2D ima, float ima_x, float ima_y, float hScale, - out float dBs, out float dBt) -{ - float s = 1.0; // negate this if flipped texture coordinate - vec2 TexDx = dFdx(texco.xy); - vec2 TexDy = dFdy(texco.xy); - - // this variant using a derivative map is described here - // http://mmikkelsen3d.blogspot.com/2011/07/derivative-maps.html - vec2 dim = vec2(ima_x, ima_y); - vec2 dBduv = hScale * dim * (2.0 * texture2D(ima, texco.xy).xy - 1.0); - - dBs = dBduv.x * TexDx.x + s * dBduv.y * TexDx.y; - dBt = dBduv.x * TexDy.x + s * dBduv.y * TexDy.y; -} - -void mtex_bump_apply( - float fDet, float dBs, float dBt, vec3 vR1, vec3 vR2, vec3 vNacc_in, - out vec3 vNacc_out, out vec3 perturbed_norm) -{ - vec3 vSurfGrad = sign(fDet) * (dBs * vR1 + dBt * vR2); - - vNacc_out = vNacc_in - vSurfGrad; - perturbed_norm = normalize(vNacc_out); -} - -void mtex_bump_apply_texspace( - float fDet, float dBs, float dBt, vec3 vR1, vec3 vR2, - sampler2D ima, vec3 texco, float ima_x, float ima_y, vec3 vNacc_in, - out vec3 vNacc_out, out vec3 perturbed_norm) -{ - vec2 TexDx = dFdx(texco.xy); - vec2 TexDy = dFdy(texco.xy); - - vec3 vSurfGrad = sign(fDet) * ( - dBs / length(vec2(ima_x * TexDx.x, ima_y * TexDx.y)) * vR1 + - dBt / length(vec2(ima_x * TexDy.x, ima_y * TexDy.y)) * vR2); - - vNacc_out = vNacc_in - vSurfGrad; - perturbed_norm = normalize(vNacc_out); -} - -void mtex_negate_texnormal(vec3 normal, out vec3 outnormal) -{ - outnormal = vec3(-normal.x, -normal.y, normal.z); -} - -void mtex_nspace_tangent(vec4 tangent, vec3 normal, vec3 texnormal, out vec3 outnormal) -{ - vec3 B = tangent.w * cross(normal, tangent.xyz); - - outnormal = texnormal.x * tangent.xyz + texnormal.y * B + texnormal.z * normal; - outnormal = normalize(outnormal); -} - -void mtex_nspace_world(mat4 viewmat, vec3 texnormal, out vec3 outnormal) -{ - outnormal = normalize((viewmat * vec4(texnormal, 0.0)).xyz); -} - -void mtex_nspace_object(vec3 texnormal, out vec3 outnormal) -{ - outnormal = normalize(gl_NormalMatrix * texnormal); -} - -void mtex_blend_normal(float norfac, vec3 normal, vec3 newnormal, out vec3 outnormal) -{ - outnormal = (1.0 - norfac) * normal + norfac * newnormal; - outnormal = normalize(outnormal); -} - -/******* MATERIAL *********/ - -void lamp_visibility_sun_hemi(vec3 lampvec, out vec3 lv, out float dist, out float visifac) -{ - lv = lampvec; - dist = 1.0; - visifac = 1.0; -} - -void lamp_visibility_other(vec3 co, vec3 lampco, out vec3 lv, out float dist, out float visifac) -{ - lv = co - lampco; - dist = length(lv); - lv = normalize(lv); - visifac = 1.0; -} - -void lamp_falloff_invlinear(float lampdist, float dist, out float visifac) -{ - visifac = lampdist / (lampdist + dist); -} - -void lamp_falloff_invsquare(float lampdist, float dist, out float visifac) -{ - visifac = lampdist / (lampdist + dist * dist); -} - -void lamp_falloff_sliders(float lampdist, float ld1, float ld2, float dist, out float visifac) -{ - float lampdistkw = lampdist * lampdist; - - visifac = lampdist / (lampdist + ld1 * dist); - visifac *= lampdistkw / (lampdistkw + ld2 * dist * dist); -} - -void lamp_falloff_invcoefficients(float coeff_const, float coeff_lin, float coeff_quad, float dist, out float visifac) -{ - vec3 coeff = vec3(coeff_const, coeff_lin, coeff_quad); - vec3 d_coeff = vec3(1.0, dist, dist * dist); - float visifac_r = dot(coeff, d_coeff); - if (visifac_r > 0.0) - visifac = 1.0 / visifac_r; - else - visifac = 0.0; -} - -void lamp_falloff_curve(float lampdist, sampler2D curvemap, float dist, out float visifac) -{ - visifac = texture2D(curvemap, vec2(dist / lampdist, 0.0)).x; -} - -void lamp_visibility_sphere(float lampdist, float dist, float visifac, out float outvisifac) -{ - float t = lampdist - dist; - - outvisifac = visifac * max(t, 0.0) / lampdist; -} - -void lamp_visibility_spot_square(vec3 lampvec, mat4 lampimat, vec2 scale, vec3 lv, out float inpr) -{ - if (dot(lv, lampvec) > 0.0) { - vec3 lvrot = (lampimat * vec4(lv, 0.0)).xyz; - /* without clever non-uniform scale, we could do: */ - // float x = max(abs(lvrot.x / lvrot.z), abs(lvrot.y / lvrot.z)); - float x = max(abs((lvrot.x / scale.x) / lvrot.z), abs((lvrot.y / scale.y) / lvrot.z)); - - inpr = 1.0 / sqrt(1.0 + x * x); - } - else - inpr = 0.0; -} - -void lamp_visibility_spot_circle(vec3 lampvec, mat4 lampimat, vec2 scale, vec3 lv, out float inpr) -{ - /* without clever non-uniform scale, we could do: */ - // inpr = dot(lv, lampvec); - if (dot(lv, lampvec) > 0.0) { - vec3 lvrot = (lampimat * vec4(lv, 0.0)).xyz; - float x = abs(lvrot.x / lvrot.z); - float y = abs(lvrot.y / lvrot.z); - - float ellipse = abs((x * x) / (scale.x * scale.x) + (y * y) / (scale.y * scale.y)); - - inpr = 1.0 / sqrt(1.0 + ellipse); - } - else - inpr = 0.0; -} - -void lamp_visibility_spot(float spotsi, float spotbl, float inpr, float visifac, out float outvisifac) -{ - float t = spotsi; - - if (inpr <= t) { - outvisifac = 0.0; - } - else { - t = inpr - t; - - /* soft area */ - if (spotbl != 0.0) - inpr *= smoothstep(0.0, 1.0, t / spotbl); - - outvisifac = visifac * inpr; - } -} - -void lamp_visibility_clamp(float visifac, out float outvisifac) -{ - outvisifac = (visifac < 0.001) ? 0.0 : visifac; -} - -void world_paper_view(vec3 vec, out vec3 outvec) -{ - vec3 nvec = normalize(vec); - outvec = (gl_ProjectionMatrix[3][3] == 0.0) ? vec3(nvec.x, 0.0, nvec.y) : vec3(0.0, 0.0, -1.0); -} - -void world_zen_mapping(vec3 view, float zenup, float zendown, out float zenfac) -{ - if (view.z >= 0.0) - zenfac = zenup; - else - zenfac = zendown; -} - -void world_blend_paper_real(vec3 vec, out float blend) -{ - blend = abs(vec.y); -} - -void world_blend_paper(vec3 vec, out float blend) -{ - blend = (vec.y + 1.0) * 0.5; -} - -void world_blend_real(vec3 vec, out float blend) -{ - blend = abs(normalize(vec).z); -} - -void world_blend(vec3 vec, out float blend) -{ - blend = (normalize(vec).z + 1) * 0.5; -} - -void shade_view(vec3 co, out vec3 view) -{ - /* handle perspective/orthographic */ - view = (gl_ProjectionMatrix[3][3] == 0.0) ? normalize(co) : vec3(0.0, 0.0, -1.0); -} - -void shade_tangent_v(vec3 lv, vec3 tang, out vec3 vn) -{ - vec3 c = cross(lv, tang); - vec3 vnor = cross(c, tang); - - vn = -normalize(vnor); -} - -void shade_inp(vec3 vn, vec3 lv, out float inp) -{ - inp = dot(vn, lv); -} - -void shade_is_no_diffuse(out float is) -{ - is = 0.0; -} - -void shade_is_hemi(float inp, out float is) -{ - is = 0.5 * inp + 0.5; -} - -float area_lamp_energy(mat4 area, vec3 co, vec3 vn) -{ - vec3 vec[4], c[4]; - float rad[4], fac; - - vec[0] = normalize(co - area[0].xyz); - vec[1] = normalize(co - area[1].xyz); - vec[2] = normalize(co - area[2].xyz); - vec[3] = normalize(co - area[3].xyz); - - c[0] = normalize(cross(vec[0], vec[1])); - c[1] = normalize(cross(vec[1], vec[2])); - c[2] = normalize(cross(vec[2], vec[3])); - c[3] = normalize(cross(vec[3], vec[0])); - - rad[0] = acos(dot(vec[0], vec[1])); - rad[1] = acos(dot(vec[1], vec[2])); - rad[2] = acos(dot(vec[2], vec[3])); - rad[3] = acos(dot(vec[3], vec[0])); - - fac = rad[0] * dot(vn, c[0]); - fac += rad[1] * dot(vn, c[1]); - fac += rad[2] * dot(vn, c[2]); - fac += rad[3] * dot(vn, c[3]); - - return max(fac, 0.0); -} - -void shade_inp_area( - vec3 position, vec3 lampco, vec3 lampvec, vec3 vn, mat4 area, float areasize, float k, - out float inp) -{ - vec3 co = position; - vec3 vec = co - lampco; - - if (dot(vec, lampvec) < 0.0) { - inp = 0.0; - } - else { - float intens = area_lamp_energy(area, co, vn); - - inp = pow(intens * areasize, k); - } -} - -void shade_diffuse_oren_nayer(float nl, vec3 n, vec3 l, vec3 v, float rough, out float is) -{ - vec3 h = normalize(v + l); - float nh = max(dot(n, h), 0.0); - float nv = max(dot(n, v), 0.0); - float realnl = dot(n, l); - - if (realnl < 0.0) { - is = 0.0; - } - else if (nl < 0.0) { - is = 0.0; - } - else { - float vh = max(dot(v, h), 0.0); - float Lit_A = acos(realnl); - float View_A = acos(nv); - - vec3 Lit_B = normalize(l - realnl * n); - vec3 View_B = normalize(v - nv * n); - - float t = max(dot(Lit_B, View_B), 0.0); - - float a, b; - - if (Lit_A > View_A) { - a = Lit_A; - b = View_A; - } - else { - a = View_A; - b = Lit_A; - } - - float A = 1.0 - (0.5 * ((rough * rough) / ((rough * rough) + 0.33))); - float B = 0.45 * ((rough * rough) / ((rough * rough) + 0.09)); - - b *= 0.95; - is = nl * (A + (B * t * sin(a) * tan(b))); - } -} - -void shade_diffuse_toon(vec3 n, vec3 l, vec3 v, float size, float tsmooth, out float is) -{ - float rslt = dot(n, l); - float ang = acos(rslt); - - if (ang < size) is = 1.0; - else if (ang > (size + tsmooth) || tsmooth == 0.0) is = 0.0; - else is = 1.0 - ((ang - size) / tsmooth); -} - -void shade_diffuse_minnaert(float nl, vec3 n, vec3 v, float darkness, out float is) -{ - if (nl <= 0.0) { - is = 0.0; - } - else { - float nv = max(dot(n, v), 0.0); - - if (darkness <= 1.0) - is = nl * pow(max(nv * nl, 0.1), darkness - 1.0); - else - is = nl * pow(1.0001 - nv, darkness - 1.0); - } -} - -float fresnel_fac(vec3 view, vec3 vn, float grad, float fac) -{ - float t1, t2; - float ffac; - - if (fac == 0.0) { - ffac = 1.0; - } - else { - t1 = dot(view, vn); - if (t1 > 0.0) t2 = 1.0 + t1; - else t2 = 1.0 - t1; - - t2 = grad + (1.0 - grad) * pow(t2, fac); - - if (t2 < 0.0) ffac = 0.0; - else if (t2 > 1.0) ffac = 1.0; - else ffac = t2; - } - - return ffac; -} - -void shade_diffuse_fresnel(vec3 vn, vec3 lv, vec3 view, float fac_i, float fac, out float is) -{ - is = fresnel_fac(lv, vn, fac_i, fac); -} - -void shade_cubic(float is, out float outis) -{ - if (is > 0.0 && is < 1.0) - outis = smoothstep(0.0, 1.0, is); - else - outis = is; -} - -void shade_visifac(float i, float visifac, float refl, out float outi) -{ - /*if (i > 0.0)*/ - outi = max(i * visifac * refl, 0.0); - /*else - outi = i;*/ -} - -void shade_tangent_v_spec(vec3 tang, out vec3 vn) -{ - vn = tang; -} - -void shade_add_to_diffuse(float i, vec3 lampcol, vec3 col, out vec3 outcol) -{ - if (i > 0.0) - outcol = i * lampcol * col; - else - outcol = vec3(0.0, 0.0, 0.0); -} - -void shade_hemi_spec(vec3 vn, vec3 lv, vec3 view, float spec, float hard, float visifac, out float t) -{ - lv += view; - lv = normalize(lv); - - t = dot(vn, lv); - t = 0.5 * t + 0.5; - - t = visifac * spec * pow(t, hard); -} - -void shade_phong_spec(vec3 n, vec3 l, vec3 v, float hard, out float specfac) -{ - vec3 h = normalize(l + v); - float rslt = max(dot(h, n), 0.0); - - specfac = pow(rslt, hard); -} - -void shade_cooktorr_spec(vec3 n, vec3 l, vec3 v, float hard, out float specfac) -{ - vec3 h = normalize(v + l); - float nh = dot(n, h); - - if (nh < 0.0) { - specfac = 0.0; - } - else { - float nv = max(dot(n, v), 0.0); - float i = pow(nh, hard); - - i = i / (0.1 + nv); - specfac = i; - } -} - -void shade_blinn_spec(vec3 n, vec3 l, vec3 v, float refrac, float spec_power, out float specfac) -{ - if (refrac < 1.0) { - specfac = 0.0; - } - else if (spec_power == 0.0) { - specfac = 0.0; - } - else { - if (spec_power < 100.0) - spec_power = sqrt(1.0 / spec_power); - else - spec_power = 10.0 / spec_power; - - vec3 h = normalize(v + l); - float nh = dot(n, h); - if (nh < 0.0) { - specfac = 0.0; - } - else { - float nv = max(dot(n, v), 0.01); - float nl = dot(n, l); - if (nl <= 0.01) { - specfac = 0.0; - } - else { - float vh = max(dot(v, h), 0.01); - - float a = 1.0; - float b = (2.0 * nh * nv) / vh; - float c = (2.0 * nh * nl) / vh; - - float g = 0.0; - - if (a < b && a < c) g = a; - else if (b < a && b < c) g = b; - else if (c < a && c < b) g = c; - - float p = sqrt(((refrac * refrac) + (vh * vh) - 1.0)); - float f = ((((p - vh) * (p - vh)) / ((p + vh) * (p + vh))) * - (1.0 + ((((vh * (p + vh)) - 1.0) * ((vh * (p + vh)) - 1.0)) / - (((vh * (p - vh)) + 1.0) * ((vh * (p - vh)) + 1.0))))); - float ang = acos(nh); - - specfac = max(f * g * exp_blender((-(ang * ang) / (2.0 * spec_power * spec_power))), 0.0); - } - } - } -} - -void shade_wardiso_spec(vec3 n, vec3 l, vec3 v, float rms, out float specfac) -{ - vec3 h = normalize(l + v); - float nh = max(dot(n, h), 0.001); - float nv = max(dot(n, v), 0.001); - float nl = max(dot(n, l), 0.001); - float angle = tan(acos(nh)); - float alpha = max(rms, 0.001); - - specfac = nl * (1.0 / (4.0 * M_PI * alpha * alpha)) * (exp_blender(-(angle * angle) / (alpha * alpha)) / (sqrt(nv * nl))); -} - -void shade_toon_spec(vec3 n, vec3 l, vec3 v, float size, float tsmooth, out float specfac) -{ - vec3 h = normalize(l + v); - float rslt = dot(h, n); - float ang = acos(rslt); - - if (ang < size) rslt = 1.0; - else if (ang >= (size + tsmooth) || tsmooth == 0.0) rslt = 0.0; - else rslt = 1.0 - ((ang - size) / tsmooth); - - specfac = rslt; -} - -void shade_spec_area_inp(float specfac, float inp, out float outspecfac) -{ - outspecfac = specfac * inp; -} - -void shade_spec_t(float shadfac, float spec, float visifac, float specfac, out float t) -{ - t = shadfac * spec * visifac * specfac; -} - -void shade_add_spec(float t, vec3 lampcol, vec3 speccol, out vec3 outcol) -{ - outcol = t * lampcol * speccol; -} - -void shade_add_mirror(vec3 mir, vec4 refcol, vec3 combined, out vec3 result) -{ - result = mir * refcol.gba + (vec3(1.0) - mir * refcol.rrr) * combined; -} - -void alpha_spec_correction(vec3 spec, float spectra, float alpha, out float outalpha) -{ - if (spectra > 0.0) { - float t = clamp(max(max(spec.r, spec.g), spec.b) * spectra, 0.0, 1.0); - outalpha = (1.0 - t) * alpha + t; - } - else { - outalpha = alpha; - } -} - -void shade_add(vec4 col1, vec4 col2, out vec4 outcol) -{ - outcol = col1 + col2; -} - -void shade_madd(vec4 col, vec4 col1, vec4 col2, out vec4 outcol) -{ - outcol = col + col1 * col2; -} - -void shade_add_clamped(vec4 col1, vec4 col2, out vec4 outcol) -{ - outcol = col1 + max(col2, vec4(0.0, 0.0, 0.0, 0.0)); -} - -void shade_madd_clamped(vec4 col, vec4 col1, vec4 col2, out vec4 outcol) -{ - outcol = col + max(col1 * col2, vec4(0.0, 0.0, 0.0, 0.0)); -} - -void env_apply(vec4 col, vec3 hor, vec3 zen, vec4 f, mat4 vm, vec3 vn, out vec4 outcol) -{ - vec3 vv = normalize(vm[2].xyz); - float skyfac = 0.5 * (1.0 + dot(vn, -vv)); - outcol = col + f * vec4(mix(hor, zen, skyfac), 0); -} - -void shade_maddf(vec4 col, float f, vec4 col1, out vec4 outcol) -{ - outcol = col + f * col1; -} - -void shade_mul(vec4 col1, vec4 col2, out vec4 outcol) -{ - outcol = col1 * col2; -} - -void shade_mul_value(float fac, vec4 col, out vec4 outcol) -{ - outcol = col * fac; -} - -void shade_mul_value_v3(float fac, vec3 col, out vec3 outcol) -{ - outcol = col * fac; -} - -void shade_obcolor(vec4 col, vec4 obcol, out vec4 outcol) -{ - outcol = vec4(col.rgb * obcol.rgb, col.a); -} - -void ramp_rgbtobw(vec3 color, out float outval) -{ - outval = color.r * 0.3 + color.g * 0.58 + color.b * 0.12; -} - -void shade_only_shadow(float i, float shadfac, float energy, vec3 shadcol, out vec3 outshadrgb) -{ - outshadrgb = i * energy * (1.0 - shadfac) * (vec3(1.0) - shadcol); -} - -void shade_only_shadow_diffuse(vec3 shadrgb, vec3 rgb, vec4 diff, out vec4 outdiff) -{ - outdiff = diff - vec4(rgb * shadrgb, 0.0); -} - -void shade_only_shadow_specular(vec3 shadrgb, vec3 specrgb, vec4 spec, out vec4 outspec) -{ - outspec = spec - vec4(specrgb * shadrgb, 0.0); -} - -void shade_clamp_positive(vec4 col, out vec4 outcol) -{ - outcol = max(col, vec4(0.0)); -} - -void test_shadowbuf( - vec3 rco, sampler2DShadow shadowmap, mat4 shadowpersmat, float shadowbias, float inp, - out float result) -{ - if (inp <= 0.0) { - result = 0.0; - } - else { - vec4 co = shadowpersmat * vec4(rco, 1.0); - - //float bias = (1.5 - inp*inp)*shadowbias; - co.z -= shadowbias * co.w; - - if (co.w > 0.0 && co.x > 0.0 && co.x / co.w < 1.0 && co.y > 0.0 && co.y / co.w < 1.0) - result = shadow2DProj(shadowmap, co).x; - else - result = 1.0; - } -} - -void test_shadowbuf_vsm( - vec3 rco, sampler2D shadowmap, mat4 shadowpersmat, float shadowbias, float bleedbias, float inp, - out float result) -{ - if (inp <= 0.0) { - result = 0.0; - } - else { - vec4 co = shadowpersmat * vec4(rco, 1.0); - if (co.w > 0.0 && co.x > 0.0 && co.x / co.w < 1.0 && co.y > 0.0 && co.y / co.w < 1.0) { - vec2 moments = texture2DProj(shadowmap, co).rg; - float dist = co.z / co.w; - float p = 0.0; - - if (dist <= moments.x) - p = 1.0; - - float variance = moments.y - (moments.x * moments.x); - variance = max(variance, shadowbias / 10.0); - - float d = moments.x - dist; - float p_max = variance / (variance + d * d); - - // Now reduce light-bleeding by removing the [0, x] tail and linearly rescaling (x, 1] - p_max = clamp((p_max - bleedbias) / (1.0 - bleedbias), 0.0, 1.0); - - result = max(p, p_max); - } - else { - result = 1.0; - } - } -} - -void shadows_only( - vec3 rco, sampler2DShadow shadowmap, mat4 shadowpersmat, - float shadowbias, vec3 shadowcolor, float inp, - out vec3 result) -{ - result = vec3(1.0); - - if (inp > 0.0) { - float shadfac; - - test_shadowbuf(rco, shadowmap, shadowpersmat, shadowbias, inp, shadfac); - result -= (1.0 - shadfac) * (vec3(1.0) - shadowcolor); - } -} - -void shadows_only_vsm( - vec3 rco, sampler2D shadowmap, mat4 shadowpersmat, - float shadowbias, float bleedbias, vec3 shadowcolor, float inp, - out vec3 result) -{ - result = vec3(1.0); - - if (inp > 0.0) { - float shadfac; - - test_shadowbuf_vsm(rco, shadowmap, shadowpersmat, shadowbias, bleedbias, inp, shadfac); - result -= (1.0 - shadfac) * (vec3(1.0) - shadowcolor); - } -} - -void shade_light_texture(vec3 rco, sampler2D cookie, mat4 shadowpersmat, out vec4 result) -{ - - vec4 co = shadowpersmat * vec4(rco, 1.0); - - result = texture2DProj(cookie, co); -} - -void shade_exposure_correct(vec3 col, float linfac, float logfac, out vec3 outcol) -{ - outcol = linfac * (1.0 - exp(col * logfac)); -} - -void shade_mist_factor( - vec3 co, float enable, float miststa, float mistdist, float misttype, float misi, - out float outfac) -{ - if (enable == 1.0) { - float fac, zcor; - - zcor = (gl_ProjectionMatrix[3][3] == 0.0) ? length(co) : -co[2]; - - fac = clamp((zcor - miststa) / mistdist, 0.0, 1.0); - if (misttype == 0.0) fac *= fac; - else if (misttype == 1.0) ; - else fac = sqrt(fac); - - outfac = 1.0 - (1.0 - fac) * (1.0 - misi); - } - else { - outfac = 0.0; - } -} - -void shade_world_mix(vec3 hor, vec4 col, out vec4 outcol) -{ - float fac = clamp(col.a, 0.0, 1.0); - outcol = vec4(mix(hor, col.rgb, fac), col.a); -} - -void shade_alpha_opaque(vec4 col, out vec4 outcol) -{ - outcol = vec4(col.rgb, 1.0); -} - -void shade_alpha_obcolor(vec4 col, vec4 obcol, out vec4 outcol) -{ - outcol = vec4(col.rgb, col.a * obcol.a); -} - /*********** NEW SHADER UTILITIES **************/ float fresnel_dielectric_0(float eta) @@ -2428,7 +966,15 @@ float hypot(float x, float y) void generated_from_orco(vec3 orco, out vec3 generated) { - generated = orco * 0.5 + vec3(0.5); +#ifdef VOLUMETRICS +#ifdef MESH_SHADER + generated = volumeObjectLocalCoord; +#else + generated = worldPosition; +#endif +#else + generated = orco; +#endif } int floor_to_int(float x) @@ -2441,7 +987,6 @@ int quick_floor(float x) return int(x) - ((x < 0) ? 1 : 0); } -#ifdef BIT_OPERATIONS float integer_noise(int n) { int nn; @@ -2505,7 +1050,6 @@ vec3 cellnoise_color(vec3 p) return vec3(r, g, b); } -#endif // BIT_OPERATIONS float floorfrac(float x, out int i) { @@ -2513,316 +1057,348 @@ float floorfrac(float x, out int i) return x - i; } +/* bsdfs */ -/* Principled BSDF operations */ - -float sqr(float a) +void convert_metallic_to_specular_tinted( + vec3 basecol, float metallic, float specular_fac, float specular_tint, + out vec3 diffuse, out vec3 f0) { - return a*a; + vec3 dielectric = vec3(0.034) * specular_fac * 2.0; + float lum = dot(basecol, vec3(0.3, 0.6, 0.1)); /* luminance approx. */ + vec3 tint = lum > 0 ? basecol / lum : vec3(1.0); /* normalize lum. to isolate hue+sat */ + f0 = mix(dielectric * mix(vec3(1.0), tint, specular_tint), basecol, metallic); + diffuse = mix(basecol, vec3(0.0), metallic); } -float schlick_fresnel(float u) +#ifndef VOLUMETRICS +void node_bsdf_diffuse(vec4 color, float roughness, vec3 N, out Closure result) { - float m = clamp(1.0 - u, 0.0, 1.0); - float m2 = m * m; - return m2 * m2 * m; // pow(m,5) + vec3 vN = normalize(mat3(ViewMatrix) * N); + result = CLOSURE_DEFAULT; + result.ssr_normal = normal_encode(vN, viewCameraVec); + eevee_closure_diffuse(N, color.rgb, 1.0, result.radiance); + result.radiance *= color.rgb; } -float GTR1(float NdotH, float a) +void node_bsdf_glossy(vec4 color, float roughness, vec3 N, float ssr_id, out Closure result) { - if (a >= 1.0) { - return M_1_PI; - } - - a = max(a, 0.001); - float a2 = a*a; - float t = 1.0 + (a2 - 1.0) * NdotH*NdotH; - return (a2 - 1.0) / (M_PI * log(a2) * t); + vec3 out_spec, ssr_spec; + 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; + result.radiance = out_spec * color.rgb; + result.ssr_data = vec4(ssr_spec * color.rgb, roughness); + result.ssr_normal = normal_encode(vN, viewCameraVec); + result.ssr_id = int(ssr_id); } -float GTR2(float NdotH, float a) +void node_bsdf_anisotropic( + vec4 color, float roughness, float anisotropy, float rotation, vec3 N, vec3 T, + out Closure result) { - float a2 = a*a; - float t = 1.0 + (a2 - 1.0) * NdotH*NdotH; - return a2 / (M_PI * t*t); + node_bsdf_diffuse(color, 0.0, N, result); } -float GTR2_aniso(float NdotH, float HdotX, float HdotY, float ax, float ay) +void node_bsdf_glass(vec4 color, float roughness, float ior, vec3 N, float ssr_id, out Closure result) { - return 1.0 / (M_PI * ax*ay * sqr(sqr(HdotX / ax) + sqr(HdotY / ay) + NdotH*NdotH)); + vec3 out_spec, out_refr, ssr_spec; + 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; + out_spec *= color.rgb; + float fresnel = F_eta(ior, dot(N, cameraVec)); + vec3 vN = normalize(mat3(ViewMatrix) * N); + result = CLOSURE_DEFAULT; + result.radiance = mix(out_refr, out_spec, fresnel); + result.ssr_data = vec4(ssr_spec * color.rgb * fresnel, roughness); + result.ssr_normal = normal_encode(vN, viewCameraVec); + result.ssr_id = int(ssr_id); } -float smithG_GGX(float NdotV, float alphaG) +void node_bsdf_toon(vec4 color, float size, float tsmooth, vec3 N, out Closure result) { - float a = alphaG*alphaG; - float b = NdotV*NdotV; - return 1.0 / (NdotV + sqrt(a + b - a * b)); + node_bsdf_diffuse(color, 0.0, N, result); } -vec3 rotate_vector(vec3 p, vec3 n, float theta) { - return ( - p * cos(theta) + cross(n, p) * - sin(theta) + n * dot(p, n) * - (1.0 - cos(theta)) - ); -} +void node_bsdf_principled_clearcoat(vec4 base_color, float subsurface, vec3 subsurface_radius, vec4 subsurface_color, float metallic, float specular, + float specular_tint, float roughness, float anisotropic, float anisotropic_rotation, float sheen, float sheen_tint, float clearcoat, + float clearcoat_roughness, float ior, float transmission, float transmission_roughness, vec3 N, vec3 CN, vec3 T, vec3 I, float ssr_id, + float sss_id, vec3 sss_scale, out Closure result) +{ + metallic = saturate(metallic); + transmission = saturate(transmission); + vec3 diffuse, f0, out_diff, out_spec, out_trans, out_refr, ssr_spec; + convert_metallic_to_specular_tinted(base_color.rgb, metallic, specular, specular_tint, diffuse, f0); -/*********** NEW SHADER NODES ***************/ + transmission *= 1.0 - metallic; + subsurface *= 1.0 - metallic; -#define NUM_LIGHTS 3 + clearcoat *= 0.25; + clearcoat *= 1.0 - transmission; -/* bsdfs */ +#ifdef USE_SSS + diffuse = mix(diffuse, vec3(0.0), subsurface); +#else + diffuse = mix(diffuse, subsurface_color.rgb, subsurface); +#endif + f0 = mix(f0, vec3(1.0), transmission); + + float sss_scalef = dot(sss_scale, vec3(1.0 / 3.0)); + eevee_closure_principled(N, diffuse, f0, int(ssr_id), roughness, + CN, clearcoat, clearcoat_roughness, 1.0, sss_scalef, ior, + out_diff, out_trans, out_spec, out_refr, ssr_spec); + + vec3 refr_color = base_color.rgb; + refr_color *= (refractionDepth > 0.0) ? refr_color : vec3(1.0); /* Simulate 2 transmission event */ + + float fresnel = F_eta(ior, dot(N, cameraVec)); + vec3 refr_spec_color = base_color.rgb * fresnel; + /* This bit maybe innacurate. */ + out_refr = out_refr * refr_color * (1.0 - fresnel) + out_spec * refr_spec_color; + + ssr_spec = mix(ssr_spec, refr_spec_color, transmission); + + vec3 vN = normalize(mat3(ViewMatrix) * N); + result = CLOSURE_DEFAULT; + result.radiance = out_spec + out_diff * diffuse; + result.radiance = mix(result.radiance, out_refr, transmission); + result.ssr_data = vec4(ssr_spec, roughness); + result.ssr_normal = normal_encode(vN, viewCameraVec); + result.ssr_id = int(ssr_id); +#ifdef USE_SSS + result.sss_data.a = sss_scalef; + result.sss_data.rgb = out_diff + out_trans; +#ifdef USE_SSS_ALBEDO + result.sss_albedo.rgb = mix(vec3(0.0), subsurface_color.rgb, subsurface); +#else + result.sss_data.rgb *= mix(vec3(0.0), subsurface_color.rgb, subsurface); +#endif + result.sss_data.rgb *= (1.0 - transmission); +#endif +} -void node_bsdf_diffuse(vec4 color, float roughness, vec3 N, out vec4 result) +void node_bsdf_translucent(vec4 color, vec3 N, out Closure result) { - /* ambient light */ - vec3 L = vec3(0.2); - - /* directional lights */ - for (int i = 0; i < NUM_LIGHTS; i++) { - vec3 light_position = gl_LightSource[i].position.xyz; - vec3 light_diffuse = gl_LightSource[i].diffuse.rgb; - - float bsdf = max(dot(N, light_position), 0.0); - L += light_diffuse * bsdf; - } - - result = vec4(L * color.rgb, 1.0); + node_bsdf_diffuse(color, 0.0, -N, result); } -void node_bsdf_glossy(vec4 color, float roughness, vec3 N, out vec4 result) +void node_bsdf_transparent(vec4 color, out Closure result) { - /* ambient light */ - vec3 L = vec3(0.2); - - /* directional lights */ - for (int i = 0; i < NUM_LIGHTS; i++) { - vec3 light_position = gl_LightSource[i].position.xyz; - vec3 H = gl_LightSource[i].halfVector.xyz; - vec3 light_diffuse = gl_LightSource[i].diffuse.rgb; - vec3 light_specular = gl_LightSource[i].specular.rgb; - - /* we mix in some diffuse so low roughness still shows up */ - 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; - } - - result = vec4(L * color.rgb, 1.0); + /* this isn't right */ + result = CLOSURE_DEFAULT; + result.radiance = vec3(0.0); + result.opacity = 0.0; + result.ssr_id = TRANSPARENT_CLOSURE_FLAG; } -void node_bsdf_anisotropic( - vec4 color, float roughness, float anisotropy, float rotation, vec3 N, vec3 T, - out vec4 result) +void node_bsdf_velvet(vec4 color, float sigma, vec3 N, out Closure result) { node_bsdf_diffuse(color, 0.0, N, result); } -void node_bsdf_glass(vec4 color, float roughness, float ior, vec3 N, out vec4 result) -{ +void node_subsurface_scattering( + vec4 color, float scale, vec3 radius, float sharpen, float texture_blur, vec3 N, float sss_id, + out Closure result) +{ +#if defined(USE_SSS) + vec3 out_diff, out_trans; + vec3 vN = normalize(mat3(ViewMatrix) * N); + result = CLOSURE_DEFAULT; + result.ssr_data = vec4(0.0); + result.ssr_normal = normal_encode(vN, viewCameraVec); + result.ssr_id = -1; + result.sss_data.a = scale; + eevee_closure_subsurface(N, color.rgb, 1.0, scale, out_diff, out_trans); + result.sss_data.rgb = out_diff + out_trans; +#ifdef USE_SSS_ALBEDO + /* Not perfect for texture_blur not exaclty equal to 0.0 or 1.0. */ + result.sss_albedo.rgb = mix(color.rgb, vec3(1.0), texture_blur); + result.sss_data.rgb *= mix(vec3(1.0), color.rgb, texture_blur); +#else + result.sss_data.rgb *= color.rgb; +#endif +#else node_bsdf_diffuse(color, 0.0, N, result); +#endif } -void node_bsdf_toon(vec4 color, float size, float tsmooth, vec3 N, out vec4 result) +void node_bsdf_refraction(vec4 color, float roughness, float ior, vec3 N, out Closure result) { - node_bsdf_diffuse(color, 0.0, N, result); + vec3 out_refr; + color.rgb *= (refractionDepth > 0.0) ? color.rgb : vec3(1.0); /* Simulate 2 absorption event. */ + 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; } -void node_bsdf_principled(vec4 base_color, float subsurface, vec3 subsurface_radius, vec4 subsurface_color, float metallic, float specular, - float specular_tint, float roughness, float anisotropic, float anisotropic_rotation, float sheen, float sheen_tint, float clearcoat, - float clearcoat_roughness, float ior, float transmission, float transmission_roughness, vec3 N, vec3 CN, vec3 T, vec3 I, out vec4 result) +void node_ambient_occlusion(vec4 color, vec3 vN, out Closure result) { - /* ambient light */ - // TODO: set ambient light to an appropriate value - vec3 L = mix(0.1, 0.03, metallic) * mix(base_color.rgb, subsurface_color.rgb, subsurface * (1.0 - metallic)); - - float eta = (2.0 / (1.0 - sqrt(0.08 * specular))) - 1.0; - - /* set the viewing vector */ - vec3 V = (gl_ProjectionMatrix[3][3] == 0.0) ? -normalize(I) : vec3(0.0, 0.0, 1.0); - - /* get the tangent */ - vec3 Tangent = T; - if (T == vec3(0.0)) { - // if no tangent is set, use a default tangent - if(N.x != N.y || N.x != N.z) { - Tangent = vec3(N.z-N.y, N.x-N.z, N.y-N.x); // (1,1,1) x N - } - else { - Tangent = vec3(N.z-N.y, N.x+N.z, -N.y-N.x); // (-1,1,1) x N - } - } - - /* rotate tangent */ - if (anisotropic_rotation != 0.0) { - Tangent = rotate_vector(Tangent, N, anisotropic_rotation * 2.0 * M_PI); - } - - /* calculate the tangent and bitangent */ - vec3 Y = normalize(cross(N, Tangent)); - vec3 X = cross(Y, N); - - /* fresnel normalization parameters */ - float F0 = fresnel_dielectric_0(eta); - float F0_norm = 1.0 / (1.0 - F0); - - /* directional lights */ - for (int i = 0; i < NUM_LIGHTS; i++) { - vec3 light_position_world = gl_LightSource[i].position.xyz; - vec3 light_position = normalize(light_position_world); - - vec3 H = normalize(light_position + V); - - vec3 light_diffuse = gl_LightSource[i].diffuse.rgb; - vec3 light_specular = gl_LightSource[i].specular.rgb; - - float NdotL = dot(N, light_position); - float NdotV = dot(N, V); - float LdotH = dot(light_position, H); - - vec3 diffuse_and_specular_bsdf = vec3(0.0); - if (NdotL >= 0.0 && NdotV >= 0.0) { - float NdotH = dot(N, H); - - float Cdlum = 0.3 * base_color.r + 0.6 * base_color.g + 0.1 * base_color.b; // luminance approx. - - vec3 Ctint = Cdlum > 0 ? base_color.rgb / Cdlum : vec3(1.0); // normalize lum. to isolate hue+sat - vec3 Cspec0 = mix(specular * 0.08 * mix(vec3(1.0), Ctint, specular_tint), base_color.rgb, metallic); - vec3 Csheen = mix(vec3(1.0), Ctint, sheen_tint); - - // Diffuse fresnel - go from 1 at normal incidence to .5 at grazing - // and mix in diffuse retro-reflection based on roughness - - float FL = schlick_fresnel(NdotL), FV = schlick_fresnel(NdotV); - float Fd90 = 0.5 + 2.0 * LdotH*LdotH * roughness; - float Fd = mix(1.0, Fd90, FL) * mix(1.0, Fd90, FV); - - // Based on Hanrahan-Krueger brdf approximation of isotropic bssrdf - // 1.25 scale is used to (roughly) preserve albedo - // Fss90 used to "flatten" retroreflection based on roughness - float Fss90 = LdotH*LdotH * roughness; - float Fss = mix(1.0, Fss90, FL) * mix(1.0, Fss90, FV); - float ss = 1.25 * (Fss * (1.0 / (NdotL + NdotV) - 0.5) + 0.5); - - // specular - float aspect = sqrt(1.0 - anisotropic * 0.9); - float a = sqr(roughness); - float ax = max(0.001, a / aspect); - float ay = max(0.001, a * aspect); - float Ds = GTR2_aniso(NdotH, dot(H, X), dot(H, Y), ax, ay); //GTR2(NdotH, a); - float FH = (fresnel_dielectric_cos(LdotH, eta) - F0) * F0_norm; - vec3 Fs = mix(Cspec0, vec3(1.0), FH); - float roughg = sqr(roughness * 0.5 + 0.5); - float Gs = smithG_GGX(NdotL, roughg) * smithG_GGX(NdotV, roughg); - - // sheen - vec3 Fsheen = schlick_fresnel(LdotH) * sheen * Csheen; - - vec3 diffuse_bsdf = (mix(Fd * base_color.rgb, ss * subsurface_color.rgb, subsurface) + Fsheen) * light_diffuse; - vec3 specular_bsdf = Gs * Fs * Ds * light_specular; - diffuse_and_specular_bsdf = diffuse_bsdf * (1.0 - metallic) + specular_bsdf; - } - diffuse_and_specular_bsdf *= max(NdotL, 0.0); + vec3 bent_normal; + vec4 rand = texelFetch(utilTex, ivec3(ivec2(gl_FragCoord.xy) % LUT_SIZE, 2.0), 0); + float final_ao = occlusion_compute(normalize(worldNormal), viewPosition, 1.0, rand, bent_normal); + result = CLOSURE_DEFAULT; + result.ssr_normal = normal_encode(vN, viewCameraVec); + result.radiance = final_ao * color.rgb; +} - float CNdotL = dot(CN, light_position); - float CNdotV = dot(CN, V); +#endif /* VOLUMETRICS */ - vec3 clearcoat_bsdf = vec3(0.0); - if (CNdotL >= 0.0 && CNdotV >= 0.0 && clearcoat > 0.0) { - float CNdotH = dot(CN, H); - //float FH = schlick_fresnel(LdotH); +/* emission */ - // clearcoat (ior = 1.5 -> F0 = 0.04) - float Dr = GTR1(CNdotH, sqr(clearcoat_roughness)); - float Fr = fresnel_dielectric_cos(LdotH, 1.5); //mix(0.04, 1.0, FH); - float Gr = smithG_GGX(CNdotL, 0.25) * smithG_GGX(CNdotV, 0.25); +void node_emission(vec4 color, float strength, vec3 vN, out Closure result) +{ +#ifndef VOLUMETRICS + color *= strength; + result = CLOSURE_DEFAULT; + result.radiance = color.rgb; + result.opacity = color.a; + result.ssr_normal = normal_encode(vN, viewCameraVec); +#else + result = Closure(vec3(0.0), vec3(0.0), color.rgb * strength, 0.0); +#endif +} - clearcoat_bsdf = clearcoat * Gr * Fr * Dr * vec3(0.25) * light_specular; - } - clearcoat_bsdf *= max(CNdotL, 0.0); +/* background */ - L += diffuse_and_specular_bsdf + clearcoat_bsdf; - } +void background_transform_to_world(vec3 viewvec, out vec3 worldvec) +{ + vec4 v = (ProjectionMatrix[3][3] == 0.0) ? vec4(viewvec, 1.0) : vec4(0.0, 0.0, 1.0, 1.0); + vec4 co_homogenous = (ProjectionMatrixInverse * v); - result = vec4(L, 1.0); + vec4 co = vec4(co_homogenous.xyz / co_homogenous.w, 0.0); +#if defined(WORLD_BACKGROUND) || defined(PROBE_CAPTURE) + worldvec = (ViewMatrixInverse * co).xyz; +#else + worldvec = (ModelViewMatrixInverse * co).xyz; +#endif } -void node_bsdf_translucent(vec4 color, vec3 N, out vec4 result) +void node_background(vec4 color, float strength, out Closure result) { - node_bsdf_diffuse(color, 0.0, N, result); +#ifndef VOLUMETRICS + color *= strength; + result = CLOSURE_DEFAULT; + result.radiance = color.rgb; + result.opacity = color.a; +#else + result = CLOSURE_DEFAULT; +#endif } -void node_bsdf_transparent(vec4 color, out vec4 result) -{ - /* this isn't right */ - result.r = color.r; - result.g = color.g; - result.b = color.b; - result.a = 0.0; -} +/* volumes */ -void node_bsdf_velvet(vec4 color, float sigma, vec3 N, out vec4 result) +void node_volume_scatter(vec4 color, float density, float anisotropy, out Closure result) { - node_bsdf_diffuse(color, 0.0, N, result); +#ifdef VOLUMETRICS + result = Closure(vec3(0.0), color.rgb * density, vec3(0.0), anisotropy); +#else + result = CLOSURE_DEFAULT; +#endif } -void node_subsurface_scattering( - vec4 color, float scale, vec3 radius, float sharpen, float texture_blur, vec3 N, - out vec4 result) +void node_volume_absorption(vec4 color, float density, out Closure result) { - node_bsdf_diffuse(color, 0.0, N, result); +#ifdef VOLUMETRICS + result = Closure((1.0 - color.rgb) * density, vec3(0.0), vec3(0.0), 0.0); +#else + result = CLOSURE_DEFAULT; +#endif } -void node_bsdf_hair(vec4 color, float offset, float roughnessu, float roughnessv, vec3 tangent, out vec4 result) +void node_blackbody(float temperature, sampler2D spectrummap, out vec4 color) { - result = 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_bsdf_refraction(vec4 color, float roughness, float ior, vec3 N, out vec4 result) +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) { - node_bsdf_diffuse(color, 0.0, N, result); -} +#ifdef VOLUMETRICS + vec3 absorption_coeff = vec3(0.0); + vec3 scatter_coeff = vec3(0.0); + vec3 emission_coeff = vec3(0.0); -void node_ambient_occlusion(vec4 color, out vec4 result) -{ - result = color; -} + /* Compute density. */ + density = max(density, 0.0); -/* emission */ + if(density > 1e-5) { + density = max(density * density_attribute, 0.0); + } -void node_emission(vec4 color, float strength, vec3 N, out vec4 result) -{ - result = color * strength; -} + if(density > 1e-5) { + /* Compute scattering and absorption coefficients. */ + vec3 scatter_color = color.rgb * color_attribute.rgb; -/* background */ + 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; + } -void background_transform_to_world(vec3 viewvec, out vec3 worldvec) -{ - vec4 v = (gl_ProjectionMatrix[3][3] == 0.0) ? vec4(viewvec, 1.0) : vec4(0.0, 0.0, 1.0, 1.0); - vec4 co_homogenous = (gl_ProjectionMatrixInverse * v); + /* Compute emission. */ + emission_strength = max(emission_strength, 0.0); - vec4 co = vec4(co_homogenous.xyz / co_homogenous.w, 0.0); - worldvec = (gl_ModelViewMatrixInverse * co).xyz; -} + if(emission_strength > 1e-5) { + emission_coeff += emission_strength * emission_color.rgb; + } -void node_background(vec4 color, float strength, vec3 N, out vec4 result) -{ - result = color * strength; + 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, vec4 shader1, vec4 shader2, out vec4 shader) +void node_mix_shader(float fac, Closure shader1, Closure shader2, out Closure shader) { - shader = mix(shader1, shader2, fac); + shader = closure_mix(shader1, shader2, fac); } -void node_add_shader(vec4 shader1, vec4 shader2, out vec4 shader) +void node_add_shader(Closure shader1, Closure shader2, out Closure shader) { - shader = shader1 + shader2; + shader = closure_add(shader1, shader2); } /* fresnel */ @@ -2830,7 +1406,7 @@ void node_add_shader(vec4 shader1, vec4 shader2, out vec4 shader) void node_fresnel(float ior, vec3 N, vec3 I, out float result) { /* handle perspective/orthographic */ - vec3 I_view = (gl_ProjectionMatrix[3][3] == 0.0) ? normalize(I) : vec3(0.0, 0.0, -1.0); + vec3 I_view = (ProjectionMatrix[3][3] == 0.0) ? normalize(I) : vec3(0.0, 0.0, -1.0); float eta = max(ior, 0.00001); result = fresnel_dielectric(I_view, N, (gl_FrontFacing) ? eta : 1.0 / eta); @@ -2842,7 +1418,7 @@ void node_layer_weight(float blend, vec3 N, vec3 I, out float fresnel, out float { /* fresnel */ float eta = max(1.0 - blend, 0.00001); - vec3 I_view = (gl_ProjectionMatrix[3][3] == 0.0) ? normalize(I) : vec3(0.0, 0.0, -1.0); + vec3 I_view = (ProjectionMatrix[3][3] == 0.0) ? normalize(I) : vec3(0.0, 0.0, -1.0); fresnel = fresnel_dielectric(I_view, N, (gl_FrontFacing) ? 1.0 / eta : eta); @@ -2872,11 +1448,67 @@ void node_gamma(vec4 col, float gamma, out vec4 outcol) /* geometry */ +void node_attribute_volume_density(sampler3D tex, out vec4 outcol, out vec3 outvec, out float outf) +{ +#if defined(MESH_SHADER) && defined(VOLUMETRICS) + vec3 cos = volumeObjectLocalCoord; +#else + vec3 cos = vec3(0.0); +#endif + outvec = texture(tex, cos).aaa; + outcol = vec4(outvec, 1.0); + outf = dot(vec3(1.0 / 3.0), outvec); +} + +void node_attribute_volume_color(sampler3D tex, out vec4 outcol, out vec3 outvec, out float outf) +{ +#if defined(MESH_SHADER) && defined(VOLUMETRICS) + vec3 cos = volumeObjectLocalCoord; +#else + vec3 cos = vec3(0.0); +#endif + + 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); +} + +void node_attribute_volume_flame(sampler3D tex, out vec4 outcol, out vec3 outvec, out float outf) +{ +#if defined(MESH_SHADER) && defined(VOLUMETRICS) + vec3 cos = volumeObjectLocalCoord; +#else + vec3 cos = vec3(0.0); +#endif + 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(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) { outcol = vec4(attr, 1.0); outvec = attr; - outf = (attr.x + attr.y + attr.z) / 3.0; + outf = dot(vec3(1.0 / 3.0), attr); } void node_uvmap(vec3 attr_uv, out vec3 outvec) @@ -2884,19 +1516,47 @@ void node_uvmap(vec3 attr_uv, out vec3 outvec) outvec = attr_uv; } +void tangent_orco_x(vec3 orco_in, out vec3 orco_out) +{ + orco_out = vec3(0.0, (orco_in.z - 0.5) * -0.5, (orco_in.y - 0.5) * 0.5); +} + +void tangent_orco_y(vec3 orco_in, out vec3 orco_out) +{ + orco_out = vec3((orco_in.z - 0.5) * -0.5, 0.0, (orco_in.x - 0.5) * 0.5); +} + +void tangent_orco_z(vec3 orco_in, out vec3 orco_out) +{ + orco_out = vec3((orco_in.y - 0.5) * -0.5, (orco_in.x - 0.5) * 0.5, 0.0); +} + +void node_tangentmap(vec4 attr_tangent, mat4 toworld, out vec3 tangent) +{ + tangent = (toworld * vec4(attr_tangent.xyz, 0.0)).xyz; +} + +void node_tangent(vec3 N, vec3 orco, mat4 objmat, mat4 toworld, out vec3 T) +{ + N = (toworld * vec4(N, 0.0)).xyz; + T = (objmat * vec4(orco, 0.0)).xyz; + T = cross(N, normalize(cross(T, N))); +} + void node_geometry( - vec3 I, vec3 N, mat4 toworld, + vec3 I, vec3 N, vec3 orco, mat4 objmat, mat4 toworld, out vec3 position, out vec3 normal, out vec3 tangent, out vec3 true_normal, out vec3 incoming, out vec3 parametric, out float backfacing, out float pointiness) { - position = (toworld * vec4(I, 1.0)).xyz; + position = worldPosition; normal = (toworld * vec4(N, 0.0)).xyz; - tangent = vec3(0.0); + tangent_orco_z(orco, orco); + node_tangent(N, orco, objmat, toworld, tangent); true_normal = normal; /* handle perspective/orthographic */ - vec3 I_view = (gl_ProjectionMatrix[3][3] == 0.0) ? normalize(I) : vec3(0.0, 0.0, -1.0); + vec3 I_view = (ProjectionMatrix[3][3] == 0.0) ? normalize(I) : vec3(0.0, 0.0, -1.0); incoming = -(toworld * vec4(I_view, 0.0)).xyz; parametric = vec3(0.0); @@ -2910,16 +1570,15 @@ void node_tex_coord( out vec3 generated, out vec3 normal, out vec3 uv, out vec3 object, out vec3 camera, out vec3 window, out vec3 reflection) { - generated = attr_orco * 0.5 + vec3(0.5); + generated = attr_orco; normal = normalize((obinvmat * (viewinvmat * vec4(N, 0.0))).xyz); uv = attr_uv; object = (obinvmat * (viewinvmat * vec4(I, 1.0))).xyz; camera = vec3(I.xy, -I.z); - vec4 projvec = gl_ProjectionMatrix * vec4(I, 1.0); + vec4 projvec = ProjectionMatrix * vec4(I, 1.0); window = vec3(mtex_2d_mapping(projvec.xyz / projvec.w).xy * camerafac.xy + camerafac.zw, 0.0); - vec3 shade_I; - shade_view(I, shade_I); + vec3 shade_I = (ProjectionMatrix[3][3] == 0.0) ? normalize(I) : vec3(0.0, 0.0, -1.0); vec3 view_reflection = reflect(shade_I, normalize(N)); reflection = (viewinvmat * vec4(view_reflection, 0.0)).xyz; } @@ -2930,13 +1589,18 @@ void node_tex_coord_background( out vec3 generated, out vec3 normal, out vec3 uv, out vec3 object, out vec3 camera, out vec3 window, out vec3 reflection) { - vec4 v = (gl_ProjectionMatrix[3][3] == 0.0) ? vec4(I, 1.0) : vec4(0.0, 0.0, 1.0, 1.0); - vec4 co_homogenous = (gl_ProjectionMatrixInverse * v); + vec4 v = (ProjectionMatrix[3][3] == 0.0) ? vec4(I, 1.0) : vec4(0.0, 0.0, 1.0, 1.0); + vec4 co_homogenous = (ProjectionMatrixInverse * v); vec4 co = vec4(co_homogenous.xyz / co_homogenous.w, 0.0); co = normalize(co); - vec3 coords = (gl_ModelViewMatrixInverse * co).xyz; + +#if defined(WORLD_BACKGROUND) || defined(PROBE_CAPTURE) + vec3 coords = (ViewMatrixInverse * co).xyz; +#else + vec3 coords = (ModelViewMatrixInverse * co).xyz; +#endif generated = coords; normal = -coords; @@ -2944,13 +1608,17 @@ void node_tex_coord_background( object = coords; camera = vec3(co.xy, -co.z); - window = (gl_ProjectionMatrix[3][3] == 0.0) ? + window = (ProjectionMatrix[3][3] == 0.0) ? vec3(mtex_2d_mapping(I).xy * camerafac.xy + camerafac.zw, 0.0) : vec3(vec2(0.5) * camerafac.xy + camerafac.zw, 0.0); reflection = -coords; } +#if defined(WORLD_BACKGROUND) || (defined(PROBE_CAPTURE) && !defined(MESH_SHADER)) +#define node_tex_coord node_tex_coord_background +#endif + /* textures */ float calc_gradient(vec3 p, int gradient_type) @@ -3020,7 +1688,6 @@ void node_tex_checker(vec3 co, vec4 color1, vec4 color2, float scale, out vec4 c fac = check ? 1.0 : 0.0; } -#ifdef BIT_OPERATIONS vec2 calc_brick_texture(vec3 p, float mortar_size, float mortar_smooth, float bias, float brick_width, float row_height, float offset_amount, int offset_frequency, @@ -3056,7 +1723,6 @@ vec2 calc_brick_texture(vec3 p, float mortar_size, float mortar_smooth, float bi return vec2(tint, smoothstep(0.0, mortar_smooth, min_dist)); } } -#endif void node_tex_brick(vec3 co, vec4 color1, vec4 color2, @@ -3067,7 +1733,6 @@ void node_tex_brick(vec3 co, float squash_amount, float squash_frequency, out vec4 color, out float fac) { -#ifdef BIT_OPERATIONS vec2 f2 = calc_brick_texture(co * scale, mortar_size, mortar_smooth, bias, brick_width, row_height, @@ -3081,10 +1746,6 @@ void node_tex_brick(vec3 co, } color = mix(color1, mortar, f); fac = f; -#else - color = vec4(1.0); - fac = 1.0; -#endif } void node_tex_clouds(vec3 co, float size, out vec4 color, out float fac) @@ -3099,7 +1760,15 @@ void node_tex_environment_equirectangular(vec3 co, sampler2D ima, out vec4 color float u = -atan(nco.y, nco.x) / (2.0 * M_PI) + 0.5; float v = atan(nco.z, hypot(nco.x, nco.y)) / M_PI + 0.5; - color = texture2D(ima, vec2(u, v)); + /* Fix pole bleeding */ + float half_width = 0.5 / float(textureSize(ima, 0).x); + v = clamp(v, half_width, 1.0 - half_width); + + /* Fix u = 0 seam */ + /* This is caused by texture filtering, since uv don't have smooth derivatives + * at u = 0 or 2PI, hardware filtering is using the smallest mipmap for certain + * texels. So we force the highest mipmap and don't do anisotropic filtering. */ + color = textureLod(ima, vec2(u, v), 0.0); } void node_tex_environment_mirror_ball(vec3 co, sampler2D ima, out vec4 color) @@ -3115,7 +1784,7 @@ void node_tex_environment_mirror_ball(vec3 co, sampler2D ima, out vec4 color) float u = 0.5 * (nco.x + 1.0); float v = 0.5 * (nco.z + 1.0); - color = texture2D(ima, vec2(u, v)); + color = texture(ima, vec2(u, v)); } void node_tex_environment_empty(vec3 co, out vec4 color) @@ -3125,7 +1794,7 @@ void node_tex_environment_empty(vec3 co, out vec4 color) void node_tex_image(vec3 co, sampler2D ima, out vec4 color, out float alpha) { - color = texture2D(ima, co.xy); + color = texture(ima, co.xy); alpha = color.a; } @@ -3199,21 +1868,21 @@ void node_tex_image_box(vec3 texco, if(signed_N.x < 0.0) { uv.x = 1.0 - uv.x; } - color += weight.x * texture2D(ima, uv); + color += weight.x * texture(ima, uv); } if (weight.y > 0.0) { vec2 uv = texco.xz; if(signed_N.y > 0.0) { uv.x = 1.0 - uv.x; } - color += weight.y * texture2D(ima, uv); + color += weight.y * texture(ima, uv); } if (weight.z > 0.0) { vec2 uv = texco.yx; if(signed_N.z > 0.0) { uv.x = 1.0 - uv.x; } - color += weight.z * texture2D(ima, uv); + color += weight.z * texture(ima, uv); } alpha = color.a; @@ -3286,7 +1955,6 @@ void node_tex_magic(vec3 co, float scale, float distortion, float depth, out vec fac = (color.x + color.y + color.z) / 3.0; } -#ifdef BIT_OPERATIONS float noise_fade(float t) { return t * t * t * (t * (t * 6.0 - 15.0) + 10.0); @@ -3361,10 +2029,9 @@ float noise_turbulence(vec3 p, float octaves, int hard) float fscale = 1.0; float amp = 1.0; float sum = 0.0; - int i, n; octaves = clamp(octaves, 0.0, 16.0); - n = int(octaves); - for (i = 0; i <= n; i++) { + int n = int(octaves); + for (int i = 0; i <= n; i++) { float t = noise(fscale * p); if (hard != 0) { t = abs(2.0 * t - 1.0); @@ -3374,7 +2041,7 @@ float noise_turbulence(vec3 p, float octaves, int hard) fscale *= 2.0; } float rmd = octaves - floor(octaves); - if (rmd != 0.0) { + if (rmd != 0.0) { float t = noise(fscale * p); if (hard != 0) { t = abs(2.0 * t - 1.0); @@ -3389,11 +2056,9 @@ float noise_turbulence(vec3 p, float octaves, int hard) return sum; } } -#endif // BIT_OPERATIONS void node_tex_noise(vec3 co, float scale, float detail, float distortion, out vec4 color, out float fac) { -#ifdef BIT_OPERATIONS vec3 p = co * scale; int hard = 0; if (distortion != 0.0) { @@ -3409,15 +2074,8 @@ void node_tex_noise(vec3 co, float scale, float detail, float distortion, out ve noise_turbulence(vec3(p.y, p.x, p.z), detail, hard), noise_turbulence(vec3(p.y, p.z, p.x), detail, hard), 1); -#else // BIT_OPERATIONS - color = vec4(1.0); - fac = 1.0; -#endif // BIT_OPERATIONS } - -#ifdef BIT_OPERATIONS - /* Musgrave fBm * * H: fractal increment parameter @@ -3433,9 +2091,8 @@ float noise_musgrave_fBm(vec3 p, float H, float lacunarity, float octaves) float value = 0.0; float pwr = 1.0; float pwHL = pow(lacunarity, -H); - int i; - for (i = 0; i < int(octaves); i++) { + for (int i = 0; i < int(octaves); i++) { value += snoise(p) * pwr; pwr *= pwHL; p *= lacunarity; @@ -3461,9 +2118,8 @@ float noise_musgrave_multi_fractal(vec3 p, float H, float lacunarity, float octa float value = 1.0; float pwr = 1.0; float pwHL = pow(lacunarity, -H); - int i; - for (i = 0; i < int(octaves); i++) { + for (int i = 0; i < int(octaves); i++) { value *= (pwr * snoise(p) + 1.0); pwr *= pwHL; p *= lacunarity; @@ -3489,13 +2145,12 @@ float noise_musgrave_hetero_terrain(vec3 p, float H, float lacunarity, float oct float value, increment, rmd; float pwHL = pow(lacunarity, -H); float pwr = pwHL; - int i; /* first unscaled octave of function; later octaves are scaled */ value = offset + snoise(p); p *= lacunarity; - for (i = 1; i < int(octaves); i++) { + for (int i = 1; i < int(octaves); i++) { increment = (snoise(p) + offset) * pwr * value; value += increment; pwr *= pwHL; @@ -3524,13 +2179,12 @@ float noise_musgrave_hybrid_multi_fractal(vec3 p, float H, float lacunarity, flo float result, signal, weight, rmd; float pwHL = pow(lacunarity, -H); float pwr = pwHL; - int i; result = snoise(p) + offset; weight = gain * result; p *= lacunarity; - for (i = 1; (weight > 0.001f) && (i < int(octaves)); i++) { + for (int i = 1; (weight > 0.001f) && (i < int(octaves)); i++) { if (weight > 1.0) weight = 1.0; @@ -3561,14 +2215,13 @@ float noise_musgrave_ridged_multi_fractal(vec3 p, float H, float lacunarity, flo float result, signal, weight; float pwHL = pow(lacunarity, -H); float pwr = pwHL; - int i; signal = offset - abs(snoise(p)); signal *= signal; result = signal; weight = 1.0; - for (i = 1; i < int(octaves); i++) { + for (int i = 1; i < int(octaves); i++) { p *= lacunarity; weight = clamp(signal * gain, 0.0, 1.0); signal = offset - abs(snoise(p)); @@ -3590,19 +2243,18 @@ float svm_musgrave(int type, float gain, vec3 p) { - if (type == 0 /*NODE_MUSGRAVE_MULTIFRACTAL*/) + if (type == 0 /* NODE_MUSGRAVE_MULTIFRACTAL */) return intensity * noise_musgrave_multi_fractal(p, dimension, lacunarity, octaves); - else if (type == 1 /*NODE_MUSGRAVE_FBM*/) + else if (type == 1 /* NODE_MUSGRAVE_FBM */) return intensity * noise_musgrave_fBm(p, dimension, lacunarity, octaves); - else if (type == 2 /*NODE_MUSGRAVE_HYBRID_MULTIFRACTAL*/) + else if (type == 2 /* NODE_MUSGRAVE_HYBRID_MULTIFRACTAL */) return intensity * noise_musgrave_hybrid_multi_fractal(p, dimension, lacunarity, octaves, offset, gain); - else if (type == 3 /*NODE_MUSGRAVE_RIDGED_MULTIFRACTAL*/) + else if (type == 3 /* NODE_MUSGRAVE_RIDGED_MULTIFRACTAL */) return intensity * noise_musgrave_ridged_multi_fractal(p, dimension, lacunarity, octaves, offset, gain); - else if (type == 4 /*NODE_MUSGRAVE_HETERO_TERRAIN*/) + else if (type == 4 /* NODE_MUSGRAVE_HETERO_TERRAIN */) return intensity * noise_musgrave_hetero_terrain(p, dimension, lacunarity, octaves, offset); return 0.0; } -#endif // #ifdef BIT_OPERATIONS void node_tex_musgrave(vec3 co, float scale, @@ -3615,7 +2267,6 @@ void node_tex_musgrave(vec3 co, out vec4 color, out float fac) { -#ifdef BIT_OPERATIONS fac = svm_musgrave(int(type), dimension, lacunarity, @@ -3624,9 +2275,6 @@ void node_tex_musgrave(vec3 co, 1.0, gain, co * scale); -#else - fac = 1.0; -#endif color = vec4(fac, fac, fac, 1.0); } @@ -3638,7 +2286,6 @@ void node_tex_sky(vec3 co, out vec4 color) void node_tex_voronoi(vec3 co, float scale, float coloring, out vec4 color, out float fac) { -#ifdef BIT_OPERATIONS vec3 p = co * scale; int xx, yy, zz, xi, yi, zi; float da[4]; @@ -3703,13 +2350,8 @@ void node_tex_voronoi(vec3 co, float scale, float coloring, out vec4 color, out color = vec4(cellnoise_color(pa[0]), 1); fac = (color.x + color.y + color.z) * (1.0 / 3.0); } -#else // BIT_OPERATIONS - color = vec4(1.0); - fac = 1.0; -#endif // BIT_OPERATIONS } -#ifdef BIT_OPERATIONS float calc_wave(vec3 p, float distortion, float detail, float detail_scale, int wave_type, int wave_profile) { float n; @@ -3731,22 +2373,16 @@ float calc_wave(vec3 p, float distortion, float detail, float detail_scale, int return (n < 0.0) ? n + 1.0 : n; } } -#endif // BIT_OPERATIONS void node_tex_wave( vec3 co, float scale, float distortion, float detail, float detail_scale, float wave_type, float wave_profile, out vec4 color, out float fac) { -#ifdef BIT_OPERATIONS float f; f = calc_wave(co * scale, distortion, detail, detail_scale, int(wave_type), int(wave_profile)); color = vec4(f, f, f, 1.0); fac = f; -#else // BIT_OPERATIONS - color = vec4(1.0); - fac = 1; -#endif // BIT_OPERATIONS } /* light path */ @@ -3766,13 +2402,21 @@ void node_light_path( out float transparent_depth, out float transmission_depth) { +#ifndef PROBE_CAPTURE is_camera_ray = 1.0; - is_shadow_ray = 0.0; - is_diffuse_ray = 0.0; is_glossy_ray = 0.0; - is_singular_ray = 0.0; + is_diffuse_ray = 0.0; is_reflection_ray = 0.0; is_transmission_ray = 0.0; +#else + is_camera_ray = 0.0; + is_glossy_ray = 1.0; + is_diffuse_ray = 1.0; + is_reflection_ray = 1.0; + is_transmission_ray = 1.0; +#endif + is_shadow_ray = 0.0; + is_singular_ray = 0.0; ray_length = 1.0; ray_depth = 1.0; diffuse_depth = 1.0; @@ -3835,6 +2479,23 @@ void node_bevel(float radius, vec3 N, out vec3 result) result = N; } +void node_hair_info(out float is_strand, out float intercept, out float thickness, out vec3 tangent, out float random) +{ +#ifdef HAIR_SHADER + is_strand = 1.0; + intercept = hairTime; + thickness = hairThickness; + tangent = normalize(worldNormal); /* TODO fix naming */ + random = 0.0; +#else + is_strand = 0.0; + intercept = 0.0; + thickness = 0.0; + tangent = vec3(1.0); + random = 0.0; +#endif +} + void node_displacement_object(float height, float midlevel, float scale, vec3 N, mat4 obmat, out vec3 result) { N = (vec4(N, 0.0) * obmat).xyz; @@ -3871,37 +2532,75 @@ void node_vector_displacement_world(vec4 vector, float midlevel, float scale, ou /* output */ -void node_output_material(vec4 surface, vec4 volume, vec3 displacement, out vec4 result) +void node_output_material(Closure surface, Closure volume, vec3 displacement, out Closure result) { +#ifdef VOLUMETRICS + result = volume; +#else result = surface; +#endif } -void node_output_world(vec4 surface, vec4 volume, out vec4 result) +uniform float backgroundAlpha; + +void node_output_world(Closure surface, Closure volume, out Closure result) { - result = surface; +#ifndef VOLUMETRICS + result.radiance = surface.radiance; + result.opacity = backgroundAlpha; +#else + result = volume; +#endif /* VOLUMETRICS */ } -/* ********************** matcap style render ******************** */ +#ifndef VOLUMETRICS +/* TODO : clean this ifdef mess */ +/* EEVEE output */ +void world_normals_get(out vec3 N) +{ + N = gl_FrontFacing ? worldNormal : -worldNormal; +} -void material_preview_matcap(vec4 color, sampler2D ima, vec4 N, vec4 mask, out vec4 result) +void node_eevee_specular( + vec4 diffuse, vec4 specular, float roughness, vec4 emissive, float transp, vec3 normal, + float clearcoat, float clearcoat_roughness, vec3 clearcoat_normal, + float occlusion, float ssr_id, out Closure result) { - vec3 normal; - vec2 tex; - -#ifndef USE_OPENSUBDIV - /* remap to 0.0 - 1.0 range. This is done because OpenGL 2.0 clamps colors - * between shader stages and we want the full range of the normal */ - normal = vec3(2.0, 2.0, 2.0) * vec3(N.x, N.y, N.z) - vec3(1.0, 1.0, 1.0); - if (normal.z < 0.0) { - normal.z = 0.0; + vec3 out_diff, out_spec, ssr_spec; + eevee_closure_default(normal, diffuse.rgb, specular.rgb, int(ssr_id), roughness, occlusion, + out_diff, out_spec, ssr_spec); + + vec3 vN = normalize(mat3(ViewMatrix) * normal); + result = CLOSURE_DEFAULT; + result.radiance = out_diff * diffuse.rgb + out_spec + emissive.rgb; + result.opacity = 1.0 - transp; + result.ssr_data = vec4(ssr_spec, roughness); + result.ssr_normal = normal_encode(vN, viewCameraVec); + result.ssr_id = int(ssr_id); +} + +void node_shader_to_rgba(Closure cl, out vec4 outcol, out float outalpha) +{ + vec4 spec_accum = vec4(0.0); + if (ssrToggle && cl.ssr_id == outputSsrId) { + vec3 V = cameraVec; + vec3 vN = normal_decode(cl.ssr_normal, viewCameraVec); + vec3 N = transform_direction(ViewMatrixInverse, vN); + float roughness = cl.ssr_data.a; + float roughnessSquared = max(1e-3, roughness * roughness); + fallback_cubemap(N, V, worldPosition, viewPosition, roughness, roughnessSquared, spec_accum); } - normal = normalize(normal); -#else - normal = inpt.v.normal; - mask = vec4(1.0, 1.0, 1.0, 1.0); -#endif - tex.x = 0.5 + 0.49 * normal.x; - tex.y = 0.5 + 0.49 * normal.y; - result = texture2D(ima, tex) * mask; + outalpha = cl.opacity; + outcol = vec4((spec_accum.rgb * cl.ssr_data.rgb) + cl.radiance, 1.0); + +# ifdef USE_SSS +# ifdef USE_SSS_ALBEDO + outcol.rgb += cl.sss_data.rgb * cl.sss_albedo; +# else + outcol.rgb += cl.sss_data.rgb; +# endif +# endif } + +#endif /* VOLUMETRICS */ diff --git a/source/blender/gpu/shaders/gpu_shader_point_uniform_color_aa_frag.glsl b/source/blender/gpu/shaders/gpu_shader_point_uniform_color_aa_frag.glsl new file mode 100644 index 00000000000..fef81cf58fe --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_point_uniform_color_aa_frag.glsl @@ -0,0 +1,24 @@ + +uniform vec4 color; + +in vec2 radii; +out vec4 fragColor; + +void main() { + float dist = length(gl_PointCoord - vec2(0.5)); + +// transparent outside of point +// --- 0 --- +// smooth transition +// --- 1 --- +// pure point color +// ... +// dist = 0 at center of point + + fragColor.rgb = color.rgb; + fragColor.a = mix(color.a, 0.0, smoothstep(radii[1], radii[0], dist)); + + if (fragColor.a == 0.0) { + discard; + } +} diff --git a/source/blender/gpu/shaders/gpu_shader_point_uniform_color_frag.glsl b/source/blender/gpu/shaders/gpu_shader_point_uniform_color_frag.glsl new file mode 100644 index 00000000000..852c76fcb26 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_point_uniform_color_frag.glsl @@ -0,0 +1,17 @@ + +uniform vec4 color; + +out vec4 fragColor; + +void main() +{ + vec2 centered = gl_PointCoord - vec2(0.5); + float dist_squared = dot(centered, centered); + const float rad_squared = 0.25; + + // round point with jaggy edges + if (dist_squared > rad_squared) + discard; + + fragColor = color; +} diff --git a/source/blender/gpu/shaders/gpu_shader_point_uniform_color_outline_aa_frag.glsl b/source/blender/gpu/shaders/gpu_shader_point_uniform_color_outline_aa_frag.glsl new file mode 100644 index 00000000000..eae5ee633ae --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_point_uniform_color_outline_aa_frag.glsl @@ -0,0 +1,36 @@ + +uniform vec4 color; +uniform vec4 outlineColor; + +in vec4 radii; +out vec4 fragColor; + +void main() { + float dist = length(gl_PointCoord - vec2(0.5)); + +// transparent outside of point +// --- 0 --- +// smooth transition +// --- 1 --- +// pure outline color +// --- 2 --- +// smooth transition +// --- 3 --- +// pure point color +// ... +// dist = 0 at center of point + + float midStroke = 0.5 * (radii[1] + radii[2]); + + if (dist > midStroke) { + fragColor.rgb = outlineColor.rgb; + fragColor.a = mix(outlineColor.a, 0.0, smoothstep(radii[1], radii[0], dist)); + } + else { + fragColor = mix(color, outlineColor, smoothstep(radii[3], radii[2], dist)); + } + + if (fragColor.a == 0.0) { + discard; + } +} diff --git a/source/blender/gpu/shaders/gpu_shader_point_varying_color_frag.glsl b/source/blender/gpu/shaders/gpu_shader_point_varying_color_frag.glsl new file mode 100644 index 00000000000..2d2724bb686 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_point_varying_color_frag.glsl @@ -0,0 +1,16 @@ + +in vec4 finalColor; +out vec4 fragColor; + +void main() +{ + vec2 centered = gl_PointCoord - vec2(0.5); + float dist_squared = dot(centered, centered); + const float rad_squared = 0.25; + + // round point with jaggy edges + if (dist_squared > rad_squared) + discard; + + fragColor = finalColor; +} diff --git a/source/blender/gpu/shaders/gpu_shader_point_varying_color_outline_aa_frag.glsl b/source/blender/gpu/shaders/gpu_shader_point_varying_color_outline_aa_frag.glsl new file mode 100644 index 00000000000..9b7d4bfc6d6 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_point_varying_color_outline_aa_frag.glsl @@ -0,0 +1,31 @@ + +uniform vec4 outlineColor; + +in vec4 radii; +in vec4 fillColor; +out vec4 fragColor; + +void main() { + float dist = length(gl_PointCoord - vec2(0.5)); + +// transparent outside of point +// --- 0 --- +// smooth transition +// --- 1 --- +// pure outline color +// --- 2 --- +// smooth transition +// --- 3 --- +// pure fill color +// ... +// dist = 0 at center of point + + float midStroke = 0.5 * (radii[1] + radii[2]); + + if (dist > midStroke) { + fragColor.rgb = outlineColor.rgb; + fragColor.a = mix(outlineColor.a, 0.0, smoothstep(radii[1], radii[0], dist)); + } + else + fragColor = mix(fillColor, outlineColor, smoothstep(radii[3], radii[2], dist)); +} diff --git a/source/blender/gpu/shaders/gpu_shader_sep_gaussian_blur_frag.glsl b/source/blender/gpu/shaders/gpu_shader_sep_gaussian_blur_frag.glsl index b485d2cce86..78241a798a2 100644 --- a/source/blender/gpu/shaders/gpu_shader_sep_gaussian_blur_frag.glsl +++ b/source/blender/gpu/shaders/gpu_shader_sep_gaussian_blur_frag.glsl @@ -1,16 +1,19 @@ uniform vec2 ScaleU; uniform sampler2D textureSource; +in vec2 texCoord_interp; +out vec4 fragColor; + void main() { vec4 color = vec4(0.0); - color += texture2D(textureSource, gl_TexCoord[0].st + vec2(-3.0 * ScaleU.x, -3.0 * ScaleU.y)) * 0.015625; - color += texture2D(textureSource, gl_TexCoord[0].st + vec2(-2.0 * ScaleU.x, -2.0 * ScaleU.y)) * 0.09375; - color += texture2D(textureSource, gl_TexCoord[0].st + vec2(-1.0 * ScaleU.x, -1.0 * ScaleU.y)) * 0.234375; - color += texture2D(textureSource, gl_TexCoord[0].st + vec2(0.0, 0.0)) * 0.3125; - color += texture2D(textureSource, gl_TexCoord[0].st + vec2(1.0 * ScaleU.x, 1.0 * ScaleU.y)) * 0.234375; - color += texture2D(textureSource, gl_TexCoord[0].st + vec2(2.0 * ScaleU.x, 2.0 * ScaleU.y)) * 0.09375; - color += texture2D(textureSource, gl_TexCoord[0].st + vec2(3.0 * ScaleU.x, 3.0 * ScaleU.y)) * 0.015625; + color += texture(textureSource, texCoord_interp.st + vec2(-3.0 * ScaleU.x, -3.0 * ScaleU.y)) * 0.015625; + color += texture(textureSource, texCoord_interp.st + vec2(-2.0 * ScaleU.x, -2.0 * ScaleU.y)) * 0.09375; + color += texture(textureSource, texCoord_interp.st + vec2(-1.0 * ScaleU.x, -1.0 * ScaleU.y)) * 0.234375; + color += texture(textureSource, texCoord_interp.st + vec2(0.0, 0.0)) * 0.3125; + color += texture(textureSource, texCoord_interp.st + vec2(1.0 * ScaleU.x, 1.0 * ScaleU.y)) * 0.234375; + color += texture(textureSource, texCoord_interp.st + vec2(2.0 * ScaleU.x, 2.0 * ScaleU.y)) * 0.09375; + color += texture(textureSource, texCoord_interp.st + vec2(3.0 * ScaleU.x, 3.0 * ScaleU.y)) * 0.015625; - gl_FragColor = color; + fragColor = color; } 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 5d00108b052..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,6 +1,14 @@ +out vec2 texCoord_interp; + void main() { - gl_Position = ftransform(); - gl_TexCoord[0] = gl_MultiTexCoord0; + 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_simple_lighting_frag.glsl b/source/blender/gpu/shaders/gpu_shader_simple_lighting_frag.glsl new file mode 100644 index 00000000000..d65768eff4d --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_simple_lighting_frag.glsl @@ -0,0 +1,18 @@ + +#ifndef USE_INSTANCE_COLOR +uniform vec4 color; +#endif +uniform vec3 light; + +in vec3 normal; +#ifdef USE_INSTANCE_COLOR +flat in vec4 finalColor; +# define color finalColor +#endif +out vec4 fragColor; + +void main() +{ + fragColor = color; + fragColor.xyz *= clamp(dot(normalize(normal), light), 0.0, 1.0); +} diff --git a/source/blender/gpu/shaders/gpu_shader_simple_lighting_smooth_color_alpha_frag.glsl b/source/blender/gpu/shaders/gpu_shader_simple_lighting_smooth_color_alpha_frag.glsl new file mode 100644 index 00000000000..6b13f408c84 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_simple_lighting_smooth_color_alpha_frag.glsl @@ -0,0 +1,14 @@ + +uniform vec3 light; +uniform float alpha; +uniform float global; + +in vec3 normal; +in vec4 finalColor; +out vec4 fragColor; + +void main() +{ + fragColor = finalColor * (global + (1.0 - global) * max(0.0, dot(normalize(normal), light))); + fragColor.a = alpha; +} diff --git a/source/blender/gpu/shaders/gpu_shader_simple_lighting_smooth_color_frag.glsl b/source/blender/gpu/shaders/gpu_shader_simple_lighting_smooth_color_frag.glsl new file mode 100644 index 00000000000..58c5f292647 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_simple_lighting_smooth_color_frag.glsl @@ -0,0 +1,16 @@ + +uniform vec3 light; + +#ifdef USE_FLAT_NORMAL +flat in vec3 normal; +flat in vec4 finalColor; +#else +in vec3 normal; +in vec4 finalColor; +#endif +out vec4 fragColor; + +void main() +{ + fragColor = finalColor * max(0.0, dot(normalize(normal), light)); +} diff --git a/source/blender/gpu/shaders/gpu_shader_smoke_frag.glsl b/source/blender/gpu/shaders/gpu_shader_smoke_frag.glsl index 6ded453225e..b57bd5b6a37 100644 --- a/source/blender/gpu/shaders/gpu_shader_smoke_frag.glsl +++ b/source/blender/gpu/shaders/gpu_shader_smoke_frag.glsl @@ -1,5 +1,6 @@ -varying vec3 coords; +in vec3 coords; +out vec4 fragColor; uniform vec3 active_color; uniform float step_size; @@ -16,7 +17,7 @@ uniform sampler3D color_band_texture; void main() { /* compute color and density from volume texture */ - vec4 soot = texture3D(soot_texture, coords); + vec4 soot = texture(soot_texture, coords); #ifndef USE_COBA vec3 soot_color; @@ -24,7 +25,7 @@ void main() soot_color = active_color * soot.rgb / soot.a; } else { - soot_color = vec3(0, 0, 0); + soot_color = vec3(0); } float soot_density = density_scale * soot.a; @@ -33,16 +34,14 @@ void main() float soot_alpha = 1.0 - soot_transmittance; /* shade */ - float shadow = texture3D(shadow_texture, coords).r; + float shadow = texture(shadow_texture, coords).r; soot_color *= soot_transmittance * shadow; /* premultiply alpha */ - vec4 color = vec4(soot_alpha * soot_color, soot_alpha); + fragColor = vec4(soot_alpha * soot_color, soot_alpha); #else - float color_band = texture3D(color_band_texture, coords).r; - vec4 transfer_function = texture1D(transfer_texture, color_band); - vec4 color = transfer_function * density_scale; + float color_band = texture(color_band_texture, coords).r; + vec4 transfer_function = texture(transfer_texture, color_band); + fragColor = transfer_function * density_scale; #endif - - gl_FragColor = color; } diff --git a/source/blender/gpu/shaders/gpu_shader_smoke_vert.glsl b/source/blender/gpu/shaders/gpu_shader_smoke_vert.glsl index 297486ae26a..8c30e9baf9e 100644 --- a/source/blender/gpu/shaders/gpu_shader_smoke_vert.glsl +++ b/source/blender/gpu/shaders/gpu_shader_smoke_vert.glsl @@ -1,5 +1,7 @@ -varying vec3 coords; +uniform mat4 ModelViewProjectionMatrix; + +out vec3 coords; uniform vec3 min_location; uniform vec3 invsize; @@ -7,6 +9,7 @@ uniform vec3 ob_sizei; void main() { - gl_Position = gl_ModelViewProjectionMatrix * vec4(gl_Vertex.xyz * ob_sizei, 1.0); + // TODO: swap gl_Vertex for vec3 pos, update smoke setup code + gl_Position = ModelViewProjectionMatrix * vec4(gl_Vertex.xyz * ob_sizei, 1.0); coords = (gl_Vertex.xyz - min_location) * invsize; } diff --git a/source/blender/gpu/shaders/gpu_shader_text_frag.glsl b/source/blender/gpu/shaders/gpu_shader_text_frag.glsl new file mode 100644 index 00000000000..fbfa4cfcc9d --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_text_frag.glsl @@ -0,0 +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 + 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 new file mode 100644 index 00000000000..338156f5b68 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_text_vert.glsl @@ -0,0 +1,17 @@ + +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() +{ + pos_rect = pos; + tex_rect = tex; + color = col; +} diff --git a/source/blender/gpu/shaders/gpu_shader_uniform_color_frag.glsl b/source/blender/gpu/shaders/gpu_shader_uniform_color_frag.glsl new file mode 100644 index 00000000000..118a661863d --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_uniform_color_frag.glsl @@ -0,0 +1,21 @@ + +#if defined(USE_COLOR_U32) +uniform uint color; +#else +uniform vec4 color; +#endif + +out vec4 fragColor; + +void main() +{ +#if defined(USE_COLOR_U32) + fragColor = vec4( + ((color ) & uint(0xFF)) * (1.0f / 255.0f), + ((color >> 8) & uint(0xFF)) * (1.0f / 255.0f), + ((color >> 16) & uint(0xFF)) * (1.0f / 255.0f), + ((color >> 24) ) * (1.0f / 255.0f)); +#else + fragColor = color; +#endif +} diff --git a/source/blender/gpu/shaders/gpu_shader_vertex.glsl b/source/blender/gpu/shaders/gpu_shader_vertex.glsl index db0068d2f3d..2a6c137e195 100644 --- a/source/blender/gpu/shaders/gpu_shader_vertex.glsl +++ b/source/blender/gpu/shaders/gpu_shader_vertex.glsl @@ -1,3 +1,8 @@ + +uniform mat4 ModelViewMatrix; +uniform mat4 ProjectionMatrix; +uniform mat3 NormalMatrix; + #ifdef USE_OPENSUBDIV in vec3 normal; in vec4 position; @@ -7,8 +12,8 @@ out block { } outpt; #endif -varying vec3 varposition; -varying vec3 varnormal; +out vec3 varposition; +out vec3 varnormal; #ifdef CLIP_WORKAROUND varying float gl_ClipDistance[6]; @@ -42,11 +47,7 @@ void srgb_to_linearrgb(vec4 col_from, out vec4 col_to) bool is_srgb(int info) { -#ifdef USE_NEW_SHADING return (info == 1)? true: false; -#else - return false; -#endif } void set_var_from_attr(float attr, int info, out float var) @@ -89,11 +90,11 @@ void main() vec3 normal = gl_Normal; #endif - vec4 co = gl_ModelViewMatrix * position; + vec4 co = ModelViewMatrix * position; varposition = co.xyz; - varnormal = normalize(gl_NormalMatrix * normal); - gl_Position = gl_ProjectionMatrix * co; + varnormal = normalize(NormalMatrix * normal); + gl_Position = ProjectionMatrix * co; #ifdef CLIP_WORKAROUND int i; diff --git a/source/blender/gpu/shaders/gpu_shader_vertex_world.glsl b/source/blender/gpu/shaders/gpu_shader_vertex_world.glsl index d45a4b316a8..af2e4ba19a2 100644 --- a/source/blender/gpu/shaders/gpu_shader_vertex_world.glsl +++ b/source/blender/gpu/shaders/gpu_shader_vertex_world.glsl @@ -1,7 +1,6 @@ -varying vec3 varposition; -varying vec3 varnormal; - +out vec3 varposition; +out vec3 varnormal; /* Color, keep in sync with: gpu_shader_vertex.glsl */ @@ -30,11 +29,7 @@ void srgb_to_linearrgb(vec4 col_from, out vec4 col_to) bool is_srgb(int info) { -#ifdef USE_NEW_SHADING return (info == 1)? true: false; -#else - return false; -#endif } void set_var_from_attr(float attr, int info, out float var) diff --git a/source/blender/gpu/shaders/gpu_shader_vsm_store_frag.glsl b/source/blender/gpu/shaders/gpu_shader_vsm_store_frag.glsl index 3761bf350eb..6aad94bbf59 100644 --- a/source/blender/gpu/shaders/gpu_shader_vsm_store_frag.glsl +++ b/source/blender/gpu/shaders/gpu_shader_vsm_store_frag.glsl @@ -2,7 +2,8 @@ * This fragment shader was initially found at http://fabiensanglard.net/shadowmappingVSM/index.php */ -varying vec4 v_position; +in vec4 v_position; +out vec4 fragColor; void main() { @@ -17,5 +18,6 @@ void main() float dy = dFdy(depth); moment2 += 0.25 * (dx * dx + dy * dy); - gl_FragColor = vec4(moment1, moment2, 0.0, 0.0); + fragColor = vec4(moment1, moment2, 0.0, 0.0); + // TODO: write to a 2-component target --^ } diff --git a/source/blender/gpu/shaders/gpu_shader_vsm_store_vert.glsl b/source/blender/gpu/shaders/gpu_shader_vsm_store_vert.glsl index 224c3e78adc..def835156f7 100644 --- a/source/blender/gpu/shaders/gpu_shader_vsm_store_vert.glsl +++ b/source/blender/gpu/shaders/gpu_shader_vsm_store_vert.glsl @@ -1,7 +1,10 @@ -varying vec4 v_position; + +uniform mat4 ModelViewProjectionMatrix; + +out vec4 v_position; void main() { - gl_Position = ftransform(); + gl_Position = ModelViewProjectionMatrix * gl_Vertex; v_position = gl_Position; } |