WIP: Brush assets project #106303
|
@ -6173,6 +6173,7 @@ def km_edit_curves(params):
|
|||
{"properties": [("mode", 'CURVE_SHRINKFATTEN')]}),
|
||||
("curves.cyclic_toggle", {"type": 'C', "value": 'PRESS', "alt": True}, None),
|
||||
("curves.handle_type_set", {"type": 'V', "value": 'PRESS'}, None),
|
||||
op_menu("VIEW3D_MT_edit_curves_add", {"type": 'A', "value": 'PRESS', "shift": True}),
|
||||
])
|
||||
|
||||
return keymap
|
||||
|
|
|
@ -1204,6 +1204,8 @@ class VIEW3D_MT_editor_menus(Menu):
|
|||
layout.menu("VIEW3D_MT_mesh_add", text="Add", text_ctxt=i18n_contexts.operator_default)
|
||||
elif mode_string == 'EDIT_CURVE':
|
||||
layout.menu("VIEW3D_MT_curve_add", text="Add", text_ctxt=i18n_contexts.operator_default)
|
||||
elif mode_string == "EDIT_CURVES":
|
||||
layout.menu("VIEW3D_MT_edit_curves_add", text="Add", text_ctxt=i18n_contexts.operator_default)
|
||||
elif mode_string == 'EDIT_SURFACE':
|
||||
layout.menu("VIEW3D_MT_surface_add", text="Add", text_ctxt=i18n_contexts.operator_default)
|
||||
elif mode_string == 'EDIT_METABALL':
|
||||
|
@ -5945,6 +5947,16 @@ class VIEW3D_MT_edit_greasepencil_point(Menu):
|
|||
layout.operator("grease_pencil.stroke_smooth", text="Smooth")
|
||||
|
||||
|
||||
class VIEW3D_MT_edit_curves_add(Menu):
|
||||
bl_label = "Add"
|
||||
|
||||
def draw(self, _context):
|
||||
layout = self.layout
|
||||
|
||||
layout.operator("curves.add_bezier", text="Bezier", icon='CURVE_BEZCURVE')
|
||||
layout.operator("curves.add_circle", text="Circle", icon='CURVE_BEZCIRCLE')
|
||||
|
||||
|
||||
class VIEW3D_MT_edit_curves(Menu):
|
||||
bl_label = "Curves"
|
||||
|
||||
|
@ -9182,6 +9194,7 @@ classes = (
|
|||
VIEW3D_MT_edit_armature_delete,
|
||||
VIEW3D_MT_edit_gpencil_transform,
|
||||
VIEW3D_MT_edit_curves,
|
||||
VIEW3D_MT_edit_curves_add,
|
||||
VIEW3D_MT_edit_curves_segments,
|
||||
VIEW3D_MT_edit_curves_control_points,
|
||||
VIEW3D_MT_edit_pointcloud,
|
||||
|
|
|
@ -603,7 +603,10 @@ void ANIM_armature_bonecoll_name_set(bArmature *armature, BoneCollection *bcoll,
|
|||
|
||||
bonecoll_ensure_name_unique(armature, bcoll);
|
||||
|
||||
/* Bone collections can be reached via .collections (4.0+) and .collections_all (4.1+).
|
||||
* Animation data from 4.0 should have been versioned to only use `.collections_all`. */
|
||||
BKE_animdata_fix_paths_rename_all(&armature->id, "collections", old_name, bcoll->name);
|
||||
BKE_animdata_fix_paths_rename_all(&armature->id, "collections_all", old_name, bcoll->name);
|
||||
}
|
||||
|
||||
void ANIM_armature_bonecoll_remove_from_index(bArmature *armature, int index)
|
||||
|
|
|
@ -892,8 +892,12 @@ static bool nlastrips_path_rename_fix(ID *owner_id,
|
|||
LISTBASE_FOREACH (NlaStrip *, strip, strips) {
|
||||
/* fix strip's action */
|
||||
if (strip->act != nullptr) {
|
||||
is_changed |= fcurves_path_rename_fix(
|
||||
const bool is_changed_action = fcurves_path_rename_fix(
|
||||
owner_id, prefix, oldName, newName, oldKey, newKey, &strip->act->curves, verify_paths);
|
||||
if (is_changed_action) {
|
||||
DEG_id_tag_update(&strip->act->id, ID_RECALC_ANIMATION);
|
||||
}
|
||||
is_changed |= is_changed_action;
|
||||
}
|
||||
/* Ignore own F-Curves, since those are local. */
|
||||
/* Check sub-strips (if meta-strips). */
|
||||
|
|
|
@ -248,6 +248,23 @@ static void version_bonegroups_to_bonecollections(Main *bmain)
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Change animation/drivers from "collections[..." to "collections_all[..." so
|
||||
* they remain stable when the bone collection hierarchy structure changes.
|
||||
*/
|
||||
static void version_bonecollection_anim(FCurve *fcurve)
|
||||
{
|
||||
const blender::StringRef rna_path(fcurve->rna_path);
|
||||
constexpr char const *rna_path_prefix = "collections[";
|
||||
if (!rna_path.startswith(rna_path_prefix)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const std::string path_remainder(rna_path.drop_known_prefix(rna_path_prefix));
|
||||
MEM_freeN(fcurve->rna_path);
|
||||
fcurve->rna_path = BLI_sprintfN("collections_all[%s", path_remainder.c_str());
|
||||
}
|
||||
|
||||
static void version_principled_bsdf_update_animdata(ID *owner_id, bNodeTree *ntree)
|
||||
{
|
||||
ID *id = &ntree->id;
|
||||
|
@ -498,6 +515,27 @@ void do_versions_after_linking_400(FileData *fd, Main *bmain)
|
|||
version_nla_tweakmode_incomplete(bmain);
|
||||
}
|
||||
|
||||
if (!MAIN_VERSION_FILE_ATLEAST(bmain, 402, 15)) {
|
||||
/* Change drivers and animation on "armature.collections" to
|
||||
* ".collections_all", so that they are drawn correctly in the tree view,
|
||||
* and keep working when the collection is moved around in the hierarchy. */
|
||||
LISTBASE_FOREACH (bArmature *, arm, &bmain->armatures) {
|
||||
AnimData *adt = BKE_animdata_from_id(&arm->id);
|
||||
if (!adt) {
|
||||
continue;
|
||||
}
|
||||
|
||||
LISTBASE_FOREACH (FCurve *, fcurve, &adt->drivers) {
|
||||
version_bonecollection_anim(fcurve);
|
||||
}
|
||||
if (adt->action) {
|
||||
LISTBASE_FOREACH (FCurve *, fcurve, &adt->action->curves) {
|
||||
version_bonecollection_anim(fcurve);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Always bump subversion in BKE_blender_version.h when adding versioning
|
||||
* code here, and wrap it inside a MAIN_VERSION_FILE_ATLEAST check.
|
||||
|
|
|
@ -968,7 +968,13 @@ void DepsgraphNodeBuilder::build_object_modifiers(Object *object)
|
|||
|
||||
BuilderWalkUserData data;
|
||||
data.builder = this;
|
||||
|
||||
/* Temporarily set the collection visibility to false, relying on the visibility flushing code
|
||||
* to flush the visibility from a modifier into collections it depends on. */
|
||||
const bool is_current_parent_collection_visible = is_parent_collection_visible_;
|
||||
is_parent_collection_visible_ = false;
|
||||
BKE_modifiers_foreach_ID_link(object, modifier_walk, &data);
|
||||
is_parent_collection_visible_ = is_current_parent_collection_visible;
|
||||
}
|
||||
|
||||
void DepsgraphNodeBuilder::build_object_data(Object *object)
|
||||
|
|
|
@ -63,9 +63,11 @@
|
|||
#include "UI_interface.hh"
|
||||
#include "UI_resources.hh"
|
||||
|
||||
#include "GEO_join_geometries.hh"
|
||||
#include "GEO_reverse_uv_sampler.hh"
|
||||
#include "GEO_set_curve_type.hh"
|
||||
#include "GEO_subdivide_curves.hh"
|
||||
#include "GEO_transform.hh"
|
||||
|
||||
/**
|
||||
* The code below uses a suffix naming convention to indicate the coordinate space:
|
||||
|
@ -1527,6 +1529,169 @@ static void CURVES_OT_subdivide(wmOperatorType *ot)
|
|||
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
|
||||
}
|
||||
|
||||
/** Add new curves primitive to an existing curves object in edit mode. */
|
||||
static void append_primitive_curve(bContext *C,
|
||||
Curves &curves_id,
|
||||
CurvesGeometry new_curves,
|
||||
wmOperator &op)
|
||||
{
|
||||
const int new_points_num = new_curves.points_num();
|
||||
const int new_curves_num = new_curves.curves_num();
|
||||
|
||||
/* Create geometry sets so that generic join code can be used. */
|
||||
bke::GeometrySet old_geometry = bke::GeometrySet::from_curves(
|
||||
&curves_id, bke::GeometryOwnershipType::ReadOnly);
|
||||
bke::GeometrySet new_geometry = bke::GeometrySet::from_curves(
|
||||
bke::curves_new_nomain(std::move(new_curves)));
|
||||
|
||||
/* Transform primitive according to settings. */
|
||||
float3 location;
|
||||
float3 rotation;
|
||||
float3 scale;
|
||||
object::add_generic_get_opts(C, &op, 'Z', location, rotation, scale, nullptr, nullptr, nullptr);
|
||||
const float4x4 transform = math::from_loc_rot_scale<float4x4>(
|
||||
location, math::EulerXYZ(rotation), scale);
|
||||
geometry::transform_geometry(new_geometry, transform);
|
||||
|
||||
bke::GeometrySet joined_geometry = geometry::join_geometries({old_geometry, new_geometry}, {});
|
||||
Curves *joined_curves_id = joined_geometry.get_curves_for_write();
|
||||
CurvesGeometry &dst_curves = curves_id.geometry.wrap();
|
||||
dst_curves = std::move(joined_curves_id->geometry.wrap());
|
||||
|
||||
/* Only select the new curves. */
|
||||
const bke::AttrDomain selection_domain = bke::AttrDomain(curves_id.selection_domain);
|
||||
const int new_element_num = selection_domain == bke::AttrDomain::Point ? new_points_num :
|
||||
new_curves_num;
|
||||
foreach_selection_attribute_writer(
|
||||
dst_curves, selection_domain, [&](bke::GSpanAttributeWriter &selection) {
|
||||
fill_selection_false(selection.span.drop_back(new_element_num));
|
||||
fill_selection_true(selection.span.take_back(new_element_num));
|
||||
});
|
||||
|
||||
dst_curves.tag_topology_changed();
|
||||
}
|
||||
|
||||
namespace add_circle {
|
||||
|
||||
static CurvesGeometry generate_circle_primitive(const float radius)
|
||||
{
|
||||
CurvesGeometry curves{4, 1};
|
||||
|
||||
MutableSpan<int> offsets = curves.offsets_for_write();
|
||||
offsets[0] = 0;
|
||||
offsets[1] = 4;
|
||||
|
||||
curves.fill_curve_types(CURVE_TYPE_BEZIER);
|
||||
curves.cyclic_for_write().fill(true);
|
||||
curves.handle_types_left_for_write().fill(BEZIER_HANDLE_AUTO);
|
||||
curves.handle_types_right_for_write().fill(BEZIER_HANDLE_AUTO);
|
||||
curves.resolution_for_write().fill(12);
|
||||
|
||||
MutableSpan<float3> positions = curves.positions_for_write();
|
||||
positions[0] = float3(-radius, 0, 0);
|
||||
positions[1] = float3(0, radius, 0);
|
||||
positions[2] = float3(radius, 0, 0);
|
||||
positions[3] = float3(0, -radius, 0);
|
||||
|
||||
/* Ensure these attributes exist. */
|
||||
curves.handle_positions_left_for_write();
|
||||
curves.handle_positions_right_for_write();
|
||||
|
||||
curves.calculate_bezier_auto_handles();
|
||||
|
||||
return curves;
|
||||
}
|
||||
|
||||
static int exec(bContext *C, wmOperator *op)
|
||||
{
|
||||
Object *object = CTX_data_edit_object(C);
|
||||
Curves *active_curves_id = static_cast<Curves *>(object->data);
|
||||
|
||||
const float radius = RNA_float_get(op->ptr, "radius");
|
||||
append_primitive_curve(C, *active_curves_id, generate_circle_primitive(radius), *op);
|
||||
|
||||
DEG_id_tag_update(&active_curves_id->id, ID_RECALC_GEOMETRY);
|
||||
WM_event_add_notifier(C, NC_GEOM | ND_DATA, active_curves_id);
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
} // namespace add_circle
|
||||
|
||||
static void CURVES_OT_add_circle(wmOperatorType *ot)
|
||||
{
|
||||
ot->name = "Add Circle";
|
||||
ot->idname = __func__;
|
||||
ot->description = "Add new circle curve";
|
||||
|
||||
ot->exec = add_circle::exec;
|
||||
ot->poll = editable_curves_in_edit_mode_poll;
|
||||
|
||||
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
||||
|
||||
object::add_unit_props_radius(ot);
|
||||
object::add_generic_props(ot, true);
|
||||
}
|
||||
|
||||
namespace add_bezier {
|
||||
|
||||
static CurvesGeometry generate_bezier_primitive(const float radius)
|
||||
{
|
||||
CurvesGeometry curves{2, 1};
|
||||
|
||||
MutableSpan<int> offsets = curves.offsets_for_write();
|
||||
offsets[0] = 0;
|
||||
offsets[1] = 2;
|
||||
|
||||
curves.fill_curve_types(CURVE_TYPE_BEZIER);
|
||||
curves.handle_types_left_for_write().fill(BEZIER_HANDLE_ALIGN);
|
||||
curves.handle_types_right_for_write().fill(BEZIER_HANDLE_ALIGN);
|
||||
curves.resolution_for_write().fill(12);
|
||||
|
||||
MutableSpan<float3> positions = curves.positions_for_write();
|
||||
MutableSpan<float3> left_handles = curves.handle_positions_left_for_write();
|
||||
MutableSpan<float3> right_handles = curves.handle_positions_right_for_write();
|
||||
|
||||
left_handles[0] = float3(-1.5f, -0.5, 0) * radius;
|
||||
positions[0] = float3(-1.0f, 0, 0) * radius;
|
||||
right_handles[0] = float3(-0.5f, 0.5f, 0) * radius;
|
||||
|
||||
left_handles[1] = float3(0, 0, 0) * radius;
|
||||
positions[1] = float3(1.0f, 0, 0) * radius;
|
||||
right_handles[1] = float3(2.0f, 0, 0) * radius;
|
||||
|
||||
return curves;
|
||||
}
|
||||
|
||||
static int exec(bContext *C, wmOperator *op)
|
||||
{
|
||||
Object *object = CTX_data_edit_object(C);
|
||||
Curves *active_curves_id = static_cast<Curves *>(object->data);
|
||||
|
||||
const float radius = RNA_float_get(op->ptr, "radius");
|
||||
append_primitive_curve(C, *active_curves_id, generate_bezier_primitive(radius), *op);
|
||||
|
||||
DEG_id_tag_update(&active_curves_id->id, ID_RECALC_GEOMETRY);
|
||||
WM_event_add_notifier(C, NC_GEOM | ND_DATA, active_curves_id);
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
} // namespace add_bezier
|
||||
|
||||
static void CURVES_OT_add_bezier(wmOperatorType *ot)
|
||||
{
|
||||
ot->name = "Add Bezier";
|
||||
ot->idname = __func__;
|
||||
ot->description = "Add new bezier curve";
|
||||
|
||||
ot->exec = add_bezier::exec;
|
||||
ot->poll = editable_curves_in_edit_mode_poll;
|
||||
|
||||
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
||||
|
||||
object::add_unit_props_radius(ot);
|
||||
object::add_generic_props(ot, true);
|
||||
}
|
||||
|
||||
namespace set_handle_type {
|
||||
|
||||
static int exec(bContext *C, wmOperator *op)
|
||||
|
@ -1608,6 +1773,8 @@ void operatortypes_curves()
|
|||
WM_operatortype_append(CURVES_OT_curve_type_set);
|
||||
WM_operatortype_append(CURVES_OT_switch_direction);
|
||||
WM_operatortype_append(CURVES_OT_subdivide);
|
||||
WM_operatortype_append(CURVES_OT_add_circle);
|
||||
WM_operatortype_append(CURVES_OT_add_bezier);
|
||||
WM_operatortype_append(CURVES_OT_handle_type_set);
|
||||
}
|
||||
|
||||
|
|
|
@ -1378,8 +1378,8 @@ static void create_inspection_string_for_field_info(const bNodeSocket &socket,
|
|||
ss << "\n";
|
||||
|
||||
for (const int i : input_tooltips.index_range()) {
|
||||
const blender::StringRef tooltip = input_tooltips[i];
|
||||
ss << fmt::format(TIP_("\u2022 {}"), TIP_(tooltip.data()));
|
||||
const blender::StringRefNull tooltip = input_tooltips[i];
|
||||
ss << fmt::format(TIP_("\u2022 {}"), TIP_(tooltip.c_str()));
|
||||
if (i < input_tooltips.size() - 1) {
|
||||
ss << ".\n";
|
||||
}
|
||||
|
@ -1461,15 +1461,16 @@ static void create_inspection_string_for_geometry_info(const geo_log::GeometryIn
|
|||
break;
|
||||
}
|
||||
case bke::GeometryComponent::Type::GreasePencil: {
|
||||
const geo_log::GeometryInfoLog::GreasePencilInfo &grease_pencil_info =
|
||||
*value_log.grease_pencil_info;
|
||||
char line[256];
|
||||
SNPRINTF(line,
|
||||
TIP_("\u2022 Grease Pencil: %s layers"),
|
||||
to_string(grease_pencil_info.layers_num).c_str());
|
||||
ss << line;
|
||||
break;
|
||||
break;
|
||||
if (U.experimental.use_grease_pencil_version3) {
|
||||
const geo_log::GeometryInfoLog::GreasePencilInfo &grease_pencil_info =
|
||||
*value_log.grease_pencil_info;
|
||||
char line[256];
|
||||
SNPRINTF(line,
|
||||
TIP_("\u2022 Grease Pencil: %s layers"),
|
||||
to_string(grease_pencil_info.layers_num).c_str());
|
||||
ss << line;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (type != component_types.last()) {
|
||||
|
@ -1592,9 +1593,9 @@ static std::string node_socket_get_tooltip(const SpaceNode *snode,
|
|||
std::stringstream output;
|
||||
if (socket.runtime->declaration != nullptr) {
|
||||
const blender::nodes::SocketDeclaration &socket_decl = *socket.runtime->declaration;
|
||||
blender::StringRef description = socket_decl.description;
|
||||
blender::StringRefNull description = socket_decl.description;
|
||||
if (!description.is_empty()) {
|
||||
output << TIP_(description.data());
|
||||
output << TIP_(description.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -74,6 +74,62 @@ enum class Type {
|
|||
SHORT4
|
||||
};
|
||||
|
||||
BLI_INLINE int to_component_count(const Type &type)
|
||||
{
|
||||
switch (type) {
|
||||
case Type::FLOAT:
|
||||
case Type::UINT:
|
||||
case Type::INT:
|
||||
case Type::BOOL:
|
||||
return 1;
|
||||
case Type::VEC2:
|
||||
case Type::UVEC2:
|
||||
case Type::IVEC2:
|
||||
return 2;
|
||||
case Type::VEC3:
|
||||
case Type::UVEC3:
|
||||
case Type::IVEC3:
|
||||
return 3;
|
||||
case Type::VEC4:
|
||||
case Type::UVEC4:
|
||||
case Type::IVEC4:
|
||||
return 4;
|
||||
case Type::MAT3:
|
||||
return 9;
|
||||
case Type::MAT4:
|
||||
return 16;
|
||||
/* Alias special types. */
|
||||
case Type::UCHAR:
|
||||
case Type::USHORT:
|
||||
return 1;
|
||||
case Type::UCHAR2:
|
||||
case Type::USHORT2:
|
||||
return 2;
|
||||
case Type::UCHAR3:
|
||||
case Type::USHORT3:
|
||||
return 3;
|
||||
case Type::UCHAR4:
|
||||
case Type::USHORT4:
|
||||
return 4;
|
||||
case Type::CHAR:
|
||||
case Type::SHORT:
|
||||
return 1;
|
||||
case Type::CHAR2:
|
||||
case Type::SHORT2:
|
||||
return 2;
|
||||
case Type::CHAR3:
|
||||
case Type::SHORT3:
|
||||
return 3;
|
||||
case Type::CHAR4:
|
||||
case Type::SHORT4:
|
||||
return 4;
|
||||
case Type::VEC3_101010I2:
|
||||
return 3;
|
||||
}
|
||||
BLI_assert_unreachable();
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* All of these functions is a bit out of place */
|
||||
static inline Type to_type(const eGPUType type)
|
||||
{
|
||||
|
|
|
@ -155,7 +155,7 @@ class MTLFrameBuffer : public FrameBuffer {
|
|||
|
||||
protected:
|
||||
void subpass_transition_impl(const GPUAttachmentState /*depth_attachment_state*/,
|
||||
Span<GPUAttachmentState> /*color_attachment_states*/) override{};
|
||||
Span<GPUAttachmentState> color_attachment_states) override;
|
||||
|
||||
public:
|
||||
void apply_state();
|
||||
|
|
|
@ -472,6 +472,27 @@ void MTLFrameBuffer::clear_attachment(GPUAttachmentType type,
|
|||
this->force_clear();
|
||||
}
|
||||
}
|
||||
void MTLFrameBuffer::subpass_transition_impl(const GPUAttachmentState /*depth_attachment_state*/,
|
||||
Span<GPUAttachmentState> color_attachment_states)
|
||||
{
|
||||
const bool is_tile_based_arch = (GPU_platform_architecture() == GPU_ARCHITECTURE_TBDR);
|
||||
if (!is_tile_based_arch) {
|
||||
/* Break renderpass if tile memory is unsupported to ensure current framebuffer results are
|
||||
* stored. */
|
||||
context_->main_command_buffer.end_active_command_encoder();
|
||||
|
||||
/* Bind framebuffer attachments as textures.
|
||||
* NOTE: Follows behaviour of gl_framebuffer. However, shaders utilising subpass_in will
|
||||
* need to avoid bindpoint collisions for image/texture resources. */
|
||||
for (int i : color_attachment_states.index_range()) {
|
||||
GPUAttachmentType type = GPU_FB_COLOR_ATTACHMENT0 + i;
|
||||
GPUTexture *attach_tex = this->attachments_[type].tex;
|
||||
if (color_attachment_states[i] == GPU_ATTACHEMENT_READ) {
|
||||
GPU_texture_image_bind(attach_tex, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MTLFrameBuffer::read(eGPUFrameBufferBits planes,
|
||||
eGPUDataFormat format,
|
||||
|
|
|
@ -414,6 +414,7 @@ class MSLGeneratorInterface {
|
|||
blender::Vector<MSLConstant> constants;
|
||||
/* Fragment tile inputs. */
|
||||
blender::Vector<MSLFragmentTileInputAttribute> fragment_tile_inputs;
|
||||
bool supports_native_tile_inputs;
|
||||
/* Should match vertex outputs, but defined separately as
|
||||
* some shader permutations will not utilize all inputs/outputs.
|
||||
* Final shader uses the intersection between the two sets. */
|
||||
|
|
|
@ -2089,6 +2089,16 @@ void MSLGeneratorInterface::prepare_from_createinfo(const shader::ShaderCreateIn
|
|||
fragment_outputs.append(mtl_frag_out);
|
||||
}
|
||||
|
||||
/** Identify support for tile inputs. */
|
||||
const bool is_tile_based_arch = (GPU_platform_architecture() == GPU_ARCHITECTURE_TBDR);
|
||||
if (is_tile_based_arch) {
|
||||
supports_native_tile_inputs = true;
|
||||
}
|
||||
else {
|
||||
/* NOTE: If emulating tile input reads, we must ensure we also expose position data. */
|
||||
supports_native_tile_inputs = false;
|
||||
}
|
||||
|
||||
/* Fragment tile inputs. */
|
||||
for (const shader::ShaderCreateInfo::SubpassIn &frag_tile_in : create_info_->subpass_inputs_) {
|
||||
|
||||
|
@ -2107,6 +2117,51 @@ void MSLGeneratorInterface::prepare_from_createinfo(const shader::ShaderCreateIn
|
|||
mtl_frag_in.raster_order_group = frag_tile_in.raster_order_group;
|
||||
|
||||
fragment_tile_inputs.append(mtl_frag_in);
|
||||
|
||||
/* If we do not support native tile inputs, generate an image-binding per input. */
|
||||
if (!supports_native_tile_inputs) {
|
||||
/* Determine type: */
|
||||
bool is_layered_fb = bool(create_info_->builtins_ & BuiltinBits::LAYER);
|
||||
/* Start with invalid value to detect failure cases. */
|
||||
ImageType image_type = ImageType::FLOAT_BUFFER;
|
||||
switch (frag_tile_in.type) {
|
||||
case Type::FLOAT:
|
||||
image_type = is_layered_fb ? ImageType::FLOAT_2D_ARRAY : ImageType::FLOAT_2D;
|
||||
break;
|
||||
case Type::INT:
|
||||
image_type = is_layered_fb ? ImageType::INT_2D_ARRAY : ImageType::INT_2D;
|
||||
break;
|
||||
case Type::UINT:
|
||||
image_type = is_layered_fb ? ImageType::UINT_2D_ARRAY : ImageType::UINT_2D;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
BLI_assert(image_type != ImageType::FLOAT_BUFFER);
|
||||
|
||||
/* Generate texture binding resource. */
|
||||
MSLTextureResource msl_image;
|
||||
msl_image.stage = ShaderStage::FRAGMENT;
|
||||
msl_image.type = image_type;
|
||||
msl_image.name = frag_tile_in.name + "_subpass_img";
|
||||
msl_image.access = MSLTextureSamplerAccess::TEXTURE_ACCESS_READ;
|
||||
msl_image.slot = texture_slot_id++;
|
||||
/* WATCH: We don't have a great place to generate the image bindings.
|
||||
* So we will use the subpass binding index and check if it collides with an existing
|
||||
* binding. */
|
||||
msl_image.location = frag_tile_in.index;
|
||||
msl_image.is_texture_sampler = false;
|
||||
BLI_assert(msl_image.slot < MTL_MAX_TEXTURE_SLOTS);
|
||||
BLI_assert(msl_image.location < MTL_MAX_TEXTURE_SLOTS);
|
||||
|
||||
/* Check existing samplers. */
|
||||
for (const auto &tex : texture_samplers) {
|
||||
BLI_assert(tex.location != msl_image.location);
|
||||
}
|
||||
|
||||
texture_samplers.append(msl_image);
|
||||
max_tex_bind_index = max_ii(max_tex_bind_index, msl_image.slot);
|
||||
}
|
||||
}
|
||||
|
||||
/* Transform feedback. */
|
||||
|
@ -3043,10 +3098,31 @@ std::string MSLGeneratorInterface::generate_msl_global_uniform_population(Shader
|
|||
std::string MSLGeneratorInterface::generate_msl_fragment_tile_input_population()
|
||||
{
|
||||
std::stringstream out;
|
||||
for (const MSLFragmentTileInputAttribute &tile_input : this->fragment_tile_inputs) {
|
||||
out << "\t" << get_shader_stage_instance_name(ShaderStage::FRAGMENT) << "." << tile_input.name
|
||||
<< " = "
|
||||
<< "fragment_tile_in." << tile_input.name << ";" << std::endl;
|
||||
|
||||
/* Native tile read is supported on tile-based architectures (Apple Silicon). */
|
||||
if (supports_native_tile_inputs) {
|
||||
for (const MSLFragmentTileInputAttribute &tile_input : this->fragment_tile_inputs) {
|
||||
out << "\t" << get_shader_stage_instance_name(ShaderStage::FRAGMENT) << "."
|
||||
<< tile_input.name << " = "
|
||||
<< "fragment_tile_in." << tile_input.name << ";" << std::endl;
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (const MSLFragmentTileInputAttribute &tile_input : this->fragment_tile_inputs) {
|
||||
/* Get read swizzle mask. */
|
||||
char swizzle[] = "xyzw";
|
||||
swizzle[to_component_count(tile_input.type)] = '\0';
|
||||
|
||||
bool is_layered_fb = bool(create_info_->builtins_ & BuiltinBits::LAYER);
|
||||
std::string texel_co = (is_layered_fb) ?
|
||||
"ivec3(ivec2(v_in._default_position_.xy), int(v_in.gpu_Layer))" :
|
||||
"ivec2(v_in._default_position_.xy)";
|
||||
|
||||
out << "\t" << get_shader_stage_instance_name(ShaderStage::FRAGMENT) << "."
|
||||
<< tile_input.name << " = texelFetch("
|
||||
<< get_shader_stage_instance_name(ShaderStage::FRAGMENT) << "." << tile_input.name
|
||||
<< "_subpass_img, " << texel_co << ", 0)." << swizzle << ";\n";
|
||||
}
|
||||
}
|
||||
return out.str();
|
||||
}
|
||||
|
|
|
@ -144,62 +144,6 @@ static const char *to_string(const Type &type)
|
|||
return "unknown";
|
||||
}
|
||||
|
||||
static int to_component_count(const Type &type)
|
||||
{
|
||||
switch (type) {
|
||||
case Type::FLOAT:
|
||||
case Type::UINT:
|
||||
case Type::INT:
|
||||
case Type::BOOL:
|
||||
return 1;
|
||||
case Type::VEC2:
|
||||
case Type::UVEC2:
|
||||
case Type::IVEC2:
|
||||
return 2;
|
||||
case Type::VEC3:
|
||||
case Type::UVEC3:
|
||||
case Type::IVEC3:
|
||||
return 3;
|
||||
case Type::VEC4:
|
||||
case Type::UVEC4:
|
||||
case Type::IVEC4:
|
||||
return 4;
|
||||
case Type::MAT3:
|
||||
return 9;
|
||||
case Type::MAT4:
|
||||
return 16;
|
||||
/* Alias special types. */
|
||||
case Type::UCHAR:
|
||||
case Type::USHORT:
|
||||
return 1;
|
||||
case Type::UCHAR2:
|
||||
case Type::USHORT2:
|
||||
return 2;
|
||||
case Type::UCHAR3:
|
||||
case Type::USHORT3:
|
||||
return 3;
|
||||
case Type::UCHAR4:
|
||||
case Type::USHORT4:
|
||||
return 4;
|
||||
case Type::CHAR:
|
||||
case Type::SHORT:
|
||||
return 1;
|
||||
case Type::CHAR2:
|
||||
case Type::SHORT2:
|
||||
return 2;
|
||||
case Type::CHAR3:
|
||||
case Type::SHORT3:
|
||||
return 3;
|
||||
case Type::CHAR4:
|
||||
case Type::SHORT4:
|
||||
return 4;
|
||||
case Type::VEC3_101010I2:
|
||||
return 3;
|
||||
}
|
||||
BLI_assert_unreachable();
|
||||
return -1;
|
||||
}
|
||||
|
||||
static Type to_component_type(const Type &type)
|
||||
{
|
||||
switch (type) {
|
||||
|
|
|
@ -470,7 +470,8 @@ static void interpolate_curve_attributes(bke::CurvesGeometry &child_curves,
|
|||
if (type == CD_PROP_STRING) {
|
||||
return true;
|
||||
}
|
||||
if (guide_curve_attributes.is_builtin(id) && !ELEM(id.name(), "radius", "tilt", "resolution"))
|
||||
if (guide_curve_attributes.is_builtin(id) &&
|
||||
!ELEM(id.name(), "radius", "tilt", "resolution", "cyclic"))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue