diff options
Diffstat (limited to 'source/blender/draw/engines/eevee_next/eevee_sync.cc')
-rw-r--r-- | source/blender/draw/engines/eevee_next/eevee_sync.cc | 316 |
1 files changed, 316 insertions, 0 deletions
diff --git a/source/blender/draw/engines/eevee_next/eevee_sync.cc b/source/blender/draw/engines/eevee_next/eevee_sync.cc new file mode 100644 index 00000000000..c0dba146f7e --- /dev/null +++ b/source/blender/draw/engines/eevee_next/eevee_sync.cc @@ -0,0 +1,316 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright 2021 Blender Foundation. + */ + +/** \file + * \ingroup eevee + * + * Converts the different renderable object types to drawcalls. + */ + +#include "eevee_engine.h" + +#include "BKE_gpencil.h" +#include "BKE_object.h" +#include "DEG_depsgraph_query.h" +#include "DNA_curves_types.h" +#include "DNA_gpencil_types.h" +#include "DNA_modifier_types.h" +#include "DNA_particle_types.h" + +#include "eevee_instance.hh" + +namespace blender::eevee { + +/* -------------------------------------------------------------------- */ +/** \name Draw Data + * + * \{ */ + +static void draw_data_init_cb(struct DrawData *dd) +{ + /* Object has just been created or was never evaluated by the engine. */ + dd->recalc = ID_RECALC_ALL; +} + +ObjectHandle &SyncModule::sync_object(Object *ob) +{ + DrawEngineType *owner = (DrawEngineType *)&DRW_engine_viewport_eevee_next_type; + struct DrawData *dd = DRW_drawdata_ensure( + (ID *)ob, owner, sizeof(eevee::ObjectHandle), draw_data_init_cb, nullptr); + ObjectHandle &eevee_dd = *reinterpret_cast<ObjectHandle *>(dd); + + if (eevee_dd.object_key.ob == nullptr) { + eevee_dd.object_key = ObjectKey(ob); + } + + const int recalc_flags = ID_RECALC_COPY_ON_WRITE | ID_RECALC_TRANSFORM | ID_RECALC_SHADING | + ID_RECALC_GEOMETRY; + if ((eevee_dd.recalc & recalc_flags) != 0) { + // inst_.sampling.reset(); + UNUSED_VARS(inst_); + } + + return eevee_dd; +} + +WorldHandle &SyncModule::sync_world(::World *world) +{ + DrawEngineType *owner = (DrawEngineType *)&DRW_engine_viewport_eevee_next_type; + struct DrawData *dd = DRW_drawdata_ensure( + (ID *)world, owner, sizeof(eevee::WorldHandle), draw_data_init_cb, nullptr); + WorldHandle &eevee_dd = *reinterpret_cast<WorldHandle *>(dd); + + const int recalc_flags = ID_RECALC_ALL; + if ((eevee_dd.recalc & recalc_flags) != 0) { + // inst_.sampling.reset(); + } + return eevee_dd; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Common + * \{ */ + +static inline void shgroup_geometry_call(DRWShadingGroup *grp, + Object *ob, + GPUBatch *geom, + int v_first = -1, + int v_count = -1, + bool use_instancing = false) +{ + if (grp == nullptr) { + return; + } + + if (v_first == -1) { + DRW_shgroup_call(grp, geom, ob); + } + else if (use_instancing) { + DRW_shgroup_call_instance_range(grp, ob, geom, v_first, v_count); + } + else { + DRW_shgroup_call_range(grp, ob, geom, v_first, v_count); + } +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Mesh + * \{ */ + +void SyncModule::sync_mesh(Object *ob, ObjectHandle &ob_handle) +{ + MaterialArray &material_array = inst_.materials.material_array_get(ob); + + GPUBatch **mat_geom = DRW_cache_object_surface_material_get( + ob, material_array.gpu_materials.data(), material_array.gpu_materials.size()); + + if (mat_geom == nullptr) { + return; + } + + bool is_shadow_caster = false; + bool is_alpha_blend = false; + for (auto i : material_array.gpu_materials.index_range()) { + GPUBatch *geom = mat_geom[i]; + if (geom == nullptr) { + continue; + } + Material *material = material_array.materials[i]; + shgroup_geometry_call(material->shading.shgrp, ob, geom); + shgroup_geometry_call(material->prepass.shgrp, ob, geom); + shgroup_geometry_call(material->shadow.shgrp, ob, geom); + + is_shadow_caster = is_shadow_caster || material->shadow.shgrp != nullptr; + is_alpha_blend = is_alpha_blend || material->is_alpha_blend_transparent; + } + // shading_passes.velocity.mesh_add(ob, ob_handle); + + // shadows.sync_object(ob, ob_handle, is_shadow_caster, is_alpha_blend); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name GPencil + * \{ */ + +#define DO_BATCHING true + +struct gpIterData { + Instance &inst; + Object *ob; + MaterialArray &material_array; + int cfra; + + /* Drawcall batching. */ + GPUBatch *geom = nullptr; + Material *material = nullptr; + int vfirst = 0; + int vcount = 0; + bool instancing = false; + + gpIterData(Instance &inst_, Object *ob_) + : inst(inst_), ob(ob_), material_array(inst_.materials.material_array_get(ob_)) + { + cfra = DEG_get_ctime(inst.depsgraph); + }; +}; + +static void gpencil_drawcall_flush(gpIterData &iter) +{ + if (iter.geom != nullptr) { + shgroup_geometry_call(iter.material->shading.shgrp, + iter.ob, + iter.geom, + iter.vfirst, + iter.vcount, + iter.instancing); + shgroup_geometry_call(iter.material->prepass.shgrp, + iter.ob, + iter.geom, + iter.vfirst, + iter.vcount, + iter.instancing); + shgroup_geometry_call(iter.material->shadow.shgrp, + iter.ob, + iter.geom, + iter.vfirst, + iter.vcount, + iter.instancing); + } + iter.geom = nullptr; + iter.vfirst = -1; + iter.vcount = 0; +} + +/* Group draw-calls that are consecutive and with the same type. Reduces GPU driver overhead. */ +static void gpencil_drawcall_add(gpIterData &iter, + GPUBatch *geom, + Material *material, + int v_first, + int v_count, + bool instancing) +{ + int last = iter.vfirst + iter.vcount; + /* Interrupt draw-call grouping if the sequence is not consecutive. */ + if (!DO_BATCHING || (geom != iter.geom) || (material != iter.material) || (v_first - last > 3)) { + gpencil_drawcall_flush(iter); + } + iter.geom = geom; + iter.material = material; + iter.instancing = instancing; + if (iter.vfirst == -1) { + iter.vfirst = v_first; + } + iter.vcount = v_first + v_count - iter.vfirst; +} + +static void gpencil_stroke_sync(bGPDlayer *UNUSED(gpl), + bGPDframe *UNUSED(gpf), + bGPDstroke *gps, + void *thunk) +{ + gpIterData &iter = *(gpIterData *)thunk; + + Material *material = iter.material_array.materials[gps->mat_nr]; + MaterialGPencilStyle *gp_style = BKE_gpencil_material_settings(iter.ob, gps->mat_nr + 1); + + bool hide_material = (gp_style->flag & GP_MATERIAL_HIDE) != 0; + bool show_stroke = ((gp_style->flag & GP_MATERIAL_STROKE_SHOW) != 0) || + (!DRW_state_is_image_render() && ((gps->flag & GP_STROKE_NOFILL) != 0)); + bool show_fill = (gps->tot_triangles > 0) && ((gp_style->flag & GP_MATERIAL_FILL_SHOW) != 0); + + if (hide_material) { + return; + } + + if (show_fill) { + GPUBatch *geom = DRW_cache_gpencil_fills_get(iter.ob, iter.cfra); + int vfirst = gps->runtime.fill_start * 3; + int vcount = gps->tot_triangles * 3; + gpencil_drawcall_add(iter, geom, material, vfirst, vcount, false); + } + + if (show_stroke) { + GPUBatch *geom = DRW_cache_gpencil_strokes_get(iter.ob, iter.cfra); + /* Start one vert before to have gl_InstanceID > 0 (see shader). */ + int vfirst = gps->runtime.stroke_start - 1; + /* Include "potential" cyclic vertex and start adj vertex (see shader). */ + int vcount = gps->totpoints + 1 + 1; + gpencil_drawcall_add(iter, geom, material, vfirst, vcount, true); + } +} + +void SyncModule::sync_gpencil(Object *ob, ObjectHandle &ob_handle) +{ + gpIterData iter(inst_, ob); + + BKE_gpencil_visible_stroke_iter((bGPdata *)ob->data, nullptr, gpencil_stroke_sync, &iter); + + gpencil_drawcall_flush(iter); + + /* TODO(fclem) Gpencil velocity. */ + // shading_passes.velocity.gpencil_add(ob, ob_handle); + + // bool is_caster = true; /* TODO material.shadow.shgrp. */ + // bool is_alpha_blend = true; /* TODO material.is_alpha_blend. */ + // shadows.sync_object(ob, ob_handle, is_caster, is_alpha_blend); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Hair + * \{ */ + +static void shgroup_curves_call(MaterialPass &matpass, + Object *ob, + ParticleSystem *part_sys = nullptr, + ModifierData *modifier_data = nullptr) +{ + if (matpass.shgrp == nullptr) { + return; + } + DRW_shgroup_hair_create_sub(ob, part_sys, modifier_data, matpass.shgrp, matpass.gpumat); +} + +void SyncModule::sync_curves(Object *ob, ObjectHandle &ob_handle, ModifierData *modifier_data) +{ + int mat_nr = CURVES_MATERIAL_NR; + + ParticleSystem *part_sys = nullptr; + if (modifier_data != nullptr) { + part_sys = reinterpret_cast<ParticleSystemModifierData *>(modifier_data)->psys; + if (!DRW_object_is_visible_psys_in_active_context(ob, part_sys)) { + return; + } + ParticleSettings *part_settings = part_sys->part; + const int draw_as = (part_settings->draw_as == PART_DRAW_REND) ? part_settings->ren_as : + part_settings->draw_as; + if (draw_as != PART_DRAW_PATH) { + return; + } + mat_nr = part_settings->omat; + } + + Material &material = inst_.materials.material_get(ob, mat_nr - 1, MAT_GEOM_CURVES); + + shgroup_curves_call(material.shading, ob, part_sys, modifier_data); + shgroup_curves_call(material.prepass, ob, part_sys, modifier_data); + shgroup_curves_call(material.shadow, ob, part_sys, modifier_data); + /* TODO(fclem) Hair velocity. */ + // shading_passes.velocity.gpencil_add(ob, ob_handle); + + // bool is_caster = material.shadow.shgrp != nullptr; + // bool is_alpha_blend = material.is_alpha_blend_transparent; + // shadows.sync_object(ob, ob_handle, is_caster, is_alpha_blend); +} + +/** \} */ + +} // namespace blender::eevee |