Merge branch 'blender-v4.3-release'

This commit is contained in:
Jeroen Bakker
2024-10-04 12:13:09 +02:00
15 changed files with 622 additions and 155 deletions

View File

@@ -43,16 +43,14 @@ class GREASE_PENCIL_UL_masks(UIList):
class GreasePencil_LayerMaskPanel:
def draw_header(self, context):
ob = context.object
grease_pencil = ob.data
grease_pencil = context.grease_pencil
layer = grease_pencil.layers.active
self.layout.prop(layer, "use_masks", text="", toggle=0)
def draw(self, context):
layout = self.layout
ob = context.object
grease_pencil = ob.data
grease_pencil = context.grease_pencil
layer = grease_pencil.layers.active
layout = self.layout
@@ -85,8 +83,7 @@ class GreasePencil_LayerTransformPanel:
layout = self.layout
layout.use_property_split = True
ob = context.object
grease_pencil = ob.data
grease_pencil = context.grease_pencil
layer = grease_pencil.layers.active
layout.active = not layer.lock
@@ -105,8 +102,7 @@ class GreasePencil_LayerAdjustmentsPanel:
layout = self.layout
layout.use_property_split = True
ob = context.object
grease_pencil = ob.data
grease_pencil = context.grease_pencil
layer = grease_pencil.layers.active
layout.active = not layer.lock
@@ -125,8 +121,7 @@ class GreasPencil_LayerRelationsPanel:
layout = self.layout
layout.use_property_split = True
ob = context.object
grease_pencil = ob.data
grease_pencil = context.grease_pencil
layer = grease_pencil.layers.active
layout.active = not layer.lock
@@ -193,8 +188,7 @@ class GREASE_PENCIL_MT_grease_pencil_add_layer_extra(Menu):
def draw(self, context):
layout = self.layout
ob = context.object
grease_pencil = ob.data
grease_pencil = context.grease_pencil
layer = grease_pencil.layers.active
layout.separator()

View File

