DRW: Use depsgraph update count to replace view_update

This avoid having to flush explicitely and the need for syncing.
It also removes a lot of complexity in the process.

These updates are not granular and do not need to so much
boiler plate code.

The depsgraph update counter now becomes atomic to avoid
undefined behavior when a depsgraph is being destroyed and
its memory reused (same thinking as the non-copy-on-eval IDs).

I tested some use cases (object update, sculpt update,
shading update) and they are all working.

Pull Request: https://projects.blender.org/blender/blender/pulls/135580
This commit is contained in:
Clément Foucault
2025-03-06 19:15:29 +01:00
committed by Clément Foucault
parent 9287bb759b
commit 2131ef0a20
11 changed files with 20 additions and 224 deletions

View File

@@ -38,17 +38,6 @@ bool DRW_engine_render_support(DrawEngineType *draw_engine_type);
void DRW_engine_external_free(RegionView3D *rv3d);
struct DRWUpdateContext {
Main *bmain;
Depsgraph *depsgraph;
Scene *scene;
ViewLayer *view_layer;
ARegion *region;
View3D *v3d;
RenderEngineType *engine_type;
};
void DRW_notify_view_update(const DRWUpdateContext *update_ctx);
enum eDRWSelectStage {
DRW_SELECT_PASS_PRE = 1,
DRW_SELECT_PASS_POST,

View File

@@ -125,13 +125,6 @@ static void eevee_cache_finish(void *vedata)
reinterpret_cast<EEVEE_Data *>(vedata)->instance->end_sync();
}
static void eevee_view_update(void *vedata)
{
if (eevee::Instance *instance = reinterpret_cast<EEVEE_Data *>(vedata)->instance) {
instance->view_update();
}
}
static void eevee_engine_free()
{
eevee::ShaderModule::module_free();
@@ -193,7 +186,7 @@ DrawEngineType draw_engine_eevee_next_type = {
/*cache_populate*/ &eevee_cache_populate,
/*cache_finish*/ &eevee_cache_finish,
/*draw_scene*/ &eevee_draw_scene,
/*view_update*/ &eevee_view_update,
/*view_update*/ nullptr,
/*id_update*/ nullptr,
/*render_to_image*/ &eevee_render_to_image,
/*store_metadata*/ &eevee_store_metadata,

View File

@@ -82,6 +82,10 @@ void Instance::init(const int2 &output_res,
}
if (is_viewport()) {
/* Note: Do not update the value here as we use it during sync for checking ID updates. */
if (depsgraph_last_update_ != DEG_get_update_count(depsgraph)) {
sampling.reset();
}
if (assign_if_different(debug_mode, (eDebugMode)G.debug_value)) {
sampling.reset();
}
@@ -191,13 +195,6 @@ void Instance::update_eval_members()
nullptr;
}
void Instance::view_update()
{
if (is_viewport()) {
sampling.reset();
}
}
/** \} */
/* -------------------------------------------------------------------- */

View File

@@ -193,8 +193,6 @@ class Instance {
const View3D *v3d = nullptr,
const RegionView3D *rv3d = nullptr);
void view_update();
void begin_sync();
void object_sync(ObjectRef &ob_ref);
void end_sync();

View File

@@ -63,6 +63,9 @@ class Instance {
* They never get actually used. */
Vector<GPUMaterial *> dummy_gpu_materials_ = {1, nullptr, {}};
/* Used to detect any scene data update. */
uint64_t depsgraph_last_update_ = 0;
public:
Span<const GPUMaterial *> get_dummy_gpu_materials(int material_count)
{
@@ -72,9 +75,12 @@ class Instance {
return dummy_gpu_materials_.as_span().slice(IndexRange(material_count));
};
void init(Object *camera_ob = nullptr)
void init(Depsgraph *depsgraph, Object *camera_ob = nullptr)
{
scene_state_.init(camera_ob);
bool scene_updated = assign_if_different(depsgraph_last_update_,
DEG_get_update_count(depsgraph));
scene_state_.init(scene_updated, camera_ob);
shadow_ps_.init(scene_state_, resources_);
resources_.init(scene_state_);
@@ -515,11 +521,6 @@ class Instance {
GPU_render_step();
}
}
void reset_taa_sample()
{
scene_state_.reset_taa_next_sample = true;
}
};
} // namespace blender::workbench
@@ -544,7 +545,7 @@ static void workbench_engine_init(void *vedata)
ved->instance = new workbench::Instance();
}
ved->instance->init();
ved->instance->init(DRW_context_state_get()->depsgraph);
}
static void workbench_cache_init(void *vedata)
@@ -587,14 +588,6 @@ static void workbench_engine_free()
workbench::ShaderCache::release();
}
static void workbench_view_update(void *vedata)
{
WORKBENCH_Data *ved = reinterpret_cast<WORKBENCH_Data *>(vedata);
if (ved->instance) {
ved->instance->reset_taa_sample();
}
}
/* RENDER */
static bool workbench_render_framebuffers_init()
@@ -743,7 +736,7 @@ static void workbench_render_to_image(void *vedata,
DRW_cache_restart();
blender::draw::View::default_set(float4x4(viewmat), float4x4(winmat));
ved->instance->init(camera_ob);
ved->instance->init(depsgraph, camera_ob);
draw::Manager &manager = *DRW_manager_get();
manager.begin_sync();
@@ -795,7 +788,7 @@ DrawEngineType draw_engine_workbench = {
/*cache_populate*/ &workbench_cache_populate,
/*cache_finish*/ &workbench_cache_finish,
/*draw_scene*/ &workbench_draw_scene,
/*view_update*/ &workbench_view_update,
/*view_update*/ nullptr,
/*id_update*/ nullptr,
/*render_to_image*/ &workbench_render_to_image,
/*store_metadata*/ nullptr,

View File

@@ -164,7 +164,7 @@ struct SceneState {
/* When r == -1.0 the shader uses the vertex color */
Material material_attribute_color = Material(float3(-1.0f));
void init(Object *camera_ob = nullptr);
void init(bool scene_updated, Object *camera_ob = nullptr);
};
struct MaterialTexture {

View File

@@ -24,9 +24,9 @@
namespace blender::workbench {
void SceneState::init(Object *camera_ob /*=nullptr*/)
void SceneState::init(bool scene_updated, Object *camera_ob /*=nullptr*/)
{
bool reset_taa = reset_taa_next_sample;
bool reset_taa = reset_taa_next_sample || scene_updated;
reset_taa_next_sample = false;
const DRWContextState *context = DRW_context_state_get();

View File

@@ -72,6 +72,7 @@ struct DrawEngineType {
void (*draw_scene)(void *vedata);
/* TODO(fclem): Remove. */
void (*view_update)(void *vedata);
/* TODO(fclem): Remove. */
void (*id_update)(void *vedata, ID *id);

View File

@@ -110,8 +110,6 @@
#include "DRW_select_buffer.hh"
static CLG_LogRef LOG = {"draw.manager"};
/* -------------------------------------------------------------------- */
/** \name Settings
*
@@ -1199,129 +1197,6 @@ static bool drw_gpencil_engine_needed(Depsgraph *depsgraph, View3D *v3d)
DEG_id_type_any_exists(depsgraph, ID_GP));
}
/* -------------------------------------------------------------------- */
/** \name View Update
* \{ */
void DRW_notify_view_update(const DRWUpdateContext *update_ctx)
{
RenderEngineType *engine_type = update_ctx->engine_type;
ARegion *region = update_ctx->region;
View3D *v3d = update_ctx->v3d;
RegionView3D *rv3d = static_cast<RegionView3D *>(region->regiondata);
Depsgraph *depsgraph = update_ctx->depsgraph;
Scene *scene = update_ctx->scene;
ViewLayer *view_layer = update_ctx->view_layer;
GPUViewport *viewport = WM_draw_region_get_viewport(region);
if (!viewport) {
return;
}
const bool gpencil_engine_needed = drw_gpencil_engine_needed(depsgraph, v3d);
/* XXX Really nasty locking. But else this could be executed by the
* material previews thread while rendering a viewport.
*
* Check for recursive lock which can deadlock. This should not
* happen, but in case there is a bug where depsgraph update is called
* during drawing we try not to hang Blender. */
if (!BLI_ticket_mutex_lock_check_recursive(system_gpu_context_mutex)) {
CLOG_ERROR(&LOG, "GPU context already bound");
BLI_assert_unreachable();
return;
}
DRWContext draw_ctx;
drw_set(draw_ctx);
BKE_view_layer_synced_ensure(scene, view_layer);
drw_get().draw_ctx = {};
drw_get().draw_ctx.region = region;
drw_get().draw_ctx.rv3d = rv3d;
drw_get().draw_ctx.v3d = v3d;
drw_get().draw_ctx.scene = scene;
drw_get().draw_ctx.view_layer = view_layer;
drw_get().draw_ctx.obact = BKE_view_layer_active_object_get(view_layer);
drw_get().draw_ctx.engine_type = engine_type;
drw_get().draw_ctx.depsgraph = depsgraph;
drw_get().draw_ctx.object_mode = OB_MODE_OBJECT;
/* Custom lightweight initialize to avoid resetting the memory-pools. */
drw_get().viewport = viewport;
drw_get().data = drw_viewport_data_ensure(drw_get().viewport);
/* Separate update for each stereo view. */
int view_count = GPU_viewport_is_stereo_get(viewport) ? 2 : 1;
for (int view = 0; view < view_count; view++) {
drw_get().view_data_active = drw_get().data->view_data[view];
drw_engines_enable(view_layer, engine_type, gpencil_engine_needed);
drw_engines_data_validate();
DRW_view_data_engines_view_update(drw_get().view_data_active);
drw_engines_disable();
}
drw_manager_exit(&draw_ctx);
BLI_ticket_mutex_unlock(system_gpu_context_mutex);
}
/* update a viewport which belongs to a GPUOffscreen */
static void drw_notify_view_update_offscreen(Depsgraph *depsgraph,
RenderEngineType *engine_type,
ARegion *region,
View3D *v3d,
GPUViewport *viewport)
{
if (viewport && GPU_viewport_do_update(viewport)) {
Scene *scene = DEG_get_evaluated_scene(depsgraph);
ViewLayer *view_layer = DEG_get_evaluated_view_layer(depsgraph);
RegionView3D *rv3d = static_cast<RegionView3D *>(region->regiondata);
const bool gpencil_engine_needed = drw_gpencil_engine_needed(depsgraph, v3d);
DRWContext draw_ctx;
drw_set(draw_ctx);
BKE_view_layer_synced_ensure(scene, view_layer);
drw_get().draw_ctx = {};
drw_get().draw_ctx.region = region;
drw_get().draw_ctx.rv3d = rv3d;
drw_get().draw_ctx.v3d = v3d;
drw_get().draw_ctx.scene = scene;
drw_get().draw_ctx.view_layer = view_layer;
drw_get().draw_ctx.obact = BKE_view_layer_active_object_get(view_layer);
drw_get().draw_ctx.engine_type = engine_type;
drw_get().draw_ctx.depsgraph = depsgraph;
/* Custom lightweight initialize to avoid resetting the memory-pools. */
drw_get().viewport = viewport;
drw_get().data = drw_viewport_data_ensure(drw_get().viewport);
/* Separate update for each stereo view. */
int view_count = GPU_viewport_is_stereo_get(viewport) ? 2 : 1;
for (int view = 0; view < view_count; view++) {
drw_get().view_data_active = drw_get().data->view_data[view];
drw_engines_enable(view_layer, engine_type, gpencil_engine_needed);
drw_engines_data_validate();
DRW_view_data_engines_view_update(drw_get().view_data_active);
drw_engines_disable();
}
drw_manager_exit(&draw_ctx);
}
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name Callbacks
* \{ */
@@ -1643,9 +1518,6 @@ void DRW_draw_render_loop_offscreen(Depsgraph *depsgraph,
if (viewport == nullptr) {
render_viewport = GPU_viewport_create();
}
else {
drw_notify_view_update_offscreen(depsgraph, engine_type, region, v3d, render_viewport);
}
GPU_viewport_bind_from_offscreen(render_viewport, ofs, is_xr_surface);

View File

@@ -63,14 +63,12 @@ void ED_render_view3d_update(Depsgraph *depsgraph,
{
Main *bmain = DEG_get_bmain(depsgraph);
Scene *scene = DEG_get_input_scene(depsgraph);
ViewLayer *view_layer = DEG_get_input_view_layer(depsgraph);
LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
if (region->regiontype != RGN_TYPE_WINDOW) {
continue;
}
View3D *v3d = static_cast<View3D *>(area->spacedata.first);
RegionView3D *rv3d = static_cast<RegionView3D *>(region->regiondata);
RenderEngine *engine = rv3d->view_render ? RE_view_engine_get(rv3d->view_render) : nullptr;
@@ -96,20 +94,6 @@ void ED_render_view3d_update(Depsgraph *depsgraph,
CTX_free(C);
}
if (!updated) {
continue;
}
DRWUpdateContext drw_context = {nullptr};
drw_context.bmain = bmain;
drw_context.depsgraph = depsgraph;
drw_context.scene = scene;
drw_context.view_layer = view_layer;
drw_context.region = region;
drw_context.v3d = v3d;
drw_context.engine_type = ED_view3d_engine_type(scene, v3d->shading.type);
DRW_notify_view_update(&drw_context);
}
}

View File

@@ -1392,27 +1392,6 @@ static void view3d_main_region_listener(const wmRegionListenerParams *params)
}
}
static void view3d_do_msg_notify_workbench_view_update(bContext *C,
wmMsgSubscribeKey * /*msg_key*/,
wmMsgSubscribeValue *msg_val)
{
Scene *scene = CTX_data_scene(C);
ScrArea *area = (ScrArea *)msg_val->user_data;
View3D *v3d = (View3D *)area->spacedata.first;
if (v3d->shading.type == OB_SOLID) {
RenderEngineType *engine_type = ED_view3d_engine_type(scene, v3d->shading.type);
DRWUpdateContext drw_context = {nullptr};
drw_context.bmain = CTX_data_main(C);
drw_context.depsgraph = CTX_data_depsgraph_pointer(C);
drw_context.scene = scene;
drw_context.view_layer = CTX_data_view_layer(C);
drw_context.region = (ARegion *)(msg_val->owner);
drw_context.v3d = v3d;
drw_context.engine_type = engine_type;
DRW_notify_view_update(&drw_context);
}
}
static void view3d_main_region_message_subscribe(const wmRegionMessageSubscribeParams *params)
{
wmMsgBus *mbus = params->message_bus;
@@ -1453,11 +1432,6 @@ static void view3d_main_region_message_subscribe(const wmRegionMessageSubscribeP
msg_sub_value_region_tag_redraw.user_data = region;
msg_sub_value_region_tag_redraw.notify = ED_region_do_msg_notify_tag_redraw;
wmMsgSubscribeValue msg_sub_value_workbench_view_update{};
msg_sub_value_workbench_view_update.owner = region;
msg_sub_value_workbench_view_update.user_data = area;
msg_sub_value_workbench_view_update.notify = view3d_do_msg_notify_workbench_view_update;
for (int i = 0; i < ARRAY_SIZE(type_array); i++) {
msg_key_params.ptr.type = type_array[i];
WM_msg_subscribe_rna_params(mbus, &msg_key_params, &msg_sub_value_region_tag_redraw, __func__);
@@ -1493,11 +1467,6 @@ static void view3d_main_region_message_subscribe(const wmRegionMessageSubscribeP
case OB_MODE_PARTICLE_EDIT:
WM_msg_subscribe_rna_anon_type(mbus, ParticleEdit, &msg_sub_value_region_tag_redraw);
break;
case OB_MODE_SCULPT:
WM_msg_subscribe_rna_anon_prop(
mbus, WorkSpace, tools, &msg_sub_value_workbench_view_update);
break;
default:
break;
}