diff options
author | Clément Foucault <foucault.clem@gmail.com> | 2022-01-26 23:57:44 +0300 |
---|---|---|
committer | Clément Foucault <foucault.clem@gmail.com> | 2022-01-27 00:03:58 +0300 |
commit | 4226c484bdbe7336f1221094916fcdfb12850034 (patch) | |
tree | 33428e72be40105c222ca77935ee1554b702facc /source/blender/gpu/intern | |
parent | 55a6a8900aec81e94f4d82401d6051e3b5507c0e (diff) | |
parent | af87b6d8cb75d9d625378dee25d726a0d55f75c6 (diff) |
Merge branch 'draw-viewport-data' into eevee-rewrite
# Conflicts:
# release/scripts/startup/bl_ui/properties_data_camera.py
# source/blender/blenkernel/BKE_camera.h
# source/blender/blenkernel/BKE_node.h
# source/blender/blenkernel/intern/camera.c
# source/blender/blenlib/BLI_float2.hh
# source/blender/blenlib/BLI_float3.hh
# source/blender/blenlib/BLI_float4.hh
# source/blender/blenlib/BLI_math_geom.h
# source/blender/blenlib/intern/math_geom.c
# source/blender/draw/CMakeLists.txt
# source/blender/draw/engines/basic/basic_engine.c
# source/blender/draw/engines/eevee/eevee_cryptomatte.c
# source/blender/draw/engines/eevee/eevee_effects.c
# source/blender/draw/engines/eevee/eevee_engine.c
# source/blender/draw/engines/eevee/eevee_lightcache.c
# source/blender/draw/engines/eevee/eevee_lightcache.h
# source/blender/draw/engines/eevee/eevee_lightprobes.c
# source/blender/draw/engines/eevee/eevee_lights.c
# source/blender/draw/engines/eevee/eevee_materials.c
# source/blender/draw/engines/eevee/eevee_motion_blur.c
# source/blender/draw/engines/eevee/eevee_occlusion.c
# source/blender/draw/engines/eevee/eevee_private.h
# source/blender/draw/engines/eevee/eevee_render.c
# source/blender/draw/engines/eevee/eevee_renderpasses.c
# source/blender/draw/engines/eevee/eevee_sampling.c
# source/blender/draw/engines/eevee/eevee_screen_raytrace.c
# source/blender/draw/engines/eevee/eevee_shaders.c
# source/blender/draw/engines/eevee/eevee_shadows.c
# source/blender/draw/engines/eevee/eevee_shadows_cube.c
# source/blender/draw/engines/eevee/eevee_temporal_sampling.c
# source/blender/draw/engines/eevee/shaders/ambient_occlusion_lib.glsl
# source/blender/draw/engines/eevee/shaders/closure_eval_lib.glsl
# source/blender/draw/engines/eevee/shaders/common_utiltex_lib.glsl
# source/blender/draw/engines/eevee/shaders/effect_dof_bokeh_frag.glsl
# source/blender/draw/engines/eevee/shaders/effect_dof_gather_frag.glsl
# source/blender/draw/engines/eevee/shaders/effect_dof_reduce_frag.glsl
# source/blender/draw/engines/eevee/shaders/effect_reflection_resolve_frag.glsl
# source/blender/draw/engines/eevee/shaders/effect_temporal_aa.glsl
# source/blender/draw/engines/eevee/shaders/random_lib.glsl
# source/blender/draw/engines/eevee/shaders/shadow_vert.glsl
# source/blender/draw/engines/eevee/shaders/surface_lib.glsl
# source/blender/draw/engines/eevee/shaders/surface_vert.glsl
# source/blender/draw/engines/eevee/shaders/volumetric_lib.glsl
# source/blender/draw/engines/external/external_engine.c
# source/blender/draw/engines/gpencil/gpencil_engine.c
# source/blender/draw/engines/image/image_engine.c
# source/blender/draw/engines/overlay/overlay_engine.c
# source/blender/draw/engines/select/select_engine.c
# source/blender/draw/engines/workbench/shaders/workbench_volume_frag.glsl
# source/blender/draw/engines/workbench/shaders/workbench_volume_vert.glsl
# source/blender/draw/engines/workbench/workbench_engine.c
# source/blender/draw/engines/workbench/workbench_shader.c
# source/blender/draw/intern/DRW_render.h
# source/blender/draw/intern/draw_debug.h
# source/blender/draw/intern/draw_manager_data.c
# source/blender/draw/intern/draw_manager_exec.c
# source/blender/draw/intern/draw_view_data.h
# source/blender/gpu/CMakeLists.txt
# source/blender/gpu/GPU_material.h
# source/blender/gpu/GPU_shader.h
# source/blender/gpu/GPU_state.h
# source/blender/gpu/GPU_vertex_buffer.h
# source/blender/gpu/intern/gpu_codegen.c
# source/blender/gpu/intern/gpu_material.c
# source/blender/gpu/intern/gpu_material_library.h
# source/blender/gpu/intern/gpu_node_graph.c
# source/blender/gpu/intern/gpu_texture_private.hh
# source/blender/gpu/intern/gpu_vertex_buffer.cc
# source/blender/gpu/opengl/gl_shader.cc
# source/blender/gpu/shaders/gpu_shader_common_obinfos_lib.glsl
# source/blender/gpu/shaders/material/gpu_shader_material_shader_to_rgba.glsl
# source/blender/nodes/shader/node_shader_tree.cc
# source/blender/nodes/shader/nodes/node_shader_background.cc
# source/blender/nodes/shader/nodes/node_shader_bsdf_anisotropic.cc
# source/blender/nodes/shader/nodes/node_shader_bsdf_diffuse.cc
# source/blender/nodes/shader/nodes/node_shader_bsdf_glass.cc
# source/blender/nodes/shader/nodes/node_shader_bsdf_glossy.cc
# source/blender/nodes/shader/nodes/node_shader_bsdf_hair.cc
# source/blender/nodes/shader/nodes/node_shader_bsdf_hair_principled.c
# source/blender/nodes/shader/nodes/node_shader_bsdf_principled.c
# source/blender/nodes/shader/nodes/node_shader_bsdf_refraction.cc
# source/blender/nodes/shader/nodes/node_shader_bsdf_toon.cc
# source/blender/nodes/shader/nodes/node_shader_bsdf_translucent.cc
# source/blender/nodes/shader/nodes/node_shader_bsdf_transparent.cc
# source/blender/nodes/shader/nodes/node_shader_bsdf_velvet.cc
# source/blender/nodes/shader/nodes/node_shader_eevee_specular.cc
# source/blender/nodes/shader/nodes/node_shader_emission.cc
# source/blender/nodes/shader/nodes/node_shader_holdout.cc
# source/blender/nodes/shader/nodes/node_shader_output_material.cc
# source/blender/nodes/shader/nodes/node_shader_subsurface_scattering.c
# source/blender/nodes/shader/nodes/node_shader_tex_coord.cc
# source/blender/nodes/shader/nodes/node_shader_vector_transform.cc
# source/blender/nodes/shader/nodes/node_shader_volume_absorption.cc
# source/blender/nodes/shader/nodes/node_shader_volume_principled.cc
# source/blender/nodes/shader/nodes/node_shader_volume_scatter.cc
# source/blender/render/RE_pipeline.h
# source/blender/render/intern/initrender.c
Diffstat (limited to 'source/blender/gpu/intern')
56 files changed, 2720 insertions, 896 deletions
diff --git a/source/blender/gpu/intern/gpu_backend.hh b/source/blender/gpu/intern/gpu_backend.hh index 73792215569..00645f34173 100644 --- a/source/blender/gpu/intern/gpu_backend.hh +++ b/source/blender/gpu/intern/gpu_backend.hh @@ -42,24 +42,24 @@ class VertBuf; class GPUBackend { public: - virtual ~GPUBackend(){}; + virtual ~GPUBackend() = default; - static GPUBackend *get(void); + static GPUBackend *get(); - virtual void samplers_update(void) = 0; + virtual void samplers_update() = 0; virtual void compute_dispatch(int groups_x_len, int groups_y_len, int groups_z_len) = 0; virtual Context *context_alloc(void *ghost_window) = 0; - virtual Batch *batch_alloc(void) = 0; + virtual Batch *batch_alloc() = 0; virtual DrawList *drawlist_alloc(int list_length) = 0; virtual FrameBuffer *framebuffer_alloc(const char *name) = 0; - virtual IndexBuf *indexbuf_alloc(void) = 0; - virtual QueryPool *querypool_alloc(void) = 0; + virtual IndexBuf *indexbuf_alloc() = 0; + virtual QueryPool *querypool_alloc() = 0; virtual Shader *shader_alloc(const char *name) = 0; virtual Texture *texture_alloc(const char *name) = 0; virtual UniformBuf *uniformbuf_alloc(int size, const char *name) = 0; - virtual VertBuf *vertbuf_alloc(void) = 0; + virtual VertBuf *vertbuf_alloc() = 0; }; } // namespace gpu diff --git a/source/blender/gpu/intern/gpu_batch.cc b/source/blender/gpu/intern/gpu_batch.cc index 0e5c7900da9..2874dea775f 100644 --- a/source/blender/gpu/intern/gpu_batch.cc +++ b/source/blender/gpu/intern/gpu_batch.cc @@ -50,7 +50,7 @@ using namespace blender::gpu; /** \name Creation & Deletion * \{ */ -GPUBatch *GPU_batch_calloc(void) +GPUBatch *GPU_batch_calloc() { GPUBatch *batch = GPUBackend::get()->batch_alloc(); memset(batch, 0, sizeof(*batch)); @@ -90,7 +90,6 @@ void GPU_batch_init_ex(GPUBatch *batch, batch->shader = nullptr; } -/* This will share the VBOs with the new batch. */ void GPU_batch_copy(GPUBatch *batch_dst, GPUBatch *batch_src) { GPU_batch_init_ex( @@ -137,7 +136,6 @@ void GPU_batch_discard(GPUBatch *batch) /** \name Buffers Management * \{ */ -/* NOTE: Override ONLY the first instance vbo (and free them if owned). */ void GPU_batch_instbuf_set(GPUBatch *batch, GPUVertBuf *inst, bool own_vbo) { BLI_assert(inst); @@ -151,7 +149,6 @@ void GPU_batch_instbuf_set(GPUBatch *batch, GPUVertBuf *inst, bool own_vbo) SET_FLAG_FROM_TEST(batch->flag, own_vbo, GPU_BATCH_OWNS_INST_VBO); } -/* NOTE: Override any previously assigned elem (and free it if owned). */ void GPU_batch_elembuf_set(GPUBatch *batch, GPUIndexBuf *elem, bool own_ibo) { BLI_assert(elem); @@ -188,7 +185,6 @@ int GPU_batch_instbuf_add_ex(GPUBatch *batch, GPUVertBuf *insts, bool own_vbo) return -1; } -/* Returns the index of verts in the batch. */ int GPU_batch_vertbuf_add_ex(GPUBatch *batch, GPUVertBuf *verts, bool own_vbo) { BLI_assert(verts); @@ -243,7 +239,6 @@ void GPU_batch_draw_range(GPUBatch *batch, int v_first, int v_count) GPU_batch_draw_advanced(batch, v_first, v_count, 0, 0); } -/* Draw multiple instance of a batch without having any instance attributes. */ void GPU_batch_draw_instanced(GPUBatch *batch, int i_count) { BLI_assert(batch->inst[0] == nullptr); @@ -301,9 +296,6 @@ void GPU_batch_program_set_builtin(GPUBatch *batch, eGPUBuiltinShader shader_id) GPU_batch_program_set_builtin_with_config(batch, shader_id, GPU_SHADER_CFG_DEFAULT); } -/* Bind program bound to IMM to the batch. - * XXX Use this with much care. Drawing with the GPUBatch API is not compatible with IMM. - * DO NOT DRAW WITH THE BATCH BEFORE CALLING immUnbindProgram. */ void GPU_batch_program_set_imm_shader(GPUBatch *batch) { GPU_batch_set_shader(batch, immGetShader()); @@ -315,12 +307,12 @@ void GPU_batch_program_set_imm_shader(GPUBatch *batch) /** \name Init/Exit * \{ */ -void gpu_batch_init(void) +void gpu_batch_init() { gpu_batch_presets_init(); } -void gpu_batch_exit(void) +void gpu_batch_exit() { 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 6a1645a71d8..b97378ad638 100644 --- a/source/blender/gpu/intern/gpu_batch_presets.c +++ b/source/blender/gpu/intern/gpu_batch_presets.c @@ -154,7 +154,6 @@ GPUBatch *GPU_batch_preset_sphere_wire(int lod) /** \name Create Sphere (3D) * \{ */ -/* Replacement for gluSphere */ GPUBatch *gpu_batch_sphere(int lat_res, int lon_res) { const float lon_inc = 2 * M_PI / lon_res; @@ -331,7 +330,6 @@ GPUBatch *GPU_batch_preset_panel_drag_widget(const float pixelsize, return g_presets_2d.batch.panel_drag_widget; } -/* To be used with procedural placement inside shader. */ GPUBatch *GPU_batch_preset_quad(void) { if (!g_presets_2d.batch.quad) { diff --git a/source/blender/gpu/intern/gpu_batch_private.hh b/source/blender/gpu/intern/gpu_batch_private.hh index eed96864f20..4c2f221e9b6 100644 --- a/source/blender/gpu/intern/gpu_batch_private.hh +++ b/source/blender/gpu/intern/gpu_batch_private.hh @@ -47,7 +47,7 @@ class Batch : public GPUBatch { virtual void draw(int v_first, int v_count, int i_first, int i_count) = 0; /* Convenience casts. */ - IndexBuf *elem_(void) const + IndexBuf *elem_() const { return unwrap(elem); } diff --git a/source/blender/gpu/intern/gpu_batch_utils.c b/source/blender/gpu/intern/gpu_batch_utils.c index e2d03d27035..a381df5974a 100644 --- a/source/blender/gpu/intern/gpu_batch_utils.c +++ b/source/blender/gpu/intern/gpu_batch_utils.c @@ -33,15 +33,6 @@ /** \name Polygon Creation (2D) * \{ */ -/** - * Creates triangles from a byte-array of polygons. - * - * See 'make_shape_2d_from_blend.py' utility to create data to pass to this function. - * - * \param polys_flat: Pairs of X, Y coordinates (repeating to signify closing the polygon). - * \param polys_flat_len: Length of the array (must be an even number). - * \param rect: Optional region to map the byte 0..255 coords to. When not set use -1..1. - */ GPUBatch *GPU_batch_tris_from_poly_2d_encoded(const uchar *polys_flat, uint polys_flat_len, const rctf *rect) diff --git a/source/blender/gpu/intern/gpu_buffers.c b/source/blender/gpu/intern/gpu_buffers.c index 43483916236..dd53bea4eca 100644 --- a/source/blender/gpu/intern/gpu_buffers.c +++ b/source/blender/gpu/intern/gpu_buffers.c @@ -57,6 +57,10 @@ /* XXX: the rest of the code in this file is used for optimized PBVH * drawing and doesn't interact at all with the buffer code above */ +/* -------------------------------------------------------------------- */ +/** \name Private Types + * \{ */ + struct GPU_PBVH_Buffers { GPUIndexBuf *index_buf, *index_buf_fast; GPUIndexBuf *index_lines_buf, *index_lines_buf_fast; @@ -204,9 +208,9 @@ static bool gpu_pbvh_is_looptri_visible(const MLoopTri *lt, sculpt_face_sets[lt->poly] > SCULPT_FACE_SET_NONE); } -/* Threaded - do not call any functions that use OpenGL calls! */ void GPU_pbvh_mesh_buffers_update(GPU_PBVH_Buffers *buffers, const MVert *mvert, + const float (*vert_normals)[3], const float *vmask, const MLoopCol *vcol, const int *sculpt_face_sets, @@ -289,7 +293,7 @@ void GPU_pbvh_mesh_buffers_update(GPU_PBVH_Buffers *buffers, copy_v3_v3(GPU_vertbuf_raw_step(&pos_step), v->co); if (buffers->smooth) { - copy_v3_v3_short(no, v->no); + normal_float_to_short_v3(no, vert_normals[vtri[j]]); } copy_v3_v3_short(GPU_vertbuf_raw_step(&nor_step), no); @@ -337,7 +341,6 @@ void GPU_pbvh_mesh_buffers_update(GPU_PBVH_Buffers *buffers, buffers->mvert = mvert; } -/* Threaded - do not call any functions that use OpenGL calls! */ GPU_PBVH_Buffers *GPU_pbvh_mesh_buffers_build(const MPoly *mpoly, const MLoop *mloop, const MLoopTri *looptri, @@ -584,7 +587,6 @@ 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, @@ -764,7 +766,6 @@ void GPU_pbvh_grid_buffers_update(GPU_PBVH_Buffers *buffers, buffers->show_overlay = !empty_mask || !default_face_set; } -/* Threaded - do not call any functions that use OpenGL calls! */ GPU_PBVH_Buffers *GPU_pbvh_grid_buffers_build(int totgrid, BLI_bitmap **grid_hidden) { GPU_PBVH_Buffers *buffers; @@ -878,9 +879,6 @@ void GPU_pbvh_bmesh_buffers_update_free(GPU_PBVH_Buffers *buffers) } } -/* Creates a vertex buffer (coordinate, normal, color) and, if smooth - * shading, an element index buffer. - * Threaded - do not call any functions that use OpenGL calls! */ void GPU_pbvh_bmesh_buffers_update(GPU_PBVH_Buffers *buffers, BMesh *bm, GSet *bm_faces, @@ -1048,7 +1046,6 @@ void GPU_pbvh_bmesh_buffers_update(GPU_PBVH_Buffers *buffers, /** \name Generic * \{ */ -/* Threaded - do not call any functions that use OpenGL calls! */ GPU_PBVH_Buffers *GPU_pbvh_bmesh_buffers_build(bool smooth_shading) { GPU_PBVH_Buffers *buffers; diff --git a/source/blender/gpu/intern/gpu_capabilities.cc b/source/blender/gpu/intern/gpu_capabilities.cc index c6e9dc210cb..f12fd96d1ba 100644 --- a/source/blender/gpu/intern/gpu_capabilities.cc +++ b/source/blender/gpu/intern/gpu_capabilities.cc @@ -44,7 +44,7 @@ using namespace blender::gpu; /** \name Capabilities * \{ */ -int GPU_max_texture_size(void) +int GPU_max_texture_size() { return GCaps.max_texture_size; } @@ -57,27 +57,27 @@ int GPU_texture_size_with_limit(int res, bool limit_gl_texture_size) return min_ii(reslimit, res); } -int GPU_max_texture_layers(void) +int GPU_max_texture_layers() { return GCaps.max_texture_layers; } -int GPU_max_textures_vert(void) +int GPU_max_textures_vert() { return GCaps.max_textures_vert; } -int GPU_max_textures_geom(void) +int GPU_max_textures_geom() { return GCaps.max_textures_geom; } -int GPU_max_textures_frag(void) +int GPU_max_textures_frag() { return GCaps.max_textures_frag; } -int GPU_max_textures(void) +int GPU_max_textures() { return GCaps.max_textures; } @@ -92,37 +92,37 @@ int GPU_max_work_group_size(int index) return GCaps.max_work_group_size[index]; } -int GPU_max_uniforms_vert(void) +int GPU_max_uniforms_vert() { return GCaps.max_uniforms_vert; } -int GPU_max_uniforms_frag(void) +int GPU_max_uniforms_frag() { return GCaps.max_uniforms_frag; } -int GPU_max_batch_indices(void) +int GPU_max_batch_indices() { return GCaps.max_batch_indices; } -int GPU_max_batch_vertices(void) +int GPU_max_batch_vertices() { return GCaps.max_batch_vertices; } -int GPU_max_vertex_attribs(void) +int GPU_max_vertex_attribs() { return GCaps.max_vertex_attribs; } -int GPU_max_varying_floats(void) +int GPU_max_varying_floats() { return GCaps.max_varying_floats; } -int GPU_extensions_len(void) +int GPU_extensions_len() { return GCaps.extensions_len; } @@ -132,43 +132,43 @@ const char *GPU_extension_get(int i) return GCaps.extension_get ? GCaps.extension_get(i) : "\0"; } -bool GPU_mip_render_workaround(void) +bool GPU_mip_render_workaround() { return GCaps.mip_render_workaround; } -bool GPU_depth_blitting_workaround(void) +bool GPU_depth_blitting_workaround() { return GCaps.depth_blitting_workaround; } -bool GPU_use_main_context_workaround(void) +bool GPU_use_main_context_workaround() { return GCaps.use_main_context_workaround; } -bool GPU_crappy_amd_driver(void) +bool GPU_crappy_amd_driver() { /* Currently are the same drivers with the `unused_fb_slot` problem. */ return GCaps.broken_amd_driver; } -bool GPU_use_hq_normals_workaround(void) +bool GPU_use_hq_normals_workaround() { return GCaps.use_hq_normals_workaround; } -bool GPU_compute_shader_support(void) +bool GPU_compute_shader_support() { return GCaps.compute_shader_support; } -bool GPU_shader_storage_buffer_objects_support(void) +bool GPU_shader_storage_buffer_objects_support() { return GCaps.shader_storage_buffer_objects_support; } -bool GPU_shader_image_load_store_support(void) +bool GPU_shader_image_load_store_support() { return GCaps.shader_image_load_store_support; } @@ -179,7 +179,7 @@ bool GPU_shader_image_load_store_support(void) /** \name Memory statistics * \{ */ -bool GPU_mem_stats_supported(void) +bool GPU_mem_stats_supported() { return GCaps.mem_stats_support; } @@ -189,8 +189,7 @@ void GPU_mem_stats_get(int *totalmem, int *freemem) Context::get()->memory_statistics_get(totalmem, freemem); } -/* Return support for the active context + window. */ -bool GPU_stereo_quadbuffer_support(void) +bool GPU_stereo_quadbuffer_support() { return Context::get()->front_right != nullptr; } diff --git a/source/blender/gpu/intern/gpu_capabilities_private.hh b/source/blender/gpu/intern/gpu_capabilities_private.hh index 95cf7fd335d..1f94b6715f1 100644 --- a/source/blender/gpu/intern/gpu_capabilities_private.hh +++ b/source/blender/gpu/intern/gpu_capabilities_private.hh @@ -29,10 +29,10 @@ namespace blender::gpu { /** * This includes both hardware capabilities & workarounds. - * Try to limit these to the implementation codebase (i.e.: gpu/opengl/). + * Try to limit these to the implementation code-base (i.e.: `gpu/opengl/`). * Only add workarounds here if they are common to all implementation or * if you need access to it outside of the GPU module. - * Same goes for capabilities (i.e.: texture size) + * Same goes for capabilities (i.e.: texture size). */ struct GPUCapabilities { int max_texture_size = 0; diff --git a/source/blender/gpu/intern/gpu_context.cc b/source/blender/gpu/intern/gpu_context.cc index 943a6151ced..98714269402 100644 --- a/source/blender/gpu/intern/gpu_context.cc +++ b/source/blender/gpu/intern/gpu_context.cc @@ -109,7 +109,6 @@ GPUContext *GPU_context_create(void *ghost_window) return wrap(ctx); } -/* to be called after GPU_context_active_set(ctx_to_destroy) */ void GPU_context_discard(GPUContext *ctx_) { Context *ctx = unwrap(ctx_); @@ -117,7 +116,6 @@ void GPU_context_discard(GPUContext *ctx_) active_ctx = nullptr; } -/* ctx can be NULL */ void GPU_context_active_set(GPUContext *ctx_) { Context *ctx = unwrap(ctx_); @@ -133,7 +131,7 @@ void GPU_context_active_set(GPUContext *ctx_) } } -GPUContext *GPU_context_active_get(void) +GPUContext *GPU_context_active_get() { return wrap(Context::get()); } @@ -146,12 +144,12 @@ GPUContext *GPU_context_active_get(void) static std::mutex main_context_mutex; -void GPU_context_main_lock(void) +void GPU_context_main_lock() { main_context_mutex.lock(); } -void GPU_context_main_unlock(void) +void GPU_context_main_unlock() { main_context_mutex.unlock(); } @@ -180,7 +178,7 @@ void GPU_backend_init(eGPUBackendType backend_type) } } -void GPU_backend_exit(void) +void GPU_backend_exit() { /* TODO: assert no resource left. Currently UI textures are still not freed in their context * correctly. */ @@ -188,6 +186,15 @@ void GPU_backend_exit(void) g_backend = nullptr; } +eGPUBackendType GPU_backend_get_type() +{ + if (g_backend && dynamic_cast<GLBackend *>(g_backend) != nullptr) { + return GPU_BACKEND_OPENGL; + } + + return GPU_BACKEND_NONE; +} + GPUBackend *GPUBackend::get() { return g_backend; diff --git a/source/blender/gpu/intern/gpu_context_private.hh b/source/blender/gpu/intern/gpu_context_private.hh index 82753b44c51..d99555b3bf5 100644 --- a/source/blender/gpu/intern/gpu_context_private.hh +++ b/source/blender/gpu/intern/gpu_context_private.hh @@ -75,22 +75,22 @@ class Context { Context(); virtual ~Context(); - static Context *get(void); + static Context *get(); - virtual void activate(void) = 0; - virtual void deactivate(void) = 0; + virtual void activate() = 0; + virtual void deactivate() = 0; /* Will push all pending commands to the GPU. */ - virtual void flush(void) = 0; + virtual void flush() = 0; /* Will wait until the GPU has finished executing all command. */ - virtual void finish(void) = 0; + virtual void finish() = 0; virtual void memory_statistics_get(int *total_mem, int *free_mem) = 0; virtual void debug_group_begin(const char *, int){}; - virtual void debug_group_end(void){}; + virtual void debug_group_end(){}; - bool is_active_on_thread(void); + bool is_active_on_thread(); }; /* Syntactic sugar. */ diff --git a/source/blender/gpu/intern/gpu_debug.cc b/source/blender/gpu/intern/gpu_debug.cc index 2d9fb7822ae..85cec67d2a7 100644 --- a/source/blender/gpu/intern/gpu_debug.cc +++ b/source/blender/gpu/intern/gpu_debug.cc @@ -45,7 +45,7 @@ void GPU_debug_group_begin(const char *name) ctx->debug_group_begin(name, stack.size()); } -void GPU_debug_group_end(void) +void GPU_debug_group_end() { if (!(G.debug & G_DEBUG_GPU)) { return; @@ -55,10 +55,6 @@ void GPU_debug_group_end(void) ctx->debug_group_end(); } -/** - * Return a formatted string showing the current group hierarchy in this format: - * "Group1 > Group 2 > Group3 > ... > GroupN : " - */ void GPU_debug_get_groups_names(int name_buf_len, char *r_name_buf) { Context *ctx = Context::get(); @@ -77,7 +73,6 @@ void GPU_debug_get_groups_names(int name_buf_len, char *r_name_buf) r_name_buf[sz - 3] = '\0'; } -/* Return true if inside a debug group with the same name. */ bool GPU_debug_group_match(const char *ref) { /* Otherwise there will be no names. */ diff --git a/source/blender/gpu/intern/gpu_framebuffer.cc b/source/blender/gpu/intern/gpu_framebuffer.cc index 9099a6e4245..5b1eac2e82f 100644 --- a/source/blender/gpu/intern/gpu_framebuffer.cc +++ b/source/blender/gpu/intern/gpu_framebuffer.cc @@ -216,18 +216,12 @@ void GPU_framebuffer_bind(GPUFrameBuffer *gpu_fb) unwrap(gpu_fb)->bind(enable_srgb); } -/** - * Workaround for binding a SRGB frame-buffer without doing the SRGB transform. - */ void GPU_framebuffer_bind_no_srgb(GPUFrameBuffer *gpu_fb) { const bool enable_srgb = false; unwrap(gpu_fb)->bind(enable_srgb); } -/** - * For stereo rendering. - */ void GPU_backbuffer_bind(eGPUBackBuffer buffer) { Context *ctx = Context::get(); @@ -240,19 +234,18 @@ void GPU_backbuffer_bind(eGPUBackBuffer buffer) } } -void GPU_framebuffer_restore(void) +void GPU_framebuffer_restore() { Context::get()->back_left->bind(false); } -GPUFrameBuffer *GPU_framebuffer_active_get(void) +GPUFrameBuffer *GPU_framebuffer_active_get() { Context *ctx = Context::get(); return wrap(ctx ? ctx->active_fb : nullptr); } -/* Returns the default frame-buffer. Will always exists even if it's just a dummy. */ -GPUFrameBuffer *GPU_framebuffer_back_get(void) +GPUFrameBuffer *GPU_framebuffer_back_get() { Context *ctx = Context::get(); return wrap(ctx ? ctx->back_left : nullptr); @@ -302,12 +295,6 @@ void GPU_framebuffer_texture_detach(GPUFrameBuffer *fb, GPUTexture *tex) unwrap(tex)->detach_from(unwrap(fb)); } -/** - * First GPUAttachment in *config is always the depth/depth_stencil buffer. - * Following GPUAttachments are color buffers. - * Setting GPUAttachment.mip to -1 will leave the texture in this slot. - * Setting GPUAttachment.tex to NULL will detach the texture in this slot. - */ void GPU_framebuffer_config_array(GPUFrameBuffer *gpu_fb, const GPUAttachment *config, int config_len) @@ -341,11 +328,6 @@ void GPU_framebuffer_config_array(GPUFrameBuffer *gpu_fb, /* ---------- Viewport & Scissor Region ----------- */ -/** - * Viewport and scissor size is stored per frame-buffer. - * It is only reset to its original dimensions explicitly OR when binding the frame-buffer after - * modifying its attachments. - */ void GPU_framebuffer_viewport_set(GPUFrameBuffer *gpu_fb, int x, int y, int width, int height) { int viewport_rect[4] = {x, y, width, height}; @@ -357,9 +339,6 @@ void GPU_framebuffer_viewport_get(GPUFrameBuffer *gpu_fb, int r_viewport[4]) unwrap(gpu_fb)->viewport_get(r_viewport); } -/** - * Reset to its attachment(s) size. - */ void GPU_framebuffer_viewport_reset(GPUFrameBuffer *gpu_fb) { unwrap(gpu_fb)->viewport_reset(); @@ -376,9 +355,6 @@ void GPU_framebuffer_clear(GPUFrameBuffer *gpu_fb, unwrap(gpu_fb)->clear(buffers, clear_col, clear_depth, clear_stencil); } -/** - * Clear all textures attached to this frame-buffer with a different color. - */ void GPU_framebuffer_multi_clear(GPUFrameBuffer *gpu_fb, const float (*clear_cols)[4]) { unwrap(gpu_fb)->clear_multi(clear_cols); @@ -425,7 +401,6 @@ void GPU_frontbuffer_read_pixels( Context::get()->front_left->read(GPU_COLOR_BIT, format, rect, channels, 0, data); } -/* read_slot and write_slot are only used for color buffers. */ /* TODO(fclem): port as texture operation. */ void GPU_framebuffer_blit(GPUFrameBuffer *gpufb_read, int read_slot, @@ -466,11 +441,6 @@ void GPU_framebuffer_blit(GPUFrameBuffer *gpufb_read, prev_fb->bind(true); } -/** - * Use this if you need to custom down-sample your texture and use the previous mip-level as - * input. This function only takes care of the correct texture handling. It execute the callback - * for each texture level. - */ void GPU_framebuffer_recursive_downsample(GPUFrameBuffer *gpu_fb, int max_lvl, void (*callback)(void *userData, int level), @@ -514,14 +484,14 @@ void GPU_framebuffer_push(GPUFrameBuffer *fb) FrameBufferStack.top++; } -GPUFrameBuffer *GPU_framebuffer_pop(void) +GPUFrameBuffer *GPU_framebuffer_pop() { BLI_assert(FrameBufferStack.top > 0); FrameBufferStack.top--; return FrameBufferStack.framebuffers[FrameBufferStack.top]; } -uint GPU_framebuffer_stack_level_get(void) +uint GPU_framebuffer_stack_level_get() { return FrameBufferStack.top; } @@ -593,7 +563,7 @@ static GPUFrameBuffer *gpu_offscreen_fb_get(GPUOffScreen *ofs) GPUOffScreen *GPU_offscreen_create( int width, int height, bool depth, eGPUTextureFormat format, char err_out[256]) { - GPUOffScreen *ofs = (GPUOffScreen *)MEM_callocN(sizeof(GPUOffScreen), __func__); + GPUOffScreen *ofs = MEM_cnew<GPUOffScreen>(__func__); /* Sometimes areas can have 0 height or width and this will * create a 1D texture which we don't want. */ @@ -704,9 +674,6 @@ GPUTexture *GPU_offscreen_color_texture(const GPUOffScreen *ofs) return ofs->color; } -/** - * \note only to be used by viewport code! - */ void GPU_offscreen_viewport_data_get(GPUOffScreen *ofs, GPUFrameBuffer **r_fb, GPUTexture **r_color, diff --git a/source/blender/gpu/intern/gpu_framebuffer_private.hh b/source/blender/gpu/intern/gpu_framebuffer_private.hh index 019f3a8d940..e7505258d2a 100644 --- a/source/blender/gpu/intern/gpu_framebuffer_private.hh +++ b/source/blender/gpu/intern/gpu_framebuffer_private.hh @@ -189,24 +189,24 @@ class FrameBuffer { copy_v4_v4_int(r_scissor, scissor_); } - inline bool scissor_test_get(void) const + inline bool scissor_test_get() const { return scissor_test_; } - inline void viewport_reset(void) + inline void viewport_reset() { int viewport_rect[4] = {0, 0, width_, height_}; viewport_set(viewport_rect); } - inline void scissor_reset(void) + inline void scissor_reset() { int scissor_rect[4] = {0, 0, width_, height_}; scissor_set(scissor_rect); } - inline GPUTexture *depth_tex(void) const + inline GPUTexture *depth_tex() const { if (attachments_[GPU_FB_DEPTH_ATTACHMENT].tex) { return attachments_[GPU_FB_DEPTH_ATTACHMENT].tex; diff --git a/source/blender/gpu/intern/gpu_immediate.cc b/source/blender/gpu/intern/gpu_immediate.cc index cdd56a117db..e28776c87b3 100644 --- a/source/blender/gpu/intern/gpu_immediate.cc +++ b/source/blender/gpu/intern/gpu_immediate.cc @@ -89,7 +89,6 @@ void immUnbindProgram() imm->shader = nullptr; } -/* XXX do not use it. Special hack to use OCIO with batch API. */ GPUShader *immGetShader() { return imm->shader; @@ -603,7 +602,6 @@ void immUniform4fv(const char *name, const float data[4]) GPU_shader_uniform_4fv(imm->shader, name, data); } -/* Note array index is not supported for name (i.e: "array[0]"). */ void immUniformArray4fv(const char *name, const float *data, int count) { GPU_shader_uniform_4fv_array(imm->shader, name, count, (const float(*)[4])data); @@ -631,6 +629,12 @@ void immBindTextureSampler(const char *name, GPUTexture *tex, eGPUSamplerState s GPU_texture_bind_ex(tex, state, binding, true); } +void immBindUniformBuf(const char *name, GPUUniformBuf *ubo) +{ + int binding = GPU_shader_get_uniform_block_binding(imm->shader, name); + GPU_uniformbuf_bind(ubo, binding); +} + /* --- convenience functions for setting "uniform vec4 color" --- */ void immUniformColor4f(float r, float g, float b, float a) diff --git a/source/blender/gpu/intern/gpu_immediate_private.hh b/source/blender/gpu/intern/gpu_immediate_private.hh index 382f70eeec4..bc1ae403c52 100644 --- a/source/blender/gpu/intern/gpu_immediate_private.hh +++ b/source/blender/gpu/intern/gpu_immediate_private.hh @@ -68,11 +68,11 @@ class Immediate { Immediate(){}; virtual ~Immediate(){}; - virtual uchar *begin(void) = 0; - virtual void end(void) = 0; + virtual uchar *begin() = 0; + virtual void end() = 0; }; } // namespace blender::gpu -void immActivate(void); -void immDeactivate(void); +void immActivate(); +void immDeactivate(); diff --git a/source/blender/gpu/intern/gpu_immediate_util.c b/source/blender/gpu/intern/gpu_immediate_util.c index d18dc862ce7..37a423d41a0 100644 --- a/source/blender/gpu/intern/gpu_immediate_util.c +++ b/source/blender/gpu/intern/gpu_immediate_util.c @@ -143,17 +143,6 @@ void immRecti_complete(int x1, int y1, int x2, int y2, const float color[4]) } #endif -/** - * Pack color into 3 bytes - * - * This define converts a numerical value to the equivalent 24-bit - * color, while not being endian-sensitive. On little-endian, this - * is the same as doing a 'naive' indexing, on big-endian, it is not! - * - * \note BGR format (i.e. 0xBBGGRR)... - * - * \param x: color. - */ void imm_cpack(uint x) { immUniformColor3ub(((x)&0xFF), (((x) >> 8) & 0xFF), (((x) >> 16) & 0xFF)); @@ -163,64 +152,44 @@ static void imm_draw_circle(GPUPrimType prim_type, const uint shdr_pos, float x, float y, - float rad_x, - float rad_y, + float radius_x, + float radius_y, int nsegments) { immBegin(prim_type, nsegments); for (int i = 0; i < nsegments; i++) { const float angle = (float)(2 * M_PI) * ((float)i / (float)nsegments); - immVertex2f(shdr_pos, x + (rad_x * cosf(angle)), y + (rad_y * sinf(angle))); + immVertex2f(shdr_pos, x + (radius_x * cosf(angle)), y + (radius_y * sinf(angle))); } immEnd(); } -/** - * Draw a circle outline with the given \a radius. - * The circle is centered at \a x, \a y and drawn in the XY plane. - * - * \param shdr_pos: The vertex attribute number for position. - * \param x: Horizontal center. - * \param y: Vertical center. - * \param rad: The circle's radius. - * \param nsegments: The number of segments to use in drawing (more = smoother). - */ -void imm_draw_circle_wire_2d(uint shdr_pos, float x, float y, float rad, int nsegments) +void imm_draw_circle_wire_2d(uint shdr_pos, float x, float y, float radius, int nsegments) { - imm_draw_circle(GPU_PRIM_LINE_LOOP, shdr_pos, x, y, rad, rad, nsegments); + imm_draw_circle(GPU_PRIM_LINE_LOOP, shdr_pos, x, y, radius, radius, nsegments); } -/** - * Draw a filled circle with the given \a radius. - * The circle is centered at \a x, \a y and drawn in the XY plane. - * - * \param shdr_pos: The vertex attribute number for position. - * \param x: Horizontal center. - * \param y: Vertical center. - * \param rad: The circle's radius. - * \param nsegments: The number of segments to use in drawing (more = smoother). - */ -void imm_draw_circle_fill_2d(uint shdr_pos, float x, float y, float rad, int nsegments) +void imm_draw_circle_fill_2d(uint shdr_pos, float x, float y, float radius, int nsegments) { - imm_draw_circle(GPU_PRIM_TRI_FAN, shdr_pos, x, y, rad, rad, nsegments); + imm_draw_circle(GPU_PRIM_TRI_FAN, shdr_pos, x, y, radius, radius, nsegments); } void imm_draw_circle_wire_aspect_2d( - uint shdr_pos, float x, float y, float rad_x, float rad_y, int nsegments) + uint shdr_pos, float x, float y, float radius_x, float radius_y, int nsegments) { - imm_draw_circle(GPU_PRIM_LINE_LOOP, shdr_pos, x, y, rad_x, rad_y, nsegments); + imm_draw_circle(GPU_PRIM_LINE_LOOP, shdr_pos, x, y, radius_x, radius_y, nsegments); } void imm_draw_circle_fill_aspect_2d( - uint shdr_pos, float x, float y, float rad_x, float rad_y, int nsegments) + uint shdr_pos, float x, float y, float radius_x, float radius_y, int nsegments) { - imm_draw_circle(GPU_PRIM_TRI_FAN, shdr_pos, x, y, rad_x, rad_y, nsegments); + imm_draw_circle(GPU_PRIM_TRI_FAN, shdr_pos, x, y, radius_x, radius_y, nsegments); } static void imm_draw_circle_partial(GPUPrimType prim_type, uint pos, float x, float y, - float rad, + float radius, int nsegments, float start, float sweep) @@ -234,15 +203,15 @@ static void imm_draw_circle_partial(GPUPrimType prim_type, const float angle = interpf(angle_start, angle_end, ((float)i / (float)(nsegments - 1))); const float angle_sin = sinf(angle); const float angle_cos = cosf(angle); - immVertex2f(pos, x + rad * angle_cos, y + rad * angle_sin); + immVertex2f(pos, x + radius * angle_cos, y + radius * angle_sin); } immEnd(); } void imm_draw_circle_partial_wire_2d( - uint pos, float x, float y, float rad, int nsegments, float start, float sweep) + uint pos, float x, float y, float radius, int nsegments, float start, float sweep) { - imm_draw_circle_partial(GPU_PRIM_LINE_STRIP, pos, x, y, rad, nsegments, start, sweep); + imm_draw_circle_partial(GPU_PRIM_LINE_STRIP, pos, x, y, radius, nsegments, start, sweep); } static void imm_draw_disk_partial(GPUPrimType prim_type, @@ -274,21 +243,6 @@ static void imm_draw_disk_partial(GPUPrimType prim_type, immEnd(); } -/** - * Draw a filled arc with the given inner and outer radius. - * The circle is centered at \a x, \a y and drawn in the XY plane. - * - * \note Arguments are `gluPartialDisk` compatible. - * - * \param pos: The vertex attribute number for position. - * \param x: Horizontal center. - * \param y: Vertical center. - * \param rad_inner: The inner circle's radius. - * \param rad_outer: The outer circle's radius (can be zero). - * \param nsegments: The number of segments to use in drawing (more = smoother). - * \param start: Specifies the starting angle, in degrees, of the disk portion. - * \param sweep: Specifies the sweep angle, in degrees, of the disk portion. - */ void imm_draw_disk_partial_fill_2d(uint pos, float x, float y, @@ -303,40 +257,31 @@ void imm_draw_disk_partial_fill_2d(uint pos, } static void imm_draw_circle_3D( - GPUPrimType prim_type, uint pos, float x, float y, float rad, int nsegments) + GPUPrimType prim_type, uint pos, float x, float y, float radius, int nsegments) { immBegin(prim_type, nsegments); for (int i = 0; i < nsegments; i++) { float angle = (float)(2 * M_PI) * ((float)i / (float)nsegments); - immVertex3f(pos, x + rad * cosf(angle), y + rad * sinf(angle), 0.0f); + immVertex3f(pos, x + radius * cosf(angle), y + radius * sinf(angle), 0.0f); } immEnd(); } -void imm_draw_circle_wire_3d(uint pos, float x, float y, float rad, int nsegments) +void imm_draw_circle_wire_3d(uint pos, float x, float y, float radius, int nsegments) { - imm_draw_circle_3D(GPU_PRIM_LINE_LOOP, pos, x, y, rad, nsegments); + imm_draw_circle_3D(GPU_PRIM_LINE_LOOP, pos, x, y, radius, nsegments); } -void imm_draw_circle_dashed_3d(uint pos, float x, float y, float rad, int nsegments) +void imm_draw_circle_dashed_3d(uint pos, float x, float y, float radius, int nsegments) { - imm_draw_circle_3D(GPU_PRIM_LINES, pos, x, y, rad, nsegments / 2); + imm_draw_circle_3D(GPU_PRIM_LINES, pos, x, y, radius, nsegments / 2); } -void imm_draw_circle_fill_3d(uint pos, float x, float y, float rad, int nsegments) +void imm_draw_circle_fill_3d(uint pos, float x, float y, float radius, int nsegments) { - imm_draw_circle_3D(GPU_PRIM_TRI_FAN, pos, x, y, rad, nsegments); + imm_draw_circle_3D(GPU_PRIM_TRI_FAN, pos, x, y, radius, nsegments); } -/** - * Draw a lined box. - * - * \param pos: The vertex attribute number for position. - * \param x1: left. - * \param y1: bottom. - * \param x2: right. - * \param y2: top. - */ void imm_draw_box_wire_2d(uint pos, float x1, float y1, float x2, float y2) { immBegin(GPU_PRIM_LINE_LOOP, 4); @@ -358,9 +303,6 @@ void imm_draw_box_wire_3d(uint pos, float x1, float y1, float x2, float y2) immEnd(); } -/** - * Draw a standard checkerboard to indicate transparent backgrounds. - */ void imm_draw_box_checker_2d_ex(float x1, float y1, float x2, @@ -391,12 +333,12 @@ void imm_draw_box_checker_2d(float x1, float y1, float x2, float y2) 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]) +void imm_draw_cube_fill_3d(uint pos, const float center[3], const float aspect[3]) { float coords[ARRAY_SIZE(cube_coords)][3]; for (int i = 0; i < ARRAY_SIZE(cube_coords); i++) { - madd_v3_v3v3v3(coords[i], co, cube_coords[i], aspect); + madd_v3_v3v3v3(coords[i], center, cube_coords[i], aspect); } immBegin(GPU_PRIM_TRIS, ARRAY_SIZE(cube_quad_index) * 3 * 2); @@ -412,12 +354,12 @@ void imm_draw_cube_fill_3d(uint pos, const float co[3], const float aspect[3]) immEnd(); } -void imm_draw_cube_wire_3d(uint pos, const float co[3], const float aspect[3]) +void imm_draw_cube_wire_3d(uint pos, const float center[3], const float aspect[3]) { float coords[ARRAY_SIZE(cube_coords)][3]; for (int i = 0; i < ARRAY_SIZE(cube_coords); i++) { - madd_v3_v3v3v3(coords[i], co, cube_coords[i], aspect); + madd_v3_v3v3v3(coords[i], center, cube_coords[i], aspect); } immBegin(GPU_PRIM_LINES, ARRAY_SIZE(cube_line_index) * 2); @@ -428,18 +370,36 @@ void imm_draw_cube_wire_3d(uint pos, const float co[3], const float aspect[3]) immEnd(); } -/** - * Draw a cylinder. Replacement for gluCylinder. - * _warning_ : Slow, better use it only if you no other choices. - * - * \param pos: The vertex attribute number for position. - * \param nor: The vertex attribute number for normal. - * \param base: Specifies the radius of the cylinder at z = 0. - * \param top: Specifies the radius of the cylinder at z = height. - * \param height: Specifies the height of the cylinder. - * \param slices: Specifies the number of subdivisions around the z axis. - * \param stacks: Specifies the number of subdivisions along the z axis. - */ +void imm_draw_cube_corners_3d(uint pos, + const float center[3], + const float aspect[3], + const float factor) +{ + float coords[ARRAY_SIZE(cube_coords)][3]; + + for (int i = 0; i < ARRAY_SIZE(cube_coords); i++) { + madd_v3_v3v3v3(coords[i], center, cube_coords[i], aspect); + } + + immBegin(GPU_PRIM_LINES, ARRAY_SIZE(cube_line_index) * 4); + for (int i = 0; i < ARRAY_SIZE(cube_line_index); i++) { + float vec[3], co[3]; + sub_v3_v3v3(vec, coords[cube_line_index[i][1]], coords[cube_line_index[i][0]]); + mul_v3_fl(vec, factor); + + copy_v3_v3(co, coords[cube_line_index[i][0]]); + immVertex3fv(pos, co); + add_v3_v3(co, vec); + immVertex3fv(pos, co); + + copy_v3_v3(co, coords[cube_line_index[i][1]]); + immVertex3fv(pos, co); + sub_v3_v3(co, vec); + immVertex3fv(pos, co); + } + immEnd(); +} + void imm_draw_cylinder_fill_normal_3d( uint pos, uint nor, float base, float top, float height, int slices, int stacks) { @@ -572,3 +532,55 @@ void imm_draw_cylinder_fill_3d( } immEnd(); } + +/* Circle Drawing - Tables for Optimized Drawing Speed */ +#define CIRCLE_RESOL 32 + +static void circball_array_fill(const float verts[CIRCLE_RESOL][3], + const float cent[3], + const float radius, + const float tmat[4][4]) +{ + /* 32 values of sin function (still same result!) */ + const float sinval[CIRCLE_RESOL] = { + 0.00000000, 0.20129852, 0.39435585, 0.57126821, 0.72479278, 0.84864425, 0.93775213, + 0.98846832, 0.99871650, 0.96807711, 0.89780453, 0.79077573, 0.65137248, 0.48530196, + 0.29936312, 0.10116832, -0.10116832, -0.29936312, -0.48530196, -0.65137248, -0.79077573, + -0.89780453, -0.96807711, -0.99871650, -0.98846832, -0.93775213, -0.84864425, -0.72479278, + -0.57126821, -0.39435585, -0.20129852, 0.00000000, + }; + + /* 32 values of cos function (still same result!) */ + const float cosval[CIRCLE_RESOL] = { + 1.00000000, 0.97952994, 0.91895781, 0.82076344, 0.68896691, 0.52896401, 0.34730525, + 0.15142777, -0.05064916, -0.25065253, -0.44039415, -0.61210598, -0.75875812, -0.87434661, + -0.95413925, -0.99486932, -0.99486932, -0.95413925, -0.87434661, -0.75875812, -0.61210598, + -0.44039415, -0.25065253, -0.05064916, 0.15142777, 0.34730525, 0.52896401, 0.68896691, + 0.82076344, 0.91895781, 0.97952994, 1.00000000, + }; + + float vx[3], vy[3]; + float *viter = (float *)verts; + + mul_v3_v3fl(vx, tmat[0], radius); + mul_v3_v3fl(vy, tmat[1], radius); + + for (uint a = 0; a < CIRCLE_RESOL; a++, viter += 3) { + viter[0] = cent[0] + sinval[a] * vx[0] + cosval[a] * vy[0]; + viter[1] = cent[1] + sinval[a] * vx[1] + cosval[a] * vy[1]; + viter[2] = cent[2] + sinval[a] * vx[2] + cosval[a] * vy[2]; + } +} + +void imm_drawcircball(const float cent[3], float radius, const float tmat[4][4], uint pos) +{ + float verts[CIRCLE_RESOL][3]; + + circball_array_fill(verts, cent, radius, tmat); + + immBegin(GPU_PRIM_LINE_LOOP, CIRCLE_RESOL); + for (int i = 0; i < CIRCLE_RESOL; i++) { + immVertex3fv(pos, verts[i]); + } + immEnd(); +} diff --git a/source/blender/gpu/intern/gpu_index_buffer.cc b/source/blender/gpu/intern/gpu_index_buffer.cc index be7470e79c1..895b2a8461b 100644 --- a/source/blender/gpu/intern/gpu_index_buffer.cc +++ b/source/blender/gpu/intern/gpu_index_buffer.cc @@ -74,11 +74,16 @@ void GPU_indexbuf_init(GPUIndexBufBuilder *builder, GPUIndexBuf *GPU_indexbuf_build_on_device(uint index_len) { GPUIndexBuf *elem_ = GPU_indexbuf_calloc(); - IndexBuf *elem = unwrap(elem_); - elem->init_build_on_device(index_len); + GPU_indexbuf_init_build_on_device(elem_, index_len); return elem_; } +void GPU_indexbuf_init_build_on_device(GPUIndexBuf *elem, uint index_len) +{ + IndexBuf *elem_ = unwrap(elem); + elem_->init_build_on_device(index_len); +} + void GPU_indexbuf_join(GPUIndexBufBuilder *builder_to, const GPUIndexBufBuilder *builder_from) { BLI_assert(builder_to->data == builder_from->data); @@ -349,7 +354,7 @@ uint32_t *IndexBuf::unmap(const uint32_t *mapped_memory) const /** \name C-API * \{ */ -GPUIndexBuf *GPU_indexbuf_calloc(void) +GPUIndexBuf *GPU_indexbuf_calloc() { return wrap(GPUBackend::get()->indexbuf_alloc()); } @@ -410,9 +415,19 @@ int GPU_indexbuf_primitive_len(GPUPrimType prim_type) return indices_per_primitive(prim_type); } +void GPU_indexbuf_use(GPUIndexBuf *elem) +{ + unwrap(elem)->upload_data(); +} + void GPU_indexbuf_bind_as_ssbo(GPUIndexBuf *elem, int binding) { unwrap(elem)->bind_as_ssbo(binding); } +void GPU_indexbuf_update_sub(GPUIndexBuf *elem, uint start, uint len, const void *data) +{ + unwrap(elem)->update_sub(start, len, data); +} + /** \} */ diff --git a/source/blender/gpu/intern/gpu_index_buffer_private.hh b/source/blender/gpu/intern/gpu_index_buffer_private.hh index ed7dd830c8c..4bb46689727 100644 --- a/source/blender/gpu/intern/gpu_index_buffer_private.hh +++ b/source/blender/gpu/intern/gpu_index_buffer_private.hh @@ -77,26 +77,30 @@ class IndexBuf { void init_subrange(IndexBuf *elem_src, uint start, uint length); void init_build_on_device(uint index_len); - uint32_t index_len_get(void) const + uint32_t index_len_get() const { return index_len_; } /* Return size in byte of the drawable data buffer range. Actual buffer size might be bigger. */ - size_t size_get(void) const + size_t size_get() const { return index_len_ * to_bytesize(index_type_); }; - bool is_init(void) const + bool is_init() const { return is_init_; }; + virtual void upload_data() = 0; + virtual void bind_as_ssbo(uint binding) = 0; virtual const uint32_t *read() const = 0; uint32_t *unmap(const uint32_t *mapped_memory) const; + virtual void update_sub(uint start, uint len, const void *data) = 0; + private: inline void squeeze_indices_short(uint min_idx, uint max_idx); inline uint index_range(uint *r_min, uint *r_max); diff --git a/source/blender/gpu/intern/gpu_init_exit.c b/source/blender/gpu/intern/gpu_init_exit.c index 0eb2fe57c28..5815fb10b0c 100644 --- a/source/blender/gpu/intern/gpu_init_exit.c +++ b/source/blender/gpu/intern/gpu_init_exit.c @@ -32,6 +32,8 @@ #include "intern/gpu_codegen.h" #include "intern/gpu_material_library.h" #include "intern/gpu_private.h" +#include "intern/gpu_shader_create_info_private.hh" +#include "intern/gpu_shader_dependency_private.h" /** * although the order of initialization and shutdown should not matter @@ -49,6 +51,9 @@ void GPU_init(void) initialized = true; + gpu_shader_dependency_init(); + gpu_shader_create_info_init(); + gpu_codegen_init(); gpu_material_library_init(); @@ -70,6 +75,9 @@ void GPU_exit(void) gpu_material_library_exit(); gpu_codegen_exit(); + gpu_shader_dependency_exit(); + gpu_shader_create_info_exit(); + initialized = false; } diff --git a/source/blender/gpu/intern/gpu_material.c b/source/blender/gpu/intern/gpu_material.c index e40d6195eab..ca1f45f7238 100644 --- a/source/blender/gpu/intern/gpu_material.c +++ b/source/blender/gpu/intern/gpu_material.c @@ -44,6 +44,8 @@ #include "BKE_scene.h" #include "BKE_world.h" +#include "NOD_shader.h" + #include "GPU_material.h" #include "GPU_shader.h" #include "GPU_texture.h" @@ -84,6 +86,7 @@ struct GPUMaterial { Material *ma; /** 1D Texture array containing all color bands. */ GPUTexture *coba_tex; + GPUColorBandBuilder *coba_builder; /* Low level node graph(s). Also contains resources needed by the material. */ GPUNodeGraph graph; @@ -100,7 +103,6 @@ enum { /* Functions */ -/* Returns the address of the future pointer to coba_tex */ GPUTexture **gpu_material_ramp_texture_row_set(GPUMaterial *mat, int size, float *pixels, @@ -189,7 +191,6 @@ 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) { return material->ma; @@ -200,11 +201,6 @@ GPUUniformBuf *GPU_material_uniform_buffer_get(GPUMaterial *material) return material->ubo; } -/** - * Create dynamic UBO from parameters - * - * \param inputs: Items are #LinkData, data is #GPUInput (`BLI_genericNodeN(GPUInput)`). - */ void GPU_material_uniform_buffer_create(GPUMaterial *material, ListBase *inputs) { #ifndef NDEBUG @@ -332,9 +328,9 @@ GPUMaterial *GPU_material_from_nodetree(Scene *scene, bNodeTree *ntree, ListBase *gpumaterials, const char *name, - const uint64_t shader_uuid, - const bool is_volume_shader, - const bool is_lookdev, + uint64_t shader_uuid, + bool is_volume_shader, + bool is_lookdev, GPUCodegenCallbackFn callback, void *thunk) { diff --git a/source/blender/gpu/intern/gpu_material_library.c b/source/blender/gpu/intern/gpu_material_library.c index 6d14993e2ac..6f68729eaae 100644 --- a/source/blender/gpu/intern/gpu_material_library.c +++ b/source/blender/gpu/intern/gpu_material_library.c @@ -62,6 +62,7 @@ extern char datatoc_gpu_shader_material_diffuse_glsl[]; extern char datatoc_gpu_shader_material_displacement_glsl[]; extern char datatoc_gpu_shader_material_eevee_specular_glsl[]; extern char datatoc_gpu_shader_material_emission_glsl[]; +extern char datatoc_gpu_shader_material_float_curve_glsl[]; extern char datatoc_gpu_shader_material_fractal_noise_glsl[]; extern char datatoc_gpu_shader_material_fresnel_glsl[]; extern char datatoc_gpu_shader_material_gamma_glsl[]; @@ -90,6 +91,7 @@ extern char datatoc_gpu_shader_material_output_aov_glsl[]; extern char datatoc_gpu_shader_material_output_material_glsl[]; extern char datatoc_gpu_shader_material_output_world_glsl[]; extern char datatoc_gpu_shader_material_particle_info_glsl[]; +extern char datatoc_gpu_shader_material_point_info_glsl[]; extern char datatoc_gpu_shader_material_principled_glsl[]; extern char datatoc_gpu_shader_material_refraction_glsl[]; extern char datatoc_gpu_shader_material_rgb_curves_glsl[]; @@ -262,6 +264,11 @@ static GPUMaterialLibrary gpu_shader_material_emission_library = { .dependencies = {NULL}, }; +static GPUMaterialLibrary gpu_shader_material_float_curve_library = { + .code = datatoc_gpu_shader_material_float_curve_glsl, + .dependencies = {NULL}, +}; + static GPUMaterialLibrary gpu_shader_material_fresnel_library = { .code = datatoc_gpu_shader_material_fresnel_glsl, .dependencies = {NULL}, @@ -289,7 +296,7 @@ static GPUMaterialLibrary gpu_shader_material_glass_library = { static GPUMaterialLibrary gpu_shader_material_hair_info_library = { .code = datatoc_gpu_shader_material_hair_info_glsl, - .dependencies = {NULL}, + .dependencies = {&gpu_shader_material_hash_library, NULL}, }; static GPUMaterialLibrary gpu_shader_material_holdout_library = { @@ -382,6 +389,11 @@ static GPUMaterialLibrary gpu_shader_material_particle_info_library = { .dependencies = {NULL}, }; +static GPUMaterialLibrary gpu_shader_material_point_info_library = { + .code = datatoc_gpu_shader_material_point_info_glsl, + .dependencies = {&gpu_shader_material_hash_library, NULL}, +}; + static GPUMaterialLibrary gpu_shader_material_principled_library = { .code = datatoc_gpu_shader_material_principled_glsl, .dependencies = {NULL}, @@ -591,6 +603,7 @@ static GPUMaterialLibrary *gpu_material_libraries[] = { &gpu_shader_material_color_util_library, &gpu_shader_material_hash_library, &gpu_shader_material_noise_library, + &gpu_shader_material_float_curve_library, &gpu_shader_material_fractal_noise_library, &gpu_shader_material_add_shader_library, &gpu_shader_material_ambient_occlusion_library, @@ -637,6 +650,7 @@ static GPUMaterialLibrary *gpu_material_libraries[] = { &gpu_shader_material_output_material_library, &gpu_shader_material_output_world_library, &gpu_shader_material_particle_info_library, + &gpu_shader_material_point_info_library, &gpu_shader_material_principled_library, &gpu_shader_material_refraction_library, &gpu_shader_material_rgb_curves_library, diff --git a/source/blender/gpu/intern/gpu_material_library.h b/source/blender/gpu/intern/gpu_material_library.h index 139f5200f59..d9c56ddd425 100644 --- a/source/blender/gpu/intern/gpu_material_library.h +++ b/source/blender/gpu/intern/gpu_material_library.h @@ -67,7 +67,7 @@ char *gpu_material_library_generate_code(struct GSet *used_libraries); /* Code Parsing */ const char *gpu_str_skip_token(const char *str, char *token, int max); -const char *gpu_data_type_to_string(const eGPUType type); +const char *gpu_data_type_to_string(eGPUType type); #ifdef __cplusplus } diff --git a/source/blender/gpu/intern/gpu_matrix.cc b/source/blender/gpu/intern/gpu_matrix.cc index bbcc241f5e3..cf3f7f5e778 100644 --- a/source/blender/gpu/intern/gpu_matrix.cc +++ b/source/blender/gpu/intern/gpu_matrix.cc @@ -67,7 +67,7 @@ struct GPUMatrixState { #define ProjectionStack Context::get()->matrix_state->projection_stack #define Projection ProjectionStack.stack[ProjectionStack.top] -GPUMatrixState *GPU_matrix_state_create(void) +GPUMatrixState *GPU_matrix_state_create() { #define MATRIX_4X4_IDENTITY \ { \ @@ -99,7 +99,7 @@ static void gpu_matrix_state_active_set_dirty(bool value) state->dirty = value; } -void GPU_matrix_reset(void) +void GPU_matrix_reset() { GPUMatrixState *state = Context::get()->matrix_state; state->model_view_stack.top = 0; @@ -132,28 +132,28 @@ static void checkmat(cosnt float *m) #endif -void GPU_matrix_push(void) +void GPU_matrix_push() { BLI_assert(ModelViewStack.top + 1 < MATRIX_STACK_DEPTH); ModelViewStack.top++; copy_m4_m4(ModelView, ModelViewStack.stack[ModelViewStack.top - 1]); } -void GPU_matrix_pop(void) +void GPU_matrix_pop() { BLI_assert(ModelViewStack.top > 0); ModelViewStack.top--; gpu_matrix_state_active_set_dirty(true); } -void GPU_matrix_push_projection(void) +void GPU_matrix_push_projection() { BLI_assert(ProjectionStack.top + 1 < MATRIX_STACK_DEPTH); ProjectionStack.top++; copy_m4_m4(Projection, ProjectionStack.stack[ProjectionStack.top - 1]); } -void GPU_matrix_pop_projection(void) +void GPU_matrix_pop_projection() { BLI_assert(ProjectionStack.top > 0); ProjectionStack.top--; @@ -167,7 +167,7 @@ void GPU_matrix_set(const float m[4][4]) gpu_matrix_state_active_set_dirty(true); } -void GPU_matrix_identity_projection_set(void) +void GPU_matrix_identity_projection_set() { unit_m4(Projection); CHECKMAT(Projection3D); @@ -181,7 +181,7 @@ void GPU_matrix_projection_set(const float m[4][4]) gpu_matrix_state_active_set_dirty(true); } -void GPU_matrix_identity_set(void) +void GPU_matrix_identity_set() { unit_m4(ModelView); gpu_matrix_state_active_set_dirty(true); @@ -668,7 +668,7 @@ void GPU_matrix_bind(GPUShader *shader) gpu_matrix_state_active_set_dirty(false); } -bool GPU_matrix_dirty_get(void) +bool GPU_matrix_dirty_get() { GPUMatrixState *state = Context::get()->matrix_state; return state->dirty; @@ -677,17 +677,18 @@ bool GPU_matrix_dirty_get(void) /* -------------------------------------------------------------------- */ /** \name Python API Helpers * \{ */ + BLI_STATIC_ASSERT(GPU_PY_MATRIX_STACK_LEN + 1 == MATRIX_STACK_DEPTH, "define mismatch"); /* Return int since caller is may subtract. */ -int GPU_matrix_stack_level_get_model_view(void) +int GPU_matrix_stack_level_get_model_view() { GPUMatrixState *state = Context::get()->matrix_state; return (int)state->model_view_stack.top; } -int GPU_matrix_stack_level_get_projection(void) +int GPU_matrix_stack_level_get_projection() { GPUMatrixState *state = Context::get()->matrix_state; return (int)state->projection_stack.top; @@ -733,9 +734,6 @@ float GPU_polygon_offset_calc(const float (*winmat)[4], float viewdist, float di return winmat[3][2] * -0.0025f * dist; } -/** - * \note \a viewdist is only for ortho at the moment. - */ void GPU_polygon_offset(float viewdist, float dist) { static float winmat[4][4], offset = 0.0f; diff --git a/source/blender/gpu/intern/gpu_node_graph.c b/source/blender/gpu/intern/gpu_node_graph.c index 7d1bd763a5b..593a89bbf21 100644 --- a/source/blender/gpu/intern/gpu_node_graph.c +++ b/source/blender/gpu/intern/gpu_node_graph.c @@ -435,7 +435,10 @@ static GPUMaterialTexture *gpu_node_graph_add_texture(GPUNodeGraph *graph, if (tex == NULL) { tex = MEM_callocN(sizeof(*tex), __func__); tex->ima = ima; - tex->iuser = iuser; + if (iuser != NULL) { + tex->iuser = *iuser; + tex->iuser_available = true; + } tex->colorband = colorband; tex->sampler_state = sampler_state; BLI_snprintf(tex->sampler_name, sizeof(tex->sampler_name), "samp%d", num_textures); @@ -644,25 +647,27 @@ bool GPU_link(GPUMaterial *mat, const char *name, ...) } va_end(params); + GPUNodeGraph *graph = gpu_material_node_graph(mat); BLI_addtail(&graph->nodes, node); return true; } -static bool gpu_stack_link_v(GPUMaterial *material, - bNode *bnode, - const char *name, - GPUNodeStack *in, - GPUNodeStack *out, - va_list params) +bool GPU_stack_link(GPUMaterial *material, + bNode *bnode, + const char *name, + GPUNodeStack *in, + GPUNodeStack *out, + ...) { - GPUNodeGraph *graph = gpu_material_node_graph(material); + GSet *used_libraries = gpu_material_used_libraries(material); GPUNode *node; GPUFunction *function; GPUNodeLink *link, **linkptr; + va_list params; int i, totin, totout; - function = gpu_material_library_use_function(graph->used_libraries, name); + function = gpu_material_library_use_function(used_libraries, name); if (!function) { fprintf(stderr, "GPU failed to find function %s\n", name); return false; @@ -690,6 +695,7 @@ static bool gpu_stack_link_v(GPUMaterial *material, } } + va_start(params, out); for (i = 0; i < function->totparam; i++) { if (function->paramqual[i] != FUNCTION_QUAL_IN) { if (totout == 0) { @@ -715,53 +721,14 @@ static bool gpu_stack_link_v(GPUMaterial *material, } } } + va_end(params); + GPUNodeGraph *graph = gpu_material_node_graph(material); BLI_addtail(&graph->nodes, node); return true; } -bool GPU_stack_link(GPUMaterial *material, - bNode *bnode, - const char *name, - GPUNodeStack *in, - GPUNodeStack *out, - ...) -{ - va_list params; - va_start(params, out); - bool valid = gpu_stack_link_v(material, bnode, name, in, out, params); - va_end(params); - - return valid; -} - -/* This is a special function to call the "*_eval" function of a BSDF node. - * This must be call right after GPU_stack_link() so that out[0] contains a valid link. */ -bool GPU_stack_eval_link(GPUMaterial *material, - bNode *bnode, - const char *name, - GPUNodeStack *in, - GPUNodeStack *out, - ...) -{ - /* Save the closure link to replace the one created by the eval function call. Avoiding - * dependency to the eval call before the end of the graph. */ - GPUNodeLink *closure_out = out[0].link; - - va_list params; - va_start(params, out); - bool valid = gpu_stack_link_v(material, bnode, name, in, out, params); - va_end(params); - - /* Save both nodes for graph amendment. */ - GPU_material_add_closure_eval(material, closure_out, out[0].link); - /* Restore original link. */ - out[0].link = closure_out; - - return valid; -} - GPUNodeLink *GPU_uniformbuf_link_out(GPUMaterial *mat, bNode *node, GPUNodeStack *stack, @@ -815,7 +782,6 @@ static void gpu_node_free(GPUNode *node) MEM_freeN(node); } -/* Free intermediate node graph. */ void gpu_node_graph_free_nodes(GPUNodeGraph *graph) { GPUNode *node; @@ -824,14 +790,9 @@ void gpu_node_graph_free_nodes(GPUNodeGraph *graph) gpu_node_free(node); } - BLI_freelistN(&graph->eval_nodes); - graph->outlink_surface = NULL; - graph->outlink_volume = NULL; - graph->outlink_displacement = NULL; - graph->outlink_thickness = NULL; + graph->outlink = NULL; } -/* Free both node graph, requested attributes and textures. */ void gpu_node_graph_free(GPUNodeGraph *graph) { BLI_freelistN(&graph->outlink_aovs); @@ -844,32 +805,28 @@ void gpu_node_graph_free(GPUNodeGraph *graph) BLI_freelistN(&graph->textures); BLI_freelistN(&graph->attributes); GPU_uniform_attr_list_free(&graph->uniform_attrs); - - if (graph->used_libraries) { - BLI_gset_free(graph->used_libraries, NULL); - graph->used_libraries = NULL; - } } /* Prune Unused Nodes */ -static void gpu_nodes_tag(GPUNodeLink *link, eGPUNodeTag tag) +static void gpu_nodes_tag(GPUNodeLink *link) { GPUNode *node; + GPUInput *input; - if (!link || !link->output) { + if (!link->output) { return; } node = link->output->node; - if (node->tag & tag) { + if (node->tag) { return; } - node->tag |= tag; - LISTBASE_FOREACH (GPUInput *, input, &node->inputs) { + node->tag = true; + for (input = node->inputs.first; input; input = input->next) { if (input->link) { - gpu_nodes_tag(input->link, tag); + gpu_nodes_tag(input->link); } } } @@ -877,30 +834,18 @@ static void gpu_nodes_tag(GPUNodeLink *link, eGPUNodeTag tag) void gpu_node_graph_prune_unused(GPUNodeGraph *graph) { LISTBASE_FOREACH (GPUNode *, node, &graph->nodes) { - node->tag = GPU_NODE_TAG_NONE; + node->tag = false; } - gpu_nodes_tag(graph->outlink_surface, GPU_NODE_TAG_SURFACE); - gpu_nodes_tag(graph->outlink_volume, GPU_NODE_TAG_VOLUME); - gpu_nodes_tag(graph->outlink_displacement, GPU_NODE_TAG_DISPLACEMENT); - gpu_nodes_tag(graph->outlink_thickness, GPU_NODE_TAG_THICKNESS); - + gpu_nodes_tag(graph->outlink); LISTBASE_FOREACH (GPUNodeGraphOutputLink *, aovlink, &graph->outlink_aovs) { - gpu_nodes_tag(aovlink->outlink, GPU_NODE_TAG_AOV); - } - - LISTBASE_FOREACH (GPUNodeGraphEvalNode *, node, &graph->eval_nodes) { - /* Copy weight node tag to avoid pruning of eval node since they are node connected to - * output. */ - if (node->weight_node->tag != GPU_NODE_TAG_NONE) { - node->eval_node->tag = GPU_NODE_TAG_EVAL | node->weight_node->tag; - } + gpu_nodes_tag(aovlink->outlink); } for (GPUNode *node = graph->nodes.first, *next = NULL; node; node = next) { next = node->next; - if (node->tag == GPU_NODE_TAG_NONE) { + if (!node->tag) { BLI_remlink(&graph->nodes, node); gpu_node_free(node); } diff --git a/source/blender/gpu/intern/gpu_node_graph.h b/source/blender/gpu/intern/gpu_node_graph.h index b3e9690dd32..9f1a729738b 100644 --- a/source/blender/gpu/intern/gpu_node_graph.h +++ b/source/blender/gpu/intern/gpu_node_graph.h @@ -191,12 +191,21 @@ typedef struct GPUNodeGraph { void gpu_node_graph_prune_unused(GPUNodeGraph *graph); void gpu_node_graph_finalize_uniform_attrs(GPUNodeGraph *graph); +/** + * Free intermediate node graph. + */ void gpu_node_graph_free_nodes(GPUNodeGraph *graph); +/** + * Free both node graph and requested attributes and textures. + */ void gpu_node_graph_free(GPUNodeGraph *graph); /* Material calls */ struct GPUNodeGraph *gpu_material_node_graph(struct GPUMaterial *material); +/** + * Returns the address of the future pointer to coba_tex. + */ struct GPUTexture **gpu_material_ramp_texture_row_set(struct GPUMaterial *mat, int size, float *pixels, diff --git a/source/blender/gpu/intern/gpu_platform.cc b/source/blender/gpu/intern/gpu_platform.cc index 49dde473300..34834a62268 100644 --- a/source/blender/gpu/intern/gpu_platform.cc +++ b/source/blender/gpu/intern/gpu_platform.cc @@ -127,37 +127,36 @@ eGPUSupportLevel GPU_platform_support_level() return GPG.support_level; } -const char *GPU_platform_vendor(void) +const char *GPU_platform_vendor() { BLI_assert(GPG.initialized); return GPG.vendor; } -const char *GPU_platform_renderer(void) +const char *GPU_platform_renderer() { BLI_assert(GPG.initialized); return GPG.renderer; } -const char *GPU_platform_version(void) +const char *GPU_platform_version() { BLI_assert(GPG.initialized); return GPG.version; } -const char *GPU_platform_support_level_key(void) +const char *GPU_platform_support_level_key() { BLI_assert(GPG.initialized); return GPG.support_key; } -const char *GPU_platform_gpu_name(void) +const char *GPU_platform_gpu_name() { BLI_assert(GPG.initialized); return GPG.gpu_name; } -/* GPU Types */ bool GPU_type_matches(eGPUDeviceType device, eGPUOSType os, eGPUDriverType driver) { BLI_assert(GPG.initialized); diff --git a/source/blender/gpu/intern/gpu_platform_private.hh b/source/blender/gpu/intern/gpu_platform_private.hh index f823269ab54..faae7c48588 100644 --- a/source/blender/gpu/intern/gpu_platform_private.hh +++ b/source/blender/gpu/intern/gpu_platform_private.hh @@ -49,7 +49,7 @@ class GPUPlatformGlobal { const char *renderer_str, const char *version_str); - void clear(void); + void clear(); }; extern GPUPlatformGlobal GPG; diff --git a/source/blender/gpu/intern/gpu_query.hh b/source/blender/gpu/intern/gpu_query.hh index 0356e145b00..a004c355c8f 100644 --- a/source/blender/gpu/intern/gpu_query.hh +++ b/source/blender/gpu/intern/gpu_query.hh @@ -45,8 +45,8 @@ class QueryPool { * Will start and end the query at this index inside the pool. * The pool will resize automatically. */ - virtual void begin_query(void) = 0; - virtual void end_query(void) = 0; + virtual void begin_query() = 0; + virtual void end_query() = 0; /** * Must be fed with a buffer large enough to contain all the queries issued. diff --git a/source/blender/gpu/intern/gpu_select.c b/source/blender/gpu/intern/gpu_select.c index 88b704a84a1..958aab65b57 100644 --- a/source/blender/gpu/intern/gpu_select.c +++ b/source/blender/gpu/intern/gpu_select.c @@ -20,8 +20,8 @@ /** \file * \ingroup gpu * - * Interface for accessing gpu-related methods for selection. The semantics are - * similar to glRenderMode(GL_SELECT) from older OpenGL versions. + * Interface for accessing GPU-related methods for selection. The semantics are + * similar to `glRenderMode(GL_SELECT)` from older OpenGL versions. */ #include <stdlib.h> #include <string.h> @@ -38,6 +38,10 @@ #include "gpu_select_private.h" +/* -------------------------------------------------------------------- */ +/** \name Internal Types + * \{ */ + /* Internal algorithm used */ enum { /** glBegin/EndQuery(GL_SAMPLES_PASSED... ), `gpu_select_query.c` @@ -57,13 +61,25 @@ typedef struct GPUSelectState { char algorithm; /* allow GPU_select_begin/end without drawing */ bool use_cache; + /** + * Signifies that #GPU_select_cache_begin has been called, + * future calls to #GPU_select_begin should initialize the cache. + * + * \note #GPU_select_cache_begin could perform initialization but doesn't as it's inconvenient + * for callers making the cache begin/end calls outside lower level selection logic + * where the `mode` to pass to #GPU_select_begin yet isn't known. + */ + bool use_cache_needs_init; } GPUSelectState; static GPUSelectState g_select_state = {0}; -/** - * initialize and provide buffer for results - */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Public API + * \{ */ + void GPU_select_begin(uint *buffer, uint bufsize, const rcti *input, char mode, int oldhits) { if (mode == GPU_SELECT_NEAREST_SECOND_PASS) { @@ -83,9 +99,26 @@ void GPU_select_begin(uint *buffer, uint bufsize, const rcti *input, char mode, g_select_state.algorithm = ALGO_GL_QUERY; } + /* This function is called when cache has already been initialized, + * so only manipulate cache values when cache is pending. */ + if (g_select_state.use_cache_needs_init) { + g_select_state.use_cache_needs_init = false; + + switch (g_select_state.algorithm) { + case ALGO_GL_QUERY: { + g_select_state.use_cache = false; + break; + } + default: { + g_select_state.use_cache = true; + gpu_select_pick_cache_begin(); + break; + } + } + } + switch (g_select_state.algorithm) { case ALGO_GL_QUERY: { - g_select_state.use_cache = false; gpu_select_query_begin((uint(*)[4])buffer, bufsize / 4, input, mode, oldhits); break; } @@ -97,14 +130,6 @@ void GPU_select_begin(uint *buffer, uint bufsize, const rcti *input, char mode, } } -/** - * loads a new selection id and ends previous query, if any. - * In second pass of selection it also returns - * if id has been hit on the first pass already. - * Thus we can skip drawing un-hit objects. - * - * \warning We rely on the order of object rendering on passes to be the same for this to work. - */ bool GPU_select_load_id(uint id) { /* if no selection mode active, ignore */ @@ -123,11 +148,6 @@ bool GPU_select_load_id(uint id) } } -/** - * Cleanup and flush selection results to buffer. - * Return number of hits and hits in buffer. - * if \a dopass is true, we will do a second pass with occlusion queries to get the closest hit. - */ uint GPU_select_end(void) { uint hits = 0; @@ -149,21 +169,24 @@ uint GPU_select_end(void) return hits; } -/* ---------------------------------------------------------------------------- - * Caching +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Caching * * Support multiple begin/end's as long as they are within the initial region. - * Currently only used by ALGO_GL_PICK. - */ + * Currently only used by #ALGO_GL_PICK. + * \{ */ void GPU_select_cache_begin(void) { - /* validate on GPU_select_begin, clear if not supported */ - BLI_assert(g_select_state.use_cache == false); - g_select_state.use_cache = true; - if (g_select_state.algorithm == ALGO_GL_PICK) { - gpu_select_pick_cache_begin(); - } + BLI_assert(g_select_state.select_is_active == false); + /* Ensure #GPU_select_cache_end is always called. */ + BLI_assert(g_select_state.use_cache_needs_init == false); + + /* Signal that cache should be used, instead of calling the algorithms cache-begin function. + * This is more convenient as the exact method of selection may not be known by the caller. */ + g_select_state.use_cache_needs_init = true; } void GPU_select_cache_load_id(void) @@ -177,9 +200,12 @@ void GPU_select_cache_load_id(void) void GPU_select_cache_end(void) { if (g_select_state.algorithm == ALGO_GL_PICK) { + BLI_assert(g_select_state.use_cache == true); gpu_select_pick_cache_end(); } g_select_state.use_cache = false; + /* Paranoid assignment, should already be false. */ + g_select_state.use_cache_needs_init = false; } bool GPU_select_is_cached(void) @@ -187,16 +213,12 @@ bool GPU_select_is_cached(void) return g_select_state.use_cache && gpu_select_pick_is_cached(); } -/* ---------------------------------------------------------------------------- - * Utilities - */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Utilities + * \{ */ -/** - * Helper function, nothing special but avoids doing inline since hits aren't sorted by depth - * and purpose of 4x buffer indices isn't so clear. - * - * Note that comparing depth as uint is fine. - */ const uint *GPU_select_buffer_near(const uint *buffer, int hits) { const uint *buffer_near = NULL; @@ -230,7 +252,6 @@ uint GPU_select_buffer_remove_by_id(uint *buffer, int hits, uint select_id) return hits_final; } -/* Part of the solution copied from `rect_subregion_stride_calc`. */ void GPU_select_buffer_stride_realign(const rcti *src, const rcti *dst, uint *r_buf) { const int x = dst->xmin - src->xmin; @@ -269,3 +290,5 @@ void GPU_select_buffer_stride_realign(const rcti *src, const rcti *dst, uint *r_ } memset(r_buf, 0, (last_px_id + 1) * sizeof(*r_buf)); } + +/** \} */ diff --git a/source/blender/gpu/intern/gpu_select_pick.c b/source/blender/gpu/intern/gpu_select_pick.c index 7fb704c29dd..ddd3dfc6879 100644 --- a/source/blender/gpu/intern/gpu_select_pick.c +++ b/source/blender/gpu/intern/gpu_select_pick.c @@ -51,9 +51,9 @@ /* Z-depth of cleared depth buffer */ #define DEPTH_MAX 0xffffffff -/* ---------------------------------------------------------------------------- - * SubRectStride - */ +/* -------------------------------------------------------------------- */ +/** \name #SubRectStride + * \{ */ /* For looping over a sub-region of a rect, could be moved into 'rct.c'. */ typedef struct SubRectStride { @@ -99,14 +99,16 @@ BLI_INLINE bool depth_is_filled(const depth_t *prev, const depth_t *curr) return (*prev != *curr) && (*curr != DEPTH_MAX); } -/* ---------------------------------------------------------------------------- - * DepthBufCache +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name #DepthBufCache * - * Result of reading glReadPixels, + * Result of reading #glReadPixels, * use for both cache and non-cached storage. - */ + * \{ */ -/* store result of glReadPixels */ +/** Store result of #glReadPixels. */ typedef struct DepthBufCache { struct DepthBufCache *next, *prev; uint id; @@ -188,11 +190,13 @@ static bool depth_buf_subrect_depth_any_filled(const DepthBufCache *rect_src, return false; } -/* ---------------------------------------------------------------------------- - * DepthID +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name #DepthID * * Internal structure for storing hits. - */ + * \{ */ typedef struct DepthID { uint id; @@ -225,6 +229,12 @@ static int depth_cmp(const void *v1, const void *v2) return 0; } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Main Selection Begin/End/Load API + * \{ */ + /* depth sorting */ typedef struct GPUPickState { /* cache on initialization */ @@ -663,7 +673,7 @@ uint gpu_select_pick_end(void) #endif /* first 3 are dummy values */ g_pick_state.buffer[hits][0] = 1; - g_pick_state.buffer[hits][1] = 0x0; /* depth_data[i].depth; */ /* unused */ + g_pick_state.buffer[hits][1] = depth_data[i].depth; g_pick_state.buffer[hits][2] = 0x0; /* z-far is currently never used. */ g_pick_state.buffer[hits][3] = depth_data[i].id; hits++; @@ -691,11 +701,13 @@ uint gpu_select_pick_end(void) return hits; } -/* ---------------------------------------------------------------------------- - * Caching +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Caching * * Support multiple begin/end's reusing depth buffers. - */ + * \{ */ void gpu_select_pick_cache_begin(void) { @@ -718,7 +730,6 @@ void gpu_select_pick_cache_end(void) BLI_freelistN(&g_pick_state.cache.bufs); } -/* is drawing needed? */ bool gpu_select_pick_is_cached(void) { return g_pick_state.is_cached; @@ -749,3 +760,5 @@ void gpu_select_pick_cache_load_id(void) } } } + +/** \} */ diff --git a/source/blender/gpu/intern/gpu_select_private.h b/source/blender/gpu/intern/gpu_select_private.h index e49feb3fc50..e5a84a037a6 100644 --- a/source/blender/gpu/intern/gpu_select_private.h +++ b/source/blender/gpu/intern/gpu_select_private.h @@ -30,16 +30,21 @@ extern "C" { #endif /* gpu_select_pick */ + void gpu_select_pick_begin(uint (*buffer)[4], uint bufsize, const rcti *input, char mode); bool gpu_select_pick_load_id(uint id, bool end); uint gpu_select_pick_end(void); void gpu_select_pick_cache_begin(void); void gpu_select_pick_cache_end(void); +/** + * \return true if drawing is not needed. + */ bool gpu_select_pick_is_cached(void); void gpu_select_pick_cache_load_id(void); /* gpu_select_sample_query */ + void gpu_select_query_begin( uint (*buffer)[4], uint bufsize, const rcti *input, char mode, int oldhits); bool gpu_select_query_load_id(uint id); diff --git a/source/blender/gpu/intern/gpu_select_sample_query.cc b/source/blender/gpu/intern/gpu_select_sample_query.cc index 7b9b3020639..a430d4a9d62 100644 --- a/source/blender/gpu/intern/gpu_select_sample_query.cc +++ b/source/blender/gpu/intern/gpu_select_sample_query.cc @@ -20,8 +20,8 @@ /** \file * \ingroup gpu * - * Interface for accessing gpu-related methods for selection. The semantics will be - * similar to glRenderMode(GL_SELECT) since the goal is to maintain compatibility. + * Interface for accessing GPU-related methods for selection. The semantics will be + * similar to `glRenderMode(GL_SELECT)` since the goal is to maintain compatibility. */ #include <cstdlib> @@ -151,7 +151,7 @@ bool gpu_select_query_load_id(uint id) return true; } -uint gpu_select_query_end(void) +uint gpu_select_query_end() { uint hits = 0; const uint maxhits = g_query_state.bufsize; diff --git a/source/blender/gpu/intern/gpu_shader.cc b/source/blender/gpu/intern/gpu_shader.cc index cab73963620..830e65f69d9 100644 --- a/source/blender/gpu/intern/gpu_shader.cc +++ b/source/blender/gpu/intern/gpu_shader.cc @@ -31,10 +31,32 @@ #include "gpu_backend.hh" #include "gpu_context_private.hh" +#include "gpu_shader_create_info.hh" +#include "gpu_shader_create_info_private.hh" +#include "gpu_shader_dependency_private.h" #include "gpu_shader_private.hh" +#include <string> + extern "C" char datatoc_gpu_shader_colorspace_lib_glsl[]; +namespace blender::gpu { + +std::string Shader::defines_declare(const shader::ShaderCreateInfo &info) const +{ + std::string defines; + for (const auto &def : info.defines_) { + defines += "#define "; + defines += def[0]; + defines += " "; + defines += def[1]; + defines += "\n"; + } + return defines; +} + +} // namespace blender::gpu + using namespace blender; using namespace blender::gpu; @@ -59,6 +81,8 @@ static void standard_defines(Vector<const char *> &sources) BLI_assert(sources.size() == 0); /* Version needs to be first. Exact values will be added by implementation. */ sources.append("version"); + /* Define to identify code usage in shading language. */ + sources.append("#define GPU_SHADER\n"); /* some useful defines to detect GPU type */ if (GPU_type_matches(GPU_DEVICE_ATI, GPU_OS_ANY, GPU_DRIVER_ANY)) { sources.append("#define GPU_ATI\n"); @@ -225,6 +249,188 @@ GPUShader *GPU_shader_create_compute(const char *computecode, shname); } +GPUShader *GPU_shader_create_from_info_name(const char *info_name) +{ + using namespace blender::gpu::shader; + const GPUShaderCreateInfo *_info = gpu_shader_create_info_get(info_name); + const ShaderCreateInfo &info = *reinterpret_cast<const ShaderCreateInfo *>(_info); + if (!info.do_static_compilation_) { + printf("Warning: Trying to compile \"%s\" which was not marked for static compilation.\n", + info.name_.c_str()); + } + return GPU_shader_create_from_info(_info); +} + +GPUShader *GPU_shader_create_from_info(const GPUShaderCreateInfo *_info) +{ + using namespace blender::gpu::shader; + const ShaderCreateInfo &info = *reinterpret_cast<const ShaderCreateInfo *>(_info); + + const_cast<ShaderCreateInfo &>(info).finalize(); + + /* At least a vertex shader and a fragment shader are required, or only a compute shader. */ + if (info.compute_source_.is_empty()) { + if (info.vertex_source_.is_empty()) { + printf("Missing vertex shader in %s.\n", info.name_.c_str()); + } + if (info.fragment_source_.is_empty()) { + printf("Missing fragment shader in %s.\n", info.name_.c_str()); + } + BLI_assert(!info.vertex_source_.is_empty() && !info.fragment_source_.is_empty()); + } + else { + if (!info.vertex_source_.is_empty()) { + printf("Compute shader has vertex_source_ shader attached in %s.\n", info.name_.c_str()); + } + if (!info.geometry_source_.is_empty()) { + printf("Compute shader has geometry_source_ shader attached in %s.\n", info.name_.c_str()); + } + if (!info.fragment_source_.is_empty()) { + printf("Compute shader has fragment_source_ shader attached in %s.\n", info.name_.c_str()); + } + BLI_assert(info.vertex_source_.is_empty() && info.geometry_source_.is_empty() && + info.fragment_source_.is_empty()); + } + + Shader *shader = GPUBackend::get()->shader_alloc(info.name_.c_str()); + + std::string defines = shader->defines_declare(info); + std::string resources = shader->resources_declare(info); + char *shader_shared_utils = nullptr; + + defines += "#define USE_GPU_SHADER_CREATE_INFO\n"; + + Vector<char *> typedefs; + for (auto filename : info.typedef_sources_) { + typedefs.append(gpu_shader_dependency_get_source(filename.c_str())); + } + if (!typedefs.is_empty()) { + shader_shared_utils = gpu_shader_dependency_get_source("gpu_shader_shared_utils.h"); + } + + if (!info.vertex_source_.is_empty()) { + uint32_t builtins = 0; + std::string interface = shader->vertex_interface_declare(info); + char *code = gpu_shader_dependency_get_resolved_source(info.vertex_source_.c_str(), &builtins); + + Vector<const char *> sources; + standard_defines(sources); + sources.append("#define GPU_VERTEX_SHADER\n"); + if (!info.geometry_source_.is_empty()) { + sources.append("#define USE_GEOMETRY_SHADER\n"); + } + sources.append(defines.c_str()); + if (!typedefs.is_empty()) { + sources.append(shader_shared_utils); + } + for (auto *types : typedefs) { + sources.append(types); + } + sources.append(resources.c_str()); + sources.append(interface.c_str()); + sources.append(code); + + shader->vertex_shader_from_glsl(sources); + + free(code); + } + + if (!info.fragment_source_.is_empty()) { + uint32_t builtins = 0; + std::string interface = shader->fragment_interface_declare(info); + char *code = gpu_shader_dependency_get_resolved_source(info.fragment_source_.c_str(), + &builtins); + + Vector<const char *> sources; + standard_defines(sources); + sources.append("#define GPU_FRAGMENT_SHADER\n"); + if (!info.geometry_source_.is_empty()) { + sources.append("#define USE_GEOMETRY_SHADER\n"); + } + sources.append(defines.c_str()); + if (!typedefs.is_empty()) { + sources.append(shader_shared_utils); + } + for (auto *types : typedefs) { + sources.append(types); + } + sources.append(resources.c_str()); + sources.append(interface.c_str()); + sources.append(code); + + shader->fragment_shader_from_glsl(sources); + + free(code); + } + + if (!info.geometry_source_.is_empty()) { + uint32_t builtins = 0; + std::string interface = shader->geometry_interface_declare(info); + std::string layout = shader->geometry_layout_declare(info); + char *code = gpu_shader_dependency_get_resolved_source(info.geometry_source_.c_str(), + &builtins); + + Vector<const char *> sources; + standard_defines(sources); + sources.append("#define GPU_GEOMETRY_SHADER\n"); + sources.append(defines.c_str()); + if (!typedefs.is_empty()) { + sources.append(shader_shared_utils); + } + for (auto *types : typedefs) { + sources.append(types); + } + sources.append(resources.c_str()); + sources.append(layout.c_str()); + sources.append(interface.c_str()); + sources.append(code); + + shader->geometry_shader_from_glsl(sources); + + free(code); + } + + if (!info.compute_source_.is_empty()) { + uint32_t builtins = 0; + char *code = gpu_shader_dependency_get_resolved_source(info.compute_source_.c_str(), + &builtins); + std::string layout = shader->compute_layout_declare(info); + + Vector<const char *> sources; + standard_defines(sources); + sources.append("#define GPU_COMPUTE_SHADER\n"); + sources.append(defines.c_str()); + if (!typedefs.is_empty()) { + sources.append(shader_shared_utils); + } + for (auto *types : typedefs) { + sources.append(types); + } + sources.append(resources.c_str()); + sources.append(layout.c_str()); + sources.append(code); + + shader->compute_shader_from_glsl(sources); + + free(code); + } + + for (auto *types : typedefs) { + free(types); + } + + if (shader_shared_utils) { + free(shader_shared_utils); + } + + if (!shader->finalize(&info)) { + delete shader; + return nullptr; + } + + return wrap(shader); +} + GPUShader *GPU_shader_create_from_python(const char *vertcode, const char *fragcode, const char *geomcode, @@ -284,26 +490,6 @@ static const char *string_join_array_maybe_alloc(const char **str_arr, bool *r_i return str_arr[0]; } -/** - * Use via #GPU_shader_create_from_arrays macro (avoids passing in param). - * - * Similar to #DRW_shader_create_with_lib with the ability to include libs for each type of shader. - * - * It has the advantage that each item can be conditionally included - * without having to build the string inline, then free it. - * - * \param params: NULL terminated arrays of strings. - * - * Example: - * \code{.c} - * sh = GPU_shader_create_from_arrays({ - * .vert = (const char *[]){shader_lib_glsl, shader_vert_glsl, NULL}, - * .geom = (const char *[]){shader_geom_glsl, NULL}, - * .frag = (const char *[]){shader_frag_glsl, NULL}, - * .defs = (const char *[]){"#define DEFINE\n", test ? "#define OTHER_DEFINE\n" : "", NULL}, - * }); - * \endcode - */ struct GPUShader *GPU_shader_create_from_arrays_impl( const struct GPU_ShaderCreateFromArray_Params *params, const char *func, int line) { @@ -359,7 +545,7 @@ void GPU_shader_bind(GPUShader *gpu_shader) } } -void GPU_shader_unbind(void) +void GPU_shader_unbind() { #ifndef NDEBUG Context *ctx = Context::get(); @@ -437,7 +623,6 @@ int GPU_shader_get_ssbo(GPUShader *shader, const char *name) return ssbo ? ssbo->location : -1; } -/* DEPRECATED. */ int GPU_shader_get_uniform_block(GPUShader *shader, const char *name) { ShaderInterface *interface = unwrap(shader)->interface; @@ -472,7 +657,6 @@ int GPU_shader_get_attribute(GPUShader *shader, const char *name) /** \name Getters * \{ */ -/* DEPRECATED: Kept only because of BGL API */ int GPU_shader_get_program(GPUShader *shader) { return unwrap(shader)->program_handle_get(); diff --git a/source/blender/gpu/intern/gpu_shader_builder.cc b/source/blender/gpu/intern/gpu_shader_builder.cc new file mode 100644 index 00000000000..334bdb2ec58 --- /dev/null +++ b/source/blender/gpu/intern/gpu_shader_builder.cc @@ -0,0 +1,102 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2021 Blender Foundation. + * All rights reserved. + */ + +/** \file + * \ingroup gpu + * + * Compile time automation of shader compilation and validation. + */ + +#include <iostream> + +#include "GHOST_C-api.h" + +#include "GPU_context.h" +#include "GPU_init_exit.h" +#include "gpu_shader_create_info_private.hh" + +#include "CLG_log.h" + +namespace blender::gpu::shader_builder { + +class ShaderBuilder { + private: + GHOST_SystemHandle ghost_system_; + GHOST_ContextHandle ghost_context_; + GPUContext *gpu_context_ = nullptr; + + public: + void init(); + bool bake_create_infos(); + void exit(); +}; + +bool ShaderBuilder::bake_create_infos() +{ + return gpu_shader_create_info_compile_all(); +} + +void ShaderBuilder::init() +{ + CLG_init(); + + GHOST_GLSettings glSettings = {0}; + ghost_system_ = GHOST_CreateSystem(); + ghost_context_ = GHOST_CreateOpenGLContext(ghost_system_, glSettings); + GHOST_ActivateOpenGLContext(ghost_context_); + + gpu_context_ = GPU_context_create(nullptr); + GPU_init(); +} + +void ShaderBuilder::exit() +{ + GPU_backend_exit(); + GPU_exit(); + + GPU_context_discard(gpu_context_); + + GHOST_DisposeOpenGLContext(ghost_system_, ghost_context_); + GHOST_DisposeSystem(ghost_system_); + + CLG_exit(); +} + +} // namespace blender::gpu::shader_builder + +/** \brief Entry point for the shader_builder. */ +int main(int argc, const char *argv[]) +{ + if (argc < 2) { + printf("Usage: %s <data_file_to>\n", argv[0]); + exit(1); + } + + int exit_code = 0; + + blender::gpu::shader_builder::ShaderBuilder builder; + builder.init(); + if (!builder.bake_create_infos()) { + exit_code = 1; + } + builder.exit(); + exit(exit_code); + + return exit_code; +} diff --git a/source/blender/gpu/intern/gpu_shader_builder_stubs.cc b/source/blender/gpu/intern/gpu_shader_builder_stubs.cc new file mode 100644 index 00000000000..40e54ab4394 --- /dev/null +++ b/source/blender/gpu/intern/gpu_shader_builder_stubs.cc @@ -0,0 +1,258 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2021 Blender Foundation. + * All rights reserved. + */ + +/** \file + * \ingroup gpu + * + * Stubs to reduce linking time for shader_builder. + */ + +#include "BLI_utildefines.h" + +#include "IMB_imbuf.h" +#include "IMB_imbuf_types.h" + +#include "BKE_customdata.h" +#include "BKE_global.h" +#include "BKE_material.h" +#include "BKE_mesh.h" +#include "BKE_node.h" +#include "BKE_paint.h" +#include "BKE_pbvh.h" +#include "BKE_subdiv_ccg.h" + +#include "DNA_userdef_types.h" + +#include "DRW_engine.h" + +#include "bmesh.h" + +#include "UI_resources.h" + +extern "C" { + +Global G; +UserDef U; + +/* -------------------------------------------------------------------- */ +/** \name Stubs of BLI_imbuf_types.h + * \{ */ + +void IMB_freeImBuf(ImBuf *UNUSED(ibuf)) +{ + BLI_assert_unreachable(); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Stubs of UI_resources.h + * \{ */ + +void UI_GetThemeColor4fv(int UNUSED(colorid), float UNUSED(col[4])) +{ + BLI_assert_unreachable(); +} + +void UI_GetThemeColor3fv(int UNUSED(colorid), float UNUSED(col[3])) +{ + BLI_assert_unreachable(); +} + +void UI_GetThemeColorShade4fv(int UNUSED(colorid), int UNUSED(offset), float UNUSED(col[4])) +{ + BLI_assert_unreachable(); +} + +void UI_GetThemeColorShadeAlpha4fv(int UNUSED(colorid), + int UNUSED(coloffset), + int UNUSED(alphaoffset), + float UNUSED(col[4])) +{ + BLI_assert_unreachable(); +} +void UI_GetThemeColorBlendShade4fv(int UNUSED(colorid1), + int UNUSED(colorid2), + float UNUSED(fac), + int UNUSED(offset), + float UNUSED(col[4])) +{ + BLI_assert_unreachable(); +} + +void UI_GetThemeColorBlend3ubv(int UNUSED(colorid1), + int UNUSED(colorid2), + float UNUSED(fac), + unsigned char UNUSED(col[3])) +{ + BLI_assert_unreachable(); +} + +void UI_GetThemeColorShadeAlpha4ubv(int UNUSED(colorid), + int UNUSED(coloffset), + int UNUSED(alphaoffset), + unsigned char UNUSED(col[4])) +{ + BLI_assert_unreachable(); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Stubs of BKE_paint.h + * \{ */ +bool paint_is_face_hidden(const struct MLoopTri *UNUSED(lt), + const struct MVert *UNUSED(mvert), + const struct MLoop *UNUSED(mloop)) +{ + BLI_assert_unreachable(); + return false; +} + +void BKE_paint_face_set_overlay_color_get(const int UNUSED(face_set), + const int UNUSED(seed), + uchar UNUSED(r_color[4])) +{ + BLI_assert_unreachable(); +} + +bool paint_is_grid_face_hidden(const unsigned int *UNUSED(grid_hidden), + int UNUSED(gridsize), + int UNUSED(x), + int UNUSED(y)) +{ + BLI_assert_unreachable(); + return false; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Stubs of BKE_mesh.h + * \{ */ +void BKE_mesh_calc_poly_normal(const struct MPoly *UNUSED(mpoly), + const struct MLoop *UNUSED(loopstart), + const struct MVert *UNUSED(mvarray), + float UNUSED(r_no[3])) +{ + BLI_assert_unreachable(); +} + +void BKE_mesh_looptri_get_real_edges(const struct Mesh *UNUSED(mesh), + const struct MLoopTri *UNUSED(looptri), + int UNUSED(r_edges[3])) +{ + BLI_assert_unreachable(); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Stubs of BKE_material.h + * \{ */ + +void BKE_material_defaults_free_gpu(void) +{ + /* This function is reachable via GPU_exit. */ +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Stubs of BKE_customdata.h + * \{ */ + +int CustomData_get_offset(const struct CustomData *UNUSED(data), int UNUSED(type)) +{ + BLI_assert_unreachable(); + return 0; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Stubs of BKE_pbvh.h + * \{ */ + +int BKE_pbvh_count_grid_quads(BLI_bitmap **UNUSED(grid_hidden), + const int *UNUSED(grid_indices), + int UNUSED(totgrid), + int UNUSED(gridsize)) +{ + BLI_assert_unreachable(); + return 0; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Stubs of BKE_subdiv_ccg.h + * \{ */ +int BKE_subdiv_ccg_grid_to_face_index(const SubdivCCG *UNUSED(subdiv_ccg), + const int UNUSED(grid_index)) +{ + BLI_assert_unreachable(); + return 0; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Stubs of BKE_node.h + * \{ */ +void ntreeGPUMaterialNodes(struct bNodeTree *UNUSED(localtree), + struct GPUMaterial *UNUSED(mat), + bool *UNUSED(has_surface_output), + bool *UNUSED(has_volume_output)) +{ + BLI_assert_unreachable(); +} + +struct bNodeTree *ntreeLocalize(struct bNodeTree *UNUSED(ntree)) +{ + BLI_assert_unreachable(); + return nullptr; +} + +void ntreeFreeLocalTree(struct bNodeTree *UNUSED(ntree)) +{ + BLI_assert_unreachable(); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Stubs of bmesh.h + * \{ */ +void BM_face_as_array_vert_tri(BMFace *UNUSED(f), BMVert *UNUSED(r_verts[3])) +{ + BLI_assert_unreachable(); +} +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Stubs of DRW_engine.h + * \{ */ +void DRW_deferred_shader_remove(struct GPUMaterial *UNUSED(mat)) +{ + BLI_assert_unreachable(); +} + +/** \} */ +} diff --git a/source/blender/gpu/intern/gpu_shader_builtin.c b/source/blender/gpu/intern/gpu_shader_builtin.c index 9ea46788f44..6b1163fdc78 100644 --- a/source/blender/gpu/intern/gpu_shader_builtin.c +++ b/source/blender/gpu/intern/gpu_shader_builtin.c @@ -77,6 +77,7 @@ extern char datatoc_gpu_shader_image_overlays_merge_frag_glsl[]; extern char datatoc_gpu_shader_image_overlays_stereo_merge_frag_glsl[]; extern char datatoc_gpu_shader_image_color_frag_glsl[]; extern char datatoc_gpu_shader_image_desaturate_frag_glsl[]; +extern char datatoc_gpu_shader_image_modulate_alpha_frag_glsl[]; extern char datatoc_gpu_shader_image_varying_color_frag_glsl[]; extern char datatoc_gpu_shader_image_shuffle_color_frag_glsl[]; extern char datatoc_gpu_shader_3D_vert_glsl[]; @@ -92,28 +93,15 @@ extern char datatoc_gpu_shader_3D_clipped_uniform_color_vert_glsl[]; extern char datatoc_gpu_shader_instance_variying_size_variying_color_vert_glsl[]; -extern char datatoc_gpu_shader_point_uniform_color_frag_glsl[]; extern char datatoc_gpu_shader_point_uniform_color_aa_frag_glsl[]; extern char datatoc_gpu_shader_point_uniform_color_outline_aa_frag_glsl[]; -extern char datatoc_gpu_shader_point_varying_color_outline_aa_frag_glsl[]; extern char datatoc_gpu_shader_point_varying_color_varying_outline_aa_frag_glsl[]; extern char datatoc_gpu_shader_point_varying_color_frag_glsl[]; extern char datatoc_gpu_shader_3D_point_fixed_size_varying_color_vert_glsl[]; -extern char datatoc_gpu_shader_3D_point_varying_size_vert_glsl[]; extern char datatoc_gpu_shader_3D_point_varying_size_varying_color_vert_glsl[]; extern char datatoc_gpu_shader_3D_point_uniform_size_aa_vert_glsl[]; -extern char datatoc_gpu_shader_3D_point_uniform_size_outline_aa_vert_glsl[]; -extern char datatoc_gpu_shader_2D_point_varying_size_varying_color_vert_glsl[]; extern char datatoc_gpu_shader_2D_point_uniform_size_aa_vert_glsl[]; extern char datatoc_gpu_shader_2D_point_uniform_size_outline_aa_vert_glsl[]; -extern char datatoc_gpu_shader_2D_point_uniform_size_varying_color_outline_aa_vert_glsl[]; - -extern char datatoc_gpu_shader_2D_edituvs_points_vert_glsl[]; -extern char datatoc_gpu_shader_2D_edituvs_facedots_vert_glsl[]; -extern char datatoc_gpu_shader_2D_edituvs_edges_vert_glsl[]; -extern char datatoc_gpu_shader_2D_edituvs_edges_frag_glsl[]; -extern char datatoc_gpu_shader_2D_edituvs_faces_vert_glsl[]; -extern char datatoc_gpu_shader_2D_edituvs_stretch_vert_glsl[]; extern char datatoc_gpu_shader_2D_line_dashed_uniform_color_vert_glsl[]; extern char datatoc_gpu_shader_2D_line_dashed_frag_glsl[]; @@ -157,133 +145,97 @@ typedef struct { const char *frag; /** Optional. */ const char *defs; + + const char *create_info; + const char *clipped_create_info; } GPUShaderStages; static const GPUShaderStages builtin_shader_stages[GPU_SHADER_BUILTIN_LEN] = { [GPU_SHADER_TEXT] = { .name = "GPU_SHADER_TEXT", - .vert = datatoc_gpu_shader_text_vert_glsl, - .frag = datatoc_gpu_shader_text_frag_glsl, + .create_info = "gpu_shader_text", }, [GPU_SHADER_KEYFRAME_SHAPE] = { .name = "GPU_SHADER_KEYFRAME_SHAPE", - .vert = datatoc_gpu_shader_keyframe_shape_vert_glsl, - .frag = datatoc_gpu_shader_keyframe_shape_frag_glsl, + .create_info = "gpu_shader_keyframe_shape", }, [GPU_SHADER_SIMPLE_LIGHTING] = { .name = "GPU_SHADER_SIMPLE_LIGHTING", - .vert = datatoc_gpu_shader_3D_normal_vert_glsl, - .frag = datatoc_gpu_shader_simple_lighting_frag_glsl, + .create_info = "gpu_shader_simple_lighting", + }, + [GPU_SHADER_3D_IMAGE_MODULATE_ALPHA] = + { + .name = "GPU_SHADER_3D_IMAGE_MODULATE_ALPHA", + .create_info = "gpu_shader_3D_image_modulate_alpha", }, - [GPU_SHADER_2D_CHECKER] = { .name = "GPU_SHADER_2D_CHECKER", - .vert = datatoc_gpu_shader_2D_vert_glsl, - .frag = datatoc_gpu_shader_checker_frag_glsl, + .create_info = "gpu_shader_2D_checker", }, [GPU_SHADER_2D_DIAG_STRIPES] = { .name = "GPU_SHADER_2D_DIAG_STRIPES", - .vert = datatoc_gpu_shader_2D_vert_glsl, - .frag = datatoc_gpu_shader_diag_stripes_frag_glsl, + .create_info = "gpu_shader_2D_diag_stripes", }, - [GPU_SHADER_2D_UNIFORM_COLOR] = - { - .name = "GPU_SHADER_2D_UNIFORM_COLOR", - .vert = datatoc_gpu_shader_2D_vert_glsl, - .frag = datatoc_gpu_shader_uniform_color_frag_glsl, - }, - [GPU_SHADER_2D_FLAT_COLOR] = - { - .name = "GPU_SHADER_2D_FLAT_COLOR", - .vert = datatoc_gpu_shader_2D_flat_color_vert_glsl, - .frag = datatoc_gpu_shader_flat_color_frag_glsl, - }, - [GPU_SHADER_2D_SMOOTH_COLOR] = - { - .name = "GPU_SHADER_2D_SMOOTH_COLOR", - .vert = datatoc_gpu_shader_2D_smooth_color_vert_glsl, - .frag = datatoc_gpu_shader_2D_smooth_color_frag_glsl, - }, + [GPU_SHADER_2D_UNIFORM_COLOR] = {.name = "GPU_SHADER_2D_UNIFORM_COLOR", + .create_info = "gpu_shader_2D_uniform_color"}, + [GPU_SHADER_2D_FLAT_COLOR] = {.name = "GPU_SHADER_2D_FLAT_COLOR", + .create_info = "gpu_shader_2D_flat_color"}, + [GPU_SHADER_2D_SMOOTH_COLOR] = {.name = "GPU_SHADER_2D_SMOOTH_COLOR", + .create_info = "gpu_shader_2D_smooth_color"}, [GPU_SHADER_2D_IMAGE_OVERLAYS_MERGE] = { .name = "GPU_SHADER_2D_IMAGE_OVERLAYS_MERGE", +#ifdef __APPLE__ + /* GPUShaderCreateInfo is disabled on MacOS due to mismatch with OCIO shader. See + * T95052 for more details. */ .vert = datatoc_gpu_shader_2D_image_vert_glsl, .frag = datatoc_gpu_shader_image_overlays_merge_frag_glsl, +#else + .create_info = "gpu_shader_2D_image_overlays_merge", +#endif }, [GPU_SHADER_2D_IMAGE_OVERLAYS_STEREO_MERGE] = - { - .name = "GPU_SHADER_2D_IMAGE_OVERLAYS_STEREO_MERGE", - .vert = datatoc_gpu_shader_2D_vert_glsl, - .frag = datatoc_gpu_shader_image_overlays_stereo_merge_frag_glsl, - }, - [GPU_SHADER_2D_IMAGE] = - { - .name = "GPU_SHADER_2D_IMAGE", - .vert = datatoc_gpu_shader_2D_image_vert_glsl, - .frag = datatoc_gpu_shader_image_frag_glsl, - }, - [GPU_SHADER_2D_IMAGE_COLOR] = - { - .name = "GPU_SHADER_2D_IMAGE_COLOR", - .vert = datatoc_gpu_shader_2D_image_vert_glsl, - .frag = datatoc_gpu_shader_image_color_frag_glsl, - }, - [GPU_SHADER_2D_IMAGE_DESATURATE_COLOR] = - { - .name = "GPU_SHADER_2D_IMAGE_DESATURATE_COLOR", - .vert = datatoc_gpu_shader_2D_image_vert_glsl, - .frag = datatoc_gpu_shader_image_desaturate_frag_glsl, - }, + {.name = "GPU_SHADER_2D_IMAGE_OVERLAYS_STEREO_MERGE", + .create_info = "gpu_shader_2D_image_overlays_stereo_merge"}, + [GPU_SHADER_2D_IMAGE] = {.name = "GPU_SHADER_2D_IMAGE", .create_info = "gpu_shader_2D_image"}, + [GPU_SHADER_2D_IMAGE_COLOR] = {.name = "GPU_SHADER_2D_IMAGE_COLOR", + .create_info = "gpu_shader_2D_image_color"}, + [GPU_SHADER_2D_IMAGE_DESATURATE_COLOR] = {.name = "GPU_SHADER_2D_IMAGE_DESATURATE_COLOR", + .create_info = + "gpu_shader_2D_image_desaturate_color"}, [GPU_SHADER_2D_IMAGE_SHUFFLE_COLOR] = { .name = "GPU_SHADER_2D_IMAGE_SHUFFLE_COLOR", - .vert = datatoc_gpu_shader_2D_image_vert_glsl, - .frag = datatoc_gpu_shader_image_shuffle_color_frag_glsl, - }, - [GPU_SHADER_2D_IMAGE_RECT_COLOR] = - { - .name = "GPU_SHADER_2D_IMAGE_RECT_COLOR", - .vert = datatoc_gpu_shader_2D_image_rect_vert_glsl, - .frag = datatoc_gpu_shader_image_color_frag_glsl, - }, - [GPU_SHADER_2D_IMAGE_MULTI_RECT_COLOR] = - { - .name = "GPU_SHADER_2D_IMAGE_MULTI_RECT_COLOR", - .vert = datatoc_gpu_shader_2D_image_multi_rect_vert_glsl, - .frag = datatoc_gpu_shader_image_varying_color_frag_glsl, + .create_info = "gpu_shader_2D_image_shuffle_color", }, + [GPU_SHADER_2D_IMAGE_RECT_COLOR] = {.name = "GPU_SHADER_2D_IMAGE_RECT_COLOR", + .create_info = "gpu_shader_2D_image_rect_color"}, + [GPU_SHADER_2D_IMAGE_MULTI_RECT_COLOR] = {.name = "GPU_SHADER_2D_IMAGE_MULTI_RECT_COLOR", + .create_info = + "gpu_shader_2D_image_multi_rect_color"}, [GPU_SHADER_3D_UNIFORM_COLOR] = { .name = "GPU_SHADER_3D_UNIFORM_COLOR", - .vert = datatoc_gpu_shader_3D_vert_glsl, - .frag = datatoc_gpu_shader_uniform_color_frag_glsl, - }, - [GPU_SHADER_3D_FLAT_COLOR] = - { - .name = "GPU_SHADER_3D_FLAT_COLOR", - .vert = datatoc_gpu_shader_3D_flat_color_vert_glsl, - .frag = datatoc_gpu_shader_flat_color_frag_glsl, - }, - [GPU_SHADER_3D_SMOOTH_COLOR] = - { - .name = "GPU_SHADER_3D_SMOOTH_COLOR", - .vert = datatoc_gpu_shader_3D_smooth_color_vert_glsl, - .frag = datatoc_gpu_shader_3D_smooth_color_frag_glsl, - }, - [GPU_SHADER_3D_DEPTH_ONLY] = - { - .name = "GPU_SHADER_3D_DEPTH_ONLY", - .vert = datatoc_gpu_shader_3D_vert_glsl, - .frag = datatoc_gpu_shader_depth_only_frag_glsl, - }, + .create_info = "gpu_shader_3D_uniform_color", + .clipped_create_info = "gpu_shader_3D_uniform_color_clipped", + }, + [GPU_SHADER_3D_FLAT_COLOR] = {.name = "GPU_SHADER_3D_FLAT_COLOR", + .create_info = "gpu_shader_3D_flat_color", + .clipped_create_info = "gpu_shader_3D_flat_color_clipped"}, + [GPU_SHADER_3D_SMOOTH_COLOR] = {.name = "GPU_SHADER_3D_SMOOTH_COLOR", + .create_info = "gpu_shader_3D_smooth_color", + .clipped_create_info = "gpu_shader_3D_smooth_color_clipped"}, + [GPU_SHADER_3D_DEPTH_ONLY] = {.name = "GPU_SHADER_3D_DEPTH_ONLY", + .create_info = "gpu_shader_3D_depth_only", + .clipped_create_info = "gpu_shader_3D_depth_only_clipped"}, [GPU_SHADER_3D_CLIPPED_UNIFORM_COLOR] = { .name = "GPU_SHADER_3D_CLIPPED_UNIFORM_COLOR", @@ -338,72 +290,26 @@ static const GPUShaderStages builtin_shader_stages[GPU_SHADER_BUILTIN_LEN] = { .frag = datatoc_gpu_shader_2D_line_dashed_frag_glsl, }, - [GPU_SHADER_2D_POINT_FIXED_SIZE_UNIFORM_COLOR] = - { - .name = "GPU_SHADER_2D_POINT_FIXED_SIZE_UNIFORM_COLOR", - .vert = datatoc_gpu_shader_2D_vert_glsl, - .frag = datatoc_gpu_shader_point_uniform_color_frag_glsl, - }, - [GPU_SHADER_2D_POINT_VARYING_SIZE_VARYING_COLOR] = - { - .name = "GPU_SHADER_2D_POINT_VARYING_SIZE_VARYING_COLOR", - .vert = datatoc_gpu_shader_2D_point_varying_size_varying_color_vert_glsl, - .frag = datatoc_gpu_shader_point_varying_color_frag_glsl, - }, [GPU_SHADER_2D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_AA] = { .name = "GPU_SHADER_2D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_AA", - .vert = datatoc_gpu_shader_2D_point_uniform_size_aa_vert_glsl, - .frag = datatoc_gpu_shader_point_uniform_color_aa_frag_glsl, + .create_info = "gpu_shader_2D_point_uniform_size_uniform_color_aa", }, [GPU_SHADER_2D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_OUTLINE_AA] = { .name = "GPU_SHADER_2D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_OUTLINE_AA", - .vert = datatoc_gpu_shader_2D_point_uniform_size_outline_aa_vert_glsl, - .frag = datatoc_gpu_shader_point_uniform_color_outline_aa_frag_glsl, - }, - [GPU_SHADER_2D_POINT_UNIFORM_SIZE_VARYING_COLOR_OUTLINE_AA] = - { - .name = "GPU_SHADER_2D_POINT_UNIFORM_SIZE_VARYING_COLOR_OUTLINE_AA", - .vert = datatoc_gpu_shader_2D_point_uniform_size_varying_color_outline_aa_vert_glsl, - .frag = datatoc_gpu_shader_point_varying_color_outline_aa_frag_glsl, - }, - [GPU_SHADER_3D_POINT_FIXED_SIZE_UNIFORM_COLOR] = - { - .name = "GPU_SHADER_3D_POINT_FIXED_SIZE_UNIFORM_COLOR", - .vert = datatoc_gpu_shader_3D_vert_glsl, - .frag = datatoc_gpu_shader_point_uniform_color_frag_glsl, + .create_info = "gpu_shader_2D_point_uniform_size_uniform_color_outline_aa", }, [GPU_SHADER_3D_POINT_FIXED_SIZE_VARYING_COLOR] = - { - .name = "GPU_SHADER_3D_POINT_FIXED_SIZE_VARYING_COLOR", - .vert = datatoc_gpu_shader_3D_point_fixed_size_varying_color_vert_glsl, - .frag = datatoc_gpu_shader_point_varying_color_frag_glsl, - }, - [GPU_SHADER_3D_POINT_VARYING_SIZE_UNIFORM_COLOR] = - { - .name = "GPU_SHADER_3D_POINT_VARYING_SIZE_UNIFORM_COLOR", - .vert = datatoc_gpu_shader_3D_point_varying_size_vert_glsl, - .frag = datatoc_gpu_shader_point_uniform_color_frag_glsl, - }, + {.name = "GPU_SHADER_3D_POINT_FIXED_SIZE_VARYING_COLOR", + .create_info = "gpu_shader_3D_point_fixed_size_varying_color"}, [GPU_SHADER_3D_POINT_VARYING_SIZE_VARYING_COLOR] = - { - .name = "GPU_SHADER_3D_POINT_VARYING_SIZE_VARYING_COLOR", - .vert = datatoc_gpu_shader_3D_point_varying_size_varying_color_vert_glsl, - .frag = datatoc_gpu_shader_point_varying_color_frag_glsl, - }, + {.name = "GPU_SHADER_3D_POINT_VARYING_SIZE_VARYING_COLOR", + .create_info = "gpu_shader_3D_point_varying_size_varying_color"}, [GPU_SHADER_3D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_AA] = - { - .name = "GPU_SHADER_3D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_AA", - .vert = datatoc_gpu_shader_3D_point_uniform_size_aa_vert_glsl, - .frag = datatoc_gpu_shader_point_uniform_color_aa_frag_glsl, - }, - [GPU_SHADER_3D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_OUTLINE_AA] = - { - .name = "GPU_SHADER_3D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_OUTLINE_AA", - .vert = datatoc_gpu_shader_3D_point_uniform_size_outline_aa_vert_glsl, - .frag = datatoc_gpu_shader_point_uniform_color_outline_aa_frag_glsl, - }, + {.name = "GPU_SHADER_3D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_AA", + .create_info = "gpu_shader_3D_point_uniform_size_uniform_color_aa", + .clipped_create_info = "gpu_shader_3D_point_uniform_size_uniform_color_aa_clipped"}, [GPU_SHADER_INSTANCE_VARIYING_COLOR_VARIYING_SIZE] = { @@ -413,12 +319,8 @@ static const GPUShaderStages builtin_shader_stages[GPU_SHADER_BUILTIN_LEN] = { .defs = "#define UNIFORM_SCALE\n", }, - [GPU_SHADER_2D_AREA_EDGES] = - { - .name = "GPU_SHADER_2D_AREA_EDGES", - .vert = datatoc_gpu_shader_2D_area_borders_vert_glsl, - .frag = datatoc_gpu_shader_2D_area_borders_frag_glsl, - }, + [GPU_SHADER_2D_AREA_BORDERS] = {.name = "GPU_SHADER_2D_AREA_BORDERS", + .create_info = "gpu_shader_2D_area_borders"}, [GPU_SHADER_2D_WIDGET_BASE] = { .name = "GPU_SHADER_2D_WIDGET_BASE", @@ -438,79 +340,14 @@ static const GPUShaderStages builtin_shader_stages[GPU_SHADER_BUILTIN_LEN] = { .vert = datatoc_gpu_shader_2D_widget_shadow_vert_glsl, .frag = datatoc_gpu_shader_2D_widget_shadow_frag_glsl, }, - [GPU_SHADER_2D_NODELINK] = - { - .name = "GPU_SHADER_2D_NODELINK", - .vert = datatoc_gpu_shader_2D_nodelink_vert_glsl, - .frag = datatoc_gpu_shader_2D_nodelink_frag_glsl, - }, - [GPU_SHADER_2D_NODELINK_INST] = - { - .name = "GPU_SHADER_2D_NODELINK_INST", - .vert = datatoc_gpu_shader_2D_nodelink_vert_glsl, - .frag = datatoc_gpu_shader_2D_nodelink_frag_glsl, - .defs = "#define USE_INSTANCE\n", - }, + [GPU_SHADER_2D_NODELINK] = {.name = "GPU_SHADER_2D_NODELINK", + .create_info = "gpu_shader_2D_nodelink"}, - [GPU_SHADER_2D_UV_UNIFORM_COLOR] = - { - .name = "GPU_SHADER_2D_UV_UNIFORM_COLOR", - .vert = datatoc_gpu_shader_2D_vert_glsl, - .frag = datatoc_gpu_shader_uniform_color_frag_glsl, - .defs = "#define UV_POS\n", - }, - [GPU_SHADER_2D_UV_VERTS] = - { - .name = "GPU_SHADER_2D_UV_VERTS", - .vert = datatoc_gpu_shader_2D_edituvs_points_vert_glsl, - .frag = datatoc_gpu_shader_point_varying_color_varying_outline_aa_frag_glsl, - }, - [GPU_SHADER_2D_UV_FACEDOTS] = - { - .name = "GPU_SHADER_2D_UV_FACEDOTS", - .vert = datatoc_gpu_shader_2D_edituvs_facedots_vert_glsl, - .frag = datatoc_gpu_shader_point_varying_color_frag_glsl, - }, - [GPU_SHADER_2D_UV_EDGES] = - { - .name = "GPU_SHADER_2D_UV_EDGES", - .vert = datatoc_gpu_shader_2D_edituvs_edges_vert_glsl, - .frag = datatoc_gpu_shader_2D_edituvs_edges_frag_glsl, - }, - [GPU_SHADER_2D_UV_EDGES_SMOOTH] = - { - .name = "GPU_SHADER_2D_UV_EDGES_SMOOTH", - .vert = datatoc_gpu_shader_2D_edituvs_edges_vert_glsl, - .frag = datatoc_gpu_shader_2D_edituvs_edges_frag_glsl, - .defs = "#define SMOOTH_COLOR\n", - }, - [GPU_SHADER_2D_UV_FACES] = - { - .name = "GPU_SHADER_2D_UV_FACES", - .vert = datatoc_gpu_shader_2D_edituvs_faces_vert_glsl, - .frag = datatoc_gpu_shader_flat_color_frag_glsl, - }, - [GPU_SHADER_2D_UV_FACES_STRETCH_AREA] = - { - .name = "GPU_SHADER_2D_UV_FACES_STRETCH_AREA", - .vert = datatoc_gpu_shader_2D_edituvs_stretch_vert_glsl, - .frag = datatoc_gpu_shader_2D_smooth_color_frag_glsl, - }, - [GPU_SHADER_2D_UV_FACES_STRETCH_ANGLE] = - { - .name = "GPU_SHADER_2D_UV_FACES_STRETCH_ANGLE", - .vert = datatoc_gpu_shader_2D_edituvs_stretch_vert_glsl, - .frag = datatoc_gpu_shader_2D_smooth_color_frag_glsl, - .defs = "#define STRETCH_ANGLE\n", - }, + [GPU_SHADER_2D_NODELINK_INST] = {.name = "GPU_SHADER_2D_NODELINK_INST", + .create_info = "gpu_shader_2D_nodelink_inst"}, - [GPU_SHADER_GPENCIL_STROKE] = - { - .name = "GPU_SHADER_GPENCIL_STROKE", - .vert = datatoc_gpu_shader_gpencil_stroke_vert_glsl, - .geom = datatoc_gpu_shader_gpencil_stroke_geom_glsl, - .frag = datatoc_gpu_shader_gpencil_stroke_frag_glsl, - }, + [GPU_SHADER_GPENCIL_STROKE] = {.name = "GPU_SHADER_GPENCIL_STROKE", + .create_info = "gpu_shader_gpencil_stroke"}, }; GPUShader *GPU_shader_get_builtin_shader_with_config(eGPUBuiltinShader shader, @@ -525,14 +362,20 @@ GPUShader *GPU_shader_get_builtin_shader_with_config(eGPUBuiltinShader shader, /* common case */ if (sh_cfg == GPU_SHADER_CFG_DEFAULT) { - *sh_p = GPU_shader_create_from_arrays_named( - stages->name, - { - .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}, - }); + if (stages->create_info != NULL) { + *sh_p = GPU_shader_create_from_info_name(stages->create_info); + } + else { + *sh_p = GPU_shader_create_from_arrays_named( + stages->name, + { + .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. */ @@ -541,21 +384,26 @@ GPUShader *GPU_shader_get_builtin_shader_with_config(eGPUBuiltinShader shader, GPU_SHADER_3D_SMOOTH_COLOR, GPU_SHADER_3D_DEPTH_ONLY, GPU_SHADER_INSTANCE_VARIYING_COLOR_VARIYING_SIZE, - GPU_SHADER_3D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_OUTLINE_AA, GPU_SHADER_3D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_AA, GPU_SHADER_3D_FLAT_COLOR, GPU_SHADER_3D_LINE_DASHED_UNIFORM_COLOR)); - const char *world_clip_lib = datatoc_gpu_shader_cfg_world_clip_lib_glsl; - const char *world_clip_def = "#define USE_WORLD_CLIP_PLANES\n"; /* In rare cases geometry shaders calculate clipping themselves. */ - *sh_p = GPU_shader_create_from_arrays_named( - stages->name, - { - .vert = (const char *[]){world_clip_lib, stages->vert, NULL}, - .geom = (const char *[]){stages->geom ? world_clip_lib : NULL, stages->geom, NULL}, - .frag = (const char *[]){datatoc_gpu_shader_colorspace_lib_glsl, stages->frag, NULL}, - .defs = (const char *[]){world_clip_def, stages->defs, NULL}, - }); + if (stages->clipped_create_info != NULL) { + *sh_p = GPU_shader_create_from_info_name(stages->clipped_create_info); + } + else { + const char *world_clip_lib = datatoc_gpu_shader_cfg_world_clip_lib_glsl; + const char *world_clip_def = "#define USE_WORLD_CLIP_PLANES\n"; + *sh_p = GPU_shader_create_from_arrays_named( + stages->name, + { + .vert = (const char *[]){world_clip_lib, stages->vert, NULL}, + .geom = (const char *[]){stages->geom ? world_clip_lib : NULL, stages->geom, NULL}, + .frag = + (const char *[]){datatoc_gpu_shader_colorspace_lib_glsl, stages->frag, NULL}, + .defs = (const char *[]){world_clip_def, stages->defs, NULL}, + }); + } } else { BLI_assert(0); diff --git a/source/blender/gpu/intern/gpu_shader_create_info.cc b/source/blender/gpu/intern/gpu_shader_create_info.cc new file mode 100644 index 00000000000..f7622751726 --- /dev/null +++ b/source/blender/gpu/intern/gpu_shader_create_info.cc @@ -0,0 +1,263 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2021 Blender Foundation. + * All rights reserved. + */ + +/** \file + * \ingroup gpu + * + * Descriptor type used to define shader structure, resources and interfaces. + */ + +#include "BLI_map.hh" +#include "BLI_set.hh" +#include "BLI_string_ref.hh" + +#include "GPU_capabilities.h" +#include "GPU_platform.h" +#include "GPU_shader.h" +#include "GPU_texture.h" + +#include "gpu_shader_create_info.hh" +#include "gpu_shader_create_info_private.hh" + +#undef GPU_SHADER_INTERFACE_INFO +#undef GPU_SHADER_CREATE_INFO + +namespace blender::gpu::shader { + +using CreateInfoDictionnary = Map<StringRef, ShaderCreateInfo *>; +using InterfaceDictionnary = Map<StringRef, StageInterfaceInfo *>; + +static CreateInfoDictionnary *g_create_infos = nullptr; +static InterfaceDictionnary *g_interfaces = nullptr; + +void ShaderCreateInfo::finalize() +{ + if (finalized_) { + return; + } + finalized_ = true; + + for (auto &info_name : additional_infos_) { + const ShaderCreateInfo &info = *reinterpret_cast<const ShaderCreateInfo *>( + gpu_shader_create_info_get(info_name.c_str())); + + /* Recursive. */ + const_cast<ShaderCreateInfo &>(info).finalize(); + +#if 0 /* Enabled for debugging merging. TODO(fclem) exception handling and error reporting in \ + console. */ + std::cout << "Merging : " << info_name << " > " << name_ << std::endl; +#endif + + interface_names_size_ += info.interface_names_size_; + + vertex_inputs_.extend(info.vertex_inputs_); + fragment_outputs_.extend(info.fragment_outputs_); + vertex_out_interfaces_.extend(info.vertex_out_interfaces_); + geometry_out_interfaces_.extend(info.geometry_out_interfaces_); + + push_constants_.extend(info.push_constants_); + defines_.extend(info.defines_); + + batch_resources_.extend(info.batch_resources_); + pass_resources_.extend(info.pass_resources_); + typedef_sources_.extend_non_duplicates(info.typedef_sources_); + + validate(info); + + if (info.compute_layout_.local_size_x != -1) { + compute_layout_.local_size_x = info.compute_layout_.local_size_x; + compute_layout_.local_size_y = info.compute_layout_.local_size_y; + compute_layout_.local_size_z = info.compute_layout_.local_size_z; + } + + if (!info.vertex_source_.is_empty()) { + BLI_assert(vertex_source_.is_empty()); + vertex_source_ = info.vertex_source_; + } + if (!info.geometry_source_.is_empty()) { + BLI_assert(geometry_source_.is_empty()); + geometry_source_ = info.geometry_source_; + geometry_layout_ = info.geometry_layout_; + } + if (!info.fragment_source_.is_empty()) { + BLI_assert(fragment_source_.is_empty()); + fragment_source_ = info.fragment_source_; + } + if (!info.compute_source_.is_empty()) { + BLI_assert(compute_source_.is_empty()); + compute_source_ = info.compute_source_; + } + + do_static_compilation_ = do_static_compilation_ || info.do_static_compilation_; + } +} + +void ShaderCreateInfo::validate(const ShaderCreateInfo &other_info) +{ + { + /* Check same bind-points usage in OGL. */ + Set<int> images, samplers, ubos, ssbos; + + auto register_resource = [&](const Resource &res) -> bool { + switch (res.bind_type) { + case Resource::BindType::UNIFORM_BUFFER: + return images.add(res.slot); + case Resource::BindType::STORAGE_BUFFER: + return samplers.add(res.slot); + case Resource::BindType::SAMPLER: + return ubos.add(res.slot); + case Resource::BindType::IMAGE: + return ssbos.add(res.slot); + default: + return false; + } + }; + + auto print_error_msg = [&](const Resource &res) { + std::cerr << name_ << ": Validation failed : Overlapping "; + + switch (res.bind_type) { + case Resource::BindType::UNIFORM_BUFFER: + std::cerr << "Uniform Buffer " << res.uniformbuf.name; + break; + case Resource::BindType::STORAGE_BUFFER: + std::cerr << "Storage Buffer " << res.storagebuf.name; + break; + case Resource::BindType::SAMPLER: + std::cerr << "Sampler " << res.sampler.name; + break; + case Resource::BindType::IMAGE: + std::cerr << "Image " << res.image.name; + break; + default: + std::cerr << "Unknown Type"; + break; + } + std::cerr << " (" << res.slot << ") while merging " << other_info.name_ << std::endl; + }; + + for (auto &res : batch_resources_) { + if (register_resource(res) == false) { + print_error_msg(res); + } + } + + for (auto &res : pass_resources_) { + if (register_resource(res) == false) { + print_error_msg(res); + } + } + } + { + /* TODO(fclem) Push constant validation. */ + } +} + +} // namespace blender::gpu::shader + +using namespace blender::gpu::shader; + +void gpu_shader_create_info_init() +{ + g_create_infos = new CreateInfoDictionnary(); + g_interfaces = new InterfaceDictionnary(); + +#define GPU_SHADER_INTERFACE_INFO(_interface, _inst_name) \ + auto *ptr_##_interface = new StageInterfaceInfo(#_interface, _inst_name); \ + auto &_interface = *ptr_##_interface; \ + g_interfaces->add_new(#_interface, ptr_##_interface); \ + _interface + +#define GPU_SHADER_CREATE_INFO(_info) \ + auto *ptr_##_info = new ShaderCreateInfo(#_info); \ + auto &_info = *ptr_##_info; \ + g_create_infos->add_new(#_info, ptr_##_info); \ + _info + +/* Declare, register and construct the infos. */ +#include "gpu_shader_create_info_list.hh" + +/* Baked shader data appended to create infos. */ +/* TODO(jbakker): should call a function with a callback. so we could switch implementations. + * We cannot compile bf_gpu twice. */ +#ifdef GPU_RUNTIME +# include "gpu_shader_baked.hh" +#endif + + /* WORKAROUND: Replace draw_mesh info with the legacy one for systems that have problems with UBO + * indexing. */ + if (GPU_type_matches(GPU_DEVICE_INTEL | GPU_DEVICE_INTEL_UHD, GPU_OS_ANY, GPU_DRIVER_ANY) || + GPU_type_matches(GPU_DEVICE_ANY, GPU_OS_MAC, GPU_DRIVER_ANY) || GPU_crappy_amd_driver()) { + draw_modelmat = draw_modelmat_legacy; + } + + /* TEST */ + // gpu_shader_create_info_compile_all(); +} + +void gpu_shader_create_info_exit() +{ + for (auto *value : g_create_infos->values()) { + delete value; + } + delete g_create_infos; + + for (auto *value : g_interfaces->values()) { + delete value; + } + delete g_interfaces; +} + +bool gpu_shader_create_info_compile_all() +{ + int success = 0; + int total = 0; + for (ShaderCreateInfo *info : g_create_infos->values()) { + if (info->do_static_compilation_) { + total++; + GPUShader *shader = GPU_shader_create_from_info( + reinterpret_cast<const GPUShaderCreateInfo *>(info)); + if (shader == nullptr) { + printf("Compilation %s Failed\n", info->name_.c_str()); + } + else { + success++; + } + GPU_shader_free(shader); + } + } + printf("===============================\n"); + printf("Shader Test compilation result: \n"); + printf("%d Total\n", total); + printf("%d Passed\n", success); + printf("%d Failed\n", total - success); + printf("===============================\n"); + return success == total; +} + +/* Runtime create infos are not registered in the dictionary and cannot be searched. */ +const GPUShaderCreateInfo *gpu_shader_create_info_get(const char *info_name) +{ + if (g_create_infos->contains(info_name) == false) { + printf("Error: Cannot find shader create info named \"%s\"\n", info_name); + } + ShaderCreateInfo *info = g_create_infos->lookup(info_name); + return reinterpret_cast<const GPUShaderCreateInfo *>(info); +} diff --git a/source/blender/gpu/intern/gpu_shader_create_info.hh b/source/blender/gpu/intern/gpu_shader_create_info.hh new file mode 100644 index 00000000000..6236e92a226 --- /dev/null +++ b/source/blender/gpu/intern/gpu_shader_create_info.hh @@ -0,0 +1,622 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2021 Blender Foundation. + * All rights reserved. + */ + +/** \file + * \ingroup gpu + * + * Descriptor type used to define shader structure, resources and interfaces. + * + * Some rule of thumb: + * - Do not include anything else than this file in each info file. + */ + +#pragma once + +#include "BLI_string_ref.hh" +#include "BLI_vector.hh" +#include "GPU_texture.h" + +namespace blender::gpu::shader { + +#ifndef GPU_SHADER_CREATE_INFO +/* Helps intelisense / auto-completion. */ +# define GPU_SHADER_INTERFACE_INFO(_interface, _inst_name) \ + StageInterfaceInfo _interface(#_interface, _inst_name); \ + _interface +# define GPU_SHADER_CREATE_INFO(_info) \ + ShaderCreateInfo _info(#_info); \ + _info +#endif + +enum class Type { + FLOAT = 0, + VEC2, + VEC3, + VEC4, + MAT3, + MAT4, + UINT, + UVEC2, + UVEC3, + UVEC4, + INT, + IVEC2, + IVEC3, + IVEC4, + BOOL, +}; + +enum class BuiltinBits { + /** + * Allow getting barycentric coordinates inside the fragment shader. + * \note Emulated on OpenGL. + */ + BARYCENTRIC_COORD = (1 << 0), + FRAG_COORD = (1 << 2), + FRONT_FACING = (1 << 4), + GLOBAL_INVOCATION_ID = (1 << 5), + INSTANCE_ID = (1 << 6), + LAYER = (1 << 7), + LOCAL_INVOCATION_ID = (1 << 8), + LOCAL_INVOCATION_INDEX = (1 << 9), + NUM_WORK_GROUP = (1 << 10), + POINT_COORD = (1 << 11), + POINT_SIZE = (1 << 12), + PRIMITIVE_ID = (1 << 13), + VERTEX_ID = (1 << 14), + WORK_GROUP_ID = (1 << 15), + WORK_GROUP_SIZE = (1 << 16), +}; +ENUM_OPERATORS(BuiltinBits, BuiltinBits::WORK_GROUP_SIZE); + +/* Samplers & images. */ +enum class ImageType { + /** Color samplers/image. */ + FLOAT_BUFFER = 0, + FLOAT_1D, + FLOAT_1D_ARRAY, + FLOAT_2D, + FLOAT_2D_ARRAY, + FLOAT_3D, + FLOAT_CUBE, + FLOAT_CUBE_ARRAY, + INT_BUFFER, + INT_1D, + INT_1D_ARRAY, + INT_2D, + INT_2D_ARRAY, + INT_3D, + INT_CUBE, + INT_CUBE_ARRAY, + UINT_BUFFER, + UINT_1D, + UINT_1D_ARRAY, + UINT_2D, + UINT_2D_ARRAY, + UINT_3D, + UINT_CUBE, + UINT_CUBE_ARRAY, + /** Depth samplers (not supported as image). */ + SHADOW_2D, + SHADOW_2D_ARRAY, + SHADOW_CUBE, + SHADOW_CUBE_ARRAY, + DEPTH_2D, + DEPTH_2D_ARRAY, + DEPTH_CUBE, + DEPTH_CUBE_ARRAY, +}; + +/* Storage qualifiers. */ +enum class Qualifier { + RESTRICT = (1 << 0), + READ_ONLY = (1 << 1), + WRITE_ONLY = (1 << 2), + QUALIFIER_MAX = (WRITE_ONLY << 1) - 1, +}; +ENUM_OPERATORS(Qualifier, Qualifier::QUALIFIER_MAX); + +enum class Frequency { + BATCH = 0, + PASS, +}; + +/* Dual Source Blending Index. */ +enum class DualBlend { + NONE = 0, + SRC_0, + SRC_1, +}; + +/* Interpolation qualifiers. */ +enum class Interpolation { + SMOOTH = 0, + FLAT, + NO_PERSPECTIVE, +}; + +/** Input layout for geometry shader. */ +enum class PrimitiveIn { + POINTS = 0, + LINES, + LINES_ADJACENCY, + TRIANGLES, + TRIANGLES_ADJACENCY, +}; + +/** Output layout for geometry shader. */ +enum class PrimitiveOut { + POINTS = 0, + LINE_STRIP, + TRIANGLE_STRIP, +}; + +struct StageInterfaceInfo { + struct InOut { + Interpolation interp; + Type type; + StringRefNull name; + }; + + StringRefNull name; + /** Name of the instance of the block (used to access). + * Can be empty string (i.e: "") only if not using geometry shader. */ + StringRefNull instance_name; + /** List of all members of the interface. */ + Vector<InOut> inouts; + + StageInterfaceInfo(const char *name_, const char *instance_name_) + : name(name_), instance_name(instance_name_){}; + ~StageInterfaceInfo(){}; + + using Self = StageInterfaceInfo; + + Self &smooth(Type type, StringRefNull _name) + { + inouts.append({Interpolation::SMOOTH, type, _name}); + return *(Self *)this; + } + + Self &flat(Type type, StringRefNull _name) + { + inouts.append({Interpolation::FLAT, type, _name}); + return *(Self *)this; + } + + Self &no_perspective(Type type, StringRefNull _name) + { + inouts.append({Interpolation::NO_PERSPECTIVE, type, _name}); + return *(Self *)this; + } +}; + +/** + * @brief Describe inputs & outputs, stage interfaces, resources and sources of a shader. + * If all data is correctly provided, this is all that is needed to create and compile + * a GPUShader. + * + * IMPORTANT: All strings are references only. Make sure all the strings used by a + * ShaderCreateInfo are not freed until it is consumed or deleted. + */ +struct ShaderCreateInfo { + /** Shader name for debugging. */ + StringRefNull name_; + /** True if the shader is static and can be pre-compiled at compile time. */ + bool do_static_compilation_ = false; + /** If true, all additionally linked create info will be merged into this one. */ + bool finalized_ = false; + /** + * Maximum length of all the resource names including each null terminator. + * Only for names used by gpu::ShaderInterface. + */ + size_t interface_names_size_ = 0; + + struct VertIn { + int index; + Type type; + StringRefNull name; + }; + Vector<VertIn> vertex_inputs_; + + struct GeometryStageLayout { + PrimitiveIn primitive_in; + int invocations; + PrimitiveOut primitive_out; + /** Set to -1 by default to check if used. */ + int max_vertices = -1; + }; + GeometryStageLayout geometry_layout_; + + struct ComputeStageLayout { + int local_size_x = -1; + int local_size_y = -1; + int local_size_z = -1; + }; + + ComputeStageLayout compute_layout_; + + struct FragOut { + int index; + Type type; + DualBlend blend; + StringRefNull name; + }; + Vector<FragOut> fragment_outputs_; + + struct Sampler { + ImageType type; + eGPUSamplerState sampler; + StringRefNull name; + }; + + struct Image { + eGPUTextureFormat format; + ImageType type; + Qualifier qualifiers; + StringRefNull name; + }; + + struct UniformBuf { + StringRefNull type_name; + StringRefNull name; + }; + + struct StorageBuf { + Qualifier qualifiers; + StringRefNull type_name; + StringRefNull name; + }; + + struct Resource { + enum BindType { + UNIFORM_BUFFER = 0, + STORAGE_BUFFER, + SAMPLER, + IMAGE, + }; + + BindType bind_type; + int slot; + union { + Sampler sampler; + Image image; + UniformBuf uniformbuf; + StorageBuf storagebuf; + }; + + Resource(BindType type, int _slot) : bind_type(type), slot(_slot){}; + }; + /** + * Resources are grouped by frequency of change. + * Pass resources are meant to be valid for the whole pass. + * Batch resources can be changed in a more granular manner (per object/material). + * Mis-usage will only produce suboptimal performance. + */ + Vector<Resource> pass_resources_, batch_resources_; + + Vector<StageInterfaceInfo *> vertex_out_interfaces_; + Vector<StageInterfaceInfo *> geometry_out_interfaces_; + + struct PushConst { + int index; + Type type; + StringRefNull name; + int array_size; + }; + + Vector<PushConst> push_constants_; + + /* Sources for resources type definitions. */ + Vector<StringRefNull> typedef_sources_; + + StringRefNull vertex_source_, geometry_source_, fragment_source_, compute_source_; + + Vector<std::array<StringRefNull, 2>> defines_; + /** + * Name of other infos to recursively merge with this one. + * No data slot must overlap otherwise we throw an error. + */ + Vector<StringRefNull> additional_infos_; + + public: + ShaderCreateInfo(const char *name) : name_(name){}; + ~ShaderCreateInfo(){}; + + using Self = ShaderCreateInfo; + + /* -------------------------------------------------------------------- */ + /** \name Shaders in/outs (fixed function pipeline config) + * \{ */ + + Self &vertex_in(int slot, Type type, StringRefNull name) + { + vertex_inputs_.append({slot, type, name}); + interface_names_size_ += name.size() + 1; + return *(Self *)this; + } + + Self &vertex_out(StageInterfaceInfo &interface) + { + vertex_out_interfaces_.append(&interface); + return *(Self *)this; + } + + /** + * IMPORTANT: invocations count is only used if GL_ARB_gpu_shader5 is supported. On + * implementations that do not supports it, the max_vertices will be be multiplied by + * invocations. Your shader needs to account for this fact. Use `#ifdef GPU_ARB_gpu_shader5` + * and make a code path that does not rely on gl_InvocationID. + */ + Self &geometry_layout(PrimitiveIn prim_in, + PrimitiveOut prim_out, + int max_vertices, + int invocations = -1) + { + geometry_layout_.primitive_in = prim_in; + geometry_layout_.primitive_out = prim_out; + geometry_layout_.max_vertices = max_vertices; + geometry_layout_.invocations = invocations; + return *(Self *)this; + } + + Self &local_group_size(int local_size_x = -1, int local_size_y = -1, int local_size_z = -1) + { + compute_layout_.local_size_x = local_size_x; + compute_layout_.local_size_y = local_size_y; + compute_layout_.local_size_z = local_size_z; + return *(Self *)this; + } + + /** + * Only needed if geometry shader is enabled. + * IMPORTANT: Input and output instance name will have respectively "_in" and "_out" suffix + * appended in the geometry shader IF AND ONLY IF the vertex_out interface instance name matches + * the geometry_out interface instance name. + */ + Self &geometry_out(StageInterfaceInfo &interface) + { + geometry_out_interfaces_.append(&interface); + return *(Self *)this; + } + + Self &fragment_out(int slot, Type type, StringRefNull name, DualBlend blend = DualBlend::NONE) + { + fragment_outputs_.append({slot, type, blend, name}); + return *(Self *)this; + } + + /** \} */ + + /* -------------------------------------------------------------------- */ + /** \name Resources bindings points + * \{ */ + + Self &uniform_buf(int slot, + StringRefNull type_name, + StringRefNull name, + Frequency freq = Frequency::PASS) + { + Resource res(Resource::BindType::UNIFORM_BUFFER, slot); + res.uniformbuf.name = name; + res.uniformbuf.type_name = type_name; + ((freq == Frequency::PASS) ? pass_resources_ : batch_resources_).append(res); + interface_names_size_ += name.size() + 1; + return *(Self *)this; + } + + Self &storage_buf(int slot, + Qualifier qualifiers, + StringRefNull type_name, + StringRefNull name, + Frequency freq = Frequency::PASS) + { + Resource res(Resource::BindType::STORAGE_BUFFER, slot); + res.storagebuf.qualifiers = qualifiers; + res.storagebuf.type_name = type_name; + res.storagebuf.name = name; + ((freq == Frequency::PASS) ? pass_resources_ : batch_resources_).append(res); + interface_names_size_ += name.size() + 1; + return *(Self *)this; + } + + Self &image(int slot, + eGPUTextureFormat format, + Qualifier qualifiers, + ImageType type, + StringRefNull name, + Frequency freq = Frequency::PASS) + { + Resource res(Resource::BindType::IMAGE, slot); + res.image.format = format; + res.image.qualifiers = qualifiers; + res.image.type = type; + res.image.name = name; + ((freq == Frequency::PASS) ? pass_resources_ : batch_resources_).append(res); + interface_names_size_ += name.size() + 1; + return *(Self *)this; + } + + Self &sampler(int slot, + ImageType type, + StringRefNull name, + Frequency freq = Frequency::PASS, + eGPUSamplerState sampler = (eGPUSamplerState)-1) + { + Resource res(Resource::BindType::SAMPLER, slot); + res.sampler.type = type; + res.sampler.name = name; + res.sampler.sampler = sampler; + ((freq == Frequency::PASS) ? pass_resources_ : batch_resources_).append(res); + interface_names_size_ += name.size() + 1; + return *(Self *)this; + } + + /** \} */ + + /* -------------------------------------------------------------------- */ + /** \name Shader Source + * \{ */ + + Self &vertex_source(StringRefNull filename) + { + vertex_source_ = filename; + return *(Self *)this; + } + + Self &geometry_source(StringRefNull filename) + { + geometry_source_ = filename; + return *(Self *)this; + } + + Self &fragment_source(StringRefNull filename) + { + fragment_source_ = filename; + return *(Self *)this; + } + + Self &compute_source(StringRefNull filename) + { + compute_source_ = filename; + return *(Self *)this; + } + + /** \} */ + + /* -------------------------------------------------------------------- */ + /** \name Push constants + * + * Data managed by GPUShader. Can be set through uniform functions. Must be less than 128bytes. + * One slot represents 4bytes. Each element needs to have enough empty space left after it. + * example: + * [0] = PUSH_CONSTANT(MAT4, "ModelMatrix"), + * ---- 16 slots occupied by ModelMatrix ---- + * [16] = PUSH_CONSTANT(VEC4, "color"), + * ---- 4 slots occupied by color ---- + * [20] = PUSH_CONSTANT(BOOL, "srgbToggle"), + * The maximum slot is 31. + * \{ */ + + Self &push_constant(int slot, Type type, StringRefNull name, int array_size = 0) + { + BLI_assert_msg(name.find("[") == -1, + "Array syntax is forbidden for push constants." + "Use the array_size parameter instead."); + push_constants_.append({slot, type, name, array_size}); + interface_names_size_ += name.size() + 1; + return *(Self *)this; + } + + /** \} */ + + /* -------------------------------------------------------------------- */ + /** \name Defines + * \{ */ + + Self &define(StringRefNull name, StringRefNull value = "") + { + defines_.append({name, value}); + return *(Self *)this; + } + + /** \} */ + + /* -------------------------------------------------------------------- */ + /** \name Defines + * \{ */ + + Self &do_static_compilation(bool value) + { + do_static_compilation_ = value; + return *(Self *)this; + } + + /** \} */ + + /* -------------------------------------------------------------------- */ + /** \name Additional Create Info + * + * Used to share parts of the infos that are common to many shaders. + * \{ */ + + Self &additional_info(StringRefNull info_name0, + StringRefNull info_name1 = "", + StringRefNull info_name2 = "", + StringRefNull info_name3 = "", + StringRefNull info_name4 = "", + StringRefNull info_name5 = "", + StringRefNull info_name6 = "") + { + additional_infos_.append(info_name0); + if (!info_name1.is_empty()) { + additional_infos_.append(info_name1); + } + if (!info_name2.is_empty()) { + additional_infos_.append(info_name2); + } + if (!info_name3.is_empty()) { + additional_infos_.append(info_name3); + } + if (!info_name4.is_empty()) { + additional_infos_.append(info_name4); + } + if (!info_name5.is_empty()) { + additional_infos_.append(info_name5); + } + if (!info_name6.is_empty()) { + additional_infos_.append(info_name6); + } + return *(Self *)this; + } + + /** \} */ + + /* -------------------------------------------------------------------- */ + /** \name Typedef Sources + * + * Some resource declarations might need some special structure defined. + * Adding a file using typedef_source will include it before the resource + * and interface definitions. + * \{ */ + + Self &typedef_source(StringRefNull filename) + { + typedef_sources_.append(filename); + return *(Self *)this; + } + + /** \} */ + + /* -------------------------------------------------------------------- */ + /** \name Recursive evaluation. + * + * Flatten all dependency so that this descriptor contains all the data from the additional + * descriptors. This avoids tedious traversal in shader source creation. + * \{ */ + + /* WARNING: Recursive. */ + void finalize(); + + /** Error detection that some backend compilers do not complain about. */ + void validate(const ShaderCreateInfo &other_info); + + /** \} */ +}; + +} // namespace blender::gpu::shader diff --git a/source/blender/gpu/intern/gpu_shader_create_info_private.hh b/source/blender/gpu/intern/gpu_shader_create_info_private.hh new file mode 100644 index 00000000000..6d2878377ad --- /dev/null +++ b/source/blender/gpu/intern/gpu_shader_create_info_private.hh @@ -0,0 +1,46 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2021 Blender Foundation. + * All rights reserved. + */ + +/** \file + * \ingroup gpu + * + * Descriptor type used to define shader structure, resources and interfaces. + * + * Some rule of thumb: + * - Do not include anything else than this file in each descriptor file. + */ + +#pragma once + +#include "GPU_shader.h" + +#ifdef __cplusplus +extern "C" { +#endif + +void gpu_shader_create_info_init(void); +void gpu_shader_create_info_exit(void); + +bool gpu_shader_create_info_compile_all(void); + +const GPUShaderCreateInfo *gpu_shader_create_info_get(const char *info_name); + +#ifdef __cplusplus +} +#endif diff --git a/source/blender/gpu/intern/gpu_shader_dependency.cc b/source/blender/gpu/intern/gpu_shader_dependency.cc new file mode 100644 index 00000000000..2333590810f --- /dev/null +++ b/source/blender/gpu/intern/gpu_shader_dependency.cc @@ -0,0 +1,388 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2021 Blender Foundation. + * All rights reserved. + */ + +/** \file + * \ingroup gpu + * + * Shader source dependency builder that make possible to support #include directive inside the + * shader files. + */ + +#include <iostream> + +#include "BLI_map.hh" +#include "BLI_set.hh" +#include "BLI_string_ref.hh" + +#include "gpu_shader_create_info.hh" +#include "gpu_shader_dependency_private.h" + +extern "C" { +#define SHADER_SOURCE(datatoc, filename, filepath) extern char datatoc[]; +#include "glsl_draw_source_list.h" +#include "glsl_gpu_source_list.h" +#undef SHADER_SOURCE +} + +namespace blender::gpu { + +using GPUSourceDictionnary = Map<StringRef, struct GPUSource *>; + +struct GPUSource { + StringRefNull fullpath; + StringRefNull filename; + StringRefNull source; + Vector<GPUSource *> dependencies; + bool dependencies_init = false; + shader::BuiltinBits builtins = (shader::BuiltinBits)0; + std::string processed_source; + + GPUSource(const char *path, const char *file, const char *datatoc) + : fullpath(path), filename(file), source(datatoc) + { + /* Scan for builtins. */ + /* FIXME: This can trigger false positive caused by disabled #if blocks. */ + /* TODO(fclem): Could be made faster by scanning once. */ + /* TODO(fclem): BARYCENTRIC_COORD. */ + if (source.find("gl_FragCoord", 0)) { + builtins |= shader::BuiltinBits::FRAG_COORD; + } + if (source.find("gl_FrontFacing", 0)) { + builtins |= shader::BuiltinBits::FRONT_FACING; + } + if (source.find("gl_GlobalInvocationID", 0)) { + builtins |= shader::BuiltinBits::GLOBAL_INVOCATION_ID; + } + if (source.find("gl_InstanceID", 0)) { + builtins |= shader::BuiltinBits::INSTANCE_ID; + } + if (source.find("gl_Layer", 0)) { + builtins |= shader::BuiltinBits::LAYER; + } + if (source.find("gl_LocalInvocationID", 0)) { + builtins |= shader::BuiltinBits::LOCAL_INVOCATION_ID; + } + if (source.find("gl_LocalInvocationIndex", 0)) { + builtins |= shader::BuiltinBits::LOCAL_INVOCATION_INDEX; + } + if (source.find("gl_NumWorkGroup", 0)) { + builtins |= shader::BuiltinBits::NUM_WORK_GROUP; + } + if (source.find("gl_PointCoord", 0)) { + builtins |= shader::BuiltinBits::POINT_COORD; + } + if (source.find("gl_PointSize", 0)) { + builtins |= shader::BuiltinBits::POINT_SIZE; + } + if (source.find("gl_PrimitiveID", 0)) { + builtins |= shader::BuiltinBits::PRIMITIVE_ID; + } + if (source.find("gl_VertexID", 0)) { + builtins |= shader::BuiltinBits::VERTEX_ID; + } + if (source.find("gl_WorkGroupID", 0)) { + builtins |= shader::BuiltinBits::WORK_GROUP_ID; + } + if (source.find("gl_WorkGroupSize", 0)) { + builtins |= shader::BuiltinBits::WORK_GROUP_SIZE; + } + + /* TODO(fclem): We could do that at compile time. */ + /* Limit to shared header files to avoid the temptation to use C++ syntax in .glsl files. */ + if (filename.endswith(".h") || filename.endswith(".hh")) { + enum_preprocess(); + } + }; + + bool is_in_comment(const StringRef &input, int64_t offset) + { + return (input.rfind("/*", offset) > input.rfind("*/", offset)) || + (input.rfind("//", offset) > input.rfind("\n", offset)); + } + + template<bool check_whole_word = true, bool reversed = false, typename T> + int64_t find_str(const StringRef &input, const T keyword, int64_t offset = 0) + { + while (1) { + if constexpr (reversed) { + offset = input.rfind(keyword, offset); + } + else { + offset = input.find(keyword, offset); + } + if (offset > 0) { + if constexpr (check_whole_word) { + /* Fix false positive if something has "enum" as suffix. */ + char previous_char = input[offset - 1]; + if (!(ELEM(previous_char, '\n', '\t', ' ', ':'))) { + offset += (reversed) ? -1 : 1; + continue; + } + } + /* Fix case where the keyword is in a comment. */ + if (is_in_comment(input, offset)) { + offset += (reversed) ? -1 : 1; + continue; + } + } + return offset; + } + } + + void print_error(const StringRef &input, int64_t offset, const StringRef message) + { + std::cout << " error: " << message << "\n"; + StringRef sub = input.substr(0, offset); + int64_t line_number = std::count(sub.begin(), sub.end(), '\n') + 1; + int64_t line_end = input.find("\n", offset); + int64_t line_start = input.rfind("\n", offset) + 1; + int64_t char_number = offset - line_start + 1; + char line_prefix[16] = ""; + SNPRINTF(line_prefix, "%5ld | ", line_number); + + /* TODO Use clog. */ + + std::cout << fullpath << ":" << line_number << ":" << char_number; + + std::cout << " error: " << message << "\n"; + std::cout << line_prefix << input.substr(line_start, line_end - line_start) << "\n"; + std::cout << " | "; + for (int64_t i = 0; i < char_number - 1; i++) { + std::cout << " "; + } + std::cout << "^\n"; + } + + /** + * Transform C,C++ enum declaration into GLSL compatible defines and constants: + * + * \code{.cpp} + * enum eMyEnum : uint32_t { + * ENUM_1 = 0u, + * ENUM_2 = 1u, + * ENUM_3 = 2u, + * }; + * \endcode + * + * or + * + * \code{.c} + * enum eMyEnum { + * ENUM_1 = 0u, + * ENUM_2 = 1u, + * ENUM_3 = 2u, + * }; + * \endcode + * + * becomes + * + * \code{.glsl} + * #define eMyEnum uint + * const uint ENUM_1 = 0u, ENUM_2 = 1u, ENUM_3 = 2u; + * \endcode + * + * IMPORTANT: This has some requirements: + * - Enums needs to have underlying types specified to uint32_t to make them usable in UBO/SSBO. + * - All values needs to be specified using constant literals to avoid compiler differencies. + * - All values needs to have the 'u' suffix to avoid GLSL compiler errors. + */ + void enum_preprocess(void) + { + const StringRefNull input = source; + std::string output = ""; + int64_t cursor = 0; + int64_t last_pos = 0; + const bool is_cpp = filename.endswith(".hh"); + +#define find_keyword find_str<true, false> +#define find_token find_str<false, false> +#define rfind_token find_str<false, true> +#define CHECK(test_value, str, ofs, msg) \ + if ((test_value) == -1) { \ + print_error(str, ofs, msg); \ + cursor++; \ + continue; \ + } + + while (1) { + cursor = find_keyword(input, "enum ", cursor); + if (cursor == -1) { + break; + } + /* Output anything between 2 enums blocks. */ + output += input.substr(last_pos, cursor - last_pos); + + /* Extract enum type name. */ + int64_t name_start = input.find(" ", cursor); + + int64_t values_start = find_token(input, '{', cursor); + CHECK(values_start, input, cursor, "Malformed enum class. Expected \'{\' after typename."); + + StringRef enum_name = input.substr(name_start, values_start - name_start); + if (is_cpp) { + int64_t name_end = find_token(enum_name, ":"); + CHECK(name_end, input, name_start, "Expected \':\' after C++ enum name."); + + int64_t underlying_type = find_keyword(enum_name, "uint32_t", name_end); + CHECK(underlying_type, input, name_start, "C++ enums needs uint32_t underlying type."); + + enum_name = input.substr(name_start, name_end); + } + + output += "#define " + enum_name + " uint\n"; + + /* Extract enum values. */ + int64_t values_end = find_token(input, '}', values_start); + CHECK(values_end, input, cursor, "Malformed enum class. Expected \'}\' after values."); + + /* Skip opening brackets. */ + values_start += 1; + + StringRef enum_values = input.substr(values_start, values_end - values_start); + + /* Really poor check. Could be done better. */ + int64_t token = find_token(enum_values, '{'); + int64_t not_found = (token == -1) ? 0 : -1; + CHECK(not_found, input, values_start + token, "Unexpected \'{\' token inside enum values."); + + /* Do not capture the comma after the last value (if present). */ + int64_t last_equal = rfind_token(enum_values, '=', values_end); + int64_t last_comma = rfind_token(enum_values, ',', values_end); + if (last_comma > last_equal) { + enum_values = input.substr(values_start, last_comma); + } + + output += "const uint " + enum_values; + + int64_t semicolon_found = (input[values_end + 1] == ';') ? 0 : -1; + CHECK(semicolon_found, input, values_end + 1, "Expected \';\' after enum type declaration."); + + /* Skip the curly bracket but not the semicolon. */ + cursor = last_pos = values_end + 1; + } + /* If nothing has been changed, do not allocate processed_source. */ + if (last_pos == 0) { + return; + } + +#undef find_keyword +#undef find_token +#undef rfind_token + + if (last_pos != 0) { + output += input.substr(last_pos); + } + processed_source = output; + source = processed_source.c_str(); + }; + + void init_dependencies(const GPUSourceDictionnary &dict) + { + if (dependencies_init) { + return; + } + dependencies_init = true; + int64_t pos = 0; + while (true) { + pos = source.find("pragma BLENDER_REQUIRE(", pos); + if (pos == -1) { + return; + } + int64_t start = source.find('(', pos) + 1; + int64_t end = source.find(')', pos); + if (end == -1) { + /* TODO Use clog. */ + std::cout << "Error: " << filename << " : Malformed BLENDER_REQUIRE: Missing \")\"." + << std::endl; + return; + } + StringRef dependency_name = source.substr(start, end - start); + GPUSource *dependency_source = dict.lookup_default(dependency_name, nullptr); + if (dependency_source == nullptr) { + /* TODO Use clog. */ + std::cout << "Error: " << filename << " : Dependency not found \"" << dependency_name + << "\"." << std::endl; + return; + } + /* Recursive. */ + dependency_source->init_dependencies(dict); + + for (auto *dep : dependency_source->dependencies) { + dependencies.append_non_duplicates(dep); + } + dependencies.append_non_duplicates(dependency_source); + pos++; + }; + } + + /* Returns the final string with all includes done. */ + void build(std::string &str, shader::BuiltinBits &out_builtins) + { + for (auto *dep : dependencies) { + out_builtins |= builtins; + str += dep->source; + } + str += source; + } +}; + +} // namespace blender::gpu + +using namespace blender::gpu; + +static GPUSourceDictionnary *g_sources = nullptr; + +void gpu_shader_dependency_init() +{ + g_sources = new GPUSourceDictionnary(); + +#define SHADER_SOURCE(datatoc, filename, filepath) \ + g_sources->add_new(filename, new GPUSource(filepath, filename, datatoc)); +#include "glsl_draw_source_list.h" +#include "glsl_gpu_source_list.h" +#undef SHADER_SOURCE + + for (auto *value : g_sources->values()) { + value->init_dependencies(*g_sources); + } +} + +void gpu_shader_dependency_exit() +{ + for (auto *value : g_sources->values()) { + delete value; + } + delete g_sources; +} + +char *gpu_shader_dependency_get_resolved_source(const char *shader_source_name, uint32_t *builtins) +{ + GPUSource *source = g_sources->lookup(shader_source_name); + std::string str; + shader::BuiltinBits out_builtins; + source->build(str, out_builtins); + *builtins |= (uint32_t)out_builtins; + return strdup(str.c_str()); +} + +char *gpu_shader_dependency_get_source(const char *shader_source_name) +{ + GPUSource *src = g_sources->lookup(shader_source_name); + return strdup(src->source.c_str()); +} diff --git a/source/blender/gpu/intern/gpu_shader_dependency_private.h b/source/blender/gpu/intern/gpu_shader_dependency_private.h new file mode 100644 index 00000000000..b129ca74a48 --- /dev/null +++ b/source/blender/gpu/intern/gpu_shader_dependency_private.h @@ -0,0 +1,44 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2021 Blender Foundation. + * All rights reserved. + */ + +/** \file + * \ingroup gpu + * + * Shader source dependency builder that make possible to support #include directive inside the + * shader files. + */ + +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +void gpu_shader_dependency_init(void); + +void gpu_shader_dependency_exit(void); + +/* User must free the resulting string using free. */ +char *gpu_shader_dependency_get_resolved_source(const char *shader_source_name, + uint32_t *builtins); +char *gpu_shader_dependency_get_source(const char *shader_source_name); + +#ifdef __cplusplus +} +#endif diff --git a/source/blender/gpu/intern/gpu_shader_info_baked.cc b/source/blender/gpu/intern/gpu_shader_info_baked.cc new file mode 100644 index 00000000000..55115a6d459 --- /dev/null +++ b/source/blender/gpu/intern/gpu_shader_info_baked.cc @@ -0,0 +1,24 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2021 Blender Foundation. + * All rights reserved. + */ + +/** \file + * \ingroup gpu + * + * Intentionally empty for compiling shader builder. + */ diff --git a/source/blender/gpu/intern/gpu_shader_interface.cc b/source/blender/gpu/intern/gpu_shader_interface.cc index ae94112b17b..937f49ccaec 100644 --- a/source/blender/gpu/intern/gpu_shader_interface.cc +++ b/source/blender/gpu/intern/gpu_shader_interface.cc @@ -65,14 +65,17 @@ static void sort_input_list(MutableSpan<ShaderInput> dst) } } -/* Sorts all inputs inside their respective array. - * This is to allow fast hash collision detection. - * See ShaderInterface::input_lookup for more details. */ void ShaderInterface::sort_inputs() { + /* Sorts all inputs inside their respective array. + * This is to allow fast hash collision detection. + * See `ShaderInterface::input_lookup` for more details. */ + sort_input_list(MutableSpan<ShaderInput>(inputs_, attr_len_)); sort_input_list(MutableSpan<ShaderInput>(inputs_ + attr_len_, ubo_len_)); sort_input_list(MutableSpan<ShaderInput>(inputs_ + attr_len_ + ubo_len_, uniform_len_)); + sort_input_list( + MutableSpan<ShaderInput>(inputs_ + attr_len_ + ubo_len_ + uniform_len_, ssbo_len_)); } void ShaderInterface::debug_print() diff --git a/source/blender/gpu/intern/gpu_shader_interface.hh b/source/blender/gpu/intern/gpu_shader_interface.hh index d4060cb80b4..f94006d1407 100644 --- a/source/blender/gpu/intern/gpu_shader_interface.hh +++ b/source/blender/gpu/intern/gpu_shader_interface.hh @@ -34,6 +34,7 @@ #include "BLI_utildefines.h" #include "GPU_shader.h" +#include "gpu_shader_create_info.hh" namespace blender::gpu { @@ -50,6 +51,7 @@ typedef struct ShaderInput { * Base class which is then specialized for each implementation (GL, VK, ...). */ class ShaderInterface { + friend shader::ShaderCreateInfo; /* TODO(fclem): should be protected. */ public: /** Flat array. In this order: Attributes, Ubos, Uniforms. */ @@ -73,9 +75,10 @@ class ShaderInterface { public: ShaderInterface(); + ShaderInterface(const shader::ShaderCreateInfo &info); virtual ~ShaderInterface(); - void debug_print(void); + void debug_print(); inline const ShaderInput *attr_get(const char *name) const { @@ -137,18 +140,24 @@ class ShaderInterface { static inline const char *builtin_buffer_block_name(GPUBufferBlockBuiltin u); inline uint32_t set_input_name(ShaderInput *input, char *name, uint32_t name_len) const; + inline void copy_input_name(ShaderInput *input, + const StringRefNull &name, + char *name_buffer, + uint32_t &name_buffer_offset) const; - /* Finalize interface construction by sorting the ShaderInputs for faster lookups. */ - void sort_inputs(void); + /** + * Finalize interface construction by sorting the #ShaderInputs for faster lookups. + */ + void sort_inputs(); private: inline const ShaderInput *input_lookup(const ShaderInput *const inputs, - const uint inputs_len, + uint inputs_len, const char *name) const; inline const ShaderInput *input_lookup(const ShaderInput *const inputs, - const uint inputs_len, - const int binding) const; + uint inputs_len, + int binding) const; }; inline const char *ShaderInterface::builtin_uniform_name(GPUUniformBuiltin u) @@ -188,11 +197,11 @@ inline const char *ShaderInterface::builtin_uniform_name(GPUUniformBuiltin u) case GPU_UNIFORM_COLOR: return "color"; case GPU_UNIFORM_BASE_INSTANCE: - return "baseInstance"; + return "gpu_BaseInstance"; case GPU_UNIFORM_RESOURCE_CHUNK: - return "resourceChunk"; + return "drw_resourceChunk"; case GPU_UNIFORM_RESOURCE_ID: - return "resourceId"; + return "drw_ResourceID"; case GPU_UNIFORM_SRGB_TRANSFORM: return "srgbTarget"; @@ -210,6 +219,13 @@ inline const char *ShaderInterface::builtin_uniform_block_name(GPUUniformBlockBu return "modelBlock"; case GPU_UNIFORM_BLOCK_INFO: return "infoBlock"; + + case GPU_UNIFORM_BLOCK_DRW_VIEW: + return "drw_view"; + case GPU_UNIFORM_BLOCK_DRW_MODEL: + return "drw_matrices"; + case GPU_UNIFORM_BLOCK_DRW_INFOS: + return "drw_infos"; default: return NULL; } @@ -232,8 +248,12 @@ inline uint32_t ShaderInterface::set_input_name(ShaderInput *input, { /* remove "[0]" from array name */ if (name[name_len - 1] == ']') { - name[name_len - 3] = '\0'; - name_len -= 3; + for (; name_len > 1; name_len--) { + if (name[name_len] == '[') { + name[name_len] = '\0'; + break; + } + } } input->name_offset = (uint32_t)(name - name_buffer_); @@ -241,6 +261,17 @@ inline uint32_t ShaderInterface::set_input_name(ShaderInput *input, return name_len + 1; /* include NULL terminator */ } +inline void ShaderInterface::copy_input_name(ShaderInput *input, + const StringRefNull &name, + char *name_buffer, + uint32_t &name_buffer_offset) const +{ + uint32_t name_len = name.size(); + /* Copy include NULL terminator. */ + memcpy(name_buffer + name_buffer_offset, name.c_str(), name_len + 1); + name_buffer_offset += set_input_name(input, name_buffer + name_buffer_offset, name_len); +} + inline const ShaderInput *ShaderInterface::input_lookup(const ShaderInput *const inputs, const uint inputs_len, const char *name) const diff --git a/source/blender/gpu/intern/gpu_shader_private.hh b/source/blender/gpu/intern/gpu_shader_private.hh index 65720e457d8..3bfecdefba7 100644 --- a/source/blender/gpu/intern/gpu_shader_private.hh +++ b/source/blender/gpu/intern/gpu_shader_private.hh @@ -24,9 +24,12 @@ #include "BLI_string_ref.hh" #include "GPU_shader.h" +#include "gpu_shader_create_info.hh" #include "gpu_shader_interface.hh" #include "gpu_vertex_buffer_private.hh" +#include <string> + namespace blender { namespace gpu { @@ -53,35 +56,40 @@ class Shader { virtual void geometry_shader_from_glsl(MutableSpan<const char *> sources) = 0; virtual void fragment_shader_from_glsl(MutableSpan<const char *> sources) = 0; virtual void compute_shader_from_glsl(MutableSpan<const char *> sources) = 0; - virtual bool finalize(void) = 0; + virtual bool finalize(const shader::ShaderCreateInfo *info = nullptr) = 0; virtual void transform_feedback_names_set(Span<const char *> name_list, - const eGPUShaderTFBType geom_type) = 0; + eGPUShaderTFBType geom_type) = 0; virtual bool transform_feedback_enable(GPUVertBuf *) = 0; - virtual void transform_feedback_disable(void) = 0; + virtual void transform_feedback_disable() = 0; - virtual void bind(void) = 0; - virtual void unbind(void) = 0; + virtual void bind() = 0; + virtual void unbind() = 0; virtual void uniform_float(int location, int comp_len, int array_size, const float *data) = 0; virtual void uniform_int(int location, int comp_len, int array_size, const int *data) = 0; virtual void vertformat_from_shader(GPUVertFormat *) const = 0; + std::string defines_declare(const shader::ShaderCreateInfo &info) const; + virtual std::string resources_declare(const shader::ShaderCreateInfo &info) const = 0; + virtual std::string vertex_interface_declare(const shader::ShaderCreateInfo &info) const = 0; + virtual std::string fragment_interface_declare(const shader::ShaderCreateInfo &info) const = 0; + virtual std::string geometry_interface_declare(const shader::ShaderCreateInfo &info) const = 0; + virtual std::string geometry_layout_declare(const shader::ShaderCreateInfo &info) const = 0; + virtual std::string compute_layout_declare(const shader::ShaderCreateInfo &info) const = 0; + /* DEPRECATED: Kept only because of BGL API. */ - virtual int program_handle_get(void) const = 0; + virtual int program_handle_get() const = 0; - inline const char *const name_get(void) const + inline const char *const name_get() const { return name; }; protected: - void print_log(Span<const char *> sources, - char *log, - const char *stage, - const bool error, - GPULogParser *parser); + void print_log( + Span<const char *> sources, char *log, const char *stage, bool error, GPULogParser *parser); }; /* Syntactic sugar. */ @@ -137,4 +145,4 @@ class GPULogParser { } // namespace blender /* XXX do not use it. Special hack to use OCIO with batch API. */ -GPUShader *immGetShader(void); +GPUShader *immGetShader(); diff --git a/source/blender/gpu/intern/gpu_shader_shared_utils.h b/source/blender/gpu/intern/gpu_shader_shared_utils.h new file mode 100644 index 00000000000..0d283fb1e66 --- /dev/null +++ b/source/blender/gpu/intern/gpu_shader_shared_utils.h @@ -0,0 +1,116 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2022 Blender Foundation. + * All rights reserved. + */ + +/** \file + * \ingroup gpu + * + * Glue definition to make shared declaration of struct & functions work in both C / C++ and GLSL. + * We use the same vector and matrix types as Blender C++. Some math functions are defined to use + * the float version to match the GLSL syntax. + * This file can be used for C & C++ code and the syntax used should follow the same rules. + * Some preprocessing is done by the GPU back-end to make it GLSL compatible. + * + * IMPORTANT: + * - Always use `u` suffix for enum values. GLSL do not support implicit cast. + * - Define all values. This is in order to simplify custom pre-processor code. + * - (C++ only) Always use `uint32_t` as underlying type (`enum eMyEnum : uint32_t`). + * - (C only) do NOT use the enum type inside UBO/SSBO structs and use `uint` instead. + * - Use float suffix by default for float literals to avoid double promotion in C++. + * - Pack one float or int after a vec3/ivec3 to fulfill alignment rules. + * + * NOTE: Due to alignment restriction and buggy drivers, do not try to use mat3 inside structs. + * NOTE: (UBO only) Do not use arrays of float. They are padded to arrays of vec4 and are not worth + * it. This does not apply to SSBO. + * + * IMPORTANT: Do not forget to align mat4, vec3 and vec4 to 16 bytes, and vec2 to 8 bytes. + * + * NOTE: You can use bool type using bool1 a int boolean type matching the GLSL type. + */ + +#ifdef GPU_SHADER +# define BLI_STATIC_ASSERT_ALIGN(type_, align_) +# define BLI_STATIC_ASSERT_SIZE(type_, size_) +# define static +# define inline +# define cosf cos +# define sinf sin +# define tanf tan +# define acosf acos +# define asinf asin +# define atanf atan +# define floorf floor +# define ceilf ceil +# define sqrtf sqrt + +# define float2 vec2 +# define float3 vec3 +# define float4 vec4 +# define float4x4 mat4 +# define int2 ivec2 +# define int3 ivec3 +# define int4 ivec4 +# define uint2 uvec2 +# define uint3 uvec3 +# define uint4 uvec4 +# define bool1 bool +# define bool2 bvec2 +# define bool3 bvec3 +# define bool4 bvec4 + +#else /* C / C++ */ +# pragma once + +# include "BLI_assert.h" + +# ifdef __cplusplus +# include "BLI_float4x4.hh" +# include "BLI_math_vec_types.hh" +using blender::float2; +using blender::float3; +using blender::float4; +using blender::float4x4; +using blender::int2; +using blender::int3; +using blender::int4; +using blender::uint2; +using blender::uint3; +using blender::uint4; +using bool1 = int; +using bool2 = blender::int2; +using bool3 = blender::int3; +using bool4 = blender::int4; + +# else /* C */ +typedef float float2[2]; +typedef float float3[3]; +typedef float float4[4]; +typedef float float4x4[4][4]; +typedef int int2[2]; +typedef int int3[2]; +typedef int int4[4]; +typedef uint uint2[2]; +typedef uint uint3[3]; +typedef uint uint4[4]; +typedef int bool1; +typedef int bool2[2]; +typedef int bool3[2]; +typedef int bool4[4]; +# endif + +#endif diff --git a/source/blender/gpu/intern/gpu_state.cc b/source/blender/gpu/intern/gpu_state.cc index 9ee8a8b8d32..a43ddb09ff8 100644 --- a/source/blender/gpu/intern/gpu_state.cc +++ b/source/blender/gpu/intern/gpu_state.cc @@ -165,11 +165,6 @@ void GPU_depth_range(float near, float far) copy_v2_fl2(state.depth_range, near, far); } -/** - * \note By convention, this is set as needed and not reset back to 1.0. - * This means code that draws lines must always set the line width beforehand, - * but is not expected to restore it's previous value. - */ void GPU_line_width(float width) { width = max_ff(1.0f, width * PIXELSIZE); @@ -184,10 +179,6 @@ void GPU_point_size(float size) state.point_size = size * ((state.point_size > 0.0) ? 1.0f : -1.0f); } -/* Programmable point size - * - shaders set their own point size when enabled - * - use GPU_point_size when disabled */ -/* TODO: remove and use program point size everywhere. */ void GPU_program_point_size(bool enable) { StateManager *stack = Context::get()->state_manager; @@ -264,7 +255,6 @@ eGPUStencilTest GPU_stencil_test_get() return (eGPUStencilTest)state.stencil_test; } -/* NOTE: Already premultiplied by U.pixelsize. */ float GPU_line_width_get() { const GPUStateMutable &state = Context::get()->state_manager->mutable_state; @@ -363,7 +353,6 @@ void GPU_bgl_start() } } -/* Just turn off the bgl safeguard system. Can be called even without GPU_bgl_start. */ void GPU_bgl_end() { Context *ctx = Context::get(); diff --git a/source/blender/gpu/intern/gpu_state_private.hh b/source/blender/gpu/intern/gpu_state_private.hh index b96b71a7ac4..864b7d0446a 100644 --- a/source/blender/gpu/intern/gpu_state_private.hh +++ b/source/blender/gpu/intern/gpu_state_private.hh @@ -62,7 +62,7 @@ union GPUState { uint32_t polygon_smooth : 1; uint32_t line_smooth : 1; }; - /* Here to allow fast bitwise ops. */ + /* Here to allow fast bit-wise ops. */ uint64_t data; }; @@ -159,18 +159,18 @@ class StateManager { StateManager(); virtual ~StateManager(){}; - virtual void apply_state(void) = 0; - virtual void force_state(void) = 0; + virtual void apply_state() = 0; + virtual void force_state() = 0; virtual void issue_barrier(eGPUBarrier barrier_bits) = 0; virtual void texture_bind(Texture *tex, eGPUSamplerState sampler, int unit) = 0; virtual void texture_unbind(Texture *tex) = 0; - virtual void texture_unbind_all(void) = 0; + virtual void texture_unbind_all() = 0; virtual void image_bind(Texture *tex, int unit) = 0; virtual void image_unbind(Texture *tex) = 0; - virtual void image_unbind_all(void) = 0; + virtual void image_unbind_all() = 0; virtual void texture_unpack_row_length_set(uint len) = 0; }; diff --git a/source/blender/gpu/intern/gpu_texture.cc b/source/blender/gpu/intern/gpu_texture.cc index 2744c0c5e17..1b8b28bf04c 100644 --- a/source/blender/gpu/intern/gpu_texture.cc +++ b/source/blender/gpu/intern/gpu_texture.cc @@ -190,7 +190,7 @@ using namespace blender::gpu; /* ------ Memory Management ------ */ -uint GPU_texture_memory_usage_get(void) +uint GPU_texture_memory_usage_get() { /* TODO(fclem): Do that inside the new Texture class. */ return 0; @@ -298,7 +298,6 @@ GPUTexture *GPU_texture_create_cube_array( name, w, w, d, GPU_TEXTURE_CUBE_ARRAY, mip_len, format, GPU_DATA_FLOAT, data); } -/* DDS texture loading. Return NULL if support is not available. */ GPUTexture *GPU_texture_create_compressed_2d( const char *name, int w, int h, int miplen, eGPUTextureFormat tex_format, const void *data) { @@ -337,7 +336,6 @@ GPUTexture *GPU_texture_create_from_vertbuf(const char *name, GPUVertBuf *vert) return reinterpret_cast<GPUTexture *>(tex); } -/* Create an error texture that will bind an invalid texture (pink) at draw time. */ GPUTexture *GPU_texture_create_error(int dimension, bool is_array) { float pixel[4] = {1.0f, 0.0f, 1.0f, 1.0f}; @@ -386,27 +384,17 @@ void *GPU_texture_read(GPUTexture *tex_, eGPUDataFormat data_format, int miplvl) return tex->read(miplvl, data_format); } -/** - * Fills the whole texture with the same data for all pixels. - * \warning Only work for 2D texture for now. - * \warning Only clears the mip 0 of the texture. - * \param data_format: data format of the pixel data. - * \param data: 1 pixel worth of data to fill the texture with. - */ void GPU_texture_clear(GPUTexture *tex, eGPUDataFormat data_format, const void *data) { BLI_assert(data != nullptr); /* Do not accept NULL as parameter. */ reinterpret_cast<Texture *>(tex)->clear(data_format, data); } -/* NOTE: Updates only mip 0. */ void GPU_texture_update(GPUTexture *tex, eGPUDataFormat data_format, const void *data) { reinterpret_cast<Texture *>(tex)->update(data_format, data); } -/* Makes data interpretation aware of the source layout. - * Skipping pixels correctly when changing rows when doing partial update. */ void GPU_unpack_row_length_set(uint len) { Context::get()->state_manager->texture_unpack_row_length_set(len); @@ -436,7 +424,7 @@ void GPU_texture_unbind(GPUTexture *tex_) Context::get()->state_manager->texture_unbind(tex); } -void GPU_texture_unbind_all(void) +void GPU_texture_unbind_all() { Context::get()->state_manager->texture_unbind_all(); } @@ -451,7 +439,7 @@ void GPU_texture_image_unbind(GPUTexture *tex) Context::get()->state_manager->image_unbind(unwrap(tex)); } -void GPU_texture_image_unbind_all(void) +void GPU_texture_image_unbind_all() { Context::get()->state_manager->image_unbind_all(); } @@ -461,7 +449,6 @@ void GPU_texture_generate_mipmap(GPUTexture *tex) reinterpret_cast<Texture *>(tex)->generate_mipmap(); } -/* Copy a texture content to a similar texture. Only MIP 0 is copied. */ void GPU_texture_copy(GPUTexture *dst_, GPUTexture *src_) { Texture *src = reinterpret_cast<Texture *>(src_); @@ -626,8 +613,7 @@ void GPU_texture_get_mipmap_size(GPUTexture *tex, int lvl, int *r_size) * Override texture sampler state for one sampler unit only. * \{ */ -/* Update user defined sampler states. */ -void GPU_samplers_update(void) +void GPU_samplers_update() { GPUBackend::get()->samplers_update(); } diff --git a/source/blender/gpu/intern/gpu_texture_private.hh b/source/blender/gpu/intern/gpu_texture_private.hh index 17c888e4fcd..73b59b9f06f 100644 --- a/source/blender/gpu/intern/gpu_texture_private.hh +++ b/source/blender/gpu/intern/gpu_texture_private.hh @@ -66,7 +66,7 @@ ENUM_OPERATORS(eGPUTextureType, GPU_TEXTURE_CUBE_ARRAY) #endif /* Maximum number of FBOs a texture can be attached to. */ -#define GPU_TEX_MAX_FBO_ATTACHED 20 +#define GPU_TEX_MAX_FBO_ATTACHED 32 /** * Implementation of Textures. @@ -123,7 +123,7 @@ class Texture { bool init_cubemap(int w, int layers, eGPUTextureFormat format); bool init_buffer(GPUVertBuf *vbo, eGPUTextureFormat format); - virtual void generate_mipmap(void) = 0; + virtual void generate_mipmap() = 0; virtual void copy_to(Texture *tex) = 0; virtual void clear(eGPUDataFormat format, const void *data) = 0; virtual void swizzle_set(const char swizzle_mask[4]) = 0; @@ -138,17 +138,17 @@ class Texture { int mip, int offset[3], int extent[3], eGPUDataFormat format, const void *data) = 0; /* TODO(fclem): Legacy. Should be removed at some point. */ - virtual uint gl_bindcode_get(void) const = 0; + virtual uint gl_bindcode_get() const = 0; - int width_get(void) const + int width_get() const { return w_; } - int height_get(void) const + int height_get() const { return h_; } - int depth_get(void) const + int depth_get() const { return d_; } @@ -188,7 +188,7 @@ class Texture { } /* Return number of dimension taking the array type into account. */ - int dimensions_count(void) const + int dimensions_count() const { const int array = (type_ & GPU_TEXTURE_ARRAY) ? 1 : 0; switch (type_ & ~GPU_TEXTURE_ARRAY) { @@ -205,7 +205,7 @@ class Texture { } } /* Return number of array layer (or face layer) for texture array or 1 for the others. */ - int layer_count(void) const + int layer_count() const { switch (type_) { case GPU_TEXTURE_1D_ARRAY: @@ -218,15 +218,15 @@ class Texture { } } - eGPUTextureFormat format_get(void) const + eGPUTextureFormat format_get() const { return format_; } - eGPUTextureFormatFlag format_flag_get(void) const + eGPUTextureFormatFlag format_flag_get() const { return format_flag_; } - eGPUTextureType type_get(void) const + eGPUTextureType type_get() const { return type_; } @@ -248,7 +248,7 @@ class Texture { } protected: - virtual bool init_internal(void) = 0; + virtual bool init_internal() = 0; virtual bool init_internal(GPUVertBuf *vbo) = 0; }; @@ -348,23 +348,12 @@ inline eGPUTextureFormatFlag to_format_flag(eGPUTextureFormat format) case GPU_DEPTH24_STENCIL8: case GPU_DEPTH32F_STENCIL8: return GPU_FORMAT_DEPTH_STENCIL; - case GPU_R8I: case GPU_R8UI: + case GPU_RG16I: case GPU_R16I: + case GPU_RG16UI: case GPU_R16UI: case GPU_R32UI: - case GPU_RG8I: - case GPU_RG8UI: - case GPU_RG16I: - case GPU_RG16UI: - case GPU_RG32I: - case GPU_RG32UI: - case GPU_RGBA8I: - case GPU_RGBA8UI: - case GPU_RGBA16I: - case GPU_RGBA16UI: - case GPU_RGBA32I: - case GPU_RGBA32UI: return GPU_FORMAT_INTEGER; case GPU_SRGB8_A8_DXT1: case GPU_SRGB8_A8_DXT3: @@ -381,16 +370,11 @@ inline eGPUTextureFormatFlag to_format_flag(eGPUTextureFormat format) inline int to_component_len(eGPUTextureFormat format) { switch (format) { - case GPU_RGBA8UI: - case GPU_RGBA8I: case GPU_RGBA8: - case GPU_RGBA32UI: - case GPU_RGBA32I: - case GPU_RGBA32F: - case GPU_RGBA16UI: - case GPU_RGBA16I: + case GPU_RGBA8UI: case GPU_RGBA16F: case GPU_RGBA16: + case GPU_RGBA32F: case GPU_SRGB8_A8: case GPU_RGB10_A2: return 4; @@ -444,27 +428,16 @@ inline bool validate_data_format(eGPUTextureFormat tex_format, eGPUDataFormat da case GPU_DEPTH24_STENCIL8: case GPU_DEPTH32F_STENCIL8: return data_format == GPU_DATA_UINT_24_8; + case GPU_R8UI: case GPU_R16UI: - case GPU_R32UI: case GPU_RG16UI: - case GPU_RG32UI: - case GPU_RGBA16UI: - case GPU_RGBA32UI: + case GPU_R32UI: return data_format == GPU_DATA_UINT; - case GPU_R16I: - case GPU_R32I: - case GPU_R8I: case GPU_RG16I: - case GPU_RG32I: - case GPU_RG8I: - case GPU_RGBA16I: - case GPU_RGBA32I: - case GPU_RGBA8I: + case GPU_R16I: return data_format == GPU_DATA_INT; case GPU_R8: - case GPU_R8UI: case GPU_RG8: - case GPU_RG8UI: case GPU_RGBA8: case GPU_RGBA8UI: case GPU_SRGB8_A8: @@ -489,27 +462,16 @@ inline eGPUDataFormat to_data_format(eGPUTextureFormat tex_format) case GPU_DEPTH24_STENCIL8: case GPU_DEPTH32F_STENCIL8: return GPU_DATA_UINT_24_8; + case GPU_R8UI: case GPU_R16UI: - case GPU_R32UI: case GPU_RG16UI: - case GPU_RG32UI: - case GPU_RGBA16UI: - case GPU_RGBA32UI: + case GPU_R32UI: return GPU_DATA_UINT; - case GPU_R16I: - case GPU_R32I: - case GPU_R8I: case GPU_RG16I: - case GPU_RG32I: - case GPU_RG8I: - case GPU_RGBA16I: - case GPU_RGBA32I: - case GPU_RGBA8I: + case GPU_R16I: return GPU_DATA_INT; case GPU_R8: - case GPU_R8UI: case GPU_RG8: - case GPU_RG8UI: case GPU_RGBA8: case GPU_RGBA8UI: case GPU_SRGB8_A8: diff --git a/source/blender/gpu/intern/gpu_uniform_buffer.cc b/source/blender/gpu/intern/gpu_uniform_buffer.cc index 3a9269d1753..332875ba81f 100644 --- a/source/blender/gpu/intern/gpu_uniform_buffer.cc +++ b/source/blender/gpu/intern/gpu_uniform_buffer.cc @@ -201,12 +201,6 @@ GPUUniformBuf *GPU_uniformbuf_create_ex(size_t size, const void *data, const cha return wrap(ubo); } -/** - * Create UBO from inputs list. - * Return NULL if failed to create or if \param inputs: is empty. - * - * \param inputs: ListBase of #BLI_genericNodeN(#GPUInput). - */ GPUUniformBuf *GPU_uniformbuf_create_from_list(ListBase *inputs, const char *name) { /* There is no point on creating an UBO if there is no arguments. */ @@ -245,7 +239,7 @@ void GPU_uniformbuf_unbind(GPUUniformBuf *ubo) unwrap(ubo)->unbind(); } -void GPU_uniformbuf_unbind_all(void) +void GPU_uniformbuf_unbind_all() { /* FIXME */ } diff --git a/source/blender/gpu/intern/gpu_uniform_buffer_private.hh b/source/blender/gpu/intern/gpu_uniform_buffer_private.hh index e8fc1343eaf..018b85c865e 100644 --- a/source/blender/gpu/intern/gpu_uniform_buffer_private.hh +++ b/source/blender/gpu/intern/gpu_uniform_buffer_private.hh @@ -54,7 +54,7 @@ class UniformBuf { virtual void update(const void *data) = 0; virtual void bind(int slot) = 0; - virtual void unbind(void) = 0; + virtual void unbind() = 0; /** Used to defer data upload at drawing time. * This is useful if the thread has no context bound. diff --git a/source/blender/gpu/intern/gpu_vertex_buffer.cc b/source/blender/gpu/intern/gpu_vertex_buffer.cc index 956d89ff832..dba31f501f2 100644 --- a/source/blender/gpu/intern/gpu_vertex_buffer.cc +++ b/source/blender/gpu/intern/gpu_vertex_buffer.cc @@ -144,6 +144,12 @@ void GPU_vertbuf_init_with_format_ex(GPUVertBuf *verts_, unwrap(verts_)->init(format, usage); } +void GPU_vertbuf_init_build_on_device(GPUVertBuf *verts, GPUVertFormat *format, uint v_len) +{ + GPU_vertbuf_init_with_format_ex(verts, format, GPU_USAGE_DEVICE_ONLY); + GPU_vertbuf_data_alloc(verts, v_len); +} + GPUVertBuf *GPU_vertbuf_duplicate(GPUVertBuf *verts_) { return wrap(unwrap(verts_)->duplicate()); @@ -159,7 +165,6 @@ void *GPU_vertbuf_unmap(const GPUVertBuf *verts, const void *mapped_data) return unwrap(verts)->unmap(mapped_data); } -/** Same as discard but does not free. */ void GPU_vertbuf_clear(GPUVertBuf *verts) { unwrap(verts)->clear(); @@ -183,21 +188,16 @@ void GPU_vertbuf_handle_ref_remove(GPUVertBuf *verts) /* -------- Data update -------- */ -/* create a new allocation, discarding any existing data */ void GPU_vertbuf_data_alloc(GPUVertBuf *verts, uint v_len) { unwrap(verts)->allocate(v_len); } -/* resize buffer keeping existing data */ void GPU_vertbuf_data_resize(GPUVertBuf *verts, uint v_len) { unwrap(verts)->resize(v_len); } -/* Set vertex count but does not change allocation. - * Only this many verts will be uploaded to the GPU and rendered. - * This is useful for streaming data. */ void GPU_vertbuf_data_len_set(GPUVertBuf *verts_, uint v_len) { VertBuf *verts = unwrap(verts_); @@ -229,7 +229,6 @@ 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 attributes). Data must match packed layout. */ void GPU_vertbuf_vert_set(GPUVertBuf *verts_, uint v_idx, const void *data) { VertBuf *verts = unwrap(verts_); @@ -284,17 +283,12 @@ void GPU_vertbuf_attr_get_raw_data(GPUVertBuf *verts_, uint a_idx, GPUVertBufRaw /* -------- Getters -------- */ -/* NOTE: Be careful when using this. The data needs to match the expected format. */ -void *GPU_vertbuf_get_data(GPUVertBuf *verts_) +void *GPU_vertbuf_get_data(const GPUVertBuf *verts) { /* TODO: Assert that the format has no padding. */ - VertBuf *verts = unwrap(verts_); - verts->flag |= GPU_VERTBUF_DATA_DIRTY; - return verts->data; + return unwrap(verts)->data; } -/* Returns the data buffer and set it to null internally to avoid freeing. - * NOTE: Be careful when using this. The data needs to match the expected format. */ void *GPU_vertbuf_steal_data(GPUVertBuf *verts_) { VertBuf *verts = unwrap(verts_); @@ -325,25 +319,32 @@ GPUVertBufStatus GPU_vertbuf_get_status(const GPUVertBuf *verts) return unwrap(verts)->flag; } +void GPU_vertbuf_tag_dirty(GPUVertBuf *verts) +{ + unwrap(verts)->flag |= GPU_VERTBUF_DATA_DIRTY; +} + uint GPU_vertbuf_get_memory_usage() { return VertBuf::memory_usage; } -/* Should be rename to GPU_vertbuf_data_upload */ void GPU_vertbuf_use(GPUVertBuf *verts) { unwrap(verts)->upload(); } +void GPU_vertbuf_wrap_handle(GPUVertBuf *verts, uint64_t handle) +{ + unwrap(verts)->wrap_handle(handle); +} + void GPU_vertbuf_bind_as_ssbo(struct GPUVertBuf *verts, int binding) { unwrap(verts)->bind_as_ssbo(binding); } -/* XXX this is just a wrapper for the use of the Hair refine workaround. - * To be used with GPU_vertbuf_use(). */ -void GPU_vertbuf_update_sub(GPUVertBuf *verts, uint start, uint len, void *data) +void GPU_vertbuf_update_sub(GPUVertBuf *verts, uint start, uint len, const void *data) { unwrap(verts)->update_sub(start, len, data); } diff --git a/source/blender/gpu/intern/gpu_vertex_buffer_private.hh b/source/blender/gpu/intern/gpu_vertex_buffer_private.hh index 9531c2c1a5f..97514b382b1 100644 --- a/source/blender/gpu/intern/gpu_vertex_buffer_private.hh +++ b/source/blender/gpu/intern/gpu_vertex_buffer_private.hh @@ -60,34 +60,36 @@ class VertBuf { virtual ~VertBuf(); void init(const GPUVertFormat *format, GPUUsageType usage); - void clear(void); + void clear(); /* Data management. */ void allocate(uint vert_len); void resize(uint vert_len); - void upload(void); + void upload(); virtual void bind_as_ssbo(uint binding) = 0; - VertBuf *duplicate(void); + virtual void wrap_handle(uint64_t handle) = 0; + + VertBuf *duplicate(); /* Size of the data allocated. */ - size_t size_alloc_get(void) const + size_t size_alloc_get() const { BLI_assert(format.packed); return vertex_alloc * format.stride; } /* Size of the data uploaded to the GPU. */ - size_t size_used_get(void) const + size_t size_used_get() const { BLI_assert(format.packed); return vertex_len * format.stride; } - void reference_add(void) + void reference_add() { handle_refcount_++; } - void reference_remove(void) + void reference_remove() { BLI_assert(handle_refcount_ > 0); handle_refcount_--; @@ -96,15 +98,15 @@ class VertBuf { } } - virtual void update_sub(uint start, uint len, void *data) = 0; + virtual void update_sub(uint start, uint len, const void *data) = 0; virtual const void *read() const = 0; virtual void *unmap(const void *mapped_data) const = 0; protected: - virtual void acquire_data(void) = 0; - virtual void resize_data(void) = 0; - virtual void release_data(void) = 0; - virtual void upload_data(void) = 0; + virtual void acquire_data() = 0; + virtual void resize_data() = 0; + virtual void release_data() = 0; + virtual void upload_data() = 0; virtual void duplicate_data(VertBuf *dst) = 0; }; diff --git a/source/blender/gpu/intern/gpu_vertex_format.cc b/source/blender/gpu/intern/gpu_vertex_format.cc index 78a119bcec8..ad45f2a4d7b 100644 --- a/source/blender/gpu/intern/gpu_vertex_format.cc +++ b/source/blender/gpu/intern/gpu_vertex_format.cc @@ -190,17 +190,6 @@ void GPU_vertformat_alias_add(GPUVertFormat *format, const char *alias) attr->names[attr->name_len++] = copy_attr_name(format, alias); } -/** - * 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 attribute name. (this limitation can be changed if needed) - * - * 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) { /* Sanity check. Maximum can be upgraded if needed. */ @@ -271,8 +260,6 @@ 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_attr_name(const char *attr_name, char *r_safe_name, uint UNUSED(max_len)) { char data[8] = {0}; @@ -306,20 +293,6 @@ void GPU_vertformat_safe_attr_name(const char *attr_name, char *r_safe_name, uin #endif } -/** - * Make attribute layout non-interleaved. - * Warning! This does not change data layout! - * Use direct buffer access to fill the data. - * This is for advanced usage. - * - * De-interleaved data means all attribute data for each attribute - * is stored continuously like this: - * 000011112222 - * instead of: - * 012012012012 - * - * \note This is per attribute de-interleaving, NOT per component. - */ void GPU_vertformat_deinterleave(GPUVertFormat *format) { /* Ideally we should change the stride and offset here. This would allow diff --git a/source/blender/gpu/intern/gpu_viewport.c b/source/blender/gpu/intern/gpu_viewport.c index ccd9a4c061b..6d8ff8e7088 100644 --- a/source/blender/gpu/intern/gpu_viewport.c +++ b/source/blender/gpu/intern/gpu_viewport.c @@ -137,19 +137,25 @@ struct DRWData **GPU_viewport_data_get(GPUViewport *viewport) static void gpu_viewport_textures_create(GPUViewport *viewport) { int *size = viewport->size; + float empty_pixel_fl[4] = {0.0f, 0.0f, 0.0f, 0.0f}; + uchar empty_pixel_u[4] = {0, 0, 0, 0}; if (viewport->color_render_tx[0] == NULL) { viewport->color_render_tx[0] = GPU_texture_create_2d( "dtxl_color", UNPACK2(size), 1, GPU_RGBA16F, NULL); + GPU_texture_clear(viewport->color_render_tx[0], GPU_DATA_FLOAT, empty_pixel_fl); viewport->color_overlay_tx[0] = GPU_texture_create_2d( "dtxl_color_overlay", UNPACK2(size), 1, GPU_SRGB8_A8, NULL); + GPU_texture_clear(viewport->color_overlay_tx[0], GPU_DATA_UBYTE, empty_pixel_u); } if ((viewport->flag & GPU_VIEWPORT_STEREO) != 0 && viewport->color_render_tx[1] == NULL) { viewport->color_render_tx[1] = GPU_texture_create_2d( "dtxl_color_stereo", UNPACK2(size), 1, GPU_RGBA16F, NULL); + GPU_texture_clear(viewport->color_render_tx[1], GPU_DATA_FLOAT, empty_pixel_fl); viewport->color_overlay_tx[1] = GPU_texture_create_2d( "dtxl_color_overlay_stereo", UNPACK2(size), 1, GPU_SRGB8_A8, NULL); + GPU_texture_clear(viewport->color_overlay_tx[1], GPU_DATA_UBYTE, empty_pixel_u); } /* Can be shared with GPUOffscreen. */ @@ -194,7 +200,6 @@ void GPU_viewport_bind(GPUViewport *viewport, int view, const rcti *rect) viewport->active_view = view; } -/* Should be called from DRW after DRW_opengl_context_enable. */ void GPU_viewport_bind_from_offscreen(GPUViewport *viewport, struct GPUOffScreen *ofs) { GPUTexture *color, *depth; @@ -258,7 +263,6 @@ void GPU_viewport_colorspace_set(GPUViewport *viewport, viewport->do_color_management = true; } -/* Merge the stereo textures. `color` and `overlay` texture will be modified. */ void GPU_viewport_stereo_composite(GPUViewport *viewport, Stereo3dFormat *stereo_format) { if (!ELEM(stereo_format->display_mode, S3D_DISPLAY_ANAGLYPH, S3D_DISPLAY_INTERLACE)) { @@ -452,10 +456,6 @@ static void gpu_viewport_draw_colormanaged(GPUViewport *viewport, } } -/** - * Version of #GPU_viewport_draw_to_screen() that lets caller decide if display colorspace - * transform should be performed. - */ void GPU_viewport_draw_to_screen_ex(GPUViewport *viewport, int view, const rcti *rect, @@ -508,21 +508,11 @@ void GPU_viewport_draw_to_screen_ex(GPUViewport *viewport, viewport, view, &pos_rect, &uv_rect, display_colorspace, do_overlay_merge); } -/** - * 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). - */ void GPU_viewport_draw_to_screen(GPUViewport *viewport, int view, const rcti *rect) { GPU_viewport_draw_to_screen_ex(viewport, view, rect, true, true); } -/** - * Clear vars assigned from offscreen, so we don't free data owned by `GPUOffScreen`. - */ void GPU_viewport_unbind_from_offscreen(GPUViewport *viewport, struct GPUOffScreen *ofs, bool display_colorspace, @@ -587,18 +577,17 @@ GPUTexture *GPU_viewport_depth_texture(GPUViewport *viewport) return viewport->depth_tx; } -/* Overlay framebuffer for drawing outside of DRW module. */ GPUFrameBuffer *GPU_viewport_framebuffer_overlay_get(GPUViewport *viewport) { - GPU_framebuffer_ensure_config(&viewport->overlay_fb, - { - GPU_ATTACHMENT_TEXTURE(viewport->depth_tx), - GPU_ATTACHMENT_TEXTURE(viewport->color_overlay_tx[0]), - }); + GPU_framebuffer_ensure_config( + &viewport->overlay_fb, + { + GPU_ATTACHMENT_TEXTURE(viewport->depth_tx), + GPU_ATTACHMENT_TEXTURE(viewport->color_overlay_tx[viewport->active_view]), + }); return viewport->overlay_fb; } -/* Must be executed inside Draw-manager OpenGL Context. */ void GPU_viewport_free(GPUViewport *viewport) { if (viewport->draw_data) { |