diff options
author | Dalai Felinto <dfelinto@gmail.com> | 2015-09-24 18:24:20 +0300 |
---|---|---|
committer | Dalai Felinto <dfelinto@gmail.com> | 2015-09-24 18:24:20 +0300 |
commit | 27b3ea622f8bd313a8e2827dfec752bf2125566c (patch) | |
tree | f212e49d224ce8e1cfc3b17a64ae524711494391 /source/blender/gpu | |
parent | 372dff8d1dc7e24d4b2cd37de245588ecfce8bfa (diff) | |
parent | de80e687689032cb85179a1f7e89750573631d5d (diff) |
Merge remote-tracking branch 'origin/master' into cycles_camera_nodescycles_camera_nodes
Note: the branch currently crashes in blender_camera_nodes.cpp:
BL::NodeTree b_ntree = b_data.node_groups[nodes_tree_name];
The crash was introduced in:
cb7cf523e5c000609f32a382e2c0fcc57f635a42
Conflicts:
intern/cycles/SConscript
intern/cycles/blender/addon/__init__.py
intern/cycles/blender/addon/properties.py
intern/cycles/blender/blender_camera.cpp
intern/cycles/kernel/kernel_types.h
intern/cycles/kernel/svm/svm.h
intern/cycles/kernel/svm/svm_types.h
intern/cycles/render/camera.cpp
intern/cycles/render/camera.h
Diffstat (limited to 'source/blender/gpu')
40 files changed, 7107 insertions, 3022 deletions
diff --git a/source/blender/gpu/CMakeLists.txt b/source/blender/gpu/CMakeLists.txt index 13e46bc7de8..328623f884f 100644 --- a/source/blender/gpu/CMakeLists.txt +++ b/source/blender/gpu/CMakeLists.txt @@ -36,6 +36,7 @@ set(INC ../nodes ../nodes/intern + ../../../intern/glew-mx ../../../intern/guardedalloc ../../../intern/smoke/extern ) @@ -49,27 +50,69 @@ set(SRC intern/gpu_codegen.c intern/gpu_draw.c intern/gpu_extensions.c + intern/gpu_init_exit.c intern/gpu_material.c intern/gpu_simple_shader.c intern/gpu_select.c + intern/gpu_compositing.c + intern/gpu_debug.c + + shaders/gpu_program_smoke_frag.glsl + shaders/gpu_program_smoke_color_frag.glsl + + shaders/gpu_shader_fx_lib.glsl + shaders/gpu_shader_fx_ssao_frag.glsl + shaders/gpu_shader_fx_dof_frag.glsl + shaders/gpu_shader_fx_dof_vert.glsl + shaders/gpu_shader_fx_dof_hq_frag.glsl + shaders/gpu_shader_fx_dof_hq_vert.glsl + shaders/gpu_shader_fx_dof_hq_geo.glsl + shaders/gpu_shader_fx_vert.glsl + shaders/gpu_shader_material.glsl + shaders/gpu_shader_sep_gaussian_blur_frag.glsl + shaders/gpu_shader_sep_gaussian_blur_vert.glsl + shaders/gpu_shader_simple_frag.glsl + shaders/gpu_shader_simple_vert.glsl + shaders/gpu_shader_vertex.glsl + shaders/gpu_shader_vsm_store_frag.glsl + shaders/gpu_shader_vsm_store_vert.glsl + shaders/gpu_shader_fx_depth_resolve.glsl GPU_buffers.h GPU_draw.h + GPU_debug.h GPU_extensions.h + GPU_glew.h + GPU_init_exit.h GPU_material.h GPU_simple_shader.h GPU_select.h + GPU_compositing.h intern/gpu_codegen.h + intern/gpu_private.h ) +data_to_c_simple(shaders/gpu_shader_geometry.glsl SRC) +data_to_c_simple(shaders/gpu_program_smoke_frag.glsl SRC) +data_to_c_simple(shaders/gpu_program_smoke_color_frag.glsl SRC) data_to_c_simple(shaders/gpu_shader_material.glsl SRC) data_to_c_simple(shaders/gpu_shader_sep_gaussian_blur_frag.glsl SRC) data_to_c_simple(shaders/gpu_shader_sep_gaussian_blur_vert.glsl SRC) data_to_c_simple(shaders/gpu_shader_simple_frag.glsl SRC) data_to_c_simple(shaders/gpu_shader_simple_vert.glsl SRC) data_to_c_simple(shaders/gpu_shader_vertex.glsl SRC) +data_to_c_simple(shaders/gpu_shader_vertex_world.glsl SRC) data_to_c_simple(shaders/gpu_shader_vsm_store_frag.glsl SRC) data_to_c_simple(shaders/gpu_shader_vsm_store_vert.glsl SRC) +data_to_c_simple(shaders/gpu_shader_fx_vert.glsl SRC) +data_to_c_simple(shaders/gpu_shader_fx_ssao_frag.glsl SRC) +data_to_c_simple(shaders/gpu_shader_fx_dof_frag.glsl SRC) +data_to_c_simple(shaders/gpu_shader_fx_dof_vert.glsl SRC) +data_to_c_simple(shaders/gpu_shader_fx_dof_hq_frag.glsl SRC) +data_to_c_simple(shaders/gpu_shader_fx_dof_hq_vert.glsl SRC) +data_to_c_simple(shaders/gpu_shader_fx_dof_hq_geo.glsl SRC) +data_to_c_simple(shaders/gpu_shader_fx_depth_resolve.glsl SRC) +data_to_c_simple(shaders/gpu_shader_fx_lib.glsl SRC) if(WITH_GAMEENGINE) add_definitions(-DWITH_GAMEENGINE) @@ -79,12 +122,15 @@ if(WITH_MOD_SMOKE) add_definitions(-DWITH_SMOKE) endif() -add_definitions(-DGLEW_STATIC) +add_definitions(${GL_DEFINITIONS}) if(WITH_IMAGE_DDS) add_definitions(-DWITH_DDS) endif() +if(WITH_OPENSUBDIV) + add_definitions(-DWITH_OPENSUBDIV) +endif() blender_add_lib(bf_gpu "${SRC}" "${INC}" "${INC_SYS}") diff --git a/source/blender/gpu/GPU_buffers.h b/source/blender/gpu/GPU_buffers.h index ba461d5f8a2..e653af0c7ec 100644 --- a/source/blender/gpu/GPU_buffers.h +++ b/source/blender/gpu/GPU_buffers.h @@ -39,32 +39,41 @@ # define DEBUG_VBO(X) #endif +#include <stddef.h> + struct BMesh; struct CCGElem; struct CCGKey; -struct CustomData; struct DMFlagMat; struct DerivedMesh; -struct GHash; struct GSet; struct GPUVertPointLink; +struct GPUDrawObject; struct PBVH; +struct MVert; typedef struct GPUBuffer { - int size; /* in bytes */ - void *pointer; /* used with vertex arrays */ - unsigned int id; /* used with vertex buffer objects */ + size_t size; /* in bytes */ + void *pointer; /* used with vertex arrays */ + unsigned int id; /* used with vertex buffer objects */ + bool use_vbo; /* true for VBOs, false for vertex arrays */ } GPUBuffer; typedef struct GPUBufferMaterial { /* range of points used for this material */ - int start; - int totpoint; + unsigned int start; + unsigned int totelements; + unsigned int totloops; + unsigned int *polys; /* array of polygons for this material */ + unsigned int totpolys; /* total polygons in polys */ + unsigned int totvisiblepolys; /* total visible polygons */ /* original material index */ short mat_nr; } GPUBufferMaterial; +void GPU_buffer_material_finalize(struct GPUDrawObject *gdo, GPUBufferMaterial *matinfo, int totmat); + /* meshes are split up by material since changing materials requires * GL state changes that can't occur in the middle of drawing an * array. @@ -85,12 +94,11 @@ typedef struct GPUDrawObject { GPUBuffer *points; GPUBuffer *normals; GPUBuffer *uv; + GPUBuffer *uv_tex; GPUBuffer *colors; GPUBuffer *edges; GPUBuffer *uvedges; - - /* for each triangle, the original MFace index */ - int *triangle_to_mface; + GPUBuffer *triangles; /* triangle index buffer */ /* for each original vertex, the list of related points */ struct GPUVertPointLink *vert_points; @@ -107,18 +115,37 @@ typedef struct GPUDrawObject { GPUBufferMaterial *materials; int totmaterial; - int tot_triangle_point; - int tot_loose_point; + unsigned int tot_triangle_point; + unsigned int tot_loose_point; + /* different than total loops since ngons get tesselated still */ + unsigned int tot_loop_verts; /* caches of the original DerivedMesh values */ - int totvert; - int totedge; + unsigned int totvert; + unsigned int totedge; + + unsigned int loose_edge_offset; + unsigned int tot_loose_edge_drawn; + unsigned int tot_edge_drawn; - /* if there was a failure allocating some buffer, use old - * rendering code */ - bool legacy; + /* for subsurf, offset where drawing of interior edges starts */ + unsigned int interior_offset; + unsigned int totinterior; } GPUDrawObject; +/* currently unused */ +// #define USE_GPU_POINT_LINK + +typedef struct GPUVertPointLink { +#ifdef USE_GPU_POINT_LINK + struct GPUVertPointLink *next; +#endif + /* -1 means uninitialized */ + int point_index; +} GPUVertPointLink; + + + /* used for GLSL materials */ typedef struct GPUAttrib { int index; @@ -129,12 +156,31 @@ typedef struct GPUAttrib { void GPU_global_buffer_pool_free(void); void GPU_global_buffer_pool_free_unused(void); -GPUBuffer *GPU_buffer_alloc(int size); +GPUBuffer *GPU_buffer_alloc(size_t size, bool force_vertex_arrays); void GPU_buffer_free(GPUBuffer *buffer); -GPUDrawObject *GPU_drawobject_new(struct DerivedMesh *dm); void GPU_drawobject_free(struct DerivedMesh *dm); +/* free special global multires grid buffer */ +void GPU_buffer_multires_free(bool force); + +/* flag that controls data type to fill buffer with, a modifier will prepare. */ +typedef enum { + GPU_BUFFER_VERTEX = 0, + GPU_BUFFER_NORMAL, + GPU_BUFFER_COLOR, + GPU_BUFFER_UV, + GPU_BUFFER_UV_TEXPAINT, + GPU_BUFFER_EDGE, + GPU_BUFFER_UVEDGE, + GPU_BUFFER_TRIANGLES +} GPUBufferType; + +typedef enum { + GPU_BINDING_ARRAY = 0, + GPU_BINDING_INDEX = 1, +} GPUBindingType; + /* called before drawing */ void GPU_vertex_setup(struct DerivedMesh *dm); void GPU_normal_setup(struct DerivedMesh *dm); @@ -142,15 +188,22 @@ void GPU_uv_setup(struct DerivedMesh *dm); void GPU_texpaint_uv_setup(struct DerivedMesh *dm); /* colType is the cddata MCol type to use! */ void GPU_color_setup(struct DerivedMesh *dm, int colType); +void GPU_buffer_bind_as_color(GPUBuffer *buffer); void GPU_edge_setup(struct DerivedMesh *dm); /* does not mix with other data */ void GPU_uvedge_setup(struct DerivedMesh *dm); + +void GPU_triangle_setup(struct DerivedMesh *dm); + int GPU_attrib_element_size(GPUAttrib data[], int numdata); -void GPU_interleaved_attrib_setup(GPUBuffer *buffer, GPUAttrib data[], int numdata); +void GPU_interleaved_attrib_setup(GPUBuffer *buffer, GPUAttrib data[], int numdata, int element_size); + +void GPU_buffer_bind(GPUBuffer *buffer, GPUBindingType binding); +void GPU_buffer_unbind(GPUBuffer *buffer, GPUBindingType binding); /* can't lock more than one buffer at once */ -void *GPU_buffer_lock(GPUBuffer *buffer); -void *GPU_buffer_lock_stream(GPUBuffer *buffer); -void GPU_buffer_unlock(GPUBuffer *buffer); +void *GPU_buffer_lock(GPUBuffer *buffer, GPUBindingType binding); +void *GPU_buffer_lock_stream(GPUBuffer *buffer, GPUBindingType binding); +void GPU_buffer_unlock(GPUBuffer *buffer, GPUBindingType binding); /* switch color rendering on=1/off=0 */ void GPU_color_switch(int mode); @@ -159,29 +212,33 @@ void GPU_color_switch(int mode); void GPU_buffer_draw_elements(GPUBuffer *elements, unsigned int mode, int start, int count); /* called after drawing */ -void GPU_buffer_unbind(void); +void GPU_buffers_unbind(void); -/* used to check whether to use the old (without buffers) code */ -bool GPU_buffer_legacy(struct DerivedMesh *dm); +/* only unbind interleaved data */ +void GPU_interleaved_attrib_unbind(void); /* Buffers for non-DerivedMesh drawing */ typedef struct GPU_PBVH_Buffers GPU_PBVH_Buffers; /* build */ -GPU_PBVH_Buffers *GPU_build_mesh_pbvh_buffers(int (*face_vert_indices)[4], - struct MFace *mface, struct MVert *mvert, - int *face_indices, int totface); +GPU_PBVH_Buffers *GPU_build_mesh_pbvh_buffers( + const int (*face_vert_indices)[4], + const struct MPoly *mpoly, const struct MLoop *mloop, const struct MLoopTri *looptri, + const struct MVert *verts, + const int *face_indices, + const int face_indices_len); GPU_PBVH_Buffers *GPU_build_grid_pbvh_buffers(int *grid_indices, int totgrid, - unsigned int **grid_hidden, int gridsize); + unsigned int **grid_hidden, int gridsize, const struct CCGKey *key); GPU_PBVH_Buffers *GPU_build_bmesh_pbvh_buffers(int smooth_shading); /* update */ -void GPU_update_mesh_pbvh_buffers(GPU_PBVH_Buffers *buffers, MVert *mvert, - int *vert_indices, int totvert, const float *vmask, - int (*face_vert_indices)[4], bool show_diffuse_color); +void GPU_update_mesh_pbvh_buffers( + GPU_PBVH_Buffers *buffers, const struct MVert *mvert, + const int *vert_indices, int totvert, const float *vmask, + const int (*face_vert_indices)[4], bool show_diffuse_color); void GPU_update_bmesh_pbvh_buffers(GPU_PBVH_Buffers *buffers, struct BMesh *bm, @@ -197,7 +254,7 @@ void GPU_update_grid_pbvh_buffers(GPU_PBVH_Buffers *buffers, struct CCGElem **gr /* draw */ void GPU_draw_pbvh_buffers(GPU_PBVH_Buffers *buffers, DMSetMaterial setMaterial, - bool wireframe); + bool wireframe, bool fast); /* debug PBVH draw*/ void GPU_draw_pbvh_BB(float min[3], float max[3], bool leaf); diff --git a/source/blender/gpu/GPU_compositing.h b/source/blender/gpu/GPU_compositing.h new file mode 100644 index 00000000000..04e89da00a7 --- /dev/null +++ b/source/blender/gpu/GPU_compositing.h @@ -0,0 +1,99 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2005 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Antony Riakiotakis. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file GPU_compositing.h + * \ingroup gpu + */ + +#ifndef __GPU_COMPOSITING_H__ +#define __GPU_COMPOSITING_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +/* opaque handle for framebuffer compositing effects (defined in gpu_compositing.c )*/ +typedef struct GPUFX GPUFX; +struct GPUDOFSettings; +struct GPUSSAOSettings; +struct GPUOffScreen; +struct GPUFXSettings; +struct rcti; +struct Scene; +enum eGPUFXFlags; + +/**** Public API *****/ + +typedef enum GPUFXShaderEffect { + /* Screen space ambient occlusion shader */ + GPU_SHADER_FX_SSAO = 1, + + /* depth of field passes. Yep, quite a complex effect */ + GPU_SHADER_FX_DEPTH_OF_FIELD_PASS_ONE = 2, + GPU_SHADER_FX_DEPTH_OF_FIELD_PASS_TWO = 3, + GPU_SHADER_FX_DEPTH_OF_FIELD_PASS_THREE = 4, + GPU_SHADER_FX_DEPTH_OF_FIELD_PASS_FOUR = 5, + GPU_SHADER_FX_DEPTH_OF_FIELD_PASS_FIVE = 6, + + /* high quality */ + GPU_SHADER_FX_DEPTH_OF_FIELD_HQ_PASS_ONE = 7, + GPU_SHADER_FX_DEPTH_OF_FIELD_HQ_PASS_TWO = 8, + GPU_SHADER_FX_DEPTH_OF_FIELD_HQ_PASS_THREE = 9, + + GPU_SHADER_FX_DEPTH_RESOLVE = 10, +} GPUFXShaderEffect; + +/* keep in synch with enum above! */ +#define MAX_FX_SHADERS 11 + +/* generate a new FX compositor */ +GPUFX *GPU_fx_compositor_create(void); + +/* destroy a text compositor */ +void GPU_fx_compositor_destroy(GPUFX *fx); + +/* initialize a framebuffer with size taken from the viewport */ +bool GPU_fx_compositor_initialize_passes( + GPUFX *fx, const struct rcti *rect, const struct rcti *scissor_rect, + const struct GPUFXSettings *fx_settings); + +/* do compositing on the fx passes that have been initialized */ +bool GPU_fx_do_composite_pass(GPUFX *fx, float projmat[4][4], bool is_persp, struct Scene *scene, struct GPUOffScreen *ofs); + +/* bind new depth buffer for XRay pass */ +void GPU_fx_compositor_setup_XRay_pass(GPUFX *fx, bool do_xray); + +/* resolve a final depth buffer by compositing the XRay and normal depth buffers */ +void GPU_fx_compositor_XRay_resolve(GPUFX *fx); + +void GPU_fx_compositor_init_dof_settings(struct GPUDOFSettings *dof); +void GPU_fx_compositor_init_ssao_settings(struct GPUSSAOSettings *ssao); +#ifdef __cplusplus +} +#endif + +#endif // __GPU_COMPOSITING_H__ diff --git a/source/blender/gpu/GPU_debug.h b/source/blender/gpu/GPU_debug.h new file mode 100644 index 00000000000..2c1728bfff1 --- /dev/null +++ b/source/blender/gpu/GPU_debug.h @@ -0,0 +1,71 @@ +/* + * ***** 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): Jason Wilkins. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file source/blender/gpu/GPU_debug.h + * \ingroup gpu + */ + +#ifndef __GPU_DEBUG_H__ +#define __GPU_DEBUG_H__ + +#include "GPU_glew.h" + +#include "BLI_utildefines.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* 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(size_t size, const char *str); + +#ifdef __cplusplus +} +#endif + +#endif /* __GPU_DEBUG_H__ */ diff --git a/source/blender/gpu/GPU_draw.h b/source/blender/gpu/GPU_draw.h index 3ddec157c49..0992f8e9d21 100644 --- a/source/blender/gpu/GPU_draw.h +++ b/source/blender/gpu/GPU_draw.h @@ -36,14 +36,16 @@ extern "C" { #endif +struct ImBuf; struct Image; struct ImageUser; -struct MTFace; +struct MTexPoly; struct Object; struct Scene; struct View3D; struct RegionView3D; struct SmokeModifierData; +struct DupliObject; /* OpenGL drawing functions related to shading. These are also * shared with the game engine, where there were previously @@ -57,10 +59,6 @@ struct SmokeModifierData; void GPU_state_init(void); -/* Debugging */ - -void GPU_state_print(void); - /* Material drawing * - first the state is initialized by a particular object and * it's materials @@ -71,10 +69,14 @@ void GPU_state_print(void); void GPU_begin_object_materials(struct View3D *v3d, struct RegionView3D *rv3d, struct Scene *scene, struct Object *ob, bool glsl, bool *do_alpha_after); void GPU_end_object_materials(void); +bool GPU_object_materials_check(void); int GPU_enable_material(int nr, void *attribs); void GPU_disable_material(void); +void GPU_begin_dupli_object(struct DupliObject *dob); +void GPU_end_dupli_object(void); + void GPU_material_diffuse_get(int nr, float diff[4]); bool GPU_material_use_matcaps_get(void); @@ -86,8 +88,9 @@ int GPU_get_material_alpha_blend(void); * be drawn using one or the other * - passing NULL clears the state again */ -int GPU_set_tpage(struct MTFace *tface, int mipmap, int transp); +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 */ @@ -99,18 +102,20 @@ int GPU_scene_object_lights(struct Scene *scene, struct Object *ob, /* Text render * - based on moving uv coordinates */ -void GPU_render_text(struct MTFace *tface, int mode, - const char *textstr, int textlen, unsigned int *col, - float *v1, float *v2, float *v3, float *v4, int glattrib); +void GPU_render_text( + struct MTexPoly *mtexpoly, int mode, + const char *textstr, int textlen, unsigned int *col, + const float *v_quad[4], const float *uv_quad[4], + int glattrib); /* Mipmap settings * - these will free textures on changes */ -void GPU_set_mipmap(int mipmap); -int GPU_get_mipmap(void); -void GPU_set_linear_mipmap(int linear); -int GPU_get_linear_mipmap(void); -void GPU_paint_set_mipmap(int mipmap); +void GPU_set_mipmap(bool mipmap); +bool GPU_get_mipmap(void); +void GPU_set_linear_mipmap(bool linear); +bool GPU_get_linear_mipmap(void); +void GPU_paint_set_mipmap(bool mipmap); /* Anisotropic filtering settings * - these will free textures on changes */ @@ -123,11 +128,11 @@ void GPU_set_gpu_mipmapping(int gpu_mipmap); /* Image updates and free * - these deal with images bound as opengl textures */ -void GPU_paint_update_image(struct Image *ima, int x, int y, int w, int h); +void GPU_paint_update_image(struct Image *ima, ImageUser *iuser, int x, int y, int w, int h); void GPU_update_images_framechange(void); int GPU_update_image_time(struct Image *ima, double time); int GPU_verify_image(struct Image *ima, struct ImageUser *iuser, int tftile, bool compare, bool mipmap, bool is_data); -void GPU_create_gl_tex(unsigned int *bind, unsigned int *pix, float *frect, int rectw, int recth, +void GPU_create_gl_tex(unsigned int *bind, unsigned int *rect, float *frect, int rectw, int recth, bool mipmap, bool use_hight_bit_depth, struct Image *ima); void GPU_create_gl_tex_compressed(unsigned int *bind, unsigned int *pix, int x, int y, int mipmap, struct Image *ima, struct ImBuf *ibuf); bool GPU_upload_dxt_texture(struct ImBuf *ibuf); @@ -143,6 +148,11 @@ void GPU_create_smoke(struct SmokeModifierData *smd, int highres); /* Delayed free of OpenGL buffers by main thread */ void GPU_free_unused_buffers(void); +#ifdef WITH_OPENSUBDIV +struct DerivedMesh; +void GPU_draw_update_fvar_offset(struct DerivedMesh *dm); +#endif + #ifdef __cplusplus } #endif diff --git a/source/blender/gpu/GPU_extensions.h b/source/blender/gpu/GPU_extensions.h index 04c4119df6e..0e8d204d224 100644 --- a/source/blender/gpu/GPU_extensions.h +++ b/source/blender/gpu/GPU_extensions.h @@ -52,48 +52,56 @@ typedef struct GPUOffScreen GPUOffScreen; struct GPUShader; typedef struct GPUShader GPUShader; +struct GPUProgram; +typedef struct GPUProgram GPUProgram; + /* GPU extensions support */ void GPU_extensions_disable(void); -void GPU_extensions_init(void); /* call this before running any of the functions below */ -void GPU_extensions_exit(void); -int GPU_print_error(const char *str); -int GPU_glsl_support(void); -int GPU_non_power_of_two_support(void); -int GPU_display_list_support(void); +bool GPU_glsl_support(void); +bool GPU_non_power_of_two_support(void); +bool GPU_vertex_buffer_support(void); +bool GPU_display_list_support(void); +bool GPU_bicubic_bump_support(void); +bool GPU_geometry_shader_support(void); +bool GPU_instanced_drawing_support(void); + +int GPU_max_texture_size(void); int GPU_color_depth(void); -void GPU_code_generate_glsl_lib(void); -int GPU_bicubic_bump_support(void); -int GPU_max_texture_size (void); +void GPU_get_dfdy_factors(float fac[2]); + +bool GPU_mem_stats_supported(void); +void GPU_mem_stats_get(int *totalmem, int *freemem); +void GPU_code_generate_glsl_lib(void); /* GPU Types */ typedef enum GPUDeviceType { - GPU_DEVICE_NVIDIA = (1<<0), - GPU_DEVICE_ATI = (1<<1), - GPU_DEVICE_INTEL = (1<<2), - GPU_DEVICE_SOFTWARE = (1<<3), - GPU_DEVICE_UNKNOWN = (1<<4), - GPU_DEVICE_ANY = (0xff) + GPU_DEVICE_NVIDIA = (1<<0), + GPU_DEVICE_ATI = (1<<1), + GPU_DEVICE_INTEL = (1<<2), + GPU_DEVICE_SOFTWARE = (1<<3), + GPU_DEVICE_UNKNOWN = (1<<4), + GPU_DEVICE_ANY = (0xff) } GPUDeviceType; typedef enum GPUOSType { - GPU_OS_WIN = (1<<8), - GPU_OS_MAC = (1<<9), - GPU_OS_UNIX = (1<<10), - GPU_OS_ANY = (0xff00) + GPU_OS_WIN = (1<<8), + GPU_OS_MAC = (1<<9), + GPU_OS_UNIX = (1<<10), + GPU_OS_ANY = (0xff00) } GPUOSType; typedef enum GPUDriverType { - GPU_DRIVER_OFFICIAL = (1<<16), + GPU_DRIVER_OFFICIAL = (1<<16), GPU_DRIVER_OPENSOURCE = (1<<17), - GPU_DRIVER_SOFTWARE = (1<<18), - GPU_DRIVER_ANY = (0xff0000) + GPU_DRIVER_SOFTWARE = (1<<18), + GPU_DRIVER_ANY = (0xff0000) } GPUDriverType; -int GPU_type_matches(GPUDeviceType device, GPUOSType os, GPUDriverType driver); +bool GPU_type_matches(GPUDeviceType device, GPUOSType os, GPUDriverType driver); /* GPU Texture * - always returns unsigned char RGBA textures @@ -109,11 +117,19 @@ int GPU_type_matches(GPUDeviceType device, GPUOSType os, GPUDriverType driver); * - if created with from_blender, will not free the texture */ -GPUTexture *GPU_texture_create_1D(int w, float *pixels, char err_out[256]); -GPUTexture *GPU_texture_create_2D(int w, int h, float *pixels, char err_out[256]); -GPUTexture *GPU_texture_create_3D(int w, int h, int depth, int channels, float *fpixels); +typedef enum GPUHDRType { + GPU_HDR_NONE = 0, + GPU_HDR_HALF_FLOAT = 1, + GPU_HDR_FULL_FLOAT = (1 << 1), +} GPUHDRType; + +GPUTexture *GPU_texture_create_1D(int w, const float *pixels, char err_out[256]); +GPUTexture *GPU_texture_create_2D(int w, int h, const float *pixels, GPUHDRType hdr, char err_out[256]); +GPUTexture *GPU_texture_create_3D(int w, int h, int depth, int channels, const float *fpixels); GPUTexture *GPU_texture_create_depth(int w, int h, char err_out[256]); GPUTexture *GPU_texture_create_vsm_shadow_map(int size, char err_out[256]); +GPUTexture *GPU_texture_create_2D_procedural(int w, int h, const float *pixels, bool repeat, char err_out[256]); +GPUTexture *GPU_texture_create_1D_procedural(int w, const float *pixels, char err_out[256]); GPUTexture *GPU_texture_from_blender(struct Image *ima, struct ImageUser *iuser, bool is_data, double time, int mipmap); GPUTexture *GPU_texture_from_preview(struct PreviewImage *prv, int mipmap); @@ -128,12 +144,14 @@ void GPU_texture_ref(GPUTexture *tex); void GPU_texture_bind(GPUTexture *tex, int number); void GPU_texture_unbind(GPUTexture *tex); +void GPU_texture_filter_mode(GPUTexture *tex, bool compare, bool use_filter); + GPUFrameBuffer *GPU_texture_framebuffer(GPUTexture *tex); -int GPU_texture_target(GPUTexture *tex); -int GPU_texture_opengl_width(GPUTexture *tex); -int GPU_texture_opengl_height(GPUTexture *tex); -int GPU_texture_opengl_bindcode(GPUTexture *tex); +int GPU_texture_target(const GPUTexture *tex); +int GPU_texture_opengl_width(const GPUTexture *tex); +int GPU_texture_opengl_height(const GPUTexture *tex); +int GPU_texture_opengl_bindcode(const GPUTexture *tex); /* GPU Framebuffer * - this is a wrapper for an OpenGL framebuffer object (FBO). in practice @@ -142,12 +160,17 @@ int GPU_texture_opengl_bindcode(GPUTexture *tex); * - after any of the GPU_framebuffer_* functions, GPU_framebuffer_restore must * be called before rendering to the window framebuffer again */ +void GPU_texture_bind_as_framebuffer(GPUTexture *tex); + GPUFrameBuffer *GPU_framebuffer_create(void); -int GPU_framebuffer_texture_attach(GPUFrameBuffer *fb, GPUTexture *tex, char err_out[256]); -void GPU_framebuffer_texture_detach(GPUFrameBuffer *fb, GPUTexture *tex); -void GPU_framebuffer_texture_bind(GPUFrameBuffer *fb, GPUTexture *tex, int w, int h); +int GPU_framebuffer_texture_attach(GPUFrameBuffer *fb, GPUTexture *tex, int slot, char err_out[256]); +void GPU_framebuffer_texture_detach(GPUTexture *tex); +void GPU_framebuffer_slots_bind(GPUFrameBuffer *fb, int slot); void GPU_framebuffer_texture_unbind(GPUFrameBuffer *fb, GPUTexture *tex); void GPU_framebuffer_free(GPUFrameBuffer *fb); +bool GPU_framebuffer_check_valid(GPUFrameBuffer *fb, char err_out[256]); + +void GPU_framebuffer_bind_no_save(GPUFrameBuffer *fb, int slot); void GPU_framebuffer_restore(void); void GPU_framebuffer_blur(GPUFrameBuffer *fb, GPUTexture *tex, GPUFrameBuffer *blurfb, GPUTexture *blurtex); @@ -158,17 +181,42 @@ void GPU_framebuffer_blur(GPUFrameBuffer *fb, GPUTexture *tex, GPUFrameBuffer *b GPUOffScreen *GPU_offscreen_create(int width, int height, char err_out[256]); void GPU_offscreen_free(GPUOffScreen *ofs); -void GPU_offscreen_bind(GPUOffScreen *ofs); -void GPU_offscreen_unbind(GPUOffScreen *ofs); +void GPU_offscreen_bind(GPUOffScreen *ofs, bool save); +void GPU_offscreen_unbind(GPUOffScreen *ofs, bool restore); void GPU_offscreen_read_pixels(GPUOffScreen *ofs, int type, void *pixels); -int GPU_offscreen_width(GPUOffScreen *ofs); -int GPU_offscreen_height(GPUOffScreen *ofs); +int GPU_offscreen_width(const GPUOffScreen *ofs); +int GPU_offscreen_height(const GPUOffScreen *ofs); + +/* Builtin/Non-generated shaders */ +typedef enum GPUProgramType { + GPU_PROGRAM_TYPE_FRAGMENT = 0 +} GPUProgramType; + + +GPUProgram *GPU_program_shader_create(GPUProgramType type, const char *code); +void GPU_program_free(GPUProgram *program); +void GPU_program_parameter_4f(GPUProgram *program, unsigned int location, float x, float y, float z, float w); +void GPU_program_bind(GPUProgram *); +void GPU_program_unbind(GPUProgram *); /* GPU Shader * - only for fragment shaders now * - must call texture bind before setting a texture as uniform! */ -GPUShader *GPU_shader_create(const char *vertexcode, const char *fragcode, const char *libcode, const char *defines); +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); +enum { + GPU_SHADER_FLAGS_NONE = 0, + GPU_SHADER_FLAGS_SPECIAL_OPENSUBDIV = (1 << 0), +}; +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); @@ -176,24 +224,36 @@ void GPU_shader_unbind(void); int GPU_shader_get_uniform(GPUShader *shader, const char *name); void GPU_shader_uniform_vector(GPUShader *shader, int location, int length, - int arraysize, float *value); + 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_texture(GPUShader *shader, int location, 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); int GPU_shader_get_attribute(GPUShader *shader, const char *name); /* Builtin/Non-generated shaders */ typedef enum GPUBuiltinShader { - GPU_SHADER_VSM_STORE = (1<<0), - GPU_SHADER_SEP_GAUSSIAN_BLUR = (1<<1), + GPU_SHADER_VSM_STORE = 0, + GPU_SHADER_SEP_GAUSSIAN_BLUR = 1, } GPUBuiltinShader; +typedef enum GPUBuiltinProgram { + GPU_PROGRAM_SMOKE = 0, + GPU_PROGRAM_SMOKE_COLORED = 1, +} GPUBuiltinProgram; + GPUShader *GPU_shader_get_builtin_shader(GPUBuiltinShader shader); +GPUProgram *GPU_shader_get_builtin_program(GPUBuiltinProgram program); +GPUShader *GPU_shader_get_builtin_fx_shader(int effects, bool persp); + void GPU_shader_free_builtin_shaders(void); /* Vertex attributes for shaders */ -#define GPU_MAX_ATTRIB 32 +#define GPU_MAX_ATTRIB 32 typedef struct GPUVertexAttribs { struct { diff --git a/source/blender/gpu/GPU_glew.h b/source/blender/gpu/GPU_glew.h new file mode 100644 index 00000000000..94217863fd6 --- /dev/null +++ b/source/blender/gpu/GPU_glew.h @@ -0,0 +1,37 @@ +/* + * ***** 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): Jason Wilkins. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file source/blender/gpu/GPU_glew.h + * \ingroup gpu + */ + +#ifndef __GPU_GLEW_H__ +#define __GPU_GLEW_H__ + +#include "glew-mx.h" + +#endif /* __GPU_GLEW_H__ */ diff --git a/source/blender/gpu/GPU_init_exit.h b/source/blender/gpu/GPU_init_exit.h new file mode 100644 index 00000000000..e89c970b7d9 --- /dev/null +++ b/source/blender/gpu/GPU_init_exit.h @@ -0,0 +1,46 @@ +/* + * ***** 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) 2013 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Jason Wilkins. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/gpu/GPU_init_exit.h + * \ingroup gpu + */ + +#ifndef __GPU_INIT_EXIT_H__ +#define __GPU_INIT_EXIT_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +void GPU_init(void); +void GPU_exit(void); + +#ifdef __cplusplus +} +#endif + +#endif /* __GPU_INIT_EXIT_H__ */ diff --git a/source/blender/gpu/GPU_material.h b/source/blender/gpu/GPU_material.h index 8d44ad87916..dd08ed83e5a 100644 --- a/source/blender/gpu/GPU_material.h +++ b/source/blender/gpu/GPU_material.h @@ -32,8 +32,11 @@ #ifndef __GPU_MATERIAL_H__ #define __GPU_MATERIAL_H__ +#include "DNA_customdata_types.h" /* for CustomDataType */ #include "DNA_listBase.h" +#include "BLI_sys_types.h" /* for bool */ + #ifdef __cplusplus extern "C" { #endif @@ -42,10 +45,7 @@ struct Image; struct ImageUser; struct Material; struct Object; -struct Lamp; struct Image; -struct bNode; -struct LinkNode; struct Scene; struct SceneRenderLayer; struct GPUVertexAttribs; @@ -56,15 +56,18 @@ struct GPUMaterial; struct GPUTexture; struct GPULamp; struct PreviewImage; +struct World; 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 { + /* The value indicates the number of elements in each type */ GPU_NONE = 0, GPU_FLOAT = 1, GPU_VEC2 = 2, @@ -72,20 +75,26 @@ typedef enum GPUType { GPU_VEC4 = 4, GPU_MAT3 = 9, GPU_MAT4 = 16, + GPU_TEX2D = 1002, GPU_SHADOW2D = 1003, GPU_ATTRIB = 3001 } GPUType; typedef enum GPUBuiltin { - GPU_VIEW_MATRIX = 1, - GPU_OBJECT_MATRIX = 2, - GPU_INVERSE_VIEW_MATRIX = 4, - GPU_INVERSE_OBJECT_MATRIX = 8, - GPU_VIEW_POSITION = 16, - GPU_VIEW_NORMAL = 32, - GPU_OBCOLOR = 64, - GPU_AUTO_BUMPSCALE = 128, + GPU_VIEW_MATRIX = (1 << 0), + GPU_OBJECT_MATRIX = (1 << 1), + GPU_INVERSE_VIEW_MATRIX = (1 << 2), + GPU_INVERSE_OBJECT_MATRIX = (1 << 3), + GPU_VIEW_POSITION = (1 << 4), + GPU_VIEW_NORMAL = (1 << 5), + GPU_OBCOLOR = (1 << 6), + GPU_AUTO_BUMPSCALE = (1 << 7), + GPU_CAMERA_TEXCO_FACTORS = (1 << 8), + GPU_PARTICLE_SCALAR_PROPS = (1 << 9), + GPU_PARTICLE_LOCATION = (1 << 10), + GPU_PARTICLE_VELOCITY = (1 << 11), + GPU_PARTICLE_ANG_VELOCITY = (1 << 12), } GPUBuiltin; typedef enum GPUOpenGLBuiltin { @@ -93,12 +102,19 @@ typedef enum GPUOpenGLBuiltin { GPU_COLOR = 2, } GPUOpenGLBuiltin; +typedef enum GPUMatType { + GPU_MATERIAL_TYPE_MESH = 1, + GPU_MATERIAL_TYPE_WORLD = 2, +} GPUMatType; + + typedef enum GPUBlendMode { GPU_BLEND_SOLID = 0, GPU_BLEND_ADD = 1, GPU_BLEND_ALPHA = 2, GPU_BLEND_CLIP = 4, - GPU_BLEND_ALPHA_SORT = 8 + GPU_BLEND_ALPHA_SORT = 8, + GPU_BLEND_ALPHA_TO_COVERAGE = 16 } GPUBlendMode; typedef struct GPUNodeStack { @@ -111,15 +127,74 @@ typedef struct GPUNodeStack { short sockettype; } GPUNodeStack; -GPUNodeLink *GPU_attribute(int type, const char *name); + +#define GPU_DYNAMIC_GROUP_FROM_TYPE(f) ((f) & 0xFFFF0000) + +#define GPU_DYNAMIC_GROUP_MISC 0x00010000 +#define GPU_DYNAMIC_GROUP_LAMP 0x00020000 +#define GPU_DYNAMIC_GROUP_OBJECT 0x00030000 +#define GPU_DYNAMIC_GROUP_SAMPLER 0x00040000 +#define GPU_DYNAMIC_GROUP_MIST 0x00050000 +#define GPU_DYNAMIC_GROUP_WORLD 0x00060000 +#define GPU_DYNAMIC_GROUP_MAT 0x00070000 + +typedef enum GPUDynamicType { + + GPU_DYNAMIC_NONE = 0, + + GPU_DYNAMIC_OBJECT_VIEWMAT = 1 | GPU_DYNAMIC_GROUP_OBJECT, + GPU_DYNAMIC_OBJECT_MAT = 2 | GPU_DYNAMIC_GROUP_OBJECT, + GPU_DYNAMIC_OBJECT_VIEWIMAT = 3 | GPU_DYNAMIC_GROUP_OBJECT, + GPU_DYNAMIC_OBJECT_IMAT = 4 | GPU_DYNAMIC_GROUP_OBJECT, + GPU_DYNAMIC_OBJECT_COLOR = 5 | GPU_DYNAMIC_GROUP_OBJECT, + GPU_DYNAMIC_OBJECT_AUTOBUMPSCALE = 6 | GPU_DYNAMIC_GROUP_OBJECT, + + GPU_DYNAMIC_LAMP_DYNVEC = 1 | GPU_DYNAMIC_GROUP_LAMP, + GPU_DYNAMIC_LAMP_DYNCO = 2 | GPU_DYNAMIC_GROUP_LAMP, + GPU_DYNAMIC_LAMP_DYNIMAT = 3 | GPU_DYNAMIC_GROUP_LAMP, + GPU_DYNAMIC_LAMP_DYNPERSMAT = 4 | GPU_DYNAMIC_GROUP_LAMP, + GPU_DYNAMIC_LAMP_DYNENERGY = 5 | GPU_DYNAMIC_GROUP_LAMP, + GPU_DYNAMIC_LAMP_DYNCOL = 6 | GPU_DYNAMIC_GROUP_LAMP, + GPU_DYNAMIC_LAMP_DISTANCE = 7 | GPU_DYNAMIC_GROUP_LAMP, + GPU_DYNAMIC_LAMP_ATT1 = 8 | GPU_DYNAMIC_GROUP_LAMP, + GPU_DYNAMIC_LAMP_ATT2 = 9 | GPU_DYNAMIC_GROUP_LAMP, + GPU_DYNAMIC_LAMP_SPOTSIZE = 10 | GPU_DYNAMIC_GROUP_LAMP, + GPU_DYNAMIC_LAMP_SPOTBLEND = 11 | GPU_DYNAMIC_GROUP_LAMP, + + GPU_DYNAMIC_SAMPLER_2DBUFFER = 1 | GPU_DYNAMIC_GROUP_SAMPLER, + GPU_DYNAMIC_SAMPLER_2DIMAGE = 2 | GPU_DYNAMIC_GROUP_SAMPLER, + GPU_DYNAMIC_SAMPLER_2DSHADOW = 3 | GPU_DYNAMIC_GROUP_SAMPLER, + + GPU_DYNAMIC_MIST_ENABLE = 1 | GPU_DYNAMIC_GROUP_MIST, + GPU_DYNAMIC_MIST_START = 2 | GPU_DYNAMIC_GROUP_MIST, + GPU_DYNAMIC_MIST_DISTANCE = 3 | GPU_DYNAMIC_GROUP_MIST, + GPU_DYNAMIC_MIST_INTENSITY = 4 | GPU_DYNAMIC_GROUP_MIST, + GPU_DYNAMIC_MIST_TYPE = 5 | GPU_DYNAMIC_GROUP_MIST, + GPU_DYNAMIC_MIST_COLOR = 6 | GPU_DYNAMIC_GROUP_MIST, + + GPU_DYNAMIC_HORIZON_COLOR = 1 | GPU_DYNAMIC_GROUP_WORLD, + GPU_DYNAMIC_AMBIENT_COLOR = 2 | GPU_DYNAMIC_GROUP_WORLD, + + GPU_DYNAMIC_MAT_DIFFRGB = 1 | GPU_DYNAMIC_GROUP_MAT, + GPU_DYNAMIC_MAT_REF = 2 | GPU_DYNAMIC_GROUP_MAT, + GPU_DYNAMIC_MAT_SPECRGB = 3 | GPU_DYNAMIC_GROUP_MAT, + GPU_DYNAMIC_MAT_SPEC = 4 | GPU_DYNAMIC_GROUP_MAT, + GPU_DYNAMIC_MAT_HARD = 5 | GPU_DYNAMIC_GROUP_MAT, + GPU_DYNAMIC_MAT_EMIT = 6 | GPU_DYNAMIC_GROUP_MAT, + GPU_DYNAMIC_MAT_AMB = 7 | GPU_DYNAMIC_GROUP_MAT, + GPU_DYNAMIC_MAT_ALPHA = 8 | GPU_DYNAMIC_GROUP_MAT +} GPUDynamicType; + +GPUNodeLink *GPU_attribute(CustomDataType type, const char *name); GPUNodeLink *GPU_uniform(float *num); -GPUNodeLink *GPU_dynamic_uniform(float *num, int dynamictype, void *data); +GPUNodeLink *GPU_dynamic_uniform(float *num, GPUDynamicType dynamictype, void *data); GPUNodeLink *GPU_image(struct Image *ima, struct ImageUser *iuser, bool is_data); GPUNodeLink *GPU_image_preview(struct PreviewImage *prv); GPUNodeLink *GPU_texture(int size, float *pixels); -GPUNodeLink *GPU_dynamic_texture(struct GPUTexture *tex, int dynamictype, void *data); +GPUNodeLink *GPU_dynamic_texture(struct GPUTexture *tex, GPUDynamicType dynamictype, void *data); GPUNodeLink *GPU_builtin(GPUBuiltin builtin); 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, ...); @@ -129,19 +204,21 @@ void GPU_material_enable_alpha(GPUMaterial *material); GPUBlendMode GPU_material_alpha_blend(GPUMaterial *material, float obcol[4]); /* High level functions to create and use GPU materials */ +GPUMaterial *GPU_material_world(struct Scene *scene, struct World *wo); -GPUMaterial *GPU_material_from_blender(struct Scene *scene, struct Material *ma); -GPUMaterial *GPU_material_matcap(struct Scene *scene, struct Material *ma); -void GPU_material_free(struct Material *ma); +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_override_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], bool scenelock); -void GPU_material_bind_uniforms(GPUMaterial *material, float obmat[4][4], float obcol[4], float autobumpscale); +void GPU_material_bind(GPUMaterial *material, int oblay, int viewlay, double time, int mipmap, float viewmat[4][4], float viewinv[4][4], float cameraborder[4], bool scenelock); +void GPU_material_bind_uniforms(GPUMaterial *material, float obmat[4][4], float obcol[4], float autobumpscale, GPUParticleInfo *pi); void GPU_material_unbind(GPUMaterial *material); -int GPU_material_bound(GPUMaterial *material); +bool GPU_material_bound(GPUMaterial *material); struct Scene *GPU_material_scene(GPUMaterial *material); +GPUMatType GPU_Material_get_type(GPUMaterial *material); void GPU_material_vertex_attributes(GPUMaterial *material, struct GPUVertexAttribs *attrib); @@ -157,6 +234,7 @@ typedef struct GPUShadeInput { GPUNodeLink *rgb, *specrgb, *vn, *view, *vcol, *ref; GPUNodeLink *alpha, *refl, *spec, *emit, *har, *amb; + GPUNodeLink *spectra; } GPUShadeInput; typedef struct GPUShadeResult { @@ -168,36 +246,9 @@ void GPU_shaderesult_set(GPUShadeInput *shi, GPUShadeResult *shr); /* Export GLSL shader */ -typedef enum GPUDynamicType { - GPU_DYNAMIC_NONE = 0, - GPU_DYNAMIC_OBJECT_VIEWMAT = 1, - GPU_DYNAMIC_OBJECT_MAT = 2, - GPU_DYNAMIC_OBJECT_VIEWIMAT = 3, - GPU_DYNAMIC_OBJECT_IMAT = 4, - GPU_DYNAMIC_OBJECT_COLOR = 5, - GPU_DYNAMIC_OBJECT_AUTOBUMPSCALE = 15, - - GPU_DYNAMIC_LAMP_FIRST = 6, - GPU_DYNAMIC_LAMP_DYNVEC = 6, - GPU_DYNAMIC_LAMP_DYNCO = 7, - GPU_DYNAMIC_LAMP_DYNIMAT = 8, - GPU_DYNAMIC_LAMP_DYNPERSMAT = 9, - GPU_DYNAMIC_LAMP_DYNENERGY = 10, - GPU_DYNAMIC_LAMP_DYNCOL = 11, - GPU_DYNAMIC_LAMP_LAST = 11, - GPU_DYNAMIC_SAMPLER_2DBUFFER = 12, - GPU_DYNAMIC_SAMPLER_2DIMAGE = 13, - GPU_DYNAMIC_SAMPLER_2DSHADOW = 14, - GPU_DYNAMIC_LAMP_DISTANCE = 16, - GPU_DYNAMIC_LAMP_ATT1 = 17, - GPU_DYNAMIC_LAMP_ATT2 = 18, - GPU_DYNAMIC_LAMP_SPOTSIZE = 19, - GPU_DYNAMIC_LAMP_SPOTBLEND = 20, -} GPUDynamicType; - typedef enum GPUDataType { GPU_DATA_NONE = 0, - GPU_DATA_1I = 1, // 1 integer + GPU_DATA_1I = 1, /* 1 integer */ GPU_DATA_1F = 2, GPU_DATA_2F = 3, GPU_DATA_3F = 4, @@ -210,23 +261,23 @@ typedef enum GPUDataType { /* this structure gives information of each uniform found in the shader */ typedef struct GPUInputUniform { struct GPUInputUniform *next, *prev; - char varname[32]; /* name of uniform in shader */ - GPUDynamicType type; /* type of uniform, data format and calculation derive from it */ - GPUDataType datatype; /* type of uniform data */ - struct Object *lamp; /* when type=GPU_DYNAMIC_LAMP_... or GPU_DYNAMIC_SAMPLER_2DSHADOW */ - struct Image *image; /* when type=GPU_DYNAMIC_SAMPLER_2DIMAGE */ - int texnumber; /* when type=GPU_DYNAMIC_SAMPLER, texture number: 0.. */ - unsigned char *texpixels; /* for internally generated texture, pixel data in RGBA format */ - int texsize; /* size in pixel of the texture in texpixels buffer: for 2D textures, this is S and T size (square texture) */ + char varname[32]; /* name of uniform in shader */ + GPUDynamicType type; /* type of uniform, data format and calculation derive from it */ + GPUDataType datatype; /* type of uniform data */ + struct Object *lamp; /* when type=GPU_DYNAMIC_LAMP_... or GPU_DYNAMIC_SAMPLER_2DSHADOW */ + struct Image *image; /* when type=GPU_DYNAMIC_SAMPLER_2DIMAGE */ + int texnumber; /* when type=GPU_DYNAMIC_SAMPLER, texture number: 0.. */ + unsigned char *texpixels; /* for internally generated texture, pixel data in RGBA format */ + int texsize; /* size in pixel of the texture in texpixels buffer: for 2D textures, this is S and T size (square texture) */ } GPUInputUniform; typedef struct GPUInputAttribute { struct GPUInputAttribute *next, *prev; - char varname[32]; /* name of attribute in shader */ - int type; /* from CustomData.type, data type derives from it */ - GPUDataType datatype; /* type of attribute data */ - const char *name; /* layer name */ - int number; /* generic attribute number */ + char varname[32]; /* name of attribute in shader */ + int type; /* from CustomData.type, data type derives from it */ + GPUDataType datatype; /* type of attribute data */ + const char *name; /* layer name */ + int number; /* generic attribute number */ } GPUInputAttribute; typedef struct GPUShaderExport { @@ -255,7 +306,27 @@ void GPU_lamp_update_colors(GPULamp *lamp, float r, float g, float b, float ener void GPU_lamp_update_distance(GPULamp *lamp, float distance, float att1, float att2); void GPU_lamp_update_spot(GPULamp *lamp, float spotsize, float spotblend); int GPU_lamp_shadow_layer(GPULamp *lamp); -GPUNodeLink *GPU_lamp_get_data(GPUMaterial *mat, GPULamp *lamp, GPUNodeLink **col, GPUNodeLink **lv, GPUNodeLink **dist, GPUNodeLink **shadow); +GPUNodeLink *GPU_lamp_get_data(GPUMaterial *mat, GPULamp *lamp, GPUNodeLink **col, GPUNodeLink **lv, GPUNodeLink **dist, GPUNodeLink **shadow, GPUNodeLink **energy); + +/* World */ +void GPU_mist_update_enable(short enable); +void GPU_mist_update_values(int type, float start, float dist, float inten, float color[3]); +void GPU_horizon_update_color(float color[3]); +void GPU_ambient_update_color(float color[3]); + +typedef struct GPUParticleInfo +{ + float scalprops[4]; + float location[3]; + float velocity[3]; + float angular_velocity[3]; +} GPUParticleInfo; + +#ifdef WITH_OPENSUBDIV +struct DerivedMesh; +void GPU_material_update_fvar_offset(GPUMaterial *gpu_material, + struct DerivedMesh *dm); +#endif #ifdef __cplusplus } diff --git a/source/blender/gpu/GPU_select.h b/source/blender/gpu/GPU_select.h index 1a274e0ad9d..09137fc998b 100644 --- a/source/blender/gpu/GPU_select.h +++ b/source/blender/gpu/GPU_select.h @@ -27,8 +27,8 @@ * \ingroup gpu */ -#ifndef __GPU_SELECT__ -#define __GPU_SELECT__ +#ifndef __GPU_SELECT_H__ +#define __GPU_SELECT_H__ #include "DNA_vec_types.h" /* rcft */ #include "BLI_sys_types.h" diff --git a/source/blender/gpu/GPU_simple_shader.h b/source/blender/gpu/GPU_simple_shader.h index c8fb1f09b04..239296209b4 100644 --- a/source/blender/gpu/GPU_simple_shader.h +++ b/source/blender/gpu/GPU_simple_shader.h @@ -42,11 +42,11 @@ extern "C" { typedef enum GPUSimpleShaderOption { GPU_SHADER_OVERRIDE_DIFFUSE = (1<<0), /* replace diffuse with glcolor */ - GPU_SHADER_LIGHTING = (1<<1), /* use lighting */ - GPU_SHADER_TWO_SIDED = (1<<2), /* flip normals towards viewer */ - GPU_SHADER_TEXTURE_2D = (1<<3), /* use 2D texture to replace diffuse color */ + GPU_SHADER_LIGHTING = (1<<1), /* use lighting */ + GPU_SHADER_TWO_SIDED = (1<<2), /* flip normals towards viewer */ + GPU_SHADER_TEXTURE_2D = (1<<3), /* use 2D texture to replace diffuse color */ - GPU_SHADER_SOLID_LIGHTING = (1<<4), /* use faster lighting (set automatically) */ + GPU_SHADER_SOLID_LIGHTING = (1<<4), /* use faster lighting (set automatically) */ GPU_SHADER_OPTIONS_NUM = 5, GPU_SHADER_OPTION_COMBINATIONS = (1<<GPU_SHADER_OPTIONS_NUM) } GPUSimpleShaderOption; diff --git a/source/blender/gpu/SConscript b/source/blender/gpu/SConscript index e9320f08eff..d27d5b09b56 100644 --- a/source/blender/gpu/SConscript +++ b/source/blender/gpu/SConscript @@ -30,13 +30,15 @@ Import ('env') sources = env.Glob('intern/*.c') sources += env.Glob('shaders/*.c') -defs = [ 'GLEW_STATIC' ] +defs = [] +defs += env['BF_GL_DEFINITIONS'] incs = [ '.', + '#/intern/glew-mx', '#/intern/guardedalloc', + env['BF_GLEW_INC'], '#/intern/smoke/extern', - '#/extern/glew/include', '../blenkernel', '../blenlib', '../bmesh', @@ -46,7 +48,6 @@ incs = [ '../makesrna', '../nodes', '../nodes/intern', - env['BF_OPENGL_INC'], ] if env['WITH_BF_GAMEENGINE']: @@ -60,15 +61,31 @@ if env['WITH_BF_SMOKE']: if env['WITH_BF_DDS']: defs.append('WITH_DDS') +if env['WITH_BF_OPENSUBDIV']: + defs.append('WITH_OPENSUBDIV') + # generated data files import os sources.extend(( + os.path.join(env['DATA_SOURCES'], "gpu_shader_geometry.glsl.c"), + os.path.join(env['DATA_SOURCES'], "gpu_program_smoke_frag.glsl.c"), + os.path.join(env['DATA_SOURCES'], "gpu_program_smoke_color_frag.glsl.c"), os.path.join(env['DATA_SOURCES'], "gpu_shader_simple_frag.glsl.c"), os.path.join(env['DATA_SOURCES'], "gpu_shader_simple_vert.glsl.c"), + os.path.join(env['DATA_SOURCES'], "gpu_shader_fx_ssao_frag.glsl.c"), + os.path.join(env['DATA_SOURCES'], "gpu_shader_fx_dof_hq_frag.glsl.c"), + os.path.join(env['DATA_SOURCES'], "gpu_shader_fx_dof_hq_vert.glsl.c"), + os.path.join(env['DATA_SOURCES'], "gpu_shader_fx_dof_hq_geo.glsl.c"), + os.path.join(env['DATA_SOURCES'], "gpu_shader_fx_dof_frag.glsl.c"), + os.path.join(env['DATA_SOURCES'], "gpu_shader_fx_dof_vert.glsl.c"), + os.path.join(env['DATA_SOURCES'], "gpu_shader_fx_depth_resolve.glsl.c"), + os.path.join(env['DATA_SOURCES'], "gpu_shader_fx_lib.glsl.c"), + os.path.join(env['DATA_SOURCES'], "gpu_shader_fx_vert.glsl.c"), os.path.join(env['DATA_SOURCES'], "gpu_shader_material.glsl.c"), os.path.join(env['DATA_SOURCES'], "gpu_shader_sep_gaussian_blur_frag.glsl.c"), os.path.join(env['DATA_SOURCES'], "gpu_shader_sep_gaussian_blur_vert.glsl.c"), os.path.join(env['DATA_SOURCES'], "gpu_shader_vertex.glsl.c"), + os.path.join(env['DATA_SOURCES'], "gpu_shader_vertex_world.glsl.c"), os.path.join(env['DATA_SOURCES'], "gpu_shader_vsm_store_frag.glsl.c"), os.path.join(env['DATA_SOURCES'], "gpu_shader_vsm_store_vert.glsl.c"), )) diff --git a/source/blender/gpu/intern/gpu_buffers.c b/source/blender/gpu/intern/gpu_buffers.c index 5d2c9cd3a90..b4617b9790e 100644 --- a/source/blender/gpu/intern/gpu_buffers.c +++ b/source/blender/gpu/intern/gpu_buffers.c @@ -36,7 +36,7 @@ #include <stddef.h> #include <string.h> -#include "GL/glew.h" +#include "GPU_glew.h" #include "MEM_guardedalloc.h" @@ -46,13 +46,12 @@ #include "BLI_ghash.h" #include "BLI_threads.h" -#include "DNA_material_types.h" #include "DNA_meshdata_types.h" #include "BKE_ccg.h" #include "BKE_DerivedMesh.h" #include "BKE_paint.h" -#include "BKE_material.h" +#include "BKE_mesh.h" #include "BKE_pbvh.h" #include "DNA_userdef_types.h" @@ -71,17 +70,80 @@ typedef enum { GPU_BUFFER_ELEMENT_STATE = (1 << 5), } GPUBufferState; +typedef struct { + GLenum gl_buffer_type; + int num_components; /* number of data components for one vertex */ +} GPUBufferTypeSettings; + + +static size_t gpu_buffer_size_from_type(DerivedMesh *dm, GPUBufferType type); + +const GPUBufferTypeSettings gpu_buffer_type_settings[] = { + /* vertex */ + {GL_ARRAY_BUFFER_ARB, 3}, + /* normal */ + {GL_ARRAY_BUFFER_ARB, 4}, /* we copy 3 shorts per normal but we add a fourth for alignment */ + /* mcol */ + {GL_ARRAY_BUFFER_ARB, 3}, + /* uv */ + {GL_ARRAY_BUFFER_ARB, 2}, + /* uv for texpaint */ + {GL_ARRAY_BUFFER_ARB, 4}, + /* edge */ + {GL_ELEMENT_ARRAY_BUFFER_ARB, 2}, + /* uv edge */ + {GL_ELEMENT_ARRAY_BUFFER_ARB, 4}, + /* triangles, 1 point since we are allocating from tottriangle points, which account for all points */ + {GL_ELEMENT_ARRAY_BUFFER_ARB, 1}, +}; + #define MAX_GPU_ATTRIB_DATA 32 #define BUFFER_OFFSET(n) ((GLubyte *)NULL + (n)) /* -1 - undefined, 0 - vertex arrays, 1 - VBOs */ -static int useVBOs = -1; static GPUBufferState GLStates = 0; static GPUAttrib attribData[MAX_GPU_ATTRIB_DATA] = { { -1, 0, 0 } }; static ThreadMutex buffer_mutex = BLI_MUTEX_INITIALIZER; +/* multires global buffer, can be used for many grids having the same grid size */ +static GPUBuffer *mres_glob_buffer = NULL; +static int mres_prev_gridsize = -1; +static GLenum mres_prev_index_type = 0; +static unsigned mres_prev_totquad = 0; + +void GPU_buffer_material_finalize(GPUDrawObject *gdo, GPUBufferMaterial *matinfo, int totmat) +{ + int i, curmat, curelement; + + /* count the number of materials used by this DerivedMesh */ + for (i = 0; i < totmat; i++) { + if (matinfo[i].totelements > 0) + gdo->totmaterial++; + } + + /* allocate an array of materials used by this DerivedMesh */ + gdo->materials = MEM_mallocN(sizeof(GPUBufferMaterial) * gdo->totmaterial, + "GPUDrawObject.materials"); + + /* initialize the materials array */ + for (i = 0, curmat = 0, curelement = 0; i < totmat; i++) { + if (matinfo[i].totelements > 0) { + gdo->materials[curmat] = matinfo[i]; + gdo->materials[curmat].start = curelement; + gdo->materials[curmat].mat_nr = i; + gdo->materials[curmat].polys = MEM_mallocN(sizeof(int) * matinfo[i].totpolys, "GPUBufferMaterial.polys"); + + curelement += matinfo[i].totelements; + curmat++; + } + } + + MEM_freeN(matinfo); +} + + /* stores recently-deleted buffers so that new buffers won't have to * be recreated as often * @@ -96,33 +158,22 @@ static ThreadMutex buffer_mutex = BLI_MUTEX_INITIALIZER; typedef struct GPUBufferPool { /* number of allocated buffers stored */ int totbuf; - int totpbvhbufids; /* actual allocated length of the arrays */ int maxsize; - int maxpbvhsize; GPUBuffer **buffers; - GLuint *pbvhbufids; } GPUBufferPool; #define MAX_FREE_GPU_BUFFERS 8 -#define MAX_FREE_GPU_BUFF_IDS 100 /* create a new GPUBufferPool */ static GPUBufferPool *gpu_buffer_pool_new(void) { GPUBufferPool *pool; - /* enable VBOs if supported */ - if (useVBOs == -1) - useVBOs = (GLEW_ARB_vertex_buffer_object ? 1 : 0); - pool = MEM_callocN(sizeof(GPUBufferPool), "GPUBuffer_Pool"); pool->maxsize = MAX_FREE_GPU_BUFFERS; - pool->maxpbvhsize = MAX_FREE_GPU_BUFF_IDS; pool->buffers = MEM_mallocN(sizeof(*pool->buffers) * pool->maxsize, "GPUBufferPool.buffers"); - pool->pbvhbufids = MEM_mallocN(sizeof(*pool->pbvhbufids) * pool->maxpbvhsize, - "GPUBufferPool.pbvhbuffers"); return pool; } @@ -158,7 +209,7 @@ static void gpu_buffer_pool_delete_last(GPUBufferPool *pool) return; /* delete the buffer's data */ - if (useVBOs) + if (last->use_vbo) glDeleteBuffersARB(1, &last->id); else MEM_freeN(last->pointer); @@ -180,7 +231,6 @@ static void gpu_buffer_pool_free(GPUBufferPool *pool) gpu_buffer_pool_delete_last(pool); MEM_freeN(pool->buffers); - MEM_freeN(pool->pbvhbufids); MEM_freeN(pool); } @@ -194,9 +244,6 @@ static void gpu_buffer_pool_free_unused(GPUBufferPool *pool) while (pool->totbuf) gpu_buffer_pool_delete_last(pool); - glDeleteBuffersARB(pool->totpbvhbufids, pool->pbvhbufids); - pool->totpbvhbufids = 0; - BLI_mutex_unlock(&buffer_mutex); } @@ -226,11 +273,12 @@ void GPU_global_buffer_pool_free_unused(void) * * Thread-unsafe version for internal usage only. */ -static GPUBuffer *gpu_buffer_alloc_intern(int size) +static GPUBuffer *gpu_buffer_alloc_intern(size_t size, bool use_VBO) { GPUBufferPool *pool; GPUBuffer *buf; - int i, bufsize, bestfit = -1; + int i, bestfit = -1; + size_t bufsize; /* bad case, leads to leak of buf since buf->pointer will allocate * NULL, leading to return without cleanup. In any case better detect early @@ -251,6 +299,11 @@ static GPUBuffer *gpu_buffer_alloc_intern(int size) for (i = 0; i < pool->totbuf; i++) { bufsize = pool->buffers[i]->size; + /* only return a buffer that matches the VBO preference */ + if (pool->buffers[i]->use_vbo != use_VBO) { + continue; + } + /* check for an exact size match */ if (bufsize == size) { bestfit = i; @@ -279,8 +332,9 @@ static GPUBuffer *gpu_buffer_alloc_intern(int size) /* no acceptable buffer found in the pool, create a new one */ buf = MEM_callocN(sizeof(GPUBuffer), "GPUBuffer"); buf->size = size; + buf->use_vbo = use_VBO; - if (useVBOs == 1) { + if (use_VBO) { /* create a new VBO and initialize it to the requested * size */ glGenBuffersARB(1, &buf->id); @@ -289,8 +343,11 @@ static GPUBuffer *gpu_buffer_alloc_intern(int size) glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0); } else { + static int time = 0; + buf->pointer = MEM_mallocN(size, "GPUBuffer.pointer"); - + + time++; /* purpose of this seems to be dealing with * out-of-memory errors? looks a bit iffy to me * though, at least on Linux I expect malloc() would @@ -299,17 +356,20 @@ static GPUBuffer *gpu_buffer_alloc_intern(int size) gpu_buffer_pool_delete_last(pool); buf->pointer = MEM_mallocN(size, "GPUBuffer.pointer"); } - if (!buf->pointer) + if (!buf->pointer) { + MEM_freeN(buf); return NULL; + } } return buf; } /* Same as above, but safe for threading. */ -GPUBuffer *GPU_buffer_alloc(int size) +GPUBuffer *GPU_buffer_alloc(size_t size, bool force_vertex_arrays) { GPUBuffer *buffer; + bool use_VBOs = (GLEW_ARB_vertex_buffer_object) && !(U.gameflags & USER_DISABLE_VBO) && !force_vertex_arrays; if (size == 0) { /* Early out, no lock needed in this case. */ @@ -317,7 +377,7 @@ GPUBuffer *GPU_buffer_alloc(int size) } BLI_mutex_lock(&buffer_mutex); - buffer = gpu_buffer_alloc_intern(size); + buffer = gpu_buffer_alloc_intern(size, use_VBOs); BLI_mutex_unlock(&buffer_mutex); return buffer; @@ -381,224 +441,95 @@ void GPU_buffer_free(GPUBuffer *buffer) BLI_mutex_unlock(&buffer_mutex); } -/* currently unused */ -// #define USE_GPU_POINT_LINK - -typedef struct GPUVertPointLink { -#ifdef USE_GPU_POINT_LINK - struct GPUVertPointLink *next; -#endif - /* -1 means uninitialized */ - int point_index; -} GPUVertPointLink; - - -/* add a new point to the list of points related to a particular - * vertex */ -#ifdef USE_GPU_POINT_LINK - -static void gpu_drawobject_add_vert_point(GPUDrawObject *gdo, int vert_index, int point_index) -{ - GPUVertPointLink *lnk; - - lnk = &gdo->vert_points[vert_index]; - - /* if first link is in use, add a new link at the end */ - if (lnk->point_index != -1) { - /* get last link */ - for (; lnk->next; lnk = lnk->next) ; - - /* add a new link from the pool */ - lnk = lnk->next = &gdo->vert_points_mem[gdo->vert_points_usage]; - gdo->vert_points_usage++; - } - - lnk->point_index = point_index; -} - -#else - -static void gpu_drawobject_add_vert_point(GPUDrawObject *gdo, int vert_index, int point_index) +void GPU_buffer_multires_free(bool force) { - GPUVertPointLink *lnk; - lnk = &gdo->vert_points[vert_index]; - if (lnk->point_index == -1) { - lnk->point_index = point_index; - } -} - -#endif /* USE_GPU_POINT_LINK */ - -/* update the vert_points and triangle_to_mface fields with a new - * triangle */ -static void gpu_drawobject_add_triangle(GPUDrawObject *gdo, - int base_point_index, - int face_index, - int v1, int v2, int v3) -{ - int i, v[3] = {v1, v2, v3}; - for (i = 0; i < 3; i++) - gpu_drawobject_add_vert_point(gdo, v[i], base_point_index + i); - gdo->triangle_to_mface[base_point_index / 3] = face_index; -} - -/* for each vertex, build a list of points related to it; these lists - * are stored in an array sized to the number of vertices */ -static void gpu_drawobject_init_vert_points(GPUDrawObject *gdo, MFace *f, int totface, int totmat) -{ - GPUBufferMaterial *mat; - int i, *mat_orig_to_new; - - mat_orig_to_new = MEM_callocN(sizeof(*mat_orig_to_new) * totmat, - "GPUDrawObject.mat_orig_to_new"); - /* allocate the array and space for links */ - gdo->vert_points = MEM_mallocN(sizeof(GPUVertPointLink) * gdo->totvert, - "GPUDrawObject.vert_points"); -#ifdef USE_GPU_POINT_LINK - gdo->vert_points_mem = MEM_callocN(sizeof(GPUVertPointLink) * gdo->tot_triangle_point, - "GPUDrawObject.vert_points_mem"); - gdo->vert_points_usage = 0; -#endif - - /* build a map from the original material indices to the new - * GPUBufferMaterial indices */ - for (i = 0; i < gdo->totmaterial; i++) - mat_orig_to_new[gdo->materials[i].mat_nr] = i; - - /* -1 indicates the link is not yet used */ - for (i = 0; i < gdo->totvert; i++) { -#ifdef USE_GPU_POINT_LINK - gdo->vert_points[i].link = NULL; -#endif - gdo->vert_points[i].point_index = -1; + if (!mres_glob_buffer) { + /* Early output, no need to lock in this case, */ + return; } - for (i = 0; i < totface; i++, f++) { - mat = &gdo->materials[mat_orig_to_new[f->mat_nr]]; - - /* add triangle */ - gpu_drawobject_add_triangle(gdo, mat->start + mat->totpoint, - i, f->v1, f->v2, f->v3); - mat->totpoint += 3; - - /* add second triangle for quads */ - if (f->v4) { - gpu_drawobject_add_triangle(gdo, mat->start + mat->totpoint, - i, f->v3, f->v4, f->v1); - mat->totpoint += 3; + if (force && BLI_thread_is_main()) { + if (mres_glob_buffer) { + if (mres_glob_buffer->id) + glDeleteBuffersARB(1, &mres_glob_buffer->id); + else if (mres_glob_buffer->pointer) + MEM_freeN(mres_glob_buffer->pointer); + MEM_freeN(mres_glob_buffer); } } - - /* map any unused vertices to loose points */ - for (i = 0; i < gdo->totvert; i++) { - if (gdo->vert_points[i].point_index == -1) { - gdo->vert_points[i].point_index = gdo->tot_triangle_point + gdo->tot_loose_point; - gdo->tot_loose_point++; - } + else { + BLI_mutex_lock(&buffer_mutex); + gpu_buffer_free_intern(mres_glob_buffer); + BLI_mutex_unlock(&buffer_mutex); } - MEM_freeN(mat_orig_to_new); + mres_glob_buffer = NULL; + mres_prev_gridsize = -1; + mres_prev_index_type = 0; + mres_prev_totquad = 0; } -/* see GPUDrawObject's structure definition for a description of the - * data being initialized here */ -GPUDrawObject *GPU_drawobject_new(DerivedMesh *dm) -{ - GPUDrawObject *gdo; - MFace *mface; - int totmat = dm->totmat; - int *points_per_mat; - int i, curmat, curpoint, totface; - - /* object contains at least one material (default included) so zero means uninitialized dm */ - BLI_assert(totmat != 0); - - mface = dm->getTessFaceArray(dm); - totface = dm->getNumTessFaces(dm); - - /* get the number of points used by each material, treating - * each quad as two triangles */ - points_per_mat = MEM_callocN(sizeof(*points_per_mat) * totmat, "GPU_drawobject_new.mat_orig_to_new"); - for (i = 0; i < totface; i++) - points_per_mat[mface[i].mat_nr] += mface[i].v4 ? 6 : 3; - - /* create the GPUDrawObject */ - gdo = MEM_callocN(sizeof(GPUDrawObject), "GPUDrawObject"); - gdo->totvert = dm->getNumVerts(dm); - gdo->totedge = dm->getNumEdges(dm); - - /* count the number of materials used by this DerivedMesh */ - for (i = 0; i < totmat; i++) { - if (points_per_mat[i] > 0) - gdo->totmaterial++; - } - - /* allocate an array of materials used by this DerivedMesh */ - gdo->materials = MEM_mallocN(sizeof(GPUBufferMaterial) * gdo->totmaterial, - "GPUDrawObject.materials"); - - /* initialize the materials array */ - for (i = 0, curmat = 0, curpoint = 0; i < totmat; i++) { - if (points_per_mat[i] > 0) { - gdo->materials[curmat].start = curpoint; - gdo->materials[curmat].totpoint = 0; - gdo->materials[curmat].mat_nr = i; - - curpoint += points_per_mat[i]; - curmat++; - } - } - - /* store total number of points used for triangles */ - gdo->tot_triangle_point = curpoint; - - gdo->triangle_to_mface = MEM_mallocN(sizeof(int) * (gdo->tot_triangle_point / 3), - "GPUDrawObject.triangle_to_mface"); - - gpu_drawobject_init_vert_points(gdo, mface, totface, totmat); - MEM_freeN(points_per_mat); - - return gdo; -} void GPU_drawobject_free(DerivedMesh *dm) { GPUDrawObject *gdo; + int i; if (!dm || !(gdo = dm->drawObject)) return; + for (i = 0; i < gdo->totmaterial; i++) { + if (gdo->materials[i].polys) + MEM_freeN(gdo->materials[i].polys); + } + MEM_freeN(gdo->materials); - MEM_freeN(gdo->triangle_to_mface); - MEM_freeN(gdo->vert_points); + if (gdo->vert_points) + MEM_freeN(gdo->vert_points); #ifdef USE_GPU_POINT_LINK MEM_freeN(gdo->vert_points_mem); #endif GPU_buffer_free(gdo->points); GPU_buffer_free(gdo->normals); GPU_buffer_free(gdo->uv); + GPU_buffer_free(gdo->uv_tex); GPU_buffer_free(gdo->colors); GPU_buffer_free(gdo->edges); GPU_buffer_free(gdo->uvedges); + GPU_buffer_free(gdo->triangles); MEM_freeN(gdo); dm->drawObject = NULL; } -typedef void (*GPUBufferCopyFunc)(DerivedMesh *dm, float *varray, int *index, - int *mat_orig_to_new, void *user_data); +static GPUBuffer *gpu_try_realloc(GPUBufferPool *pool, GPUBuffer *buffer, size_t size, bool use_VBOs) +{ + /* try freeing an entry from the pool + * and reallocating the buffer */ + gpu_buffer_free_intern(buffer); + + buffer = NULL; + + while (pool->totbuf && !buffer) { + gpu_buffer_pool_delete_last(pool); + buffer = gpu_buffer_alloc_intern(size, use_VBOs); + } + + return buffer; +} static GPUBuffer *gpu_buffer_setup(DerivedMesh *dm, GPUDrawObject *object, - int vector_size, int size, GLenum target, - void *user, GPUBufferCopyFunc copy_f) + int type, void *user) { GPUBufferPool *pool; GPUBuffer *buffer; float *varray; int *mat_orig_to_new; - int *cur_index_per_mat; int i; - bool success; + const GPUBufferTypeSettings *ts = &gpu_buffer_type_settings[type]; + GLenum target = ts->gl_buffer_type; + size_t size = gpu_buffer_size_from_type(dm, type); + bool use_VBOs = (GLEW_ARB_vertex_buffer_object) && !(U.gameflags & USER_DISABLE_VBO); GLboolean uploaded; pool = gpu_get_global_buffer_pool(); @@ -606,30 +537,21 @@ static GPUBuffer *gpu_buffer_setup(DerivedMesh *dm, GPUDrawObject *object, BLI_mutex_lock(&buffer_mutex); /* alloc a GPUBuffer; fall back to legacy mode on failure */ - if (!(buffer = gpu_buffer_alloc_intern(size))) - dm->drawObject->legacy = 1; - - /* nothing to do for legacy mode */ - if (dm->drawObject->legacy) { + if (!(buffer = gpu_buffer_alloc_intern(size, use_VBOs))) { BLI_mutex_unlock(&buffer_mutex); return NULL; } mat_orig_to_new = MEM_mallocN(sizeof(*mat_orig_to_new) * dm->totmat, "GPU_buffer_setup.mat_orig_to_new"); - cur_index_per_mat = MEM_mallocN(sizeof(int) * object->totmaterial, - "GPU_buffer_setup.cur_index_per_mat"); for (i = 0; i < object->totmaterial; i++) { - /* for each material, the current index to copy data to */ - cur_index_per_mat[i] = object->materials[i].start * vector_size; - /* map from original material index to new * GPUBufferMaterial index */ mat_orig_to_new[object->materials[i].mat_nr] = i; } - if (useVBOs) { - success = 0; + if (use_VBOs) { + bool success = false; while (!success) { /* bind the buffer and discard previous data, @@ -639,36 +561,26 @@ static GPUBuffer *gpu_buffer_setup(DerivedMesh *dm, GPUDrawObject *object, /* attempt to map the buffer */ if (!(varray = glMapBufferARB(target, GL_WRITE_ONLY_ARB))) { - /* failed to map the buffer; delete it */ - gpu_buffer_free_intern(buffer); - gpu_buffer_pool_delete_last(pool); - buffer = NULL; - - /* try freeing an entry from the pool - * and reallocating the buffer */ - if (pool->totbuf > 0) { - gpu_buffer_pool_delete_last(pool); - buffer = gpu_buffer_alloc_intern(size); - } + buffer = gpu_try_realloc(pool, buffer, size, true); /* allocation still failed; fall back * to legacy mode */ - if (!buffer) { - dm->drawObject->legacy = 1; - success = 1; + if (!(buffer && (varray = glMapBufferARB(target, GL_WRITE_ONLY_ARB)))) { + use_VBOs = false; + success = true; } } else { - success = 1; + success = true; } } /* check legacy fallback didn't happen */ - if (dm->drawObject->legacy == 0) { + if (use_VBOs) { uploaded = GL_FALSE; /* attempt to upload the data to the VBO */ while (uploaded == GL_FALSE) { - (*copy_f)(dm, varray, cur_index_per_mat, mat_orig_to_new, user); + dm->copy_gpu_data(dm, type, varray, mat_orig_to_new, user); /* glUnmapBuffer returns GL_FALSE if * the data store is corrupted; retry * in that case */ @@ -677,18 +589,18 @@ static GPUBuffer *gpu_buffer_setup(DerivedMesh *dm, GPUDrawObject *object, } glBindBufferARB(target, 0); } - else { + if (!use_VBOs) { /* VBO not supported, use vertex array fallback */ - if (buffer->pointer) { - varray = buffer->pointer; - (*copy_f)(dm, varray, cur_index_per_mat, mat_orig_to_new, user); + if (!buffer || !buffer->pointer) { + buffer = gpu_try_realloc(pool, buffer, size, false); } - else { - dm->drawObject->legacy = 1; + + if (buffer) { + varray = buffer->pointer; + dm->copy_gpu_data(dm, type, varray, mat_orig_to_new, user); } } - MEM_freeN(cur_index_per_mat); MEM_freeN(mat_orig_to_new); BLI_mutex_unlock(&buffer_mutex); @@ -696,316 +608,6 @@ static GPUBuffer *gpu_buffer_setup(DerivedMesh *dm, GPUDrawObject *object, return buffer; } -static void GPU_buffer_copy_vertex(DerivedMesh *dm, float *varray, int *index, int *mat_orig_to_new, void *UNUSED(user)) -{ - MVert *mvert; - MFace *f; - int i, j, start, totface; - - mvert = dm->getVertArray(dm); - f = dm->getTessFaceArray(dm); - - totface = dm->getNumTessFaces(dm); - for (i = 0; i < totface; i++, f++) { - start = index[mat_orig_to_new[f->mat_nr]]; - - /* v1 v2 v3 */ - copy_v3_v3(&varray[start], mvert[f->v1].co); - copy_v3_v3(&varray[start + 3], mvert[f->v2].co); - copy_v3_v3(&varray[start + 6], mvert[f->v3].co); - index[mat_orig_to_new[f->mat_nr]] += 9; - - if (f->v4) { - /* v3 v4 v1 */ - copy_v3_v3(&varray[start + 9], mvert[f->v3].co); - copy_v3_v3(&varray[start + 12], mvert[f->v4].co); - copy_v3_v3(&varray[start + 15], mvert[f->v1].co); - index[mat_orig_to_new[f->mat_nr]] += 9; - } - } - - /* copy loose points */ - j = dm->drawObject->tot_triangle_point * 3; - for (i = 0; i < dm->drawObject->totvert; i++) { - if (dm->drawObject->vert_points[i].point_index >= dm->drawObject->tot_triangle_point) { - copy_v3_v3(&varray[j], mvert[i].co); - j += 3; - } - } -} - -static void GPU_buffer_copy_normal(DerivedMesh *dm, float *varray, int *index, int *mat_orig_to_new, void *UNUSED(user)) -{ - int i, totface; - int start; - float f_no[3]; - - const float *nors = dm->getTessFaceDataArray(dm, CD_NORMAL); - short (*tlnors)[4][3] = dm->getTessFaceDataArray(dm, CD_TESSLOOPNORMAL); - MVert *mvert = dm->getVertArray(dm); - MFace *f = dm->getTessFaceArray(dm); - - totface = dm->getNumTessFaces(dm); - for (i = 0; i < totface; i++, f++) { - const int smoothnormal = (f->flag & ME_SMOOTH); - - start = index[mat_orig_to_new[f->mat_nr]]; - index[mat_orig_to_new[f->mat_nr]] += f->v4 ? 18 : 9; - - if (tlnors) { - short (*tlnor)[3] = tlnors[i]; - /* Copy loop normals */ - normal_short_to_float_v3(&varray[start], tlnor[0]); - normal_short_to_float_v3(&varray[start + 3], tlnor[1]); - normal_short_to_float_v3(&varray[start + 6], tlnor[2]); - - if (f->v4) { - normal_short_to_float_v3(&varray[start + 9], tlnor[2]); - normal_short_to_float_v3(&varray[start + 12], tlnor[3]); - normal_short_to_float_v3(&varray[start + 15], tlnor[0]); - } - } - else if (smoothnormal) { - /* copy vertex normal */ - normal_short_to_float_v3(&varray[start], mvert[f->v1].no); - normal_short_to_float_v3(&varray[start + 3], mvert[f->v2].no); - normal_short_to_float_v3(&varray[start + 6], mvert[f->v3].no); - - if (f->v4) { - normal_short_to_float_v3(&varray[start + 9], mvert[f->v3].no); - normal_short_to_float_v3(&varray[start + 12], mvert[f->v4].no); - normal_short_to_float_v3(&varray[start + 15], mvert[f->v1].no); - } - } - else if (nors) { - /* copy cached face normal */ - copy_v3_v3(&varray[start], &nors[i * 3]); - copy_v3_v3(&varray[start + 3], &nors[i * 3]); - copy_v3_v3(&varray[start + 6], &nors[i * 3]); - - if (f->v4) { - copy_v3_v3(&varray[start + 9], &nors[i * 3]); - copy_v3_v3(&varray[start + 12], &nors[i * 3]); - copy_v3_v3(&varray[start + 15], &nors[i * 3]); - } - } - else { - /* calculate face normal */ - if (f->v4) - normal_quad_v3(f_no, mvert[f->v1].co, mvert[f->v2].co, mvert[f->v3].co, mvert[f->v4].co); - else - normal_tri_v3(f_no, mvert[f->v1].co, mvert[f->v2].co, mvert[f->v3].co); - - copy_v3_v3(&varray[start], f_no); - copy_v3_v3(&varray[start + 3], f_no); - copy_v3_v3(&varray[start + 6], f_no); - - if (f->v4) { - copy_v3_v3(&varray[start + 9], f_no); - copy_v3_v3(&varray[start + 12], f_no); - copy_v3_v3(&varray[start + 15], f_no); - } - } - } -} - -static void GPU_buffer_copy_uv(DerivedMesh *dm, float *varray, int *index, int *mat_orig_to_new, void *UNUSED(user)) -{ - int start; - int i, totface; - - MTFace *mtface; - MFace *f; - - if (!(mtface = DM_get_tessface_data_layer(dm, CD_MTFACE))) - return; - f = dm->getTessFaceArray(dm); - - totface = dm->getNumTessFaces(dm); - for (i = 0; i < totface; i++, f++) { - start = index[mat_orig_to_new[f->mat_nr]]; - - /* v1 v2 v3 */ - copy_v2_v2(&varray[start], mtface[i].uv[0]); - copy_v2_v2(&varray[start + 2], mtface[i].uv[1]); - copy_v2_v2(&varray[start + 4], mtface[i].uv[2]); - index[mat_orig_to_new[f->mat_nr]] += 6; - - if (f->v4) { - /* v3 v4 v1 */ - copy_v2_v2(&varray[start + 6], mtface[i].uv[2]); - copy_v2_v2(&varray[start + 8], mtface[i].uv[3]); - copy_v2_v2(&varray[start + 10], mtface[i].uv[0]); - index[mat_orig_to_new[f->mat_nr]] += 6; - } - } -} - - -static void GPU_buffer_copy_uv_texpaint(DerivedMesh *dm, float *varray, int *index, int *mat_orig_to_new, void *UNUSED(user)) -{ - int start; - int i, totface; - - int totmaterial = dm->totmat; - MTFace **mtface_base; - MTFace *stencil_base; - int stencil; - MFace *mf; - - /* should have been checked for before, reassert */ - BLI_assert(DM_get_tessface_data_layer(dm, CD_MTFACE)); - mf = dm->getTessFaceArray(dm); - mtface_base = MEM_mallocN(totmaterial * sizeof(*mtface_base), "texslots"); - - for (i = 0; i < totmaterial; i++) { - mtface_base[i] = DM_paint_uvlayer_active_get(dm, i); - } - - stencil = CustomData_get_stencil_layer(&dm->faceData, CD_MTFACE); - stencil_base = CustomData_get_layer_n(&dm->faceData, CD_MTFACE, stencil); - - totface = dm->getNumTessFaces(dm); - - for (i = 0; i < totface; i++, mf++) { - int mat_i = mf->mat_nr; - start = index[mat_orig_to_new[mat_i]]; - - /* v1 v2 v3 */ - copy_v2_v2(&varray[start], mtface_base[mat_i][i].uv[0]); - copy_v2_v2(&varray[start + 2], stencil_base[i].uv[0]); - copy_v2_v2(&varray[start + 4], mtface_base[mat_i][i].uv[1]); - copy_v2_v2(&varray[start + 6], stencil_base[i].uv[1]); - copy_v2_v2(&varray[start + 8], mtface_base[mat_i][i].uv[2]); - copy_v2_v2(&varray[start + 10], stencil_base[i].uv[2]); - index[mat_orig_to_new[mat_i]] += 12; - - if (mf->v4) { - /* v3 v4 v1 */ - copy_v2_v2(&varray[start + 12], mtface_base[mat_i][i].uv[2]); - copy_v2_v2(&varray[start + 14], stencil_base[i].uv[2]); - copy_v2_v2(&varray[start + 16], mtface_base[mat_i][i].uv[3]); - copy_v2_v2(&varray[start + 18], stencil_base[i].uv[3]); - copy_v2_v2(&varray[start + 20], mtface_base[mat_i][i].uv[0]); - copy_v2_v2(&varray[start + 22], stencil_base[i].uv[0]); - index[mat_orig_to_new[mat_i]] += 12; - } - } - - MEM_freeN(mtface_base); -} - - -static void copy_mcol_uc3(unsigned char *v, unsigned char *col) -{ - v[0] = col[3]; - v[1] = col[2]; - v[2] = col[1]; -} - -/* treat varray_ as an array of MCol, four MCol's per face */ -static void GPU_buffer_copy_mcol(DerivedMesh *dm, float *varray_, int *index, int *mat_orig_to_new, void *user) -{ - int i, totface; - unsigned char *varray = (unsigned char *)varray_; - unsigned char *mcol = (unsigned char *)user; - MFace *f = dm->getTessFaceArray(dm); - - totface = dm->getNumTessFaces(dm); - for (i = 0; i < totface; i++, f++) { - int start = index[mat_orig_to_new[f->mat_nr]]; - - /* v1 v2 v3 */ - copy_mcol_uc3(&varray[start], &mcol[i * 16]); - copy_mcol_uc3(&varray[start + 3], &mcol[i * 16 + 4]); - copy_mcol_uc3(&varray[start + 6], &mcol[i * 16 + 8]); - index[mat_orig_to_new[f->mat_nr]] += 9; - - if (f->v4) { - /* v3 v4 v1 */ - copy_mcol_uc3(&varray[start + 9], &mcol[i * 16 + 8]); - copy_mcol_uc3(&varray[start + 12], &mcol[i * 16 + 12]); - copy_mcol_uc3(&varray[start + 15], &mcol[i * 16]); - index[mat_orig_to_new[f->mat_nr]] += 9; - } - } -} - -static void GPU_buffer_copy_edge(DerivedMesh *dm, float *varray_, int *UNUSED(index), int *UNUSED(mat_orig_to_new), void *UNUSED(user)) -{ - MEdge *medge; - unsigned int *varray = (unsigned int *)varray_; - int i, totedge; - - medge = dm->getEdgeArray(dm); - totedge = dm->getNumEdges(dm); - - for (i = 0; i < totedge; i++, medge++) { - varray[i * 2] = dm->drawObject->vert_points[medge->v1].point_index; - varray[i * 2 + 1] = dm->drawObject->vert_points[medge->v2].point_index; - } -} - -static void GPU_buffer_copy_uvedge(DerivedMesh *dm, float *varray, int *UNUSED(index), int *UNUSED(mat_orig_to_new), void *UNUSED(user)) -{ - MTFace *tf = DM_get_tessface_data_layer(dm, CD_MTFACE); - int i, j = 0; - - if (!tf) - return; - - for (i = 0; i < dm->numTessFaceData; i++, tf++) { - MFace mf; - dm->getTessFace(dm, i, &mf); - - copy_v2_v2(&varray[j], tf->uv[0]); - copy_v2_v2(&varray[j + 2], tf->uv[1]); - - copy_v2_v2(&varray[j + 4], tf->uv[1]); - copy_v2_v2(&varray[j + 6], tf->uv[2]); - - if (!mf.v4) { - copy_v2_v2(&varray[j + 8], tf->uv[2]); - copy_v2_v2(&varray[j + 10], tf->uv[0]); - j += 12; - } - else { - copy_v2_v2(&varray[j + 8], tf->uv[2]); - copy_v2_v2(&varray[j + 10], tf->uv[3]); - - copy_v2_v2(&varray[j + 12], tf->uv[3]); - copy_v2_v2(&varray[j + 14], tf->uv[0]); - j += 16; - } - } -} - -typedef enum { - GPU_BUFFER_VERTEX = 0, - GPU_BUFFER_NORMAL, - GPU_BUFFER_COLOR, - GPU_BUFFER_UV, - GPU_BUFFER_UV_TEXPAINT, - GPU_BUFFER_EDGE, - GPU_BUFFER_UVEDGE, -} GPUBufferType; - -typedef struct { - GPUBufferCopyFunc copy; - GLenum gl_buffer_type; - int vector_size; -} GPUBufferTypeSettings; - -const GPUBufferTypeSettings gpu_buffer_type_settings[] = { - {GPU_buffer_copy_vertex, GL_ARRAY_BUFFER_ARB, 3}, - {GPU_buffer_copy_normal, GL_ARRAY_BUFFER_ARB, 3}, - {GPU_buffer_copy_mcol, GL_ARRAY_BUFFER_ARB, 3}, - {GPU_buffer_copy_uv, GL_ARRAY_BUFFER_ARB, 2}, - {GPU_buffer_copy_uv_texpaint, GL_ARRAY_BUFFER_ARB, 4}, - {GPU_buffer_copy_edge, GL_ELEMENT_ARRAY_BUFFER_ARB, 2}, - {GPU_buffer_copy_uvedge, GL_ELEMENT_ARRAY_BUFFER_ARB, 4} -}; - /* get the GPUDrawObject buffer associated with a type */ static GPUBuffer **gpu_drawobject_buffer_from_type(GPUDrawObject *gdo, GPUBufferType type) { @@ -1019,39 +621,38 @@ static GPUBuffer **gpu_drawobject_buffer_from_type(GPUDrawObject *gdo, GPUBuffer case GPU_BUFFER_UV: return &gdo->uv; case GPU_BUFFER_UV_TEXPAINT: - return &gdo->uv; + return &gdo->uv_tex; case GPU_BUFFER_EDGE: return &gdo->edges; case GPU_BUFFER_UVEDGE: return &gdo->uvedges; + case GPU_BUFFER_TRIANGLES: + return &gdo->triangles; default: return NULL; } } /* get the amount of space to allocate for a buffer of a particular type */ -static int gpu_buffer_size_from_type(DerivedMesh *dm, GPUBufferType type) +static size_t gpu_buffer_size_from_type(DerivedMesh *dm, GPUBufferType type) { switch (type) { case GPU_BUFFER_VERTEX: - return sizeof(float) * 3 * (dm->drawObject->tot_triangle_point + dm->drawObject->tot_loose_point); + return sizeof(float) * gpu_buffer_type_settings[type].num_components * (dm->drawObject->tot_loop_verts + dm->drawObject->tot_loose_point); case GPU_BUFFER_NORMAL: - return sizeof(float) * 3 * dm->drawObject->tot_triangle_point; + return sizeof(short) * gpu_buffer_type_settings[type].num_components * dm->drawObject->tot_loop_verts; case GPU_BUFFER_COLOR: - return sizeof(char) * 3 * dm->drawObject->tot_triangle_point; + return sizeof(char) * gpu_buffer_type_settings[type].num_components * dm->drawObject->tot_loop_verts; case GPU_BUFFER_UV: - return sizeof(float) * 2 * dm->drawObject->tot_triangle_point; + return sizeof(float) * gpu_buffer_type_settings[type].num_components * dm->drawObject->tot_loop_verts; case GPU_BUFFER_UV_TEXPAINT: - return sizeof(float) * 4 * dm->drawObject->tot_triangle_point; + return sizeof(float) * gpu_buffer_type_settings[type].num_components * dm->drawObject->tot_loop_verts; case GPU_BUFFER_EDGE: - return sizeof(int) * 2 * dm->drawObject->totedge; + return sizeof(int) * gpu_buffer_type_settings[type].num_components * dm->drawObject->totedge; case GPU_BUFFER_UVEDGE: - /* each face gets 3 points, 3 edges per triangle, and - * each edge has its own, non-shared coords, so each - * tri corner needs minimum of 4 floats, quads used - * less so here we can over allocate and assume all - * tris. */ - return sizeof(float) * 4 * dm->drawObject->tot_triangle_point; + return sizeof(int) * gpu_buffer_type_settings[type].num_components * dm->drawObject->tot_loop_verts; + case GPU_BUFFER_TRIANGLES: + return sizeof(int) * gpu_buffer_type_settings[type].num_components * dm->drawObject->tot_triangle_point; default: return -1; } @@ -1060,25 +661,20 @@ static int gpu_buffer_size_from_type(DerivedMesh *dm, GPUBufferType type) /* call gpu_buffer_setup with settings for a particular type of buffer */ static GPUBuffer *gpu_buffer_setup_type(DerivedMesh *dm, GPUBufferType type) { - const GPUBufferTypeSettings *ts; void *user_data = NULL; GPUBuffer *buf; - ts = &gpu_buffer_type_settings[type]; - /* special handling for MCol and UV buffers */ if (type == GPU_BUFFER_COLOR) { - if (!(user_data = DM_get_tessface_data_layer(dm, dm->drawObject->colType))) + if (!(user_data = DM_get_loop_data_layer(dm, dm->drawObject->colType))) return NULL; } else if (ELEM(type, GPU_BUFFER_UV, GPU_BUFFER_UV_TEXPAINT)) { - if (!DM_get_tessface_data_layer(dm, CD_MTFACE)) + if (!DM_get_loop_data_layer(dm, CD_MLOOPUV)) return NULL; } - buf = gpu_buffer_setup(dm, dm->drawObject, ts->vector_size, - gpu_buffer_size_from_type(dm, type), - ts->gl_buffer_type, user_data, ts->copy); + buf = gpu_buffer_setup(dm, dm->drawObject, type, user_data); return buf; } @@ -1090,7 +686,7 @@ static GPUBuffer *gpu_buffer_setup_common(DerivedMesh *dm, GPUBufferType type) GPUBuffer **buf; if (!dm->drawObject) - dm->drawObject = GPU_drawobject_new(dm); + dm->drawObject = dm->gpuObjectNew(dm); buf = gpu_drawobject_buffer_from_type(dm->drawObject, type); if (!(*buf)) @@ -1105,7 +701,7 @@ void GPU_vertex_setup(DerivedMesh *dm) return; glEnableClientState(GL_VERTEX_ARRAY); - if (useVBOs) { + if (dm->drawObject->points->use_vbo) { glBindBufferARB(GL_ARRAY_BUFFER_ARB, dm->drawObject->points->id); glVertexPointer(3, GL_FLOAT, 0, 0); } @@ -1122,12 +718,12 @@ void GPU_normal_setup(DerivedMesh *dm) return; glEnableClientState(GL_NORMAL_ARRAY); - if (useVBOs) { + if (dm->drawObject->normals->use_vbo) { glBindBufferARB(GL_ARRAY_BUFFER_ARB, dm->drawObject->normals->id); - glNormalPointer(GL_FLOAT, 0, 0); + glNormalPointer(GL_SHORT, 4 * sizeof(short), 0); } else { - glNormalPointer(GL_FLOAT, 0, dm->drawObject->normals->pointer); + glNormalPointer(GL_SHORT, 4 * sizeof(short), dm->drawObject->normals->pointer); } GLStates |= GPU_BUFFER_NORMAL_STATE; @@ -1139,7 +735,7 @@ void GPU_uv_setup(DerivedMesh *dm) return; glEnableClientState(GL_TEXTURE_COORD_ARRAY); - if (useVBOs) { + if (dm->drawObject->uv->use_vbo) { glBindBufferARB(GL_ARRAY_BUFFER_ARB, dm->drawObject->uv->id); glTexCoordPointer(2, GL_FLOAT, 0, 0); } @@ -1156,8 +752,8 @@ void GPU_texpaint_uv_setup(DerivedMesh *dm) return; glEnableClientState(GL_TEXTURE_COORD_ARRAY); - if (useVBOs) { - glBindBufferARB(GL_ARRAY_BUFFER_ARB, dm->drawObject->uv->id); + if (dm->drawObject->uv_tex->use_vbo) { + glBindBufferARB(GL_ARRAY_BUFFER_ARB, dm->drawObject->uv_tex->id); glTexCoordPointer(2, GL_FLOAT, 4 * sizeof(float), 0); glClientActiveTexture(GL_TEXTURE2); glEnableClientState(GL_TEXTURE_COORD_ARRAY); @@ -1165,10 +761,10 @@ void GPU_texpaint_uv_setup(DerivedMesh *dm) glClientActiveTexture(GL_TEXTURE0); } else { - glTexCoordPointer(2, GL_FLOAT, 4 * sizeof(float), dm->drawObject->uv->pointer); + glTexCoordPointer(2, GL_FLOAT, 4 * sizeof(float), dm->drawObject->uv_tex->pointer); glClientActiveTexture(GL_TEXTURE2); glEnableClientState(GL_TEXTURE_COORD_ARRAY); - glTexCoordPointer(2, GL_FLOAT, 4 * sizeof(float), (char *)dm->drawObject->uv->pointer + 2 * sizeof(float)); + glTexCoordPointer(2, GL_FLOAT, 4 * sizeof(float), (char *)dm->drawObject->uv_tex->pointer + 2 * sizeof(float)); glClientActiveTexture(GL_TEXTURE0); } @@ -1181,7 +777,7 @@ void GPU_color_setup(DerivedMesh *dm, int colType) if (!dm->drawObject) { /* XXX Not really nice, but we need a valid gpu draw object to set the colType... * Else we would have to add a new param to gpu_buffer_setup_common. */ - dm->drawObject = GPU_drawobject_new(dm); + dm->drawObject = dm->gpuObjectNew(dm); dm->dirty &= ~DM_DIRTY_MCOL_UPDATE_DRAW; dm->drawObject->colType = colType; } @@ -1202,7 +798,7 @@ void GPU_color_setup(DerivedMesh *dm, int colType) return; glEnableClientState(GL_COLOR_ARRAY); - if (useVBOs) { + if (dm->drawObject->colors->use_vbo) { glBindBufferARB(GL_ARRAY_BUFFER_ARB, dm->drawObject->colors->id); glColorPointer(3, GL_UNSIGNED_BYTE, 0, 0); } @@ -1213,6 +809,21 @@ void GPU_color_setup(DerivedMesh *dm, int colType) GLStates |= GPU_BUFFER_COLOR_STATE; } +void GPU_buffer_bind_as_color(GPUBuffer *buffer) +{ + glEnableClientState(GL_COLOR_ARRAY); + if (buffer->use_vbo) { + glBindBufferARB(GL_ARRAY_BUFFER_ARB, buffer->id); + glColorPointer(4, GL_UNSIGNED_BYTE, 0, 0); + } + else { + glColorPointer(4, GL_UNSIGNED_BYTE, 0, buffer->pointer); + } + + GLStates |= GPU_BUFFER_COLOR_STATE; +} + + void GPU_edge_setup(DerivedMesh *dm) { if (!gpu_buffer_setup_common(dm, GPU_BUFFER_EDGE)) @@ -1222,7 +833,7 @@ void GPU_edge_setup(DerivedMesh *dm) return; glEnableClientState(GL_VERTEX_ARRAY); - if (useVBOs) { + if (dm->drawObject->points->use_vbo) { glBindBufferARB(GL_ARRAY_BUFFER_ARB, dm->drawObject->points->id); glVertexPointer(3, GL_FLOAT, 0, 0); } @@ -1232,7 +843,7 @@ void GPU_edge_setup(DerivedMesh *dm) GLStates |= GPU_BUFFER_VERTEX_STATE; - if (useVBOs) + if (dm->drawObject->edges->use_vbo) glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, dm->drawObject->edges->id); GLStates |= GPU_BUFFER_ELEMENT_STATE; @@ -1244,7 +855,7 @@ void GPU_uvedge_setup(DerivedMesh *dm) return; glEnableClientState(GL_VERTEX_ARRAY); - if (useVBOs) { + if (dm->drawObject->uvedges->use_vbo) { glBindBufferARB(GL_ARRAY_BUFFER_ARB, dm->drawObject->uvedges->id); glVertexPointer(2, GL_FLOAT, 0, 0); } @@ -1255,6 +866,18 @@ void GPU_uvedge_setup(DerivedMesh *dm) GLStates |= GPU_BUFFER_VERTEX_STATE; } +void GPU_triangle_setup(struct DerivedMesh *dm) +{ + if (!gpu_buffer_setup_common(dm, GPU_BUFFER_TRIANGLES)) + return; + + if (dm->drawObject->triangles->use_vbo) { + glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, dm->drawObject->triangles->id); + } + + GLStates |= GPU_BUFFER_ELEMENT_STATE; +} + static int GPU_typesize(int type) { switch (type) { @@ -1285,11 +908,12 @@ int GPU_attrib_element_size(GPUAttrib data[], int numdata) return elementsize; } -void GPU_interleaved_attrib_setup(GPUBuffer *buffer, GPUAttrib data[], int numdata) +void GPU_interleaved_attrib_setup(GPUBuffer *buffer, GPUAttrib data[], int numdata, int element_size) { int i; int elementsize; intptr_t offset = 0; + char *basep; for (i = 0; i < MAX_GPU_ATTRIB_DATA; i++) { if (attribData[i].index != -1) { @@ -1298,34 +922,47 @@ void GPU_interleaved_attrib_setup(GPUBuffer *buffer, GPUAttrib data[], int numda else break; } - elementsize = GPU_attrib_element_size(data, numdata); + if (element_size == 0) + elementsize = GPU_attrib_element_size(data, numdata); + else + elementsize = element_size; - if (useVBOs) { + if (buffer->use_vbo) { glBindBufferARB(GL_ARRAY_BUFFER_ARB, buffer->id); - for (i = 0; i < numdata; i++) { - glEnableVertexAttribArrayARB(data[i].index); - glVertexAttribPointerARB(data[i].index, data[i].size, data[i].type, - GL_FALSE, elementsize, (void *)offset); - offset += data[i].size * GPU_typesize(data[i].type); - - attribData[i].index = data[i].index; - attribData[i].size = data[i].size; - attribData[i].type = data[i].type; - } - attribData[numdata].index = -1; + basep = NULL; } else { - for (i = 0; i < numdata; i++) { - glEnableVertexAttribArrayARB(data[i].index); - glVertexAttribPointerARB(data[i].index, data[i].size, data[i].type, - GL_FALSE, elementsize, (char *)buffer->pointer + offset); - offset += data[i].size * GPU_typesize(data[i].type); - } + basep = buffer->pointer; } + + for (i = 0; i < numdata; i++) { + glEnableVertexAttribArrayARB(data[i].index); + glVertexAttribPointerARB(data[i].index, data[i].size, data[i].type, + GL_FALSE, elementsize, (void *)(basep + offset)); + offset += data[i].size * GPU_typesize(data[i].type); + + attribData[i].index = data[i].index; + attribData[i].size = data[i].size; + attribData[i].type = data[i].type; + } + + attribData[numdata].index = -1; } +void GPU_interleaved_attrib_unbind(void) +{ + int i; + for (i = 0; i < MAX_GPU_ATTRIB_DATA; i++) { + if (attribData[i].index != -1) { + glDisableVertexAttribArrayARB(attribData[i].index); + } + else + break; + } + attribData[0].index = -1; +} -void GPU_buffer_unbind(void) +void GPU_buffers_unbind(void) { int i; @@ -1343,7 +980,8 @@ void GPU_buffer_unbind(void) if (GLStates & GPU_BUFFER_COLOR_STATE) glDisableClientState(GL_COLOR_ARRAY); if (GLStates & GPU_BUFFER_ELEMENT_STATE) { - if (useVBOs) { + /* not guaranteed we used VBOs but in that case it's just a no-op */ + if (GLEW_ARB_vertex_buffer_object) { glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0); } } @@ -1358,8 +996,10 @@ void GPU_buffer_unbind(void) else break; } + attribData[0].index = -1; - if (useVBOs) + /* not guaranteed we used VBOs but in that case it's just a no-op */ + if (GLEW_ARB_vertex_buffer_object) glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0); } @@ -1377,29 +1017,23 @@ void GPU_color_switch(int mode) } } -/* return 1 if drawing should be done using old immediate-mode - * code, 0 otherwise */ -bool GPU_buffer_legacy(DerivedMesh *dm) +static int gpu_binding_type_gl[] = { - int test = (U.gameflags & USER_DISABLE_VBO); - if (test) - return 1; - - if (dm->drawObject == NULL) - dm->drawObject = GPU_drawobject_new(dm); - return dm->drawObject->legacy; -} + GL_ARRAY_BUFFER_ARB, + GL_ELEMENT_ARRAY_BUFFER_ARB +}; -void *GPU_buffer_lock(GPUBuffer *buffer) +void *GPU_buffer_lock(GPUBuffer *buffer, GPUBindingType binding) { float *varray; if (!buffer) return 0; - if (useVBOs) { - glBindBufferARB(GL_ARRAY_BUFFER_ARB, buffer->id); - varray = glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB); + if (buffer->use_vbo) { + int bindtypegl = gpu_binding_type_gl[binding]; + glBindBufferARB(bindtypegl, buffer->id); + varray = glMapBufferARB(bindtypegl, GL_WRITE_ONLY_ARB); return varray; } else { @@ -1407,18 +1041,19 @@ void *GPU_buffer_lock(GPUBuffer *buffer) } } -void *GPU_buffer_lock_stream(GPUBuffer *buffer) +void *GPU_buffer_lock_stream(GPUBuffer *buffer, GPUBindingType binding) { float *varray; if (!buffer) return 0; - if (useVBOs) { - glBindBufferARB(GL_ARRAY_BUFFER_ARB, buffer->id); + if (buffer->use_vbo) { + int bindtypegl = gpu_binding_type_gl[binding]; + glBindBufferARB(bindtypegl, buffer->id); /* discard previous data, avoid stalling gpu */ - glBufferDataARB(GL_ARRAY_BUFFER_ARB, buffer->size, 0, GL_STREAM_DRAW_ARB); - varray = glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB); + glBufferDataARB(bindtypegl, buffer->size, 0, GL_STREAM_DRAW_ARB); + varray = glMapBufferARB(bindtypegl, GL_WRITE_ONLY_ARB); return varray; } else { @@ -1426,15 +1061,30 @@ void *GPU_buffer_lock_stream(GPUBuffer *buffer) } } -void GPU_buffer_unlock(GPUBuffer *buffer) +void GPU_buffer_unlock(GPUBuffer *buffer, GPUBindingType binding) { - if (useVBOs) { - if (buffer) { - /* note: this operation can fail, could return - * an error code from this function? */ - glUnmapBufferARB(GL_ARRAY_BUFFER_ARB); - } - glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0); + if (buffer->use_vbo) { + int bindtypegl = gpu_binding_type_gl[binding]; + /* note: this operation can fail, could return + * an error code from this function? */ + glUnmapBufferARB(bindtypegl); + glBindBufferARB(bindtypegl, 0); + } +} + +void GPU_buffer_bind(GPUBuffer *buffer, GPUBindingType binding) +{ + if (buffer->use_vbo) { + int bindtypegl = gpu_binding_type_gl[binding]; + glBindBufferARB(bindtypegl, buffer->id); + } +} + +void GPU_buffer_unbind(GPUBuffer *buffer, GPUBindingType binding) +{ + if (buffer->use_vbo) { + int bindtypegl = gpu_binding_type_gl[binding]; + glBindBufferARB(bindtypegl, 0); } } @@ -1442,7 +1092,7 @@ void GPU_buffer_unlock(GPUBuffer *buffer) void GPU_buffer_draw_elements(GPUBuffer *elements, unsigned int mode, int start, int count) { glDrawElements(mode, count, GL_UNSIGNED_INT, - (useVBOs ? + (elements->use_vbo ? (void *)(start * sizeof(unsigned int)) : ((int *)elements->pointer) + start)); } @@ -1451,14 +1101,6 @@ void GPU_buffer_draw_elements(GPUBuffer *elements, unsigned int mode, int start, /* 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 */ -/* Return false if VBO is either unavailable or disabled by the user, - * true otherwise */ -static int gpu_vbo_enabled(void) -{ - return (GLEW_ARB_vertex_buffer_object && - !(U.gameflags & USER_DISABLE_VBO)); -} - /* Convenience struct for building the VBO. */ typedef struct { float co[3]; @@ -1474,14 +1116,20 @@ typedef struct { struct GPU_PBVH_Buffers { /* opengl buffer handles */ - GLuint vert_buf, index_buf; + GPUBuffer *vert_buf, *index_buf, *index_buf_fast; GLenum index_type; + int *baseelemarray; + void **baseindex; + /* mesh pointers in case buffer allocation fails */ - MFace *mface; - MVert *mvert; + const MPoly *mpoly; + const MLoop *mloop; + const MLoopTri *looptri; + const MVert *mvert; + const int *face_indices; - int totface; + int face_indices_len; const float *vmask; /* grid pointers */ @@ -1505,6 +1153,7 @@ struct GPU_PBVH_Buffers { bool use_matcaps; float diffuse_color[4]; }; + typedef enum { VBO_ENABLED, VBO_DISABLED @@ -1541,22 +1190,6 @@ static void gpu_color_from_mask_copy(float mask, const float diffuse_color[4], u out[2] = diffuse_color[2] * mask_color; } -static void gpu_color_from_mask_set(float mask, float diffuse_color[4]) -{ - float color = gpu_color_from_mask(mask); - glColor3f(diffuse_color[0] * color, diffuse_color[1] * color, diffuse_color[2] * color); -} - -static float gpu_color_from_mask_quad(const CCGKey *key, - CCGElem *a, CCGElem *b, - CCGElem *c, CCGElem *d) -{ - return gpu_color_from_mask((*CCG_elem_mask(key, a) + - *CCG_elem_mask(key, b) + - *CCG_elem_mask(key, c) + - *CCG_elem_mask(key, d)) * 0.25f); -} - static void gpu_color_from_mask_quad_copy(const CCGKey *key, CCGElem *a, CCGElem *b, CCGElem *c, CCGElem *d, @@ -1574,47 +1207,38 @@ static void gpu_color_from_mask_quad_copy(const CCGKey *key, out[2] = diffuse_color[2] * mask_color; } -static void gpu_color_from_mask_quad_set(const CCGKey *key, - CCGElem *a, CCGElem *b, - CCGElem *c, CCGElem *d, - const float diffuse_color[4]) -{ - float color = gpu_color_from_mask_quad(key, a, b, c, d); - glColor3f(diffuse_color[0] * color, diffuse_color[1] * color, diffuse_color[2] * color); -} - -void GPU_update_mesh_pbvh_buffers(GPU_PBVH_Buffers *buffers, MVert *mvert, - int *vert_indices, int totvert, const float *vmask, - int (*face_vert_indices)[4], bool show_diffuse_color) +void GPU_update_mesh_pbvh_buffers( + GPU_PBVH_Buffers *buffers, const MVert *mvert, + const int *vert_indices, int totvert, const float *vmask, + const int (*face_vert_indices)[4], bool show_diffuse_color) { VertexBufferFormat *vert_data; - int i, j, k; + int i, j; buffers->vmask = vmask; buffers->show_diffuse_color = show_diffuse_color; buffers->use_matcaps = GPU_material_use_matcaps_get(); - if (buffers->vert_buf) { + { int totelem = (buffers->smooth ? totvert : (buffers->tot_tri * 3)); float diffuse_color[4] = {0.8f, 0.8f, 0.8f, 0.8f}; if (buffers->use_matcaps) diffuse_color[0] = diffuse_color[1] = diffuse_color[2] = 1.0; else if (show_diffuse_color) { - MFace *f = buffers->mface + buffers->face_indices[0]; + const MLoopTri *lt = &buffers->looptri[buffers->face_indices[0]]; + const MPoly *mp = &buffers->mpoly[lt->poly]; - GPU_material_diffuse_get(f->mat_nr + 1, diffuse_color); + GPU_material_diffuse_get(mp->mat_nr + 1, diffuse_color); } copy_v4_v4(buffers->diffuse_color, diffuse_color); /* Build VBO */ - glBindBufferARB(GL_ARRAY_BUFFER_ARB, buffers->vert_buf); - glBufferDataARB(GL_ARRAY_BUFFER_ARB, - sizeof(VertexBufferFormat) * totelem, - NULL, GL_STATIC_DRAW_ARB); - - vert_data = glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB); + if (buffers->vert_buf) + GPU_buffer_free(buffers->vert_buf); + buffers->vert_buf = GPU_buffer_alloc(sizeof(VertexBufferFormat) * totelem, false); + vert_data = GPU_buffer_lock(buffers->vert_buf, GPU_BINDING_ARRAY); if (vert_data) { /* Vertex data is shared if smooth-shaded, but separate @@ -1622,7 +1246,7 @@ void GPU_update_mesh_pbvh_buffers(GPU_PBVH_Buffers *buffers, MVert *mvert, * shouldn't be shared. */ if (buffers->smooth) { for (i = 0; i < totvert; ++i) { - MVert *v = mvert + vert_indices[i]; + const MVert *v = &mvert[vert_indices[i]]; VertexBufferFormat *out = vert_data + i; copy_v3_v3(out->co, v->co); @@ -1638,118 +1262,114 @@ void GPU_update_mesh_pbvh_buffers(GPU_PBVH_Buffers *buffers, MVert *mvert, rgb_float_to_uchar(out->color, diffuse_color); \ } (void)0 - for (i = 0; i < buffers->totface; i++) { - MFace *f = buffers->mface + buffers->face_indices[i]; + for (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, + buffers->mloop[lt->tri[1]].v, + buffers->mloop[lt->tri[2]].v, + }; - UPDATE_VERTEX(i, f->v1, 0, diffuse_color); - UPDATE_VERTEX(i, f->v2, 1, diffuse_color); - UPDATE_VERTEX(i, f->v3, 2, diffuse_color); - if (f->v4) - UPDATE_VERTEX(i, f->v4, 3, diffuse_color); + UPDATE_VERTEX(i, vtri[0], 0, diffuse_color); + UPDATE_VERTEX(i, vtri[1], 1, diffuse_color); + UPDATE_VERTEX(i, vtri[2], 2, diffuse_color); } #undef UPDATE_VERTEX } else { - for (i = 0; i < buffers->totface; ++i) { - const MFace *f = &buffers->mface[buffers->face_indices[i]]; - const unsigned int *fv = &f->v1; - const int vi[2][3] = {{0, 1, 2}, {3, 0, 2}}; - float fno[3]; - short no[3]; + /* calculate normal for each polygon only once */ + unsigned int mpoly_prev = UINT_MAX; + short no[3]; + + for (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, + buffers->mloop[lt->tri[1]].v, + buffers->mloop[lt->tri[2]].v, + }; float fmask; - if (paint_is_face_hidden(f, mvert)) + if (paint_is_face_hidden(lt, mvert, buffers->mloop)) continue; /* Face normal and mask */ - if (f->v4) { - normal_quad_v3(fno, - mvert[fv[0]].co, - mvert[fv[1]].co, - mvert[fv[2]].co, - mvert[fv[3]].co); - if (vmask) { - fmask = (vmask[fv[0]] + - vmask[fv[1]] + - vmask[fv[2]] + - vmask[fv[3]]) * 0.25f; - } + if (lt->poly != mpoly_prev) { + const MPoly *mp = &buffers->mpoly[lt->poly]; + float fno[3]; + BKE_mesh_calc_poly_normal(mp, &buffers->mloop[mp->loopstart], mvert, fno); + normal_float_to_short_v3(no, fno); + mpoly_prev = lt->poly; } - else { - normal_tri_v3(fno, - mvert[fv[0]].co, - mvert[fv[1]].co, - mvert[fv[2]].co); - if (vmask) { - fmask = (vmask[fv[0]] + - vmask[fv[1]] + - vmask[fv[2]]) / 3.0f; - } + + if (vmask) { + fmask = (vmask[vtri[0]] + + vmask[vtri[1]] + + vmask[vtri[2]]) / 3.0f; } - normal_float_to_short_v3(no, fno); - for (j = 0; j < (f->v4 ? 2 : 1); j++) { - for (k = 0; k < 3; k++) { - const MVert *v = &mvert[fv[vi[j][k]]]; - VertexBufferFormat *out = vert_data; + for (j = 0; j < 3; j++) { + const MVert *v = &mvert[vtri[j]]; + VertexBufferFormat *out = vert_data; - copy_v3_v3(out->co, v->co); - memcpy(out->no, no, sizeof(short) * 3); + copy_v3_v3(out->co, v->co); + copy_v3_v3_short(out->no, no); - if (vmask) - gpu_color_from_mask_copy(fmask, diffuse_color, out->color); - else - rgb_float_to_uchar(out->color, diffuse_color); + if (vmask) + gpu_color_from_mask_copy(fmask, diffuse_color, out->color); + else + rgb_float_to_uchar(out->color, diffuse_color); - vert_data++; - } + vert_data++; } } } - glUnmapBufferARB(GL_ARRAY_BUFFER_ARB); + GPU_buffer_unlock(buffers->vert_buf, GPU_BINDING_ARRAY); } else { - glDeleteBuffersARB(1, &buffers->vert_buf); - buffers->vert_buf = 0; + GPU_buffer_free(buffers->vert_buf); + buffers->vert_buf = NULL; } - - glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0); } buffers->mvert = mvert; } -GPU_PBVH_Buffers *GPU_build_mesh_pbvh_buffers(int (*face_vert_indices)[4], - MFace *mface, MVert *mvert, - int *face_indices, - int totface) +GPU_PBVH_Buffers *GPU_build_mesh_pbvh_buffers( + const int (*face_vert_indices)[4], + const MPoly *mpoly, const MLoop *mloop, const MLoopTri *looptri, + const MVert *mvert, + const int *face_indices, + const int face_indices_len) { GPU_PBVH_Buffers *buffers; unsigned short *tri_data; - int i, j, k, tottri; + int i, j, tottri; buffers = MEM_callocN(sizeof(GPU_PBVH_Buffers), "GPU_Buffers"); buffers->index_type = GL_UNSIGNED_SHORT; - buffers->smooth = mface[face_indices[0]].flag & ME_SMOOTH; + buffers->smooth = mpoly[looptri[face_indices[0]].poly].flag & ME_SMOOTH; buffers->show_diffuse_color = false; buffers->use_matcaps = false; /* Count the number of visible triangles */ - for (i = 0, tottri = 0; i < totface; ++i) { - const MFace *f = &mface[face_indices[i]]; - if (!paint_is_face_hidden(f, mvert)) - tottri += f->v4 ? 2 : 1; + for (i = 0, tottri = 0; i < face_indices_len; ++i) { + const MLoopTri *lt = &looptri[face_indices[i]]; + if (!paint_is_face_hidden(lt, mvert, mloop)) + tottri++; } if (tottri == 0) { buffers->tot_tri = 0; - buffers->mface = mface; + buffers->mpoly = mpoly; + buffers->mloop = mloop; + buffers->looptri = looptri; buffers->face_indices = face_indices; - buffers->totface = 0; + buffers->face_indices_len = 0; return buffers; } @@ -1757,65 +1377,48 @@ GPU_PBVH_Buffers *GPU_build_mesh_pbvh_buffers(int (*face_vert_indices)[4], /* An element index buffer is used for smooth shading, but flat * shading requires separate vertex normals so an index buffer is * can't be used there. */ - if (gpu_vbo_enabled() && buffers->smooth) - glGenBuffersARB(1, &buffers->index_buf); + if (buffers->smooth) + buffers->index_buf = GPU_buffer_alloc(sizeof(unsigned short) * tottri * 3, false); if (buffers->index_buf) { - /* Generate index buffer object */ - glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, buffers->index_buf); - glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, - sizeof(unsigned short) * tottri * 3, NULL, GL_STATIC_DRAW_ARB); - /* Fill the triangle buffer */ - tri_data = glMapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB); + tri_data = GPU_buffer_lock(buffers->index_buf, GPU_BINDING_INDEX); if (tri_data) { - for (i = 0; i < totface; ++i) { - const MFace *f = mface + face_indices[i]; - int v[3]; + for (i = 0; i < face_indices_len; ++i) { + const MLoopTri *lt = &looptri[face_indices[i]]; /* Skip hidden faces */ - if (paint_is_face_hidden(f, mvert)) + if (paint_is_face_hidden(lt, mvert, mloop)) continue; - v[0] = 0; - v[1] = 1; - v[2] = 2; - - for (j = 0; j < (f->v4 ? 2 : 1); ++j) { - for (k = 0; k < 3; ++k) { - *tri_data = face_vert_indices[i][v[k]]; - tri_data++; - } - v[0] = 3; - v[1] = 0; - v[2] = 2; + for (j = 0; j < 3; ++j) { + *tri_data = face_vert_indices[i][j]; + tri_data++; } } - glUnmapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB); + GPU_buffer_unlock(buffers->index_buf, GPU_BINDING_INDEX); } else { - glDeleteBuffersARB(1, &buffers->index_buf); - buffers->index_buf = 0; + GPU_buffer_free(buffers->index_buf); + buffers->index_buf = NULL; } - - glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0); } - if (gpu_vbo_enabled() && (buffers->index_buf || !buffers->smooth)) - glGenBuffersARB(1, &buffers->vert_buf); - buffers->tot_tri = tottri; - buffers->mface = mface; + buffers->mpoly = mpoly; + buffers->mloop = mloop; + buffers->looptri = looptri; + buffers->face_indices = face_indices; - buffers->totface = totface; + buffers->face_indices_len = face_indices_len; return buffers; } void GPU_update_grid_pbvh_buffers(GPU_PBVH_Buffers *buffers, CCGElem **grids, - const DMFlagMat *grid_flag_mats, int *grid_indices, - int totgrid, const CCGKey *key, bool show_diffuse_color) + const DMFlagMat *grid_flag_mats, int *grid_indices, + int totgrid, const CCGKey *key, bool show_diffuse_color) { VertexBufferFormat *vert_data; int i, j, k, x, y; @@ -1825,7 +1428,6 @@ void GPU_update_grid_pbvh_buffers(GPU_PBVH_Buffers *buffers, CCGElem **grids, /* Build VBO */ if (buffers->vert_buf) { - int totvert = key->grid_area * totgrid; int smooth = grid_flag_mats[grid_indices[0]].flag & ME_SMOOTH; const int has_mask = key->has_mask; float diffuse_color[4] = {0.8f, 0.8f, 0.8f, 1.0f}; @@ -1840,11 +1442,7 @@ void GPU_update_grid_pbvh_buffers(GPU_PBVH_Buffers *buffers, CCGElem **grids, copy_v4_v4(buffers->diffuse_color, diffuse_color); - glBindBufferARB(GL_ARRAY_BUFFER_ARB, buffers->vert_buf); - glBufferDataARB(GL_ARRAY_BUFFER_ARB, - sizeof(VertexBufferFormat) * totvert, - NULL, GL_STATIC_DRAW_ARB); - vert_data = glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB); + vert_data = GPU_buffer_lock_stream(buffers->vert_buf, GPU_BINDING_ARRAY); if (vert_data) { for (i = 0; i < totgrid; ++i) { VertexBufferFormat *vd = vert_data; @@ -1905,13 +1503,13 @@ void GPU_update_grid_pbvh_buffers(GPU_PBVH_Buffers *buffers, CCGElem **grids, vert_data += key->grid_area; } - glUnmapBufferARB(GL_ARRAY_BUFFER_ARB); + + GPU_buffer_unlock(buffers->vert_buf, GPU_BINDING_ARRAY); } else { - glDeleteBuffersARB(1, &buffers->vert_buf); - buffers->vert_buf = 0; + GPU_buffer_free(buffers->vert_buf); + buffers->vert_buf = NULL; } - glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0); } buffers->grids = grids; @@ -1928,107 +1526,112 @@ void GPU_update_grid_pbvh_buffers(GPU_PBVH_Buffers *buffers, CCGElem **grids, /* Build the element array buffer of grid indices using either * unsigned shorts or unsigned ints. */ #define FILL_QUAD_BUFFER(type_, tot_quad_, buffer_) \ - { \ - type_ *tri_data; \ - int offset = 0; \ - int i, j, k; \ - \ - glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, \ - sizeof(type_) * (tot_quad_) * 6, NULL, \ - GL_STATIC_DRAW_ARB); \ - \ - /* Fill the buffer */ \ - tri_data = glMapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, \ - GL_WRITE_ONLY_ARB); \ - if (tri_data) { \ - 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; \ - } \ - glUnmapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB); \ - } \ - else { \ - glDeleteBuffersARB(1, &(buffer_)); \ - (buffer_) = 0; \ - } \ - } (void)0 + { \ + type_ *tri_data; \ + int offset = 0; \ + int i, j, k; \ + buffer_ = GPU_buffer_alloc(sizeof(type_) * (tot_quad_) * 6, \ + false); \ + \ + /* 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 (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; \ + } \ + GPU_buffer_unlock(buffer_, GPU_BINDING_INDEX); \ + } \ + else { \ + GPU_buffer_free(buffer_); \ + (buffer_) = NULL; \ + } \ + } (void)0 /* end FILL_QUAD_BUFFER */ -static GLuint gpu_get_grid_buffer(int gridsize, GLenum *index_type, unsigned *totquad) +static GPUBuffer *gpu_get_grid_buffer(int gridsize, GLenum *index_type, unsigned *totquad) { - static int prev_gridsize = -1; - static GLenum prev_index_type = 0; - static GLuint buffer = 0; - static unsigned prev_totquad; - /* used in the FILL_QUAD_BUFFER macro */ BLI_bitmap * const *grid_hidden = NULL; const int *grid_indices = NULL; int totgrid = 1; - /* VBO is disabled; delete the previous buffer (if it exists) and - * return an invalid handle */ - if (!gpu_vbo_enabled()) { - if (buffer) - glDeleteBuffersARB(1, &buffer); - return 0; - } - /* VBO is already built */ - if (buffer && prev_gridsize == gridsize) { - *index_type = prev_index_type; - *totquad = prev_totquad; - return buffer; + if (mres_glob_buffer && mres_prev_gridsize == gridsize) { + *index_type = mres_prev_index_type; + *totquad = mres_prev_totquad; + return mres_glob_buffer; + } + /* we can't reuse old, delete the existing buffer */ + else if (mres_glob_buffer) { + GPU_buffer_free(mres_glob_buffer); } /* Build new VBO */ - glGenBuffersARB(1, &buffer); - if (buffer) { - *totquad = (gridsize - 1) * (gridsize - 1); + *totquad = (gridsize - 1) * (gridsize - 1); - glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, buffer); - - if (gridsize * gridsize < USHRT_MAX) { - *index_type = GL_UNSIGNED_SHORT; - FILL_QUAD_BUFFER(unsigned short, *totquad, buffer); - } - else { - *index_type = GL_UNSIGNED_INT; - FILL_QUAD_BUFFER(unsigned int, *totquad, buffer); - } - - glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0); + if (gridsize * gridsize < USHRT_MAX) { + *index_type = GL_UNSIGNED_SHORT; + FILL_QUAD_BUFFER(unsigned short, *totquad, mres_glob_buffer); } - - prev_gridsize = gridsize; - prev_index_type = *index_type; - prev_totquad = *totquad; - return buffer; -} + else { + *index_type = GL_UNSIGNED_INT; + FILL_QUAD_BUFFER(unsigned int, *totquad, mres_glob_buffer); + } + + mres_prev_gridsize = gridsize; + mres_prev_index_type = *index_type; + mres_prev_totquad = *totquad; + return mres_glob_buffer; +} + +#define FILL_FAST_BUFFER(type_) \ +{ \ + type_ *buffer; \ + buffers->index_buf_fast = GPU_buffer_alloc(sizeof(type_) * 6 * totgrid, false); \ + 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; \ + } \ +} (void)0 GPU_PBVH_Buffers *GPU_build_grid_pbvh_buffers(int *grid_indices, int totgrid, - BLI_bitmap **grid_hidden, int gridsize) + BLI_bitmap **grid_hidden, int gridsize, const CCGKey *key) { GPU_PBVH_Buffers *buffers; int totquad; @@ -2048,28 +1651,28 @@ GPU_PBVH_Buffers *GPU_build_grid_pbvh_buffers(int *grid_indices, int totgrid, if (totquad == 0) 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); + } + if (totquad == fully_visible_totquad) { buffers->index_buf = gpu_get_grid_buffer(gridsize, &buffers->index_type, &buffers->tot_quad); buffers->has_hidden = 0; } - else if (GLEW_ARB_vertex_buffer_object && !(U.gameflags & USER_DISABLE_VBO)) { - /* Build new VBO */ - glGenBuffersARB(1, &buffers->index_buf); - if (buffers->index_buf) { - buffers->tot_quad = totquad; - - glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, buffers->index_buf); - - 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); - } + else { + buffers->tot_quad = totquad; - glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0); + 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); } buffers->has_hidden = 1; @@ -2077,7 +1680,19 @@ GPU_PBVH_Buffers *GPU_build_grid_pbvh_buffers(int *grid_indices, int totgrid, /* Build coord/normal VBO */ if (buffers->index_buf) - glGenBuffersARB(1, &buffers->vert_buf); + buffers->vert_buf = GPU_buffer_alloc(sizeof(VertexBufferFormat) * totgrid * key->grid_area, false); + + if (GLEW_ARB_draw_elements_base_vertex) { + int i; + buffers->baseelemarray = MEM_mallocN(sizeof(int) * totgrid * 2, "GPU_PBVH_Buffers.baseelemarray"); + buffers->baseindex = MEM_mallocN(sizeof(void *) * totgrid, "GPU_PBVH_Buffers.baseindex"); + for (i = 0; i < totgrid; i++) { + buffers->baseelemarray[i] = buffers->tot_quad * 6; + buffers->baseelemarray[i + totgrid] = i * key->grid_area; + buffers->baseindex[i] = buffers->index_buf && !buffers->index_buf->use_vbo ? + buffers->index_buf->pointer : NULL; + } + } return buffers; } @@ -2110,7 +1725,6 @@ static void gpu_bmesh_vert_to_buffer_copy(BMVert *v, BM_ELEM_CD_GET_FLOAT(v, cd_vert_mask_offset), diffuse_color, vd->color); - /* Assign index for use in the triangle index buffer */ /* note: caller must set: bm->elem_index_dirty |= BM_VERT; */ @@ -2160,11 +1774,11 @@ static int gpu_bmesh_face_visible_count(GSet *bm_faces) /* Creates a vertex buffer (coordinate, normal, color) and, if smooth * shading, an element index buffer. */ void GPU_update_bmesh_pbvh_buffers(GPU_PBVH_Buffers *buffers, - BMesh *bm, - GSet *bm_faces, - GSet *bm_unique_verts, - GSet *bm_other_verts, - bool show_diffuse_color) + BMesh *bm, + GSet *bm_faces, + GSet *bm_unique_verts, + GSet *bm_other_verts, + bool show_diffuse_color) { VertexBufferFormat *vert_data; void *tri_data; @@ -2177,9 +1791,6 @@ void GPU_update_bmesh_pbvh_buffers(GPU_PBVH_Buffers *buffers, buffers->show_diffuse_color = show_diffuse_color; buffers->use_matcaps = GPU_material_use_matcaps_get(); - if (!buffers->vert_buf || (buffers->smooth && !buffers->index_buf)) - return; - /* Count visible triangles */ tottri = gpu_bmesh_face_visible_count(bm_faces); @@ -2209,13 +1820,12 @@ void GPU_update_bmesh_pbvh_buffers(GPU_PBVH_Buffers *buffers, copy_v4_v4(buffers->diffuse_color, diffuse_color); /* Initialize vertex buffer */ - glBindBufferARB(GL_ARRAY_BUFFER_ARB, buffers->vert_buf); - glBufferDataARB(GL_ARRAY_BUFFER_ARB, - sizeof(VertexBufferFormat) * totvert, - NULL, GL_STATIC_DRAW_ARB); + if (buffers->vert_buf) + GPU_buffer_free(buffers->vert_buf); + buffers->vert_buf = GPU_buffer_alloc(sizeof(VertexBufferFormat) * totvert, false); /* Fill vertex buffer */ - vert_data = glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB); + vert_data = GPU_buffer_lock(buffers->vert_buf, GPU_BINDING_ARRAY); if (vert_data) { int v_index = 0; @@ -2253,7 +1863,9 @@ void GPU_update_bmesh_pbvh_buffers(GPU_PBVH_Buffers *buffers, float fmask = 0; int i; - // BM_iter_as_array(bm, BM_VERTS_OF_FACE, f, (void**)v, 3); +#if 0 + BM_iter_as_array(bm, BM_VERTS_OF_FACE, f, (void**)v, 3); +#endif BM_face_as_array_vert_tri(f, v); /* Average mask value */ @@ -2273,15 +1885,15 @@ void GPU_update_bmesh_pbvh_buffers(GPU_PBVH_Buffers *buffers, buffers->tot_tri = tottri; } - glUnmapBufferARB(GL_ARRAY_BUFFER_ARB); + GPU_buffer_unlock(buffers->vert_buf, GPU_BINDING_ARRAY); /* gpu_bmesh_vert_to_buffer_copy sets dirty index values */ bm->elem_index_dirty |= BM_VERT; } else { /* Memory map failed */ - glDeleteBuffersARB(1, &buffers->vert_buf); - buffers->vert_buf = 0; + GPU_buffer_free(buffers->vert_buf); + buffers->vert_buf = NULL; return; } @@ -2289,15 +1901,14 @@ void GPU_update_bmesh_pbvh_buffers(GPU_PBVH_Buffers *buffers, const int use_short = (maxvert < USHRT_MAX); /* Initialize triangle index buffer */ - glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, buffers->index_buf); - glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, - (use_short ? - sizeof(unsigned short) : - sizeof(unsigned int)) * 3 * tottri, - NULL, GL_STATIC_DRAW_ARB); + if (buffers->index_buf) + GPU_buffer_free(buffers->index_buf); + buffers->index_buf = GPU_buffer_alloc((use_short ? + sizeof(unsigned short) : + sizeof(unsigned int)) * 3 * tottri, false); /* Fill triangle index buffer */ - tri_data = glMapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB); + tri_data = GPU_buffer_lock(buffers->index_buf, GPU_BINDING_INDEX); if (tri_data) { GSetIterator gs_iter; @@ -2327,7 +1938,7 @@ void GPU_update_bmesh_pbvh_buffers(GPU_PBVH_Buffers *buffers, } } - glUnmapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB); + GPU_buffer_unlock(buffers->index_buf, GPU_BINDING_INDEX); buffers->tot_tri = tottri; buffers->index_type = (use_short ? @@ -2336,10 +1947,13 @@ void GPU_update_bmesh_pbvh_buffers(GPU_PBVH_Buffers *buffers, } else { /* Memory map failed */ - glDeleteBuffersARB(1, &buffers->index_buf); - buffers->index_buf = 0; + GPU_buffer_free(buffers->index_buf); + buffers->index_buf = NULL; } } + else if (buffers->index_buf) { + GPU_buffer_free(buffers->index_buf); + } } GPU_PBVH_Buffers *GPU_build_bmesh_pbvh_buffers(int smooth_shading) @@ -2347,9 +1961,6 @@ GPU_PBVH_Buffers *GPU_build_bmesh_pbvh_buffers(int smooth_shading) GPU_PBVH_Buffers *buffers; buffers = MEM_callocN(sizeof(GPU_PBVH_Buffers), "GPU_Buffers"); - if (smooth_shading) - glGenBuffersARB(1, &buffers->index_buf); - glGenBuffersARB(1, &buffers->vert_buf); buffers->use_bmesh = true; buffers->smooth = smooth_shading; buffers->show_diffuse_color = false; @@ -2358,217 +1969,17 @@ GPU_PBVH_Buffers *GPU_build_bmesh_pbvh_buffers(int smooth_shading) return buffers; } -static void gpu_draw_buffers_legacy_mesh(GPU_PBVH_Buffers *buffers) -{ - const MVert *mvert = buffers->mvert; - int i, j; - const int has_mask = (buffers->vmask != NULL); - const MFace *face = &buffers->mface[buffers->face_indices[0]]; - float diffuse_color[4] = {0.8f, 0.8f, 0.8f, 1.0f}; - - if (buffers->use_matcaps) - diffuse_color[0] = diffuse_color[1] = diffuse_color[2] = 1.0; - else if (buffers->show_diffuse_color) - GPU_material_diffuse_get(face->mat_nr + 1, diffuse_color); - - if (has_mask) { - gpu_colors_enable(VBO_DISABLED); - } - - for (i = 0; i < buffers->totface; ++i) { - MFace *f = buffers->mface + buffers->face_indices[i]; - int S = f->v4 ? 4 : 3; - unsigned int *fv = &f->v1; - - if (paint_is_face_hidden(f, buffers->mvert)) - continue; - - glBegin((f->v4) ? GL_QUADS : GL_TRIANGLES); - - if (buffers->smooth) { - for (j = 0; j < S; j++) { - if (has_mask) { - gpu_color_from_mask_set(buffers->vmask[fv[j]], diffuse_color); - } - glNormal3sv(mvert[fv[j]].no); - glVertex3fv(mvert[fv[j]].co); - } - } - else { - float fno[3]; - - /* calculate face normal */ - if (f->v4) { - normal_quad_v3(fno, mvert[fv[0]].co, mvert[fv[1]].co, - mvert[fv[2]].co, mvert[fv[3]].co); - } - else - normal_tri_v3(fno, mvert[fv[0]].co, mvert[fv[1]].co, mvert[fv[2]].co); - glNormal3fv(fno); - - if (has_mask) { - float fmask; - - /* calculate face mask color */ - fmask = (buffers->vmask[fv[0]] + - buffers->vmask[fv[1]] + - buffers->vmask[fv[2]]); - if (f->v4) - fmask = (fmask + buffers->vmask[fv[3]]) * 0.25f; - else - fmask /= 3.0f; - gpu_color_from_mask_set(fmask, diffuse_color); - } - - for (j = 0; j < S; j++) - glVertex3fv(mvert[fv[j]].co); - } - - glEnd(); - } - - if (has_mask) { - gpu_colors_disable(VBO_DISABLED); - } -} - -static void gpu_draw_buffers_legacy_grids(GPU_PBVH_Buffers *buffers) -{ - const CCGKey *key = &buffers->gridkey; - int i, j, x, y, gridsize = buffers->gridkey.grid_size; - const int has_mask = key->has_mask; - const DMFlagMat *flags = &buffers->grid_flag_mats[buffers->grid_indices[0]]; - float diffuse_color[4] = {0.8f, 0.8f, 0.8f, 1.0f}; - - if (buffers->use_matcaps) - diffuse_color[0] = diffuse_color[1] = diffuse_color[2] = 1.0; - else if (buffers->show_diffuse_color) - GPU_material_diffuse_get(flags->mat_nr + 1, diffuse_color); - - if (has_mask) { - gpu_colors_enable(VBO_DISABLED); - } - - for (i = 0; i < buffers->totgrid; ++i) { - int g = buffers->grid_indices[i]; - CCGElem *grid = buffers->grids[g]; - BLI_bitmap *gh = buffers->grid_hidden[g]; - - /* TODO: could use strips with hiding as well */ - - if (gh) { - glBegin(GL_QUADS); - - for (y = 0; y < gridsize - 1; y++) { - for (x = 0; x < gridsize - 1; x++) { - CCGElem *e[4] = { - CCG_grid_elem(key, grid, x + 1, y + 1), - CCG_grid_elem(key, grid, x + 1, y), - CCG_grid_elem(key, grid, x, y), - CCG_grid_elem(key, grid, x, y + 1) - }; - - /* skip face if any of its corners are hidden */ - if (paint_is_grid_face_hidden(gh, gridsize, x, y)) - continue; - - if (buffers->smooth) { - for (j = 0; j < 4; j++) { - if (has_mask) { - gpu_color_from_mask_set(*CCG_elem_mask(key, e[j]), diffuse_color); - } - glNormal3fv(CCG_elem_no(key, e[j])); - glVertex3fv(CCG_elem_co(key, e[j])); - } - } - else { - float fno[3]; - normal_quad_v3(fno, - CCG_elem_co(key, e[0]), - CCG_elem_co(key, e[1]), - CCG_elem_co(key, e[2]), - CCG_elem_co(key, e[3])); - glNormal3fv(fno); - - if (has_mask) { - gpu_color_from_mask_quad_set(key, e[0], e[1], e[2], e[3], diffuse_color); - } - - for (j = 0; j < 4; j++) - glVertex3fv(CCG_elem_co(key, e[j])); - } - } - } - - glEnd(); - } - else if (buffers->smooth) { - for (y = 0; y < gridsize - 1; y++) { - glBegin(GL_QUAD_STRIP); - for (x = 0; x < gridsize; x++) { - CCGElem *a = CCG_grid_elem(key, grid, x, y); - CCGElem *b = CCG_grid_elem(key, grid, x, y + 1); - - if (has_mask) { - gpu_color_from_mask_set(*CCG_elem_mask(key, a), diffuse_color); - } - glNormal3fv(CCG_elem_no(key, a)); - glVertex3fv(CCG_elem_co(key, a)); - if (has_mask) { - gpu_color_from_mask_set(*CCG_elem_mask(key, b), diffuse_color); - } - glNormal3fv(CCG_elem_no(key, b)); - glVertex3fv(CCG_elem_co(key, b)); - } - glEnd(); - } - } - else { - for (y = 0; y < gridsize - 1; y++) { - glBegin(GL_QUAD_STRIP); - for (x = 0; x < gridsize; x++) { - CCGElem *a = CCG_grid_elem(key, grid, x, y); - CCGElem *b = CCG_grid_elem(key, grid, x, y + 1); - - if (x > 0) { - CCGElem *c = CCG_grid_elem(key, grid, x - 1, y); - CCGElem *d = CCG_grid_elem(key, grid, x - 1, y + 1); - - float fno[3]; - normal_quad_v3(fno, - CCG_elem_co(key, d), - CCG_elem_co(key, b), - CCG_elem_co(key, a), - CCG_elem_co(key, c)); - glNormal3fv(fno); - - if (has_mask) { - gpu_color_from_mask_quad_set(key, a, b, c, d, diffuse_color); - } - } - - glVertex3fv(CCG_elem_co(key, a)); - glVertex3fv(CCG_elem_co(key, b)); - } - glEnd(); - } - } - } - - if (has_mask) { - gpu_colors_disable(VBO_DISABLED); - } -} - void GPU_draw_pbvh_buffers(GPU_PBVH_Buffers *buffers, DMSetMaterial setMaterial, - bool wireframe) + 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->totface) { - const MFace *f = &buffers->mface[buffers->face_indices[0]]; - if (!setMaterial(f->mat_nr + 1, NULL)) + 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) { @@ -2582,51 +1993,86 @@ void GPU_draw_pbvh_buffers(GPU_PBVH_Buffers *buffers, DMSetMaterial setMaterial, } } - glShadeModel((buffers->smooth || buffers->totface) ? GL_SMOOTH : GL_FLAT); + glShadeModel((buffers->smooth || buffers->face_indices_len) ? GL_SMOOTH : GL_FLAT); if (buffers->vert_buf) { + char *base = NULL; + char *index_base = NULL; glEnableClientState(GL_VERTEX_ARRAY); if (!wireframe) { glEnableClientState(GL_NORMAL_ARRAY); gpu_colors_enable(VBO_ENABLED); } - glBindBufferARB(GL_ARRAY_BUFFER_ARB, buffers->vert_buf); + GPU_buffer_bind(buffers->vert_buf, GPU_BINDING_ARRAY); - if (buffers->index_buf) - glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, buffers->index_buf); + if (!buffers->vert_buf->use_vbo) + base = (char *)buffers->vert_buf->pointer; + + if (do_fast) { + GPU_buffer_bind(buffers->index_buf_fast, GPU_BINDING_INDEX); + if (!buffers->index_buf_fast->use_vbo) + index_base = buffers->index_buf_fast->pointer; + } + else if (buffers->index_buf) { + GPU_buffer_bind(buffers->index_buf, GPU_BINDING_INDEX); + if (!buffers->index_buf->use_vbo) + index_base = buffers->index_buf->pointer; + } if (wireframe) glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); if (buffers->tot_quad) { - const char *offset = 0; - int i, last = buffers->has_hidden ? 1 : buffers->totgrid; - for (i = 0; i < last; i++) { + 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)); glNormalPointer(GL_SHORT, sizeof(VertexBufferFormat), offset + offsetof(VertexBufferFormat, no)); glColorPointer(3, GL_UNSIGNED_BYTE, sizeof(VertexBufferFormat), offset + offsetof(VertexBufferFormat, color)); - - glDrawElements(GL_TRIANGLES, buffers->tot_quad * 6, buffers->index_type, 0); - offset += buffers->gridkey.grid_area * sizeof(VertexBufferFormat); + 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)); + glNormalPointer(GL_SHORT, sizeof(VertexBufferFormat), + offset + offsetof(VertexBufferFormat, no)); + glColorPointer(3, GL_UNSIGNED_BYTE, sizeof(VertexBufferFormat), + offset + offsetof(VertexBufferFormat, color)); + + if (do_fast) + glDrawElements(GL_TRIANGLES, buffers->totgrid * 6, buffers->index_type, index_base); + else + glDrawElements(GL_TRIANGLES, buffers->tot_quad * 6, buffers->index_type, index_base); + + offset += buffers->gridkey.grid_area * sizeof(VertexBufferFormat); + } } } else if (buffers->tot_tri) { int totelem = buffers->tot_tri * 3; glVertexPointer(3, GL_FLOAT, sizeof(VertexBufferFormat), - (void *)offsetof(VertexBufferFormat, co)); + (void *)(base + offsetof(VertexBufferFormat, co))); glNormalPointer(GL_SHORT, sizeof(VertexBufferFormat), - (void *)offsetof(VertexBufferFormat, no)); + (void *)(base + offsetof(VertexBufferFormat, no))); glColorPointer(3, GL_UNSIGNED_BYTE, sizeof(VertexBufferFormat), - (void *)offsetof(VertexBufferFormat, color)); + (void *)(base + offsetof(VertexBufferFormat, color))); if (buffers->index_buf) - glDrawElements(GL_TRIANGLES, totelem, buffers->index_type, 0); + glDrawElements(GL_TRIANGLES, totelem, buffers->index_type, index_base); else glDrawArrays(GL_TRIANGLES, 0, totelem); } @@ -2634,9 +2080,9 @@ void GPU_draw_pbvh_buffers(GPU_PBVH_Buffers *buffers, DMSetMaterial setMaterial, if (wireframe) glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); - glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0); - if (buffers->index_buf) - glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0); + GPU_buffer_unbind(buffers->vert_buf, GPU_BINDING_ARRAY); + if (buffers->index_buf || do_fast) + GPU_buffer_unbind(do_fast ? buffers->index_buf_fast : buffers->index_buf, GPU_BINDING_INDEX); glDisableClientState(GL_VERTEX_ARRAY); if (!wireframe) { @@ -2644,13 +2090,6 @@ void GPU_draw_pbvh_buffers(GPU_PBVH_Buffers *buffers, DMSetMaterial setMaterial, gpu_colors_disable(VBO_ENABLED); } } - /* fallbacks if we are out of memory or VBO is disabled */ - else if (buffers->totface) { - gpu_draw_buffers_legacy_mesh(buffers); - } - else if (buffers->totgrid) { - gpu_draw_buffers_legacy_grids(buffers); - } } bool GPU_pbvh_buffers_diffuse_changed(GPU_PBVH_Buffers *buffers, GSet *bm_faces, bool show_diffuse_color) @@ -2667,13 +2106,14 @@ bool GPU_pbvh_buffers_diffuse_changed(GPU_PBVH_Buffers *buffers, GSet *bm_faces, if ((buffers->show_diffuse_color == false) || use_matcaps) return false; - if (buffers->mface) { - MFace *f = buffers->mface + buffers->face_indices[0]; + if (buffers->looptri) { + const MLoopTri *lt = &buffers->looptri[buffers->face_indices[0]]; + const MPoly *mp = &buffers->mpoly[lt->poly]; - GPU_material_diffuse_get(f->mat_nr + 1, diffuse_color); + GPU_material_diffuse_get(mp->mat_nr + 1, diffuse_color); } else if (buffers->use_bmesh) { - /* due to dynamc nature of dyntopo, only get first material */ + /* due to dynamic nature of dyntopo, only get first material */ if (BLI_gset_size(bm_faces) > 0) { GSetIterator gs_iter; BMFace *f; @@ -2695,50 +2135,19 @@ bool GPU_pbvh_buffers_diffuse_changed(GPU_PBVH_Buffers *buffers, GSet *bm_faces, return !equals_v3v3(diffuse_color, buffers->diffuse_color); } -/* release a GPU_PBVH_Buffers id; - * - * Thread-unsafe version for internal usage only. - */ -static void gpu_pbvh_buffer_free_intern(GLuint id) -{ - GPUBufferPool *pool; - - /* zero id is vertex buffers off */ - if (!id) - return; - - pool = gpu_get_global_buffer_pool(); - - /* free the buffers immediately if we are on main thread */ - if (BLI_thread_is_main()) { - glDeleteBuffersARB(1, &id); - - if (pool->totpbvhbufids > 0) { - glDeleteBuffersARB(pool->totpbvhbufids, pool->pbvhbufids); - pool->totpbvhbufids = 0; - } - return; - } - /* outside of main thread, can't safely delete the - * buffer, so increase pool size */ - if (pool->maxpbvhsize == pool->totpbvhbufids) { - pool->maxpbvhsize += MAX_FREE_GPU_BUFF_IDS; - pool->pbvhbufids = MEM_reallocN(pool->pbvhbufids, - sizeof(*pool->pbvhbufids) * pool->maxpbvhsize); - } - - /* insert the buffer into the beginning of the pool */ - pool->pbvhbufids[pool->totpbvhbufids++] = id; -} - - void GPU_free_pbvh_buffers(GPU_PBVH_Buffers *buffers) { if (buffers) { if (buffers->vert_buf) - gpu_pbvh_buffer_free_intern(buffers->vert_buf); + GPU_buffer_free(buffers->vert_buf); if (buffers->index_buf && (buffers->tot_tri || buffers->has_hidden)) - gpu_pbvh_buffer_free_intern(buffers->index_buf); + GPU_buffer_free(buffers->index_buf); + if (buffers->index_buf_fast) + GPU_buffer_free(buffers->index_buf_fast); + if (buffers->baseelemarray) + MEM_freeN(buffers->baseelemarray); + if (buffers->baseindex) + MEM_freeN(buffers->baseindex); MEM_freeN(buffers); } @@ -2748,34 +2157,34 @@ void GPU_free_pbvh_buffers(GPU_PBVH_Buffers *buffers) /* debug function, draws the pbvh BB */ void GPU_draw_pbvh_BB(float min[3], float max[3], bool leaf) { - 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]} - }, - - { - {min[0], min[1], min[2]}, - {min[0], max[1], min[2]}, - {min[0], max[1], max[2]}, - {min[0], min[1], max[2]} - }, - - { - {max[0], max[1], min[2]}, - {max[0], min[1], min[2]}, - {max[0], min[1], max[2]}, - {max[0], max[1], max[2]} - }, - - { - {max[0], max[1], min[2]}, - {min[0], max[1], min[2]}, - {min[0], max[1], max[2]}, - {max[0], max[1], max[2]} - }, + 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]} + }, + + { + {min[0], min[1], min[2]}, + {min[0], max[1], min[2]}, + {min[0], max[1], max[2]}, + {min[0], min[1], max[2]} + }, + + { + {max[0], max[1], min[2]}, + {max[0], min[1], min[2]}, + {max[0], min[1], max[2]}, + {max[0], max[1], max[2]} + }, + + { + {max[0], max[1], min[2]}, + {min[0], max[1], min[2]}, + {min[0], max[1], max[2]}, + {max[0], max[1], max[2]} + }, }; if (leaf) @@ -2797,7 +2206,6 @@ void GPU_init_draw_pbvh_BB(void) glDisable(GL_LIGHTING); glDisable(GL_COLOR_MATERIAL); glEnable(GL_BLEND); - glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0); } void GPU_end_draw_pbvh_BB(void) diff --git a/source/blender/gpu/intern/gpu_codegen.c b/source/blender/gpu/intern/gpu_codegen.c index 6b46db89a93..496302bb44e 100644 --- a/source/blender/gpu/intern/gpu_codegen.c +++ b/source/blender/gpu/intern/gpu_codegen.c @@ -31,8 +31,6 @@ * Convert material node-trees to GLSL. */ -#include "GL/glew.h" - #include "MEM_guardedalloc.h" #include "DNA_customdata_types.h" @@ -44,39 +42,59 @@ #include "BLI_dynstr.h" #include "BLI_ghash.h" +#include "GPU_glew.h" #include "GPU_material.h" #include "GPU_extensions.h" -#include "BLI_sys_types.h" // for intptr_t support +#include "BLI_sys_types.h" /* for intptr_t support */ #include "gpu_codegen.h" -#include "node_util.h" /* For muting node stuff... */ - #include <string.h> #include <stdarg.h> extern char datatoc_gpu_shader_material_glsl[]; extern char datatoc_gpu_shader_vertex_glsl[]; - +extern char datatoc_gpu_shader_vertex_world_glsl[]; +extern char datatoc_gpu_shader_geometry_glsl[]; static char *glsl_material_library = NULL; -/* structs and defines */ +/* type definitions and constants */ + +enum { + MAX_FUNCTION_NAME = 64 +}; +enum { + MAX_PARAMETER = 32 +}; +typedef enum { + FUNCTION_QUAL_IN, + FUNCTION_QUAL_OUT, + FUNCTION_QUAL_INOUT +} GPUFunctionQual; + +typedef struct GPUFunction { + char name[MAX_FUNCTION_NAME]; + GPUType paramtype[MAX_PARAMETER]; + GPUFunctionQual paramqual[MAX_PARAMETER]; + int totparam; +} 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"}; -#define LINK_IMAGE_BLENDER 1 -#define LINK_IMAGE_PREVIEW 2 - /* GLSL code parsing for finding function definitions. * These are stored in a hash for lookup when creating a material. */ -static GHash *FUNCTION_HASH= NULL; -/* static char *FUNCTION_PROTOTYPES= NULL; - * static GPUShader *FUNCTION_LIB= NULL;*/ +static GHash *FUNCTION_HASH = NULL; +#if 0 +static char *FUNCTION_PROTOTYPES = NULL; +static GPUShader *FUNCTION_LIB = NULL; +#endif static int gpu_str_prefix(const char *str, const char *prefix) { @@ -100,8 +118,8 @@ static char *gpu_str_skip_token(char *str, char *token, int max) if (ELEM(*str, ' ', '(', ')', ',', '\t', '\n', '\r')) break; else { - if (token && len < max-1) { - *token= *str; + if (token && len < max - 1) { + *token = *str; token++; len++; } @@ -110,7 +128,7 @@ static char *gpu_str_skip_token(char *str, char *token, int max) } if (token) - *token= '\0'; + *token = '\0'; /* skip the next special characters: * note the missing ')' */ @@ -127,7 +145,9 @@ static char *gpu_str_skip_token(char *str, char *token, int max) static void gpu_parse_functions_string(GHash *hash, char *code) { GPUFunction *function; - int i, type, qual; + GPUType type; + GPUFunctionQual qual; + int i; while ((code = strstr(code, "void "))) { function = MEM_callocN(sizeof(GPUFunction), "GPUFunction"); @@ -147,10 +167,10 @@ static void gpu_parse_functions_string(GHash *hash, char *code) code = gpu_str_skip_token(code, NULL, 0); /* test for type */ - type= 0; - for (i=1; i<=16; i++) { + type = GPU_NONE; + for (i = 1; i <= 16; i++) { if (GPU_DATATYPE_STR[i] && gpu_str_prefix(code, GPU_DATATYPE_STR[i])) { - type= i; + type = i; break; } } @@ -161,11 +181,11 @@ static void gpu_parse_functions_string(GHash *hash, char *code) type= GPU_TEX2D; if (type) { - /* add paramater */ + /* add parameter */ code = gpu_str_skip_token(code, NULL, 0); code = gpu_str_skip_token(code, NULL, 0); - function->paramqual[function->totparam]= qual; - function->paramtype[function->totparam]= type; + function->paramqual[function->totparam] = qual; + function->paramtype[function->totparam] = type; function->totparam++; } else { @@ -202,7 +222,7 @@ static char *gpu_generate_function_prototyps(GHash *hash) function = BLI_ghashIterator_getValue(ghi); BLI_dynstr_appendf(ds, "void %s(", name); - for (a=0; a<function->totparam; a++) { + for (a = 0; a < function->totparam; a++) { if (function->paramqual[a] == FUNCTION_QUAL_OUT) BLI_dynstr_append(ds, "out "); else if (function->paramqual[a] == FUNCTION_QUAL_INOUT) @@ -214,10 +234,11 @@ static char *gpu_generate_function_prototyps(GHash *hash) BLI_dynstr_append(ds, "sampler2DShadow"); else BLI_dynstr_append(ds, GPU_DATATYPE_STR[function->paramtype[a]]); - - //BLI_dynstr_appendf(ds, " param%d", a); - - if (a != function->totparam-1) +# if 0 + BLI_dynstr_appendf(ds, " param%d", a); +# endif + + if (a != function->totparam - 1) BLI_dynstr_append(ds, ", "); } BLI_dynstr_append(ds, ");\n"); @@ -232,27 +253,27 @@ static char *gpu_generate_function_prototyps(GHash *hash) } #endif -GPUFunction *GPU_lookup_function(const char *name) +static GPUFunction *gpu_lookup_function(const char *name) { if (!FUNCTION_HASH) { FUNCTION_HASH = BLI_ghash_str_new("GPU_lookup_function gh"); gpu_parse_functions_string(FUNCTION_HASH, glsl_material_library); } - return (GPUFunction*)BLI_ghash_lookup(FUNCTION_HASH, (void *)name); + return BLI_ghash_lookup(FUNCTION_HASH, (const void *)name); } -void GPU_codegen_init(void) +void gpu_codegen_init(void) { GPU_code_generate_glsl_lib(); } -void GPU_codegen_exit(void) +void gpu_codegen_exit(void) { - extern Material defmaterial; // render module abuse... + extern Material defmaterial; /* render module abuse... */ if (defmaterial.gpumaterial.first) - GPU_material_free(&defmaterial); + GPU_material_free(&defmaterial.gpumaterial); if (FUNCTION_HASH) { BLI_ghash_free(FUNCTION_HASH, NULL, MEM_freeN); @@ -266,14 +287,16 @@ void GPU_codegen_exit(void) glsl_material_library = NULL; } - /*if (FUNCTION_PROTOTYPES) { +#if 0 + if (FUNCTION_PROTOTYPES) { MEM_freeN(FUNCTION_PROTOTYPES); FUNCTION_PROTOTYPES = NULL; - }*/ - /*if (FUNCTION_LIB) { + } + if (FUNCTION_LIB) { GPU_shader_free(FUNCTION_LIB); FUNCTION_LIB = NULL; - }*/ + } +#endif } /* GLSL code generation */ @@ -288,18 +311,16 @@ static void codegen_convert_datatype(DynStr *ds, int from, int to, const char *t BLI_dynstr_append(ds, name); } else if (to == GPU_FLOAT) { - if (from == GPU_VEC4) - BLI_dynstr_appendf(ds, "dot(%s.rgb, vec3(0.35, 0.45, 0.2))", name); - else if (from == GPU_VEC3) - BLI_dynstr_appendf(ds, "dot(%s, vec3(0.33))", name); + if (from == GPU_VEC4 || from == GPU_VEC3) + BLI_dynstr_appendf(ds, "(%s.r + %s.g + %s.b) / 3.0", name, name, name); else if (from == GPU_VEC2) BLI_dynstr_appendf(ds, "%s.r", name); } else if (to == GPU_VEC2) { if (from == GPU_VEC4) - BLI_dynstr_appendf(ds, "vec2(dot(%s.rgb, vec3(0.35, 0.45, 0.2)), %s.a)", name, name); + BLI_dynstr_appendf(ds, "vec2((%s.r + %s.g + %s.b) / 3.0, %s.a)", name, name, name, name); else if (from == GPU_VEC3) - BLI_dynstr_appendf(ds, "vec2(dot(%s.rgb, vec3(0.33)), 1.0)", name); + BLI_dynstr_appendf(ds, "vec2((%s.r + %s.g + %s.b) / 3.0, 1.0)", name, name, name); else if (from == GPU_FLOAT) BLI_dynstr_appendf(ds, "vec2(%s, 1.0)", name); } @@ -321,15 +342,15 @@ static void codegen_convert_datatype(DynStr *ds, int from, int to, const char *t } } -static void codegen_print_datatype(DynStr *ds, int type, float *data) +static void codegen_print_datatype(DynStr *ds, const GPUType type, float *data) { int i; BLI_dynstr_appendf(ds, "%s(", GPU_DATATYPE_STR[type]); - for (i=0; i<type; i++) { + for (i = 0; i < type; i++) { BLI_dynstr_appendf(ds, "%f", data[i]); - if (i == type-1) + if (i == type - 1) BLI_dynstr_append(ds, ")"); else BLI_dynstr_append(ds, ", "); @@ -364,10 +385,36 @@ const char *GPU_builtin_name(GPUBuiltin builtin) return "unfobcolor"; else if (builtin == GPU_AUTO_BUMPSCALE) return "unfobautobumpscale"; + else if (builtin == GPU_CAMERA_TEXCO_FACTORS) + return "unfcameratexfactors"; + else if (builtin == GPU_PARTICLE_SCALAR_PROPS) + return "unfparticlescalarprops"; + else if (builtin == GPU_PARTICLE_LOCATION) + return "unfparticleco"; + else if (builtin == GPU_PARTICLE_VELOCITY) + return "unfparticlevel"; + else if (builtin == GPU_PARTICLE_ANG_VELOCITY) + return "unfparticleangvel"; else return ""; } +/* assign only one texid per buffer to avoid sampling the same texture twice */ +static void codegen_set_texid(GHash *bindhash, GPUInput *input, int *texid, void *key) +{ + if (BLI_ghash_haskey(bindhash, key)) { + /* Reuse existing texid */ + input->texid = GET_INT_FROM_POINTER(BLI_ghash_lookup(bindhash, key)); + } + else { + /* Allocate new texid */ + input->texid = *texid; + (*texid)++; + input->bindtex = true; + BLI_ghash_insert(bindhash, key, SET_INT_IN_POINTER(input->texid)); + } +} + static void codegen_set_unique_ids(ListBase *nodes) { GHash *bindhash, *definehash; @@ -376,75 +423,50 @@ static void codegen_set_unique_ids(ListBase *nodes) GPUOutput *output; int id = 1, texid = 0; - bindhash= BLI_ghash_ptr_new("codegen_set_unique_ids1 gh"); - definehash= BLI_ghash_ptr_new("codegen_set_unique_ids2 gh"); + bindhash = BLI_ghash_ptr_new("codegen_set_unique_ids1 gh"); + definehash = BLI_ghash_ptr_new("codegen_set_unique_ids2 gh"); - for (node=nodes->first; node; node=node->next) { - for (input=node->inputs.first; input; input=input->next) { + for (node = nodes->first; node; node = node->next) { + for (input = node->inputs.first; input; input = input->next) { /* set id for unique names of uniform variables */ input->id = id++; - input->bindtex = 0; - input->definetex = 0; + input->bindtex = false; + input->definetex = false; /* set texid used for settings texture slot with multitexture */ if (codegen_input_has_texture(input) && ((input->source == GPU_SOURCE_TEX) || (input->source == GPU_SOURCE_TEX_PIXEL))) { + /* assign only one texid per buffer to avoid sampling + * the same texture twice */ if (input->link) { - /* input is texture from buffer, assign only one texid per - * buffer to avoid sampling the same texture twice */ - if (!BLI_ghash_haskey(bindhash, input->link)) { - input->texid = texid++; - input->bindtex = 1; - BLI_ghash_insert(bindhash, input->link, SET_INT_IN_POINTER(input->texid)); - } - else - input->texid = GET_INT_FROM_POINTER(BLI_ghash_lookup(bindhash, input->link)); + /* input is texture from buffer */ + codegen_set_texid(bindhash, input, &texid, input->link); } else if (input->ima) { - /* input is texture from image, assign only one texid per - * buffer to avoid sampling the same texture twice */ - if (!BLI_ghash_haskey(bindhash, input->ima)) { - input->texid = texid++; - input->bindtex = 1; - BLI_ghash_insert(bindhash, input->ima, SET_INT_IN_POINTER(input->texid)); - } - else - input->texid = GET_INT_FROM_POINTER(BLI_ghash_lookup(bindhash, input->ima)); + /* input is texture from image */ + codegen_set_texid(bindhash, input, &texid, input->ima); } else if (input->prv) { - /* input is texture from preview render, assign only one texid per - * buffer to avoid sampling the same texture twice */ - if (!BLI_ghash_haskey(bindhash, input->prv)) { - input->texid = texid++; - input->bindtex = 1; - BLI_ghash_insert(bindhash, input->prv, SET_INT_IN_POINTER(input->texid)); - } - else - input->texid = GET_INT_FROM_POINTER(BLI_ghash_lookup(bindhash, input->prv)); + /* input is texture from preview render */ + codegen_set_texid(bindhash, input, &texid, input->prv); } - else { - if (!BLI_ghash_haskey(bindhash, input->tex)) { - /* input is user created texture, check tex pointer */ - input->texid = texid++; - input->bindtex = 1; - BLI_ghash_insert(bindhash, input->tex, SET_INT_IN_POINTER(input->texid)); - } - else - input->texid = GET_INT_FROM_POINTER(BLI_ghash_lookup(bindhash, input->tex)); + else if (input->tex) { + /* input is user created texture, check tex pointer */ + codegen_set_texid(bindhash, input, &texid, input->tex); } /* make sure this pixel is defined exactly once */ if (input->source == GPU_SOURCE_TEX_PIXEL) { if (input->ima) { if (!BLI_ghash_haskey(definehash, input->ima)) { - input->definetex = 1; + input->definetex = true; BLI_ghash_insert(definehash, input->ima, SET_INT_IN_POINTER(input->texid)); } } else { if (!BLI_ghash_haskey(definehash, input->link)) { - input->definetex = 1; + input->definetex = true; BLI_ghash_insert(definehash, input->link, SET_INT_IN_POINTER(input->texid)); } } @@ -452,7 +474,7 @@ static void codegen_set_unique_ids(ListBase *nodes) } } - for (output=node->outputs.first; output; output=output->next) + for (output = node->outputs.first; output; output = output->next) /* set id for unique names of tmp variables storing output */ output->id = id++; } @@ -469,8 +491,8 @@ static int codegen_print_uniforms_functions(DynStr *ds, ListBase *nodes) int builtins = 0; /* print uniforms */ - for (node=nodes->first; node; node=node->next) { - for (input=node->inputs.first; input; input=input->next) { + for (node = nodes->first; node; node = node->next) { + for (input = node->inputs.first; input; input = input->next) { if ((input->source == GPU_SOURCE_TEX) || (input->source == GPU_SOURCE_TEX_PIXEL)) { /* create exactly one sampler for each texture */ if (codegen_input_has_texture(input) && input->bindtex) @@ -509,8 +531,19 @@ static int codegen_print_uniforms_functions(DynStr *ds, ListBase *nodes) } } else if (input->source == GPU_SOURCE_ATTRIB && input->attribfirst) { +#ifdef WITH_OPENSUBDIV + bool skip_opensubdiv = input->attribtype == CD_TANGENT; + if (skip_opensubdiv) { + BLI_dynstr_appendf(ds, "#ifndef USE_OPENSUBDIV\n"); + } +#endif BLI_dynstr_appendf(ds, "varying %s var%d;\n", GPU_DATATYPE_STR[input->type], input->attribid); +#ifdef WITH_OPENSUBDIV + if (skip_opensubdiv) { + BLI_dynstr_appendf(ds, "#endif\n"); + } +#endif } } } @@ -526,9 +559,9 @@ static void codegen_declare_tmps(DynStr *ds, ListBase *nodes) GPUInput *input; GPUOutput *output; - for (node=nodes->first; node; node=node->next) { + for (node = nodes->first; node; node = node->next) { /* load pixels from textures */ - for (input=node->inputs.first; input; input=input->next) { + for (input = node->inputs.first; input; input = input->next) { if (input->source == GPU_SOURCE_TEX_PIXEL) { if (codegen_input_has_texture(input) && input->definetex) { BLI_dynstr_appendf(ds, "\tvec4 tex%d = texture2D(", input->texid); @@ -539,7 +572,7 @@ 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) + 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); } @@ -553,10 +586,10 @@ static void codegen_call_functions(DynStr *ds, ListBase *nodes, GPUOutput *final GPUInput *input; GPUOutput *output; - for (node=nodes->first; node; node=node->next) { + for (node = nodes->first; node; node = node->next) { BLI_dynstr_appendf(ds, "\t%s(", node->name); - for (input=node->inputs.first; input; input=input->next) { + for (input = node->inputs.first; input; input = input->next) { if (input->source == GPU_SOURCE_TEX) { BLI_dynstr_appendf(ds, "samp%d", input->texid); if (input->link) @@ -591,7 +624,7 @@ static void codegen_call_functions(DynStr *ds, ListBase *nodes, GPUOutput *final BLI_dynstr_append(ds, ", "); } - for (output=node->outputs.first; output; output=output->next) { + for (output = node->outputs.first; output; output = output->next) { BLI_dynstr_appendf(ds, "tmp%d", output->id); if (output->next) BLI_dynstr_append(ds, ", "); @@ -605,26 +638,63 @@ static void codegen_call_functions(DynStr *ds, ListBase *nodes, GPUOutput *final BLI_dynstr_append(ds, ";\n"); } -static char *code_generate_fragment(ListBase *nodes, GPUOutput *output, const char *UNUSED(name)) +static char *code_generate_fragment(ListBase *nodes, GPUOutput *output) { DynStr *ds = BLI_dynstr_new(); char *code; int builtins; - /*BLI_dynstr_append(ds, FUNCTION_PROTOTYPES);*/ +#ifdef WITH_OPENSUBDIV + GPUNode *node; + GPUInput *input; +#endif + + +#if 0 + BLI_dynstr_append(ds, FUNCTION_PROTOTYPES); +#endif codegen_set_unique_ids(nodes); builtins = codegen_print_uniforms_functions(ds, nodes); - //if (G.debug & G_DEBUG) - // BLI_dynstr_appendf(ds, "/* %s */\n", name); +#if 0 + if (G.debug & G_DEBUG) + BLI_dynstr_appendf(ds, "/* %s */\n", name); +#endif BLI_dynstr_append(ds, "void main(void)\n"); BLI_dynstr_append(ds, "{\n"); if (builtins & GPU_VIEW_NORMAL) BLI_dynstr_append(ds, "\tvec3 facingnormal = (gl_FrontFacing)? varnormal: -varnormal;\n"); - + + /* Calculate tangent space. */ +#ifdef WITH_OPENSUBDIV + { + bool has_tangent = false; + 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) { + BLI_dynstr_appendf(ds, "#ifdef USE_OPENSUBDIV\n"); + BLI_dynstr_appendf(ds, "\t%s var%d;\n", + GPU_DATATYPE_STR[input->type], + input->attribid); + if (has_tangent == false) { + BLI_dynstr_appendf(ds, "\tvec3 Q1 = dFdx(inpt.v.position.xyz);\n"); + BLI_dynstr_appendf(ds, "\tvec3 Q2 = dFdy(inpt.v.position.xyz);\n"); + BLI_dynstr_appendf(ds, "\tvec2 st1 = dFdx(inpt.v.uv);\n"); + BLI_dynstr_appendf(ds, "\tvec2 st2 = dFdy(inpt.v.uv);\n"); + BLI_dynstr_appendf(ds, "\tvec3 T = normalize(Q1 * st2.t - Q2 * st1.t);\n"); + } + BLI_dynstr_appendf(ds, "\tvar%d = vec4(T, 1.0);\n", input->attribid); + BLI_dynstr_appendf(ds, "#endif\n"); + } + } + } + } + } +#endif codegen_declare_tmps(ds, nodes); codegen_call_functions(ds, nodes, output); @@ -635,41 +705,86 @@ static char *code_generate_fragment(ListBase *nodes, GPUOutput *output, const ch code = BLI_dynstr_get_cstring(ds); BLI_dynstr_free(ds); - //if (G.debug & G_DEBUG) printf("%s\n", code); +#if 0 + if (G.debug & G_DEBUG) printf("%s\n", code); +#endif return code; } -static char *code_generate_vertex(ListBase *nodes) +static char *code_generate_vertex(ListBase *nodes, const GPUMatType type) { DynStr *ds = BLI_dynstr_new(); GPUNode *node; GPUInput *input; char *code; + char *vertcode = NULL; - for (node=nodes->first; node; node=node->next) { - for (input=node->inputs.first; input; input=input->next) { + for (node = nodes->first; node; node = node->next) { + for (input = node->inputs.first; input; input = input->next) { if (input->source == GPU_SOURCE_ATTRIB && input->attribfirst) { +#ifdef WITH_OPENSUBDIV + bool skip_opensubdiv = ELEM(input->attribtype, CD_MTFACE, CD_TANGENT); + if (skip_opensubdiv) { + BLI_dynstr_appendf(ds, "#ifndef USE_OPENSUBDIV\n"); + } +#endif BLI_dynstr_appendf(ds, "attribute %s att%d;\n", GPU_DATATYPE_STR[input->type], input->attribid); BLI_dynstr_appendf(ds, "varying %s var%d;\n", GPU_DATATYPE_STR[input->type], input->attribid); +#ifdef WITH_OPENSUBDIV + if (skip_opensubdiv) { + BLI_dynstr_appendf(ds, "#endif\n"); + } +#endif } } } BLI_dynstr_append(ds, "\n"); - BLI_dynstr_append(ds, datatoc_gpu_shader_vertex_glsl); - for (node=nodes->first; node; node=node->next) - for (input=node->inputs.first; input; input=input->next) + switch (type) { + case GPU_MATERIAL_TYPE_MESH: + vertcode = datatoc_gpu_shader_vertex_glsl; + break; + case GPU_MATERIAL_TYPE_WORLD: + vertcode = datatoc_gpu_shader_vertex_world_glsl; + break; + default: + fprintf(stderr, "invalid material type, set one after GPU_material_construct_begin\n"); + break; + } + + BLI_dynstr_append(ds, vertcode); + + 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.xyz = normalize((gl_ModelViewMatrix * vec4(att%d.xyz, 0)).xyz);\n", input->attribid, input->attribid); +#ifdef WITH_OPENSUBDIV + BLI_dynstr_appendf(ds, "#ifndef USE_OPENSUBDIV\n"); +#endif + BLI_dynstr_appendf(ds, "\tvar%d.xyz = normalize(gl_NormalMatrix * att%d.xyz);\n", input->attribid, input->attribid); BLI_dynstr_appendf(ds, "\tvar%d.w = att%d.w;\n", input->attribid, input->attribid); +#ifdef WITH_OPENSUBDIV + BLI_dynstr_appendf(ds, "#endif\n"); +#endif } - else + else { +#ifdef WITH_OPENSUBDIV + bool is_mtface = input->attribtype == CD_MTFACE; + if (is_mtface) { + BLI_dynstr_appendf(ds, "#ifndef USE_OPENSUBDIV\n"); + } +#endif BLI_dynstr_appendf(ds, "\tvar%d = att%d;\n", input->attribid, input->attribid); +#ifdef WITH_OPENSUBDIV + if (is_mtface) { + BLI_dynstr_appendf(ds, "#endif\n"); + } +#endif + } } /* unfortunately special handling is needed here because we abuse gl_Color/gl_SecondaryColor flat shading */ else if (input->source == GPU_SOURCE_OPENGL_BUILTIN) { @@ -690,14 +805,69 @@ static char *code_generate_vertex(ListBase *nodes) BLI_dynstr_free(ds); - //if (G.debug & G_DEBUG) printf("%s\n", code); +#if 0 + if (G.debug & G_DEBUG) printf("%s\n", code); +#endif return code; } -int GPU_bicubic_bump_support(void) +static char *code_generate_geometry(ListBase *nodes, bool use_opensubdiv) { - return GLEW_ARB_texture_query_lod && GLEW_VERSION_3_0; +#ifdef WITH_OPENSUBDIV + if (use_opensubdiv) { + DynStr *ds = BLI_dynstr_new(); + GPUNode *node; + GPUInput *input; + char *code; + + /* Generate varying declarations. */ + for (node = nodes->first; node; node = node->next) { + for (input = node->inputs.first; input; input = input->next) { + if (input->source == GPU_SOURCE_ATTRIB && input->attribfirst) { + if (input->attribtype == CD_MTFACE) { + BLI_dynstr_appendf(ds, "varying %s var%d;\n", + GPU_DATATYPE_STR[input->type], + input->attribid); + BLI_dynstr_appendf(ds, "uniform int fvar%d_offset;\n", + input->attribid); + } + } + } + } + + BLI_dynstr_append(ds, datatoc_gpu_shader_geometry_glsl); + + /* Generate varying assignments. */ + /* TODO(sergey): Disabled for now, needs revisit. */ +#if 0 + for (node = nodes->first; node; node = node->next) { + for (input = node->inputs.first; input; input = input->next) { + if (input->source == GPU_SOURCE_ATTRIB && input->attribfirst) { + if (input->attribtype == CD_MTFACE) { + BLI_dynstr_appendf(ds, + "\tINTERP_FACE_VARYING_2(var%d, " + "fvar%d_offset, st);\n", + input->attribid, + input->attribid); + } + } + } + } +#endif + + BLI_dynstr_append(ds, "}\n\n"); + code = BLI_dynstr_get_cstring(ds); + BLI_dynstr_free(ds); + + //if (G.debug & G_DEBUG) printf("%s\n", code); + + return code; + } +#else + UNUSED_VARS(nodes, use_opensubdiv); +#endif + return NULL; } void GPU_code_generate_glsl_lib(void) @@ -726,7 +896,7 @@ GPUShader *GPU_pass_shader(GPUPass *pass) return pass->shader; } -static void GPU_nodes_extract_dynamic_inputs(GPUPass *pass, ListBase *nodes) +static void gpu_nodes_extract_dynamic_inputs(GPUPass *pass, ListBase *nodes) { GPUShader *shader = pass->shader; GPUNode *node; @@ -741,15 +911,35 @@ static void GPU_nodes_extract_dynamic_inputs(GPUPass *pass, ListBase *nodes) GPU_shader_bind(shader); - for (node=nodes->first; node; node=node->next) { + for (node = nodes->first; node; node = node->next) { z = 0; - for (input=node->inputs.first; input; input=next, z++) { + 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 || - input->source == GPU_SOURCE_BUILTIN || + if (input->source == GPU_SOURCE_ATTRIB) { +#ifdef WITH_OPENSUBDIV + /* We do need mtface attributes for later, so we can + * update face-varuing variables offset in the texture + * buffer for proper sampling from the shader. + * + * We don't do anything about attribute itself, we + * only use it to learn which uniform name is to be + * updated. + * + * TODO(sergey): We can add ad extra uniform input + * for the offset, which will be purely internal and + * which would avoid having such an exceptions. + */ + if (input->attribtype != CD_MTFACE) { + continue; + } +#else + continue; +#endif + } + if (input->source == GPU_SOURCE_BUILTIN || input->source == GPU_SOURCE_OPENGL_BUILTIN) { continue; @@ -773,6 +963,14 @@ static void GPU_nodes_extract_dynamic_inputs(GPUPass *pass, ListBase *nodes) if (extract) input->shaderloc = GPU_shader_get_uniform(shader, input->shadername); +#ifdef WITH_OPENSUBDIV + if (input->source == GPU_SOURCE_ATTRIB && + input->attribtype == CD_MTFACE) + { + extract = 1; + } +#endif + /* extract nodes */ if (extract) { BLI_remlink(&node->inputs, input); @@ -796,7 +994,7 @@ void GPU_pass_bind(GPUPass *pass, double time, int mipmap) GPU_shader_bind(shader); /* now bind the textures */ - for (input=inputs->first; input; input=input->next) { + for (input = inputs->first; input; input = input->next) { if (input->ima) input->tex = GPU_texture_from_blender(input->ima, input->iuser, input->image_isdata, time, mipmap); else if (input->prv) @@ -820,10 +1018,19 @@ void GPU_pass_update_uniforms(GPUPass *pass) return; /* pass dynamic inputs to opengl, others were removed */ - for (input=inputs->first; input; input=input->next) - if (!(input->ima || input->tex || input->prv)) - GPU_shader_uniform_vector(shader, input->shaderloc, input->type, 1, - input->dynamicvec); + for (input = inputs->first; input; input = input->next) { + if (!(input->ima || input->tex || input->prv)) { + if (input->dynamictype == GPU_DYNAMIC_MAT_HARD) { + // The hardness is actually a short pointer, so we convert it here + float val = (float)(*(short*)input->dynamicvec); + GPU_shader_uniform_vector(shader, input->shaderloc, 1, 1, &val); + } + else { + GPU_shader_uniform_vector(shader, input->shaderloc, input->type, 1, + input->dynamicvec); + } + } + } } void GPU_pass_unbind(GPUPass *pass) @@ -835,7 +1042,7 @@ void GPU_pass_unbind(GPUPass *pass) if (!shader) return; - for (input=inputs->first; input; input=input->next) { + for (input = inputs->first; input; input = input->next) { if (input->tex && input->bindtex) GPU_texture_unbind(input->tex); @@ -848,16 +1055,16 @@ void GPU_pass_unbind(GPUPass *pass) /* Node Link Functions */ -static GPUNodeLink *GPU_node_link_create(int type) +static GPUNodeLink *GPU_node_link_create(void) { GPUNodeLink *link = MEM_callocN(sizeof(GPUNodeLink), "GPUNodeLink"); - link->type = type; + link->type = GPU_NONE; link->users++; return link; } -static void GPU_node_link_free(GPUNodeLink *link) +static void gpu_node_link_free(GPUNodeLink *link) { link->users--; @@ -877,17 +1084,12 @@ static GPUNode *GPU_node_begin(const char *name) { GPUNode *node = MEM_callocN(sizeof(GPUNode), "GPUNode"); - node->name= name; + node->name = name; return node; } -static void GPU_node_end(GPUNode *UNUSED(node)) -{ - /* empty */ -} - -static void gpu_node_input_link(GPUNode *node, GPUNodeLink *link, int type) +static void gpu_node_input_link(GPUNode *node, GPUNodeLink *link, const GPUType type) { GPUInput *input; GPUNode *outnode; @@ -896,8 +1098,11 @@ static void gpu_node_input_link(GPUNode *node, GPUNodeLink *link, int type) if (link->output) { outnode = link->output->node; name = outnode->name; + input = outnode->inputs.first; - if (strcmp(name, "set_value")==0 || strcmp(name, "set_rgb")==0) { + if ((STREQ(name, "set_value") || STREQ(name, "set_rgb")) && + (input->type == type)) + { input = MEM_dupallocN(outnode->inputs.first); input->type = type; if (input->link) @@ -941,7 +1146,7 @@ static void gpu_node_input_link(GPUNode *node, GPUNodeLink *link, int type) input->tex = link->dynamictex; input->textarget = GL_TEXTURE_2D; input->textype = type; - input->dynamictex = 1; + input->dynamictex = true; input->dynamicdata = link->ptr2; MEM_freeN(link); } @@ -951,8 +1156,10 @@ static void gpu_node_input_link(GPUNode *node, GPUNodeLink *link, int type) input->source = GPU_SOURCE_TEX; input->textype = type; - //input->tex = GPU_texture_create_2D(link->texturesize, link->texturesize, link->ptr2, NULL); - input->tex = GPU_texture_create_2D(link->texturesize, 1, link->ptr1, NULL); +#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->textarget = GL_TEXTURE_2D; MEM_freeN(link->ptr1); @@ -963,7 +1170,7 @@ static void gpu_node_input_link(GPUNode *node, GPUNodeLink *link, int type) input->type = GPU_VEC4; input->source = GPU_SOURCE_TEX; - if (link->image == LINK_IMAGE_PREVIEW) + if (link->image == GPU_NODE_LINK_IMAGE_PREVIEW) input->prv = link->ptr1; else { input->ima = link->ptr1; @@ -990,9 +1197,9 @@ static void gpu_node_input_link(GPUNode *node, GPUNodeLink *link, int type) memcpy(input->vec, link->ptr1, type*sizeof(float)); if (link->dynamic) { - input->dynamicvec= link->ptr1; - input->dynamictype= link->dynamictype; - input->dynamicdata= link->ptr2; + input->dynamicvec = link->ptr1; + input->dynamictype = link->dynamictype; + input->dynamicdata = link->ptr2; } MEM_freeN(link); } @@ -1008,13 +1215,13 @@ static void gpu_node_input_socket(GPUNode *node, GPUNodeStack *sock) gpu_node_input_link(node, sock->link, sock->type); } else { - link = GPU_node_link_create(0); + link = GPU_node_link_create(); link->ptr1 = sock->vec; gpu_node_input_link(node, link, sock->type); } } -static void GPU_node_output(GPUNode *node, int type, const char *UNUSED(name), GPUNodeLink **link) +static void gpu_node_output(GPUNode *node, const GPUType type, GPUNodeLink **link) { GPUOutput *output = MEM_callocN(sizeof(GPUOutput), "GPUOutput"); @@ -1022,10 +1229,11 @@ static void GPU_node_output(GPUNode *node, int type, const char *UNUSED(name), G output->node = node; if (link) { - *link = output->link = GPU_node_link_create(type); + *link = output->link = GPU_node_link_create(); + output->link->type = type; output->link->output = output; - /* note: the caller owns the reference to the linkfer, GPUOutput + /* note: the caller owns the reference to the link, GPUOutput * merely points to it, and if the node is destroyed it will * set that pointer to NULL */ } @@ -1033,13 +1241,13 @@ static void GPU_node_output(GPUNode *node, int type, const char *UNUSED(name), G BLI_addtail(&node->outputs, output); } -static void GPU_inputs_free(ListBase *inputs) +static void gpu_inputs_free(ListBase *inputs) { GPUInput *input; - for (input=inputs->first; input; input=input->next) { + for (input = inputs->first; input; input = input->next) { if (input->link) - GPU_node_link_free(input->link); + gpu_node_link_free(input->link); else if (input->tex && !input->dynamictex) GPU_texture_free(input->tex); } @@ -1047,28 +1255,28 @@ static void GPU_inputs_free(ListBase *inputs) BLI_freelistN(inputs); } -static void GPU_node_free(GPUNode *node) +static void gpu_node_free(GPUNode *node) { GPUOutput *output; - GPU_inputs_free(&node->inputs); + gpu_inputs_free(&node->inputs); - for (output=node->outputs.first; output; output=output->next) + for (output = node->outputs.first; output; output = output->next) if (output->link) { output->link->output = NULL; - GPU_node_link_free(output->link); + gpu_node_link_free(output->link); } BLI_freelistN(&node->outputs); MEM_freeN(node); } -static void GPU_nodes_free(ListBase *nodes) +static void gpu_nodes_free(ListBase *nodes) { GPUNode *node; while ((node = BLI_pophead(nodes))) { - GPU_node_free(node); + gpu_node_free(node); } } @@ -1085,12 +1293,12 @@ static void gpu_nodes_get_vertex_attributes(ListBase *nodes, GPUVertexAttribs *a memset(attribs, 0, sizeof(*attribs)); - for (node=nodes->first; node; node=node->next) { - for (input=node->inputs.first; input; input=input->next) { + for (node = nodes->first; node; node = node->next) { + for (input = node->inputs.first; input; input = input->next) { if (input->source == GPU_SOURCE_ATTRIB) { - for (a=0; a<attribs->totlayer; a++) { + for (a = 0; a < attribs->totlayer; a++) { if (attribs->layer[a].type == input->attribtype && - strcmp(attribs->layer[a].name, input->attribname) == 0) + STREQ(attribs->layer[a].name, input->attribname)) { break; } @@ -1120,43 +1328,43 @@ static void gpu_nodes_get_builtin_flag(ListBase *nodes, int *builtin) GPUNode *node; GPUInput *input; - *builtin= 0; + *builtin = 0; - for (node=nodes->first; node; node=node->next) - for (input=node->inputs.first; input; input=input->next) + for (node = nodes->first; node; node = node->next) + for (input = node->inputs.first; input; input = input->next) if (input->source == GPU_SOURCE_BUILTIN) *builtin |= input->builtin; } /* varargs linking */ -GPUNodeLink *GPU_attribute(int type, const char *name) +GPUNodeLink *GPU_attribute(const CustomDataType type, const char *name) { - GPUNodeLink *link = GPU_node_link_create(0); + GPUNodeLink *link = GPU_node_link_create(); - link->attribtype= type; - link->attribname= name; + link->attribtype = type; + link->attribname = name; return link; } GPUNodeLink *GPU_uniform(float *num) { - GPUNodeLink *link = GPU_node_link_create(0); + GPUNodeLink *link = GPU_node_link_create(); - link->ptr1= num; - link->ptr2= NULL; + link->ptr1 = num; + link->ptr2 = NULL; return link; } -GPUNodeLink *GPU_dynamic_uniform(float *num, int dynamictype, void *data) +GPUNodeLink *GPU_dynamic_uniform(float *num, GPUDynamicType dynamictype, void *data) { - GPUNodeLink *link = GPU_node_link_create(0); + GPUNodeLink *link = GPU_node_link_create(); - link->ptr1= num; - link->ptr2= data; - link->dynamic= 1; + link->ptr1 = num; + link->ptr2 = data; + link->dynamic = true; link->dynamictype = dynamictype; @@ -1165,9 +1373,9 @@ GPUNodeLink *GPU_dynamic_uniform(float *num, int dynamictype, void *data) GPUNodeLink *GPU_image(Image *ima, ImageUser *iuser, bool is_data) { - GPUNodeLink *link = GPU_node_link_create(0); + GPUNodeLink *link = GPU_node_link_create(); - link->image = LINK_IMAGE_BLENDER; + link->image = GPU_NODE_LINK_IMAGE_BLENDER; link->ptr1 = ima; link->ptr2 = iuser; link->image_isdata = is_data; @@ -1177,10 +1385,10 @@ GPUNodeLink *GPU_image(Image *ima, ImageUser *iuser, bool is_data) GPUNodeLink *GPU_image_preview(PreviewImage *prv) { - GPUNodeLink *link = GPU_node_link_create(0); + GPUNodeLink *link = GPU_node_link_create(); - link->image= LINK_IMAGE_PREVIEW; - link->ptr1= prv; + link->image = GPU_NODE_LINK_IMAGE_PREVIEW; + link->ptr1 = prv; return link; } @@ -1188,20 +1396,20 @@ GPUNodeLink *GPU_image_preview(PreviewImage *prv) GPUNodeLink *GPU_texture(int size, float *pixels) { - GPUNodeLink *link = GPU_node_link_create(0); + GPUNodeLink *link = GPU_node_link_create(); - link->texture = 1; + link->texture = true; link->texturesize = size; - link->ptr1= pixels; + link->ptr1 = pixels; return link; } -GPUNodeLink *GPU_dynamic_texture(GPUTexture *tex, int dynamictype, void *data) +GPUNodeLink *GPU_dynamic_texture(GPUTexture *tex, GPUDynamicType dynamictype, void *data) { - GPUNodeLink *link = GPU_node_link_create(0); + GPUNodeLink *link = GPU_node_link_create(); - link->dynamic = 1; + link->dynamic = true; link->dynamictex = tex; link->dynamictype = dynamictype; link->ptr2 = data; @@ -1211,7 +1419,7 @@ GPUNodeLink *GPU_dynamic_texture(GPUTexture *tex, int dynamictype, void *data) GPUNodeLink *GPU_builtin(GPUBuiltin builtin) { - GPUNodeLink *link = GPU_node_link_create(0); + GPUNodeLink *link = GPU_node_link_create(); link->builtin= builtin; @@ -1220,7 +1428,7 @@ GPUNodeLink *GPU_builtin(GPUBuiltin builtin) GPUNodeLink *GPU_opengl_builtin(GPUOpenGLBuiltin builtin) { - GPUNodeLink *link = GPU_node_link_create(0); + GPUNodeLink *link = GPU_node_link_create(); link->oglbuiltin = builtin; @@ -1235,7 +1443,7 @@ bool GPU_link(GPUMaterial *mat, const char *name, ...) va_list params; int i; - function = GPU_lookup_function(name); + function = gpu_lookup_function(name); if (!function) { fprintf(stderr, "GPU failed to find function %s\n", name); return 0; @@ -1244,20 +1452,18 @@ bool GPU_link(GPUMaterial *mat, const char *name, ...) node = GPU_node_begin(name); va_start(params, name); - for (i=0; i<function->totparam; i++) { + for (i = 0; i<function->totparam; i++) { if (function->paramqual[i] != FUNCTION_QUAL_IN) { - linkptr= va_arg(params, GPUNodeLink**); - GPU_node_output(node, function->paramtype[i], "", linkptr); + linkptr = va_arg(params, GPUNodeLink**); + gpu_node_output(node, function->paramtype[i], linkptr); } else { - link= va_arg(params, GPUNodeLink*); + link = va_arg(params, GPUNodeLink*); gpu_node_input_link(node, link, function->paramtype[i]); } } va_end(params); - GPU_node_end(node); - gpu_material_add_node(mat, node); return 1; @@ -1271,7 +1477,7 @@ bool GPU_stack_link(GPUMaterial *mat, const char *name, GPUNodeStack *in, GPUNod va_list params; int i, totin, totout; - function = GPU_lookup_function(name); + function = gpu_lookup_function(name); if (!function) { fprintf(stderr, "GPU failed to find function %s\n", name); return 0; @@ -1290,24 +1496,24 @@ bool GPU_stack_link(GPUMaterial *mat, const char *name, GPUNodeStack *in, GPUNod if (out) { for (i = 0; out[i].type != GPU_NONE; i++) { - GPU_node_output(node, out[i].type, out[i].name, &out[i].link); + gpu_node_output(node, out[i].type, &out[i].link); totout++; } } va_start(params, out); - for (i=0; i<function->totparam; i++) { + for (i = 0; i<function->totparam; i++) { if (function->paramqual[i] != FUNCTION_QUAL_IN) { if (totout == 0) { - linkptr= va_arg(params, GPUNodeLink**); - GPU_node_output(node, function->paramtype[i], "", linkptr); + linkptr = va_arg(params, GPUNodeLink**); + gpu_node_output(node, function->paramtype[i], linkptr); } else totout--; } else { if (totin == 0) { - link= va_arg(params, GPUNodeLink*); + link = va_arg(params, GPUNodeLink*); if (link->socket) gpu_node_input_socket(node, link->socket); else @@ -1319,8 +1525,6 @@ bool GPU_stack_link(GPUMaterial *mat, const char *name, GPUNodeStack *in, GPUNod } va_end(params); - GPU_node_end(node); - gpu_material_add_node(mat, node); return 1; @@ -1336,7 +1540,7 @@ int GPU_link_changed(GPUNodeLink *link) node = link->output->node; name = node->name; - if (strcmp(name, "set_value")==0 || strcmp(name, "set_rgb")==0) { + if (STREQ(name, "set_value") || STREQ(name, "set_rgb")) { input = node->inputs.first; return (input->link != NULL); } @@ -1361,8 +1565,8 @@ static void gpu_nodes_tag(GPUNodeLink *link) if (node->tag) return; - node->tag= 1; - for (input=node->inputs.first; input; input=input->next) + node->tag = true; + for (input = node->inputs.first; input; input = input->next) if (input->link) gpu_nodes_tag(input->link); } @@ -1371,31 +1575,35 @@ static void gpu_nodes_prune(ListBase *nodes, GPUNodeLink *outlink) { GPUNode *node, *next; - for (node=nodes->first; node; node=node->next) - node->tag= 0; + for (node = nodes->first; node; node = node->next) + node->tag = false; gpu_nodes_tag(outlink); - for (node=nodes->first; node; node=next) { + for (node = nodes->first; node; node = next) { next = node->next; if (!node->tag) { BLI_remlink(nodes, node); - GPU_node_free(node); + gpu_node_free(node); } } } -GPUPass *GPU_generate_pass(ListBase *nodes, GPUNodeLink *outlink, GPUVertexAttribs *attribs, int *builtins, const char *name) +GPUPass *GPU_generate_pass(ListBase *nodes, GPUNodeLink *outlink, + GPUVertexAttribs *attribs, int *builtins, + const GPUMatType type, const char *UNUSED(name), const bool use_opensubdiv) { GPUShader *shader; GPUPass *pass; - char *vertexcode, *fragmentcode; + char *vertexcode, *geometrycode, *fragmentcode; - /*if (!FUNCTION_LIB) { +#if 0 + if (!FUNCTION_LIB) { GPU_nodes_free(nodes); return NULL; - }*/ + } +#endif /* prune unused nodes */ gpu_nodes_prune(nodes, outlink); @@ -1404,9 +1612,19 @@ GPUPass *GPU_generate_pass(ListBase *nodes, GPUNodeLink *outlink, GPUVertexAttri gpu_nodes_get_builtin_flag(nodes, builtins); /* generate code and compile with opengl */ - fragmentcode = code_generate_fragment(nodes, outlink->output, name); - vertexcode = code_generate_vertex(nodes); - shader = GPU_shader_create(vertexcode, fragmentcode, glsl_material_library, NULL); + fragmentcode = code_generate_fragment(nodes, outlink->output); + vertexcode = code_generate_vertex(nodes, type); + geometrycode = code_generate_geometry(nodes, use_opensubdiv); + shader = GPU_shader_create_ex(vertexcode, + fragmentcode, + geometrycode, + glsl_material_library, + NULL, + 0, + 0, + 0, + use_opensubdiv ? GPU_SHADER_FLAGS_SPECIAL_OPENSUBDIV + : GPU_SHADER_FLAGS_NONE); /* failed? */ if (!shader) { @@ -1416,7 +1634,7 @@ GPUPass *GPU_generate_pass(ListBase *nodes, GPUNodeLink *outlink, GPUVertexAttri MEM_freeN(vertexcode); memset(attribs, 0, sizeof(*attribs)); memset(builtins, 0, sizeof(*builtins)); - GPU_nodes_free(nodes); + gpu_nodes_free(nodes); return NULL; } @@ -1426,12 +1644,13 @@ GPUPass *GPU_generate_pass(ListBase *nodes, GPUNodeLink *outlink, GPUVertexAttri pass->output = outlink->output; pass->shader = shader; pass->fragmentcode = fragmentcode; + pass->geometrycode = geometrycode; pass->vertexcode = vertexcode; pass->libcode = glsl_material_library; /* extract dynamic inputs and throw away nodes */ - GPU_nodes_extract_dynamic_inputs(pass, nodes); - GPU_nodes_free(nodes); + gpu_nodes_extract_dynamic_inputs(pass, nodes); + gpu_nodes_free(nodes); return pass; } @@ -1439,11 +1658,12 @@ GPUPass *GPU_generate_pass(ListBase *nodes, GPUNodeLink *outlink, GPUVertexAttri void GPU_pass_free(GPUPass *pass) { GPU_shader_free(pass->shader); - GPU_inputs_free(&pass->inputs); + gpu_inputs_free(&pass->inputs); if (pass->fragmentcode) MEM_freeN(pass->fragmentcode); + if (pass->geometrycode) + MEM_freeN(pass->geometrycode); if (pass->vertexcode) MEM_freeN(pass->vertexcode); MEM_freeN(pass); } - diff --git a/source/blender/gpu/intern/gpu_codegen.h b/source/blender/gpu/intern/gpu_codegen.h index b6db923e5c2..5aa187014ba 100644 --- a/source/blender/gpu/intern/gpu_codegen.h +++ b/source/blender/gpu/intern/gpu_codegen.h @@ -33,34 +33,18 @@ #ifndef __GPU_CODEGEN_H__ #define __GPU_CODEGEN_H__ +#include "DNA_customdata_types.h" #include "DNA_listBase.h" #include "GPU_material.h" -#include "GL/glew.h" +#include "GPU_glew.h" struct ListBase; struct GPUShader; struct GPUOutput; struct GPUNode; struct GPUVertexAttribs; -struct GPUFrameBuffer; struct PreviewImage; -#define MAX_FUNCTION_NAME 64 -#define MAX_PARAMETER 32 - -#define FUNCTION_QUAL_IN 0 -#define FUNCTION_QUAL_OUT 1 -#define FUNCTION_QUAL_INOUT 2 - -typedef struct GPUFunction { - char name[MAX_FUNCTION_NAME]; - int paramtype[MAX_PARAMETER]; - int paramqual[MAX_PARAMETER]; - int totparam; -} GPUFunction; - -GPUFunction *GPU_lookup_function(const char *name); - /* Pass Generation * - Takes a list of nodes and a desired output, and makes a pass. This * will take ownership of the nodes and free them early if unused or @@ -76,11 +60,19 @@ typedef enum GPUDataSource { GPU_SOURCE_ATTRIB } GPUDataSource; +typedef enum { + GPU_NODE_LINK_IMAGE_NONE = 0, + GPU_NODE_LINK_IMAGE_BLENDER = 1, + GPU_NODE_LINK_IMAGE_PREVIEW = 2 +} GPUNodeLinkImage; + struct GPUNode { struct GPUNode *next, *prev; const char *name; - int tag; + + /* Internal flag to mark nodes during pruning */ + bool tag; ListBase inputs; ListBase outputs; @@ -89,24 +81,26 @@ struct GPUNode { struct GPUNodeLink { GPUNodeStack *socket; - int attribtype; + CustomDataType attribtype; const char *attribname; - int image; - int image_isdata; + GPUNodeLinkImage image; + bool image_isdata; - int texture; + bool texture; int texturesize; void *ptr1, *ptr2; - int dynamic; - int dynamictype; + bool dynamic; + GPUDynamicType dynamictype; + + GPUType type; - int type; + /* Refcount */ int users; - GPUTexture *dynamictex; + struct GPUTexture *dynamictex; GPUBuiltin builtin; GPUOpenGLBuiltin oglbuiltin; @@ -118,9 +112,9 @@ typedef struct GPUOutput { struct GPUOutput *next, *prev; GPUNode *node; - int type; /* data type = length of vector/matrix */ - GPUNodeLink *link; /* output link */ - int id; /* unique id as created by code generator */ + GPUType type; /* data type = length of vector/matrix */ + GPUNodeLink *link; /* output link */ + int id; /* unique id as created by code generator */ } GPUOutput; typedef struct GPUInput { @@ -128,35 +122,35 @@ typedef struct GPUInput { GPUNode *node; - int type; /* datatype */ - int source; /* data source */ - - int id; /* unique id as created by code generator */ - int texid; /* number for multitexture */ - int attribid; /* id for vertex attributes */ - int bindtex; /* input is responsible for binding the texture? */ - int definetex; /* input is responsible for defining the pixel? */ - int textarget; /* GL_TEXTURE_* */ - int textype; /* datatype */ - - struct Image *ima; /* image */ - struct ImageUser *iuser;/* image user */ - struct PreviewImage *prv; /* preview images & icons */ - int image_isdata; /* image does not contain color data */ - float *dynamicvec; /* vector data in case it is dynamic */ - int dynamictype; /* origin of the dynamic uniform (GPUDynamicType) */ - void *dynamicdata; /* data source of the dynamic uniform */ - GPUTexture *tex; /* input texture, only set at runtime */ - int shaderloc; /* id from opengl */ - char shadername[32]; /* name in shader */ - - float vec[16]; /* vector data */ + GPUType type; /* datatype */ + GPUDataSource source; /* data source */ + + int id; /* unique id as created by code generator */ + int texid; /* number for multitexture, starting from zero */ + int attribid; /* id for vertex attributes */ + bool bindtex; /* input is responsible for binding the texture? */ + bool definetex; /* input is responsible for defining the pixel? */ + int textarget; /* GL texture target, e.g. GL_TEXTURE_2D */ + GPUType textype; /* datatype */ + + struct Image *ima; /* image */ + struct ImageUser *iuser; /* image user */ + struct PreviewImage *prv; /* preview images & icons */ + bool image_isdata; /* image does not contain color data */ + float *dynamicvec; /* vector data in case it is dynamic */ + GPUDynamicType dynamictype; /* origin of the dynamic uniform */ + void *dynamicdata; /* data source of the dynamic uniform */ + struct GPUTexture *tex; /* input texture, only set at runtime */ + int shaderloc; /* id from opengl */ + char shadername[32]; /* name in shader */ + + float vec[16]; /* vector data */ GPUNodeLink *link; - int dynamictex; /* dynamic? */ - int attribtype; /* attribute type */ - char attribname[32]; /* attribute name */ - int attribfirst; /* this is the first one that is bound */ - GPUBuiltin builtin; /* builtin uniform */ + bool dynamictex; /* dynamic? */ + CustomDataType attribtype; /* attribute type */ + char attribname[MAX_CUSTOMDATA_LAYER_NAME]; /* attribute name */ + int attribfirst; /* this is the first one that is bound */ + GPUBuiltin builtin; /* builtin uniform */ GPUOpenGLBuiltin oglbuiltin; /* opengl built in varying */ } GPUInput; @@ -167,6 +161,7 @@ struct GPUPass { struct GPUOutput *output; struct GPUShader *shader; char *fragmentcode; + char *geometrycode; char *vertexcode; const char *libcode; }; @@ -175,7 +170,8 @@ struct GPUPass { typedef struct GPUPass GPUPass; GPUPass *GPU_generate_pass(ListBase *nodes, struct GPUNodeLink *outlink, - struct GPUVertexAttribs *attribs, int *builtin, const char *name); + struct GPUVertexAttribs *attribs, int *builtin, + const GPUMatType type, const char *name, const bool use_opensubdiv); struct GPUShader *GPU_pass_shader(GPUPass *pass); @@ -185,8 +181,8 @@ void GPU_pass_unbind(GPUPass *pass); void GPU_pass_free(GPUPass *pass); -void GPU_codegen_init(void); -void GPU_codegen_exit(void); +void gpu_codegen_init(void); +void gpu_codegen_exit(void); /* Material calls */ diff --git a/source/blender/gpu/intern/gpu_compositing.c b/source/blender/gpu/intern/gpu_compositing.c new file mode 100644 index 00000000000..da5db73d382 --- /dev/null +++ b/source/blender/gpu/intern/gpu_compositing.c @@ -0,0 +1,1289 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2006 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Antony Riakiotakis. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/gpu/intern/gpu_compositing.c + * \ingroup gpu + * + * System that manages framebuffer compositing. + */ + +#include "BLI_sys_types.h" +#include "BLI_rect.h" +#include "BLI_math.h" +#include "BLI_listbase.h" +#include "BLI_linklist.h" + +#include "BLI_rand.h" +#include "BLI_listbase.h" + +#include "DNA_vec_types.h" +#include "DNA_view3d_types.h" +#include "DNA_scene_types.h" +#include "DNA_object_types.h" +#include "DNA_camera_types.h" +#include "DNA_gpu_types.h" + +#include "GPU_extensions.h" +#include "GPU_compositing.h" + +#include "GPU_glew.h" + +#include "MEM_guardedalloc.h" + +static const float fullscreencos[4][2] = {{-1.0f, -1.0f}, {1.0f, -1.0f}, {-1.0f, 1.0f}, {1.0f, 1.0f}}; +static const float fullscreenuvs[4][2] = {{0.0f, 0.0f}, {1.0f, 0.0f}, {0.0f, 1.0f}, {1.0f, 1.0f}}; + +struct GPUFX { + /* we borrow the term gbuffer from deferred rendering however this is just a regular + * depth/color framebuffer. Could be extended later though */ + GPUFrameBuffer *gbuffer; + + /* dimensions of the gbuffer */ + int gbuffer_dim[2]; + + /* texture bound to the first color attachment of the gbuffer */ + GPUTexture *color_buffer; + + /* second texture used for ping-pong compositing */ + GPUTexture *color_buffer_sec; + /* texture bound to the depth attachment of the gbuffer */ + GPUTexture *depth_buffer; + GPUTexture *depth_buffer_xray; + + /* texture used for jittering for various effects */ + GPUTexture *jitter_buffer; + + /* all those buffers below have to coexist. Fortunately they are all quarter sized (1/16th of memory) of original framebuffer */ + int dof_downsampled_w; + int dof_downsampled_h; + + /* texture used for near coc and color blurring calculation */ + GPUTexture *dof_near_coc_buffer; + /* blurred near coc buffer. */ + GPUTexture *dof_near_coc_blurred_buffer; + /* final near coc buffer. */ + GPUTexture *dof_near_coc_final_buffer; + + /* half size blur buffer */ + GPUTexture *dof_half_downsampled_near; + GPUTexture *dof_half_downsampled_far; + /* high quality dof texture downsamplers. 6 levels means 64 pixels wide - should be enough */ + GPUTexture *dof_nearfar_coc; + GPUTexture *dof_near_blur; + GPUTexture *dof_far_blur; + + /* for high quality we use again a spiral texture with radius adapted */ + bool dof_high_quality; + + /* texture used for ssao */ + int ssao_sample_count_cache; + GPUTexture *ssao_spiral_samples_tex; + + + GPUFXSettings settings; + + /* or-ed flags of enabled effects */ + int effects; + + /* number of passes, needed to detect if ping pong buffer allocation is needed */ + int num_passes; + + /* we have a stencil, restore the previous state */ + bool restore_stencil; + + unsigned int vbuffer; +}; + +#if 0 +/* concentric mapping, see "A Low Distortion Map Between Disk and Square" and + * http://psgraphics.blogspot.nl/2011/01/improved-code-for-concentric-map.html */ +static GPUTexture * create_concentric_sample_texture(int side) +{ + GPUTexture *tex; + float midpoint = 0.5f * (side - 1); + float *texels = (float *)MEM_mallocN(sizeof(float) * 2 * side * side, "concentric_tex"); + int i, j; + + for (i = 0; i < side; i++) { + for (j = 0; j < side; j++) { + int index = (i * side + j) * 2; + float a = 1.0f - i / midpoint; + float b = 1.0f - j / midpoint; + float phi, r; + if (a * a > b * b) { + r = a; + phi = (M_PI_4) * (b / a); + } + else { + r = b; + phi = M_PI_2 - (M_PI_4) * (a / b); + } + texels[index] = r * cos(phi); + texels[index + 1] = r * sin(phi); + } + } + + tex = GPU_texture_create_1D_procedural(side * side, texels, NULL); + MEM_freeN(texels); + return tex; +} +#endif + +static GPUTexture *create_spiral_sample_texture(int numsaples) +{ + GPUTexture *tex; + float (*texels)[2] = MEM_mallocN(sizeof(float[2]) * numsaples, "concentric_tex"); + const float numsaples_inv = 1.0f / numsaples; + int i; + /* arbitrary number to ensure we don't get conciding samples every circle */ + const float spirals = 7.357; + + for (i = 0; i < numsaples; i++) { + float r = (i + 0.5f) * numsaples_inv; + float phi = r * spirals * (float)(2.0 * M_PI); + texels[i][0] = r * cosf(phi); + texels[i][1] = r * sinf(phi); + } + + tex = GPU_texture_create_1D_procedural(numsaples, (float *)texels, NULL); + MEM_freeN(texels); + return tex; +} + +/* generate a new FX compositor */ +GPUFX *GPU_fx_compositor_create(void) +{ + GPUFX *fx = MEM_callocN(sizeof(GPUFX), "GPUFX compositor"); + + if (GLEW_ARB_vertex_buffer_object) { + glGenBuffersARB(1, &fx->vbuffer); + glBindBufferARB(GL_ARRAY_BUFFER_ARB, fx->vbuffer); + glBufferDataARB(GL_ARRAY_BUFFER_ARB, 16 * sizeof(float), NULL, GL_STATIC_DRAW); + glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, 0, 8 * sizeof(float), fullscreencos); + glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, 8 * sizeof(float), 8 * sizeof(float), fullscreenuvs); + glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0); + } + return fx; +} + +static void cleanup_fx_dof_buffers(GPUFX *fx) +{ + if (fx->dof_near_coc_blurred_buffer) { + GPU_texture_free(fx->dof_near_coc_blurred_buffer); + fx->dof_near_coc_blurred_buffer = NULL; + } + if (fx->dof_near_coc_buffer) { + GPU_texture_free(fx->dof_near_coc_buffer); + fx->dof_near_coc_buffer = NULL; + } + if (fx->dof_near_coc_final_buffer) { + GPU_texture_free(fx->dof_near_coc_final_buffer); + fx->dof_near_coc_final_buffer = NULL; + } + + if (fx->dof_half_downsampled_near) { + GPU_texture_free(fx->dof_half_downsampled_near); + fx->dof_half_downsampled_near = NULL; + } + if (fx->dof_half_downsampled_far) { + GPU_texture_free(fx->dof_half_downsampled_far); + fx->dof_half_downsampled_far = NULL; + } + if (fx->dof_nearfar_coc) { + GPU_texture_free(fx->dof_nearfar_coc); + fx->dof_nearfar_coc = NULL; + } + if (fx->dof_near_blur) { + GPU_texture_free(fx->dof_near_blur); + fx->dof_near_blur = NULL; + } + if (fx->dof_far_blur) { + GPU_texture_free(fx->dof_far_blur); + fx->dof_far_blur = NULL; + } +} + +static void cleanup_fx_gl_data(GPUFX *fx, bool do_fbo) +{ + if (fx->color_buffer) { + GPU_framebuffer_texture_detach(fx->color_buffer); + GPU_texture_free(fx->color_buffer); + fx->color_buffer = NULL; + } + + if (fx->color_buffer_sec) { + GPU_framebuffer_texture_detach(fx->color_buffer_sec); + GPU_texture_free(fx->color_buffer_sec); + fx->color_buffer_sec = NULL; + } + + if (fx->depth_buffer) { + GPU_framebuffer_texture_detach(fx->depth_buffer); + GPU_texture_free(fx->depth_buffer); + fx->depth_buffer = NULL; + } + + if (fx->depth_buffer_xray) { + GPU_framebuffer_texture_detach(fx->depth_buffer_xray); + GPU_texture_free(fx->depth_buffer_xray); + fx->depth_buffer_xray = NULL; + } + + cleanup_fx_dof_buffers(fx); + + if (fx->ssao_spiral_samples_tex) { + GPU_texture_free(fx->ssao_spiral_samples_tex); + fx->ssao_spiral_samples_tex = NULL; + } + + if (fx->jitter_buffer && do_fbo) { + GPU_texture_free(fx->jitter_buffer); + fx->jitter_buffer = NULL; + } + + if (fx->gbuffer && do_fbo) { + GPU_framebuffer_free(fx->gbuffer); + fx->gbuffer = NULL; + } +} + +/* destroy a text compositor */ +void GPU_fx_compositor_destroy(GPUFX *fx) +{ + cleanup_fx_gl_data(fx, true); + if (GLEW_ARB_vertex_buffer_object) + glDeleteBuffersARB(1, &fx->vbuffer); + MEM_freeN(fx); +} + +static GPUTexture * create_jitter_texture(void) +{ + float jitter [64 * 64][2]; + int i; + + for (i = 0; i < 64 * 64; i++) { + jitter[i][0] = 2.0f * BLI_frand() - 1.0f; + jitter[i][1] = 2.0f * BLI_frand() - 1.0f; + normalize_v2(jitter[i]); + } + + return GPU_texture_create_2D_procedural(64, 64, &jitter[0][0], true, NULL); +} + + +bool GPU_fx_compositor_initialize_passes( + GPUFX *fx, const rcti *rect, const rcti *scissor_rect, + const GPUFXSettings *fx_settings) +{ + int w = BLI_rcti_size_x(rect), h = BLI_rcti_size_y(rect); + char err_out[256]; + int num_passes = 0; + char fx_flag; + + fx->effects = 0; + + if (!GPU_non_power_of_two_support() || !GLEW_EXT_framebuffer_object || !GLEW_ARB_fragment_shader) + return false; + + if (!fx_settings) { + cleanup_fx_gl_data(fx, true); + return false; + } + + fx_flag = fx_settings->fx_flag; + + /* disable effects if no options passed for them */ + if (!fx_settings->dof) { + fx_flag &= ~GPU_FX_FLAG_DOF; + } + if (!fx_settings->ssao || fx_settings->ssao->samples < 1) { + fx_flag &= ~GPU_FX_FLAG_SSAO; + } + + if (!fx_flag) { + cleanup_fx_gl_data(fx, true); + return false; + } + + /* scissor is missing when drawing offscreen, in that case, dimensions match exactly. In opposite case + * add one to match viewport dimensions */ + if (scissor_rect) { + w++, h++; + } + + fx->num_passes = 0; + /* dof really needs a ping-pong buffer to work */ + if (fx_flag & GPU_FX_FLAG_DOF) + num_passes++; + + if (fx_flag & GPU_FX_FLAG_SSAO) + num_passes++; + + if (!fx->gbuffer) { + fx->gbuffer = GPU_framebuffer_create(); + + if (!fx->gbuffer) { + return false; + } + } + + /* try creating the jitter texture */ + if (!fx->jitter_buffer) + fx->jitter_buffer = create_jitter_texture(); + + /* check if color buffers need recreation */ + if (!fx->color_buffer || !fx->depth_buffer || w != fx->gbuffer_dim[0] || h != fx->gbuffer_dim[1]) { + cleanup_fx_gl_data(fx, false); + + if (!(fx->color_buffer = GPU_texture_create_2D(w, h, NULL, GPU_HDR_NONE, err_out))) { + printf(".256%s\n", err_out); + cleanup_fx_gl_data(fx, true); + return false; + } + + if (!(fx->depth_buffer = GPU_texture_create_depth(w, h, err_out))) { + printf("%.256s\n", err_out); + cleanup_fx_gl_data(fx, true); + return false; + } + } + + if (fx_flag & GPU_FX_FLAG_SSAO) { + if (fx_settings->ssao->samples != fx->ssao_sample_count_cache || !fx->ssao_spiral_samples_tex) { + if (fx_settings->ssao->samples < 1) + fx_settings->ssao->samples = 1; + + fx->ssao_sample_count_cache = fx_settings->ssao->samples; + + if (fx->ssao_spiral_samples_tex) { + GPU_texture_free(fx->ssao_spiral_samples_tex); + } + + fx->ssao_spiral_samples_tex = create_spiral_sample_texture(fx_settings->ssao->samples); + } + } + else { + if (fx->ssao_spiral_samples_tex) { + GPU_texture_free(fx->ssao_spiral_samples_tex); + fx->ssao_spiral_samples_tex = NULL; + } + } + + /* create textures for dof effect */ + if (fx_flag & GPU_FX_FLAG_DOF) { + bool dof_high_quality = (fx_settings->dof->high_quality != 0) && + GPU_geometry_shader_support() && GPU_instanced_drawing_support(); + + /* cleanup buffers if quality setting has changed (no need to keep more buffers around than necessary ) */ + if (dof_high_quality != fx->dof_high_quality) + cleanup_fx_dof_buffers(fx); + + if (dof_high_quality) { + fx->dof_downsampled_w = w / 2; + fx->dof_downsampled_h = h / 2; + + if (!fx->dof_half_downsampled_near || !fx->dof_nearfar_coc || !fx->dof_near_blur || + !fx->dof_far_blur || !fx->dof_half_downsampled_far) { + + if (!(fx->dof_half_downsampled_near = GPU_texture_create_2D( + fx->dof_downsampled_w, fx->dof_downsampled_h, NULL, GPU_HDR_NONE, err_out))) + { + printf("%.256s\n", err_out); + cleanup_fx_gl_data(fx, true); + return false; + } + if (!(fx->dof_half_downsampled_far = GPU_texture_create_2D( + fx->dof_downsampled_w, fx->dof_downsampled_h, NULL, GPU_HDR_NONE, err_out))) + { + printf("%.256s\n", err_out); + cleanup_fx_gl_data(fx, true); + return false; + } + if (!(fx->dof_nearfar_coc = GPU_texture_create_2D_procedural( + fx->dof_downsampled_w, fx->dof_downsampled_h, NULL, false, err_out))) + { + printf("%.256s\n", err_out); + cleanup_fx_gl_data(fx, true); + return false; + } + + + if (!(fx->dof_near_blur = GPU_texture_create_2D( + fx->dof_downsampled_w, fx->dof_downsampled_h, NULL, GPU_HDR_HALF_FLOAT, err_out))) + { + printf("%.256s\n", err_out); + cleanup_fx_gl_data(fx, true); + return false; + } + + if (!(fx->dof_far_blur = GPU_texture_create_2D( + fx->dof_downsampled_w, fx->dof_downsampled_h, NULL, GPU_HDR_HALF_FLOAT, err_out))) + { + printf("%.256s\n", err_out); + cleanup_fx_gl_data(fx, true); + return false; + } + } + } + else { + fx->dof_downsampled_w = w / 4; + fx->dof_downsampled_h = h / 4; + + if (!fx->dof_near_coc_buffer || !fx->dof_near_coc_blurred_buffer || !fx->dof_near_coc_final_buffer) { + + if (!(fx->dof_near_coc_buffer = GPU_texture_create_2D( + fx->dof_downsampled_w, fx->dof_downsampled_h, NULL, GPU_HDR_NONE, err_out))) + { + printf("%.256s\n", err_out); + cleanup_fx_gl_data(fx, true); + return false; + } + if (!(fx->dof_near_coc_blurred_buffer = GPU_texture_create_2D( + fx->dof_downsampled_w, fx->dof_downsampled_h, NULL, GPU_HDR_NONE, err_out))) + { + printf("%.256s\n", err_out); + cleanup_fx_gl_data(fx, true); + return false; + } + if (!(fx->dof_near_coc_final_buffer = GPU_texture_create_2D( + fx->dof_downsampled_w, fx->dof_downsampled_h, NULL, GPU_HDR_NONE, err_out))) + { + printf("%.256s\n", err_out); + cleanup_fx_gl_data(fx, true); + return false; + } + } + } + + fx->dof_high_quality = dof_high_quality; + } + else { + /* cleanup unnecessary buffers */ + cleanup_fx_dof_buffers(fx); + } + + /* we need to pass data between shader stages, allocate an extra color buffer */ + if (num_passes > 1) { + if (!fx->color_buffer_sec) { + if (!(fx->color_buffer_sec = GPU_texture_create_2D(w, h, NULL, GPU_HDR_NONE, err_out))) { + printf(".256%s\n", err_out); + cleanup_fx_gl_data(fx, true); + return false; + } + } + } + else { + if (fx->color_buffer_sec) { + GPU_framebuffer_texture_detach(fx->color_buffer_sec); + GPU_texture_free(fx->color_buffer_sec); + fx->color_buffer_sec = NULL; + } + } + + /* bind the buffers */ + + /* first depth buffer, because system assumes read/write buffers */ + if (!GPU_framebuffer_texture_attach(fx->gbuffer, fx->depth_buffer, 0, err_out)) + printf("%.256s\n", err_out); + + if (!GPU_framebuffer_texture_attach(fx->gbuffer, fx->color_buffer, 0, err_out)) + printf("%.256s\n", err_out); + + if (!GPU_framebuffer_check_valid(fx->gbuffer, err_out)) + printf("%.256s\n", err_out); + + GPU_texture_bind_as_framebuffer(fx->color_buffer); + + /* enable scissor test. It's needed to ensure sculpting works correctly */ + if (scissor_rect) { + int w_sc = BLI_rcti_size_x(scissor_rect) + 1; + int h_sc = BLI_rcti_size_y(scissor_rect) + 1; + glPushAttrib(GL_SCISSOR_BIT); + glEnable(GL_SCISSOR_TEST); + glScissor(scissor_rect->xmin - rect->xmin, scissor_rect->ymin - rect->ymin, + w_sc, h_sc); + fx->restore_stencil = true; + } + else { + fx->restore_stencil = false; + } + + fx->effects = fx_flag; + + if (fx_settings) + fx->settings = *fx_settings; + fx->gbuffer_dim[0] = w; + fx->gbuffer_dim[1] = h; + + fx->num_passes = num_passes; + + return true; +} + +static void gpu_fx_bind_render_target(int *passes_left, GPUFX *fx, struct GPUOffScreen *ofs, GPUTexture *target) +{ + if ((*passes_left)-- == 1) { + GPU_framebuffer_texture_unbind(fx->gbuffer, NULL); + if (ofs) { + GPU_offscreen_bind(ofs, false); + } + else + GPU_framebuffer_restore(); + } + else { + /* bind the ping buffer to the color buffer */ + GPU_framebuffer_texture_attach(fx->gbuffer, target, 0, NULL); + } +} + +void GPU_fx_compositor_setup_XRay_pass(GPUFX *fx, bool do_xray) +{ + char err_out[256]; + + if (do_xray) { + if (!fx->depth_buffer_xray && !(fx->depth_buffer_xray = GPU_texture_create_depth(fx->gbuffer_dim[0], fx->gbuffer_dim[1], err_out))) { + printf("%.256s\n", err_out); + cleanup_fx_gl_data(fx, true); + return; + } + } + else { + if (fx->depth_buffer_xray) { + GPU_framebuffer_texture_detach(fx->depth_buffer_xray); + GPU_texture_free(fx->depth_buffer_xray); + fx->depth_buffer_xray = NULL; + } + return; + } + + GPU_framebuffer_texture_detach(fx->depth_buffer); + + /* first depth buffer, because system assumes read/write buffers */ + if (!GPU_framebuffer_texture_attach(fx->gbuffer, fx->depth_buffer_xray, 0, err_out)) + printf("%.256s\n", err_out); +} + + +void GPU_fx_compositor_XRay_resolve(GPUFX *fx) +{ + GPUShader *depth_resolve_shader; + GPU_framebuffer_texture_detach(fx->depth_buffer_xray); + + /* attach regular framebuffer */ + GPU_framebuffer_texture_attach(fx->gbuffer, fx->depth_buffer, 0, NULL); + + /* full screen quad where we will always write to depth buffer */ + glPushAttrib(GL_DEPTH_BUFFER_BIT | GL_SCISSOR_BIT); + glDepthFunc(GL_ALWAYS); + /* disable scissor from sculpt if any */ + glDisable(GL_SCISSOR_TEST); + /* disable writing to color buffer, it's depth only pass */ + glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); + + /* set up quad buffer */ + glBindBufferARB(GL_ARRAY_BUFFER_ARB, 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) { + int depth_uniform; + + depth_uniform = GPU_shader_get_uniform(depth_resolve_shader, "depthbuffer"); + + GPU_shader_bind(depth_resolve_shader); + + GPU_texture_bind(fx->depth_buffer_xray, 0); + GPU_texture_filter_mode(fx->depth_buffer_xray, false, true); + GPU_shader_uniform_texture(depth_resolve_shader, depth_uniform, fx->depth_buffer_xray); + + /* draw */ + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + + /* disable bindings */ + GPU_texture_filter_mode(fx->depth_buffer_xray, true, false); + GPU_texture_unbind(fx->depth_buffer_xray); + + GPU_shader_unbind(); + } + + glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); + + glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0); + glDisableClientState(GL_VERTEX_ARRAY); + glDisableClientState(GL_TEXTURE_COORD_ARRAY); + + glPopAttrib(); +} + + +bool GPU_fx_do_composite_pass(GPUFX *fx, float projmat[4][4], bool is_persp, struct Scene *scene, struct GPUOffScreen *ofs) +{ + GPUTexture *src, *target; + int numslots = 0; + float invproj[4][4]; + int i; + float dfdyfac[2]; + /* number of passes left. when there are no more passes, the result is passed to the frambuffer */ + int passes_left = fx->num_passes; + /* view vectors for the corners of the view frustum. Can be used to recreate the world space position easily */ + float viewvecs[3][4] = { + {-1.0f, -1.0f, -1.0f, 1.0f}, + {1.0f, -1.0f, -1.0f, 1.0f}, + {-1.0f, 1.0f, -1.0f, 1.0f} + }; + + if (fx->effects == 0) + return false; + + GPU_get_dfdy_factors(dfdyfac); + /* first, unbind the render-to-texture framebuffer */ + GPU_framebuffer_texture_detach(fx->color_buffer); + GPU_framebuffer_texture_detach(fx->depth_buffer); + + if (fx->restore_stencil) + glPopAttrib(); + + src = fx->color_buffer; + target = fx->color_buffer_sec; + + /* set up quad buffer */ + glBindBufferARB(GL_ARRAY_BUFFER_ARB, fx->vbuffer); + glVertexPointer(2, GL_FLOAT, 0, NULL); + glTexCoordPointer(2, GL_FLOAT, 0, ((GLubyte *)NULL + 8 * sizeof(float))); + glEnableClientState(GL_VERTEX_ARRAY); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + + /* full screen FX pass */ + + /* invert the view matrix */ + invert_m4_m4(invproj, projmat); + + /* convert the view vectors to view space */ + for (i = 0; i < 3; i++) { + mul_m4_v4(invproj, viewvecs[i]); + /* normalized trick see http://www.derschmale.com/2014/01/26/reconstructing-positions-from-the-depth-buffer */ + mul_v3_fl(viewvecs[i], 1.0f / viewvecs[i][3]); + if (is_persp) + mul_v3_fl(viewvecs[i], 1.0f / viewvecs[i][2]); + viewvecs[i][3] = 1.0; + } + + /* we need to store the differences */ + viewvecs[1][0] -= viewvecs[0][0]; + viewvecs[1][1] = viewvecs[2][1] - viewvecs[0][1]; + + /* calculate a depth offset as well */ + if (!is_persp) { + float vec_far[] = {-1.0f, -1.0f, 1.0f, 1.0f}; + mul_m4_v4(invproj, vec_far); + mul_v3_fl(vec_far, 1.0f / vec_far[3]); + viewvecs[1][2] = vec_far[2] - viewvecs[0][2]; + } + + /* set invalid color in case shader fails */ + glColor3f(1.0, 0.0, 1.0); + glDisable(GL_DEPTH_TEST); + + /* ssao pass */ + if (fx->effects & GPU_FX_FLAG_SSAO) { + GPUShader *ssao_shader; + ssao_shader = GPU_shader_get_builtin_fx_shader(GPU_SHADER_FX_SSAO, is_persp); + if (ssao_shader) { + const GPUSSAOSettings *fx_ssao = fx->settings.ssao; + int color_uniform, depth_uniform; + int ssao_uniform, ssao_color_uniform, viewvecs_uniform, ssao_sample_params_uniform; + int ssao_jitter_uniform, ssao_concentric_tex; + float ssao_params[4] = {fx_ssao->distance_max, fx_ssao->factor, fx_ssao->attenuation, 0.0f}; + float sample_params[3]; + + sample_params[0] = fx->ssao_sample_count_cache; + /* multiplier so we tile the random texture on screen */ + sample_params[1] = fx->gbuffer_dim[0] / 64.0; + sample_params[2] = fx->gbuffer_dim[1] / 64.0; + + ssao_params[3] = (passes_left == 1 && !ofs) ? dfdyfac[0] : dfdyfac[1]; + + ssao_uniform = GPU_shader_get_uniform(ssao_shader, "ssao_params"); + ssao_color_uniform = GPU_shader_get_uniform(ssao_shader, "ssao_color"); + color_uniform = GPU_shader_get_uniform(ssao_shader, "colorbuffer"); + depth_uniform = GPU_shader_get_uniform(ssao_shader, "depthbuffer"); + viewvecs_uniform = GPU_shader_get_uniform(ssao_shader, "viewvecs"); + ssao_sample_params_uniform = GPU_shader_get_uniform(ssao_shader, "ssao_sample_params"); + ssao_concentric_tex = GPU_shader_get_uniform(ssao_shader, "ssao_concentric_tex"); + ssao_jitter_uniform = GPU_shader_get_uniform(ssao_shader, "jitter_tex"); + + GPU_shader_bind(ssao_shader); + + GPU_shader_uniform_vector(ssao_shader, ssao_uniform, 4, 1, ssao_params); + GPU_shader_uniform_vector(ssao_shader, ssao_color_uniform, 4, 1, fx_ssao->color); + GPU_shader_uniform_vector(ssao_shader, viewvecs_uniform, 4, 3, viewvecs[0]); + GPU_shader_uniform_vector(ssao_shader, ssao_sample_params_uniform, 3, 1, sample_params); + + GPU_texture_bind(src, numslots++); + GPU_shader_uniform_texture(ssao_shader, color_uniform, src); + + GPU_texture_bind(fx->depth_buffer, numslots++); + GPU_texture_filter_mode(fx->depth_buffer, false, true); + GPU_shader_uniform_texture(ssao_shader, depth_uniform, fx->depth_buffer); + + GPU_texture_bind(fx->jitter_buffer, numslots++); + GPU_shader_uniform_texture(ssao_shader, ssao_jitter_uniform, fx->jitter_buffer); + + GPU_texture_bind(fx->ssao_spiral_samples_tex, numslots++); + GPU_shader_uniform_texture(ssao_shader, ssao_concentric_tex, fx->ssao_spiral_samples_tex); + + /* draw */ + gpu_fx_bind_render_target(&passes_left, fx, ofs, target); + + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + + /* disable bindings */ + GPU_texture_unbind(src); + GPU_texture_filter_mode(fx->depth_buffer, true, false); + GPU_texture_unbind(fx->depth_buffer); + GPU_texture_unbind(fx->jitter_buffer); + GPU_texture_unbind(fx->ssao_spiral_samples_tex); + + /* may not be attached, in that case this just returns */ + if (target) { + GPU_framebuffer_texture_detach(target); + if (ofs) { + GPU_offscreen_bind(ofs, false); + } + else { + GPU_framebuffer_restore(); + } + } + + /* swap here, after src/target have been unbound */ + SWAP(GPUTexture *, target, src); + numslots = 0; + } + } + + /* second pass, dof */ + if (fx->effects & GPU_FX_FLAG_DOF) { + const GPUDOFSettings *fx_dof = fx->settings.dof; + float dof_params[4]; + float scale = scene->unit.system ? scene->unit.scale_length : 1.0f; + /* this is factor that converts to the scene scale. focal length and sensor are expressed in mm + * unit.scale_length is how many meters per blender unit we have. We want to convert to blender units though + * because the shader reads coordinates in world space, which is in blender units. */ + float scale_camera = 0.001f / scale; + /* we want radius here for the aperture number */ + float aperture = 0.5f * scale_camera * fx_dof->focal_length / fx_dof->fstop; + + dof_params[0] = aperture * fabsf(scale_camera * fx_dof->focal_length / ((fx_dof->focus_distance / scale) - scale_camera * fx_dof->focal_length)); + dof_params[1] = fx_dof->focus_distance / scale; + dof_params[2] = fx->gbuffer_dim[0] / (scale_camera * fx_dof->sensor); + dof_params[3] = fx_dof->num_blades; + + if (fx->dof_high_quality) { + GPUShader *dof_shader_pass1, *dof_shader_pass2, *dof_shader_pass3; + + /* custom shaders close to the effect described in CryEngine 3 Graphics Gems */ + dof_shader_pass1 = GPU_shader_get_builtin_fx_shader(GPU_SHADER_FX_DEPTH_OF_FIELD_HQ_PASS_ONE, is_persp); + dof_shader_pass2 = GPU_shader_get_builtin_fx_shader(GPU_SHADER_FX_DEPTH_OF_FIELD_HQ_PASS_TWO, is_persp); + dof_shader_pass3 = GPU_shader_get_builtin_fx_shader(GPU_SHADER_FX_DEPTH_OF_FIELD_HQ_PASS_THREE, is_persp); + + /* error occured, restore framebuffers and return */ + if (!(dof_shader_pass1 && dof_shader_pass2 && dof_shader_pass3)) { + GPU_framebuffer_texture_unbind(fx->gbuffer, NULL); + GPU_framebuffer_restore(); + glDisableClientState(GL_VERTEX_ARRAY); + glDisableClientState(GL_TEXTURE_COORD_ARRAY); + + GPU_shader_unbind(); + glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0); + return false; + } + + /* pass first, downsample the color buffer to near/far targets and calculate coc texture */ + { + int depth_uniform, dof_uniform; + int viewvecs_uniform; + int invrendertargetdim_uniform, color_uniform; + + float invrendertargetdim[2] = {1.0f / fx->dof_downsampled_w, 1.0f / fx->dof_downsampled_h}; + + invrendertargetdim_uniform = GPU_shader_get_uniform(dof_shader_pass1, "invrendertargetdim"); + color_uniform = GPU_shader_get_uniform(dof_shader_pass1, "colorbuffer"); + dof_uniform = GPU_shader_get_uniform(dof_shader_pass1, "dof_params"); + invrendertargetdim_uniform = GPU_shader_get_uniform(dof_shader_pass1, "invrendertargetdim"); + depth_uniform = GPU_shader_get_uniform(dof_shader_pass1, "depthbuffer"); + viewvecs_uniform = GPU_shader_get_uniform(dof_shader_pass1, "viewvecs"); + + GPU_shader_bind(dof_shader_pass1); + + GPU_shader_uniform_vector(dof_shader_pass1, dof_uniform, 4, 1, dof_params); + GPU_shader_uniform_vector(dof_shader_pass1, invrendertargetdim_uniform, 2, 1, invrendertargetdim); + GPU_shader_uniform_vector(dof_shader_pass1, viewvecs_uniform, 4, 3, viewvecs[0]); + + GPU_shader_uniform_vector(dof_shader_pass1, invrendertargetdim_uniform, 2, 1, invrendertargetdim); + + GPU_texture_bind(fx->depth_buffer, numslots++); + GPU_texture_filter_mode(fx->depth_buffer, false, false); + GPU_shader_uniform_texture(dof_shader_pass1, depth_uniform, fx->depth_buffer); + + GPU_texture_bind(src, numslots++); + /* disable filtering for the texture so custom downsample can do the right thing */ + GPU_texture_filter_mode(src, false, false); + GPU_shader_uniform_texture(dof_shader_pass2, color_uniform, src); + + /* target is the downsampled coc buffer */ + GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_half_downsampled_near, 0, NULL); + GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_half_downsampled_far, 1, NULL); + GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_nearfar_coc, 2, NULL); + /* binding takes care of setting the viewport to the downsampled size */ + GPU_framebuffer_slots_bind(fx->gbuffer, 0); + + GPU_framebuffer_check_valid(fx->gbuffer, NULL); + + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + /* disable bindings */ + GPU_texture_filter_mode(src, false, true); + GPU_texture_unbind(src); + GPU_texture_filter_mode(fx->depth_buffer, true, false); + GPU_texture_unbind(fx->depth_buffer); + + GPU_framebuffer_texture_detach(fx->dof_half_downsampled_near); + GPU_framebuffer_texture_detach(fx->dof_half_downsampled_far); + GPU_framebuffer_texture_detach(fx->dof_nearfar_coc); + GPU_framebuffer_texture_unbind(fx->gbuffer, fx->dof_half_downsampled_near); + + numslots = 0; + } + + /* second pass, shoot quads for every pixel in the downsampled buffers, scaling according + * to circle of confusion */ + { + int rendertargetdim_uniform, coc_uniform, color_uniform, select_uniform, dof_uniform; + int rendertargetdim[2] = {fx->dof_downsampled_w, fx->dof_downsampled_h}; + float selection[2] = {0.0f, 1.0f}; + + rendertargetdim_uniform = GPU_shader_get_uniform(dof_shader_pass2, "rendertargetdim"); + + color_uniform = GPU_shader_get_uniform(dof_shader_pass2, "colorbuffer"); + coc_uniform = GPU_shader_get_uniform(dof_shader_pass2, "cocbuffer"); + select_uniform = GPU_shader_get_uniform(dof_shader_pass2, "layerselection"); + dof_uniform = GPU_shader_get_uniform(dof_shader_pass2, "dof_params"); + + GPU_shader_bind(dof_shader_pass2); + + GPU_shader_uniform_vector(dof_shader_pass2, dof_uniform, 4, 1, dof_params); + GPU_shader_uniform_vector_int(dof_shader_pass2, rendertargetdim_uniform, 2, 1, rendertargetdim); + GPU_shader_uniform_vector(dof_shader_pass2, select_uniform, 2, 1, selection); + + GPU_texture_bind(fx->dof_nearfar_coc, numslots++); + GPU_shader_uniform_texture(dof_shader_pass2, 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, color_uniform, fx->dof_half_downsampled_far); + GPU_texture_filter_mode(fx->dof_half_downsampled_far, false, false); + + /* target is the downsampled coc buffer */ + GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_far_blur, 0, NULL); + GPU_texture_bind_as_framebuffer(fx->dof_far_blur); + + glDisable(GL_DEPTH_TEST); + glEnable(GL_BLEND); + glBlendFunc(GL_ONE, GL_ONE); + /* have to clear the buffer unfortunately */ + glClearColor(0.0, 0.0, 0.0, 0.0); + glClear(GL_COLOR_BUFFER_BIT); + /* the draw call we all waited for, draw a point per pixel, scaled per circle of confusion */ + glDrawArraysInstancedARB(GL_POINTS, 0, 1, fx->dof_downsampled_w * fx->dof_downsampled_h); + + GPU_texture_unbind(fx->dof_half_downsampled_far); + GPU_framebuffer_texture_detach(fx->dof_far_blur); + + GPU_shader_uniform_texture(dof_shader_pass2, 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, select_uniform, 2, 1, selection); + + GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_near_blur, 0, NULL); + /* have to clear the buffer unfortunately */ + glClear(GL_COLOR_BUFFER_BIT); + /* the draw call we all waited for, draw a point per pixel, scaled per circle of confusion */ + glDrawArraysInstancedARB(GL_POINTS, 0, 1, fx->dof_downsampled_w * fx->dof_downsampled_h); + + /* disable bindings */ + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glDisable(GL_BLEND); + + GPU_framebuffer_texture_detach(fx->dof_near_blur); + + GPU_texture_unbind(fx->dof_half_downsampled_near); + GPU_texture_unbind(fx->dof_nearfar_coc); + + GPU_framebuffer_texture_unbind(fx->gbuffer, fx->dof_far_blur); + } + + /* third pass, accumulate the near/far blur fields */ + { + int invrendertargetdim_uniform, near_uniform, color_uniform; + int dof_uniform, far_uniform, viewvecs_uniform, depth_uniform; + + float invrendertargetdim[2] = {1.0f / fx->dof_downsampled_w, 1.0f / fx->dof_downsampled_h}; + + dof_uniform = GPU_shader_get_uniform(dof_shader_pass3, "dof_params"); + invrendertargetdim_uniform = GPU_shader_get_uniform(dof_shader_pass3, "invrendertargetdim"); + color_uniform = GPU_shader_get_uniform(dof_shader_pass3, "colorbuffer"); + far_uniform = GPU_shader_get_uniform(dof_shader_pass3, "farbuffer"); + near_uniform = GPU_shader_get_uniform(dof_shader_pass3, "nearbuffer"); + viewvecs_uniform = GPU_shader_get_uniform(dof_shader_pass3, "viewvecs"); + depth_uniform = GPU_shader_get_uniform(dof_shader_pass3, "depthbuffer"); + + GPU_shader_bind(dof_shader_pass3); + + GPU_shader_uniform_vector(dof_shader_pass3, dof_uniform, 4, 1, dof_params); + + GPU_shader_uniform_vector(dof_shader_pass3, invrendertargetdim_uniform, 2, 1, invrendertargetdim); + GPU_shader_uniform_vector(dof_shader_pass3, viewvecs_uniform, 4, 3, viewvecs[0]); + + GPU_texture_bind(fx->dof_near_blur, numslots++); + GPU_shader_uniform_texture(dof_shader_pass3, near_uniform, fx->dof_near_blur); + GPU_texture_filter_mode(fx->dof_near_blur, false, true); + + GPU_texture_bind(fx->dof_far_blur, numslots++); + GPU_shader_uniform_texture(dof_shader_pass3, far_uniform, fx->dof_far_blur); + GPU_texture_filter_mode(fx->dof_far_blur, false, true); + + GPU_texture_bind(fx->depth_buffer, numslots++); + GPU_texture_filter_mode(fx->depth_buffer, false, false); + GPU_shader_uniform_texture(dof_shader_pass3, depth_uniform, fx->depth_buffer); + + GPU_texture_bind(src, numslots++); + GPU_shader_uniform_texture(dof_shader_pass3, color_uniform, src); + + /* if this is the last pass, prepare for rendering on the frambuffer */ + gpu_fx_bind_render_target(&passes_left, fx, ofs, target); + + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + + /* disable bindings */ + GPU_texture_unbind(fx->dof_near_blur); + GPU_texture_unbind(fx->dof_far_blur); + GPU_texture_unbind(src); + GPU_texture_filter_mode(fx->depth_buffer, true, false); + GPU_texture_unbind(fx->depth_buffer); + + /* may not be attached, in that case this just returns */ + if (target) { + GPU_framebuffer_texture_detach(target); + if (ofs) { + GPU_offscreen_bind(ofs, false); + } + else { + GPU_framebuffer_restore(); + } + } + + numslots = 0; + } + } + else { + GPUShader *dof_shader_pass1, *dof_shader_pass2, *dof_shader_pass3, *dof_shader_pass4, *dof_shader_pass5; + + /* DOF effect has many passes but most of them are performed on a texture whose dimensions are 4 times less than the original + * (16 times lower than original screen resolution). Technique used is not very exact but should be fast enough and is based + * on "Practical Post-Process Depth of Field" see http://http.developer.nvidia.com/GPUGems3/gpugems3_ch28.html */ + dof_shader_pass1 = GPU_shader_get_builtin_fx_shader(GPU_SHADER_FX_DEPTH_OF_FIELD_PASS_ONE, is_persp); + dof_shader_pass2 = GPU_shader_get_builtin_fx_shader(GPU_SHADER_FX_DEPTH_OF_FIELD_PASS_TWO, is_persp); + dof_shader_pass3 = GPU_shader_get_builtin_fx_shader(GPU_SHADER_FX_DEPTH_OF_FIELD_PASS_THREE, is_persp); + dof_shader_pass4 = GPU_shader_get_builtin_fx_shader(GPU_SHADER_FX_DEPTH_OF_FIELD_PASS_FOUR, is_persp); + dof_shader_pass5 = GPU_shader_get_builtin_fx_shader(GPU_SHADER_FX_DEPTH_OF_FIELD_PASS_FIVE, is_persp); + + /* error occured, restore framebuffers and return */ + if (!(dof_shader_pass1 && dof_shader_pass2 && dof_shader_pass3 && dof_shader_pass4 && dof_shader_pass5)) { + GPU_framebuffer_texture_unbind(fx->gbuffer, NULL); + GPU_framebuffer_restore(); + glDisableClientState(GL_VERTEX_ARRAY); + glDisableClientState(GL_TEXTURE_COORD_ARRAY); + + GPU_shader_unbind(); + glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0); + return false; + } + + /* pass first, first level of blur in low res buffer */ + { + int invrendertargetdim_uniform, color_uniform, depth_uniform, dof_uniform; + int viewvecs_uniform; + + float invrendertargetdim[2] = {1.0f / fx->gbuffer_dim[0], 1.0f / fx->gbuffer_dim[1]}; + + dof_uniform = GPU_shader_get_uniform(dof_shader_pass1, "dof_params"); + invrendertargetdim_uniform = GPU_shader_get_uniform(dof_shader_pass1, "invrendertargetdim"); + color_uniform = GPU_shader_get_uniform(dof_shader_pass1, "colorbuffer"); + depth_uniform = GPU_shader_get_uniform(dof_shader_pass1, "depthbuffer"); + viewvecs_uniform = GPU_shader_get_uniform(dof_shader_pass1, "viewvecs"); + + GPU_shader_bind(dof_shader_pass1); + + GPU_shader_uniform_vector(dof_shader_pass1, dof_uniform, 4, 1, dof_params); + GPU_shader_uniform_vector(dof_shader_pass1, invrendertargetdim_uniform, 2, 1, invrendertargetdim); + GPU_shader_uniform_vector(dof_shader_pass1, viewvecs_uniform, 4, 3, viewvecs[0]); + + GPU_texture_bind(src, numslots++); + GPU_shader_uniform_texture(dof_shader_pass1, color_uniform, src); + + GPU_texture_bind(fx->depth_buffer, numslots++); + GPU_texture_filter_mode(fx->depth_buffer, false, true); + GPU_shader_uniform_texture(dof_shader_pass1, depth_uniform, fx->depth_buffer); + + /* target is the downsampled coc buffer */ + GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_near_coc_buffer, 0, NULL); + /* binding takes care of setting the viewport to the downsampled size */ + GPU_texture_bind_as_framebuffer(fx->dof_near_coc_buffer); + + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + /* disable bindings */ + GPU_texture_unbind(src); + GPU_texture_filter_mode(fx->depth_buffer, true, false); + GPU_texture_unbind(fx->depth_buffer); + + GPU_framebuffer_texture_detach(fx->dof_near_coc_buffer); + numslots = 0; + } + + /* second pass, gaussian blur the downsampled image */ + { + int invrendertargetdim_uniform, color_uniform, depth_uniform, dof_uniform; + int viewvecs_uniform; + float invrendertargetdim[2] = {1.0f / GPU_texture_opengl_width(fx->dof_near_coc_blurred_buffer), + 1.0f / GPU_texture_opengl_height(fx->dof_near_coc_blurred_buffer)}; + float tmp = invrendertargetdim[0]; + invrendertargetdim[0] = 0.0f; + + dof_params[2] = GPU_texture_opengl_width(fx->dof_near_coc_blurred_buffer) / (scale_camera * fx_dof->sensor); + + dof_uniform = GPU_shader_get_uniform(dof_shader_pass2, "dof_params"); + invrendertargetdim_uniform = GPU_shader_get_uniform(dof_shader_pass2, "invrendertargetdim"); + color_uniform = GPU_shader_get_uniform(dof_shader_pass2, "colorbuffer"); + depth_uniform = GPU_shader_get_uniform(dof_shader_pass2, "depthbuffer"); + viewvecs_uniform = GPU_shader_get_uniform(dof_shader_pass2, "viewvecs"); + + /* Blurring vertically */ + GPU_shader_bind(dof_shader_pass2); + + GPU_shader_uniform_vector(dof_shader_pass2, dof_uniform, 4, 1, dof_params); + GPU_shader_uniform_vector(dof_shader_pass2, invrendertargetdim_uniform, 2, 1, invrendertargetdim); + GPU_shader_uniform_vector(dof_shader_pass2, viewvecs_uniform, 4, 3, viewvecs[0]); + + GPU_texture_bind(fx->depth_buffer, numslots++); + GPU_texture_filter_mode(fx->depth_buffer, false, true); + GPU_shader_uniform_texture(dof_shader_pass2, depth_uniform, fx->depth_buffer); + + GPU_texture_bind(fx->dof_near_coc_buffer, numslots++); + GPU_shader_uniform_texture(dof_shader_pass2, color_uniform, fx->dof_near_coc_buffer); + + /* use final buffer as a temp here */ + GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_near_coc_final_buffer, 0, NULL); + + /* Drawing quad */ + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + + /* *unbind/detach */ + GPU_texture_unbind(fx->dof_near_coc_buffer); + GPU_framebuffer_texture_detach(fx->dof_near_coc_final_buffer); + + /* Blurring horizontally */ + invrendertargetdim[0] = tmp; + invrendertargetdim[1] = 0.0f; + GPU_shader_uniform_vector(dof_shader_pass2, invrendertargetdim_uniform, 2, 1, invrendertargetdim); + + GPU_texture_bind(fx->dof_near_coc_final_buffer, numslots++); + GPU_shader_uniform_texture(dof_shader_pass2, color_uniform, fx->dof_near_coc_final_buffer); + + GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_near_coc_blurred_buffer, 0, NULL); + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + + /* *unbind/detach */ + GPU_texture_filter_mode(fx->depth_buffer, true, false); + GPU_texture_unbind(fx->depth_buffer); + + GPU_texture_unbind(fx->dof_near_coc_final_buffer); + GPU_framebuffer_texture_detach(fx->dof_near_coc_blurred_buffer); + + dof_params[2] = fx->gbuffer_dim[0] / (scale_camera * fx_dof->sensor); + + numslots = 0; + } + + /* third pass, calculate near coc */ + { + int near_coc_downsampled, near_coc_blurred; + + near_coc_downsampled = GPU_shader_get_uniform(dof_shader_pass3, "colorbuffer"); + near_coc_blurred = GPU_shader_get_uniform(dof_shader_pass3, "blurredcolorbuffer"); + + GPU_shader_bind(dof_shader_pass3); + + GPU_texture_bind(fx->dof_near_coc_buffer, numslots++); + GPU_shader_uniform_texture(dof_shader_pass3, near_coc_downsampled, fx->dof_near_coc_buffer); + + GPU_texture_bind(fx->dof_near_coc_blurred_buffer, numslots++); + GPU_shader_uniform_texture(dof_shader_pass3, near_coc_blurred, fx->dof_near_coc_blurred_buffer); + + GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_near_coc_final_buffer, 0, NULL); + + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + /* disable bindings */ + GPU_texture_unbind(fx->dof_near_coc_buffer); + GPU_texture_unbind(fx->dof_near_coc_blurred_buffer); + + /* unbinding here restores the size to the original */ + GPU_framebuffer_texture_detach(fx->dof_near_coc_final_buffer); + + numslots = 0; + } + + /* fourth pass blur final coc once to eliminate discontinuities */ + { + int near_coc_downsampled; + int invrendertargetdim_uniform; + float invrendertargetdim[2] = {1.0f / GPU_texture_opengl_width(fx->dof_near_coc_blurred_buffer), + 1.0f / GPU_texture_opengl_height(fx->dof_near_coc_blurred_buffer)}; + + near_coc_downsampled = GPU_shader_get_uniform(dof_shader_pass4, "colorbuffer"); + invrendertargetdim_uniform = GPU_shader_get_uniform(dof_shader_pass4, "invrendertargetdim"); + + GPU_shader_bind(dof_shader_pass4); + + GPU_texture_bind(fx->dof_near_coc_final_buffer, numslots++); + GPU_shader_uniform_texture(dof_shader_pass4, near_coc_downsampled, fx->dof_near_coc_final_buffer); + GPU_shader_uniform_vector(dof_shader_pass4, invrendertargetdim_uniform, 2, 1, invrendertargetdim); + + GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_near_coc_buffer, 0, NULL); + + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + /* disable bindings */ + GPU_texture_unbind(fx->dof_near_coc_final_buffer); + + /* unbinding here restores the size to the original */ + GPU_framebuffer_texture_unbind(fx->gbuffer, fx->dof_near_coc_buffer); + GPU_framebuffer_texture_detach(fx->dof_near_coc_buffer); + + numslots = 0; + } + + /* final pass, merge blurred layers according to final calculated coc */ + { + int medium_blurred_uniform, high_blurred_uniform, original_uniform, depth_uniform, dof_uniform; + int invrendertargetdim_uniform, viewvecs_uniform; + float invrendertargetdim[2] = {1.0f / fx->gbuffer_dim[0], 1.0f / fx->gbuffer_dim[1]}; + + medium_blurred_uniform = GPU_shader_get_uniform(dof_shader_pass5, "mblurredcolorbuffer"); + high_blurred_uniform = GPU_shader_get_uniform(dof_shader_pass5, "blurredcolorbuffer"); + dof_uniform = GPU_shader_get_uniform(dof_shader_pass5, "dof_params"); + invrendertargetdim_uniform = GPU_shader_get_uniform(dof_shader_pass5, "invrendertargetdim"); + original_uniform = GPU_shader_get_uniform(dof_shader_pass5, "colorbuffer"); + depth_uniform = GPU_shader_get_uniform(dof_shader_pass5, "depthbuffer"); + viewvecs_uniform = GPU_shader_get_uniform(dof_shader_pass5, "viewvecs"); + + GPU_shader_bind(dof_shader_pass5); + + GPU_shader_uniform_vector(dof_shader_pass5, dof_uniform, 4, 1, dof_params); + GPU_shader_uniform_vector(dof_shader_pass5, invrendertargetdim_uniform, 2, 1, invrendertargetdim); + GPU_shader_uniform_vector(dof_shader_pass5, viewvecs_uniform, 4, 3, viewvecs[0]); + + GPU_texture_bind(src, numslots++); + GPU_shader_uniform_texture(dof_shader_pass5, original_uniform, src); + + GPU_texture_bind(fx->dof_near_coc_blurred_buffer, numslots++); + GPU_shader_uniform_texture(dof_shader_pass5, high_blurred_uniform, fx->dof_near_coc_blurred_buffer); + + GPU_texture_bind(fx->dof_near_coc_buffer, numslots++); + GPU_shader_uniform_texture(dof_shader_pass5, medium_blurred_uniform, fx->dof_near_coc_buffer); + + GPU_texture_bind(fx->depth_buffer, numslots++); + GPU_texture_filter_mode(fx->depth_buffer, false, true); + GPU_shader_uniform_texture(dof_shader_pass5, depth_uniform, fx->depth_buffer); + + /* if this is the last pass, prepare for rendering on the frambuffer */ + gpu_fx_bind_render_target(&passes_left, fx, ofs, target); + + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + /* disable bindings */ + GPU_texture_unbind(fx->dof_near_coc_buffer); + GPU_texture_unbind(fx->dof_near_coc_blurred_buffer); + GPU_texture_unbind(src); + GPU_texture_filter_mode(fx->depth_buffer, true, false); + GPU_texture_unbind(fx->depth_buffer); + + /* may not be attached, in that case this just returns */ + if (target) { + GPU_framebuffer_texture_detach(target); + if (ofs) { + GPU_offscreen_bind(ofs, false); + } + else { + GPU_framebuffer_restore(); + } + } + + SWAP(GPUTexture *, target, src); + numslots = 0; + } + } + } + + glDisableClientState(GL_VERTEX_ARRAY); + glDisableClientState(GL_TEXTURE_COORD_ARRAY); + glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0); + + GPU_shader_unbind(); + + return true; +} + +void GPU_fx_compositor_init_dof_settings(GPUDOFSettings *fx_dof) +{ + fx_dof->fstop = 128.0f; + fx_dof->focal_length = 1.0f; + fx_dof->focus_distance = 1.0f; + fx_dof->sensor = 1.0f; + fx_dof->num_blades = 6; +} + +void GPU_fx_compositor_init_ssao_settings(GPUSSAOSettings *fx_ssao) +{ + fx_ssao->factor = 1.0f; + fx_ssao->distance_max = 0.2f; + fx_ssao->attenuation = 1.0f; + fx_ssao->samples = 20; +} diff --git a/source/blender/gpu/intern/gpu_debug.c b/source/blender/gpu/intern/gpu_debug.c new file mode 100644 index 00000000000..1c194f517aa --- /dev/null +++ b/source/blender/gpu/intern/gpu_debug.c @@ -0,0 +1,724 @@ +/* + * ***** 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, Jason Wilkins. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file source/blender/gpu/intern/gpu_debug.c + * \ingroup gpu + */ + +#include "BLI_sys_types.h" + +#include "BKE_global.h" + +#include "GPU_glew.h" +#include "GPU_debug.h" +#include "intern/gpu_private.h" + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#define CASE_CODE_RETURN_STR(code) case code: return #code; + +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 + + 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 + + +static void APIENTRY gpu_debug_proc( + GLenum source, GLenum type, GLuint UNUSED(id), + GLenum UNUSED(severity), GLsizei UNUSED(length), + const GLchar *message, const GLvoid *UNUSED(userParm)) +{ + if (source == GL_DEBUG_SOURCE_API && type == GL_DEBUG_TYPE_ERROR) { + fprintf(stderr, "GL: %s\n", message); + fflush(stderr); + } + else if (G.debug_value == 20) { + fprintf(stderr, "GL: %s\n", message); + fflush(stderr); + } +} + + +#ifndef GLEW_ES_ONLY +static void APIENTRY gpu_debug_proc_amd( + GLuint UNUSED(id), GLenum UNUSED(category), + GLenum UNUSED(severity), GLsizei UNUSED(length), + const GLchar *message, GLvoid *UNUSED(userParm)) +{ + fprintf(stderr, "GL: %s\n", message); +} +#endif + + +#undef APIENTRY + +void gpu_debug_init(void) +{ + const char success[] = "Successfully hooked OpenGL debug callback."; + +#if !defined(WITH_GLEW_ES) && !defined(GLEW_ES_ONLY) + if (GLEW_VERSION_4_3) { + glEnable(GL_DEBUG_OUTPUT); + glDebugMessageCallback(gpu_debug_proc, mxGetCurrentContext()); + glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, NULL, GL_TRUE); + GPU_string_marker(sizeof(success), success); + return; + } +#endif + + if (GLEW_KHR_debug) { +#ifndef GLEW_ES_ONLY + glDebugMessageCallback(gpu_debug_proc, mxGetCurrentContext()); + glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, NULL, GL_TRUE); + GPU_string_marker(sizeof(success), success); +#endif + return; + } + +#ifndef GLEW_ES_ONLY + if (GLEW_ARB_debug_output) { + glDebugMessageCallbackARB(gpu_debug_proc, mxGetCurrentContext()); + glDebugMessageControlARB(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, NULL, GL_TRUE); + GPU_string_marker(sizeof(success), success); + + return; + } + + if (GLEW_AMD_debug_output) { + glDebugMessageCallbackAMD(gpu_debug_proc_amd, mxGetCurrentContext()); + glDebugMessageEnableAMD(GL_DONT_CARE, GL_DONT_CARE, 0, NULL, GL_TRUE); + GPU_string_marker(sizeof(success), success); + + return; + } +#endif + + fprintf(stderr, "Failed to hook OpenGL debug callback.\n"); + + return; +} + + +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 + glDebugMessageCallback(NULL, NULL); +#endif + return; + } + +#ifndef GLEW_ES_ONLY + if (GLEW_ARB_debug_output) { + glDebugMessageCallbackARB(NULL, NULL); + + return; + } + + if (GLEW_AMD_debug_output) { + glDebugMessageCallbackAMD(NULL, NULL); + + return; + } +#endif + + return; +} + +void GPU_string_marker(size_t length, 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, length, buf); + + return; + } +#endif +#endif + + if (GLEW_KHR_debug) { +#ifndef GLEW_ES_ONLY + glDebugMessageInsert(GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_MARKER, 0, GL_DEBUG_SEVERITY_NOTIFICATION, length, buf); +#endif + return; + } + +#ifndef GLEW_ES_ONLY + if (GLEW_ARB_debug_output) { + glDebugMessageInsertARB(GL_DEBUG_SOURCE_APPLICATION_ARB, GL_DEBUG_TYPE_OTHER_ARB, 0, GL_DEBUG_SEVERITY_LOW_ARB, length, buf); + + return; + } + + if (GLEW_AMD_debug_output) { + glDebugMessageInsertAMD(GL_DEBUG_CATEGORY_APPLICATION_AMD, GL_DEBUG_SEVERITY_LOW_AMD, 0, length, buf); + + return; + } + + if (GLEW_GREMEDY_string_marker) { + glStringMarkerGREMEDY(length, buf); + + return; + } +#endif + + return; +} + +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) +{ + const unsigned char err_mark[4] = {0xff, 0xff, 0xff, 0xff}; + + float value[32]; + int a; + + memset(value, 0xff, sizeof(value)); + glGetFloatv(type, value); + + if (glGetError() == GL_NO_ERROR) { + printf("%s: ", name); + for (a = 0; a < 32; a++) { + if (memcmp(&value[a], err_mark, sizeof(value[a])) == 0) { + break; + } + printf("%.2f ", value[a]); + } + printf("\n"); + } +} + +#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_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); + 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_MULTISAMPLE_ARB); + 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_CUBE_MAP_ARB); + 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 7295f0259c5..bf7b8fbc386 100644 --- a/source/blender/gpu/intern/gpu_draw.c +++ b/source/blender/gpu/intern/gpu_draw.c @@ -38,7 +38,8 @@ #include <string.h> -#include "GL/glew.h" +#include "GPU_glew.h" +#include "GPU_debug.h" #include "BLI_blenlib.h" #include "BLI_linklist.h" @@ -55,6 +56,7 @@ #include "DNA_scene_types.h" #include "DNA_smoke_types.h" #include "DNA_view3d_types.h" +#include "DNA_particle_types.h" #include "MEM_guardedalloc.h" @@ -69,6 +71,7 @@ #include "BKE_node.h" #include "BKE_object.h" #include "BKE_scene.h" +#include "BKE_subsurf.h" #include "BKE_DerivedMesh.h" #include "GPU_buffers.h" @@ -80,6 +83,13 @@ #include "smoke_API.h" +#ifdef WITH_OPENSUBDIV +# include "DNA_mesh_types.h" +# include "BKE_editmesh.h" + +# include "gpu_codegen.h" +#endif + extern Material defmaterial; /* from material.c */ /* Text Rendering */ @@ -87,16 +97,22 @@ extern Material defmaterial; /* from material.c */ static void gpu_mcol(unsigned int ucol) { /* mcol order is swapped */ - const char *cp= (char *)&ucol; + const char *cp = (char *)&ucol; glColor3ub(cp[3], cp[2], cp[1]); } -void GPU_render_text(MTFace *tface, int mode, - const char *textstr, int textlen, unsigned int *col, - float *v1, float *v2, float *v3, float *v4, int glattrib) +void GPU_render_text( + MTexPoly *mtexpoly, int mode, + const char *textstr, int textlen, unsigned int *col, + const float *v_quad[4], const float *uv_quad[4], + int glattrib) { - if ((mode & GEMAT_TEXT) && (textlen>0) && tface->tpage) { - Image* ima = (Image *)tface->tpage; + if ((mode & GEMAT_TEXT) && (textlen > 0) && mtexpoly->tpage) { + const float *v1 = v_quad[0]; + const float *v2 = v_quad[1]; + const float *v3 = v_quad[2]; + const float *v4 = v_quad[3]; + Image *ima = (Image *)mtexpoly->tpage; ImBuf *first_ibuf; const size_t textlen_st = textlen; size_t index; @@ -104,7 +120,7 @@ void GPU_render_text(MTFace *tface, int mode, float advance_tab; /* multiline */ - float line_start= 0.0f, line_height; + 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]); @@ -115,8 +131,8 @@ void GPU_render_text(MTFace *tface, int mode, /* color has been set */ - if (tface->mode & TF_OBCOL) - col= NULL; + if (mtexpoly->mode & TF_OBCOL) + col = NULL; else if (!col) glColor3f(1.0f, 1.0f, 1.0f); @@ -127,23 +143,23 @@ void GPU_render_text(MTFace *tface, int mode, matrixGlyph(first_ibuf, ' ', ¢erx, ¢ery, &sizex, &sizey, &transx, &transy, &movex, &movey, &advance); - advance_tab= advance * 4; /* tab width could also be an option */ + advance_tab = advance * 4; /* tab width could also be an option */ for (index = 0; index < textlen_st; ) { unsigned int character; float uv[4][2]; - // lets calculate offset stuff + /* 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.0); + if (character == '\n') { + glTranslatef(line_start, -line_height, 0.0f); line_start = 0.0f; continue; } - else if (character=='\t') { - glTranslatef(advance_tab, 0.0, 0.0); + else if (character == '\t') { + glTranslatef(advance_tab, 0.0f, 0.0f); line_start -= advance_tab; /* so we can go back to the start of the line */ continue; @@ -153,17 +169,17 @@ void GPU_render_text(MTFace *tface, int mode, character = '?'; } - // space starts at offset 1 - // character = character - ' ' + 1; + /* space starts at offset 1 */ + /* character = character - ' ' + 1; */ matrixGlyph(first_ibuf, character, & centerx, ¢ery, &sizex, &sizey, &transx, &transy, &movex, &movey, &advance); - uv[0][0] = (tface->uv[0][0] - centerx) * sizex + transx; - uv[0][1] = (tface->uv[0][1] - centery) * sizey + transy; - uv[1][0] = (tface->uv[1][0] - centerx) * sizex + transx; - uv[1][1] = (tface->uv[1][1] - centery) * sizey + transy; - uv[2][0] = (tface->uv[2][0] - centerx) * sizex + transx; - uv[2][1] = (tface->uv[2][1] - centery) * sizey + transy; + uv[0][0] = (uv_quad[0][0] - centerx) * sizex + transx; + uv[0][1] = (uv_quad[0][1] - centery) * sizey + transy; + uv[1][0] = (uv_quad[1][0] - centerx) * sizex + transx; + uv[1][1] = (uv_quad[1][1] - centery) * sizey + transy; + uv[2][0] = (uv_quad[2][0] - centerx) * sizex + transx; + uv[2][1] = (uv_quad[2][1] - centery) * sizey + transy; glBegin(GL_POLYGON); if (glattrib >= 0) glVertexAttrib2fvARB(glattrib, uv[0]); @@ -182,8 +198,8 @@ void GPU_render_text(MTFace *tface, int mode, glVertex3f(sizex * v3[0] + movex, sizey * v3[1] + movey, v3[2]); if (v4) { - uv[3][0] = (tface->uv[3][0] - centerx) * sizex + transx; - uv[3][1] = (tface->uv[3][1] - centery) * sizey + transy; + uv[3][0] = (uv_quad[3][0] - centerx) * sizex + transx; + uv[3][1] = (uv_quad[3][1] - centery) * sizey + transy; if (glattrib >= 0) glVertexAttrib2fvARB(glattrib, uv[3]); else glTexCoord2fv(uv[3]); @@ -192,7 +208,7 @@ void GPU_render_text(MTFace *tface, int mode, } glEnd(); - glTranslatef(advance, 0.0, 0.0); + glTranslatef(advance, 0.0f, 0.0f); line_start -= advance; /* so we can go back to the start of the line */ } glPopMatrix(); @@ -238,14 +254,18 @@ static struct GPUTextureState { int curtileYRep, tileYRep; Image *ima, *curima; - int domipmap, linearmipmap; - int texpaint; /* store this so that new images created while texture painting won't be set to mipmapped */ + /* also controls min/mag filtering */ + bool domipmap; + /* only use when 'domipmap' is set */ + bool linearmipmap; + /* store this so that new images created while texture painting won't be set to mipmapped */ + bool texpaint; int alphablend; float anisotropic; int gpu_mipmap; - MTFace *lasttface; -} GTS = {0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, 1, 0, 0, -1, 1.f, 0, NULL}; + MTexPoly *lasttface; +} GTS = {0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, 1, 0, 0, -1, 1.0f, 0, NULL}; /* Mipmap settings */ @@ -280,49 +300,53 @@ static void gpu_generate_mipmap(GLenum target) glDisable(target); } -void GPU_set_mipmap(int mipmap) +void GPU_set_mipmap(bool mipmap) { - if (GTS.domipmap != (mipmap != 0)) { + if (GTS.domipmap != mipmap) { GPU_free_images(); - GTS.domipmap = mipmap != 0; + GTS.domipmap = mipmap; } } -void GPU_set_linear_mipmap(int linear) +void GPU_set_linear_mipmap(bool linear) { - if (GTS.linearmipmap != (linear != 0)) { - GPU_free_images(); - GTS.linearmipmap = linear != 0; + if (GTS.linearmipmap != linear) { + GTS.linearmipmap = linear; } } -int GPU_get_mipmap(void) +bool GPU_get_mipmap(void) { return GTS.domipmap && !GTS.texpaint; } -int GPU_get_linear_mipmap(void) +bool GPU_get_linear_mipmap(void) { return GTS.linearmipmap; } -static GLenum gpu_get_mipmap_filter(int mag) +static GLenum gpu_get_mipmap_filter(bool mag) { /* linearmipmap is off by default *when mipmapping is off, * use unfiltered display */ if (mag) { - if (GTS.linearmipmap || GTS.domipmap) + if (GTS.domipmap) return GL_LINEAR; else return GL_NEAREST; } else { - if (GTS.linearmipmap) - return GL_LINEAR_MIPMAP_LINEAR; - else if (GTS.domipmap) - return GL_LINEAR_MIPMAP_NEAREST; - else + if (GTS.domipmap) { + if (GTS.linearmipmap) { + return GL_LINEAR_MIPMAP_LINEAR; + } + else { + return GL_LINEAR_MIPMAP_NEAREST; + } + } + else { return GL_NEAREST; + } } } @@ -352,41 +376,41 @@ static void gpu_make_repbind(Image *ima) ImBuf *ibuf; ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL); - if (ibuf==NULL) + if (ibuf == NULL) return; if (ima->repbind) { glDeleteTextures(ima->totbind, (GLuint *)ima->repbind); MEM_freeN(ima->repbind); - ima->repbind= NULL; + ima->repbind = NULL; ima->tpageflag &= ~IMA_MIPMAP_COMPLETE; } - ima->totbind= ima->xrep*ima->yrep; + ima->totbind = ima->xrep*ima->yrep; if (ima->totbind>1) - ima->repbind= MEM_callocN(sizeof(int)*ima->totbind, "repbind"); + ima->repbind = MEM_callocN(sizeof(int) * ima->totbind, "repbind"); BKE_image_release_ibuf(ima, ibuf, NULL); } void GPU_clear_tpage(bool force) { - if (GTS.lasttface==NULL && !force) + if (GTS.lasttface == NULL && !force) return; - GTS.lasttface= NULL; - GTS.curtile= 0; - GTS.curima= NULL; - if (GTS.curtilemode!=0) { + 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; + GTS.curtilemode = 0; + GTS.curtileXRep = 0; + GTS.curtileYRep = 0; + GTS.alphablend = -1; glDisable(GL_BLEND); glDisable(GL_TEXTURE_2D); @@ -400,15 +424,18 @@ static void gpu_set_alpha_blend(GPUBlendMode alphablend) if (alphablend == GPU_BLEND_SOLID) { glDisable(GL_BLEND); glDisable(GL_ALPHA_TEST); + glDisable(GL_SAMPLE_ALPHA_TO_COVERAGE); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); } - else if (alphablend==GPU_BLEND_ADD) { + else if (alphablend == GPU_BLEND_ADD) { glEnable(GL_BLEND); glBlendFunc(GL_ONE, GL_ONE); glDisable(GL_ALPHA_TEST); + glDisable(GL_SAMPLE_ALPHA_TO_COVERAGE); } else if (ELEM(alphablend, GPU_BLEND_ALPHA, GPU_BLEND_ALPHA_SORT)) { glEnable(GL_BLEND); + glDisable(GL_SAMPLE_ALPHA_TO_COVERAGE); /* for OpenGL render we use the alpha channel, this makes alpha blend correct */ if (GLEW_VERSION_1_4) @@ -428,11 +455,17 @@ static void gpu_set_alpha_blend(GPUBlendMode alphablend) glAlphaFunc(GL_GREATER, U.glalphaclip); } } - else if (alphablend==GPU_BLEND_CLIP) { - glDisable(GL_BLEND); + 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) @@ -442,7 +475,7 @@ static void gpu_verify_alpha_blend(int alphablend) return; gpu_set_alpha_blend(alphablend); - GTS.alphablend= alphablend; + GTS.alphablend = alphablend; } static void gpu_verify_reflection(Image *ima) @@ -466,9 +499,9 @@ int GPU_verify_image(Image *ima, ImageUser *iuser, int tftile, bool compare, boo { ImBuf *ibuf = NULL; unsigned int *bind = NULL; - int rectw, recth, tpx=0, tpy=0, y; - unsigned int *tilerect= NULL, *rect= NULL; - float *ftilerect= NULL, *frect = NULL; + int rectw, recth, tpx = 0, tpy = 0, y; + unsigned int *tilerect = NULL, *rect = NULL; + float *ftilerect = NULL, *frect = NULL; float *srgb_frect = NULL; short texwindx, texwindy, texwinsx, texwinsy; /* flag to determine whether high resolution format is used */ @@ -476,15 +509,15 @@ int GPU_verify_image(Image *ima, ImageUser *iuser, int tftile, bool compare, boo /* initialize tile mode and number of repeats */ GTS.ima = ima; - GTS.tilemode= (ima && (ima->tpageflag & (IMA_TILES|IMA_TWINANIM))); + GTS.tilemode = (ima && (ima->tpageflag & (IMA_TILES|IMA_TWINANIM))); GTS.tileXRep = 0; GTS.tileYRep = 0; /* setting current tile according to frame */ if (ima && (ima->tpageflag & IMA_TWINANIM)) - GTS.tile= ima->lastframe; + GTS.tile = ima->lastframe; else - GTS.tile= tftile; + GTS.tile = tftile; GTS.tile = MAX2(0, GTS.tile); @@ -502,26 +535,26 @@ int GPU_verify_image(Image *ima, ImageUser *iuser, int tftile, bool compare, boo } /* if tiling mode or repeat changed, change texture matrix to fit */ - if (GTS.tilemode!=GTS.curtilemode || GTS.curtileXRep!=GTS.tileXRep || + 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.0); + glScalef(ima->xrep, ima->yrep, 1.0f); glMatrixMode(GL_MODELVIEW); } /* check if we have a valid image */ - if (ima==NULL || ima->ok==0) + if (ima == NULL || ima->ok == 0) return 0; /* check if we have a valid image buffer */ - ibuf= BKE_image_acquire_ibuf(ima, iuser, NULL); + ibuf = BKE_image_acquire_ibuf(ima, iuser, NULL); - if (ibuf==NULL) + if (ibuf == NULL) return 0; if (ibuf->rect_float) { @@ -551,59 +584,58 @@ int GPU_verify_image(Image *ima, ImageUser *iuser, int tftile, bool compare, boo if (GTS.tilemode) { /* tiled mode */ - if (ima->repbind==NULL) gpu_make_repbind(ima); - if (GTS.tile>=ima->totbind) GTS.tile= 0; + 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) bind= &ima->repbind[GTS.tile]; - else bind= &ima->bindcode; + if (ima->repbind) bind = &ima->repbind[GTS.tile]; + else bind = &ima->bindcode; - if (*bind==0) { - - texwindx= ibuf->x/ima->xrep; - texwindy= ibuf->y/ima->yrep; + if (*bind == 0) { + texwindx = ibuf->x / ima->xrep; + texwindy = ibuf->y / ima->yrep; - if (GTS.tile>=ima->xrep*ima->yrep) - GTS.tile= ima->xrep*ima->yrep-1; + if (GTS.tile >= ima->xrep * ima->yrep) + GTS.tile = ima->xrep * ima->yrep - 1; - texwinsy= GTS.tile / ima->xrep; - texwinsx= GTS.tile - texwinsy*ima->xrep; + texwinsy = GTS.tile / ima->xrep; + texwinsx = GTS.tile - texwinsy * ima->xrep; - texwinsx*= texwindx; - texwinsy*= texwindy; + texwinsx *= texwindx; + texwinsy *= texwindy; - tpx= texwindx; - tpy= texwindy; + tpx = texwindx; + tpy = texwindy; if (use_high_bit_depth) { if (do_color_management) { - srgb_frect = MEM_mallocN(ibuf->x*ibuf->y*sizeof(float)*4, "floar_buf_col_cor"); + srgb_frect = MEM_mallocN(ibuf->x * ibuf->y * sizeof(float) * 4, "floar_buf_col_cor"); IMB_buffer_float_from_float(srgb_frect, ibuf->rect_float, ibuf->channels, IB_PROFILE_SRGB, IB_PROFILE_LINEAR_RGB, true, ibuf->x, ibuf->y, ibuf->x, ibuf->x); IMB_buffer_float_unpremultiply(srgb_frect, ibuf->x, ibuf->y); /* clamp buffer colors to 1.0 to avoid artifacts due to glu for hdr images */ IMB_buffer_float_clamp(srgb_frect, ibuf->x, ibuf->y); - frect= srgb_frect + texwinsy*ibuf->x + texwinsx; + frect = srgb_frect + texwinsy*ibuf->x + texwinsx; } else - frect= ibuf->rect_float + texwinsy*ibuf->x + texwinsx; + frect = ibuf->rect_float + texwinsy*ibuf->x + texwinsx; } else - rect= ibuf->rect + texwinsy*ibuf->x + texwinsx; + rect = ibuf->rect + texwinsy*ibuf->x + texwinsx; } } else { /* regular image mode */ bind= &ima->bindcode; - if (*bind==0) { - tpx= ibuf->x; - tpy= ibuf->y; - rect= ibuf->rect; + if (*bind == 0) { + tpx = ibuf->x; + tpy = ibuf->y; + rect = ibuf->rect; if (use_high_bit_depth) { if (do_color_management) { - frect = srgb_frect = MEM_mallocN(ibuf->x*ibuf->y*sizeof(*srgb_frect)*4, "floar_buf_col_cor"); + frect = srgb_frect = MEM_mallocN(ibuf->x * ibuf->y * sizeof(*srgb_frect) * 4, "floar_buf_col_cor"); IMB_buffer_float_from_float(srgb_frect, ibuf->rect_float, ibuf->channels, IB_PROFILE_SRGB, IB_PROFILE_LINEAR_RGB, true, ibuf->x, ibuf->y, ibuf->x, ibuf->x); @@ -612,7 +644,7 @@ int GPU_verify_image(Image *ima, ImageUser *iuser, int tftile, bool compare, boo IMB_buffer_float_clamp(srgb_frect, ibuf->x, ibuf->y); } else - frect= ibuf->rect_float; + frect = ibuf->rect_float; } } } @@ -632,35 +664,35 @@ int GPU_verify_image(Image *ima, ImageUser *iuser, int tftile, bool compare, boo if (use_high_bit_depth) { float *frectrow, *ftilerectrow; - ftilerect= MEM_mallocN(rectw*recth*sizeof(*ftilerect), "tilerect"); + ftilerect = MEM_mallocN(rectw*recth*sizeof(*ftilerect), "tilerect"); - for (y=0; y<recth; y++) { - frectrow= &frect[y*ibuf->x]; - ftilerectrow= &ftilerect[y*rectw]; + for (y = 0; y < recth; y++) { + frectrow = &frect[y * ibuf->x]; + ftilerectrow = &ftilerect[y * rectw]; - memcpy(ftilerectrow, frectrow, tpx*sizeof(*frectrow)); + memcpy(ftilerectrow, frectrow, tpx * sizeof(*frectrow)); } - frect= ftilerect; + frect = ftilerect; } else { unsigned int *rectrow, *tilerectrow; - tilerect= MEM_mallocN(rectw*recth*sizeof(*tilerect), "tilerect"); + tilerect = MEM_mallocN(rectw*recth*sizeof(*tilerect), "tilerect"); - for (y=0; y<recth; y++) { - rectrow= &rect[y*ibuf->x]; - tilerectrow= &tilerect[y*rectw]; + for (y = 0; y < recth; y++) { + rectrow = &rect[y * ibuf->x]; + tilerectrow = &tilerect[y * rectw]; - memcpy(tilerectrow, rectrow, tpx*sizeof(*rectrow)); + memcpy(tilerectrow, rectrow, tpx * sizeof(*rectrow)); } - rect= tilerect; + rect = tilerect; } } #ifdef WITH_DDS - if (ibuf->ftype & DDS) + if (ibuf->ftype == IMB_FTYPE_DDS) GPU_create_gl_tex_compressed(bind, rect, rectw, recth, mipmap, ima, ibuf); else #endif @@ -688,11 +720,10 @@ int GPU_verify_image(Image *ima, ImageUser *iuser, int tftile, bool compare, boo } /* Image *ima can be NULL */ -void GPU_create_gl_tex(unsigned int *bind, unsigned int *pix, float *frect, int rectw, int recth, +void GPU_create_gl_tex(unsigned int *bind, unsigned int *rect, float *frect, int rectw, int recth, bool mipmap, bool use_high_bit_depth, Image *ima) { - unsigned int *scalerect = NULL; - float *fscalerect = NULL; + ImBuf *ibuf = NULL; int tpx = rectw; int tpy = recth; @@ -702,20 +733,20 @@ void GPU_create_gl_tex(unsigned int *bind, unsigned int *pix, float *frect, int * Then don't bother scaling for hardware that supports NPOT textures! */ if ((!GPU_non_power_of_two_support() && !is_power_of_2_resolution(rectw, recth)) || is_over_resolution_limit(rectw, recth)) { - rectw= smaller_power_of_2_limit(rectw); - recth= smaller_power_of_2_limit(recth); + rectw = smaller_power_of_2_limit(rectw); + recth = smaller_power_of_2_limit(recth); if (use_high_bit_depth) { - fscalerect= MEM_mallocN(rectw*recth*sizeof(*fscalerect)*4, "fscalerect"); - gluScaleImage(GL_RGBA, tpx, tpy, GL_FLOAT, frect, rectw, recth, GL_FLOAT, fscalerect); + ibuf = IMB_allocFromBuffer(NULL, frect, tpx, tpy); + IMB_scaleImBuf(ibuf, rectw, recth); - frect = fscalerect; + frect = ibuf->rect_float; } else { - scalerect= MEM_mallocN(rectw*recth*sizeof(*scalerect), "scalerect"); - gluScaleImage(GL_RGBA, tpx, tpy, GL_UNSIGNED_BYTE, pix, rectw, recth, GL_UNSIGNED_BYTE, scalerect); + ibuf = IMB_allocFromBuffer(rect, NULL, tpx, tpy); + IMB_scaleImBuf(ibuf, rectw, recth); - pix= scalerect; + rect = ibuf->rect; } } @@ -723,45 +754,64 @@ void GPU_create_gl_tex(unsigned int *bind, unsigned int *pix, float *frect, int glGenTextures(1, (GLuint *)bind); glBindTexture(GL_TEXTURE_2D, *bind); - if (!(GPU_get_mipmap() && mipmap)) { - if (use_high_bit_depth) - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16, rectw, recth, 0, GL_RGBA, GL_FLOAT, frect); + if (use_high_bit_depth) { + if (GLEW_ARB_texture_float) + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, rectw, recth, 0, GL_RGBA, GL_FLOAT, frect); else - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, rectw, recth, 0, GL_RGBA, GL_UNSIGNED_BYTE, pix); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gpu_get_mipmap_filter(1)); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16, rectw, recth, 0, GL_RGBA, GL_FLOAT, frect); } - else { - if (GTS.gpu_mipmap) { - if (use_high_bit_depth) - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16, rectw, recth, 0, GL_RGBA, GL_FLOAT, frect); - else - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, rectw, recth, 0, GL_RGBA, GL_UNSIGNED_BYTE, pix); + else + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, rectw, recth, 0, GL_RGBA, GL_UNSIGNED_BYTE, rect); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gpu_get_mipmap_filter(1)); + if (GPU_get_mipmap() && mipmap) { + if (GTS.gpu_mipmap) { gpu_generate_mipmap(GL_TEXTURE_2D); } else { - if (use_high_bit_depth) - gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGBA16, rectw, recth, GL_RGBA, GL_FLOAT, frect); - else - gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGBA, rectw, recth, GL_RGBA, GL_UNSIGNED_BYTE, pix); + int i; + + if (!ibuf) { + if (use_high_bit_depth) { + ibuf = IMB_allocFromBuffer(NULL, frect, tpx, tpy); + } + else { + ibuf = IMB_allocFromBuffer(rect, NULL, tpx, tpy); + } + } + + IMB_makemipmap(ibuf, true); + + for (i = 1; i < ibuf->miptot; i++) { + ImBuf *mip = ibuf->mipmap[i - 1]; + if (use_high_bit_depth) { + if (GLEW_ARB_texture_float) + glTexImage2D(GL_TEXTURE_2D, i, GL_RGBA16F, mip->x, mip->y, 0, GL_RGBA, GL_FLOAT, mip->rect_float); + else + glTexImage2D(GL_TEXTURE_2D, i, GL_RGBA16, mip->x, mip->y, 0, GL_RGBA, GL_FLOAT, mip->rect_float); + } + else { + glTexImage2D(GL_TEXTURE_2D, i, GL_RGBA, mip->x, mip->y, 0, GL_RGBA, GL_UNSIGNED_BYTE, mip->rect); + } + } } glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gpu_get_mipmap_filter(0)); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gpu_get_mipmap_filter(1)); if (ima) ima->tpageflag |= IMA_MIPMAP_COMPLETE; } + else { + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + } if (GLEW_EXT_texture_filter_anisotropic) glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, GPU_get_anisotropic()); /* set to modulate with vertex color */ glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); - if (scalerect) - MEM_freeN(scalerect); - if (fscalerect) - MEM_freeN(fscalerect); + if (ibuf) + IMB_freeImBuf(ibuf); } /** @@ -788,12 +838,12 @@ bool GPU_upload_dxt_texture(ImBuf *ibuf) } if (format == 0) { - printf("Unable to find a suitable DXT compression, falling back to uncompressed\n"); + fprintf(stderr, "Unable to find a suitable DXT compression, falling back to uncompressed\n"); return false; } if (!is_power_of_2_resolution(width, height)) { - printf("Unable to load non-power-of-two DXT image resolution, falling back to uncompressed\n"); + fprintf(stderr, "Unable to load non-power-of-two DXT image resolution, falling back to uncompressed\n"); return false; } @@ -806,7 +856,7 @@ bool GPU_upload_dxt_texture(ImBuf *ibuf) glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, GPU_get_anisotropic()); blocksize = (ibuf->dds_data.fourcc == FOURCC_DXT1) ? 8 : 16; - for (i=0; i<ibuf->dds_data.nummipmaps && (width||height); ++i) { + for (i = 0; i < ibuf->dds_data.nummipmaps && (width||height); ++i) { if (width == 0) width = 1; if (height == 0) @@ -823,7 +873,7 @@ bool GPU_upload_dxt_texture(ImBuf *ibuf) } /* set number of mipmap levels we have, needed in case they don't go down to 1x1 */ - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, i-1); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, i - 1); return true; #else @@ -864,26 +914,26 @@ static void gpu_verify_repeat(Image *ima) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); } -int GPU_set_tpage(MTFace *tface, int mipmap, int alphablend) +int GPU_set_tpage(MTexPoly *mtexpoly, int mipmap, int alphablend) { Image *ima; /* check if we need to clear the state */ - if (tface==NULL) { + if (mtexpoly == NULL) { GPU_clear_tpage(false); return 0; } - ima= tface->tpage; - GTS.lasttface= tface; + ima = mtexpoly->tpage; + GTS.lasttface = mtexpoly; gpu_verify_alpha_blend(alphablend); gpu_verify_reflection(ima); - if (GPU_verify_image(ima, NULL, tface->tile, 1, mipmap, false)) { - GTS.curtile= GTS.tile; - GTS.curima= GTS.ima; - GTS.curtilemode= GTS.tilemode; + if (GPU_verify_image(ima, NULL, 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; @@ -892,9 +942,9 @@ int GPU_set_tpage(MTFace *tface, int mipmap, int alphablend) else { glDisable(GL_TEXTURE_2D); - GTS.curtile= 0; - GTS.curima= NULL; - GTS.curtilemode= 0; + GTS.curtile = 0; + GTS.curima = NULL; + GTS.curtilemode = 0; GTS.curtileXRep = 0; GTS.curtileYRep = 0; @@ -913,9 +963,9 @@ int GPU_set_tpage(MTFace *tface, int mipmap, int alphablend) * temporary disabling/enabling mipmapping on all images for quick texture * updates with glTexSubImage2D. images that didn't change don't have to be * re-uploaded to OpenGL */ -void GPU_paint_set_mipmap(int mipmap) +void GPU_paint_set_mipmap(bool mipmap) { - Image* ima; + Image *ima; if (!GTS.domipmap) return; @@ -923,7 +973,7 @@ void GPU_paint_set_mipmap(int mipmap) GTS.texpaint = !mipmap; if (mipmap) { - for (ima=G.main->image.first; ima; ima=ima->id.next) { + for (ima = G.main->image.first; ima; ima = ima->id.next) { if (ima->bindcode) { if (ima->tpageflag & IMA_MIPMAP_COMPLETE) { glBindTexture(GL_TEXTURE_2D, ima->bindcode); @@ -939,7 +989,7 @@ void GPU_paint_set_mipmap(int mipmap) } else { - for (ima=G.main->image.first; ima; ima=ima->id.next) { + for (ima = G.main->image.first; ima; ima = ima->id.next) { if (ima->bindcode) { glBindTexture(GL_TEXTURE_2D, ima->bindcode); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); @@ -977,16 +1027,16 @@ static bool GPU_check_scaled_image(ImBuf *ibuf, Image *ima, float *frect, int x, if (rectw + x > x_limit) rectw--; if (recth + y > y_limit) recth--; - /* float rectangles are already continuous in memory so we can use gluScaleImage */ + /* float rectangles are already continuous in memory so we can use IMB_scaleImBuf */ if (frect) { - float *fscalerect = MEM_mallocN(rectw*recth*sizeof(*fscalerect)*4, "fscalerect"); - gluScaleImage(GL_RGBA, w, h, GL_FLOAT, frect, rectw, recth, GL_FLOAT, fscalerect); + ImBuf *ibuf = IMB_allocFromBuffer(NULL, frect, w, h); + IMB_scaleImBuf(ibuf, rectw, recth); glBindTexture(GL_TEXTURE_2D, ima->bindcode); glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, rectw, recth, GL_RGBA, - GL_FLOAT, fscalerect); + GL_FLOAT, ibuf->rect_float); - MEM_freeN(fscalerect); + IMB_freeImBuf(ibuf); } /* byte images are not continuous in memory so do manual interpolation */ else { @@ -1022,11 +1072,11 @@ static bool GPU_check_scaled_image(ImBuf *ibuf, Image *ima, float *frect, int x, return false; } -void GPU_paint_update_image(Image *ima, int x, int y, int w, int h) +void GPU_paint_update_image(Image *ima, ImageUser *iuser, int x, int y, int w, int h) { ImBuf *ibuf; - ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL); + ibuf = BKE_image_acquire_ibuf(ima, iuser, NULL); if (ima->repbind || (GPU_get_mipmap() && !GTS.gpu_mipmap) || !ima->bindcode || !ibuf || (w == 0) || (h == 0)) @@ -1052,8 +1102,7 @@ void GPU_paint_update_image(Image *ima, int x, int y, int w, int h) } glBindTexture(GL_TEXTURE_2D, ima->bindcode); - glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, w, h, GL_RGBA, - GL_FLOAT, buffer); + glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, w, h, GL_RGBA, GL_FLOAT, buffer); MEM_freeN(buffer); @@ -1108,16 +1157,16 @@ void GPU_update_images_framechange(void) { Image *ima; - for (ima=G.main->image.first; ima; ima=ima->id.next) { + for (ima = G.main->image.first; ima; ima = ima->id.next) { if (ima->tpageflag & IMA_TWINANIM) { - if (ima->twend >= ima->xrep*ima->yrep) - ima->twend= ima->xrep*ima->yrep-1; + 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; + ima->lastframe = ima->twsta; } } } @@ -1125,33 +1174,33 @@ void GPU_update_images_framechange(void) int GPU_update_image_time(Image *ima, double time) { int inc = 0; - float diff; + float diff; int newframe; if (!ima) return 0; - if (ima->lastupdate<0) + if (ima->lastupdate < 0) ima->lastupdate = 0; if (ima->lastupdate > (float)time) - ima->lastupdate=(float)time; + ima->lastupdate = (float)time; if (ima->tpageflag & IMA_TWINANIM) { - if (ima->twend >= ima->xrep*ima->yrep) ima->twend= ima->xrep*ima->yrep-1; + 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) */ diff = (float)((float)time - ima->lastupdate); - inc = (int)(diff*(float)ima->animspeed); + inc = (int)(diff * (float)ima->animspeed); - ima->lastupdate+=((float)inc/(float)ima->animspeed); + ima->lastupdate += ((float)inc / (float)ima->animspeed); - newframe = ima->lastframe+inc; + newframe = ima->lastframe + inc; if (newframe > (int)ima->twend) { - if (ima->twend-ima->twsta != 0) - newframe = (int)ima->twsta-1 + (newframe-ima->twend)%(ima->twend-ima->twsta); + if (ima->twend - ima->twsta != 0) + newframe = (int)ima->twsta - 1 + (newframe - ima->twend) % (ima->twend - ima->twsta); else newframe = ima->twsta; } @@ -1188,7 +1237,7 @@ void GPU_create_smoke(SmokeModifierData *smd, int highres) if (!sds->tex && !highres) { /* rgba texture for color + density */ if (smoke_has_colors(sds->fluid)) { - float *data = MEM_callocN(sizeof(float)*sds->total_cells*4, "smokeColorTexture"); + 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); MEM_freeN(data); @@ -1202,7 +1251,7 @@ void GPU_create_smoke(SmokeModifierData *smd, int highres) 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"); + 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); MEM_freeN(data); @@ -1218,9 +1267,9 @@ void GPU_create_smoke(SmokeModifierData *smd, int highres) } #else // WITH_SMOKE (void)highres; - smd->domain->tex= NULL; - smd->domain->tex_flame= NULL; - smd->domain->tex_shadow= NULL; + smd->domain->tex = NULL; + smd->domain->tex_flame = NULL; + smd->domain->tex_shadow = NULL; #endif // WITH_SMOKE } @@ -1244,7 +1293,7 @@ void GPU_free_unused_buffers(void) BLI_lock_thread(LOCK_OPENGL); /* images */ - for (node=image_free_queue; node; node=node->next) { + for (node = image_free_queue; node; node = node->next) { ima = node->link; /* check in case it was freed in the meantime */ @@ -1271,13 +1320,13 @@ void GPU_free_image(Image *ima) /* free regular image binding */ if (ima->bindcode) { glDeleteTextures(1, (GLuint *)&ima->bindcode); - ima->bindcode= 0; + ima->bindcode = 0; } /* free glsl image binding */ if (ima->gputexture) { GPU_texture_free(ima->gputexture); - ima->gputexture= NULL; + ima->gputexture = NULL; } /* free repeated image binding */ @@ -1285,7 +1334,7 @@ void GPU_free_image(Image *ima) glDeleteTextures(ima->totbind, (GLuint *)ima->repbind); MEM_freeN(ima->repbind); - ima->repbind= NULL; + ima->repbind = NULL; } ima->tpageflag &= ~(IMA_MIPMAP_COMPLETE|IMA_GLBIND_IS_DATA); @@ -1293,20 +1342,20 @@ void GPU_free_image(Image *ima) void GPU_free_images(void) { - Image* ima; + Image *ima; if (G.main) - for (ima=G.main->image.first; ima; ima=ima->id.next) + for (ima = G.main->image.first; ima; ima = ima->id.next) GPU_free_image(ima); } /* same as above but only free animated images */ void GPU_free_images_anim(void) { - Image* ima; + Image *ima; if (G.main) - for (ima=G.main->image.first; ima; ima=ima->id.next) + for (ima = G.main->image.first; ima; ima = ima->id.next) if (BKE_image_is_animated(ima)) GPU_free_image(ima); } @@ -1352,7 +1401,7 @@ void GPU_free_images_old(void) /* OpenGL Materials */ -#define FIXEDMAT 8 +#define FIXEDMAT 8 /* OpenGL state caching for materials */ @@ -1367,15 +1416,21 @@ static struct GPUMaterialState { GPUMaterialFixed matbuf_fixed[FIXEDMAT]; int totmat; + /* set when called inside GPU_begin_object_materials / GPU_end_object_materials + * otherwise calling GPU_enable_material returns zero */ + bool is_enabled; + Material **gmatbuf; Material *gmatbuf_fixed[FIXEDMAT]; Material *gboundmat; Object *gob; + DupliObject *dob; Scene *gscene; int glay; bool gscenelock; float (*gviewmat)[4]; float (*gviewinv)[4]; + float (*gviewcamtexcofac); bool backface_culling; @@ -1386,30 +1441,50 @@ static struct GPUMaterialState { int lastmatnr, lastretval; GPUBlendMode lastalphablend; + bool is_opensubdiv; } GMS = {NULL}; /* fixed function material, alpha handed by caller */ -static void gpu_material_to_fixed(GPUMaterialFixed *smat, const Material *bmat, const int gamma, const Object *ob, const int new_shading_nodes) +static void gpu_material_to_fixed(GPUMaterialFixed *smat, const Material *bmat, const int gamma, const Object *ob, const int new_shading_nodes, + const bool dimdown) { - if (new_shading_nodes || bmat->mode & MA_SHLESS) { + if (bmat->mode & MA_SHLESS) { copy_v3_v3(smat->diff, &bmat->r); - smat->diff[3]= 1.0; + smat->diff[3] = 1.0; if (gamma) linearrgb_to_srgb_v3_v3(smat->diff, smat->diff); zero_v4(smat->spec); - smat->hard= 0; + smat->hard = 0; + } + else if (new_shading_nodes) { + copy_v3_v3(smat->diff, &bmat->r); + smat->diff[3] = 1.0; + + copy_v3_v3(smat->spec, &bmat->specr); + smat->spec[3] = 1.0; + smat->hard = CLAMPIS(bmat->har, 0, 128); + + if (dimdown) { + mul_v3_fl(smat->diff, 0.8f); + mul_v3_fl(smat->spec, 0.5f); + } + + if (gamma) { + linearrgb_to_srgb_v3_v3(smat->diff, smat->diff); + linearrgb_to_srgb_v3_v3(smat->spec, smat->spec); + } } else { mul_v3_v3fl(smat->diff, &bmat->r, bmat->ref + bmat->emit); - smat->diff[3]= 1.0; /* caller may set this to bmat->alpha */ + smat->diff[3] = 1.0; /* caller may set this to bmat->alpha */ if (bmat->shade_flag & MA_OBCOLOR) mul_v3_v3(smat->diff, ob->col); mul_v3_v3fl(smat->spec, &bmat->specr, bmat->spec); - smat->spec[3]= 1.0; /* always 1 */ + smat->spec[3] = 1.0; /* always 1 */ smat->hard= CLAMPIS(bmat->har, 0, 128); if (gamma) { @@ -1433,15 +1508,51 @@ static Material *gpu_active_node_material(Material *ma) return ma; } +void GPU_begin_dupli_object(DupliObject *dob) +{ + GMS.dob = dob; +} + +void GPU_end_dupli_object(void) +{ + GMS.dob = NULL; +} + void GPU_begin_object_materials(View3D *v3d, RegionView3D *rv3d, Scene *scene, Object *ob, bool glsl, bool *do_alpha_after) { Material *ma; GPUMaterial *gpumat; GPUBlendMode alphablend; + DupliObject *dob; int a; const bool gamma = BKE_scene_check_color_management_enabled(scene); const bool new_shading_nodes = BKE_scene_use_new_shading_nodes(scene); const bool use_matcap = (v3d->flag2 & V3D_SHOW_SOLID_MATCAP) != 0; /* assumes v3d->defmaterial->preview is set */ + bool use_opensubdiv = false; + +#ifdef WITH_OPENSUBDIV + { + DerivedMesh *derivedFinal = NULL; + if (ob->type == OB_MESH) { + Mesh *me = ob->data; + BMEditMesh *em = me->edit_btmesh; + if (em != NULL) { + derivedFinal = em->derivedFinal; + } + else { + derivedFinal = ob->derivedFinal; + } + } + else { + derivedFinal = ob->derivedFinal; + } + + if (derivedFinal != NULL && derivedFinal->type == DM_TYPE_CCGDM) { + CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) derivedFinal; + use_opensubdiv = ccgdm->useGpuBackend; + } + } +#endif #ifdef WITH_GAMEENGINE if (rv3d->rflag & RV3D_IS_GAME_ENGINE) { @@ -1450,7 +1561,11 @@ void GPU_begin_object_materials(View3D *v3d, RegionView3D *rv3d, Scene *scene, O #endif /* initialize state */ + /* DupliObject must be restored */ + dob = GMS.dob; memset(&GMS, 0, sizeof(GMS)); + GMS.is_enabled = true; + GMS.dob = dob; GMS.lastmatnr = -1; GMS.lastretval = -1; GMS.lastalphablend = GPU_BLEND_SOLID; @@ -1460,11 +1575,13 @@ void GPU_begin_object_materials(View3D *v3d, RegionView3D *rv3d, Scene *scene, O GMS.gob = ob; GMS.gscene = scene; + GMS.is_opensubdiv = use_opensubdiv; GMS.totmat = use_matcap ? 1 : ob->totcol + 1; /* materials start from 1, default material is 0 */ - GMS.glay= (v3d->localvd)? v3d->localvd->lay: v3d->lay; /* keep lamps visible in local view */ + GMS.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.gviewmat = rv3d->viewmat; + GMS.gviewinv = rv3d->viewinv; + GMS.gviewcamtexcofac = rv3d->viewcamtexcofac; /* alpha pass setup. there's various cases to handle here: * - object transparency on: only solid materials draw in the first pass, @@ -1477,68 +1594,68 @@ void GPU_begin_object_materials(View3D *v3d, RegionView3D *rv3d, Scene *scene, O *do_alpha_after = false; if (GMS.totmat > FIXEDMAT) { - GMS.matbuf= MEM_callocN(sizeof(GPUMaterialFixed)*GMS.totmat, "GMS.matbuf"); - GMS.gmatbuf= MEM_callocN(sizeof(*GMS.gmatbuf)*GMS.totmat, "GMS.matbuf"); - GMS.alphablend= MEM_callocN(sizeof(*GMS.alphablend)*GMS.totmat, "GMS.matbuf"); + GMS.matbuf = MEM_callocN(sizeof(GPUMaterialFixed) * GMS.totmat, "GMS.matbuf"); + GMS.gmatbuf = MEM_callocN(sizeof(*GMS.gmatbuf) * GMS.totmat, "GMS.matbuf"); + GMS.alphablend = MEM_callocN(sizeof(*GMS.alphablend) * GMS.totmat, "GMS.matbuf"); } else { - GMS.matbuf= GMS.matbuf_fixed; - GMS.gmatbuf= GMS.gmatbuf_fixed; - GMS.alphablend= GMS.alphablend_fixed; + GMS.matbuf = GMS.matbuf_fixed; + GMS.gmatbuf = GMS.gmatbuf_fixed; + GMS.alphablend = GMS.alphablend_fixed; } /* viewport material, setup in space_view3d, defaults to matcap using ma->preview now */ if (use_matcap) { GMS.gmatbuf[0] = v3d->defmaterial; - GPU_material_matcap(scene, v3d->defmaterial); + GPU_material_matcap(scene, v3d->defmaterial, use_opensubdiv); /* do material 1 too, for displists! */ memcpy(&GMS.matbuf[1], &GMS.matbuf[0], sizeof(GPUMaterialFixed)); - GMS.alphablend[0]= GPU_BLEND_SOLID; + 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); + if (ob->totcol == 0) { + gpu_material_to_fixed(&GMS.matbuf[0], &defmaterial, 0, ob, new_shading_nodes, true); /* do material 1 too, for displists! */ memcpy(&GMS.matbuf[1], &GMS.matbuf[0], sizeof(GPUMaterialFixed)); if (glsl) { - GMS.gmatbuf[0]= &defmaterial; - GPU_material_from_blender(GMS.gscene, &defmaterial); + GMS.gmatbuf[0] = &defmaterial; + GPU_material_from_blender(GMS.gscene, &defmaterial, GMS.is_opensubdiv); } - GMS.alphablend[0]= GPU_BLEND_SOLID; + GMS.alphablend[0] = GPU_BLEND_SOLID; } /* setup materials */ - for (a=1; a<=ob->totcol; a++) { + for (a = 1; a <= ob->totcol; a++) { /* find a suitable material */ - ma= give_current_material(ob, a); - if (!glsl && !new_shading_nodes) ma= gpu_active_node_material(ma); - if (ma==NULL) ma= &defmaterial; + ma = give_current_material(ob, a); + if (!glsl && !new_shading_nodes) ma = gpu_active_node_material(ma); + if (ma == NULL) ma = &defmaterial; /* create glsl material if requested */ - gpumat = (glsl)? GPU_material_from_blender(GMS.gscene, ma): NULL; + gpumat = glsl? GPU_material_from_blender(GMS.gscene, ma, GMS.is_opensubdiv): NULL; if (gpumat) { /* do glsl only if creating it succeed, else fallback */ - GMS.gmatbuf[a]= ma; + GMS.gmatbuf[a] = ma; alphablend = GPU_material_alpha_blend(gpumat, ob->col); } else { /* fixed function opengl materials */ - gpu_material_to_fixed(&GMS.matbuf[a], ma, gamma, ob, new_shading_nodes); + gpu_material_to_fixed(&GMS.matbuf[a], ma, gamma, ob, new_shading_nodes, false); if (GMS.use_alpha_pass && ((ma->mode & MA_TRANSP) || (new_shading_nodes && ma->alpha != 1.0f))) { - GMS.matbuf[a].diff[3]= ma->alpha; + GMS.matbuf[a].diff[3] = ma->alpha; alphablend = (ma->alpha == 1.0f)? GPU_BLEND_SOLID: GPU_BLEND_ALPHA; } else { - GMS.matbuf[a].diff[3]= 1.0f; + GMS.matbuf[a].diff[3] = 1.0f; alphablend = GPU_BLEND_SOLID; } } @@ -1549,14 +1666,44 @@ void GPU_begin_object_materials(View3D *v3d, RegionView3D *rv3d, Scene *scene, O if (ELEM(alphablend, GPU_BLEND_ALPHA, GPU_BLEND_ADD, GPU_BLEND_ALPHA_SORT)) *do_alpha_after = true; - GMS.alphablend[a]= alphablend; + GMS.alphablend[a] = alphablend; } } - + /* let's start with a clean state */ GPU_disable_material(); } +static int GPU_get_particle_info(GPUParticleInfo *pi) +{ + ParticleData *p; + DupliObject *dob = GMS.dob; + int ind; + if (dob->particle_system) { + if (dob->persistent_id[0] < dob->particle_system->totpart) + ind = dob->persistent_id[0]; + else { + ind = dob->particle_system->child[dob->persistent_id[0] - dob->particle_system->totpart].parent; + } + if (ind >= 0) { + p = &dob->particle_system->particles[ind]; + + pi->scalprops[0] = ind; + pi->scalprops[1] = GMS.gscene->r.cfra - p->time; + pi->scalprops[2] = p->lifetime; + pi->scalprops[3] = p->size; + + copy_v3_v3(pi->location, p->state.co); + copy_v3_v3(pi->velocity, p->state.vel); + copy_v3_v3(pi->angular_velocity, p->state.ave); + return 1; + } + else return 0; + } + else + return 0; +} + int GPU_enable_material(int nr, void *attribs) { GPUVertexAttribs *gattribs = attribs; @@ -1570,10 +1717,10 @@ int GPU_enable_material(int nr, void *attribs) memset(&GMS, 0, sizeof(GMS)); mul_v3_v3fl(diff, &defmaterial.r, defmaterial.ref + defmaterial.emit); - diff[3]= 1.0; + diff[3] = 1.0; mul_v3_v3fl(spec, &defmaterial.specr, defmaterial.spec); - spec[3]= 1.0; + spec[3] = 1.0; glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, diff); glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, spec); @@ -1583,21 +1730,21 @@ int GPU_enable_material(int nr, void *attribs) } /* prevent index to use un-initialized array items */ - if (nr>=GMS.totmat) - nr= 0; + if (nr >= GMS.totmat) + nr = 0; if (gattribs) memset(gattribs, 0, sizeof(*gattribs)); /* keep current material */ - if (nr==GMS.lastmatnr) + if (nr == GMS.lastmatnr) return GMS.lastretval; /* unbind glsl material */ if (GMS.gboundmat) { if (GMS.is_alpha_pass) glDepthMask(0); - GPU_material_unbind(GPU_material_from_blender(GMS.gscene, GMS.gboundmat)); - GMS.gboundmat= NULL; + GPU_material_unbind(GPU_material_from_blender(GMS.gscene, GMS.gboundmat, GMS.is_opensubdiv)); + GMS.gboundmat = NULL; } /* draw materials with alpha in alpha pass */ @@ -1619,15 +1766,21 @@ int GPU_enable_material(int nr, void *attribs) if (gattribs && GMS.gmatbuf[nr]) { /* bind glsl material and get attributes */ Material *mat = GMS.gmatbuf[nr]; + GPUParticleInfo partile_info; + float auto_bump_scale; - gpumat = GPU_material_from_blender(GMS.gscene, mat); + gpumat = GPU_material_from_blender(GMS.gscene, mat, GMS.is_opensubdiv); GPU_material_vertex_attributes(gpumat, gattribs); - GPU_material_bind(gpumat, GMS.gob->lay, GMS.glay, 1.0, !(GMS.gob->mode & OB_MODE_TEXTURE_PAINT), GMS.gviewmat, GMS.gviewinv, GMS.gscenelock); + + if (GMS.dob) + GPU_get_particle_info(&partile_info); + + GPU_material_bind(gpumat, GMS.gob->lay, GMS.glay, 1.0, !(GMS.gob->mode & OB_MODE_TEXTURE_PAINT), GMS.gviewmat, GMS.gviewinv, GMS.gviewcamtexcofac, GMS.gscenelock); auto_bump_scale = GMS.gob->derivedFinal != NULL ? GMS.gob->derivedFinal->auto_bump_scale : 1.0f; - GPU_material_bind_uniforms(gpumat, GMS.gob->obmat, GMS.gob->col, auto_bump_scale); - GMS.gboundmat= mat; + GPU_material_bind_uniforms(gpumat, GMS.gob->obmat, GMS.gob->col, auto_bump_scale, &partile_info); + GMS.gboundmat = mat; /* for glsl use alpha blend mode, unless it's set to solid and * we are already drawing in an alpha pass */ @@ -1644,7 +1797,7 @@ int GPU_enable_material(int nr, void *attribs) } if (GMS.use_matcaps) - glColor3f(1.0, 1.0, 1.0f); + glColor3f(1.0f, 1.0f, 1.0f); } else { /* or do fixed function opengl material */ @@ -1676,16 +1829,16 @@ int GPU_get_material_alpha_blend(void) void GPU_disable_material(void) { - GMS.lastmatnr= -1; - GMS.lastretval= 1; + GMS.lastmatnr = -1; + GMS.lastretval = 1; if (GMS.gboundmat) { if (GMS.backface_culling) glDisable(GL_CULL_FACE); if (GMS.is_alpha_pass) glDepthMask(0); - GPU_material_unbind(GPU_material_from_blender(GMS.gscene, GMS.gboundmat)); - GMS.gboundmat= NULL; + GPU_material_unbind(GPU_material_from_blender(GMS.gscene, GMS.gboundmat, GMS.is_opensubdiv)); + GMS.gboundmat = NULL; } GPU_set_material_alpha_blend(GPU_BLEND_SOLID); @@ -1711,20 +1864,26 @@ bool GPU_material_use_matcaps_get(void) return GMS.use_matcaps; } +bool GPU_object_materials_check(void) +{ + return GMS.is_enabled; +} void GPU_end_object_materials(void) { GPU_disable_material(); + GMS.is_enabled = false; + if (GMS.matbuf && GMS.matbuf != GMS.matbuf_fixed) { MEM_freeN(GMS.matbuf); MEM_freeN(GMS.gmatbuf); MEM_freeN(GMS.alphablend); } - GMS.matbuf= NULL; - GMS.gmatbuf= NULL; - GMS.alphablend= NULL; + GMS.matbuf = NULL; + GMS.gmatbuf = NULL; + GMS.alphablend = NULL; /* resetting the texture matrix after the scaling needed for tiled textures */ if (GTS.tilemode) { @@ -1742,57 +1901,57 @@ int GPU_default_lights(void) int a, count = 0; /* initialize */ - if (U.light[0].flag==0 && U.light[1].flag==0 && U.light[2].flag==0) { - U.light[0].flag= 1; - U.light[0].vec[0]= -0.3; U.light[0].vec[1]= 0.3; U.light[0].vec[2]= 0.9; - U.light[0].col[0]= 0.8; U.light[0].col[1]= 0.8; U.light[0].col[2]= 0.8; - U.light[0].spec[0]= 0.5; U.light[0].spec[1]= 0.5; U.light[0].spec[2]= 0.5; - U.light[0].spec[3]= 1.0; + if (U.light[0].flag == 0 && U.light[1].flag == 0 && U.light[2].flag == 0) { + U.light[0].flag = 1; + U.light[0].vec[0] = -0.3; U.light[0].vec[1] = 0.3; U.light[0].vec[2] = 0.9; + U.light[0].col[0] = 0.8; U.light[0].col[1] = 0.8; U.light[0].col[2] = 0.8; + U.light[0].spec[0] = 0.5; U.light[0].spec[1] = 0.5; U.light[0].spec[2] = 0.5; + U.light[0].spec[3] = 1.0; - U.light[1].flag= 0; - U.light[1].vec[0]= 0.5; U.light[1].vec[1]= 0.5; U.light[1].vec[2]= 0.1; - U.light[1].col[0]= 0.4; U.light[1].col[1]= 0.4; U.light[1].col[2]= 0.8; - U.light[1].spec[0]= 0.3; U.light[1].spec[1]= 0.3; U.light[1].spec[2]= 0.5; - U.light[1].spec[3]= 1.0; + U.light[1].flag = 0; + U.light[1].vec[0] = 0.5; U.light[1].vec[1] = 0.5; U.light[1].vec[2] = 0.1; + U.light[1].col[0] = 0.4; U.light[1].col[1] = 0.4; U.light[1].col[2] = 0.8; + U.light[1].spec[0] = 0.3; U.light[1].spec[1] = 0.3; U.light[1].spec[2] = 0.5; + U.light[1].spec[3] = 1.0; - U.light[2].flag= 0; - U.light[2].vec[0]= 0.3; U.light[2].vec[1]= -0.3; U.light[2].vec[2]= -0.2; - U.light[2].col[0]= 0.8; U.light[2].col[1]= 0.5; U.light[2].col[2]= 0.4; - U.light[2].spec[0]= 0.5; U.light[2].spec[1]= 0.4; U.light[2].spec[2]= 0.3; - U.light[2].spec[3]= 1.0; + U.light[2].flag = 0; + U.light[2].vec[0] = 0.3; U.light[2].vec[1] = -0.3; U.light[2].vec[2] = -0.2; + U.light[2].col[0] = 0.8; U.light[2].col[1] = 0.5; U.light[2].col[2] = 0.4; + U.light[2].spec[0] = 0.5; U.light[2].spec[1] = 0.4; U.light[2].spec[2] = 0.3; + U.light[2].spec[3] = 1.0; } glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_FALSE); - for (a=0; a<8; a++) { - if (a<3) { + for (a = 0; a < 8; a++) { + if (a < 3) { if (U.light[a].flag) { - glEnable(GL_LIGHT0+a); + glEnable(GL_LIGHT0 + a); normalize_v3_v3(position, U.light[a].vec); - position[3]= 0.0f; + position[3] = 0.0f; - glLightfv(GL_LIGHT0+a, GL_POSITION, position); - glLightfv(GL_LIGHT0+a, GL_DIFFUSE, U.light[a].col); - glLightfv(GL_LIGHT0+a, GL_SPECULAR, U.light[a].spec); + glLightfv(GL_LIGHT0 + a, GL_POSITION, position); + glLightfv(GL_LIGHT0 + a, GL_DIFFUSE, U.light[a].col); + glLightfv(GL_LIGHT0 + a, GL_SPECULAR, U.light[a].spec); count++; } else { - glDisable(GL_LIGHT0+a); + glDisable(GL_LIGHT0 + a); - glLightfv(GL_LIGHT0+a, GL_POSITION, zero); - glLightfv(GL_LIGHT0+a, GL_DIFFUSE, zero); - glLightfv(GL_LIGHT0+a, GL_SPECULAR, zero); + glLightfv(GL_LIGHT0 + a, GL_POSITION, zero); + glLightfv(GL_LIGHT0 + a, GL_DIFFUSE, zero); + glLightfv(GL_LIGHT0 + a, GL_SPECULAR, zero); } - // clear stuff from other opengl lamp usage - glLightf(GL_LIGHT0+a, GL_SPOT_CUTOFF, 180.0); - glLightf(GL_LIGHT0+a, GL_CONSTANT_ATTENUATION, 1.0); - glLightf(GL_LIGHT0+a, GL_LINEAR_ATTENUATION, 0.0); + /* clear stuff from other opengl lamp usage */ + glLightf(GL_LIGHT0 + a, GL_SPOT_CUTOFF, 180.0); + glLightf(GL_LIGHT0 + a, GL_CONSTANT_ATTENUATION, 1.0); + glLightf(GL_LIGHT0 + a, GL_LINEAR_ATTENUATION, 0.0); } else - glDisable(GL_LIGHT0+a); + glDisable(GL_LIGHT0 + a); } glDisable(GL_LIGHTING); @@ -1810,74 +1969,105 @@ int GPU_scene_object_lights(Scene *scene, Object *ob, int lay, float viewmat[4][ float position[4], direction[4], energy[4]; /* disable all lights */ - for (count=0; count<8; count++) - glDisable(GL_LIGHT0+count); + for (count = 0; count < 8; count++) + glDisable(GL_LIGHT0 + count); - /* view direction for specular is not compute correct by default in + /* view direction for specular is not computed correct by default in * opengl, so we set the settings ourselfs */ - glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, (ortho)? GL_FALSE: GL_TRUE); + glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, ortho ? GL_FALSE : GL_TRUE); - count= 0; - - for (base=scene->base.first; base; base=base->next) { - if (base->object->type!=OB_LAMP) + count = 0; + + for (base = scene->base.first; base; base = base->next) { + if (base->object->type != OB_LAMP) continue; if (!(base->lay & lay) || !(base->lay & ob->lay)) continue; - la= base->object->data; + la = base->object->data; /* setup lamp transform */ glPushMatrix(); glLoadMatrixf((float *)viewmat); - if (la->type==LA_SUN) { + if (la->type == LA_SUN) { /* sun lamp */ copy_v3_v3(direction, base->object->obmat[2]); - direction[3]= 0.0; + direction[3] = 0.0; glLightfv(GL_LIGHT0+count, GL_POSITION, direction); } else { /* other lamps with attenuation */ copy_v3_v3(position, base->object->obmat[3]); - position[3]= 1.0f; + position[3] = 1.0f; glLightfv(GL_LIGHT0+count, GL_POSITION, position); glLightf(GL_LIGHT0+count, GL_CONSTANT_ATTENUATION, 1.0); - glLightf(GL_LIGHT0+count, GL_LINEAR_ATTENUATION, la->att1/la->dist); - glLightf(GL_LIGHT0+count, GL_QUADRATIC_ATTENUATION, la->att2/(la->dist*la->dist)); + glLightf(GL_LIGHT0+count, GL_LINEAR_ATTENUATION, la->att1 / la->dist); + glLightf(GL_LIGHT0+count, GL_QUADRATIC_ATTENUATION, la->att2 / (la->dist * la->dist)); - if (la->type==LA_SPOT) { + if (la->type == LA_SPOT) { /* spot lamp */ negate_v3_v3(direction, base->object->obmat[2]); - glLightfv(GL_LIGHT0+count, GL_SPOT_DIRECTION, direction); - glLightf(GL_LIGHT0+count, GL_SPOT_CUTOFF, RAD2DEGF(la->spotsize * 0.5f)); - glLightf(GL_LIGHT0+count, GL_SPOT_EXPONENT, 128.0f*la->spotblend); + glLightfv(GL_LIGHT0 + count, GL_SPOT_DIRECTION, direction); + glLightf(GL_LIGHT0 + count, GL_SPOT_CUTOFF, RAD2DEGF(la->spotsize * 0.5f)); + glLightf(GL_LIGHT0 + count, GL_SPOT_EXPONENT, 128.0f * la->spotblend); } else - glLightf(GL_LIGHT0+count, GL_SPOT_CUTOFF, 180.0); + glLightf(GL_LIGHT0 + count, GL_SPOT_CUTOFF, 180.0); } /* setup energy */ mul_v3_v3fl(energy, &la->r, la->energy); - energy[3]= 1.0; + energy[3] = 1.0; - glLightfv(GL_LIGHT0+count, GL_DIFFUSE, energy); - glLightfv(GL_LIGHT0+count, GL_SPECULAR, energy); - glEnable(GL_LIGHT0+count); + glLightfv(GL_LIGHT0 + count, GL_DIFFUSE, energy); + glLightfv(GL_LIGHT0 + count, GL_SPECULAR, energy); + glEnable(GL_LIGHT0 + count); glPopMatrix(); count++; - if (count==8) + if (count == 8) break; } return count; } +static void gpu_multisample(bool enable) +{ + if (GLEW_VERSION_1_3 || GLEW_ARB_multisample) { +#ifdef __linux__ + /* changing multisample from the default (enabled) causes problems on some + * systems (NVIDIA/Linux) when the pixel format doesn't have a multisample buffer */ + bool toggle_ok = true; + + if (GPU_type_matches(GPU_DEVICE_NVIDIA, GPU_OS_UNIX, GPU_DRIVER_ANY)) { + int samples = 0; + glGetIntegerv(GL_SAMPLES, &samples); + + if (samples == 0) + toggle_ok = false; + } + + if (toggle_ok) { + if (enable) + glEnable(GL_MULTISAMPLE); + else + glDisable(GL_MULTISAMPLE); + } +#else + if (enable) + glEnable(GL_MULTISAMPLE); + else + glDisable(GL_MULTISAMPLE); +#endif + } +} + /* Default OpenGL State */ void GPU_state_init(void) @@ -1886,8 +2076,8 @@ 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 }; int a, x, y; - GLubyte pat[32*32]; - const GLubyte *patc= pat; + GLubyte pat[32 * 32]; + const GLubyte *patc = pat; glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, mat_ambient); glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mat_specular); @@ -1932,14 +2122,14 @@ void GPU_state_init(void) glPixelTransferi(GL_DEPTH_SCALE, 1); glDepthRange(0.0, 1.0); - a= 0; - for (x=0; x<32; x++) { - for (y=0; y<4; y++) { - if ( (x) & 1) pat[a++]= 0x88; - else pat[a++]= 0x22; + a = 0; + for (x = 0; x < 32; x++) { + for (y = 0; y < 4; y++) { + if (x & 1) pat[a++] = 0x88; + else pat[a++] = 0x22; } } - + glPolygonStipple(patc); glMatrixMode(GL_TEXTURE); @@ -1950,395 +2140,34 @@ void GPU_state_init(void) glCullFace(GL_BACK); glDisable(GL_CULL_FACE); - /* calling this makes drawing very slow when AA is not set up in ghost - * on Linux/NVIDIA. */ - // glDisable(GL_MULTISAMPLE); + gpu_multisample(false); } -#ifdef DEBUG -/* debugging aid */ -static void gpu_state_print_fl_ex(const char *name, GLenum type) +#ifdef WITH_OPENSUBDIV +/* Update face-varying variables offset which might be + * different from mesh to mesh sharing the same material. + */ +void GPU_draw_update_fvar_offset(DerivedMesh *dm) { - const unsigned char err_mark[4] = {0xff, 0xff, 0xff, 0xff}; + int i; - float value[32]; - int a; + /* Sanity check to be sure we only do this for OpenSubdiv draw. */ + BLI_assert(dm->type == DM_TYPE_CCGDM); + BLI_assert(GMS.is_opensubdiv); - memset(value, 0xff, sizeof(value)); - glGetFloatv(type, value); + for (i = 0; i < GMS.totmat; ++i) { + Material *material = GMS.gmatbuf[i]; + GPUMaterial *gpu_material; - printf("%s: ", name); - for (a = 0; a < 32; a++) { - if (memcmp(&value[a], err_mark, sizeof(value[a])) == 0) { - break; + if (material == NULL) { + continue; } - printf("%.2f ", value[a]); - } - printf("\n"); -} -#define gpu_state_print_fl(val) gpu_state_print_fl_ex(#val, val) + gpu_material = GPU_material_from_blender(GMS.gscene, + material, + GMS.is_opensubdiv); -void GPU_state_print(void) -{ - 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_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); - 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_MULTISAMPLE_ARB); - 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_CUBE_MAP_ARB); - 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); + GPU_material_update_fvar_offset(gpu_material, dm); + } } - -#undef gpu_state_print_fl - #endif diff --git a/source/blender/gpu/intern/gpu_extensions.c b/source/blender/gpu/intern/gpu_extensions.c index 17c495c82d6..e30eeebf934 100644 --- a/source/blender/gpu/intern/gpu_extensions.c +++ b/source/blender/gpu/intern/gpu_extensions.c @@ -33,8 +33,6 @@ */ -#include "GL/glew.h" - #include "DNA_image_types.h" #include "MEM_guardedalloc.h" @@ -42,13 +40,18 @@ #include "BLI_blenlib.h" #include "BLI_utildefines.h" #include "BLI_math_base.h" +#include "BLI_math_vector.h" #include "BKE_global.h" +#include "GPU_glew.h" +#include "GPU_debug.h" #include "GPU_draw.h" #include "GPU_extensions.h" +#include "GPU_compositing.h" #include "GPU_simple_shader.h" -#include "gpu_codegen.h" + +#include "intern/gpu_private.h" #include <stdlib.h> #include <stdio.h> @@ -58,7 +61,9 @@ # include "BLI_winstuff.h" #endif -#define MAX_DEFINE_LENGTH 72 +/* TODO(sergey): Find better default values for this constants. */ +#define MAX_DEFINE_LENGTH 1024 +#define MAX_EXT_DEFINE_LENGTH 1024 /* Extensions support */ @@ -73,14 +78,29 @@ */ /* Non-generated shaders */ +extern char datatoc_gpu_program_smoke_frag_glsl[]; +extern char datatoc_gpu_program_smoke_color_frag_glsl[]; extern char datatoc_gpu_shader_vsm_store_vert_glsl[]; extern char datatoc_gpu_shader_vsm_store_frag_glsl[]; extern char datatoc_gpu_shader_sep_gaussian_blur_vert_glsl[]; extern char datatoc_gpu_shader_sep_gaussian_blur_frag_glsl[]; +extern char datatoc_gpu_shader_fx_vert_glsl[]; +extern char datatoc_gpu_shader_fx_ssao_frag_glsl[]; +extern char datatoc_gpu_shader_fx_dof_frag_glsl[]; +extern char datatoc_gpu_shader_fx_dof_vert_glsl[]; +extern char datatoc_gpu_shader_fx_dof_hq_frag_glsl[]; +extern char datatoc_gpu_shader_fx_dof_hq_vert_glsl[]; +extern char datatoc_gpu_shader_fx_dof_hq_geo_glsl[]; +extern char datatoc_gpu_shader_fx_depth_resolve_glsl[]; +extern char datatoc_gpu_shader_fx_lib_glsl[]; typedef struct GPUShaders { GPUShader *vsm_store; GPUShader *sep_gaussian_blur; + GPUProgram *smoke; + GPUProgram *smoke_colored; + /* cache for shader fx. Those can exist in combinations so store them here */ + GPUShader *fx_shaders[MAX_FX_SHADERS * 2]; } GPUShaders; static struct GPUGlobal { @@ -99,19 +119,30 @@ static struct GPUGlobal { GPUTexture *invalid_tex_1D; /* texture used in place of invalid textures (not loaded correctly, missing) */ GPUTexture *invalid_tex_2D; GPUTexture *invalid_tex_3D; + float dfdyfactors[2]; /* workaround for different calculation of dfdy factors on GPUs. Some GPUs/drivers + calculate dfdy in shader differently when drawing to an offscreen buffer. First + number is factor on screen and second is off-screen */ } GG = {1, 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 + +struct GPUFrameBuffer { + GLuint object; + GPUTexture *colortex[GPU_FB_MAX_SLOTS]; + GPUTexture *depthtex; +}; + + /* GPU Types */ -int GPU_type_matches(GPUDeviceType device, GPUOSType os, GPUDriverType driver) +bool GPU_type_matches(GPUDeviceType device, GPUOSType os, GPUDriverType driver) { return (GG.device & device) && (GG.os & os) && (GG.driver & driver); } /* GPU Extensions */ -static int gpu_extensions_init = 0; - void GPU_extensions_disable(void) { GG.extdisabled = 1; @@ -122,17 +153,15 @@ int GPU_max_texture_size(void) return GG.maxtexsize; } -void GPU_extensions_init(void) +void GPU_get_dfdy_factors(float fac[2]) { - GLint r, g, b; - const char *vendor, *renderer; - - /* can't avoid calling this multiple times, see wm_window_add_ghostwindow */ - if (gpu_extensions_init) return; - gpu_extensions_init= 1; + copy_v2_v2(fac, GG.dfdyfactors); +} - glewInit(); - GPU_codegen_init(); +void gpu_extensions_init(void) +{ + GLint r, g, b; + const char *vendor, *renderer, *version; /* glewIsSupported("GL_VERSION_2_0") */ @@ -149,10 +178,11 @@ void GPU_extensions_init(void) 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 */ + GG.colordepth = r + g + b; /* assumes same depth for RGB */ vendor = (const char *)glGetString(GL_VENDOR); renderer = (const char *)glGetString(GL_RENDERER); + version = (const char *)glGetString(GL_VERSION); if (strstr(vendor, "ATI")) { GG.device = GPU_DEVICE_ATI; @@ -229,85 +259,110 @@ void GPU_extensions_init(void) #endif + /* df/dy calculation factors, those are dependent on driver */ + if ((strstr(vendor, "ATI") && strstr(version, "3.3.10750"))) { + GG.dfdyfactors[0] = 1.0; + GG.dfdyfactors[1] = -1.0; + } + else if (GG.device == GPU_DEVICE_INTEL && GG.os == GPU_OS_WIN && + (strstr(version, "4.0.0 - Build 10.18.10.3308") || + strstr(version, "4.0.0 - Build 9.18.10.3186") || + strstr(version, "4.0.0 - Build 9.18.10.3165") || + strstr(version, "3.1.0 - Build 9.17.10.3347") || + strstr(version, "3.1.0 - Build 9.17.10.4101"))) + { + GG.dfdyfactors[0] = -1.0; + GG.dfdyfactors[1] = 1.0; + } + else { + GG.dfdyfactors[0] = 1.0; + GG.dfdyfactors[1] = 1.0; + } + + GPU_invalid_tex_init(); GPU_simple_shaders_init(); } -void GPU_extensions_exit(void) +void gpu_extensions_exit(void) { - gpu_extensions_init = 0; - GPU_codegen_exit(); GPU_simple_shaders_exit(); GPU_invalid_tex_free(); } -int GPU_glsl_support(void) +bool GPU_glsl_support(void) { return !GG.extdisabled && GG.glslsupport; } -int GPU_non_power_of_two_support(void) +bool GPU_non_power_of_two_support(void) { if (GG.npotdisabled) - return 0; + return false; return GLEW_ARB_texture_non_power_of_two; } -int GPU_display_list_support(void) +bool GPU_vertex_buffer_support(void) +{ + return GLEW_ARB_vertex_buffer_object || GLEW_VERSION_1_5; +} + +bool GPU_display_list_support(void) { return !GG.dlistsdisabled; } -int GPU_color_depth(void) +bool GPU_bicubic_bump_support(void) { - return GG.colordepth; + return GLEW_ARB_texture_query_lod && GLEW_VERSION_3_0; } -int GPU_print_error(const char *str) +bool GPU_geometry_shader_support(void) { - GLenum errCode; + return GLEW_EXT_geometry_shader4 || GLEW_VERSION_3_2; +} - if (G.debug & G_DEBUG) { - if ((errCode = glGetError()) != GL_NO_ERROR) { - fprintf(stderr, "%s opengl error: %s\n", str, gluErrorString(errCode)); - return 1; - } - } +bool GPU_instanced_drawing_support(void) +{ + return GLEW_ARB_draw_instanced; +} - return 0; +int GPU_color_depth(void) +{ + return GG.colordepth; } static void GPU_print_framebuffer_error(GLenum status, char err_out[256]) { - const char *err= "unknown"; + const char *err = "unknown"; switch (status) { case GL_FRAMEBUFFER_COMPLETE_EXT: break; case GL_INVALID_OPERATION: - err= "Invalid operation"; + err = "Invalid operation"; break; case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT: - err= "Incomplete attachment"; + err = "Incomplete attachment"; break; case GL_FRAMEBUFFER_UNSUPPORTED_EXT: - err= "Unsupported framebuffer format"; + err = "Unsupported framebuffer format"; break; case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT: - err= "Missing attachment"; + err = "Missing attachment"; break; case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT: - err= "Attached images must have same dimensions"; + err = "Attached images must have same dimensions"; break; case GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT: - err= "Attached images must have same format"; + err = "Attached images must have same format"; break; case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT: - err= "Missing draw buffer"; + err = "Missing draw buffer"; break; case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT: - err= "Missing read buffer"; + err = "Missing read buffer"; break; } @@ -324,28 +379,30 @@ static void GPU_print_framebuffer_error(GLenum status, char err_out[256]) /* GPUTexture */ struct GPUTexture { - int w, h; /* width/height */ - int number; /* number for multitexture binding */ - int refcount; /* reference count */ - GLenum target; /* GL_TEXTURE_* */ - GLuint bindcode; /* opengl identifier for texture */ - int fromblender; /* we got the texture from Blender */ - - GPUFrameBuffer *fb; /* GPUFramebuffer this texture is attached to */ - int depth; /* is a depth texture? */ + int w, h; /* width/height */ + int w_orig, h_orig; /* width/height (before power of 2 is applied) */ + int number; /* number for multitexture binding */ + int refcount; /* reference count */ + GLenum target; /* GL_TEXTURE_* */ + GLuint bindcode; /* opengl identifier for texture */ + int fromblender; /* we got the texture from Blender */ + + GPUFrameBuffer *fb; /* GPUFramebuffer this texture is attached to */ + int fb_attachment; /* slot the texture is attached to */ + int depth; /* is a depth texture? if 3D how deep? */ + int depth_orig; /* depth (before power of 2 is applied) */ }; -static unsigned char *GPU_texture_convert_pixels(int length, float *fpixels) +static unsigned char *GPU_texture_convert_pixels(int length, const float *fpixels) { unsigned char *pixels, *p; - const float *fp; - int a, len; + const float *fp = fpixels; + const int len = 4 * length; + int a; - len = 4*length; - fp = fpixels; - p = pixels = MEM_callocN(sizeof(unsigned char)*len, "GPUTexturePixels"); + p = pixels = MEM_callocN(sizeof(unsigned char) * len, "GPUTexturePixels"); - for (a=0; a<len; a++, p++, fp++) + for (a = 0; a < len; a++, p++, fp++) *p = FTOCHAR((*fp)); return pixels; @@ -353,7 +410,7 @@ static unsigned char *GPU_texture_convert_pixels(int length, float *fpixels) static void GPU_glTexSubImageEmpty(GLenum target, GLenum format, int x, int y, int w, int h) { - void *pixels = MEM_callocN(sizeof(char)*4*w*h, "GPUTextureEmptyPixels"); + void *pixels = MEM_callocN(sizeof(char) * 4 * w * h, "GPUTextureEmptyPixels"); if (target == GL_TEXTURE_1D) glTexSubImage1D(target, 0, x, w, format, GL_UNSIGNED_BYTE, pixels); @@ -363,7 +420,9 @@ static void GPU_glTexSubImageEmpty(GLenum target, GLenum format, int x, int y, i MEM_freeN(pixels); } -static GPUTexture *GPU_texture_create_nD(int w, int h, int n, float *fpixels, int depth, char err_out[256]) +static GPUTexture *GPU_texture_create_nD( + int w, int h, int n, const float *fpixels, int depth, GPUHDRType hdr_type, int components, + char err_out[256]) { GPUTexture *tex; GLenum type, format, internalformat; @@ -373,12 +432,13 @@ static GPUTexture *GPU_texture_create_nD(int w, int h, int n, float *fpixels, in return NULL; tex = MEM_callocN(sizeof(GPUTexture), "GPUTexture"); - tex->w = w; - tex->h = h; + tex->w = tex->w_orig = w; + tex->h = tex->h_orig = h; tex->number = -1; tex->refcount = 1; tex->target = (n == 1)? GL_TEXTURE_1D: GL_TEXTURE_2D; - tex->depth = depth; + tex->depth = tex->depth_orig = depth; + tex->fb_attachment = -1; glGenTextures(1, &tex->bindcode); @@ -409,12 +469,45 @@ static GPUTexture *GPU_texture_create_nD(int w, int h, int n, float *fpixels, in internalformat = GL_DEPTH_COMPONENT; } else { - type = GL_UNSIGNED_BYTE; - format = GL_RGBA; - internalformat = GL_RGBA8; + type = GL_FLOAT; + + if (components == 4) { + format = GL_RGBA; + switch (hdr_type) { + case GPU_HDR_NONE: + internalformat = GL_RGBA8; + break; + case GPU_HDR_HALF_FLOAT: + internalformat = GL_RGBA16F; + break; + case GPU_HDR_FULL_FLOAT: + internalformat = GL_RGBA32F; + break; + default: + break; + } + } + else if (components == 2) { + 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; + } + } - if (fpixels) + if (fpixels && hdr_type == GPU_HDR_NONE) { + type = GL_UNSIGNED_BYTE; pixels = GPU_texture_convert_pixels(w*h, fpixels); + } } if (tex->target == GL_TEXTURE_1D) { @@ -460,15 +553,8 @@ static GPUTexture *GPU_texture_create_nD(int w, int h, int n, float *fpixels, in } if (tex->target != GL_TEXTURE_1D) { - /* CLAMP_TO_BORDER is an OpenGL 1.3 core feature */ - GLenum wrapmode = (depth || tex->h == 1)? GL_CLAMP_TO_EDGE: GL_CLAMP_TO_BORDER; - glTexParameteri(tex->target, GL_TEXTURE_WRAP_S, wrapmode); - glTexParameteri(tex->target, GL_TEXTURE_WRAP_T, wrapmode); - -#if 0 - float borderColor[] = { 1.0f, 1.0f, 1.0f, 1.0f }; - glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, borderColor); -#endif + glTexParameteri(tex->target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(tex->target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); } else glTexParameteri(tex->target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); @@ -477,20 +563,21 @@ static GPUTexture *GPU_texture_create_nD(int w, int h, int n, float *fpixels, in } -GPUTexture *GPU_texture_create_3D(int w, int h, int depth, int channels, float *fpixels) +GPUTexture *GPU_texture_create_3D(int w, int h, int depth, int channels, const float *fpixels) { GPUTexture *tex; GLenum type, format, internalformat; void *pixels = NULL; - float vfBorderColor[4] = {0.0f, 0.0f, 0.0f, 0.0f}; + int r_width; + bool rescale = false; if (!GLEW_VERSION_1_2) return NULL; tex = MEM_callocN(sizeof(GPUTexture), "GPUTexture"); - tex->w = w; - tex->h = h; - tex->depth = depth; + tex->w = tex->w_orig = w; + tex->h = tex->h_orig = h; + tex->depth = tex->depth_orig = depth; tex->number = -1; tex->refcount = 1; tex->target = GL_TEXTURE_3D; @@ -513,7 +600,7 @@ GPUTexture *GPU_texture_create_3D(int w, int h, int depth, int channels, float * tex->number = 0; glBindTexture(tex->target, tex->bindcode); - GPU_print_error("3D glBindTexture"); + GPU_ASSERT_NO_GL_ERRORS("3D glBindTexture"); type = GL_FLOAT; if (channels == 4) { @@ -525,35 +612,90 @@ GPUTexture *GPU_texture_create_3D(int w, int h, int depth, int channels, float * internalformat = GL_INTENSITY; } - //if (fpixels) - // pixels = GPU_texture_convert_pixels(w*h*depth, fpixels); + /* 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); + glGetTexLevelParameteriv(GL_PROXY_TEXTURE_3D, 0, GL_TEXTURE_WIDTH, &r_width); - glTexImage3D(tex->target, 0, internalformat, tex->w, tex->h, tex->depth, 0, format, type, NULL); + 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); + } + + /* 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); - GPU_print_error("3D glTexImage3D"); +#if 0 + if (fpixels) + pixels = GPU_texture_convert_pixels(w*h*depth, fpixels); +#endif - if (fpixels) { - if (!GPU_non_power_of_two_support() && (w != tex->w || h != tex->h || depth != tex->depth)) { - /* clear first to avoid unitialized pixels */ - float *zero= MEM_callocN(sizeof(float)*tex->w*tex->h*tex->depth, "zero"); - glTexSubImage3D(tex->target, 0, 0, 0, 0, tex->w, tex->h, tex->depth, format, type, zero); - MEM_freeN(zero); + 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) { + unsigned int i, j, k; + 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 (k = 0; k < tex->depth; k++) { + for (j = 0; j < tex->h; j++) { + for (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]; + } + } } - glTexSubImage3D(tex->target, 0, 0, 0, 0, w, h, depth, format, type, fpixels); - GPU_print_error("3D glTexSubImage3D"); + glTexImage3D(tex->target, 0, internalformat, tex->w, tex->h, tex->depth, 0, format, type, tex3d); + + MEM_freeN(tex3d); + } + else { + if (fpixels) { + if (!GPU_non_power_of_two_support() && (w != tex->w || h != tex->h || depth != tex->depth)) { + /* clear first to avoid unitialized pixels */ + float *zero= MEM_callocN(sizeof(float)*tex->w*tex->h*tex->depth, "zero"); + glTexImage3D(tex->target, 0, internalformat, tex->w, tex->h, tex->depth, 0, format, type, NULL); + glTexSubImage3D(tex->target, 0, 0, 0, 0, tex->w, tex->h, tex->depth, GL_INTENSITY, GL_FLOAT, zero); + glTexSubImage3D(tex->target, 0, 0, 0, 0, w, h, depth, format, type, fpixels); + MEM_freeN(zero); + } + else { + glTexImage3D(tex->target, 0, internalformat, tex->w, tex->h, tex->depth, 0, format, type, fpixels); + } + + GPU_ASSERT_NO_GL_ERRORS("3D glTexSubImage3D"); + } } - glTexParameterfv(GL_TEXTURE_3D, GL_TEXTURE_BORDER_COLOR, vfBorderColor); - GPU_print_error("3D GL_TEXTURE_BORDER_COLOR"); glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - GPU_print_error("3D 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); - GPU_print_error("3D GL_CLAMP_TO_BORDER"); if (pixels) MEM_freeN(pixels); @@ -590,7 +732,7 @@ GPUTexture *GPU_texture_from_blender(Image *ima, ImageUser *iuser, bool is_data, ima->gputexture= tex; if (!glIsTexture(tex->bindcode)) { - GPU_print_error("Blender Texture Not Loaded"); + GPU_ASSERT_NO_GL_ERRORS("Blender Texture Not Loaded"); } else { glBindTexture(GL_TEXTURE_2D, tex->bindcode); @@ -598,8 +740,8 @@ GPUTexture *GPU_texture_from_blender(Image *ima, ImageUser *iuser, bool is_data, glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &h); glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_BORDER, &border); - tex->w = w - border; - tex->h = h - border; + tex->w = tex->w_orig = w - border; + tex->h = tex->h_orig = h - border; } glBindTexture(GL_TEXTURE_2D, lastbindcode); @@ -634,18 +776,18 @@ GPUTexture *GPU_texture_from_preview(PreviewImage *prv, int mipmap) tex->refcount = 1; tex->target = GL_TEXTURE_2D; - prv->gputexture[0]= tex; + prv->gputexture[0] = tex; if (!glIsTexture(tex->bindcode)) { - GPU_print_error("Blender Texture Not Loaded"); + GPU_ASSERT_NO_GL_ERRORS("Blender Texture Not Loaded"); } else { glBindTexture(GL_TEXTURE_2D, tex->bindcode); glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &w); glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &h); - tex->w = w; - tex->h = h; + tex->w = tex->w_orig = w; + tex->h = tex->h_orig = h; } glBindTexture(GL_TEXTURE_2D, lastbindcode); @@ -654,9 +796,9 @@ GPUTexture *GPU_texture_from_preview(PreviewImage *prv, int mipmap) } -GPUTexture *GPU_texture_create_1D(int w, float *fpixels, char err_out[256]) +GPUTexture *GPU_texture_create_1D(int w, const float *fpixels, char err_out[256]) { - GPUTexture *tex = GPU_texture_create_nD(w, 1, 1, fpixels, 0, err_out); + GPUTexture *tex = GPU_texture_create_nD(w, 1, 1, fpixels, 0, GPU_HDR_NONE, 4, err_out); if (tex) GPU_texture_unbind(tex); @@ -664,9 +806,9 @@ GPUTexture *GPU_texture_create_1D(int w, float *fpixels, char err_out[256]) return tex; } -GPUTexture *GPU_texture_create_2D(int w, int h, float *fpixels, char err_out[256]) +GPUTexture *GPU_texture_create_2D(int w, int h, const float *fpixels, GPUHDRType hdr, char err_out[256]) { - GPUTexture *tex = GPU_texture_create_nD(w, h, 2, fpixels, 0, err_out); + GPUTexture *tex = GPU_texture_create_nD(w, h, 2, fpixels, 0, hdr, 4, err_out); if (tex) GPU_texture_unbind(tex); @@ -676,7 +818,7 @@ GPUTexture *GPU_texture_create_2D(int w, int h, float *fpixels, 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, NULL, 1, err_out); + GPUTexture *tex = GPU_texture_create_nD(w, h, 2, NULL, 1, GPU_HDR_NONE, 1, err_out); if (tex) GPU_texture_unbind(tex); @@ -689,13 +831,47 @@ 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 *tex = GPU_texture_create_nD(size, size, 2, NULL, 0, err_out); + GPUTexture *tex = GPU_texture_create_nD(size, size, 2, NULL, 0, GPU_HDR_FULL_FLOAT, 2, 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); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RG32F, size, size, 0, GL_RG, GL_FLOAT, NULL); + + GPU_texture_unbind(tex); + } + + return tex; +} + +GPUTexture *GPU_texture_create_2D_procedural(int w, int h, const float *pixels, bool repeat, char err_out[256]) +{ + GPUTexture *tex = GPU_texture_create_nD(w, h, 2, pixels, 0, GPU_HDR_HALF_FLOAT, 2, 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); + + GPU_texture_unbind(tex); + } + + return tex; +} + +GPUTexture *GPU_texture_create_1D_procedural(int w, const float *pixels, char err_out[256]) +{ + GPUTexture *tex = GPU_texture_create_nD(w, 0, 1, pixels, 0, GPU_HDR_HALF_FLOAT, 2, err_out); + + 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); GPU_texture_unbind(tex); } @@ -705,9 +881,9 @@ GPUTexture *GPU_texture_create_vsm_shadow_map(int size, char err_out[256]) void GPU_invalid_tex_init(void) { - float color[4] = {1.0f, 0.0f, 1.0f, 1.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, 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); } @@ -728,9 +904,12 @@ void GPU_invalid_tex_bind(int mode) void GPU_invalid_tex_free(void) { - GPU_texture_free(GG.invalid_tex_1D); - GPU_texture_free(GG.invalid_tex_2D); - GPU_texture_free(GG.invalid_tex_3D); + if (GG.invalid_tex_1D) + GPU_texture_free(GG.invalid_tex_1D); + if (GG.invalid_tex_2D) + GPU_texture_free(GG.invalid_tex_2D); + if (GG.invalid_tex_3D) + GPU_texture_free(GG.invalid_tex_3D); } @@ -739,14 +918,20 @@ void GPU_texture_bind(GPUTexture *tex, int number) GLenum arbnumber; if (number >= GG.maxtextures) { - GPU_print_error("Not enough texture slots."); + fprintf(stderr, "Not enough texture slots."); return; } - if (number == -1) + if ((G.debug & G_DEBUG)) { + if (tex->fb && tex->fb->object == GG.currentfb) { + fprintf(stderr, "Feedback loop warning!: Attempting to bind texture attached to current framebuffer!\n"); + } + } + + if (number < 0) return; - GPU_print_error("Pre Texture Bind"); + GPU_ASSERT_NO_GL_ERRORS("Pre Texture Bind"); arbnumber = (GLenum)((GLuint)GL_TEXTURE0_ARB + number); if (number != 0) glActiveTextureARB(arbnumber); @@ -760,7 +945,7 @@ void GPU_texture_bind(GPUTexture *tex, int number) tex->number = number; - GPU_print_error("Post Texture Bind"); + GPU_ASSERT_NO_GL_ERRORS("Post Texture Bind"); } void GPU_texture_unbind(GPUTexture *tex) @@ -768,14 +953,14 @@ void GPU_texture_unbind(GPUTexture *tex) GLenum arbnumber; if (tex->number >= GG.maxtextures) { - GPU_print_error("Not enough texture slots."); + fprintf(stderr, "Not enough texture slots."); return; } if (tex->number == -1) return; - GPU_print_error("Pre Texture Unbind"); + GPU_ASSERT_NO_GL_ERRORS("Pre Texture Unbind"); arbnumber = (GLenum)((GLuint)GL_TEXTURE0_ARB + tex->number); if (tex->number != 0) glActiveTextureARB(arbnumber); @@ -785,7 +970,44 @@ void GPU_texture_unbind(GPUTexture *tex) tex->number = -1; - GPU_print_error("Post Texture Unbind"); + GPU_ASSERT_NO_GL_ERRORS("Post Texture Unbind"); +} + +void GPU_texture_filter_mode(GPUTexture *tex, bool compare, bool use_filter) +{ + GLenum arbnumber; + + if (tex->number >= GG.maxtextures) { + fprintf(stderr, "Not enough texture slots."); + return; + } + + if (tex->number == -1) + return; + + GPU_ASSERT_NO_GL_ERRORS("Pre Texture Unbind"); + + arbnumber = (GLenum)((GLuint)GL_TEXTURE0_ARB + tex->number); + if (tex->number != 0) glActiveTextureARB(arbnumber); + + 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 (use_filter) { + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + } + else { + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + } + if (tex->number != 0) glActiveTextureARB(GL_TEXTURE0_ARB); + + GPU_ASSERT_NO_GL_ERRORS("Post Texture Unbind"); } void GPU_texture_free(GPUTexture *tex) @@ -797,7 +1019,7 @@ void GPU_texture_free(GPUTexture *tex) if (tex->refcount == 0) { if (tex->fb) - GPU_framebuffer_texture_detach(tex->fb, tex); + GPU_framebuffer_texture_detach(tex); if (tex->bindcode && !tex->fromblender) glDeleteTextures(1, &tex->bindcode); @@ -810,22 +1032,22 @@ void GPU_texture_ref(GPUTexture *tex) tex->refcount++; } -int GPU_texture_target(GPUTexture *tex) +int GPU_texture_target(const GPUTexture *tex) { return tex->target; } -int GPU_texture_opengl_width(GPUTexture *tex) +int GPU_texture_opengl_width(const GPUTexture *tex) { return tex->w; } -int GPU_texture_opengl_height(GPUTexture *tex) +int GPU_texture_opengl_height(const GPUTexture *tex) { return tex->h; } -int GPU_texture_opengl_bindcode(GPUTexture *tex) +int GPU_texture_opengl_bindcode(const GPUTexture *tex) { return tex->bindcode; } @@ -837,12 +1059,6 @@ GPUFrameBuffer *GPU_texture_framebuffer(GPUTexture *tex) /* GPUFrameBuffer */ -struct GPUFrameBuffer { - GLuint object; - GPUTexture *colortex; - GPUTexture *depthtex; -}; - GPUFrameBuffer *GPU_framebuffer_create(void) { GPUFrameBuffer *fb; @@ -850,7 +1066,7 @@ GPUFrameBuffer *GPU_framebuffer_create(void) if (!GLEW_EXT_framebuffer_object) return NULL; - fb= MEM_callocN(sizeof(GPUFrameBuffer), "GPUFrameBuffer"); + fb = MEM_callocN(sizeof(GPUFrameBuffer), "GPUFrameBuffer"); glGenFramebuffersEXT(1, &fb->object); if (!fb->object) { @@ -860,19 +1076,35 @@ GPUFrameBuffer *GPU_framebuffer_create(void) 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); + glReadBuffer(GL_NONE); + glDrawBuffer(GL_NONE); + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); + return fb; } -int GPU_framebuffer_texture_attach(GPUFrameBuffer *fb, GPUTexture *tex, char err_out[256]) +int GPU_framebuffer_texture_attach(GPUFrameBuffer *fb, GPUTexture *tex, int slot, char err_out[256]) { - GLenum status; GLenum attachment; GLenum error; + if (slot >= GPU_FB_MAX_SLOTS) { + fprintf(stderr, "Attaching to index %d framebuffer slot unsupported in blender use at most %d\n", slot, GPU_FB_MAX_SLOTS); + return 0; + } + + if ((G.debug & G_DEBUG)) { + if (tex->number != -1) { + fprintf(stderr, "Feedback loop warning!: Attempting to attach texture to framebuffer while still bound to texture unit for drawing!"); + } + } + if (tex->depth) attachment = GL_DEPTH_ATTACHMENT_EXT; else - attachment = GL_COLOR_ATTACHMENT0_EXT; + attachment = GL_COLOR_ATTACHMENT0_EXT + slot; glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb->object); GG.currentfb = fb->object; @@ -891,42 +1123,29 @@ int GPU_framebuffer_texture_attach(GPUFrameBuffer *fb, GPUTexture *tex, char err return 0; } - if (tex->depth) { - glDrawBuffer(GL_NONE); - glReadBuffer(GL_NONE); - } - else { - glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT); - glReadBuffer(GL_COLOR_ATTACHMENT0_EXT); - } - - status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); - - if (status != GL_FRAMEBUFFER_COMPLETE_EXT) { - GPU_framebuffer_restore(); - GPU_print_framebuffer_error(status, err_out); - return 0; - } - if (tex->depth) fb->depthtex = tex; else - fb->colortex = tex; + fb->colortex[slot] = tex; tex->fb= fb; + tex->fb_attachment = slot; return 1; } -void GPU_framebuffer_texture_detach(GPUFrameBuffer *fb, GPUTexture *tex) +void GPU_framebuffer_texture_detach(GPUTexture *tex) { GLenum attachment; + GPUFrameBuffer *fb; if (!tex->fb) return; - if (GG.currentfb != tex->fb->object) { - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, tex->fb->object); + fb = tex->fb; + + if (GG.currentfb != fb->object) { + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb->object); GG.currentfb = tex->fb->object; } @@ -935,18 +1154,24 @@ void GPU_framebuffer_texture_detach(GPUFrameBuffer *fb, GPUTexture *tex) attachment = GL_DEPTH_ATTACHMENT_EXT; } else { - fb->colortex = NULL; - attachment = GL_COLOR_ATTACHMENT0_EXT; + BLI_assert(fb->colortex[tex->fb_attachment] == tex); + fb->colortex[tex->fb_attachment] = NULL; + attachment = GL_COLOR_ATTACHMENT0_EXT + tex->fb_attachment; } - glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, attachment, - tex->target, 0, 0); + glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, attachment, tex->target, 0, 0); tex->fb = NULL; + tex->fb_attachment = -1; } -void GPU_framebuffer_texture_bind(GPUFrameBuffer *UNUSED(fb), GPUTexture *tex, int w, int h) +void GPU_texture_bind_as_framebuffer(GPUTexture *tex) { + if (!tex->fb) { + fprintf(stderr, "Error, texture not bound to framebuffer!"); + return; + } + /* push attributes */ glPushAttrib(GL_ENABLE_BIT | GL_VIEWPORT_BIT); glDisable(GL_SCISSOR_TEST); @@ -954,8 +1179,18 @@ void GPU_framebuffer_texture_bind(GPUFrameBuffer *UNUSED(fb), GPUTexture *tex, i /* bind framebuffer */ glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, tex->fb->object); + if (tex->depth) { + glDrawBuffer(GL_NONE); + glReadBuffer(GL_NONE); + } + else { + /* last bound prevails here, better allow explicit control here too */ + glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT + tex->fb_attachment); + glReadBuffer(GL_COLOR_ATTACHMENT0_EXT + tex->fb_attachment); + } + /* push matrices and set default viewport and matrix */ - glViewport(0, 0, w, h); + glViewport(0, 0, tex->w_orig, tex->h_orig); GG.currentfb = tex->fb->object; glMatrixMode(GL_PROJECTION); @@ -964,6 +1199,45 @@ void GPU_framebuffer_texture_bind(GPUFrameBuffer *UNUSED(fb), GPUTexture *tex, i glPushMatrix(); } +void GPU_framebuffer_slots_bind(GPUFrameBuffer *fb, int slot) +{ + int numslots = 0, i; + GLenum attachments[4]; + + if (!fb->colortex[slot]) { + fprintf(stderr, "Error, framebuffer slot empty!"); + return; + } + + for (i = 0; i < 4; i++) { + if (fb->colortex[i]) { + attachments[numslots] = GL_COLOR_ATTACHMENT0_EXT + i; + numslots++; + } + } + + /* push attributes */ + glPushAttrib(GL_ENABLE_BIT | GL_VIEWPORT_BIT); + glDisable(GL_SCISSOR_TEST); + + /* bind framebuffer */ + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb->object); + + /* last bound prevails here, better allow explicit control here too */ + glDrawBuffers(numslots, attachments); + glReadBuffer(GL_COLOR_ATTACHMENT0_EXT + slot); + + /* push matrices and set default viewport and matrix */ + glViewport(0, 0, fb->colortex[slot]->w_orig, fb->colortex[slot]->h_orig); + GG.currentfb = fb->object; + + glMatrixMode(GL_PROJECTION); + glPushMatrix(); + glMatrixMode(GL_MODELVIEW); + glPushMatrix(); +} + + void GPU_framebuffer_texture_unbind(GPUFrameBuffer *UNUSED(fb), GPUTexture *UNUSED(tex)) { /* restore matrix */ @@ -974,15 +1248,53 @@ void GPU_framebuffer_texture_unbind(GPUFrameBuffer *UNUSED(fb), GPUTexture *UNUS /* restore attributes */ glPopAttrib(); - glEnable(GL_SCISSOR_TEST); +} + +void GPU_framebuffer_bind_no_save(GPUFrameBuffer *fb, int slot) +{ + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb->object); + /* last bound prevails here, better allow explicit control here too */ + glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT + slot); + glReadBuffer(GL_COLOR_ATTACHMENT0_EXT + slot); + + /* push matrices and set default viewport and matrix */ + glViewport(0, 0, fb->colortex[slot]->w_orig, fb->colortex[slot]->h_orig); + GG.currentfb = fb->object; + GG.currentfb = fb->object; +} + +bool GPU_framebuffer_check_valid(GPUFrameBuffer *fb, char err_out[256]) +{ + GLenum status; + + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb->object); + GG.currentfb = fb->object; + + /* Clean glError buffer. */ + while (glGetError() != GL_NO_ERROR) {} + + status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); + + if (status != GL_FRAMEBUFFER_COMPLETE_EXT) { + GPU_framebuffer_restore(); + GPU_print_framebuffer_error(status, err_out); + return false; + } + + return true; } void GPU_framebuffer_free(GPUFrameBuffer *fb) { + int i; if (fb->depthtex) - GPU_framebuffer_texture_detach(fb, fb->depthtex); - if (fb->colortex) - GPU_framebuffer_texture_detach(fb, fb->colortex); + GPU_framebuffer_texture_detach(fb->depthtex); + + for (i = 0; i < GPU_FB_MAX_SLOTS; i++) { + if (fb->colortex[i]) { + GPU_framebuffer_texture_detach(fb->colortex[i]); + } + } if (fb->object) { glDeleteFramebuffersEXT(1, &fb->object); @@ -1006,8 +1318,8 @@ void GPU_framebuffer_restore(void) void GPU_framebuffer_blur(GPUFrameBuffer *fb, GPUTexture *tex, GPUFrameBuffer *blurfb, GPUTexture *blurtex) { - float scaleh[2] = {1.0f/GPU_texture_opengl_width(blurtex), 0.0f}; - float scalev[2] = {0.0f, 1.0f/GPU_texture_opengl_height(tex)}; + const float scaleh[2] = {1.0f / blurtex->w_orig, 0.0f}; + const float scalev[2] = {0.0f, 1.0f / tex->h_orig}; GPUShader *blur_shader = GPU_shader_get_builtin_shader(GPU_SHADER_SEP_GAUSSIAN_BLUR); int scale_uniform, texture_source_uniform; @@ -1023,11 +1335,15 @@ void GPU_framebuffer_blur(GPUFrameBuffer *fb, GPUTexture *tex, GPUFrameBuffer *b /* 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); + + /* avoid warnings from texture binding */ + GG.currentfb = blurfb->object; GPU_shader_bind(blur_shader); - GPU_shader_uniform_vector(blur_shader, scale_uniform, 2, 1, (float *)scaleh); + 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_opengl_width(blurtex), GPU_texture_opengl_height(blurtex)); + glViewport(0, 0, blurtex->w_orig, blurtex->h_orig); /* Peparing to draw quad */ glMatrixMode(GL_MODELVIEW); @@ -1048,12 +1364,16 @@ void GPU_framebuffer_blur(GPUFrameBuffer *fb, GPUTexture *tex, GPUFrameBuffer *b glTexCoord2d(1, 1); glVertex2f(-1, -1); glTexCoord2d(0, 1); glVertex2f(1, -1); glEnd(); - + /* Blurring vertically */ glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb->object); - glViewport(0, 0, GPU_texture_opengl_width(tex), GPU_texture_opengl_height(tex)); - GPU_shader_uniform_vector(blur_shader, scale_uniform, 2, 1, (float *)scalev); + glDrawBuffer(GL_COLOR_ATTACHMENT0); + + GG.currentfb = fb->object; + + glViewport(0, 0, tex->w_orig, tex->h_orig); + 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); @@ -1073,19 +1393,13 @@ struct GPUOffScreen { GPUFrameBuffer *fb; GPUTexture *color; GPUTexture *depth; - - /* requested width/height, may be smaller than actual texture size due - * to missing non-power of two support, so we compensate for that */ - int w, h; }; GPUOffScreen *GPU_offscreen_create(int width, int height, char err_out[256]) { GPUOffScreen *ofs; - ofs= MEM_callocN(sizeof(GPUOffScreen), "GPUOffScreen"); - ofs->w= width; - ofs->h= height; + ofs = MEM_callocN(sizeof(GPUOffScreen), "GPUOffScreen"); ofs->fb = GPU_framebuffer_create(); if (!ofs->fb) { @@ -1099,21 +1413,27 @@ GPUOffScreen *GPU_offscreen_create(int width, int height, char err_out[256]) return NULL; } - if (!GPU_framebuffer_texture_attach(ofs->fb, ofs->depth, err_out)) { + if (!GPU_framebuffer_texture_attach(ofs->fb, ofs->depth, 0, err_out)) { GPU_offscreen_free(ofs); return NULL; } - ofs->color = GPU_texture_create_2D(width, height, NULL, err_out); + ofs->color = GPU_texture_create_2D(width, height, NULL, GPU_HDR_NONE, err_out); if (!ofs->color) { GPU_offscreen_free(ofs); return NULL; } - if (!GPU_framebuffer_texture_attach(ofs->fb, ofs->color, err_out)) { + if (!GPU_framebuffer_texture_attach(ofs->fb, ofs->color, 0, err_out)) { GPU_offscreen_free(ofs); return NULL; } + + /* check validity at the very end! */ + if (!GPU_framebuffer_check_valid(ofs->fb, err_out)) { + GPU_offscreen_free(ofs); + return NULL; + } GPU_framebuffer_restore(); @@ -1132,62 +1452,75 @@ void GPU_offscreen_free(GPUOffScreen *ofs) MEM_freeN(ofs); } -void GPU_offscreen_bind(GPUOffScreen *ofs) +void GPU_offscreen_bind(GPUOffScreen *ofs, bool save) { glDisable(GL_SCISSOR_TEST); - GPU_framebuffer_texture_bind(ofs->fb, ofs->color, ofs->w, ofs->h); + if (save) + GPU_texture_bind_as_framebuffer(ofs->color); + else { + GPU_framebuffer_bind_no_save(ofs->fb, 0); + } } -void GPU_offscreen_unbind(GPUOffScreen *ofs) +void GPU_offscreen_unbind(GPUOffScreen *ofs, bool restore) { - GPU_framebuffer_texture_unbind(ofs->fb, ofs->color); + if (restore) + GPU_framebuffer_texture_unbind(ofs->fb, ofs->color); GPU_framebuffer_restore(); glEnable(GL_SCISSOR_TEST); } void GPU_offscreen_read_pixels(GPUOffScreen *ofs, int type, void *pixels) { - glReadPixels(0, 0, ofs->w, ofs->h, GL_RGBA, type, pixels); + glReadPixels(0, 0, ofs->color->w_orig, ofs->color->h_orig, GL_RGBA, type, pixels); } -int GPU_offscreen_width(GPUOffScreen *ofs) +int GPU_offscreen_width(const GPUOffScreen *ofs) { - return ofs->w; + return ofs->color->w_orig; } -int GPU_offscreen_height(GPUOffScreen *ofs) +int GPU_offscreen_height(const GPUOffScreen *ofs) { - return ofs->h; + return ofs->color->h_orig; } /* GPUShader */ struct GPUShader { - GLhandleARB object; /* handle for full shader */ - GLhandleARB vertex; /* handle for vertex shader */ - GLhandleARB fragment; /* handle for fragment shader */ - GLhandleARB lib; /* handle for libment shader */ - int totattrib; /* total number of attributes */ + GLhandleARB object; /* handle for full shader */ + GLhandleARB vertex; /* handle for vertex shader */ + GLhandleARB fragment; /* handle for fragment shader */ + GLhandleARB geometry; /* handle for geometry shader */ + GLhandleARB lib; /* handle for libment shader */ + int totattrib; /* total number of attributes */ + int uniforms; /* required uniforms */ }; -static void shader_print_errors(const char *task, char *log, const char **code, int totcode) +struct GPUProgram { + GPUProgramType type; + GLuint prog; +}; + + +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++) { const char *c, *pos, *end = code[i] + strlen(code[i]); - int line = 1; - - if (G.debug & G_DEBUG) { + + if ((G.debug & G_DEBUG)) { fprintf(stderr, "===== shader string %d ====\n", i + 1); c = code[i]; while ((c < end) && (pos = strchr(c, '\n'))) { fprintf(stderr, "%2d ", line); - fwrite(c, (pos+1)-c, 1, stderr); - c = pos+1; + fwrite(c, (pos + 1) - c, 1, stderr); + c = pos + 1; line++; } @@ -1198,8 +1531,16 @@ static void shader_print_errors(const char *task, char *log, const char **code, fprintf(stderr, "%s\n", log); } -static const char *gpu_shader_version(void) +static const char *gpu_shader_version(bool use_opensubdiv) { +#ifdef WITH_OPENSUBDIV + if (use_opensubdiv) { + return "#version 130\n"; + } +#else + UNUSED_VARS(use_opensubdiv); +#endif + /* turn on glsl 1.30 for bicubic bump mapping and ATI clipping support */ if (GLEW_VERSION_3_0 && (GPU_bicubic_bump_support() || GPU_type_matches(GPU_DEVICE_ATI, GPU_OS_ANY, GPU_DRIVER_ANY))) @@ -1211,16 +1552,34 @@ static const char *gpu_shader_version(void) } -static const char *gpu_shader_standard_extensions(void) +static void gpu_shader_standard_extensions(char defines[MAX_EXT_DEFINE_LENGTH], bool use_opensubdiv) { - /* need this extensions for high quality bump mapping */ +#ifdef WITH_OPENSUBDIV + if (use_opensubdiv) { + strcat(defines, "#extension GL_ARB_texture_query_lod: enable\n" + "#extension GL_ARB_gpu_shader5 : enable\n" + "#extension GL_ARB_explicit_attrib_location : require\n"); + } + else if (GPU_bicubic_bump_support()) + strcat(defines, "#extension GL_ARB_texture_query_lod: enable\n"); +#else + /* need this extension for high quality bump mapping */ if (GPU_bicubic_bump_support()) - return "#extension GL_ARB_texture_query_lod: enable\n"; + strcat(defines, "#extension GL_ARB_texture_query_lod: enable\n"); + (void) use_opensubdiv; +#endif - return ""; + if (GPU_geometry_shader_support()) + strcat(defines, "#extension GL_EXT_geometry_shader4: enable\n"); + + if (GPU_instanced_drawing_support()) { + strcat(defines, "#extension GL_EXT_gpu_shader4: enable\n"); + strcat(defines, "#extension GL_ARB_draw_instanced: enable\n"); + } } -static void gpu_shader_standard_defines(char defines[MAX_DEFINE_LENGTH]) +static void gpu_shader_standard_defines(bool use_opensubdiv, + char defines[MAX_DEFINE_LENGTH]) { /* some useful defines to detect GPU type */ if (GPU_type_matches(GPU_DEVICE_ATI, GPU_OS_ANY, GPU_DRIVER_ANY)) { @@ -1235,18 +1594,144 @@ static void gpu_shader_standard_defines(char defines[MAX_DEFINE_LENGTH]) if (GPU_bicubic_bump_support()) strcat(defines, "#define BUMP_BICUBIC\n"); + +#ifdef WITH_OPENSUBDIV + /* TODO(sergey): Check whether we actually compiling shader for + * the OpenSubdiv mesh. + */ + if (use_opensubdiv) { + strcat(defines, "#define USE_OPENSUBDIV\n"); + + /* TODO(sergey): not strictly speaking a define, but this is + * a global typedef which we don't have better place to define + * in yet. + */ + strcat(defines, "struct VertexData {\n" + " vec4 position;\n" + " vec3 normal;\n" + " vec2 uv;" + "};\n"); + } +#else + UNUSED_VARS(use_opensubdiv); +#endif + return; } -GPUShader *GPU_shader_create(const char *vertexcode, const char *fragcode, const char *libcode, const char *defines) +void GPU_program_bind(GPUProgram *program) +{ + glEnable(program->type); + glBindProgramARB(program->type, program->prog); +} + +void GPU_program_unbind(GPUProgram *program) +{ + glDisable(program->type); + glBindProgramARB(program->type, 0); +} + + +GPUProgram *GPU_program_shader_create(GPUProgramType type, const char *code) +{ + GPUProgram *program; + GLint error_pos, is_native; + + if (!(GLEW_ARB_fragment_program && type == GPU_PROGRAM_TYPE_FRAGMENT)) + return NULL; + + program = MEM_callocN(sizeof(GPUProgram), "GPUProgram"); + + switch (type) { + case GPU_PROGRAM_TYPE_FRAGMENT: + program->type = GL_FRAGMENT_PROGRAM_ARB; + break; + } + + /* create the object and set its code string */ + glGenProgramsARB(1, &program->prog); + glBindProgramARB(program->type, program->prog); + + glProgramStringARB(program->type, GL_PROGRAM_FORMAT_ASCII_ARB, (GLsizei)strlen(code), code); + + glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB, &error_pos); + glGetProgramivARB(GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_UNDER_NATIVE_LIMITS_ARB, &is_native); + if ((error_pos == -1) && (is_native == 1)) { + return program; + } + else { + /* glGetError is set before that, clear it */ + while (glGetError() != GL_NO_ERROR) + ; + shader_print_errors("compile", (const char *)glGetString(GL_PROGRAM_ERROR_STRING_ARB), &code, 1); + MEM_freeN(program); + } + + return NULL; +} + +void GPU_program_free(GPUProgram *program) +{ + glDeleteProgramsARB(1, &program->prog); + MEM_freeN(program); +} + +void GPU_program_parameter_4f(GPUProgram *program, unsigned int location, float x, float y, float z, float w) { + glProgramLocalParameter4fARB(program->type, location, x, y, z, w); +} + +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) +{ + return GPU_shader_create_ex(vertexcode, + fragcode, + geocode, + libcode, + defines, + input, + output, + number, + GPU_SHADER_FLAGS_NONE); +} + +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 + bool use_opensubdiv = false; +#endif GLint status; GLcharARB log[5000]; GLsizei length = 0; GPUShader *shader; char standard_defines[MAX_DEFINE_LENGTH] = ""; + char standard_extensions[MAX_EXT_DEFINE_LENGTH] = ""; - if (!GLEW_ARB_vertex_shader || !GLEW_ARB_fragment_shader) +#ifndef WITH_OPENSUBDIV + UNUSED_VARS(flags); +#endif + + if (!GLEW_ARB_vertex_shader || !GLEW_ARB_fragment_shader || (geocode && !GPU_geometry_shader_support())) return NULL; shader = MEM_callocN(sizeof(GPUShader), "GPUShader"); @@ -1255,30 +1740,35 @@ GPUShader *GPU_shader_create(const char *vertexcode, const char *fragcode, const shader->vertex = glCreateShaderObjectARB(GL_VERTEX_SHADER_ARB); if (fragcode) shader->fragment = glCreateShaderObjectARB(GL_FRAGMENT_SHADER_ARB); + if (geocode) + shader->geometry = glCreateShaderObjectARB(GL_GEOMETRY_SHADER_EXT); + shader->object = glCreateProgramObjectARB(); if (!shader->object || (vertexcode && !shader->vertex) || - (fragcode && !shader->fragment)) + (fragcode && !shader->fragment) || + (geocode && !shader->geometry)) { fprintf(stderr, "GPUShader, object creation failed.\n"); GPU_shader_free(shader); return NULL; } - gpu_shader_standard_defines(standard_defines); + gpu_shader_standard_defines(use_opensubdiv, standard_defines); + gpu_shader_standard_extensions(standard_extensions, use_opensubdiv); if (vertexcode) { const char *source[5]; /* custom limit, may be too small, beware */ int num_source = 0; - source[num_source++] = gpu_shader_version(); - source[num_source++] = gpu_shader_standard_extensions(); + source[num_source++] = gpu_shader_version(use_opensubdiv); + source[num_source++] = standard_extensions; source[num_source++] = standard_defines; if (defines) source[num_source++] = defines; - if (vertexcode) source[num_source++] = vertexcode; + source[num_source++] = vertexcode; glAttachObjectARB(shader->object, shader->vertex); glShaderSourceARB(shader->vertex, num_source, source, NULL); @@ -1296,16 +1786,28 @@ GPUShader *GPU_shader_create(const char *vertexcode, const char *fragcode, const } if (fragcode) { - const char *source[6]; + const char *source[7]; int num_source = 0; - source[num_source++] = gpu_shader_version(); - source[num_source++] = gpu_shader_standard_extensions(); + source[num_source++] = gpu_shader_version(use_opensubdiv); + source[num_source++] = standard_extensions; source[num_source++] = standard_defines; +#ifdef WITH_OPENSUBDIV + /* TODO(sergey): Move to fragment shader source code generation. */ + if (use_opensubdiv) { + source[num_source++] = + "#ifdef USE_OPENSUBDIV\n" + "in block {\n" + " VertexData v;\n" + "} inpt;\n" + "#endif\n"; + } +#endif + if (defines) source[num_source++] = defines; if (libcode) source[num_source++] = libcode; - if (fragcode) source[num_source++] = fragcode; + source[num_source++] = fragcode; glAttachObjectARB(shader->object, shader->fragment); glShaderSourceARB(shader->fragment, num_source, source, NULL); @@ -1322,11 +1824,54 @@ GPUShader *GPU_shader_create(const char *vertexcode, const char *fragcode, const } } + if (geocode) { + const char *source[6]; + int num_source = 0; + + source[num_source++] = gpu_shader_version(use_opensubdiv); + source[num_source++] = standard_extensions; + source[num_source++] = standard_defines; + + if (defines) source[num_source++] = defines; + source[num_source++] = geocode; + + glAttachObjectARB(shader->object, shader->geometry); + glShaderSourceARB(shader->geometry, num_source, source, NULL); + + glCompileShaderARB(shader->geometry); + glGetObjectParameterivARB(shader->geometry, GL_OBJECT_COMPILE_STATUS_ARB, &status); + + if (!status) { + glGetInfoLogARB(shader->geometry, sizeof(log), &length, log); + shader_print_errors("compile", log, source, num_source); + + GPU_shader_free(shader); + return NULL; + } + + if (!use_opensubdiv) { + GPU_shader_geometry_stage_primitive_io(shader, input, output, number); + } + } + + #if 0 if (lib && lib->lib) glAttachObjectARB(shader->object, lib->lib); #endif +#ifdef WITH_OPENSUBDIV + if (use_opensubdiv) { + glBindAttribLocation(shader->object, 0, "position"); + glBindAttribLocation(shader->object, 1, "normal"); + GPU_shader_geometry_stage_primitive_io(shader, + GL_LINES_ADJACENCY_EXT, + GL_TRIANGLE_STRIP, + 4); + + } +#endif + glLinkProgramARB(shader->object); glGetObjectParameterivARB(shader->object, GL_OBJECT_LINK_STATUS_ARB, &status); if (!status) { @@ -1334,11 +1879,21 @@ GPUShader *GPU_shader_create(const char *vertexcode, const char *fragcode, const if (fragcode) shader_print_errors("linking", log, &fragcode, 1); else if (vertexcode) shader_print_errors("linking", log, &vertexcode, 1); else if (libcode) shader_print_errors("linking", log, &libcode, 1); + else if (geocode) shader_print_errors("linking", log, &geocode, 1); GPU_shader_free(shader); return NULL; } +#ifdef WITH_OPENSUBDIV + /* TODO(sergey): Find a better place for this. */ + if (use_opensubdiv && GLEW_VERSION_4_1) { + glProgramUniform1i(shader->object, + glGetUniformLocation(shader->object, "FVarDataBuffer"), + 31); /* GL_TEXTURE31 */ + } +#endif + return shader; } @@ -1382,16 +1937,16 @@ GPUShader *GPU_shader_create_lib(const char *code) void GPU_shader_bind(GPUShader *shader) { - GPU_print_error("Pre Shader Bind"); + GPU_ASSERT_NO_GL_ERRORS("Pre Shader Bind"); glUseProgramObjectARB(shader->object); - GPU_print_error("Post Shader Bind"); + GPU_ASSERT_NO_GL_ERRORS("Post Shader Bind"); } void GPU_shader_unbind(void) { - GPU_print_error("Pre Shader Unbind"); + GPU_ASSERT_NO_GL_ERRORS("Pre Shader Unbind"); glUseProgramObjectARB(0); - GPU_print_error("Post Shader Unbind"); + GPU_ASSERT_NO_GL_ERRORS("Post Shader Unbind"); } void GPU_shader_free(GPUShader *shader) @@ -1412,12 +1967,12 @@ int GPU_shader_get_uniform(GPUShader *shader, const char *name) return glGetUniformLocationARB(shader->object, name); } -void GPU_shader_uniform_vector(GPUShader *UNUSED(shader), int location, int length, int arraysize, float *value) +void GPU_shader_uniform_vector(GPUShader *UNUSED(shader), int location, int length, int arraysize, const float *value) { - if (location == -1) + if (location == -1 || value == NULL) return; - GPU_print_error("Pre Uniform Vector"); + GPU_ASSERT_NO_GL_ERRORS("Pre Uniform Vector"); if (length == 1) glUniform1fvARB(location, arraysize, value); else if (length == 2) glUniform2fvARB(location, arraysize, value); @@ -1426,7 +1981,22 @@ void GPU_shader_uniform_vector(GPUShader *UNUSED(shader), int location, int leng else if (length == 9) glUniformMatrix3fvARB(location, arraysize, 0, value); else if (length == 16) glUniformMatrix4fvARB(location, arraysize, 0, value); - GPU_print_error("Post Uniform Vector"); + 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) +{ + if (location == -1) + return; + + GPU_ASSERT_NO_GL_ERRORS("Pre Uniform Vector"); + + if (length == 1) glUniform1ivARB(location, arraysize, value); + else if (length == 2) glUniform2ivARB(location, arraysize, value); + else if (length == 3) glUniform3ivARB(location, arraysize, value); + else if (length == 4) glUniform4ivARB(location, arraysize, value); + + GPU_ASSERT_NO_GL_ERRORS("Post Uniform Vector"); } void GPU_shader_uniform_int(GPUShader *UNUSED(shader), int location, int value) @@ -1434,9 +2004,14 @@ void GPU_shader_uniform_int(GPUShader *UNUSED(shader), int location, int value) if (location == -1) return; - GPU_print_error("Pre Uniform Int"); - glUniform1iARB(location, value); - GPU_print_error("Post Uniform Int"); + GPU_CHECK_ERRORS_AROUND(glUniform1iARB(location, value)); +} + +void GPU_shader_geometry_stage_primitive_io(GPUShader *shader, int input, int output, int number) +{ + glProgramParameteriEXT(shader->object, GL_GEOMETRY_INPUT_TYPE_EXT, input); + glProgramParameteriEXT(shader->object, GL_GEOMETRY_OUTPUT_TYPE_EXT, output); + glProgramParameteriEXT(shader->object, GL_GEOMETRY_VERTICES_OUT_EXT, number); } void GPU_shader_uniform_texture(GPUShader *UNUSED(shader), int location, GPUTexture *tex) @@ -1444,7 +2019,7 @@ void GPU_shader_uniform_texture(GPUShader *UNUSED(shader), int location, GPUText GLenum arbnumber; if (tex->number >= GG.maxtextures) { - GPU_print_error("Not enough texture slots."); + fprintf(stderr, "Not enough texture slots."); return; } @@ -1454,7 +2029,7 @@ void GPU_shader_uniform_texture(GPUShader *UNUSED(shader), int location, GPUText if (location == -1) return; - GPU_print_error("Pre Uniform Texture"); + GPU_ASSERT_NO_GL_ERRORS("Pre Uniform Texture"); arbnumber = (GLenum)((GLuint)GL_TEXTURE0_ARB + tex->number); @@ -1467,18 +2042,14 @@ void GPU_shader_uniform_texture(GPUShader *UNUSED(shader), int location, GPUText glEnable(tex->target); if (tex->number != 0) glActiveTextureARB(GL_TEXTURE0_ARB); - GPU_print_error("Post Uniform Texture"); + GPU_ASSERT_NO_GL_ERRORS("Post Uniform Texture"); } int GPU_shader_get_attribute(GPUShader *shader, const char *name) { int index; - GPU_print_error("Pre Get Attribute"); - - index = glGetAttribLocationARB(shader->object, name); - - GPU_print_error("Post Get Attribute"); + GPU_CHECK_ERRORS_AROUND(index = glGetAttribLocationARB(shader->object, name)); return index; } @@ -1490,36 +2061,183 @@ GPUShader *GPU_shader_get_builtin_shader(GPUBuiltinShader shader) 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); + 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); + 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; } if (retval == NULL) - printf("Unable to create a GPUShader for builtin shader: %d\n", shader); + printf("Unable to create a GPUShader for builtin shader: %u\n", shader); return retval; } +GPUProgram *GPU_shader_get_builtin_program(GPUBuiltinProgram program) +{ + GPUProgram *retval = NULL; + + switch (program) { + case GPU_PROGRAM_SMOKE: + if (!GG.shaders.smoke) + GG.shaders.smoke = GPU_program_shader_create(GPU_PROGRAM_TYPE_FRAGMENT, datatoc_gpu_program_smoke_frag_glsl); + retval = GG.shaders.smoke; + break; + case GPU_PROGRAM_SMOKE_COLORED: + if (!GG.shaders.smoke_colored) + GG.shaders.smoke_colored = GPU_program_shader_create(GPU_PROGRAM_TYPE_FRAGMENT, datatoc_gpu_program_smoke_color_frag_glsl); + retval = GG.shaders.smoke_colored; + break; + } + + if (retval == NULL) + printf("Unable to create a GPUProgram for builtin program: %u\n", program); + + return retval; +} + +#define MAX_DEFINES 100 + +GPUShader *GPU_shader_get_builtin_fx_shader(int effects, bool persp) +{ + int offset; + char defines[MAX_DEFINES] = ""; + /* avoid shaders out of range */ + if (effects >= MAX_FX_SHADERS) + return NULL; + + offset = 2 * effects; + + if (persp) { + offset += 1; + strcat(defines, "#define PERSP_MATRIX\n"); + } + + if (!GG.shaders.fx_shaders[offset]) { + GPUShader *shader; + + switch (effects) { + case GPU_SHADER_FX_SSAO: + GG.shaders.fx_shaders[offset] = 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); + break; + + case GPU_SHADER_FX_DEPTH_OF_FIELD_PASS_ONE: + strcat(defines, "#define FIRST_PASS\n"); + GG.shaders.fx_shaders[offset] = 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); + break; + + case GPU_SHADER_FX_DEPTH_OF_FIELD_PASS_TWO: + strcat(defines, "#define SECOND_PASS\n"); + GG.shaders.fx_shaders[offset] = 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); + break; + + case GPU_SHADER_FX_DEPTH_OF_FIELD_PASS_THREE: + strcat(defines, "#define THIRD_PASS\n"); + GG.shaders.fx_shaders[offset] = 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); + break; + + case GPU_SHADER_FX_DEPTH_OF_FIELD_PASS_FOUR: + strcat(defines, "#define FOURTH_PASS\n"); + GG.shaders.fx_shaders[offset] = 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); + break; + + case GPU_SHADER_FX_DEPTH_OF_FIELD_PASS_FIVE: + strcat(defines, "#define FIFTH_PASS\n"); + GG.shaders.fx_shaders[offset] = 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); + break; + + case GPU_SHADER_FX_DEPTH_OF_FIELD_HQ_PASS_ONE: + strcat(defines, "#define FIRST_PASS\n"); + GG.shaders.fx_shaders[offset] = 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); + 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); + GG.shaders.fx_shaders[offset] = shader; + break; + + case GPU_SHADER_FX_DEPTH_OF_FIELD_HQ_PASS_THREE: + strcat(defines, "#define THIRD_PASS\n"); + GG.shaders.fx_shaders[offset] = 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); + break; + + case GPU_SHADER_FX_DEPTH_RESOLVE: + GG.shaders.fx_shaders[offset] = GPU_shader_create(datatoc_gpu_shader_fx_vert_glsl, datatoc_gpu_shader_fx_depth_resolve_glsl, NULL, NULL, defines, 0, 0, 0); + } + } + + return GG.shaders.fx_shaders[offset]; +} + + void GPU_shader_free_builtin_shaders(void) { + int i; + if (GG.shaders.vsm_store) { - MEM_freeN(GG.shaders.vsm_store); + GPU_shader_free(GG.shaders.vsm_store); GG.shaders.vsm_store = NULL; } if (GG.shaders.sep_gaussian_blur) { - MEM_freeN(GG.shaders.sep_gaussian_blur); + GPU_shader_free(GG.shaders.sep_gaussian_blur); GG.shaders.sep_gaussian_blur = NULL; } + + if (GG.shaders.smoke) { + GPU_program_free(GG.shaders.smoke); + GG.shaders.smoke = NULL; + } + + if (GG.shaders.smoke_colored) { + GPU_program_free(GG.shaders.smoke_colored); + GG.shaders.smoke_colored = 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; + } + } } -#if 0 +bool GPU_mem_stats_supported(void) +{ + return (GLEW_NVX_gpu_memory_info || (GLEW_ATI_meminfo)) && (G.debug & G_DEBUG_GPU_MEM); +} + + +void GPU_mem_stats_get(int *totalmem, int *freemem) +{ + if (GLEW_NVX_gpu_memory_info) { + /* returned value in Kb */ + glGetIntegerv(GL_GPU_MEMORY_INFO_TOTAL_AVAILABLE_MEMORY_NVX, totalmem); + + glGetIntegerv(GL_GPU_MEMORY_INFO_CURRENT_AVAILABLE_VIDMEM_NVX, freemem); + } + else if (GLEW_ATI_meminfo) { + int stats[4]; + + glGetIntegerv(GL_TEXTURE_FREE_MEMORY_ATI, stats); + *freemem = stats[0]; + *totalmem = 0; + } + else { + *totalmem = 0; + *freemem = 0; + } +} + + +#if 0 /* unused */ + /* GPUPixelBuffer */ typedef struct GPUPixelBuffer { @@ -1545,7 +2263,7 @@ GPUPixelBuffer *gpu_pixelbuffer_create(int x, int y, int halffloat, int numbuffe return NULL; pb = MEM_callocN(sizeof(GPUPixelBuffer), "GPUPBO"); - pb->datasize = x*y*4*((halffloat)? 16: 8); + pb->datasize = x * y * 4 * (halffloat ? 16 : 8); pb->numbuffers = numbuffers; pb->halffloat = halffloat; @@ -1573,10 +2291,13 @@ void GPU_pixelbuffer_texture(GPUTexture *tex, GPUPixelBuffer *pb) GL_STREAM_DRAW_ARB); pixels = glMapBufferARB(GL_PIXEL_UNPACK_BUFFER_EXT, GL_WRITE_ONLY); - /*memcpy(pixels, _oImage.data(), pb->datasize);*/ + +# if 0 + memcpy(pixels, _oImage.data(), pb->datasize); +# endif if (!glUnmapBufferARB(GL_PIXEL_UNPACK_BUFFER_EXT)) { - fprintf(stderr, "Could not unmap opengl PBO\n"); + fprintf(stderr, "Could not unmap OpenGL PBO\n"); break; } } @@ -1594,7 +2315,7 @@ static int pixelbuffer_map_into_gpu(GLuint bindcode) /* do stuff in pixels */ if (!glUnmapBufferARB(GL_PIXEL_UNPACK_BUFFER_EXT)) { - fprintf(stderr, "Could not unmap opengl PBO\n"); + fprintf(stderr, "Could not unmap OpenGL PBO\n"); return 0; } @@ -1607,8 +2328,7 @@ static void pixelbuffer_copy_to_texture(GPUTexture *tex, GPUPixelBuffer *pb, GLu glBindTexture(GL_TEXTURE_RECTANGLE_EXT, tex->bindcode); glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_EXT, bindcode); - glTexSubImage2D(GL_TEXTURE_RECTANGLE_EXT, 0, 0, 0, tex->w, tex->h, - GL_RGBA, type, NULL); + glTexSubImage2D(GL_TEXTURE_RECTANGLE_EXT, 0, 0, 0, tex->w, tex->h, GL_RGBA, type, NULL); glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_EXT, 0); glBindTexture(GL_TEXTURE_RECTANGLE_EXT, 0); @@ -1623,12 +2343,12 @@ void GPU_pixelbuffer_async_to_gpu(GPUTexture *tex, GPUPixelBuffer *pb) pixelbuffer_map_into_gpu(pb->bindcode[0]); } else { - pb->current = (pb->current+1)%pb->numbuffers; - newbuffer = (pb->current+1)%pb->numbuffers; + pb->current = (pb->current + 1) % pb->numbuffers; + newbuffer = (pb->current + 1) % pb->numbuffers; pixelbuffer_map_into_gpu(pb->bindcode[newbuffer]); pixelbuffer_copy_to_texture(tex, pb, pb->bindcode[pb->current]); } } -#endif +#endif /* unused */ diff --git a/source/blender/gpu/intern/gpu_init_exit.c b/source/blender/gpu/intern/gpu_init_exit.c new file mode 100644 index 00000000000..3a8a6fca23b --- /dev/null +++ b/source/blender/gpu/intern/gpu_init_exit.c @@ -0,0 +1,79 @@ +/* + * ***** 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) 2013 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Jason Wilkins + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file source/blender/gpu/intern/gpu_init_exit.c + * \ingroup gpu + */ + +#include "BKE_DerivedMesh.h" + +#include "BLI_sys_types.h" +#include "GPU_init_exit.h" /* interface */ +#include "GPU_buffers.h" + +#include "BKE_global.h" + +#include "intern/gpu_codegen.h" +#include "intern/gpu_private.h" + +/** + * although the order of initialization and shutdown should not matter + * (except for the extensions), I chose alphabetical and reverse alphabetical order + */ + +static bool initialized = false; + +void GPU_init(void) +{ + /* can't avoid calling this multiple times, see wm_window_add_ghostwindow */ + if (initialized) + return; + + initialized = true; + + gpu_extensions_init(); /* must come first */ + + gpu_codegen_init(); + + if (G.debug & G_DEBUG_GPU) + gpu_debug_init(); + +} + + + +void GPU_exit(void) +{ + if (G.debug & G_DEBUG_GPU) + gpu_debug_exit(); + gpu_codegen_exit(); + + gpu_extensions_exit(); /* must come last */ + GPU_buffer_multires_free(true); + + initialized = false; +} diff --git a/source/blender/gpu/intern/gpu_material.c b/source/blender/gpu/intern/gpu_material.c index 81dcd9cf450..5b647232934 100644 --- a/source/blender/gpu/intern/gpu_material.c +++ b/source/blender/gpu/intern/gpu_material.c @@ -35,8 +35,6 @@ #include <math.h> #include <string.h> -#include "GL/glew.h" - #include "MEM_guardedalloc.h" #include "DNA_lamp_types.h" @@ -78,10 +76,25 @@ typedef enum DynMatProperty { DYN_LAMP_PERSMAT = 8, } DynMatProperty; +static struct GPUWorld { + float mistenabled; + float mistype; + float miststart; + float mistdistance; + float mistintensity; + float mistcol[4]; + float horicol[3]; + float ambcol[4]; +} GPUWorld; + struct GPUMaterial { Scene *scene; Material *ma; + /* material for mesh surface, worlds or something else. + * some code generation is done differently depending on the use case */ + int type; + /* for creating the material */ ListBase nodes; GPUNodeLink *outlink; @@ -89,7 +102,6 @@ struct GPUMaterial { /* for binding the material */ GPUPass *pass; GPUVertexAttribs attribs; - int bound; int builtins; int alpha, obcolalpha; int dynproperty; @@ -98,8 +110,17 @@ struct GPUMaterial { int viewmatloc, invviewmatloc; int obmatloc, invobmatloc; int obcolloc, obautobumpscaleloc; + int cameratexcofacloc; + + int partscalarpropsloc; + int partcoloc; + int partvel; + int partangvel; ListBase lamps; + bool bound; + + bool is_opensubdiv; }; struct GPULamp { @@ -153,7 +174,7 @@ static GPUMaterial *GPU_material_construct_begin(Material *ma) { GPUMaterial *material = MEM_callocN(sizeof(GPUMaterial), "GPUMaterial"); - material->ma= ma; + material->ma = ma; return material; } @@ -166,14 +187,14 @@ static void gpu_material_set_attrib_id(GPUMaterial *material) char name[32]; int a, b; - attribs= &material->attribs; - pass= material->pass; + attribs = &material->attribs; + pass = material->pass; if (!pass) { attribs->totlayer = 0; return; } - shader= GPU_pass_shader(pass); + shader = GPU_pass_shader(pass); if (!shader) { attribs->totlayer = 0; return; @@ -183,7 +204,7 @@ static void gpu_material_set_attrib_id(GPUMaterial *material) * in case the attrib does not get a valid index back, it was probably * removed by the glsl compiler by dead code elimination */ - for (a=0, b=0; a<attribs->totlayer; a++) { + for (a = 0, b = 0; a < attribs->totlayer; a++) { BLI_snprintf(name, sizeof(name), "att%d", attribs->layer[a].attribid); attribs->layer[a].glindex = GPU_shader_get_attribute(shader, name); @@ -196,7 +217,7 @@ static void gpu_material_set_attrib_id(GPUMaterial *material) attribs->totlayer = b; } -static int GPU_material_construct_end(GPUMaterial *material) +static int GPU_material_construct_end(GPUMaterial *material, const char *passname) { if (material->outlink) { GPUNodeLink *outlink; @@ -204,7 +225,8 @@ static int GPU_material_construct_end(GPUMaterial *material) outlink = material->outlink; material->pass = GPU_generate_pass(&material->nodes, outlink, - &material->attribs, &material->builtins, material->ma->id.name); + &material->attribs, &material->builtins, material->type, + passname, material->is_opensubdiv); if (!material->pass) return 0; @@ -225,39 +247,53 @@ static int GPU_material_construct_end(GPUMaterial *material) material->obcolloc = GPU_shader_get_uniform(shader, GPU_builtin_name(GPU_OBCOLOR)); if (material->builtins & GPU_AUTO_BUMPSCALE) material->obautobumpscaleloc = GPU_shader_get_uniform(shader, GPU_builtin_name(GPU_AUTO_BUMPSCALE)); + if (material->builtins & GPU_CAMERA_TEXCO_FACTORS) + material->cameratexcofacloc = GPU_shader_get_uniform(shader, GPU_builtin_name(GPU_CAMERA_TEXCO_FACTORS)); + if (material->builtins & GPU_PARTICLE_SCALAR_PROPS) + material->partscalarpropsloc = GPU_shader_get_uniform(shader, GPU_builtin_name(GPU_PARTICLE_SCALAR_PROPS)); + if (material->builtins & GPU_PARTICLE_LOCATION) + material->partcoloc = GPU_shader_get_uniform(shader, GPU_builtin_name(GPU_PARTICLE_LOCATION)); + if (material->builtins & GPU_PARTICLE_VELOCITY) + material->partvel = GPU_shader_get_uniform(shader, GPU_builtin_name(GPU_PARTICLE_VELOCITY)); + if (material->builtins & GPU_PARTICLE_ANG_VELOCITY) + material->partangvel = GPU_shader_get_uniform(shader, GPU_builtin_name(GPU_PARTICLE_ANG_VELOCITY)); return 1; } return 0; } -void GPU_material_free(Material *ma) +void GPU_material_free(ListBase *gpumaterial) { LinkData *link; LinkData *nlink, *mlink, *next; - for (link=ma->gpumaterial.first; link; link=link->next) { + for (link = gpumaterial->first; link; link = link->next) { GPUMaterial *material = link->data; if (material->pass) GPU_pass_free(material->pass); - for (nlink=material->lamps.first; nlink; nlink=nlink->next) { + for (nlink = material->lamps.first; nlink; nlink = nlink->next) { GPULamp *lamp = nlink->data; - for (mlink=lamp->materials.first; mlink; mlink=next) { - next = mlink->next; - if (mlink->data == ma) - BLI_freelinkN(&lamp->materials, mlink); + if (material->ma) { + Material *ma = material->ma; + + for (mlink = lamp->materials.first; mlink; mlink = next) { + next = mlink->next; + if (mlink->data == ma) + BLI_freelinkN(&lamp->materials, mlink); + } } } - + BLI_freelistN(&material->lamps); MEM_freeN(material); } - BLI_freelistN(&ma->gpumaterial); + BLI_freelistN(gpumaterial); } bool GPU_lamp_override_visible(GPULamp *lamp, SceneRenderLayer *srl, Material *ma) @@ -270,7 +306,7 @@ bool GPU_lamp_override_visible(GPULamp *lamp, SceneRenderLayer *srl, Material *m return true; } -void GPU_material_bind(GPUMaterial *material, int oblay, int viewlay, double time, int mipmap, float viewmat[4][4], float viewinv[4][4], bool scenelock) +void GPU_material_bind(GPUMaterial *material, int oblay, int viewlay, double time, int mipmap, float viewmat[4][4], float viewinv[4][4], float camerafactors[4], bool scenelock) { if (material->pass) { LinkData *nlink; @@ -282,42 +318,44 @@ void GPU_material_bind(GPUMaterial *material, int oblay, int viewlay, double tim viewlay &= srl->lay; /* handle layer lamps */ - for (nlink=material->lamps.first; nlink; nlink=nlink->next) { - lamp= nlink->data; - - if (!lamp->hide && (lamp->lay & viewlay) && (!(lamp->mode & LA_LAYER) || (lamp->lay & oblay)) - && GPU_lamp_override_visible(lamp, srl, material->ma)) { - lamp->dynenergy = lamp->energy; - copy_v3_v3(lamp->dyncol, lamp->col); - } - else { - lamp->dynenergy = 0.0f; - lamp->dyncol[0]= lamp->dyncol[1]= lamp->dyncol[2] = 0.0f; - } - - if (material->dynproperty & DYN_LAMP_VEC) { - copy_v3_v3(lamp->dynvec, lamp->vec); - normalize_v3(lamp->dynvec); - negate_v3(lamp->dynvec); - mul_mat3_m4_v3(viewmat, lamp->dynvec); - } - - if (material->dynproperty & DYN_LAMP_CO) { - copy_v3_v3(lamp->dynco, lamp->co); - mul_m4_v3(viewmat, lamp->dynco); - } - - if (material->dynproperty & DYN_LAMP_IMAT) { - mul_m4_m4m4(lamp->dynimat, lamp->imat, viewinv); - } - - if (material->dynproperty & DYN_LAMP_PERSMAT) { - if (!GPU_lamp_has_shadow_buffer(lamp)) /* The lamp matrices are already updated if we're using shadow buffers */ - GPU_lamp_update_buffer_mats(lamp); - mul_m4_m4m4(lamp->dynpersmat, lamp->persmat, viewinv); + if (material->type == GPU_MATERIAL_TYPE_MESH) { + for (nlink = material->lamps.first; nlink; nlink = nlink->next) { + lamp = nlink->data; + + if (!lamp->hide && (lamp->lay & viewlay) && (!(lamp->mode & LA_LAYER) || (lamp->lay & oblay)) + && GPU_lamp_override_visible(lamp, srl, material->ma)) { + lamp->dynenergy = lamp->energy; + copy_v3_v3(lamp->dyncol, lamp->col); + } + else { + lamp->dynenergy = 0.0f; + lamp->dyncol[0] = lamp->dyncol[1] = lamp->dyncol[2] = 0.0f; + } + + if (material->dynproperty & DYN_LAMP_VEC) { + copy_v3_v3(lamp->dynvec, lamp->vec); + normalize_v3(lamp->dynvec); + negate_v3(lamp->dynvec); + mul_mat3_m4_v3(viewmat, lamp->dynvec); + } + + if (material->dynproperty & DYN_LAMP_CO) { + copy_v3_v3(lamp->dynco, lamp->co); + mul_m4_v3(viewmat, lamp->dynco); + } + + if (material->dynproperty & DYN_LAMP_IMAT) { + mul_m4_m4m4(lamp->dynimat, lamp->imat, viewinv); + } + + if (material->dynproperty & DYN_LAMP_PERSMAT) { + if (!GPU_lamp_has_shadow_buffer(lamp)) /* The lamp matrices are already updated if we're using shadow buffers */ + GPU_lamp_update_buffer_mats(lamp); + mul_m4_m4m4(lamp->dynpersmat, lamp->persmat, viewinv); + } } } - + /* note material must be bound before setting uniforms */ GPU_pass_bind(material->pass, time, mipmap); @@ -328,6 +366,16 @@ void GPU_material_bind(GPUMaterial *material, int oblay, int viewlay, double tim if (material->builtins & GPU_INVERSE_VIEW_MATRIX) { GPU_shader_uniform_vector(shader, material->invviewmatloc, 16, 1, (float*)viewinv); } + if (material->builtins & GPU_CAMERA_TEXCO_FACTORS) { + if (camerafactors) { + GPU_shader_uniform_vector(shader, material->cameratexcofacloc, 4, 1, (float*)camerafactors); + } + else { + /* use default, no scaling no offset */ + float borders[4] = {1.0f, 1.0f, 0.0f, 0.0f}; + GPU_shader_uniform_vector(shader, material->cameratexcofacloc, 4, 1, (float*)borders); + } + } GPU_pass_update_uniforms(material->pass); @@ -335,7 +383,7 @@ void GPU_material_bind(GPUMaterial *material, int oblay, int viewlay, double tim } } -void GPU_material_bind_uniforms(GPUMaterial *material, float obmat[4][4], float obcol[4], float autobumpscale) +void GPU_material_bind_uniforms(GPUMaterial *material, float obmat[4][4], float obcol[4], float autobumpscale, GPUParticleInfo* pi) { if (material->pass) { GPUShader *shader = GPU_pass_shader(material->pass); @@ -357,6 +405,19 @@ void GPU_material_bind_uniforms(GPUMaterial *material, float obmat[4][4], float if (material->builtins & GPU_AUTO_BUMPSCALE) { GPU_shader_uniform_vector(shader, material->obautobumpscaleloc, 1, 1, &autobumpscale); } + if (material->builtins & GPU_PARTICLE_SCALAR_PROPS) { + GPU_shader_uniform_vector(shader, material->partscalarpropsloc, 4, 1, pi->scalprops); + } + if (material->builtins & GPU_PARTICLE_LOCATION) { + GPU_shader_uniform_vector(shader, material->partcoloc, 3, 1, pi->location); + } + if (material->builtins & GPU_PARTICLE_VELOCITY) { + GPU_shader_uniform_vector(shader, material->partvel, 3, 1, pi->velocity); + } + if (material->builtins & GPU_PARTICLE_ANG_VELOCITY) { + GPU_shader_uniform_vector(shader, material->partangvel, 3, 1, pi->angular_velocity); + } + } } @@ -368,7 +429,7 @@ void GPU_material_unbind(GPUMaterial *material) } } -int GPU_material_bound(GPUMaterial *material) +bool GPU_material_bound(GPUMaterial *material) { return material->bound; } @@ -378,6 +439,12 @@ Scene *GPU_material_scene(GPUMaterial *material) return material->scene; } +GPUMatType GPU_Material_get_type(GPUMaterial *material) +{ + return material->type; +} + + void GPU_material_vertex_attributes(GPUMaterial *material, GPUVertexAttribs *attribs) { *attribs = material->attribs; @@ -386,12 +453,12 @@ void GPU_material_vertex_attributes(GPUMaterial *material, GPUVertexAttribs *att void GPU_material_output_link(GPUMaterial *material, GPUNodeLink *link) { if (!material->outlink) - material->outlink= link; + material->outlink = link; } void GPU_material_enable_alpha(GPUMaterial *material) { - material->alpha= 1; + material->alpha = 1; } GPUBlendMode GPU_material_alpha_blend(GPUMaterial *material, float obcol[4]) @@ -414,7 +481,7 @@ bool GPU_material_do_color_management(GPUMaterial *mat) if (!BKE_scene_check_color_management_enabled(mat->scene)) return false; - return !((mat->scene->gm.flag & GAME_GLSL_NO_COLOR_MANAGEMENT)); + return true; } bool GPU_material_use_new_shading_nodes(GPUMaterial *mat) @@ -427,7 +494,7 @@ static GPUNodeLink *lamp_get_visibility(GPUMaterial *mat, GPULamp *lamp, GPUNode GPUNodeLink *visifac, *inpr; /* from get_lamp_visibility */ - if (lamp->type==LA_SUN || lamp->type==LA_HEMI) { + if (lamp->type == LA_SUN || lamp->type == LA_HEMI) { mat->dynproperty |= DYN_LAMP_VEC; GPU_link(mat, "lamp_visibility_sun_hemi", GPU_dynamic_uniform(lamp->dynvec, GPU_DYNAMIC_LAMP_DYNVEC, lamp->ob), lv, dist, &visifac); return visifac; @@ -436,7 +503,7 @@ static GPUNodeLink *lamp_get_visibility(GPUMaterial *mat, GPULamp *lamp, GPUNode mat->dynproperty |= DYN_LAMP_CO; GPU_link(mat, "lamp_visibility_other", GPU_builtin(GPU_VIEW_POSITION), GPU_dynamic_uniform(lamp->dynco, GPU_DYNAMIC_LAMP_DYNCO, lamp->ob), lv, dist, &visifac); - if (lamp->type==LA_AREA) + if (lamp->type == LA_AREA) return visifac; switch (lamp->falloff_type) { @@ -452,15 +519,16 @@ static GPUNodeLink *lamp_get_visibility(GPUMaterial *mat, GPULamp *lamp, GPUNode GPU_link(mat, "lamp_falloff_sliders", GPU_dynamic_uniform(&lamp->dist, GPU_DYNAMIC_LAMP_DISTANCE, lamp->ob), GPU_dynamic_uniform(&lamp->att1, GPU_DYNAMIC_LAMP_ATT1, lamp->ob), GPU_dynamic_uniform(&lamp->att2, GPU_DYNAMIC_LAMP_ATT2, lamp->ob), *dist, &visifac); break; case LA_FALLOFF_CURVE: - { - float *array; - int size; + { + float *array; + int size; + + curvemapping_initialize(lamp->curfalloff); + curvemapping_table_RGBA(lamp->curfalloff, &array, &size); + GPU_link(mat, "lamp_falloff_curve", GPU_dynamic_uniform(&lamp->dist, GPU_DYNAMIC_LAMP_DISTANCE, lamp->ob), GPU_texture(size, array), *dist, &visifac); - curvemapping_initialize(lamp->curfalloff); - curvemapping_table_RGBA(lamp->curfalloff, &array, &size); - GPU_link(mat, "lamp_falloff_curve", GPU_dynamic_uniform(&lamp->dist, GPU_DYNAMIC_LAMP_DISTANCE, lamp->ob), GPU_texture(size, array), *dist, &visifac); - } break; + } } if (lamp->mode & LA_SPHERE) @@ -488,34 +556,34 @@ static GPUNodeLink *lamp_get_visibility(GPUMaterial *mat, GPULamp *lamp, GPUNode #if 0 static void area_lamp_vectors(LampRen *lar) { - float xsize= 0.5*lar->area_size, ysize= 0.5*lar->area_sizey, multifac; + float xsize = 0.5f * lar->area_size, ysize = 0.5f * lar->area_sizey, multifac; /* make it smaller, so area light can be multisampled */ - multifac= 1.0f/sqrt((float)lar->ray_totsamp); + multifac = 1.0f / sqrtf((float)lar->ray_totsamp); xsize *= multifac; ysize *= multifac; /* corner vectors */ - lar->area[0][0]= lar->co[0] - xsize*lar->mat[0][0] - ysize*lar->mat[1][0]; - lar->area[0][1]= lar->co[1] - xsize*lar->mat[0][1] - ysize*lar->mat[1][1]; - lar->area[0][2]= lar->co[2] - xsize*lar->mat[0][2] - ysize*lar->mat[1][2]; + lar->area[0][0] = lar->co[0] - xsize * lar->mat[0][0] - ysize * lar->mat[1][0]; + lar->area[0][1] = lar->co[1] - xsize * lar->mat[0][1] - ysize * lar->mat[1][1]; + lar->area[0][2] = lar->co[2] - xsize * lar->mat[0][2] - ysize * lar->mat[1][2]; /* corner vectors */ - lar->area[1][0]= lar->co[0] - xsize*lar->mat[0][0] + ysize*lar->mat[1][0]; - lar->area[1][1]= lar->co[1] - xsize*lar->mat[0][1] + ysize*lar->mat[1][1]; - lar->area[1][2]= lar->co[2] - xsize*lar->mat[0][2] + ysize*lar->mat[1][2]; + lar->area[1][0] = lar->co[0] - xsize * lar->mat[0][0] + ysize * lar->mat[1][0]; + lar->area[1][1] = lar->co[1] - xsize * lar->mat[0][1] + ysize * lar->mat[1][1]; + lar->area[1][2] = lar->co[2] - xsize * lar->mat[0][2] + ysize * lar->mat[1][2]; /* corner vectors */ - lar->area[2][0]= lar->co[0] + xsize*lar->mat[0][0] + ysize*lar->mat[1][0]; - lar->area[2][1]= lar->co[1] + xsize*lar->mat[0][1] + ysize*lar->mat[1][1]; - lar->area[2][2]= lar->co[2] + xsize*lar->mat[0][2] + ysize*lar->mat[1][2]; + lar->area[2][0] = lar->co[0] + xsize * lar->mat[0][0] + ysize * lar->mat[1][0]; + lar->area[2][1] = lar->co[1] + xsize * lar->mat[0][1] + ysize * lar->mat[1][1]; + lar->area[2][2] = lar->co[2] + xsize * lar->mat[0][2] + ysize * lar->mat[1][2]; /* corner vectors */ - lar->area[3][0]= lar->co[0] + xsize*lar->mat[0][0] - ysize*lar->mat[1][0]; - lar->area[3][1]= lar->co[1] + xsize*lar->mat[0][1] - ysize*lar->mat[1][1]; - lar->area[3][2]= lar->co[2] + xsize*lar->mat[0][2] - ysize*lar->mat[1][2]; + lar->area[3][0] = lar->co[0] + xsize * lar->mat[0][0] - ysize * lar->mat[1][0]; + lar->area[3][1] = lar->co[1] + xsize * lar->mat[0][1] - ysize * lar->mat[1][1]; + lar->area[3][2] = lar->co[2] + xsize * lar->mat[0][2] - ysize * lar->mat[1][2]; /* only for correction button size, matrix size works on energy */ - lar->areasize= lar->dist*lar->dist/(4.0*xsize*ysize); + lar->areasize = lar->dist * lar->dist / (4.0f * xsize * ysize); } #endif @@ -549,8 +617,8 @@ static void do_colorband_blend(GPUMaterial *mat, ColorBand *coba, GPUNodeLink *f static void ramp_diffuse_result(GPUShadeInput *shi, GPUNodeLink **diff) { - Material *ma= shi->mat; - GPUMaterial *mat= shi->gpumat; + Material *ma = shi->mat; + GPUMaterial *mat = shi->gpumat; GPUNodeLink *fac; if (!(mat->scene->gm.flag & GAME_GLSL_NO_RAMPS)) { @@ -579,18 +647,18 @@ static void add_to_diffuse(GPUMaterial *mat, Material *ma, GPUShadeInput *shi, G else { /* input */ switch (ma->rampin_col) { - case MA_RAMP_IN_ENERGY: - GPU_link(mat, "ramp_rgbtobw", rgb, &fac); - break; - case MA_RAMP_IN_SHADER: - fac= is; - break; - case MA_RAMP_IN_NOR: - GPU_link(mat, "vec_math_dot", shi->view, shi->vn, &tmp, &fac); - break; - default: - GPU_link(mat, "set_value_zero", &fac); - break; + case MA_RAMP_IN_ENERGY: + GPU_link(mat, "ramp_rgbtobw", rgb, &fac); + break; + case MA_RAMP_IN_SHADER: + fac= is; + break; + case MA_RAMP_IN_NOR: + GPU_link(mat, "vec_math_dot", shi->view, shi->vn, &tmp, &fac); + break; + default: + GPU_link(mat, "set_value_zero", &fac); + break; } /* colorband + blend */ @@ -606,12 +674,12 @@ static void add_to_diffuse(GPUMaterial *mat, Material *ma, GPUShadeInput *shi, G static void ramp_spec_result(GPUShadeInput *shi, GPUNodeLink **spec) { - Material *ma= shi->mat; - GPUMaterial *mat= shi->gpumat; + Material *ma = shi->mat; + GPUMaterial *mat = shi->gpumat; GPUNodeLink *fac; if (!(mat->scene->gm.flag & GAME_GLSL_NO_RAMPS) && - ma->ramp_spec && ma->rampin_spec==MA_RAMP_IN_RESULT) + ma->ramp_spec && ma->rampin_spec == MA_RAMP_IN_RESULT) { GPU_link(mat, "ramp_rgbtobw", *spec, &fac); @@ -622,29 +690,29 @@ static void ramp_spec_result(GPUShadeInput *shi, GPUNodeLink **spec) static void do_specular_ramp(GPUShadeInput *shi, GPUNodeLink *is, GPUNodeLink *t, GPUNodeLink **spec) { - Material *ma= shi->mat; - GPUMaterial *mat= shi->gpumat; + Material *ma = shi->mat; + GPUMaterial *mat = shi->gpumat; GPUNodeLink *fac, *tmp; *spec = shi->specrgb; /* MA_RAMP_IN_RESULT is exception */ - if (ma->ramp_spec && (ma->rampin_spec!=MA_RAMP_IN_RESULT)) { + if (ma->ramp_spec && (ma->rampin_spec != MA_RAMP_IN_RESULT)) { /* input */ switch (ma->rampin_spec) { - case MA_RAMP_IN_ENERGY: - fac = t; - break; - case MA_RAMP_IN_SHADER: - fac = is; - break; - case MA_RAMP_IN_NOR: - GPU_link(mat, "vec_math_dot", shi->view, shi->vn, &tmp, &fac); - break; - default: - GPU_link(mat, "set_value_zero", &fac); - break; + case MA_RAMP_IN_ENERGY: + fac = t; + break; + case MA_RAMP_IN_SHADER: + fac = is; + break; + case MA_RAMP_IN_NOR: + GPU_link(mat, "vec_math_dot", shi->view, shi->vn, &tmp, &fac); + break; + default: + GPU_link(mat, "set_value_zero", &fac); + break; } /* colorband + blend */ @@ -666,10 +734,10 @@ static void shade_light_textures(GPUMaterial *mat, GPULamp *lamp, GPUNodeLink ** int i; float one = 1.f; - for (i=0; i<MAX_MTEX; ++i) { + for (i = 0; i < MAX_MTEX; ++i) { mtex = lamp->la->mtex[i]; - if (mtex && mtex->tex->type & TEX_IMAGE && mtex->tex->ima) { + if (mtex && mtex->tex->type & TEX_IMAGE && mtex->tex->ima) { mat->dynproperty |= DYN_LAMP_PERSMAT; GPU_link(mat, "shade_light_texture", @@ -677,29 +745,31 @@ static void shade_light_textures(GPUMaterial *mat, GPULamp *lamp, GPUNodeLink ** GPU_image(mtex->tex->ima, &mtex->tex->iuser, false), GPU_dynamic_uniform((float*)lamp->dynpersmat, GPU_DYNAMIC_LAMP_DYNPERSMAT, lamp->ob), &tex_rgb); - texture_rgb_blend(mat, tex_rgb, *rgb, GPU_uniform(&one), GPU_uniform(&mtex->colfac), mtex->blendtype, rgb); + texture_rgb_blend(mat, tex_rgb, *rgb, GPU_uniform(&one), GPU_uniform(&mtex->colfac), mtex->blendtype, rgb); } } } static void shade_one_light(GPUShadeInput *shi, GPUShadeResult *shr, GPULamp *lamp) { - Material *ma= shi->mat; - GPUMaterial *mat= shi->gpumat; + Material *ma = shi->mat; + GPUMaterial *mat = shi->gpumat; GPUNodeLink *lv, *dist, *visifac, *is, *inp, *i, *vn, *view; - GPUNodeLink *outcol, *specfac, *t, *shadfac= NULL, *lcol; + GPUNodeLink *outcol, *specfac, *t, *shadfac = NULL, *lcol; float one = 1.0f; if ((lamp->mode & LA_ONLYSHADOW) && !(ma->mode & MA_SHADOW)) return; - vn= shi->vn; - view= shi->view; + vn = shi->vn; + view = shi->view; - visifac= lamp_get_visibility(mat, lamp, &lv, &dist); + visifac = lamp_get_visibility(mat, lamp, &lv, &dist); - /*if (ma->mode & MA_TANGENT_V) - GPU_link(mat, "shade_tangent_v", lv, GPU_attribute(CD_TANGENT, ""), &vn);*/ +#if 0 + if (ma->mode & MA_TANGENT_V) + GPU_link(mat, "shade_tangent_v", lv, GPU_attribute(CD_TANGENT, ""), &vn); +#endif GPU_link(mat, "shade_inp", vn, lv, &inp); @@ -711,23 +781,23 @@ static void shade_one_light(GPUShadeInput *shi, GPUShadeResult *shr, GPULamp *la } else { if (lamp->type == LA_AREA) { - float area[4][4]= {{0.0f}}, areasize= 0.0f; + float area[4][4] = {{0.0f}}, areasize = 0.0f; mat->dynproperty |= DYN_LAMP_VEC|DYN_LAMP_CO; GPU_link(mat, "shade_inp_area", GPU_builtin(GPU_VIEW_POSITION), GPU_dynamic_uniform(lamp->dynco, GPU_DYNAMIC_LAMP_DYNCO, lamp->ob), GPU_dynamic_uniform(lamp->dynvec, GPU_DYNAMIC_LAMP_DYNVEC, lamp->ob), vn, GPU_uniform((float*)area), GPU_uniform(&areasize), GPU_uniform(&lamp->k), &inp); } - is= inp; /* Lambert */ + is = inp; /* Lambert */ if (!(mat->scene->gm.flag & GAME_GLSL_NO_SHADERS)) { - if (ma->diff_shader==MA_DIFF_ORENNAYAR) + if (ma->diff_shader == MA_DIFF_ORENNAYAR) GPU_link(mat, "shade_diffuse_oren_nayer", inp, vn, lv, view, GPU_uniform(&ma->roughness), &is); - else if (ma->diff_shader==MA_DIFF_TOON) + else if (ma->diff_shader == MA_DIFF_TOON) GPU_link(mat, "shade_diffuse_toon", vn, lv, view, GPU_uniform(&ma->param[0]), GPU_uniform(&ma->param[1]), &is); - else if (ma->diff_shader==MA_DIFF_MINNAERT) + else if (ma->diff_shader == MA_DIFF_MINNAERT) GPU_link(mat, "shade_diffuse_minnaert", inp, vn, view, GPU_uniform(&ma->darkness), &is); - else if (ma->diff_shader==MA_DIFF_FRESNEL) + else if (ma->diff_shader == MA_DIFF_FRESNEL) GPU_link(mat, "shade_diffuse_fresnel", vn, lv, view, GPU_uniform(&ma->param[0]), GPU_uniform(&ma->param[1]), &is); } } @@ -739,8 +809,9 @@ static void shade_one_light(GPUShadeInput *shi, GPUShadeResult *shr, GPULamp *la i = is; GPU_link(mat, "shade_visifac", i, visifac, shi->refl, &i); - GPU_link(mat, "set_value", GPU_dynamic_uniform(lamp->dyncol, GPU_DYNAMIC_LAMP_DYNCOL, lamp->ob), &lcol); + GPU_link(mat, "set_rgb", GPU_dynamic_uniform(lamp->dyncol, GPU_DYNAMIC_LAMP_DYNCOL, lamp->ob), &lcol); shade_light_textures(mat, lamp, &lcol); + GPU_link(mat, "shade_mul_value_v3", GPU_dynamic_uniform(&lamp->dynenergy, GPU_DYNAMIC_LAMP_DYNENERGY, lamp->ob), lcol, &lcol); #if 0 if (ma->mode & MA_TANGENT_VN) @@ -748,7 +819,7 @@ static void shade_one_light(GPUShadeInput *shi, GPUShadeResult *shr, GPULamp *la #endif /* this replaces if (i > 0.0) conditional until that is supported */ - // done in shade_visifac now, GPU_link(mat, "mtex_value_clamp_positive", i, &i); + /* done in shade_visifac now, GPU_link(mat, "mtex_value_clamp_positive", i, &i); */ if ((ma->mode & MA_SHADOW) && GPU_lamp_has_shadow_buffer(lamp)) { if (!(mat->scene->gm.flag & GAME_GLSL_NO_SHADOWS)) { @@ -821,18 +892,18 @@ static void shade_one_light(GPUShadeInput *shi, GPUShadeResult *shr, GPULamp *la GPU_link(mat, "shade_add_clamped", shr->spec, outcol, &shr->spec); } else { - if (ma->spec_shader==MA_SPEC_PHONG) + if (ma->spec_shader == MA_SPEC_PHONG) GPU_link(mat, "shade_phong_spec", vn, lv, view, shi->har, &specfac); - else if (ma->spec_shader==MA_SPEC_COOKTORR) + else if (ma->spec_shader == MA_SPEC_COOKTORR) GPU_link(mat, "shade_cooktorr_spec", vn, lv, view, shi->har, &specfac); - else if (ma->spec_shader==MA_SPEC_BLINN) + else if (ma->spec_shader == MA_SPEC_BLINN) GPU_link(mat, "shade_blinn_spec", vn, lv, view, GPU_uniform(&ma->refrac), shi->har, &specfac); - else if (ma->spec_shader==MA_SPEC_WARDISO) + else if (ma->spec_shader == MA_SPEC_WARDISO) GPU_link(mat, "shade_wardiso_spec", vn, lv, view, GPU_uniform(&ma->rms), &specfac); else GPU_link(mat, "shade_toon_spec", vn, lv, view, GPU_uniform(&ma->param[2]), GPU_uniform(&ma->param[3]), &specfac); - if (lamp->type==LA_AREA) + if (lamp->type == LA_AREA) GPU_link(mat, "shade_spec_area_inp", specfac, inp, &specfac); GPU_link(mat, "shade_spec_t", shadfac, shi->spec, visifac, specfac, &t); @@ -862,9 +933,9 @@ static void material_lights(GPUShadeInput *shi, GPUShadeResult *shr) GPULamp *lamp; for (SETLOOPER(shi->gpumat->scene, sce_iter, base)) { - ob= base->object; + ob = base->object; - if (ob->type==OB_LAMP) { + if (ob->type == OB_LAMP) { lamp = GPU_lamp_from_blender(shi->gpumat->scene, ob, NULL); if (lamp) shade_one_light(shi, shr, lamp); @@ -874,10 +945,10 @@ static void material_lights(GPUShadeInput *shi, GPUShadeResult *shr) DupliObject *dob; ListBase *lb = object_duplilist(G.main->eval_ctx, shi->gpumat->scene, ob); - for (dob=lb->first; dob; dob=dob->next) { + for (dob = lb->first; dob; dob = dob->next) { Object *ob_iter = dob->ob; - if (ob_iter->type==OB_LAMP) { + if (ob_iter->type == OB_LAMP) { float omat[4][4]; copy_m4_m4(omat, ob_iter->obmat); copy_m4_m4(ob_iter->obmat, dob->mat); @@ -994,8 +1065,8 @@ static void texture_value_blend(GPUMaterial *mat, GPUNodeLink *tex, GPUNodeLink static void do_material_tex(GPUShadeInput *shi) { - Material *ma= shi->mat; - GPUMaterial *mat= shi->gpumat; + Material *ma = shi->mat; + GPUMaterial *mat = shi->gpumat; MTex *mtex; Tex *tex; GPUNodeLink *texco, *tin, *trgb, *tnor, *tcol, *stencil, *tnorfac; @@ -1006,9 +1077,9 @@ static void do_material_tex(GPUShadeInput *shi) float one = 1.0f, norfac, ofs[3]; int tex_nr, rgbnor, talpha; bool init_done = false; - int iBumpSpacePrev = 0; /* Not necessary, quiting gcc warning. */ + int iBumpSpacePrev = 0; /* Not necessary, quieting gcc warning. */ GPUNodeLink *vNorg, *vNacc, *fPrevMagnitude; - int iFirstTimeNMap=1; + int iFirstTimeNMap = 1; int found_deriv_map = 0; GPU_link(mat, "set_value", GPU_uniform(&one), &stencil); @@ -1018,44 +1089,46 @@ static void do_material_tex(GPUShadeInput *shi) GPU_link(mat, "texco_object", GPU_builtin(GPU_INVERSE_VIEW_MATRIX), GPU_builtin(GPU_INVERSE_OBJECT_MATRIX), GPU_builtin(GPU_VIEW_POSITION), &texco_object); - //GPU_link(mat, "texco_tangent", GPU_attribute(CD_TANGENT, ""), &texco_tangent); +#if 0 + GPU_link(mat, "texco_tangent", GPU_attribute(CD_TANGENT, ""), &texco_tangent); +#endif GPU_link(mat, "texco_global", GPU_builtin(GPU_INVERSE_VIEW_MATRIX), GPU_builtin(GPU_VIEW_POSITION), &texco_global); orn= texco_norm; /* go over texture slots */ - for (tex_nr=0; tex_nr<MAX_MTEX; tex_nr++) { + for (tex_nr = 0; tex_nr < MAX_MTEX; tex_nr++) { /* separate tex switching */ - if (ma->septex & (1<<tex_nr)) continue; + if (ma->septex & (1 << tex_nr)) continue; if (ma->mtex[tex_nr]) { - mtex= ma->mtex[tex_nr]; + mtex = ma->mtex[tex_nr]; - tex= mtex->tex; + tex = mtex->tex; if (tex == NULL) continue; /* which coords */ - if (mtex->texco==TEXCO_ORCO) - texco= texco_orco; - else if (mtex->texco==TEXCO_OBJECT) - texco= texco_object; - else if (mtex->texco==TEXCO_NORM) - texco= orn; - else if (mtex->texco==TEXCO_TANGENT) - texco= texco_object; - else if (mtex->texco==TEXCO_GLOB) - texco= texco_global; - else if (mtex->texco==TEXCO_REFL) { + if (mtex->texco == TEXCO_ORCO) + texco = texco_orco; + else if (mtex->texco == TEXCO_OBJECT) + texco = texco_object; + else if (mtex->texco == TEXCO_NORM) + texco = orn; + else if (mtex->texco == TEXCO_TANGENT) + texco = texco_object; + else if (mtex->texco == TEXCO_GLOB) + texco = texco_global; + else if (mtex->texco == TEXCO_REFL) { GPU_link(mat, "texco_refl", shi->vn, shi->view, &shi->ref); - texco= shi->ref; + texco = shi->ref; } - else if (mtex->texco==TEXCO_UV) { + else if (mtex->texco == TEXCO_UV) { if (1) { //!(texco_uv && strcmp(mtex->uvname, lastuvname) == 0)) { GPU_link(mat, "texco_uv", GPU_attribute(CD_MTFACE, mtex->uvname), &texco_uv); /*lastuvname = mtex->uvname;*/ /*UNUSED*/ } - texco= texco_uv; + texco = texco_uv; } else continue; @@ -1067,8 +1140,8 @@ static void do_material_tex(GPUShadeInput *shi) if (mtex->size[0] != 1.0f || mtex->size[1] != 1.0f || mtex->size[2] != 1.0f) GPU_link(mat, "mtex_mapping_size", texco, GPU_uniform(mtex->size), &texco); - ofs[0] = mtex->ofs[0] + 0.5f - 0.5f*mtex->size[0]; - ofs[1] = mtex->ofs[1] + 0.5f - 0.5f*mtex->size[1]; + ofs[0] = mtex->ofs[0] + 0.5f - 0.5f * mtex->size[0]; + ofs[1] = mtex->ofs[1] + 0.5f - 0.5f * mtex->size[1]; ofs[2] = 0.0f; if (ofs[0] != 0.0f || ofs[1] != 0.0f || ofs[2] != 0.0f) GPU_link(mat, "mtex_mapping_ofs", texco, GPU_uniform(ofs), &texco); @@ -1077,7 +1150,7 @@ static void do_material_tex(GPUShadeInput *shi) if (tex && tex->type == TEX_IMAGE && tex->ima) { GPU_link(mat, "mtex_image", texco, GPU_image(tex->ima, &tex->iuser, false), &tin, &trgb); - rgbnor= TEX_RGB; + rgbnor = TEX_RGB; talpha = ((tex->imaflag & TEX_USEALPHA) && tex->ima && (tex->ima->flag & IMA_IGNORE_ALPHA) == 0); } @@ -1122,7 +1195,7 @@ static void do_material_tex(GPUShadeInput *shi) GPU_link(mat, "set_value_one", &tin); } - if (tex->type==TEX_IMAGE) + if (tex->type == TEX_IMAGE) if (GPU_material_do_color_management(mat)) GPU_link(mat, "srgb_to_linearrgb", tcol, &tcol); @@ -1146,7 +1219,7 @@ static void do_material_tex(GPUShadeInput *shi) } if (!(mat->scene->gm.flag & GAME_GLSL_NO_EXTRA_TEX) && (mtex->mapto & MAP_NORM)) { - if (tex->type==TEX_IMAGE) { + if (tex->type == TEX_IMAGE) { found_deriv_map = tex->imaflag & TEX_DERIVATIVEMAP; if (tex->imaflag & TEX_NORMALMAP) { @@ -1170,7 +1243,7 @@ static void do_material_tex(GPUShadeInput *shi) } else if (mtex->normapspace == MTEX_NSPACE_OBJECT) { /* transform normal by object then view matrix */ - GPU_link(mat, "mtex_nspace_object", GPU_builtin(GPU_VIEW_MATRIX), GPU_builtin(GPU_OBJECT_MATRIX), tnor, &newnor); + GPU_link(mat, "mtex_nspace_object", tnor, &newnor); } else if (mtex->normapspace == MTEX_NSPACE_WORLD) { /* transform normal by view matrix */ @@ -1196,44 +1269,43 @@ static void do_material_tex(GPUShadeInput *shi) } } - else if ( (mtex->texflag & (MTEX_3TAP_BUMP|MTEX_5TAP_BUMP|MTEX_BICUBIC_BUMP)) || found_deriv_map) { + else if ((mtex->texflag & (MTEX_3TAP_BUMP | MTEX_5TAP_BUMP | MTEX_BICUBIC_BUMP)) || found_deriv_map) { /* ntap bumpmap image */ int iBumpSpace; float ima_x, ima_y; float hScale; - float imag_tspace_dimension_x = 1024.0f; // only used for texture space variant + float imag_tspace_dimension_x = 1024.0f; /* only used for texture space variant */ float aspect = 1.0f; - GPUNodeLink *surf_pos = GPU_builtin(GPU_VIEW_POSITION); GPUNodeLink *vR1, *vR2; GPUNodeLink *dBs, *dBt, *fDet; - hScale = 0.1; // compatibility adjustment factor for all bumpspace types - if ( mtex->texflag & MTEX_BUMP_TEXTURESPACE ) - hScale = 13.0f; // factor for scaling texspace bumps + hScale = 0.1; /* compatibility adjustment factor for all bumpspace types */ + if (mtex->texflag & MTEX_BUMP_TEXTURESPACE) + hScale = 13.0f; /* factor for scaling texspace bumps */ else if (found_deriv_map!=0) hScale = 1.0f; - // resolve texture resolution - if ( (mtex->texflag & MTEX_BUMP_TEXTURESPACE) || found_deriv_map ) { - ImBuf *ibuf= BKE_image_acquire_ibuf(tex->ima, &tex->iuser, NULL); - ima_x= 512.0f; ima_y= 512.f; // prevent calling textureSize, glsl 1.3 only + /* resolve texture resolution */ + if ((mtex->texflag & MTEX_BUMP_TEXTURESPACE) || found_deriv_map) { + ImBuf *ibuf = BKE_image_acquire_ibuf(tex->ima, &tex->iuser, NULL); + ima_x = 512.0f; ima_y = 512.f; /* prevent calling textureSize, glsl 1.3 only */ if (ibuf) { - ima_x= ibuf->x; - ima_y= ibuf->y; - aspect = ((float) ima_y) / ima_x; + ima_x = ibuf->x; + ima_y = ibuf->y; + aspect = (float)ima_y / ima_x; } BKE_image_release_ibuf(tex->ima, ibuf, NULL); } - // The negate on norfac is done because the - // normal in the renderer points inward which corresponds - // to inverting the bump map. Should this ever change - // this negate must be removed. + /* The negate on norfac is done because the + * normal in the renderer points inward which corresponds + * to inverting the bump map. Should this ever change + * this negate must be removed. */ norfac = -hScale * mtex->norfac; if (found_deriv_map) { - float fVirtDim = sqrtf(fabsf(ima_x*mtex->size[0]*ima_y*mtex->size[1])); + float fVirtDim = sqrtf(fabsf(ima_x * mtex->size[0] * ima_y * mtex->size[1])); norfac /= MAX2(fVirtDim, FLT_EPSILON); } @@ -1245,25 +1317,26 @@ static void do_material_tex(GPUShadeInput *shi) if (GPU_link_changed(stencil)) GPU_link(mat, "math_multiply", tnorfac, stencil, &tnorfac); - if ( !init_done ) { - // copy shi->vn to vNorg and vNacc, set magnitude to 1 + if (!init_done) { + /* copy shi->vn to vNorg and vNacc, set magnitude to 1 */ GPU_link(mat, "mtex_bump_normals_init", shi->vn, &vNorg, &vNacc, &fPrevMagnitude); iBumpSpacePrev = 0; init_done = true; } // find current bump space - if ( mtex->texflag & MTEX_BUMP_OBJECTSPACE ) + if (mtex->texflag & MTEX_BUMP_OBJECTSPACE) iBumpSpace = 1; - else if ( mtex->texflag & MTEX_BUMP_TEXTURESPACE ) + else if (mtex->texflag & MTEX_BUMP_TEXTURESPACE) iBumpSpace = 2; else - iBumpSpace = 4; // ViewSpace + iBumpSpace = 4; /* ViewSpace */ - // re-initialize if bump space changed - if ( iBumpSpacePrev != iBumpSpace ) { - - if ( mtex->texflag & MTEX_BUMP_OBJECTSPACE ) + /* re-initialize if bump space changed */ + if (iBumpSpacePrev != iBumpSpace) { + GPUNodeLink *surf_pos = GPU_builtin(GPU_VIEW_POSITION); + + if (mtex->texflag & MTEX_BUMP_OBJECTSPACE) GPU_link(mat, "mtex_bump_init_objspace", surf_pos, vNorg, GPU_builtin(GPU_VIEW_MATRIX), GPU_builtin(GPU_INVERSE_VIEW_MATRIX), GPU_builtin(GPU_OBJECT_MATRIX), GPU_builtin(GPU_INVERSE_OBJECT_MATRIX), @@ -1271,7 +1344,7 @@ static void do_material_tex(GPUShadeInput *shi) &fPrevMagnitude, &vNacc, &vR1, &vR2, &fDet); - else if ( mtex->texflag & MTEX_BUMP_TEXTURESPACE ) + else if (mtex->texflag & MTEX_BUMP_TEXTURESPACE) GPU_link(mat, "mtex_bump_init_texturespace", surf_pos, vNorg, fPrevMagnitude, vNacc, @@ -1292,17 +1365,17 @@ static void do_material_tex(GPUShadeInput *shi) if (found_deriv_map) { GPU_link(mat, "mtex_bump_deriv", texco, GPU_image(tex->ima, &tex->iuser, true), GPU_uniform(&ima_x), GPU_uniform(&ima_y), tnorfac, - &dBs, &dBt ); + &dBs, &dBt); } - else if ( mtex->texflag & MTEX_3TAP_BUMP) + else if (mtex->texflag & MTEX_3TAP_BUMP) GPU_link(mat, "mtex_bump_tap3", texco, GPU_image(tex->ima, &tex->iuser, true), tnorfac, - &dBs, &dBt ); - else if ( mtex->texflag & MTEX_5TAP_BUMP) + &dBs, &dBt); + else if (mtex->texflag & MTEX_5TAP_BUMP) GPU_link(mat, "mtex_bump_tap5", texco, GPU_image(tex->ima, &tex->iuser, true), tnorfac, - &dBs, &dBt ); - else if ( mtex->texflag & MTEX_BICUBIC_BUMP ) { + &dBs, &dBt); + else if (mtex->texflag & MTEX_BICUBIC_BUMP) { if (GPU_bicubic_bump_support()) { GPU_link(mat, "mtex_bump_bicubic", texco, GPU_image(tex->ima, &tex->iuser, true), tnorfac, @@ -1316,18 +1389,18 @@ static void do_material_tex(GPUShadeInput *shi) } - if ( mtex->texflag & MTEX_BUMP_TEXTURESPACE ) { - float imag_tspace_dimension_y = aspect*imag_tspace_dimension_x; + if (mtex->texflag & MTEX_BUMP_TEXTURESPACE) { + float imag_tspace_dimension_y = aspect * imag_tspace_dimension_x; GPU_link(mat, "mtex_bump_apply_texspace", fDet, dBs, dBt, vR1, vR2, GPU_image(tex->ima, &tex->iuser, true), texco, GPU_uniform(&imag_tspace_dimension_x), GPU_uniform(&imag_tspace_dimension_y), vNacc, - &vNacc, &shi->vn ); + &vNacc, &shi->vn); } else GPU_link(mat, "mtex_bump_apply", fDet, dBs, dBt, vR1, vR2, vNacc, - &vNacc, &shi->vn ); + &vNacc, &shi->vn); } } @@ -1405,7 +1478,6 @@ static void do_material_tex(GPUShadeInput *shi) void GPU_shadeinput_set(GPUMaterial *mat, Material *ma, GPUShadeInput *shi) { - float hard = ma->har; float one = 1.0f; memset(shi, 0, sizeof(*shi)); @@ -1413,20 +1485,21 @@ void GPU_shadeinput_set(GPUMaterial *mat, Material *ma, GPUShadeInput *shi) shi->gpumat = mat; shi->mat = ma; - GPU_link(mat, "set_rgb", GPU_uniform(&ma->r), &shi->rgb); - GPU_link(mat, "set_rgb", GPU_uniform(&ma->specr), &shi->specrgb); + GPU_link(mat, "set_rgb", GPU_dynamic_uniform(&ma->r, GPU_DYNAMIC_MAT_DIFFRGB, NULL), &shi->rgb); + GPU_link(mat, "set_rgb", GPU_dynamic_uniform(&ma->specr, GPU_DYNAMIC_MAT_SPECRGB, NULL), &shi->specrgb); GPU_link(mat, "shade_norm", GPU_builtin(GPU_VIEW_NORMAL), &shi->vn); if (mat->alpha) - GPU_link(mat, "set_value", GPU_uniform(&ma->alpha), &shi->alpha); + GPU_link(mat, "set_value", GPU_dynamic_uniform(&ma->alpha, GPU_DYNAMIC_MAT_ALPHA, NULL), &shi->alpha); else GPU_link(mat, "set_value", GPU_uniform(&one), &shi->alpha); - GPU_link(mat, "set_value", GPU_uniform(&ma->ref), &shi->refl); - GPU_link(mat, "set_value", GPU_uniform(&ma->spec), &shi->spec); - GPU_link(mat, "set_value", GPU_uniform(&ma->emit), &shi->emit); - GPU_link(mat, "set_value", GPU_uniform(&hard), &shi->har); - GPU_link(mat, "set_value", GPU_uniform(&ma->amb), &shi->amb); + GPU_link(mat, "set_value", GPU_dynamic_uniform(&ma->ref, GPU_DYNAMIC_MAT_REF, NULL), &shi->refl); + GPU_link(mat, "set_value", GPU_dynamic_uniform(&ma->spec, GPU_DYNAMIC_MAT_SPEC, NULL), &shi->spec); + GPU_link(mat, "set_value", GPU_dynamic_uniform(&ma->emit, GPU_DYNAMIC_MAT_EMIT, NULL), &shi->emit); + GPU_link(mat, "set_value", GPU_dynamic_uniform((float*)&ma->har, GPU_DYNAMIC_MAT_HARD, NULL), &shi->har); + GPU_link(mat, "set_value", GPU_dynamic_uniform(&ma->amb, GPU_DYNAMIC_MAT_AMB, NULL), &shi->amb); + GPU_link(mat, "set_value", GPU_uniform(&ma->spectra), &shi->spectra); GPU_link(mat, "shade_view", GPU_builtin(GPU_VIEW_POSITION), &shi->view); GPU_link(mat, "vcol_attribute", GPU_attribute(CD_MCOL, ""), &shi->vcol); if (GPU_material_do_color_management(mat)) @@ -1434,13 +1507,39 @@ void GPU_shadeinput_set(GPUMaterial *mat, Material *ma, GPUShadeInput *shi) GPU_link(mat, "texco_refl", shi->vn, shi->view, &shi->ref); } +void GPU_mist_update_enable(short enable) +{ + GPUWorld.mistenabled = (float)enable; +} + +void GPU_mist_update_values(int type, float start, float dist, float inten, float color[3]) +{ + GPUWorld.mistype = (float)type; + GPUWorld.miststart = start; + GPUWorld.mistdistance = dist; + GPUWorld.mistintensity = inten; + copy_v3_v3(GPUWorld.mistcol, color); + GPUWorld.mistcol[3] = 1.0f; +} + +void GPU_horizon_update_color(float color[3]) +{ + copy_v3_v3(GPUWorld.horicol, color); +} + +void GPU_ambient_update_color(float color[3]) +{ + copy_v3_v3(GPUWorld.ambcol, color); + GPUWorld.ambcol[3] = 1.0f; +} + void GPU_shaderesult_set(GPUShadeInput *shi, GPUShadeResult *shr) { - GPUMaterial *mat= shi->gpumat; + GPUMaterial *mat = shi->gpumat; GPUNodeLink *emit, *ulinfac, *ulogfac, *mistfac; - Material *ma= shi->mat; - World *world= mat->scene->world; - float linfac, logfac, misttype; + Material *ma = shi->mat; + World *world = mat->scene->world; + float linfac, logfac; memset(shr, 0, sizeof(*shr)); @@ -1457,7 +1556,7 @@ void GPU_shaderesult_set(GPUShadeInput *shi, GPUShadeResult *shr) } else { if (GPU_link_changed(shi->emit) || ma->emit != 0.0f) { - if ((ma->mode & (MA_VERTEXCOL|MA_VERTEXCOLP))== MA_VERTEXCOL) { + if ((ma->mode & (MA_VERTEXCOL|MA_VERTEXCOLP)) == MA_VERTEXCOL) { GPU_link(mat, "shade_add", shi->emit, shi->vcol, &emit); GPU_link(mat, "shade_mul", emit, shi->rgb, &shr->diff); } @@ -1477,9 +1576,9 @@ void GPU_shaderesult_set(GPUShadeInput *shi, GPUShadeResult *shr) if (world) { /* exposure correction */ - if (world->exp!=0.0f || world->range!=1.0f) { - linfac= 1.0f + powf((2.0f*world->exp + 0.5f), -10); - logfac= logf((linfac-1.0f)/linfac)/world->range; + if (world->exp != 0.0f || world->range != 1.0f) { + linfac = 1.0f + powf((2.0f * world->exp + 0.5f), -10); + logfac = logf((linfac - 1.0f) / linfac) / world->range; GPU_link(mat, "set_value", GPU_uniform(&linfac), &ulinfac); GPU_link(mat, "set_value", GPU_uniform(&logfac), &ulogfac); @@ -1491,13 +1590,19 @@ void GPU_shaderesult_set(GPUShadeInput *shi, GPUShadeResult *shr) } /* ambient color */ - if (world->ambr!=0.0f || world->ambg!=0.0f || world->ambb!=0.0f) { - if (GPU_link_changed(shi->amb) || ma->amb != 0.0f) - GPU_link(mat, "shade_maddf", shr->combined, GPU_uniform(&ma->amb), - GPU_uniform(&world->ambr), &shr->combined); + if (GPU_link_changed(shi->amb) || ma->amb != 0.0f) { + GPU_link(mat, "shade_maddf", shr->combined, GPU_uniform(&ma->amb), + GPU_dynamic_uniform(GPUWorld.ambcol, GPU_DYNAMIC_AMBIENT_COLOR, NULL), + &shr->combined); } } + if (ma->mode & MA_TRANSP && (ma->mode & (MA_ZTRANSP|MA_RAYTRANSP))) { + if (GPU_link_changed(shi->spectra) || ma->spectra != 0.0f) + GPU_link(mat, "alpha_spec_correction", shr->spec, shi->spectra, + shi->alpha, &shr->alpha); + } + if (ma->mode & MA_RAMP_COL) ramp_diffuse_result(shi, &shr->combined); if (ma->mode & MA_RAMP_SPEC) ramp_spec_result(shi, &shr->spec); @@ -1510,21 +1615,22 @@ void GPU_shaderesult_set(GPUShadeInput *shi, GPUShadeResult *shr) if (ma->shade_flag & MA_OBCOLOR) GPU_link(mat, "shade_obcolor", shr->combined, GPU_builtin(GPU_OBCOLOR), &shr->combined); - if (world && (world->mode & WO_MIST) && !(ma->mode & MA_NOMIST)) { - misttype = world->mistype; - + if (!(ma->mode & MA_NOMIST)) { GPU_link(mat, "shade_mist_factor", GPU_builtin(GPU_VIEW_POSITION), - GPU_uniform(&world->miststa), GPU_uniform(&world->mistdist), - GPU_uniform(&misttype), GPU_uniform(&world->misi), &mistfac); + GPU_dynamic_uniform(&GPUWorld.mistenabled, GPU_DYNAMIC_MIST_ENABLE, NULL), + GPU_dynamic_uniform(&GPUWorld.miststart, GPU_DYNAMIC_MIST_START, NULL), + GPU_dynamic_uniform(&GPUWorld.mistdistance, GPU_DYNAMIC_MIST_DISTANCE, NULL), + GPU_dynamic_uniform(&GPUWorld.mistype, GPU_DYNAMIC_MIST_TYPE, NULL), + GPU_dynamic_uniform(&GPUWorld.mistintensity, GPU_DYNAMIC_MIST_INTENSITY, NULL), &mistfac); GPU_link(mat, "mix_blend", mistfac, shr->combined, - GPU_uniform(&world->horr), &shr->combined); + GPU_dynamic_uniform(GPUWorld.mistcol, GPU_DYNAMIC_MIST_COLOR, NULL), &shr->combined); } if (!mat->alpha) { if (world && (GPU_link_changed(shr->alpha) || ma->alpha != 1.0f)) - GPU_link(mat, "shade_world_mix", GPU_uniform(&world->horr), - shr->combined, &shr->combined); + GPU_link(mat, "shade_world_mix", GPU_dynamic_uniform(GPUWorld.horicol, GPU_DYNAMIC_HORIZON_COLOR, NULL), + shr->combined, &shr->combined); GPU_link(mat, "shade_alpha_opaque", shr->combined, &shr->combined); } @@ -1570,20 +1676,27 @@ static GPUNodeLink *gpu_material_preview_matcap(GPUMaterial *mat, Material *ma) } /* new solid draw mode with glsl matcaps */ -GPUMaterial *GPU_material_matcap(Scene *scene, Material *ma) +GPUMaterial *GPU_material_matcap(Scene *scene, Material *ma, bool use_opensubdiv) { GPUMaterial *mat; GPUNodeLink *outlink; LinkData *link; - for (link=ma->gpumaterial.first; link; link=link->next) - if (((GPUMaterial*)link->data)->scene == scene) - return link->data; + for (link = ma->gpumaterial.first; link; link = link->next) { + GPUMaterial *current_material = (GPUMaterial*)link->data; + if (current_material->scene == scene && + current_material->is_opensubdiv == use_opensubdiv) + { + return current_material; + } + } /* allocate material */ mat = GPU_material_construct_begin(ma); mat->scene = scene; - + mat->type = GPU_MATERIAL_TYPE_MESH; + mat->is_opensubdiv = use_opensubdiv; + if (ma->preview && ma->preview->rect[0]) { outlink = gpu_material_preview_matcap(mat, ma); } @@ -1593,7 +1706,7 @@ GPUMaterial *GPU_material_matcap(Scene *scene, Material *ma) GPU_material_output_link(mat, outlink); - GPU_material_construct_end(mat); + GPU_material_construct_end(mat, "matcap_pass"); /* note that even if building the shader fails in some way, we still keep * it to avoid trying to compile again and again, and simple do not use @@ -1606,19 +1719,65 @@ GPUMaterial *GPU_material_matcap(Scene *scene, Material *ma) return mat; } -GPUMaterial *GPU_material_from_blender(Scene *scene, Material *ma) +GPUMaterial *GPU_material_world(struct Scene *scene, struct World *wo) { - GPUMaterial *mat; - GPUNodeLink *outlink; LinkData *link; + GPUMaterial *mat; - for (link=ma->gpumaterial.first; link; link=link->next) + for (link = wo->gpumaterial.first; link; link = link->next) if (((GPUMaterial*)link->data)->scene == scene) return link->data; /* allocate material */ + mat = GPU_material_construct_begin(NULL); + mat->scene = scene; + mat->type = GPU_MATERIAL_TYPE_WORLD; + + /* create nodes */ + if (BKE_scene_use_new_shading_nodes(scene) && wo->nodetree && wo->use_nodes) + ntreeGPUMaterialNodes(wo->nodetree, mat, NODE_NEW_SHADING); + else { + /* old fixed function world */ + } + + if (GPU_material_do_color_management(mat)) + if (mat->outlink) + GPU_link(mat, "linearrgb_to_srgb", mat->outlink, &mat->outlink); + + GPU_material_construct_end(mat, wo->id.name); + + /* note that even if building the shader fails in some way, we still keep + * it to avoid trying to compile again and again, and simple do not use + * the actual shader on drawing */ + + link = MEM_callocN(sizeof(LinkData), "GPUMaterialLink"); + link->data = mat; + BLI_addtail(&wo->gpumaterial, link); + + return mat; +} + + +GPUMaterial *GPU_material_from_blender(Scene *scene, Material *ma, bool use_opensubdiv) +{ + GPUMaterial *mat; + GPUNodeLink *outlink; + LinkData *link; + + for (link = ma->gpumaterial.first; link; link = link->next) { + GPUMaterial *current_material = (GPUMaterial*)link->data; + if (current_material->scene == scene && + current_material->is_opensubdiv == use_opensubdiv) + { + return current_material; + } + } + + /* allocate material */ mat = GPU_material_construct_begin(ma); mat->scene = scene; + mat->type = GPU_MATERIAL_TYPE_MESH; + mat->is_opensubdiv = use_opensubdiv; /* render pipeline option */ if (ma->mode & MA_TRANSP) @@ -1648,7 +1807,7 @@ GPUMaterial *GPU_material_from_blender(Scene *scene, Material *ma) if (mat->outlink) GPU_link(mat, "linearrgb_to_srgb", mat->outlink, &mat->outlink); - GPU_material_construct_end(mat); + GPU_material_construct_end(mat, ma->id.name); /* note that even if building the shader fails in some way, we still keep * it to avoid trying to compile again and again, and simple do not use @@ -1665,14 +1824,18 @@ void GPU_materials_free(void) { Object *ob; Material *ma; + World *wo; extern Material defmaterial; - for (ma=G.main->mat.first; ma; ma=ma->id.next) - GPU_material_free(ma); + for (ma = G.main->mat.first; ma; ma = ma->id.next) + GPU_material_free(&ma->gpumaterial); - GPU_material_free(&defmaterial); + for (wo = G.main->world.first; wo; wo = wo->id.next) + GPU_material_free(&wo->gpumaterial); + + GPU_material_free(&defmaterial.gpumaterial); - for (ob=G.main->object.first; ob; ob=ob->id.next) + for (ob = G.main->object.first; ob; ob = ob->id.next) GPU_lamp_free(ob); } @@ -1687,10 +1850,10 @@ static void gpu_lamp_calc_winmat(GPULamp *lamp) orthographic_m4(lamp->winmat, -wsize, wsize, -wsize, wsize, lamp->d, lamp->clipend); } else { - angle= saacos(lamp->spotsi); - temp= 0.5f*lamp->size*cosf(angle)/sinf(angle); - pixsize= (lamp->d)/temp; - wsize= pixsize*0.5f*lamp->size; + angle = saacos(lamp->spotsi); + temp = 0.5f * lamp->size * cosf(angle) / sinf(angle); + pixsize = lamp->d / temp; + wsize = pixsize * 0.5f * lamp->size; perspective_m4(lamp->winmat, -wsize, wsize, -wsize, wsize, lamp->d, lamp->clipend); } } @@ -1714,11 +1877,11 @@ 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) { lamp->energy = energy; - if (lamp->mode & LA_NEG) lamp->energy= -lamp->energy; + if (lamp->mode & LA_NEG) lamp->energy = -lamp->energy; - lamp->col[0]= r* lamp->energy; - lamp->col[1]= g* lamp->energy; - lamp->col[2]= b* 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) @@ -1748,11 +1911,11 @@ static void gpu_lamp_from_blender(Scene *scene, Object *ob, Object *par, Lamp *l lamp->type = la->type; lamp->energy = la->energy; - if (lamp->mode & LA_NEG) lamp->energy= -lamp->energy; + if (lamp->mode & LA_NEG) lamp->energy = -lamp->energy; - lamp->col[0]= la->r*lamp->energy; - lamp->col[1]= la->g*lamp->energy; - lamp->col[2]= la->b*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); @@ -1761,20 +1924,20 @@ static void gpu_lamp_from_blender(Scene *scene, Object *ob, Object *par, Lamp *l 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->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->curfalloff= la->curfalloff; + lamp->dist = la->dist; + lamp->falloff_type = la->falloff_type; + lamp->att1 = la->att1; + lamp->att2 = la->att2; + lamp->curfalloff = la->curfalloff; /* initshadowbuf */ - lamp->bias = 0.02f*la->bias; + lamp->bias = 0.02f * la->bias; lamp->size = la->bufsize; - lamp->d= la->clipsta; - lamp->clipend= la->clipend; + lamp->d = la->clipsta; + lamp->clipend = la->clipend; /* arbitrary correction for the fact we do no soft transition */ lamp->bias *= 0.25f; @@ -1787,23 +1950,23 @@ static void gpu_lamp_shadow_free(GPULamp *lamp) { if (lamp->tex) { GPU_texture_free(lamp->tex); - lamp->tex= NULL; + lamp->tex = NULL; } if (lamp->depthtex) { GPU_texture_free(lamp->depthtex); - lamp->depthtex= NULL; + lamp->depthtex = NULL; } if (lamp->fb) { GPU_framebuffer_free(lamp->fb); - lamp->fb= NULL; + lamp->fb = NULL; } if (lamp->blurtex) { GPU_texture_free(lamp->blurtex); - lamp->blurtex= NULL; + lamp->blurtex = NULL; } if (lamp->blurfb) { GPU_framebuffer_free(lamp->blurfb); - lamp->blurfb= NULL; + lamp->blurfb = NULL; } } @@ -1813,7 +1976,7 @@ GPULamp *GPU_lamp_from_blender(Scene *scene, Object *ob, Object *par) GPULamp *lamp; LinkData *link; - for (link=ob->gpulamp.first; link; link=link->next) { + for (link = ob->gpulamp.first; link; link = link->next) { lamp = (GPULamp*)link->data; if (lamp->par == par && lamp->scene == scene) @@ -1829,7 +1992,7 @@ GPULamp *GPU_lamp_from_blender(Scene *scene, Object *ob, Object *par) 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))) { + 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) { @@ -1845,7 +2008,7 @@ GPULamp *GPU_lamp_from_blender(Scene *scene, Object *ob, Object *par) return lamp; } - if (!GPU_framebuffer_texture_attach(lamp->fb, lamp->depthtex, NULL)) { + if (!GPU_framebuffer_texture_attach(lamp->fb, lamp->depthtex, 0, NULL)) { gpu_lamp_shadow_free(lamp); return lamp; } @@ -1857,11 +2020,16 @@ GPULamp *GPU_lamp_from_blender(Scene *scene, Object *ob, Object *par) return lamp; } - if (!GPU_framebuffer_texture_attach(lamp->fb, lamp->tex, NULL)) { + 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) { @@ -1869,16 +2037,26 @@ GPULamp *GPU_lamp_from_blender(Scene *scene, Object *ob, Object *par) return lamp; } - lamp->blurtex = GPU_texture_create_vsm_shadow_map(lamp->size*0.5, NULL); + 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, NULL)) { + 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); @@ -1887,10 +2065,15 @@ GPULamp *GPU_lamp_from_blender(Scene *scene, Object *ob, Object *par) return lamp; } - if (!GPU_framebuffer_texture_attach(lamp->fb, lamp->tex, NULL)) { + 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(); @@ -1915,7 +2098,7 @@ void GPU_lamp_free(Object *ob) LinkData *nlink; Material *ma; - for (link=ob->gpulamp.first; link; link=link->next) { + for (link = ob->gpulamp.first; link; link = link->next) { lamp = link->data; while (lamp->materials.first) { @@ -1924,7 +2107,7 @@ void GPU_lamp_free(Object *ob) BLI_freelinkN(&lamp->materials, nlink); if (ma->gpumaterial.first) - GPU_material_free(ma); + GPU_material_free(&ma->gpumaterial); } gpu_lamp_shadow_free(lamp); @@ -1973,8 +2156,7 @@ void GPU_lamp_shadow_buffer_bind(GPULamp *lamp, float viewmat[4][4], int *winsiz /* opengl */ glDisable(GL_SCISSOR_TEST); - GPU_framebuffer_texture_bind(lamp->fb, lamp->tex, - GPU_texture_opengl_width(lamp->tex), GPU_texture_opengl_height(lamp->tex)); + 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)); @@ -2009,12 +2191,14 @@ int GPU_lamp_shadow_layer(GPULamp *lamp) return -1; } -GPUNodeLink *GPU_lamp_get_data(GPUMaterial *mat, GPULamp *lamp, GPUNodeLink **col, GPUNodeLink **lv, GPUNodeLink **dist, GPUNodeLink **shadow) +GPUNodeLink *GPU_lamp_get_data(GPUMaterial *mat, GPULamp *lamp, GPUNodeLink **col, GPUNodeLink **lv, GPUNodeLink **dist, GPUNodeLink **shadow, GPUNodeLink **energy) { GPUNodeLink *visifac; *col = GPU_dynamic_uniform(lamp->dyncol, GPU_DYNAMIC_LAMP_DYNCOL, lamp->ob); + *energy = GPU_dynamic_uniform(&lamp->dynenergy, GPU_DYNAMIC_LAMP_DYNENERGY, lamp->ob); visifac = lamp_get_visibility(mat, lamp, lv, dist); + shade_light_textures(mat, lamp, col); if (GPU_lamp_has_shadow_buffer(lamp)) { @@ -2026,18 +2210,18 @@ GPUNodeLink *GPU_lamp_get_data(GPUMaterial *mat, GPULamp *lamp, GPUNodeLink **co if (lamp->la->shadowmap_type == LA_SHADMAP_VARIANCE) { GPU_link(mat, "shadows_only_vsm", - GPU_builtin(GPU_VIEW_POSITION), - GPU_dynamic_texture(lamp->tex, GPU_DYNAMIC_SAMPLER_2DSHADOW, lamp->ob), - GPU_dynamic_uniform((float*)lamp->dynpersmat, GPU_DYNAMIC_LAMP_DYNPERSMAT, lamp->ob), - GPU_uniform(&lamp->bias), GPU_uniform(&lamp->la->bleedbias), - GPU_uniform(lamp->shadow_color), inp, shadow); + GPU_builtin(GPU_VIEW_POSITION), + GPU_dynamic_texture(lamp->tex, GPU_DYNAMIC_SAMPLER_2DSHADOW, lamp->ob), + GPU_dynamic_uniform((float*)lamp->dynpersmat, GPU_DYNAMIC_LAMP_DYNPERSMAT, lamp->ob), + GPU_uniform(&lamp->bias), GPU_uniform(&lamp->la->bleedbias), + GPU_uniform(lamp->shadow_color), inp, shadow); } else { GPU_link(mat, "shadows_only", - GPU_builtin(GPU_VIEW_POSITION), - GPU_dynamic_texture(lamp->tex, GPU_DYNAMIC_SAMPLER_2DSHADOW, lamp->ob), - GPU_dynamic_uniform((float*)lamp->dynpersmat, GPU_DYNAMIC_LAMP_DYNPERSMAT, lamp->ob), - GPU_uniform(&lamp->bias), GPU_uniform(lamp->shadow_color), inp, shadow); + GPU_builtin(GPU_VIEW_POSITION), + GPU_dynamic_texture(lamp->tex, GPU_DYNAMIC_SAMPLER_2DSHADOW, lamp->ob), + GPU_dynamic_uniform((float*)lamp->dynpersmat, GPU_DYNAMIC_LAMP_DYNPERSMAT, lamp->ob), + GPU_uniform(&lamp->bias), GPU_uniform(lamp->shadow_color), inp, shadow); } } else { @@ -2081,7 +2265,8 @@ GPUShaderExport *GPU_shader_export(struct Scene *scene, struct Material *ma) if (!GPU_glsl_support()) return NULL; - mat = GPU_material_from_blender(scene, ma); + /* TODO(sergey): How to detemine whether we need OSD or not here? */ + mat = GPU_material_from_blender(scene, ma, false); pass = (mat)? mat->pass: NULL; if (pass && pass->fragmentcode && pass->vertexcode) { @@ -2120,33 +2305,49 @@ GPUShaderExport *GPU_shader_export(struct Scene *scene, struct Material *ma) glBindTexture(GL_TEXTURE_2D, lastbindcode); } break; + + case GPU_NONE: + case GPU_FLOAT: + case GPU_VEC2: + case GPU_VEC3: + case GPU_VEC4: + case GPU_MAT3: + case GPU_MAT4: + case GPU_ATTRIB: + break; } } else { uniform->type = input->dynamictype; BLI_strncpy(uniform->varname, input->shadername, sizeof(uniform->varname)); switch (input->type) { - case 1: + case GPU_FLOAT: uniform->datatype = GPU_DATA_1F; break; - case 2: + case GPU_VEC2: uniform->datatype = GPU_DATA_2F; break; - case 3: + case GPU_VEC3: uniform->datatype = GPU_DATA_3F; break; - case 4: + case GPU_VEC4: uniform->datatype = GPU_DATA_4F; break; - case 9: + case GPU_MAT3: uniform->datatype = GPU_DATA_9F; break; - case 16: + case GPU_MAT4: uniform->datatype = GPU_DATA_16F; break; + + case GPU_NONE: + case GPU_TEX2D: + case GPU_SHADOW2D: + case GPU_ATTRIB: + break; } - if (uniform->type >= GPU_DYNAMIC_LAMP_FIRST && uniform->type <= GPU_DYNAMIC_LAMP_LAST) + if (GPU_DYNAMIC_GROUP_FROM_TYPE(uniform->type) == GPU_DYNAMIC_GROUP_LAMP) uniform->lamp = input->dynamicdata; } @@ -2157,7 +2358,7 @@ GPUShaderExport *GPU_shader_export(struct Scene *scene, struct Material *ma) } /* process builtin uniform */ - for (i=0; builtins[i].gputype; i++) { + for (i = 0; builtins[i].gputype; i++) { if (mat->builtins & builtins[i].gputype) { uniform = MEM_callocN(sizeof(GPUInputUniform), "GPUInputUniform"); uniform->type = builtins[i].dynamictype; @@ -2171,14 +2372,14 @@ GPUShaderExport *GPU_shader_export(struct Scene *scene, struct Material *ma) /* TBD: remove the function that are not used in the main function */ liblen = (pass->libcode) ? strlen(pass->libcode) : 0; fraglen = strlen(pass->fragmentcode); - shader->fragment = (char *)MEM_mallocN(liblen+fraglen+1, "GPUFragShader"); + shader->fragment = (char *)MEM_mallocN(liblen + fraglen + 1, "GPUFragShader"); if (pass->libcode) memcpy(shader->fragment, pass->libcode, liblen); memcpy(&shader->fragment[liblen], pass->fragmentcode, fraglen); - shader->fragment[liblen+fraglen] = 0; + shader->fragment[liblen + fraglen] = 0; // export the attribute - for (i=0; i<mat->attribs.totlayer; i++) { + for (i = 0; i < mat->attribs.totlayer; i++) { attribute = MEM_callocN(sizeof(GPUInputAttribute), "GPUInputAttribute"); attribute->type = mat->attribs.layer[i].type; attribute->number = mat->attribs.layer[i].glindex; @@ -2207,7 +2408,7 @@ GPUShaderExport *GPU_shader_export(struct Scene *scene, struct Material *ma) MEM_freeN(attribute); } - // export the vertex shader + /* export the vertex shader */ shader->vertex = BLI_strdup(pass->vertexcode); } @@ -2221,7 +2422,7 @@ void GPU_free_shader_export(GPUShaderExport *shader) if (shader == NULL) return; - for (uniform = shader->uniforms.first; uniform; uniform=uniform->next) + for (uniform = shader->uniforms.first; uniform; uniform = uniform->next) if (uniform->texpixels) MEM_freeN(uniform->texpixels); @@ -2236,3 +2437,54 @@ void GPU_free_shader_export(GPUShaderExport *shader) MEM_freeN(shader); } +#ifdef WITH_OPENSUBDIV +void GPU_material_update_fvar_offset(GPUMaterial *gpu_material, + DerivedMesh *dm) +{ + GPUPass *pass = gpu_material->pass; + GPUShader *shader = (pass != NULL ? pass->shader : NULL); + ListBase *inputs = (pass != NULL ? &pass->inputs : NULL); + GPUInput *input; + + if (shader == NULL) { + return; + } + + GPU_shader_bind(shader); + + for (input = inputs->first; + input != NULL; + input = input->next) + { + if (input->source == GPU_SOURCE_ATTRIB && + input->attribtype == CD_MTFACE) + { + char name[64]; + /* TODO(sergey): This will work for until names are + * consistent, we'll need to solve this somehow in the future. + */ + int layer_index; + int location; + + if (input->attribname[0] != '\0') { + layer_index = CustomData_get_named_layer(&dm->loopData, + CD_MLOOPUV, + input->attribname); + } + else { + layer_index = CustomData_get_active_layer(&dm->loopData, + CD_MLOOPUV); + } + + BLI_snprintf(name, sizeof(name), + "fvar%d_offset", + input->attribid); + location = GPU_shader_get_uniform(shader, name); + /* Multiply by 2 because we're offseting U and V variables. */ + GPU_shader_uniform_int(shader, location, layer_index * 2); + } + } + + GPU_shader_unbind(); +} +#endif diff --git a/source/blender/gpu/intern/gpu_private.h b/source/blender/gpu/intern/gpu_private.h new file mode 100644 index 00000000000..72627e3563e --- /dev/null +++ b/source/blender/gpu/intern/gpu_private.h @@ -0,0 +1,36 @@ +/* + * ***** 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_private.h + * \ingroup gpu + */ + +#ifndef __GPU_PRIVATE_H__ +#define __GPU_PRIVATE_H__ + +/* call this before running any of the functions below */ +void gpu_extensions_init(void); +void gpu_extensions_exit(void); + +/* gpu_debug.c */ +void gpu_debug_init(void); +void gpu_debug_exit(void); + +#endif /* __GPU_PRIVATE_H__ */ diff --git a/source/blender/gpu/intern/gpu_select.c b/source/blender/gpu/intern/gpu_select.c index 1d448231dda..4978229a350 100644 --- a/source/blender/gpu/intern/gpu_select.c +++ b/source/blender/gpu/intern/gpu_select.c @@ -31,14 +31,13 @@ */ #include "GPU_select.h" #include "GPU_extensions.h" - -#include "BLI_utildefines.h" - +#include "GPU_glew.h" + #include "MEM_guardedalloc.h" #include "DNA_userdef_types.h" -#include <GL/glew.h> +#include "BLI_utildefines.h" /* Ad hoc number of queries to allocate to skip doing many glGenQueries */ #define ALLOC_QUERIES 200 @@ -60,6 +59,7 @@ typedef struct GPUQueryState { bool use_gpu_select; /* cache on initialization */ unsigned int *buffer; + /* buffer size (stores number of integers, for actual size multiply by sizeof integer)*/ unsigned int bufsize; /* mode of operation */ char mode; @@ -83,7 +83,7 @@ void GPU_select_begin(unsigned int *buffer, unsigned int bufsize, rctf *input, c g_query_state.oldhits = oldhits; if (!g_query_state.use_gpu_select) { - glSelectBuffer( bufsize, (GLuint *)buffer); + glSelectBuffer(bufsize, (GLuint *)buffer); glRenderMode(GL_SELECT); glInitNames(); glPushName(-1); @@ -93,8 +93,8 @@ void GPU_select_begin(unsigned int *buffer, unsigned int bufsize, rctf *input, c g_query_state.num_of_queries = ALLOC_QUERIES; - g_query_state.queries = MEM_mallocN(g_query_state.num_of_queries * sizeof(*g_query_state.queries) , "gpu selection queries"); - g_query_state.id = MEM_mallocN(g_query_state.num_of_queries * sizeof(*g_query_state.id) , "gpu selection ids"); + g_query_state.queries = MEM_mallocN(g_query_state.num_of_queries * sizeof(*g_query_state.queries), "gpu selection queries"); + g_query_state.id = MEM_mallocN(g_query_state.num_of_queries * sizeof(*g_query_state.id), "gpu selection ids"); glGenQueriesARB(g_query_state.num_of_queries, g_query_state.queries); glPushAttrib(GL_DEPTH_BUFFER_BIT | GL_VIEWPORT_BIT); @@ -136,7 +136,7 @@ void GPU_select_begin(unsigned int *buffer, unsigned int bufsize, rctf *input, c bool GPU_select_load_id(unsigned int id) { /* if no selection mode active, ignore */ - if(!g_query_state.select_is_active) + if (!g_query_state.select_is_active) return true; if (!g_query_state.use_gpu_select) { @@ -159,7 +159,7 @@ bool GPU_select_load_id(unsigned int id) g_query_state.active_query++; g_query_state.query_issued = true; - if (g_query_state.mode == GPU_SELECT_NEAREST_SECOND_PASS) { + if (g_query_state.mode == GPU_SELECT_NEAREST_SECOND_PASS && g_query_state.index < g_query_state.oldhits) { if (g_query_state.buffer[g_query_state.index * 4 + 3] == id) { g_query_state.index++; return true; @@ -192,7 +192,9 @@ unsigned int GPU_select_end(void) glGetQueryObjectuivARB(g_query_state.queries[i], GL_QUERY_RESULT_ARB, &result); if (result > 0) { if (g_query_state.mode != GPU_SELECT_NEAREST_SECOND_PASS) { - if(hits < g_query_state.bufsize) { + int maxhits = g_query_state.bufsize / 4; + + if (hits < maxhits) { g_query_state.buffer[hits * 4] = 1; g_query_state.buffer[hits * 4 + 1] = 0xFFFF; g_query_state.buffer[hits * 4 + 2] = 0xFFFF; diff --git a/source/blender/gpu/intern/gpu_simple_shader.c b/source/blender/gpu/intern/gpu_simple_shader.c index 0cb712d220f..89d3c0f59df 100644 --- a/source/blender/gpu/intern/gpu_simple_shader.c +++ b/source/blender/gpu/intern/gpu_simple_shader.c @@ -42,14 +42,11 @@ * - Optimize for case where no texture matrix is used. */ -#include "GL/glew.h" +#include "GPU_glew.h" #include "BLI_math.h" #include "BLI_utildefines.h" -#include "DNA_mesh_types.h" -#include "DNA_object_types.h" - #include "GPU_extensions.h" #include "GPU_simple_shader.h" @@ -154,7 +151,9 @@ static GPUShader *gpu_simple_shader(int options) shader = GPU_shader_create( datatoc_gpu_shader_simple_vert_glsl, datatoc_gpu_shader_simple_frag_glsl, - NULL, defines); + NULL, + NULL, + defines, 0, 0, 0); if (shader) { /* set texture map to first texture unit */ diff --git a/source/blender/gpu/shaders/gpu_program_smoke_color_frag.glsl b/source/blender/gpu/shaders/gpu_program_smoke_color_frag.glsl new file mode 100644 index 00000000000..a94c823f408 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_program_smoke_color_frag.glsl @@ -0,0 +1,32 @@ +!!ARBfp1.0 +PARAM dx = program.local[0]; +PARAM darkness = program.local[1]; +PARAM render = program.local[2]; +PARAM f = {1.442695041, 1.442695041, 1.442695041, 1.442695041}; +TEMP temp, shadow, flame, spec, value; +TEX temp, fragment.texcoord[0], texture[0], 3D; +TEX shadow, fragment.texcoord[0], texture[1], 3D; +TEX flame, fragment.texcoord[0], texture[2], 3D; +TEX spec, flame.r, texture[3], 1D; +# unpremultiply volume texture +RCP value.r, temp.a; +MUL temp.r, temp.r, value.r; +MUL temp.g, temp.g, value.r; +MUL temp.b, temp.b, value.r; +# calculate shading factor from density +MUL value.r, temp.a, darkness.a; +MUL value.r, value.r, dx.r; +MUL value.r, value.r, f.r; +EX2 value.r, -value.r; +# alpha +SUB temp.a, 1.0, value.r; +# shade colors +MUL temp.r, temp.r, shadow.r; +MUL temp.g, temp.g, shadow.r; +MUL temp.b, temp.b, shadow.r; +MUL temp.r, temp.r, value.r; +MUL temp.g, temp.g, value.r; +MUL temp.b, temp.b, value.r; +# for now this just replace smoke shading if rendering fire +CMP result.color, render.r, temp, spec; +END diff --git a/source/blender/gpu/shaders/gpu_program_smoke_frag.glsl b/source/blender/gpu/shaders/gpu_program_smoke_frag.glsl new file mode 100644 index 00000000000..04b171d24bd --- /dev/null +++ b/source/blender/gpu/shaders/gpu_program_smoke_frag.glsl @@ -0,0 +1,27 @@ +!!ARBfp1.0 +PARAM dx = program.local[0]; +PARAM darkness = program.local[1]; +PARAM render = program.local[2]; +PARAM f = {1.442695041, 1.442695041, 1.442695041, 0.01}; +TEMP temp, shadow, flame, spec, value; +TEX temp, fragment.texcoord[0], texture[0], 3D; +TEX shadow, fragment.texcoord[0], texture[1], 3D; +TEX flame, fragment.texcoord[0], texture[2], 3D; +TEX spec, flame.r, texture[3], 1D; +# calculate shading factor from density +MUL value.r, temp.a, darkness.a; +MUL value.r, value.r, dx.r; +MUL value.r, value.r, f.r; +EX2 temp, -value.r; +# alpha +SUB temp.a, 1.0, temp.r; +# shade colors +MUL temp.r, temp.r, shadow.r; +MUL temp.g, temp.g, shadow.r; +MUL temp.b, temp.b, shadow.r; +MUL temp.r, temp.r, darkness.r; +MUL temp.g, temp.g, darkness.g; +MUL temp.b, temp.b, darkness.b; +# for now this just replace smoke shading if rendering fire +CMP result.color, render.r, temp, spec; +END diff --git a/source/blender/gpu/shaders/gpu_shader_fx_depth_resolve.glsl b/source/blender/gpu/shaders/gpu_shader_fx_depth_resolve.glsl new file mode 100644 index 00000000000..e04cd7d3306 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_fx_depth_resolve.glsl @@ -0,0 +1,14 @@ +uniform sampler2D depthbuffer; +varying vec4 uvcoordsvar; + +void main(void) +{ + float depth = texture2D(depthbuffer, uvcoordsvar.xy).r; + + /* XRay background, discard */ + if (depth >= 1.0) { + discard; + } + + gl_FragDepth = depth; +} diff --git a/source/blender/gpu/shaders/gpu_shader_fx_dof_frag.glsl b/source/blender/gpu/shaders/gpu_shader_fx_dof_frag.glsl new file mode 100644 index 00000000000..e9dab04de5d --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_fx_dof_frag.glsl @@ -0,0 +1,208 @@ +/* amount of offset to move one pixel left-right. + * In second pass some dimensions are zero to control verical/horizontal convolution */ +uniform vec2 invrendertargetdim; +// color buffer +uniform sampler2D colorbuffer; +//blurred color buffer for DOF effect +uniform sampler2D blurredcolorbuffer; +// slightly blurred buffer +uniform sampler2D mblurredcolorbuffer; +// depth buffer +uniform sampler2D depthbuffer; + +// this includes focal distance in x and aperture size in y +uniform vec4 dof_params; + +// viewvectors for reconstruction of world space +uniform vec4 viewvecs[3]; + +// coordinates on framebuffer in normalized (0.0-1.0) uv space +varying vec4 uvcoordsvar; + +/* color texture coordinates, offset by a small amount */ +varying vec2 color_uv1; +varying vec2 color_uv2; + +varying vec2 depth_uv1; +varying vec2 depth_uv2; +varying vec2 depth_uv3; +varying vec2 depth_uv4; + + +float calculate_far_coc(in float zdepth) +{ + float coc = dof_params.x * max(1.0 - dof_params.y / zdepth, 0.0); + + /* multiply by 1.0 / sensor size to get the normalized size */ + return coc * dof_params.z; +} + +/* near coc only! when distance is nearer than focus plane first term is bigger than one */ +vec4 calculate_near_coc(in vec4 zdepth) +{ + vec4 coc = dof_params.x * max(vec4(dof_params.y) / zdepth - vec4(1.0), vec4(0.0)); + + /* multiply by 1.0 / sensor size to get the normalized size */ + return coc * dof_params.z; +} + +/* first pass blurs the color buffer heavily and gets the near coc only. + * There are many texture accesses here but they are done on a + * lower resolution image so overall bandwidth is not a concern */ +void first_pass() +{ + vec4 depth; + vec4 zdepth; + vec4 coc; + float final_coc; + + /* amount to add to uvs so that they move one row further */ + vec2 offset_row[3]; + offset_row[0] = vec2(0.0, invrendertargetdim.y); + offset_row[1] = 2.0 * offset_row[0]; + 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]); + 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; + + 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; + + 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; + + 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; + + 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); +} + +/* second pass, gaussian blur the downsampled image */ +void second_pass() +{ + vec4 depth = vec4(texture2D(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; +} + + +/* 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); + float coc = 2.0 * max(color_blurred.a, color.a); - color.a; + gl_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); + + gl_FragColor = color / 4.0; +} + +vec4 small_sample_blur(in sampler2D colorbuffer, in vec2 uv, in vec4 color) +{ + float weight = 1.0/ 17.0; + 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); + + return result; +} + + +/* fourth pass, just visualize the third pass contents */ +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 smallblurred = small_sample_blur(colorbuffer, uvcoordsvar.xy, color_orig); + float depth = texture2D(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); + + /* calculate final coc here */ + float coc = max(max(coc_far, mediumblurred.a), 0.0); + + float width = 2.5; + float radius = 0.2; + + factors.x = 1.0 - clamp(width * coc, 0.0, 1.0); + factors.y = 1.0 - clamp(abs(width * (coc - 2.0 * radius)), 0.0, 1.0); + factors.z = 1.0 - clamp(abs(width * (coc - 3.0 * radius)), 0.0, 1.0); + factors.w = 1.0 - clamp(abs(width * (coc - 4.0 * radius)), 0.0, 1.0); + /* blend! */ + vec4 color = factors.x * color_orig + factors.y * smallblurred + factors.z * mediumblurred + factors.w * highblurred; + + 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); +} + + +void main() +{ +#ifdef FIRST_PASS + first_pass(); +#elif defined(SECOND_PASS) + second_pass(); +#elif defined(THIRD_PASS) + third_pass(); +#elif defined(FOURTH_PASS) + fourth_pass(); +#elif defined(FIFTH_PASS) + fifth_pass(); +#endif +} 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 new file mode 100644 index 00000000000..e315d2fb97a --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_fx_dof_hq_frag.glsl @@ -0,0 +1,166 @@ +/* amount of offset to move one pixel left-right. + * In second pass some dimensions are zero to control verical/horizontal convolution */ +uniform vec2 invrendertargetdim; + +uniform ivec2 rendertargetdim; + +/* color buffer */ +uniform sampler2D colorbuffer; +uniform sampler2D farbuffer; +uniform sampler2D nearbuffer; + +/* depth buffer */ +uniform sampler2D depthbuffer; + +uniform sampler2D cocbuffer; + +/* this includes focal distance in x and aperture size in y */ +uniform vec4 dof_params; + +/* viewvectors for reconstruction of world space */ +uniform vec4 viewvecs[3]; + +/* initial uv coordinate */ +varying vec2 uvcoord; + +/* coordinate used for calculating radius et al set in geometry shader */ +varying vec2 particlecoord; +varying vec4 color; + +/* downsampling coordinates */ +varying vec2 downsample1; +varying vec2 downsample2; +varying vec2 downsample3; +varying vec2 downsample4; + +#define M_PI 3.1415926535897932384626433832795 + +/* calculate 4 samples at once */ +vec4 calculate_coc(in vec4 zdepth) +{ + vec4 coc = dof_params.x * (vec4(dof_params.y) / zdepth - vec4(1.0)); + + /* multiply by 1.0 / sensor size to get the normalized size */ + return coc * dof_params.z; +} + +#define THRESHOLD 0.0 + +/* downsample the color buffer to half resolution */ +void downsample_pass() +{ + vec4 depth; + vec4 zdepth; + vec4 coc; + 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); + + depth.r = texture2D(depthbuffer, downsample1).r; + depth.g = texture2D(depthbuffer, downsample2).r; + depth.b = texture2D(depthbuffer, downsample3).r; + depth.a = texture2D(depthbuffer, downsample4).r; + + zdepth = get_view_space_z_from_depth(vec4(viewvecs[0].z), vec4(viewvecs[1].z), depth); + coc = calculate_coc(zdepth); + vec4 coc_far = -coc; + + /* now we need to write the near-far fields premultiplied by the coc */ + vec4 near_weights = vec4((coc.x >= THRESHOLD) ? 1.0 : 0.0, (coc.y >= THRESHOLD) ? 1.0 : 0.0, + (coc.z >= THRESHOLD) ? 1.0 : 0.0, (coc.w >= THRESHOLD) ? 1.0 : 0.0); + vec4 far_weights = vec4((coc_far.x >= THRESHOLD) ? 1.0 : 0.0, (coc_far.y >= THRESHOLD) ? 1.0 : 0.0, + (coc_far.z >= THRESHOLD) ? 1.0 : 0.0, (coc_far.w >= THRESHOLD) ? 1.0 : 0.0); + + near_coc = max(max(max(coc.x, coc.y), max(coc.z, coc.w)), 0.0); + far_coc = max(max(max(coc_far.x, coc_far.y), max(coc_far.z, coc_far.w)), 0.0); + + float norm_near = dot(near_weights, vec4(1.0)); + 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 + + color4 * near_weights.w; + gl_FragData[1] = 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; + if (norm_far > 0.0) + gl_FragData[1] /= norm_far; + gl_FragData[2] = vec4(near_coc, far_coc, 0.0, 1.0); +} + +/* accumulate color in the near/far blur buffers */ +void accumulate_pass(void) { + float theta = atan(particlecoord.y, particlecoord.x); + float r; + + 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)))); + + if (dot(particlecoord, particlecoord) > r * r) + discard; + + gl_FragData[0] = color; +} +#define MERGE_THRESHOLD 4.0 + +/* combine the passes, */ +void final_pass(void) { + vec4 finalcolor; + float totalweight; + float depth = texture2D(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); + float farweight = farcolor.a; + if (farweight > 0.0) + farcolor /= farweight; + vec4 nearcolor = texture2D(nearbuffer, uvcoord); + + vec4 srccolor = texture2D(colorbuffer, uvcoord); + + vec4 coc = texture2D(cocbuffer, uvcoord); + + float mixfac = smoothstep(1.0, MERGE_THRESHOLD, coc_far); + finalcolor = mix(srccolor, farcolor, mixfac); + + farweight = mix(1.0, farweight, mixfac); + + float nearweight = nearcolor.a; + if (nearweight > 0.0) { + nearcolor /= nearweight; + } + + if (coc_near > 1.0) { + nearweight = 1.0; + finalcolor = nearcolor; + } + else { + totalweight = nearweight + farweight; + finalcolor = mix(finalcolor, nearcolor, nearweight / totalweight); + } + + gl_FragData[0] = finalcolor; +} + +void main() +{ +#ifdef FIRST_PASS + downsample_pass(); +#elif defined(SECOND_PASS) + accumulate_pass(); +#elif defined(THIRD_PASS) + final_pass(); +#endif +} 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 new file mode 100644 index 00000000000..7918122a681 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_fx_dof_hq_geo.glsl @@ -0,0 +1,50 @@ +uniform ivec2 rendertargetdim; +uniform sampler2D colorbuffer; + +uniform vec2 layerselection; + +uniform sampler2D cocbuffer; + +/* initial uv coordinate */ +varying in vec2 uvcoord[1]; +varying out vec2 particlecoord; +varying out vec4 color; + + +#define M_PI 3.1415926535897932384626433832795 + +void main(void) +{ + vec4 coc = texture2DLod(cocbuffer, uvcoord[0], 0.0); + + float offset_val = dot(coc.rg, layerselection); + if (offset_val < 1.0) + return; + + vec4 colortex = texture2DLod(colorbuffer, uvcoord[0], 0.0); + + /* find the area the pixel will cover and divide the color by it */ + float alpha = 1.0 / (offset_val * offset_val * M_PI); + colortex *= alpha; + colortex.a = alpha; + + vec2 offset_far = vec2(offset_val * 0.5) / vec2(rendertargetdim.x, rendertargetdim.y); + + gl_Position = gl_PositionIn[0] + vec4(-offset_far.x, -offset_far.y, 0.0, 0.0); + color = colortex; + particlecoord = vec2(-1.0, -1.0); + EmitVertex(); + gl_Position = gl_PositionIn[0] + vec4(-offset_far.x, offset_far.y, 0.0, 0.0); + particlecoord = vec2(-1.0, 1.0); + color = colortex; + EmitVertex(); + gl_Position = gl_PositionIn[0] + vec4(offset_far.x, -offset_far.y, 0.0, 0.0); + particlecoord = vec2(1.0, -1.0); + color = colortex; + EmitVertex(); + gl_Position = gl_PositionIn[0] + 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 new file mode 100644 index 00000000000..09a0c75facc --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_fx_dof_hq_vert.glsl @@ -0,0 +1,58 @@ +uniform vec2 invrendertargetdim; +uniform ivec2 rendertargetdim; +/* initial uv coordinate */ +varying vec2 uvcoord; + +/* coordinate used for calculating radius et al set in geometry shader */ +varying vec2 particlecoord; + +/* downsampling coordinates */ +varying vec2 downsample1; +varying vec2 downsample2; +varying vec2 downsample3; +varying vec2 downsample4; + +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; + + gl_Position = gl_Vertex; +} + +/* geometry shading pass, calculate a texture coordinate based on the indexed id */ +void vert_dof_coc_scatter_pass() +{ + vec2 pixel = vec2(rendertargetdim.x, rendertargetdim.y); + /* some math to get the target pixel */ + int row = gl_InstanceID / rendertargetdim.x; + int column = gl_InstanceID % rendertargetdim.x; + uvcoord = (vec2(column, row) + vec2(0.5)) / pixel; + + vec2 pos = uvcoord * 2.0 - vec2(1.0); + gl_Position = vec4(pos.x, pos.y, 0.0, 1.0); + +// uvcoord = vec2(0.5, 0.5); +// gl_Position = vec4(0.0, 0.0, 0.0, 1.0); +} + +void vert_dof_final() +{ + uvcoord = gl_MultiTexCoord0.xy; + gl_Position = gl_Vertex; +} + +void main() +{ +#if defined(FIRST_PASS) + vert_dof_downsample(); +#elif defined(SECOND_PASS) + vert_dof_coc_scatter_pass(); +#else + vert_dof_final(); +#endif +}
\ No newline at end of file diff --git a/source/blender/gpu/shaders/gpu_shader_fx_dof_vert.glsl b/source/blender/gpu/shaders/gpu_shader_fx_dof_vert.glsl new file mode 100644 index 00000000000..a2ef990c4e8 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_fx_dof_vert.glsl @@ -0,0 +1,68 @@ +uniform vec2 invrendertargetdim; + +//texture coordinates for framebuffer read +varying vec4 uvcoordsvar; + +/* color texture coordinates, offset by a small amount */ +varying vec2 color_uv1; +varying vec2 color_uv2; + +varying vec2 depth_uv1; +varying vec2 depth_uv2; +varying vec2 depth_uv3; +varying vec2 depth_uv4; + +//very simple shader for gull screen FX, just pass values on + +void vert_generic() +{ + uvcoordsvar = gl_MultiTexCoord0; + gl_Position = gl_Vertex; +} + +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; + + 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; + + gl_Position = gl_Vertex; +} + +void vert_dof_fourth_pass() +{ + vec4 halfpixel = vec4(-0.5, 0.5, -0.5, 0.5); + uvcoordsvar = gl_MultiTexCoord0.xxyy + halfpixel * vec4(invrendertargetdim.x, + invrendertargetdim.x, invrendertargetdim.y, invrendertargetdim.y); + + gl_Position = gl_Vertex; +} + +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; +} + +void main() +{ +#ifdef FIRST_PASS + vert_dof_first_pass(); +#elif defined(FOURTH_PASS) + vert_dof_fourth_pass(); +#elif defined(FIFTH_PASS) + vert_dof_fifth_pass(); +#else + vert_generic(); +#endif +} + diff --git a/source/blender/gpu/shaders/gpu_shader_fx_lib.glsl b/source/blender/gpu/shaders/gpu_shader_fx_lib.glsl new file mode 100644 index 00000000000..1dc49b52be1 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_fx_lib.glsl @@ -0,0 +1,39 @@ +/* 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]); + + return zview * (viewvec_origin + vec3(uvcoords, 0.0) * viewvec_diff); +} + +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])); +} + +#else +/* orthographic camera code */ + +vec3 get_view_space_from_depth(in vec2 uvcoords, in vec3 viewvec_origin, in vec3 viewvec_diff, in float depth) +{ + vec3 offset = vec3(uvcoords, depth); + + return vec3(viewvec_origin + offset * viewvec_diff); +} + +vec4 get_view_space_z_from_depth(in vec4 near, in vec4 range, in vec4 depth) +{ + return -(near + depth * range); +} + +#endif diff --git a/source/blender/gpu/shaders/gpu_shader_fx_ssao_frag.glsl b/source/blender/gpu/shaders/gpu_shader_fx_ssao_frag.glsl new file mode 100644 index 00000000000..494a74dcdf8 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_fx_ssao_frag.glsl @@ -0,0 +1,94 @@ +// color buffer +uniform sampler2D colorbuffer; + +// jitter texture for ssao +uniform sampler2D jitter_tex; + +// concentric sample texture for ssao +uniform sampler1D ssao_concentric_tex; + +// depth buffer +uniform sampler2D depthbuffer; +// coordinates on framebuffer in normalized (0.0-1.0) uv space +varying vec4 uvcoordsvar; + +/* ssao_params.x : pixel scale for the ssao radious */ +/* ssao_params.y : factor for the ssao darkening */ +uniform vec4 ssao_params; +uniform vec3 ssao_sample_params; +uniform vec4 ssao_color; + +/* store the view space vectors for the corners of the view frustum here. + * It helps to quickly reconstruct view space vectors by using uv coordinates, + * see http://www.derschmale.com/2014/01/26/reconstructing-positions-from-the-depth-buffer */ +uniform vec4 viewvecs[3]; + +vec3 calculate_view_space_normal(in vec3 viewposition) +{ + vec3 normal = cross(normalize(dFdx(viewposition)), + ssao_params.w * normalize(dFdy(viewposition))); + normalize(normal); + return normal; +} + +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 rotY = vec2(-rotX.y, rotX.x); + + /* occlusion is zero in full depth */ + if (depth == 1.0) + return 0.0; + + vec3 position = get_view_space_from_depth(uvcoordsvar.xy, viewvecs[0].xyz, viewvecs[1].xyz, depth); + vec3 normal = calculate_view_space_normal(position); + + // 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; + /* convert from -1.0...1.0 range to 0.0..1.0 for easy use with texture coordinates */ + offset *= 0.5; + + float factor = 0.0; + int x; + 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; + + /* rotate with random direction to get jittered result */ + vec2 dir_jittered = vec2(dot(dir_sample, rotX), dot(dir_sample, rotY)); + + vec2 uvcoords = uvcoordsvar.xy + dir_jittered * offset; + + 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; + 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; + float len = length(dir); + float f = dot(dir, normal); + + /* use minor bias here to avoid self shadowing */ + if (f > 0.05 * len + 0.0001) + factor += f * 1.0/(len * (1.0 + len * len * ssao_params.z)); + } + } + + factor /= ssao_sample_params.x; + + return clamp(factor * ssao_params.y, 0.0, 1.0); +} + +void main() +{ + float depth = texture2D(depthbuffer, uvcoordsvar.xy).r; + vec4 scene_col = texture2D(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); +} diff --git a/source/blender/gpu/shaders/gpu_shader_fx_vert.glsl b/source/blender/gpu/shaders/gpu_shader_fx_vert.glsl new file mode 100644 index 00000000000..5194e414520 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_fx_vert.glsl @@ -0,0 +1,9 @@ +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 new file mode 100644 index 00000000000..a0ae96a1f72 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_geometry.glsl @@ -0,0 +1,100 @@ +uniform int PrimitiveIdBase; +uniform int osd_active_uv_offset; + +varying vec3 varnormal; +varying vec3 varposition; + +in block { + VertexData v; +} inpt[4]; + +uniform bool osd_flat_shading; +uniform int osd_fvar_count; + +#define INTERP_FACE_VARYING_2(result, fvarOffset, tessCoord) \ + { \ + vec2 v[4]; \ + int primOffset = (gl_PrimitiveID + PrimitiveIdBase) * 4; \ + for (int i = 0; i < 4; ++i) { \ + int index = (primOffset + i) * osd_fvar_count + fvarOffset; \ + v[i] = vec2(texelFetch(FVarDataBuffer, index).s, \ + texelFetch(FVarDataBuffer, index + 1).s); \ + } \ + result = mix(mix(v[0], v[1], tessCoord.s), \ + mix(v[3], v[2], tessCoord.s), \ + tessCoord.t); \ + } + +uniform samplerBuffer FVarDataBuffer; + +out block { + VertexData v; +} outpt; + +void set_mtface_vertex_attrs(vec2 st); + +void emit_flat(int index, vec3 normal) +{ + outpt.v.position = inpt[index].v.position; + outpt.v.normal = normal; + + /* Compatibility */ + varnormal = outpt.v.normal; + varposition = outpt.v.position.xyz; + + /* TODO(sergey): Only uniform subdivisions atm. */ + vec2 quadst[4] = vec2[](vec2(0,0), vec2(1,0), vec2(1,1), vec2(0,1)); + vec2 st = quadst[index]; + + INTERP_FACE_VARYING_2(outpt.v.uv, osd_active_uv_offset, st); + + set_mtface_vertex_attrs(st); + + gl_Position = gl_ProjectionMatrix * inpt[index].v.position; + EmitVertex(); +} + +void emit_smooth(int index) +{ + outpt.v.position = inpt[index].v.position; + outpt.v.normal = inpt[index].v.normal; + + /* Compatibility */ + varnormal = outpt.v.normal; + varposition = outpt.v.position.xyz; + + /* TODO(sergey): Only uniform subdivisions atm. */ + vec2 quadst[4] = vec2[](vec2(0,0), vec2(1,0), vec2(1,1), vec2(0,1)); + vec2 st = quadst[index]; + + INTERP_FACE_VARYING_2(outpt.v.uv, osd_active_uv_offset, st); + + set_mtface_vertex_attrs(st); + + gl_Position = gl_ProjectionMatrix * inpt[index].v.position; + EmitVertex(); +} + +void main() +{ + gl_PrimitiveID = gl_PrimitiveIDIn; + + if (osd_flat_shading) { + vec3 A = (inpt[0].v.position - inpt[1].v.position).xyz; + vec3 B = (inpt[3].v.position - inpt[1].v.position).xyz; + vec3 flat_normal = normalize(cross(B, A)); + emit_flat(0, flat_normal); + emit_flat(1, flat_normal); + emit_flat(3, flat_normal); + emit_flat(2, flat_normal); + } + else { + emit_smooth(0); + emit_smooth(1); + emit_smooth(3); + emit_smooth(2); + } + EndPrimitive(); +} + +void set_mtface_vertex_attrs(vec2 st) { diff --git a/source/blender/gpu/shaders/gpu_shader_material.glsl b/source/blender/gpu/shaders/gpu_shader_material.glsl index 3ba36c11311..311fcb8ead2 100644 --- a/source/blender/gpu/shaders/gpu_shader_material.glsl +++ b/source/blender/gpu/shaders/gpu_shader_material.glsl @@ -149,10 +149,23 @@ void geom(vec3 co, vec3 nor, mat4 viewinvmat, vec3 attorco, vec2 attuv, vec4 att uv_attribute(attuv, uv); normal = -normalize(nor); /* blender render normal is negated */ vcol_attribute(attvcol, vcol); + srgb_to_linearrgb(vcol, vcol); vcol_alpha = attvcol.a; frontback = (gl_FrontFacing)? 1.0: 0.0; } +void particle_info(vec4 sprops, vec3 loc, vec3 vel, vec3 avel, out float index, out float age, out float life_time, out vec3 location, out float size, out vec3 velocity, out vec3 angular_velocity) +{ + index = sprops.x; + age = sprops.y; + life_time = sprops.z; + size = sprops.w; + + location = loc; + velocity = vel; + angular_velocity = avel; +} + void mapping(vec3 vec, mat4 mat, vec3 minvec, vec3 maxvec, float domin, float domax, out vec3 outvec) { outvec = (mat * vec4(vec, 1.0)).xyz; @@ -169,9 +182,9 @@ void camera(vec3 co, out vec3 outview, out float outdepth, out float outdist) outview = normalize(co); } -void lamp(vec4 col, vec3 lv, float dist, vec3 shadow, float visifac, out vec4 outcol, out vec3 outlv, out float outdist, out vec4 outshadow, out float outvisifac) +void lamp(vec4 col, float energy, vec3 lv, float dist, vec3 shadow, float visifac, out vec4 outcol, out vec3 outlv, out float outdist, out vec4 outshadow, out float outvisifac) { - outcol = col; + outcol = col * energy; outlv = lv; outdist = dist; outshadow = vec4(shadow, 1.0); @@ -297,6 +310,10 @@ void math_modulo(float val1, float val2, out float outval) outval = 0.0; else outval = mod(val1, val2); + + /* change sign to match C convention, mod in GLSL will take absolute for negative numbers, + * see https://www.opengl.org/sdk/docs/man/html/mod.xhtml */ + outval = (val1 > 0.0) ? outval : -outval; } void math_abs(float val1, out float outval) @@ -338,6 +355,7 @@ void vec_math_cross(vec3 v1, vec3 v2, out vec3 outvec, out float outval) { outvec = cross(v1, v2); outval = length(outvec); + outvec /= outval; } void vec_math_normalize(vec3 v, out vec3 outvec, out float outval) @@ -357,6 +375,12 @@ void normal(vec3 dir, vec3 nor, out vec3 outnor, out float outdot) outdot = -dot(dir, nor); } +void normal_new_shading(vec3 dir, vec3 nor, out vec3 outnor, out float outdot) +{ + outnor = normalize(nor); + outdot = dot(normalize(dir), nor); +} + 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; @@ -687,22 +711,7 @@ void mix_linear(float fac, vec4 col1, vec4 col2, out vec4 outcol) { fac = clamp(fac, 0.0, 1.0); - outcol = col1; - - if(col2.r > 0.5) - outcol.r= col1.r + fac*(2.0*(col2.r - 0.5)); - else - outcol.r= col1.r + fac*(2.0*(col2.r) - 1.0); - - if(col2.g > 0.5) - outcol.g= col1.g + fac*(2.0*(col2.g - 0.5)); - else - outcol.g= col1.g + fac*(2.0*(col2.g) - 1.0); - - if(col2.b > 0.5) - outcol.b= col1.b + fac*(2.0*(col2.b - 0.5)); - else - outcol.b= col1.b + fac*(2.0*(col2.b) - 1.0); + outcol = col1 + fac*(2.0*(col2 - vec4(0.5))); } void valtorgb(float fac, sampler2D colormap, out vec4 outcol, out float outalpha) @@ -722,6 +731,16 @@ void invert(float fac, vec4 col, out vec4 outcol) outcol.w = col.w; } +void clamp_vec3(vec3 vec, vec3 min, vec3 max, out vec3 out_vec) +{ + out_vec = clamp(vec, min, max); +} + +void clamp_val(float value, float min, float max, out float out_value) +{ + out_value = clamp(value, min, max); +} + void hue_sat(float hue, float sat, float value, float fac, vec4 col, out vec4 outcol) { vec4 hsv; @@ -1507,9 +1526,9 @@ void mtex_nspace_world(mat4 viewmat, vec3 texnormal, out vec3 outnormal) outnormal = normalize((viewmat*vec4(texnormal, 0.0)).xyz); } -void mtex_nspace_object(mat4 viewmat, mat4 obmat, vec3 texnormal, out vec3 outnormal) +void mtex_nspace_object(vec3 texnormal, out vec3 outnormal) { - outnormal = normalize((viewmat*(obmat*vec4(texnormal, 0.0))).xyz); + outnormal = normalize(gl_NormalMatrix * texnormal); } void mtex_blend_normal(float norfac, vec3 normal, vec3 newnormal, out vec3 outnormal) @@ -1925,6 +1944,17 @@ void shade_add_spec(float t, vec3 lampcol, vec3 speccol, out vec3 outcol) outcol = t*lampcol*speccol; } +void alpha_spec_correction(vec3 spec, float spectra, float alpha, out float outalpha) +{ + if (spectra > 0.0) { + float t = clamp(max(max(spec.r, spec.g), spec.b) * spectra, 0.0, 1.0); + outalpha = (1.0 - t) * alpha + t; + } + else { + outalpha = alpha; + } +} + void shade_add(vec4 col1, vec4 col2, out vec4 outcol) { outcol = col1 + col2; @@ -1960,6 +1990,11 @@ void shade_mul_value(float fac, vec4 col, out vec4 outcol) outcol = col*fac; } +void shade_mul_value_v3(float fac, vec3 col, out vec3 outcol) +{ + outcol = col*fac; +} + void shade_obcolor(vec4 col, vec4 obcol, out vec4 outcol) { outcol = vec4(col.rgb*obcol.rgb, col.a); @@ -2077,18 +2112,23 @@ void shade_exposure_correct(vec3 col, float linfac, float logfac, out vec3 outco outcol = linfac*(1.0 - exp(col*logfac)); } -void shade_mist_factor(vec3 co, float miststa, float mistdist, float misttype, float misi, out float outfac) +void shade_mist_factor(vec3 co, float enable, float miststa, float mistdist, float misttype, float misi, out float outfac) { - float fac, zcor; + if(enable == 1.0) { + float fac, zcor; - zcor = (gl_ProjectionMatrix[3][3] == 0.0)? length(co): -co[2]; - - fac = clamp((zcor-miststa)/mistdist, 0.0, 1.0); - if(misttype == 0.0) fac *= fac; - else if(misttype == 1.0); - else fac = sqrt(fac); + zcor = (gl_ProjectionMatrix[3][3] == 0.0)? length(co): -co[2]; + + fac = clamp((zcor - miststa) / mistdist, 0.0, 1.0); + if(misttype == 0.0) fac *= fac; + else if(misttype == 1.0); + else fac = sqrt(fac); - outfac = 1.0 - (1.0-fac)*(1.0-misi); + outfac = 1.0 - (1.0 - fac) * (1.0 - misi); + } + else { + outfac = 0.0; + } } void shade_world_mix(vec3 hor, vec4 col, out vec4 outcol) @@ -2223,6 +2263,16 @@ void node_bsdf_hair(vec4 color, float offset, float roughnessu, float roughnessv result = color; } +void node_bsdf_refraction(vec4 color, float roughness, float ior, vec3 N, out vec4 result) +{ + node_bsdf_diffuse(color, 0.0, N, result); +} + +void node_ambient_occlusion(vec4 color, out vec4 result) +{ + result = color; +} + /* emission */ void node_emission(vec4 color, float strength, vec3 N, out vec4 result) @@ -2230,6 +2280,22 @@ void node_emission(vec4 color, float strength, vec3 N, out vec4 result) result = color*strength; } +/* 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 co = vec4(co_homogenous.xyz / co_homogenous.w, 0.0); + worldvec = (gl_ModelViewMatrixInverse * co).xyz; +} + +void node_background(vec4 color, float strength, vec3 N, out vec4 result) +{ + result = color*strength; +} + /* closures */ void node_mix_shader(float fac, vec4 shader1, vec4 shader2, out vec4 shader) @@ -2259,10 +2325,12 @@ void node_layer_weight(float blend, vec3 N, vec3 I, out float fresnel, out float { /* fresnel */ float eta = max(1.0 - blend, 0.00001); - fresnel = fresnel_dielectric(normalize(I), N, (gl_FrontFacing)? 1.0/eta : eta ); + vec3 I_view = (gl_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 ); /* facing */ - facing = abs(dot(normalize(I), N)); + facing = abs(dot(I_view, N)); if(blend != 0.5) { blend = clamp(blend, 0.0, 0.99999); blend = (blend < 0.5)? 2.0*blend: 0.5/(1.0 - blend); @@ -2302,7 +2370,7 @@ void node_uvmap(vec3 attr_uv, out vec3 outvec) void node_geometry(vec3 I, vec3 N, 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 backfacing, out float pointiness) { position = (toworld*vec4(I, 1.0)).xyz; normal = (toworld*vec4(N, 0.0)).xyz; @@ -2315,20 +2383,21 @@ void node_geometry(vec3 I, vec3 N, mat4 toworld, parametric = vec3(0.0); backfacing = (gl_FrontFacing)? 0.0: 1.0; + pointiness = 0.0; } -void node_tex_coord(vec3 I, vec3 N, mat4 viewinvmat, mat4 obinvmat, +void node_tex_coord(vec3 I, vec3 N, mat4 viewinvmat, mat4 obinvmat, vec4 camerafac, vec3 attr_orco, vec3 attr_uv, out vec3 generated, out vec3 normal, out vec3 uv, out vec3 object, out vec3 camera, out vec3 window, out vec3 reflection) { - generated = mtex_2d_mapping(attr_orco); + generated = attr_orco * 0.5 + vec3(0.5); normal = normalize((obinvmat*(viewinvmat*vec4(N, 0.0))).xyz); uv = attr_uv; object = (obinvmat*(viewinvmat*vec4(I, 1.0))).xyz; - camera = I; + camera = vec3(I.xy, -I.z); vec4 projvec = gl_ProjectionMatrix * vec4(I, 1.0); - window = mtex_2d_mapping(projvec.xyz/projvec.w); + window = vec3(mtex_2d_mapping(projvec.xyz/projvec.w).xy * camerafac.xy + camerafac.zw, 0.0); vec3 shade_I; shade_view(I, shade_I); @@ -2336,6 +2405,32 @@ void node_tex_coord(vec3 I, vec3 N, mat4 viewinvmat, mat4 obinvmat, reflection = (viewinvmat*vec4(view_reflection, 0.0)).xyz; } +void node_tex_coord_background(vec3 I, vec3 N, mat4 viewinvmat, mat4 obinvmat, vec4 camerafac, + vec3 attr_orco, vec3 attr_uv, + 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 co = vec4(co_homogenous.xyz / co_homogenous.w, 0.0); + + co = normalize(co); + vec3 coords = (gl_ModelViewMatrixInverse * co).xyz; + + generated = coords; + normal = -coords; + uv = vec3(attr_uv.xy, 0.0); + object = coords; + + camera = vec3(co.xy, -co.z); + window = (gl_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; +} + /* textures */ void node_tex_gradient(vec3 co, out vec4 color, out float fac) @@ -2362,17 +2457,34 @@ void node_tex_clouds(vec3 co, float size, out vec4 color, out float fac) fac = 1.0; } -void node_tex_environment(vec3 co, sampler2D ima, out vec4 color) +void node_tex_environment_equirectangular(vec3 co, sampler2D ima, out vec4 color) +{ + vec3 nco = normalize(co); + 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)); +} + +void node_tex_environment_mirror_ball(vec3 co, sampler2D ima, out vec4 color) { - float u = (atan(co.y, co.x) + M_PI)/(2.0*M_PI); - float v = atan(co.z, hypot(co.x, co.y))/M_PI + 0.5; + vec3 nco = normalize(co); + + nco.y -= 1.0; + + float div = 2.0*sqrt(max(-0.5*nco.y, 0.0)); + if(div > 0.0) + nco /= div; + + float u = 0.5*(nco.x + 1.0); + float v = 0.5*(nco.z + 1.0); color = texture2D(ima, vec2(u, v)); } void node_tex_environment_empty(vec3 co, out vec4 color) { - color = vec4(0.0); + color = vec4(1.0, 0.0, 1.0, 1.0); } void node_tex_image(vec3 co, sampler2D ima, out vec4 color, out float alpha) @@ -2480,6 +2592,11 @@ void node_output_material(vec4 surface, vec4 volume, float displacement, out vec result = surface; } +void node_output_world(vec4 surface, vec4 volume, out vec4 result) +{ + result = surface; +} + /* ********************** matcap style render ******************** */ void material_preview_matcap(vec4 color, sampler2D ima, vec4 N, vec4 mask, out vec4 result) @@ -2487,6 +2604,7 @@ void material_preview_matcap(vec4 color, sampler2D ima, vec4 N, vec4 mask, out v 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); @@ -2494,6 +2612,10 @@ void material_preview_matcap(vec4 color, sampler2D ima, vec4 N, vec4 mask, out v normal.z = 0.0; } normal = normalize(normal); +#else + normal = inpt.v.normal; + mask = vec4(1.0, 1.0, 1.0, 1.0); +#endif tex.x = 0.5 + 0.49 * normal.x; tex.y = 0.5 + 0.49 * normal.y; 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 978b6db1b9a..5f406c959f1 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 @@ -10,7 +10,7 @@ void main() 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 += texture2D( textureSource, gl_TexCoord[0].st + vec2(3.0 * ScaleU.x, 3.0 * ScaleU.y ) ) * 0.015625; gl_FragColor = color; } diff --git a/source/blender/gpu/shaders/gpu_shader_vertex.glsl b/source/blender/gpu/shaders/gpu_shader_vertex.glsl index b5d8dcc0f35..7e332706695 100644 --- a/source/blender/gpu/shaders/gpu_shader_vertex.glsl +++ b/source/blender/gpu/shaders/gpu_shader_vertex.glsl @@ -1,3 +1,11 @@ +#ifdef USE_OPENSUBDIV +in vec3 normal; +in vec4 position; + +out block { + VertexData v; +} outpt; +#endif varying vec3 varposition; varying vec3 varnormal; @@ -8,10 +16,15 @@ varying float gl_ClipDistance[6]; void main() { - vec4 co = gl_ModelViewMatrix * gl_Vertex; +#ifndef USE_OPENSUBDIV + vec4 position = gl_Vertex; + vec3 normal = gl_Normal; +#endif + + vec4 co = gl_ModelViewMatrix * position; varposition = co.xyz; - varnormal = normalize(gl_NormalMatrix * gl_Normal); + varnormal = normalize(gl_NormalMatrix * normal); gl_Position = gl_ProjectionMatrix * co; #ifdef CLIP_WORKAROUND @@ -24,3 +37,7 @@ void main() gl_ClipVertex = co; #endif +#ifdef USE_OPENSUBDIV + outpt.v.position = co; + outpt.v.normal = varnormal; +#endif diff --git a/source/blender/gpu/shaders/gpu_shader_vertex_world.glsl b/source/blender/gpu/shaders/gpu_shader_vertex_world.glsl new file mode 100644 index 00000000000..9dbcaeb7a32 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_vertex_world.glsl @@ -0,0 +1,13 @@ + +varying vec3 varposition; +varying vec3 varnormal; + +void main() +{ + /* position does not need to be transformed, we already have it */ + gl_Position = gl_Vertex; + + varposition = gl_Vertex.xyz; + + varnormal = normalize(-varposition); + |