Merge branch 'master' into temp_bmesh_multires

This commit is contained in:
Joseph Eagar 2021-04-05 21:26:04 -07:00
commit 8aac19cab5
33 changed files with 411 additions and 176 deletions

View File

@ -1,2 +1,2 @@
Sphinx==3.5.1
sphinx_rtd_theme==0.5.1
Sphinx==3.5.3
sphinx_rtd_theme==0.5.2

View File

@ -41,6 +41,9 @@ class AddPresetIntegrator(AddPresetBase, Operator):
"cycles.caustics_reflective",
"cycles.caustics_refractive",
"cycles.blur_glossy"
"cycles.use_fast_gi"
"cycles.ao_bounces"
"cycles.ao_bounces_render"
]
preset_subdir = "cycles/integrator"

View File

@ -801,17 +801,22 @@ class CyclesRenderSettings(bpy.types.PropertyGroup):
items=enum_texture_limit
)
use_fast_gi: BoolProperty(
name="Fast GI Approximation",
description="Approximate diffuse indirect light with background tinted ambient occlusion. This provides fast alternative to full global illumination, for interactive viewport rendering or final renders with reduced quality",
default=False,
)
ao_bounces: IntProperty(
name="AO Bounces",
default=0,
description="Approximate indirect light with background tinted ambient occlusion at the specified bounce, 0 disables this feature",
default=1,
description="After this number of light bounces, use approximate global illumination. 0 disables this feature",
min=0, max=1024,
)
ao_bounces_render: IntProperty(
name="AO Bounces Render",
default=0,
description="Approximate indirect light with background tinted ambient occlusion at the specified bounce, 0 disables this feature",
default=1,
description="After this number of light bounces, use approximate global illumination. 0 disables this feature",
min=0, max=1024,
)

View File

