Compositor: add new node: Kuwahara filter #107015

Merged
Habib Gahbiche merged 22 commits from zazizizou/blender:com-kuwahara-filter-node into main 2023-06-08 16:14:51 +02:00
41 changed files with 713 additions and 96 deletions
Showing only changes of commit 2fee5865d0 - Show all commits

View File

@ -79,6 +79,7 @@ struct CCLShadowContext
#endif
IntegratorShadowState isect_s;
float throughput;
float max_t;
bool opaque_hit;
numhit_t max_hits;
numhit_t num_hits;
@ -314,7 +315,7 @@ ccl_device_forceinline void kernel_embree_filter_occluded_shadow_all_func_impl(
/* Current implementation in Cycles assumes only single-ray intersection queries. */
assert(args->N == 1);
RTCRay *ray = (RTCRay *)args->ray;
const RTCRay *ray = (RTCRay *)args->ray;
RTCHit *hit = (RTCHit *)args->hit;
#if EMBREE_MAJOR_VERSION >= 4
CCLShadowContext *ctx = (CCLShadowContext *)(args->context);
@ -367,42 +368,51 @@ ccl_device_forceinline void kernel_embree_filter_occluded_shadow_all_func_impl(
}
}
/* Test if we need to record this transparent intersection. */
const numhit_t max_record_hits = min(ctx->max_hits, numhit_t(INTEGRATOR_SHADOW_ISECT_SIZE));
if (ctx->num_recorded_hits < max_record_hits) {
/* If maximum number of hits was reached, replace the intersection with the
* highest distance. We want to find the N closest intersections. */
const numhit_t num_recorded_hits = min(ctx->num_recorded_hits, max_record_hits);
numhit_t isect_index = num_recorded_hits;
if (num_recorded_hits + 1 >= max_record_hits) {
float max_t = INTEGRATOR_STATE_ARRAY(ctx->isect_s, shadow_isect, 0, t);
numhit_t max_recorded_hit = numhit_t(0);
for (numhit_t i = numhit_t(1); i < num_recorded_hits; ++i) {
const float isect_t = INTEGRATOR_STATE_ARRAY(ctx->isect_s, shadow_isect, i, t);
if (isect_t > max_t) {
max_recorded_hit = i;
max_t = isect_t;
}
}
if (num_recorded_hits >= max_record_hits) {
isect_index = max_recorded_hit;
}
/* Limit the ray distance and stop counting hits beyond this. */
ray->tfar = max(current_isect.t, max_t);
}
integrator_state_write_shadow_isect(ctx->isect_s, &current_isect, isect_index);
}
numhit_t isect_index = ctx->num_recorded_hits;
/* Always increase the number of recorded hits, even beyond the maximum,
* so that we can detect this and trace another ray if needed. */
* so that we can detect this and trace another ray if needed.
* More details about the related logic can be found in implementation of
* "shadow_intersections_has_remaining" and "integrate_transparent_shadow"
* functions. */
++ctx->num_recorded_hits;
/* This tells Embree to continue tracing. */
*args->valid = 0;
const numhit_t max_record_hits = min(ctx->max_hits, numhit_t(INTEGRATOR_SHADOW_ISECT_SIZE));
/* If the maximum number of hits was reached, replace the furthest intersection
* with a closer one so we get the N closest intersections. */
if (isect_index >= max_record_hits) {
/* When recording only N closest hits, max_t will always only decrease.
* So let's test if we are already not meeting criteria and can skip max_t recalculation. */
if (current_isect.t >= ctx->max_t) {
return;
}
float max_t = INTEGRATOR_STATE_ARRAY(ctx->isect_s, shadow_isect, 0, t);
numhit_t max_recorded_hit = numhit_t(0);
for (numhit_t i = numhit_t(1); i < max_record_hits; ++i) {
const float isect_t = INTEGRATOR_STATE_ARRAY(ctx->isect_s, shadow_isect, i, t);
if (isect_t > max_t) {
max_recorded_hit = i;
max_t = isect_t;
}
}
isect_index = max_recorded_hit;
/* Limit the ray distance and avoid processing hits beyond this. */
ctx->max_t = max_t;
/* If it's further away than max_t, we don't record this transparent intersection. */
if (current_isect.t >= max_t) {
return;
}
}
integrator_state_write_shadow_isect(ctx->isect_s, &current_isect, isect_index);
}
ccl_device_forceinline void kernel_embree_filter_occluded_local_func_impl(

View File

@ -350,7 +350,7 @@ def main():
if name.rpartition(".")[2].isdigit():
continue
if not ob_eval.data.attributes.active_color:
if (not hasattr(ob_eval.data, 'attributes')) or not ob_eval.data.attributes.active_color:
print("Skipping:", name, "(no vertex colors)")
continue

View File

@ -1836,6 +1836,10 @@ def km_graph_editor(params):
("graph.delete", {"type": 'DEL', "value": 'PRESS'}, {"properties": [("confirm", False)]}),
("graph.duplicate_move", {"type": 'D', "value": 'PRESS', "shift": True}, None),
("graph.keyframe_insert", {"type": 'I', "value": 'PRESS'}, None),
("graph.keyframe_jump", {"type": 'UP_ARROW', "value": 'PRESS', "repeat": True},
{"properties": [("next", True)]}),
("graph.keyframe_jump", {"type": 'DOWN_ARROW', "value": 'PRESS', "repeat": True},
{"properties": [("next", False)]}),
("graph.click_insert", {"type": params.action_mouse, "value": 'CLICK', "ctrl": True}, None),
("graph.click_insert", {"type": params.action_mouse, "value": 'CLICK', "shift": True, "ctrl": True},
{"properties": [("extend", True)]}),

View File

@ -3111,7 +3111,7 @@ class VIEW3D_PT_tools_active(ToolSelectPanelHelper, Panel):
*_tools_annotate,
],
'EDIT_GPENCIL': [
*_tools_gpencil_select,
*_tools_select,
_defs_view3d_generic.cursor,
None,
*_tools_transform,

View File

@ -38,6 +38,13 @@ typedef struct AssetTypeInfo {
struct AssetMetaData *BKE_asset_metadata_create(void);
void BKE_asset_metadata_free(struct AssetMetaData **asset_data);
/**
* Create a copy of the #AssetMetaData so that it can be assigned to another asset.
*
* The caller becomes the owner of the returned pointer.
*/
struct AssetMetaData *BKE_asset_metadata_copy(const struct AssetMetaData *source);
struct AssetTagEnsureResult {
struct AssetTag *tag;
/* Set to false if a tag of this name was already present. */

View File

@ -51,5 +51,8 @@ struct GeometryDeformation {
GeometryDeformation get_evaluated_curves_deformation(const Object *ob_eval, const Object &ob_orig);
GeometryDeformation get_evaluated_curves_deformation(const Depsgraph &depsgraph,
const Object &ob_orig);
GeometryDeformation get_evaluated_grease_pencil_drawing_deformation(const Object *ob_eval,
const Object &ob_orig,
int drawing_index);
} // namespace blender::bke::crazyspace

View File

@ -39,6 +39,38 @@ void BKE_asset_metadata_free(AssetMetaData **asset_data)
*asset_data = nullptr;
}
AssetMetaData *BKE_asset_metadata_copy(const AssetMetaData *source)
{
AssetMetaData *copy = BKE_asset_metadata_create();
copy->local_type_info = source->local_type_info;
if (source->properties) {
copy->properties = IDP_CopyProperty(source->properties);
}
BKE_asset_metadata_catalog_id_set(copy, source->catalog_id, source->catalog_simple_name);
if (source->author) {
copy->author = BLI_strdup(source->author);
}
if (source->description) {
copy->description = BLI_strdup(source->description);
}
if (source->copyright) {
copy->copyright = BLI_strdup(source->copyright);
}
if (source->license) {
copy->license = BLI_strdup(source->license);
}
BLI_duplicatelist(&copy->tags, &source->tags);
copy->active_tag = source->active_tag;
copy->tot_tags = source->tot_tags;
return copy;
}
AssetMetaData::~AssetMetaData()
{
if (properties) {

View File

@ -24,6 +24,7 @@
#include "BKE_curves.hh"
#include "BKE_editmesh.h"
#include "BKE_geometry_set.hh"
#include "BKE_grease_pencil.hh"
#include "BKE_lib_id.h"
#include "BKE_mesh.hh"
#include "BKE_mesh_wrapper.h"
@ -662,4 +663,37 @@ GeometryDeformation get_evaluated_curves_deformation(const Depsgraph &depsgraph,
return get_evaluated_curves_deformation(ob_eval, ob_orig);
}
GeometryDeformation get_evaluated_grease_pencil_drawing_deformation(const Object *ob_eval,
const Object &ob_orig,
const int drawing_index)
{
BLI_assert(ob_orig.type == OB_GREASE_PENCIL);
const GreasePencil &grease_pencil_orig = *static_cast<const GreasePencil *>(ob_orig.data);
GreasePencilDrawingBase *drawing_base = grease_pencil_orig.drawings()[drawing_index];
GeometryDeformation deformation;
if (drawing_base->type == GP_DRAWING) {
GreasePencilDrawing *drawing = reinterpret_cast<GreasePencilDrawing *>(drawing_base);
/* Use the undeformed positions by default. */
deformation.positions = drawing->geometry.wrap().positions();
}
else if (drawing_base->type == GP_DRAWING_REFERENCE) {
/* TODO */
}
if (ob_eval == nullptr) {
return deformation;
}
const GeometrySet *geometry_eval = ob_eval->runtime.geometry_set_eval;
if (geometry_eval == nullptr) {
return deformation;
}
/* TODO: Read `GeometryComponentEditData` from `geometry_eval` and populate deformation with it.
*/
return deformation;
}
} // namespace blender::bke::crazyspace

View File

@ -1061,7 +1061,7 @@ enum ForeachDrawingMode {
static void foreach_drawing_ex(GreasePencil &grease_pencil,
int frame,
ForeachDrawingMode mode,
blender::FunctionRef<void(GreasePencilDrawing &)> function)
blender::FunctionRef<void(int, GreasePencilDrawing &)> function)
{
using namespace blender::bke::greasepencil;
@ -1089,7 +1089,7 @@ static void foreach_drawing_ex(GreasePencil &grease_pencil,
GreasePencilDrawingBase *drawing_base = drawings[index];
if (drawing_base->type == GP_DRAWING) {
GreasePencilDrawing *drawing = reinterpret_cast<GreasePencilDrawing *>(drawing_base);
function(*drawing);
function(index, *drawing);
}
else if (drawing_base->type == GP_DRAWING_REFERENCE) {
/* TODO */
@ -1098,13 +1098,13 @@ static void foreach_drawing_ex(GreasePencil &grease_pencil,
}
void GreasePencil::foreach_visible_drawing(
int frame, blender::FunctionRef<void(GreasePencilDrawing &)> function)
int frame, blender::FunctionRef<void(int, GreasePencilDrawing &)> function)
{
foreach_drawing_ex(*this, frame, VISIBLE, function);
}
void GreasePencil::foreach_editable_drawing(
int frame, blender::FunctionRef<void(GreasePencilDrawing &)> function)
int frame, blender::FunctionRef<void(int, GreasePencilDrawing &)> function)
{
foreach_drawing_ex(*this, frame, EDITABLE, function);
}

View File

@ -204,7 +204,8 @@ static void grease_pencil_geom_batch_ensure(GreasePencil &grease_pencil, int cfr
/* Get the visible drawings. */
Vector<const GreasePencilDrawing *> drawings;
grease_pencil.foreach_visible_drawing(
cfra, [&](GreasePencilDrawing &drawing) { drawings.append(&drawing); });
cfra,
[&](int /*drawing_index*/, GreasePencilDrawing &drawing) { drawings.append(&drawing); });
/* First, count how many vertices and triangles are needed for the whole object. Also record the
* offsets into the curves for the vertices and triangles. */

View File

@ -12,6 +12,7 @@
extern "C" {
#endif
struct AssetMetaData;
struct ID;
struct Main;
struct bContext;
@ -42,6 +43,18 @@ void ED_asset_generate_preview(const struct bContext *C, struct ID *id);
*/
bool ED_asset_clear_id(struct ID *id);
/**
* Copy the asset metadata to the given destination ID.
*
* The copy is assigned to \a destination, any pre-existing asset metadata is
* freed before that. If \a destination was not yet marked as asset, it will be
* after this call.
*
* \return true when the copy succeeded, false otherwise. The only reason for
* failure is when \a destination is of a type that cannot be an asset.
*/
bool ED_asset_copy_to_id(const struct AssetMetaData *asset_data, struct ID *destination);
void ED_assets_pre_save(struct Main *bmain);
bool ED_asset_can_mark_single_from_context(const struct bContext *C);

View File

@ -27,6 +27,9 @@
#include "ED_asset_mark_clear.h"
#include "ED_asset_type.h"
#include "WM_api.h"
#include "WM_types.h"
bool ED_asset_mark_id(ID *id)
{
if (id->asset_data) {
@ -96,3 +99,16 @@ bool ED_asset_can_mark_single_from_context(const bContext *C)
}
return ED_asset_type_is_supported(id);
}
bool ED_asset_copy_to_id(const struct AssetMetaData *asset_data, struct ID *destination)
{
if (!BKE_id_can_be_asset(destination)) {
return false;
}
if (destination->asset_data) {
BKE_asset_metadata_free(&destination->asset_data);
}
destination->asset_data = BKE_asset_metadata_copy(asset_data);
return true;
}

View File

@ -48,10 +48,11 @@ static int select_all_exec(bContext *C, wmOperator *op)
Object *object = CTX_data_active_object(C);
GreasePencil &grease_pencil = *static_cast<GreasePencil *>(object->data);
grease_pencil.foreach_editable_drawing(scene->r.cfra, [action](GreasePencilDrawing &drawing) {
// TODO: Support different selection domains.
blender::ed::curves::select_all(drawing.geometry.wrap(), ATTR_DOMAIN_POINT, action);
});
grease_pencil.foreach_editable_drawing(
scene->r.cfra, [action](int /*drawing_index*/, GreasePencilDrawing &drawing) {
// TODO: Support different selection domains.
blender::ed::curves::select_all(drawing.geometry.wrap(), ATTR_DOMAIN_POINT, action);
});
/* Use #ID_RECALC_GEOMETRY instead of #ID_RECALC_SELECT because it is handled as a generic
* attribute for now. */

View File

@ -2408,7 +2408,10 @@ void uiTemplateImage(uiLayout *layout,
struct PointerRNA *userptr,
bool compact,
bool multiview);
void uiTemplateImageSettings(uiLayout *layout, struct PointerRNA *imfptr, bool color_management);
void uiTemplateImageSettings(uiLayout *layout,
struct PointerRNA *imfptr,
bool color_management,
bool show_z_buffer);
void uiTemplateImageStereo3d(uiLayout *layout, struct PointerRNA *stereo3d_format_ptr);
void uiTemplateImageViews(uiLayout *layout, struct PointerRNA *imaptr);
void uiTemplateImageFormatViews(uiLayout *layout,

View File

@ -35,6 +35,7 @@
#include "interface_intern.hh"
#include "RNA_access.h"
#include "RNA_path.h"
#include "RNA_prototypes.h"
#ifdef WITH_PYTHON
@ -344,7 +345,10 @@ static bUserMenuItem *ui_but_user_menu_find(bContext *C, uiBut *but, bUserMenu *
}
if (but->rnaprop) {
char *member_id_data_path = WM_context_path_resolve_full(C, &but->rnapoin);
const char *prop_id = RNA_property_identifier(but->rnaprop);
/* Ignore the actual array index [pass -1] since the index is handled separately. */
const char *prop_id = RNA_property_is_idprop(but->rnaprop) ?
RNA_path_property_py(&but->rnapoin, but->rnaprop, -1) :
RNA_property_identifier(but->rnaprop);
bUserMenuItem *umi = (bUserMenuItem *)ED_screen_user_menu_item_find_prop(
&um->items, member_id_data_path, prop_id, but->rnaindex);
MEM_freeN(member_id_data_path);
@ -419,7 +423,10 @@ static void ui_but_user_menu_add(bContext *C, uiBut *but, bUserMenu *um)
else if (but->rnaprop) {
/* NOTE: 'member_id' may be a path. */
char *member_id_data_path = WM_context_path_resolve_full(C, &but->rnapoin);
const char *prop_id = RNA_property_identifier(but->rnaprop);
/* Ignore the actual array index [pass -1] since the index is handled separately. */
const char *prop_id = RNA_property_is_idprop(but->rnaprop) ?
RNA_path_property_py(&but->rnapoin, but->rnaprop, -1) :
RNA_property_identifier(but->rnaprop);
/* NOTE: ignore 'drawstr', use property idname always. */
ED_screen_user_menu_item_add_prop(&um->items, "", member_id_data_path, prop_id, but->rnaindex);
MEM_freeN(member_id_data_path);

View File

@ -3180,6 +3180,12 @@ static int keyframe_jump_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
static bool keyframe_jump_poll(bContext *C)
{
/* There is a keyframe jump operator specifically for the Graph Editor. */
return ED_operator_screenactive_norender(C) && CTX_wm_area(C)->spacetype != SPACE_GRAPH;
}
static void SCREEN_OT_keyframe_jump(wmOperatorType *ot)
{
ot->name = "Jump to Keyframe";
@ -3188,7 +3194,7 @@ static void SCREEN_OT_keyframe_jump(wmOperatorType *ot)
ot->exec = keyframe_jump_exec;
ot->poll = ED_operator_screenactive_norender;
ot->poll = keyframe_jump_poll;
ot->flag = OPTYPE_UNDO_GROUPED;
ot->undo_group = "Frame Change";

View File

@ -218,7 +218,7 @@ static void screenshot_draw(bContext *UNUSED(C), wmOperator *op)
/* image template */
PointerRNA ptr;
RNA_pointer_create(NULL, &RNA_ImageFormatSettings, &scd->im_format, &ptr);
uiTemplateImageSettings(layout, &ptr, false);
uiTemplateImageSettings(layout, &ptr, false, true);
/* main draw call */
uiDefAutoButsRNA(

View File

@ -39,6 +39,7 @@
#include "BKE_global.h"
#include "BKE_nla.h"
#include "BKE_report.h"
#include "BKE_scene.h"
#include "DEG_depsgraph_build.h"
@ -2179,6 +2180,104 @@ void GRAPH_OT_frame_jump(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
static bool find_closest_frame(const FCurve *fcu,
const float frame,
const bool next,
float *closest_frame)
{
bool replace;
int bezt_index = BKE_fcurve_bezt_binarysearch_index(fcu->bezt, frame, fcu->totvert, &replace);
BezTriple *bezt;
if (next) {
if (replace) {
bezt_index++;
}
if (bezt_index > fcu->totvert - 1) {
return false;
}
bezt = &fcu->bezt[bezt_index];
}
else {
if (bezt_index - 1 < 0) {
return false;
}
bezt = &fcu->bezt[bezt_index - 1];
}
*closest_frame = bezt->vec[1][0];
return true;
}
static int keyframe_jump_exec(bContext *C, wmOperator *op)
{
bAnimContext ac;
Scene *scene = CTX_data_scene(C);
bool next = RNA_boolean_get(op->ptr, "next");
/* Get editor data. */
if (ANIM_animdata_get_context(C, &ac) == 0) {
return OPERATOR_CANCELLED;
}
ListBase anim_data = {NULL, NULL};
int filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FCURVESONLY |
ANIMFILTER_NODUPLIS);
if (U.animation_flag & USER_ANIM_ONLY_SHOW_SELECTED_CURVE_KEYS) {
filter |= ANIMFILTER_SEL;
}
ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
float closest_frame = next ? FLT_MAX : -FLT_MAX;
bool found = false;
const float current_frame = BKE_scene_frame_get(scene);
LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
const FCurve *fcu = ale->key_data;
if (!fcu->bezt) {
continue;
}
float closest_fcu_frame;
if (!find_closest_frame(fcu, current_frame, next, &closest_fcu_frame)) {
continue;
}
if ((next && closest_fcu_frame < closest_frame) ||
(!next && closest_fcu_frame > closest_frame)) {
closest_frame = closest_fcu_frame;
found = true;
}
}
if (!found) {
BKE_report(op->reports, RPT_INFO, "No more keyframes to jump to in this direction");
return OPERATOR_CANCELLED;
}
BKE_scene_frame_set(scene, closest_frame);
/* Set notifier that things have changed. */
WM_event_add_notifier(C, NC_SCENE | ND_FRAME, ac.scene);
return OPERATOR_FINISHED;
}
void GRAPH_OT_keyframe_jump(wmOperatorType *ot)
{
ot->name = "Jump to Keyframe";
ot->description = "Jump to previous/next keyframe";
ot->idname = "GRAPH_OT_keyframe_jump";
ot->exec = keyframe_jump_exec;
ot->poll = graphkeys_framejump_poll;
ot->flag = OPTYPE_UNDO_GROUPED;
ot->undo_group = "Frame Change";
/* properties */
RNA_def_boolean(ot->srna, "next", true, "Next Keyframe", "");
}
/* snap 2D cursor value to the average value of selected keyframe */
static int graphkeys_snap_cursor_value_exec(bContext *C, wmOperator *UNUSED(op))
{

View File

@ -131,6 +131,7 @@ void GRAPH_OT_extrapolation_type(struct wmOperatorType *ot);
void GRAPH_OT_easing_type(struct wmOperatorType *ot);
void GRAPH_OT_frame_jump(struct wmOperatorType *ot);
void GRAPH_OT_keyframe_jump(struct wmOperatorType *ot);
void GRAPH_OT_snap_cursor_value(struct wmOperatorType *ot);
void GRAPH_OT_snap(struct wmOperatorType *ot);
void GRAPH_OT_equalize_handles(struct wmOperatorType *ot);

View File

@ -449,6 +449,7 @@ void graphedit_operatortypes(void)
WM_operatortype_append(GRAPH_OT_equalize_handles);
WM_operatortype_append(GRAPH_OT_mirror);
WM_operatortype_append(GRAPH_OT_frame_jump);
WM_operatortype_append(GRAPH_OT_keyframe_jump);
WM_operatortype_append(GRAPH_OT_snap_cursor_value);
WM_operatortype_append(GRAPH_OT_handle_type);
WM_operatortype_append(GRAPH_OT_interpolation_type);

View File

@ -962,7 +962,10 @@ void uiTemplateImage(uiLayout *layout,
UI_block_funcN_set(block, NULL, NULL, NULL);
}
void uiTemplateImageSettings(uiLayout *layout, PointerRNA *imfptr, bool color_management)
void uiTemplateImageSettings(uiLayout *layout,
PointerRNA *imfptr,
bool color_management,
bool show_z_buffer)
{
ImageFormatData *imf = imfptr->data;
ID *id = imfptr->owner_id;
@ -1014,7 +1017,7 @@ void uiTemplateImageSettings(uiLayout *layout, PointerRNA *imfptr, bool color_ma
uiItemR(col, imfptr, "exr_codec", 0, NULL, ICON_NONE);
}
if (BKE_imtype_supports_zbuf(imf->imtype)) {
if (BKE_imtype_supports_zbuf(imf->imtype) && show_z_buffer) {
uiItemR(col, imfptr, "use_zbuffer", 0, NULL, ICON_NONE);
}

View File

@ -2007,7 +2007,7 @@ static void image_save_as_draw(bContext *UNUSED(C), wmOperator *op)
/* Image format settings. */
RNA_pointer_create(NULL, &RNA_ImageFormatSettings, &isd->opts.im_format, &imf_ptr);
uiTemplateImageSettings(layout, &imf_ptr, save_as_render);
uiTemplateImageSettings(layout, &imf_ptr, save_as_render, true);
if (!save_as_render) {
PointerRNA linear_settings_ptr = RNA_pointer_get(&imf_ptr, "linear_colorspace_settings");

View File

@ -53,6 +53,7 @@
#include "BKE_crazyspace.hh"
#include "BKE_curve.h"
#include "BKE_editmesh.h"
#include "BKE_grease_pencil.hh"
#include "BKE_layer.h"
#include "BKE_mball.h"
#include "BKE_mesh.hh"
@ -1171,6 +1172,43 @@ static bool do_lasso_select_meta(ViewContext *vc,
return data.is_changed;
}
static bool do_lasso_select_grease_pencil(ViewContext *vc,
const int mcoords[][2],
const int mcoords_len,
const eSelectOp sel_op)
{
using namespace blender;
const Object *ob_eval = DEG_get_evaluated_object(vc->depsgraph,
const_cast<Object *>(vc->obedit));
GreasePencil &grease_pencil = *static_cast<GreasePencil *>(vc->obedit->data);
bool changed = false;
grease_pencil.foreach_editable_drawing(
vc->scene->r.cfra, [&](int drawing_index, GreasePencilDrawing &drawing) {
bke::crazyspace::GeometryDeformation deformation =
bke::crazyspace::get_evaluated_grease_pencil_drawing_deformation(
ob_eval, *vc->obedit, drawing_index);
/* TODO: Support different selection domains. */
changed = ed::curves::select_lasso(
*vc,
drawing.geometry.wrap(),
deformation.positions,
ATTR_DOMAIN_POINT,
Span<int2>(reinterpret_cast<const int2 *>(mcoords), mcoords_len),
sel_op);
});
if (changed) {
/* Use #ID_RECALC_GEOMETRY instead of #ID_RECALC_SELECT because it is handled as a
* generic attribute for now. */
DEG_id_tag_update(static_cast<ID *>(vc->obedit->data), ID_RECALC_GEOMETRY);
WM_event_add_notifier(vc->C, NC_GEOM | ND_DATA, vc->obedit->data);
}
return changed;
}
struct LassoSelectUserData_ForMeshVert {
LassoSelectUserData lasso_data;
blender::MutableSpan<bool> select_vert;
@ -1388,6 +1426,10 @@ static bool view3d_lasso_select(bContext *C,
}
break;
}
case OB_GREASE_PENCIL: {
changed = do_lasso_select_grease_pencil(vc, mcoords, mcoords_len, sel_op);
break;
}
default:
BLI_assert_msg(0, "lasso select on incorrect object type");
break;
@ -3097,6 +3139,112 @@ static bool ed_curves_select_pick(bContext &C, const int mval[2], const SelectPi
return true;
}
struct ClosestGreasePencilDrawing {
GreasePencilDrawing *drawing = nullptr;
blender::ed::curves::FindClosestData elem = {};
};
/**
* Cursor selection for all Grease Pencil curves in edit mode.
*
* \returns true if the selection changed.
*/
static bool ed_grease_pencil_select_pick(bContext *C,
const int mval[2],
const SelectPick_Params &params)
{
using namespace blender;
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
ViewContext vc;
/* Setup view context for argument to callbacks. */
ED_view3d_viewcontext_init(C, &vc, depsgraph);
/* Collect editable drawings. */
const Object *ob_eval = DEG_get_evaluated_object(vc.depsgraph, const_cast<Object *>(vc.obedit));
GreasePencil &grease_pencil = *static_cast<GreasePencil *>(vc.obedit->data);
Vector<GreasePencilDrawing *> drawings;
Vector<int> drawing_indices;
grease_pencil.foreach_editable_drawing(vc.scene->r.cfra,
[&](int drawing_index, GreasePencilDrawing &drawing) {
drawings.append(&drawing);
drawing_indices.append(drawing_index);
});
/* TODO: Support different selection domains. */
const eAttrDomain selection_domain = ATTR_DOMAIN_POINT;
const ClosestGreasePencilDrawing closest = threading::parallel_reduce(
drawings.index_range(),
1L,
ClosestGreasePencilDrawing(),
[&](const IndexRange range, const ClosestGreasePencilDrawing &init) {
ClosestGreasePencilDrawing new_closest = init;
for (const int i : range) {
/* Get deformation by modifiers. */
bke::crazyspace::GeometryDeformation deformation =
bke::crazyspace::get_evaluated_grease_pencil_drawing_deformation(
ob_eval, *vc.obedit, drawing_indices[i]);
std::optional<ed::curves::FindClosestData> new_closest_elem =
ed::curves::closest_elem_find_screen_space(vc,
*vc.obedit,
drawings[i]->geometry.wrap(),
deformation.positions,
selection_domain,
mval,
new_closest.elem);
if (new_closest_elem) {
new_closest.elem = *new_closest_elem;
new_closest.drawing = drawings[i];
}
}
return new_closest;
},
[](const ClosestGreasePencilDrawing &a, const ClosestGreasePencilDrawing &b) {
return (a.elem.distance < b.elem.distance) ? a : b;
});
std::atomic<bool> deselected = false;
if (params.deselect_all || params.sel_op == SEL_OP_SET) {
threading::parallel_for(drawings.index_range(), 1L, [&](const IndexRange range) {
for (const int i : range) {
bke::CurvesGeometry &curves = drawings[i]->geometry.wrap();
if (ed::curves::has_anything_selected(curves)) {
bke::GSpanAttributeWriter selection = ed::curves::ensure_selection_attribute(
curves, selection_domain, CD_PROP_BOOL);
ed::curves::fill_selection_false(selection.span);
selection.finish();
deselected = true;
/* Use #ID_RECALC_GEOMETRY instead of #ID_RECALC_SELECT because it is handled as a
* generic attribute for now. */
DEG_id_tag_update(&grease_pencil.id, ID_RECALC_GEOMETRY);
WM_event_add_notifier(C, NC_GEOM | ND_DATA, &grease_pencil);
}
}
});
}
if (!closest.drawing) {
return deselected;
}
bke::GSpanAttributeWriter selection = ed::curves::ensure_selection_attribute(
closest.drawing->geometry.wrap(), selection_domain, CD_PROP_BOOL);
ed::curves::apply_selection_operation_at_index(
selection.span, closest.elem.index, params.sel_op);
selection.finish();
/* Use #ID_RECALC_GEOMETRY instead of #ID_RECALC_SELECT because it is handled as a
* generic attribute for now. */
if (!deselected) {
DEG_id_tag_update(&grease_pencil.id, ID_RECALC_GEOMETRY);
WM_event_add_notifier(C, NC_GEOM | ND_DATA, &grease_pencil);
}
return true;
}
static int view3d_select_exec(bContext *C, wmOperator *op)
{
Scene *scene = CTX_data_scene(C);
@ -3193,6 +3341,9 @@ static int view3d_select_exec(bContext *C, wmOperator *op)
else if (obedit->type == OB_CURVES) {
changed = ed_curves_select_pick(*C, mval, params);
}
else if (obedit->type == OB_GREASE_PENCIL) {
changed = ed_grease_pencil_select_pick(C, mval, params);
}
}
else if (obact && obact->mode & OB_MODE_PARTICLE_EDIT) {
changed = PE_mouse_particles(C, mval, &params);
@ -4028,6 +4179,32 @@ static bool do_pose_box_select(bContext *C,
return changed_multi;
}
static bool do_grease_pencil_box_select(ViewContext *vc, const rcti *rect, const eSelectOp sel_op)
{
using namespace blender;
Scene *scene = vc->scene;
const Object *ob_eval = DEG_get_evaluated_object(vc->depsgraph,
const_cast<Object *>(vc->obedit));
GreasePencil &grease_pencil = *static_cast<GreasePencil *>(vc->obedit->data);
bool changed = false;
grease_pencil.foreach_editable_drawing(
scene->r.cfra, [&](int drawing_index, GreasePencilDrawing &drawing) {
bke::crazyspace::GeometryDeformation deformation =
bke::crazyspace::get_evaluated_grease_pencil_drawing_deformation(
ob_eval, *vc->obedit, drawing_index);
changed |= ed::curves::select_box(
*vc, drawing.geometry.wrap(), deformation.positions, ATTR_DOMAIN_POINT, *rect, sel_op);
});
if (changed) {
DEG_id_tag_update(&grease_pencil.id, ID_RECALC_GEOMETRY);
WM_event_add_notifier(vc->C, NC_GEOM | ND_DATA, &grease_pencil);
}
return changed;
}
static int view3d_box_select_exec(bContext *C, wmOperator *op)
{
using namespace blender;
@ -4113,6 +4290,10 @@ static int view3d_box_select_exec(bContext *C, wmOperator *op)
}
break;
}
case OB_GREASE_PENCIL: {
changed = do_grease_pencil_box_select(&vc, &rect, sel_op);
break;
}
default:
BLI_assert_msg(0, "box select on incorrect object type");
break;

View File

@ -428,13 +428,11 @@ static void test_texture_roundtrip__GPU_DATA_FLOAT__GPU_RGB9_E5()
GPU_TEST(texture_roundtrip__GPU_DATA_FLOAT__GPU_RGB9_E5);
#endif
#if RUN_UNSUPPORTED
static void test_texture_roundtrip__GPU_DATA_FLOAT__GPU_DEPTH_COMPONENT32F()
{
texture_create_upload_read_with_bias<GPU_DEPTH_COMPONENT32F, GPU_DATA_FLOAT>(0.0f);
}
GPU_TEST(texture_roundtrip__GPU_DATA_FLOAT__GPU_DEPTH_COMPONENT32F);
#endif
#if RUN_COMPONENT_UNIMPLEMENTED
static void test_texture_roundtrip__GPU_DATA_FLOAT__GPU_DEPTH_COMPONENT24()
@ -622,7 +620,6 @@ static void test_texture_roundtrip__GPU_DATA_UINT__GPU_R32UI()
}
GPU_TEST(texture_roundtrip__GPU_DATA_UINT__GPU_R32UI);
#if RUN_UNSUPPORTED
static void test_texture_roundtrip__GPU_DATA_UINT__GPU_DEPTH32F_STENCIL8()
{
texture_create_upload_read<GPU_DEPTH32F_STENCIL8, GPU_DATA_UINT, uint32_t>();
@ -634,7 +631,6 @@ static void test_texture_roundtrip__GPU_DATA_UINT__GPU_DEPTH24_STENCIL8()
texture_create_upload_read<GPU_DEPTH24_STENCIL8, GPU_DATA_UINT, uint32_t>();
}
GPU_TEST(texture_roundtrip__GPU_DATA_UINT__GPU_DEPTH24_STENCIL8);
#endif
#if RUN_UNSUPPORTED
static void test_texture_roundtrip__GPU_DATA_UINT__GPU_RGB8UI()
@ -656,7 +652,6 @@ static void test_texture_roundtrip__GPU_DATA_UINT__GPU_RGB32UI()
GPU_TEST(texture_roundtrip__GPU_DATA_UINT__GPU_RGB32UI);
#endif
#if RUN_COMPONENT_UNIMPLEMENTED
static void test_texture_roundtrip__GPU_DATA_UINT__GPU_DEPTH_COMPONENT32F()
{
texture_create_upload_read<GPU_DEPTH_COMPONENT32F, GPU_DATA_UINT, uint32_t>();
@ -669,6 +664,7 @@ static void test_texture_roundtrip__GPU_DATA_UINT__GPU_DEPTH_COMPONENT24()
}
GPU_TEST(texture_roundtrip__GPU_DATA_UINT__GPU_DEPTH_COMPONENT24);
#if RUN_COMPONENT_UNIMPLEMENTED
static void test_texture_roundtrip__GPU_DATA_UINT__GPU_DEPTH_COMPONENT16()
{
texture_create_upload_read<GPU_DEPTH_COMPONENT16, GPU_DATA_UINT, uint32_t>();
@ -718,13 +714,11 @@ static void test_texture_roundtrip__GPU_DATA_UBYTE__GPU_R8()
}
GPU_TEST(texture_roundtrip__GPU_DATA_UBYTE__GPU_R8);
#if RUN_SRGB_UNIMPLEMENTED
static void test_texture_roundtrip__GPU_DATA_UBYTE__GPU_SRGB8_A8()
{
texture_create_upload_read<GPU_SRGB8_A8, GPU_DATA_UBYTE, uint8_t>();
}
GPU_TEST(texture_roundtrip__GPU_DATA_UBYTE__GPU_SRGB8_A8);
#endif
#if RUN_UNSUPPORTED
static void test_texture_roundtrip__GPU_DATA_UBYTE__GPU_RGB8I()

View File

@ -73,6 +73,18 @@ void VKBackend::platform_init(const VKDevice &device)
driver_version.c_str());
}
void VKBackend::detect_workarounds(VKDevice &device)
{
VKWorkarounds workarounds;
/* AMD GPUs don't support texture formats that use are aligned to 24 or 48 bits. */
if (GPU_type_matches(GPU_DEVICE_ATI, GPU_OS_ANY, GPU_DRIVER_ANY)) {
workarounds.not_aligned_pixel_formats = true;
}
device.workarounds_ = workarounds;
}
void VKBackend::platform_exit()
{
GPG.clear();
@ -174,7 +186,7 @@ shaderc::Compiler &VKBackend::get_shaderc_compiler()
return shaderc_compiler_;
}
void VKBackend::capabilities_init(const VKDevice &device)
void VKBackend::capabilities_init(VKDevice &device)
{
const VkPhysicalDeviceProperties &properties = device.physical_device_properties_get();
const VkPhysicalDeviceLimits &limits = properties.limits;
@ -205,6 +217,8 @@ void VKBackend::capabilities_init(const VKDevice &device)
GCaps.max_varying_floats = limits.maxVertexOutputComponents;
GCaps.max_shader_storage_buffer_bindings = limits.maxPerStageDescriptorStorageBuffers;
GCaps.max_compute_shader_storage_blocks = limits.maxPerStageDescriptorStorageBuffers;
detect_workarounds(device);
}
} // namespace blender::gpu

View File

@ -88,9 +88,10 @@ class VKBackend : public GPUBackend {
}
static void platform_init(const VKDevice &device);
static void capabilities_init(const VKDevice &device);
static void capabilities_init(VKDevice &device);
private:
static void detect_workarounds(VKDevice &device);
static void platform_init();
static void platform_exit();

View File

@ -201,15 +201,28 @@ void VKCommandBuffer::copy(VKTexture &dst_texture,
}
void VKCommandBuffer::blit(VKTexture &dst_texture,
VKTexture &src_buffer,
VKTexture &src_texture,
Span<VkImageBlit> regions)
{
blit(dst_texture,
dst_texture.current_layout_get(),
src_texture,
src_texture.current_layout_get(),
regions);
}
void VKCommandBuffer::blit(VKTexture &dst_texture,
VkImageLayout dst_layout,
VKTexture &src_texture,
VkImageLayout src_layout,
Span<VkImageBlit> regions)
{
ensure_no_active_framebuffer();
vkCmdBlitImage(vk_command_buffer_,
src_buffer.vk_image_handle(),
src_buffer.current_layout_get(),
src_texture.vk_image_handle(),
src_layout,
dst_texture.vk_image_handle(),
dst_texture.current_layout_get(),
dst_layout,
regions.size(),
regions.data(),
VK_FILTER_NEAREST);

View File

@ -165,6 +165,11 @@ class VKCommandBuffer : NonCopyable, NonMovable {
void copy(VKTexture &dst_texture, VKBuffer &src_buffer, Span<VkBufferImageCopy> regions);
void copy(VKTexture &dst_texture, VKTexture &src_texture, Span<VkImageCopy> regions);
void blit(VKTexture &dst_texture, VKTexture &src_texture, Span<VkImageBlit> regions);
void blit(VKTexture &dst_texture,
VkImageLayout dst_layout,
VKTexture &src_texture,
VkImageLayout src_layout,
Span<VkImageBlit> regions);
void pipeline_barrier(VkPipelineStageFlags source_stages,
VkPipelineStageFlags destination_stages);
void pipeline_barrier(Span<VkImageMemoryBarrier> image_memory_barriers);

View File

@ -32,6 +32,9 @@ enum class ConversionType {
FLOAT_TO_SNORM16,
SNORM16_TO_FLOAT,
FLOAT_TO_UNORM32,
UNORM32_TO_FLOAT,
UI32_TO_UI16,
UI16_TO_UI32,
@ -239,6 +242,7 @@ static ConversionType type_of_conversion_uint(eGPUTextureFormat device_format)
case GPU_RGBA32UI:
case GPU_RG32UI:
case GPU_R32UI:
case GPU_DEPTH_COMPONENT24:
return ConversionType::PASS_THROUGH;
case GPU_RGBA16UI:
@ -252,6 +256,10 @@ static ConversionType type_of_conversion_uint(eGPUTextureFormat device_format)
case GPU_R8UI:
return ConversionType::UI32_TO_UI8;
case GPU_DEPTH_COMPONENT32F:
case GPU_DEPTH32F_STENCIL8:
return ConversionType::UNORM32_TO_FLOAT;
case GPU_RGBA8I:
case GPU_RGBA8:
case GPU_RGBA16I:
@ -276,7 +284,6 @@ static ConversionType type_of_conversion_uint(eGPUTextureFormat device_format)
case GPU_RGB10_A2:
case GPU_RGB10_A2UI:
case GPU_R11F_G11F_B10F:
case GPU_DEPTH32F_STENCIL8:
case GPU_DEPTH24_STENCIL8:
case GPU_SRGB8_A8:
case GPU_RGBA8_SNORM:
@ -304,8 +311,6 @@ static ConversionType type_of_conversion_uint(eGPUTextureFormat device_format)
case GPU_RGBA8_DXT5:
case GPU_SRGB8:
case GPU_RGB9_E5:
case GPU_DEPTH_COMPONENT32F:
case GPU_DEPTH_COMPONENT24:
case GPU_DEPTH_COMPONENT16:
return ConversionType::UNSUPPORTED;
}
@ -396,6 +401,7 @@ static ConversionType type_of_conversion_ubyte(eGPUTextureFormat device_format)
case GPU_RG8:
case GPU_R8UI:
case GPU_R8:
case GPU_SRGB8_A8:
return ConversionType::PASS_THROUGH;
case GPU_RGBA8I:
@ -427,7 +433,6 @@ static ConversionType type_of_conversion_ubyte(eGPUTextureFormat device_format)
case GPU_R11F_G11F_B10F:
case GPU_DEPTH32F_STENCIL8:
case GPU_DEPTH24_STENCIL8:
case GPU_SRGB8_A8:
case GPU_RGBA8_SNORM:
case GPU_RGBA16_SNORM:
case GPU_RGB8UI:
@ -523,6 +528,7 @@ static ConversionType reversed(ConversionType type)
CASE_PAIR(FLOAT, SNORM8)
CASE_PAIR(FLOAT, UNORM16)
CASE_PAIR(FLOAT, SNORM16)
CASE_PAIR(FLOAT, UNORM32)
CASE_PAIR(UI32, UI16)
CASE_PAIR(I32, I16)
CASE_PAIR(UI32, UI8)
@ -632,6 +638,7 @@ template<typename InnerType> struct SignedNormalized {
template<typename InnerType> struct UnsignedNormalized {
static_assert(std::is_same<InnerType, uint8_t>() || std::is_same<InnerType, uint16_t>() ||
std::is_same<InnerType, uint32_t>() ||
std::is_same<InnerType, DepthComponent24>());
InnerType value;
@ -645,15 +652,24 @@ template<typename InnerType> struct UnsignedNormalized {
}
}
static constexpr int32_t scalar()
static constexpr uint32_t scalar()
{
return (1 << (used_byte_size() * 8)) - 1;
if constexpr (std::is_same<InnerType, DepthComponent24>()) {
return (1 << (used_byte_size() * 8)) - 1;
}
else {
return std::numeric_limits<InnerType>::max();
}
}
static constexpr int32_t max()
static constexpr uint32_t max()
{
return ((1 << (used_byte_size() * 8)) - 1);
if constexpr (std::is_same<InnerType, DepthComponent24>()) {
return (1 << (used_byte_size() * 8)) - 1;
}
else {
return std::numeric_limits<InnerType>::max();
}
}
};
@ -674,15 +690,15 @@ template<typename StorageType> void convert(F32 &dst, const SignedNormalized<Sto
template<typename StorageType> void convert(UnsignedNormalized<StorageType> &dst, const F32 &src)
{
static constexpr int32_t scalar = UnsignedNormalized<StorageType>::scalar();
static constexpr int32_t max = scalar;
dst.value = (clamp_i((src.value * scalar), 0, max));
static constexpr uint32_t scalar = UnsignedNormalized<StorageType>::scalar();
static constexpr uint32_t max = scalar;
dst.value = (clamp_f((src.value * scalar), 0, max));
}
template<typename StorageType> void convert(F32 &dst, const UnsignedNormalized<StorageType> &src)
{
static constexpr int32_t scalar = UnsignedNormalized<StorageType>::scalar();
dst.value = float(int32_t(src.value)) / scalar;
static constexpr uint32_t scalar = UnsignedNormalized<StorageType>::scalar();
dst.value = float(uint32_t(src.value)) / scalar;
}
/* Copy the contents of src to dst with out performing any actual conversion. */
@ -860,6 +876,15 @@ static void convert_buffer(void *dst_memory,
dst_memory, src_memory, buffer_size, device_format);
break;
case ConversionType::FLOAT_TO_UNORM32:
convert_per_component<UnsignedNormalized<uint32_t>, F32>(
dst_memory, src_memory, buffer_size, device_format);
break;
case ConversionType::UNORM32_TO_FLOAT:
convert_per_component<F32, UnsignedNormalized<uint32_t>>(
dst_memory, src_memory, buffer_size, device_format);
break;
case ConversionType::FLOAT_TO_HALF:
convert_per_component<F16, F32>(dst_memory, src_memory, buffer_size, device_format);
break;

View File

@ -15,6 +15,17 @@
#include "vk_descriptor_pools.hh"
namespace blender::gpu {
class VKBackend;
struct VKWorkarounds {
/**
* Some devices don't support pixel formats that are aligned to 24 and 48 bits.
* In this case we need to use a different texture format.
*
* If set to true we should work around this issue by using a different texture format.
*/
bool not_aligned_pixel_formats = false;
};
class VKDevice : public NonCopyable {
private:
@ -35,6 +46,9 @@ class VKDevice : public NonCopyable {
/** Functions of vk_ext_debugutils for this device/instance. */
debug::VKDebuggingTools debugging_tools_;
/* Workarounds */
VKWorkarounds workarounds_;
public:
VkPhysicalDevice physical_device_get() const
{
@ -95,11 +109,19 @@ class VKDevice : public NonCopyable {
std::string vendor_name() const;
std::string driver_version() const;
const VKWorkarounds &workarounds_get() const
{
return workarounds_;
}
private:
void init_physical_device_properties();
void init_debug_callbacks();
void init_memory_allocator();
void init_descriptor_pools();
/* During initialization the backend requires access to update the workarounds. */
friend VKBackend;
};
} // namespace blender::gpu

View File

@ -914,6 +914,7 @@ bool VKShader::finalize_descriptor_set_layouts(VkDevice vk_device,
{
return false;
};
debug::object_label(layout_, name_get());
return true;
}

View File

@ -127,7 +127,7 @@ void VKStateManager::image_unbind(Texture *tex)
void VKStateManager::image_unbind_all()
{
for (TextureBinding &binding : texture_bindings_) {
for (ImageBinding &binding : image_bindings_) {
binding.texture = nullptr;
}
}

View File

@ -41,7 +41,56 @@ void VKTexture::init(VkImage vk_image, VkImageLayout layout)
void VKTexture::generate_mipmap()
{
NOT_YET_IMPLEMENTED
if (mipmaps_ <= 1) {
return;
}
ensure_allocated();
VKContext &context = *VKContext::get();
VKCommandBuffer &command_buffer = context.command_buffer_get();
layout_ensure(context, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
for (int src_mipmap : IndexRange(mipmaps_ - 1)) {
int dst_mipmap = src_mipmap + 1;
int3 src_size(1);
int3 dst_size(1);
mip_size_get(src_mipmap, src_size);
mip_size_get(dst_mipmap, dst_size);
layout_ensure(context,
IndexRange(src_mipmap, 1),
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
VkImageBlit image_blit = {};
image_blit.srcOffsets[0] = {0, 0, 0};
image_blit.srcOffsets[1] = {src_size.x, src_size.y, src_size.z};
image_blit.srcSubresource.aspectMask = to_vk_image_aspect_flag_bits(format_);
image_blit.srcSubresource.mipLevel = src_mipmap;
image_blit.srcSubresource.baseArrayLayer = 0;
image_blit.srcSubresource.layerCount = layer_count();
image_blit.dstOffsets[0] = {0, 0, 0};
image_blit.dstOffsets[1] = {dst_size.x, dst_size.y, dst_size.z};
image_blit.dstSubresource.aspectMask = to_vk_image_aspect_flag_bits(format_);
image_blit.dstSubresource.mipLevel = dst_mipmap;
image_blit.dstSubresource.baseArrayLayer = 0;
image_blit.dstSubresource.layerCount = layer_count();
command_buffer.blit(*this,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
*this,
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
Span<VkImageBlit>(&image_blit, 1));
}
/* Ensure that all mipmap levels are in `VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL`. All miplevels are
* except the last one. */
layout_ensure(context,
IndexRange(mipmaps_ - 1, 1),
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
current_layout_set(VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
}
void VKTexture::copy_to(Texture *tex)
@ -151,10 +200,6 @@ void *VKTexture::read(int mip, eGPUDataFormat format)
void VKTexture::update_sub(
int mip, int offset[3], int extent_[3], eGPUDataFormat format, const void *data)
{
if (mip != 0) {
NOT_YET_IMPLEMENTED;
return;
}
if (!is_allocated()) {
allocate();
}
@ -220,6 +265,15 @@ bool VKTexture::init_internal()
* at this moment, so we cannot initialize here. The initialization is postponed until the
* allocation of the texture on the device. */
const VKDevice &device = VKBackend::get().device_get();
const VKWorkarounds &workarounds = device.workarounds_get();
if (format_ == GPU_DEPTH_COMPONENT24 && workarounds.not_aligned_pixel_formats) {
format_ = GPU_DEPTH_COMPONENT32F;
}
if (format_ == GPU_DEPTH24_STENCIL8 && workarounds.not_aligned_pixel_formats) {
format_ = GPU_DEPTH32F_STENCIL8;
}
/* TODO: return false when texture format isn't supported. */
return true;
}
@ -330,7 +384,7 @@ bool VKTexture::allocate()
image_info.extent.width = extent[0];
image_info.extent.height = extent[1];
image_info.extent.depth = extent[2];
image_info.mipLevels = 1;
image_info.mipLevels = max_ii(mipmaps_, 1);
image_info.arrayLayers = 1;
image_info.format = to_vk_format(format_);
/* Some platforms (NVIDIA) requires that attached textures are always tiled optimal.
@ -449,16 +503,27 @@ void VKTexture::layout_ensure(VKContext &context, const VkImageLayout requested_
if (current_layout == requested_layout) {
return;
}
layout_ensure(context, IndexRange(0, VK_REMAINING_MIP_LEVELS), current_layout, requested_layout);
current_layout_set(requested_layout);
}
void VKTexture::layout_ensure(VKContext &context,
const IndexRange mipmap_range,
const VkImageLayout current_layout,
const VkImageLayout requested_layout)
{
BLI_assert(is_allocated());
VkImageMemoryBarrier barrier{};
barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
barrier.oldLayout = current_layout;
barrier.newLayout = requested_layout;
barrier.image = vk_image_;
barrier.subresourceRange.aspectMask = to_vk_image_aspect_flag_bits(format_);
barrier.subresourceRange.levelCount = VK_REMAINING_MIP_LEVELS;
barrier.subresourceRange.baseMipLevel = uint32_t(mipmap_range.start());
barrier.subresourceRange.levelCount = uint32_t(mipmap_range.size());
barrier.subresourceRange.baseArrayLayer = 0;
barrier.subresourceRange.layerCount = VK_REMAINING_ARRAY_LAYERS;
context.command_buffer_get().pipeline_barrier(Span<VkImageMemoryBarrier>(&barrier, 1));
current_layout_set(requested_layout);
}
/** \} */

View File

@ -111,6 +111,17 @@ class VKTexture : public Texture {
*/
void layout_ensure(VKContext &context, VkImageLayout requested_layout);
private:
/**
* Internal function to ensure the layout of a single mipmap level. Note that the caller is
* responsible to update the current_layout of the image at the end of the operation and make
* sure that all mipmap levels are in that given layout.
*/
void layout_ensure(VKContext &context,
IndexRange mipmap_range,
VkImageLayout current_layout,
VkImageLayout requested_layout);
/** \} */
};

View File

@ -14,6 +14,11 @@
namespace blender::gpu {
VKUniformBuffer::~VKUniformBuffer()
{
unbind();
}
void VKUniformBuffer::update(const void *data)
{
if (!buffer_.is_allocated()) {
@ -68,8 +73,10 @@ void VKUniformBuffer::bind_as_ssbo(int slot)
void VKUniformBuffer::unbind()
{
VKContext &context = *VKContext::get();
context.state_manager_get().uniform_buffer_unbind(this);
VKContext *context = VKContext::get();
if (context) {
context->state_manager_get().uniform_buffer_unbind(this);
}
}
} // namespace blender::gpu

View File

@ -21,6 +21,7 @@ class VKUniformBuffer : public UniformBuf, NonCopyable {
public:
VKUniformBuffer(int size, const char *name) : UniformBuf(size, name) {}
~VKUniformBuffer();
void update(const void *data) override;
void clear_to_zero() override;

View File

@ -119,9 +119,9 @@ void VKVertexBuffer::resize_data()
void VKVertexBuffer::release_data()
{
if (should_unbind_) {
VKContext &context = *VKContext::get();
context.state_manager_get().texel_buffer_unbind(this);
VKContext *context = VKContext::get();
if (should_unbind_ && context) {
context->state_manager_get().texel_buffer_unbind(this);
}
if (vk_buffer_view_ != VK_NULL_HANDLE) {

View File

@ -453,9 +453,9 @@ typedef struct GreasePencil {
void remove_drawing(int index);
void foreach_visible_drawing(int frame,
blender::FunctionRef<void(GreasePencilDrawing &)> function);
blender::FunctionRef<void(int, GreasePencilDrawing &)> function);
void foreach_editable_drawing(int frame,
blender::FunctionRef<void(GreasePencilDrawing &)> function);
blender::FunctionRef<void(int, GreasePencilDrawing &)> function);
bool bounds_min_max(blender::float3 &min, blender::float3 &max) const;

View File

@ -725,6 +725,38 @@ static void rna_ID_asset_clear(ID *id)
}
}
static void rna_ID_asset_data_set(PointerRNA *ptr, PointerRNA value, struct ReportList *reports)
{
ID *destination = ptr->data;
/* Avoid marking as asset by assigning. This should be done wiht .asset_mark(). This is just for
* clarity of the API, and to accomodate future changes. */
if (destination->asset_data == NULL) {
BKE_report(reports,
RPT_ERROR,
"Asset data can only be assigned to assets. Use asset_mark() to mark as an asset");
return;
}
const AssetMetaData *asset_data = value.data;
if (asset_data == NULL) {
/* Avoid clearing the asset data on assets. Un-marking as asset should be done with
* .asset_clear(). This is just for clarity of the API, and to accomodate future changes. */
BKE_report(reports, RPT_ERROR, "Asset data cannot be None");
return;
}
const bool assigned_ok = ED_asset_copy_to_id(asset_data, destination);
if (!assigned_ok) {
BKE_reportf(
reports, RPT_ERROR, "'%s' is of a type that cannot be an asset", destination->name + 2);
return;
}
WM_main_add_notifier(NC_ASSET | NA_EDITED, NULL);
WM_main_add_notifier(NC_ID | NA_EDITED, NULL);
}
static ID *rna_ID_override_create(ID *id, Main *bmain, bool remap_local_usages)
{
if (!ID_IS_OVERRIDABLE_LIBRARY(id)) {
@ -2131,7 +2163,8 @@ static void rna_def_ID(BlenderRNA *brna)
RNA_def_property_override_flag(prop, PROPOVERRIDE_NO_COMPARISON);
prop = RNA_def_property(srna, "asset_data", PROP_POINTER, PROP_NONE);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_flag(prop, PROP_EDITABLE);
RNA_def_property_pointer_funcs(prop, NULL, "rna_ID_asset_data_set", NULL, NULL);
RNA_def_property_override_flag(prop, PROPOVERRIDE_NO_COMPARISON);
RNA_def_property_ui_text(prop, "Asset Data", "Additional data for an asset data-block");

View File

@ -1637,6 +1637,7 @@ void RNA_api_ui_layout(StructRNA *srna)
parm = RNA_def_pointer(func, "image_settings", "ImageFormatSettings", "", "");
RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
RNA_def_boolean(func, "color_management", false, "", "Show color management settings");
RNA_def_boolean(func, "show_z_buffer", true, "", "Show option to save z-buffer");
func = RNA_def_function(srna, "template_image_stereo_3d", "uiTemplateImageStereo3d");
RNA_def_function_ui_description(func, "User interface for setting image stereo 3d options");

View File

@ -305,9 +305,11 @@ static void node_composit_buts_file_output_ex(uiLayout *layout, bContext *C, Poi
const bool multilayer = RNA_enum_get(&imfptr, "file_format") == R_IMF_IMTYPE_MULTILAYER;
const bool is_exr = RNA_enum_get(&imfptr, "file_format") == R_IMF_IMTYPE_OPENEXR;
const bool is_multiview = (scene->r.scemode & R_MULTIVIEW) != 0;
/* Unclear where to get z-information from, so deactivate it. */
const bool show_z_buffer = false;
node_composit_buts_file_output(layout, C, ptr);
uiTemplateImageSettings(layout, &imfptr, true);
uiTemplateImageSettings(layout, &imfptr, true, show_z_buffer);
/* disable stereo output for multilayer, too much work for something that no one will use */
/* if someone asks for that we can implement it */
@ -430,7 +432,7 @@ static void node_composit_buts_file_output_ex(uiLayout *layout, bContext *C, Poi
const bool use_color_management = RNA_boolean_get(&active_input_ptr, "save_as_render");
col = uiLayoutColumn(layout, false);
uiTemplateImageSettings(col, &imfptr, use_color_management);
uiTemplateImageSettings(col, &imfptr, use_color_management, show_z_buffer);
if (is_multiview) {
col = uiLayoutColumn(layout, false);