diff options
Diffstat (limited to 'source/blender/gpu')
59 files changed, 1938 insertions, 1599 deletions
diff --git a/source/blender/gpu/CMakeLists.txt b/source/blender/gpu/CMakeLists.txt index cf1d449ad3b..1d6a5031d7e 100644 --- a/source/blender/gpu/CMakeLists.txt +++ b/source/blender/gpu/CMakeLists.txt @@ -146,8 +146,6 @@ data_to_c_simple(shaders/gpu_shader_uniform_color_frag.glsl SRC) data_to_c_simple(shaders/gpu_shader_checker_frag.glsl SRC) data_to_c_simple(shaders/gpu_shader_diag_stripes_frag.glsl SRC) data_to_c_simple(shaders/gpu_shader_simple_lighting_frag.glsl SRC) -data_to_c_simple(shaders/gpu_shader_simple_lighting_smooth_color_frag.glsl SRC) -data_to_c_simple(shaders/gpu_shader_simple_lighting_smooth_color_alpha_frag.glsl SRC) data_to_c_simple(shaders/gpu_shader_flat_color_frag.glsl SRC) data_to_c_simple(shaders/gpu_shader_flat_color_alpha_test_0_frag.glsl SRC) data_to_c_simple(shaders/gpu_shader_flat_id_frag.glsl SRC) @@ -165,7 +163,6 @@ data_to_c_simple(shaders/gpu_shader_2D_line_dashed_uniform_color_vert.glsl SRC) data_to_c_simple(shaders/gpu_shader_2D_line_dashed_frag.glsl SRC) data_to_c_simple(shaders/gpu_shader_2D_smooth_color_vert.glsl SRC) data_to_c_simple(shaders/gpu_shader_2D_smooth_color_frag.glsl SRC) -data_to_c_simple(shaders/gpu_shader_2D_smooth_color_dithered_frag.glsl SRC) data_to_c_simple(shaders/gpu_shader_2D_image_vert.glsl SRC) data_to_c_simple(shaders/gpu_shader_2D_image_rect_vert.glsl SRC) data_to_c_simple(shaders/gpu_shader_2D_image_multi_rect_vert.glsl SRC) @@ -179,16 +176,15 @@ data_to_c_simple(shaders/gpu_shader_image_modulate_alpha_frag.glsl SRC) data_to_c_simple(shaders/gpu_shader_image_alpha_color_frag.glsl SRC) data_to_c_simple(shaders/gpu_shader_image_color_frag.glsl SRC) data_to_c_simple(shaders/gpu_shader_image_varying_color_frag.glsl SRC) -data_to_c_simple(shaders/gpu_shader_image_depth_linear_frag.glsl SRC) -data_to_c_simple(shaders/gpu_shader_image_depth_copy_frag.glsl SRC) -data_to_c_simple(shaders/gpu_shader_image_multisample_resolve_frag.glsl SRC) data_to_c_simple(shaders/gpu_shader_3D_image_vert.glsl SRC) data_to_c_simple(shaders/gpu_shader_3D_vert.glsl SRC) data_to_c_simple(shaders/gpu_shader_3D_normal_vert.glsl SRC) data_to_c_simple(shaders/gpu_shader_3D_flat_color_vert.glsl SRC) data_to_c_simple(shaders/gpu_shader_3D_line_dashed_uniform_color_vert.glsl SRC) +data_to_c_simple(shaders/gpu_shader_3D_polyline_frag.glsl SRC) +data_to_c_simple(shaders/gpu_shader_3D_polyline_geom.glsl SRC) +data_to_c_simple(shaders/gpu_shader_3D_polyline_vert.glsl SRC) data_to_c_simple(shaders/gpu_shader_3D_smooth_color_vert.glsl SRC) -data_to_c_simple(shaders/gpu_shader_3D_normal_smooth_color_vert.glsl SRC) data_to_c_simple(shaders/gpu_shader_3D_smooth_color_frag.glsl SRC) data_to_c_simple(shaders/gpu_shader_3D_passthrough_vert.glsl SRC) data_to_c_simple(shaders/gpu_shader_3D_clipped_uniform_color_vert.glsl SRC) @@ -321,6 +317,7 @@ data_to_c_simple(shaders/gpu_shader_gpencil_fill_vert.glsl SRC) data_to_c_simple(shaders/gpu_shader_gpencil_fill_frag.glsl SRC) data_to_c_simple(shaders/gpu_shader_cfg_world_clip_lib.glsl SRC) +data_to_c_simple(shaders/gpu_shader_colorspace_lib.glsl SRC) data_to_c_simple(shaders/gpu_shader_common_obinfos_lib.glsl SRC) diff --git a/source/blender/gpu/GPU_batch_presets.h b/source/blender/gpu/GPU_batch_presets.h index ba8ad3c4990..eb803333d98 100644 --- a/source/blender/gpu/GPU_batch_presets.h +++ b/source/blender/gpu/GPU_batch_presets.h @@ -39,6 +39,10 @@ extern "C" { /* Replacement for gluSphere */ struct GPUBatch *GPU_batch_preset_sphere(int lod) ATTR_WARN_UNUSED_RESULT; struct GPUBatch *GPU_batch_preset_sphere_wire(int lod) ATTR_WARN_UNUSED_RESULT; +struct GPUBatch *GPU_batch_preset_panel_drag_widget(const float pixelsize, + const float col_high[4], + const float col_dark[4], + const float width) ATTR_WARN_UNUSED_RESULT; void gpu_batch_presets_init(void); void gpu_batch_presets_register(struct GPUBatch *preset_batch); diff --git a/source/blender/gpu/GPU_buffers.h b/source/blender/gpu/GPU_buffers.h index 9d91fd79137..ab16bfc43c4 100644 --- a/source/blender/gpu/GPU_buffers.h +++ b/source/blender/gpu/GPU_buffers.h @@ -42,14 +42,14 @@ struct MPoly; struct MVert; struct Mesh; struct PBVH; +struct SubdivCCG; /* Buffers for drawing from PBVH grids. */ typedef struct GPU_PBVH_Buffers GPU_PBVH_Buffers; /* Build must be called once before using the other functions, used every time * mesh topology changes. Threaded. */ -GPU_PBVH_Buffers *GPU_pbvh_mesh_buffers_build(const int (*face_vert_indices)[3], - const struct MPoly *mpoly, +GPU_PBVH_Buffers *GPU_pbvh_mesh_buffers_build(const struct MPoly *mpoly, const struct MLoop *mloop, const struct MLoopTri *looptri, const struct MVert *verts, @@ -77,14 +77,11 @@ enum { void GPU_pbvh_mesh_buffers_update(GPU_PBVH_Buffers *buffers, const struct MVert *mvert, - const int *vert_indices, - int totvert, const float *vmask, const struct MLoopCol *vcol, const int *sculpt_face_sets, const int face_sets_color_seed, const int face_sets_color_default, - const int (*face_vert_indices)[3], const int update_flags); void GPU_pbvh_bmesh_buffers_update(GPU_PBVH_Buffers *buffers, @@ -95,10 +92,14 @@ void GPU_pbvh_bmesh_buffers_update(GPU_PBVH_Buffers *buffers, const int update_flags); void GPU_pbvh_grid_buffers_update(GPU_PBVH_Buffers *buffers, + struct SubdivCCG *subdiv_ccg, struct CCGElem **grids, const struct DMFlagMat *grid_flag_mats, int *grid_indices, int totgrid, + const int *sculpt_face_sets, + const int face_sets_color_seed, + const int face_sets_color_default, const struct CCGKey *key, const int update_flags); diff --git a/source/blender/gpu/GPU_context.h b/source/blender/gpu/GPU_context.h index dd7611fe2fc..9876aa6998c 100644 --- a/source/blender/gpu/GPU_context.h +++ b/source/blender/gpu/GPU_context.h @@ -26,14 +26,14 @@ #ifndef __GPU_CONTEXT_H__ #define __GPU_CONTEXT_H__ -#ifdef __cplusplus -extern "C" { -#endif - #include "GPU_batch.h" #include "GPU_common.h" #include "GPU_shader_interface.h" +#ifdef __cplusplus +extern "C" { +#endif + typedef struct GPUContext GPUContext; GPUContext *GPU_context_create(GLuint default_framebuffer); diff --git a/source/blender/gpu/GPU_draw.h b/source/blender/gpu/GPU_draw.h index f521fa3c702..ab507d852e8 100644 --- a/source/blender/gpu/GPU_draw.h +++ b/source/blender/gpu/GPU_draw.h @@ -24,6 +24,9 @@ #ifndef __GPU_DRAW_H__ #define __GPU_DRAW_H__ +#include "BLI_utildefines.h" +#include "DNA_object_enums.h" + #ifdef __cplusplus extern "C" { #endif @@ -34,18 +37,8 @@ struct Image; struct ImageUser; struct Main; -#include "BLI_utildefines.h" -#include "DNA_object_enums.h" - /* OpenGL drawing functions related to shading. */ -/* Initialize - * - sets the default Blender opengl state, if in doubt, check - * the contents of this function - * - this is called when starting Blender, for opengl rendering. */ - -void GPU_state_init(void); - /* Mipmap settings * - these will free textures on changes */ @@ -57,7 +50,7 @@ void GPU_paint_set_mipmap(struct Main *bmain, bool mipmap); /* Anisotropic filtering settings * - these will free textures on changes */ -void GPU_set_anisotropic(struct Main *bmain, float value); +void GPU_set_anisotropic(float value); float GPU_get_anisotropic(void); /* Image updates and free diff --git a/source/blender/gpu/GPU_immediate_util.h b/source/blender/gpu/GPU_immediate_util.h index 1cf6475408f..47b44b59461 100644 --- a/source/blender/gpu/GPU_immediate_util.h +++ b/source/blender/gpu/GPU_immediate_util.h @@ -70,6 +70,13 @@ void imm_draw_disk_partial_fill_2d(uint pos, void imm_draw_box_wire_2d(uint pos, float x1, float y1, float x2, float y2); void imm_draw_box_wire_3d(uint pos, float x1, float y1, float x2, float y2); +void imm_draw_box_checker_2d_ex(float x1, + float y1, + float x2, + float y2, + const float color_primary[4], + const float color_secondary[4], + int checker_size); void imm_draw_box_checker_2d(float x1, float y1, float x2, float y2); void imm_draw_cube_fill_3d(uint pos, const float co[3], const float aspect[3]); diff --git a/source/blender/gpu/GPU_init_exit.h b/source/blender/gpu/GPU_init_exit.h index 0046eaa942b..3e30a1ddcf5 100644 --- a/source/blender/gpu/GPU_init_exit.h +++ b/source/blender/gpu/GPU_init_exit.h @@ -24,12 +24,12 @@ #ifndef __GPU_INIT_EXIT_H__ #define __GPU_INIT_EXIT_H__ +#include "BLI_utildefines.h" + #ifdef __cplusplus extern "C" { #endif -#include "BLI_utildefines.h" - void GPU_init(void); void GPU_exit(void); bool GPU_is_initialized(void); diff --git a/source/blender/gpu/GPU_material.h b/source/blender/gpu/GPU_material.h index 337c0b03308..eeb2d2caef2 100644 --- a/source/blender/gpu/GPU_material.h +++ b/source/blender/gpu/GPU_material.h @@ -29,6 +29,8 @@ #include "BLI_sys_types.h" /* for bool */ +#include "GPU_texture.h" /* for eGPUSamplerState */ + #ifdef __cplusplus extern "C" { #endif @@ -138,8 +140,14 @@ typedef enum eGPUMaterialStatus { GPUNodeLink *GPU_constant(const float *num); GPUNodeLink *GPU_uniform(const float *num); GPUNodeLink *GPU_attribute(GPUMaterial *mat, CustomDataType type, const char *name); -GPUNodeLink *GPU_image(GPUMaterial *mat, struct Image *ima, struct ImageUser *iuser); -GPUNodeLink *GPU_image_tiled(GPUMaterial *mat, struct Image *ima, struct ImageUser *iuser); +GPUNodeLink *GPU_image(GPUMaterial *mat, + struct Image *ima, + struct ImageUser *iuser, + eGPUSamplerState sampler_state); +GPUNodeLink *GPU_image_tiled(GPUMaterial *mat, + struct Image *ima, + struct ImageUser *iuser, + eGPUSamplerState sampler_state); GPUNodeLink *GPU_image_tiled_mapping(GPUMaterial *mat, struct Image *ima, struct ImageUser *iuser); GPUNodeLink *GPU_color_band(GPUMaterial *mat, int size, float *pixels, float *layer); GPUNodeLink *GPU_volume_grid(GPUMaterial *mat, const char *name); @@ -190,6 +198,7 @@ void GPU_materials_free(struct Main *bmain); struct Scene *GPU_material_scene(GPUMaterial *material); struct GPUPass *GPU_material_get_pass(GPUMaterial *material); +struct GPUShader *GPU_material_get_shader(GPUMaterial *material); struct Material *GPU_material_get_material(GPUMaterial *material); eGPUMaterialStatus GPU_material_status(GPUMaterial *mat); @@ -228,6 +237,7 @@ typedef struct GPUMaterialTexture { char sampler_name[32]; /* Name of sampler in GLSL. */ char tiled_mapping_name[32]; /* Name of tile mapping sampler in GLSL. */ int users; + int sampler_state; /* eGPUSamplerState */ } GPUMaterialTexture; typedef struct GPUMaterialVolumeGrid { diff --git a/source/blender/gpu/GPU_shader.h b/source/blender/gpu/GPU_shader.h index 334e295c636..0ad472113c9 100644 --- a/source/blender/gpu/GPU_shader.h +++ b/source/blender/gpu/GPU_shader.h @@ -29,6 +29,7 @@ extern "C" { #endif typedef struct GPUShader GPUShader; +struct GPUShaderInterface; struct GPUTexture; struct GPUUniformBuffer; @@ -49,6 +50,11 @@ GPUShader *GPU_shader_create(const char *vertexcode, const char *libcode, const char *defines, const char *shader_name); +GPUShader *GPU_shader_create_from_python(const char *vertexcode, + const char *fragcode, + const char *geocode, + const char *libcode, + const char *defines); GPUShader *GPU_shader_create_ex(const char *vertexcode, const char *fragcode, const char *geocode, @@ -83,17 +89,21 @@ int GPU_shader_get_program(GPUShader *shader); void *GPU_shader_get_interface(GPUShader *shader); +void GPU_shader_set_srgb_uniform(const struct GPUShaderInterface *interface); + int GPU_shader_get_uniform(GPUShader *shader, const char *name); -int GPU_shader_get_uniform_ensure(GPUShader *shader, const char *name); int GPU_shader_get_builtin_uniform(GPUShader *shader, int builtin); +int GPU_shader_get_builtin_block(GPUShader *shader, int builtin); int GPU_shader_get_uniform_block(GPUShader *shader, const char *name); + +int GPU_shader_get_uniform_block_binding(GPUShader *shader, const char *name); +int GPU_shader_get_texture_binding(GPUShader *shader, const char *name); + void GPU_shader_uniform_vector( GPUShader *shader, int location, int length, int arraysize, const float *value); void GPU_shader_uniform_vector_int( GPUShader *shader, int location, int length, int arraysize, const int *value); -void GPU_shader_uniform_buffer(GPUShader *shader, int location, struct GPUUniformBuffer *ubo); -void GPU_shader_uniform_texture(GPUShader *shader, int location, struct GPUTexture *tex); void GPU_shader_uniform_float(GPUShader *shader, int location, float value); void GPU_shader_uniform_int(GPUShader *shader, int location, int value); @@ -101,16 +111,14 @@ int GPU_shader_get_attribute(GPUShader *shader, const char *name); char *GPU_shader_get_binary(GPUShader *shader, uint *r_binary_format, int *r_binary_len); +void GPU_shader_set_framebuffer_srgb_target(int use_srgb_to_linear); + /* Builtin/Non-generated shaders */ typedef enum eGPUBuiltinShader { /* specialized drawing */ GPU_SHADER_TEXT, GPU_SHADER_KEYFRAME_DIAMOND, GPU_SHADER_SIMPLE_LIGHTING, - GPU_SHADER_SIMPLE_LIGHTING_FLAT_COLOR, - GPU_SHADER_SIMPLE_LIGHTING_SMOOTH_COLOR, - GPU_SHADER_SIMPLE_LIGHTING_SMOOTH_COLOR_ALPHA, - /* for simple 2D drawing */ /** * Take a single color for all the vertices and a 2D position for each vertex. @@ -133,7 +141,6 @@ typedef enum eGPUBuiltinShader { * \param pos: in vec2 */ GPU_SHADER_2D_SMOOTH_COLOR, - GPU_SHADER_2D_SMOOTH_COLOR_DITHER, GPU_SHADER_2D_IMAGE, GPU_SHADER_2D_IMAGE_COLOR, GPU_SHADER_2D_IMAGE_DESATURATE_COLOR, @@ -141,14 +148,6 @@ typedef enum eGPUBuiltinShader { GPU_SHADER_2D_IMAGE_ALPHA, GPU_SHADER_2D_IMAGE_RECT_COLOR, GPU_SHADER_2D_IMAGE_MULTI_RECT_COLOR, - GPU_SHADER_2D_IMAGE_MULTISAMPLE_2, - GPU_SHADER_2D_IMAGE_MULTISAMPLE_4, - GPU_SHADER_2D_IMAGE_MULTISAMPLE_8, - GPU_SHADER_2D_IMAGE_MULTISAMPLE_16, - GPU_SHADER_2D_IMAGE_MULTISAMPLE_2_DEPTH_TEST, - GPU_SHADER_2D_IMAGE_MULTISAMPLE_4_DEPTH_TEST, - GPU_SHADER_2D_IMAGE_MULTISAMPLE_8_DEPTH_TEST, - GPU_SHADER_2D_IMAGE_MULTISAMPLE_16_DEPTH_TEST, GPU_SHADER_2D_CHECKER, GPU_SHADER_2D_DIAG_STRIPES, /* for simple 3D drawing */ @@ -159,8 +158,7 @@ typedef enum eGPUBuiltinShader { * \param pos: in vec3 */ GPU_SHADER_3D_UNIFORM_COLOR, - /* Sets Z-depth to 1.0 (draw onto background). */ - GPU_SHADER_3D_UNIFORM_COLOR_BACKGROUND, + GPU_SHADER_3D_CLIPPED_UNIFORM_COLOR, /** * Take a 3D position and color for each vertex without color interpolation. * @@ -176,12 +174,37 @@ typedef enum eGPUBuiltinShader { */ GPU_SHADER_3D_SMOOTH_COLOR, /** + * Take a single color for all the vertices and a 3D position for each vertex. + * Used for drawing wide lines. + * + * \param color: uniform vec4 + * \param pos: in vec3 + */ + GPU_SHADER_3D_POLYLINE_UNIFORM_COLOR, + GPU_SHADER_3D_POLYLINE_CLIPPED_UNIFORM_COLOR, + /** + * Take a 3D position and color for each vertex without color interpolation. + * Used for drawing wide lines. + * + * \param color: in vec4 + * \param pos: in vec3 + */ + GPU_SHADER_3D_POLYLINE_FLAT_COLOR, + /** + * Take a 3D position and color for each vertex with perspective correct interpolation. + * Used for drawing wide lines. + * + * \param color: in vec4 + * \param pos: in vec3 + */ + GPU_SHADER_3D_POLYLINE_SMOOTH_COLOR, + /** * Take a 3D position for each vertex and output only depth. + * Used for drawing wide lines. * * \param pos: in vec3 */ GPU_SHADER_3D_DEPTH_ONLY, - GPU_SHADER_3D_CLIPPED_UNIFORM_COLOR, /* basic image drawing */ GPU_SHADER_2D_IMAGE_OVERLAYS_MERGE, GPU_SHADER_2D_IMAGE_OVERLAYS_STEREO_MERGE, @@ -196,18 +219,6 @@ typedef enum eGPUBuiltinShader { * \param pos: in vec3 */ GPU_SHADER_3D_IMAGE_MODULATE_ALPHA, - /** - * Draw linearized depth texture relate to near and far distances. - * Take a 3D position and a 2D texture coordinate for each vertex. - * - * \param znear: uniform float - * \param zfar: uniform float - * \param image: uniform sampler2D - * \param texCoord: in vec2 - * \param pos: in vec3 - */ - GPU_SHADER_3D_IMAGE_DEPTH, - GPU_SHADER_3D_IMAGE_DEPTH_COPY, /* points */ /** * Draw round points with a hardcoded size. diff --git a/source/blender/gpu/GPU_shader_interface.h b/source/blender/gpu/GPU_shader_interface.h index 8b0d25e51a3..28ee162bdbd 100644 --- a/source/blender/gpu/GPU_shader_interface.h +++ b/source/blender/gpu/GPU_shader_interface.h @@ -33,9 +33,7 @@ extern "C" { #endif typedef enum { - GPU_UNIFORM_NONE = 0, /* uninitialized/unknown */ - - GPU_UNIFORM_MODEL, /* mat4 ModelMatrix */ + GPU_UNIFORM_MODEL = 0, /* mat4 ModelMatrix */ GPU_UNIFORM_VIEW, /* mat4 ViewMatrix */ GPU_UNIFORM_MODELVIEW, /* mat4 ModelViewMatrix */ GPU_UNIFORM_PROJECTION, /* mat4 ProjectionMatrix */ @@ -56,48 +54,58 @@ typedef enum { GPU_UNIFORM_BASE_INSTANCE, /* int baseInstance */ GPU_UNIFORM_RESOURCE_CHUNK, /* int resourceChunk */ GPU_UNIFORM_RESOURCE_ID, /* int resourceId */ - - GPU_UNIFORM_CUSTOM, /* custom uniform, not one of the above built-ins */ + GPU_UNIFORM_SRGB_TRANSFORM, /* bool srgbTarget */ GPU_NUM_UNIFORMS, /* Special value, denotes number of builtin uniforms. */ } GPUUniformBuiltin; +typedef enum { + GPU_UNIFORM_BLOCK_VIEW = 0, /* viewBlock */ + GPU_UNIFORM_BLOCK_MODEL, /* modelBlock */ + GPU_UNIFORM_BLOCK_INFO, /* infoBlock */ + + GPU_NUM_UNIFORM_BLOCKS, /* Special value, denotes number of builtin uniforms block. */ +} GPUUniformBlockBuiltin; + typedef struct GPUShaderInput { - struct GPUShaderInput *next; uint32_t name_offset; - uint name_hash; - /** Only for uniform inputs. */ - GPUUniformBuiltin builtin_type; - /** Only for attribute inputs. */ - uint32_t gl_type; - /** Only for attribute inputs. */ - int32_t size; + uint32_t name_hash; int32_t location; + /** Defined at interface creation or in shader. Only for Samplers, UBOs and Vertex Attribs. */ + int32_t binding; } GPUShaderInput; -#define GPU_NUM_SHADERINTERFACE_BUCKETS 257 #define GPU_SHADERINTERFACE_REF_ALLOC_COUNT 16 typedef struct GPUShaderInterface { - int32_t program; - uint32_t name_buffer_offset; - GPUShaderInput *attr_buckets[GPU_NUM_SHADERINTERFACE_BUCKETS]; - GPUShaderInput *uniform_buckets[GPU_NUM_SHADERINTERFACE_BUCKETS]; - GPUShaderInput *ubo_buckets[GPU_NUM_SHADERINTERFACE_BUCKETS]; - GPUShaderInput *builtin_uniforms[GPU_NUM_UNIFORMS]; + /** Buffer containing all inputs names separated by '\0'. */ char *name_buffer; - struct GPUBatch **batches; /* references to batches using this interface */ + /** Reference to GPUBatches using this interface */ + struct GPUBatch **batches; uint batches_len; + /** Input counts. */ + uint attribute_len; + uint ubo_len; + uint uniform_len; + /** Enabled bindpoints that needs to be fed with data. */ + uint16_t enabled_attr_mask; + uint16_t enabled_ubo_mask; + uint64_t enabled_tex_mask; + /** Opengl Location of builtin uniforms. Fast access, no lookup needed. */ + int32_t builtins[GPU_NUM_UNIFORMS]; + int32_t builtin_blocks[GPU_NUM_UNIFORM_BLOCKS]; + /** Flat array. In this order: Attributes, Ubos, Uniforms. */ + GPUShaderInput inputs[0]; } GPUShaderInterface; GPUShaderInterface *GPU_shaderinterface_create(int32_t program_id); void GPU_shaderinterface_discard(GPUShaderInterface *); const GPUShaderInput *GPU_shaderinterface_uniform(const GPUShaderInterface *, const char *name); -const GPUShaderInput *GPU_shaderinterface_uniform_ensure(const GPUShaderInterface *, - const char *name); -const GPUShaderInput *GPU_shaderinterface_uniform_builtin(const GPUShaderInterface *, - GPUUniformBuiltin); +int32_t GPU_shaderinterface_uniform_builtin(const GPUShaderInterface *shaderface, + GPUUniformBuiltin builtin); +int32_t GPU_shaderinterface_block_builtin(const GPUShaderInterface *shaderface, + GPUUniformBlockBuiltin builtin); const GPUShaderInput *GPU_shaderinterface_ubo(const GPUShaderInterface *, const char *name); const GPUShaderInput *GPU_shaderinterface_attr(const GPUShaderInterface *, const char *name); diff --git a/source/blender/gpu/GPU_state.h b/source/blender/gpu/GPU_state.h index 9ce91d31d69..4daf3f8dba5 100644 --- a/source/blender/gpu/GPU_state.h +++ b/source/blender/gpu/GPU_state.h @@ -40,6 +40,12 @@ typedef enum eGPUFilterFunction { GPU_LINEAR, } eGPUFilterFunction; +/* Initialize + * - sets the default Blender opengl state, if in doubt, check + * the contents of this function + * - this is called when starting Blender, for opengl rendering. */ +void GPU_state_init(void); + void GPU_blend(bool enable); void GPU_blend_set_func(eGPUBlendFunction sfactor, eGPUBlendFunction dfactor); void GPU_blend_set_func_separate(eGPUBlendFunction src_rgb, diff --git a/source/blender/gpu/GPU_texture.h b/source/blender/gpu/GPU_texture.h index 892452a2738..a13f61177e6 100644 --- a/source/blender/gpu/GPU_texture.h +++ b/source/blender/gpu/GPU_texture.h @@ -41,6 +41,31 @@ struct PreviewImage; struct GPUFrameBuffer; typedef struct GPUTexture GPUTexture; +/* GPU Samplers state + * - Specify the sampler state to bind a texture with. + * - Internally used by textures. + * - All states are created at startup to avoid runtime costs. + */ + +typedef enum eGPUSamplerState { + GPU_SAMPLER_FILTER = (1 << 0), + GPU_SAMPLER_MIPMAP = (1 << 1), + GPU_SAMPLER_REPEAT_S = (1 << 2), + GPU_SAMPLER_REPEAT_T = (1 << 3), + GPU_SAMPLER_REPEAT_R = (1 << 4), + GPU_SAMPLER_CLAMP_BORDER = (1 << 5), /* Clamp to border color instead of border texel. */ + GPU_SAMPLER_COMPARE = (1 << 6), + GPU_SAMPLER_ANISO = (1 << 7), + /* Don't use that. */ + GPU_SAMPLER_MAX = (1 << 8), +} eGPUSamplerState; + +#define GPU_SAMPLER_DEFAULT GPU_SAMPLER_FILTER +#define GPU_SAMPLER_REPEAT (GPU_SAMPLER_REPEAT_S | GPU_SAMPLER_REPEAT_T | GPU_SAMPLER_REPEAT_R) + +void GPU_samplers_init(void); +void GPU_samplers_free(void); + /* GPU Texture * - always returns unsigned char RGBA textures * - if texture with non square dimensions is created, depending on the @@ -236,14 +261,17 @@ void GPU_texture_free(GPUTexture *tex); void GPU_texture_ref(GPUTexture *tex); void GPU_texture_bind(GPUTexture *tex, int number); +void GPU_texture_bind_ex(GPUTexture *tex, eGPUSamplerState state, int unit, const bool set_number); void GPU_texture_unbind(GPUTexture *tex); -int GPU_texture_bound_number(GPUTexture *tex); +void GPU_texture_unbind_all(void); + +void GPU_texture_copy(GPUTexture *dst, GPUTexture *src); void GPU_texture_generate_mipmap(GPUTexture *tex); void GPU_texture_compare_mode(GPUTexture *tex, bool use_compare); void GPU_texture_filter_mode(GPUTexture *tex, bool use_filter); void GPU_texture_mipmap_mode(GPUTexture *tex, bool use_mipmap, bool use_filter); -void GPU_texture_wrap_mode(GPUTexture *tex, bool use_repeat); +void GPU_texture_wrap_mode(GPUTexture *tex, bool use_repeat, bool use_clamp); void GPU_texture_filters(GPUTexture *tex, eGPUFilterFunction min_filter, eGPUFilterFunction mag_filter); diff --git a/source/blender/gpu/GPU_vertex_format.h b/source/blender/gpu/GPU_vertex_format.h index 7e384d0a692..61b14a4c5c0 100644 --- a/source/blender/gpu/GPU_vertex_format.h +++ b/source/blender/gpu/GPU_vertex_format.h @@ -39,7 +39,7 @@ extern "C" { #define GPU_VERT_ATTR_NAMES_BUF_LEN 256 #define GPU_VERT_FORMAT_MAX_NAMES 63 /* More than enough, actual max is ~30. */ /* Computed as GPU_VERT_ATTR_NAMES_BUF_LEN / 30 (actual max format name). */ -#define GPU_MAX_SAFE_ATTRIB_NAME 12 +#define GPU_MAX_SAFE_ATTR_NAME 12 typedef enum { GPU_COMP_I8, @@ -94,19 +94,18 @@ typedef struct GPUVertFormat { uint packed : 1; /** Current offset in names[]. */ uint name_offset : 8; - /** Store each attrib in one contiguous buffer region. */ + /** Store each attribute in one contiguous buffer region. */ uint deinterleaved : 1; GPUVertAttr attrs[GPU_VERT_ATTR_MAX_LEN]; char names[GPU_VERT_ATTR_NAMES_BUF_LEN]; } GPUVertFormat; -struct GPUShaderInterface; +struct GPUShader; void GPU_vertformat_clear(GPUVertFormat *); void GPU_vertformat_copy(GPUVertFormat *dest, const GPUVertFormat *src); -void GPU_vertformat_from_interface(GPUVertFormat *format, - const struct GPUShaderInterface *shaderface); +void GPU_vertformat_from_shader(GPUVertFormat *format, const struct GPUShader *shader); uint GPU_vertformat_attr_add( GPUVertFormat *, const char *name, GPUVertCompType, uint comp_len, GPUVertFetchMode); @@ -125,7 +124,7 @@ BLI_INLINE const char *GPU_vertformat_attr_name_get(const GPUVertFormat *format, return format->names + attr->names[n_idx]; } -void GPU_vertformat_safe_attrib_name(const char *attrib_name, char *r_safe_name, uint max_len); +void GPU_vertformat_safe_attr_name(const char *attr_name, char *r_safe_name, uint max_len); /* format conversion */ diff --git a/source/blender/gpu/intern/gpu_batch.c b/source/blender/gpu/intern/gpu_batch.c index 6bc3cd27130..5f77f13c135 100644 --- a/source/blender/gpu/intern/gpu_batch.c +++ b/source/blender/gpu/intern/gpu_batch.c @@ -42,6 +42,8 @@ #include <stdlib.h> #include <string.h> +static GLuint g_default_attr_vbo = 0; + static void batch_update_program_bindings(GPUBatch *batch, uint i_first); void GPU_batch_vao_cache_clear(GPUBatch *batch) @@ -373,7 +375,7 @@ void GPU_batch_program_set_no_use(GPUBatch *batch, const GPUShaderInterface *shaderface) { #if TRUST_NO_ONE - assert(glIsProgram(shaderface->program)); + assert(glIsProgram(program)); assert(batch->program_in_use == 0); #endif batch->interface = shaderface; @@ -414,6 +416,7 @@ void gpu_batch_remove_interface_ref(GPUBatch *batch, const GPUShaderInterface *i static void create_bindings(GPUVertBuf *verts, const GPUShaderInterface *interface, + uint16_t *attr_mask, uint v_first, const bool use_instancing) { @@ -446,6 +449,8 @@ static void create_bindings(GPUVertBuf *verts, continue; } + *attr_mask &= ~(1 << input->location); + if (a->comp_len == 16 || a->comp_len == 12 || a->comp_len == 8) { #if TRUST_NO_ONE assert(a->fetch_mode == GPU_FETCH_FLOAT); @@ -487,17 +492,35 @@ static void create_bindings(GPUVertBuf *verts, static void batch_update_program_bindings(GPUBatch *batch, uint i_first) { - /* Reverse order so first vbos have more prevalence (in term of attrib override). */ + uint16_t attr_mask = batch->interface->enabled_attr_mask; + + /* Reverse order so first VBO'S have more prevalence (in term of attribute override). */ for (int v = GPU_BATCH_VBO_MAX_LEN - 1; v > -1; v--) { if (batch->verts[v] != NULL) { - create_bindings(batch->verts[v], batch->interface, 0, false); + create_bindings(batch->verts[v], batch->interface, &attr_mask, 0, false); } } + for (int v = GPU_BATCH_INST_VBO_MAX_LEN - 1; v > -1; v--) { if (batch->inst[v]) { - create_bindings(batch->inst[v], batch->interface, i_first, true); + create_bindings(batch->inst[v], batch->interface, &attr_mask, i_first, true); + } + } + + if (attr_mask != 0 && GLEW_ARB_vertex_attrib_binding) { + for (uint16_t mask = 1, a = 0; a < 16; a++, mask <<= 1) { + if (attr_mask & mask) { + /* This replaces glVertexAttrib4f(a, 0.0f, 0.0f, 0.0f, 1.0f); with a more modern style. + * Fix issues for some drivers (see T75069). */ + glBindVertexBuffer(a, g_default_attr_vbo, (intptr_t)0, (intptr_t)0); + + glEnableVertexAttribArray(a); + glVertexAttribFormat(a, 4, GL_FLOAT, GL_FALSE, 0); + glVertexAttribBinding(a, a); + } } } + if (batch->elem) { GPU_indexbuf_use(batch->elem); } @@ -528,11 +551,11 @@ void GPU_batch_program_use_end(GPUBatch *batch) #if TRUST_NO_ONE # define GET_UNIFORM \ - const GPUShaderInput *uniform = GPU_shaderinterface_uniform_ensure(batch->interface, name); \ + const GPUShaderInput *uniform = GPU_shaderinterface_uniform(batch->interface, name); \ assert(uniform); #else # define GET_UNIFORM \ - const GPUShaderInput *uniform = GPU_shaderinterface_uniform_ensure(batch->interface, name); + const GPUShaderInput *uniform = GPU_shaderinterface_uniform(batch->interface, name); #endif void GPU_batch_uniform_1ui(GPUBatch *batch, const char *name, uint value) @@ -652,6 +675,7 @@ void GPU_batch_draw(GPUBatch *batch) #endif GPU_batch_program_use_begin(batch); GPU_matrix_bind(batch->interface); // external call. + GPU_shader_set_srgb_uniform(batch->interface); GPU_batch_bind(batch); GPU_batch_draw_advanced(batch, 0, 0, 0, 0); @@ -689,8 +713,8 @@ void GPU_batch_draw_advanced(GPUBatch *batch, int v_first, int v_count, int i_fi } /* Verify there is enough data do draw. */ - /* TODO(fclem) Nice to have but this is invalid when using procedural drawcalls. - * The right assert would be to check if there is an enabled attrib from each VBO + /* TODO(fclem) Nice to have but this is invalid when using procedural draw-calls. + * The right assert would be to check if there is an enabled attribute from each VBO * and check their length. */ // BLI_assert(i_first + i_count <= (batch->inst ? batch->inst->vertex_len : INT_MAX)); // BLI_assert(v_first + v_count <= @@ -1002,11 +1026,23 @@ void GPU_batch_program_set_imm_shader(GPUBatch *batch) void gpu_batch_init(void) { + if (g_default_attr_vbo == 0) { + g_default_attr_vbo = GPU_buf_alloc(); + + float default_attrib_data[4] = {0.0f, 0.0f, 0.0f, 1.0f}; + glBindBuffer(GL_ARRAY_BUFFER, g_default_attr_vbo); + glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 4, default_attrib_data, GL_STATIC_DRAW); + glBindBuffer(GL_ARRAY_BUFFER, 0); + } + gpu_batch_presets_init(); } void gpu_batch_exit(void) { + GPU_buf_free(g_default_attr_vbo); + g_default_attr_vbo = 0; + gpu_batch_presets_exit(); } diff --git a/source/blender/gpu/intern/gpu_batch_presets.c b/source/blender/gpu/intern/gpu_batch_presets.c index e00b6f78c2e..d16edab5ac9 100644 --- a/source/blender/gpu/intern/gpu_batch_presets.c +++ b/source/blender/gpu/intern/gpu_batch_presets.c @@ -27,13 +27,20 @@ #include "BLI_utildefines.h" #include "MEM_guardedalloc.h" +#include "DNA_userdef_types.h" + #include "UI_interface.h" +#include "UI_resources.h" #include "GPU_batch.h" #include "GPU_batch_presets.h" /* own include */ #include "GPU_batch_utils.h" #include "gpu_shader_private.h" +/* -------------------------------------------------------------------- */ +/** \name Local Structures + * \{ */ + /* Struct to store 3D Batches and their format */ static struct { struct { @@ -53,8 +60,27 @@ static struct { ThreadMutex mutex; } g_presets_3d = {{0}}; +static struct { + struct { + GPUBatch *panel_drag_widget; + } batch; + + float panel_drag_widget_pixelsize; + float panel_drag_widget_width; + float panel_drag_widget_col_high[4]; + float panel_drag_widget_col_dark[4]; + + GPUVertFormat format; + + struct { + uint pos, col; + } attr_id; +} g_presets_2d = {{0}}; + static ListBase presets_list = {NULL, NULL}; +/** \} */ + /* -------------------------------------------------------------------- */ /** \name 3D Primitives * \{ */ @@ -71,6 +97,18 @@ static GPUVertFormat *preset_3d_format(void) return &g_presets_3d.format; } +static GPUVertFormat *preset_2d_format(void) +{ + if (g_presets_2d.format.attr_len == 0) { + GPUVertFormat *format = &g_presets_2d.format; + g_presets_2d.attr_id.pos = GPU_vertformat_attr_add( + format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); + g_presets_2d.attr_id.col = GPU_vertformat_attr_add( + format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT); + } + return &g_presets_2d.format; +} + static void batch_sphere_lat_lon_vert(GPUVertBufRaw *pos_step, GPUVertBufRaw *nor_step, float lat, @@ -193,6 +231,114 @@ static GPUBatch *batch_sphere_wire(int lat_res, int lon_res) /** \} */ +/* -------------------------------------------------------------------- */ +/** \name Panel Drag Widget + * \{ */ + +static void gpu_batch_preset_rectf_tris_color_ex(GPUVertBufRaw *pos_step, + float x1, + float y1, + float x2, + float y2, + GPUVertBufRaw *col_step, + const float color[4]) +{ + copy_v2_v2(GPU_vertbuf_raw_step(pos_step), (const float[2]){x1, y1}); + copy_v4_v4(GPU_vertbuf_raw_step(col_step), color); + + copy_v2_v2(GPU_vertbuf_raw_step(pos_step), (const float[2]){x2, y1}); + copy_v4_v4(GPU_vertbuf_raw_step(col_step), color); + + copy_v2_v2(GPU_vertbuf_raw_step(pos_step), (const float[2]){x2, y2}); + copy_v4_v4(GPU_vertbuf_raw_step(col_step), color); + + copy_v2_v2(GPU_vertbuf_raw_step(pos_step), (const float[2]){x1, y1}); + copy_v4_v4(GPU_vertbuf_raw_step(col_step), color); + + copy_v2_v2(GPU_vertbuf_raw_step(pos_step), (const float[2]){x2, y2}); + copy_v4_v4(GPU_vertbuf_raw_step(col_step), color); + + copy_v2_v2(GPU_vertbuf_raw_step(pos_step), (const float[2]){x1, y2}); + copy_v4_v4(GPU_vertbuf_raw_step(col_step), color); +} + +static GPUBatch *gpu_batch_preset_panel_drag_widget(float pixelsize, + const float col_high[4], + const float col_dark[4], + const float width) +{ + GPUVertBuf *vbo = GPU_vertbuf_create_with_format(preset_2d_format()); + const uint vbo_len = 4 * 2 * (6 * 2); + GPU_vertbuf_data_alloc(vbo, vbo_len); + + GPUVertBufRaw pos_step, col_step; + GPU_vertbuf_attr_get_raw_data(vbo, g_presets_2d.attr_id.pos, &pos_step); + GPU_vertbuf_attr_get_raw_data(vbo, g_presets_2d.attr_id.col, &col_step); + + const int px = (int)pixelsize; + const int px_zoom = max_ii(round_fl_to_int(width / 22.0f), 1); + + const int box_margin = max_ii(round_fl_to_int((float)(px_zoom * 2.0f)), px); + const int box_size = max_ii(round_fl_to_int((width / 8.0f) - px), px); + + const int y_ofs = max_ii(round_fl_to_int(width / 2.5f), px); + const int x_ofs = y_ofs; + int i_x, i_y; + + for (i_x = 0; i_x < 4; i_x++) { + for (i_y = 0; i_y < 2; i_y++) { + const int x_co = (x_ofs) + (i_x * (box_size + box_margin)); + const int y_co = (y_ofs) + (i_y * (box_size + box_margin)); + + gpu_batch_preset_rectf_tris_color_ex(&pos_step, + x_co - box_size, + y_co - px_zoom, + x_co, + (y_co + box_size) - px_zoom, + &col_step, + col_dark); + gpu_batch_preset_rectf_tris_color_ex( + &pos_step, x_co - box_size, y_co, x_co, y_co + box_size, &col_step, col_high); + } + } + return GPU_batch_create_ex(GPU_PRIM_TRIS, vbo, NULL, GPU_BATCH_OWNS_VBO); +} + +GPUBatch *GPU_batch_preset_panel_drag_widget(const float pixelsize, + const float col_high[4], + const float col_dark[4], + const float width) +{ + const bool parameters_changed = (g_presets_2d.panel_drag_widget_pixelsize != pixelsize) || + (g_presets_2d.panel_drag_widget_width != width) || + !equals_v4v4(g_presets_2d.panel_drag_widget_col_high, + col_high) || + !equals_v4v4(g_presets_2d.panel_drag_widget_col_dark, col_dark); + + if (g_presets_2d.batch.panel_drag_widget && parameters_changed) { + gpu_batch_presets_unregister(g_presets_2d.batch.panel_drag_widget); + GPU_batch_discard(g_presets_2d.batch.panel_drag_widget); + g_presets_2d.batch.panel_drag_widget = NULL; + } + + if (!g_presets_2d.batch.panel_drag_widget) { + g_presets_2d.batch.panel_drag_widget = gpu_batch_preset_panel_drag_widget( + pixelsize, col_high, col_dark, width); + gpu_batch_presets_register(g_presets_2d.batch.panel_drag_widget); + g_presets_2d.panel_drag_widget_pixelsize = pixelsize; + g_presets_2d.panel_drag_widget_width = width; + copy_v4_v4(g_presets_2d.panel_drag_widget_col_high, col_high); + copy_v4_v4(g_presets_2d.panel_drag_widget_col_dark, col_dark); + } + return g_presets_2d.batch.panel_drag_widget; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Preset Registration Management + * \{ */ + void gpu_batch_presets_init(void) { BLI_mutex_init(&g_presets_3d.mutex); @@ -241,7 +387,7 @@ void gpu_batch_presets_reset(void) BLI_mutex_lock(&g_presets_3d.mutex); /* Reset vao caches for these every time we switch opengl context. * This way they will draw correctly for each window. */ - for (LinkData *link = presets_list.first; link; link = link->next) { + LISTBASE_FOREACH (LinkData *, link, &presets_list) { GPUBatch *preset = link->data; GPU_batch_vao_cache_clear(preset); } @@ -259,3 +405,5 @@ void gpu_batch_presets_exit(void) BLI_mutex_end(&g_presets_3d.mutex); } + +/** \} */ diff --git a/source/blender/gpu/intern/gpu_batch_private.h b/source/blender/gpu/intern/gpu_batch_private.h index 42cfc1e2a5c..58d1810ac7a 100644 --- a/source/blender/gpu/intern/gpu_batch_private.h +++ b/source/blender/gpu/intern/gpu_batch_private.h @@ -27,14 +27,14 @@ #ifndef __GPU_BATCH_PRIVATE_H__ #define __GPU_BATCH_PRIVATE_H__ -#ifdef __cplusplus -extern "C" { -#endif - #include "GPU_batch.h" #include "GPU_context.h" #include "GPU_shader_interface.h" +#ifdef __cplusplus +extern "C" { +#endif + void gpu_batch_remove_interface_ref(GPUBatch *batch, const GPUShaderInterface *interface); #ifdef __cplusplus diff --git a/source/blender/gpu/intern/gpu_buffers.c b/source/blender/gpu/intern/gpu_buffers.c index 168a3c83a91..cef90d57ef5 100644 --- a/source/blender/gpu/intern/gpu_buffers.c +++ b/source/blender/gpu/intern/gpu_buffers.c @@ -43,6 +43,7 @@ #include "BKE_mesh.h" #include "BKE_paint.h" #include "BKE_pbvh.h" +#include "BKE_subdiv_ccg.h" #include "GPU_batch.h" #include "GPU_buffers.h" @@ -150,7 +151,10 @@ static bool gpu_pbvh_vert_buf_data_set(GPU_PBVH_Buffers *buffers, uint vert_len) /* Initialize vertex buffer (match 'VertexBufferFormat'). */ buffers->vert_buf = GPU_vertbuf_create_with_format_ex(&g_vbo_id.format, GPU_USAGE_STATIC); } - GPU_vertbuf_data_alloc(buffers->vert_buf, vert_len); + if (buffers->vert_buf->data == NULL || buffers->vert_buf->vertex_len != vert_len) { + /* Allocate buffer if not allocated yet or size changed. */ + GPU_vertbuf_data_alloc(buffers->vert_buf, vert_len); + } #endif return buffers->vert_buf->data != NULL; @@ -218,14 +222,11 @@ static bool gpu_pbvh_is_looptri_visible(const MLoopTri *lt, /* Threaded - do not call any functions that use OpenGL calls! */ void GPU_pbvh_mesh_buffers_update(GPU_PBVH_Buffers *buffers, const MVert *mvert, - const int *vert_indices, - int totvert, const float *vmask, const MLoopCol *vcol, const int *sculpt_face_sets, const int face_sets_color_seed, const int face_sets_color_default, - const int (*face_vert_indices)[3], const int update_flags) { const bool show_mask = vmask && (update_flags & GPU_PBVH_BUFFERS_SHOW_MASK) != 0; @@ -236,7 +237,7 @@ void GPU_pbvh_mesh_buffers_update(GPU_PBVH_Buffers *buffers, bool default_face_set = true; { - int totelem = (buffers->smooth ? totvert : (buffers->tot_tri * 3)); + const int totelem = buffers->tot_tri * 3; /* Build VBO */ if (gpu_pbvh_vert_buf_data_set(buffers, totelem)) { @@ -254,127 +255,77 @@ void GPU_pbvh_mesh_buffers_update(GPU_PBVH_Buffers *buffers, GPU_vertbuf_attr_get_raw_data(buffers->vert_buf, g_vbo_id.col, &col_step); } - /* Vertex data is shared if smooth-shaded, but separate - * copies are made for flat shading because normals - * shouldn't be shared. */ - if (buffers->smooth) { - for (uint i = 0; i < totvert; i++) { - const int vidx = vert_indices[i]; - const MVert *v = &mvert[vidx]; - copy_v3_v3(GPU_vertbuf_raw_step(&pos_step), v->co); - copy_v3_v3_short(GPU_vertbuf_raw_step(&nor_step), v->no); + /* calculate normal for each polygon only once */ + uint mpoly_prev = UINT_MAX; + short no[3] = {0, 0, 0}; - uchar mask; - if (show_mask) { - mask = (uchar)(vmask[vidx] * 255); - } - else { - mask = 0.0f; - } - *(uchar *)GPU_vertbuf_raw_step(&msk_step) = mask; - empty_mask = empty_mask && (mask == 0); + for (uint i = 0; i < buffers->face_indices_len; i++) { + const MLoopTri *lt = &buffers->looptri[buffers->face_indices[i]]; + const uint vtri[3] = { + buffers->mloop[lt->tri[0]].v, + buffers->mloop[lt->tri[1]].v, + buffers->mloop[lt->tri[2]].v, + }; + + if (!gpu_pbvh_is_looptri_visible(lt, mvert, buffers->mloop, sculpt_face_sets)) { + continue; } - /* Face Sets. */ - for (uint i = 0; i < buffers->face_indices_len; i++) { - uchar face_set_color[4] = {UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX}; - if (show_face_sets) { - const MLoopTri *lt = &buffers->looptri[buffers->face_indices[i]]; - const int fset = abs(sculpt_face_sets[lt->poly]); - - /* Skip for the default color Face Set to render it white. */ - if (fset != face_sets_color_default) { - face_set_overlay_color_get(fset, face_sets_color_seed, face_set_color); - default_face_set = false; - } - } - for (int j = 0; j < 3; j++) { - const int vidx = face_vert_indices[i][j]; - GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.fset, vidx, &face_set_color); - } + /* Face normal and mask */ + if (lt->poly != mpoly_prev && !buffers->smooth) { + 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; } - if (show_vcol) { - for (uint i = 0; i < buffers->face_indices_len; i++) { - const MLoopTri *lt = &buffers->looptri[buffers->face_indices[i]]; - for (int j = 0; j < 3; j++) { - const int loop_index = lt->tri[j]; - const int vidx = face_vert_indices[i][j]; - const MLoopCol *mcol = &vcol[loop_index]; - ushort scol[4]; - scol[0] = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mcol->r]); - scol[1] = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mcol->g]); - scol[2] = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mcol->b]); - scol[3] = unit_float_to_ushort_clamp(mcol->a * (1.0f / 255.0f)); - GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.col, vidx, scol); - } + uchar face_set_color[4] = {UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX}; + if (show_face_sets) { + const int fset = abs(sculpt_face_sets[lt->poly]); + /* Skip for the default color Face Set to render it white. */ + if (fset != face_sets_color_default) { + face_set_overlay_color_get(fset, face_sets_color_seed, face_set_color); + default_face_set = false; } } - } - else { - /* calculate normal for each polygon only once */ - uint mpoly_prev = UINT_MAX; - short no[3] = {0, 0, 0}; - - for (uint i = 0; i < buffers->face_indices_len; i++) { - const MLoopTri *lt = &buffers->looptri[buffers->face_indices[i]]; - const uint vtri[3] = { - buffers->mloop[lt->tri[0]].v, - buffers->mloop[lt->tri[1]].v, - buffers->mloop[lt->tri[2]].v, - }; - - if (!gpu_pbvh_is_looptri_visible(lt, mvert, buffers->mloop, sculpt_face_sets)) { - continue; - } - /* Face normal and mask */ - 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; - } + float fmask = 0.0f; + uchar cmask = 0; + if (show_mask && !buffers->smooth) { + fmask = (vmask[vtri[0]] + vmask[vtri[1]] + vmask[vtri[2]]) / 3.0f; + cmask = (uchar)(fmask * 255); + } - uchar face_set_color[4] = {UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX}; - if (show_face_sets) { - const int fset = abs(sculpt_face_sets[lt->poly]); - /* Skip for the default color Face Set to render it white. */ - if (fset != face_sets_color_default) { - face_set_overlay_color_get(fset, face_sets_color_seed, face_set_color); - default_face_set = false; - } - } + for (uint j = 0; j < 3; j++) { + const MVert *v = &mvert[vtri[j]]; + copy_v3_v3(GPU_vertbuf_raw_step(&pos_step), v->co); - float fmask = 0.0f; - uchar cmask = 0; - if (show_mask) { - fmask = (vmask[vtri[0]] + vmask[vtri[1]] + vmask[vtri[2]]) / 3.0f; - cmask = (uchar)(fmask * 255); + if (buffers->smooth) { + copy_v3_v3_short(no, v->no); } + copy_v3_v3_short(GPU_vertbuf_raw_step(&nor_step), no); - for (uint j = 0; j < 3; j++) { - const MVert *v = &mvert[vtri[j]]; - - copy_v3_v3(GPU_vertbuf_raw_step(&pos_step), v->co); - copy_v3_v3_short(GPU_vertbuf_raw_step(&nor_step), no); - *(uchar *)GPU_vertbuf_raw_step(&msk_step) = cmask; - empty_mask = empty_mask && (cmask == 0); - /* Face Sets. */ - memcpy(GPU_vertbuf_raw_step(&fset_step), face_set_color, sizeof(uchar) * 3); + if (show_mask && buffers->smooth) { + cmask = (uchar)(vmask[vtri[j]] * 255); + } - if (show_vcol) { - const uint loop_index = lt->tri[j]; - const MLoopCol *mcol = &vcol[loop_index]; - ushort scol[4]; - scol[0] = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mcol->r]); - scol[1] = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mcol->g]); - scol[2] = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mcol->b]); - scol[3] = unit_float_to_ushort_clamp(mcol->a * (1.0f / 255.0f)); - memcpy(GPU_vertbuf_raw_step(&col_step), scol, sizeof(scol)); - } + *(uchar *)GPU_vertbuf_raw_step(&msk_step) = cmask; + empty_mask = empty_mask && (cmask == 0); + + if (show_vcol) { + const uint loop_index = lt->tri[j]; + const MLoopCol *mcol = &vcol[loop_index]; + ushort scol[4]; + scol[0] = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mcol->r]); + scol[1] = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mcol->g]); + scol[2] = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mcol->b]); + scol[3] = unit_float_to_ushort_clamp(mcol->a * (1.0f / 255.0f)); + memcpy(GPU_vertbuf_raw_step(&col_step), scol, sizeof(scol)); } + + /* Face Sets. */ + memcpy(GPU_vertbuf_raw_step(&fset_step), face_set_color, sizeof(uchar) * 3); } } @@ -392,8 +343,7 @@ void GPU_pbvh_mesh_buffers_update(GPU_PBVH_Buffers *buffers, } /* Threaded - do not call any functions that use OpenGL calls! */ -GPU_PBVH_Buffers *GPU_pbvh_mesh_buffers_build(const int (*face_vert_indices)[3], - const MPoly *mpoly, +GPU_PBVH_Buffers *GPU_pbvh_mesh_buffers_build(const MPoly *mpoly, const MLoop *mloop, const MLoopTri *looptri, const MVert *mvert, @@ -440,70 +390,34 @@ GPU_PBVH_Buffers *GPU_pbvh_mesh_buffers_build(const int (*face_vert_indices)[3], return buffers; } - /* An element index buffer is used for smooth shading, but flat - * shading requires separate vertex normals so an index buffer - * can't be used there. */ - if (buffers->smooth) { - /* Fill the triangle and line buffers. */ - GPUIndexBufBuilder elb, elb_lines; - GPU_indexbuf_init(&elb, GPU_PRIM_TRIS, tottri, INT_MAX); - GPU_indexbuf_init(&elb_lines, GPU_PRIM_LINES, tot_real_edges, INT_MAX); - - for (i = 0; i < face_indices_len; i++) { - const MLoopTri *lt = &looptri[face_indices[i]]; - - /* Skip hidden faces */ - if (!gpu_pbvh_is_looptri_visible(lt, mvert, mloop, sculpt_face_sets)) { - continue; - } + /* Fill the only the line buffer. */ + GPUIndexBufBuilder elb_lines; + GPU_indexbuf_init(&elb_lines, GPU_PRIM_LINES, tot_real_edges, INT_MAX); + int vert_idx = 0; - GPU_indexbuf_add_tri_verts(&elb, UNPACK3(face_vert_indices[i])); - int r_edges[3]; - BKE_mesh_looptri_get_real_edges(mesh, lt, r_edges); + for (i = 0; i < face_indices_len; i++) { + const MLoopTri *lt = &looptri[face_indices[i]]; - if (r_edges[0] != -1) { - GPU_indexbuf_add_line_verts(&elb_lines, face_vert_indices[i][0], face_vert_indices[i][1]); - } - if (r_edges[1] != -1) { - GPU_indexbuf_add_line_verts(&elb_lines, face_vert_indices[i][1], face_vert_indices[i][2]); - } - if (r_edges[2] != -1) { - GPU_indexbuf_add_line_verts(&elb_lines, face_vert_indices[i][2], face_vert_indices[i][0]); - } + /* Skip hidden faces */ + if (!gpu_pbvh_is_looptri_visible(lt, mvert, mloop, sculpt_face_sets)) { + continue; } - buffers->index_buf = GPU_indexbuf_build(&elb); - buffers->index_lines_buf = GPU_indexbuf_build(&elb_lines); - } - else { - /* Fill the only the line buffer. */ - GPUIndexBufBuilder elb_lines; - GPU_indexbuf_init(&elb_lines, GPU_PRIM_LINES, tot_real_edges, INT_MAX); - int vert_idx = 0; - for (i = 0; i < face_indices_len; i++) { - const MLoopTri *lt = &looptri[face_indices[i]]; - - /* Skip hidden faces */ - if (!gpu_pbvh_is_looptri_visible(lt, mvert, mloop, sculpt_face_sets)) { - continue; - } - - int r_edges[3]; - BKE_mesh_looptri_get_real_edges(mesh, lt, r_edges); - if (r_edges[0] != -1) { - GPU_indexbuf_add_line_verts(&elb_lines, vert_idx * 3 + 0, vert_idx * 3 + 1); - } - if (r_edges[1] != -1) { - GPU_indexbuf_add_line_verts(&elb_lines, vert_idx * 3 + 1, vert_idx * 3 + 2); - } - if (r_edges[2] != -1) { - GPU_indexbuf_add_line_verts(&elb_lines, vert_idx * 3 + 2, vert_idx * 3 + 0); - } - - vert_idx++; + int r_edges[3]; + BKE_mesh_looptri_get_real_edges(mesh, lt, r_edges); + if (r_edges[0] != -1) { + GPU_indexbuf_add_line_verts(&elb_lines, vert_idx * 3 + 0, vert_idx * 3 + 1); } - buffers->index_lines_buf = GPU_indexbuf_build(&elb_lines); + if (r_edges[1] != -1) { + GPU_indexbuf_add_line_verts(&elb_lines, vert_idx * 3 + 1, vert_idx * 3 + 2); + } + if (r_edges[2] != -1) { + GPU_indexbuf_add_line_verts(&elb_lines, vert_idx * 3 + 2, vert_idx * 3 + 0); + } + + vert_idx++; } + buffers->index_lines_buf = GPU_indexbuf_build(&elb_lines); buffers->tot_tri = tottri; @@ -523,8 +437,13 @@ GPU_PBVH_Buffers *GPU_pbvh_mesh_buffers_build(const int (*face_vert_indices)[3], /** \name Grid PBVH * \{ */ -static void gpu_pbvh_grid_fill_index_buffers( - GPU_PBVH_Buffers *buffers, int *grid_indices, uint visible_quad_len, int totgrid, int gridsize) +static void gpu_pbvh_grid_fill_index_buffers(GPU_PBVH_Buffers *buffers, + SubdivCCG *UNUSED(subdiv_ccg), + const int *UNUSED(face_sets), + int *grid_indices, + uint visible_quad_len, + int totgrid, + int gridsize) { GPUIndexBufBuilder elb, elb_lines; GPUIndexBufBuilder elb_fast, elb_lines_fast; @@ -594,7 +513,6 @@ static void gpu_pbvh_grid_fill_index_buffers( const uint grid_vert_len = square_uint(gridsize - 1) * 4; for (int i = 0; i < totgrid; i++, offset += grid_vert_len) { bool grid_visible = false; - BLI_bitmap *gh = buffers->grid_hidden[grid_indices[i]]; uint v0, v1, v2, v3; @@ -673,16 +591,24 @@ void GPU_pbvh_grid_buffers_update_free(GPU_PBVH_Buffers *buffers, /* Threaded - do not call any functions that use OpenGL calls! */ void GPU_pbvh_grid_buffers_update(GPU_PBVH_Buffers *buffers, + SubdivCCG *subdiv_ccg, CCGElem **grids, - const DMFlagMat *grid_flag_mats, + const struct DMFlagMat *grid_flag_mats, int *grid_indices, int totgrid, - const CCGKey *key, + const int *sculpt_face_sets, + const int face_sets_color_seed, + const int face_sets_color_default, + const struct CCGKey *key, const int update_flags) { const bool show_mask = (update_flags & GPU_PBVH_BUFFERS_SHOW_MASK) != 0; const bool show_vcol = (update_flags & GPU_PBVH_BUFFERS_SHOW_VCOL) != 0; + const bool show_face_sets = sculpt_face_sets && + (update_flags & GPU_PBVH_BUFFERS_SHOW_SCULPT_FACE_SETS) != 0; bool empty_mask = true; + bool default_face_set = true; + int i, j, k, x, y; /* Build VBO */ @@ -702,8 +628,13 @@ void GPU_pbvh_grid_buffers_update(GPU_PBVH_Buffers *buffers, return; } - gpu_pbvh_grid_fill_index_buffers( - buffers, grid_indices, visible_quad_len, totgrid, key->grid_size); + gpu_pbvh_grid_fill_index_buffers(buffers, + subdiv_ccg, + sculpt_face_sets, + grid_indices, + visible_quad_len, + totgrid, + key->grid_size); } uint vbo_index_offset = 0; @@ -716,9 +647,23 @@ void GPU_pbvh_grid_buffers_update(GPU_PBVH_Buffers *buffers, } for (i = 0; i < totgrid; i++) { - CCGElem *grid = grids[grid_indices[i]]; + const int grid_index = grid_indices[i]; + CCGElem *grid = grids[grid_index]; int vbo_index = vbo_index_offset; + uchar face_set_color[4] = {UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX}; + + if (show_face_sets && subdiv_ccg && sculpt_face_sets) { + const int face_index = BKE_subdiv_ccg_grid_to_face_index(subdiv_ccg, grid_index); + + const int fset = abs(sculpt_face_sets[face_index]); + /* Skip for the default color Face Set to render it white. */ + if (fset != face_sets_color_default) { + face_set_overlay_color_get(fset, face_sets_color_seed, face_set_color); + default_face_set = false; + } + } + if (buffers->smooth) { for (y = 0; y < key->grid_size; y++) { for (x = 0; x < key->grid_size; x++) { @@ -742,8 +687,7 @@ void GPU_pbvh_grid_buffers_update(GPU_PBVH_Buffers *buffers, GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.col, vbo_index, &vcol); } - uchar fsets[3] = {UCHAR_MAX, UCHAR_MAX, UCHAR_MAX}; - GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.fset, vbo_index, &fsets); + GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.fset, vbo_index, &face_set_color); vbo_index += 1; } @@ -799,11 +743,10 @@ void GPU_pbvh_grid_buffers_update(GPU_PBVH_Buffers *buffers, GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.col, vbo_index + 2, &vcol); GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.col, vbo_index + 3, &vcol); - uchar fsets[3] = {UCHAR_MAX, UCHAR_MAX, UCHAR_MAX}; - GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.fset, vbo_index + 0, &fsets); - GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.fset, vbo_index + 1, &fsets); - GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.fset, vbo_index + 2, &fsets); - GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.fset, vbo_index + 3, &fsets); + GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.fset, vbo_index + 0, &face_set_color); + GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.fset, vbo_index + 1, &face_set_color); + GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.fset, vbo_index + 2, &face_set_color); + GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.fset, vbo_index + 3, &face_set_color); vbo_index += 4; } @@ -823,7 +766,7 @@ void GPU_pbvh_grid_buffers_update(GPU_PBVH_Buffers *buffers, buffers->totgrid = totgrid; buffers->grid_flag_mats = grid_flag_mats; buffers->gridkey = *key; - buffers->show_overlay = !empty_mask; + buffers->show_overlay = !empty_mask || !default_face_set; } /* Threaded - do not call any functions that use OpenGL calls! */ @@ -1143,13 +1086,24 @@ short GPU_pbvh_buffers_material_index_get(GPU_PBVH_Buffers *buffers) return buffers->material_index; } +static void gpu_pbvh_buffers_clear(GPU_PBVH_Buffers *buffers) +{ + GPU_BATCH_DISCARD_SAFE(buffers->lines); + GPU_BATCH_DISCARD_SAFE(buffers->lines_fast); + GPU_BATCH_DISCARD_SAFE(buffers->triangles); + GPU_BATCH_DISCARD_SAFE(buffers->triangles_fast); + GPU_INDEXBUF_DISCARD_SAFE(buffers->index_lines_buf_fast); + GPU_INDEXBUF_DISCARD_SAFE(buffers->index_lines_buf); + GPU_INDEXBUF_DISCARD_SAFE(buffers->index_buf_fast); + GPU_INDEXBUF_DISCARD_SAFE(buffers->index_buf); + GPU_VERTBUF_DISCARD_SAFE(buffers->vert_buf); +} + void GPU_pbvh_buffers_update_flush(GPU_PBVH_Buffers *buffers) { /* Free empty bmesh node buffers. */ if (buffers->clear_bmesh_on_flush) { - GPU_BATCH_DISCARD_SAFE(buffers->triangles); - GPU_INDEXBUF_DISCARD_SAFE(buffers->index_buf); - GPU_VERTBUF_DISCARD_SAFE(buffers->vert_buf); + gpu_pbvh_buffers_clear(buffers); buffers->clear_bmesh_on_flush = false; } @@ -1162,16 +1116,7 @@ void GPU_pbvh_buffers_update_flush(GPU_PBVH_Buffers *buffers) void GPU_pbvh_buffers_free(GPU_PBVH_Buffers *buffers) { if (buffers) { - GPU_BATCH_DISCARD_SAFE(buffers->lines); - GPU_BATCH_DISCARD_SAFE(buffers->lines_fast); - GPU_BATCH_DISCARD_SAFE(buffers->triangles); - GPU_BATCH_DISCARD_SAFE(buffers->triangles_fast); - GPU_INDEXBUF_DISCARD_SAFE(buffers->index_lines_buf_fast); - GPU_INDEXBUF_DISCARD_SAFE(buffers->index_lines_buf); - GPU_INDEXBUF_DISCARD_SAFE(buffers->index_buf_fast); - GPU_INDEXBUF_DISCARD_SAFE(buffers->index_buf); - GPU_VERTBUF_DISCARD_SAFE(buffers->vert_buf); - + gpu_pbvh_buffers_clear(buffers); MEM_freeN(buffers); } } diff --git a/source/blender/gpu/intern/gpu_codegen.c b/source/blender/gpu/intern/gpu_codegen.c index 211ae0b3897..c1e7933d7ba 100644 --- a/source/blender/gpu/intern/gpu_codegen.c +++ b/source/blender/gpu/intern/gpu_codegen.c @@ -75,7 +75,7 @@ static uint32_t gpu_pass_hash(const char *frag_gen, const char *defs, ListBase * BLI_HashMurmur2A hm2a; BLI_hash_mm2a_init(&hm2a, 0); BLI_hash_mm2a_add(&hm2a, (uchar *)frag_gen, strlen(frag_gen)); - for (GPUMaterialAttribute *attr = attributes->first; attr; attr = attr->next) { + LISTBASE_FOREACH (GPUMaterialAttribute *, attr, attributes) { BLI_hash_mm2a_add(&hm2a, (uchar *)attr->name, strlen(attr->name)); } if (defs) { @@ -314,12 +314,12 @@ static int codegen_process_uniforms_functions(GPUMaterial *material, ListBase ubo_inputs = {NULL, NULL}; /* Attributes */ - for (GPUMaterialAttribute *attr = graph->attributes.first; attr; attr = attr->next) { + LISTBASE_FOREACH (GPUMaterialAttribute *, attr, &graph->attributes) { BLI_dynstr_appendf(ds, "in %s var%d;\n", gpu_data_type_to_string(attr->gputype), attr->id); } /* Textures */ - for (GPUMaterialTexture *tex = graph->textures.first; tex; tex = tex->next) { + LISTBASE_FOREACH (GPUMaterialTexture *, tex, &graph->textures) { if (tex->colorband) { BLI_dynstr_appendf(ds, "uniform sampler1DArray %s;\n", tex->sampler_name); } @@ -333,7 +333,7 @@ static int codegen_process_uniforms_functions(GPUMaterial *material, } /* Volume Grids */ - for (GPUMaterialVolumeGrid *grid = graph->volume_grids.first; grid; grid = grid->next) { + LISTBASE_FOREACH (GPUMaterialVolumeGrid *, grid, &graph->volume_grids) { BLI_dynstr_appendf(ds, "uniform sampler3D %s;\n", grid->sampler_name); BLI_dynstr_appendf(ds, "uniform mat4 %s = mat4(0.0);\n", grid->transform_name); } @@ -381,7 +381,7 @@ static int codegen_process_uniforms_functions(GPUMaterial *material, /* Inputs are sorted */ BLI_dynstr_appendf(ds, "\nlayout (std140) uniform %s {\n", GPU_UBO_BLOCK_NAME); - for (LinkData *link = ubo_inputs.first; link; link = link->next) { + LISTBASE_FOREACH (LinkData *, link, &ubo_inputs) { input = link->data; BLI_dynstr_appendf(ds, "\t%s unf%d;\n", gpu_data_type_to_string(input->type), input->id); } @@ -673,7 +673,7 @@ static char *code_generate_vertex(GPUNodeGraph *graph, const char *vert_code, bo "#define DEFINE_ATTR(type, attr) in type attr\n" "#endif\n"); - for (GPUMaterialAttribute *attr = graph->attributes.first; attr; attr = attr->next) { + LISTBASE_FOREACH (GPUMaterialAttribute *, attr, &graph->attributes) { /* XXX FIXME : see notes in mesh_render_data_create() */ /* NOTE : Replicate changes to mesh_render_data_create() in draw_cache_impl_mesh.c */ if (attr->type == CD_ORCO) { @@ -689,8 +689,8 @@ static char *code_generate_vertex(GPUNodeGraph *graph, const char *vert_code, bo BLI_dynstr_appendf(ds, "#define att%d %s\n", attr->id, attr_prefix_get(attr->type)); } else { - char attr_safe_name[GPU_MAX_SAFE_ATTRIB_NAME]; - GPU_vertformat_safe_attrib_name(attr->name, attr_safe_name, GPU_MAX_SAFE_ATTRIB_NAME); + char attr_safe_name[GPU_MAX_SAFE_ATTR_NAME]; + GPU_vertformat_safe_attr_name(attr->name, attr_safe_name, GPU_MAX_SAFE_ATTR_NAME); BLI_dynstr_appendf(ds, "DEFINE_ATTR(%s, %s%s);\n", gpu_data_type_to_string(attr->gputype), @@ -787,7 +787,7 @@ static char *code_generate_vertex(GPUNodeGraph *graph, const char *vert_code, bo BLI_dynstr_append(ds, "\tbarycentricPosg = position;\n"); } - for (GPUMaterialAttribute *attr = graph->attributes.first; attr; attr = attr->next) { + LISTBASE_FOREACH (GPUMaterialAttribute *, attr, &graph->attributes) { if (attr->type == CD_TANGENT) { /* Not supported by hairs */ BLI_dynstr_appendf(ds, "\tvar%d%s = vec4(0.0);\n", attr->id, use_geom ? "g" : ""); @@ -820,7 +820,7 @@ static char *code_generate_vertex(GPUNodeGraph *graph, const char *vert_code, bo BLI_dynstr_append(ds, "\tbarycentricPosg = (ModelMatrix * vec4(position, 1.0)).xyz;\n"); } - for (GPUMaterialAttribute *attr = graph->attributes.first; attr; attr = attr->next) { + LISTBASE_FOREACH (GPUMaterialAttribute *, attr, &graph->attributes) { if (attr->type == CD_TANGENT) { /* silly exception */ BLI_dynstr_appendf(ds, "\tvar%d%s.xyz = transpose(mat3(ModelMatrixInverse)) * att%d.xyz;\n", @@ -903,7 +903,7 @@ static char *code_generate_geometry(GPUNodeGraph *graph, } } - for (GPUMaterialAttribute *attr = graph->attributes.first; attr; attr = attr->next) { + LISTBASE_FOREACH (GPUMaterialAttribute *, attr, &graph->attributes) { BLI_dynstr_appendf(ds, "in %s var%dg[];\n", gpu_data_type_to_string(attr->gputype), attr->id); BLI_dynstr_appendf(ds, "out %s var%d;\n", gpu_data_type_to_string(attr->gputype), attr->id); } @@ -1010,7 +1010,7 @@ static char *code_generate_geometry(GPUNodeGraph *graph, BLI_dynstr_append(ds, "#endif\n"); } - for (GPUMaterialAttribute *attr = graph->attributes.first; attr; attr = attr->next) { + LISTBASE_FOREACH (GPUMaterialAttribute *, attr, &graph->attributes) { /* TODO let shader choose what to do depending on what the attribute is. */ BLI_dynstr_appendf(ds, "\tvar%d = var%dg[vert];\n", attr->id, attr->id); } @@ -1160,7 +1160,7 @@ static int count_active_texture_sampler(GPUShader *shader, char *source) if (*code != '\0') { char sampler_name[64]; code = gpu_str_skip_token(code, sampler_name, sizeof(sampler_name)); - int id = GPU_shader_get_uniform_ensure(shader, sampler_name); + int id = GPU_shader_get_uniform(shader, sampler_name); if (id == -1) { continue; diff --git a/source/blender/gpu/intern/gpu_context_private.h b/source/blender/gpu/intern/gpu_context_private.h index c9379e5433f..f64cdf439a1 100644 --- a/source/blender/gpu/intern/gpu_context_private.h +++ b/source/blender/gpu/intern/gpu_context_private.h @@ -26,12 +26,12 @@ #ifndef __GPU_CONTEXT_PRIVATE_H__ #define __GPU_CONTEXT_PRIVATE_H__ +#include "GPU_context.h" + #ifdef __cplusplus extern "C" { #endif -#include "GPU_context.h" - struct GPUFrameBuffer; GLuint GPU_vao_default(void); diff --git a/source/blender/gpu/intern/gpu_draw.c b/source/blender/gpu/intern/gpu_draw.c index 350c616e359..1c346217e9f 100644 --- a/source/blender/gpu/intern/gpu_draw.c +++ b/source/blender/gpu/intern/gpu_draw.c @@ -158,10 +158,10 @@ static GLenum gpu_get_mipmap_filter(bool mag) } /* Anisotropic filtering settings */ -void GPU_set_anisotropic(Main *bmain, float value) +void GPU_set_anisotropic(float value) { if (GTS.anisotropic != value) { - GPU_free_images(bmain); + GPU_samplers_free(); /* Clamp value to the maximum value the graphics card supports */ const float max = GPU_max_texture_anisotropy(); @@ -170,6 +170,8 @@ void GPU_set_anisotropic(Main *bmain, float value) } GTS.anisotropic = value; + + GPU_samplers_init(); } } @@ -449,22 +451,12 @@ static uint gpu_texture_create_tile_array(Image *ima, ImBuf *main_ibuf) BKE_image_release_ibuf(ima, ibuf, NULL); } - glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, gpu_get_mipmap_filter(1)); - if (GPU_get_mipmap()) { glGenerateMipmap(GL_TEXTURE_2D_ARRAY); - glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, gpu_get_mipmap_filter(0)); if (ima) { ima->gpuflag |= IMA_GPU_MIPMAP_COMPLETE; } } - else { - glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - } - - if (GLEW_EXT_texture_filter_anisotropic) { - glTexParameterf(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAX_ANISOTROPY_EXT, GPU_get_anisotropic()); - } glBindTexture(GL_TEXTURE_2D_ARRAY, 0); @@ -905,7 +897,7 @@ GPUTexture *GPU_texture_from_blender(Image *ima, ImageUser *iuser, ImBuf *ibuf, bindcode = gpu_texture_create_tile_array(ima, ibuf_intern); } else if (textarget == GL_TEXTURE_1D_ARRAY) { - bindcode = gpu_texture_create_tile_mapping(ima, iuser->multiview_eye); + bindcode = gpu_texture_create_tile_mapping(ima, iuser ? iuser->multiview_eye : 0); } else { bindcode = gpu_texture_create_from_ibuf(ima, ibuf_intern, textarget); @@ -1098,18 +1090,12 @@ void GPU_create_gl_tex(uint *bind, GL_TEXTURE_2D, 0, internal_format, 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) { glGenerateMipmap(GL_TEXTURE_2D); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gpu_get_mipmap_filter(0)); if (ima) { ima->gpuflag |= IMA_GPU_MIPMAP_COMPLETE; } } - else { - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - } } else if (textarget == GL_TEXTURE_CUBE_MAP) { int w = rectw / 3, h = recth / 2; @@ -1132,22 +1118,13 @@ void GPU_create_gl_tex(uint *bind, } } - glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, gpu_get_mipmap_filter(1)); - if (GPU_get_mipmap() && mipmap) { glGenerateMipmap(GL_TEXTURE_CUBE_MAP); - glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, gpu_get_mipmap_filter(0)); if (ima) { ima->gpuflag |= IMA_GPU_MIPMAP_COMPLETE; } } - else { - glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - } - glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); gpu_del_cube_map(cube_map); } @@ -1156,10 +1133,6 @@ void GPU_create_gl_tex(uint *bind, } } - if (GLEW_EXT_texture_filter_anisotropic) { - glTexParameterf(textarget, GL_TEXTURE_MAX_ANISOTROPY_EXT, GPU_get_anisotropic()); - } - glBindTexture(textarget, 0); if (ibuf) { @@ -1211,10 +1184,6 @@ bool GPU_upload_dxt_texture(ImBuf *ibuf, bool use_srgb) 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 (GLEW_EXT_texture_filter_anisotropic) { - 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++) { if (width == 0) { @@ -1481,66 +1450,3 @@ void GPU_free_images_old(Main *bmain) ima = ima->id.next; } } - -static void gpu_disable_multisample(void) -{ -#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) { - glDisable(GL_MULTISAMPLE); - } -#else - glDisable(GL_MULTISAMPLE); -#endif -} - -/* Default OpenGL State - * - * This is called on startup, for opengl offscreen render. - * Generally we should always return to this state when - * temporarily modifying the state for drawing, though that are (undocumented) - * exceptions that we should try to get rid of. */ - -void GPU_state_init(void) -{ - GPU_program_point_size(false); - - glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS); - - glDepthFunc(GL_LEQUAL); - - glDisable(GL_BLEND); - glDisable(GL_DEPTH_TEST); - glDisable(GL_COLOR_LOGIC_OP); - glDisable(GL_STENCIL_TEST); - - glDepthRange(0.0, 1.0); - - glFrontFace(GL_CCW); - glCullFace(GL_BACK); - glDisable(GL_CULL_FACE); - - gpu_disable_multisample(); - - /* This is a bit dangerous since addons could change this. */ - glEnable(GL_PRIMITIVE_RESTART); - glPrimitiveRestartIndex((GLuint)0xFFFFFFFF); - - /* TODO: Should become default. But needs at least GL 4.3 */ - if (GLEW_ARB_ES3_compatibility) { - /* Takes predecence over GL_PRIMITIVE_RESTART */ - glEnable(GL_PRIMITIVE_RESTART_FIXED_INDEX); - } -} diff --git a/source/blender/gpu/intern/gpu_extensions.c b/source/blender/gpu/intern/gpu_extensions.c index e3632b82778..8dd468b5414 100644 --- a/source/blender/gpu/intern/gpu_extensions.c +++ b/source/blender/gpu/intern/gpu_extensions.c @@ -304,6 +304,14 @@ void gpu_extensions_init(void) GG.context_local_shaders_workaround = GLEW_ARB_get_program_binary; } + /* Special fix for theses specific GPUs. + * Without this workaround, blender crashes on startup. (see T72098) */ + if (GPU_type_matches(GPU_DEVICE_INTEL, GPU_OS_WIN, GPU_DRIVER_OFFICIAL) && + (strstr(renderer, "HD Graphics 620") || strstr(renderer, "HD Graphics 630"))) { + GG.mip_render_workaround = true; + GG.context_local_shaders_workaround = GLEW_ARB_get_program_binary; + } + /* df/dy calculation factors, those are dependent on driver */ GG.dfdyfactors[0] = 1.0; GG.dfdyfactors[1] = 1.0; @@ -347,11 +355,13 @@ void gpu_extensions_init(void) } GPU_invalid_tex_init(); + GPU_samplers_init(); } void gpu_extensions_exit(void) { GPU_invalid_tex_free(); + GPU_samplers_free(); } bool GPU_mem_stats_supported(void) diff --git a/source/blender/gpu/intern/gpu_framebuffer.c b/source/blender/gpu/intern/gpu_framebuffer.c index 59d0be2cefb..5af9364b92c 100644 --- a/source/blender/gpu/intern/gpu_framebuffer.c +++ b/source/blender/gpu/intern/gpu_framebuffer.c @@ -514,6 +514,11 @@ void GPU_framebuffer_bind(GPUFrameBuffer *fb) if (GPU_framebuffer_active_get() != fb) { glBindFramebuffer(GL_FRAMEBUFFER, fb->object); glEnable(GL_FRAMEBUFFER_SRGB); + + GPUTexture *first_target = fb->attachments[GPU_FB_COLOR_ATTACHMENT0].tex; + const bool is_srgb_target = (first_target && + (GPU_texture_format(first_target) == GPU_SRGB8_A8)); + GPU_shader_set_framebuffer_srgb_target(is_srgb_target); } gpu_framebuffer_current_set(fb); @@ -536,10 +541,6 @@ void GPU_framebuffer_bind(GPUFrameBuffer *fb) } #endif - if (fb->multisample) { - glEnable(GL_MULTISAMPLE); - } - glViewport(0, 0, fb->width, fb->height); } @@ -549,6 +550,7 @@ void GPU_framebuffer_restore(void) glBindFramebuffer(GL_FRAMEBUFFER, GPU_framebuffer_default()); gpu_framebuffer_current_set(NULL); glDisable(GL_FRAMEBUFFER_SRGB); + GPU_shader_set_framebuffer_srgb_target(false); } } @@ -944,6 +946,7 @@ void GPU_offscreen_bind(GPUOffScreen *ofs, bool save) GPUFrameBuffer *ofs_fb = gpu_offscreen_fb_get(ofs); GPU_framebuffer_bind(ofs_fb); glDisable(GL_FRAMEBUFFER_SRGB); + GPU_shader_set_framebuffer_srgb_target(false); } void GPU_offscreen_unbind(GPUOffScreen *UNUSED(ofs), bool restore) diff --git a/source/blender/gpu/intern/gpu_immediate.c b/source/blender/gpu/intern/gpu_immediate.c index 4523df8be7c..9ea273f33cf 100644 --- a/source/blender/gpu/intern/gpu_immediate.c +++ b/source/blender/gpu/intern/gpu_immediate.c @@ -43,6 +43,13 @@ extern void GPU_matrix_bind(const GPUShaderInterface *); extern bool GPU_matrix_dirty_get(void); +typedef struct ImmediateDrawBuffer { + GLuint vbo_id; + GLubyte *buffer_data; + uint buffer_offset; + uint buffer_size; +} ImmediateDrawBuffer; + typedef struct { /* TODO: organize this struct by frequency of change (run-time) */ @@ -50,14 +57,14 @@ typedef struct { GPUContext *context; /* current draw call */ - GLubyte *buffer_data; - uint buffer_offset; - uint buffer_bytes_mapped; - uint vertex_len; bool strict_vertex_len; + uint vertex_len; + uint buffer_bytes_mapped; + ImmediateDrawBuffer *active_buffer; GPUPrimType prim_type; - GPUVertFormat vertex_format; + ImmediateDrawBuffer draw_buffer; + ImmediateDrawBuffer draw_buffer_strict; /* current vertex */ uint vertex_idx; @@ -65,7 +72,6 @@ typedef struct { uint16_t unassigned_attr_bits; /* which attributes of current vertex have not been given values? */ - GLuint vbo_id; GLuint vao_id; GLuint bound_program; @@ -76,7 +82,6 @@ typedef struct { /* size of internal buffer */ #define DEFAULT_INTERNAL_BUFFER_SIZE (4 * 1024 * 1024) -static uint imm_buffer_size = DEFAULT_INTERNAL_BUFFER_SIZE; static bool initialized = false; static Immediate imm; @@ -88,9 +93,14 @@ void immInit(void) #endif memset(&imm, 0, sizeof(Immediate)); - imm.vbo_id = GPU_buf_alloc(); - glBindBuffer(GL_ARRAY_BUFFER, imm.vbo_id); - glBufferData(GL_ARRAY_BUFFER, imm_buffer_size, NULL, GL_DYNAMIC_DRAW); + imm.draw_buffer.vbo_id = GPU_buf_alloc(); + imm.draw_buffer.buffer_size = DEFAULT_INTERNAL_BUFFER_SIZE; + glBindBuffer(GL_ARRAY_BUFFER, imm.draw_buffer.vbo_id); + glBufferData(GL_ARRAY_BUFFER, imm.draw_buffer.buffer_size, NULL, GL_DYNAMIC_DRAW); + imm.draw_buffer_strict.vbo_id = GPU_buf_alloc(); + imm.draw_buffer_strict.buffer_size = DEFAULT_INTERNAL_BUFFER_SIZE; + glBindBuffer(GL_ARRAY_BUFFER, imm.draw_buffer_strict.vbo_id); + glBufferData(GL_ARRAY_BUFFER, imm.draw_buffer_strict.buffer_size, NULL, GL_DYNAMIC_DRAW); imm.prim_type = GPU_PRIM_NONE; imm.strict_vertex_len = true; @@ -124,7 +134,8 @@ void immDeactivate(void) void immDestroy(void) { - GPU_buf_free(imm.vbo_id); + GPU_buf_free(imm.draw_buffer.vbo_id); + GPU_buf_free(imm.draw_buffer_strict.vbo_id); initialized = false; } @@ -151,6 +162,7 @@ void immBindProgram(GLuint program, const GPUShaderInterface *shaderface) glUseProgram(program); get_attr_locations(&imm.vertex_format, &imm.attr_binding, shaderface); GPU_matrix_bind(shaderface); + GPU_shader_set_srgb_uniform(shaderface); } void immBindBuiltinProgram(eGPUBuiltinShader shader_id) @@ -212,6 +224,7 @@ void immBegin(GPUPrimType prim_type, uint vertex_len) assert(initialized); assert(imm.prim_type == GPU_PRIM_NONE); /* make sure we haven't already begun */ assert(vertex_count_makes_sense_for_primitive(vertex_len, prim_type)); + assert(imm.active_buffer == NULL); #endif imm.prim_type = prim_type; imm.vertex_len = vertex_len; @@ -220,54 +233,66 @@ void immBegin(GPUPrimType prim_type, uint vertex_len) /* how many bytes do we need for this draw call? */ const uint bytes_needed = vertex_buffer_size(&imm.vertex_format, vertex_len); + ImmediateDrawBuffer *active_buffer = imm.strict_vertex_len ? &imm.draw_buffer_strict : + &imm.draw_buffer; + imm.active_buffer = active_buffer; - glBindBuffer(GL_ARRAY_BUFFER, imm.vbo_id); + glBindBuffer(GL_ARRAY_BUFFER, active_buffer->vbo_id); /* does the current buffer have enough room? */ - const uint available_bytes = imm_buffer_size - imm.buffer_offset; + const uint available_bytes = active_buffer->buffer_size - active_buffer->buffer_offset; bool recreate_buffer = false; - if (bytes_needed > imm_buffer_size) { + if (bytes_needed > active_buffer->buffer_size) { /* expand the internal buffer */ - imm_buffer_size = bytes_needed; + active_buffer->buffer_size = bytes_needed; recreate_buffer = true; } else if (bytes_needed < DEFAULT_INTERNAL_BUFFER_SIZE && - imm_buffer_size > DEFAULT_INTERNAL_BUFFER_SIZE) { + active_buffer->buffer_size > DEFAULT_INTERNAL_BUFFER_SIZE) { /* shrink the internal buffer */ - imm_buffer_size = DEFAULT_INTERNAL_BUFFER_SIZE; + active_buffer->buffer_size = DEFAULT_INTERNAL_BUFFER_SIZE; recreate_buffer = true; } /* ensure vertex data is aligned */ /* Might waste a little space, but it's safe. */ - const uint pre_padding = padding(imm.buffer_offset, imm.vertex_format.stride); + const uint pre_padding = padding(active_buffer->buffer_offset, imm.vertex_format.stride); if (!recreate_buffer && ((bytes_needed + pre_padding) <= available_bytes)) { - imm.buffer_offset += pre_padding; + active_buffer->buffer_offset += pre_padding; } else { /* orphan this buffer & start with a fresh one */ /* this method works on all platforms, old & new */ - glBufferData(GL_ARRAY_BUFFER, imm_buffer_size, NULL, GL_DYNAMIC_DRAW); + glBufferData(GL_ARRAY_BUFFER, active_buffer->buffer_size, NULL, GL_DYNAMIC_DRAW); - imm.buffer_offset = 0; + active_buffer->buffer_offset = 0; } /* printf("mapping %u to %u\n", imm.buffer_offset, imm.buffer_offset + bytes_needed - 1); */ - imm.buffer_data = glMapBufferRange(GL_ARRAY_BUFFER, - imm.buffer_offset, - bytes_needed, - GL_MAP_WRITE_BIT | GL_MAP_UNSYNCHRONIZED_BIT | - (imm.strict_vertex_len ? 0 : GL_MAP_FLUSH_EXPLICIT_BIT)); +#if TRUST_NO_ONE + { + GLint bufsize; + glGetBufferParameteriv(GL_ARRAY_BUFFER, GL_BUFFER_SIZE, &bufsize); + assert(active_buffer->buffer_offset + bytes_needed <= bufsize); + } +#endif + + active_buffer->buffer_data = glMapBufferRange( + GL_ARRAY_BUFFER, + active_buffer->buffer_offset, + bytes_needed, + GL_MAP_WRITE_BIT | GL_MAP_UNSYNCHRONIZED_BIT | + (imm.strict_vertex_len ? 0 : GL_MAP_FLUSH_EXPLICIT_BIT)); #if TRUST_NO_ONE - assert(imm.buffer_data != NULL); + assert(active_buffer->buffer_data != NULL); #endif imm.buffer_bytes_mapped = bytes_needed; - imm.vertex_data = imm.buffer_data; + imm.vertex_data = active_buffer->buffer_data; } void immBeginAtMost(GPUPrimType prim_type, uint vertex_len) @@ -337,7 +362,7 @@ static void immDrawSetup(void) for (uint a_idx = 0; a_idx < imm.vertex_format.attr_len; a_idx++) { const GPUVertAttr *a = &imm.vertex_format.attrs[a_idx]; - const uint offset = imm.buffer_offset + a->offset; + const uint offset = imm.active_buffer->buffer_offset + a->offset; const GLvoid *pointer = (const GLubyte *)0 + offset; const uint loc = read_attr_location(&imm.attr_binding, a_idx); @@ -364,6 +389,7 @@ void immEnd(void) { #if TRUST_NO_ONE assert(imm.prim_type != GPU_PRIM_NONE); /* make sure we're between a Begin/End pair */ + assert(imm.active_buffer || imm.batch); #endif uint buffer_bytes_used; @@ -420,12 +446,13 @@ void immEnd(void) // glBindBuffer(GL_ARRAY_BUFFER, 0); // glBindVertexArray(0); /* prep for next immBegin */ - imm.buffer_offset += buffer_bytes_used; + imm.active_buffer->buffer_offset += buffer_bytes_used; } /* prep for next immBegin */ imm.prim_type = GPU_PRIM_NONE; imm.strict_vertex_len = true; + imm.active_buffer = NULL; } static void setAttrValueBit(uint attr_id) @@ -732,13 +759,11 @@ void immVertex2iv(uint attr_id, const int data[2]) #if 0 # if TRUST_NO_ONE # define GET_UNIFORM \ - const GPUShaderInput *uniform = GPU_shaderinterface_uniform_ensure(imm.shader_interface, \ - name); \ + const GPUShaderInput *uniform = GPU_shaderinterface_uniform(imm.shader_interface, name); \ assert(uniform); # else # define GET_UNIFORM \ - const GPUShaderInput *uniform = GPU_shaderinterface_uniform_ensure(imm.shader_interface, \ - name); + const GPUShaderInput *uniform = GPU_shaderinterface_uniform(imm.shader_interface, name); # endif #else /* NOTE: It is possible to have uniform fully optimized out from the shader. @@ -746,8 +771,7 @@ void immVertex2iv(uint attr_id, const int data[2]) * TODO(sergey): How can we detect existing-but-optimized-out uniform but still * catch typos in uniform names passed to immUniform*() functions? */ # define GET_UNIFORM \ - const GPUShaderInput *uniform = GPU_shaderinterface_uniform_ensure(imm.shader_interface, \ - name); \ + const GPUShaderInput *uniform = GPU_shaderinterface_uniform(imm.shader_interface, name); \ if (uniform == NULL) \ return; #endif @@ -785,20 +809,9 @@ void immUniform3fv(const char *name, const float data[3]) /* can increase this limit or move to another file */ #define MAX_UNIFORM_NAME_LEN 60 -void immUniformArray3fv(const char *bare_name, const float *data, int count) +/* Note array index is not supported for name (i.e: "array[0]"). */ +void immUniformArray3fv(const char *name, const float *data, int count) { - /* look up "name[0]" when given "name" */ - const size_t len = strlen(bare_name); -#if TRUST_NO_ONE - assert(len <= MAX_UNIFORM_NAME_LEN); -#endif - char name[MAX_UNIFORM_NAME_LEN]; - strcpy(name, bare_name); - name[len + 0] = '['; - name[len + 1] = '0'; - name[len + 2] = ']'; - name[len + 3] = '\0'; - GET_UNIFORM glUniform3fv(uniform->location, count, data); } @@ -815,20 +828,9 @@ void immUniform4fv(const char *name, const float data[4]) glUniform4fv(uniform->location, 1, data); } -void immUniformArray4fv(const char *bare_name, const float *data, int count) +/* Note array index is not supported for name (i.e: "array[0]"). */ +void immUniformArray4fv(const char *name, const float *data, int count) { - /* look up "name[0]" when given "name" */ - const size_t len = strlen(bare_name); -#if TRUST_NO_ONE - assert(len <= MAX_UNIFORM_NAME_LEN); -#endif - char name[MAX_UNIFORM_NAME_LEN]; - strcpy(name, bare_name); - name[len + 0] = '['; - name[len + 1] = '0'; - name[len + 2] = ']'; - name[len + 3] = '\0'; - GET_UNIFORM glUniform4fv(uniform->location, count, data); } @@ -855,12 +857,10 @@ void immUniform4iv(const char *name, const int data[4]) void immUniformColor4f(float r, float g, float b, float a) { - const GPUShaderInput *uniform = GPU_shaderinterface_uniform_builtin(imm.shader_interface, - GPU_UNIFORM_COLOR); -#if TRUST_NO_ONE - assert(uniform != NULL); -#endif - glUniform4f(uniform->location, r, g, b, a); + int32_t uniform_loc = GPU_shaderinterface_uniform_builtin(imm.shader_interface, + GPU_UNIFORM_COLOR); + BLI_assert(uniform_loc != -1); + glUniform4f(uniform_loc, r, g, b, a); } void immUniformColor4fv(const float rgba[4]) diff --git a/source/blender/gpu/intern/gpu_immediate_util.c b/source/blender/gpu/intern/gpu_immediate_util.c index 7266f595447..e834d6afccb 100644 --- a/source/blender/gpu/intern/gpu_immediate_util.c +++ b/source/blender/gpu/intern/gpu_immediate_util.c @@ -361,25 +361,35 @@ void imm_draw_box_wire_3d(uint pos, float x1, float y1, float x2, float y2) /** * Draw a standard checkerboard to indicate transparent backgrounds. */ -void imm_draw_box_checker_2d(float x1, float y1, float x2, float y2) +void imm_draw_box_checker_2d_ex(float x1, + float y1, + float x2, + float y2, + const float color_primary[4], + const float color_secondary[4], + int checker_size) { uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); - float checker_primary[4]; - float checker_secondary[4]; - int checker_size = UI_GetThemeValue(TH_TRANSPARENT_CHECKER_SIZE); immBindBuiltinProgram(GPU_SHADER_2D_CHECKER); - UI_GetThemeColor4fv(TH_TRANSPARENT_CHECKER_PRIMARY, checker_primary); - UI_GetThemeColor4fv(TH_TRANSPARENT_CHECKER_SECONDARY, checker_secondary); - immUniform4fv("color1", checker_primary); - immUniform4fv("color2", checker_secondary); + immUniform4fv("color1", color_primary); + immUniform4fv("color2", color_secondary); immUniform1i("size", checker_size); immRectf(pos, x1, y1, x2, y2); immUnbindProgram(); } +void imm_draw_box_checker_2d(float x1, float y1, float x2, float y2) +{ + float checker_primary[4]; + float checker_secondary[4]; + UI_GetThemeColor4fv(TH_TRANSPARENT_CHECKER_PRIMARY, checker_primary); + UI_GetThemeColor4fv(TH_TRANSPARENT_CHECKER_SECONDARY, checker_secondary); + int checker_size = UI_GetThemeValue(TH_TRANSPARENT_CHECKER_SIZE); + imm_draw_box_checker_2d_ex(x1, y1, x2, y2, checker_primary, checker_secondary, checker_size); +} void imm_draw_cube_fill_3d(uint pos, const float co[3], const float aspect[3]) { diff --git a/source/blender/gpu/intern/gpu_material.c b/source/blender/gpu/intern/gpu_material.c index 3e73d156440..d2384b9c065 100644 --- a/source/blender/gpu/intern/gpu_material.c +++ b/source/blender/gpu/intern/gpu_material.c @@ -191,7 +191,7 @@ static void gpu_material_free_single(GPUMaterial *material) void GPU_material_free(ListBase *gpumaterial) { - for (LinkData *link = gpumaterial->first; link; link = link->next) { + LISTBASE_FOREACH (LinkData *, link, gpumaterial) { GPUMaterial *material = link->data; gpu_material_free_single(material); MEM_freeN(material); @@ -209,6 +209,11 @@ GPUPass *GPU_material_get_pass(GPUMaterial *material) return material->pass; } +GPUShader *GPU_material_get_shader(GPUMaterial *material) +{ + return material->pass ? GPU_pass_shader_get(material->pass) : NULL; +} + /* Return can be NULL if it's a world material. */ Material *GPU_material_get_material(GPUMaterial *material) { @@ -628,7 +633,7 @@ GPUMaterial *GPU_material_from_nodetree_find(ListBase *gpumaterials, const void *engine_type, int options) { - for (LinkData *link = gpumaterials->first; link; link = link->next) { + LISTBASE_FOREACH (LinkData *, link, gpumaterials) { GPUMaterial *current_material = (GPUMaterial *)link->data; if (current_material->engine_type == engine_type && current_material->options == options) { return current_material; @@ -662,6 +667,9 @@ GPUMaterial *GPU_material_from_nodetree(Scene *scene, /* Caller must re-use materials. */ BLI_assert(GPU_material_from_nodetree_find(gpumaterials, engine_type, options) == NULL); + /* HACK: Eevee assume this to create Ghash keys. */ + BLI_assert(sizeof(GPUPass) > 16); + /* allocate material */ GPUMaterial *mat = MEM_callocN(sizeof(GPUMaterial), "GPUMaterial"); mat->ma = ma; diff --git a/source/blender/gpu/intern/gpu_matrix.c b/source/blender/gpu/intern/gpu_matrix.c index 8260e1496ff..2687f56ad27 100644 --- a/source/blender/gpu/intern/gpu_matrix.c +++ b/source/blender/gpu/intern/gpu_matrix.c @@ -654,63 +654,59 @@ void GPU_matrix_bind(const GPUShaderInterface *shaderface) * call glUseProgram before this, as glUniform expects program to be bound */ - const GPUShaderInput *MV = GPU_shaderinterface_uniform_builtin(shaderface, - GPU_UNIFORM_MODELVIEW); - const GPUShaderInput *P = GPU_shaderinterface_uniform_builtin(shaderface, - GPU_UNIFORM_PROJECTION); - const GPUShaderInput *MVP = GPU_shaderinterface_uniform_builtin(shaderface, GPU_UNIFORM_MVP); - - const GPUShaderInput *N = GPU_shaderinterface_uniform_builtin(shaderface, GPU_UNIFORM_NORMAL); - const GPUShaderInput *MV_inv = GPU_shaderinterface_uniform_builtin(shaderface, - GPU_UNIFORM_MODELVIEW_INV); - const GPUShaderInput *P_inv = GPU_shaderinterface_uniform_builtin(shaderface, - GPU_UNIFORM_PROJECTION_INV); - - if (MV) { + int32_t MV = GPU_shaderinterface_uniform_builtin(shaderface, GPU_UNIFORM_MODELVIEW); + int32_t P = GPU_shaderinterface_uniform_builtin(shaderface, GPU_UNIFORM_PROJECTION); + int32_t MVP = GPU_shaderinterface_uniform_builtin(shaderface, GPU_UNIFORM_MVP); + + int32_t N = GPU_shaderinterface_uniform_builtin(shaderface, GPU_UNIFORM_NORMAL); + int32_t MV_inv = GPU_shaderinterface_uniform_builtin(shaderface, GPU_UNIFORM_MODELVIEW_INV); + int32_t P_inv = GPU_shaderinterface_uniform_builtin(shaderface, GPU_UNIFORM_PROJECTION_INV); + + if (MV != -1) { #if DEBUG_MATRIX_BIND puts("setting MV matrix"); #endif - glUniformMatrix4fv(MV->location, 1, GL_FALSE, (const float *)GPU_matrix_model_view_get(NULL)); + glUniformMatrix4fv(MV, 1, GL_FALSE, (const float *)GPU_matrix_model_view_get(NULL)); } - if (P) { + if (P != -1) { #if DEBUG_MATRIX_BIND puts("setting P matrix"); #endif - glUniformMatrix4fv(P->location, 1, GL_FALSE, (const float *)GPU_matrix_projection_get(NULL)); + glUniformMatrix4fv(P, 1, GL_FALSE, (const float *)GPU_matrix_projection_get(NULL)); } - if (MVP) { + if (MVP != -1) { #if DEBUG_MATRIX_BIND puts("setting MVP matrix"); #endif glUniformMatrix4fv( - MVP->location, 1, GL_FALSE, (const float *)GPU_matrix_model_view_projection_get(NULL)); + MVP, 1, GL_FALSE, (const float *)GPU_matrix_model_view_projection_get(NULL)); } - if (N) { + if (N != -1) { #if DEBUG_MATRIX_BIND puts("setting normal matrix"); #endif - glUniformMatrix3fv(N->location, 1, GL_FALSE, (const float *)GPU_matrix_normal_get(NULL)); + glUniformMatrix3fv(N, 1, GL_FALSE, (const float *)GPU_matrix_normal_get(NULL)); } - if (MV_inv) { + if (MV_inv != -1) { Mat4 m; GPU_matrix_model_view_get(m); invert_m4(m); - glUniformMatrix4fv(MV_inv->location, 1, GL_FALSE, (const float *)m); + glUniformMatrix4fv(MV_inv, 1, GL_FALSE, (const float *)m); } - if (P_inv) { + if (P_inv != -1) { Mat4 m; GPU_matrix_projection_get(m); invert_m4(m); - glUniformMatrix4fv(P_inv->location, 1, GL_FALSE, (const float *)m); + glUniformMatrix4fv(P_inv, 1, GL_FALSE, (const float *)m); } gpu_matrix_state_active_set_dirty(false); diff --git a/source/blender/gpu/intern/gpu_node_graph.c b/source/blender/gpu/intern/gpu_node_graph.c index 953b2eb40d8..17d97dc05e2 100644 --- a/source/blender/gpu/intern/gpu_node_graph.c +++ b/source/blender/gpu/intern/gpu_node_graph.c @@ -34,6 +34,8 @@ #include "BLI_string.h" #include "BLI_utildefines.h" +#include "GPU_texture.h" + #include "gpu_material_library.h" #include "gpu_node_graph.h" @@ -298,13 +300,14 @@ static GPUMaterialTexture *gpu_node_graph_add_texture(GPUNodeGraph *graph, Image *ima, ImageUser *iuser, struct GPUTexture **colorband, - GPUNodeLinkType link_type) + GPUNodeLinkType link_type, + eGPUSamplerState sampler_state) { /* Find existing texture. */ int num_textures = 0; GPUMaterialTexture *tex = graph->textures.first; for (; tex; tex = tex->next) { - if (tex->ima == ima && tex->colorband == colorband) { + if (tex->ima == ima && tex->colorband == colorband && tex->sampler_state == sampler_state) { break; } num_textures++; @@ -316,6 +319,7 @@ static GPUMaterialTexture *gpu_node_graph_add_texture(GPUNodeGraph *graph, tex->ima = ima; tex->iuser = iuser; tex->colorband = colorband; + tex->sampler_state = sampler_state; BLI_snprintf(tex->sampler_name, sizeof(tex->sampler_name), "samp%d", num_textures); if (ELEM(link_type, GPU_NODE_LINK_IMAGE_TILED, GPU_NODE_LINK_IMAGE_TILED_MAPPING)) { BLI_snprintf( @@ -389,21 +393,29 @@ GPUNodeLink *GPU_uniform(const float *num) return link; } -GPUNodeLink *GPU_image(GPUMaterial *mat, Image *ima, ImageUser *iuser) +GPUNodeLink *GPU_image(GPUMaterial *mat, + Image *ima, + ImageUser *iuser, + eGPUSamplerState sampler_state) { GPUNodeGraph *graph = gpu_material_node_graph(mat); GPUNodeLink *link = gpu_node_link_create(); link->link_type = GPU_NODE_LINK_IMAGE; - link->texture = gpu_node_graph_add_texture(graph, ima, iuser, NULL, link->link_type); + link->texture = gpu_node_graph_add_texture( + graph, ima, iuser, NULL, link->link_type, sampler_state); return link; } -GPUNodeLink *GPU_image_tiled(GPUMaterial *mat, Image *ima, ImageUser *iuser) +GPUNodeLink *GPU_image_tiled(GPUMaterial *mat, + Image *ima, + ImageUser *iuser, + eGPUSamplerState sampler_state) { GPUNodeGraph *graph = gpu_material_node_graph(mat); GPUNodeLink *link = gpu_node_link_create(); link->link_type = GPU_NODE_LINK_IMAGE_TILED; - link->texture = gpu_node_graph_add_texture(graph, ima, iuser, NULL, link->link_type); + link->texture = gpu_node_graph_add_texture( + graph, ima, iuser, NULL, link->link_type, sampler_state); return link; } @@ -412,7 +424,8 @@ GPUNodeLink *GPU_image_tiled_mapping(GPUMaterial *mat, Image *ima, ImageUser *iu GPUNodeGraph *graph = gpu_material_node_graph(mat); GPUNodeLink *link = gpu_node_link_create(); link->link_type = GPU_NODE_LINK_IMAGE_TILED_MAPPING; - link->texture = gpu_node_graph_add_texture(graph, ima, iuser, NULL, link->link_type); + link->texture = gpu_node_graph_add_texture( + graph, ima, iuser, NULL, link->link_type, GPU_SAMPLER_MAX); return link; } @@ -424,7 +437,8 @@ GPUNodeLink *GPU_color_band(GPUMaterial *mat, int size, float *pixels, float *ro GPUNodeGraph *graph = gpu_material_node_graph(mat); GPUNodeLink *link = gpu_node_link_create(); link->link_type = GPU_NODE_LINK_COLORBAND; - link->texture = gpu_node_graph_add_texture(graph, NULL, NULL, colorband, link->link_type); + link->texture = gpu_node_graph_add_texture( + graph, NULL, NULL, colorband, link->link_type, GPU_SAMPLER_MAX); return link; } @@ -645,7 +659,7 @@ void gpu_node_graph_free(GPUNodeGraph *graph) { gpu_node_graph_free_nodes(graph); - for (GPUMaterialVolumeGrid *grid = graph->volume_grids.first; grid; grid = grid->next) { + LISTBASE_FOREACH (GPUMaterialVolumeGrid *, grid, &graph->volume_grids) { MEM_SAFE_FREE(grid->name); } BLI_freelistN(&graph->volume_grids); @@ -679,7 +693,7 @@ static void gpu_nodes_tag(GPUNodeLink *link) void gpu_node_graph_prune_unused(GPUNodeGraph *graph) { - for (GPUNode *node = graph->nodes.first; node; node = node->next) { + LISTBASE_FOREACH (GPUNode *, node, &graph->nodes) { node->tag = false; } diff --git a/source/blender/gpu/intern/gpu_select_pick.c b/source/blender/gpu/intern/gpu_select_pick.c index 56fe1e40d87..4b38cd333a1 100644 --- a/source/blender/gpu/intern/gpu_select_pick.c +++ b/source/blender/gpu/intern/gpu_select_pick.c @@ -314,17 +314,10 @@ void gpu_select_pick_begin(uint (*buffer)[4], uint bufsize, const rcti *input, c glEnable(GL_DEPTH_TEST); glDepthMask(GL_TRUE); - - if (mode == GPU_SELECT_PICK_ALL) { - /* Note that other depth settings (such as #GL_LEQUAL) work too, - * since the depth is always cleared. - * Noting this for cases when depth picking is used where - * drawing calls change depth settings. */ - glDepthFunc(GL_ALWAYS); - } - else { - glDepthFunc(GL_LEQUAL); - } + /* Always use #GL_LEQUAL even though GPU_SELECT_PICK_ALL always clears the buffer. This is + * because individual objects themselves might have sections that overlap and we need these + * to have the correct distance information. */ + glDepthFunc(GL_LEQUAL); float viewport[4]; glGetFloatv(GL_VIEWPORT, viewport); @@ -731,8 +724,7 @@ void gpu_select_pick_cache_load_id(void) #ifdef DEBUG_PRINT printf("%s (building depth from cache)\n", __func__); #endif - for (DepthBufCache *rect_depth = ps->cache.bufs.first; rect_depth; - rect_depth = rect_depth->next) { + LISTBASE_FOREACH (DepthBufCache *, rect_depth, &ps->cache.bufs) { if (rect_depth->next != NULL) { /* we know the buffers differ, but this sub-region may not. * double check before adding an id-pass */ diff --git a/source/blender/gpu/intern/gpu_shader.c b/source/blender/gpu/intern/gpu_shader.c index c6ffcfa2d86..8c03567b95f 100644 --- a/source/blender/gpu/intern/gpu_shader.c +++ b/source/blender/gpu/intern/gpu_shader.c @@ -54,9 +54,6 @@ extern char datatoc_gpu_shader_uniform_color_frag_glsl[]; extern char datatoc_gpu_shader_checker_frag_glsl[]; extern char datatoc_gpu_shader_diag_stripes_frag_glsl[]; extern char datatoc_gpu_shader_simple_lighting_frag_glsl[]; -extern char datatoc_gpu_shader_simple_lighting_flat_color_frag_glsl[]; -extern char datatoc_gpu_shader_simple_lighting_smooth_color_frag_glsl[]; -extern char datatoc_gpu_shader_simple_lighting_smooth_color_alpha_frag_glsl[]; extern char datatoc_gpu_shader_flat_color_frag_glsl[]; extern char datatoc_gpu_shader_flat_color_alpha_test_0_frag_glsl[]; extern char datatoc_gpu_shader_flat_id_frag_glsl[]; @@ -67,7 +64,6 @@ extern char datatoc_gpu_shader_2D_flat_color_vert_glsl[]; extern char datatoc_gpu_shader_2D_smooth_color_uniform_alpha_vert_glsl[]; extern char datatoc_gpu_shader_2D_smooth_color_vert_glsl[]; extern char datatoc_gpu_shader_2D_smooth_color_frag_glsl[]; -extern char datatoc_gpu_shader_2D_smooth_color_dithered_frag_glsl[]; extern char datatoc_gpu_shader_2D_image_vert_glsl[]; extern char datatoc_gpu_shader_2D_image_rect_vert_glsl[]; extern char datatoc_gpu_shader_2D_image_multi_rect_vert_glsl[]; @@ -89,15 +85,13 @@ extern char datatoc_gpu_shader_image_alpha_color_frag_glsl[]; extern char datatoc_gpu_shader_image_shuffle_color_frag_glsl[]; extern char datatoc_gpu_shader_image_mask_uniform_color_frag_glsl[]; extern char datatoc_gpu_shader_image_modulate_alpha_frag_glsl[]; -extern char datatoc_gpu_shader_image_depth_linear_frag_glsl[]; -extern char datatoc_gpu_shader_image_depth_copy_frag_glsl[]; -extern char datatoc_gpu_shader_image_multisample_resolve_frag_glsl[]; extern char datatoc_gpu_shader_3D_vert_glsl[]; extern char datatoc_gpu_shader_3D_normal_vert_glsl[]; extern char datatoc_gpu_shader_3D_flat_color_vert_glsl[]; +extern char datatoc_gpu_shader_3D_polyline_frag_glsl[]; +extern char datatoc_gpu_shader_3D_polyline_geom_glsl[]; +extern char datatoc_gpu_shader_3D_polyline_vert_glsl[]; extern char datatoc_gpu_shader_3D_smooth_color_vert_glsl[]; -extern char datatoc_gpu_shader_3D_normal_flat_color_vert_glsl[]; -extern char datatoc_gpu_shader_3D_normal_smooth_color_vert_glsl[]; extern char datatoc_gpu_shader_3D_smooth_color_frag_glsl[]; extern char datatoc_gpu_shader_3D_passthrough_vert_glsl[]; extern char datatoc_gpu_shader_3D_clipped_uniform_color_vert_glsl[]; @@ -143,21 +137,25 @@ extern char datatoc_gpu_shader_gpencil_fill_vert_glsl[]; extern char datatoc_gpu_shader_gpencil_fill_frag_glsl[]; extern char datatoc_gpu_shader_cfg_world_clip_lib_glsl[]; +extern char datatoc_gpu_shader_colorspace_lib_glsl[]; + const struct GPUShaderConfigData GPU_shader_cfg_data[GPU_SHADER_CFG_LEN] = { [GPU_SHADER_CFG_DEFAULT] = { .lib = "", - .def = "", + .def = "#define blender_srgb_to_framebuffer_space(a) a\n", }, [GPU_SHADER_CFG_CLIPPED] = { .lib = datatoc_gpu_shader_cfg_world_clip_lib_glsl, - .def = "#define USE_WORLD_CLIP_PLANES\n", + .def = "#define USE_WORLD_CLIP_PLANES\n" + "#define blender_srgb_to_framebuffer_space(a) a\n", }, }; /* cache of built-in shaders (each is created on first use) */ static GPUShader *builtin_shaders[GPU_SHADER_CFG_LEN][GPU_SHADER_BUILTIN_LEN] = {{NULL}}; +static int g_shader_builtin_srgb_transform = 0; #ifndef NDEBUG static uint g_shaderid = 0; @@ -298,6 +296,28 @@ GPUShader *GPU_shader_create(const char *vertexcode, vertexcode, fragcode, geocode, libcode, defines, GPU_SHADER_TFB_NONE, NULL, 0, shname); } +GPUShader *GPU_shader_create_from_python(const char *vertexcode, + const char *fragcode, + const char *geocode, + const char *libcode, + const char *defines) +{ + char *libcodecat = NULL; + + if (libcode == NULL) { + libcode = datatoc_gpu_shader_colorspace_lib_glsl; + } + else { + libcode = libcodecat = BLI_strdupcat(libcode, datatoc_gpu_shader_colorspace_lib_glsl); + } + + GPUShader *sh = GPU_shader_create_ex( + vertexcode, fragcode, geocode, libcode, defines, GPU_SHADER_TFB_NONE, NULL, 0, NULL); + + MEM_SAFE_FREE(libcodecat); + return sh; +} + GPUShader *GPU_shader_load_from_binary(const char *binary, const int binary_format, const int binary_len, @@ -311,6 +331,8 @@ GPUShader *GPU_shader_load_from_binary(const char *binary, glGetProgramiv(program, GL_LINK_STATUS, &success); if (success) { + glUseProgram(program); + GPUShader *shader = MEM_callocN(sizeof(*shader), __func__); shader->interface = GPU_shaderinterface_create(program); shader->program = program; @@ -552,6 +574,7 @@ GPUShader *GPU_shader_create_ex(const char *vertexcode, return NULL; } + glUseProgram(shader->program); shader->interface = GPU_shaderinterface_create(shader->program); return shader; @@ -638,6 +661,7 @@ void GPU_shader_bind(GPUShader *shader) glUseProgram(shader->program); GPU_matrix_bind(shader->interface); + GPU_shader_set_srgb_uniform(shader->interface); } void GPU_shader_unbind(void) @@ -705,21 +729,19 @@ int GPU_shader_get_uniform(GPUShader *shader, const char *name) { BLI_assert(shader && shader->program); const GPUShaderInput *uniform = GPU_shaderinterface_uniform(shader->interface, name); - return uniform ? uniform->location : -2; + return uniform ? uniform->location : -1; } -int GPU_shader_get_uniform_ensure(GPUShader *shader, const char *name) +int GPU_shader_get_builtin_uniform(GPUShader *shader, int builtin) { BLI_assert(shader && shader->program); - const GPUShaderInput *uniform = GPU_shaderinterface_uniform_ensure(shader->interface, name); - return uniform ? uniform->location : -1; + return GPU_shaderinterface_uniform_builtin(shader->interface, builtin); } -int GPU_shader_get_builtin_uniform(GPUShader *shader, int builtin) +int GPU_shader_get_builtin_block(GPUShader *shader, int builtin) { BLI_assert(shader && shader->program); - const GPUShaderInput *uniform = GPU_shaderinterface_uniform_builtin(shader->interface, builtin); - return uniform ? uniform->location : -1; + return GPU_shaderinterface_block_builtin(shader->interface, builtin); } int GPU_shader_get_uniform_block(GPUShader *shader, const char *name) @@ -729,6 +751,20 @@ int GPU_shader_get_uniform_block(GPUShader *shader, const char *name) return ubo ? ubo->location : -1; } +int GPU_shader_get_uniform_block_binding(GPUShader *shader, const char *name) +{ + BLI_assert(shader && shader->program); + const GPUShaderInput *ubo = GPU_shaderinterface_ubo(shader->interface, name); + return ubo ? ubo->binding : -1; +} + +int GPU_shader_get_texture_binding(GPUShader *shader, const char *name) +{ + BLI_assert(shader && shader->program); + const GPUShaderInput *tex = GPU_shaderinterface_uniform(shader->interface, name); + return tex ? tex->binding : -1; +} + void *GPU_shader_get_interface(GPUShader *shader) { return shader->interface; @@ -816,32 +852,12 @@ void GPU_shader_uniform_int(GPUShader *UNUSED(shader), int location, int value) glUniform1i(location, value); } -void GPU_shader_uniform_buffer(GPUShader *shader, int location, GPUUniformBuffer *ubo) +void GPU_shader_set_srgb_uniform(const GPUShaderInterface *interface) { - int bindpoint = GPU_uniformbuffer_bindpoint(ubo); - - if (location == -1) { - return; + int32_t loc = GPU_shaderinterface_uniform_builtin(interface, GPU_UNIFORM_SRGB_TRANSFORM); + if (loc != -1) { + glUniform1i(loc, g_shader_builtin_srgb_transform); } - - glUniformBlockBinding(shader->program, location, bindpoint); -} - -void GPU_shader_uniform_texture(GPUShader *UNUSED(shader), int location, GPUTexture *tex) -{ - int number = GPU_texture_bound_number(tex); - - if (number == -1) { - fprintf(stderr, "Texture is not bound.\n"); - BLI_assert(0); - return; - } - - if (location == -1) { - return; - } - - glUniform1i(location, number); } int GPU_shader_get_attribute(GPUShader *shader, const char *name) @@ -868,6 +884,11 @@ char *GPU_shader_get_binary(GPUShader *shader, uint *r_binary_format, int *r_bin return r_binary; } +void GPU_shader_set_framebuffer_srgb_target(int use_srgb_to_linear) +{ + g_shader_builtin_srgb_transform = use_srgb_to_linear; +} + static const GPUShaderStages builtin_shader_stages[GPU_SHADER_BUILTIN_LEN] = { [GPU_SHADER_TEXT] = { @@ -884,23 +905,6 @@ static const GPUShaderStages builtin_shader_stages[GPU_SHADER_BUILTIN_LEN] = { .vert = datatoc_gpu_shader_3D_normal_vert_glsl, .frag = datatoc_gpu_shader_simple_lighting_frag_glsl, }, - /* Use 'USE_FLAT_NORMAL' to make flat shader from smooth */ - [GPU_SHADER_SIMPLE_LIGHTING_FLAT_COLOR] = - { - .vert = datatoc_gpu_shader_3D_normal_smooth_color_vert_glsl, - .frag = datatoc_gpu_shader_simple_lighting_smooth_color_frag_glsl, - .defs = "#define USE_FLAT_NORMAL\n", - }, - [GPU_SHADER_SIMPLE_LIGHTING_SMOOTH_COLOR] = - { - .vert = datatoc_gpu_shader_3D_normal_smooth_color_vert_glsl, - .frag = datatoc_gpu_shader_simple_lighting_smooth_color_frag_glsl, - }, - [GPU_SHADER_SIMPLE_LIGHTING_SMOOTH_COLOR_ALPHA] = - { - .vert = datatoc_gpu_shader_3D_normal_smooth_color_vert_glsl, - .frag = datatoc_gpu_shader_simple_lighting_smooth_color_alpha_frag_glsl, - }, [GPU_SHADER_2D_IMAGE_MASK_UNIFORM_COLOR] = { @@ -912,69 +916,6 @@ static const GPUShaderStages builtin_shader_stages[GPU_SHADER_BUILTIN_LEN] = { .vert = datatoc_gpu_shader_3D_image_vert_glsl, .frag = datatoc_gpu_shader_image_modulate_alpha_frag_glsl, }, - [GPU_SHADER_3D_IMAGE_DEPTH] = - { - .vert = datatoc_gpu_shader_3D_image_vert_glsl, - .frag = datatoc_gpu_shader_image_depth_linear_frag_glsl, - }, - [GPU_SHADER_3D_IMAGE_DEPTH_COPY] = - { - .vert = datatoc_gpu_shader_3D_image_vert_glsl, - .frag = datatoc_gpu_shader_image_depth_copy_frag_glsl, - }, - [GPU_SHADER_2D_IMAGE_MULTISAMPLE_2] = - { - .vert = datatoc_gpu_shader_2D_vert_glsl, - .frag = datatoc_gpu_shader_image_multisample_resolve_frag_glsl, - .defs = "#define SAMPLES 2\n", - }, - [GPU_SHADER_2D_IMAGE_MULTISAMPLE_4] = - { - .vert = datatoc_gpu_shader_2D_vert_glsl, - .frag = datatoc_gpu_shader_image_multisample_resolve_frag_glsl, - .defs = "#define SAMPLES 4\n", - }, - [GPU_SHADER_2D_IMAGE_MULTISAMPLE_8] = - { - .vert = datatoc_gpu_shader_2D_vert_glsl, - .frag = datatoc_gpu_shader_image_multisample_resolve_frag_glsl, - .defs = "#define SAMPLES 8\n", - }, - [GPU_SHADER_2D_IMAGE_MULTISAMPLE_16] = - { - .vert = datatoc_gpu_shader_2D_vert_glsl, - .frag = datatoc_gpu_shader_image_multisample_resolve_frag_glsl, - .defs = "#define SAMPLES 16\n", - }, - [GPU_SHADER_2D_IMAGE_MULTISAMPLE_2_DEPTH_TEST] = - { - .vert = datatoc_gpu_shader_2D_vert_glsl, - .frag = datatoc_gpu_shader_image_multisample_resolve_frag_glsl, - .defs = "#define SAMPLES 2\n" - "#define USE_DEPTH\n", - }, - [GPU_SHADER_2D_IMAGE_MULTISAMPLE_4_DEPTH_TEST] = - { - .vert = datatoc_gpu_shader_2D_vert_glsl, - .frag = datatoc_gpu_shader_image_multisample_resolve_frag_glsl, - .defs = "#define SAMPLES 4\n" - "#define USE_DEPTH\n", - }, - [GPU_SHADER_2D_IMAGE_MULTISAMPLE_8_DEPTH_TEST] = - { - .vert = datatoc_gpu_shader_2D_vert_glsl, - .frag = datatoc_gpu_shader_image_multisample_resolve_frag_glsl, - .defs = "#define SAMPLES 8\n" - "#define USE_DEPTH\n", - }, - [GPU_SHADER_2D_IMAGE_MULTISAMPLE_16_DEPTH_TEST] = - { - .vert = datatoc_gpu_shader_2D_vert_glsl, - .frag = datatoc_gpu_shader_image_multisample_resolve_frag_glsl, - .defs = "#define SAMPLES 16\n" - "#define USE_DEPTH\n", - }, - [GPU_SHADER_2D_CHECKER] = { .vert = datatoc_gpu_shader_2D_vert_glsl, @@ -1002,11 +943,6 @@ static const GPUShaderStages builtin_shader_stages[GPU_SHADER_BUILTIN_LEN] = { .vert = datatoc_gpu_shader_2D_smooth_color_vert_glsl, .frag = datatoc_gpu_shader_2D_smooth_color_frag_glsl, }, - [GPU_SHADER_2D_SMOOTH_COLOR_DITHER] = - { - .vert = datatoc_gpu_shader_2D_smooth_color_vert_glsl, - .frag = datatoc_gpu_shader_2D_smooth_color_dithered_frag_glsl, - }, [GPU_SHADER_2D_IMAGE_OVERLAYS_MERGE] = { .vert = datatoc_gpu_shader_2D_image_vert_glsl, @@ -1058,12 +994,6 @@ static const GPUShaderStages builtin_shader_stages[GPU_SHADER_BUILTIN_LEN] = { .vert = datatoc_gpu_shader_3D_vert_glsl, .frag = datatoc_gpu_shader_uniform_color_frag_glsl, }, - [GPU_SHADER_3D_UNIFORM_COLOR_BACKGROUND] = - { - .vert = datatoc_gpu_shader_3D_vert_glsl, - .frag = datatoc_gpu_shader_uniform_color_frag_glsl, - .defs = "#define USE_BACKGROUND\n", - }, [GPU_SHADER_3D_FLAT_COLOR] = { .vert = datatoc_gpu_shader_3D_flat_color_vert_glsl, @@ -1085,6 +1015,36 @@ static const GPUShaderStages builtin_shader_stages[GPU_SHADER_BUILTIN_LEN] = { .frag = datatoc_gpu_shader_uniform_color_frag_glsl, }, + [GPU_SHADER_3D_POLYLINE_UNIFORM_COLOR] = + { + .vert = datatoc_gpu_shader_3D_polyline_vert_glsl, + .geom = datatoc_gpu_shader_3D_polyline_geom_glsl, + .frag = datatoc_gpu_shader_3D_polyline_frag_glsl, + .defs = "#define UNIFORM\n", + }, + [GPU_SHADER_3D_POLYLINE_CLIPPED_UNIFORM_COLOR] = + { + .vert = datatoc_gpu_shader_3D_polyline_vert_glsl, + .geom = datatoc_gpu_shader_3D_polyline_geom_glsl, + .frag = datatoc_gpu_shader_3D_polyline_frag_glsl, + .defs = "#define UNIFORM\n" + "#define CLIP\n", + }, + [GPU_SHADER_3D_POLYLINE_FLAT_COLOR] = + { + .vert = datatoc_gpu_shader_3D_polyline_vert_glsl, + .geom = datatoc_gpu_shader_3D_polyline_geom_glsl, + .frag = datatoc_gpu_shader_3D_polyline_frag_glsl, + .defs = "#define FLAT\n", + }, + [GPU_SHADER_3D_POLYLINE_SMOOTH_COLOR] = + { + .vert = datatoc_gpu_shader_3D_polyline_vert_glsl, + .geom = datatoc_gpu_shader_3D_polyline_geom_glsl, + .frag = datatoc_gpu_shader_3D_polyline_frag_glsl, + .defs = "#define SMOOTH\n", + }, + [GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR] = { .vert = datatoc_gpu_shader_2D_line_dashed_uniform_color_vert_glsl, @@ -1262,8 +1222,12 @@ GPUShader *GPU_shader_get_builtin_shader_with_config(eGPUBuiltinShader shader, /* common case */ if (sh_cfg == GPU_SHADER_CFG_DEFAULT) { - *sh_p = GPU_shader_create( - stages->vert, stages->frag, stages->geom, NULL, stages->defs, __func__); + *sh_p = GPU_shader_create_from_arrays({ + .vert = (const char *[]){stages->vert, NULL}, + .geom = (const char *[]){stages->geom, NULL}, + .frag = (const char *[]){datatoc_gpu_shader_colorspace_lib_glsl, stages->frag, NULL}, + .defs = (const char *[]){stages->defs, NULL}, + }); } else if (sh_cfg == GPU_SHADER_CFG_CLIPPED) { /* Remove eventually, for now ensure support for each shader has been added. */ @@ -1282,7 +1246,7 @@ GPUShader *GPU_shader_get_builtin_shader_with_config(eGPUBuiltinShader shader, *sh_p = GPU_shader_create_from_arrays({ .vert = (const char *[]){world_clip_lib, stages->vert, NULL}, .geom = (const char *[]){stages->geom ? world_clip_lib : NULL, stages->geom, NULL}, - .frag = (const char *[]){stages->frag, NULL}, + .frag = (const char *[]){datatoc_gpu_shader_colorspace_lib_glsl, stages->frag, NULL}, .defs = (const char *[]){world_clip_def, stages->defs, NULL}, }); } diff --git a/source/blender/gpu/intern/gpu_shader_interface.c b/source/blender/gpu/intern/gpu_shader_interface.c index f23a0a438d6..9d9f98c6bb0 100644 --- a/source/blender/gpu/intern/gpu_shader_interface.c +++ b/source/blender/gpu/intern/gpu_shader_interface.c @@ -24,6 +24,10 @@ */ #include "BKE_global.h" + +#include "BLI_bitmap.h" +#include "BLI_math_base.h" + #include "MEM_guardedalloc.h" #include "GPU_shader_interface.h" @@ -36,7 +40,6 @@ #include <string.h> #define DEBUG_SHADER_INTERFACE 0 -#define DEBUG_SHADER_UNIFORMS 0 #if DEBUG_SHADER_INTERFACE # include <stdio.h> @@ -45,8 +48,6 @@ static const char *BuiltinUniform_name(GPUUniformBuiltin u) { static const char *names[] = { - [GPU_UNIFORM_NONE] = NULL, - [GPU_UNIFORM_MODEL] = "ModelMatrix", [GPU_UNIFORM_VIEW] = "ViewMatrix", [GPU_UNIFORM_MODELVIEW] = "ModelViewMatrix", @@ -68,14 +69,27 @@ static const char *BuiltinUniform_name(GPUUniformBuiltin u) [GPU_UNIFORM_BASE_INSTANCE] = "baseInstance", [GPU_UNIFORM_RESOURCE_CHUNK] = "resourceChunk", [GPU_UNIFORM_RESOURCE_ID] = "resourceId", + [GPU_UNIFORM_SRGB_TRANSFORM] = "srgbTarget", - [GPU_UNIFORM_CUSTOM] = NULL, [GPU_NUM_UNIFORMS] = NULL, }; return names[u]; } +static const char *BuiltinUniformBlock_name(GPUUniformBlockBuiltin u) +{ + static const char *names[] = { + [GPU_UNIFORM_BLOCK_VIEW] = "viewBlock", + [GPU_UNIFORM_BLOCK_MODEL] = "modelBlock", + [GPU_UNIFORM_BLOCK_INFO] = "infoBlock", + + [GPU_NUM_UNIFORM_BLOCKS] = NULL, + }; + + return names[u]; +} + GPU_INLINE bool match(const char *a, const char *b) { return strcmp(a, b) == 0; @@ -90,129 +104,136 @@ GPU_INLINE uint hash_string(const char *str) return i; } -GPU_INLINE void set_input_name(GPUShaderInterface *shaderface, - GPUShaderInput *input, - const char *name, - uint32_t name_len) +GPU_INLINE uint32_t set_input_name(GPUShaderInterface *shaderface, + GPUShaderInput *input, + char *name, + uint32_t name_len) { - input->name_offset = shaderface->name_buffer_offset; - input->name_hash = hash_string(name); - shaderface->name_buffer_offset += name_len + 1; /* include NULL terminator */ -} + /* remove "[0]" from array name */ + if (name[name_len - 1] == ']') { + name[name_len - 3] = '\0'; + name_len -= 3; + } -GPU_INLINE void shader_input_to_bucket(GPUShaderInput *input, - GPUShaderInput *buckets[GPU_NUM_SHADERINTERFACE_BUCKETS]) -{ - const uint bucket_index = input->name_hash % GPU_NUM_SHADERINTERFACE_BUCKETS; - input->next = buckets[bucket_index]; - buckets[bucket_index] = input; + input->name_offset = (uint32_t)(name - shaderface->name_buffer); + input->name_hash = hash_string(name); + return name_len + 1; /* include NULL terminator */ } -GPU_INLINE const GPUShaderInput *buckets_lookup( - GPUShaderInput *const buckets[GPU_NUM_SHADERINTERFACE_BUCKETS], - const char *name_buffer, - const char *name) +GPU_INLINE const GPUShaderInput *input_lookup(const GPUShaderInterface *shaderface, + const GPUShaderInput *const inputs, + const uint inputs_len, + const char *name) { const uint name_hash = hash_string(name); - const uint bucket_index = name_hash % GPU_NUM_SHADERINTERFACE_BUCKETS; - const GPUShaderInput *input = buckets[bucket_index]; - if (input == NULL) { - /* Requested uniform is not found at all. */ - return NULL; - } - /* Optimization bit: if there is no hash collision detected when constructing shader interface - * it means we can only request the single possible uniform. Surely, it's possible we request - * uniform which causes hash collision, but that will be detected in debug builds. */ - if (input->next == NULL) { - if (name_hash == input->name_hash) { -#if TRUST_NO_ONE - assert(match(name_buffer + input->name_offset, name)); -#endif - return input; - } - return NULL; - } - /* Work through possible collisions. */ - const GPUShaderInput *next = input; - while (next != NULL) { - input = next; - next = input->next; - if (input->name_hash != name_hash) { - continue; - } - if (match(name_buffer + input->name_offset, name)) { - return input; + /* Simple linear search for now. */ + for (int i = inputs_len - 1; i >= 0; i--) { + if (inputs[i].name_hash == name_hash) { + if ((i > 0) && UNLIKELY(inputs[i - 1].name_hash == name_hash)) { + /* Hash colision resolve. */ + for (; i >= 0 && inputs[i].name_hash == name_hash; i--) { + if (match(name, shaderface->name_buffer + inputs[i].name_offset)) { + return inputs + i; /* not found */ + } + } + return NULL; /* not found */ + } + else { + /* This is a bit dangerous since we could have a hash collision. + * where the asked uniform that does not exist has the same hash + * as a real uniform. */ + BLI_assert(match(name, shaderface->name_buffer + inputs[i].name_offset)); + return inputs + i; + } } } return NULL; /* not found */ } -GPU_INLINE void buckets_free(GPUShaderInput *buckets[GPU_NUM_SHADERINTERFACE_BUCKETS]) +/* Note that this modify the src array. */ +GPU_INLINE void sort_input_list(GPUShaderInput *dst, GPUShaderInput *src, const uint input_len) { - for (uint bucket_index = 0; bucket_index < GPU_NUM_SHADERINTERFACE_BUCKETS; bucket_index++) { - GPUShaderInput *input = buckets[bucket_index]; - while (input != NULL) { - GPUShaderInput *input_next = input->next; - MEM_freeN(input); - input = input_next; + for (uint i = 0; i < input_len; i++) { + GPUShaderInput *input_src = &src[0]; + for (uint j = 1; j < input_len; j++) { + if (src[j].name_hash > input_src->name_hash) { + input_src = &src[j]; + } } + dst[i] = *input_src; + input_src->name_hash = 0; } } -static bool setup_builtin_uniform(GPUShaderInput *input, const char *name) +static int block_binding(int32_t program, uint32_t block_index) { - /* TODO: reject DOUBLE, IMAGE, ATOMIC_COUNTER gl_types */ - - /* detect built-in uniforms (name must match) */ - for (GPUUniformBuiltin u = GPU_UNIFORM_NONE + 1; u < GPU_UNIFORM_CUSTOM; u++) { - const char *builtin_name = BuiltinUniform_name(u); - if (match(name, builtin_name)) { - input->builtin_type = u; - return true; - } - } - input->builtin_type = GPU_UNIFORM_CUSTOM; - return false; + /* For now just assign a consecutive index. In the future, we should set it in + * the shader using layout(binding = i) and query its value. */ + glUniformBlockBinding(program, block_index, block_index); + return block_index; } -static const GPUShaderInput *add_uniform(GPUShaderInterface *shaderface, const char *name) +static int sampler_binding(int32_t program, + uint32_t uniform_index, + int32_t uniform_location, + int *sampler_len) { - GPUShaderInput *input = MEM_mallocN(sizeof(GPUShaderInput), "GPUShaderInput Unif"); - - input->location = glGetUniformLocation(shaderface->program, name); - - const uint name_len = strlen(name); - /* Include NULL terminator. */ - shaderface->name_buffer = MEM_reallocN(shaderface->name_buffer, - shaderface->name_buffer_offset + name_len + 1); - char *name_buffer = shaderface->name_buffer + shaderface->name_buffer_offset; - strcpy(name_buffer, name); - - set_input_name(shaderface, input, name, name_len); - setup_builtin_uniform(input, name); - - shader_input_to_bucket(input, shaderface->uniform_buckets); - if (input->builtin_type != GPU_UNIFORM_NONE && input->builtin_type != GPU_UNIFORM_CUSTOM) { - shaderface->builtin_uniforms[input->builtin_type] = input; + /* Identify sampler uniforms and asign sampler units to them. */ + GLint type; + glGetActiveUniformsiv(program, 1, &uniform_index, GL_UNIFORM_TYPE, &type); + + switch (type) { + case GL_SAMPLER_1D: + case GL_SAMPLER_2D: + case GL_SAMPLER_3D: + case GL_SAMPLER_CUBE: + case GL_SAMPLER_CUBE_MAP_ARRAY_ARB: /* OpenGL 4.0 */ + case GL_SAMPLER_1D_SHADOW: + case GL_SAMPLER_2D_SHADOW: + case GL_SAMPLER_1D_ARRAY: + case GL_SAMPLER_2D_ARRAY: + case GL_SAMPLER_1D_ARRAY_SHADOW: + case GL_SAMPLER_2D_ARRAY_SHADOW: + case GL_SAMPLER_2D_MULTISAMPLE: + case GL_SAMPLER_2D_MULTISAMPLE_ARRAY: + case GL_SAMPLER_CUBE_SHADOW: + case GL_SAMPLER_BUFFER: + case GL_INT_SAMPLER_1D: + case GL_INT_SAMPLER_2D: + case GL_INT_SAMPLER_3D: + case GL_INT_SAMPLER_CUBE: + case GL_INT_SAMPLER_1D_ARRAY: + case GL_INT_SAMPLER_2D_ARRAY: + case GL_INT_SAMPLER_2D_MULTISAMPLE: + case GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY: + case GL_INT_SAMPLER_BUFFER: + case GL_UNSIGNED_INT_SAMPLER_1D: + case GL_UNSIGNED_INT_SAMPLER_2D: + case GL_UNSIGNED_INT_SAMPLER_3D: + case GL_UNSIGNED_INT_SAMPLER_CUBE: + case GL_UNSIGNED_INT_SAMPLER_1D_ARRAY: + case GL_UNSIGNED_INT_SAMPLER_2D_ARRAY: + case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE: + case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY: + case GL_UNSIGNED_INT_SAMPLER_BUFFER: { + /* For now just assign a consecutive index. In the future, we should set it in + * the shader using layout(binding = i) and query its value. */ + int binding = *sampler_len; + glUniform1i(uniform_location, binding); + (*sampler_len)++; + return binding; + } + default: + return -1; } -#if DEBUG_SHADER_INTERFACE - printf("GPUShaderInterface %p, program %d, uniform[] '%s' at location %d\n", - shaderface, - shaderface->program, - name, - input->location); -#endif - return input; } GPUShaderInterface *GPU_shaderinterface_create(int32_t program) { - GPUShaderInterface *shaderface = MEM_callocN(sizeof(GPUShaderInterface), "GPUShaderInterface"); - shaderface->program = program; - -#if DEBUG_SHADER_INTERFACE - printf("%s {\n", __func__); /* enter function */ - printf("GPUShaderInterface %p, program %d\n", shaderface, program); +#ifndef NDEBUG + GLint curr_program; + glGetIntegerv(GL_CURRENT_PROGRAM, &curr_program); + BLI_assert(curr_program == program); #endif GLint max_attr_name_len = 0, attr_len = 0; @@ -223,6 +244,11 @@ GPUShaderInterface *GPU_shaderinterface_create(int32_t program) glGetProgramiv(program, GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH, &max_ubo_name_len); glGetProgramiv(program, GL_ACTIVE_UNIFORM_BLOCKS, &ubo_len); + GLint max_uniform_name_len = 0, active_uniform_len = 0, uniform_len = 0; + glGetProgramiv(program, GL_ACTIVE_UNIFORM_MAX_LENGTH, &max_uniform_name_len); + glGetProgramiv(program, GL_ACTIVE_UNIFORMS, &active_uniform_len); + uniform_len = active_uniform_len; + /* Work around driver bug with Intel HD 4600 on Windows 7/8, where * GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH does not work. */ if (attr_len > 0 && max_attr_name_len == 0) { @@ -231,78 +257,190 @@ GPUShaderInterface *GPU_shaderinterface_create(int32_t program) if (ubo_len > 0 && max_ubo_name_len == 0) { max_ubo_name_len = 256; } + if (uniform_len > 0 && max_uniform_name_len == 0) { + max_uniform_name_len = 256; + } - const uint32_t name_buffer_len = attr_len * max_attr_name_len + ubo_len * max_ubo_name_len; - shaderface->name_buffer = MEM_mallocN(name_buffer_len, "name_buffer"); - - /* Attributes */ - for (uint32_t i = 0; i < attr_len; i++) { - GPUShaderInput *input = MEM_mallocN(sizeof(GPUShaderInput), "GPUShaderInput Attr"); - GLsizei remaining_buffer = name_buffer_len - shaderface->name_buffer_offset; - char *name = shaderface->name_buffer + shaderface->name_buffer_offset; - GLsizei name_len = 0; + /* GL_ACTIVE_UNIFORMS lied to us! Remove the UBO uniforms from the total before + * allocating the uniform array. */ + GLint max_ubo_uni_len = 0; + for (int i = 0; i < ubo_len; i++) { + GLint ubo_uni_len; + glGetActiveUniformBlockiv(program, i, GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS, &ubo_uni_len); + max_ubo_uni_len = max_ii(max_ubo_uni_len, ubo_uni_len); + uniform_len -= ubo_uni_len; + } + /* Bit set to true if uniform comes from a uniform block. */ + BLI_bitmap *uniforms_from_blocks = BLI_BITMAP_NEW(active_uniform_len, __func__); + /* Set uniforms from block for exclusion. */ + GLint *ubo_uni_ids = MEM_mallocN(sizeof(GLint) * max_ubo_uni_len, __func__); + for (int i = 0; i < ubo_len; i++) { + GLint ubo_uni_len; + glGetActiveUniformBlockiv(program, i, GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS, &ubo_uni_len); + glGetActiveUniformBlockiv(program, i, GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES, ubo_uni_ids); + for (int u = 0; u < ubo_uni_len; u++) { + BLI_BITMAP_ENABLE(uniforms_from_blocks, ubo_uni_ids[u]); + } + } + MEM_freeN(ubo_uni_ids); - glGetActiveAttrib( - program, i, remaining_buffer, &name_len, &input->size, &input->gl_type, name); + uint32_t name_buffer_offset = 0; + const uint32_t name_buffer_len = attr_len * max_attr_name_len + ubo_len * max_ubo_name_len + + uniform_len * max_uniform_name_len; - /* remove "[0]" from array name */ - if (name[name_len - 1] == ']') { - name[name_len - 3] = '\0'; - name_len -= 3; - } + int input_tot_len = attr_len + ubo_len + uniform_len; + size_t interface_size = sizeof(GPUShaderInterface) + sizeof(GPUShaderInput) * input_tot_len; - /* TODO: reject DOUBLE gl_types */ + GPUShaderInterface *shaderface = MEM_callocN(interface_size, "GPUShaderInterface"); + shaderface->attribute_len = attr_len; + shaderface->ubo_len = ubo_len; + shaderface->uniform_len = uniform_len; + shaderface->name_buffer = MEM_mallocN(name_buffer_len, "name_buffer"); + GPUShaderInput *inputs = shaderface->inputs; - input->location = glGetAttribLocation(program, name); + /* Temp buffer. */ + int input_tmp_len = max_iii(attr_len, ubo_len, uniform_len); + GPUShaderInput *inputs_tmp = MEM_mallocN(sizeof(GPUShaderInput) * input_tmp_len, "name_buffer"); - set_input_name(shaderface, input, name, name_len); + /* Attributes */ + shaderface->enabled_attr_mask = 0; + for (int i = 0, idx = 0; i < attr_len; i++) { + char *name = shaderface->name_buffer + name_buffer_offset; + GLsizei remaining_buffer = name_buffer_len - name_buffer_offset; + GLsizei name_len = 0; + GLenum type; + GLint size; + + glGetActiveAttrib(program, i, remaining_buffer, &name_len, &size, &type, name); + GLint location = glGetAttribLocation(program, name); + /* Ignore OpenGL names like `gl_BaseInstanceARB`, `gl_InstanceID` and `gl_VertexID`. */ + if (location == -1) { + shaderface->attribute_len--; + continue; + } - shader_input_to_bucket(input, shaderface->attr_buckets); + GPUShaderInput *input = &inputs_tmp[idx++]; + input->location = input->binding = location; -#if DEBUG_SHADER_INTERFACE - printf("attr[%u] '%s' at location %d\n", i, name, input->location); -#endif + name_buffer_offset += set_input_name(shaderface, input, name, name_len); + shaderface->enabled_attr_mask |= (1 << input->location); } + sort_input_list(inputs, inputs_tmp, shaderface->attribute_len); + inputs += shaderface->attribute_len; + /* Uniform Blocks */ - for (uint32_t i = 0; i < ubo_len; i++) { - GPUShaderInput *input = MEM_mallocN(sizeof(GPUShaderInput), "GPUShaderInput UBO"); - GLsizei remaining_buffer = name_buffer_len - shaderface->name_buffer_offset; - char *name = shaderface->name_buffer + shaderface->name_buffer_offset; + for (int i = 0, idx = 0; i < ubo_len; i++) { + char *name = shaderface->name_buffer + name_buffer_offset; + GLsizei remaining_buffer = name_buffer_len - name_buffer_offset; GLsizei name_len = 0; glGetActiveUniformBlockName(program, i, remaining_buffer, &name_len, name); - input->location = i; + GPUShaderInput *input = &inputs_tmp[idx++]; + input->binding = input->location = block_binding(program, i); - set_input_name(shaderface, input, name, name_len); + name_buffer_offset += set_input_name(shaderface, input, name, name_len); + shaderface->enabled_ubo_mask |= (1 << input->binding); + } + sort_input_list(inputs, inputs_tmp, shaderface->ubo_len); + inputs += shaderface->ubo_len; - shader_input_to_bucket(input, shaderface->ubo_buckets); + /* Uniforms */ + for (int i = 0, idx = 0, sampler = 0; i < active_uniform_len; i++) { + if (BLI_BITMAP_TEST(uniforms_from_blocks, i)) { + continue; + } + char *name = shaderface->name_buffer + name_buffer_offset; + GLsizei remaining_buffer = name_buffer_len - name_buffer_offset; + GLsizei name_len = 0; -#if DEBUG_SHADER_INTERFACE - printf("ubo '%s' at location %d\n", name, input->location); -#endif + glGetActiveUniformName(program, i, remaining_buffer, &name_len, name); + + GPUShaderInput *input = &inputs_tmp[idx++]; + input->location = glGetUniformLocation(program, name); + input->binding = sampler_binding(program, i, input->location, &sampler); + + name_buffer_offset += set_input_name(shaderface, input, name, name_len); + shaderface->enabled_tex_mask |= (input->binding != -1) ? (1lu << input->binding) : 0lu; } + sort_input_list(inputs, inputs_tmp, shaderface->uniform_len); + /* Builtin Uniforms */ - for (GPUUniformBuiltin u = GPU_UNIFORM_NONE + 1; u < GPU_UNIFORM_CUSTOM; u++) { - const char *builtin_name = BuiltinUniform_name(u); - if (glGetUniformLocation(program, builtin_name) != -1) { - add_uniform((GPUShaderInterface *)shaderface, builtin_name); - } + for (GPUUniformBuiltin u = 0; u < GPU_NUM_UNIFORMS; u++) { + shaderface->builtins[u] = glGetUniformLocation(program, BuiltinUniform_name(u)); } + + /* Builtin Uniforms Blocks */ + for (GPUUniformBlockBuiltin u = 0; u < GPU_NUM_UNIFORM_BLOCKS; u++) { + const GPUShaderInput *block = GPU_shaderinterface_ubo(shaderface, BuiltinUniformBlock_name(u)); + shaderface->builtin_blocks[u] = (block != NULL) ? block->binding : -1; + } + /* Batches ref buffer */ shaderface->batches_len = GPU_SHADERINTERFACE_REF_ALLOC_COUNT; shaderface->batches = MEM_callocN(shaderface->batches_len * sizeof(GPUBatch *), "GPUShaderInterface batches"); + MEM_freeN(uniforms_from_blocks); + MEM_freeN(inputs_tmp); + + /* Resize name buffer to save some memory. */ + if (name_buffer_offset < name_buffer_len) { + shaderface->name_buffer = MEM_reallocN(shaderface->name_buffer, name_buffer_offset); + } + +#if DEBUG_SHADER_INTERFACE + char *name_buf = shaderface->name_buffer; + printf("--- GPUShaderInterface %p, program %d ---\n", shaderface, program); + if (shaderface->attribute_len > 0) { + printf("Attributes {\n"); + for (int i = 0; i < shaderface->attribute_len; i++) { + GPUShaderInput *input = shaderface->inputs + i; + printf("\t(location = %d) %s;\n", input->location, name_buf + input->name_offset); + } + printf("};\n"); + } + if (shaderface->ubo_len > 0) { + printf("Uniform Buffer Objects {\n"); + for (int i = 0; i < shaderface->ubo_len; i++) { + GPUShaderInput *input = shaderface->inputs + shaderface->attribute_len + i; + printf("\t(binding = %d) %s;\n", input->binding, name_buf + input->name_offset); + } + printf("};\n"); + } + if (shaderface->enabled_tex_mask > 0) { + printf("Samplers {\n"); + for (int i = 0; i < shaderface->uniform_len; i++) { + GPUShaderInput *input = shaderface->inputs + shaderface->attribute_len + + shaderface->ubo_len + i; + if (input->binding != -1) { + printf("\t(location = %d, binding = %d) %s;\n", + input->location, + input->binding, + name_buf + input->name_offset); + } + } + printf("};\n"); + } + if (shaderface->uniform_len > 0) { + printf("Uniforms {\n"); + for (int i = 0; i < shaderface->uniform_len; i++) { + GPUShaderInput *input = shaderface->inputs + shaderface->attribute_len + + shaderface->ubo_len + i; + if (input->binding == -1) { + printf("\t(location = %d) %s;\n", input->location, name_buf + input->name_offset); + } + } + printf("};\n"); + } + printf("--- GPUShaderInterface end ---\n\n"); +#endif + return shaderface; } void GPU_shaderinterface_discard(GPUShaderInterface *shaderface) { - /* Free memory used by buckets and has entries. */ - buckets_free(shaderface->uniform_buckets); - buckets_free(shaderface->attr_buckets); - buckets_free(shaderface->ubo_buckets); /* Free memory used by name_buffer. */ MEM_freeN(shaderface->name_buffer); /* Remove this interface from all linked Batches vao cache. */ @@ -316,59 +454,39 @@ void GPU_shaderinterface_discard(GPUShaderInterface *shaderface) MEM_freeN(shaderface); } -const GPUShaderInput *GPU_shaderinterface_uniform(const GPUShaderInterface *shaderface, - const char *name) +const GPUShaderInput *GPU_shaderinterface_attr(const GPUShaderInterface *shaderface, + const char *name) { - return buckets_lookup(shaderface->uniform_buckets, shaderface->name_buffer, name); + uint ofs = 0; + return input_lookup(shaderface, shaderface->inputs + ofs, shaderface->attribute_len, name); } -const GPUShaderInput *GPU_shaderinterface_uniform_ensure(const GPUShaderInterface *shaderface, - const char *name) +const GPUShaderInput *GPU_shaderinterface_ubo(const GPUShaderInterface *shaderface, + const char *name) { - const GPUShaderInput *input = GPU_shaderinterface_uniform(shaderface, name); - /* If input is not found add it so it's found next time. */ - if (input == NULL) { - input = add_uniform((GPUShaderInterface *)shaderface, name); - - if ((G.debug & G_DEBUG_GPU) && (input->location == -1)) { - fprintf(stderr, "GPUShaderInterface: Warning: Uniform '%s' not found!\n", name); - } - } - -#if DEBUG_SHADER_UNIFORMS - if ((G.debug & G_DEBUG_GPU) && input->builtin_type != GPU_UNIFORM_NONE && - input->builtin_type != GPU_UNIFORM_CUSTOM) { - /* Warn if we find a matching builtin, since these can be looked up much quicker. */ - fprintf(stderr, - "GPUShaderInterface: Warning: Uniform '%s' is a builtin uniform but not queried as " - "such!\n", - name); - } -#endif - return (input->location != -1) ? input : NULL; + uint ofs = shaderface->attribute_len; + return input_lookup(shaderface, shaderface->inputs + ofs, shaderface->ubo_len, name); } -const GPUShaderInput *GPU_shaderinterface_uniform_builtin(const GPUShaderInterface *shaderface, - GPUUniformBuiltin builtin) +const GPUShaderInput *GPU_shaderinterface_uniform(const GPUShaderInterface *shaderface, + const char *name) { -#if TRUST_NO_ONE - assert(builtin != GPU_UNIFORM_NONE); - assert(builtin != GPU_UNIFORM_CUSTOM); - assert(builtin != GPU_NUM_UNIFORMS); -#endif - return shaderface->builtin_uniforms[builtin]; + uint ofs = shaderface->attribute_len + shaderface->ubo_len; + return input_lookup(shaderface, shaderface->inputs + ofs, shaderface->uniform_len, name); } -const GPUShaderInput *GPU_shaderinterface_ubo(const GPUShaderInterface *shaderface, - const char *name) +int32_t GPU_shaderinterface_uniform_builtin(const GPUShaderInterface *shaderface, + GPUUniformBuiltin builtin) { - return buckets_lookup(shaderface->ubo_buckets, shaderface->name_buffer, name); + BLI_assert(builtin >= 0 && builtin < GPU_NUM_UNIFORMS); + return shaderface->builtins[builtin]; } -const GPUShaderInput *GPU_shaderinterface_attr(const GPUShaderInterface *shaderface, - const char *name) +int32_t GPU_shaderinterface_block_builtin(const GPUShaderInterface *shaderface, + GPUUniformBlockBuiltin builtin) { - return buckets_lookup(shaderface->attr_buckets, shaderface->name_buffer, name); + BLI_assert(builtin >= 0 && builtin < GPU_NUM_UNIFORM_BLOCKS); + return shaderface->builtin_blocks[builtin]; } void GPU_shaderinterface_add_batch_ref(GPUShaderInterface *shaderface, GPUBatch *batch) diff --git a/source/blender/gpu/intern/gpu_state.c b/source/blender/gpu/intern/gpu_state.c index d6f044a79e3..908f5fa5771 100644 --- a/source/blender/gpu/intern/gpu_state.c +++ b/source/blender/gpu/intern/gpu_state.c @@ -370,4 +370,44 @@ void gpuPopAttr(void) #undef Attr #undef AttrStack +/* Default OpenGL State + * + * This is called on startup, for opengl offscreen render. + * Generally we should always return to this state when + * temporarily modifying the state for drawing, though that are (undocumented) + * exceptions that we should try to get rid of. */ + +void GPU_state_init(void) +{ + GPU_program_point_size(false); + + glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS); + + glDisable(GL_BLEND); + glDisable(GL_DEPTH_TEST); + glDisable(GL_COLOR_LOGIC_OP); + glDisable(GL_STENCIL_TEST); + glDisable(GL_DITHER); + + glDepthFunc(GL_LEQUAL); + glDepthRange(0.0, 1.0); + + glFrontFace(GL_CCW); + glCullFace(GL_BACK); + glDisable(GL_CULL_FACE); + + /* Is default but better be explicit. */ + glEnable(GL_MULTISAMPLE); + + /* This is a bit dangerous since addons could change this. */ + glEnable(GL_PRIMITIVE_RESTART); + glPrimitiveRestartIndex((GLuint)0xFFFFFFFF); + + /* TODO: Should become default. But needs at least GL 4.3 */ + if (GLEW_ARB_ES3_compatibility) { + /* Takes predecence over GL_PRIMITIVE_RESTART */ + glEnable(GL_PRIMITIVE_RESTART_FIXED_INDEX); + } +} + /** \} */ diff --git a/source/blender/gpu/intern/gpu_texture.c b/source/blender/gpu/intern/gpu_texture.c index 075a8e8aeb5..ca0d633aa9e 100644 --- a/source/blender/gpu/intern/gpu_texture.c +++ b/source/blender/gpu/intern/gpu_texture.c @@ -50,7 +50,9 @@ static struct GPUTextureGlobal { GPUTexture *invalid_tex_1D; GPUTexture *invalid_tex_2D; GPUTexture *invalid_tex_3D; -} GG = {NULL, NULL, NULL}; + /** Sampler objects used to replace internal texture parameters. */ + GLuint samplers[GPU_SAMPLER_MAX]; +} GG = {NULL}; /* Maximum number of FBOs a texture can be attached to. */ #define GPU_TEX_MAX_FBO_ATTACHED 12 @@ -72,7 +74,7 @@ typedef enum eGPUTextureFormatFlag { struct GPUTexture { int w, h, d; /* width/height/depth */ int orig_w, orig_h; /* width/height (of source data), optional. */ - int number; /* number for multitexture binding */ + int number; /* Texture unit to which this texture is bound. */ int refcount; /* reference count */ GLenum target; /* GL_TEXTURE_* */ GLenum target_base; /* same as target, (but no multisample) @@ -81,6 +83,7 @@ struct GPUTexture { eGPUTextureFormat format; eGPUTextureFormatFlag format_flag; + eGPUSamplerState sampler_state; /* Internal Sampler state. */ int mipmaps; /* number of mipmaps */ int components; /* number of color/alpha channels */ @@ -88,9 +91,13 @@ struct GPUTexture { int fb_attachment[GPU_TEX_MAX_FBO_ATTACHED]; GPUFrameBuffer *fb[GPU_TEX_MAX_FBO_ATTACHED]; + /* Legacy workaround for texture copy. */ + GLuint copy_fb; + GPUContext *copy_fb_ctx; }; static uint gpu_get_bytesize(eGPUTextureFormat data_type); +static void gpu_texture_framebuffer_ensure(GPUTexture *tex); /* ------ Memory Management ------- */ /* Records every texture allocation / free @@ -165,26 +172,33 @@ static const char *gl_enum_to_str(GLenum e) ENUM_TO_STRING(TEXTURE_2D_MULTISAMPLE), ENUM_TO_STRING(RGBA32F), ENUM_TO_STRING(RGBA16F), + ENUM_TO_STRING(RGBA16UI), + ENUM_TO_STRING(RGBA16I), ENUM_TO_STRING(RGBA16), - ENUM_TO_STRING(RG32F), + ENUM_TO_STRING(RGBA8UI), + ENUM_TO_STRING(RGBA8I), + ENUM_TO_STRING(RGBA8), ENUM_TO_STRING(RGB16F), + ENUM_TO_STRING(RG32F), ENUM_TO_STRING(RG16F), + ENUM_TO_STRING(RG16UI), ENUM_TO_STRING(RG16I), ENUM_TO_STRING(RG16), - ENUM_TO_STRING(RGBA8), - ENUM_TO_STRING(RGBA8UI), + ENUM_TO_STRING(RG8UI), + ENUM_TO_STRING(RG8I), + ENUM_TO_STRING(RG8), + ENUM_TO_STRING(R8UI), + ENUM_TO_STRING(R8I), + ENUM_TO_STRING(R8), ENUM_TO_STRING(R32F), ENUM_TO_STRING(R32UI), ENUM_TO_STRING(R32I), ENUM_TO_STRING(R16F), - ENUM_TO_STRING(R16I), ENUM_TO_STRING(R16UI), - ENUM_TO_STRING(RG8), - ENUM_TO_STRING(RG16UI), + ENUM_TO_STRING(R16I), ENUM_TO_STRING(R16), - ENUM_TO_STRING(R8), - ENUM_TO_STRING(R8UI), ENUM_TO_STRING(R11F_G11F_B10F), + ENUM_TO_STRING(SRGB8_ALPHA8), ENUM_TO_STRING(DEPTH24_STENCIL8), ENUM_TO_STRING(DEPTH32F_STENCIL8), ENUM_TO_STRING(DEPTH_COMPONENT32F), @@ -457,7 +471,7 @@ static GLenum gpu_format_to_gl_internalformat(eGPUTextureFormat format) case GPU_RG16I: return GL_RG16I; case GPU_RG16F: - return GL_RGBA32F; + return GL_RG16F; case GPU_RG16: return GL_RG16; case GPU_R8UI: @@ -816,12 +830,12 @@ GPUTexture *GPU_texture_create_nD(int w, tex->h = h; tex->d = d; tex->samples = samples; - tex->number = -1; tex->refcount = 1; tex->format = tex_format; tex->components = gpu_get_component_count(tex_format); tex->mipmaps = 0; tex->format_flag = 0; + tex->number = -1; if (n == 2) { if (d == 0) { @@ -965,26 +979,13 @@ GPUTexture *GPU_texture_create_nD(int w, if (GPU_texture_stencil(tex) || /* Does not support filtering */ GPU_texture_integer(tex) || /* Does not support filtering */ GPU_texture_depth(tex)) { - glTexParameteri(tex->target_base, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(tex->target_base, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + tex->sampler_state = GPU_SAMPLER_DEFAULT & ~GPU_SAMPLER_FILTER; } else { - glTexParameteri(tex->target_base, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(tex->target_base, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - } - - if (GPU_texture_depth(tex)) { - glTexParameteri(tex->target_base, GL_TEXTURE_COMPARE_MODE, GL_NONE); - glTexParameteri(tex->target_base, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL); - } - - glTexParameteri(tex->target_base, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - if (n > 1) { - glTexParameteri(tex->target_base, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - } - if (n > 2) { - glTexParameteri(tex->target_base, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); + tex->sampler_state = GPU_SAMPLER_DEFAULT; } + /* Avoid issue with incomplete textures. */ + glTexParameteri(tex->target_base, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glBindTexture(tex->target, 0); @@ -1003,12 +1004,12 @@ GPUTexture *GPU_texture_cube_create(int w, tex->h = w; tex->d = d; tex->samples = 0; - tex->number = -1; tex->refcount = 1; tex->format = tex_format; tex->components = gpu_get_component_count(tex_format); tex->mipmaps = 0; tex->format_flag = GPU_FORMAT_CUBE; + tex->number = -1; if (d == 0) { tex->target_base = tex->target = GL_TEXTURE_CUBE_MAP; @@ -1106,22 +1107,13 @@ GPUTexture *GPU_texture_cube_create(int w, if (GPU_texture_stencil(tex) || /* Does not support filtering */ GPU_texture_integer(tex) || /* Does not support filtering */ GPU_texture_depth(tex)) { - glTexParameteri(tex->target_base, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(tex->target_base, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + tex->sampler_state = GPU_SAMPLER_DEFAULT & ~GPU_SAMPLER_FILTER; } else { - glTexParameteri(tex->target_base, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(tex->target_base, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - } - - if (GPU_texture_depth(tex)) { - glTexParameteri(tex->target_base, GL_TEXTURE_COMPARE_MODE, GL_NONE); - glTexParameteri(tex->target_base, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL); + tex->sampler_state = GPU_SAMPLER_DEFAULT; } - - glTexParameteri(tex->target_base, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(tex->target_base, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTexParameteri(tex->target_base, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); + /* Avoid issue with incomplete textures. */ + glTexParameteri(tex->target_base, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glBindTexture(tex->target, 0); @@ -1132,13 +1124,13 @@ GPUTexture *GPU_texture_cube_create(int w, GPUTexture *GPU_texture_create_buffer(eGPUTextureFormat tex_format, const GLuint buffer) { GPUTexture *tex = MEM_callocN(sizeof(GPUTexture), "GPUTexture"); - tex->number = -1; tex->refcount = 1; tex->format = tex_format; tex->components = gpu_get_component_count(tex_format); tex->format_flag = 0; tex->target_base = tex->target = GL_TEXTURE_BUFFER; tex->mipmaps = 0; + tex->number = -1; GLenum internalformat = gpu_format_to_gl_internalformat(tex_format); @@ -1185,11 +1177,15 @@ GPUTexture *GPU_texture_from_bindcode(int textarget, int bindcode) { GPUTexture *tex = MEM_callocN(sizeof(GPUTexture), "GPUTexture"); tex->bindcode = bindcode; - tex->number = -1; tex->refcount = 1; tex->target = textarget; tex->target_base = textarget; tex->samples = 0; + tex->sampler_state = GPU_SAMPLER_REPEAT | GPU_SAMPLER_ANISO; + if (GPU_get_mipmap()) { + tex->sampler_state |= (GPU_SAMPLER_MIPMAP | GPU_SAMPLER_FILTER); + } + tex->number = -1; if (!glIsTexture(tex->bindcode)) { GPU_print_error_debug("Blender Texture Not Loaded"); @@ -1560,25 +1556,117 @@ void *GPU_texture_read(GPUTexture *tex, eGPUDataFormat gpu_data_format, int mipl void GPU_texture_clear(GPUTexture *tex, eGPUDataFormat gpu_data_format, const void *color) { - if (GLEW_ARB_clear_texture) { - GLenum data_format = gpu_get_gl_dataformat(tex->format, &tex->format_flag); + BLI_assert(color != NULL); /* Do not accept NULL as parameter. */ + gpu_validate_data_format(tex->format, gpu_data_format); + + if (false && GLEW_ARB_clear_texture) { GLenum data_type = gpu_get_gl_datatype(gpu_data_format); + GLenum data_format = gpu_get_gl_dataformat(tex->format, &tex->format_flag); glClearTexImage(tex->bindcode, 0, data_format, data_type, color); + + if (GPU_texture_stencil(tex) && GPU_texture_depth(tex)) { + /* TODO(clem) implement in fallback. */ + BLI_assert(0); + } + else if (GPU_texture_depth(tex)) { + switch (gpu_data_format) { + case GPU_DATA_FLOAT: + case GPU_DATA_UNSIGNED_INT: + break; + default: + /* TODO(clem) implement in fallback. */ + BLI_assert(0); + break; + } + } + else { + switch (gpu_data_format) { + case GPU_DATA_FLOAT: + case GPU_DATA_UNSIGNED_INT: + case GPU_DATA_UNSIGNED_BYTE: + break; + default: + /* TODO(clem) implement in fallback. */ + BLI_assert(0); + break; + } + } } else { - size_t buffer_len = gpu_texture_memory_footprint_compute(tex); - unsigned char *pixels = MEM_mallocN(buffer_len, __func__); - if (color) { - const size_t bytesize = (size_t)gpu_get_bytesize(tex->format); - for (size_t byte = 0; byte < buffer_len; byte += bytesize) { - memcpy(&pixels[byte], color, bytesize); + /* Fallback for older GL. */ + GPUFrameBuffer *prev_fb = GPU_framebuffer_active_get(); + + gpu_texture_framebuffer_ensure(tex); + /* This means that this function can only be used in one context for each texture. */ + BLI_assert(tex->copy_fb_ctx == GPU_context_active_get()); + + glBindFramebuffer(GL_FRAMEBUFFER, tex->copy_fb); + glViewport(0, 0, tex->w, tex->h); + + /* Watch: Write mask could prevent the clear. + * glClearTexImage does not change the state so we don't do it here either. */ + if (GPU_texture_stencil(tex) && GPU_texture_depth(tex)) { + /* TODO(clem) implement. */ + BLI_assert(0); + } + else if (GPU_texture_depth(tex)) { + float depth; + switch (gpu_data_format) { + case GPU_DATA_FLOAT: { + depth = *(float *)color; + break; + } + case GPU_DATA_UNSIGNED_INT: { + depth = *(uint *)color / (float)UINT_MAX; + break; + } + default: + BLI_assert(!"Unhandled data format"); + depth = 0.0f; + break; } + glClearDepth(depth); + glClear(GL_DEPTH_BUFFER_BIT); } else { - memset(pixels, 0, buffer_len); + float r, g, b, a; + switch (gpu_data_format) { + case GPU_DATA_FLOAT: { + float *f_color = (float *)color; + r = f_color[0]; + g = (tex->components > 1) ? f_color[1] : 0.0f; + b = (tex->components > 2) ? f_color[2] : 0.0f; + a = (tex->components > 3) ? f_color[3] : 0.0f; + break; + } + case GPU_DATA_UNSIGNED_INT: { + uint *u_color = (uint *)color; + r = u_color[0] / (float)UINT_MAX; + g = (tex->components > 1) ? u_color[1] / (float)UINT_MAX : 0.0f; + b = (tex->components > 2) ? u_color[2] / (float)UINT_MAX : 0.0f; + a = (tex->components > 3) ? u_color[3] / (float)UINT_MAX : 0.0f; + break; + } + case GPU_DATA_UNSIGNED_BYTE: { + uchar *ub_color = (uchar *)color; + r = ub_color[0] / 255.0f; + g = (tex->components > 1) ? ub_color[1] / 255.0f : 0.0f; + b = (tex->components > 2) ? ub_color[2] / 255.0f : 0.0f; + a = (tex->components > 3) ? ub_color[3] / 255.0f : 0.0f; + break; + } + default: + BLI_assert(!"Unhandled data format"); + r = g = b = a = 0.0f; + break; + } + glClearColor(r, g, b, a); + glClear(GL_COLOR_BUFFER_BIT); + } + + if (prev_fb) { + GPU_framebuffer_bind(prev_fb); } - GPU_texture_update(tex, gpu_data_format, pixels); - MEM_freeN(pixels); } } @@ -1624,16 +1712,17 @@ void GPU_invalid_tex_free(void) } } -void GPU_texture_bind(GPUTexture *tex, int number) +/* set_number is to save the the texture unit for setting texture parameters. */ +void GPU_texture_bind_ex(GPUTexture *tex, eGPUSamplerState state, int unit, const bool set_number) { - BLI_assert(number >= 0); + BLI_assert(unit >= 0); - if (number >= GPU_max_textures()) { + if (unit >= GPU_max_textures()) { fprintf(stderr, "Not enough texture slots.\n"); return; } - if ((G.debug & G_DEBUG)) { + if (G.debug & G_DEBUG) { for (int i = 0; i < GPU_TEX_MAX_FBO_ATTACHED; i++) { if (tex->fb[i] && GPU_framebuffer_bound(tex->fb[i])) { fprintf(stderr, @@ -1645,16 +1734,27 @@ void GPU_texture_bind(GPUTexture *tex, int number) } } - glActiveTexture(GL_TEXTURE0 + number); + if (set_number) { + tex->number = unit; + } + + glActiveTexture(GL_TEXTURE0 + unit); + + state = (state < GPU_SAMPLER_MAX) ? state : tex->sampler_state; if (tex->bindcode != 0) { glBindTexture(tex->target, tex->bindcode); + glBindSampler(unit, GG.samplers[state]); } else { GPU_invalid_tex_bind(tex->target_base); + glBindSampler(unit, 0); } +} - tex->number = number; +void GPU_texture_bind(GPUTexture *tex, int unit) +{ + GPU_texture_bind_ex(tex, GPU_SAMPLER_MAX, unit, true); } void GPU_texture_unbind(GPUTexture *tex) @@ -1665,13 +1765,34 @@ void GPU_texture_unbind(GPUTexture *tex) glActiveTexture(GL_TEXTURE0 + tex->number); glBindTexture(tex->target, 0); - + glBindSampler(tex->number, 0); tex->number = -1; } -int GPU_texture_bound_number(GPUTexture *tex) +void GPU_texture_unbind_all(void) { - return tex->number; + if (GLEW_ARB_multi_bind) { + glBindTextures(0, GPU_max_textures(), NULL); + glBindSamplers(0, GPU_max_textures(), NULL); + return; + } + + for (int i = 0; i < GPU_max_textures(); i++) { + glActiveTexture(GL_TEXTURE0 + i); + glBindTexture(GL_TEXTURE_2D, 0); + glBindTexture(GL_TEXTURE_2D_ARRAY, 0); + glBindTexture(GL_TEXTURE_1D, 0); + glBindTexture(GL_TEXTURE_1D_ARRAY, 0); + glBindTexture(GL_TEXTURE_3D, 0); + glBindTexture(GL_TEXTURE_CUBE_MAP, 0); + glBindTexture(GL_TEXTURE_BUFFER, 0); + if (GPU_arb_texture_cube_map_array_is_supported()) { + glBindTexture(GL_TEXTURE_CUBE_MAP_ARRAY_ARB, 0); + } + glBindSampler(i, 0); + } + + glActiveTexture(GL_TEXTURE0); } #define WARN_NOT_BOUND(_tex) \ @@ -1695,8 +1816,8 @@ void GPU_texture_generate_mipmap(GPUTexture *tex) if (GPU_texture_depth(tex)) { /* Some drivers have bugs when using glGenerateMipmap with depth textures (see T56789). - * In this case we just create a complete texture with mipmaps manually without down-sampling. - * You must initialize the texture levels using other methods like + * In this case we just create a complete texture with mipmaps manually without + * down-sampling. You must initialize the texture levels using other methods like * GPU_framebuffer_recursive_downsample(). */ eGPUDataFormat data_format = gpu_get_data_format_from_tex_format(tex->format); for (int i = 1; i < levels; i++) { @@ -1712,66 +1833,125 @@ void GPU_texture_generate_mipmap(GPUTexture *tex) gpu_texture_memory_footprint_add(tex); } -void GPU_texture_compare_mode(GPUTexture *tex, bool use_compare) +static GLenum gpu_texture_default_attachment(GPUTexture *tex) { - WARN_NOT_BOUND(tex); + return !GPU_texture_depth(tex) ? + GL_COLOR_ATTACHMENT0 : + (GPU_texture_stencil(tex) ? GL_DEPTH_STENCIL_ATTACHMENT : GL_DEPTH_ATTACHMENT); +} + +static void gpu_texture_framebuffer_ensure(GPUTexture *tex) +{ + if (tex->copy_fb == 0) { + tex->copy_fb = GPU_fbo_alloc(); + tex->copy_fb_ctx = GPU_context_active_get(); + + GLenum attachment = gpu_texture_default_attachment(tex); + glBindFramebuffer(GL_FRAMEBUFFER, tex->copy_fb); + glFramebufferTexture(GL_FRAMEBUFFER, attachment, tex->bindcode, 0); + if (!GPU_texture_depth(tex)) { + glReadBuffer(GL_COLOR_ATTACHMENT0); + glDrawBuffer(GL_COLOR_ATTACHMENT0); + } + BLI_assert(glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE); + glBindFramebuffer(GL_FRAMEBUFFER, 0); + } +} + +/* Copy a texture content to a similar texture. Only Mip 0 is copied. */ +void GPU_texture_copy(GPUTexture *dst, GPUTexture *src) +{ + BLI_assert(dst->target == src->target); + BLI_assert(dst->w == src->w); + BLI_assert(dst->h == src->h); + BLI_assert(!GPU_texture_cube(src) && !GPU_texture_cube(dst)); + /* TODO support array / 3D textures. */ + BLI_assert(dst->d == 0); + BLI_assert(dst->format == src->format); + + if (GLEW_ARB_copy_image) { + /* Opengl 4.3 */ + glCopyImageSubData(src->bindcode, + src->target, + 0, + 0, + 0, + 0, + dst->bindcode, + dst->target, + 0, + 0, + 0, + 0, + src->w, + src->h, + 1); + } + else { + /* Fallback for older GL. */ + GPUFrameBuffer *prev_fb = GPU_framebuffer_active_get(); + + gpu_texture_framebuffer_ensure(src); + gpu_texture_framebuffer_ensure(dst); + + /* This means that this function can only be used in one context for each texture. */ + BLI_assert(src->copy_fb_ctx == GPU_context_active_get()); + BLI_assert(dst->copy_fb_ctx == GPU_context_active_get()); + + glBindFramebuffer(GL_READ_FRAMEBUFFER, src->copy_fb); + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, dst->copy_fb); + + GLbitfield mask = 0; + if (GPU_texture_stencil(src)) { + mask |= GL_STENCIL_BUFFER_BIT; + } + if (GPU_texture_depth(src)) { + mask |= GL_DEPTH_BUFFER_BIT; + } + else { + mask |= GL_COLOR_BUFFER_BIT; + } + + glBlitFramebuffer(0, 0, src->w, src->h, 0, 0, src->w, src->h, mask, GL_NEAREST); + + if (prev_fb) { + GPU_framebuffer_bind(prev_fb); + } + } +} + +void GPU_texture_compare_mode(GPUTexture *tex, bool use_compare) +{ /* Could become an assertion ? (fclem) */ if (!GPU_texture_depth(tex)) { return; } - - GLenum mode = (use_compare) ? GL_COMPARE_REF_TO_TEXTURE : GL_NONE; - - glActiveTexture(GL_TEXTURE0 + tex->number); - glTexParameteri(tex->target_base, GL_TEXTURE_COMPARE_MODE, mode); + SET_FLAG_FROM_TEST(tex->sampler_state, use_compare, GPU_SAMPLER_COMPARE); } void GPU_texture_filter_mode(GPUTexture *tex, bool use_filter) { - WARN_NOT_BOUND(tex); - /* Stencil and integer format does not support filtering. */ BLI_assert(!use_filter || !(GPU_texture_stencil(tex) || GPU_texture_integer(tex))); - GLenum filter = (use_filter) ? GL_LINEAR : GL_NEAREST; - - glActiveTexture(GL_TEXTURE0 + tex->number); - glTexParameteri(tex->target_base, GL_TEXTURE_MAG_FILTER, filter); - glTexParameteri(tex->target_base, GL_TEXTURE_MIN_FILTER, filter); + SET_FLAG_FROM_TEST(tex->sampler_state, use_filter, GPU_SAMPLER_FILTER); } void GPU_texture_mipmap_mode(GPUTexture *tex, bool use_mipmap, bool use_filter) { - WARN_NOT_BOUND(tex); - /* Stencil and integer format does not support filtering. */ - BLI_assert((!use_filter && !use_mipmap) || + BLI_assert(!(use_filter || use_mipmap) || !(GPU_texture_stencil(tex) || GPU_texture_integer(tex))); - GLenum filter = (use_filter) ? GL_LINEAR : GL_NEAREST; - GLenum mipmap = ((use_filter) ? (use_mipmap) ? GL_LINEAR_MIPMAP_LINEAR : GL_LINEAR : - (use_mipmap) ? GL_NEAREST_MIPMAP_LINEAR : GL_NEAREST); - - glActiveTexture(GL_TEXTURE0 + tex->number); - glTexParameteri(tex->target_base, GL_TEXTURE_MIN_FILTER, mipmap); - glTexParameteri(tex->target_base, GL_TEXTURE_MAG_FILTER, filter); + SET_FLAG_FROM_TEST(tex->sampler_state, use_mipmap, GPU_SAMPLER_MIPMAP); + SET_FLAG_FROM_TEST(tex->sampler_state, use_filter, GPU_SAMPLER_FILTER); } -void GPU_texture_wrap_mode(GPUTexture *tex, bool use_repeat) +void GPU_texture_wrap_mode(GPUTexture *tex, bool use_repeat, bool use_clamp) { - WARN_NOT_BOUND(tex); - - GLenum repeat = (use_repeat) ? GL_REPEAT : GL_CLAMP_TO_EDGE; - - glActiveTexture(GL_TEXTURE0 + tex->number); - glTexParameteri(tex->target_base, GL_TEXTURE_WRAP_S, repeat); - if (tex->target_base != GL_TEXTURE_1D) { - glTexParameteri(tex->target_base, GL_TEXTURE_WRAP_T, repeat); - } - if (tex->target_base == GL_TEXTURE_3D) { - glTexParameteri(tex->target_base, GL_TEXTURE_WRAP_R, repeat); - } + SET_FLAG_FROM_TEST(tex->sampler_state, use_repeat, GPU_SAMPLER_REPEAT); + SET_FLAG_FROM_TEST(tex->sampler_state, !use_clamp, GPU_SAMPLER_CLAMP_BORDER); } void GPU_texture_swizzle_channel_auto(GPUTexture *tex, int channels) @@ -1785,34 +1965,6 @@ void GPU_texture_swizzle_channel_auto(GPUTexture *tex, int channels) glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_SWIZZLE_A, (channels >= 4) ? GL_ALPHA : GL_ONE); } -static GLenum gpu_get_gl_filterfunction(eGPUFilterFunction filter) -{ - switch (filter) { - case GPU_NEAREST: - return GL_NEAREST; - case GPU_LINEAR: - return GL_LINEAR; - default: - BLI_assert(!"Unhandled filter mode"); - return GL_NEAREST; - } -} - -void GPU_texture_filters(GPUTexture *tex, - eGPUFilterFunction min_filter, - eGPUFilterFunction mag_filter) -{ - WARN_NOT_BOUND(tex); - - /* Stencil and integer format does not support filtering. */ - BLI_assert(!(GPU_texture_stencil(tex) || GPU_texture_integer(tex))); - BLI_assert(mag_filter == GPU_NEAREST || mag_filter == GPU_LINEAR); - - glActiveTexture(GL_TEXTURE0 + tex->number); - glTexParameteri(tex->target_base, GL_TEXTURE_MIN_FILTER, gpu_get_gl_filterfunction(min_filter)); - glTexParameteri(tex->target_base, GL_TEXTURE_MAG_FILTER, gpu_get_gl_filterfunction(mag_filter)); -} - void GPU_texture_free(GPUTexture *tex) { tex->refcount--; @@ -1831,6 +1983,9 @@ void GPU_texture_free(GPUTexture *tex) if (tex->bindcode) { GPU_tex_free(tex->bindcode); } + if (tex->copy_fb) { + GPU_fbo_free(tex->copy_fb, tex->copy_fb_ctx); + } gpu_texture_memory_footprint_remove(tex); @@ -1970,3 +2125,55 @@ void GPU_texture_get_mipmap_size(GPUTexture *tex, int lvl, int *size) size[2] = max_ii(1, tex->d / div); } } + +/* -------------------------------------------------------------------- */ +/** \name GPU Sampler Objects + * + * Simple wrapper around opengl sampler objects. + * Override texture sampler state for one sampler unit only. + * \{ */ + +void GPU_samplers_init(void) +{ + glGenSamplers(GPU_SAMPLER_MAX, GG.samplers); + for (int i = 0; i < GPU_SAMPLER_MAX; i++) { + eGPUSamplerState state = i; + GLenum clamp_type = (state & GPU_SAMPLER_CLAMP_BORDER) ? GL_CLAMP_TO_BORDER : GL_CLAMP_TO_EDGE; + GLenum wrap_s = (state & GPU_SAMPLER_REPEAT_S) ? GL_REPEAT : clamp_type; + GLenum wrap_t = (state & GPU_SAMPLER_REPEAT_T) ? GL_REPEAT : clamp_type; + GLenum wrap_r = (state & GPU_SAMPLER_REPEAT_R) ? GL_REPEAT : clamp_type; + GLenum mag_filter = (state & GPU_SAMPLER_FILTER) ? GL_LINEAR : GL_NEAREST; + GLenum min_filter = (state & GPU_SAMPLER_FILTER) ? + ((state & GPU_SAMPLER_MIPMAP) ? GL_LINEAR_MIPMAP_LINEAR : GL_LINEAR) : + ((state & GPU_SAMPLER_MIPMAP) ? GL_NEAREST_MIPMAP_LINEAR : GL_NEAREST); + GLenum compare_mode = (state & GPU_SAMPLER_COMPARE) ? GL_COMPARE_REF_TO_TEXTURE : GL_NONE; + float aniso_filter = ((state & GPU_SAMPLER_MIPMAP) && (state & GPU_SAMPLER_ANISO)) ? + GPU_get_anisotropic() : + 1.0f; + + glSamplerParameteri(GG.samplers[i], GL_TEXTURE_WRAP_S, wrap_s); + glSamplerParameteri(GG.samplers[i], GL_TEXTURE_WRAP_T, wrap_t); + glSamplerParameteri(GG.samplers[i], GL_TEXTURE_WRAP_R, wrap_r); + glSamplerParameteri(GG.samplers[i], GL_TEXTURE_MIN_FILTER, min_filter); + glSamplerParameteri(GG.samplers[i], GL_TEXTURE_MAG_FILTER, mag_filter); + glSamplerParameteri(GG.samplers[i], GL_TEXTURE_COMPARE_MODE, compare_mode); + glSamplerParameteri(GG.samplers[i], GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL); + if (GLEW_EXT_texture_filter_anisotropic) { + glSamplerParameterf(GG.samplers[i], GL_TEXTURE_MAX_ANISOTROPY_EXT, aniso_filter); + } + + /** Other states are left to default: + * - GL_TEXTURE_BORDER_COLOR is {0, 0, 0, 0}. + * - GL_TEXTURE_MIN_LOD is -1000. + * - GL_TEXTURE_MAX_LOD is 1000. + * - GL_TEXTURE_LOD_BIAS is 0.0f. + **/ + } +} + +void GPU_samplers_free(void) +{ + glDeleteSamplers(GPU_SAMPLER_MAX, GG.samplers); +} + +/** \} */ diff --git a/source/blender/gpu/intern/gpu_uniformbuffer.c b/source/blender/gpu/intern/gpu_uniformbuffer.c index 943793956d1..130e8fe7da1 100644 --- a/source/blender/gpu/intern/gpu_uniformbuffer.c +++ b/source/blender/gpu/intern/gpu_uniformbuffer.c @@ -147,7 +147,7 @@ GPUUniformBuffer *GPU_uniformbuffer_dynamic_create(ListBase *inputs, char err_ou /* Make sure we comply to the ubo alignment requirements. */ gpu_uniformbuffer_inputs_sort(inputs); - for (LinkData *link = inputs->first; link; link = link->next) { + LISTBASE_FOREACH (LinkData *, link, inputs) { const eGPUType gputype = get_padded_gpu_type(link); ubo->buffer.size += gputype * sizeof(float); } @@ -160,7 +160,7 @@ GPUUniformBuffer *GPU_uniformbuffer_dynamic_create(ListBase *inputs, char err_ou /* Now that we know the total ubo size we can start populating it. */ float *offset = ubo->data; - for (LinkData *link = inputs->first; link; link = link->next) { + LISTBASE_FOREACH (LinkData *, link, inputs) { GPUInput *input = link->data; memcpy(offset, input->vec, input->type * sizeof(float)); offset += get_padded_gpu_type(link); @@ -272,7 +272,7 @@ static void gpu_uniformbuffer_inputs_sort(ListBase *inputs) LinkData *inputs_lookup[MAX_UBO_GPU_TYPE + 1] = {NULL}; eGPUType cur_type = MAX_UBO_GPU_TYPE + 1; - for (LinkData *link = inputs->first; link; link = link->next) { + LISTBASE_FOREACH (LinkData *, link, inputs) { GPUInput *input = link->data; if (input->type == GPU_MAT3) { diff --git a/source/blender/gpu/intern/gpu_vertex_buffer.c b/source/blender/gpu/intern/gpu_vertex_buffer.c index 1df7e68e08b..25daabe601d 100644 --- a/source/blender/gpu/intern/gpu_vertex_buffer.c +++ b/source/blender/gpu/intern/gpu_vertex_buffer.c @@ -196,7 +196,7 @@ void GPU_vertbuf_attr_fill(GPUVertBuf *verts, uint a_idx, const void *data) GPU_vertbuf_attr_fill_stride(verts, a_idx, stride, data); } -/** Fills a whole vertex (all attribs). Data must match packed layout. */ +/** Fills a whole vertex (all attributes). Data must match packed layout. */ void GPU_vertbuf_vert_set(GPUVertBuf *verts, uint v_idx, const void *data) { const GPUVertFormat *format = &verts->format; diff --git a/source/blender/gpu/intern/gpu_vertex_format.c b/source/blender/gpu/intern/gpu_vertex_format.c index 8370bcf4beb..b84a7e0f554 100644 --- a/source/blender/gpu/intern/gpu_vertex_format.c +++ b/source/blender/gpu/intern/gpu_vertex_format.c @@ -23,8 +23,6 @@ * GPU vertex format */ -#include "GPU_shader_interface.h" - #include "GPU_vertex_format.h" #include "gpu_vertex_format_private.h" #include <stddef.h> @@ -34,6 +32,9 @@ #include "BLI_string.h" #include "BLI_utildefines.h" +#include "GPU_shader.h" +#include "gpu_shader_private.h" + #define PACK_DEBUG 0 #if PACK_DEBUG @@ -207,15 +208,15 @@ void GPU_vertformat_alias_add(GPUVertFormat *format, const char *alias) } /** - * Makes vertex attrib from the next vertices to be accessible in the vertex shader. - * For an attrib named "attr" you can access the next nth vertex using "attrn". - * Use this function after specifying all the attribs in the format. + * Makes vertex attribute from the next vertices to be accessible in the vertex shader. + * For an attribute named "attr" you can access the next nth vertex using "attr{number}". + * Use this function after specifying all the attributes in the format. * * NOTE: This does NOT work when using indexed rendering. - * NOTE: Only works for first attrib name. (this limitation can be changed if needed) + * NOTE: Only works for first attribute name. (this limitation can be changed if needed) * - * WARNING: this function creates a lot of aliases/attribs, make sure to keep the attrib name - * short to avoid overflowing the namebuffer. + * WARNING: this function creates a lot of aliases/attributes, make sure to keep the attribute + * name short to avoid overflowing the name-buffer. * */ void GPU_vertformat_multiload_enable(GPUVertFormat *format, int load_count) { @@ -276,28 +277,26 @@ static void safe_bytes(char out[11], const char data[8]) /* Warning: Always add a prefix to the result of this function as * the generated string can start with a number and not be a valid attribute name. */ -void GPU_vertformat_safe_attrib_name(const char *attrib_name, - char *r_safe_name, - uint UNUSED(max_len)) +void GPU_vertformat_safe_attr_name(const char *attr_name, char *r_safe_name, uint UNUSED(max_len)) { char data[8] = {0}; - uint len = strlen(attrib_name); + uint len = strlen(attr_name); if (len > 8) { /* Start with the first 4 chars of the name; */ for (int i = 0; i < 4; i++) { - data[i] = attrib_name[i]; + data[i] = attr_name[i]; } /* We use a hash to identify each data layer based on its name. * NOTE: This is still prone to hash collision but the risks are very low.*/ /* Start hashing after the first 2 chars. */ - *(uint *)&data[4] = BLI_ghashutil_strhash_p_murmur(attrib_name + 4); + *(uint *)&data[4] = BLI_ghashutil_strhash_p_murmur(attr_name + 4); } else { /* Copy the whole name. Collision is barely possible * (hash would have to be equal to the last 4 bytes). */ - for (int i = 0; i < 8 && attrib_name[i] != '\0'; i++) { - data[i] = attrib_name[i]; + for (int i = 0; i < 8 && attr_name[i] != '\0'; i++) { + data[i] = attr_name[i]; } } /* Convert to safe bytes characters. */ @@ -305,9 +304,9 @@ void GPU_vertformat_safe_attrib_name(const char *attrib_name, /* End the string */ r_safe_name[11] = '\0'; - BLI_assert(GPU_MAX_SAFE_ATTRIB_NAME >= 12); + BLI_assert(GPU_MAX_SAFE_ATTR_NAME >= 12); #if 0 /* For debugging */ - printf("%s > %lx > %s\n", attrib_name, *(uint64_t *)data, r_safe_name); + printf("%s > %lx > %s\n", attr_name, *(uint64_t *)data, r_safe_name); #endif } @@ -316,13 +315,13 @@ void GPU_vertformat_safe_attrib_name(const char *attrib_name, * Use direct buffer access to fill the data. * This is for advanced usage. * - * Deinterleaved data means all attrib data for each attrib - * is stored continuously like this : + * De-interleaved data means all attribute data for each attribute + * is stored continuously like this: * 000011112222 * instead of : * 012012012012 * - * Note this is per attrib deinterleaving, NOT per component. + * Note this is per attribute de-interleaving, NOT per component. * */ void GPU_vertformat_deinterleave(GPUVertFormat *format) { @@ -393,38 +392,37 @@ void VertexFormat_pack(GPUVertFormat *format) format->packed = true; } -static uint calc_input_component_size(const GPUShaderInput *input) +static uint calc_component_size(const GLenum gl_type) { - int size = input->size; - switch (input->gl_type) { + switch (gl_type) { case GL_FLOAT_VEC2: case GL_INT_VEC2: case GL_UNSIGNED_INT_VEC2: - return size * 2; + return 2; case GL_FLOAT_VEC3: case GL_INT_VEC3: case GL_UNSIGNED_INT_VEC3: - return size * 3; + return 3; case GL_FLOAT_VEC4: case GL_FLOAT_MAT2: case GL_INT_VEC4: case GL_UNSIGNED_INT_VEC4: - return size * 4; + return 4; case GL_FLOAT_MAT3: - return size * 9; + return 9; case GL_FLOAT_MAT4: - return size * 16; + return 16; case GL_FLOAT_MAT2x3: case GL_FLOAT_MAT3x2: - return size * 6; + return 6; case GL_FLOAT_MAT2x4: case GL_FLOAT_MAT4x2: - return size * 8; + return 8; case GL_FLOAT_MAT3x4: case GL_FLOAT_MAT4x3: - return size * 12; + return 12; default: - return size; + return 1; } } @@ -468,42 +466,39 @@ static void get_fetch_mode_and_comp_type(int gl_type, } } -void GPU_vertformat_from_interface(GPUVertFormat *format, const GPUShaderInterface *shaderface) +void GPU_vertformat_from_shader(GPUVertFormat *format, const GPUShader *shader) { - const char *name_buffer = shaderface->name_buffer; - - for (int i = 0; i < GPU_NUM_SHADERINTERFACE_BUCKETS; i++) { - const GPUShaderInput *input = shaderface->attr_buckets[i]; - if (input == NULL) { - continue; - } + GPU_vertformat_clear(format); + GPUVertAttr *attr = &format->attrs[0]; - const GPUShaderInput *next = input; - while (next != NULL) { - input = next; - next = input->next; + GLint attr_len; + glGetProgramiv(shader->program, GL_ACTIVE_ATTRIBUTES, &attr_len); - /* OpenGL attributes such as `gl_VertexID` have a location of -1. */ - if (input->location < 0) { - continue; - } - - format->name_len++; /* multiname support */ - format->attr_len++; - - GPUVertCompType comp_type; - GPUVertFetchMode fetch_mode; - get_fetch_mode_and_comp_type(input->gl_type, &comp_type, &fetch_mode); + for (int i = 0; i < attr_len; i++) { + char name[256]; + GLenum gl_type; + GLint size; + glGetActiveAttrib(shader->program, i, sizeof(name), NULL, &size, &gl_type, name); - GPUVertAttr *attr = &format->attrs[input->location]; - - attr->names[attr->name_len++] = copy_attr_name(format, name_buffer + input->name_offset); - attr->offset = 0; /* offsets & stride are calculated later (during pack) */ - attr->comp_len = calc_input_component_size(input); - attr->sz = attr->comp_len * 4; - attr->fetch_mode = fetch_mode; - attr->comp_type = comp_type; - attr->gl_comp_type = convert_comp_type_to_gl(comp_type); + /* Ignore OpenGL names like `gl_BaseInstanceARB`, `gl_InstanceID` and `gl_VertexID`. */ + if (glGetAttribLocation(shader->program, name) == -1) { + continue; } + + format->name_len++; /* multiname support */ + format->attr_len++; + + GPUVertCompType comp_type; + GPUVertFetchMode fetch_mode; + get_fetch_mode_and_comp_type(gl_type, &comp_type, &fetch_mode); + + attr->names[attr->name_len++] = copy_attr_name(format, name); + attr->offset = 0; /* offsets & stride are calculated later (during pack) */ + attr->comp_len = calc_component_size(gl_type) * size; + attr->sz = attr->comp_len * 4; + attr->fetch_mode = fetch_mode; + attr->comp_type = comp_type; + attr->gl_comp_type = convert_comp_type_to_gl(comp_type); + attr += 1; } } diff --git a/source/blender/gpu/intern/gpu_viewport.c b/source/blender/gpu/intern/gpu_viewport.c index 57efaf99b8b..753da8544ea 100644 --- a/source/blender/gpu/intern/gpu_viewport.c +++ b/source/blender/gpu/intern/gpu_viewport.c @@ -65,6 +65,24 @@ typedef struct ViewportTempTexture { GPUTexture *texture; } ViewportTempTexture; +/* Struct storing a viewport specific GPUBatch. + * The end-goal is to have a single batch shared across viewport and use a model matrix to place + * the batch. Due to OCIO and Image/UV editor we are not able to use an model matrix yet. */ +struct GPUViewportBatch { + GPUBatch *batch; + struct { + rctf rect_pos; + rctf rect_uv; + } last_used_parameters; +}; + +static struct { + GPUVertFormat format; + struct { + uint pos, tex_coord; + } attr_id; +} g_viewport = {{0}}; + struct GPUViewport { int size[2]; int flag; @@ -93,10 +111,12 @@ struct GPUViewport { /* Color management. */ ColorManagedViewSettings view_settings; ColorManagedDisplaySettings display_settings; + CurveMapping *orig_curve_mapping; float dither; /* TODO(fclem) the uvimage display use the viewport but do not set any view transform for the * moment. The end goal would be to let the GPUViewport do the color management. */ bool do_color_management; + struct GPUViewportBatch batch; }; enum { @@ -197,18 +217,6 @@ static void gpu_viewport_framebuffer_view_set(GPUViewport *viewport, int view) GPU_ATTACHMENT_TEXTURE(dtxl->color_overlay), }); - if (((viewport->flag & GPU_VIEWPORT_STEREO) != 0)) { - GPU_framebuffer_ensure_config(&dfbl->stereo_comp_fb, - { - GPU_ATTACHMENT_NONE, - GPU_ATTACHMENT_TEXTURE(dtxl->color), - GPU_ATTACHMENT_TEXTURE(dtxl->color_overlay), - }); - } - else { - dfbl->stereo_comp_fb = NULL; - } - viewport->active_view = view; } @@ -355,7 +363,7 @@ GPUTexture *GPU_viewport_texture_pool_query( { GPUTexture *tex; - for (ViewportTempTexture *tmp_tex = viewport->tex_pool.first; tmp_tex; tmp_tex = tmp_tex->next) { + LISTBASE_FOREACH (ViewportTempTexture *, tmp_tex, &viewport->tex_pool) { if ((GPU_texture_format(tmp_tex->texture) == format) && (GPU_texture_width(tmp_tex->texture) == width) && (GPU_texture_height(tmp_tex->texture) == height)) { @@ -374,12 +382,10 @@ GPUTexture *GPU_viewport_texture_pool_query( } tex = GPU_texture_create_2d(width, height, format, NULL, NULL); - GPU_texture_bind(tex, 0); /* Doing filtering for depth does not make sense when not doing shadow mapping, * and enabling texture filtering on integer texture make them unreadable. */ bool do_filter = !GPU_texture_depth(tex) && !GPU_texture_integer(tex); GPU_texture_filter_mode(tex, do_filter); - GPU_texture_unbind(tex); ViewportTempTexture *tmp_tex = MEM_callocN(sizeof(ViewportTempTexture), "ViewportTempTexture"); tmp_tex->texture = tex; @@ -412,7 +418,7 @@ static void gpu_viewport_texture_pool_clear_users(GPUViewport *viewport) static void gpu_viewport_texture_pool_free(GPUViewport *viewport) { - for (ViewportTempTexture *tmp_tex = viewport->tex_pool.first; tmp_tex; tmp_tex = tmp_tex->next) { + LISTBASE_FOREACH (ViewportTempTexture *, tmp_tex, &viewport->tex_pool) { GPU_texture_free(tmp_tex->texture); } @@ -472,9 +478,6 @@ static void gpu_viewport_default_fb_create(GPUViewport *viewport) ok = ok && GPU_framebuffer_check_valid(dfbl->color_only_fb, NULL); ok = ok && GPU_framebuffer_check_valid(dfbl->depth_only_fb, NULL); ok = ok && GPU_framebuffer_check_valid(dfbl->overlay_only_fb, NULL); - if (((viewport->flag & GPU_VIEWPORT_STEREO) != 0)) { - ok = ok && GPU_framebuffer_check_valid(dfbl->stereo_comp_fb, NULL); - } cleanup: if (!ok) { GPU_viewport_free(viewport); @@ -552,8 +555,43 @@ void GPU_viewport_colorspace_set(GPUViewport *viewport, ColorManagedDisplaySettings *display_settings, float dither) { - memcpy(&viewport->view_settings, view_settings, sizeof(*view_settings)); - memcpy(&viewport->display_settings, display_settings, sizeof(*display_settings)); + /** + * HACK(fclem): We copy the settings here to avoid use after free if an update frees the scene + * and the viewport stays cached (see T75443). But this means the OCIO curve-mapping caching + * (which is based on #CurveMap pointer address) cannot operate correctly and it will create + * a different OCIO processor for each viewport. We try to only reallocate the curve-map copy + * if needed to avoid unneeded cache invalidation. + */ + if (view_settings->curve_mapping) { + if (viewport->view_settings.curve_mapping) { + if (view_settings->curve_mapping->changed_timestamp != + viewport->view_settings.curve_mapping->changed_timestamp) { + BKE_color_managed_view_settings_free(&viewport->view_settings); + } + } + } + + if (viewport->orig_curve_mapping != view_settings->curve_mapping) { + viewport->orig_curve_mapping = view_settings->curve_mapping; + BKE_color_managed_view_settings_free(&viewport->view_settings); + } + /* Don't copy the curve mapping already. */ + CurveMapping *tmp_curve_mapping = view_settings->curve_mapping; + CurveMapping *tmp_curve_mapping_vp = viewport->view_settings.curve_mapping; + view_settings->curve_mapping = NULL; + viewport->view_settings.curve_mapping = NULL; + + BKE_color_managed_view_settings_copy(&viewport->view_settings, view_settings); + /* Restore. */ + view_settings->curve_mapping = tmp_curve_mapping; + viewport->view_settings.curve_mapping = tmp_curve_mapping_vp; + /* Only copy curvemapping if needed. Avoid uneeded OCIO cache miss. */ + if (tmp_curve_mapping && viewport->view_settings.curve_mapping == NULL) { + BKE_color_managed_view_settings_free(&viewport->view_settings); + viewport->view_settings.curve_mapping = BKE_curvemapping_copy(tmp_curve_mapping); + } + + BKE_color_managed_display_settings_copy(&viewport->display_settings, display_settings); viewport->dither = dither; viewport->do_color_management = true; } @@ -570,6 +608,14 @@ void GPU_viewport_stereo_composite(GPUViewport *viewport, Stereo3dFormat *stereo DefaultTextureList *dtxl = viewport->txl; DefaultFramebufferList *dfbl = viewport->fbl; + /* The composite framebuffer object needs to be created in the window context. */ + GPU_framebuffer_ensure_config(&dfbl->stereo_comp_fb, + { + GPU_ATTACHMENT_NONE, + GPU_ATTACHMENT_TEXTURE(dtxl->color), + GPU_ATTACHMENT_TEXTURE(dtxl->color_overlay), + }); + GPUVertFormat *vert_format = immVertexFormat(); uint pos = GPU_vertformat_attr_add(vert_format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); GPU_framebuffer_bind(dfbl->stereo_comp_fb); @@ -625,6 +671,76 @@ void GPU_viewport_stereo_composite(GPUViewport *viewport, Stereo3dFormat *stereo GPU_framebuffer_restore(); } +/* -------------------------------------------------------------------- */ +/** \name Viewport Batches + * \{ */ + +static GPUVertFormat *gpu_viewport_batch_format(void) +{ + if (g_viewport.format.attr_len == 0) { + GPUVertFormat *format = &g_viewport.format; + g_viewport.attr_id.pos = GPU_vertformat_attr_add( + format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); + g_viewport.attr_id.tex_coord = GPU_vertformat_attr_add( + format, "texCoord", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); + } + return &g_viewport.format; +} + +static GPUBatch *gpu_viewport_batch_create(const rctf *rect_pos, const rctf *rect_uv) +{ + GPUVertBuf *vbo = GPU_vertbuf_create_with_format(gpu_viewport_batch_format()); + const uint vbo_len = 4; + GPU_vertbuf_data_alloc(vbo, vbo_len); + + GPUVertBufRaw pos_step, tex_coord_step; + GPU_vertbuf_attr_get_raw_data(vbo, g_viewport.attr_id.pos, &pos_step); + GPU_vertbuf_attr_get_raw_data(vbo, g_viewport.attr_id.tex_coord, &tex_coord_step); + + copy_v2_fl2(GPU_vertbuf_raw_step(&pos_step), rect_pos->xmin, rect_pos->ymin); + copy_v2_fl2(GPU_vertbuf_raw_step(&tex_coord_step), rect_uv->xmin, rect_uv->ymin); + copy_v2_fl2(GPU_vertbuf_raw_step(&pos_step), rect_pos->xmax, rect_pos->ymin); + copy_v2_fl2(GPU_vertbuf_raw_step(&tex_coord_step), rect_uv->xmax, rect_uv->ymin); + copy_v2_fl2(GPU_vertbuf_raw_step(&pos_step), rect_pos->xmin, rect_pos->ymax); + copy_v2_fl2(GPU_vertbuf_raw_step(&tex_coord_step), rect_uv->xmin, rect_uv->ymax); + copy_v2_fl2(GPU_vertbuf_raw_step(&pos_step), rect_pos->xmax, rect_pos->ymax); + copy_v2_fl2(GPU_vertbuf_raw_step(&tex_coord_step), rect_uv->xmax, rect_uv->ymax); + + return GPU_batch_create_ex(GPU_PRIM_TRI_STRIP, vbo, NULL, GPU_BATCH_OWNS_VBO); +} + +static GPUBatch *gpu_viewport_batch_get(GPUViewport *viewport, + const rctf *rect_pos, + const rctf *rect_uv) +{ + const float compare_limit = 0.0001f; + const bool parameters_changed = + (!BLI_rctf_compare( + &viewport->batch.last_used_parameters.rect_pos, rect_pos, compare_limit) || + !BLI_rctf_compare(&viewport->batch.last_used_parameters.rect_uv, rect_uv, compare_limit)); + + if (viewport->batch.batch && parameters_changed) { + GPU_batch_discard(viewport->batch.batch); + viewport->batch.batch = NULL; + } + + if (!viewport->batch.batch) { + viewport->batch.batch = gpu_viewport_batch_create(rect_pos, rect_uv); + viewport->batch.last_used_parameters.rect_pos = *rect_pos; + viewport->batch.last_used_parameters.rect_uv = *rect_uv; + } + return viewport->batch.batch; +} + +static void gpu_viewport_batch_free(GPUViewport *viewport) +{ + if (viewport->batch.batch) { + GPU_batch_discard(viewport->batch.batch); + viewport->batch.batch = NULL; + } +} + +/** \} */ static void gpu_viewport_draw_colormanaged(GPUViewport *viewport, const rctf *rect_pos, @@ -635,13 +751,17 @@ static void gpu_viewport_draw_colormanaged(GPUViewport *viewport, GPUTexture *color = dtxl->color; GPUTexture *color_overlay = dtxl->color_overlay; - GPUVertFormat *vert_format = immVertexFormat(); - uint pos = GPU_vertformat_attr_add(vert_format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); - uint texco = GPU_vertformat_attr_add(vert_format, "texCoord", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); - bool use_ocio = false; if (viewport->do_color_management && display_colorspace) { + /* During the binding process the last used VertexFormat is tested and can assert as it is not + * valid. By calling the `immVertexFormat` the last used VertexFormat is reset and the assert + * does not happen. This solves a chicken and egg problem when using GPUBatches. GPUBatches + * contain the correct vertex format, but can only bind after the shader is bound. + * + * Image/UV editor still uses imm, after that has been changed we could move this fix to the + * OCIO. */ + immVertexFormat(); use_ocio = IMB_colormanagement_setup_glsl_draw_from_space(&viewport->view_settings, &viewport->display_settings, NULL, @@ -650,38 +770,26 @@ static void gpu_viewport_draw_colormanaged(GPUViewport *viewport, true); } - if (!use_ocio) { - immBindBuiltinProgram(GPU_SHADER_2D_IMAGE_OVERLAYS_MERGE); - immUniform1i("display_transform", display_colorspace); - immUniform1i("image_texture", 0); - immUniform1i("overlays_texture", 1); + GPUBatch *batch = gpu_viewport_batch_get(viewport, rect_pos, rect_uv); + if (use_ocio) { + GPU_batch_program_set_imm_shader(batch); + } + else { + GPU_batch_program_set_builtin(batch, GPU_SHADER_2D_IMAGE_OVERLAYS_MERGE); + GPU_batch_uniform_1i(batch, "display_transform", display_colorspace); + GPU_batch_uniform_1i(batch, "image_texture", 0); + GPU_batch_uniform_1i(batch, "overlays_texture", 1); } GPU_texture_bind(color, 0); GPU_texture_bind(color_overlay, 1); - - immBegin(GPU_PRIM_TRI_STRIP, 4); - - immAttr2f(texco, rect_uv->xmin, rect_uv->ymin); - immVertex2f(pos, rect_pos->xmin, rect_pos->ymin); - immAttr2f(texco, rect_uv->xmax, rect_uv->ymin); - immVertex2f(pos, rect_pos->xmax, rect_pos->ymin); - immAttr2f(texco, rect_uv->xmin, rect_uv->ymax); - immVertex2f(pos, rect_pos->xmin, rect_pos->ymax); - immAttr2f(texco, rect_uv->xmax, rect_uv->ymax); - immVertex2f(pos, rect_pos->xmax, rect_pos->ymax); - - immEnd(); - + GPU_batch_draw(batch); GPU_texture_unbind(color); GPU_texture_unbind(color_overlay); if (use_ocio) { IMB_colormanagement_finish_glsl_draw(); } - else { - immUnbindProgram(); - } } /** @@ -745,8 +853,8 @@ void GPU_viewport_draw_to_screen_ex(GPUViewport *viewport, * Merge and draw the buffers of \a viewport into the currently active framebuffer, performing * color transform to display space. * - * \param rect: Coordinates to draw into. By swapping min and max values, drawing can be done with - * inversed axis coordinates (upside down or sideways). + * \param rect: Coordinates to draw into. By swapping min and max values, drawing can be done + * with inversed axis coordinates (upside down or sideways). */ void GPU_viewport_draw_to_screen(GPUViewport *viewport, int view, const rcti *rect) { @@ -923,5 +1031,8 @@ void GPU_viewport_free(GPUViewport *viewport) DRW_instance_data_list_free(viewport->idatalist); MEM_freeN(viewport->idatalist); + BKE_color_managed_view_settings_free(&viewport->view_settings); + gpu_viewport_batch_free(viewport); + MEM_freeN(viewport); } diff --git a/source/blender/gpu/shaders/gpu_shader_2D_smooth_color_dithered_frag.glsl b/source/blender/gpu/shaders/gpu_shader_2D_smooth_color_dithered_frag.glsl deleted file mode 100644 index 181b1bf3fad..00000000000 --- a/source/blender/gpu/shaders/gpu_shader_2D_smooth_color_dithered_frag.glsl +++ /dev/null @@ -1,18 +0,0 @@ - -noperspective in vec4 finalColor; -out vec4 fragColor; - -/* 4x4 bayer matrix prepared for 8bit UNORM precision error. */ -#define P(x) (((x + 0.5) * (1.0 / 16.0) - 0.5) * (1.0 / 255.0)) -const vec4 dither_mat4x4[4] = vec4[4](vec4(P(0.0), P(8.0), P(2.0), P(10.0)), - vec4(P(12.0), P(4.0), P(14.0), P(6.0)), - vec4(P(3.0), P(11.0), P(1.0), P(9.0)), - vec4(P(15.0), P(7.0), P(13.0), P(5.0))); - -void main() -{ - ivec2 tx1 = ivec2(gl_FragCoord.xy) % 4; - ivec2 tx2 = ivec2(gl_FragCoord.xy) % 2; - float dither_noise = dither_mat4x4[tx1.x][tx1.y]; - fragColor = finalColor + dither_noise; -} diff --git a/source/blender/gpu/shaders/gpu_shader_2D_smooth_color_frag.glsl b/source/blender/gpu/shaders/gpu_shader_2D_smooth_color_frag.glsl index 4f275c5b220..1333c00682c 100644 --- a/source/blender/gpu/shaders/gpu_shader_2D_smooth_color_frag.glsl +++ b/source/blender/gpu/shaders/gpu_shader_2D_smooth_color_frag.glsl @@ -5,4 +5,5 @@ out vec4 fragColor; void main() { fragColor = finalColor; + fragColor = blender_srgb_to_framebuffer_space(fragColor); } diff --git a/source/blender/gpu/shaders/gpu_shader_2D_widget_base_frag.glsl b/source/blender/gpu/shaders/gpu_shader_2D_widget_base_frag.glsl index 18f58d52f32..bdc87baf924 100644 --- a/source/blender/gpu/shaders/gpu_shader_2D_widget_base_frag.glsl +++ b/source/blender/gpu/shaders/gpu_shader_2D_widget_base_frag.glsl @@ -35,4 +35,6 @@ void main() if (butCo > 0.0) { fragColor.a = 1.0; } + + fragColor = blender_srgb_to_framebuffer_space(fragColor); } diff --git a/source/blender/gpu/shaders/gpu_shader_2D_widget_base_vert.glsl b/source/blender/gpu/shaders/gpu_shader_2D_widget_base_vert.glsl index 0b2bc08944e..d7cc851556b 100644 --- a/source/blender/gpu/shaders/gpu_shader_2D_widget_base_vert.glsl +++ b/source/blender/gpu/shaders/gpu_shader_2D_widget_base_vert.glsl @@ -12,42 +12,15 @@ /* 4bits for corner id */ #define CORNER_VEC_OFS 2u #define CORNER_VEC_RANGE BIT_RANGE(4) -const vec2 cornervec[36] = vec2[36](vec2(0.0, 1.0), - vec2(0.02, 0.805), - vec2(0.067, 0.617), - vec2(0.169, 0.45), - vec2(0.293, 0.293), - vec2(0.45, 0.169), - vec2(0.617, 0.076), - vec2(0.805, 0.02), - vec2(1.0, 0.0), - vec2(-1.0, 0.0), - vec2(-0.805, 0.02), - vec2(-0.617, 0.067), - vec2(-0.45, 0.169), - vec2(-0.293, 0.293), - vec2(-0.169, 0.45), - vec2(-0.076, 0.617), - vec2(-0.02, 0.805), - vec2(0.0, 1.0), - vec2(0.0, -1.0), - vec2(-0.02, -0.805), - vec2(-0.067, -0.617), - vec2(-0.169, -0.45), - vec2(-0.293, -0.293), - vec2(-0.45, -0.169), - vec2(-0.617, -0.076), - vec2(-0.805, -0.02), - vec2(-1.0, 0.0), - vec2(1.0, 0.0), - vec2(0.805, -0.02), - vec2(0.617, -0.067), - vec2(0.45, -0.169), - vec2(0.293, -0.293), - vec2(0.169, -0.45), - vec2(0.076, -0.617), - vec2(0.02, -0.805), - vec2(0.0, -1.0)); +const vec2 cornervec[9] = vec2[9](vec2(0.0, 1.0), + vec2(0.02, 0.805), + vec2(0.067, 0.617), + vec2(0.169, 0.45), + vec2(0.293, 0.293), + vec2(0.45, 0.169), + vec2(0.617, 0.076), + vec2(0.805, 0.02), + vec2(1.0, 0.0)); /* 4bits for jitter id */ #define JIT_OFS 6u @@ -189,26 +162,26 @@ vec2 do_widget(void) { uint cflag = vflag & CNR_FLAG_RANGE; uint vofs = (vflag >> CORNER_VEC_OFS) & CORNER_VEC_RANGE; - - vec2 v = cornervec[cflag * 9u + vofs]; - bool is_inner = (vflag & INNER_FLAG) != 0u; + vec2 v = cornervec[vofs]; /* Scale by corner radius */ v *= roundCorners[cflag] * ((is_inner) ? radsi : rads); - - /* Position to corner */ + /* Flip in the right direction and osition to corner */ vec4 rct = (is_inner) ? recti : rect; if (cflag == BOTTOM_LEFT) { v += rct.xz; } else if (cflag == BOTTOM_RIGHT) { + v = vec2(-v.y, v.x); v += rct.yz; } else if (cflag == TOP_RIGHT) { + v = -v; v += rct.yw; } else /* (cflag == TOP_LEFT) */ { + v = vec2(v.y, -v.x); v += rct.xw; } @@ -238,7 +211,7 @@ vec2 do_widget(void) } bool is_emboss = (vflag & EMBOSS_FLAG) != 0u; - v.y -= (is_emboss) ? 1.0f : 0.0; + v.y -= (is_emboss) ? (recti.z - rect.z) : 0.0; return v; } diff --git a/source/blender/gpu/shaders/gpu_shader_3D_normal_smooth_color_vert.glsl b/source/blender/gpu/shaders/gpu_shader_3D_normal_smooth_color_vert.glsl deleted file mode 100644 index 7fa571343a2..00000000000 --- a/source/blender/gpu/shaders/gpu_shader_3D_normal_smooth_color_vert.glsl +++ /dev/null @@ -1,22 +0,0 @@ - -uniform mat4 ModelViewProjectionMatrix; -uniform mat3 NormalMatrix; - -in vec3 pos; -in vec3 nor; -in vec4 color; - -#ifdef USE_FLAT_NORMAL -flat out vec3 normal; -flat out vec4 finalColor; -#else -out vec3 normal; -out vec4 finalColor; -#endif - -void main() -{ - normal = normalize(NormalMatrix * nor); - gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0); - finalColor = color; -} diff --git a/source/blender/gpu/shaders/gpu_shader_3D_polyline_frag.glsl b/source/blender/gpu/shaders/gpu_shader_3D_polyline_frag.glsl new file mode 100644 index 00000000000..9c6b109d659 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_3D_polyline_frag.glsl @@ -0,0 +1,24 @@ + +uniform float lineWidth; + +in vec4 finalColor; +noperspective in float smoothline; +#ifdef CLIP +in float clip; +#endif + +out vec4 fragColor; + +#define SMOOTH_WIDTH 1.0 + +void main() +{ +#ifdef CLIP + if (clip < 0.0) { + discard; + } +#endif + fragColor = finalColor; + fragColor.a *= clamp((lineWidth + SMOOTH_WIDTH) * 0.5 - abs(smoothline), 0.0, 1.0); + fragColor = blender_srgb_to_framebuffer_space(fragColor); +} diff --git a/source/blender/gpu/shaders/gpu_shader_3D_polyline_geom.glsl b/source/blender/gpu/shaders/gpu_shader_3D_polyline_geom.glsl new file mode 100644 index 00000000000..b28205b349e --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_3D_polyline_geom.glsl @@ -0,0 +1,68 @@ + +layout(lines) in; +layout(triangle_strip, max_vertices = 4) out; + +uniform vec4 color; +uniform vec2 viewportSize; +uniform float lineWidth; + +#if !defined(UNIFORM) +in vec4 finalColor_g[]; +#endif + +#ifdef CLIP +in float clip_g[]; +out float clip; +#endif + +out vec4 finalColor; +noperspective out float smoothline; + +#define SMOOTH_WIDTH 1.0 + +void do_vertex(const int i, vec2 ofs) +{ +#if defined(UNIFORM) + finalColor = color; + +#elif defined(FLAT) + finalColor = finalColor_g[0]; + +#elif defined(SMOOTH) + finalColor = finalColor_g[i]; +#endif + +#ifdef CLIP + clip = clip_g[i]; +#endif + + smoothline = (lineWidth + SMOOTH_WIDTH) * 0.5; + gl_Position = gl_in[i].gl_Position; + gl_Position.xy += ofs * gl_Position.w; + EmitVertex(); + + smoothline = -(lineWidth + SMOOTH_WIDTH) * 0.5; + gl_Position = gl_in[i].gl_Position; + gl_Position.xy -= ofs * gl_Position.w; + EmitVertex(); +} + +void main(void) +{ + vec2 p0 = gl_in[0].gl_Position.xy / gl_in[0].gl_Position.w; + vec2 p1 = gl_in[1].gl_Position.xy / gl_in[1].gl_Position.w; + vec2 e = normalize((p1 - p0) * viewportSize.xy); +#if 0 /* Hard turn when line direction changes quadrant. */ + e = abs(e); + vec2 ofs = (e.x > e.y) ? vec2(0.0, 1.0 / e.x) : vec2(1.0 / e.y, 0.0); +#else /* Use perpendicular direction. */ + vec2 ofs = vec2(-e.y, e.x); +#endif + ofs /= viewportSize.xy; + ofs *= lineWidth + SMOOTH_WIDTH; + + do_vertex(0, ofs); + do_vertex(1, ofs); + + EndPrimitive(); +} diff --git a/source/blender/gpu/shaders/gpu_shader_3D_polyline_vert.glsl b/source/blender/gpu/shaders/gpu_shader_3D_polyline_vert.glsl new file mode 100644 index 00000000000..28aa2a4ccc6 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_3D_polyline_vert.glsl @@ -0,0 +1,28 @@ + +uniform mat4 ModelViewProjectionMatrix; +uniform mat4 ModelMatrix; +uniform vec4 ClipPlane; + +in vec3 pos; + +#if !defined(UNIFORM) +in vec4 color; + +out vec4 finalColor_g; +#endif + +#ifdef CLIP +out float clip_g; +#endif + +void main() +{ + gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0); +#if !defined(UNIFORM) + finalColor_g = color; +#endif + +#ifdef CLIP + clip_g = dot(ModelMatrix * vec4(pos, 1.0), ClipPlane); +#endif +} diff --git a/source/blender/gpu/shaders/gpu_shader_3D_smooth_color_frag.glsl b/source/blender/gpu/shaders/gpu_shader_3D_smooth_color_frag.glsl index 7bd44ba9b88..3a2d96c9929 100644 --- a/source/blender/gpu/shaders/gpu_shader_3D_smooth_color_frag.glsl +++ b/source/blender/gpu/shaders/gpu_shader_3D_smooth_color_frag.glsl @@ -5,4 +5,5 @@ out vec4 fragColor; void main() { fragColor = finalColor; + fragColor = blender_srgb_to_framebuffer_space(fragColor); } diff --git a/source/blender/gpu/shaders/gpu_shader_colorspace_lib.glsl b/source/blender/gpu/shaders/gpu_shader_colorspace_lib.glsl new file mode 100644 index 00000000000..aae659516bb --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_colorspace_lib.glsl @@ -0,0 +1,16 @@ + +/* Undefine the macro that avoids compilation errors. */ +#undef blender_srgb_to_framebuffer_space + +uniform bool srgbTarget = false; + +vec4 blender_srgb_to_framebuffer_space(vec4 color) +{ + if (srgbTarget) { + vec3 c = max(color.rgb, vec3(0.0)); + vec3 c1 = c * (1.0 / 12.92); + vec3 c2 = pow((c + 0.055) * (1.0 / 1.055), vec3(2.4)); + color.rgb = mix(c1, c2, step(vec3(0.04045), c)); + } + return color; +} diff --git a/source/blender/gpu/shaders/gpu_shader_flat_color_frag.glsl b/source/blender/gpu/shaders/gpu_shader_flat_color_frag.glsl index 6c214534812..99d8b6ab685 100644 --- a/source/blender/gpu/shaders/gpu_shader_flat_color_frag.glsl +++ b/source/blender/gpu/shaders/gpu_shader_flat_color_frag.glsl @@ -5,4 +5,5 @@ out vec4 fragColor; void main() { fragColor = finalColor; + fragColor = blender_srgb_to_framebuffer_space(fragColor); } diff --git a/source/blender/gpu/shaders/gpu_shader_image_depth_copy_frag.glsl b/source/blender/gpu/shaders/gpu_shader_image_depth_copy_frag.glsl deleted file mode 100644 index 0f2749362b9..00000000000 --- a/source/blender/gpu/shaders/gpu_shader_image_depth_copy_frag.glsl +++ /dev/null @@ -1,12 +0,0 @@ - -in vec2 texCoord_interp; -out vec4 fragColor; - -uniform sampler2D image; - -void main() -{ - float depth = texture(image, texCoord_interp).r; - fragColor = vec4(depth); - gl_FragDepth = depth; -} diff --git a/source/blender/gpu/shaders/gpu_shader_image_depth_linear_frag.glsl b/source/blender/gpu/shaders/gpu_shader_image_depth_linear_frag.glsl deleted file mode 100644 index 017b21076c8..00000000000 --- a/source/blender/gpu/shaders/gpu_shader_image_depth_linear_frag.glsl +++ /dev/null @@ -1,16 +0,0 @@ - -in vec2 texCoord_interp; -out vec4 fragColor; - -uniform float znear; -uniform float zfar; -uniform sampler2D image; - -void main() -{ - float depth = texture(image, texCoord_interp).r; - - /* normalize */ - fragColor.rgb = vec3((2.0f * znear) / (zfar + znear - (depth * (zfar - znear)))); - fragColor.a = 1.0f; -} diff --git a/source/blender/gpu/shaders/gpu_shader_image_multisample_resolve_frag.glsl b/source/blender/gpu/shaders/gpu_shader_image_multisample_resolve_frag.glsl deleted file mode 100644 index ca425374a1b..00000000000 --- a/source/blender/gpu/shaders/gpu_shader_image_multisample_resolve_frag.glsl +++ /dev/null @@ -1,119 +0,0 @@ - -uniform sampler2DMS depthMulti; -uniform sampler2DMS colorMulti; - -out vec4 fragColor; - -#if SAMPLES > 16 -# error "Too many samples" -#endif - -void main() -{ - ivec2 texel = ivec2(gl_FragCoord.xy); - - bvec4 b1, b2, b3, b4; - vec4 w1, w2, w3, w4; - vec4 d1, d2, d3, d4; - vec4 c1, c2, c3, c4, c5, c6, c7, c8; - vec4 c9, c10, c11, c12, c13, c14, c15, c16; - d1 = d2 = d3 = d4 = vec4(0.5); - w1 = w2 = w3 = w4 = vec4(0.0); - c1 = c2 = c3 = c4 = c5 = c6 = c7 = c8 = vec4(0.0); - c9 = c10 = c11 = c12 = c13 = c14 = c15 = c16 = vec4(0.0); - -#ifdef USE_DEPTH - /* Depth */ - d1.x = texelFetch(depthMulti, texel, 0).r; - d1.y = texelFetch(depthMulti, texel, 1).r; -# if SAMPLES > 2 - d1.z = texelFetch(depthMulti, texel, 2).r; - d1.w = texelFetch(depthMulti, texel, 3).r; -# endif -# if SAMPLES > 4 - d2.x = texelFetch(depthMulti, texel, 4).r; - d2.y = texelFetch(depthMulti, texel, 5).r; - d2.z = texelFetch(depthMulti, texel, 6).r; - d2.w = texelFetch(depthMulti, texel, 7).r; -# endif -# if SAMPLES > 8 - d3.x = texelFetch(depthMulti, texel, 8).r; - d3.y = texelFetch(depthMulti, texel, 9).r; - d3.z = texelFetch(depthMulti, texel, 10).r; - d3.w = texelFetch(depthMulti, texel, 11).r; - d4.x = texelFetch(depthMulti, texel, 12).r; - d4.y = texelFetch(depthMulti, texel, 13).r; - d4.z = texelFetch(depthMulti, texel, 14).r; - d4.w = texelFetch(depthMulti, texel, 15).r; -# endif -#endif - - /* COLOR */ - b1 = notEqual(d1, vec4(1.0)); - if (any(b1)) { - c1 = texelFetch(colorMulti, texel, 0); - c2 = texelFetch(colorMulti, texel, 1); -#if SAMPLES > 2 - c3 = texelFetch(colorMulti, texel, 2); - c4 = texelFetch(colorMulti, texel, 3); -#endif - w1 = vec4(b1); - } -#if SAMPLES > 4 - b2 = notEqual(d2, vec4(1.0)); - if (any(b2)) { - c5 = texelFetch(colorMulti, texel, 4); - c6 = texelFetch(colorMulti, texel, 5); - c7 = texelFetch(colorMulti, texel, 6); - c8 = texelFetch(colorMulti, texel, 7); - w2 = vec4(b2); - } -#endif -#if SAMPLES > 8 - b3 = notEqual(d3, vec4(1.0)); - if (any(b3)) { - c9 = texelFetch(colorMulti, texel, 8); - c10 = texelFetch(colorMulti, texel, 9); - c11 = texelFetch(colorMulti, texel, 10); - c12 = texelFetch(colorMulti, texel, 11); - w3 = vec4(b3); - } - b4 = notEqual(d4, vec4(1.0)); - if (any(b4)) { - c13 = texelFetch(colorMulti, texel, 12); - c14 = texelFetch(colorMulti, texel, 13); - c15 = texelFetch(colorMulti, texel, 14); - c16 = texelFetch(colorMulti, texel, 15); - w4 = vec4(b4); - } -#endif - -#ifdef USE_DEPTH -# if SAMPLES > 8 - d1 = min(d1, min(d3, d4)); -# endif -# if SAMPLES > 4 - d1 = min(d1, d2); - d1 = min(d1, d2); -# endif -# if SAMPLES > 2 - d1.xy = min(d1.xy, d1.zw); -# endif - gl_FragDepth = min(d1.x, d1.y); -#endif - - c1 = c1 + c2; -#if SAMPLES > 2 - c1 += c3 + c4; -#endif -#if SAMPLES > 4 - c1 += c5 + c6 + c7 + c8; -#endif -#if SAMPLES > 8 - c1 += c9 + c10 + c11 + c12 + c13 + c14 + c15 + c16; -#endif - - const float inv_samples = 1.0 / float(SAMPLES); - - fragColor = c1 * inv_samples; -} diff --git a/source/blender/gpu/shaders/gpu_shader_simple_lighting_smooth_color_alpha_frag.glsl b/source/blender/gpu/shaders/gpu_shader_simple_lighting_smooth_color_alpha_frag.glsl deleted file mode 100644 index 2ed99be2bcf..00000000000 --- a/source/blender/gpu/shaders/gpu_shader_simple_lighting_smooth_color_alpha_frag.glsl +++ /dev/null @@ -1,14 +0,0 @@ - -uniform vec3 light; -uniform float alpha; -uniform float global; - -in vec3 normal; -in vec4 finalColor; -out vec4 fragColor; - -void main() -{ - fragColor = finalColor * (global + (1.0 - global) * max(0.0, dot(normalize(normal), light))); - fragColor.a = alpha; -} diff --git a/source/blender/gpu/shaders/gpu_shader_simple_lighting_smooth_color_frag.glsl b/source/blender/gpu/shaders/gpu_shader_simple_lighting_smooth_color_frag.glsl deleted file mode 100644 index 738b0d84e51..00000000000 --- a/source/blender/gpu/shaders/gpu_shader_simple_lighting_smooth_color_frag.glsl +++ /dev/null @@ -1,16 +0,0 @@ - -uniform vec3 light; - -#ifdef USE_FLAT_NORMAL -flat in vec3 normal; -flat in vec4 finalColor; -#else -in vec3 normal; -in vec4 finalColor; -#endif -out vec4 fragColor; - -void main() -{ - fragColor = finalColor * max(0.0, dot(normalize(normal), light)); -} diff --git a/source/blender/gpu/shaders/gpu_shader_uniform_color_frag.glsl b/source/blender/gpu/shaders/gpu_shader_uniform_color_frag.glsl index cfa82572e87..2033401db67 100644 --- a/source/blender/gpu/shaders/gpu_shader_uniform_color_frag.glsl +++ b/source/blender/gpu/shaders/gpu_shader_uniform_color_frag.glsl @@ -17,8 +17,5 @@ void main() #else fragColor = color; #endif - -#if defined(USE_BACKGROUND) - gl_FragDepth = 1.0; -#endif + fragColor = blender_srgb_to_framebuffer_space(fragColor); } diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_fractal_noise.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_fractal_noise.glsl index 701b07b4aae..f25691c1a83 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_fractal_noise.glsl +++ b/source/blender/gpu/shaders/material/gpu_shader_material_fractal_noise.glsl @@ -1,111 +1,115 @@ /* The fractal_noise functions are all exactly the same except for the input type. */ -float fractal_noise(float p, float octaves) +float fractal_noise(float p, float octaves, float roughness) { float fscale = 1.0; float amp = 1.0; + float maxamp = 0.0; float sum = 0.0; octaves = clamp(octaves, 0.0, 16.0); int n = int(octaves); for (int i = 0; i <= n; i++) { float t = noise(fscale * p); sum += t * amp; - amp *= 0.5; + maxamp += amp; + amp *= clamp(roughness, 0.0, 1.0); fscale *= 2.0; } float rmd = octaves - floor(octaves); if (rmd != 0.0) { float t = noise(fscale * p); float sum2 = sum + t * amp; - sum *= (float(1 << n) / float((1 << (n + 1)) - 1)); - sum2 *= (float(1 << (n + 1)) / float((1 << (n + 2)) - 1)); + sum /= maxamp; + sum2 /= maxamp + amp; return (1.0 - rmd) * sum + rmd * sum2; } else { - sum *= (float(1 << n) / float((1 << (n + 1)) - 1)); - return sum; + return sum / maxamp; } } /* The fractal_noise functions are all exactly the same except for the input type. */ -float fractal_noise(vec2 p, float octaves) +float fractal_noise(vec2 p, float octaves, float roughness) { float fscale = 1.0; float amp = 1.0; + float maxamp = 0.0; float sum = 0.0; octaves = clamp(octaves, 0.0, 16.0); int n = int(octaves); for (int i = 0; i <= n; i++) { float t = noise(fscale * p); sum += t * amp; - amp *= 0.5; + maxamp += amp; + amp *= clamp(roughness, 0.0, 1.0); fscale *= 2.0; } float rmd = octaves - floor(octaves); if (rmd != 0.0) { float t = noise(fscale * p); float sum2 = sum + t * amp; - sum *= (float(1 << n) / float((1 << (n + 1)) - 1)); - sum2 *= (float(1 << (n + 1)) / float((1 << (n + 2)) - 1)); + sum /= maxamp; + sum2 /= maxamp + amp; return (1.0 - rmd) * sum + rmd * sum2; } else { - sum *= (float(1 << n) / float((1 << (n + 1)) - 1)); - return sum; + return sum / maxamp; } } /* The fractal_noise functions are all exactly the same except for the input type. */ -float fractal_noise(vec3 p, float octaves) +float fractal_noise(vec3 p, float octaves, float roughness) { float fscale = 1.0; float amp = 1.0; + float maxamp = 0.0; float sum = 0.0; octaves = clamp(octaves, 0.0, 16.0); int n = int(octaves); for (int i = 0; i <= n; i++) { float t = noise(fscale * p); sum += t * amp; - amp *= 0.5; + maxamp += amp; + amp *= clamp(roughness, 0.0, 1.0); fscale *= 2.0; } float rmd = octaves - floor(octaves); if (rmd != 0.0) { float t = noise(fscale * p); float sum2 = sum + t * amp; - sum *= (float(1 << n) / float((1 << (n + 1)) - 1)); - sum2 *= (float(1 << (n + 1)) / float((1 << (n + 2)) - 1)); + sum /= maxamp; + sum2 /= maxamp + amp; return (1.0 - rmd) * sum + rmd * sum2; } else { - sum *= (float(1 << n) / float((1 << (n + 1)) - 1)); - return sum; + return sum / maxamp; } } /* The fractal_noise functions are all exactly the same except for the input type. */ -float fractal_noise(vec4 p, float octaves) +float fractal_noise(vec4 p, float octaves, float roughness) { float fscale = 1.0; float amp = 1.0; + float maxamp = 0.0; float sum = 0.0; octaves = clamp(octaves, 0.0, 16.0); int n = int(octaves); for (int i = 0; i <= n; i++) { float t = noise(fscale * p); sum += t * amp; - amp *= 0.5; + maxamp += amp; + amp *= clamp(roughness, 0.0, 1.0); fscale *= 2.0; } float rmd = octaves - floor(octaves); if (rmd != 0.0) { float t = noise(fscale * p); float sum2 = sum + t * amp; - sum *= (float(1 << n) / float((1 << (n + 1)) - 1)); - sum2 *= (float(1 << (n + 1)) / float((1 << (n + 2)) - 1)); + sum /= maxamp; + sum2 /= maxamp + amp; return (1.0 - rmd) * sum + rmd * sum2; } else { - sum *= (float(1 << n) / float((1 << (n + 1)) - 1)); - return sum; + return sum / maxamp; } } diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_output_material.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_output_material.glsl index 62f76d46088..4cb00c15b78 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_output_material.glsl +++ b/source/blender/gpu/shaders/material/gpu_shader_material_output_material.glsl @@ -1,8 +1,16 @@ -void node_output_material(Closure surface, Closure volume, vec3 displacement, out Closure result) +void node_output_material( + Closure surface, Closure volume, vec3 displacement, float alpha_threshold, out Closure result) { #ifdef VOLUMETRICS result = volume; #else result = surface; +# if defined(USE_ALPHA_HASH) + /* Alpha clip emulation. */ + if (alpha_threshold >= 0.0) { + float alpha = saturate(1.0 - avg(result.transmittance)); + result.transmittance = vec3(step(alpha, alpha_threshold)); + } +# endif #endif } diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_tex_environment.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_tex_environment.glsl index 9bd36f8a757..20a65f23c05 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_tex_environment.glsl +++ b/source/blender/gpu/shaders/material/gpu_shader_material_tex_environment.glsl @@ -15,16 +15,11 @@ void node_tex_environment_texco(vec3 viewvec, out vec3 worldvec) #endif } -void node_tex_environment_equirectangular(vec3 co, float clamp_size, sampler2D ima, out vec3 uv) +void node_tex_environment_equirectangular(vec3 co, out vec3 uv) { vec3 nco = normalize(co); uv.x = -atan(nco.y, nco.x) / (2.0 * M_PI) + 0.5; uv.y = atan(nco.z, hypot(nco.x, nco.y)) / M_PI + 0.5; - - /* Fix pole bleeding */ - float half_height = clamp_size / float(textureSize(ima, 0).y); - uv.y = clamp(uv.y, half_height, 1.0 - half_height); - uv.z = 0.0; } void node_tex_environment_mirror_ball(vec3 co, out vec3 uv) diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_tex_image.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_tex_image.glsl index c39bec8ac64..df949f7358b 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_tex_image.glsl +++ b/source/blender/gpu/shaders/material/gpu_shader_material_tex_image.glsl @@ -54,19 +54,6 @@ void node_tex_image_linear(vec3 co, sampler2D ima, out vec4 color, out float alp alpha = color.a; } -void node_tex_image_linear_no_mip(vec3 co, sampler2D ima, out vec4 color, out float alpha) -{ - color = safe_color(textureLod(ima, co.xy, 0.0)); - alpha = color.a; -} - -void node_tex_image_nearest(vec3 co, sampler2D ima, out vec4 color, out float alpha) -{ - ivec2 pix = ivec2(fract(co.xy) * textureSize(ima, 0).xy); - color = safe_color(texelFetch(ima, pix, 0)); - alpha = color.a; -} - /** \param f: Signed distance to texel center. */ void cubic_bspline_coefs(vec2 f, out vec2 w0, out vec2 w1, out vec2 w2, out vec2 w3) { @@ -79,8 +66,7 @@ void cubic_bspline_coefs(vec2 f, out vec2 w0, out vec2 w1, out vec2 w2, out vec2 w2 = 1.0 - w0 - w1 - w3; } -void node_tex_image_cubic_ex( - vec3 co, sampler2D ima, float do_extend, out vec4 color, out float alpha) +void node_tex_image_cubic(vec3 co, sampler2D ima, out vec4 color, out float alpha) { vec2 tex_size = vec2(textureSize(ima, 0).xy); @@ -101,9 +87,6 @@ void node_tex_image_cubic_ex( final_co.xy = tc - 1.0 + f0; final_co.zw = tc + 1.0 + f1; - if (do_extend == 1.0) { - final_co = clamp(final_co, vec4(0.5), tex_size.xyxy - 0.5); - } final_co /= tex_size.xyxy; color = safe_color(textureLod(ima, final_co.xy, 0.0)) * s0.x * s0.y; @@ -136,22 +119,6 @@ void node_tex_image_cubic_ex( alpha = color.a; } -void node_tex_image_cubic(vec3 co, sampler2D ima, out vec4 color, out float alpha) -{ - node_tex_image_cubic_ex(co, ima, 0.0, color, alpha); -} - -void node_tex_image_cubic_extend(vec3 co, sampler2D ima, out vec4 color, out float alpha) -{ - node_tex_image_cubic_ex(co, ima, 1.0, color, alpha); -} - -void node_tex_image_smart(vec3 co, sampler2D ima, out vec4 color, out float alpha) -{ - /* use cubic for now */ - node_tex_image_cubic_ex(co, ima, 0.0, color, alpha); -} - void tex_box_sample_linear( vec3 texco, vec3 N, sampler2D ima, out vec4 color1, out vec4 color2, out vec4 color3) { @@ -175,32 +142,6 @@ void tex_box_sample_linear( color3 = texture(ima, uv); } -void tex_box_sample_nearest( - vec3 texco, vec3 N, sampler2D ima, out vec4 color1, out vec4 color2, out vec4 color3) -{ - /* X projection */ - vec2 uv = texco.yz; - if (N.x < 0.0) { - uv.x = 1.0 - uv.x; - } - ivec2 pix = ivec2(fract(uv.xy) * textureSize(ima, 0).xy); - color1 = texelFetch(ima, pix, 0); - /* Y projection */ - uv = texco.xz; - if (N.y > 0.0) { - uv.x = 1.0 - uv.x; - } - pix = ivec2(fract(uv.xy) * textureSize(ima, 0).xy); - color2 = texelFetch(ima, pix, 0); - /* Z projection */ - uv = texco.yx; - if (N.z > 0.0) { - uv.x = 1.0 - uv.x; - } - pix = ivec2(fract(uv.xy) * textureSize(ima, 0).xy); - color3 = texelFetch(ima, pix, 0); -} - void tex_box_sample_cubic( vec3 texco, vec3 N, sampler2D ima, out vec4 color1, out vec4 color2, out vec4 color3) { @@ -210,36 +151,23 @@ void tex_box_sample_cubic( if (N.x < 0.0) { uv.x = 1.0 - uv.x; } - node_tex_image_cubic_ex(uv.xyy, ima, 0.0, color1, alpha); + node_tex_image_cubic(uv.xyy, ima, color1, alpha); /* Y projection */ uv = texco.xz; if (N.y > 0.0) { uv.x = 1.0 - uv.x; } - node_tex_image_cubic_ex(uv.xyy, ima, 0.0, color2, alpha); + node_tex_image_cubic(uv.xyy, ima, color2, alpha); /* Z projection */ uv = texco.yx; if (N.z > 0.0) { uv.x = 1.0 - uv.x; } - node_tex_image_cubic_ex(uv.xyy, ima, 0.0, color3, alpha); + node_tex_image_cubic(uv.xyy, ima, color3, alpha); } -void tex_box_sample_smart( - vec3 texco, vec3 N, sampler2D ima, out vec4 color1, out vec4 color2, out vec4 color3) -{ - tex_box_sample_cubic(texco, N, ima, color1, color2, color3); -} - -void node_tex_image_box(vec3 texco, - vec3 N, - vec4 color1, - vec4 color2, - vec4 color3, - sampler2D ima, - float blend, - out vec4 color, - out float alpha) +void tex_box_blend( + vec3 N, vec4 color1, vec4 color2, vec4 color3, float blend, out vec4 color, out float alpha) { /* project from direction vector to barycentric coordinates in triangles */ N = abs(N); @@ -284,70 +212,6 @@ void node_tex_image_box(vec3 texco, alpha = color.a; } -void tex_clip_linear(vec3 co, sampler2D ima, vec4 icolor, out vec4 color, out float alpha) -{ - vec2 tex_size = vec2(textureSize(ima, 0).xy); - vec2 minco = min(co.xy, 1.0 - co.xy); - minco = clamp(minco * tex_size + 0.5, 0.0, 1.0); - float fac = minco.x * minco.y; - - color = mix(vec4(0.0), icolor, fac); - alpha = color.a; -} - -void tex_clip_nearest(vec3 co, sampler2D ima, vec4 icolor, out vec4 color, out float alpha) -{ - vec4 minco = vec4(co.xy, 1.0 - co.xy); - color = (any(lessThan(minco, vec4(0.0)))) ? vec4(0.0) : icolor; - alpha = color.a; -} - -void tex_clip_cubic(vec3 co, sampler2D ima, vec4 icolor, out vec4 color, out float alpha) -{ - vec2 tex_size = vec2(textureSize(ima, 0).xy); - - co.xy *= tex_size; - /* texel center */ - vec2 tc = floor(co.xy - 0.5) + 0.5; - vec2 w0, w1, w2, w3; - cubic_bspline_coefs(co.xy - tc, w0, w1, w2, w3); - - /* TODO Optimize this part. I'm sure there is a smarter way to do that. - * Could do that when sampling? */ -#define CLIP_CUBIC_SAMPLE(samp, size) \ - (float(all(greaterThan(samp, vec2(-0.5)))) * float(all(lessThan(ivec2(samp), itex_size)))) - ivec2 itex_size = textureSize(ima, 0).xy; - float fac; - fac = CLIP_CUBIC_SAMPLE(tc + vec2(-1.0, -1.0), itex_size) * w0.x * w0.y; - fac += CLIP_CUBIC_SAMPLE(tc + vec2(0.0, -1.0), itex_size) * w1.x * w0.y; - fac += CLIP_CUBIC_SAMPLE(tc + vec2(1.0, -1.0), itex_size) * w2.x * w0.y; - fac += CLIP_CUBIC_SAMPLE(tc + vec2(2.0, -1.0), itex_size) * w3.x * w0.y; - - fac += CLIP_CUBIC_SAMPLE(tc + vec2(-1.0, 0.0), itex_size) * w0.x * w1.y; - fac += CLIP_CUBIC_SAMPLE(tc + vec2(0.0, 0.0), itex_size) * w1.x * w1.y; - fac += CLIP_CUBIC_SAMPLE(tc + vec2(1.0, 0.0), itex_size) * w2.x * w1.y; - fac += CLIP_CUBIC_SAMPLE(tc + vec2(2.0, 0.0), itex_size) * w3.x * w1.y; - - fac += CLIP_CUBIC_SAMPLE(tc + vec2(-1.0, 1.0), itex_size) * w0.x * w2.y; - fac += CLIP_CUBIC_SAMPLE(tc + vec2(0.0, 1.0), itex_size) * w1.x * w2.y; - fac += CLIP_CUBIC_SAMPLE(tc + vec2(1.0, 1.0), itex_size) * w2.x * w2.y; - fac += CLIP_CUBIC_SAMPLE(tc + vec2(2.0, 1.0), itex_size) * w3.x * w2.y; - - fac += CLIP_CUBIC_SAMPLE(tc + vec2(-1.0, 2.0), itex_size) * w0.x * w3.y; - fac += CLIP_CUBIC_SAMPLE(tc + vec2(0.0, 2.0), itex_size) * w1.x * w3.y; - fac += CLIP_CUBIC_SAMPLE(tc + vec2(1.0, 2.0), itex_size) * w2.x * w3.y; - fac += CLIP_CUBIC_SAMPLE(tc + vec2(2.0, 2.0), itex_size) * w3.x * w3.y; -#undef CLIP_CUBIC_SAMPLE - - color = mix(vec4(0.0), icolor, fac); - alpha = color.a; -} - -void tex_clip_smart(vec3 co, sampler2D ima, vec4 icolor, out vec4 color, out float alpha) -{ - tex_clip_cubic(co, ima, icolor, color, alpha); -} - void node_tex_image_empty(vec3 co, out vec4 color, out float alpha) { color = vec4(0.0); @@ -389,20 +253,6 @@ void node_tex_tile_linear( alpha = color.a; } -void node_tex_tile_nearest( - vec3 co, sampler2DArray ima, sampler1DArray map, out vec4 color, out float alpha) -{ - if (node_tex_tile_lookup(co, ima, map)) { - ivec3 pix = ivec3(fract(co.xy) * textureSize(ima, 0).xy, co.z); - color = safe_color(texelFetch(ima, pix, 0)); - } - else { - color = vec4(1.0, 0.0, 1.0, 1.0); - } - - alpha = color.a; -} - void node_tex_tile_cubic( vec3 co, sampler2DArray ima, sampler1DArray map, out vec4 color, out float alpha) { @@ -437,9 +287,3 @@ void node_tex_tile_cubic( alpha = color.a; } - -void node_tex_tile_smart( - vec3 co, sampler2DArray ima, sampler1DArray map, out vec4 color, out float alpha) -{ - node_tex_tile_cubic(co, ima, map, color, alpha); -} diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_tex_noise.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_tex_noise.glsl index 6aeb23b1f99..d8d9ecdf287 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_tex_noise.glsl +++ b/source/blender/gpu/shaders/material/gpu_shader_material_tex_noise.glsl @@ -32,23 +32,35 @@ vec4 random_vec4_offset(float seed) 100.0 + hash_vec2_to_float(vec2(seed, 3.0)) * 100.0); } -void node_noise_texture_1d( - vec3 co, float w, float scale, float detail, float distortion, out float value, out vec4 color) +void node_noise_texture_1d(vec3 co, + float w, + float scale, + float detail, + float roughness, + float distortion, + out float value, + out vec4 color) { float p = w * scale; if (distortion != 0.0) { p += snoise(p + random_float_offset(0.0)) * distortion; } - value = fractal_noise(p, detail); + value = fractal_noise(p, detail, roughness); color = vec4(value, - fractal_noise(p + random_float_offset(1.0), detail), - fractal_noise(p + random_float_offset(2.0), detail), + fractal_noise(p + random_float_offset(1.0), detail, roughness), + fractal_noise(p + random_float_offset(2.0), detail, roughness), 1.0); } -void node_noise_texture_2d( - vec3 co, float w, float scale, float detail, float distortion, out float value, out vec4 color) +void node_noise_texture_2d(vec3 co, + float w, + float scale, + float detail, + float roughness, + float distortion, + out float value, + out vec4 color) { vec2 p = co.xy * scale; if (distortion != 0.0) { @@ -56,15 +68,21 @@ void node_noise_texture_2d( snoise(p + random_vec2_offset(1.0)) * distortion); } - value = fractal_noise(p, detail); + value = fractal_noise(p, detail, roughness); color = vec4(value, - fractal_noise(p + random_vec2_offset(2.0), detail), - fractal_noise(p + random_vec2_offset(3.0), detail), + fractal_noise(p + random_vec2_offset(2.0), detail, roughness), + fractal_noise(p + random_vec2_offset(3.0), detail, roughness), 1.0); } -void node_noise_texture_3d( - vec3 co, float w, float scale, float detail, float distortion, out float value, out vec4 color) +void node_noise_texture_3d(vec3 co, + float w, + float scale, + float detail, + float roughness, + float distortion, + out float value, + out vec4 color) { vec3 p = co * scale; if (distortion != 0.0) { @@ -73,15 +91,21 @@ void node_noise_texture_3d( snoise(p + random_vec3_offset(2.0)) * distortion); } - value = fractal_noise(p, detail); + value = fractal_noise(p, detail, roughness); color = vec4(value, - fractal_noise(p + random_vec3_offset(3.0), detail), - fractal_noise(p + random_vec3_offset(4.0), detail), + fractal_noise(p + random_vec3_offset(3.0), detail, roughness), + fractal_noise(p + random_vec3_offset(4.0), detail, roughness), 1.0); } -void node_noise_texture_4d( - vec3 co, float w, float scale, float detail, float distortion, out float value, out vec4 color) +void node_noise_texture_4d(vec3 co, + float w, + float scale, + float detail, + float roughness, + float distortion, + out float value, + out vec4 color) { vec4 p = vec4(co, w) * scale; if (distortion != 0.0) { @@ -91,9 +115,9 @@ void node_noise_texture_4d( snoise(p + random_vec4_offset(3.0)) * distortion); } - value = fractal_noise(p, detail); + value = fractal_noise(p, detail, roughness); color = vec4(value, - fractal_noise(p + random_vec4_offset(4.0), detail), - fractal_noise(p + random_vec4_offset(5.0), detail), + fractal_noise(p + random_vec4_offset(4.0), detail, roughness), + fractal_noise(p + random_vec4_offset(5.0), detail, roughness), 1.0); } diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_tex_wave.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_tex_wave.glsl index c72f9717af3..070f42a5e30 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_tex_wave.glsl +++ b/source/blender/gpu/shaders/material/gpu_shader_material_tex_wave.glsl @@ -2,6 +2,7 @@ float calc_wave(vec3 p, float distortion, float detail, float detail_scale, + float detail_roughness, float phase, int wave_type, int bands_dir, @@ -46,7 +47,7 @@ float calc_wave(vec3 p, n += phase; if (distortion != 0.0) { - n += distortion * (fractal_noise(p * detail_scale, detail) * 2.0 - 1.0); + n += distortion * (fractal_noise(p * detail_scale, detail, detail_roughness) * 2.0 - 1.0); } if (wave_profile == 0) { /* profile sin */ @@ -67,6 +68,7 @@ void node_tex_wave(vec3 co, float distortion, float detail, float detail_scale, + float detail_roughness, float phase, float wave_type, float bands_dir, @@ -80,6 +82,7 @@ void node_tex_wave(vec3 co, distortion, detail, detail_scale, + detail_roughness, phase, int(wave_type), int(bands_dir), |