@ -526,6 +526,35 @@ class CYCLES_RENDER_PT_light_paths_caustics(CyclesButtonsPanel, Panel):
col.prop(cscene, "caustics_refractive", text="Refractive")
class CYCLES_RENDER_PT_light_paths_fast_gi(CyclesButtonsPanel, Panel):
bl_label = "Fast GI Approximation"
bl_options = {'DEFAULT_CLOSED'}
bl_parent_id = "CYCLES_RENDER_PT_light_paths"
def draw_header(self, context):
scene = context.scene
cscene = scene.cycles
self.layout.prop(cscene, "use_fast_gi", text="")
def draw(self, context):
scene = context.scene
cscene = scene.cycles
world = scene.world
layout = self.layout
layout.use_property_split = True
layout.use_property_decorate = False
col = layout.column(align=True)
col.prop(cscene, "ao_bounces", text="Viewport Bounces")
col.prop(cscene, "ao_bounces_render", text="Render Bounces")
if world:
light = world.light_settings
layout.prop(light, "distance", text="AO Distance")
class CYCLES_RENDER_PT_motion_blur(CyclesButtonsPanel, Panel):
bl_label = "Motion Blur"
bl_options = {'DEFAULT_CLOSED'}
@ -746,7 +775,7 @@ class CYCLES_RENDER_PT_performance_final_render(CyclesButtonsPanel, Panel):
col = layout.column()
col.prop(rd, "use_save_buffers")
col.prop(rd, "use_persistent_data", text="Persistent Images")
col.prop(rd, "use_persistent_data", text="Persistent Data")
class CYCLES_RENDER_PT_performance_viewport(CyclesButtonsPanel, Panel):
@ -2041,7 +2070,6 @@ class CYCLES_RENDER_PT_simplify_viewport(CyclesButtonsPanel, Panel):
col.prop(rd, "simplify_subdivision", text="Max Subdivision")
col.prop(rd, "simplify_child_particles", text="Child Particles")
col.prop(cscene, "texture_limit", text="Texture Limit")
col.prop(cscene, "ao_bounces", text="AO Bounces")
col.prop(rd, "simplify_volumes", text="Volume Resolution")
@ -2067,7 +2095,6 @@ class CYCLES_RENDER_PT_simplify_render(CyclesButtonsPanel, Panel):
col.prop(rd, "simplify_subdivision_render", text="Max Subdivision")
col.prop(rd, "simplify_child_particles_render", text="Child Particles")
col.prop(cscene, "texture_limit_render", text="Texture Limit")
col.prop(cscene, "ao_bounces_render", text="AO Bounces")
class CYCLES_RENDER_PT_simplify_culling(CyclesButtonsPanel, Panel):
@ -2245,6 +2272,7 @@ classes = (
CYCLES_RENDER_PT_light_paths_max_bounces,
CYCLES_RENDER_PT_light_paths_clamping,
CYCLES_RENDER_PT_light_paths_caustics,
CYCLES_RENDER_PT_light_paths_fast_gi,
CYCLES_RENDER_PT_volumes,
CYCLES_RENDER_PT_subdivision,
CYCLES_RENDER_PT_hair,

View File

@ -217,6 +217,15 @@ def do_versions(self):
baov.name = caov.get("name", "AOV")
baov.type = "COLOR" if caov.get("type", 1) == 1 else "VALUE"
if version <= (2, 93, 16):
cscene = scene.cycles
if scene.render.use_simplify and \
(cscene.ao_bounces or cscene.ao_bounces_render):
cscene.use_fast_gi = True
else:
cscene.ao_bounces = 1
cscene.ao_bounces_render = 1
# Lamps
for light in bpy.data.lights:
if light.library not in libraries:

View File

@ -143,12 +143,6 @@ void BlenderSession::create_session()
session->scene = scene;
/* There is no single depsgraph to use for the entire render.
* So we need to handle this differently.
*
* We could loop over the final render result render layers in pipeline and keep Cycles unaware
* of multiple layers, or perhaps move syncing further down in the pipeline.
*/
/* create sync */
sync = new BlenderSync(b_engine, b_data, b_scene, scene, !background, session->progress);
BL::Object b_camera_override(b_engine.camera_override());
@ -213,7 +207,7 @@ void BlenderSession::reset_session(BL::BlendData &b_data, BL::Depsgraph &b_depsg
SceneParams scene_params = BlenderSync::get_scene_params(b_scene, background);
if (scene->params.modified(scene_params) || session->params.modified(session_params) ||
!scene_params.persistent_data) {
!this->b_render.use_persistent_data()) {
/* if scene or session parameters changed, it's easier to simply re-create
* them rather than trying to distinguish which settings need to be updated
*/
@ -225,7 +219,6 @@ void BlenderSession::reset_session(BL::BlendData &b_data, BL::Depsgraph &b_depsg
}
session->progress.reset();
scene->reset();
session->tile_manager.set_tile_order(session_params.tile_order);
@ -234,12 +227,15 @@ void BlenderSession::reset_session(BL::BlendData &b_data, BL::Depsgraph &b_depsg
*/
session->stats.mem_peak = session->stats.mem_used;
/* There is no single depsgraph to use for the entire render.
* See note on create_session().
*/
/* sync object should be re-created */
delete sync;
sync = new BlenderSync(b_engine, b_data, b_scene, scene, !background, session->progress);
if (is_new_session) {
/* Sync object should be re-created for new scene. */
delete sync;
sync = new BlenderSync(b_engine, b_data, b_scene, scene, !background, session->progress);
}
else {
/* Sync recalculations to do just the required updates. */
sync->sync_recalc(b_depsgraph, b_v3d);
}
BL::SpaceView3D b_null_space_view3d(PointerRNA_NULL);
BL::RegionView3D b_null_region_view3d(PointerRNA_NULL);
@ -598,18 +594,6 @@ void BlenderSession::render(BL::Depsgraph &b_depsgraph_)
/* clear callback */
session->write_render_tile_cb = function_null;
session->update_render_tile_cb = function_null;
/* TODO: find a way to clear this data for persistent data render */
#if 0
/* free all memory used (host and device), so we wouldn't leave render
* engine with extra memory allocated
*/
session->device_free();
delete sync;
sync = NULL;
#endif
}
static int bake_pass_filter_get(const int pass_filter)

View File

@ -211,9 +211,11 @@ void BlenderSync::sync_recalc(BL::Depsgraph &b_depsgraph, BL::SpaceView3D &b_v3d
}
}
BlenderViewportParameters new_viewport_parameters(b_v3d);
if (viewport_parameters.modified(new_viewport_parameters)) {
world_recalc = true;
if (b_v3d) {
BlenderViewportParameters new_viewport_parameters(b_v3d);
if (viewport_parameters.modified(new_viewport_parameters)) {
world_recalc = true;
}
}
}
@ -358,7 +360,7 @@ void BlenderSync::sync_integrator()
integrator->set_adaptive_min_samples(adaptive_min_samples);
if (b_scene.render().use_simplify()) {
if (get_boolean(cscene, "use_fast_gi")) {
if (preview) {
integrator->set_ao_bounces(get_int(cscene, "ao_bounces"));
}
@ -757,7 +759,6 @@ void BlenderSync::free_data_after_sync(BL::Depsgraph &b_depsgraph)
SceneParams BlenderSync::get_scene_params(BL::Scene &b_scene, bool background)
{
BL::RenderSettings r = b_scene.render();
SceneParams params;
PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles");
const bool shadingsystem = RNA_boolean_get(&cscene, "shading_system");
@ -781,11 +782,6 @@ SceneParams BlenderSync::get_scene_params(BL::Scene &b_scene, bool background)
params.hair_shape = (CurveShapeType)get_enum(
csscene, "shape", CURVE_NUM_SHAPE_TYPES, CURVE_THICK);
if (background && params.shadingsystem != SHADINGSYSTEM_OSL)
params.persistent_data = r.use_persistent_data();
else
params.persistent_data = false;
int texture_limit;
if (background) {
texture_limit = RNA_enum_get(&cscene, "texture_limit_render");

View File

@ -179,7 +179,7 @@ void Scene::free_memory(bool final)
bake_manager->device_free(device, &dscene);
if (!params.persistent_data || final)
if (final)
image_manager->device_free(device);
else
image_manager->device_free_builtin(device);

View File

@ -178,7 +178,6 @@ class SceneParams {
int num_bvh_time_steps;
int hair_subdivisions;
CurveShapeType hair_shape;
bool persistent_data;
int texture_limit;
bool background;
@ -193,7 +192,6 @@ class SceneParams {
num_bvh_time_steps = 0;
hair_subdivisions = 3;
hair_shape = CURVE_RIBBON;
persistent_data = false;
texture_limit = 0;
background = true;
}
@ -206,7 +204,7 @@ class SceneParams {
use_bvh_unaligned_nodes == params.use_bvh_unaligned_nodes &&
num_bvh_time_steps == params.num_bvh_time_steps &&
hair_subdivisions == params.hair_subdivisions && hair_shape == params.hair_shape &&
persistent_data == params.persistent_data && texture_limit == params.texture_limit);
texture_limit == params.texture_limit);
}
int curve_subdivisions()
@ -301,7 +299,7 @@ class Scene : public NodeOwner {
* node array (e.g. Scene::geometry for Geometry nodes) and tag the appropriate
* manager for an update.
*/
template<typename T, typename... Args> T *create_node(Args &&... args)
template<typename T, typename... Args> T *create_node(Args &&...args)
{
T *node = new T(args...);
node->set_owner(this);

View File

@ -0,0 +1,14 @@
import bpy
cycles = bpy.context.scene.cycles
cycles.max_bounces = 12
cycles.caustics_reflective = True
cycles.caustics_refractive = True
cycles.diffuse_bounces = 4
cycles.glossy_bounces = 4
cycles.transmission_bounces = 12
cycles.volume_bounces = 0
cycles.transparent_max_bounces = 8
cycles.use_fast_gi = False
cycles.ao_bounces = 1
cycles.ao_bounces_render = 1

View File

@ -9,3 +9,6 @@ cycles.glossy_bounces = 1
cycles.transmission_bounces = 2
cycles.volume_bounces = 0
cycles.transparent_max_bounces = 8
cycles.use_fast_gi = False
cycles.ao_bounces = 1
cycles.ao_bounces_render = 1

View File

@ -0,0 +1,14 @@
import bpy
cycles = bpy.context.scene.cycles
cycles.max_bounces = 8
cycles.caustics_reflective = False
cycles.caustics_refractive = False
cycles.diffuse_bounces = 1
cycles.glossy_bounces = 4
cycles.transmission_bounces = 8
cycles.volume_bounces = 2
cycles.transparent_max_bounces = 8
cycles.use_fast_gi = True
cycles.ao_bounces = 2
cycles.ao_bounces_render = 2

View File

@ -1,11 +1,14 @@
import bpy
cycles = bpy.context.scene.cycles
cycles.max_bounces = 128
cycles.max_bounces = 32
cycles.caustics_reflective = True
cycles.caustics_refractive = True
cycles.diffuse_bounces = 128
cycles.glossy_bounces = 128
cycles.transmission_bounces = 128
cycles.volume_bounces = 128
cycles.transparent_max_bounces = 128
cycles.diffuse_bounces = 32
cycles.glossy_bounces = 32
cycles.transmission_bounces = 32
cycles.volume_bounces = 32
cycles.transparent_max_bounces = 32
cycles.use_fast_gi = False
cycles.ao_bounces = 1
cycles.ao_bounces_render = 1

View File

@ -7,5 +7,8 @@ cycles.caustics_refractive = False
cycles.diffuse_bounces = 1
cycles.glossy_bounces = 4
cycles.transmission_bounces = 8
cycles.volume_bounces = 2
cycles.volume_bounces = 0
cycles.transparent_max_bounces = 8
cycles.use_fast_gi = False
cycles.ao_bounces = 1
cycles.ao_bounces_render = 1

View File

@ -39,7 +39,7 @@ extern "C" {
/* Blender file format version. */
#define BLENDER_FILE_VERSION BLENDER_VERSION
#define BLENDER_FILE_SUBVERSION 16
#define BLENDER_FILE_SUBVERSION 17
/* Minimum Blender version that supports reading file written with the current
* version. Older Blender versions will test this and show a warning if the file

View File

@ -2661,7 +2661,7 @@ static void scene_graph_update_tagged(Depsgraph *depsgraph, Main *bmain, bool on
bmain, &scene->id, depsgraph, BKE_CB_EVT_DEPSGRAPH_UPDATE_POST);
/* It is possible that the custom callback modified scene and removed some IDs from the main
* database. In this case DEG_ids_clear_recalc() will crash because it iterates over all IDs
* database. In this case DEG_editors_update() will crash because it iterates over all IDs
* which depsgraph was built for.
*
* The solution is to update relations prior to this call, avoiding access to freed IDs.
@ -2674,9 +2674,7 @@ static void scene_graph_update_tagged(Depsgraph *depsgraph, Main *bmain, bool on
DEG_graph_relations_update(depsgraph);
}
/* Inform editors about possible changes. */
DEG_ids_check_recalc(bmain, depsgraph, scene, view_layer, false);
/* Clear recalc flags. */
DEG_ids_clear_recalc(bmain, depsgraph);
DEG_editors_update(bmain, depsgraph, scene, view_layer, false);
/* If user callback did not tag anything for update we can skip second iteration.
* Otherwise we update scene once again, but without running callbacks to bring
@ -2737,14 +2735,12 @@ void BKE_scene_graph_update_for_newframe(Depsgraph *depsgraph)
BKE_callback_exec_id_depsgraph(bmain, &scene->id, depsgraph, BKE_CB_EVT_FRAME_CHANGE_POST);
/* NOTE: Similar to this case in scene_graph_update_tagged(). Need to ensure that
* DEG_ids_clear_recalc() doesn't access freed memory of possibly removed ID. */
* DEG_editors_update() doesn't access freed memory of possibly removed ID. */
DEG_graph_relations_update(depsgraph);
}
/* Inform editors about possible changes. */
DEG_ids_check_recalc(bmain, depsgraph, scene, view_layer, true);
/* clear recalc flags */
DEG_ids_clear_recalc(bmain, depsgraph);
DEG_editors_update(bmain, depsgraph, scene, view_layer, true);
/* If user callback did not tag anything for update we can skip second iteration.
* Otherwise we update scene once again, but without running callbacks to bring
@ -3463,6 +3459,9 @@ static Depsgraph **scene_ensure_depsgraph_p(Main *bmain, Scene *scene, ViewLayer
BLI_snprintf(name, sizeof(name), "%s :: %s", scene->id.name, view_layer->name);
DEG_debug_name_set(*depsgraph_ptr, name);
/* These viewport depsgraphs communicate changes to the editors. */
DEG_enable_editors_update(*depsgraph_ptr);
return depsgraph_ptr;
}

View File

@ -337,10 +337,10 @@ bool _bli_array_iter_spiral_square(const void *arr_v,
center[1] < arr_shape[1]);
const char *arr = arr_v;
const int stride[2] = {arr_shape[1] * (int)elem_size, (int)elem_size};
const int stride[2] = {arr_shape[0] * (int)elem_size, (int)elem_size};
/* Test center first. */
int ofs[2] = {center[0] * stride[0], center[1] * stride[1]};
int ofs[2] = {center[0] * stride[1], center[1] * stride[0]};
if (test_fn(arr + ofs[0] + ofs[1], user_data)) {
return true;
}

View File

@ -139,16 +139,20 @@ void DEG_graph_time_tag_update(struct Depsgraph *depsgraph);
void DEG_graph_id_type_tag(struct Depsgraph *depsgraph, short id_type);
void DEG_id_type_tag(struct Main *bmain, short id_type);
void DEG_ids_clear_recalc(struct Main *bmain, Depsgraph *depsgraph);
/* Set a depsgraph to flush updates to editors. This would be done
* for viewport depsgraphs, but not render or export depsgraph for example. */
void DEG_enable_editors_update(struct Depsgraph *depsgraph);
/* Check if something was changed in the database and inform
* editors about this.
*/
void DEG_ids_check_recalc(struct Main *bmain,
struct Depsgraph *depsgraph,
struct Scene *scene,
struct ViewLayer *view_layer,
bool time);
/* Check if something was changed in the database and inform editors about this,
* then clear recalc flags. */
void DEG_editors_update(struct Main *bmain,
struct Depsgraph *depsgraph,
struct Scene *scene,
struct ViewLayer *view_layer,
bool time);
/* Clear recalc flags after editors or renderers have handled updates. */
void DEG_ids_clear_recalc(Depsgraph *depsgraph);
/* ************************************************ */
/* Evaluation Engine API */

View File

@ -70,7 +70,8 @@ Depsgraph::Depsgraph(Main *bmain, Scene *scene, ViewLayer *view_layer, eEvaluati
scene_cow(nullptr),
is_active(false),
is_evaluating(false),
is_render_pipeline_depsgraph(false)
is_render_pipeline_depsgraph(false),
use_editors_update(false)
{
BLI_spin_init(&lock);
memset(id_type_updated, 0, sizeof(id_type_updated));
@ -285,7 +286,9 @@ Depsgraph *DEG_graph_new(Main *bmain, Scene *scene, ViewLayer *view_layer, eEval
}
/* Replace the "owner" pointers (currently Main/Scene/ViewLayer) of this depsgraph.
* Used during undo steps when we do want to re-use the old depsgraph data as much as possible. */
* Used for:
* - Undo steps when we do want to re-use the old depsgraph data as much as possible.
* - Rendering where we want to re-use objects between different view layers. */
void DEG_graph_replace_owners(struct Depsgraph *depsgraph,
Main *bmain,
Scene *scene,

View File

@ -161,6 +161,9 @@ struct Depsgraph {
* does not need any bases. */
bool is_render_pipeline_depsgraph;
/* Notify editors about changes to IDs in this depsgrpah. */
bool use_editors_update;
/* Cached list of colliders/effectors for collections and the scene
* created along with relations, for fast lookup during evaluation. */
Map<const ID *, ListBase *> *physics_relations[DEG_PHYSICS_RELATIONS_NUM];

View File

@ -816,11 +816,22 @@ void DEG_on_visible_update(Main *bmain, const bool do_time)
}
}
void DEG_enable_editors_update(Depsgraph *depsgraph)
{
deg::Depsgraph *graph = (deg::Depsgraph *)depsgraph;
graph->use_editors_update = true;
}
/* Check if something was changed in the database and inform
* editors about this. */
void DEG_ids_check_recalc(
void DEG_editors_update(
Main *bmain, Depsgraph *depsgraph, Scene *scene, ViewLayer *view_layer, bool time)
{
deg::Depsgraph *graph = (deg::Depsgraph *)depsgraph;
if (!graph->use_editors_update) {
return;
}
bool updated = time || DEG_id_type_any_updated(depsgraph);
DEGEditorUpdateContext update_ctx = {nullptr};
@ -829,6 +840,8 @@ void DEG_ids_check_recalc(
update_ctx.scene = scene;
update_ctx.view_layer = view_layer;
deg::deg_editors_scene_update(&update_ctx, updated);
DEG_ids_clear_recalc(depsgraph);
}
static void deg_graph_clear_id_recalc_flags(ID *id)
@ -842,7 +855,7 @@ static void deg_graph_clear_id_recalc_flags(ID *id)
/* XXX And what about scene's master collection here? */
}
void DEG_ids_clear_recalc(Main *UNUSED(bmain), Depsgraph *depsgraph)
void DEG_ids_clear_recalc(Depsgraph *depsgraph)
{
deg::Depsgraph *deg_graph = reinterpret_cast<deg::Depsgraph *>(depsgraph);
/* TODO(sergey): Re-implement POST_UPDATE_HANDLER_WORKAROUND using entry_tags

View File

@ -206,7 +206,9 @@ static bool stroke_elem_project(const struct CurveDrawData *cdd,
else {
const ViewDepths *depths = rv3d->depths;
if (depths && ((uint)mval_i[0] < depths->w) && ((uint)mval_i[1] < depths->h)) {
const double depth = (double)ED_view3d_depth_read_cached(&cdd->vc, mval_i);
float depth_fl = 1.0f;
ED_view3d_depth_read_cached(depths, mval_i, 0, &depth_fl);
const double depth = (double)depth_fl;
if ((depth > depths->depth_range[0]) && (depth < depths->depth_range[1])) {
if (ED_view3d_depth_unproject(region, mval_i, depth, r_location_world)) {
is_location_world_set = true;

View File

@ -155,7 +155,10 @@ void ED_view3d_depth_override(struct Depsgraph *depsgraph,
struct Object *obact,
eV3DDepthOverrideMode mode,
bool update_cache);
float ED_view3d_depth_read_cached(const struct ViewContext *vc, const int mval[2]);
bool ED_view3d_depth_read_cached(const ViewDepths *vd,
const int mval[2],
int margin,
float *r_depth);
bool ED_view3d_depth_read_cached_normal(const ViewContext *vc,
const int mval[2],
float r_normal[3]);

View File

@ -1865,28 +1865,30 @@ static int object_transform_axis_target_modal(bContext *C, wmOperator *op, const
if (event->type == MOUSEMOVE || is_translate_init) {
const ViewDepths *depths = xfd->vc.rv3d->depths;
if (depths && ((uint)event->mval[0] < depths->w) && ((uint)event->mval[1] < depths->h)) {
double depth = (double)ED_view3d_depth_read_cached(&xfd->vc, event->mval);
float depth_fl = 1.0f;
ED_view3d_depth_read_cached(depths, event->mval, 0, &depth_fl);
float location_world[3];
if (depth == 1.0f) {
if (depth_fl == 1.0f) {
if (xfd->prev.is_depth_valid) {
depth = (double)xfd->prev.depth;
depth_fl = xfd->prev.depth;
}
}
#ifdef USE_FAKE_DEPTH_INIT
/* First time only. */
if (depth == 1.0f) {
if (depth_fl == 1.0f) {
if (xfd->prev.is_depth_valid == false) {
object_transform_axis_target_calc_depth_init(xfd, event->mval);
if (xfd->prev.is_depth_valid) {
depth = (double)xfd->prev.depth;
depth_fl = xfd->prev.depth;
}
}
}
#endif
double depth = (double)depth_fl;
if ((depth > depths->depth_range[0]) && (depth < depths->depth_range[1])) {
xfd->prev.depth = depth;
xfd->prev.depth = depth_fl;
xfd->prev.is_depth_valid = true;
if (ED_view3d_depth_unproject(region, event->mval, depth, location_world)) {
if (is_translate) {

View File

@ -188,7 +188,7 @@ void ED_render_engine_changed(Main *bmain, const bool update_scene_data)
ED_render_engine_area_exit(bmain, area);
}
}
RE_FreePersistentData();
RE_FreePersistentData(NULL);
/* Inform all render engines and draw managers. */
DEGEditorUpdateContext update_ctx = {NULL};
update_ctx.bmain = bmain;

View File

@ -36,6 +36,7 @@
#include "MEM_guardedalloc.h"
#include "BLI_array_utils.h"
#include "BLI_bitmap_draw_2d.h"
#include "BLI_blenlib.h"
#include "BLI_math.h"
@ -1629,19 +1630,48 @@ bool ED_view3d_camera_to_view_selected(struct Main *bmain,
/** \name Depth Buffer Utilities
* \{ */
float ED_view3d_depth_read_cached(const ViewContext *vc, const int mval[2])
static bool depth_read_test_fn(const void *value, void *userdata)
{
ViewDepths *vd = vc->rv3d->depths;
float *r_depth = userdata;
float depth = *(float *)value;
if (depth < *r_depth) {
*r_depth = depth;
}
return false;
}
bool ED_view3d_depth_read_cached(const ViewDepths *vd,
const int mval[2],
int margin,
float *r_depth)
{
if (!vd || !vd->depths) {
return false;
}
int x = mval[0];
int y = mval[1];
if (x < 0 || y < 0 || x >= vd->w || y >= vd->h) {
return false;
}
if (vd && vd->depths && x > 0 && y > 0 && x < vd->w && y < vd->h) {
return vd->depths[y * vd->w + x];
float depth = 1.0f;
if (margin) {
/* TODO: No need to go spiral. */
int shape[2] = {vd->w, vd->h};
BLI_array_iter_spiral_square(vd->depths, shape, mval, depth_read_test_fn, &depth);
}
else {
depth = vd->depths[y * vd->w + x];
}
BLI_assert(1.0 <= vd->depth_range[1]);
return 1.0f;
if (depth != 1.0f) {
*r_depth = depth;
return true;
}
return false;
}
bool ED_view3d_depth_read_cached_normal(const ViewContext *vc,
@ -1662,7 +1692,9 @@ bool ED_view3d_depth_read_cached_normal(const ViewContext *vc,
for (int y = 0; y < 2; y++) {
const int mval_ofs[2] = {mval[0] + (x - 1), mval[1] + (y - 1)};
const double depth = (double)ED_view3d_depth_read_cached(vc, mval_ofs);
float depth_fl = 1.0f;
ED_view3d_depth_read_cached(depths, mval_ofs, 0, &depth_fl);
const double depth = (double)depth_fl;
if ((depth > depths->depth_range[0]) && (depth < depths->depth_range[1])) {
if (ED_view3d_depth_unproject(region, mval_ofs, depth, coords[i])) {
depths_valid[i] = true;

View File

@ -298,13 +298,13 @@ static void rna_RenderEngine_unregister(Main *bmain, StructRNA *type)
return;
}
/* Stop all renders in case we were using this one. */
ED_render_engine_changed(bmain, false);
RE_FreeAllPersistentData();
RNA_struct_free_extension(type, &et->rna_ext);
RNA_struct_free(&BLENDER_RNA, type);
BLI_freelinkN(&R_engines, et);
/* Stop all renders in case we were using this one. */
ED_render_engine_changed(bmain, false);
}
static StructRNA *rna_RenderEngine_register(Main *bmain,

View File

@ -1896,10 +1896,10 @@ static void rna_Scene_use_persistent_data_update(Main *UNUSED(bmain),
Scene *UNUSED(scene),
PointerRNA *ptr)
{
Scene *sce = (Scene *)ptr->owner_id;
Scene *scene = (Scene *)ptr->owner_id;
if (!(sce->r.mode & R_PERSISTENT_DATA)) {
RE_FreePersistentData();
if (!(scene->r.mode & R_PERSISTENT_DATA)) {
RE_FreePersistentData(scene);
}
}
@ -6606,8 +6606,10 @@ static void rna_def_scene_render_data(BlenderRNA *brna)
/* persistent data */
prop = RNA_def_property(srna, "use_persistent_data", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "mode", R_PERSISTENT_DATA);
RNA_def_property_ui_text(
prop, "Persistent Data", "Keep render data around for faster re-renders");
RNA_def_property_ui_text(prop,
"Persistent Data",
"Keep render data around for faster re-renders and animation renders, "
"at the cost of increased memory usage");
RNA_def_property_update(prop, 0, "rna_Scene_use_persistent_data_update");
/* Freestyle line thickness options */

View File

@ -112,18 +112,6 @@ static bool rna_Screen_fullscreen_get(PointerRNA *ptr)
return (screen->state == SCREENMAXIMIZED);
}
/* UI compatible list: should not be needed, but for now we need to keep EMPTY
* at least in the static version of this enum for python scripts. */
static const EnumPropertyItem *rna_Area_type_itemf(bContext *UNUSED(C),
PointerRNA *UNUSED(ptr),
PropertyRNA *UNUSED(prop),
bool *r_free)
{
/* +1 to skip SPACE_EMPTY */
*r_free = false;
return rna_enum_space_type_items + 1;
}
static int rna_Area_type_get(PointerRNA *ptr)
{
ScrArea *area = (ScrArea *)ptr->data;
@ -142,6 +130,11 @@ static void rna_Area_type_set(PointerRNA *ptr, int value)
}
ScrArea *area = (ScrArea *)ptr->data;
/* Empty areas are locked. */
if ((value == SPACE_EMPTY) || (area->spacetype == SPACE_EMPTY)) {
return;
}
area->butspacetype = value;
}
@ -188,16 +181,20 @@ static void rna_Area_type_update(bContext *C, PointerRNA *ptr)
}
static const EnumPropertyItem *rna_Area_ui_type_itemf(bContext *C,
PointerRNA *UNUSED(ptr),
PointerRNA *ptr,
PropertyRNA *UNUSED(prop),
bool *r_free)
{
EnumPropertyItem *item = NULL;
int totitem = 0;
/* +1 to skip SPACE_EMPTY */
for (const EnumPropertyItem *item_from = rna_enum_space_type_items + 1; item_from->identifier;
item_from++) {
ScrArea *area = (ScrArea *)ptr->data;
const EnumPropertyItem *item_from = rna_enum_space_type_items;
if (area->spacetype != SPACE_EMPTY) {
item_from += 1; /* +1 to skip SPACE_EMPTY */
}
for (; item_from->identifier; item_from++) {
if (ELEM(item_from->value, SPACE_TOPBAR, SPACE_STATUSBAR)) {
continue;
}
@ -224,6 +221,10 @@ static const EnumPropertyItem *rna_Area_ui_type_itemf(bContext *C,
static int rna_Area_ui_type_get(PointerRNA *ptr)
{
ScrArea *area = ptr->data;
/* This is for the Python API which may inspect empty areas. */
if (UNLIKELY(area->spacetype == SPACE_EMPTY)) {
return SPACE_EMPTY;
}
const int area_type = rna_Area_type_get(ptr);
const bool area_changing = area->butspacetype != SPACE_EMPTY;
int value = area_type << 16;
@ -252,6 +253,10 @@ static void rna_Area_ui_type_set(PointerRNA *ptr, int value)
{
ScrArea *area = ptr->data;
const int space_type = value >> 16;
/* Empty areas are locked. */
if ((space_type == SPACE_EMPTY) || (area->spacetype == SPACE_EMPTY)) {
return;
}
SpaceType *st = BKE_spacetype_from_id(space_type);
rna_Area_type_set(ptr, space_type);
@ -380,12 +385,17 @@ static void rna_def_area(BlenderRNA *brna)
RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", HEADER_NO_PULLDOWN);
RNA_def_property_ui_text(prop, "Show Menus", "Show menus in the header");
/* Note on space type use of #SPACE_EMPTY, this is not visible to the user,
* and script authors should be able to assign this value, however the value may be set
* and needs to be read back by script authors.
*
* This happens when an area is full-screen (when #ScrArea.full is set).
* in this case reading the empty value is needed, but it should never be set, see: T87187. */
prop = RNA_def_property(srna, "type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "spacetype");
RNA_def_property_enum_items(prop, rna_enum_space_type_items);
RNA_def_property_enum_default(prop, SPACE_VIEW3D);
RNA_def_property_enum_funcs(
prop, "rna_Area_type_get", "rna_Area_type_set", "rna_Area_type_itemf");
RNA_def_property_enum_funcs(prop, "rna_Area_type_get", "rna_Area_type_set", NULL);
RNA_def_property_ui_text(prop, "Editor Type", "Current editor type for this area");
RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);

View File

@ -224,6 +224,8 @@ void RE_engine_register_pass(struct RenderEngine *engine,
const char *chanid,
eNodeSocketDatatype type);
bool RE_engine_use_persistent_data(struct RenderEngine *engine);
/* Engine Types */
void RE_engines_init(void);

View File

@ -184,14 +184,14 @@ void RE_InitRenderCB(struct Render *re);
void RE_FreeRender(struct Render *re);
/* only called on exit */
void RE_FreeAllRender(void);
/* Free memory used by persistent data.
* Invoked when loading new file.
*/
void RE_FreeAllPersistentData(void);
/* only call on file load */
/* On file load, free render results. */
void RE_FreeAllRenderResults(void);
/* for external render engines that can keep persistent data */
void RE_FreePersistentData(void);
/* On file load or changes engines, free persistent render data.
* Assumes no engines are currently rendering. */
void RE_FreeAllPersistentData(void);
/* Free persistent render data, optionally only for the given scene. */
void RE_FreePersistentData(const Scene *scene);
/* get results and statistics */
void RE_FreeRenderResult(struct RenderResult *rr);

View File

@ -140,6 +140,27 @@ RenderEngine *RE_engine_create(RenderEngineType *type)
return engine;
}
static void engine_depsgraph_free(RenderEngine *engine)
{
if (engine->depsgraph) {
/* Need GPU context since this might free GPU buffers. This function can
* only be called from a render thread. We do not currently support
* persistent data with GPU contexts for that reason. */
const bool use_gpu_context = (engine->type->flag & RE_USE_GPU_CONTEXT);
if (use_gpu_context) {
BLI_assert(!BLI_thread_is_main());
DRW_render_context_enable(engine->re);
}
DEG_graph_free(engine->depsgraph);
engine->depsgraph = NULL;
if (use_gpu_context) {
DRW_render_context_disable(engine->re);
}
}
}
void RE_engine_free(RenderEngine *engine)
{
#ifdef WITH_PYTHON
@ -148,6 +169,8 @@ void RE_engine_free(RenderEngine *engine)
}
#endif
engine_depsgraph_free(engine);
BLI_mutex_end(&engine->update_render_passes_mutex);
MEM_freeN(engine);
@ -598,34 +621,94 @@ RenderData *RE_engine_get_render_data(Render *re)
return &re->r;
}
bool RE_engine_use_persistent_data(RenderEngine *engine)
{
/* See engine_depsgraph_free() for why preserving the depsgraph for
* re-renders is not supported with GPU contexts. */
return (engine->re->r.mode & R_PERSISTENT_DATA) && !(engine->type->flag & RE_USE_GPU_CONTEXT);
}
static bool engine_keep_depsgraph(RenderEngine *engine)
{
/* For persistent data or GPU engines like Eevee, reuse the depsgraph between
* view layers and animation frames. For renderers like Cycles that create
* their own copy of the scene, persistent data must be explicitly enabled to
* keep memory usage low by default. */
return (engine->re->r.mode & R_PERSISTENT_DATA) || (engine->type->flag & RE_USE_GPU_CONTEXT);
}
/* Depsgraph */
static void engine_depsgraph_init(RenderEngine *engine, ViewLayer *view_layer)
{
Main *bmain = engine->re->main;
Scene *scene = engine->re->scene;
bool reuse_depsgraph = false;
engine->depsgraph = DEG_graph_new(bmain, scene, view_layer, DAG_EVAL_RENDER);
DEG_debug_name_set(engine->depsgraph, "RENDER");
/* Reuse depsgraph from persistent data if possible. */
if (engine->depsgraph) {
if (DEG_get_bmain(engine->depsgraph) != bmain ||
DEG_get_input_scene(engine->depsgraph) != scene) {
/* If bmain or scene changes, we need a completely new graph. */
engine_depsgraph_free(engine);
}
else if (DEG_get_input_view_layer(engine->depsgraph) != view_layer) {
/* If only view layer changed, reuse depsgraph in the hope of reusing
* objects shared between view layers. */
DEG_graph_replace_owners(engine->depsgraph, bmain, scene, view_layer);
DEG_graph_tag_relations_update(engine->depsgraph);
}
reuse_depsgraph = true;
}
if (!engine->depsgraph) {
/* Ensure we only use persistent data for one scene / view layer at a time,
* to avoid excessive memory usage. */
RE_FreePersistentData(NULL);
/* Create new depsgraph if not cached with persistent data. */
engine->depsgraph = DEG_graph_new(bmain, scene, view_layer, DAG_EVAL_RENDER);
DEG_debug_name_set(engine->depsgraph, "RENDER");
}
if (engine->re->r.scemode & R_BUTS_PREVIEW) {
/* Update for preview render. */
Depsgraph *depsgraph = engine->depsgraph;
DEG_graph_relations_update(depsgraph);
/* Need GPU context since this might free GPU buffers. */
const bool use_gpu_context = (engine->type->flag & RE_USE_GPU_CONTEXT) && reuse_depsgraph;
if (use_gpu_context) {
DRW_render_context_enable(engine->re);
}
DEG_evaluate_on_framechange(depsgraph, CFRA);
DEG_ids_check_recalc(bmain, depsgraph, scene, view_layer, true);
DEG_ids_clear_recalc(bmain, depsgraph);
if (use_gpu_context) {
DRW_render_context_disable(engine->re);
}
}
else {
/* Go through update with full Python callbacks for regular render. */
BKE_scene_graph_update_for_newframe(engine->depsgraph);
}
engine->has_grease_pencil = DRW_render_check_grease_pencil(engine->depsgraph);
}
static void engine_depsgraph_free(RenderEngine *engine)
static void engine_depsgraph_exit(RenderEngine *engine)
{
DEG_graph_free(engine->depsgraph);
engine->depsgraph = NULL;
if (engine->depsgraph) {
if (engine_keep_depsgraph(engine)) {
/* Clear recalc flags since the engine should have handled the updates for the currently
* rendered framed by now. */
DEG_ids_clear_recalc(engine->depsgraph);
}
else {
/* Free immediately to save memory. */
engine_depsgraph_free(engine);
}
}
}
void RE_engine_frame_set(RenderEngine *engine, int frame, float subframe)
@ -670,7 +753,6 @@ bool RE_bake_engine(Render *re,
{
RenderEngineType *type = RE_engines_find(re->r.engine);
RenderEngine *engine;
bool persistent_data = (re->r.mode & R_PERSISTENT_DATA) != 0;
/* set render info */
re->i.cfra = re->scene->r.cfra;
@ -729,13 +811,13 @@ bool RE_bake_engine(Render *re,
engine->tile_y = 0;
engine->flag &= ~RE_ENGINE_RENDERING;
/* Free depsgraph outside of parts mutex lock, since this locks OpenGL context
* while the the UI drawing might also lock the OpenGL context and parts mutex. */
engine_depsgraph_free(engine);
BLI_rw_mutex_lock(&re->partsmutex, THREAD_LOCK_WRITE);
/* re->engine becomes zero if user changed active render engine during render */
if (!persistent_data || !re->engine) {
RE_engine_free(engine);
re->engine = NULL;
}
RE_engine_free(engine);
re->engine = NULL;
RE_parts_free(re);
BLI_rw_mutex_unlock(&re->partsmutex);
@ -778,13 +860,14 @@ static void engine_render_view_layer(Render *re,
/* Perform render with engine. */
if (use_engine) {
if (engine->type->flag & RE_USE_GPU_CONTEXT) {
const bool use_gpu_context = (engine->type->flag & RE_USE_GPU_CONTEXT);
if (use_gpu_context) {
DRW_render_context_enable(engine->re);
}
engine->type->render(engine, engine->depsgraph);
if (engine->type->flag & RE_USE_GPU_CONTEXT) {
if (use_gpu_context) {
DRW_render_context_disable(engine->re);
}
}
@ -800,13 +883,12 @@ static void engine_render_view_layer(Render *re,
}
/* Free dependency graph, if engine has not done it already. */
engine_depsgraph_free(engine);
engine_depsgraph_exit(engine);
}
bool RE_engine_render(Render *re, bool do_all)
{
RenderEngineType *type = RE_engines_find(re->r.engine);
bool persistent_data = (re->r.mode & R_PERSISTENT_DATA) != 0;
/* verify if we can render */
if (!type->render) {
@ -953,7 +1035,13 @@ bool RE_engine_render(Render *re, bool do_all)
}
/* re->engine becomes zero if user changed active render engine during render */
if (!persistent_data || !re->engine) {
if (!engine_keep_depsgraph(engine) || !re->engine) {
/* Free depsgraph outside of parts mutex lock, since this locks OpenGL context
* while the the UI drawing might also lock the OpenGL context and parts mutex. */
BLI_rw_mutex_unlock(&re->partsmutex);
engine_depsgraph_free(engine);
BLI_rw_mutex_lock(&re->partsmutex, THREAD_LOCK_WRITE);
RE_engine_free(engine);
re->engine = NULL;
}
@ -1023,9 +1111,8 @@ void RE_engine_free_blender_memory(RenderEngine *engine)
*
* TODO(sergey): Find better solution for this.
*/
if (engine->has_grease_pencil) {
if (engine->has_grease_pencil || engine_keep_depsgraph(engine)) {
return;
}
DEG_graph_free(engine->depsgraph);
engine->depsgraph = NULL;
engine_depsgraph_free(engine);
}

View File

@ -662,17 +662,6 @@ void RE_FreeAllRender(void)
#endif
}
void RE_FreeAllPersistentData(void)
{
Render *re;
for (re = RenderGlobal.renderlist.first; re != NULL; re = re->next) {
if ((re->r.mode & R_PERSISTENT_DATA) != 0 && re->engine != NULL) {
RE_engine_free(re->engine);
re->engine = NULL;
}
}
}
/* on file load, free all re */
void RE_FreeAllRenderResults(void)
{
@ -687,23 +676,43 @@ void RE_FreeAllRenderResults(void)
}
}
void RE_FreePersistentData(void)
void RE_FreeAllPersistentData(void)
{
Render *re;
/* render engines can be kept around for quick re-render, this clears all */
for (re = RenderGlobal.renderlist.first; re; re = re->next) {
if (re->engine) {
/* if engine is currently rendering, just tag it to be freed when render is finished */
if (!(re->engine->flag & RE_ENGINE_RENDERING)) {
RE_engine_free(re->engine);
}
for (re = RenderGlobal.renderlist.first; re != NULL; re = re->next) {
if (re->engine != NULL) {
BLI_assert(!(re->engine->flag & RE_ENGINE_RENDERING));
RE_engine_free(re->engine);
re->engine = NULL;
}
}
}
static void re_free_persistent_data(Render *re)
{
/* If engine is currently rendering, just wait for it to be freed when it finishes rendering. */
if (re->engine && !(re->engine->flag & RE_ENGINE_RENDERING)) {
RE_engine_free(re->engine);
re->engine = NULL;
}
}
void RE_FreePersistentData(const Scene *scene)
{
/* Render engines can be kept around for quick re-render, this clears all or one scene. */
if (scene) {
Render *re = RE_GetSceneRender(scene);
if (re) {
re_free_persistent_data(re);
}
}
else {
for (Render *re = RenderGlobal.renderlist.first; re; re = re->next) {
re_free_persistent_data(re);
}
}
}
/* ********* initialize state ******** */
/* clear full sample and tile flags if needed */
@ -2669,13 +2678,17 @@ void RE_PreviewRender(Render *re, Main *bmain, Scene *sce)
void RE_CleanAfterRender(Render *re)
{
/* Destroy the opengl context in the correct thread. */
RE_gl_context_destroy(re);
if (re->engine && !RE_engine_use_persistent_data(re->engine)) {
RE_engine_free(re->engine);
re->engine = NULL;
}
if (re->pipeline_depsgraph != NULL) {
DEG_graph_free(re->pipeline_depsgraph);
re->pipeline_depsgraph = NULL;
re->pipeline_scene_eval = NULL;
}
re->pipeline_depsgraph = NULL;
re->pipeline_scene_eval = NULL;
/* Destroy the opengl context in the correct thread. */
RE_gl_context_destroy(re);
}
/* note; repeated win/disprect calc... solve that nicer, also in compo */