@@ -26,6 +26,12 @@
namespace blender::ed::greasepencil {
bool grease_pencil_context_poll(bContext *C)
{
GreasePencil *grease_pencil = blender::ed::greasepencil::from_context(*C);
return grease_pencil != nullptr;
}
void select_layer_channel(GreasePencil &grease_pencil, bke::greasepencil::Layer *layer)
{
using namespace blender::bke::greasepencil;
@@ -43,9 +49,8 @@ void select_layer_channel(GreasePencil &grease_pencil, bke::greasepencil::Layer
static int grease_pencil_layer_add_exec(bContext *C, wmOperator *op)
{
using namespace blender::bke::greasepencil;
Object *object = CTX_data_active_object(C);
Scene *scene = CTX_data_scene(C);
GreasePencil &grease_pencil = *static_cast<GreasePencil *>(object->data);
GreasePencil &grease_pencil = *blender::ed::greasepencil::from_context(*C);
int new_layer_name_length;
char *new_layer_name = RNA_string_get_alloc(
@@ -89,7 +94,7 @@ static void GREASE_PENCIL_OT_layer_add(wmOperatorType *ot)
/* callbacks */
ot->invoke = grease_pencil_layer_add_invoke;
ot->exec = grease_pencil_layer_add_exec;
ot->poll = active_grease_pencil_poll;
ot->poll = grease_pencil_context_poll;
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@@ -102,8 +107,7 @@ static void GREASE_PENCIL_OT_layer_add(wmOperatorType *ot)
static int grease_pencil_layer_remove_exec(bContext *C, wmOperator * /*op*/)
{
using namespace blender::bke::greasepencil;
Object *object = CTX_data_active_object(C);
GreasePencil &grease_pencil = *static_cast<GreasePencil *>(object->data);
GreasePencil &grease_pencil = *blender::ed::greasepencil::from_context(*C);
if (!grease_pencil.has_active_layer()) {
return OPERATOR_CANCELLED;
@@ -193,7 +197,7 @@ static void GREASE_PENCIL_OT_layer_reorder(wmOperatorType *ot)
/* callbacks */
ot->exec = grease_pencil_layer_reorder_exec;
ot->poll = active_grease_pencil_poll;
ot->poll = grease_pencil_context_poll;
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@@ -220,12 +224,11 @@ static const EnumPropertyItem enum_layer_move_direction[] = {
static bool grease_pencil_layer_move_poll(bContext *C)
{
using namespace blender::bke::greasepencil;
if (!active_grease_pencil_poll(C)) {
if (!grease_pencil_context_poll(C)) {
return false;
}
Object *object = CTX_data_active_object(C);
GreasePencil &grease_pencil = *static_cast<GreasePencil *>(object->data);
GreasePencil &grease_pencil = *blender::ed::greasepencil::from_context(*C);
const TreeNode *active_node = grease_pencil.get_active_node();
if (active_node == nullptr) {
@@ -244,8 +247,7 @@ static bool grease_pencil_layer_move_poll(bContext *C)
static int grease_pencil_layer_move_exec(bContext *C, wmOperator *op)
{
using namespace blender::bke::greasepencil;
Object *object = CTX_data_active_object(C);
GreasePencil &grease_pencil = *static_cast<GreasePencil *>(object->data);
GreasePencil &grease_pencil = *blender::ed::greasepencil::from_context(*C);
const LayerMoveDirection direction = LayerMoveDirection(RNA_enum_get(op->ptr, "direction"));
@@ -319,8 +321,7 @@ static void GREASE_PENCIL_OT_layer_active(wmOperatorType *ot)
static int grease_pencil_layer_group_add_exec(bContext *C, wmOperator *op)
{
using namespace blender::bke::greasepencil;
Object *object = CTX_data_active_object(C);
GreasePencil &grease_pencil = *static_cast<GreasePencil *>(object->data);
GreasePencil &grease_pencil = *blender::ed::greasepencil::from_context(*C);
int new_layer_group_name_length;
char *new_layer_group_name = RNA_string_get_alloc(
@@ -358,7 +359,7 @@ static void GREASE_PENCIL_OT_layer_group_add(wmOperatorType *ot)
/* callbacks */
ot->exec = grease_pencil_layer_group_add_exec;
ot->poll = active_grease_pencil_poll;
ot->poll = grease_pencil_context_poll;
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@@ -396,7 +397,7 @@ static void GREASE_PENCIL_OT_layer_group_remove(wmOperatorType *ot)
/* callbacks */
ot->exec = grease_pencil_layer_group_remove_exec;
ot->poll = active_grease_pencil_poll;
ot->poll = grease_pencil_context_poll;
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@@ -410,8 +411,7 @@ static void GREASE_PENCIL_OT_layer_group_remove(wmOperatorType *ot)
static int grease_pencil_layer_hide_exec(bContext *C, wmOperator *op)
{
using namespace blender::bke::greasepencil;
Object *object = CTX_data_active_object(C);
GreasePencil &grease_pencil = *static_cast<GreasePencil *>(object->data);
GreasePencil &grease_pencil = *blender::ed::greasepencil::from_context(*C);
const bool unselected = RNA_boolean_get(op->ptr, "unselected");
if (!grease_pencil.has_active_layer()) {
@@ -448,7 +448,7 @@ static void GREASE_PENCIL_OT_layer_hide(wmOperatorType *ot)
/* callbacks */
ot->exec = grease_pencil_layer_hide_exec;
ot->poll = active_grease_pencil_poll;
ot->poll = grease_pencil_context_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@@ -463,8 +463,7 @@ static void GREASE_PENCIL_OT_layer_hide(wmOperatorType *ot)
static int grease_pencil_layer_reveal_exec(bContext *C, wmOperator * /*op*/)
{
using namespace blender::bke::greasepencil;
Object *object = CTX_data_active_object(C);
GreasePencil &grease_pencil = *static_cast<GreasePencil *>(object->data);
GreasePencil &grease_pencil = *blender::ed::greasepencil::from_context(*C);
if (!grease_pencil.has_active_layer()) {
return OPERATOR_CANCELLED;
@@ -491,7 +490,7 @@ static void GREASE_PENCIL_OT_layer_reveal(wmOperatorType *ot)
/* callbacks */
ot->exec = grease_pencil_layer_reveal_exec;
ot->poll = active_grease_pencil_poll;
ot->poll = grease_pencil_context_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@@ -500,8 +499,7 @@ static void GREASE_PENCIL_OT_layer_reveal(wmOperatorType *ot)
static int grease_pencil_layer_isolate_exec(bContext *C, wmOperator *op)
{
using namespace blender::bke::greasepencil;
Object *object = CTX_data_active_object(C);
GreasePencil &grease_pencil = *static_cast<GreasePencil *>(object->data);
GreasePencil &grease_pencil = *blender::ed::greasepencil::from_context(*C);
const int affect_visibility = RNA_boolean_get(op->ptr, "affect_visibility");
bool isolate = false;
@@ -559,8 +557,7 @@ static void GREASE_PENCIL_OT_layer_isolate(wmOperatorType *ot)
static int grease_pencil_layer_lock_all_exec(bContext *C, wmOperator *op)
{
using namespace blender::bke::greasepencil;
Object *object = CTX_data_active_object(C);
GreasePencil &grease_pencil = *static_cast<GreasePencil *>(object->data);
GreasePencil &grease_pencil = *blender::ed::greasepencil::from_context(*C);
const bool lock_value = RNA_boolean_get(op->ptr, "lock");
if (grease_pencil.layers().is_empty()) {
@@ -600,8 +597,7 @@ static void GREASE_PENCIL_OT_layer_lock_all(wmOperatorType *ot)
static int grease_pencil_layer_duplicate_exec(bContext *C, wmOperator *op)
{
using namespace blender::bke::greasepencil;
Object *object = CTX_data_active_object(C);
GreasePencil &grease_pencil = *static_cast<GreasePencil *>(object->data);
GreasePencil &grease_pencil = *blender::ed::greasepencil::from_context(*C);
const bool empty_keyframes = RNA_boolean_get(op->ptr, "empty_keyframes");
if (!grease_pencil.has_active_layer()) {
@@ -807,8 +803,7 @@ static void GREASE_PENCIL_OT_layer_merge(wmOperatorType *ot)
static int grease_pencil_layer_mask_add_exec(bContext *C, wmOperator *op)
{
using namespace blender::bke::greasepencil;
Object *object = CTX_data_active_object(C);
GreasePencil &grease_pencil = *static_cast<GreasePencil *>(object->data);
GreasePencil &grease_pencil = *blender::ed::greasepencil::from_context(*C);
if (!grease_pencil.has_active_layer()) {
return OPERATOR_CANCELLED;
@@ -869,8 +864,7 @@ static void GREASE_PENCIL_OT_layer_mask_add(wmOperatorType *ot)
static int grease_pencil_layer_mask_remove_exec(bContext *C, wmOperator * /*op*/)
{
using namespace blender::bke::greasepencil;
Object *object = CTX_data_active_object(C);
GreasePencil &grease_pencil = *static_cast<GreasePencil *>(object->data);
GreasePencil &grease_pencil = *blender::ed::greasepencil::from_context(*C);
if (!grease_pencil.has_active_layer()) {
return OPERATOR_CANCELLED;
@@ -911,8 +905,7 @@ static void GREASE_PENCIL_OT_layer_mask_remove(wmOperatorType *ot)
static int grease_pencil_layer_mask_reorder_exec(bContext *C, wmOperator *op)
{
using namespace blender::bke::greasepencil;
Object *object = CTX_data_active_object(C);
GreasePencil &grease_pencil = *static_cast<GreasePencil *>(object->data);
GreasePencil &grease_pencil = *blender::ed::greasepencil::from_context(*C);
if (!grease_pencil.has_active_layer()) {
return OPERATOR_CANCELLED;
@@ -974,8 +967,7 @@ const EnumPropertyItem enum_layergroup_color_items[] = {
static int grease_pencil_layer_group_color_tag_exec(bContext *C, wmOperator *op)
{
using namespace blender::bke::greasepencil;
Object *object = CTX_data_active_object(C);
GreasePencil &grease_pencil = *static_cast<GreasePencil *>(object->data);
GreasePencil &grease_pencil = *blender::ed::greasepencil::from_context(*C);
const int color_tag = RNA_enum_get(op->ptr, "color_tag");
LayerGroup *active_group = grease_pencil.get_active_group();
@@ -995,7 +987,7 @@ static void GREASE_PENCIL_OT_layer_group_color_tag(wmOperatorType *ot)
ot->description = "Change layer group icon";
ot->exec = grease_pencil_layer_group_color_tag_exec;
ot->poll = active_grease_pencil_poll;
ot->poll = grease_pencil_context_poll;
ot->flag = OPTYPE_UNDO;

View File

@@ -58,12 +58,8 @@ bool editable_grease_pencil_poll(bContext *C)
bool active_grease_pencil_layer_poll(bContext *C)
{
Object *object = CTX_data_active_object(C);
if (object == nullptr || object->type != OB_GREASE_PENCIL) {
return false;
}
const GreasePencil *grease_pencil = static_cast<GreasePencil *>(object->data);
return grease_pencil->has_active_layer();
const GreasePencil *grease_pencil = blender::ed::greasepencil::from_context(*C);
return grease_pencil && grease_pencil->has_active_layer();
}
bool editable_grease_pencil_point_selection_poll(bContext *C)
@@ -111,7 +107,7 @@ bool grease_pencil_painting_poll(bContext *C)
return true;
}
static bool grease_pencil_edit_poll(bContext *C)
bool grease_pencil_edit_poll(bContext *C)
{
if (!active_grease_pencil_poll(C)) {
return false;

View File

@@ -420,7 +420,7 @@ void ED_undosys_type_grease_pencil(UndoType *ut)
using namespace blender::ed;
ut->name = "Edit GreasePencil";
ut->poll = greasepencil::editable_grease_pencil_poll;
ut->poll = greasepencil::grease_pencil_edit_poll;
ut->step_encode = greasepencil::undo::step_encode;
ut->step_decode = greasepencil::undo::step_decode;
ut->step_free = greasepencil::undo::step_free;

View File

@@ -27,6 +27,8 @@
#include "DNA_scene_types.h"
#include "DNA_view3d_types.h"
#include "RNA_prototypes.hh"
#include "ED_curves.hh"
#include "ED_grease_pencil.hh"
#include "ED_view3d.hh"
@@ -1580,4 +1582,18 @@ float4x2 calculate_texture_space(const Scene *scene,
float4(v_dir, -math::dot(v_dir, origin))));
}
GreasePencil *from_context(bContext &C)
{
GreasePencil *grease_pencil = static_cast<GreasePencil *>(
CTX_data_pointer_get_type(&C, "grease_pencil", &RNA_GreasePencilv3).data);
if (grease_pencil == nullptr) {
Object *object = CTX_data_active_object(&C);
if (object && object->type == OB_GREASE_PENCIL) {
grease_pencil = static_cast<GreasePencil *>(object->data);
}
}
return grease_pencil;
}
} // namespace blender::ed::greasepencil

View File

@@ -292,6 +292,7 @@ bool active_grease_pencil_layer_poll(bContext *C);
bool editable_grease_pencil_point_selection_poll(bContext *C);
bool grease_pencil_selection_poll(bContext *C);
bool grease_pencil_painting_poll(bContext *C);
bool grease_pencil_edit_poll(bContext *C);
bool grease_pencil_sculpting_poll(bContext *C);
bool grease_pencil_weight_painting_poll(bContext *C);
bool grease_pencil_vertex_painting_poll(bContext *C);
@@ -886,4 +887,5 @@ void set_lineart_modifier_limits(GreasePencilLineartModifierData &lmd,
GreasePencilLineartModifierData *get_first_lineart_modifier(const Object &ob);
GreasePencil *from_context(bContext &C);
} // namespace blender::ed::greasepencil

View File

@@ -488,7 +488,8 @@ bool modifier_apply(Main *bmain,
Object *ob,
ModifierData *md,
int mode,
bool keep_modifier);
bool keep_modifier,
bool do_all_keyframes);
bool modifier_copy(ReportList *reports, Main *bmain, Scene *scene, Object *ob, ModifierData *md);
void modifier_link(bContext *C, Object *ob_dst, Object *ob_src);
bool modifier_copy_to_object(Main *bmain,

View File

@@ -19,6 +19,7 @@
#include "RNA_access.hh"
#include "RNA_prototypes.hh"
#include "ED_grease_pencil.hh"
#include "ED_undo.hh"
#include "WM_api.hh"
@@ -460,18 +461,18 @@ void uiTemplateGreasePencilLayerTree(uiLayout *layout, bContext *C)
{
using namespace blender;
Object *object = CTX_data_active_object(C);
if (!object || object->type != OB_GREASE_PENCIL) {
GreasePencil *grease_pencil = blender::ed::greasepencil::from_context(*C);
if (grease_pencil == nullptr) {
return;
}
GreasePencil &grease_pencil = *static_cast<GreasePencil *>(object->data);
uiBlock *block = uiLayoutGetBlock(layout);
ui::AbstractTreeView *tree_view = UI_block_add_view(
*block,
"Grease Pencil Layer Tree View",
std::make_unique<blender::ui::greasepencil::LayerTreeView>(grease_pencil));
std::make_unique<blender::ui::greasepencil::LayerTreeView>(*grease_pencil));
tree_view->set_context_menu_title("Grease Pencil Layer");
tree_view->set_default_rows(6);

View File

@@ -987,72 +987,51 @@ static void remove_invalid_attribute_strings(Mesh &mesh)
}
}
static bool apply_grease_pencil_for_modifier(Depsgraph *depsgraph,
Object *ob,
Object *ob_eval,
GreasePencil &grease_pencil_orig,
ModifierData *md_eval,
ReportList *reports)
static void apply_eval_grease_pencil_data(const GreasePencil &src_grease_pencil,
const int eval_frame,
const IndexMask &orig_layers_to_apply,
GreasePencil &orig_grease_pencil)
{
using namespace bke;
using namespace bke::greasepencil;
const ModifierTypeInfo *mti = BKE_modifier_get_info(ModifierType(md_eval->type));
GreasePencil *grease_pencil_for_eval = ob_eval->runtime->data_orig ?
reinterpret_cast<GreasePencil *>(
ob_eval->runtime->data_orig) :
&grease_pencil_orig;
const int eval_frame = int(DEG_get_ctime(depsgraph));
GreasePencil *grease_pencil_temp = reinterpret_cast<GreasePencil *>(
BKE_id_copy_ex(nullptr, &grease_pencil_for_eval->id, nullptr, LIB_ID_COPY_LOCALIZE));
grease_pencil_temp->runtime->eval_frame = eval_frame;
GeometrySet eval_geometry_set = GeometrySet::from_grease_pencil(grease_pencil_temp,
GeometryOwnershipType::Owned);
ModifierEvalContext mectx = {depsgraph, ob_eval, MOD_APPLY_TO_ORIGINAL};
mti->modify_geometry_set(md_eval, &mectx, &eval_geometry_set);
if (!eval_geometry_set.has_grease_pencil()) {
BKE_report(reports,
RPT_ERROR,
"Evaluated geometry from modifier does not contain grease pencil geometry");
return false;
}
GreasePencil &grease_pencil_result =
*eval_geometry_set.get_component_for_write<GreasePencilComponent>().get_for_write();
/* Anonymous attributes shouldn't be available on original geometry. */
grease_pencil_result.attributes_for_write().remove_anonymous();
/* Ensure that the layer names are unique by merging layers with the same name. */
const int old_layers_num = grease_pencil_result.layers().size();
const int old_layers_num = src_grease_pencil.layers().size();
Vector<Vector<int>> layers_map;
Map<StringRef, int> new_layer_index_by_name;
for (const int layer_i : IndexRange(old_layers_num)) {
const Layer &layer = grease_pencil_result.layer(layer_i);
const Layer &layer = src_grease_pencil.layer(layer_i);
const int new_layer_index = new_layer_index_by_name.lookup_or_add_cb(
layer.name(), [&]() { return layers_map.append_and_get_index_as(); });
layers_map[new_layer_index].append(layer_i);
}
if (GreasePencil *merged_layers_grease_pencil = geometry::merge_layers(
grease_pencil_result, layers_map, {}))
{
grease_pencil_result = std::move(*merged_layers_grease_pencil);
}
GreasePencil &merged_layers_grease_pencil = *geometry::merge_layers(
src_grease_pencil, layers_map, {});
Map<const Layer *, const Layer *> eval_to_orig_layer_map;
{
Set<Layer *> mapped_original_layers;
TreeNode *previous_node = nullptr;
const Span<const Layer *> result_layers = grease_pencil_result.layers();
const Span<const Layer *> result_layers = merged_layers_grease_pencil.layers();
for (const Layer *layer_eval : result_layers) {
/* Check if the original geometry has a layer with the same name. */
TreeNode *node_orig = grease_pencil_orig.find_node_by_name(layer_eval->name());
TreeNode *node_orig = orig_grease_pencil.find_node_by_name(layer_eval->name());
if (!node_orig || node_orig->is_group()) {
/* No layer with the same name found. Create a new layer. */
Layer &layer_orig = grease_pencil_orig.add_layer(layer_eval->name());
/* No layer with the same name found. Create a new layer.
* Note: This name might be empty! This has to be resolved at a later stage! */
Layer &layer_orig = orig_grease_pencil.add_layer(layer_eval->name(), false);
/* Make sure to add a new keyframe with a new drawing. */
grease_pencil_orig.insert_frame(layer_orig, eval_frame);
orig_grease_pencil.insert_frame(layer_orig, eval_frame);
node_orig = &layer_orig.as_node();
}
else if (node_orig->is_layer()) {
const int orig_layer_index = *orig_grease_pencil.get_layer_index(node_orig->as_layer());
if (!orig_layers_to_apply.contains(orig_layer_index)) {
/* Mark as mapped so it won't be removed. */
mapped_original_layers.add_new(&node_orig->as_layer());
continue;
}
}
BLI_assert(node_orig != nullptr);
Layer &layer_orig = node_orig->as_layer();
layer_orig.opacity = layer_eval->opacity;
@@ -1061,7 +1040,7 @@ static bool apply_grease_pencil_for_modifier(Depsgraph *depsgraph,
/* Insert the updated node after the previous node. This keeps the layer order consistent. */
if (previous_node) {
BLI_assert(node_orig != nullptr);
grease_pencil_orig.move_node_after(*node_orig, *previous_node);
orig_grease_pencil.move_node_after(*node_orig, *previous_node);
}
previous_node = node_orig;
@@ -1070,13 +1049,18 @@ static bool apply_grease_pencil_for_modifier(Depsgraph *depsgraph,
mapped_original_layers.add_new(&layer_orig);
}
/* Remove all the unmapped layers from the original geometry. */
/* IMPORTANT: We copy the span of pointers into a local array here, because the runtime cache
* of the layers actually changes while we remove the layers. */
const Array<Layer *> original_layers = grease_pencil_orig.layers_for_write();
for (Layer *layer_orig : original_layers) {
/* Clear keyframes of unmapped layers. */
for (Layer *layer_orig : orig_grease_pencil.layers_for_write()) {
if (!mapped_original_layers.contains(layer_orig)) {
grease_pencil_orig.remove_layer(*layer_orig);
/* Try inserting a frame. */
Drawing *drawing_orig = orig_grease_pencil.insert_frame(*layer_orig, eval_frame);
if (drawing_orig == nullptr) {
/* If that fails, get the drawing for this frame. */
drawing_orig = orig_grease_pencil.get_drawing_at(*layer_orig, eval_frame);
}
/* Clear the existing drawing. */
drawing_orig->strokes_for_write() = {};
drawing_orig->tag_topology_changed();
}
}
}
@@ -1084,15 +1068,14 @@ static bool apply_grease_pencil_for_modifier(Depsgraph *depsgraph,
/* Update the drawings. */
VectorSet<Drawing *> all_updated_drawings;
for (auto [layer_eval, layer_orig] : eval_to_orig_layer_map.items()) {
Drawing *drawing_eval = grease_pencil_result.get_drawing_at(*layer_eval, eval_frame);
if (drawing_eval) {
/* Anonymous attributes shouldn't be available on original geometry. */
drawing_eval->strokes_for_write().attributes_for_write().remove_anonymous();
}
Drawing *drawing_orig = grease_pencil_orig.get_drawing_at(*layer_orig, eval_frame);
const Drawing *drawing_eval = merged_layers_grease_pencil.get_drawing_at(*layer_eval,
eval_frame);
Drawing *drawing_orig = orig_grease_pencil.get_drawing_at(*layer_orig, eval_frame);
if (drawing_orig && drawing_eval) {
/* Write the data to the original drawing. */
drawing_orig->strokes_for_write() = std::move(drawing_eval->strokes_for_write());
drawing_orig->strokes_for_write() = std::move(drawing_eval->strokes());
/* Anonymous attributes shouldn't be available on original geometry. */
drawing_orig->strokes_for_write().attributes_for_write().remove_anonymous();
drawing_orig->tag_topology_changed();
all_updated_drawings.add_new(drawing_orig);
}
@@ -1100,8 +1083,8 @@ static bool apply_grease_pencil_for_modifier(Depsgraph *depsgraph,
/* Get the original material pointers from the result geometry. */
VectorSet<Material *> original_materials;
const Span<Material *> eval_materials = Span{grease_pencil_result.material_array,
grease_pencil_result.material_array_num};
const Span<Material *> eval_materials = Span{merged_layers_grease_pencil.material_array,
merged_layers_grease_pencil.material_array_num};
for (Material *eval_material : eval_materials) {
if (eval_material != nullptr && eval_material->id.orig_id != nullptr) {
original_materials.add_new(reinterpret_cast<Material *>(eval_material->id.orig_id));
@@ -1113,9 +1096,9 @@ static bool apply_grease_pencil_for_modifier(Depsgraph *depsgraph,
* result geometry are already correct, but this might not be the case for all drawings in the
* original geometry (like for drawings that are not visible on the frame that the modifier is
* being applied on). */
Array<int> material_indices_map(grease_pencil_orig.material_array_num);
for (const int mat_i : IndexRange(grease_pencil_orig.material_array_num)) {
Material *material = grease_pencil_orig.material_array[mat_i];
Array<int> material_indices_map(orig_grease_pencil.material_array_num);
for (const int mat_i : IndexRange(orig_grease_pencil.material_array_num)) {
Material *material = orig_grease_pencil.material_array[mat_i];
const int map_index = original_materials.index_of_try(material);
if (map_index != -1) {
material_indices_map[mat_i] = map_index;
@@ -1125,9 +1108,9 @@ static bool apply_grease_pencil_for_modifier(Depsgraph *depsgraph,
/* Remap material indices for all other drawings. */
if (!material_indices_map.is_empty() &&
!array_utils::indices_are_range(material_indices_map,
IndexRange(grease_pencil_orig.material_array_num)))
IndexRange(orig_grease_pencil.material_array_num)))
{
for (GreasePencilDrawingBase *base : grease_pencil_orig.drawings()) {
for (GreasePencilDrawingBase *base : orig_grease_pencil.drawings()) {
if (base->type != GP_DRAWING) {
continue;
}
@@ -1152,18 +1135,24 @@ static bool apply_grease_pencil_for_modifier(Depsgraph *depsgraph,
}
/* Convert the layer map into an index mapping. */
Array<int> eval_to_orig_layer_indices_map(grease_pencil_result.layers().size());
for (const int layer_eval_i : grease_pencil_result.layers().index_range()) {
const Layer *layer_eval = &grease_pencil_result.layer(layer_eval_i);
const Layer *layer_orig = eval_to_orig_layer_map.lookup(layer_eval);
const int layer_orig_index = *grease_pencil_orig.get_layer_index(*layer_orig);
eval_to_orig_layer_indices_map[layer_eval_i] = layer_orig_index;
Map<int, int> eval_to_orig_layer_indices_map;
for (const int layer_eval_i : merged_layers_grease_pencil.layers().index_range()) {
const Layer *layer_eval = &merged_layers_grease_pencil.layer(layer_eval_i);
if (eval_to_orig_layer_map.contains(layer_eval)) {
const Layer *layer_orig = eval_to_orig_layer_map.lookup(layer_eval);
const int layer_orig_index = *orig_grease_pencil.get_layer_index(*layer_orig);
eval_to_orig_layer_indices_map.add(layer_eval_i, layer_orig_index);
}
}
/* Propagate layer attributes. */
AttributeAccessor src_attributes = grease_pencil_result.attributes();
MutableAttributeAccessor dst_attributes = grease_pencil_orig.attributes_for_write();
AttributeAccessor src_attributes = merged_layers_grease_pencil.attributes();
MutableAttributeAccessor dst_attributes = orig_grease_pencil.attributes_for_write();
src_attributes.foreach_attribute([&](const bke::AttributeIter &iter) {
/* Anonymous attributes shouldn't be available on original geometry. */
if (attribute_name_is_anonymous(iter.name)) {
return;
}
if (iter.data_type == CD_PROP_STRING) {
return;
}
@@ -1175,19 +1164,153 @@ static bool apply_grease_pencil_for_modifier(Depsgraph *depsgraph,
}
attribute_math::convert_to_static_type(src.type(), [&](auto dummy) {
using T = decltype(dummy);
array_utils::scatter(
src.typed<T>(), eval_to_orig_layer_indices_map.as_span(), dst.span.typed<T>());
Span<T> src_span = src.typed<T>();
MutableSpan<T> dst_span = dst.span.typed<T>();
for (const auto [src_i, dst_i] : eval_to_orig_layer_indices_map.items()) {
dst_span[dst_i] = src_span[src_i];
}
});
dst.finish();
});
/* Free temporary grease pencil struct. */
BKE_id_free(nullptr, &merged_layers_grease_pencil);
}
static bool apply_grease_pencil_for_modifier(Depsgraph *depsgraph,
Object *ob,
GreasePencil &grease_pencil_orig,
ModifierData *md_eval)
{
using namespace bke;
using namespace bke::greasepencil;
const ModifierTypeInfo *mti = BKE_modifier_get_info(ModifierType(md_eval->type));
Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob);
GreasePencil *grease_pencil_for_eval = ob_eval->runtime->data_orig ?
reinterpret_cast<GreasePencil *>(
ob_eval->runtime->data_orig) :
&grease_pencil_orig;
const int eval_frame = int(DEG_get_ctime(depsgraph));
GreasePencil *grease_pencil_temp = reinterpret_cast<GreasePencil *>(
BKE_id_copy_ex(nullptr, &grease_pencil_for_eval->id, nullptr, LIB_ID_COPY_LOCALIZE));
grease_pencil_temp->runtime->eval_frame = eval_frame;
GeometrySet eval_geometry_set = GeometrySet::from_grease_pencil(grease_pencil_temp,
GeometryOwnershipType::Owned);
ModifierEvalContext mectx = {depsgraph, ob_eval, MOD_APPLY_TO_ORIGINAL};
mti->modify_geometry_set(md_eval, &mectx, &eval_geometry_set);
if (!eval_geometry_set.has_grease_pencil()) {
return false;
}
GreasePencil &grease_pencil_result =
*eval_geometry_set.get_component_for_write<GreasePencilComponent>().get_for_write();
apply_eval_grease_pencil_data(grease_pencil_result,
eval_frame,
grease_pencil_orig.layers().index_range(),
grease_pencil_orig);
Main *bmain = DEG_get_bmain(depsgraph);
/* There might be layers with empty names after evaluation. Make sure to rename them. */
for (Layer *layer : grease_pencil_orig.layers_for_write()) {
if (layer->name().is_empty()) {
grease_pencil_orig.rename_node(*bmain, layer->as_node(), DATA_("Layer"));
}
}
BKE_object_material_from_eval_data(bmain, ob, &grease_pencil_result.id);
return true;
}
static bool modifier_apply_obdata(
ReportList *reports, Depsgraph *depsgraph, Scene *scene, Object *ob, ModifierData *md_eval)
static bool apply_grease_pencil_for_modifier_all_keyframes(Depsgraph *depsgraph,
Scene *scene,
Object *ob,
GreasePencil &grease_pencil_orig,
ModifierData *md_eval)
{
using namespace bke;
using namespace bke::greasepencil;
Main *bmain = DEG_get_bmain(depsgraph);
const ModifierTypeInfo *mti = BKE_modifier_get_info(ModifierType(md_eval->type));
WM_cursor_wait(true);
Map<int, Vector<int>> layer_indices_to_apply_per_frame;
{
for (const int layer_i : grease_pencil_orig.layers().index_range()) {
const Layer &layer = grease_pencil_orig.layer(layer_i);
for (const auto &[key, value] : layer.frames().items()) {
if (value.is_end()) {
continue;
}
layer_indices_to_apply_per_frame.lookup_or_add(key, {}).append(layer_i);
}
}
}
Array<int> sorted_frame_times(layer_indices_to_apply_per_frame.size());
int i = 0;
for (const int key : layer_indices_to_apply_per_frame.keys()) {
sorted_frame_times[i++] = key;
}
std::sort(sorted_frame_times.begin(), sorted_frame_times.end());
const int prev_frame = int(DEG_get_ctime(depsgraph));
bool changed = false;
for (const int eval_frame : sorted_frame_times) {
const Span<int> layer_indices = layer_indices_to_apply_per_frame.lookup(eval_frame).as_span();
scene->r.cfra = eval_frame;
BKE_scene_graph_update_for_newframe(depsgraph);
Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob);
GreasePencil *grease_pencil_for_eval = ob_eval->runtime->data_orig ?
reinterpret_cast<GreasePencil *>(
ob_eval->runtime->data_orig) :
&grease_pencil_orig;
GreasePencil *grease_pencil_temp = reinterpret_cast<GreasePencil *>(
BKE_id_copy_ex(nullptr, &grease_pencil_for_eval->id, nullptr, LIB_ID_COPY_LOCALIZE));
grease_pencil_temp->runtime->eval_frame = eval_frame;
GeometrySet eval_geometry_set = GeometrySet::from_grease_pencil(grease_pencil_temp,
GeometryOwnershipType::Owned);
ModifierEvalContext mectx = {depsgraph, ob_eval, MOD_APPLY_TO_ORIGINAL};
mti->modify_geometry_set(md_eval, &mectx, &eval_geometry_set);
if (!eval_geometry_set.has_grease_pencil()) {
continue;
}
GreasePencil &grease_pencil_result =
*eval_geometry_set.get_component_for_write<GreasePencilComponent>().get_for_write();
IndexMaskMemory memory;
const IndexMask orig_layers_to_apply = IndexMask::from_indices(layer_indices, memory);
apply_eval_grease_pencil_data(
grease_pencil_result, eval_frame, orig_layers_to_apply, grease_pencil_orig);
BKE_object_material_from_eval_data(bmain, ob, &grease_pencil_result.id);
changed = true;
}
scene->r.cfra = prev_frame;
BKE_scene_graph_update_for_newframe(depsgraph);
/* There might be layers with empty names after evaluation. Make sure to rename them. */
for (Layer *layer : grease_pencil_orig.layers_for_write()) {
if (layer->name().is_empty()) {
grease_pencil_orig.rename_node(*bmain, layer->as_node(), DATA_("Layer"));
}
}
WM_cursor_wait(false);
return changed;
}
static bool modifier_apply_obdata(ReportList *reports,
Depsgraph *depsgraph,
Scene *scene,
Object *ob,
ModifierData *md_eval,
const bool do_all_keyframes)
{
const ModifierTypeInfo *mti = BKE_modifier_get_info((ModifierType)md_eval->type);
@@ -1351,11 +1474,19 @@ static bool modifier_apply_obdata(
BKE_report(reports, RPT_ERROR, "Cannot apply this modifier to grease pencil geometry");
return false;
}
Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob);
GreasePencil &grease_pencil_orig = *static_cast<GreasePencil *>(ob->data);
if (!apply_grease_pencil_for_modifier(
depsgraph, ob, ob_eval, grease_pencil_orig, md_eval, reports))
{
bool success = false;
if (do_all_keyframes) {
success = apply_grease_pencil_for_modifier_all_keyframes(
depsgraph, scene, ob, grease_pencil_orig, md_eval);
}
else {
success = apply_grease_pencil_for_modifier(depsgraph, ob, grease_pencil_orig, md_eval);
}
if (!success) {
BKE_report(reports,
RPT_ERROR,
"Evaluated geometry from modifier does not contain grease pencil geometry");
return false;
}
}
@@ -1386,7 +1517,8 @@ bool modifier_apply(Main *bmain,
Object *ob,
ModifierData *md,
int mode,
bool keep_modifier)
bool keep_modifier,
const bool do_all_keyframes)
{
if (BKE_object_is_in_editmode(ob)) {
BKE_report(reports, RPT_ERROR, "Modifiers cannot be applied in edit mode");
@@ -1449,7 +1581,8 @@ bool modifier_apply(Main *bmain,
did_apply = modifier_apply_shape(bmain, reports, apply_depsgraph, scene, ob, md_eval);
}
else {
did_apply = modifier_apply_obdata(reports, apply_depsgraph, scene, ob, md_eval);
did_apply = modifier_apply_obdata(
reports, apply_depsgraph, scene, ob, md_eval, do_all_keyframes);
}
if (did_apply) {
@@ -2108,6 +2241,9 @@ static int modifier_apply_exec_ex(bContext *C, wmOperator *op, int apply_as, boo
const bool do_merge_customdata = (apply_as == MODIFIER_APPLY_DATA) ?
RNA_boolean_get(op->ptr, "merge_customdata") :
false;
const bool do_all_keyframes = (apply_as == MODIFIER_APPLY_DATA) ?
RNA_boolean_get(op->ptr, "all_keyframes") :
false;
bool changed = false;
for (const PointerRNA &ptr : objects) {
@@ -2126,7 +2262,16 @@ static int modifier_apply_exec_ex(bContext *C, wmOperator *op, int apply_as, boo
DEG_relations_tag_update(bmain);
}
if (!modifier_apply(bmain, op->reports, depsgraph, scene, ob, md, apply_as, keep_modifier)) {
if (!modifier_apply(bmain,
op->reports,
depsgraph,
scene,
ob,
md,
apply_as,
keep_modifier,
do_all_keyframes))
{
continue;
}
changed = true;
@@ -2192,6 +2337,8 @@ static int modifier_apply_invoke(bContext *C, wmOperator *op, const wmEvent *eve
void OBJECT_OT_modifier_apply(wmOperatorType *ot)
{
PropertyRNA *prop;
ot->name = "Apply Modifier";
ot->description = "Apply modifier and remove from the stack";
ot->idname = "OBJECT_OT_modifier_apply";
@@ -2212,11 +2359,17 @@ void OBJECT_OT_modifier_apply(wmOperatorType *ot)
"Merge UVs",
"For mesh objects, merge UV coordinates that share a vertex to account for "
"imprecision in some modifiers");
PropertyRNA *prop = RNA_def_boolean(ot->srna,
"single_user",
false,
"Make Data Single User",
"Make the object's data single user if needed");
prop = RNA_def_boolean(ot->srna,
"single_user",
false,
"Make Data Single User",
"Make the object's data single user if needed");
RNA_def_property_flag(prop, (PropertyFlag)(PROP_HIDDEN | PROP_SKIP_SAVE));
prop = RNA_def_boolean(ot->srna,
"all_keyframes",
false,
"Apply to all keyframes",
"For Grease Pencil objects, apply the modifier to all the keyframes");
RNA_def_property_flag(prop, (PropertyFlag)(PROP_HIDDEN | PROP_SKIP_SAVE));
modifier_register_use_selected_objects_prop(ot);
}

View File

@@ -2310,7 +2310,7 @@ static void modifier_fn(int event, TreeElement *te, TreeStoreElem * /*tselem*/,
}
else if (event == OL_MODIFIER_OP_APPLY) {
object::modifier_apply(
bmain, data->reports, depsgraph, scene, ob, md, object::MODIFIER_APPLY_DATA, false);
bmain, data->reports, depsgraph, scene, ob, md, object::MODIFIER_APPLY_DATA, false, false);
DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
DEG_relations_tag_update(bmain);
WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob);

View File

@@ -698,4 +698,219 @@ TEST(vk_render_graph, begin_draw_copy_framebuffer_draw_end)
EXPECT_EQ("end_rendering()", log[10]);
}
/**
* Update buffers can be moved to before the rendering scope as when the destination buffer isn't
* used.
*/
TEST(vk_render_graph, begin_update_draw_update_draw_update_draw_end)
{
VkHandle<VkBuffer> buffer_a(1u);
VkHandle<VkBuffer> buffer_b(2u);
VkHandle<VkImage> image(3u);
VkHandle<VkImageView> image_view(4u);
VkHandle<VkPipelineLayout> pipeline_layout(5u);
VkHandle<VkPipeline> pipeline(6u);
Vector<std::string> log;
VKResourceStateTracker resources;
VKRenderGraph render_graph(std::make_unique<CommandBufferLog>(log), resources);
resources.add_image(image, 1, VK_IMAGE_LAYOUT_UNDEFINED, ResourceOwner::APPLICATION);
resources.add_buffer(buffer_a);
resources.add_buffer(buffer_b);
{
VKResourceAccessInfo access_info = {};
access_info.images.append(
{image, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_IMAGE_ASPECT_COLOR_BIT, 0});
VKBeginRenderingNode::CreateInfo begin_rendering(access_info);
begin_rendering.node_data.color_attachments[0].sType =
VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO_KHR;
begin_rendering.node_data.color_attachments[0].imageLayout =
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
begin_rendering.node_data.color_attachments[0].imageView = image_view;
begin_rendering.node_data.color_attachments[0].loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
begin_rendering.node_data.color_attachments[0].storeOp = VK_ATTACHMENT_STORE_OP_STORE;
begin_rendering.node_data.vk_rendering_info.sType = VK_STRUCTURE_TYPE_RENDERING_INFO;
begin_rendering.node_data.vk_rendering_info.colorAttachmentCount = 1;
begin_rendering.node_data.vk_rendering_info.layerCount = 1;
begin_rendering.node_data.vk_rendering_info.pColorAttachments =
begin_rendering.node_data.color_attachments;
render_graph.add_node(begin_rendering);
}
{
VKUpdateBufferNode::CreateInfo update_buffer = {};
update_buffer.dst_buffer = buffer_a;
update_buffer.data_size = 16;
update_buffer.data = MEM_callocN(16, __func__);
render_graph.add_node(update_buffer);
}
{
VKResourceAccessInfo access_info = {};
access_info.buffers.append({buffer_a, VK_ACCESS_UNIFORM_READ_BIT});
VKDrawNode::CreateInfo draw(access_info);
draw.node_data.first_instance = 0;
draw.node_data.first_vertex = 0;
draw.node_data.instance_count = 1;
draw.node_data.vertex_count = 1;
draw.node_data.pipeline_data.push_constants_data = nullptr;
draw.node_data.pipeline_data.push_constants_size = 0;
draw.node_data.pipeline_data.vk_descriptor_set = VK_NULL_HANDLE;
draw.node_data.pipeline_data.vk_pipeline = pipeline;
draw.node_data.pipeline_data.vk_pipeline_layout = pipeline_layout;
render_graph.add_node(draw);
}
{
VKUpdateBufferNode::CreateInfo update_buffer = {};
update_buffer.dst_buffer = buffer_b;
update_buffer.data_size = 24;
update_buffer.data = MEM_callocN(24, __func__);
render_graph.add_node(update_buffer);
}
{
VKResourceAccessInfo access_info = {};
access_info.buffers.append({buffer_b, VK_ACCESS_UNIFORM_READ_BIT});
VKDrawNode::CreateInfo draw(access_info);
draw.node_data.first_instance = 0;
draw.node_data.first_vertex = 0;
draw.node_data.instance_count = 1;
draw.node_data.vertex_count = 2;
draw.node_data.pipeline_data.push_constants_data = nullptr;
draw.node_data.pipeline_data.push_constants_size = 0;
draw.node_data.pipeline_data.vk_descriptor_set = VK_NULL_HANDLE;
draw.node_data.pipeline_data.vk_pipeline = pipeline;
draw.node_data.pipeline_data.vk_pipeline_layout = pipeline_layout;
render_graph.add_node(draw);
}
{
VKUpdateBufferNode::CreateInfo update_buffer = {};
update_buffer.dst_buffer = buffer_a;
update_buffer.data_size = 16;
update_buffer.data = MEM_callocN(16, __func__);
render_graph.add_node(update_buffer);
}
{
VKResourceAccessInfo access_info = {};
access_info.buffers.append({buffer_a, VK_ACCESS_UNIFORM_READ_BIT});
VKDrawNode::CreateInfo draw(access_info);
draw.node_data.first_instance = 0;
draw.node_data.first_vertex = 0;
draw.node_data.instance_count = 1;
draw.node_data.vertex_count = 3;
draw.node_data.pipeline_data.push_constants_data = nullptr;
draw.node_data.pipeline_data.push_constants_size = 0;
draw.node_data.pipeline_data.vk_descriptor_set = VK_NULL_HANDLE;
draw.node_data.pipeline_data.vk_pipeline = pipeline;
draw.node_data.pipeline_data.vk_pipeline_layout = pipeline_layout;
render_graph.add_node(draw);
}
{
VKEndRenderingNode::CreateInfo end_rendering = {};
render_graph.add_node(end_rendering);
}
render_graph.submit();
ASSERT_EQ(16, log.size());
EXPECT_EQ("update_buffer(dst_buffer=0x1, dst_offset=0, data_size=16)", log[0]);
EXPECT_EQ("update_buffer(dst_buffer=0x2, dst_offset=0, data_size=24)", log[1]);
EXPECT_EQ(
"pipeline_barrier(src_stage_mask=VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, "
"dst_stage_mask=VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT" +
endl() +
" - image_barrier(src_access_mask=, "
"dst_access_mask=VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, "
"old_layout=VK_IMAGE_LAYOUT_UNDEFINED, "
"new_layout=VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, "
"image=0x3, subresource_range=" +
endl() +
" aspect_mask=VK_IMAGE_ASPECT_COLOR_BIT, "
"base_mip_level=0, level_count=4294967295, base_array_layer=0, layer_count=4294967295 "
")" +
endl() + ")",
log[2]);
EXPECT_EQ(
"pipeline_barrier(src_stage_mask=VK_PIPELINE_STAGE_TRANSFER_BIT, "
"dst_stage_mask=VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT" +
endl() +
" - "
"buffer_barrier(src_access_mask=VK_ACCESS_TRANSFER_WRITE_BIT, "
"dst_access_mask=VK_ACCESS_UNIFORM_READ_BIT, buffer=0x1, offset=0, "
"size=18446744073709551615)" +
endl() + ")",
log[3]);
EXPECT_EQ(
"pipeline_barrier(src_stage_mask=VK_PIPELINE_STAGE_TRANSFER_BIT, "
"dst_stage_mask=VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT" +
endl() +
" - "
"buffer_barrier(src_access_mask=VK_ACCESS_TRANSFER_WRITE_BIT, "
"dst_access_mask=VK_ACCESS_UNIFORM_READ_BIT, buffer=0x2, offset=0, "
"size=18446744073709551615)" +
endl() + ")",
log[4]);
EXPECT_EQ(
"begin_rendering(p_rendering_info=flags=VK_RENDERING_SUSPENDING_BIT, "
"VK_RENDERING_SUSPENDING_BIT_KHR, render_area=" +
endl() + " offset=" + endl() + " x=0, y=0 , extent=" + endl() +
" width=0, height=0 , layer_count=1, view_mask=0, color_attachment_count=1, "
"p_color_attachments=" +
endl() +
" image_view=0x4, image_layout=VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, "
"resolve_mode=VK_RESOLVE_MODE_NONE, resolve_image_view=0, "
"resolve_image_layout=VK_IMAGE_LAYOUT_UNDEFINED, "
"load_op=VK_ATTACHMENT_LOAD_OP_DONT_CARE, store_op=VK_ATTACHMENT_STORE_OP_STORE" +
endl() + ")",
log[5]);
EXPECT_EQ("bind_pipeline(pipeline_bind_point=VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline=0x6)",
log[6]);
EXPECT_EQ("draw(vertex_count=1, instance_count=1, first_vertex=0, first_instance=0)", log[7]);
EXPECT_EQ("draw(vertex_count=2, instance_count=1, first_vertex=0, first_instance=0)", log[8]);
EXPECT_EQ("end_rendering()", log[9]);
EXPECT_EQ(
"pipeline_barrier(src_stage_mask=VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, "
"dst_stage_mask=VK_PIPELINE_STAGE_TRANSFER_BIT" +
endl() +
" - buffer_barrier(src_access_mask=VK_ACCESS_UNIFORM_READ_BIT, "
"dst_access_mask=VK_ACCESS_TRANSFER_WRITE_BIT, buffer=0x1, offset=0, "
"size=18446744073709551615)" +
endl() + ")",
log[10]);
EXPECT_EQ("update_buffer(dst_buffer=0x1, dst_offset=0, data_size=16)", log[11]);
EXPECT_EQ(
"pipeline_barrier(src_stage_mask=VK_PIPELINE_STAGE_TRANSFER_BIT, "
"dst_stage_mask=VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT" +
endl() +
" - buffer_barrier(src_access_mask=VK_ACCESS_TRANSFER_WRITE_BIT, "
"dst_access_mask=VK_ACCESS_UNIFORM_READ_BIT, buffer=0x1, offset=0, "
"size=18446744073709551615)" +
endl() + ")",
log[12]);
EXPECT_EQ(
"begin_rendering(p_rendering_info=flags=VK_RENDERING_RESUMING_BIT, "
"VK_RENDERING_RESUMING_BIT_KHR, render_area=" +
endl() + " offset=" + endl() + " x=0, y=0 , extent=" + endl() +
" width=0, height=0 , layer_count=1, view_mask=0, color_attachment_count=1, "
"p_color_attachments=" +
endl() +
" image_view=0x4, image_layout=VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, "
"resolve_mode=VK_RESOLVE_MODE_NONE, resolve_image_view=0, "
"resolve_image_layout=VK_IMAGE_LAYOUT_UNDEFINED, "
"load_op=VK_ATTACHMENT_LOAD_OP_DONT_CARE, store_op=VK_ATTACHMENT_STORE_OP_STORE" +
endl() + ")",
log[13]);
EXPECT_EQ("draw(vertex_count=3, instance_count=1, first_vertex=0, first_instance=0)", log[14]);
EXPECT_EQ("end_rendering()", log[15]);
}
} // namespace blender::gpu::render_graph

View File

@@ -201,7 +201,6 @@ class CommandBufferLog : public VKCommandBufferInterface {
ss << ", dst_offset=" << dst_offset;
ss << ", data_size=" << data_size;
ss << ")";
ss << std::endl;
log_.append(ss.str());
}
void copy_buffer(VkBuffer src_buffer,

View File

@@ -40,6 +40,7 @@ namespace blender::gpu::render_graph {
class VKCommandBuilder;
struct VKRenderGraphLink;
class VKScheduler;
using ResourceHandle = uint64_t;
@@ -122,6 +123,7 @@ class VKResourceStateTracker {
* During the syncing the command builder attributes are resized to reduce reallocations. */
friend class VKCommandBuilder;
friend struct VKRenderGraphLink;
friend class VKScheduler;
/**
* A render resource can be a buffer or an image that needs to be tracked during rendering.
@@ -311,6 +313,12 @@ class VKResourceStateTracker {
*/
void reset_image_layouts();
/** Get the resource type for the given handle. */
VKResourceType resource_type_get(ResourceHandle resource_handle) const
{
return resources_.lookup(resource_handle).type;
}
private:
/**
* Get the current stamp of the resource.

View File

@@ -89,6 +89,10 @@ std::optional<std::pair<int64_t, int64_t>> VKScheduler::find_rendering_scope(
void VKScheduler::move_transfer_and_dispatch_outside_rendering_scope(
const VKRenderGraph &render_graph)
{
Vector<NodeHandle> pre_rendering_scope;
Vector<NodeHandle> rendering_scope;
Set<ResourceHandle> used_buffers;
foreach_rendering_scope(render_graph, [&](int64_t start_index, int64_t end_index) {
/* Move end_rendering right after the last graphics node. */
for (int index = end_index - 1; index >= start_index; index--) {
@@ -111,6 +115,74 @@ void VKScheduler::move_transfer_and_dispatch_outside_rendering_scope(
std::swap(result_[start_index], result_[index]);
start_index += 1;
}
/* Move buffer update buffer commands to before the rendering scope, unless the buffer is
* already being used by a draw command. Images modification could also be moved outside the
* rendering scope, but it is more tricky as they could also be attached to the framebuffer. */
pre_rendering_scope.clear();
rendering_scope.clear();
used_buffers.clear();
for (int index = start_index + 1; index < end_index; index++) {
NodeHandle node_handle = result_[index];
const VKRenderGraphNode &node = render_graph.nodes_[node_handle];
/* Should we add this node to the rendering scope. This is only done when we need to reorder
* nodes. In that case the rendering_scope has already an item and we should add this node to
* or the rendering scope or before the rendering scope. Adding nodes before rendering scope
* is done in the VKNodeType::UPDATE_BUFFER branch. */
bool add_to_rendering_scope = !rendering_scope.is_empty();
if (node.type == VKNodeType::UPDATE_BUFFER) {
if (!used_buffers.contains(
render_graph.resources_.buffer_resources_.lookup(node.update_buffer.dst_buffer)))
{
/* Buffer isn't used by this rendering scope so we can safely move it before the
* rendering scope begins. */
pre_rendering_scope.append(node_handle);
add_to_rendering_scope = false;
/* When this is the first time we move a node before the rendering we should start
* building up the rendering scope as well. This is postponed so we can safe some cycles
* when no nodes needs to be moved at all. */
if (rendering_scope.is_empty()) {
rendering_scope.extend(Span<NodeHandle>(&result_[start_index], index - start_index));
}
}
}
if (add_to_rendering_scope) {
/* When rendering scope has an item we are rewriting the execution order and need to track
* what should be inside the rendering scope. */
rendering_scope.append(node_handle);
}
/* Any read/write to buffer resources should be added to used_buffers in order to detect if
* it is safe to move a node before the rendering scope.*/
const VKRenderGraphNodeLinks &links = render_graph.links_[node_handle];
for (const VKRenderGraphLink &input : links.inputs) {
if (render_graph.resources_.resource_type_get(input.resource.handle) ==
VKResourceType::BUFFER)
{
used_buffers.add(input.resource.handle);
}
}
for (const VKRenderGraphLink &output : links.outputs) {
if (render_graph.resources_.resource_type_get(output.resource.handle) ==
VKResourceType::BUFFER)
{
used_buffers.add(output.resource.handle);
}
}
}
/* When pre_rendering_scope has an item we want to rewrite the order.
* The number of nodes are not changed, so we can do this inline. */
if (!pre_rendering_scope.is_empty()) {
MutableSpan<NodeHandle> store_none_rendering = result_.as_mutable_span().slice(
start_index, pre_rendering_scope.size());
MutableSpan<NodeHandle> store_rendering = result_.as_mutable_span().slice(
start_index + pre_rendering_scope.size(), rendering_scope.size());
store_none_rendering.copy_from(pre_rendering_scope);
store_rendering.copy_from(rendering_scope);
start_index += pre_rendering_scope.size();
}
});
}

View File

@@ -219,10 +219,28 @@ static void modifier_ops_extra_draw(bContext *C, uiLayout *layout, void *md_v)
uiLayoutSetUnitsX(layout, 4.0f);
/* Apply. */
uiItemO(layout,
CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Apply"),
ICON_CHECKMARK,
"OBJECT_OT_modifier_apply");
if (ob->type == OB_GREASE_PENCIL) {
uiItemO(layout,
CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Apply (Active Keyframe)"),
ICON_CHECKMARK,
"OBJECT_OT_modifier_apply");
uiItemFullO(layout,
"OBJECT_OT_modifier_apply",
IFACE_("Apply (All Keyframes)"),
ICON_KEYFRAME,
nullptr,
WM_OP_INVOKE_DEFAULT,
UI_ITEM_NONE,
&op_ptr);
RNA_boolean_set(&op_ptr, "all_keyframes", true);
}
else {
uiItemO(layout,
CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Apply"),
ICON_CHECKMARK,
"OBJECT_OT_modifier_apply");
}
/* Apply as shapekey. */
if (BKE_modifier_is_same_topology(md) && !BKE_modifier_is_non_geometrical(md)) {