diff options
Diffstat (limited to 'source/blender/gpu')
149 files changed, 11457 insertions, 3966 deletions
diff --git a/source/blender/gpu/CMakeLists.txt b/source/blender/gpu/CMakeLists.txt index 885ff2ff159..5c0115d967a 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,6 +51,8 @@ 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 @@ -54,13 +60,19 @@ set(SRC 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_lamp.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 +81,7 @@ 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_fullscreen_vert.glsl shaders/gpu_shader_material.glsl shaders/gpu_shader_sep_gaussian_blur_frag.glsl shaders/gpu_shader_sep_gaussian_blur_vert.glsl @@ -85,6 +97,7 @@ set(SRC shaders/gpu_shader_smoke_vert.glsl GPU_basic_shader.h + GPU_batch.h GPU_buffers.h GPU_compositing.h GPU_debug.h @@ -92,16 +105,109 @@ set(SRC GPU_extensions.h GPU_framebuffer.h GPU_glew.h + GPU_immediate.h + GPU_immediate_util.h GPU_init_exit.h + GPU_lamp.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_lamp_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_2D_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_image_vert.glsl SRC) +data_to_c_simple(shaders/gpu_shader_image_frag.glsl SRC) +data_to_c_simple(shaders/gpu_shader_image_linear_frag.glsl SRC) +data_to_c_simple(shaders/gpu_shader_image_shuffle_color_frag.glsl SRC) +data_to_c_simple(shaders/gpu_shader_image_mask_uniform_color_frag.glsl SRC) +data_to_c_simple(shaders/gpu_shader_image_modulate_alpha_frag.glsl SRC) +data_to_c_simple(shaders/gpu_shader_image_alpha_color_frag.glsl SRC) +data_to_c_simple(shaders/gpu_shader_image_color_frag.glsl SRC) +data_to_c_simple(shaders/gpu_shader_image_depth_linear_frag.glsl SRC) +data_to_c_simple(shaders/gpu_shader_image_depth_copy_frag.glsl SRC) +data_to_c_simple(shaders/gpu_shader_image_interlace_frag.glsl SRC) +data_to_c_simple(shaders/gpu_shader_3D_image_vert.glsl SRC) +data_to_c_simple(shaders/gpu_shader_3D_vert.glsl SRC) +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_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_instance_bone_envelope_solid_vert.glsl SRC) +data_to_c_simple(shaders/gpu_shader_instance_bone_envelope_wire_vert.glsl SRC) +data_to_c_simple(shaders/gpu_shader_instance_mball_handles_vert.glsl SRC) + +data_to_c_simple(shaders/gpu_shader_3D_groundline_geom.glsl SRC) +data_to_c_simple(shaders/gpu_shader_3D_groundpoint_vert.glsl SRC) + +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_vert.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,7 +222,7 @@ 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_fullscreen_vert.glsl SRC) data_to_c_simple(shaders/gpu_shader_fx_ssao_frag.glsl SRC) data_to_c_simple(shaders/gpu_shader_fx_dof_frag.glsl SRC) data_to_c_simple(shaders/gpu_shader_fx_dof_vert.glsl SRC) 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..fda24018150 --- /dev/null +++ b/source/blender/gpu/GPU_batch.h @@ -0,0 +1,72 @@ +/* + * ***** 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 "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_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..0d8a7a45ee9 100644 --- a/source/blender/gpu/GPU_buffers.h +++ b/source/blender/gpu/GPU_buffers.h @@ -51,6 +51,7 @@ struct GPUVertPointLink; struct GPUDrawObject; struct GridCommonGPUBuffer; struct PBVH; +struct Gwn_Batch; struct MVert; typedef struct GPUBuffer { @@ -266,11 +267,10 @@ void GPU_pbvh_grid_buffers_update( 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); 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..e437b4e4f58 100644 --- a/source/blender/gpu/GPU_draw.h +++ b/source/blender/gpu/GPU_draw.h @@ -39,13 +39,16 @@ extern "C" { struct ImBuf; struct Image; struct ImageUser; -struct MTexPoly; struct Object; struct Scene; +struct ViewLayer; struct View3D; struct RegionView3D; struct SmokeModifierData; struct DupliObject; +struct EvaluationContext; + +#include "DNA_object_enums.h" /* OpenGL drawing functions related to shading. These are also * shared with the game engine, where there were previously @@ -59,6 +62,13 @@ struct DupliObject; void GPU_state_init(void); +/* Programmable point size + * - shaders set their own point size when enabled + * - use glPointSize when disabled */ + +void GPU_enable_program_point_size(void); +void GPU_disable_program_point_size(void); + /* Material drawing * - first the state is initialized by a particular object and * it's materials @@ -66,8 +76,10 @@ void GPU_state_init(void); * GPU_object_material_bind returns 0 if drawing should be skipped * - after drawing, the material must be disabled again */ -void GPU_begin_object_materials(struct View3D *v3d, struct RegionView3D *rv3d, - struct Scene *scene, struct Object *ob, bool glsl, bool *do_alpha_after); +void GPU_begin_object_materials( + struct View3D *v3d, struct RegionView3D *rv3d, + struct Scene *scene, struct ViewLayer *view_layer, + struct Object *ob, bool glsl, const eObjectMode object_mode, bool *do_alpha_after); void GPU_end_object_materials(void); bool GPU_object_materials_check(void); @@ -84,29 +96,19 @@ 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); - /* 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); + struct ViewLayer *view_layer, 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, + int mode, const char *textstr, int textlen, unsigned int *col, const float *v_quad[4], const float *uv_quad[4], int glattrib); @@ -166,6 +168,17 @@ 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..31f24aa7c2e 100644 --- a/source/blender/gpu/GPU_framebuffer.h +++ b/source/blender/gpu/GPU_framebuffer.h @@ -50,8 +50,13 @@ struct GPUTexture; void GPU_texture_bind_as_framebuffer(struct GPUTexture *tex); GPUFrameBuffer *GPU_framebuffer_create(void); -int GPU_framebuffer_texture_attach(GPUFrameBuffer *fb, struct GPUTexture *tex, int slot, char err_out[256]); +bool GPU_framebuffer_texture_attach(GPUFrameBuffer *fb, struct GPUTexture *tex, int slot, int mip); +bool GPU_framebuffer_texture_layer_attach( + GPUFrameBuffer *fb, struct GPUTexture *tex, int slot, int layer, int mip); +bool GPU_framebuffer_texture_cubeface_attach( + GPUFrameBuffer *fb, struct GPUTexture *tex, int slot, int face, int mip); void GPU_framebuffer_texture_detach(struct GPUTexture *tex); +void GPU_framebuffer_bind(GPUFrameBuffer *fb); void GPU_framebuffer_slots_bind(GPUFrameBuffer *fb, int slot); void GPU_framebuffer_texture_unbind(GPUFrameBuffer *fb, struct GPUTexture *tex); void GPU_framebuffer_free(GPUFrameBuffer *fb); @@ -66,18 +71,32 @@ void GPU_framebuffer_blur( GPUFrameBuffer *fb, struct GPUTexture *tex, GPUFrameBuffer *blurfb, struct GPUTexture *blurtex); +void GPU_framebuffer_blit( + GPUFrameBuffer *fb_read, int read_slot, + GPUFrameBuffer *fb_write, int write_slot, bool use_depth, bool use_stencil); + +void GPU_framebuffer_recursive_downsample( + GPUFrameBuffer *fb, struct GPUTexture *tex, int num_iter, + void (*callback)(void *userData, int level), void *userData); + /* GPU OffScreen * - wrapper around framebuffer and texture for simple offscreen drawing * - changes size if graphics card can't support it */ -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_blit(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..6206e973908 --- /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_lamp.h b/source/blender/gpu/GPU_lamp.h new file mode 100644 index 00000000000..87350f1ceb4 --- /dev/null +++ b/source/blender/gpu/GPU_lamp.h @@ -0,0 +1,77 @@ +/* + * ***** 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): Brecht Van Lommel, Clément Foucault. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file GPU_lamp.h + * \ingroup gpu + */ + +#ifndef __GPU_LAMP_H__ +#define __GPU_LAMP_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +struct Scene; +struct Object; +struct RenderEngineType; + +typedef struct GPULamp GPULamp; + +#define MAX_LAMP_DATA 2 + +typedef struct LampEngineData { + void *storage[MAX_LAMP_DATA]; +} LampEngineData; + +LampEngineData *GPU_lamp_engine_data_get(struct Scene *scene, struct Object *ob, struct Object *par, struct RenderEngineType *re); + +GPULamp *GPU_lamp_from_blender(struct Scene *scene, struct Object *ob, struct Object *par); +void GPU_lamp_free(struct Object *ob); +void GPU_lamp_engine_data_free(LampEngineData *led); + +bool GPU_lamp_visible(GPULamp *lamp, struct Material *ma); +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); + +#ifdef __cplusplus +} +#endif + +#endif /* __GPU_LAMP_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..b486ff14dd1 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,12 +136,12 @@ 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; @@ -141,6 +154,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 +214,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,26 +225,36 @@ 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]); +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); + /* High level functions to create and use GPU materials */ GPUMaterial *GPU_material_world(struct Scene *scene, struct World *wo); - +GPUMaterial *GPU_material_from_nodetree_find( + struct ListBase *gpumaterials, const void *engine_type, int options); +GPUMaterial *GPU_material_from_nodetree( + struct Scene *scene, struct bNodeTree *ntree, struct ListBase *gpumaterials, const void *engine_type, int options, + const char *vert_code, const char *geom_code, const char *frag_lib, const char *defines); GPUMaterial *GPU_material_from_blender(struct Scene *scene, struct Material *ma, bool use_opensubdiv); GPUMaterial *GPU_material_matcap(struct Scene *scene, struct Material *ma, bool use_opensubdiv); void GPU_material_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); + float viewmat[4][4], float viewinv[4][4], float cameraborder[4]); 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]); @@ -237,6 +262,11 @@ 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 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); @@ -244,6 +274,8 @@ void GPU_material_vertex_attributes(GPUMaterial *material, 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); +bool GPU_material_use_domain_surface(GPUMaterial *mat); +bool GPU_material_use_domain_volume(GPUMaterial *mat); /* Exported shading */ @@ -312,26 +344,8 @@ 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, + GPUMaterial *mat, struct GPULamp *lamp, GPUNodeLink **r_col, GPUNodeLink **r_lv, GPUNodeLink **r_dist, GPUNodeLink **r_shadow, GPUNodeLink **r_energy); /* World */ 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..def0b0bfbc7 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 @@ -54,29 +55,35 @@ GPUShader *GPU_shader_create( 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); void GPU_shader_free(GPUShader *shader); void GPU_shader_bind(GPUShader *shader); void GPU_shader_unbind(void); +int GPU_shader_get_program(GPUShader *shader); + void *GPU_shader_get_interface(GPUShader *shader); -void GPU_shader_set_interface(GPUShader *shader, void *interface); + +void *GPU_fx_shader_get_interface(GPUShader *shader); +void GPU_fx_shader_set_interface(GPUShader *shader, void *interface); + int GPU_shader_get_uniform(GPUShader *shader, const char *name); +int GPU_shader_get_builtin_uniform(GPUShader *shader, int builtin); +int GPU_shader_get_uniform_block(GPUShader *shader, const char *name); 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,13 +92,104 @@ 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_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 */ + GPU_SHADER_2D_UNIFORM_COLOR, + GPU_SHADER_2D_FLAT_COLOR, + GPU_SHADER_2D_SMOOTH_COLOR, + GPU_SHADER_2D_IMAGE, + GPU_SHADER_2D_IMAGE_COLOR, + GPU_SHADER_2D_IMAGE_ALPHA_COLOR, + GPU_SHADER_2D_IMAGE_ALPHA, + GPU_SHADER_2D_CHECKER, + GPU_SHADER_2D_DIAG_STRIPES, + /* for simple 3D drawing */ + GPU_SHADER_3D_UNIFORM_COLOR, + GPU_SHADER_3D_UNIFORM_COLOR_U32, + GPU_SHADER_3D_UNIFORM_COLOR_INSTANCE, + GPU_SHADER_3D_FLAT_COLOR, + GPU_SHADER_3D_FLAT_COLOR_U32, /* use for select-id's */ + GPU_SHADER_3D_SMOOTH_COLOR, + 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, + GPU_SHADER_3D_IMAGE_MODULATE_ALPHA, + GPU_SHADER_3D_IMAGE_DEPTH, + GPU_SHADER_3D_IMAGE_DEPTH_COPY, + /* stereo 3d */ + GPU_SHADER_2D_IMAGE_INTERLACE, + /* points */ + GPU_SHADER_2D_POINT_FIXED_SIZE_UNIFORM_COLOR, + GPU_SHADER_2D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_AA, + GPU_SHADER_2D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_OUTLINE_AA, + GPU_SHADER_2D_POINT_UNIFORM_SIZE_VARYING_COLOR_OUTLINE_AA, + GPU_SHADER_2D_POINT_VARYING_SIZE_VARYING_COLOR, + GPU_SHADER_3D_POINT_FIXED_SIZE_UNIFORM_COLOR, + GPU_SHADER_3D_POINT_FIXED_SIZE_VARYING_COLOR, + GPU_SHADER_3D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_AA, + GPU_SHADER_3D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_OUTLINE_AA, + GPU_SHADER_3D_POINT_VARYING_SIZE_UNIFORM_COLOR, + 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_COLOR_VARIYING_SIZE, /* Uniformly scaled */ + GPU_SHADER_INSTANCE_VARIYING_COLOR_VARIYING_SCALE, + GPU_SHADER_INSTANCE_EDGES_VARIYING_COLOR, + + GPU_SHADER_3D_INSTANCE_BONE_ENVELOPE_SOLID, + GPU_SHADER_3D_INSTANCE_BONE_ENVELOPE_WIRE, + + GPU_SHADER_3D_INSTANCE_MBALL_HANDLES, + + 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); diff --git a/source/blender/gpu/GPU_texture.h b/source/blender/gpu/GPU_texture.h index 756fe79151b..1b64d66469b 100644 --- a/source/blender/gpu/GPU_texture.h +++ b/source/blender/gpu/GPU_texture.h @@ -55,25 +55,123 @@ 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; +/* 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_RGBA32F, + GPU_RGBA16F, + GPU_RGBA8, + GPU_RG32F, + GPU_RG16F, + GPU_RG16I, + GPU_R32F, + GPU_R16F, + GPU_RG8, + GPU_R8, +#if 0 + GPU_RGBA32I, + GPU_RGBA32UI, + GPU_RGBA16, + GPU_RGBA16I, + GPU_RGBA16UI, + GPU_RGBA8I, + GPU_RGBA8UI, + GPU_RG32I, + GPU_RG32UI, + GPU_RG16, + GPU_RG16UI, + GPU_RG8I, + GPU_RG8UI, + GPU_R32I, + GPU_R32UI, + GPU_R16I, + GPU_R16UI, + GPU_R16, + GPU_R8I, + GPU_R8UI, +#endif + + /* 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, 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_1D_custom( + int w, int channels, GPUTextureFormat data_type, const float *pixels, char err_out[256]); +GPUTexture *GPU_texture_create_2D(int w, int h, const float *pixels, char err_out[256]); +GPUTexture *GPU_texture_create_2D_custom( + int w, int h, int channels, GPUTextureFormat data_type, const float *pixels, char err_out[256]); +GPUTexture *GPU_texture_create_2D_multisample(int w, int h, const float *pixels, int samples, char err_out[256]); +GPUTexture *GPU_texture_create_2D_custom_multisample( + int w, int h, int channels, GPUTextureFormat data_type, const float *pixels, int samples, char err_out[256]); +GPUTexture *GPU_texture_create_2D_array_custom( + int w, int h, int d, int channels, GPUTextureFormat data_type, const float *pixels, char err_out[256]); +GPUTexture *GPU_texture_create_3D(int w, int h, int d, const float *pixels, char err_out[256]); +GPUTexture *GPU_texture_create_3D_custom( + int w, int h, int d, int channels, GPUTextureFormat data_type, const float *pixels, char err_out[256]); +GPUTexture *GPU_texture_create_cube_custom( + int w, int channels, GPUTextureFormat data_type, const float *pixels, char err_out[256]); 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]); -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_with_stencil(int w, int h, char err_out[256]); GPUTexture *GPU_texture_create_depth_multisample(int w, int h, int samples, char err_out[256]); +GPUTexture *GPU_texture_create_depth_with_stencil_multisample(int w, int h, int samples, char err_out[256]); + 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,12 +179,15 @@ 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); @@ -95,7 +196,9 @@ void GPU_texture_framebuffer_set(GPUTexture *tex, struct GPUFrameBuffer *fb, int 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); +int GPU_texture_format(const GPUTexture *tex); +bool GPU_texture_depth(const GPUTexture *tex); +bool GPU_texture_stencil(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..dff7e278ae1 --- /dev/null +++ b/source/blender/gpu/GPU_viewport.h @@ -0,0 +1,135 @@ +/* + * ***** 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 *calls_generate; + 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 cache_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]); + +void GPU_viewport_tag_update(GPUViewport *viewport); +bool GPU_viewport_do_update(GPUViewport *viewport); + +/* Texture pool */ +GPUTexture *GPU_viewport_texture_pool_query(GPUViewport *viewport, void *engine, int width, int height, int channels, int format); + +bool GPU_viewport_engines_data_validate(GPUViewport *viewport, unsigned int hash); +void GPU_viewport_cache_release(GPUViewport *viewport); + +/* debug */ +bool GPU_viewport_debug_depth_create(GPUViewport *viewport, int width, int height, char err_out[256]); +void GPU_viewport_debug_depth_free(GPUViewport *viewport); +void GPU_viewport_debug_depth_store(GPUViewport *viewport, const int x, const int y); +void GPU_viewport_debug_depth_draw(GPUViewport *viewport, const float znear, const float zfar); +bool GPU_viewport_debug_depth_is_valid(GPUViewport *viewport); +int GPU_viewport_debug_depth_width(const GPUViewport *viewport); +int GPU_viewport_debug_depth_height(const GPUViewport *viewport); + +#endif // __GPU_VIEWPORT_H__ diff --git a/source/blender/gpu/intern/gpu_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..332102aca46 --- /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_basic_shader.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..950f1a2dab3 --- /dev/null +++ b/source/blender/gpu/intern/gpu_batch_presets.c @@ -0,0 +1,214 @@ +/* + * ***** 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 "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}; + +/* We may want 2D presets later. */ + +/* -------------------------------------------------------------------- */ +/** \name 3D Primitives + * \{ */ + +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(&g_presets_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(&g_presets_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) +{ + if (g_presets_3d.format.attrib_ct == 0) { + Gwn_VertFormat *format = &g_presets_3d.format; + g_presets_3d.attr_id.pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT); + g_presets_3d.attr_id.nor = GWN_vertformat_attr_add(format, "nor", GWN_COMP_F32, 3, GWN_FETCH_FLOAT); + } + + /* Hard coded resolution */ + g_presets_3d.batch.sphere_low = gpu_batch_sphere(8, 16); + g_presets_3d.batch.sphere_med = gpu_batch_sphere(16, 10); + g_presets_3d.batch.sphere_high = gpu_batch_sphere(32, 24); + + g_presets_3d.batch.sphere_wire_low = batch_sphere_wire(6, 8); + g_presets_3d.batch.sphere_wire_med = batch_sphere_wire(8, 16); +} + +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. */ + gwn_batch_vao_cache_clear(g_presets_3d.batch.sphere_low); + gwn_batch_vao_cache_clear(g_presets_3d.batch.sphere_med); + gwn_batch_vao_cache_clear(g_presets_3d.batch.sphere_high); + gwn_batch_vao_cache_clear(g_presets_3d.batch.sphere_wire_low); + gwn_batch_vao_cache_clear(g_presets_3d.batch.sphere_wire_med); +} + +void gpu_batch_presets_exit(void) +{ + GWN_batch_discard(g_presets_3d.batch.sphere_low); + GWN_batch_discard(g_presets_3d.batch.sphere_med); + GWN_batch_discard(g_presets_3d.batch.sphere_high); + GWN_batch_discard(g_presets_3d.batch.sphere_wire_low); + GWN_batch_discard(g_presets_3d.batch.sphere_wire_med); +} diff --git a/source/blender/gpu/intern/gpu_buffers.c b/source/blender/gpu/intern/gpu_buffers.c index ea8f7516726..3043b3ab686 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,10 +53,14 @@ #include "GPU_buffers.h" #include "GPU_draw.h" -#include "GPU_basic_shader.h" +#include "GPU_immediate.h" +#include "GPU_batch.h" #include "bmesh.h" +/* TODO: gawain support for baseelemarray */ +// #define USE_BASE_ELEM + typedef enum { GPU_BUFFER_VERTEX_STATE = (1 << 0), GPU_BUFFER_NORMAL_STATE = (1 << 1), @@ -106,9 +108,8 @@ 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; @@ -943,26 +944,12 @@ void GPU_buffer_draw_elements(GPUBuffer *UNUSED(elements), unsigned int mode, in /* 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; @@ -999,6 +986,39 @@ struct GPU_PBVH_Buffers { float diffuse_color[4]; }; +typedef struct { + uint pos, nor, col; +} VertexBufferAttrID; + +static void gpu_pbvh_vert_format_init__gwn(Gwn_VertFormat *format, VertexBufferAttrID *vbo_id) +{ + vbo_id->pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT); + vbo_id->nor = GWN_vertformat_attr_add(format, "nor", GWN_COMP_I16, 3, GWN_FETCH_INT_TO_FLOAT_UNIT); + vbo_id->col = GWN_vertformat_attr_add(format, "color", GWN_COMP_U8, 3, GWN_FETCH_INT_TO_FLOAT_UNIT); +} + +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); + } + + GWN_BATCH_DISCARD_SAFE(buffers->triangles); + buffers->triangles = GWN_batch_create( + GWN_PRIM_TRIS, buffers->vert_buf, + /* can be NULL */ + buffers->index_buf); + + GWN_BATCH_DISCARD_SAFE(buffers->triangles_fast); + if (buffers->index_buf_fast) { + 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,8 +1060,6 @@ 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; @@ -1067,35 +1085,39 @@ 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); + GWN_VERTBUF_DISCARD_SAFE(buffers->vert_buf); + + /* match 'VertexBufferFormat' */ + Gwn_VertFormat format = {0}; + VertexBufferAttrID vbo_id; + gpu_pbvh_vert_format_init__gwn(&format, &vbo_id); + + buffers->vert_buf = GWN_vertbuf_create_with_format(&format); + GWN_vertbuf_data_alloc(buffers->vert_buf, totelem); - if (vert_data) { + if (buffers->vert_buf->data) { /* 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, vbo_id.pos, i, v->co); + GWN_vertbuf_attr_set(buffers->vert_buf, 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, vbo_id.col, vidx, color_ub); } else { - copy_v3_v3_uchar(out->color, diffuse_color_ub); + GWN_vertbuf_attr_set(buffers->vert_buf, vbo_id.col, vidx, diffuse_color_ub); } } } @@ -1104,8 +1126,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 +1159,20 @@ 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, vbo_id.pos, vbo_index, v->co); + GWN_vertbuf_attr_set(buffers->vert_buf, vbo_id.nor, vbo_index, no); + GWN_vertbuf_attr_set(buffers->vert_buf, vbo_id.col, vbo_index, color_ub); - vert_data++; + vbo_index++; } } } - GPU_buffer_unlock(buffers->vert_buf, GPU_BINDING_ARRAY); + gpu_pbvh_batch_init(buffers); } else { - GPU_buffer_free(buffers->vert_buf); - buffers->vert_buf = NULL; + GWN_VERTBUF_DISCARD_SAFE(buffers->vert_buf); } } @@ -1166,12 +1187,17 @@ 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; @@ -1200,35 +1226,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,7 +1270,6 @@ 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; @@ -1260,12 +1278,13 @@ void GPU_pbvh_grid_buffers_update( 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) + if (buffers->use_matcaps) { diffuse_color[0] = diffuse_color[1] = diffuse_color[2] = 1.0; + } else if (show_diffuse_color) { const DMFlagMat *flags = &grid_flag_mats[grid_indices[0]]; @@ -1274,38 +1293,48 @@ void GPU_pbvh_grid_buffers_update( copy_v4_v4(buffers->diffuse_color, diffuse_color); - vert_data = GPU_buffer_lock_stream(buffers->vert_buf, GPU_BINDING_ARRAY); - if (vert_data) { + Gwn_VertFormat format = {0}; + VertexBufferAttrID vbo_id; + gpu_pbvh_vert_format_init__gwn(&format, &vbo_id); + + /* Build coord/normal VBO */ + GWN_VERTBUF_DISCARD_SAFE(buffers->vert_buf); + buffers->vert_buf = GWN_vertbuf_create_with_format(&format); + GWN_vertbuf_data_alloc(buffers->vert_buf, totgrid * key->grid_area); + + uint vbo_index_offset = 0; + if (buffers->vert_buf->data) { 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, 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, 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 { - F3TOCHAR3(diffuse_color, vd->color); + F3TOCHAR3(diffuse_color, color_ub); } + GWN_vertbuf_attr_set(buffers->vert_buf, 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 +1351,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, 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 +1365,24 @@ void GPU_pbvh_grid_buffers_update( elems[2], elems[3], diffuse_color, - vd->color); + color_ub); } else { - F3TOCHAR3(diffuse_color, vd->color); + F3TOCHAR3(diffuse_color, color_ub); } + GWN_vertbuf_attr_set(buffers->vert_buf, 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); + gpu_pbvh_batch_init(buffers); } else { - GPU_buffer_free(buffers->vert_buf); - buffers->vert_buf = NULL; + GWN_VERTBUF_DISCARD_SAFE(buffers->vert_buf); } } @@ -1365,57 +1397,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 +1452,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; @@ -1504,39 +1516,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 +1546,7 @@ GPU_PBVH_Buffers *GPU_pbvh_grid_buffers_build( buffers->baseindex[i] = NULL; } } +#endif return buffers; } @@ -1559,32 +1559,45 @@ 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, + const VertexBufferAttrID *vbo_id, + 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, 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, 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, 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 +1656,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}; @@ -1684,13 +1695,17 @@ void GPU_pbvh_bmesh_buffers_update( 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); + GWN_VERTBUF_DISCARD_SAFE(buffers->vert_buf); + /* match 'VertexBufferFormat' */ + Gwn_VertFormat format = {0}; + VertexBufferAttrID vbo_id; + gpu_pbvh_vert_format_init__gwn(&format, &vbo_id); + + buffers->vert_buf = GWN_vertbuf_create_with_format(&format); + GWN_vertbuf_data_alloc(buffers->vert_buf, totvert); /* Fill vertex buffer */ - vert_data = GPU_buffer_lock(buffers->vert_buf, GPU_BINDING_ARRAY); - if (vert_data) { + if (buffers->vert_buf->data) { int v_index = 0; if (buffers->smooth) { @@ -1701,17 +1716,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, &vbo_id, &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, &vbo_id, &v_index, NULL, NULL, + cd_vert_mask_offset, diffuse_color, + show_mask); } maxvert = v_index; @@ -1741,10 +1758,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, &vbo_id, + &v_index, f->no, &fmask, + cd_vert_mask_offset, diffuse_color, + show_mask); } } } @@ -1752,32 +1770,30 @@ 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 { + GWN_VERTBUF_DISCARD_SAFE(buffers->vert_buf); /* 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); + if (buffers->triangles && !buffers->is_index_buf_global) { + GWN_BATCH_DISCARD_SAFE(buffers->triangles); + } 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 +1805,25 @@ 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); - } - buffers->index_buf = NULL; - buffers->is_index_buf_global = false; + + buffers->index_buf = GWN_indexbuf_build(&elb); } } 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) @@ -1849,145 +1844,42 @@ void GPU_pbvh_buffers_draw( GPU_PBVH_Buffers *buffers, DMSetMaterial setMaterial, bool wireframe, 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)); - } + UNUSED_VARS(wireframe, fast, setMaterial); + bool do_fast = fast && buffers->triangles_fast; + Gwn_Batch *triangles = do_fast ? buffers->triangles_fast : buffers->triangles; - 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); + if (triangles) { - 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); - } + /* Simple Shader: use when drawing without the draw-manager (old 2.7x viewport) */ + if (triangles->interface == NULL) { + GPUBuiltinShader shader_id = + buffers->smooth ? GPU_SHADER_SIMPLE_LIGHTING_SMOOTH_COLOR : GPU_SHADER_SIMPLE_LIGHTING_FLAT_COLOR; + GPUShader *shader = GPU_shader_get_builtin_shader(shader_id); - if (wireframe) - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + GWN_batch_program_set( + triangles, + GPU_shader_get_program(shader), GPU_shader_get_interface(shader)); - 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); + static float light[3] = {-0.3f, 0.5f, 1.0f}; + static float alpha = 1.0f; + static float world_light = 1.0f; - glDisableClientState(GL_VERTEX_ARRAY); - if (!wireframe) { - glDisableClientState(GL_NORMAL_ARRAY); - glDisableClientState(GL_COLOR_ARRAY); - } + GPU_shader_uniform_vector(shader, GPU_shader_get_uniform(shader, "light"), 3, 1, light); + GPU_shader_uniform_vector(shader, GPU_shader_get_uniform(shader, "alpha"), 1, 1, &alpha); + GPU_shader_uniform_vector(shader, GPU_shader_get_uniform(shader, "global"), 1, 1, &world_light); - if (bound_options_new & ~bound_options_old) { - GPU_basic_shader_bind(bound_options_old); } + GWN_batch_draw(triangles); } } -bool GPU_pbvh_buffers_diffuse_changed( - GPU_PBVH_Buffers *buffers, GSet *bm_faces, bool show_diffuse_color) +Gwn_Batch *GPU_pbvh_buffers_batch_get(GPU_PBVH_Buffers *buffers, bool fast) +{ + 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) { float diffuse_color[4]; bool use_matcaps = GPU_material_use_matcaps_get(); @@ -2038,16 +1930,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 +1956,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 +1965,57 @@ 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]); -void GPU_pbvh_BB_draw_end(void) -{ - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); - glPopAttrib(); + /* 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(); } diff --git a/source/blender/gpu/intern/gpu_codegen.c b/source/blender/gpu/intern/gpu_codegen.c index b5512aa108d..ece78d4a5cf 100644 --- a/source/blender/gpu/intern/gpu_codegen.c +++ b/source/blender/gpu/intern/gpu_codegen.c @@ -36,6 +36,7 @@ #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_utildefines.h" @@ -47,6 +48,7 @@ #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 */ @@ -88,7 +90,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 +174,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 +190,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 +359,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 +423,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 +517,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 +546,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 +564,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 +606,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 +647,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 +680,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 +728,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, bool use_new_shading) { DynStr *ds = BLI_dynstr_new(); char *code; @@ -677,17 +749,47 @@ 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_NORMAL) - BLI_dynstr_append(ds, "\tvec3 facingnormal = gl_FrontFacing? varnormal: -varnormal;\n"); + if (use_new_shading) { + 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? viewNormal: -viewNormal;\n"); + if (builtins & GPU_VIEW_POSITION) + BLI_dynstr_append(ds, "\tvec3 viewposition = viewPosition;\n"); + } + else { + if (builtins & GPU_VIEW_MATRIX) + BLI_dynstr_append(ds, "\tmat4 viewmat = unfviewmat;\n"); + if (builtins & GPU_CAMERA_TEXCO_FACTORS) + BLI_dynstr_append(ds, "\tvec4 camtexfac = unfcameratexfactors;\n"); + if (builtins & GPU_OBJECT_MATRIX) + BLI_dynstr_append(ds, "\tmat4 objmat = unfobmat;\n"); + if (builtins & GPU_INVERSE_OBJECT_MATRIX) + BLI_dynstr_append(ds, "\tmat4 objinv = unfinvobmat;\n"); + if (builtins & GPU_INVERSE_VIEW_MATRIX) + BLI_dynstr_append(ds, "\tmat4 viewinv = unfinvviewmat;\n"); + if (builtins & GPU_VIEW_NORMAL) + BLI_dynstr_append(ds, "\tvec3 facingnormal = gl_FrontFacing? varnormal: -varnormal;\n"); + if (builtins & GPU_VIEW_POSITION) + BLI_dynstr_append(ds, "\tvec3 viewposition = varposition;\n"); + } /* Calculate tangent space. */ #ifdef WITH_OPENSUBDIV @@ -722,6 +824,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,6 +846,95 @@ static char *code_generate_fragment(ListBase *nodes, GPUOutput *output) return code; } +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_new(ListBase *nodes, const char *vert_code, bool use_geom) +{ + DynStr *ds = BLI_dynstr_new(); + GPUNode *node; + GPUInput *input; + char *code; + + 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) { + /* 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"); + } + else if (input->attribname[0] == '\0') { + BLI_dynstr_appendf(ds, "in %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)); + } + else { + unsigned int hash = BLI_ghashutil_strhash_p(input->attribname); + BLI_dynstr_appendf(ds, "in %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); + } + 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"); + + BLI_dynstr_append(ds, "#define ATTRIB\n"); + BLI_dynstr_append(ds, "uniform mat3 NormalMatrix;\n"); + BLI_dynstr_append(ds, "void pass_attrib(in vec3 position) {\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 */ + BLI_dynstr_appendf( + ds, "\tvar%d%s.xyz = normalize(NormalMatrix * att%d.xyz);\n", + input->attribid, use_geom ? "g" : "", input->attribid); + BLI_dynstr_appendf( + ds, "\tvar%d%s.w = att%d.w;\n", + input->attribid, use_geom ? "g" : "", input->attribid); + } + else if (input->attribtype == CD_ORCO) { + BLI_dynstr_appendf(ds, "\tvar%d%s = OrcoTexCoFactors[0] + position * OrcoTexCoFactors[1];\n", + input->attribid, use_geom ? "g" : ""); + } + else { + BLI_dynstr_appendf(ds, "\tvar%d%s = att%d;\n", + input->attribid, use_geom ? "g" : "", input->attribid); + } + } + } + } + + BLI_dynstr_append(ds, "}\n"); + + BLI_dynstr_append(ds, vert_code); + + code = BLI_dynstr_get_cstring(ds); + + BLI_dynstr_free(ds); + +#if 0 + if (G.debug & G_DEBUG) printf("%s\n", code); +#endif + + return code; +} + static char *code_generate_vertex(ListBase *nodes, const GPUMatType type) { DynStr *ds = BLI_dynstr_new(); @@ -790,7 +992,7 @@ static char *code_generate_vertex(ListBase *nodes, const GPUMatType type) BLI_dynstr_appendf(ds, "#ifndef USE_OPENSUBDIV\n"); #endif BLI_dynstr_appendf( - ds, "\tvar%d.xyz = normalize(gl_NormalMatrix * att%d.xyz);\n", + ds, "\tvar%d.xyz = normalize(NormalMatrix * att%d.xyz);\n", input->attribid, input->attribid); BLI_dynstr_appendf( ds, "\tvar%d.w = att%d.w;\n", @@ -841,6 +1043,51 @@ static char *code_generate_vertex(ListBase *nodes, const GPUMatType type) return code; } +static char *code_generate_geometry_new(ListBase *nodes, const char *geom_code) +{ + DynStr *ds = BLI_dynstr_new(); + GPUNode *node; + GPUInput *input; + char *code; + + /* 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, geom_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) { + 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); + } + } + } + + /* 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"); + + code = BLI_dynstr_get_cstring(ds); + BLI_dynstr_free(ds); + + return code; +} + static char *code_generate_geometry(ListBase *nodes, bool use_opensubdiv) { #ifdef WITH_OPENSUBDIV @@ -928,6 +1175,67 @@ GPUShader *GPU_pass_shader(GPUPass *pass) return pass->shader; } +static void gpu_nodes_extract_dynamic_inputs_new(GPUPass *pass, ListBase *nodes) +{ + GPUShader *shader = pass->shader; + GPUNode *node; + GPUInput *next, *input; + ListBase *inputs = &pass->inputs; + int extract, z; + + memset(inputs, 0, sizeof(*inputs)); + + if (!shader) + return; + + GPU_shader_bind(shader); + + for (node = nodes->first; node; node = node->next) { + z = 0; + for (input = node->inputs.first; input; input = next, z++) { + next = input->next; + + /* attributes don't need to be bound, they already have + * an id that the drawing functions will use */ + if (input->source == GPU_SOURCE_ATTRIB) { + continue; + } + + if (input->source == GPU_SOURCE_BUILTIN || + input->source == GPU_SOURCE_OPENGL_BUILTIN) + { + continue; + } + + if (input->ima || input->tex || input->prv) + BLI_snprintf(input->shadername, sizeof(input->shadername), "samp%d", input->texid); + else + BLI_snprintf(input->shadername, sizeof(input->shadername), "unf%d", input->id); + + /* pass non-dynamic uniforms to opengl */ + extract = 0; + + if (input->ima || input->tex || input->prv) { + if (input->bindtex) + extract = 1; + } + else if (input->dynamicvec) + extract = 1; + + if (extract) + input->shaderloc = GPU_shader_get_uniform(shader, input->shadername); + + /* extract nodes */ + if (extract) { + BLI_remlink(&node->inputs, input); + BLI_addtail(inputs, input); + } + } + } + + GPU_shader_unbind(); +} + static void gpu_nodes_extract_dynamic_inputs(GPUPass *pass, ListBase *nodes) { GPUShader *shader = pass->shader; @@ -1135,7 +1443,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 +1502,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, link->ptr1, NULL); input->textarget = GL_TEXTURE_2D; MEM_freeN(link->ptr1); @@ -1235,6 +1543,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 +1560,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) { - GPUNodeLink *link; + 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) +{ + 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); } @@ -1387,7 +1780,14 @@ 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 +1816,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 +1941,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 +1960,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 +1991,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 +2001,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 +2027,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) @@ -1647,6 +2071,78 @@ static void gpu_nodes_prune(ListBase *nodes, GPUNodeLink *outlink) } } +GPUPass *GPU_generate_pass_new( + struct GPUMaterial *material, + ListBase *nodes, struct GPUNodeLink *frag_outlink, + GPUVertexAttribs *attribs, + const char *vert_code, const char *geom_code, + const char *frag_lib, const char *defines) +{ + GPUShader *shader; + GPUPass *pass; + char *vertexgen, *fragmentgen, *tmp; + char *vertexcode, *geometrycode, *fragmentcode; + + /* prune unused nodes */ + gpu_nodes_prune(nodes, frag_outlink); + + gpu_nodes_get_vertex_attributes(nodes, attribs); + + /* generate code and compile with opengl */ + fragmentgen = code_generate_fragment(material, nodes, frag_outlink->output, true); + vertexgen = code_generate_vertex_new(nodes, vert_code, (geom_code != NULL)); + + tmp = BLI_strdupcat(frag_lib, glsl_material_library); + fragmentcode = BLI_strdupcat(tmp, fragmentgen); + vertexcode = BLI_strdup(vertexgen); + + if (geom_code) { + geometrycode = code_generate_geometry_new(nodes, geom_code); + } + else { + geometrycode = NULL; + } + + shader = GPU_shader_create(vertexcode, + fragmentcode, + geometrycode, + NULL, + defines); + + MEM_freeN(tmp); + + /* failed? */ + if (!shader) { + if (fragmentcode) + MEM_freeN(fragmentcode); + if (vertexcode) + MEM_freeN(vertexcode); + if (geometrycode) + MEM_freeN(geometrycode); + MEM_freeN(fragmentgen); + MEM_freeN(vertexgen); + gpu_nodes_free(nodes); + return NULL; + } + + /* create pass */ + pass = MEM_callocN(sizeof(GPUPass), "GPUPass"); + pass->shader = shader; + pass->fragmentcode = fragmentcode; + pass->geometrycode = geometrycode; + pass->vertexcode = vertexcode; + pass->libcode = glsl_material_library; + + /* extract dynamic inputs and throw away nodes */ + gpu_nodes_extract_dynamic_inputs_new(pass, nodes); + gpu_nodes_free(nodes); + + MEM_freeN(fragmentgen); + MEM_freeN(vertexgen); + + return pass; +} + GPUPass *GPU_generate_pass( ListBase *nodes, GPUNodeLink *outlink, GPUVertexAttribs *attribs, int *builtins, @@ -1672,7 +2168,7 @@ GPUPass *GPU_generate_pass( gpu_nodes_get_builtin_flag(nodes, builtins); /* generate code and compile with opengl */ - fragmentcode = code_generate_fragment(nodes, outlink->output); + fragmentcode = code_generate_fragment(NULL, nodes, outlink->output, false); vertexcode = code_generate_vertex(nodes, type); geometrycode = code_generate_geometry(nodes, use_opensubdiv); @@ -1688,9 +2184,6 @@ GPUPass *GPU_generate_pass( geometrycode, glsl_material_library, NULL, - 0, - 0, - 0, flags); /* failed? */ @@ -1708,7 +2201,6 @@ GPUPass *GPU_generate_pass( /* create pass */ pass = MEM_callocN(sizeof(GPUPass), "GPUPass"); - pass->output = outlink->output; pass->shader = shader; pass->fragmentcode = fragmentcode; pass->geometrycode = geometrycode; diff --git a/source/blender/gpu/intern/gpu_codegen.h b/source/blender/gpu/intern/gpu_codegen.h index 7af17f9122d..14e07a6e012 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,10 +157,7 @@ typedef struct GPUInput { } GPUInput; struct GPUPass { - struct GPUPass *next, *prev; - ListBase inputs; - struct GPUOutput *output; struct GPUShader *shader; char *fragmentcode; char *geometrycode; @@ -170,11 +168,18 @@ struct GPUPass { 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( + struct GPUMaterial *material, + ListBase *nodes, struct GPUNodeLink *frag_outlink, + struct GPUVertexAttribs *attribs, + const char *vert_code, const char *geom_code, + const char *frag_lib, const char *defines); +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); struct GPUShader *GPU_pass_shader(GPUPass *pass); diff --git a/source/blender/gpu/intern/gpu_compositing.c b/source/blender/gpu/intern/gpu_compositing.c index 2f2a16f9e1d..ca81ca72a32 100644 --- a/source/blender/gpu/intern/gpu_compositing.c +++ b/source/blender/gpu/intern/gpu_compositing.c @@ -42,11 +42,13 @@ #include "DNA_gpu_types.h" #include "GPU_compositing.h" +#include "GPU_draw.h" #include "GPU_extensions.h" #include "GPU_framebuffer.h" #include "GPU_glew.h" #include "GPU_shader.h" #include "GPU_texture.h" +#include "GPU_batch.h" #include "MEM_guardedalloc.h" @@ -193,7 +195,8 @@ struct GPUFX { /* we have a stencil, restore the previous state */ bool restore_stencil; - unsigned int vbuffer; + Gwn_Batch *quad_batch; + Gwn_Batch *point_batch; }; #if 0 @@ -225,7 +228,13 @@ static GPUTexture * create_concentric_sample_texture(int side) } } - tex = GPU_texture_create_1D_procedural(side * side, texels, NULL); + tex = GPU_texture_create_1D_custom(side * side, 2, GPU_RG16F, (float *)texels, NULL); + + /* Set parameters */ + GPU_texture_bind(tex, 0); + GPU_texture_filter_mode(tex, false); + GPU_texture_unbind(tex); + MEM_freeN(texels); return tex; } @@ -247,7 +256,13 @@ static GPUTexture *create_spiral_sample_texture(int numsaples) texels[i][1] = r * sinf(phi); } - tex = GPU_texture_create_1D_procedural(numsaples, (float *)texels, NULL); + tex = GPU_texture_create_1D_custom(numsaples, 2, GPU_RG16F, (float *)texels, NULL); + + /* Set parameters */ + GPU_texture_bind(tex, 0); + GPU_texture_filter_mode(tex, false); + GPU_texture_unbind(tex); + MEM_freeN(texels); return tex; } @@ -257,12 +272,32 @@ 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); + /* Quad buffer */ + static Gwn_VertFormat format = {0}; + static unsigned int pos, uvs; + if (format.attrib_ct == 0) { + pos = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT); + uvs = GWN_vertformat_attr_add(&format, "uvs", GWN_COMP_F32, 2, GWN_FETCH_FLOAT); + } + Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&format); + GWN_vertbuf_data_alloc(vbo, 4); + for (int i = 0; i < 4; ++i) { + GWN_vertbuf_attr_set(vbo, pos, i, fullscreencos[i]); + GWN_vertbuf_attr_set(vbo, uvs, i, fullscreenuvs[i]); + } + fx->quad_batch = GWN_batch_create_ex(GWN_PRIM_TRI_STRIP, vbo, NULL, GWN_BATCH_OWNS_VBO); + + /* Point Buffer */ + static Gwn_VertFormat format_point = {0}; + static unsigned int dummy_attrib; + if (format_point.attrib_ct == 0) { + dummy_attrib = GWN_vertformat_attr_add(&format_point, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT); + } + float dummy[2] = {0.0f, 0.0f}; + Gwn_VertBuf *vbo_point = GWN_vertbuf_create_with_format(&format_point); + GWN_vertbuf_data_alloc(vbo_point, 1); + GWN_vertbuf_attr_set(vbo_point, dummy_attrib, 0, &dummy); + fx->point_batch = GWN_batch_create_ex(GWN_PRIM_POINTS, vbo_point, NULL, GWN_BATCH_OWNS_VBO); return fx; } @@ -352,12 +387,14 @@ static void cleanup_fx_gl_data(GPUFX *fx, bool do_fbo) void GPU_fx_compositor_destroy(GPUFX *fx) { cleanup_fx_gl_data(fx, true); - glDeleteBuffers(1, &fx->vbuffer); + GWN_batch_discard(fx->quad_batch); + GWN_batch_discard(fx->point_batch); MEM_freeN(fx); } static GPUTexture * create_jitter_texture(void) { + GPUTexture *tex; float jitter[64 * 64][2]; int i; @@ -367,7 +404,15 @@ static GPUTexture * create_jitter_texture(void) normalize_v2(jitter[i]); } - return GPU_texture_create_2D_procedural(64, 64, &jitter[0][0], true, NULL); + tex = GPU_texture_create_2D_custom(64, 64, 2, GPU_RG16F, &jitter[0][0], NULL); + + /* Set parameters */ + GPU_texture_bind(tex, 0); + GPU_texture_filter_mode(tex, false); + GPU_texture_wrap_mode(tex, true); + GPU_texture_unbind(tex); + + return tex; } @@ -382,9 +427,6 @@ bool GPU_fx_compositor_initialize_passes( fx->effects = 0; - if (!GLEW_EXT_framebuffer_object) - return false; - if (!fx_settings) { cleanup_fx_gl_data(fx, true); return false; @@ -436,7 +478,7 @@ bool GPU_fx_compositor_initialize_passes( 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))) { + if (!(fx->color_buffer = GPU_texture_create_2D(w, h, NULL, err_out))) { printf(".256%s\n", err_out); cleanup_fx_gl_data(fx, true); return false; @@ -472,8 +514,7 @@ bool GPU_fx_compositor_initialize_passes( /* 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(); + bool dof_high_quality = (fx_settings->dof->high_quality != 0); /* cleanup buffers if quality setting has changed (no need to keep more buffers around than necessary ) */ if (dof_high_quality != fx->dof_high_quality) @@ -488,38 +529,42 @@ bool GPU_fx_compositor_initialize_passes( { if (!(fx->dof_half_downsampled_near = GPU_texture_create_2D( - fx->dof_downsampled_w, fx->dof_downsampled_h, NULL, GPU_HDR_NONE, err_out))) + fx->dof_downsampled_w, fx->dof_downsampled_h, NULL, err_out))) { printf("%.256s\n", err_out); cleanup_fx_gl_data(fx, true); return false; } if (!(fx->dof_half_downsampled_far = GPU_texture_create_2D( - fx->dof_downsampled_w, fx->dof_downsampled_h, NULL, GPU_HDR_NONE, err_out))) + fx->dof_downsampled_w, fx->dof_downsampled_h, NULL, err_out))) { printf("%.256s\n", err_out); cleanup_fx_gl_data(fx, true); return false; } - if (!(fx->dof_nearfar_coc = GPU_texture_create_2D_procedural( - fx->dof_downsampled_w, fx->dof_downsampled_h, NULL, false, err_out))) + + if (!(fx->dof_nearfar_coc = GPU_texture_create_2D_custom( + fx->dof_downsampled_w, fx->dof_downsampled_h, 2, GPU_RG16F, NULL, err_out))) { printf("%.256s\n", err_out); cleanup_fx_gl_data(fx, true); return false; } + GPU_texture_bind(fx->dof_nearfar_coc, 0); + GPU_texture_filter_mode(fx->dof_nearfar_coc, false); + GPU_texture_wrap_mode(fx->dof_nearfar_coc, false); + GPU_texture_unbind(fx->dof_nearfar_coc); - - if (!(fx->dof_near_blur = GPU_texture_create_2D( - fx->dof_downsampled_w, fx->dof_downsampled_h, NULL, GPU_HDR_HALF_FLOAT, err_out))) + if (!(fx->dof_near_blur = GPU_texture_create_2D_custom( + fx->dof_downsampled_w, fx->dof_downsampled_h, 4, GPU_RGBA16F, NULL, err_out))) { printf("%.256s\n", err_out); cleanup_fx_gl_data(fx, true); return false; } - if (!(fx->dof_far_blur = GPU_texture_create_2D( - fx->dof_downsampled_w, fx->dof_downsampled_h, NULL, GPU_HDR_HALF_FLOAT, err_out))) + if (!(fx->dof_far_blur = GPU_texture_create_2D_custom( + fx->dof_downsampled_w, fx->dof_downsampled_h, 4, GPU_RGBA16F, NULL, err_out))) { printf("%.256s\n", err_out); cleanup_fx_gl_data(fx, true); @@ -534,21 +579,21 @@ bool GPU_fx_compositor_initialize_passes( 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))) + fx->dof_downsampled_w, fx->dof_downsampled_h, NULL, err_out))) { printf("%.256s\n", err_out); cleanup_fx_gl_data(fx, true); return false; } if (!(fx->dof_near_coc_blurred_buffer = GPU_texture_create_2D( - fx->dof_downsampled_w, fx->dof_downsampled_h, NULL, GPU_HDR_NONE, err_out))) + fx->dof_downsampled_w, fx->dof_downsampled_h, NULL, err_out))) { printf("%.256s\n", err_out); cleanup_fx_gl_data(fx, true); return false; } if (!(fx->dof_near_coc_final_buffer = GPU_texture_create_2D( - fx->dof_downsampled_w, fx->dof_downsampled_h, NULL, GPU_HDR_NONE, err_out))) + fx->dof_downsampled_w, fx->dof_downsampled_h, NULL, err_out))) { printf("%.256s\n", err_out); cleanup_fx_gl_data(fx, true); @@ -567,7 +612,7 @@ bool GPU_fx_compositor_initialize_passes( /* 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))) { + if (!(fx->color_buffer_sec = GPU_texture_create_2D(w, h, NULL, err_out))) { printf(".256%s\n", err_out); cleanup_fx_gl_data(fx, true); return false; @@ -585,11 +630,8 @@ bool GPU_fx_compositor_initialize_passes( /* 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); + GPU_framebuffer_texture_attach(fx->gbuffer, fx->depth_buffer, 0, 0); + GPU_framebuffer_texture_attach(fx->gbuffer, fx->color_buffer, 0, 0); if (!GPU_framebuffer_check_valid(fx->gbuffer, err_out)) printf("%.256s\n", err_out); @@ -600,7 +642,7 @@ bool GPU_fx_compositor_initialize_passes( 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); + gpuPushAttrib(GPU_SCISSOR_BIT); glEnable(GL_SCISSOR_TEST); glScissor(scissor_rect->xmin - rect->xmin, scissor_rect->ymin - rect->ymin, w_sc, h_sc); @@ -634,7 +676,7 @@ static void gpu_fx_bind_render_target(int *passes_left, GPUFX *fx, struct GPUOff } else { /* bind the ping buffer to the color buffer */ - GPU_framebuffer_texture_attach(fx->gbuffer, target, 0, NULL); + GPU_framebuffer_texture_attach(fx->gbuffer, target, 0, 0); } } @@ -663,8 +705,7 @@ void GPU_fx_compositor_setup_XRay_pass(GPUFX *fx, bool do_xray) 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); + GPU_framebuffer_texture_attach(fx->gbuffer, fx->depth_buffer_xray, 0, 0); } @@ -674,39 +715,35 @@ void GPU_fx_compositor_XRay_resolve(GPUFX *fx) GPU_framebuffer_texture_detach(fx->depth_buffer_xray); /* attach regular framebuffer */ - GPU_framebuffer_texture_attach(fx->gbuffer, fx->depth_buffer, 0, NULL); + GPU_framebuffer_texture_attach(fx->gbuffer, fx->depth_buffer, 0, 0); /* full screen quad where we will always write to depth buffer */ - glPushAttrib(GL_DEPTH_BUFFER_BIT | GL_SCISSOR_BIT); + gpuPushAttrib(GPU_DEPTH_BUFFER_BIT | GPU_SCISSOR_BIT); glDepthFunc(GL_ALWAYS); /* disable scissor from sculpt if any */ glDisable(GL_SCISSOR_TEST); /* disable writing to color buffer, it's depth only pass */ glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); - /* 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); + GPUDepthResolveInterface *interface = GPU_fx_shader_get_interface(depth_resolve_shader); - GPU_shader_bind(depth_resolve_shader); + /* set up quad buffer */ + GWN_batch_program_set(fx->quad_batch, GPU_shader_get_program(depth_resolve_shader), GPU_shader_get_interface(depth_resolve_shader)); GPU_texture_bind(fx->depth_buffer_xray, 0); - GPU_texture_filter_mode(fx->depth_buffer_xray, false, true); + GPU_texture_compare_mode(fx->depth_buffer_xray, false); + GPU_texture_filter_mode(fx->depth_buffer_xray, true); GPU_shader_uniform_texture(depth_resolve_shader, interface->depth_uniform, fx->depth_buffer_xray); /* draw */ - glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + GWN_batch_draw(fx->quad_batch); /* disable bindings */ - GPU_texture_filter_mode(fx->depth_buffer_xray, true, false); + GPU_texture_compare_mode(fx->depth_buffer_xray, true); + GPU_texture_filter_mode(fx->depth_buffer_xray, false); GPU_texture_unbind(fx->depth_buffer_xray); GPU_shader_unbind(); @@ -714,11 +751,7 @@ void GPU_fx_compositor_XRay_resolve(GPUFX *fx) glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); - glBindBuffer(GL_ARRAY_BUFFER, 0); - glDisableClientState(GL_VERTEX_ARRAY); - glDisableClientState(GL_TEXTURE_COORD_ARRAY); - - glPopAttrib(); + gpuPopAttrib(); } @@ -748,19 +781,13 @@ bool GPU_fx_do_composite_pass( GPU_framebuffer_texture_detach(fx->color_buffer); GPU_framebuffer_texture_detach(fx->depth_buffer); - if (fx->restore_stencil) - glPopAttrib(); + if (fx->restore_stencil) { + gpuPopAttrib(); + } 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 */ @@ -788,8 +815,6 @@ bool GPU_fx_do_composite_pass( 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 */ @@ -810,9 +835,9 @@ bool GPU_fx_do_composite_pass( ssao_params[3] = (passes_left == 1 && !ofs) ? dfdyfac[0] : dfdyfac[1]; - GPUSSAOShaderInterface *interface = GPU_shader_get_interface(ssao_shader); + GPUSSAOShaderInterface *interface = GPU_fx_shader_get_interface(ssao_shader); - GPU_shader_bind(ssao_shader); + GWN_batch_program_set(fx->quad_batch, GPU_shader_get_program(ssao_shader), GPU_shader_get_interface(ssao_shader)); GPU_shader_uniform_vector(ssao_shader, interface->ssao_uniform, 4, 1, ssao_params); GPU_shader_uniform_vector(ssao_shader, interface->ssao_color_uniform, 4, 1, fx_ssao->color); @@ -823,7 +848,8 @@ bool GPU_fx_do_composite_pass( 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_texture_compare_mode(fx->depth_buffer, false); + GPU_texture_filter_mode(fx->depth_buffer, true); GPU_shader_uniform_texture(ssao_shader, interface->depth_uniform, fx->depth_buffer); GPU_texture_bind(fx->jitter_buffer, numslots++); @@ -835,11 +861,12 @@ bool GPU_fx_do_composite_pass( /* draw */ gpu_fx_bind_render_target(&passes_left, fx, ofs, target); - glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + GWN_batch_draw(fx->quad_batch); /* disable bindings */ GPU_texture_unbind(src); - GPU_texture_filter_mode(fx->depth_buffer, true, false); + GPU_texture_compare_mode(fx->depth_buffer, true); + GPU_texture_filter_mode(fx->depth_buffer, false); GPU_texture_unbind(fx->depth_buffer); GPU_texture_unbind(fx->jitter_buffer); GPU_texture_unbind(fx->ssao_spiral_samples_tex); @@ -892,11 +919,8 @@ bool GPU_fx_do_composite_pass( 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; } @@ -904,9 +928,9 @@ bool GPU_fx_do_composite_pass( { float invrendertargetdim[2] = {1.0f / fx->dof_downsampled_w, 1.0f / fx->dof_downsampled_h}; - GPUDOFHQPassOneInterface *interface = GPU_shader_get_interface(dof_shader_pass1); + GPUDOFHQPassOneInterface *interface = GPU_fx_shader_get_interface(dof_shader_pass1); - GPU_shader_bind(dof_shader_pass1); + GWN_batch_program_set(fx->quad_batch, GPU_shader_get_program(dof_shader_pass1), GPU_shader_get_interface(dof_shader_pass1)); GPU_shader_uniform_vector(dof_shader_pass1, interface->dof_uniform, 4, 1, dof_params); GPU_shader_uniform_vector(dof_shader_pass1, interface->invrendertargetdim_uniform, 2, 1, invrendertargetdim); @@ -915,28 +939,31 @@ bool GPU_fx_do_composite_pass( 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_texture_compare_mode(fx->depth_buffer, false); + GPU_texture_filter_mode(fx->depth_buffer, false); GPU_shader_uniform_texture(dof_shader_pass1, interface->depth_uniform, fx->depth_buffer); GPU_texture_bind(src, numslots++); /* disable filtering for the texture so custom downsample can do the right thing */ - GPU_texture_filter_mode(src, false, false); + GPU_texture_filter_mode(src, false); GPU_shader_uniform_texture(dof_shader_pass2, interface->color_uniform, src); /* target is the downsampled coc buffer */ - GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_half_downsampled_near, 0, 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); + GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_half_downsampled_near, 0, 0); + GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_half_downsampled_far, 1, 0); + GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_nearfar_coc, 2, 0); /* binding takes care of setting the viewport to the downsampled size */ GPU_framebuffer_slots_bind(fx->gbuffer, 0); GPU_framebuffer_check_valid(fx->gbuffer, NULL); - glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + GWN_batch_draw(fx->quad_batch); + /* disable bindings */ - GPU_texture_filter_mode(src, false, true); + GPU_texture_filter_mode(src, true); GPU_texture_unbind(src); - GPU_texture_filter_mode(fx->depth_buffer, true, false); + GPU_texture_compare_mode(fx->depth_buffer, true); + GPU_texture_filter_mode(fx->depth_buffer, false); GPU_texture_unbind(fx->depth_buffer); GPU_framebuffer_texture_detach(fx->dof_half_downsampled_near); @@ -953,24 +980,23 @@ bool GPU_fx_do_composite_pass( 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); + GPUDOFHQPassTwoInterface *interface = GPU_fx_shader_get_interface(dof_shader_pass2); - GPU_shader_bind(dof_shader_pass2); + GWN_batch_program_set(fx->point_batch, GPU_shader_get_program(dof_shader_pass2), GPU_shader_get_interface(dof_shader_pass2)); + + GPU_texture_bind(fx->dof_nearfar_coc, numslots++); + GPU_texture_bind(fx->dof_half_downsampled_far, numslots++); + GPU_texture_bind(fx->dof_half_downsampled_near, numslots++); GPU_shader_uniform_vector(dof_shader_pass2, interface->dof_uniform, 4, 1, dof_params); GPU_shader_uniform_vector_int(dof_shader_pass2, interface->rendertargetdim_uniform, 2, 1, rendertargetdim); GPU_shader_uniform_vector(dof_shader_pass2, interface->select_uniform, 2, 1, selection); - - GPU_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); + GPU_texture_filter_mode(fx->dof_half_downsampled_far, false); /* target is the downsampled coc buffer */ - GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_far_blur, 0, NULL); + GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_far_blur, 0, 0); GPU_texture_bind_as_framebuffer(fx->dof_far_blur); glDisable(GL_DEPTH_TEST); @@ -981,27 +1007,27 @@ bool GPU_fx_do_composite_pass( 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); + // GWN_batch_draw_stupid_instanced(fx->point_batch, 0, fx->dof_downsampled_w * fx->dof_downsampled_h, 0, 0, 0, NULL, NULL); GPU_texture_unbind(fx->dof_half_downsampled_far); GPU_framebuffer_texture_detach(fx->dof_far_blur); - 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_shader_uniform_texture(dof_shader_pass2, interface->color_uniform, fx->dof_half_downsampled_near); + GPU_texture_filter_mode(fx->dof_half_downsampled_near, false); - GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_near_blur, 0, NULL); + GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_near_blur, 0, 0); /* have to clear the buffer unfortunately */ glClear(GL_COLOR_BUFFER_BIT); /* the draw call we all waited for, draw a point per pixel, scaled per circle of confusion */ - glDrawArraysInstancedARB(GL_POINTS, 0, 1, fx->dof_downsampled_w * fx->dof_downsampled_h); + // GWN_batch_draw_stupid_instanced(fx->point_batch, 0, fx->dof_downsampled_w * fx->dof_downsampled_h, 0, 0, 0, NULL, NULL); + GWN_batch_program_use_end(fx->point_batch); /* disable bindings */ - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); glDisable(GL_BLEND); GPU_framebuffer_texture_detach(fx->dof_near_blur); @@ -1010,15 +1036,16 @@ bool GPU_fx_do_composite_pass( GPU_texture_unbind(fx->dof_nearfar_coc); GPU_framebuffer_texture_unbind(fx->gbuffer, fx->dof_far_blur); + numslots = 0; } /* third pass, accumulate the near/far blur fields */ { float invrendertargetdim[2] = {1.0f / fx->dof_downsampled_w, 1.0f / fx->dof_downsampled_h}; - GPUDOFHQPassThreeInterface *interface = GPU_shader_get_interface(dof_shader_pass3); + GPUDOFHQPassThreeInterface *interface = GPU_fx_shader_get_interface(dof_shader_pass3); - GPU_shader_bind(dof_shader_pass3); + GWN_batch_program_set(fx->quad_batch, GPU_shader_get_program(dof_shader_pass3), GPU_shader_get_interface(dof_shader_pass3)); GPU_shader_uniform_vector(dof_shader_pass3, interface->dof_uniform, 4, 1, dof_params); @@ -1027,14 +1054,15 @@ bool GPU_fx_do_composite_pass( 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_filter_mode(fx->dof_near_blur, true); GPU_texture_bind(fx->dof_far_blur, numslots++); GPU_shader_uniform_texture(dof_shader_pass3, interface->far_uniform, fx->dof_far_blur); - GPU_texture_filter_mode(fx->dof_far_blur, false, true); + GPU_texture_filter_mode(fx->dof_far_blur, true); GPU_texture_bind(fx->depth_buffer, numslots++); - GPU_texture_filter_mode(fx->depth_buffer, false, false); + GPU_texture_compare_mode(fx->depth_buffer, false); + GPU_texture_filter_mode(fx->depth_buffer, false); GPU_shader_uniform_texture(dof_shader_pass3, interface->depth_uniform, fx->depth_buffer); GPU_texture_bind(src, numslots++); @@ -1043,13 +1071,13 @@ bool GPU_fx_do_composite_pass( /* 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); + GWN_batch_draw(fx->quad_batch); /* disable bindings */ GPU_texture_unbind(fx->dof_near_blur); GPU_texture_unbind(fx->dof_far_blur); GPU_texture_unbind(src); - GPU_texture_filter_mode(fx->depth_buffer, true, false); + GPU_texture_compare_mode(fx->depth_buffer, true); GPU_texture_unbind(fx->depth_buffer); /* may not be attached, in that case this just returns */ @@ -1085,11 +1113,8 @@ bool GPU_fx_do_composite_pass( 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; } @@ -1097,9 +1122,9 @@ bool GPU_fx_do_composite_pass( { float invrendertargetdim[2] = {1.0f / fx->gbuffer_dim[0], 1.0f / fx->gbuffer_dim[1]}; - GPUDOFPassOneInterface *interface = GPU_shader_get_interface(dof_shader_pass1); + GPUDOFPassOneInterface *interface = GPU_fx_shader_get_interface(dof_shader_pass1); - GPU_shader_bind(dof_shader_pass1); + GWN_batch_program_set(fx->quad_batch, GPU_shader_get_program(dof_shader_pass1), GPU_shader_get_interface(dof_shader_pass1)); GPU_shader_uniform_vector(dof_shader_pass1, interface->dof_uniform, 4, 1, dof_params); GPU_shader_uniform_vector(dof_shader_pass1, interface->invrendertargetdim_uniform, 2, 1, invrendertargetdim); @@ -1109,18 +1134,20 @@ bool GPU_fx_do_composite_pass( 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_texture_compare_mode(fx->depth_buffer, false); + GPU_texture_filter_mode(fx->depth_buffer, true); GPU_shader_uniform_texture(dof_shader_pass1, interface->depth_uniform, fx->depth_buffer); /* target is the downsampled coc buffer */ - GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_near_coc_buffer, 0, NULL); + GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_near_coc_buffer, 0, 0); /* binding takes care of setting the viewport to the downsampled size */ GPU_texture_bind_as_framebuffer(fx->dof_near_coc_buffer); - glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + GWN_batch_draw(fx->quad_batch); /* disable bindings */ GPU_texture_unbind(src); - GPU_texture_filter_mode(fx->depth_buffer, true, false); + GPU_texture_compare_mode(fx->depth_buffer, true); + GPU_texture_filter_mode(fx->depth_buffer, false); GPU_texture_unbind(fx->depth_buffer); GPU_framebuffer_texture_detach(fx->dof_near_coc_buffer); @@ -1134,32 +1161,37 @@ bool GPU_fx_do_composite_pass( float tmp = invrendertargetdim[0]; invrendertargetdim[0] = 0.0f; - GPUDOFPassTwoInterface *interface = GPU_shader_get_interface(dof_shader_pass2); + GPUDOFPassTwoInterface *interface = GPU_fx_shader_get_interface(dof_shader_pass2); dof_params[2] = GPU_texture_width(fx->dof_near_coc_blurred_buffer) / (scale_camera * fx_dof->sensor); /* Blurring vertically */ - GPU_shader_bind(dof_shader_pass2); + GWN_batch_program_set(fx->quad_batch, GPU_shader_get_program(dof_shader_pass2), GPU_shader_get_interface(dof_shader_pass2)); GPU_shader_uniform_vector(dof_shader_pass2, interface->dof_uniform, 4, 1, dof_params); GPU_shader_uniform_vector(dof_shader_pass2, interface->invrendertargetdim_uniform, 2, 1, invrendertargetdim); GPU_shader_uniform_vector(dof_shader_pass2, interface->viewvecs_uniform, 4, 3, viewvecs[0]); GPU_texture_bind(fx->depth_buffer, numslots++); - GPU_texture_filter_mode(fx->depth_buffer, false, true); + GPU_texture_compare_mode(fx->depth_buffer, false); + GPU_texture_filter_mode(fx->depth_buffer, true); GPU_shader_uniform_texture(dof_shader_pass2, interface->depth_uniform, fx->depth_buffer); GPU_texture_bind(fx->dof_near_coc_buffer, numslots++); GPU_shader_uniform_texture(dof_shader_pass2, interface->color_uniform, fx->dof_near_coc_buffer); /* use final buffer as a temp here */ - GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_near_coc_final_buffer, 0, NULL); + GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_near_coc_final_buffer, 0, 0); /* Drawing quad */ - glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + GWN_batch_draw(fx->quad_batch); + + /* Rebind Shader */ + GWN_batch_program_set(fx->quad_batch, GPU_shader_get_program(dof_shader_pass2), GPU_shader_get_interface(dof_shader_pass2)); /* *unbind/detach */ GPU_texture_unbind(fx->dof_near_coc_buffer); + GPU_framebuffer_texture_detach(fx->dof_near_coc_final_buffer); /* Blurring horizontally */ @@ -1170,11 +1202,13 @@ bool GPU_fx_do_composite_pass( 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); + GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_near_coc_blurred_buffer, 0, 0); + + GWN_batch_draw(fx->quad_batch); /* *unbind/detach */ - GPU_texture_filter_mode(fx->depth_buffer, true, false); + GPU_texture_compare_mode(fx->depth_buffer, true); + GPU_texture_filter_mode(fx->depth_buffer, false); GPU_texture_unbind(fx->depth_buffer); GPU_texture_unbind(fx->dof_near_coc_final_buffer); @@ -1187,9 +1221,9 @@ bool GPU_fx_do_composite_pass( /* third pass, calculate near coc */ { - GPUDOFPassThreeInterface *interface = GPU_shader_get_interface(dof_shader_pass3); + GPUDOFPassThreeInterface *interface = GPU_fx_shader_get_interface(dof_shader_pass3); - GPU_shader_bind(dof_shader_pass3); + GWN_batch_program_set(fx->quad_batch, GPU_shader_get_program(dof_shader_pass3), GPU_shader_get_interface(dof_shader_pass3)); GPU_texture_bind(fx->dof_near_coc_buffer, numslots++); GPU_shader_uniform_texture(dof_shader_pass3, interface->near_coc_downsampled, fx->dof_near_coc_buffer); @@ -1197,9 +1231,9 @@ bool GPU_fx_do_composite_pass( 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); + GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_near_coc_final_buffer, 0, 0); - glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + GWN_batch_draw(fx->quad_batch); /* disable bindings */ GPU_texture_unbind(fx->dof_near_coc_buffer); GPU_texture_unbind(fx->dof_near_coc_blurred_buffer); @@ -1215,17 +1249,17 @@ bool GPU_fx_do_composite_pass( 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); + GPUDOFPassFourInterface *interface = GPU_fx_shader_get_interface(dof_shader_pass4); - GPU_shader_bind(dof_shader_pass4); + GWN_batch_program_set(fx->quad_batch, GPU_shader_get_program(dof_shader_pass4), GPU_shader_get_interface(dof_shader_pass4)); GPU_texture_bind(fx->dof_near_coc_final_buffer, numslots++); GPU_shader_uniform_texture(dof_shader_pass4, interface->near_coc_downsampled, fx->dof_near_coc_final_buffer); GPU_shader_uniform_vector(dof_shader_pass4, interface->invrendertargetdim_uniform, 2, 1, invrendertargetdim); - GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_near_coc_buffer, 0, NULL); + GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_near_coc_buffer, 0, 0); - glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + GWN_batch_draw(fx->quad_batch); /* disable bindings */ GPU_texture_unbind(fx->dof_near_coc_final_buffer); @@ -1240,9 +1274,9 @@ bool GPU_fx_do_composite_pass( { float invrendertargetdim[2] = {1.0f / fx->gbuffer_dim[0], 1.0f / fx->gbuffer_dim[1]}; - GPUDOFPassFiveInterface *interface = GPU_shader_get_interface(dof_shader_pass5); + GPUDOFPassFiveInterface *interface = GPU_fx_shader_get_interface(dof_shader_pass5); - GPU_shader_bind(dof_shader_pass5); + GWN_batch_program_set(fx->quad_batch, GPU_shader_get_program(dof_shader_pass5), GPU_shader_get_interface(dof_shader_pass5)); GPU_shader_uniform_vector(dof_shader_pass5, interface->dof_uniform, 4, 1, dof_params); GPU_shader_uniform_vector(dof_shader_pass5, interface->invrendertargetdim_uniform, 2, 1, invrendertargetdim); @@ -1258,18 +1292,20 @@ bool GPU_fx_do_composite_pass( 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_texture_compare_mode(fx->depth_buffer, false); + GPU_texture_filter_mode(fx->depth_buffer, true); GPU_shader_uniform_texture(dof_shader_pass5, interface->depth_uniform, fx->depth_buffer); /* if this is the last pass, prepare for rendering on the frambuffer */ gpu_fx_bind_render_target(&passes_left, fx, ofs, target); - glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + GWN_batch_draw(fx->quad_batch); /* disable bindings */ GPU_texture_unbind(fx->dof_near_coc_buffer); GPU_texture_unbind(fx->dof_near_coc_blurred_buffer); GPU_texture_unbind(src); - GPU_texture_filter_mode(fx->depth_buffer, true, false); + GPU_texture_compare_mode(fx->depth_buffer, true); + GPU_texture_filter_mode(fx->depth_buffer, false); GPU_texture_unbind(fx->depth_buffer); /* may not be attached, in that case this just returns */ @@ -1289,10 +1325,6 @@ bool GPU_fx_do_composite_pass( } } - glDisableClientState(GL_VERTEX_ARRAY); - glDisableClientState(GL_TEXTURE_COORD_ARRAY); - glBindBuffer(GL_ARRAY_BUFFER, 0); - GPU_shader_unbind(); return true; @@ -1305,6 +1337,7 @@ void GPU_fx_compositor_init_dof_settings(GPUDOFSettings *fx_dof) fx_dof->focus_distance = 1.0f; fx_dof->sensor = 1.0f; fx_dof->num_blades = 6; + fx_dof->ratio = 1.0f; } void GPU_fx_compositor_init_ssao_settings(GPUSSAOSettings *fx_ssao) @@ -1315,7 +1348,7 @@ void GPU_fx_compositor_init_ssao_settings(GPUSSAOSettings *fx_ssao) fx_ssao->samples = 20; } -void GPU_fx_shader_init_interface(struct GPUShader *shader, GPUFXShaderEffect effect) +void GPU_fx_shader_init_interface(GPUShader *shader, GPUFXShaderEffect effect) { if (!shader) return; @@ -1334,7 +1367,7 @@ void GPU_fx_shader_init_interface(struct GPUShader *shader, GPUFXShaderEffect ef 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); + GPU_fx_shader_set_interface(shader, interface); break; } @@ -1348,7 +1381,7 @@ void GPU_fx_shader_init_interface(struct GPUShader *shader, GPUFXShaderEffect ef interface->depth_uniform = GPU_shader_get_uniform(shader, "depthbuffer"); interface->viewvecs_uniform = GPU_shader_get_uniform(shader, "viewvecs"); - GPU_shader_set_interface(shader, interface); + GPU_fx_shader_set_interface(shader, interface); break; } @@ -1362,7 +1395,7 @@ void GPU_fx_shader_init_interface(struct GPUShader *shader, GPUFXShaderEffect ef 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); + GPU_fx_shader_set_interface(shader, interface); break; } @@ -1378,7 +1411,7 @@ void GPU_fx_shader_init_interface(struct GPUShader *shader, GPUFXShaderEffect ef interface->viewvecs_uniform = GPU_shader_get_uniform(shader, "viewvecs"); interface->depth_uniform = GPU_shader_get_uniform(shader, "depthbuffer"); - GPU_shader_set_interface(shader, interface); + GPU_fx_shader_set_interface(shader, interface); break; } @@ -1392,7 +1425,7 @@ void GPU_fx_shader_init_interface(struct GPUShader *shader, GPUFXShaderEffect ef interface->depth_uniform = GPU_shader_get_uniform(shader, "depthbuffer"); interface->viewvecs_uniform = GPU_shader_get_uniform(shader, "viewvecs"); - GPU_shader_set_interface(shader, interface); + GPU_fx_shader_set_interface(shader, interface); break; } case GPU_SHADER_FX_DEPTH_OF_FIELD_PASS_TWO: @@ -1405,7 +1438,7 @@ void GPU_fx_shader_init_interface(struct GPUShader *shader, GPUFXShaderEffect ef interface->depth_uniform = GPU_shader_get_uniform(shader, "depthbuffer"); interface->viewvecs_uniform = GPU_shader_get_uniform(shader, "viewvecs"); - GPU_shader_set_interface(shader, interface); + GPU_fx_shader_set_interface(shader, interface); break; } case GPU_SHADER_FX_DEPTH_OF_FIELD_PASS_THREE: @@ -1415,7 +1448,7 @@ void GPU_fx_shader_init_interface(struct GPUShader *shader, GPUFXShaderEffect ef 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); + GPU_fx_shader_set_interface(shader, interface); break; } case GPU_SHADER_FX_DEPTH_OF_FIELD_PASS_FOUR: @@ -1425,7 +1458,7 @@ void GPU_fx_shader_init_interface(struct GPUShader *shader, GPUFXShaderEffect ef 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); + GPU_fx_shader_set_interface(shader, interface); break; } case GPU_SHADER_FX_DEPTH_OF_FIELD_PASS_FIVE: @@ -1440,7 +1473,7 @@ void GPU_fx_shader_init_interface(struct GPUShader *shader, GPUFXShaderEffect ef interface->depth_uniform = GPU_shader_get_uniform(shader, "depthbuffer"); interface->viewvecs_uniform = GPU_shader_get_uniform(shader, "viewvecs"); - GPU_shader_set_interface(shader, interface); + GPU_fx_shader_set_interface(shader, interface); break; } @@ -1450,7 +1483,7 @@ void GPU_fx_shader_init_interface(struct GPUShader *shader, GPUFXShaderEffect ef interface->depth_uniform = GPU_shader_get_uniform(shader, "depthbuffer"); - GPU_shader_set_interface(shader, interface); + GPU_fx_shader_set_interface(shader, interface); 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..fdb5894e9ed 100644 --- a/source/blender/gpu/intern/gpu_draw.c +++ b/source/blender/gpu/intern/gpu_draw.c @@ -38,8 +38,6 @@ #include <string.h> -#include "GPU_glew.h" - #include "BLI_blenlib.h" #include "BLI_hash.h" #include "BLI_linklist.h" @@ -81,6 +79,7 @@ #include "GPU_draw.h" #include "GPU_extensions.h" #include "GPU_material.h" +#include "GPU_matrix.h" #include "GPU_shader.h" #include "GPU_texture.h" @@ -109,23 +108,27 @@ static void gpu_mcol(unsigned int ucol) } void GPU_render_text( - MTexPoly *mtexpoly, int mode, - const char *textstr, int textlen, unsigned int *col, + 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) { + /* XXX, 2.8 removes texface */ +#if 0 + Image *ima = mtexpoly->tpage; +#else + Image *ima = NULL; +#endif + if ((mode & GEMAT_TEXT) && (textlen > 0) && ima) { 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 @@ -133,50 +136,48 @@ void GPU_render_text( line_height *= 1.2f; /* could be an option? */ /* end multiline */ - + /* color has been set */ - if (mtexpoly->mode & TF_OBCOL) - col = NULL; - else if (!col) + if (!col) glColor3f(1.0f, 1.0f, 1.0f); - glPushMatrix(); - + gpuPushMatrix(); + /* 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); - + &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); + gpuTranslate2f(line_start, -line_height); line_start = 0.0f; continue; } else if (character == '\t') { - glTranslatef(advance_tab, 0.0f, 0.0f); + gpuTranslate2f(advance_tab, 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); + &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; @@ -184,13 +185,13 @@ void GPU_render_text( 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]); @@ -212,28 +213,29 @@ void GPU_render_text( } glEnd(); - glTranslatef(advance, 0.0f, 0.0f); + gpuTranslate2f(advance, 0.0f); line_start -= advance; /* so we can go back to the start of the line */ } - glPopMatrix(); + gpuPopMatrix(); BKE_image_release_ibuf(ima, first_ibuf, NULL); } } /* 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); } @@ -269,8 +271,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 = {0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, 1, 0, 0, -1, 1.0f, 0}; /* Mipmap settings */ @@ -279,36 +280,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) { @@ -415,43 +393,16 @@ 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); + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); } else if (alphablend == GPU_BLEND_ADD) { glEnable(GL_BLEND); 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)) { @@ -460,59 +411,20 @@ static void gpu_set_alpha_blend(GPUBlendMode alphablend) /* 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 +446,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, @@ -604,19 +514,6 @@ int GPU_verify_image( 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,29 +549,29 @@ 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; @@ -748,7 +645,7 @@ int GPU_verify_image( memcpy(tilerectrow, rectrow, tpx * sizeof(*rectrow)); } - + rect = tilerect; } } @@ -759,13 +656,13 @@ int GPU_verify_image( 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 */ @@ -858,30 +755,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); @@ -900,7 +773,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; @@ -951,7 +824,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 +848,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 +929,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 +964,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 +1023,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 +1076,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; @@ -1296,7 +1111,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 +1126,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 +1152,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 +1160,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; @@ -1361,9 +1176,9 @@ void GPU_update_images_framechange(void) 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; @@ -1386,9 +1201,9 @@ int GPU_update_image_time(Image *ima, double time) 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); @@ -1437,31 +1252,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], 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_custom(sds->res[0], sds->res[1], sds->res[2], 1, + 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_custom(sds->res[0], sds->res[1], sds->res[2], 1, + 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], 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_custom(sds->res_wt[0], sds->res_wt[1], sds->res_wt[2], 1, + 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_custom(sds->res_wt[0], sds->res_wt[1], sds->res_wt[2], 1, + 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_custom(sds->res[0], sds->res[1], sds->res[2], 1, + GPU_R8, sds->shadow, NULL); } #else // WITH_SMOKE (void)highres; @@ -1528,7 +1372,7 @@ 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; } @@ -1601,7 +1445,7 @@ typedef struct GPUMaterialFixed { float spec[3]; int hard; float alpha; -} GPUMaterialFixed; +} GPUMaterialFixed; static struct GPUMaterialState { GPUMaterialFixed (*matbuf); @@ -1616,10 +1460,10 @@ static struct GPUMaterialState { Material *gmatbuf_fixed[FIXEDMAT]; Material *gboundmat; Object *gob; + eObjectMode gob_object_mode; DupliObject *dob; Scene *gscene; int glay; - bool gscenelock; float (*gviewmat)[4]; float (*gviewinv)[4]; float (*gviewcamtexcofac); @@ -1657,12 +1501,12 @@ static void gpu_material_to_fixed( 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); @@ -1673,7 +1517,7 @@ static void gpu_material_to_fixed( 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; @@ -1710,8 +1554,8 @@ void GPU_end_dupli_object(void) } void GPU_begin_object_materials( - View3D *v3d, RegionView3D *rv3d, Scene *scene, Object *ob, - bool glsl, bool *do_alpha_after) + View3D *v3d, RegionView3D *rv3d, Scene *scene, ViewLayer *view_layer, Object *ob, + bool glsl, const eObjectMode object_mode, bool *do_alpha_after) { Material *ma; GPUMaterial *gpumat; @@ -1749,8 +1593,10 @@ void GPU_begin_object_materials( #ifdef WITH_GAMEENGINE if (rv3d->rflag & RV3D_IS_GAME_ENGINE) { - ob = BKE_object_lod_matob_get(ob, scene); + ob = BKE_object_lod_matob_get(ob, view_layer, object_mode); } +#else + UNUSED_VARS(view_layer); #endif /* initialize state */ @@ -1771,11 +1617,11 @@ void GPU_begin_object_materials( GMS.two_sided_lighting = (((Mesh *)ob->data)->flag & ME_TWOSIDED) != 0; GMS.gob = ob; + GMS.gob_object_mode = object_mode; 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; @@ -1789,7 +1635,7 @@ void GPU_begin_object_materials( 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"); @@ -1808,11 +1654,11 @@ void GPU_begin_object_materials( /* 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); @@ -1827,7 +1673,7 @@ void GPU_begin_object_materials( GMS.alphablend[0] = GPU_BLEND_SOLID; } - + /* setup materials */ for (a = 1; a <= ob->totcol; a++) { /* find a suitable material */ @@ -1987,13 +1833,13 @@ int GPU_object_material_bind(int nr, void *attribs) gpu_get_particle_info(&partile_info); } - if (GPU_get_material_builtins(gpumat) & GPU_OBJECT_INFO) { + if ((GPU_get_material_builtins(gpumat) & GPU_OBJECT_INFO) != 0) { 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); + gpumat, GMS.gob->lay, GMS.glay, 1.0, !(GMS.gob_object_mode & OB_MODE_TEXTURE_PAINT), + GMS.gviewmat, GMS.gviewinv, GMS.gviewcamtexcofac); 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); @@ -2064,7 +1910,7 @@ void GPU_set_material_alpha_blend(int alphablend) { if (GMS.lastalphablend == alphablend) return; - + gpu_set_alpha_blend(alphablend); GMS.lastalphablend = alphablend; } @@ -2135,13 +1981,6 @@ void GPU_end_object_materials(void) 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 */ @@ -2155,13 +1994,13 @@ int GPU_default_lights(void) 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; @@ -2194,31 +2033,28 @@ int GPU_default_lights(void) return count; } -int GPU_scene_object_lights(Scene *scene, Object *ob, int lay, float viewmat[4][4], int ortho) +int GPU_scene_object_lights(ViewLayer *view_layer, 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) { + for (Base *base = FIRSTBASE(view_layer); 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); - + gpuPushMatrix(); + gpuLoadMatrix(viewmat); + /* setup light */ GPULightData light = {0}; @@ -2237,7 +2073,7 @@ int GPU_scene_object_lights(Scene *scene, Object *ob, int lay, float viewmat[4][ 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]); @@ -2248,11 +2084,11 @@ int GPU_scene_object_lights(Scene *scene, Object *ob, int lay, float viewmat[4][ else light.type = GPU_LIGHT_POINT; } - + GPU_basic_shader_light_set(count, &light); - - glPopMatrix(); - + + gpuPopMatrix(); + count++; if (count == 8) break; @@ -2261,7 +2097,7 @@ int GPU_scene_object_lights(Scene *scene, Object *ob, int lay, float viewmat[4][ 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,16 +2113,10 @@ static void gpu_multisample(bool enable) } if (toggle_ok) { - if (enable) - glEnable(GL_MULTISAMPLE); - else - glDisable(GL_MULTISAMPLE); + glDisable(GL_MULTISAMPLE); } #else - if (enable) - glEnable(GL_MULTISAMPLE); - else - glDisable(GL_MULTISAMPLE); + glDisable(GL_MULTISAMPLE); #endif } @@ -2299,64 +2129,36 @@ static void gpu_multisample(bool enable) 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_disable_multisample(); +} - GPU_basic_shader_bind(GPU_SHADER_USE_COLOR); +void GPU_enable_program_point_size(void) +{ + glEnable(GL_PROGRAM_POINT_SIZE); +} + +void GPU_disable_program_point_size(void) +{ + glDisable(GL_PROGRAM_POINT_SIZE); } #ifdef WITH_OPENSUBDIV @@ -2502,10 +2304,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 +2335,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 Gwn_VertAttr 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) +{ + Gwn_VertAttr.mask = mask; + + if ((mask & GPU_DEPTH_BUFFER_BIT) != 0) { + Gwn_VertAttr.is_depth_test = glIsEnabled(GL_DEPTH_TEST); + glGetIntegerv(GL_DEPTH_FUNC, &Gwn_VertAttr.depth_func); + glGetDoublev(GL_DEPTH_CLEAR_VALUE, &Gwn_VertAttr.depth_clear_value); + glGetBooleanv(GL_DEPTH_WRITEMASK, (GLboolean *)&Gwn_VertAttr.depth_write_mask); + } + + if ((mask & GPU_ENABLE_BIT) != 0) { + Gwn_VertAttr.is_blend = glIsEnabled(GL_BLEND); + + for (int i = 0; i < 6; i++) { + Gwn_VertAttr.is_clip_plane[i] = glIsEnabled(GL_CLIP_PLANE0 + i); + } + + Gwn_VertAttr.is_cull_face = glIsEnabled(GL_CULL_FACE); + Gwn_VertAttr.is_depth_test = glIsEnabled(GL_DEPTH_TEST); + Gwn_VertAttr.is_dither = glIsEnabled(GL_DITHER); + Gwn_VertAttr.is_line_smooth = glIsEnabled(GL_LINE_SMOOTH); + Gwn_VertAttr.is_color_logic_op = glIsEnabled(GL_COLOR_LOGIC_OP); + Gwn_VertAttr.is_multisample = glIsEnabled(GL_MULTISAMPLE); + Gwn_VertAttr.is_polygon_offset_line = glIsEnabled(GL_POLYGON_OFFSET_LINE); + Gwn_VertAttr.is_polygon_offset_fill = glIsEnabled(GL_POLYGON_OFFSET_FILL); + Gwn_VertAttr.is_polygon_smooth = glIsEnabled(GL_POLYGON_SMOOTH); + Gwn_VertAttr.is_sample_alpha_to_coverage = glIsEnabled(GL_SAMPLE_ALPHA_TO_COVERAGE); + Gwn_VertAttr.is_scissor_test = glIsEnabled(GL_SCISSOR_TEST); + Gwn_VertAttr.is_stencil_test = glIsEnabled(GL_STENCIL_TEST); + } + + if ((mask & GPU_SCISSOR_BIT) != 0) { + Gwn_VertAttr.is_scissor_test = glIsEnabled(GL_SCISSOR_TEST); + glGetIntegerv(GL_SCISSOR_BOX, (GLint *)&Gwn_VertAttr.scissor_box); + } + + if ((mask & GPU_VIEWPORT_BIT) != 0) { + glGetDoublev(GL_DEPTH_RANGE, (GLdouble *)&Gwn_VertAttr.near_far); + glGetIntegerv(GL_VIEWPORT, (GLint *)&Gwn_VertAttr.viewport); + } + + if ((mask & GPU_BLEND_BIT) != 0) { + Gwn_VertAttr.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 = Gwn_VertAttr.mask; + + if ((mask & GPU_DEPTH_BUFFER_BIT) != 0) { + restore_mask(GL_DEPTH_TEST, Gwn_VertAttr.is_depth_test); + glDepthFunc(Gwn_VertAttr.depth_func); + glClearDepth(Gwn_VertAttr.depth_clear_value); + glDepthMask(Gwn_VertAttr.depth_write_mask); + } + + if ((mask & GPU_ENABLE_BIT) != 0) { + restore_mask(GL_BLEND, Gwn_VertAttr.is_blend); + + for (int i = 0; i < 6; i++) { + restore_mask(GL_CLIP_PLANE0 + i, Gwn_VertAttr.is_clip_plane[i]); + } + + restore_mask(GL_CULL_FACE, Gwn_VertAttr.is_cull_face); + restore_mask(GL_DEPTH_TEST, Gwn_VertAttr.is_depth_test); + restore_mask(GL_DITHER, Gwn_VertAttr.is_dither); + restore_mask(GL_LINE_SMOOTH, Gwn_VertAttr.is_line_smooth); + restore_mask(GL_COLOR_LOGIC_OP, Gwn_VertAttr.is_color_logic_op); + restore_mask(GL_MULTISAMPLE, Gwn_VertAttr.is_multisample); + restore_mask(GL_POLYGON_OFFSET_LINE, Gwn_VertAttr.is_polygon_offset_line); + restore_mask(GL_POLYGON_OFFSET_FILL, Gwn_VertAttr.is_polygon_offset_fill); + restore_mask(GL_POLYGON_SMOOTH, Gwn_VertAttr.is_polygon_smooth); + restore_mask(GL_SAMPLE_ALPHA_TO_COVERAGE, Gwn_VertAttr.is_sample_alpha_to_coverage); + restore_mask(GL_SCISSOR_TEST, Gwn_VertAttr.is_scissor_test); + restore_mask(GL_STENCIL_TEST, Gwn_VertAttr.is_stencil_test); + } + + if ((mask & GPU_VIEWPORT_BIT) != 0) { + glViewport(Gwn_VertAttr.viewport[0], Gwn_VertAttr.viewport[1], Gwn_VertAttr.viewport[2], Gwn_VertAttr.viewport[3]); + glDepthRange(Gwn_VertAttr.near_far[0], Gwn_VertAttr.near_far[1]); + } + + if ((mask & GPU_SCISSOR_BIT) != 0) { + restore_mask(GL_SCISSOR_TEST, Gwn_VertAttr.is_scissor_test); + glScissor(Gwn_VertAttr.scissor_box[0], Gwn_VertAttr.scissor_box[1], Gwn_VertAttr.scissor_box[2], Gwn_VertAttr.scissor_box[3]); + } + + if ((mask & GPU_BLEND_BIT) != 0) { + restore_mask(GL_BLEND, Gwn_VertAttr.is_blend); + } +} + +#undef Gwn_VertAttr +#undef AttribStack + /** \} */ diff --git a/source/blender/gpu/intern/gpu_extensions.c b/source/blender/gpu/intern/gpu_extensions.c index e0ce87d0e68..6bf330179d3 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_UNIFORM_BUFFER_BINDINGS, &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..e83eeefe2c5 100644 --- a/source/blender/gpu/intern/gpu_framebuffer.c +++ b/source/blender/gpu/intern/gpu_framebuffer.c @@ -32,9 +32,11 @@ #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" @@ -43,8 +45,8 @@ static struct GPUFrameBufferGlobal { } GG = {0}; /* 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 + * We support 5 outputs for now (usually we wouldn't need more to preserve fill rate) */ +#define GPU_FB_MAX_SLOTS 5 struct GPUFrameBuffer { GLuint object; @@ -54,44 +56,37 @@ struct GPUFrameBuffer { 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); } } @@ -101,41 +96,33 @@ GPUFrameBuffer *GPU_framebuffer_create(void) { GPUFrameBuffer *fb; - if (!(GLEW_VERSION_3_0 || GLEW_ARB_framebuffer_object || - (GLEW_EXT_framebuffer_object && GLEW_EXT_framebuffer_blit))) - { - return NULL; - } - fb = MEM_callocN(sizeof(GPUFrameBuffer), "GPUFrameBuffer"); - glGenFramebuffersEXT(1, &fb->object); + glGenFramebuffers(1, &fb->object); if (!fb->object) { - fprintf(stderr, "GPUFFrameBuffer: framebuffer gen failed. %d\n", - (int)glGetError()); + fprintf(stderr, "GPUFFrameBuffer: framebuffer gen failed.\n"); GPU_framebuffer_free(fb); return NULL; } /* make sure no read buffer is enabled, so completeness check will not fail. We set those at binding time */ - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb->object); + glBindFramebuffer(GL_FRAMEBUFFER, fb->object); glReadBuffer(GL_NONE); glDrawBuffer(GL_NONE); - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); + glBindFramebuffer(GL_FRAMEBUFFER, 0); return fb; } -int GPU_framebuffer_texture_attach(GPUFrameBuffer *fb, GPUTexture *tex, int slot, char err_out[256]) +bool GPU_framebuffer_texture_attach(GPUFrameBuffer *fb, GPUTexture *tex, int slot, int mip) { GLenum attachment; - GLenum error; if (slot >= GPU_FB_MAX_SLOTS) { fprintf(stderr, "Attaching to index %d framebuffer slot unsupported. " "Use at most %d\n", slot, GPU_FB_MAX_SLOTS); - return 0; + return false; } if ((G.debug & G_DEBUG)) { @@ -146,26 +133,64 @@ int GPU_framebuffer_texture_attach(GPUFrameBuffer *fb, GPUTexture *tex, int slot } } + glBindFramebuffer(GL_FRAMEBUFFER, fb->object); + GG.currentfb = fb->object; + + if (GPU_texture_stencil(tex) && GPU_texture_depth(tex)) + attachment = GL_DEPTH_STENCIL_ATTACHMENT; + else if (GPU_texture_depth(tex)) + attachment = GL_DEPTH_ATTACHMENT; + else + attachment = GL_COLOR_ATTACHMENT0 + slot; + + glFramebufferTexture(GL_FRAMEBUFFER, attachment, GPU_texture_opengl_bindcode(tex), mip); + if (GPU_texture_depth(tex)) - attachment = GL_DEPTH_ATTACHMENT_EXT; + fb->depthtex = tex; else - attachment = GL_COLOR_ATTACHMENT0_EXT + slot; + fb->colortex[slot] = tex; - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb->object); - GG.currentfb = fb->object; + GPU_texture_framebuffer_set(tex, fb, slot); - /* Clean glError buffer. */ - while (glGetError() != GL_NO_ERROR) {} + return true; +} - glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, attachment, - GPU_texture_target(tex), GPU_texture_opengl_bindcode(tex), 0); +static bool gpu_framebuffer_texture_layer_attach_ex(GPUFrameBuffer *fb, GPUTexture *tex, int slot, int layer, int mip, bool cubemap) +{ + GLenum attachment; + GLenum facetarget; + + if (slot >= GPU_FB_MAX_SLOTS) { + fprintf(stderr, + "Attaching to index %d framebuffer slot unsupported. " + "Use at most %d\n", slot, GPU_FB_MAX_SLOTS); + return false; + } - error = glGetError(); + 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"); + } + } - if (error == GL_INVALID_OPERATION) { - GPU_framebuffer_restore(); - gpu_print_framebuffer_error(error, err_out); - return 0; + glBindFramebuffer(GL_FRAMEBUFFER, fb->object); + GG.currentfb = fb->object; + + if (GPU_texture_stencil(tex) && GPU_texture_depth(tex)) + attachment = GL_DEPTH_STENCIL_ATTACHMENT; + else if (GPU_texture_depth(tex)) + attachment = GL_DEPTH_ATTACHMENT; + else + attachment = GL_COLOR_ATTACHMENT0 + slot; + + if (cubemap) { + facetarget = GL_TEXTURE_CUBE_MAP_POSITIVE_X + layer; + glFramebufferTexture2D(GL_FRAMEBUFFER, attachment, facetarget, GPU_texture_opengl_bindcode(tex), mip); + } + else { + glFramebufferTextureLayer(GL_FRAMEBUFFER, attachment, GPU_texture_opengl_bindcode(tex), mip, layer); } if (GPU_texture_depth(tex)) @@ -175,7 +200,18 @@ int GPU_framebuffer_texture_attach(GPUFrameBuffer *fb, GPUTexture *tex, int slot GPU_texture_framebuffer_set(tex, fb, slot); - return 1; + return true; +} + +bool GPU_framebuffer_texture_layer_attach(GPUFrameBuffer *fb, GPUTexture *tex, int slot, int layer, int mip) +{ + return gpu_framebuffer_texture_layer_attach_ex(fb, tex, slot, layer, mip, false); +} + +bool GPU_framebuffer_texture_cubeface_attach(GPUFrameBuffer *fb, GPUTexture *tex, int slot, int face, int mip) +{ + BLI_assert(GPU_texture_target(tex) == GL_TEXTURE_CUBE_MAP); + return gpu_framebuffer_texture_layer_attach_ex(fb, tex, slot, face, mip, true); } void GPU_framebuffer_texture_detach(GPUTexture *tex) @@ -188,21 +224,25 @@ void GPU_framebuffer_texture_detach(GPUTexture *tex) return; if (GG.currentfb != fb->object) { - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb->object); + glBindFramebuffer(GL_FRAMEBUFFER, fb->object); GG.currentfb = fb->object; } - if (GPU_texture_depth(tex)) { + if (GPU_texture_stencil(tex) && GPU_texture_depth(tex)) { + fb->depthtex = NULL; + attachment = GL_DEPTH_STENCIL_ATTACHMENT; + } + else if (GPU_texture_depth(tex)) { fb->depthtex = NULL; - attachment = GL_DEPTH_ATTACHMENT_EXT; + attachment = GL_DEPTH_ATTACHMENT; } else { BLI_assert(fb->colortex[fb_attachment] == tex); fb->colortex[fb_attachment] = NULL; - attachment = GL_COLOR_ATTACHMENT0_EXT + fb_attachment; + attachment = GL_COLOR_ATTACHMENT0 + fb_attachment; } - glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, attachment, GPU_texture_target(tex), 0, 0); + glFramebufferTexture(GL_FRAMEBUFFER, attachment, 0, 0); GPU_texture_framebuffer_set(tex, NULL, -1); } @@ -218,11 +258,11 @@ void GPU_texture_bind_as_framebuffer(GPUTexture *tex) } /* push attributes */ - glPushAttrib(GL_ENABLE_BIT | GL_VIEWPORT_BIT); + gpuPushAttrib(GPU_ENABLE_BIT | GPU_VIEWPORT_BIT); glDisable(GL_SCISSOR_TEST); /* bind framebuffer */ - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb->object); + glBindFramebuffer(GL_FRAMEBUFFER, fb->object); if (GPU_texture_depth(tex)) { glDrawBuffer(GL_NONE); @@ -230,86 +270,109 @@ void GPU_texture_bind_as_framebuffer(GPUTexture *tex) } 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); + glDrawBuffer(GL_COLOR_ATTACHMENT0 + fb_attachment); + glReadBuffer(GL_COLOR_ATTACHMENT0 + fb_attachment); } if (GPU_texture_target(tex) == GL_TEXTURE_2D_MULTISAMPLE) { glEnable(GL_MULTISAMPLE); } - /* push matrices and set default viewport and matrix */ + /* set default viewport */ glViewport(0, 0, GPU_texture_width(tex), GPU_texture_height(tex)); GG.currentfb = fb->object; - - glMatrixMode(GL_PROJECTION); - glPushMatrix(); - glMatrixMode(GL_MODELVIEW); - glPushMatrix(); } void GPU_framebuffer_slots_bind(GPUFrameBuffer *fb, int slot) { int numslots = 0, i; - GLenum attachments[4]; + GLenum attachments[GPU_FB_MAX_SLOTS]; if (!fb->colortex[slot]) { fprintf(stderr, "Error, framebuffer slot empty!\n"); return; } - for (i = 0; i < 4; i++) { + for (i = 0; i < GPU_FB_MAX_SLOTS; i++) { if (fb->colortex[i]) { - attachments[numslots] = GL_COLOR_ATTACHMENT0_EXT + i; + attachments[numslots] = GL_COLOR_ATTACHMENT0 + i; numslots++; } } /* push attributes */ - glPushAttrib(GL_ENABLE_BIT | GL_VIEWPORT_BIT); + gpuPushAttrib(GPU_ENABLE_BIT | GPU_VIEWPORT_BIT); glDisable(GL_SCISSOR_TEST); /* bind framebuffer */ - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb->object); + glBindFramebuffer(GL_FRAMEBUFFER, fb->object); /* last bound prevails here, better allow explicit control here too */ glDrawBuffers(numslots, attachments); - glReadBuffer(GL_COLOR_ATTACHMENT0_EXT + slot); + glReadBuffer(GL_COLOR_ATTACHMENT0 + slot); - /* push matrices and set default viewport and matrix */ + /* set default viewport */ glViewport(0, 0, GPU_texture_width(fb->colortex[slot]), GPU_texture_height(fb->colortex[slot])); GG.currentfb = fb->object; - - glMatrixMode(GL_PROJECTION); - glPushMatrix(); - glMatrixMode(GL_MODELVIEW); - glPushMatrix(); } +void GPU_framebuffer_bind(GPUFrameBuffer *fb) +{ + int numslots = 0, i; + GLenum attachments[GPU_FB_MAX_SLOTS]; + GLenum readattachement = 0; + GPUTexture *tex; + + for (i = 0; i < GPU_FB_MAX_SLOTS; i++) { + if (fb->colortex[i]) { + attachments[numslots] = GL_COLOR_ATTACHMENT0 + i; + tex = fb->colortex[i]; + + if (!readattachement) + readattachement = GL_COLOR_ATTACHMENT0 + i; + + numslots++; + } + } + + /* bind framebuffer */ + glBindFramebuffer(GL_FRAMEBUFFER, fb->object); + + if (numslots == 0) { + glDrawBuffer(GL_NONE); + glReadBuffer(GL_NONE); + tex = fb->depthtex; + } + else { + /* last bound prevails here, better allow explicit control here too */ + glDrawBuffers(numslots, attachments); + glReadBuffer(readattachement); + } + + if (GPU_texture_target(tex) == GL_TEXTURE_2D_MULTISAMPLE) { + glEnable(GL_MULTISAMPLE); + } + + glViewport(0, 0, GPU_texture_width(tex), GPU_texture_height(tex)); + GG.currentfb = fb->object; +} void GPU_framebuffer_texture_unbind(GPUFrameBuffer *UNUSED(fb), GPUTexture *UNUSED(tex)) { - /* restore matrix */ - glMatrixMode(GL_PROJECTION); - glPopMatrix(); - glMatrixMode(GL_MODELVIEW); - glPopMatrix(); - - /* restore attributes */ - glPopAttrib(); + /* Restore attributes. */ + gpuPopAttrib(); } void GPU_framebuffer_bind_no_save(GPUFrameBuffer *fb, int slot) { - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb->object); + glBindFramebuffer(GL_FRAMEBUFFER, fb->object); /* last bound prevails here, better allow explicit control here too */ - glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT + slot); - glReadBuffer(GL_COLOR_ATTACHMENT0_EXT + slot); + glDrawBuffer(GL_COLOR_ATTACHMENT0 + slot); + glReadBuffer(GL_COLOR_ATTACHMENT0 + slot); /* push matrices and set default viewport and matrix */ glViewport(0, 0, GPU_texture_width(fb->colortex[slot]), GPU_texture_height(fb->colortex[slot])); GG.currentfb = fb->object; - GG.currentfb = fb->object; } bool GPU_framebuffer_bound(GPUFrameBuffer *fb) @@ -319,22 +382,24 @@ bool GPU_framebuffer_bound(GPUFrameBuffer *fb) bool GPU_framebuffer_check_valid(GPUFrameBuffer *fb, char err_out[256]) { - GLenum status; - - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb->object); + glBindFramebuffer(GL_FRAMEBUFFER, 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) { + + /* On macOS glDrawBuffer must be set when checking completeness, + * otherwise it will return GL_FRAMEBUFFER_UNSUPPORTED when only a + * color buffer without depth is used. */ + if (fb->colortex[0]) { + glDrawBuffer(GL_COLOR_ATTACHMENT0); + } + + GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); + + if (status != GL_FRAMEBUFFER_COMPLETE) { GPU_framebuffer_restore(); gpu_print_framebuffer_error(status, err_out); return false; } - + return true; } @@ -351,10 +416,10 @@ void GPU_framebuffer_free(GPUFrameBuffer *fb) } if (fb->object) { - glDeleteFramebuffersEXT(1, &fb->object); + glDeleteFramebuffers(1, &fb->object); if (GG.currentfb == fb->object) { - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); + glBindFramebuffer(GL_FRAMEBUFFER, 0); GG.currentfb = 0; } } @@ -365,7 +430,7 @@ void GPU_framebuffer_free(GPUFrameBuffer *fb) void GPU_framebuffer_restore(void) { if (GG.currentfb != 0) { - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); + glBindFramebuffer(GL_FRAMEBUFFER, 0); GG.currentfb = 0; } } @@ -374,73 +439,205 @@ void GPU_framebuffer_blur( GPUFrameBuffer *fb, GPUTexture *tex, GPUFrameBuffer *blurfb, GPUTexture *blurtex) { + const float fullscreencos[4][2] = {{-1.0f, -1.0f}, {1.0f, -1.0f}, {-1.0f, 1.0f}, {1.0f, 1.0f}}; + const float fullscreenuvs[4][2] = {{0.0f, 0.0f}, {1.0f, 0.0f}, {0.0f, 1.0f}, {1.0f, 1.0f}}; + + static Gwn_VertFormat format = {0}; + static Gwn_VertBuf vbo = {{0}}; + static Gwn_Batch batch = {{0}}; + const float scaleh[2] = {1.0f / GPU_texture_width(blurtex), 0.0f}; const float scalev[2] = {0.0f, 1.0f / GPU_texture_height(tex)}; GPUShader *blur_shader = GPU_shader_get_builtin_shader(GPU_SHADER_SEP_GAUSSIAN_BLUR); - int scale_uniform, texture_source_uniform; if (!blur_shader) return; - scale_uniform = GPU_shader_get_uniform(blur_shader, "ScaleU"); - texture_source_uniform = GPU_shader_get_uniform(blur_shader, "textureSource"); + /* Preparing to draw quad */ + if (format.attrib_ct == 0) { + unsigned int i = 0; + /* Vertex format */ + unsigned int pos = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT); + unsigned int uvs = GWN_vertformat_attr_add(&format, "uvs", GWN_COMP_F32, 2, GWN_FETCH_FLOAT); + + /* Vertices */ + GWN_vertbuf_init_with_format(&vbo, &format); + GWN_vertbuf_data_alloc(&vbo, 36); + + for (int j = 0; j < 3; ++j) { + GWN_vertbuf_attr_set(&vbo, uvs, i, fullscreenuvs[j]); + GWN_vertbuf_attr_set(&vbo, pos, i++, fullscreencos[j]); + } + for (int j = 1; j < 4; ++j) { + GWN_vertbuf_attr_set(&vbo, uvs, i, fullscreenuvs[j]); + GWN_vertbuf_attr_set(&vbo, pos, i++, fullscreencos[j]); + } + + GWN_batch_init(&batch, GL_TRIANGLES, &vbo, NULL); + } + glDisable(GL_DEPTH_TEST); + /* Blurring horizontally */ - /* We do the bind ourselves rather than using GPU_framebuffer_texture_bind() to avoid * pushing unnecessary matrices onto the OpenGL stack. */ - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, blurfb->object); - glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT); + glBindFramebuffer(GL_FRAMEBUFFER, blurfb->object); + glDrawBuffer(GL_COLOR_ATTACHMENT0); /* 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(); + GWN_batch_program_set_builtin(&batch, GPU_SHADER_SEP_GAUSSIAN_BLUR); + GWN_batch_uniform_2f(&batch, "ScaleU", scaleh[0], scaleh[1]); + GWN_batch_uniform_1i(&batch, "textureSource", GL_TEXTURE0); + GWN_batch_draw(&batch); /* Blurring vertically */ - - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb->object); - glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT); + glBindFramebuffer(GL_FRAMEBUFFER, fb->object); + glDrawBuffer(GL_COLOR_ATTACHMENT0); 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); - 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(); + /* Hack to make the following uniform stick */ + GWN_batch_program_set_builtin(&batch, GPU_SHADER_SEP_GAUSSIAN_BLUR); + GWN_batch_uniform_2f(&batch, "ScaleU", scalev[0], scalev[1]); + GWN_batch_uniform_1i(&batch, "textureSource", GL_TEXTURE0); + GWN_batch_draw(&batch); +} + +void GPU_framebuffer_blit( + GPUFrameBuffer *fb_read, int read_slot, GPUFrameBuffer *fb_write, + int write_slot, bool use_depth, bool use_stencil) +{ + GPUTexture *read_tex = (use_depth || use_stencil) ? fb_read->depthtex : fb_read->colortex[read_slot]; + GPUTexture *write_tex = (use_depth || use_stencil) ? fb_write->depthtex : fb_write->colortex[write_slot]; + int read_attach = (use_depth) ? GL_DEPTH_ATTACHMENT : + (use_stencil) ? GL_DEPTH_STENCIL_ATTACHMENT : + GL_COLOR_ATTACHMENT0 + GPU_texture_framebuffer_attachment(read_tex); + int write_attach = (use_depth) ? GL_DEPTH_ATTACHMENT : + (use_stencil) ? GL_DEPTH_STENCIL_ATTACHMENT : + GL_COLOR_ATTACHMENT0 + GPU_texture_framebuffer_attachment(write_tex); + int read_bind = GPU_texture_opengl_bindcode(read_tex); + int write_bind = GPU_texture_opengl_bindcode(write_tex); + const int read_w = GPU_texture_width(read_tex); + const int read_h = GPU_texture_height(read_tex); + const int write_w = GPU_texture_width(write_tex); + const int write_h = GPU_texture_height(write_tex); + + + /* Never both! */ + BLI_assert(!(use_depth && use_stencil)); + + if (use_depth) { + BLI_assert(GPU_texture_depth(read_tex) && GPU_texture_depth(write_tex)); + BLI_assert(GPU_texture_format(read_tex) == GPU_texture_format(write_tex)); + } + else if (use_stencil) { + BLI_assert(GPU_texture_stencil(read_tex) && GPU_texture_stencil(write_tex)); + BLI_assert(GPU_texture_format(read_tex) == GPU_texture_format(write_tex)); + } - GPU_shader_unbind(); + /* read from multi-sample buffer */ + glBindFramebuffer(GL_READ_FRAMEBUFFER, fb_read->object); + glFramebufferTexture2D( + GL_READ_FRAMEBUFFER, read_attach, + GPU_texture_target(read_tex), read_bind, 0); + BLI_assert(glCheckFramebufferStatus(GL_READ_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE); + + /* write into new single-sample buffer */ + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fb_write->object); + glFramebufferTexture2D( + GL_DRAW_FRAMEBUFFER, write_attach, + GPU_texture_target(write_tex), write_bind, 0); + BLI_assert(glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE); + + glDrawBuffer((use_depth || use_stencil) ? GL_COLOR_ATTACHMENT0 : read_attach); + glBlitFramebuffer(0, 0, read_w, read_h, 0, 0, write_w, write_h, + (use_depth) ? GL_DEPTH_BUFFER_BIT : + (use_stencil) ? GL_STENCIL_BUFFER_BIT : + GL_COLOR_BUFFER_BIT, GL_NEAREST); + + /* Restore previous framebuffer */ + glBindFramebuffer(GL_FRAMEBUFFER, GG.currentfb); + glDrawBuffer(GL_COLOR_ATTACHMENT0); +} + +/** + * Use this if you need to custom downsample your texture and use the previous mip level as input. + * This function only takes care of the correct texture handling. It execute the callback for each texture level. + **/ +void GPU_framebuffer_recursive_downsample( + GPUFrameBuffer *fb, GPUTexture *tex, int num_iter, void (*callback)(void *userData, int level), void *userData) +{ + int i; + int current_dim[2] = {GPU_texture_width(tex), GPU_texture_height(tex)}; + GLenum attachment; + + /* Manually setup framebuffer to not use GPU_texture_framebuffer_set() */ + glBindFramebuffer(GL_FRAMEBUFFER, fb->object); + GG.currentfb = fb->object; + + if (GPU_texture_stencil(tex) && GPU_texture_depth(tex)) + attachment = GL_DEPTH_STENCIL_ATTACHMENT; + else if (GPU_texture_depth(tex)) + attachment = GL_DEPTH_ATTACHMENT; + else + attachment = GL_COLOR_ATTACHMENT0; + + /* last bound prevails here, better allow explicit control here too */ + if (GPU_texture_depth(tex)) { + glDrawBuffer(GL_NONE); + glReadBuffer(GL_NONE); + } + else { + glDrawBuffer(GL_COLOR_ATTACHMENT0); + glReadBuffer(GL_COLOR_ATTACHMENT0); + } + + for (i = 1; i < num_iter + 1; i++) { + + /* calculate next viewport size */ + current_dim[0] /= 2; + current_dim[1] /= 2; + + if (current_dim[0] <= 2 && current_dim[1] <= 2) { + /* Cannot reduce further. */ + break; + } + + /* ensure that the viewport size is always at least 1x1 */ + CLAMP_MIN(current_dim[0], 1); + CLAMP_MIN(current_dim[1], 1); + + glViewport(0, 0, current_dim[0], current_dim[1]); + + /* bind next level for rendering but first restrict fetches only to previous level */ + GPU_texture_bind(tex, 0); + glTexParameteri(GPU_texture_target(tex), GL_TEXTURE_BASE_LEVEL, i - 1); + glTexParameteri(GPU_texture_target(tex), GL_TEXTURE_MAX_LEVEL, i - 1); + GPU_texture_unbind(tex); + + glFramebufferTexture(GL_FRAMEBUFFER, attachment, GPU_texture_opengl_bindcode(tex), i); + + callback(userData, i); + } + + glFramebufferTexture(GL_FRAMEBUFFER, attachment, 0, 0); + + /* reset mipmap level range for the depth image */ + GPU_texture_bind(tex, 0); + glTexParameteri(GPU_texture_target(tex), GL_TEXTURE_BASE_LEVEL, 0); + glTexParameteri(GPU_texture_target(tex), GL_TEXTURE_MAX_LEVEL, i - 1); + GPU_texture_unbind(tex); } /* GPUOffScreen */ @@ -451,7 +648,7 @@ 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; @@ -464,12 +661,7 @@ GPUOffScreen *GPU_offscreen_create(int width, int height, int samples, char err_ } 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 || + if (!GLEW_ARB_texture_multisample || /* This is required when blitting from a multi-sampled buffers, * even though we're not scaling. */ !GLEW_EXT_framebuffer_multisample_blit_scaled) @@ -478,24 +670,31 @@ GPUOffScreen *GPU_offscreen_create(int width, int height, int samples, char err_ } } - ofs->depth = GPU_texture_create_depth_multisample(width, height, samples, err_out); - if (!ofs->depth) { - GPU_offscreen_free(ofs); - return NULL; - } + if (depth) { + ofs->depth = GPU_texture_create_depth_with_stencil_multisample(width, height, samples, err_out); + if (!ofs->depth) { + GPU_offscreen_free(ofs); + return NULL; + } - if (!GPU_framebuffer_texture_attach(ofs->fb, ofs->depth, 0, err_out)) { - GPU_offscreen_free(ofs); - return NULL; + if (!GPU_framebuffer_texture_attach(ofs->fb, ofs->depth, 0, 0)) { + GPU_offscreen_free(ofs); + return NULL; + } } - ofs->color = GPU_texture_create_2D_multisample(width, height, NULL, GPU_HDR_NONE, samples, err_out); + if (high_bitdepth) { + ofs->color = GPU_texture_create_2D_custom_multisample(width, height, 4, GPU_RGBA16F, NULL, samples, err_out); + } + else { + ofs->color = GPU_texture_create_2D_multisample(width, height, NULL, samples, err_out); + } if (!ofs->color) { GPU_offscreen_free(ofs); return NULL; } - if (!GPU_framebuffer_texture_attach(ofs->fb, ofs->color, 0, err_out)) { + if (!GPU_framebuffer_texture_attach(ofs->fb, ofs->color, 0, 0)) { GPU_offscreen_free(ofs); return NULL; } @@ -541,6 +740,24 @@ void GPU_offscreen_unbind(GPUOffScreen *ofs, bool restore) glEnable(GL_SCISSOR_TEST); } +void GPU_offscreen_blit(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) { const int w = GPU_texture_width(ofs->color); @@ -569,37 +786,37 @@ void GPU_offscreen_read_pixels(GPUOffScreen *ofs, int type, void *pixels) #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, + glBindFramebuffer(GL_READ_FRAMEBUFFER, ofs->color->fb->object); + glFramebufferTexture2D( + GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + ofs->color->fb_attachment, GL_TEXTURE_2D_MULTISAMPLE, ofs->color->bindcode, 0); - status = glCheckFramebufferStatusEXT(GL_READ_FRAMEBUFFER_EXT); - if (status != GL_FRAMEBUFFER_COMPLETE_EXT) { + status = glCheckFramebufferStatus(GL_READ_FRAMEBUFFER); + if (status != GL_FRAMEBUFFER_COMPLETE) { goto finally; } #endif /* 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, + glGenFramebuffers(1, &fbo_blit); + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo_blit); + glFramebufferTexture2D( + GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex_blit, 0); - status = glCheckFramebufferStatusEXT(GL_DRAW_FRAMEBUFFER_EXT); - if (status != GL_FRAMEBUFFER_COMPLETE_EXT) { + 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); + glBindFramebuffer(GL_FRAMEBUFFER, ofs->color->fb->object); #undef USE_FBO_CTX_SWITCH #endif @@ -610,10 +827,8 @@ finally: glDeleteTextures(1, &tex_blit); } if (fbo_blit) { - glDeleteFramebuffersEXT(1, &fbo_blit); + glDeleteFramebuffers(1, &fbo_blit); } - - GPU_ASSERT_NO_GL_ERRORS("Read Multi-Sample Pixels"); } else { glReadPixels(0, 0, w, h, GL_RGBA, type, pixels); @@ -630,8 +845,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..7a6b1ff6c70 100644 --- a/source/blender/gpu/intern/gpu_init_exit.c +++ b/source/blender/gpu/intern/gpu_init_exit.c @@ -31,7 +31,8 @@ #include "BLI_sys_types.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 +60,22 @@ void GPU_init(void) if (G.debug & G_DEBUG_GPU) gpu_debug_init(); + gpu_batch_init(); + + immInit(); } void GPU_exit(void) { + 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_lamp.c b/source/blender/gpu/intern/gpu_lamp.c new file mode 100644 index 00000000000..3c49c057b49 --- /dev/null +++ b/source/blender/gpu/intern/gpu_lamp.c @@ -0,0 +1,483 @@ +/* + * ***** 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): Brecht Van Lommel, Clément Foucault. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/gpu/intern/gpu_lamp.c + * \ingroup gpu + * + * Manages Opengl lights. + */ + +#include "MEM_guardedalloc.h" + +#include "DNA_lamp_types.h" +#include "DNA_object_types.h" +#include "DNA_scene_types.h" + +#include "BLI_listbase.h" +#include "BLI_math.h" +#include "BLI_utildefines.h" + +#include "BKE_group.h" + +#include "GPU_framebuffer.h" +#include "GPU_glew.h" +#include "GPU_lamp.h" +#include "GPU_material.h" +#include "GPU_shader.h" +#include "GPU_texture.h" + +#include "gpu_lamp_private.h" + +bool GPU_lamp_visible(GPULamp *lamp, Material *ma) +{ + if (lamp->hide) + return false; + else if (ma && ma->group) + return BKE_group_object_exists(ma->group, lamp->ob); + else + return true; +} + +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; + } +} + +static GPUTexture *gpu_lamp_create_vsm_shadow_map(int size) +{ + return GPU_texture_create_2D_custom(size, size, 2, GPU_RG32F, NULL, NULL); +} + +LampEngineData *GPU_lamp_engine_data_get(Scene *scene, Object *ob, Object *par, struct RenderEngineType *re) +{ + GPULamp *lamp; + LinkData *link; + + for (link = ob->gpulamp.first; link; link = link->next) { + lamp = (GPULamp *)link->data; + + if ((lamp->par == par) && (lamp->scene == scene) && (lamp->re == re)) + return &lamp->data; + } + + lamp = MEM_callocN(sizeof(GPULamp), "GPULamp"); + + link = MEM_callocN(sizeof(LinkData), "GPULampLink"); + link->data = lamp; + BLI_addtail(&ob->gpulamp, link); + + lamp->scene = scene; + lamp->ob = ob; + lamp->par = par; + lamp->la = ob->data; + lamp->re = re; + + return &lamp->data; +} + +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; + } + + GPU_texture_bind(lamp->depthtex, 0); + GPU_texture_compare_mode(lamp->depthtex, true); + GPU_texture_unbind(lamp->depthtex); + + if (!GPU_framebuffer_texture_attach(lamp->fb, lamp->depthtex, 0, 0)) { + gpu_lamp_shadow_free(lamp); + return lamp; + } + + /* Shadow color map */ + lamp->tex = gpu_lamp_create_vsm_shadow_map(lamp->size); + if (!lamp->tex) { + gpu_lamp_shadow_free(lamp); + return lamp; + } + + if (!GPU_framebuffer_texture_attach(lamp->fb, lamp->tex, 0, 0)) { + gpu_lamp_shadow_free(lamp); + return lamp; + } + + if (!GPU_framebuffer_check_valid(lamp->fb, NULL)) { + gpu_lamp_shadow_free(lamp); + return lamp; + } + + /* FBO and texture for blurring */ + lamp->blurfb = GPU_framebuffer_create(); + if (!lamp->blurfb) { + gpu_lamp_shadow_free(lamp); + return lamp; + } + + lamp->blurtex = gpu_lamp_create_vsm_shadow_map(lamp->size * 0.5); + if (!lamp->blurtex) { + gpu_lamp_shadow_free(lamp); + return lamp; + } + + if (!GPU_framebuffer_texture_attach(lamp->blurfb, lamp->blurtex, 0, 0)) { + gpu_lamp_shadow_free(lamp); + return lamp; + } + + /* 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; + } + + GPU_texture_bind(lamp->tex, 0); + GPU_texture_compare_mode(lamp->tex, true); + GPU_texture_unbind(lamp->tex); + + if (!GPU_framebuffer_texture_attach(lamp->fb, lamp->tex, 0, 0)) { + gpu_lamp_shadow_free(lamp); + return lamp; + } + + 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_engine_data_free(LampEngineData *led) +{ + for (int i = 0; i < MAX_LAMP_DATA; ++i) { + if (led->storage[i]) { + MEM_freeN(led->storage[i]); + led->storage[i] = NULL; + } + } +} + +void GPU_lamp_free(Object *ob) +{ + GPULamp *lamp; + LinkData *link; + + for (link = ob->gpulamp.first; link; link = link->next) { + lamp = link->data; + + gpu_lamp_shadow_free(lamp); + GPU_lamp_engine_data_free(&lamp->data); + + 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; +} diff --git a/source/blender/gpu/intern/gpu_lamp_private.h b/source/blender/gpu/intern/gpu_lamp_private.h new file mode 100644 index 00000000000..f227ce74e7e --- /dev/null +++ b/source/blender/gpu/intern/gpu_lamp_private.h @@ -0,0 +1,84 @@ +/* + * ***** 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): Brecht Van Lommel, Clément Foucault. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file gpu_lamp_private.h + * \ingroup gpu + */ + +#ifndef __GPU_LAMP_PRIVATE_H__ +#define __GPU_LAMP_PRIVATE_H__ + +#include "BLI_sys_types.h" /* for bool */ + +struct GPULamp { + Scene *scene; + Object *ob; + Object *par; + Lamp *la; + struct RenderEngineType *re; + + /* Old Viewport (pre-2.8) */ + 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; + + /* New viewport */ + struct LampEngineData data; +}; + +#endif /* __GPU_LAMP_PRIVATE_H__ */ diff --git a/source/blender/gpu/intern/gpu_material.c b/source/blender/gpu/intern/gpu_material.c index edb6c9a29f9..2d7b9415030 100644 --- a/source/blender/gpu/intern/gpu_material.c +++ b/source/blender/gpu/intern/gpu_material.c @@ -45,12 +45,14 @@ #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" @@ -60,11 +62,14 @@ #include "GPU_extensions.h" #include "GPU_framebuffer.h" +#include "GPU_lamp.h" #include "GPU_material.h" #include "GPU_shader.h" #include "GPU_texture.h" +#include "GPU_uniformbuffer.h" #include "gpu_codegen.h" +#include "gpu_lamp_private.h" #ifdef WITH_OPENSUBDIV # include "BKE_DerivedMesh.h" @@ -92,12 +97,15 @@ static struct GPUWorld { } 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 */ + + const void *engine_type; /* attached engine type */ + int options; /* to identify shader variations (shadow, probe, world background...) */ /* for creating the material */ ListBase nodes; @@ -128,50 +136,26 @@ struct GPUMaterial { 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; + /* XXX: Should be in Material. But it depends on the output node + * used and since the output selection is difference for GPUMaterial... + */ + int domain; + + GPUUniformBuffer *ubo; /* UBOs for shader uniforms. */ + 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; +}; - ListBase materials; +enum { + GPU_DOMAIN_SURFACE = (1 << 0), + GPU_DOMAIN_VOLUME = (1 << 1), + GPU_DOMAIN_SSS = (1 << 2) }; /* Forward declaration so shade_light_textures() can use this, while still keeping the code somewhat organized */ @@ -289,21 +273,18 @@ void GPU_material_free(ListBase *gpumaterial) if (material->pass) GPU_pass_free(material->pass); - for (LinkData *nlink = material->lamps.first; nlink; nlink = nlink->next) { - GPULamp *lamp = nlink->data; + if (material->ubo != NULL) { + GPU_uniformbuffer_free(material->ubo); + } - 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); - } - } + if (material->sss_tex_profile != NULL) { + GPU_texture_free(material->sss_tex_profile); } - + + if (material->sss_profile != NULL) { + GPU_uniformbuffer_free(material->sss_profile); + } + BLI_freelistN(&material->lamps); MEM_freeN(material); @@ -312,28 +293,12 @@ void GPU_material_free(ListBase *gpumaterial) BLI_freelistN(gpumaterial); } -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; -} - 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) + float viewmat[4][4], float viewinv[4][4], float camerafactors[4]) { 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) { @@ -341,7 +306,7 @@ void GPU_material_bind( GPULamp *lamp = nlink->data; if ((lamp->lay & viewlay) && (!(lamp->mode & LA_LAYER) || (lamp->lay & oblay)) && - GPU_lamp_visible(lamp, srl, material->ma)) + GPU_lamp_visible(lamp, material->ma)) { lamp->dynenergy = lamp->energy; copy_v3_v3(lamp->dyncol, lamp->col); @@ -490,6 +455,350 @@ GPUMatType GPU_Material_get_type(GPUMaterial *material) return material->type; } +GPUPass *GPU_material_get_pass(GPUMaterial *material) +{ + return material->pass; +} + +GPUUniformBuffer *GPU_material_get_uniform_buffer(GPUMaterial *material) +{ + return material->ubo; +} + +/** + * Create dynamic UBO from parameters + * \param ListBase of BLI_genericNodeN(GPUInput) + */ +void GPU_material_create_uniform_buffer(GPUMaterial *material, ListBase *inputs) +{ + material->ubo = GPU_uniformbuffer_dynamic_create(inputs, NULL); +} + +void GPU_material_uniform_buffer_tag_dirty(ListBase *gpumaterials) +{ + 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; + } + } +} + +/* Eevee Subsurface scattering. */ +/* Based on Separable SSS. by Jorge Jimenez and Diego Gutierrez */ + +#define SSS_SAMPLES 65 +#define SSS_EXPONENT 2.0f /* Importance sampling exponent */ + +typedef struct GPUSssKernelData { + float kernel[SSS_SAMPLES][4]; + float param[3], max_radius; + int samples; +} GPUSssKernelData; + +static void sss_calculate_offsets(GPUSssKernelData *kd, int count, float exponent) +{ + 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; + } +} + +#define GAUSS_TRUNCATE 12.46f +static float gaussian_profile(float r, float radius) +{ + const float v = radius * radius * (0.25f * 0.25f); + const float Rm = sqrtf(v * GAUSS_TRUNCATE); + + if (r >= Rm) { + return 0.0f; + } + return expf(-r * r / (2.0f * v)) / (2.0f * M_PI * v); +} + +#define BURLEY_TRUNCATE 16.0f +#define BURLEY_TRUNCATE_CDF 0.9963790093708328f // cdf(BURLEY_TRUNCATE) +static float burley_profile(float r, float d) +{ + 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); +} + +static float cubic_profile(float r, float radius, float sharpness) +{ + float Rm = radius * (1.0f + sharpness); + + 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; + + Rmy = powf(Rm, y); + ry = powf(r, y); + ryinv = (r > 0.0f) ? powf(r, y - 1.0f) : 0.0f; + + const float Rmy5 = (Rmy * Rmy) * (Rmy * Rmy) * Rmy; + const float f = Rmy - ry; + const float num = f * (f * f) * (y * ryinv); + + return (10.0f * num) / (Rmy5 * M_PI); +} + +static float eval_profile(float r, short falloff_type, float sharpness, float param) +{ + r = fabsf(r); + + if (falloff_type == SHD_SUBSURFACE_BURLEY || + falloff_type == SHD_SUBSURFACE_RANDOM_WALK) + { + return burley_profile(r, param) / BURLEY_TRUNCATE_CDF; + } + else if (falloff_type == SHD_SUBSURFACE_CUBIC) { + return cubic_profile(r, param, sharpness); + } + else { + return gaussian_profile(r, param); + } +} + +/* 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) +{ + const float range = x1 - x0; + const float step = range / INTEGRAL_RESOLUTION; + float integral = 0.0f; + + 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 compute_sss_kernel( + GPUSssKernelData *kd, float *radii, int sample_ct, int falloff_type, float sharpness) +{ + 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); + + /* Christensen-Burley fitting */ + float l[3], d[3]; + + 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]); + + copy_v3_v3(kd->param, d); + } + 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 { + kd->max_radius = MAX3(rad[0], rad[1], rad[2]); + + copy_v3_v3(kd->param, rad); + } + + /* Compute samples locations on the 1d kernel [-1..1] */ + sss_calculate_offsets(kd, sample_ct, SSS_EXPONENT); + + /* Weights sum for normalization */ + float sum[3] = {0.0f, 0.0f, 0.0f}; + + /* 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 { + x0 = (kd->kernel[i - 1][3] + kd->kernel[i][3]) / 2.0f; + } + + 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; + } + + x0 *= kd->max_radius; + x1 *= kd->max_radius; + + 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]); + + sum[0] += kd->kernel[i][0]; + sum[1] += kd->kernel[i][1]; + sum[2] += kd->kernel[i][2]; + } + + 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]; + } + } + else { + /* Avoid 0 kernel sum. */ + kd->kernel[sample_ct / 2][i] = 1.0f; + } + } + + /* 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); + + kd->samples = sample_ct; +} + +#define INTEGRAL_RESOLUTION 512 +static void compute_sss_translucence_kernel( + const GPUSssKernelData *kd, int resolution, short falloff_type, float sharpness, float **output) +{ + float (*texels)[4]; + texels = MEM_callocN(sizeof(float) * 4 * resolution, "compute_sss_translucence_kernel"); + *output = (float *)texels; + + /* 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); + + /* 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); + + 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]); + + /* 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); + + 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)); + } + + /* 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; + } + + /* 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; + + /* 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_material_sss_profile_create(GPUMaterial *material, float *radii, short *falloff_type, float *sharpness) +{ + material->sss_radii = radii; + material->sss_falloff = falloff_type; + material->sss_sharpness = sharpness; + material->sss_dirty = true; + + /* Update / Create UBO */ + if (material->sss_profile == NULL) { + material->sss_profile = GPU_uniformbuffer_create(sizeof(GPUSssKernelData), NULL, NULL); + } +} + +struct GPUUniformBuffer *GPU_material_sss_profile_get(GPUMaterial *material, int sample_ct, GPUTexture **tex_profile) +{ + if (material->sss_radii == NULL) + return NULL; + + if (material->sss_dirty || (material->sss_samples != sample_ct)) { + GPUSssKernelData kd; + + float sharpness = (material->sss_sharpness != NULL) ? *material->sss_sharpness : 0.0f; + + /* XXX Black magic but it seems to fit. Maybe because we integrate -1..1 */ + sharpness *= 0.5f; + + compute_sss_kernel(&kd, material->sss_radii, sample_ct, *material->sss_falloff, sharpness); + + /* Update / Create UBO */ + GPU_uniformbuffer_update(material->sss_profile, &kd); + + /* Update / Create Tex */ + float *translucence_profile; + compute_sss_translucence_kernel(&kd, 64, *material->sss_falloff, sharpness, &translucence_profile); + + if (material->sss_tex_profile != NULL) { + GPU_texture_free(material->sss_tex_profile); + } + + material->sss_tex_profile = GPU_texture_create_1D_custom(64, 4, GPU_RGBA16F, translucence_profile, NULL); + + MEM_freeN(translucence_profile); + + material->sss_samples = sample_ct; + material->sss_dirty = false; + } + + if (tex_profile != NULL) { + *tex_profile = material->sss_tex_profile; + } + return material->sss_profile; +} + +#undef SSS_EXPONENT +#undef SSS_SAMPLES void GPU_material_vertex_attributes(GPUMaterial *material, GPUVertexAttribs *attribs) { @@ -540,6 +849,16 @@ bool GPU_material_use_world_space_shading(GPUMaterial *mat) return BKE_scene_use_world_space_shading(mat->scene); } +bool GPU_material_use_domain_surface(GPUMaterial *mat) +{ + return (mat->domain & GPU_DOMAIN_SURFACE); +} + +bool GPU_material_use_domain_volume(GPUMaterial *mat) +{ + return (mat->domain & GPU_DOMAIN_VOLUME); +} + static GPUNodeLink *lamp_get_visibility(GPUMaterial *mat, GPULamp *lamp, GPUNodeLink **lv, GPUNodeLink **dist) { GPUNodeLink *visifac; @@ -951,14 +1270,12 @@ static void shade_one_light(GPUShadeInput *shi, GPUShadeResult *shr, GPULamp *la } 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 @@ -1025,7 +1342,6 @@ static void shade_one_light(GPUShadeInput *shi, GPUShadeResult *shr, GPULamp *la } add_user_list(&mat->lamps, lamp); - add_user_list(&lamp->materials, shi->gpumat->ma); } static void material_lights(GPUShadeInput *shi, GPUShadeResult *shr) @@ -2150,6 +2466,73 @@ GPUMaterial *GPU_material_world(struct Scene *scene, struct World *wo) return mat; } +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; + } + } + + return NULL; +} + +/** + * TODO: This is supposed to replace GPU_material_from_blender/_world in the future + * + * \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, + const char *vert_code, const char *geom_code, const char *frag_lib, const char *defines) +{ + GPUMaterial *mat; + GPUNodeLink *outlink; + LinkData *link; + bool has_volume_output, has_surface_output; + + /* 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); /* TODO remove GPU_material_construct_begin */ + mat->scene = scene; + 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; + } + if (has_volume_output) { + mat->domain |= GPU_DOMAIN_VOLUME; + } + + /* Let Draw manager finish the construction. */ + if (mat->outlink) { + outlink = mat->outlink; + mat->pass = GPU_generate_pass_new( + mat, &mat->nodes, outlink, &mat->attribs, vert_code, geom_code, frag_lib, defines); + } + + /* 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(gpumaterials, link); + + return mat; +} GPUMaterial *GPU_material_from_blender(Scene *scene, Material *ma, bool use_opensubdiv) { @@ -2237,386 +2620,6 @@ void GPU_materials_free(void) /* 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) @@ -2658,7 +2661,6 @@ GPUNodeLink *GPU_lamp_get_data( /* ensure shadow buffer and lamp textures will be updated */ add_user_list(&mat->lamps, lamp); - add_user_list(&lamp->materials, mat->ma); return visifac; } @@ -2728,6 +2730,7 @@ GPUShaderExport *GPU_shader_export(struct Scene *scene, struct Material *ma) break; case GPU_NONE: + case GPU_TEX3D: case GPU_TEXCUBE: case GPU_FLOAT: case GPU_VEC2: @@ -2735,6 +2738,7 @@ GPUShaderExport *GPU_shader_export(struct Scene *scene, struct Material *ma) case GPU_VEC4: case GPU_MAT3: case GPU_MAT4: + case GPU_CLOSURE: case GPU_ATTRIB: break; } @@ -2763,7 +2767,9 @@ GPUShaderExport *GPU_shader_export(struct Scene *scene, struct Material *ma) break; case GPU_NONE: + case GPU_CLOSURE: case GPU_TEX2D: + case GPU_TEX3D: case GPU_TEXCUBE: case GPU_SHADOW2D: case GPU_ATTRIB: 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 e2837d96b0f..3240688d24b 100644 --- a/source/blender/gpu/intern/gpu_select.c +++ b/source/blender/gpu/intern/gpu_select.c @@ -210,12 +210,7 @@ unsigned int 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); } /* ---------------------------------------------------------------------------- @@ -255,3 +250,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 d7a3ad07558..2d36c6f120c 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); @@ -331,10 +333,6 @@ 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); @@ -550,7 +548,7 @@ unsigned int gpu_select_pick_end(void) if (ps->is_cached == false) { gpu_select_pick_finalize(); - 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 3d589986281..e3bd20f3776 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" @@ -94,7 +96,7 @@ void gpu_select_query_begin( g_query_state.id = MEM_mallocN(g_query_state.num_of_queries * sizeof(*g_query_state.id), "gpu selection ids"); glGenQueries(g_query_state.num_of_queries, g_query_state.queries); - glPushAttrib(GL_DEPTH_BUFFER_BIT | GL_VIEWPORT_BIT); + gpuPushAttrib(GPU_DEPTH_BUFFER_BIT | GPU_VIEWPORT_BIT); /* disable writing to the framebuffer */ glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); @@ -206,7 +208,7 @@ unsigned int 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..b06ee56c21f 100644 --- a/source/blender/gpu/intern/gpu_shader.c +++ b/source/blender/gpu/intern/gpu_shader.c @@ -30,22 +30,114 @@ #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 "DNA_space_types.h" + #include "GPU_compositing.h" -#include "GPU_debug.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_2D_vert_glsl[]; +extern char datatoc_gpu_shader_2D_flat_color_vert_glsl[]; +extern char datatoc_gpu_shader_2D_smooth_color_vert_glsl[]; +extern char datatoc_gpu_shader_2D_smooth_color_frag_glsl[]; +extern char datatoc_gpu_shader_2D_image_vert_glsl[]; + +extern char datatoc_gpu_shader_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_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_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_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_bone_envelope_solid_vert_glsl[]; +extern char datatoc_gpu_shader_instance_bone_envelope_wire_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_frag_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,7 +145,7 @@ 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_fullscreen_vert_glsl[]; extern char datatoc_gpu_shader_fx_ssao_frag_glsl[]; extern char datatoc_gpu_shader_fx_dof_frag_glsl[]; extern char datatoc_gpu_shader_fx_dof_vert_glsl[]; @@ -63,41 +155,25 @@ 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 */ +/* cache of built-in shaders (each is created on first use) */ +static GPUShader *builtin_shaders[GPU_NUM_BUILTIN_SHADERS] = { NULL }; -struct GPUShader { - GLuint program; /* handle for full program (links shader stages below) */ +/* cache for shader fx. Those can exist in combinations so store them here */ +static GPUShader *fx_shaders[MAX_FX_SHADERS * 2] = { NULL }; - 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 */ -}; +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,71 +196,19 @@ 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], @@ -207,10 +231,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. @@ -243,37 +263,71 @@ 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); } +#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, const char *fragcode, const char *geocode, const char *libcode, const char *defines, - int input, - int output, - int number, const int flags) { #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 +340,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); @@ -313,7 +365,7 @@ 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); + gpu_shader_standard_extensions(standard_extensions); if (vertexcode) { const char *source[5]; @@ -327,6 +379,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 +420,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 +448,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,20 +463,12 @@ 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 @@ -436,38 +486,54 @@ 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"); } void GPU_shader_free(GPUShader *shader) { + BLI_assert(shader); + if (shader->vertex) glDeleteShader(shader->vertex); if (shader->geometry) @@ -480,20 +546,51 @@ void GPU_shader_free(GPUShader *shader) 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; } -void *GPU_shader_get_interface(GPUShader *shader) +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_fx_shader_get_interface(GPUShader *shader) { return shader->uniform_interface; } -void GPU_shader_set_interface(GPUShader *shader, void *interface) +void *GPU_shader_get_interface(GPUShader *shader) +{ + return shader->interface; +} + +/* Clement : Temp */ +int GPU_shader_get_program(GPUShader *shader) +{ + return (int)shader->program; +} + +void GPU_fx_shader_set_interface(GPUShader *shader, void *interface) { shader->uniform_interface = interface; } @@ -503,16 +600,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 +613,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,22 +624,22 @@ 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); @@ -566,78 +655,232 @@ void GPU_shader_uniform_texture(GPUShader *UNUSED(shader), int location, GPUText if (location == -1) return; - GPU_ASSERT_NO_GL_ERRORS("Pre Uniform Texture"); - - arbnumber = (GLenum)((GLuint)GL_TEXTURE0 + number); + if (number != 0) + glActiveTexture(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"); + if (number != 0) + glActiveTexture(GL_TEXTURE0); } 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; - } + 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 }, + [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_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_IMAGE_LINEAR_TO_SRGB] = { datatoc_gpu_shader_2D_image_vert_glsl, + datatoc_gpu_shader_image_linear_frag_glsl }, + [GPU_SHADER_2D_IMAGE] = { datatoc_gpu_shader_2D_image_vert_glsl, + datatoc_gpu_shader_image_frag_glsl }, + [GPU_SHADER_2D_IMAGE_COLOR] = { datatoc_gpu_shader_2D_image_vert_glsl, + datatoc_gpu_shader_image_color_frag_glsl }, + [GPU_SHADER_2D_IMAGE_ALPHA_COLOR] = { datatoc_gpu_shader_2D_image_vert_glsl, + datatoc_gpu_shader_image_alpha_color_frag_glsl }, + [GPU_SHADER_2D_IMAGE_ALPHA] = { datatoc_gpu_shader_2D_image_vert_glsl, + datatoc_gpu_shader_image_modulate_alpha_frag_glsl }, + [GPU_SHADER_2D_IMAGE_SHUFFLE_COLOR] = { datatoc_gpu_shader_2D_image_vert_glsl, + datatoc_gpu_shader_image_shuffle_color_frag_glsl }, + [GPU_SHADER_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_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_3D_INSTANCE_BONE_ENVELOPE_SOLID] = { datatoc_gpu_shader_instance_bone_envelope_solid_vert_glsl, + datatoc_gpu_shader_simple_lighting_frag_glsl }, + [GPU_SHADER_3D_INSTANCE_BONE_ENVELOPE_WIRE] = { datatoc_gpu_shader_instance_bone_envelope_wire_vert_glsl, + datatoc_gpu_shader_flat_color_frag_glsl }, + + [GPU_SHADER_3D_INSTANCE_MBALL_HANDLES] = { datatoc_gpu_shader_instance_mball_handles_vert_glsl, + datatoc_gpu_shader_flat_color_frag_glsl }, + }; + + if (builtin_shaders[shader] == NULL) { + /* just a few special cases */ + const char *defines = NULL; + switch (shader) { + case GPU_SHADER_SMOKE_COBA: + defines = "#define USE_COBA;\n"; + break; + case GPU_SHADER_INSTANCE_VARIYING_COLOR_VARIYING_SIZE: + defines = "#define UNIFORM_SCALE;\n"; + break; + case GPU_SHADER_3D_INSTANCE_SCREEN_ALIGNED_AXIS: + defines = "#define AXIS_NAME;\n"; + break; + case GPU_SHADER_3D_OBJECTSPACE_SIMPLE_LIGHTING_VARIYING_COLOR: + case GPU_SHADER_3D_INSTANCE_BONE_ENVELOPE_SOLID: + defines = "#define USE_INSTANCE_COLOR;\n"; + break; + 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; + } + + const GPUShaderStages *stages = builtin_shader_stages + shader; - if (retval == NULL) - printf("Unable to create a GPUShader for builtin shader: %u\n", shader); + 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 (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; + } - return retval; + /* common case */ + builtin_shaders[shader] = GPU_shader_create(stages->vert, stages->frag, stages->geom, NULL, defines); + } + + return builtin_shaders[shader]; } #define MAX_DEFINES 100 @@ -657,103 +900,80 @@ GPUShader *GPU_shader_get_builtin_fx_shader(int effect, bool persp) strcat(defines, "#define PERSP_MATRIX\n"); } - if (!GG.shaders.fx_shaders[offset]) { + if (!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); + shader = GPU_shader_create(datatoc_gpu_shader_fullscreen_vert_glsl, datatoc_gpu_shader_fx_ssao_frag_glsl, NULL, datatoc_gpu_shader_fx_lib_glsl, defines); break; case GPU_SHADER_FX_DEPTH_OF_FIELD_PASS_ONE: strcat(defines, "#define FIRST_PASS\n"); - shader = GPU_shader_create(datatoc_gpu_shader_fx_dof_vert_glsl, datatoc_gpu_shader_fx_dof_frag_glsl, NULL, datatoc_gpu_shader_fx_lib_glsl, defines, 0, 0, 0); + shader = GPU_shader_create(datatoc_gpu_shader_fx_dof_vert_glsl, datatoc_gpu_shader_fx_dof_frag_glsl, NULL, datatoc_gpu_shader_fx_lib_glsl, defines); break; case GPU_SHADER_FX_DEPTH_OF_FIELD_PASS_TWO: strcat(defines, "#define SECOND_PASS\n"); - shader = GPU_shader_create(datatoc_gpu_shader_fx_dof_vert_glsl, datatoc_gpu_shader_fx_dof_frag_glsl, NULL, datatoc_gpu_shader_fx_lib_glsl, defines, 0, 0, 0); + shader = GPU_shader_create(datatoc_gpu_shader_fx_dof_vert_glsl, datatoc_gpu_shader_fx_dof_frag_glsl, NULL, datatoc_gpu_shader_fx_lib_glsl, defines); break; case GPU_SHADER_FX_DEPTH_OF_FIELD_PASS_THREE: strcat(defines, "#define THIRD_PASS\n"); - shader = GPU_shader_create(datatoc_gpu_shader_fx_dof_vert_glsl, datatoc_gpu_shader_fx_dof_frag_glsl, NULL, datatoc_gpu_shader_fx_lib_glsl, defines, 0, 0, 0); + shader = GPU_shader_create(datatoc_gpu_shader_fx_dof_vert_glsl, datatoc_gpu_shader_fx_dof_frag_glsl, NULL, datatoc_gpu_shader_fx_lib_glsl, defines); break; case GPU_SHADER_FX_DEPTH_OF_FIELD_PASS_FOUR: strcat(defines, "#define FOURTH_PASS\n"); - shader = GPU_shader_create(datatoc_gpu_shader_fx_dof_vert_glsl, datatoc_gpu_shader_fx_dof_frag_glsl, NULL, datatoc_gpu_shader_fx_lib_glsl, defines, 0, 0, 0); + shader = GPU_shader_create(datatoc_gpu_shader_fx_dof_vert_glsl, datatoc_gpu_shader_fx_dof_frag_glsl, NULL, datatoc_gpu_shader_fx_lib_glsl, defines); break; case GPU_SHADER_FX_DEPTH_OF_FIELD_PASS_FIVE: strcat(defines, "#define FIFTH_PASS\n"); - shader = GPU_shader_create(datatoc_gpu_shader_fx_dof_vert_glsl, datatoc_gpu_shader_fx_dof_frag_glsl, NULL, datatoc_gpu_shader_fx_lib_glsl, defines, 0, 0, 0); + shader = GPU_shader_create(datatoc_gpu_shader_fx_dof_vert_glsl, datatoc_gpu_shader_fx_dof_frag_glsl, NULL, datatoc_gpu_shader_fx_lib_glsl, defines); break; case GPU_SHADER_FX_DEPTH_OF_FIELD_HQ_PASS_ONE: strcat(defines, "#define FIRST_PASS\n"); - shader = GPU_shader_create(datatoc_gpu_shader_fx_dof_hq_vert_glsl, datatoc_gpu_shader_fx_dof_hq_frag_glsl, NULL, datatoc_gpu_shader_fx_lib_glsl, defines, 0, 0, 0); + shader = GPU_shader_create(datatoc_gpu_shader_fx_dof_hq_vert_glsl, datatoc_gpu_shader_fx_dof_hq_frag_glsl, NULL, datatoc_gpu_shader_fx_lib_glsl, defines); break; case GPU_SHADER_FX_DEPTH_OF_FIELD_HQ_PASS_TWO: strcat(defines, "#define SECOND_PASS\n"); - shader = GPU_shader_create(datatoc_gpu_shader_fx_dof_hq_vert_glsl, datatoc_gpu_shader_fx_dof_hq_frag_glsl, datatoc_gpu_shader_fx_dof_hq_geo_glsl, datatoc_gpu_shader_fx_lib_glsl, - defines, GL_POINTS, GL_TRIANGLE_STRIP, 4); + shader = GPU_shader_create(datatoc_gpu_shader_fx_dof_hq_vert_glsl, datatoc_gpu_shader_fx_dof_hq_frag_glsl, datatoc_gpu_shader_fx_dof_hq_geo_glsl, datatoc_gpu_shader_fx_lib_glsl, defines); break; case GPU_SHADER_FX_DEPTH_OF_FIELD_HQ_PASS_THREE: strcat(defines, "#define THIRD_PASS\n"); - shader = GPU_shader_create(datatoc_gpu_shader_fx_dof_hq_vert_glsl, datatoc_gpu_shader_fx_dof_hq_frag_glsl, NULL, datatoc_gpu_shader_fx_lib_glsl, defines, 0, 0, 0); + shader = GPU_shader_create(datatoc_gpu_shader_fx_dof_hq_vert_glsl, datatoc_gpu_shader_fx_dof_hq_frag_glsl, NULL, datatoc_gpu_shader_fx_lib_glsl, defines); break; case GPU_SHADER_FX_DEPTH_RESOLVE: - shader = GPU_shader_create(datatoc_gpu_shader_fx_vert_glsl, datatoc_gpu_shader_fx_depth_resolve_glsl, NULL, NULL, defines, 0, 0, 0); + shader = GPU_shader_create(datatoc_gpu_shader_fullscreen_vert_glsl, datatoc_gpu_shader_fx_depth_resolve_glsl, NULL, NULL, defines); break; } - GG.shaders.fx_shaders[offset] = shader; + fx_shaders[offset] = shader; GPU_fx_shader_init_interface(shader, effect); } - return GG.shaders.fx_shaders[offset]; + return fx_shaders[offset]; } void GPU_shader_free_builtin_shaders(void) { - int i; - - if (GG.shaders.vsm_store) { - GPU_shader_free(GG.shaders.vsm_store); - GG.shaders.vsm_store = NULL; - } - - if (GG.shaders.sep_gaussian_blur) { - GPU_shader_free(GG.shaders.sep_gaussian_blur); - GG.shaders.sep_gaussian_blur = NULL; - } - - if (GG.shaders.smoke) { - GPU_shader_free(GG.shaders.smoke); - GG.shaders.smoke = NULL; - } - - if (GG.shaders.smoke_fire) { - GPU_shader_free(GG.shaders.smoke_fire); - GG.shaders.smoke_fire = NULL; - } - - if (GG.shaders.smoke_coba) { - GPU_shader_free(GG.shaders.smoke_coba); - GG.shaders.smoke_coba = NULL; + for (int i = 0; i < GPU_NUM_BUILTIN_SHADERS; ++i) { + if (builtin_shaders[i]) { + GPU_shader_free(builtin_shaders[i]); + builtin_shaders[i] = NULL; + } } - 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; + for (int i = 0; i < 2 * MAX_FX_SHADERS; ++i) { + if (fx_shaders[i]) { + GPU_shader_free(fx_shaders[i]); + fx_shaders[i] = NULL; } } } - - diff --git a/source/blender/gpu/intern/gpu_shader_private.h b/source/blender/gpu/intern/gpu_shader_private.h new file mode 100644 index 00000000000..f883773df17 --- /dev/null +++ b/source/blender/gpu/intern/gpu_shader_private.h @@ -0,0 +1,45 @@ +/* + * ***** 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 */ + + void *uniform_interface; /* cached uniform interface for shader. Data depends on shader */ + /* NOTE: ^-- only FX compositing shaders use this */ + + Gwn_ShaderInterface *interface; /* cached uniform & attrib interface for shader */ +}; + +#endif /* __GPU_SHADER_PRIVATE_H__ */ + diff --git a/source/blender/gpu/intern/gpu_texture.c b/source/blender/gpu/intern/gpu_texture.c index 1c97c2ce811..d6b641af225 100644 --- a/source/blender/gpu/intern/gpu_texture.c +++ b/source/blender/gpu/intern/gpu_texture.c @@ -49,9 +49,8 @@ static struct GPUTextureGlobal { } GG = {NULL, NULL, NULL}; /* 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_* */ @@ -62,43 +61,277 @@ struct GPUTexture { 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? */ + bool depth; /* is a depth texture? */ + bool stencil; /* is a stencil texture? */ + + unsigned int bytesize; /* number of byte for one pixel */ + int format; /* GPUTextureFormat */ + int components; /* number of color/alpha channels */ }; -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; + switch (tex->target) { + case GL_TEXTURE_1D: + return tex->bytesize * tex->w; + case GL_TEXTURE_1D_ARRAY: + case GL_TEXTURE_2D: + return tex->bytesize * tex->w * tex->h; + case GL_TEXTURE_2D_ARRAY: + case GL_TEXTURE_3D: + return tex->bytesize * tex->w * tex->h * tex->d; + case GL_TEXTURE_CUBE_MAP: + return tex->bytesize * 6 * tex->w * tex->h; + case GL_TEXTURE_CUBE_MAP_ARRAY: + return tex->bytesize * 6 * tex->w * tex->h * tex->d; + 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 = FTOCHAR((*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, bool *is_depth, bool *is_stencil, 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)) + { + *is_depth = true; + *is_stencil = false; + *data_format = GL_FLOAT; + *format = GL_DEPTH_COMPONENT; + } + else if (data_type == GPU_DEPTH24_STENCIL8) { + *is_depth = true; + *is_stencil = true; + *data_format = GL_UNSIGNED_INT_24_8; + *format = GL_DEPTH_STENCIL; + } + else { + *is_depth = false; + *is_stencil = false; + + /* Integer formats */ + if (ELEM(data_type, GPU_RG16I)) { + *data_format = GL_INT; + + 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; + + 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; + } + } + } - 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); + switch (data_type) { + case GPU_RGBA32F: + *bytesize = 32; + break; + case GPU_RG32F: + case GPU_RGBA16F: + *bytesize = 16; + break; + case GPU_RGB16F: + *bytesize = 12; + break; + case GPU_RG16F: + case GPU_RG16I: + case GPU_DEPTH24_STENCIL8: + case GPU_DEPTH_COMPONENT32F: + case GPU_RGBA8: + case GPU_R11F_G11F_B10F: + case GPU_R32F: + *bytesize = 4; + break; + case GPU_DEPTH_COMPONENT24: + *bytesize = 3; + break; + case GPU_DEPTH_COMPONENT16: + case GPU_R16F: + 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_RG32F: return GL_RG32F; + case GPU_RGB16F: return GL_RGB16F; + case GPU_RG16F: return GL_RG16F; + case GPU_RG16I: return GL_RG16I; + case GPU_RGBA8: return GL_RGBA8; + case GPU_R32F: return GL_R32F; + case GPU_R16F: return GL_R16F; + case GPU_RG8: return GL_RG8; + 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 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 components, int samples, + const bool can_rescale, char err_out[256]) +{ if (samples) { CLAMP_MAX(samples, GPU_max_color_texture_samples()); } @@ -106,264 +339,206 @@ static GPUTexture *GPU_texture_create_nD( GPUTexture *tex = MEM_callocN(sizeof(GPUTexture), "GPUTexture"); tex->w = w; tex->h = h; + tex->d = d; 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 = components; + + 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(components, data_type, &format, &data_format, &tex->depth, &tex->stencil, &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, 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 (tex->depth) { 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_MODE, GL_NONE); glTexParameteri(tex->target_base, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL); - glTexParameteri(tex->target_base, GL_DEPTH_TEXTURE_MODE, GL_INTENSITY); } 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); + 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); + } + + GPU_texture_unbind(tex); 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, int components, + 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->number = -1; tex->refcount = 1; - tex->target = GL_TEXTURE_3D; - tex->target_base = GL_TEXTURE_3D; - - glGenTextures(1, &tex->bindcode); - - if (!tex->bindcode) { - fprintf(stderr, "GPUTexture: texture create failed: %d\n", - (int)glGetError()); - GPU_texture_free(tex); - return NULL; - } - - tex->number = 0; - glBindTexture(tex->target, tex->bindcode); - - GPU_ASSERT_NO_GL_ERRORS("3D glBindTexture"); + tex->fb_attachment = -1; + tex->format = data_type; + tex->components = components; - type = GL_FLOAT; - if (channels == 4) { - format = GL_RGBA; - internalformat = GL_RGBA8; + if (d == 0) { + tex->target_base = tex->target = GL_TEXTURE_CUBE_MAP; } else { - format = GL_RED; - internalformat = GL_INTENSITY8; + BLI_assert(false && "Cubemap array Not implemented yet"); + // tex->target_base = tex->target = GL_TEXTURE_CUBE_MAP_ARRAY; } - /* 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); + internalformat = gpu_texture_get_format(components, data_type, &format, &data_format, &tex->depth, &tex->stencil, &tex->bytesize); - bool rescale = false; - int r_width; + gpu_texture_memory_footprint_add(tex); - glGetTexLevelParameteriv(GL_PROXY_TEXTURE_3D, 0, GL_TEXTURE_WIDTH, &r_width); + /* Generate Texture object */ + glGenTextures(1, &tex->bindcode); - 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 (!tex->bindcode) { + 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; } - /* 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 - - 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); - - 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]; - } - } - } + tex->number = 0; + glBindTexture(tex->target, tex->bindcode); - glTexImage3D(tex->target, 0, internalformat, tex->w, tex->h, tex->depth, 0, format, type, tex3d); + /* 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); - MEM_freeN(tex3d); + /* Texture Parameters */ + if (tex->depth) { + glTexParameteri(tex->target_base, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(tex->target_base, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(tex->target_base, GL_TEXTURE_COMPARE_MODE, GL_NONE); + glTexParameteri(tex->target_base, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL); } 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"); - } + glTexParameteri(tex->target_base, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(tex->target_base, GL_TEXTURE_MAG_FILTER, GL_LINEAR); } - - 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); + glTexParameteri(tex->target_base, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(tex->target_base, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameteri(tex->target_base, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); GPU_texture_unbind(tex); @@ -380,6 +555,7 @@ GPUTexture *GPU_texture_from_blender(Image *ima, ImageUser *iuser, int textarget /* 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 +574,16 @@ 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; 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 +595,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 +628,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 +653,129 @@ 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, 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, GPU_RGBA8, 4, 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_1D_custom( + int w, int channels, 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, 0, 0, 1, pixels, data_type, channels, 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]) -{ - GPUTexture *tex = GPU_texture_create_nD(w, h, 2, fpixels, 0, hdr, 4, samples, err_out); - - if (tex) - GPU_texture_unbind(tex); - return tex; +GPUTexture *GPU_texture_create_2D(int w, int h, const float *pixels, char err_out[256]) +{ + return GPU_texture_create_nD(w, h, 0, 2, pixels, GPU_RGBA8, 4, 0, false, err_out); } -GPUTexture *GPU_texture_create_depth(int w, int h, char err_out[256]) +GPUTexture *GPU_texture_create_2D_custom( + int w, int h, int channels, 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, 0, 2, pixels, data_type, channels, 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); +GPUTexture *GPU_texture_create_2D_multisample(int w, int h, const float *pixels, int samples, char err_out[256]) +{ + return GPU_texture_create_nD(w, h, 0, 2, pixels, GPU_RGBA8, 4, samples, false, err_out); +} - return tex; +GPUTexture *GPU_texture_create_2D_custom_multisample( + int w, int h, int channels, GPUTextureFormat data_type, const float *pixels, int samples, char err_out[256]) +{ + return GPU_texture_create_nD(w, h, 0, 2, pixels, data_type, channels, samples, false, 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_2D_array_custom(int w, int h, int d, int channels, GPUTextureFormat data_type, const float *pixels, char err_out[256]) { - GPUTexture *tex = GPU_texture_create_nD(size, size, 2, NULL, 0, GPU_HDR_FULL_FLOAT, 2, 0, err_out); + return GPU_texture_create_nD(w, h, d, 2, pixels, data_type, channels, 0, false, 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); +GPUTexture *GPU_texture_create_3D(int w, int h, int d, const float *pixels, char err_out[256]) +{ + return GPU_texture_create_nD(w, h, d, 3, pixels, GPU_RGBA8, 4, 0, true, err_out); +} - GPU_texture_unbind(tex); +GPUTexture *GPU_texture_create_3D_custom(int w, int h, int d, int channels, GPUTextureFormat data_type, const float *pixels, char err_out[256]) +{ + return GPU_texture_create_nD(w, h, d, 3, pixels, data_type, channels, 0, true, err_out); +} +GPUTexture *GPU_texture_create_cube_custom(int w, int channels, GPUTextureFormat data_type, const float *fpixels, char err_out[256]) +{ + const float *fpixels_px, *fpixels_py, *fpixels_pz, *fpixels_nx, *fpixels_ny, *fpixels_nz; + + 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, channels, 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_depth(int w, int h, char err_out[256]) { - GPUTexture *tex = GPU_texture_create_nD(w, h, 2, pixels, 0, GPU_HDR_HALF_FLOAT, 2, 0, err_out); + return GPU_texture_create_nD(w, h, 0, 2, NULL, GPU_DEPTH_COMPONENT24, 1, 0, false, err_out); +} - 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); +GPUTexture *GPU_texture_create_depth_with_stencil(int w, int h, char err_out[256]) +{ + return GPU_texture_create_nD(w, h, 0, 2, NULL, GPU_DEPTH24_STENCIL8, 1, 0, false, err_out); +} - GPU_texture_unbind(tex); - } +GPUTexture *GPU_texture_create_depth_multisample(int w, int h, int samples, char err_out[256]) +{ + return GPU_texture_create_nD(w, h, 0, 2, NULL, GPU_DEPTH_COMPONENT24, 1, samples, false, err_out); +} - return tex; +GPUTexture *GPU_texture_create_depth_with_stencil_multisample(int w, int h, int samples, char err_out[256]) +{ + return GPU_texture_create_nD(w, h, 0, 2, NULL, GPU_DEPTH24_STENCIL8, 1, samples, false, err_out); } -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->depth, &tex->stencil, &tex->bytesize); + + glBindTexture(tex->target, tex->bindcode); - GPU_texture_unbind(tex); + 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_2D = GPU_texture_create_2D(1, 1, color, NULL); + GG.invalid_tex_3D = GPU_texture_create_3D(1, 1, 1, color, NULL); } void GPU_invalid_tex_bind(int mode) @@ -627,21 +820,18 @@ void GPU_texture_bind(GPUTexture *tex, int number) if (number < 0) return; - GPU_ASSERT_NO_GL_ERRORS("Pre Texture Bind"); + if (number != 0) + 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; + if (number != 0) + glActiveTexture(GL_TEXTURE0); - GPU_ASSERT_NO_GL_ERRORS("Post Texture Bind"); + tex->number = number; } void GPU_texture_unbind(GPUTexture *tex) @@ -653,18 +843,16 @@ void GPU_texture_unbind(GPUTexture *tex) 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); + if (tex->number != 0) + glActiveTexture(GL_TEXTURE0 + tex->number); - tex->number = -1; + glBindTexture(tex->target, 0); - GPU_ASSERT_NO_GL_ERRORS("Post Texture Unbind"); + if (tex->number != 0) + glActiveTexture(GL_TEXTURE0); + + tex->number = -1; } int GPU_texture_bound_number(GPUTexture *tex) @@ -672,7 +860,7 @@ int GPU_texture_bound_number(GPUTexture *tex) return tex->number; } -void GPU_texture_filter_mode(GPUTexture *tex, bool compare, bool use_filter) +void GPU_texture_generate_mipmap(GPUTexture *tex) { if (tex->number >= GPU_max_textures()) { fprintf(stderr, "Not enough texture slots.\n"); @@ -682,29 +870,104 @@ void GPU_texture_filter_mode(GPUTexture *tex, bool compare, bool use_filter) if (tex->number == -1) return; - GPU_ASSERT_NO_GL_ERRORS("Pre Texture Unbind"); + if (tex->number != 0) + glActiveTexture(GL_TEXTURE0 + tex->number); - GLenum arbnumber = (GLenum)((GLuint)GL_TEXTURE0 + tex->number); - if (tex->number != 0) glActiveTexture(arbnumber); + glGenerateMipmap(tex->target_base); - 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); + if (tex->number != 0) + glActiveTexture(GL_TEXTURE0); +} + +void GPU_texture_compare_mode(GPUTexture *tex, bool use_compare) +{ + if (tex->number >= GPU_max_textures()) { + fprintf(stderr, "Not enough texture slots.\n"); + return; + } + + if (tex->number == -1) + return; + + if (tex->number != 0) + glActiveTexture(GL_TEXTURE0 + tex->number); + + /* TODO viewport: use GL_COMPARE_REF_TO_TEXTURE after we switch to core profile */ + if (tex->depth) + glTexParameteri(tex->target_base, GL_TEXTURE_COMPARE_MODE, use_compare ? GL_COMPARE_R_TO_TEXTURE : GL_NONE); + + if (tex->number != 0) + glActiveTexture(GL_TEXTURE0); +} + +void GPU_texture_filter_mode(GPUTexture *tex, bool use_filter) +{ + if (tex->number >= GPU_max_textures()) { + fprintf(stderr, "Not enough texture slots.\n"); + return; } - if (use_filter) { - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + if (tex->number == -1) + return; + + if (tex->number != 0) + glActiveTexture(GL_TEXTURE0 + tex->number); + + GLenum filter = use_filter ? GL_LINEAR : GL_NEAREST; + glTexParameteri(tex->target_base, GL_TEXTURE_MAG_FILTER, filter); + glTexParameteri(tex->target_base, GL_TEXTURE_MIN_FILTER, filter); + + if (tex->number != 0) + glActiveTexture(GL_TEXTURE0); +} + +void GPU_texture_mipmap_mode(GPUTexture *tex, bool use_mipmap, bool use_filter) +{ + if (tex->number >= GPU_max_textures()) { + fprintf(stderr, "Not enough texture slots.\n"); + return; } - else { - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + + if (tex->number == -1) + return; + + if (tex->number != 0) + glActiveTexture(GL_TEXTURE0 + tex->number); + + GLenum mipmap = (use_filter) + ? use_mipmap ? GL_LINEAR_MIPMAP_LINEAR : GL_LINEAR + : use_mipmap ? GL_NEAREST_MIPMAP_LINEAR : GL_NEAREST; + glTexParameteri(tex->target_base, GL_TEXTURE_MIN_FILTER, mipmap); + + GLenum filter = use_filter ? GL_LINEAR : GL_NEAREST; + glTexParameteri(tex->target_base, GL_TEXTURE_MAG_FILTER, filter); + + if (tex->number != 0) + glActiveTexture(GL_TEXTURE0); +} + +void GPU_texture_wrap_mode(GPUTexture *tex, bool use_repeat) +{ + if (tex->number >= GPU_max_textures()) { + fprintf(stderr, "Not enough texture slots.\n"); + return; } - if (tex->number != 0) glActiveTexture(GL_TEXTURE0); - GPU_ASSERT_NO_GL_ERRORS("Post Texture Unbind"); + if (tex->number == -1) + return; + + if (tex->number != 0) + glActiveTexture(GL_TEXTURE0 + tex->number); + + GLenum repeat = use_repeat ? GL_REPEAT : GL_CLAMP_TO_EDGE; + glTexParameteri(tex->target_base, GL_TEXTURE_WRAP_S, repeat); + if (tex->target_base != GL_TEXTURE_1D) + glTexParameteri(tex->target_base, GL_TEXTURE_WRAP_T, repeat); + if (tex->target_base == GL_TEXTURE_3D) + glTexParameteri(tex->target_base, GL_TEXTURE_WRAP_R, repeat); + + if (tex->number != 0) + glActiveTexture(GL_TEXTURE0); } void GPU_texture_free(GPUTexture *tex) @@ -720,6 +983,8 @@ void GPU_texture_free(GPUTexture *tex) if (tex->bindcode && !tex->fromblender) glDeleteTextures(1, &tex->bindcode); + gpu_texture_memory_footprint_remove(tex); + MEM_freeN(tex); } } @@ -744,11 +1009,21 @@ int GPU_texture_height(const GPUTexture *tex) return tex->h; } -int GPU_texture_depth(const GPUTexture *tex) +int GPU_texture_format(const GPUTexture *tex) +{ + return tex->format; +} + +bool GPU_texture_depth(const GPUTexture *tex) { return tex->depth; } +bool GPU_texture_stencil(const GPUTexture *tex) +{ + return tex->stencil; +} + int GPU_texture_opengl_bindcode(const GPUTexture *tex) { return tex->bindcode; diff --git a/source/blender/gpu/intern/gpu_uniformbuffer.c b/source/blender/gpu/intern/gpu_uniformbuffer.c new file mode 100644 index 00000000000..6d52dab5a1f --- /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..83b9a8f0b0e --- /dev/null +++ b/source/blender/gpu/intern/gpu_viewport.c @@ -0,0 +1,704 @@ +/* + * ***** 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 "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 "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 { + float pad[4]; + + /* debug */ + GPUTexture *debug_depth; + 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 */ +}; + +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); + +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(); + GPU_offscreen_viewport_data_get(ofs, &viewport->fbl->default_fb, &viewport->txl->color, &viewport->txl->depth); + viewport->size[0] = GPU_offscreen_width(ofs); + viewport->size[1] = GPU_offscreen_height(ofs); + return viewport; +} +/** + * Clear vars assigned from offscreen, so we don't free data owned by `GPUOffScreen`. + */ +void GPU_viewport_clear_from_offscreen(GPUViewport *viewport) +{ + viewport->fbl->default_fb = NULL; + viewport->txl->color = NULL; + viewport->txl->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]; +} + +/** + * 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 channels, int format) +{ + GPUTexture *tex; + + for (ViewportTempTexture *tmp_tex = viewport->tex_pool.first; tmp_tex; tmp_tex = tmp_tex->next) { + if ((GPU_texture_width(tmp_tex->texture) == width) && + (GPU_texture_height(tmp_tex->texture) == height) && + (GPU_texture_format(tmp_tex->texture) == format)) + { + /* 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_custom(width, height, channels, format, NULL, NULL); + + 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); + } +} + +void GPU_viewport_bind(GPUViewport *viewport, const rcti *rect) +{ + DefaultFramebufferList *dfbl = viewport->fbl; + DefaultTextureList *dtxl = viewport->txl; + 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); + } + } + + gpu_viewport_texture_pool_clear_users(viewport); + + /* Multisample Buffer */ + if (U.ogl_multisamples > 0) { + if (!dfbl->default_fb) { + bool ok = true; + viewport->samples = U.ogl_multisamples; + + dfbl->multisample_fb = GPU_framebuffer_create(); + if (!dfbl->multisample_fb) { + ok = false; + goto cleanup_multisample; + } + + /* Color */ + dtxl->multisample_color = GPU_texture_create_2D_multisample(rect_w, rect_h, NULL, U.ogl_multisamples, NULL); + if (!dtxl->multisample_color) { + ok = false; + goto cleanup_multisample; + } + + if (!GPU_framebuffer_texture_attach(dfbl->multisample_fb, dtxl->multisample_color, 0, 0)) { + ok = false; + goto cleanup_multisample; + } + + /* Depth */ + dtxl->multisample_depth = GPU_texture_create_depth_with_stencil_multisample(rect_w, rect_h, + U.ogl_multisamples, NULL); + + if (!dtxl->multisample_depth) { + ok = false; + goto cleanup_multisample; + } + + if (!GPU_framebuffer_texture_attach(dfbl->multisample_fb, dtxl->multisample_depth, 0, 0)) { + ok = false; + goto cleanup_multisample; + } + else if (!GPU_framebuffer_check_valid(dfbl->multisample_fb, NULL)) { + ok = false; + goto cleanup_multisample; + } + +cleanup_multisample: + if (!ok) { + GPU_viewport_free(viewport); + MEM_freeN(viewport); + return; + } + } + } + + if (!dfbl->default_fb) { + bool ok = true; + viewport->size[0] = rect_w; + viewport->size[1] = rect_h; + + dfbl->default_fb = GPU_framebuffer_create(); + if (!dfbl->default_fb) { + ok = false; + goto cleanup; + } + + /* Color */ + dtxl->color = GPU_texture_create_2D(rect_w, rect_h, NULL, NULL); + if (!dtxl->color) { + ok = false; + goto cleanup; + } + + if (!GPU_framebuffer_texture_attach(dfbl->default_fb, dtxl->color, 0, 0)) { + ok = false; + goto cleanup; + } + + /* Depth */ + dtxl->depth = GPU_texture_create_depth_with_stencil(rect_w, rect_h, NULL); + + if (dtxl->depth) { + /* Define texture parameters */ + GPU_texture_bind(dtxl->depth, 0); + GPU_texture_compare_mode(dtxl->depth, false); + GPU_texture_filter_mode(dtxl->depth, true); + GPU_texture_unbind(dtxl->depth); + } + else { + ok = false; + goto cleanup; + } + + if (!GPU_framebuffer_texture_attach(dfbl->default_fb, dtxl->depth, 0, 0)) { + ok = false; + goto cleanup; + } + else if (!GPU_framebuffer_check_valid(dfbl->default_fb, NULL)) { + ok = false; + goto cleanup; + } + +cleanup: + if (!ok) { + GPU_viewport_free(viewport); + MEM_freeN(viewport); + DRW_opengl_context_disable(); + return; + } + + GPU_framebuffer_restore(); + } + + GPU_framebuffer_slots_bind(dfbl->default_fb, 0); +} + +static void draw_ofs_to_screen(GPUViewport *viewport, const rcti *rect) +{ + 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); + + Gwn_VertFormat *format = immVertexFormat(); + unsigned int texcoord = GWN_vertformat_attr_add(format, "texCoord", GWN_COMP_F32, 2, GWN_FETCH_FLOAT); + unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_3D_IMAGE_MODULATE_ALPHA); + GPU_texture_bind(color, 0); + + immUniform1i("image", 0); /* default GL_TEXTURE0 unit */ + + immBegin(GWN_PRIM_TRI_STRIP, 4); + + immAttrib2f(texcoord, 0.0f, 0.0f); + immVertex2f(pos, rect->xmin, rect->ymin); + + immAttrib2f(texcoord, 1.0f, 0.0f); + immVertex2f(pos, rect->xmin + w, rect->ymin); + + immAttrib2f(texcoord, 0.0f, 1.0f); + immVertex2f(pos, rect->xmin, rect->ymin + h); + + immAttrib2f(texcoord, 1.0f, 1.0f); + immVertex2f(pos, rect->xmin + w, rect->ymin + h); + + immEnd(); + + GPU_texture_unbind(color); + + immUnbindProgram(); +} + +void GPU_viewport_unbind(GPUViewport *viewport) +{ + DefaultFramebufferList *dfbl = viewport->fbl; + + if (dfbl->default_fb) { + GPU_framebuffer_texture_unbind(NULL, NULL); + GPU_framebuffer_restore(); + } + + DRW_opengl_context_disable(); + + if (dfbl->default_fb) { + glEnable(GL_SCISSOR_TEST); + glDisable(GL_DEPTH_TEST); + } +} + +void GPU_viewport_draw_to_screen(GPUViewport *viewport, const rcti *rect) +{ + DefaultFramebufferList *dfbl = viewport->fbl; + + if (dfbl->default_fb) { + /* This might be bandwidth limiting */ + draw_ofs_to_screen(viewport, rect); + } +} + +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.calls_generate != NULL) { + BLI_mempool_destroy(viewport->vmempool.calls_generate); + } + 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); + + GPU_viewport_debug_depth_free(viewport); +} + +/****************** debug ********************/ + +bool GPU_viewport_debug_depth_create(GPUViewport *viewport, int width, int height, char err_out[256]) +{ + viewport->debug_depth = GPU_texture_create_2D_custom(width, height, 4, GPU_RGBA16F, NULL, err_out); + return (viewport->debug_depth != NULL); +} + +void GPU_viewport_debug_depth_free(GPUViewport *viewport) +{ + if (viewport->debug_depth != NULL) { + MEM_freeN(viewport->debug_depth); + viewport->debug_depth = NULL; + } +} + +void GPU_viewport_debug_depth_store(GPUViewport *viewport, const int x, const int y) +{ + const int w = GPU_texture_width(viewport->debug_depth); + const int h = GPU_texture_height(viewport->debug_depth); + + GPU_texture_bind(viewport->debug_depth, 0); + glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT24, x, y, w, h, 0); + GPU_texture_unbind(viewport->debug_depth); +} + +void GPU_viewport_debug_depth_draw(GPUViewport *viewport, const float znear, const float zfar) +{ + const float w = (float)GPU_texture_width(viewport->debug_depth); + const float h = (float)GPU_texture_height(viewport->debug_depth); + + Gwn_VertFormat *format = immVertexFormat(); + unsigned int texcoord = GWN_vertformat_attr_add(format, "texCoord", GWN_COMP_F32, 2, GWN_FETCH_FLOAT); + unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_3D_IMAGE_DEPTH); + + GPU_texture_bind(viewport->debug_depth, 0); + + immUniform1f("znear", znear); + immUniform1f("zfar", zfar); + immUniform1i("image", 0); /* default GL_TEXTURE0 unit */ + + immBegin(GWN_PRIM_TRI_STRIP, 4); + + immAttrib2f(texcoord, 0.0f, 0.0f); + immVertex2f(pos, 0.0f, 0.0f); + + immAttrib2f(texcoord, 1.0f, 0.0f); + immVertex2f(pos, w, 0.0f); + + immAttrib2f(texcoord, 0.0f, 1.0f); + immVertex2f(pos, 0.0f, h); + + immAttrib2f(texcoord, 1.0f, 1.0f); + immVertex2f(pos, w, h); + + immEnd(); + + GPU_texture_unbind(viewport->debug_depth); + + immUnbindProgram(); +} + +int GPU_viewport_debug_depth_width(const GPUViewport *viewport) +{ + return GPU_texture_width(viewport->debug_depth); +} + +int GPU_viewport_debug_depth_height(const GPUViewport *viewport) +{ + return GPU_texture_height(viewport->debug_depth); +} + +bool GPU_viewport_debug_depth_is_valid(GPUViewport *viewport) +{ + return viewport->debug_depth != NULL; +} 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_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_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_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_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..10b5fad7972 --- /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_fullscreen_vert.glsl b/source/blender/gpu/shaders/gpu_shader_fullscreen_vert.glsl new file mode 100644 index 00000000000..fc5cc1cdcc3 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_fullscreen_vert.glsl @@ -0,0 +1,10 @@ + +in vec2 pos; +in vec2 uvs; +out vec4 uvcoordsvar; + +void main() +{ + uvcoordsvar = vec4(uvs, 0.0, 0.0); + gl_Position = vec4(pos, 0.0, 1.0); +} diff --git a/source/blender/gpu/shaders/gpu_shader_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..7586050b258 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; @@ -69,7 +70,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 +91,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_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..c2b25cc8011 --- /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); +}
\ No newline at end of file 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_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_instance_bone_envelope_solid_vert.glsl b/source/blender/gpu/shaders/gpu_shader_instance_bone_envelope_solid_vert.glsl new file mode 100644 index 00000000000..d0f2a8dcd51 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_instance_bone_envelope_solid_vert.glsl @@ -0,0 +1,121 @@ + + +/* This shader essentially operates in Object space, where it aligns given geometry with bone, scales it accordingly + * to given radii, and then does usual basic solid operations. + * Note that if one of head/tail radius is negative, it assumes it only works on the other end of the bone + * (used to draw head/tail spheres). */ + + +uniform mat4 ViewMatrix; +uniform mat4 ViewProjectionMatrix; + + +/* ---- Instanciated Attribs ---- */ +in vec4 pos; /* w encodes head (== 0.0f), tail (== 1.0f) or in-between. */ + +/* ---- Per instance Attribs ---- */ +in mat4 InstanceModelMatrix; +in vec4 color; + +in float radius_head; +in float radius_tail; + + +out vec3 normal; +flat out vec4 finalColor; + + +void main() +{ + /* We get head/tail in object space. */ + vec4 head = InstanceModelMatrix * vec4(0.0f, 0.0f, 0.0f, 1.0f); + vec4 tail = InstanceModelMatrix * vec4(0.0f, 1.0f, 0.0f, 1.0f); + + /* We need rotation from bone mat, but not scaling. */ + mat3 bone_mat = mat3(InstanceModelMatrix); + bone_mat[0] = normalize(bone_mat[0]); + bone_mat[1] = normalize(bone_mat[1]); + bone_mat[2] = normalize(bone_mat[2]); + + mat3 nor_mat = transpose(inverse(mat3(ViewMatrix) * bone_mat)); + + /* Where does this comes from???? Don't know why, but is mandatory anyway... :/ */ + const float size = 2.0f; + + head.xyz *= size; + tail.xyz *= size; + + bool head_only = (radius_tail < 0.0f); + bool tail_only = (radius_head < 0.0f); + /* == 0: head; == 1: tail; in-between: along bone. */ + float head_fac = head_only ? 0.0f : (tail_only ? 1.0f : pos.w); + + vec4 ob_pos; + vec4 ob_bone_origin; + float radius; + + /* head */ + if (head_fac <= 0.0f) { + if (!head_only) { + /* We are drawing the body itself, need to adjust start/end positions and radius! */ + vec3 bone_vec = tail.xyz - head.xyz; + float len = length(bone_vec); + + if (len > (radius_head + radius_tail)) { + float fac = (len - radius_head) / len; + radius = fac * radius_head + (1.0f - fac) * radius_tail; + bone_vec /= len; + ob_bone_origin = vec4(head.xyz + bone_vec * radius_head * size, 1.0f); + } + else { + radius = (radius_head + radius_tail) / 2.0f; + ob_bone_origin = (head + tail) / 2.0f; + } + } + else { + radius = radius_head; + ob_bone_origin = head; + } + } + /* tail */ + else if (head_fac >= 1.0f) { + if (!tail_only) { + /* We are drawing the body itself, need to adjust start/end positions and radius! */ + vec3 bone_vec = tail.xyz - head.xyz; + float len = length(bone_vec); + + if (len > (radius_head + radius_tail)) { + float fac = (len - radius_tail) / len; + radius = fac * radius_tail + (1.0f - fac) * radius_head; + bone_vec /= len; + ob_bone_origin = vec4(tail.xyz - bone_vec * radius_tail * size, 1.0f); + } + else { + radius = (radius_head + radius_tail) / 2.0f; + ob_bone_origin = (head + tail) / 2.0f; + } + } + else { + radius = radius_tail; + ob_bone_origin = tail; + } + } + /* Body of the bone */ +#if 0 /* Note: not used currently! */ + else { + float tail_fac = 1.0f - head_fac; + radius = radius_head * head_fac + radius_tail * tail_fac; + ob_bone_origin = head * head_fac + tail * tail_fac; + } +#endif + + /* Yep, since input pos is unit sphere coordinates, it's also our normal. */ + vec3 nor = pos.xyz; + ob_pos = pos * radius * size; + ob_pos.xyz = bone_mat * ob_pos.xyz; + ob_pos.w = 1.0f; + + gl_Position = ViewProjectionMatrix * (ob_pos + ob_bone_origin); + normal = normalize(nor_mat * nor); + finalColor = color; +} diff --git a/source/blender/gpu/shaders/gpu_shader_instance_bone_envelope_wire_vert.glsl b/source/blender/gpu/shaders/gpu_shader_instance_bone_envelope_wire_vert.glsl new file mode 100644 index 00000000000..1bdad924bd2 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_instance_bone_envelope_wire_vert.glsl @@ -0,0 +1,100 @@ + + +/* This shader takes a 2D shape, puts it in 3D Object space such that is stays aligned with view and bone, + * and scales head/tail/distance according to per-instance attributes + * (and 'role' of current vertex, encoded in zw input, head or tail, and inner or outer for distance outline). + * It is used for both the distance outline drawing, and the wire version of envelope bone. + * Note that if one of head/tail radius is negative, it assumes it only works on the other end of the bone + * (used to draw head/tail spheres). */ + +uniform mat4 ViewMatrix; +uniform mat4 ProjectionMatrix; + +/* ---- Instanciated Attribs ---- */ +in vec4 pos; /* z encodes head (== 0.0f), tail (== 1.0f) or in-between; w encodes inner (0.0f) or outer border. */ + +/* ---- Per instance Attribs ---- */ +in mat4 InstanceModelMatrix; +in vec4 color; + +in float radius_head; +in float radius_tail; +in float distance; + + +flat out vec4 finalColor; + + +void main() +{ + /* We get head/tail in object space. */ + mat4 bone_mat = InstanceModelMatrix; + vec4 head = bone_mat * vec4(0.0f, 0.0f, 0.0f, 1.0f); + vec4 tail = bone_mat * vec4(0.0f, 1.0f, 0.0f, 1.0f); + + /* We generate our XY axes in object space, Y axis being aligned with bone in view space. */ + mat4 obview_mat = ViewMatrix; + mat4 iobview_mat = inverse(obview_mat); + + vec4 view_bone_vec = obview_mat * normalize(tail - head); + view_bone_vec.z = 0.0f; + if (length(view_bone_vec.xy) <= 1e-5f) { + /* A bit weak, but will do the job for now. + * Ideally we could compute head/tail radius in view space, and take larger one... */ + if (view_bone_vec.x > view_bone_vec.y) { + view_bone_vec.x = 1e-5f; + } + else { + view_bone_vec.y = 1e-5f; + } + } + vec3 bone_axis_y = normalize((iobview_mat * view_bone_vec).xyz); + vec3 bone_axis_x = normalize(cross(bone_axis_y, iobview_mat[2].xyz)); + + /* Where does this comes from???? Don't know why, but is mandatory anyway... :/ */ + float size = 2.0f; + + head.xyz *= size; + tail.xyz *= size; + + bool head_only = (radius_tail < 0.0f); + bool tail_only = (radius_head < 0.0f); + /* == 0: head; == 1: tail; in-between: along bone. */ + float head_fac = head_only ? 0.0f : (tail_only ? 1.0f : pos.z); + bool do_distance_offset = (pos.w != 0.0f) && (distance >= 0.0f); + + vec2 xy_pos = pos.xy; + vec4 ob_pos; + + vec4 ob_bone_origin; + float radius; + + /* head */ + if (head_fac <= 0.0f) { + radius = radius_head; + ob_bone_origin = head; + } + /* tail */ + else if (head_fac >= 1.0f) { + radius = radius_tail; + ob_bone_origin = tail; + } + /* Body of the bone */ +#if 0 /* Note: not used currently! */ + else { + float tail_fac = 1.0f - head_fac; + radius = radius_head * head_fac + radius_tail * tail_fac; + ob_bone_origin = head * head_fac + tail * tail_fac; + } +#endif + + if (do_distance_offset) { + radius += distance; + } + + xy_pos = xy_pos * radius * size; + + ob_pos = ob_bone_origin + vec4(bone_axis_x * xy_pos.x + bone_axis_y * xy_pos.y, 1.0f); + gl_Position = ProjectionMatrix * obview_mat * ob_pos; + finalColor = color; +} 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..142df70e68a --- /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); +}
\ No newline at end of file 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..6f580ef3ff6 --- /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_mball_handles_vert.glsl b/source/blender/gpu/shaders/gpu_shader_instance_mball_handles_vert.glsl new file mode 100644 index 00000000000..819199c26c7 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_instance_mball_handles_vert.glsl @@ -0,0 +1,36 @@ + +/* This shader takes a 2D shape, puts it in 3D Object space such that is stays aligned with view, + * and scales the shape according to per-instance attributes + * Note that if the stiffness is zero, it assumes the scale is directly multiplied by the radius */ + + + #define M_PI_2 1.570796f // pi/2 + +uniform mat4 ViewProjectionMatrix; +uniform vec3 screen_vecs[2]; + +/* ---- Instanciated Attribs ---- */ +in vec2 pos; + +/* ---- Per instance Attribs ---- */ +in mat3x4 ScaleTranslationMatrix; +in float radius; +in vec3 color; + +flat out vec4 finalColor; + +void main() +{ + mat3 Scamat = mat3(ScaleTranslationMatrix); + vec4 world_pos = vec4( + ScaleTranslationMatrix[0][3], + ScaleTranslationMatrix[1][3], + ScaleTranslationMatrix[2][3], + 1.0); + + vec3 screen_pos = screen_vecs[0].xyz * pos.x + screen_vecs[1].xyz * pos.y; + world_pos.xyz += Scamat * (screen_pos * radius); + + gl_Position = ViewProjectionMatrix * world_pos; + finalColor = vec4(color, 1.0); +} 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_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 1f5ffbdcc7e..1269f81180c 100644 --- a/source/blender/gpu/shaders/gpu_shader_material.glsl +++ b/source/blender/gpu/shaders/gpu_shader_material.glsl @@ -1,11 +1,57 @@ + +uniform mat4 ModelViewMatrix; +#ifndef EEVEE_ENGINE +uniform mat4 ProjectionMatrix; +uniform mat4 ViewMatrixInverse; +uniform mat4 ViewMatrix; +#endif +uniform mat4 ModelMatrix; +uniform mat4 ModelMatrixInverse; +uniform mat4 ModelViewMatrixInverse; +uniform mat4 ProjectionMatrixInverse; +uniform mat3 NormalMatrix; +uniform vec4 CameraTexCoFactors; + +/* 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; + return dot(color.rgb, vec3(0.2126, 0.7152, 0.0722)); #else - return (color.r + color.g + color.b) / 3.0; + return (color.r + color.g + color.b) * 0.333333; #endif } @@ -53,7 +99,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,15 +201,18 @@ 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); + vcol = vec4(attvcol.xyz, 1.0); } void uv_attribute(vec2 attuv, out vec3 uv) @@ -177,7 +226,7 @@ void geom( 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); + view = (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); @@ -421,13 +470,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) @@ -443,7 +492,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); } @@ -485,9 +534,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)); @@ -496,9 +545,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)); @@ -818,22 +867,23 @@ 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; + vec3 factors = vec3(0.2126, 0.7152, 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 */ + vec3 factors = vec3(0.35, 0.45, 0.2); /* keep these factors in sync with texture.h:RGBTOBW */ #endif + 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; } @@ -918,12 +968,12 @@ void texture_flip_blend(vec3 vec, out vec3 outvec) void texture_blend_lin(vec3 vec, out float outval) { - outval = (1.0 + vec.x) / 2.0; + outval = (1.0 + vec.x) * 0.5; } void texture_blend_quad(vec3 vec, out float outval) { - outval = max((1.0 + vec.x) / 2.0, 0.0); + outval = max((1.0 + vec.x) * 0.5, 0.0); outval *= outval; } @@ -934,12 +984,12 @@ void texture_wood_sin(vec3 vec, out float value, out vec4 color, out vec3 normal value = wi; color = vec4(wi, wi, wi, 1.0); - normal = vec3(0.0, 0.0, 0.0); + normal = vec3(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); + color = texture(ima, (vec.xy + vec2(1.0)) * 0.5); value = color.a; normal.x = 2.0 * (color.r - 0.5); @@ -1279,11 +1329,7 @@ void mtex_har_divide(float har, out float outhar) 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; + outhar = clamp(har * 128.0, 1.0, 511.0); } void mtex_alpha_from_col(vec4 col, out float alpha) @@ -1352,14 +1398,14 @@ vec3 mtex_2d_mapping(vec3 vec) void mtex_cube_map(vec3 co, samplerCube ima, out float value, out vec4 color) { - color = textureCube(ima, co); + color = texture(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); + color = texture(ima, reflecteddirection); value = color.a; } @@ -1370,13 +1416,13 @@ void mtex_cube_map_refl( 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); + color = texture(ima, reflecteddirection); value = 1.0; } void mtex_image(vec3 texco, sampler2D ima, out float value, out vec4 color) { - color = texture2D(ima, texco.xy); + color = texture(ima, texco.xy); value = 1.0; } @@ -1387,7 +1433,7 @@ void mtex_normal(vec3 texco, sampler2D ima, out vec3 normal) // 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); + vec4 color = texture(ima, texco.xy); normal = 2.0 * (vec3(-color.r, color.g, color.b) - vec3(-0.5, 0.5, 0.5)); } @@ -1415,8 +1461,8 @@ void mtex_bump_init_objspace( 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); + mat3 obj2view = to_mat3(ModelViewMatrix); + mat3 view2obj = to_mat3(ModelViewMatrixInverse); vec3 vSigmaS = view2obj * dFdx(surf_pos); vec3 vSigmaT = view2obj * dFdy(surf_pos); @@ -1483,9 +1529,9 @@ void mtex_bump_tap3( 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); + rgbtobw(texture(ima, STll), Hll); + rgbtobw(texture(ima, STlr), Hlr); + rgbtobw(texture(ima, STul), Hul); dBs = hScale * (Hlr - Hll); dBt = hScale * (Hul - Hll); @@ -1510,10 +1556,10 @@ void mtex_bump_bicubic( 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); + rgbtobw(texture(ima, STl), Hl); + rgbtobw(texture(ima, STr), Hr); + rgbtobw(texture(ima, STd), Hd); + rgbtobw(texture(ima, STu), Hu); vec2 dHdxy = vec2(Hr - Hl, Hu - Hd); float fBlend = clamp(1.0 - textureQueryLOD(ima, texco.xy).x, 0.0, 1.0); @@ -1599,11 +1645,11 @@ void mtex_bump_tap5( 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); + rgbtobw(texture(ima, STc), Hc); + rgbtobw(texture(ima, STl), Hl); + rgbtobw(texture(ima, STr), Hr); + rgbtobw(texture(ima, STd), Hd); + rgbtobw(texture(ima, STu), Hu); dBs = hScale * (Hr - Hl); dBt = hScale * (Hu - Hd); @@ -1620,7 +1666,7 @@ void mtex_bump_deriv( // 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); + vec2 dBduv = hScale * dim * (2.0 * texture(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; @@ -1672,7 +1718,7 @@ void mtex_nspace_world(mat4 viewmat, vec3 texnormal, out vec3 outnormal) void mtex_nspace_object(vec3 texnormal, out vec3 outnormal) { - outnormal = normalize(gl_NormalMatrix * texnormal); + outnormal = normalize(NormalMatrix * texnormal); } void mtex_blend_normal(float norfac, vec3 normal, vec3 newnormal, out vec3 outnormal) @@ -1729,7 +1775,7 @@ void lamp_falloff_invcoefficients(float coeff_const, float coeff_lin, float coef void lamp_falloff_curve(float lampdist, sampler2D curvemap, float dist, out float visifac) { - visifac = texture2D(curvemap, vec2(dist / lampdist, 0.0)).x; + visifac = texture(curvemap, vec2(dist / lampdist, 0.0)).x; } void lamp_visibility_sphere(float lampdist, float dist, float visifac, out float outvisifac) @@ -1796,7 +1842,7 @@ void lamp_visibility_clamp(float visifac, out float outvisifac) 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); + outvec = (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) @@ -1830,7 +1876,7 @@ void world_blend(vec3 vec, out float blend) 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); + view = (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) @@ -2022,7 +2068,7 @@ 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); + outcol = vec3(0.0); } void shade_hemi_spec(vec3 vn, vec3 lv, vec3 view, float spec, float hard, float visifac, out float t) @@ -2179,12 +2225,12 @@ void shade_madd(vec4 col, vec4 col1, vec4 col2, out vec4 outcol) void shade_add_clamped(vec4 col1, vec4 col2, out vec4 outcol) { - outcol = col1 + max(col2, vec4(0.0, 0.0, 0.0, 0.0)); + outcol = col1 + max(col2, vec4(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)); + outcol = col + max(col1 * col2, vec4(0.0)); } void env_apply(vec4 col, vec3 hor, vec3 zen, vec4 f, mat4 vm, vec3 vn, out vec4 outcol) @@ -2221,7 +2267,7 @@ void shade_obcolor(vec4 col, vec4 obcol, out vec4 outcol) void ramp_rgbtobw(vec3 color, out float outval) { - outval = color.r * 0.3 + color.g * 0.58 + color.b * 0.12; + outval = dot(color, vec3(0.3, 0.58, 0.12)); } void shade_only_shadow(float i, float shadfac, float energy, vec3 shadcol, out vec3 outshadrgb) @@ -2257,10 +2303,12 @@ void test_shadowbuf( //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 + 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 = textureProj(shadowmap, co); + } + else { result = 1.0; + } } } @@ -2274,7 +2322,7 @@ void test_shadowbuf_vsm( 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; + vec2 moments = textureProj(shadowmap, co).rg; float dist = co.z / co.w; float p = 0.0; @@ -2333,7 +2381,7 @@ void shade_light_texture(vec3 rco, sampler2D cookie, mat4 shadowpersmat, out vec vec4 co = shadowpersmat * vec4(rco, 1.0); - result = texture2DProj(cookie, co); + result = textureProj(cookie, co); } void shade_exposure_correct(vec3 col, float linfac, float logfac, out vec3 outcol) @@ -2348,7 +2396,7 @@ void shade_mist_factor( if (enable == 1.0) { float fac, zcor; - zcor = (gl_ProjectionMatrix[3][3] == 0.0) ? length(co) : -co[2]; + zcor = (ProjectionMatrix[3][3] == 0.0) ? length(co) : -co[2]; fac = clamp((zcor - miststa) / mistdist, 0.0, 1.0); if (misttype == 0.0) fac *= fac; @@ -2423,7 +2471,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) @@ -2436,7 +2492,6 @@ int quick_floor(float x) return int(x) - ((x < 0) ? 1 : 0); } -#ifdef BIT_OPERATIONS float integer_noise(int n) { int nn; @@ -2500,7 +2555,6 @@ vec3 cellnoise_color(vec3 p) return vec3(r, g, b); } -#endif // BIT_OPERATIONS float floorfrac(float x, out int i) { @@ -2562,41 +2616,107 @@ vec3 rotate_vector(vec3 p, vec3 n, float theta) { ); } +void prepare_tangent( + float anisotropic, float anisotropic_rotation, float roughness, vec3 N, vec3 T, + out vec3 X, out vec3 Y, out float ax, out float ay) +{ + /* rotate tangent */ + if (anisotropic_rotation != 0.0) { + T = rotate_vector(T, N, anisotropic_rotation * 2.0 * M_PI); + } + + Y = normalize(cross(T, N)); + + float aspect = sqrt(1.0 - anisotropic * 0.9); + float a = sqr(roughness); + ax = max(0.001, a / aspect); + ay = max(0.001, a * aspect); +} + +void convert_metallic_to_specular(vec3 basecol, float metallic, float specular_fac, out vec3 diffuse, out vec3 f0) +{ + vec3 dielectric = vec3(0.034) * specular_fac * 2.0; + diffuse = mix(basecol, vec3(0.0), metallic); + f0 = mix(dielectric, basecol, metallic); +} + +void convert_metallic_to_specular_tinted( + vec3 basecol, float metallic, float specular_fac, float specular_tint, + out vec3 diffuse, out vec3 f0) +{ + 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); +} /*********** NEW SHADER NODES ***************/ #define NUM_LIGHTS 3 -/* bsdfs */ +struct glLight { + vec4 position; + vec4 diffuse; + vec4 specular; + vec4 halfVector; +}; -void node_bsdf_diffuse(vec4 color, float roughness, vec3 N, out vec4 result) -{ +layout(std140) uniform lightSource { + glLight glLightSource[NUM_LIGHTS]; +}; + +#ifndef VOLUMETRICS +/* bsdfs */ +void node_bsdf_diffuse(vec4 color, float roughness, vec3 N, out Closure result) +{ +#ifdef EEVEE_ENGINE + 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; +#else /* 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; + vec3 light_position = glLightSource[i].position.xyz; + vec3 light_diffuse = glLightSource[i].diffuse.rgb; float bsdf = max(dot(N, light_position), 0.0); L += light_diffuse * bsdf; } - result = vec4(L * color.rgb, 1.0); + result = Closure(L * color.rgb, 1.0); +#endif } -void node_bsdf_glossy(vec4 color, float roughness, vec3 N, out vec4 result) +void node_bsdf_glossy(vec4 color, float roughness, vec3 N, float ssr_id, out Closure result) { +#ifdef EEVEE_ENGINE + vec3 out_spec, ssr_spec; + roughness = sqrt(roughness); + eevee_closure_glossy(N, vec3(1.0), int(ssr_id), roughness, 1.0, out_spec, ssr_spec); + vec3 vN = normalize(mat3(ViewMatrix) * N); + result = CLOSURE_DEFAULT; + 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); +#else /* ambient light */ vec3 L = vec3(0.2); + direction_transform_m4v3(N, ViewMatrix, N); + /* 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; + vec3 light_position = glLightSource[i].position.xyz; + vec3 H = glLightSource[i].halfVector.xyz; + vec3 light_diffuse = glLightSource[i].diffuse.rgb; + vec3 light_specular = glLightSource[i].specular.rgb; /* we mix in some diffuse so low roughness still shows up */ float bsdf = 0.5 * pow(max(dot(N, H), 0.0), 1.0 / roughness); @@ -2604,30 +2724,52 @@ void node_bsdf_glossy(vec4 color, float roughness, vec3 N, out vec4 result) L += light_specular * bsdf; } - result = vec4(L * color.rgb, 1.0); + result = Closure(L * color.rgb, 1.0); +#endif } void node_bsdf_anisotropic( vec4 color, float roughness, float anisotropy, float rotation, vec3 N, vec3 T, - out vec4 result) + 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_bsdf_glass(vec4 color, float roughness, float ior, vec3 N, float ssr_id, out Closure result) +{ +#ifdef EEVEE_ENGINE + vec3 out_spec, out_refr, ssr_spec; + roughness = sqrt(roughness); + vec3 refr_color = (refractionDepth > 0.0) ? color.rgb * color.rgb : color.rgb; /* Simulate 2 transmission event */ + eevee_closure_glass(N, vec3(1.0), int(ssr_id), roughness, 1.0, ior, out_spec, out_refr, ssr_spec); + out_refr *= refr_color; + 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); +#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_toon(vec4 color, float size, float tsmooth, vec3 N, out Closure result) { node_bsdf_diffuse(color, 0.0, N, result); } +#ifndef EEVEE_ENGINE 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) + float clearcoat_roughness, float ior, float transmission, float transmission_roughness, vec3 N, vec3 CN, vec3 T, vec3 I, out Closure result) { + vec3 X, Y; + float ax, ay; + prepare_tangent(anisotropic, anisotropic_rotation, roughness, N, T, X, Y, ax, ay); + /* 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)); @@ -2635,28 +2777,7 @@ void node_bsdf_principled(vec4 base_color, float subsurface, vec3 subsurface_rad 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); + vec3 V = (ProjectionMatrix[3][3] == 0.0) ? -normalize(I) : vec3(0.0, 0.0, 1.0); /* fresnel normalization parameters */ float F0 = fresnel_dielectric_0(eta); @@ -2664,13 +2785,13 @@ void node_bsdf_principled(vec4 base_color, float subsurface, vec3 subsurface_rad /* directional lights */ for (int i = 0; i < NUM_LIGHTS; i++) { - vec3 light_position_world = gl_LightSource[i].position.xyz; + vec3 light_position_world = glLightSource[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; + vec3 light_diffuse = glLightSource[i].diffuse.rgb; + vec3 light_specular = glLightSource[i].specular.rgb; float NdotL = dot(N, light_position); float NdotV = dot(N, V); @@ -2680,7 +2801,7 @@ void node_bsdf_principled(vec4 base_color, float subsurface, vec3 subsurface_rad 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. + float Cdlum = dot(base_color.rgb, vec3(0.3, 0.6, 0.1)); // 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); @@ -2701,10 +2822,6 @@ void node_bsdf_principled(vec4 base_color, float subsurface, vec3 subsurface_rad 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); @@ -2740,83 +2857,313 @@ void node_bsdf_principled(vec4 base_color, float subsurface, vec3 subsurface_rad L += diffuse_and_specular_bsdf + clearcoat_bsdf; } - result = vec4(L, 1.0); + result = Closure(L, 1.0); } +#endif -void node_bsdf_translucent(vec4 color, vec3 N, out vec4 result) +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) { - node_bsdf_diffuse(color, 0.0, N, result); +#ifdef EEVEE_ENGINE + 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); + + transmission *= 1.0 - metallic; + subsurface *= 1.0 - metallic; + + clearcoat *= 0.25; + clearcoat *= 1.0 - transmission; + +#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 + +#else + node_bsdf_principled(base_color, subsurface, subsurface_radius, subsurface_color, metallic, specular, + specular_tint, roughness, anisotropic, anisotropic_rotation, sheen, sheen_tint, clearcoat, + clearcoat_roughness, ior, transmission, transmission_roughness, N, CN, T, I, result); +#endif } -void node_bsdf_transparent(vec4 color, out vec4 result) +void node_bsdf_translucent(vec4 color, vec3 N, out Closure result) +{ + node_bsdf_diffuse(color, 0.0, -N, result); +} + +void node_bsdf_transparent(vec4 color, out Closure result) { /* this isn't right */ - result.r = color.r; - result.g = color.g; - result.b = color.b; - result.a = 0.0; + result = CLOSURE_DEFAULT; + result.radiance = vec3(0.0); + result.opacity = 0.0; +#ifdef EEVEE_ENGINE + result.ssr_id = TRANSPARENT_CLOSURE_FLAG; +#endif } -void node_bsdf_velvet(vec4 color, float sigma, vec3 N, 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_subsurface_scattering( - vec4 color, float scale, vec3 radius, float sharpen, float texture_blur, vec3 N, - out vec4 result) -{ + vec4 color, float scale, vec3 radius, float sharpen, float texture_blur, vec3 N, float sss_id, + out Closure result) +{ +#if defined(EEVEE_ENGINE) && 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_hair(vec4 color, float offset, float roughnessu, float roughnessv, vec3 tangent, out vec4 result) +void node_bsdf_refraction(vec4 color, float roughness, float ior, vec3 N, out Closure result) { - result = color; +#ifdef EEVEE_ENGINE + vec3 out_refr; + color.rgb *= (refractionDepth > 0.0) ? color.rgb : vec3(1.0); /* Simulate 2 absorption event. */ + roughness = sqrt(roughness); + eevee_closure_refraction(N, roughness, ior, out_refr); + vec3 vN = normalize(mat3(ViewMatrix) * N); + result = CLOSURE_DEFAULT; + result.ssr_normal = normal_encode(vN, viewCameraVec); + result.radiance = out_refr * color.rgb; + result.ssr_id = REFRACT_CLOSURE_FLAG; +#else + node_bsdf_diffuse(color, 0.0, N, result); +#endif /* EEVEE_ENGINE */ } -void node_bsdf_refraction(vec4 color, float roughness, float ior, vec3 N, out vec4 result) +/* Unsupported for now */ +#ifndef EEVEE_ENGINE +void node_bsdf_hair(vec4 color, float offset, float roughnessu, float roughnessv, vec3 tangent, out Closure result) { - node_bsdf_diffuse(color, 0.0, N, result); + result = Closure(color.rgb, color.a); } -void node_ambient_occlusion(vec4 color, out vec4 result) +void node_ambient_occlusion(vec4 color, out Closure result) { - result = color; + result = Closure(color.rgb, color.a); } +#endif /* EEVEE_ENGINE */ + +#endif /* VOLUMETRICS */ /* emission */ -void node_emission(vec4 color, float strength, vec3 N, out vec4 result) +void node_emission(vec4 color, float strength, vec3 vN, out Closure result) { - result = color * strength; +#ifndef VOLUMETRICS + color *= strength; +#ifdef EEVEE_ENGINE + result = CLOSURE_DEFAULT; + result.radiance = color.rgb; + result.opacity = color.a; + result.ssr_normal = normal_encode(vN, viewCameraVec); +#else + result = Closure(color.rgb, color.a); +#endif +#else + result = Closure(vec3(0.0), vec3(0.0), color.rgb * strength, 0.0); +#endif } /* background */ 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); + 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); vec4 co = vec4(co_homogenous.xyz / co_homogenous.w, 0.0); - worldvec = (gl_ModelViewMatrixInverse * co).xyz; +#if defined(WORLD_BACKGROUND) || defined(PROBE_CAPTURE) + worldvec = (ViewMatrixInverse * co).xyz; +#else + worldvec = (ModelViewMatrixInverse * co).xyz; +#endif +} + +void node_background(vec4 color, float strength, out Closure result) +{ +#ifndef VOLUMETRICS + color *= strength; +#ifdef EEVEE_ENGINE + result = CLOSURE_DEFAULT; + result.radiance = color.rgb; + result.opacity = color.a; +#else + result = Closure(color.rgb, color.a); +#endif +#else + result = CLOSURE_DEFAULT; +#endif +} + +/* volumes */ + +void node_volume_scatter(vec4 color, float density, float anisotropy, out Closure result) +{ +#ifdef VOLUMETRICS + result = Closure(vec3(0.0), color.rgb * density, vec3(0.0), anisotropy); +#else + result = CLOSURE_DEFAULT; +#endif } -void node_background(vec4 color, float strength, vec3 N, out vec4 result) +void node_volume_absorption(vec4 color, float density, out Closure result) { - result = color * strength; +#ifdef VOLUMETRICS + result = Closure((1.0 - color.rgb) * density, vec3(0.0), vec3(0.0), 0.0); +#else + result = CLOSURE_DEFAULT; +#endif +} + +void node_blackbody(float temperature, sampler2D spectrummap, out vec4 color) +{ + if(temperature >= 12000.0) { + color = vec4(0.826270103, 0.994478524, 1.56626022, 1.0); + } + else if(temperature < 965.0) { + color = vec4(4.70366907, 0.0, 0.0, 1.0); + } + else { + float t = (temperature - 965.0) / (12000.0 - 965.0); + color = vec4(texture(spectrummap, vec2(t, 0.0)).rgb, 1.0); + } +} + +void node_volume_principled( + vec4 color, + float density, + float anisotropy, + vec4 absorption_color, + float emission_strength, + vec4 emission_color, + float blackbody_intensity, + vec4 blackbody_tint, + float temperature, + float density_attribute, + vec4 color_attribute, + float temperature_attribute, + sampler2D spectrummap, + out Closure result) +{ +#ifdef VOLUMETRICS + vec3 absorption_coeff = vec3(0.0); + vec3 scatter_coeff = vec3(0.0); + vec3 emission_coeff = vec3(0.0); + + /* Compute density. */ + density = max(density, 0.0); + + if(density > 1e-5) { + density = max(density * density_attribute, 0.0); + } + + if(density > 1e-5) { + /* Compute scattering and absorption coefficients. */ + vec3 scatter_color = color.rgb * color_attribute.rgb; + + scatter_coeff = scatter_color * density; + absorption_coeff = max(1.0 - scatter_color, 0.0) * max(1.0 - absorption_color.rgb, 0.0) * density; + } + + /* Compute emission. */ + emission_strength = max(emission_strength, 0.0); + + if(emission_strength > 1e-5) { + emission_coeff += emission_strength * emission_color.rgb; + } + + if(blackbody_intensity > 1e-3) { + /* Add temperature from attribute. */ + float T = max(temperature * max(temperature_attribute, 0.0), 0.0); + + /* Stefan-Boltzman law. */ + float T4 = (T * T) * (T * T); + float sigma = 5.670373e-8 * 1e-6 / M_PI; + float intensity = sigma * mix(1.0, T4, blackbody_intensity); + + if(intensity > 1e-5) { + vec4 bb; + node_blackbody(T, spectrummap, bb); + emission_coeff += bb.rgb * blackbody_tint.rgb * intensity; + } + } + + result = Closure(absorption_coeff, scatter_coeff, emission_coeff, anisotropy); +#else + result = CLOSURE_DEFAULT; +#endif } /* closures */ -void node_mix_shader(float fac, 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 */ @@ -2824,7 +3171,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); @@ -2836,7 +3183,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); @@ -2866,11 +3213,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(EEVEE_ENGINE) && 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(EEVEE_ENGINE) && 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 > 0.0) + 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(EEVEE_ENGINE) && 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(EEVEE_ENGINE) && defined(MESH_SHADER) && defined(VOLUMETRICS) + vec3 cos = volumeObjectLocalCoord; +#else + vec3 cos = vec3(0.0); +#endif + float flame = texture(tex, cos).r; + + outf = (flame > 0.01) ? temperature.x + flame * (temperature.y - temperature.x): 0.0; + outvec = vec3(outf, outf, outf); + outcol = vec4(outf, outf, outf, 1.0); +} + void node_attribute(vec3 attr, out vec4 outcol, out vec3 outvec, out float outf) { 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) @@ -2878,19 +3281,51 @@ 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) { +#ifdef EEVEE_ENGINE + position = worldPosition; +#else position = (toworld * vec4(I, 1.0)).xyz; +#endif 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); @@ -2904,12 +3339,12 @@ 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; @@ -2924,13 +3359,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; @@ -2938,13 +3378,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) @@ -3014,7 +3458,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, @@ -3050,7 +3493,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, @@ -3061,7 +3503,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, @@ -3075,10 +3516,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) @@ -3093,7 +3530,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) @@ -3109,7 +3554,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) @@ -3119,7 +3564,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; } @@ -3193,21 +3638,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; @@ -3280,7 +3725,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); @@ -3355,10 +3799,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); @@ -3368,7 +3811,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); @@ -3383,11 +3826,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) { @@ -3403,15 +3844,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 @@ -3427,9 +3861,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; @@ -3455,9 +3888,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; @@ -3483,13 +3915,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; @@ -3518,13 +3949,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; @@ -3555,14 +3985,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)); @@ -3584,19 +4013,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, @@ -3609,7 +4037,6 @@ void node_tex_musgrave(vec3 co, out vec4 color, out float fac) { -#ifdef BIT_OPERATIONS fac = svm_musgrave(int(type), dimension, lacunarity, @@ -3618,9 +4045,6 @@ void node_tex_musgrave(vec3 co, 1.0, gain, co * scale); -#else - fac = 1.0; -#endif color = vec4(fac, fac, fac, 1.0); } @@ -3632,7 +4056,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]; @@ -3697,13 +4120,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; @@ -3725,22 +4143,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 */ @@ -3760,13 +4172,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; @@ -3865,37 +4285,79 @@ 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 +#ifdef EEVEE_ENGINE + result.radiance = surface.radiance; + result.opacity = backgroundAlpha; +#else + result = Closure(surface.radiance, backgroundAlpha); +#endif +#else + result = volume; +#endif /* VOLUMETRICS */ } +#ifndef VOLUMETRICS +/* TODO : clean this ifdef mess */ +/* EEVEE output */ +#ifdef EEVEE_ENGINE +void world_normals_get(out vec3 N) +{ + N = gl_FrontFacing ? worldNormal : -worldNormal; +} + +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 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); +} + +#endif /* EEVEE_ENGINE */ +#endif /* VOLUMETRICS */ + /* ********************** matcap style render ******************** */ void material_preview_matcap(vec4 color, sampler2D ima, vec4 N, vec4 mask, out vec4 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; - } + normal = 2.0 * N.xyz - vec3(1.0); + normal.z = max(normal.z, 0.0); normal = normalize(normal); #else normal = inpt.v.normal; - mask = vec4(1.0, 1.0, 1.0, 1.0); + mask = vec4(1.0); #endif - tex.x = 0.5 + 0.49 * normal.x; - tex.y = 0.5 + 0.49 * normal.y; - result = texture2D(ima, tex) * mask; + vec2 tex = 0.49 * normal.xy + vec2(0.5); + + result = texture(ima, tex) * mask; } 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..1319e386c65 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,12 @@ +uniform mat4 ModelViewProjectionMatrix; + +in vec2 pos; +in vec2 uvs; +out vec2 texCoord_interp; + void main() { - gl_Position = ftransform(); - gl_TexCoord[0] = gl_MultiTexCoord0; + gl_Position = ModelViewProjectionMatrix * vec4(pos, 0.0, 1.0); + texCoord_interp = uvs; } 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..4d7131c4eb1 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_simple_lighting_frag.glsl @@ -0,0 +1,17 @@ + +#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 * max(0.0, dot(normalize(normal), light)); +} 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..7ff90ad4f21 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_text_frag.glsl @@ -0,0 +1,15 @@ + +flat in vec4 color_flat; +noperspective in vec2 texCoord_interp; +out vec4 fragColor; + +uniform sampler2D glyph; + +void main() +{ + // input color replaces texture color + fragColor.rgb = color_flat.rgb; + + // modulate input alpha & texture alpha + fragColor.a = color_flat.a * texture(glyph, texCoord_interp).r; +} 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..6129f49ce22 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_text_vert.glsl @@ -0,0 +1,16 @@ + +uniform mat4 ModelViewProjectionMatrix; + +in vec2 pos; +in vec2 texCoord; +in vec4 color; +flat out vec4 color_flat; +noperspective out vec2 texCoord_interp; + +void main() +{ + gl_Position = ModelViewProjectionMatrix * vec4(pos, 0.0, 1.0); + + color_flat = color; + texCoord_interp = texCoord; +} 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..4ebd10d514f 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]; @@ -89,11 +94,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..89a2f391a12 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 */ 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; } |