Compare commits

...

36 commits

Author SHA1 Message Date
Thaddeus Crews
e825169957
Merge pull request #107836 from aaronfranke/gltf-without-nodes
GLTF: Allow parsing glTF files without nodes
2025-10-13 19:29:03 -05:00
Thaddeus Crews
4ae535b3b9
Merge pull request #111419 from YeldhamDev/numbers_numbers_numbers
Add source lines to file locations on POT generation
2025-10-13 19:29:01 -05:00
Thaddeus Crews
c0c75561d2
Merge pull request #111129 from DarioSamo/particle-pipeline-deferral
Push pipeline compilation of various effects to the worker thread pool.
2025-10-13 19:29:00 -05:00
Thaddeus Crews
8ce4f80dd9
Merge pull request #106263 from lodetrick/tabbar-individual-colors
Add support for custom font colors in the TabBar
2025-10-13 19:28:58 -05:00
Thaddeus Crews
d3285f5468
Merge pull request #111185 from WhalesState/vp-disable-xr
More XR disable for Viewport and export.
2025-10-13 19:28:56 -05:00
Thaddeus Crews
c6df8d3253
Merge pull request #111476 from kleonc/canvas_item_draw_set_transform_fix_rotation_scale_order
Fix rotation/scale order in `CanvasItem::draw_set_transform`
2025-10-13 19:28:55 -05:00
Thaddeus Crews
988a7f7bdf
Merge pull request #111507 from nikitalita/fix-skeleton-dynamic-physics
Scene importer: Fix skeleton path when physics body type is dynamic
2025-10-13 19:28:53 -05:00
Thaddeus Crews
0b4cca38ea
Merge pull request #111538 from MajorMcDoom/xr-tracker-name-optimization
Make `XRPose` only set name on creation instead of on pose update
2025-10-13 19:28:51 -05:00
Thaddeus Crews
8be090c03a
Merge pull request #111569 from DeeJayLSP/harfbuzz-update
Update HarfBuzz to 12.1.0
2025-10-13 19:28:49 -05:00
Thaddeus Crews
c5754ccc52
Merge pull request #111310 from Caaz/patch-1
Update tutorial link for calling Javascript from script
2025-10-13 19:28:48 -05:00
Thaddeus Crews
21a6488c7f
Merge pull request #109421 from aaronfranke/gltf-export-mesh-name
GLTF: Preserve mesh names on export
2025-10-13 19:28:46 -05:00
Thaddeus Crews
3dbd7d36d0
Merge pull request #111461 from DeeJayLSP/fthb
Use HarfBuzz to fix variant hinting in `TextServerAdvanced`
2025-10-13 19:28:44 -05:00
Thaddeus Crews
cd74a9cb12
Merge pull request #111206 from j20001970/camera-feed-datatype-changed
Emit `format_changed` on CameraFeed datatype change
2025-10-13 19:28:42 -05:00
Thaddeus Crews
cd13a9df14
Merge pull request #111621 from scgm0/Fix-some-compilation-errors
Fix some compilation errors
2025-10-13 19:28:41 -05:00
Thaddeus Crews
58894136b7
Merge pull request #107395 from lodetrick/bottom-panel-margin-fixes
Fix TabContainer Editor theming and remove Debugger style hacks
2025-10-13 19:28:39 -05:00
Thaddeus Crews
40dde2a9a1
Merge pull request #111139 from Calinou/doc-node2d-look-at-get-angle-to
Document link between `Node2D.look_at()` and `Node2D.get_angle_to()`
2025-10-13 19:28:37 -05:00
Thaddeus Crews
3ef37d7bf3
Merge pull request #111586 from KoBeWi/some_favorites_are_bigger_because_they_are_more_favored
Fix favorites icon size in FileSystem dock
2025-10-13 19:28:36 -05:00
Thaddeus Crews
2568505535
Merge pull request #108065 from lodetrick/range-hint-cleanup
Clean up numeric EditorProperty `setup()` methods
2025-10-13 19:28:34 -05:00
scgm0
cbc960c997 Fix some compilation errors 2025-10-14 05:54:58 +08:00
Logan Detrick
914a72f8a4 Give TabBar overridable colors per tab 2025-10-13 11:52:07 -07:00
Hugo Locurcio
082766a990
Document link between Node2D.look_at() and Node2D.get_angle_to()
These methods are closely related, as `Node2D.get_angle_to()` can
be used to get the rotation value that is being applied to `look_at()`
without actually applying it to the node.
2025-10-13 20:47:55 +02:00
DeeJayLSP
276e1c222c Update HarfBuzz to 12.1.0 2025-10-13 15:12:33 -03:00
Dario
ba268416d5 Push pipeline compilation of various effects to the worker thread pool. 2025-10-13 12:00:23 -03:00
kobewi
7cee91f05b Fix favorites icon size in FileSystem dock 2025-10-13 13:58:10 +02:00
Jason Kuo
2e00156657 Emit format_changed on CameraFeed datatype change 2025-10-13 00:26:29 +08:00
Zi Ye
e38bbf88e5 Make XRPose only set name on creation, instead of on every update. 2025-10-11 20:24:23 -05:00
nikitalita
03923c6ed7 scene importer: Fix skeleton path when physics body type is dynamic 2025-10-11 04:39:14 -07:00
DeeJayLSP
70f180975b Use HarfBuzz to fix variant hinting in TextServerAdvanced 2025-10-10 18:01:03 -03:00
kleonc
2dce5172e2 Fix rotation/scale order in CanvasItem::draw_set_transform 2025-10-10 15:09:25 +02:00
Logan Detrick
7998b5e8d2 Cleanup EditorProperty setup methods 2025-10-08 15:52:46 -07:00
Michael Alexsander
0de3f8b21f
Add source lines to file locations on POT generation 2025-10-08 16:43:22 -03:00
Mounir Tohami
9894256e3a More XR disable for Viewport and export. 2025-10-06 20:15:07 +03:00
Daniel Cavazos
3fa500d2f3
Update tutorial link for calling Javascript from script 2025-10-05 21:32:19 -07:00
Aaron Franke
5d492e1aed
GLTF: Allow parsing glTF files without nodes 2025-10-05 17:39:49 -07:00
Aaron Franke
da9a77ce42
GLTF: Preserve mesh name on export 2025-09-24 20:28:52 -07:00
Logan Detrick
78045df591 Fix TabBar corner radius and generalize Debugger hack 2025-07-07 16:50:12 -07:00
185 changed files with 9075 additions and 7199 deletions

View file

@ -5,7 +5,7 @@
</brief_description>
<description>
[EditorTranslationParserPlugin] is invoked when a file is being parsed to extract strings that require translation. To define the parsing and string extraction logic, override the [method _parse_file] method in script.
The return value should be an [Array] of [PackedStringArray]s, one for each extracted translatable string. Each entry should contain [code][msgid, msgctxt, msgid_plural, comment][/code], where all except [code]msgid[/code] are optional. Empty strings will be ignored.
The return value should be an [Array] of [PackedStringArray]s, one for each extracted translatable string. Each entry should contain [code][msgid, msgctxt, msgid_plural, comment, source_line][/code], where all except [code]msgid[/code] are optional. Empty strings will be ignored.
The extracted strings will be written into a POT file selected by user under "POT Generation" in "Localization" tab in "Project Settings" menu.
Below shows an example of a custom parser that extracts strings from a CSV file to write into a POT.
[codeblocks]
@ -54,19 +54,19 @@
}
[/csharp]
[/codeblocks]
To add a translatable string associated with a context, plural, or comment:
To add a translatable string associated with a context, plural, comment, or source line:
[codeblocks]
[gdscript]
# This will add a message with msgid "Test 1", msgctxt "context", msgid_plural "test 1 plurals", and comment "test 1 comment".
ret.append(PackedStringArray(["Test 1", "context", "test 1 plurals", "test 1 comment"]))
# This will add a message with msgid "Test 1", msgctxt "context", msgid_plural "test 1 plurals", comment "test 1 comment", and source line "7".
ret.append(PackedStringArray(["Test 1", "context", "test 1 plurals", "test 1 comment", "7"]))
# This will add a message with msgid "A test without context" and msgid_plural "plurals".
ret.append(PackedStringArray(["A test without context", "", "plurals"]))
# This will add a message with msgid "Only with context" and msgctxt "a friendly context".
ret.append(PackedStringArray(["Only with context", "a friendly context"]))
[/gdscript]
[csharp]
// This will add a message with msgid "Test 1", msgctxt "context", msgid_plural "test 1 plurals", and comment "test 1 comment".
ret.Add(["Test 1", "context", "test 1 plurals", "test 1 comment"]);
// This will add a message with msgid "Test 1", msgctxt "context", msgid_plural "test 1 plurals", comment "test 1 comment", and source line "7".
ret.Add(["Test 1", "context", "test 1 plurals", "test 1 comment", "7"]);
// This will add a message with msgid "A test without context" and msgid_plural "plurals".
ret.Add(["A test without context", "", "plurals"]);
// This will add a message with msgid "Only with context" and msgctxt "a friendly context".

View file

@ -8,7 +8,7 @@
[b]Note:[/b] This singleton can be disabled at build-time to improve security. By default, the JavaScriptBridge singleton is enabled. Official export templates also have the JavaScriptBridge singleton enabled. See [url=$DOCS_URL/engine_details/development/compiling/compiling_for_web.html]Compiling for the Web[/url] in the documentation for more information.
</description>
<tutorials>
<link title="Exporting for the Web: Calling JavaScript from script">$DOCS_URL/tutorials/export/exporting_for_web.html#calling-javascript-from-script</link>
<link title="The JavaScriptBridge singleton">$DOCS_URL/tutorials/platform/web/javascript_bridge.html</link>
</tutorials>
<methods>
<method name="create_callback">

View file

@ -19,11 +19,11 @@
Multiplies the current scale by the [param ratio] vector.
</description>
</method>
<method name="get_angle_to" qualifiers="const">
<method name="get_angle_to" qualifiers="const" keywords="look_at">
<return type="float" />
<param index="0" name="point" type="Vector2" />
<description>
Returns the angle between the node and the [param point] in radians.
Returns the angle between the node and the [param point] in radians. See also [method look_at].
[url=https://raw.githubusercontent.com/godotengine/godot-docs/master/img/node2d_get_angle_to.png]Illustration of the returned angle.[/url]
</description>
</method>
@ -45,7 +45,7 @@
<return type="void" />
<param index="0" name="point" type="Vector2" />
<description>
Rotates the node so that its local +X axis points towards the [param point], which is expected to use global coordinates.
Rotates the node so that its local +X axis points towards the [param point], which is expected to use global coordinates. This method is a combination of both [method rotate] and [method get_angle_to].
[param point] should not be the same as the node's position, otherwise the node always looks to the right.
</description>
</method>
@ -69,7 +69,7 @@
<return type="void" />
<param index="0" name="radians" type="float" />
<description>
Applies a rotation to the node, in radians, starting from its current rotation.
Applies a rotation to the node, in radians, starting from its current rotation. This is equivalent to [code]rotation += radians[/code].
</description>
</method>
<method name="to_global" qualifiers="const">
@ -90,7 +90,7 @@
<return type="void" />
<param index="0" name="offset" type="Vector2" />
<description>
Translates the node by the given [param offset] in local coordinates.
Translates the node by the given [param offset] in local coordinates. This is equivalent to [code]position += offset[/code].
</description>
</method>
</methods>

View file

@ -65,9 +65,11 @@ EditorDebuggerNode::EditorDebuggerNode() {
singleton = this;
}
add_theme_constant_override("margin_left", -EditorNode::get_singleton()->get_editor_theme()->get_stylebox(SNAME("BottomPanelDebuggerOverride"), EditorStringName(EditorStyles))->get_margin(SIDE_LEFT));
add_theme_constant_override("margin_right", -EditorNode::get_singleton()->get_editor_theme()->get_stylebox(SNAME("BottomPanelDebuggerOverride"), EditorStringName(EditorStyles))->get_margin(SIDE_RIGHT));
add_theme_constant_override("margin_bottom", -EditorNode::get_singleton()->get_editor_theme()->get_stylebox(SNAME("BottomPanelDebuggerOverride"), EditorStringName(EditorStyles))->get_margin(SIDE_BOTTOM));
Ref<StyleBox> bottom_panel_margins = EditorNode::get_singleton()->get_editor_theme()->get_stylebox(SNAME("BottomPanel"), EditorStringName(EditorStyles));
add_theme_constant_override("margin_top", -bottom_panel_margins->get_margin(SIDE_TOP));
add_theme_constant_override("margin_left", -bottom_panel_margins->get_margin(SIDE_LEFT));
add_theme_constant_override("margin_right", -bottom_panel_margins->get_margin(SIDE_RIGHT));
add_theme_constant_override("margin_bottom", -bottom_panel_margins->get_margin(SIDE_BOTTOM));
tabs = memnew(TabContainer);
tabs->set_tabs_visible(false);
@ -331,9 +333,11 @@ void EditorDebuggerNode::_notification(int p_what) {
tabs->add_theme_style_override(SceneStringName(panel), EditorNode::get_singleton()->get_editor_theme()->get_stylebox(SNAME("DebuggerPanel"), EditorStringName(EditorStyles)));
}
add_theme_constant_override("margin_left", -EditorNode::get_singleton()->get_editor_theme()->get_stylebox(SNAME("BottomPanelDebuggerOverride"), EditorStringName(EditorStyles))->get_margin(SIDE_LEFT));
add_theme_constant_override("margin_right", -EditorNode::get_singleton()->get_editor_theme()->get_stylebox(SNAME("BottomPanelDebuggerOverride"), EditorStringName(EditorStyles))->get_margin(SIDE_RIGHT));
add_theme_constant_override("margin_bottom", -EditorNode::get_singleton()->get_editor_theme()->get_stylebox(SNAME("BottomPanelDebuggerOverride"), EditorStringName(EditorStyles))->get_margin(SIDE_BOTTOM));
Ref<StyleBox> bottom_panel_margins = EditorNode::get_singleton()->get_editor_theme()->get_stylebox(SNAME("BottomPanel"), EditorStringName(EditorStyles));
add_theme_constant_override("margin_top", -bottom_panel_margins->get_margin(SIDE_TOP));
add_theme_constant_override("margin_left", -bottom_panel_margins->get_margin(SIDE_LEFT));
add_theme_constant_override("margin_right", -bottom_panel_margins->get_margin(SIDE_RIGHT));
add_theme_constant_override("margin_bottom", -bottom_panel_margins->get_margin(SIDE_BOTTOM));
remote_scene_tree->update_icon_max_width();
} break;

View file

@ -415,8 +415,8 @@ void FileSystemDock::_update_tree(const Vector<String> &p_uncollapsed_paths, boo
Ref<Texture2D> folder_icon = get_editor_theme_icon(SNAME("Folder"));
const Color default_folder_color = get_theme_color(SNAME("folder_icon_color"), SNAME("FileDialog"));
for (int i = 0; i < favorite_paths.size(); i++) {
const String &favorite = favorite_paths[i];
const int icon_size = get_theme_constant(SNAME("class_icon_size"), EditorStringName(Editor));
for (const String &favorite : favorite_paths) {
if (!favorite.begins_with("res://")) {
continue;
}
@ -448,6 +448,7 @@ void FileSystemDock::_update_tree(const Vector<String> &p_uncollapsed_paths, boo
ti->set_text(0, text);
ti->set_icon(0, icon);
ti->set_icon_modulate(0, color);
ti->set_icon_max_width(0, icon_size);
ti->set_tooltip_text(0, favorite);
ti->set_selectable(0, true);
ti->set_metadata(0, favorite);

View file

@ -683,10 +683,6 @@ void EditorNode::_update_theme(bool p_skip_creation) {
help_menu->set_item_icon(help_menu->get_item_index(HELP_ABOUT), _get_editor_theme_native_menu_icon(SNAME("Godot"), global_menu, dark_mode));
help_menu->set_item_icon(help_menu->get_item_index(HELP_SUPPORT_GODOT_DEVELOPMENT), _get_editor_theme_native_menu_icon(SNAME("Heart"), global_menu, dark_mode));
if (EditorDebuggerNode::get_singleton()->is_visible()) {
bottom_panel->add_theme_style_override(SceneStringName(panel), theme->get_stylebox(SNAME("BottomPanelDebuggerOverride"), EditorStringName(EditorStyles)));
}
_update_renderer_color();
}

View file

@ -125,11 +125,13 @@ bool ShaderBakerExportPlugin::_begin_customize_resources(const Ref<EditorExportP
customization_configuration_hash = to_hash.as_string().hash64();
BitField<RenderingShaderLibrary::FeatureBits> renderer_features = {};
#ifndef XR_DISABLED
bool xr_enabled = GLOBAL_GET("xr/shaders/enabled");
renderer_features.set_flag(RenderingShaderLibrary::FEATURE_ADVANCED_BIT);
if (xr_enabled) {
renderer_features.set_flag(RenderingShaderLibrary::FEATURE_MULTIVIEW_BIT);
}
#endif // XR_DISABLED
int vrs_mode = GLOBAL_GET("rendering/vrs/mode");
if (vrs_mode != 0) {

View file

@ -128,12 +128,6 @@ void EditorBottomPanel::_switch_to_item(bool p_visible, int p_idx, bool p_ignore
items[i].button->set_pressed_no_signal(i == p_idx);
items[i].control->set_visible(i == p_idx);
}
if (EditorDebuggerNode::get_singleton() == items[p_idx].control) {
// This is the debug panel which uses tabs, so the top section should be smaller.
add_theme_style_override(SceneStringName(panel), get_theme_stylebox(SNAME("BottomPanelDebuggerOverride"), EditorStringName(EditorStyles)));
} else {
add_theme_style_override(SceneStringName(panel), get_theme_stylebox(SNAME("BottomPanel"), EditorStringName(EditorStyles)));
}
center_split->set_dragger_visibility(SplitContainer::DRAGGER_VISIBLE);
center_split->set_collapsed(false);
@ -145,7 +139,6 @@ void EditorBottomPanel::_switch_to_item(bool p_visible, int p_idx, bool p_ignore
}
callable_mp(this, &EditorBottomPanel::_ensure_control_visible).call_deferred(items[p_idx].button->get_instance_id());
} else {
add_theme_style_override(SceneStringName(panel), get_theme_stylebox(SNAME("BottomPanel"), EditorStringName(EditorStyles)));
items[p_idx].button->set_pressed_no_signal(false);
items[p_idx].control->set_visible(false);
center_split->set_dragger_visibility(SplitContainer::DRAGGER_HIDDEN);

View file

@ -1699,6 +1699,11 @@ Node *ResourceImporterScene::_post_fix_node(Node *p_node, Node *p_root, HashMap<
base = col;
} break;
case MESH_PHYSICS_RIGID_BODY_AND_MESH: {
NodePath skeleton_path = mi->get_skeleton_path();
Skeleton3D *skeleton = nullptr;
if (!skeleton_path.is_empty()) {
skeleton = Object::cast_to<Skeleton3D>(mi->get_node_or_null(skeleton_path));
}
RigidBody3D *rigid_body = memnew(RigidBody3D);
rigid_body->set_name(p_node->get_name());
_copy_meta(p_node, rigid_body);
@ -1714,6 +1719,10 @@ Node *ResourceImporterScene::_post_fix_node(Node *p_node, Node *p_root, HashMap<
rigid_body->set_physics_material_override(pmo);
}
base = rigid_body;
if (skeleton) {
skeleton_path = mi->get_path_to(skeleton);
mi->set_skeleton_path(skeleton_path);
}
} break;
case MESH_PHYSICS_STATIC_COLLIDER_ONLY: {
StaticBody3D *col = memnew(StaticBody3D);

View file

@ -1476,18 +1476,18 @@ void EditorPropertyInteger::update_property() {
#endif
}
void EditorPropertyInteger::setup(int64_t p_min, int64_t p_max, int64_t p_step, bool p_prefer_slider, bool p_hide_control, bool p_allow_greater, bool p_allow_lesser, const String &p_suffix) {
spin->set_min(p_min);
spin->set_max(p_max);
spin->set_step(p_step);
if (p_hide_control) {
void EditorPropertyInteger::setup(const EditorPropertyRangeHint &p_range_hint) {
spin->set_min(p_range_hint.min);
spin->set_max(p_range_hint.max);
spin->set_step(Math::round(p_range_hint.step));
if (p_range_hint.hide_control) {
spin->set_control_state(EditorSpinSlider::CONTROL_STATE_HIDE);
} else {
spin->set_control_state(p_prefer_slider ? EditorSpinSlider::CONTROL_STATE_PREFER_SLIDER : EditorSpinSlider::CONTROL_STATE_DEFAULT);
spin->set_control_state(p_range_hint.prefer_slider ? EditorSpinSlider::CONTROL_STATE_PREFER_SLIDER : EditorSpinSlider::CONTROL_STATE_DEFAULT);
}
spin->set_allow_greater(p_allow_greater);
spin->set_allow_lesser(p_allow_lesser);
spin->set_suffix(p_suffix);
spin->set_allow_greater(p_range_hint.or_greater);
spin->set_allow_lesser(p_range_hint.or_less);
spin->set_suffix(p_range_hint.suffix);
}
EditorPropertyInteger::EditorPropertyInteger() {
@ -1607,18 +1607,18 @@ void EditorPropertyFloat::update_property() {
spin->set_value_no_signal(val);
}
void EditorPropertyFloat::setup(double p_min, double p_max, double p_step, bool p_hide_control, bool p_exp_range, bool p_greater, bool p_lesser, const String &p_suffix, bool p_radians_as_degrees) {
radians_as_degrees = p_radians_as_degrees;
spin->set_min(p_min);
spin->set_max(p_max);
spin->set_step(p_step);
if (p_hide_control) {
void EditorPropertyFloat::setup(const EditorPropertyRangeHint &p_range_hint) {
radians_as_degrees = p_range_hint.radians_as_degrees;
spin->set_min(p_range_hint.min);
spin->set_max(p_range_hint.max);
spin->set_step(p_range_hint.step);
if (p_range_hint.hide_control) {
spin->set_control_state(EditorSpinSlider::CONTROL_STATE_HIDE);
}
spin->set_exp_ratio(p_exp_range);
spin->set_allow_greater(p_greater);
spin->set_allow_lesser(p_lesser);
spin->set_suffix(p_suffix);
spin->set_exp_ratio(p_range_hint.exp_range);
spin->set_allow_greater(p_range_hint.or_greater);
spin->set_allow_lesser(p_range_hint.or_less);
spin->set_suffix(p_range_hint.suffix);
}
EditorPropertyFloat::EditorPropertyFloat() {
@ -1897,17 +1897,17 @@ void EditorPropertyRect2::_notification(int p_what) {
}
}
void EditorPropertyRect2::setup(double p_min, double p_max, double p_step, bool p_hide_control, const String &p_suffix) {
void EditorPropertyRect2::setup(const EditorPropertyRangeHint &p_range_hint) {
for (int i = 0; i < 4; i++) {
spin[i]->set_min(p_min);
spin[i]->set_max(p_max);
spin[i]->set_step(p_step);
if (p_hide_control) {
spin[i]->set_min(p_range_hint.min);
spin[i]->set_max(p_range_hint.max);
spin[i]->set_step(p_range_hint.step);
if (p_range_hint.hide_control) {
spin[i]->set_control_state(EditorSpinSlider::CONTROL_STATE_HIDE);
}
spin[i]->set_allow_greater(true);
spin[i]->set_allow_lesser(true);
spin[i]->set_suffix(p_suffix);
spin[i]->set_suffix(p_range_hint.suffix);
}
}
@ -1993,14 +1993,14 @@ void EditorPropertyRect2i::_notification(int p_what) {
}
}
void EditorPropertyRect2i::setup(int p_min, int p_max, const String &p_suffix) {
void EditorPropertyRect2i::setup(const EditorPropertyRangeHint &p_range_hint) {
for (int i = 0; i < 4; i++) {
spin[i]->set_min(p_min);
spin[i]->set_max(p_max);
spin[i]->set_min(p_range_hint.min);
spin[i]->set_max(p_range_hint.max);
spin[i]->set_step(1);
spin[i]->set_allow_greater(true);
spin[i]->set_allow_lesser(true);
spin[i]->set_suffix(p_suffix);
spin[i]->set_suffix(p_range_hint.suffix);
spin[i]->set_editing_integer(true);
}
}
@ -2087,18 +2087,18 @@ void EditorPropertyPlane::_notification(int p_what) {
}
}
void EditorPropertyPlane::setup(double p_min, double p_max, double p_step, bool p_hide_control, const String &p_suffix) {
void EditorPropertyPlane::setup(const EditorPropertyRangeHint &p_range_hint) {
for (int i = 0; i < 4; i++) {
spin[i]->set_min(p_min);
spin[i]->set_max(p_max);
spin[i]->set_step(p_step);
if (p_hide_control) {
spin[i]->set_min(p_range_hint.min);
spin[i]->set_max(p_range_hint.max);
spin[i]->set_step(p_range_hint.step);
if (p_range_hint.hide_control) {
spin[i]->set_control_state(EditorSpinSlider::CONTROL_STATE_HIDE);
}
spin[i]->set_allow_greater(true);
spin[i]->set_allow_lesser(true);
}
spin[3]->set_suffix(p_suffix);
spin[3]->set_suffix(p_range_hint.suffix);
}
EditorPropertyPlane::EditorPropertyPlane(bool p_force_wide) {
@ -2238,19 +2238,19 @@ void EditorPropertyQuaternion::_notification(int p_what) {
}
}
void EditorPropertyQuaternion::setup(double p_min, double p_max, double p_step, bool p_hide_control, const String &p_suffix, bool p_hide_editor) {
void EditorPropertyQuaternion::setup(const EditorPropertyRangeHint &p_range_hint, bool p_hide_editor) {
for (int i = 0; i < 4; i++) {
spin[i]->set_min(p_min);
spin[i]->set_max(p_max);
spin[i]->set_step(p_step);
if (p_hide_control) {
spin[i]->set_min(p_range_hint.min);
spin[i]->set_max(p_range_hint.max);
spin[i]->set_step(p_range_hint.step);
if (p_range_hint.hide_control) {
spin[i]->set_control_state(EditorSpinSlider::CONTROL_STATE_HIDE);
}
spin[i]->set_allow_greater(true);
spin[i]->set_allow_lesser(true);
// Quaternion is inherently unitless, however someone may want to use it as
// a generic way to store 4 values, so we'll still respect the suffix.
spin[i]->set_suffix(p_suffix);
spin[i]->set_suffix(p_range_hint.suffix);
}
for (int i = 0; i < 3; i++) {
@ -2385,17 +2385,17 @@ void EditorPropertyAABB::_notification(int p_what) {
}
}
void EditorPropertyAABB::setup(double p_min, double p_max, double p_step, bool p_hide_control, const String &p_suffix) {
void EditorPropertyAABB::setup(const EditorPropertyRangeHint &p_range_hint) {
for (int i = 0; i < 6; i++) {
spin[i]->set_min(p_min);
spin[i]->set_max(p_max);
spin[i]->set_step(p_step);
if (p_hide_control) {
spin[i]->set_min(p_range_hint.min);
spin[i]->set_max(p_range_hint.max);
spin[i]->set_step(p_range_hint.step);
if (p_range_hint.hide_control) {
spin[i]->set_control_state(EditorSpinSlider::CONTROL_STATE_HIDE);
}
spin[i]->set_allow_greater(true);
spin[i]->set_allow_lesser(true);
spin[i]->set_suffix(p_suffix);
spin[i]->set_suffix(p_range_hint.suffix);
}
}
@ -2465,18 +2465,18 @@ void EditorPropertyTransform2D::_notification(int p_what) {
}
}
void EditorPropertyTransform2D::setup(double p_min, double p_max, double p_step, bool p_hide_control, const String &p_suffix) {
void EditorPropertyTransform2D::setup(const EditorPropertyRangeHint &p_range_hint) {
for (int i = 0; i < 6; i++) {
spin[i]->set_min(p_min);
spin[i]->set_max(p_max);
spin[i]->set_step(p_step);
if (p_hide_control) {
spin[i]->set_min(p_range_hint.min);
spin[i]->set_max(p_range_hint.max);
spin[i]->set_step(p_range_hint.step);
if (p_range_hint.hide_control) {
spin[i]->set_control_state(EditorSpinSlider::CONTROL_STATE_HIDE);
}
spin[i]->set_allow_greater(true);
spin[i]->set_allow_lesser(true);
if (i % 3 == 2) {
spin[i]->set_suffix(p_suffix);
spin[i]->set_suffix(p_range_hint.suffix);
}
}
}
@ -2549,19 +2549,19 @@ void EditorPropertyBasis::_notification(int p_what) {
}
}
void EditorPropertyBasis::setup(double p_min, double p_max, double p_step, bool p_hide_control, const String &p_suffix) {
void EditorPropertyBasis::setup(const EditorPropertyRangeHint &p_range_hint) {
for (int i = 0; i < 9; i++) {
spin[i]->set_min(p_min);
spin[i]->set_max(p_max);
spin[i]->set_step(p_step);
if (p_hide_control) {
spin[i]->set_min(p_range_hint.min);
spin[i]->set_max(p_range_hint.max);
spin[i]->set_step(p_range_hint.step);
if (p_range_hint.hide_control) {
spin[i]->set_control_state(EditorSpinSlider::CONTROL_STATE_HIDE);
}
spin[i]->set_allow_greater(true);
spin[i]->set_allow_lesser(true);
// Basis is inherently unitless, however someone may want to use it as
// a generic way to store 9 values, so we'll still respect the suffix.
spin[i]->set_suffix(p_suffix);
spin[i]->set_suffix(p_range_hint.suffix);
}
}
@ -2640,18 +2640,18 @@ void EditorPropertyTransform3D::_notification(int p_what) {
}
}
void EditorPropertyTransform3D::setup(double p_min, double p_max, double p_step, bool p_hide_control, const String &p_suffix) {
void EditorPropertyTransform3D::setup(const EditorPropertyRangeHint &p_range_hint) {
for (int i = 0; i < 12; i++) {
spin[i]->set_min(p_min);
spin[i]->set_max(p_max);
spin[i]->set_step(p_step);
if (p_hide_control) {
spin[i]->set_min(p_range_hint.min);
spin[i]->set_max(p_range_hint.max);
spin[i]->set_step(p_range_hint.step);
if (p_range_hint.hide_control) {
spin[i]->set_control_state(EditorSpinSlider::CONTROL_STATE_HIDE);
}
spin[i]->set_allow_greater(true);
spin[i]->set_allow_lesser(true);
if (i % 4 == 3) {
spin[i]->set_suffix(p_suffix);
spin[i]->set_suffix(p_range_hint.suffix);
}
}
}
@ -2739,18 +2739,18 @@ void EditorPropertyProjection::_notification(int p_what) {
}
}
void EditorPropertyProjection::setup(double p_min, double p_max, double p_step, bool p_hide_control, const String &p_suffix) {
void EditorPropertyProjection::setup(const EditorPropertyRangeHint &p_range_hint) {
for (int i = 0; i < 16; i++) {
spin[i]->set_min(p_min);
spin[i]->set_max(p_max);
spin[i]->set_step(p_step);
if (p_hide_control) {
spin[i]->set_min(p_range_hint.min);
spin[i]->set_max(p_range_hint.max);
spin[i]->set_step(p_range_hint.step);
if (p_range_hint.hide_control) {
spin[i]->set_control_state(EditorSpinSlider::CONTROL_STATE_HIDE);
}
spin[i]->set_allow_greater(true);
spin[i]->set_allow_lesser(true);
if (i % 4 == 3) {
spin[i]->set_suffix(p_suffix);
spin[i]->set_suffix(p_range_hint.suffix);
}
}
}
@ -3652,19 +3652,6 @@ bool EditorInspectorDefaultPlugin::parse_property(Object *p_object, const Varian
return false;
}
struct EditorPropertyRangeHint {
bool or_greater = true;
bool or_less = true;
double min = 0.0;
double max = 0.0;
double step = 1.0;
String suffix;
bool exp_range = false;
bool prefer_slider = false;
bool hide_control = true;
bool radians_as_degrees = false;
};
static EditorPropertyRangeHint _parse_range_hint(PropertyHint p_hint, const String &p_hint_text, double p_default_step, bool is_int = false) {
EditorPropertyRangeHint hint;
hint.step = p_default_step;
@ -3836,10 +3823,7 @@ EditorProperty *EditorInspectorDefaultPlugin::get_editor_for_property(Object *p_
} else {
EditorPropertyInteger *editor = memnew(EditorPropertyInteger);
EditorPropertyRangeHint hint = _parse_range_hint(p_hint, p_hint_text, 1, true);
editor->setup(hint.min, hint.max, hint.step, hint.prefer_slider, hint.hide_control, hint.or_greater, hint.or_less, hint.suffix);
editor->setup(_parse_range_hint(p_hint, p_hint_text, 1, true));
return editor;
}
} break;
@ -3864,10 +3848,7 @@ EditorProperty *EditorInspectorDefaultPlugin::get_editor_for_property(Object *p_
} else {
EditorPropertyFloat *editor = memnew(EditorPropertyFloat);
EditorPropertyRangeHint hint = _parse_range_hint(p_hint, p_hint_text, default_float_step);
editor->setup(hint.min, hint.max, hint.step, hint.hide_control, hint.exp_range, hint.or_greater, hint.or_less, hint.suffix, hint.radians_as_degrees);
editor->setup(_parse_range_hint(p_hint, p_hint_text, default_float_step));
return editor;
}
} break;
@ -3930,101 +3911,91 @@ EditorProperty *EditorInspectorDefaultPlugin::get_editor_for_property(Object *p_
case Variant::VECTOR2: {
EditorPropertyVector2 *editor = memnew(EditorPropertyVector2(p_wide));
EditorPropertyRangeHint hint = _parse_range_hint(p_hint, p_hint_text, default_float_step);
editor->setup(hint.min, hint.max, hint.step, hint.hide_control, p_hint == PROPERTY_HINT_LINK, hint.suffix, hint.radians_as_degrees);
editor->setup(_parse_range_hint(p_hint, p_hint_text, default_float_step), p_hint == PROPERTY_HINT_LINK);
return editor;
} break;
case Variant::VECTOR2I: {
EditorPropertyVector2i *editor = memnew(EditorPropertyVector2i(p_wide));
EditorPropertyRangeHint hint = _parse_range_hint(p_hint, p_hint_text, 1, true);
editor->setup(hint.min, hint.max, 1, false, p_hint == PROPERTY_HINT_LINK, hint.suffix, false, true);
hint.step = Math::round(hint.step);
editor->setup(hint, p_hint == PROPERTY_HINT_LINK, true);
return editor;
} break;
case Variant::RECT2: {
EditorPropertyRect2 *editor = memnew(EditorPropertyRect2(p_wide));
EditorPropertyRangeHint hint = _parse_range_hint(p_hint, p_hint_text, default_float_step);
editor->setup(hint.min, hint.max, hint.step, hint.hide_control, hint.suffix);
editor->setup(_parse_range_hint(p_hint, p_hint_text, default_float_step));
return editor;
} break;
case Variant::RECT2I: {
EditorPropertyRect2i *editor = memnew(EditorPropertyRect2i(p_wide));
EditorPropertyRangeHint hint = _parse_range_hint(p_hint, p_hint_text, 1, true);
editor->setup(hint.min, hint.max, hint.suffix);
editor->setup(_parse_range_hint(p_hint, p_hint_text, 1, true));
return editor;
} break;
case Variant::VECTOR3: {
EditorPropertyVector3 *editor = memnew(EditorPropertyVector3(p_wide));
EditorPropertyRangeHint hint = _parse_range_hint(p_hint, p_hint_text, default_float_step);
editor->setup(hint.min, hint.max, hint.step, hint.hide_control, p_hint == PROPERTY_HINT_LINK, hint.suffix, hint.radians_as_degrees);
editor->setup(_parse_range_hint(p_hint, p_hint_text, default_float_step), p_hint == PROPERTY_HINT_LINK);
return editor;
} break;
case Variant::VECTOR3I: {
EditorPropertyVector3i *editor = memnew(EditorPropertyVector3i(p_wide));
EditorPropertyRangeHint hint = _parse_range_hint(p_hint, p_hint_text, 1, true);
editor->setup(hint.min, hint.max, 1, false, p_hint == PROPERTY_HINT_LINK, hint.suffix, false, true);
hint.step = Math::round(hint.step);
editor->setup(hint, p_hint == PROPERTY_HINT_LINK, true);
return editor;
} break;
case Variant::VECTOR4: {
EditorPropertyVector4 *editor = memnew(EditorPropertyVector4);
EditorPropertyRangeHint hint = _parse_range_hint(p_hint, p_hint_text, default_float_step);
editor->setup(hint.min, hint.max, hint.step, hint.hide_control, p_hint == PROPERTY_HINT_LINK, hint.suffix, hint.radians_as_degrees);
editor->setup(_parse_range_hint(p_hint, p_hint_text, default_float_step), p_hint == PROPERTY_HINT_LINK);
return editor;
} break;
case Variant::VECTOR4I: {
EditorPropertyVector4i *editor = memnew(EditorPropertyVector4i);
EditorPropertyRangeHint hint = _parse_range_hint(p_hint, p_hint_text, 1, true);
editor->setup(hint.min, hint.max, 1, false, p_hint == PROPERTY_HINT_LINK, hint.suffix, false, true);
hint.step = Math::round(hint.step);
editor->setup(hint, p_hint == PROPERTY_HINT_LINK, true);
return editor;
} break;
case Variant::TRANSFORM2D: {
EditorPropertyTransform2D *editor = memnew(EditorPropertyTransform2D);
EditorPropertyRangeHint hint = _parse_range_hint(p_hint, p_hint_text, default_float_step);
editor->setup(hint.min, hint.max, hint.step, hint.hide_control, hint.suffix);
editor->setup(_parse_range_hint(p_hint, p_hint_text, default_float_step));
return editor;
} break;
case Variant::PLANE: {
EditorPropertyPlane *editor = memnew(EditorPropertyPlane(p_wide));
EditorPropertyRangeHint hint = _parse_range_hint(p_hint, p_hint_text, default_float_step);
editor->setup(hint.min, hint.max, hint.step, hint.hide_control, hint.suffix);
editor->setup(_parse_range_hint(p_hint, p_hint_text, default_float_step));
return editor;
} break;
case Variant::QUATERNION: {
EditorPropertyQuaternion *editor = memnew(EditorPropertyQuaternion);
EditorPropertyRangeHint hint = _parse_range_hint(p_hint, p_hint_text, default_float_step);
editor->setup(hint.min, hint.max, hint.step, hint.hide_control, hint.suffix, p_hint == PROPERTY_HINT_HIDE_QUATERNION_EDIT);
editor->setup(_parse_range_hint(p_hint, p_hint_text, default_float_step), p_hint == PROPERTY_HINT_HIDE_QUATERNION_EDIT);
return editor;
} break;
case Variant::AABB: {
EditorPropertyAABB *editor = memnew(EditorPropertyAABB);
EditorPropertyRangeHint hint = _parse_range_hint(p_hint, p_hint_text, default_float_step);
editor->setup(hint.min, hint.max, hint.step, hint.hide_control, hint.suffix);
editor->setup(_parse_range_hint(p_hint, p_hint_text, default_float_step));
return editor;
} break;
case Variant::BASIS: {
EditorPropertyBasis *editor = memnew(EditorPropertyBasis);
EditorPropertyRangeHint hint = _parse_range_hint(p_hint, p_hint_text, default_float_step);
editor->setup(hint.min, hint.max, hint.step, hint.hide_control, hint.suffix);
editor->setup(_parse_range_hint(p_hint, p_hint_text, default_float_step));
return editor;
} break;
case Variant::TRANSFORM3D: {
EditorPropertyTransform3D *editor = memnew(EditorPropertyTransform3D);
EditorPropertyRangeHint hint = _parse_range_hint(p_hint, p_hint_text, default_float_step);
editor->setup(hint.min, hint.max, hint.step, hint.hide_control, hint.suffix);
editor->setup(_parse_range_hint(p_hint, p_hint_text, default_float_step));
return editor;
} break;
case Variant::PROJECTION: {
EditorPropertyProjection *editor = memnew(EditorPropertyProjection);
EditorPropertyRangeHint hint = _parse_range_hint(p_hint, p_hint_text, default_float_step);
editor->setup(hint.min, hint.max, hint.step, hint.hide_control, hint.suffix);
editor->setup(_parse_range_hint(p_hint, p_hint_text, default_float_step));
return editor;
} break;

View file

@ -46,6 +46,19 @@ class SceneTreeDialog;
class TextEdit;
class TextureButton;
struct EditorPropertyRangeHint {
bool or_greater = true;
bool or_less = true;
double min = 0.0;
double max = 0.0;
double step = 1.0;
String suffix;
bool exp_range = false;
bool prefer_slider = false;
bool hide_control = true;
bool radians_as_degrees = false;
};
class EditorPropertyNil : public EditorProperty {
GDCLASS(EditorPropertyNil, EditorProperty);
LineEdit *text = nullptr;
@ -371,7 +384,7 @@ protected:
public:
virtual void update_property() override;
void setup(int64_t p_min, int64_t p_max, int64_t p_step, bool p_prefer_slider, bool p_hide_control, bool p_allow_greater, bool p_allow_lesser, const String &p_suffix = String());
void setup(const EditorPropertyRangeHint &p_range_hint);
EditorPropertyInteger();
};
@ -422,7 +435,7 @@ protected:
public:
virtual void update_property() override;
void setup(double p_min, double p_max, double p_step, bool p_hide_control, bool p_exp_range, bool p_greater, bool p_lesser, const String &p_suffix = String(), bool p_radians_as_degrees = false);
void setup(const EditorPropertyRangeHint &p_range_hint);
EditorPropertyFloat();
};
@ -478,7 +491,7 @@ protected:
public:
virtual void update_property() override;
void setup(double p_min, double p_max, double p_step, bool p_hide_control, const String &p_suffix = String());
void setup(const EditorPropertyRangeHint &p_range_hint);
EditorPropertyRect2(bool p_force_wide = false);
};
@ -493,7 +506,7 @@ protected:
public:
virtual void update_property() override;
void setup(int p_min, int p_max, const String &p_suffix = String());
void setup(const EditorPropertyRangeHint &p_range_hint);
EditorPropertyRect2i(bool p_force_wide = false);
};
@ -508,7 +521,7 @@ protected:
public:
virtual void update_property() override;
void setup(double p_min, double p_max, double p_step, bool p_hide_control, const String &p_suffix = String());
void setup(const EditorPropertyRangeHint &p_range_hint);
EditorPropertyPlane(bool p_force_wide = false);
};
@ -540,7 +553,7 @@ protected:
public:
virtual void update_property() override;
void setup(double p_min, double p_max, double p_step, bool p_hide_control, const String &p_suffix = String(), bool p_hide_editor = false);
void setup(const EditorPropertyRangeHint &p_range_hint, bool p_hide_editor = false);
EditorPropertyQuaternion();
};
@ -555,7 +568,7 @@ protected:
public:
virtual void update_property() override;
void setup(double p_min, double p_max, double p_step, bool p_hide_control, const String &p_suffix = String());
void setup(const EditorPropertyRangeHint &p_range_hint);
EditorPropertyAABB();
};
@ -570,7 +583,7 @@ protected:
public:
virtual void update_property() override;
void setup(double p_min, double p_max, double p_step, bool p_hide_control, const String &p_suffix = String());
void setup(const EditorPropertyRangeHint &p_range_hint);
EditorPropertyTransform2D(bool p_include_origin = true);
};
@ -585,7 +598,7 @@ protected:
public:
virtual void update_property() override;
void setup(double p_min, double p_max, double p_step, bool p_hide_control, const String &p_suffix = String());
void setup(const EditorPropertyRangeHint &p_range_hint);
EditorPropertyBasis();
};
@ -601,7 +614,7 @@ protected:
public:
virtual void update_property() override;
virtual void update_using_transform(Transform3D p_transform);
void setup(double p_min, double p_max, double p_step, bool p_hide_control, const String &p_suffix = String());
void setup(const EditorPropertyRangeHint &p_range_hint);
EditorPropertyTransform3D();
};
@ -617,7 +630,7 @@ protected:
public:
virtual void update_property() override;
virtual void update_using_transform(Projection p_transform);
void setup(double p_min, double p_max, double p_step, bool p_hide_control, const String &p_suffix = String());
void setup(const EditorPropertyRangeHint &p_range_hint);
EditorPropertyProjection();
};

View file

@ -153,19 +153,19 @@ void EditorPropertyVectorN::_notification(int p_what) {
}
}
void EditorPropertyVectorN::setup(double p_min, double p_max, double p_step, bool p_hide_control, bool p_link, const String &p_suffix, bool p_radians_as_degrees, bool p_is_int) {
radians_as_degrees = p_radians_as_degrees;
void EditorPropertyVectorN::setup(const EditorPropertyRangeHint &p_range_hint, bool p_link, bool p_is_int) {
radians_as_degrees = p_range_hint.radians_as_degrees;
for (EditorSpinSlider *spin : spin_sliders) {
spin->set_min(p_min);
spin->set_max(p_max);
spin->set_step(p_step);
if (p_hide_control) {
spin->set_min(p_range_hint.min);
spin->set_max(p_range_hint.max);
spin->set_step(p_range_hint.step);
if (p_range_hint.hide_control) {
spin->set_control_state(EditorSpinSlider::CONTROL_STATE_HIDE);
}
spin->set_allow_greater(true);
spin->set_allow_lesser(true);
spin->set_suffix(p_suffix);
spin->set_suffix(p_range_hint.suffix);
spin->set_editing_integer(p_is_int);
}

View file

@ -31,6 +31,7 @@
#pragma once
#include "editor/inspector/editor_inspector.h"
#include "editor/inspector/editor_properties.h"
class EditorSpinSlider;
class TextureButton;
@ -61,7 +62,7 @@ protected:
public:
virtual void update_property() override;
void setup(double p_min, double p_max, double p_step = 1.0, bool p_hide_control = true, bool p_link = false, const String &p_suffix = String(), bool p_radians_as_degrees = false, bool p_is_int = false);
void setup(const EditorPropertyRangeHint &p_range_hint, bool p_link = false, bool p_is_int = false);
EditorPropertyVectorN(Variant::Type p_type, bool p_force_wide, bool p_horizontal);
};

View file

@ -390,6 +390,14 @@ TileProxiesManagerDialog::TileProxiesManagerDialog() {
HBoxContainer *hboxcontainer = memnew(HBoxContainer);
vbox_container->add_child(hboxcontainer);
EditorPropertyRangeHint range_hint;
range_hint.min = -1;
range_hint.hide_control = false;
range_hint.or_less = false;
EditorPropertyRangeHint coords_property_editor_range_hint;
coords_property_editor_range_hint.min = -1;
// From
VBoxContainer *vboxcontainer_from = memnew(VBoxContainer);
vboxcontainer_from->set_h_size_flags(Control::SIZE_EXPAND_FILL);
@ -401,7 +409,7 @@ TileProxiesManagerDialog::TileProxiesManagerDialog() {
source_from_property_editor->connect("property_changed", callable_mp(this, &TileProxiesManagerDialog::_property_changed));
source_from_property_editor->set_selectable(false);
source_from_property_editor->set_h_size_flags(Control::SIZE_EXPAND_FILL);
source_from_property_editor->setup(-1, 99999, 1, false, false, true, false);
source_from_property_editor->setup(range_hint);
vboxcontainer_from->add_child(source_from_property_editor);
coords_from_property_editor = memnew(EditorPropertyVector2i);
@ -410,7 +418,7 @@ TileProxiesManagerDialog::TileProxiesManagerDialog() {
coords_from_property_editor->connect("property_changed", callable_mp(this, &TileProxiesManagerDialog::_property_changed));
coords_from_property_editor->set_selectable(false);
coords_from_property_editor->set_h_size_flags(Control::SIZE_EXPAND_FILL);
coords_from_property_editor->setup(-1, 99999, true);
coords_from_property_editor->setup(coords_property_editor_range_hint);
coords_from_property_editor->hide();
vboxcontainer_from->add_child(coords_from_property_editor);
@ -420,7 +428,7 @@ TileProxiesManagerDialog::TileProxiesManagerDialog() {
alternative_from_property_editor->connect("property_changed", callable_mp(this, &TileProxiesManagerDialog::_property_changed));
alternative_from_property_editor->set_selectable(false);
alternative_from_property_editor->set_h_size_flags(Control::SIZE_EXPAND_FILL);
alternative_from_property_editor->setup(-1, 99999, 1, false, false, true, false);
alternative_from_property_editor->setup(range_hint);
alternative_from_property_editor->hide();
vboxcontainer_from->add_child(alternative_from_property_editor);
@ -435,7 +443,7 @@ TileProxiesManagerDialog::TileProxiesManagerDialog() {
source_to_property_editor->connect("property_changed", callable_mp(this, &TileProxiesManagerDialog::_property_changed));
source_to_property_editor->set_selectable(false);
source_to_property_editor->set_h_size_flags(Control::SIZE_EXPAND_FILL);
source_to_property_editor->setup(-1, 99999, 1, false, false, true, false);
source_to_property_editor->setup(range_hint);
vboxcontainer_to->add_child(source_to_property_editor);
coords_to_property_editor = memnew(EditorPropertyVector2i);
@ -444,7 +452,7 @@ TileProxiesManagerDialog::TileProxiesManagerDialog() {
coords_to_property_editor->connect("property_changed", callable_mp(this, &TileProxiesManagerDialog::_property_changed));
coords_to_property_editor->set_selectable(false);
coords_to_property_editor->set_h_size_flags(Control::SIZE_EXPAND_FILL);
coords_to_property_editor->setup(-1, 99999, true);
coords_to_property_editor->setup(coords_property_editor_range_hint);
coords_to_property_editor->hide();
vboxcontainer_to->add_child(coords_to_property_editor);
@ -454,7 +462,7 @@ TileProxiesManagerDialog::TileProxiesManagerDialog() {
alternative_to_property_editor->connect("property_changed", callable_mp(this, &TileProxiesManagerDialog::_property_changed));
alternative_to_property_editor->set_selectable(false);
alternative_to_property_editor->set_h_size_flags(Control::SIZE_EXPAND_FILL);
alternative_to_property_editor->setup(-1, 99999, 1, false, false, true, false);
alternative_to_property_editor->setup(range_hint);
alternative_to_property_editor->hide();
vboxcontainer_to->add_child(alternative_to_property_editor);

View file

@ -63,8 +63,13 @@ void BonePropertiesEditor::create_editors() {
section->get_vbox()->add_child(enabled_checkbox);
// Position property.
EditorPropertyRangeHint large_range_hint;
large_range_hint.min = -10000;
large_range_hint.max = 10000;
large_range_hint.step = 0.001;
position_property = memnew(EditorPropertyVector3());
position_property->setup(-10000, 10000, 0.001, true);
position_property->setup(large_range_hint);
position_property->set_label("Position");
position_property->set_selectable(false);
position_property->connect("property_changed", callable_mp(this, &BonePropertiesEditor::_value_changed));
@ -73,7 +78,7 @@ void BonePropertiesEditor::create_editors() {
// Rotation property.
rotation_property = memnew(EditorPropertyQuaternion());
rotation_property->setup(-10000, 10000, 0.001, true);
rotation_property->setup(large_range_hint);
rotation_property->set_label("Rotation");
rotation_property->set_selectable(false);
rotation_property->connect("property_changed", callable_mp(this, &BonePropertiesEditor::_value_changed));
@ -82,7 +87,7 @@ void BonePropertiesEditor::create_editors() {
// Scale property.
scale_property = memnew(EditorPropertyVector3());
scale_property->setup(-10000, 10000, 0.001, true, true);
scale_property->setup(large_range_hint, true);
scale_property->set_label("Scale");
scale_property->set_selectable(false);
scale_property->connect("property_changed", callable_mp(this, &BonePropertiesEditor::_value_changed));
@ -96,7 +101,7 @@ void BonePropertiesEditor::create_editors() {
// Transform/Matrix property.
rest_matrix = memnew(EditorPropertyTransform3D());
rest_matrix->setup(-10000, 10000, 0.001, true);
rest_matrix->setup(large_range_hint);
rest_matrix->set_label("Transform");
rest_matrix->set_selectable(false);
rest_section->get_vbox()->add_child(rest_matrix);

View file

@ -465,7 +465,12 @@ void EditorPropertyOTVariation::update_property() {
Vector3i range = supported.get_value_at_index(i);
EditorPropertyInteger *prop = memnew(EditorPropertyInteger);
prop->setup(range.x, range.y, 1, false, true, false, false);
EditorPropertyRangeHint hint;
hint.min = range.x;
hint.max = range.y;
hint.or_greater = false;
hint.or_less = false;
prop->setup(hint);
prop->set_object_and_property(object.ptr(), "keys/" + itos(name_tag));
String name = TS->tag_to_name(name_tag);
@ -746,7 +751,13 @@ void EditorPropertyOTFeatures::update_property() {
} break;
case Variant::INT: {
EditorPropertyInteger *editor = memnew(EditorPropertyInteger);
editor->setup(0, 255, 1, false, false, false, false);
EditorPropertyRangeHint hint;
hint.min = 0;
hint.max = 255;
hint.hide_control = false;
hint.or_greater = false;
hint.or_less = false;
editor->setup(hint);
prop = editor;
} break;
default: {

View file

@ -1147,7 +1147,7 @@ void EditorThemeManager::_populate_standard_styles(const Ref<EditorTheme> &p_the
Ref<StyleBoxFlat> style_tab_focus = p_config.button_style_focus->duplicate();
Ref<StyleBoxFlat> style_tabbar_background = make_flat_stylebox(p_config.dark_color_1, 0, 0, 0, 0, p_config.corner_radius * EDSCALE);
Ref<StyleBoxFlat> style_tabbar_background = make_flat_stylebox(p_config.dark_color_1, 0, 0, 0, 0, p_config.corner_radius);
style_tabbar_background->set_corner_radius(CORNER_BOTTOM_LEFT, 0);
style_tabbar_background->set_corner_radius(CORNER_BOTTOM_RIGHT, 0);
p_theme->set_stylebox("tabbar_background", "TabContainer", style_tabbar_background);
@ -2553,18 +2553,6 @@ void EditorThemeManager::_populate_editor_styles(const Ref<EditorTheme> &p_theme
Ref<StyleBoxFlat> debugger_panel_style = p_config.content_panel_style->duplicate();
debugger_panel_style->set_border_width(SIDE_BOTTOM, 0);
p_theme->set_stylebox("DebuggerPanel", EditorStringName(EditorStyles), debugger_panel_style);
// This pattern of get_font()->get_height(get_font_size()) is used quite a lot and is very verbose.
// FIXME: Introduce Theme::get_font_height() / Control::get_theme_font_height() / Window::get_theme_font_height().
const int offset_i1 = p_theme->get_font(SNAME("tab_selected"), SNAME("TabContainer"))->get_height(p_theme->get_font_size(SNAME("tab_selected"), SNAME("TabContainer")));
const int offset_i2 = p_theme->get_stylebox(SNAME("tab_selected"), SNAME("TabContainer"))->get_minimum_size().height;
const int offset_i3 = p_theme->get_stylebox(SceneStringName(panel), SNAME("TabContainer"))->get_content_margin(SIDE_TOP);
const int invisible_top_offset = offset_i1 + offset_i2 + offset_i3;
Ref<StyleBoxFlat> invisible_top_panel_style = p_config.content_panel_style->duplicate();
invisible_top_panel_style->set_expand_margin(SIDE_TOP, -invisible_top_offset);
invisible_top_panel_style->set_content_margin(SIDE_TOP, 0);
p_theme->set_stylebox("BottomPanelDebuggerOverride", EditorStringName(EditorStyles), invisible_top_panel_style);
}
// Resource and node editors.

View file

@ -84,7 +84,12 @@ void POTGenerator::generate_pot(const String &p_file) {
const String &msgctxt = (translation.size() > 1) ? translation[1] : String();
const String &msgid_plural = (translation.size() > 2) ? translation[2] : String();
const String &comment = (translation.size() > 3) ? translation[3] : String();
_add_new_msgid(translation[0], msgctxt, msgid_plural, file_path, comment);
const int source_line = (translation.size() > 4) ? translation[4].to_int() : 0;
String location = file_path;
if (source_line > 0) {
location += vformat(":%d", source_line);
}
_add_new_msgid(translation[0], msgctxt, msgid_plural, location, comment);
}
}

View file

@ -72,6 +72,12 @@ if env["builtin_freetype"]:
if env["builtin_libpng"]:
env_freetype.Prepend(CPPPATH=["#thirdparty/libpng"])
if "text_server_adv" in env.module_list:
# HarfBuzz is only available if TextServerAdvanced is enabled
env_freetype.Append(CPPDEFINES=["FT_CONFIG_OPTION_USE_HARFBUZZ"])
if env["builtin_harfbuzz"]:
env_freetype.Prepend(CPPPATH=["#thirdparty/harfbuzz/src/"])
sfnt = thirdparty_dir + "src/sfnt/sfnt.c"
# Must be done after all CPPDEFINES are being set so we can copy them.
if env["platform"] == "web":

View file

@ -126,7 +126,7 @@ void GDScriptEditorTranslationParserPlugin::_add_id(const String &p_id, int p_li
return;
}
translations->push_back({ p_id, String(), String(), comment });
translations->push_back({ p_id, String(), String(), comment, itos(p_line) });
}
void GDScriptEditorTranslationParserPlugin::_add_id_ctx_plural(const Vector<String> &p_id_ctx_plural, int p_line) {
@ -136,7 +136,7 @@ void GDScriptEditorTranslationParserPlugin::_add_id_ctx_plural(const Vector<Stri
return;
}
translations->push_back({ p_id_ctx_plural[0], p_id_ctx_plural[1], p_id_ctx_plural[2], comment });
translations->push_back({ p_id_ctx_plural[0], p_id_ctx_plural[1], p_id_ctx_plural[2], comment, itos(p_line) });
}
void GDScriptEditorTranslationParserPlugin::_traverse_class(const GDScriptParser::ClassNode *p_class) {

View file

@ -135,6 +135,7 @@ static Ref<ImporterMesh> _mesh_to_importer_mesh(Ref<Mesh> p_mesh) {
mat_name, p_mesh->surface_get_format(surface_i));
}
importer_mesh->merge_meta_from(*p_mesh);
importer_mesh->set_name(p_mesh->get_name());
return importer_mesh;
}
@ -565,7 +566,9 @@ String GLTFDocument::_gen_unique_bone_name(Ref<GLTFState> p_state, const GLTFSke
Error GLTFDocument::_parse_scenes(Ref<GLTFState> p_state) {
p_state->unique_names.insert("Skeleton3D"); // Reserve skeleton name.
ERR_FAIL_COND_V(!p_state->json.has("scenes"), ERR_FILE_CORRUPT);
if (!p_state->json.has("scenes")) {
return OK; // No scenes.
}
const Array &scenes = p_state->json["scenes"];
int loaded_scene = 0;
if (p_state->json.has("scene")) {
@ -577,10 +580,11 @@ Error GLTFDocument::_parse_scenes(Ref<GLTFState> p_state) {
if (scenes.size()) {
ERR_FAIL_COND_V(loaded_scene >= scenes.size(), ERR_FILE_CORRUPT);
const Dictionary &scene_dict = scenes[loaded_scene];
ERR_FAIL_COND_V(!scene_dict.has("nodes"), ERR_UNAVAILABLE);
const Array &nodes = scene_dict["nodes"];
for (int j = 0; j < nodes.size(); j++) {
p_state->root_nodes.push_back(nodes[j]);
if (scene_dict.has("nodes")) {
const Array &nodes = scene_dict["nodes"];
for (const Variant &node : nodes) {
p_state->root_nodes.push_back(node);
}
}
// Determine what to use for the scene name.
if (scene_dict.has("name") && !String(scene_dict["name"]).is_empty() && !((String)scene_dict["name"]).begins_with("Scene")) {
@ -597,7 +601,9 @@ Error GLTFDocument::_parse_scenes(Ref<GLTFState> p_state) {
}
Error GLTFDocument::_parse_nodes(Ref<GLTFState> p_state) {
ERR_FAIL_COND_V(!p_state->json.has("nodes"), ERR_FILE_CORRUPT);
if (!p_state->json.has("nodes")) {
return OK; // No nodes to parse.
}
const Array &nodes = p_state->json["nodes"];
for (int i = 0; i < nodes.size(); i++) {
Ref<GLTFNode> node;
@ -2840,13 +2846,14 @@ Error GLTFDocument::_serialize_meshes(Ref<GLTFState> p_state) {
Array meshes;
for (GLTFMeshIndex gltf_mesh_i = 0; gltf_mesh_i < p_state->meshes.size(); gltf_mesh_i++) {
print_verbose("glTF: Serializing mesh: " + itos(gltf_mesh_i));
Ref<ImporterMesh> import_mesh = p_state->meshes.write[gltf_mesh_i]->get_mesh();
Ref<GLTFMesh> &gltf_mesh = p_state->meshes.write[gltf_mesh_i];
Ref<ImporterMesh> import_mesh = gltf_mesh->get_mesh();
if (import_mesh.is_null()) {
continue;
}
Array instance_materials = p_state->meshes.write[gltf_mesh_i]->get_instance_materials();
Array instance_materials = gltf_mesh->get_instance_materials();
Array primitives;
Dictionary gltf_mesh;
Dictionary mesh_dict;
Array target_names;
Array weights;
for (int morph_i = 0; morph_i < import_mesh->get_blend_shape_count(); morph_i++) {
@ -3233,27 +3240,31 @@ Error GLTFDocument::_serialize_meshes(Ref<GLTFState> p_state) {
if (!target_names.is_empty()) {
Dictionary e;
e["targetNames"] = target_names;
gltf_mesh["extras"] = e;
mesh_dict["extras"] = e;
}
_attach_meta_to_extras(import_mesh, gltf_mesh);
_attach_meta_to_extras(import_mesh, mesh_dict);
weights.resize(target_names.size());
for (int name_i = 0; name_i < target_names.size(); name_i++) {
real_t weight = 0.0;
if (name_i < p_state->meshes.write[gltf_mesh_i]->get_blend_weights().size()) {
weight = p_state->meshes.write[gltf_mesh_i]->get_blend_weights()[name_i];
if (name_i < gltf_mesh->get_blend_weights().size()) {
weight = gltf_mesh->get_blend_weights()[name_i];
}
weights[name_i] = weight;
}
if (weights.size()) {
gltf_mesh["weights"] = weights;
mesh_dict["weights"] = weights;
}
ERR_FAIL_COND_V(target_names.size() != weights.size(), FAILED);
gltf_mesh["primitives"] = primitives;
mesh_dict["primitives"] = primitives;
meshes.push_back(gltf_mesh);
if (!gltf_mesh->get_name().is_empty()) {
mesh_dict["name"] = gltf_mesh->get_name();
}
meshes.push_back(mesh_dict);
}
if (!meshes.size()) {
@ -4482,19 +4493,19 @@ Error GLTFDocument::_parse_texture_samplers(Ref<GLTFState> p_state) {
Error GLTFDocument::_serialize_materials(Ref<GLTFState> p_state) {
Array materials;
for (int32_t i = 0; i < p_state->materials.size(); i++) {
Dictionary d;
Dictionary mat_dict;
Ref<Material> material = p_state->materials[i];
if (material.is_null()) {
materials.push_back(d);
materials.push_back(mat_dict);
continue;
}
if (!material->get_name().is_empty()) {
d["name"] = _gen_unique_name(p_state, material->get_name());
mat_dict["name"] = _gen_unique_name(p_state, material->get_name());
}
Ref<BaseMaterial3D> base_material = material;
if (base_material.is_null()) {
materials.push_back(d);
materials.push_back(mat_dict);
continue;
}
@ -4647,7 +4658,7 @@ Error GLTFDocument::_serialize_materials(Ref<GLTFState> p_state) {
if (has_ao) {
Dictionary occt;
occt["index"] = orm_texture_index;
d["occlusionTexture"] = occt;
mat_dict["occlusionTexture"] = occt;
}
if (has_roughness || has_metalness) {
mrt["index"] = orm_texture_index;
@ -4661,7 +4672,7 @@ Error GLTFDocument::_serialize_materials(Ref<GLTFState> p_state) {
}
}
d["pbrMetallicRoughness"] = mr;
mat_dict["pbrMetallicRoughness"] = mr;
if (base_material->get_feature(BaseMaterial3D::FEATURE_NORMAL_MAPPING) && _image_format != "None") {
Dictionary nt;
Ref<ImageTexture> tex;
@ -4701,14 +4712,14 @@ Error GLTFDocument::_serialize_materials(Ref<GLTFState> p_state) {
nt["scale"] = base_material->get_normal_scale();
if (gltf_texture_index != -1) {
nt["index"] = gltf_texture_index;
d["normalTexture"] = nt;
mat_dict["normalTexture"] = nt;
}
}
if (base_material->get_feature(BaseMaterial3D::FEATURE_EMISSION)) {
const Color c = base_material->get_emission().linear_to_srgb();
Array arr = { c.r, c.g, c.b };
d["emissiveFactor"] = arr;
mat_dict["emissiveFactor"] = arr;
}
if (base_material->get_feature(BaseMaterial3D::FEATURE_EMISSION) && _image_format != "None") {
@ -4722,20 +4733,20 @@ Error GLTFDocument::_serialize_materials(Ref<GLTFState> p_state) {
if (gltf_texture_index != -1) {
et["index"] = gltf_texture_index;
d["emissiveTexture"] = et;
mat_dict["emissiveTexture"] = et;
}
}
const bool ds = base_material->get_cull_mode() == BaseMaterial3D::CULL_DISABLED;
if (ds) {
d["doubleSided"] = ds;
mat_dict["doubleSided"] = ds;
}
if (base_material->get_transparency() == BaseMaterial3D::TRANSPARENCY_ALPHA_SCISSOR) {
d["alphaMode"] = "MASK";
d["alphaCutoff"] = base_material->get_alpha_scissor_threshold();
mat_dict["alphaMode"] = "MASK";
mat_dict["alphaCutoff"] = base_material->get_alpha_scissor_threshold();
} else if (base_material->get_transparency() != BaseMaterial3D::TRANSPARENCY_DISABLED) {
d["alphaMode"] = "BLEND";
mat_dict["alphaMode"] = "BLEND";
}
Dictionary extensions;
@ -4750,10 +4761,10 @@ Error GLTFDocument::_serialize_materials(Ref<GLTFState> p_state) {
extensions["KHR_materials_emissive_strength"] = mat_emissive_strength;
p_state->add_used_extension("KHR_materials_emissive_strength");
}
d["extensions"] = extensions;
mat_dict["extensions"] = extensions;
_attach_meta_to_extras(material, d);
materials.push_back(d);
_attach_meta_to_extras(material, mat_dict);
materials.push_back(mat_dict);
}
if (!materials.size()) {
return OK;
@ -5858,6 +5869,10 @@ GLTFMeshIndex GLTFDocument::_convert_mesh_to_gltf(Ref<GLTFState> p_state, MeshIn
Ref<GLTFMesh> gltf_mesh;
gltf_mesh.instantiate();
if (!mesh_resource->get_name().is_empty()) {
gltf_mesh->set_original_name(mesh_resource->get_name());
gltf_mesh->set_name(_gen_unique_name(p_state, mesh_resource->get_name()));
}
gltf_mesh->set_instance_materials(instance_materials);
gltf_mesh->set_mesh(current_mesh);
gltf_mesh->set_blend_weights(blend_weights);
@ -8677,6 +8692,7 @@ Node *GLTFDocument::_generate_scene_node_tree(Ref<GLTFState> p_state) {
// Generate the node tree.
Node *single_root;
if (p_state->extensions_used.has("GODOT_single_root")) {
ERR_FAIL_COND_V_MSG(p_state->nodes.is_empty(), nullptr, "glTF: Single root file has no nodes. This glTF file is invalid.");
if (_naming_version < 2) {
_generate_scene_node_compat_4pt4(p_state, 0, nullptr, nullptr);
} else {
@ -8844,50 +8860,53 @@ Error GLTFDocument::write_to_filesystem(Ref<GLTFState> p_state, const String &p_
}
Node *GLTFDocument::generate_scene(Ref<GLTFState> p_state, float p_bake_fps, bool p_trimming, bool p_remove_immutable_tracks) {
Ref<GLTFState> state = p_state;
ERR_FAIL_COND_V(state.is_null(), nullptr);
ERR_FAIL_INDEX_V(0, state->root_nodes.size(), nullptr);
ERR_FAIL_COND_V(p_state.is_null(), nullptr);
// The glTF file must have nodes, and have some marked as root nodes, in order to generate a scene.
if (p_state->nodes.is_empty()) {
WARN_PRINT("glTF: This glTF file has no nodes, the generated Godot scene will be empty.");
}
// Now that we know that we have glTF nodes, we can begin generating a scene from the parsed glTF data.
Error err = OK;
p_state->set_bake_fps(p_bake_fps);
Node *root = _generate_scene_node_tree(state);
ERR_FAIL_NULL_V(root, nullptr);
_process_mesh_instances(state, root);
if (state->get_create_animations() && state->animations.size()) {
AnimationPlayer *ap = memnew(AnimationPlayer);
root->add_child(ap, true);
ap->set_owner(root);
for (int i = 0; i < state->animations.size(); i++) {
_import_animation(state, ap, i, p_trimming, p_remove_immutable_tracks);
Node *godot_root_node = _generate_scene_node_tree(p_state);
ERR_FAIL_NULL_V(godot_root_node, nullptr);
_process_mesh_instances(p_state, godot_root_node);
if (p_state->get_create_animations() && p_state->animations.size()) {
AnimationPlayer *anim_player = memnew(AnimationPlayer);
godot_root_node->add_child(anim_player, true);
anim_player->set_owner(godot_root_node);
for (int i = 0; i < p_state->animations.size(); i++) {
_import_animation(p_state, anim_player, i, p_trimming, p_remove_immutable_tracks);
}
}
for (KeyValue<GLTFNodeIndex, Node *> E : state->scene_nodes) {
for (KeyValue<GLTFNodeIndex, Node *> E : p_state->scene_nodes) {
ERR_CONTINUE(!E.value);
for (Ref<GLTFDocumentExtension> ext : document_extensions) {
ERR_CONTINUE(ext.is_null());
Dictionary node_json;
if (state->json.has("nodes")) {
Array nodes = state->json["nodes"];
if (p_state->json.has("nodes")) {
Array nodes = p_state->json["nodes"];
if (0 <= E.key && E.key < nodes.size()) {
node_json = nodes[E.key];
}
}
Ref<GLTFNode> gltf_node = state->nodes[E.key];
Ref<GLTFNode> gltf_node = p_state->nodes[E.key];
err = ext->import_node(p_state, gltf_node, node_json, E.value);
ERR_CONTINUE(err != OK);
}
}
ImporterMeshInstance3D *root_importer_mesh = Object::cast_to<ImporterMeshInstance3D>(root);
ImporterMeshInstance3D *root_importer_mesh = Object::cast_to<ImporterMeshInstance3D>(godot_root_node);
if (unlikely(root_importer_mesh)) {
root = GLTFDocumentExtensionConvertImporterMesh::convert_importer_mesh_instance_3d(root_importer_mesh);
godot_root_node = GLTFDocumentExtensionConvertImporterMesh::convert_importer_mesh_instance_3d(root_importer_mesh);
memdelete(root_importer_mesh);
}
for (Ref<GLTFDocumentExtension> ext : document_extensions) {
ERR_CONTINUE(ext.is_null());
err = ext->import_post(p_state, root);
err = ext->import_post(p_state, godot_root_node);
ERR_CONTINUE(err != OK);
}
ERR_FAIL_NULL_V(root, nullptr);
return root;
ERR_FAIL_NULL_V(godot_root_node, nullptr);
return godot_root_node;
}
Error GLTFDocument::append_from_scene(Node *p_node, Ref<GLTFState> p_state, uint32_t p_flags) {

View file

@ -55,6 +55,7 @@ if env["builtin_harfbuzz"]:
# "src/hb-glib.cc",
# "src/hb-gobject-structs.cc",
"src/hb-icu.cc",
# "src/hb-kbts.cc",
"src/hb-map.cc",
"src/hb-number.cc",
"src/hb-ot-cff1-table.cc",
@ -95,14 +96,19 @@ if env["builtin_harfbuzz"]:
"src/hb-shaper.cc",
"src/hb-static.cc",
"src/hb-style.cc",
"src/hb-subset-cff-common.cc",
"src/hb-subset-cff1.cc",
"src/hb-subset-cff2.cc",
"src/hb-subset-input.cc",
"src/hb-subset-instancer-iup.cc",
"src/hb-subset-instancer-solver.cc",
"src/hb-subset-plan.cc",
"src/hb-subset-serialize.cc",
# "src/hb-subset-cff-common.cc",
# "src/hb-subset-cff1.cc",
# "src/hb-subset-cff2.cc",
# "src/hb-subset-input.cc",
# "src/hb-subset-instancer-iup.cc",
# "src/hb-subset-instancer-solver.cc",
# "src/hb-subset-plan.cc",
# "src/hb-subset-serialize.cc",
# "src/hb-subset-table-cff.cc",
# "src/hb-subset-table-color.cc",
# "src/hb-subset-table-layout.cc",
# "src/hb-subset-table-other.cc",
# "src/hb-subset-table-var.cc",
"src/hb-subset.cc",
"src/hb-ucd.cc",
"src/hb-unicode.cc",

View file

@ -2177,7 +2177,9 @@ void EditorExportPlatformAndroid::get_export_options(List<ExportOption> *r_optio
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "shader_baker/enabled"), false));
#ifndef XR_DISABLED
r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "xr_features/xr_mode", PROPERTY_HINT_ENUM, "Regular,OpenXR"), XR_MODE_REGULAR, false, true));
#endif // XR_DISABLED
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "gesture/swipe_to_dismiss"), false));
@ -3087,6 +3089,7 @@ void EditorExportPlatformAndroid::get_command_line_flags(const Ref<EditorExportP
command_line_strings.push_back(apk_expansion_public_key.strip_edges());
}
#ifndef XR_DISABLED
int xr_mode_index = p_preset->get("xr_features/xr_mode");
if (xr_mode_index == XR_MODE_OPENXR) {
command_line_strings.push_back("--xr_mode_openxr");
@ -3100,6 +3103,7 @@ void EditorExportPlatformAndroid::get_command_line_flags(const Ref<EditorExportP
command_line_strings.push_back("--xr-mode");
command_line_strings.push_back("off");
}
#endif // XR_DISABLED
bool immersive = p_preset->get("screen/immersive_mode");
if (immersive) {

View file

@ -31,6 +31,7 @@
#pragma once
#include "scene/2d/node_2d.h"
#include "scene/resources/mesh.h"
class NavigationPolygon;
class NavigationMeshSourceGeometryData2D;

View file

@ -37,6 +37,7 @@
#include "scene/2d/tile_map.h"
#include "scene/gui/control.h"
#include "scene/resources/2d/navigation_mesh_source_geometry_data_2d.h"
#include "scene/resources/material.h"
#include "scene/resources/world_2d.h"
#ifndef PHYSICS_2D_DISABLED

View file

@ -32,6 +32,7 @@
#include "animation_blend_tree.h"
#include "core/math/geometry_2d.h"
#include "scene/resources/material.h"
void AnimationNodeBlendSpace2D::get_parameter_list(List<PropertyInfo> *r_list) const {
AnimationNode::get_parameter_list(r_list);

View file

@ -36,6 +36,10 @@
#include "scene/main/viewport.h"
#include "scene/theme/theme_db.h"
static inline Color _select_color(const Color &p_override_color, const Color &p_default_color) {
return p_override_color.a > 0 ? p_override_color : p_default_color;
}
Size2 TabBar::get_minimum_size() const {
Size2 ms;
@ -527,15 +531,15 @@ void TabBar::_notification(int p_what) {
if (tabs[i].disabled) {
sb = theme_cache.tab_disabled_style;
fnt_col = theme_cache.font_disabled_color;
fnt_col = _select_color(tabs[i].font_color_overrides[DrawMode::DRAW_DISABLED], theme_cache.font_disabled_color);
icn_col = theme_cache.icon_disabled_color;
} else if (i == hover) {
sb = theme_cache.tab_hovered_style;
fnt_col = theme_cache.font_hovered_color;
fnt_col = _select_color(tabs[i].font_color_overrides[DrawMode::DRAW_HOVER], theme_cache.font_hovered_color);
icn_col = theme_cache.icon_hovered_color;
} else {
sb = theme_cache.tab_unselected_style;
fnt_col = theme_cache.font_unselected_color;
fnt_col = _select_color(tabs[i].font_color_overrides[DrawMode::DRAW_NORMAL], theme_cache.font_unselected_color);
icn_col = theme_cache.icon_unselected_color;
}
@ -546,8 +550,9 @@ void TabBar::_notification(int p_what) {
// Draw selected tab in the front, but only if it's visible.
if (current >= offset && current <= max_drawn_tab && !tabs[current].hidden) {
Ref<StyleBox> sb = tabs[current].disabled ? theme_cache.tab_disabled_style : theme_cache.tab_selected_style;
Color col = _select_color(tabs[current].font_color_overrides[DrawMode::DRAW_PRESSED], theme_cache.font_selected_color);
_draw_tab(sb, theme_cache.font_selected_color, theme_cache.icon_selected_color, current, rtl ? (size.width - tabs[current].ofs_cache - tabs[current].size_cache) : tabs[current].ofs_cache, has_focus(true));
_draw_tab(sb, col, theme_cache.icon_selected_color, current, rtl ? (size.width - tabs[current].ofs_cache - tabs[current].size_cache) : tabs[current].ofs_cache, has_focus(true));
}
if (buttons_visible) {
@ -1009,6 +1014,37 @@ int TabBar::get_tab_icon_max_width(int p_tab) const {
return tabs[p_tab].icon_max_width;
}
void TabBar::set_font_color_override_all(int p_tab, const Color &p_color) {
ERR_FAIL_INDEX(p_tab, tabs.size());
Tab &tab = tabs.write[p_tab];
for (int i = 0; i < DrawMode::DRAW_MAX; i++) {
tab.font_color_overrides[i] = p_color;
}
queue_redraw();
}
void TabBar::set_font_color_override(int p_tab, DrawMode p_draw_mode, const Color &p_color) {
ERR_FAIL_INDEX(p_tab, tabs.size());
ERR_FAIL_INDEX(p_draw_mode, DrawMode::DRAW_MAX);
if (tabs[p_tab].font_color_overrides[p_draw_mode] == p_color) {
return;
}
tabs.write[p_tab].font_color_overrides[p_draw_mode] = p_color;
queue_redraw();
}
Color TabBar::get_font_color_override(int p_tab, DrawMode p_draw_mode) const {
ERR_FAIL_INDEX_V(p_tab, tabs.size(), Color());
ERR_FAIL_INDEX_V(p_draw_mode, DrawMode::DRAW_MAX, Color());
return tabs[p_tab].font_color_overrides[p_draw_mode];
}
void TabBar::set_tab_disabled(int p_tab, bool p_disabled) {
ERR_FAIL_INDEX(p_tab, tabs.size());

View file

@ -52,11 +52,22 @@ public:
CLOSE_BUTTON_MAX
};
enum DrawMode {
DRAW_NORMAL,
DRAW_PRESSED,
DRAW_HOVER,
DRAW_DISABLED,
DRAW_MAX,
};
private:
struct Tab {
mutable RID accessibility_item_element;
mutable bool accessibility_item_dirty = true;
// Corresponds to color overrides for the DrawMode enum
Color font_color_overrides[DrawMode::DRAW_MAX] = { Color(0, 0, 0, 0), Color(0, 0, 0, 0), Color(0, 0, 0, 0), Color(0, 0, 0, 0) };
String text;
String tooltip;
@ -228,6 +239,10 @@ public:
void set_tab_icon_max_width(int p_tab, int p_width);
int get_tab_icon_max_width(int p_tab) const;
void set_font_color_override_all(int p_tab, const Color &p_color);
void set_font_color_override(int p_tab, DrawMode p_draw_mode, const Color &p_color);
Color get_font_color_override(int p_tab, DrawMode p_draw_mode) const;
void set_tab_disabled(int p_tab, bool p_disabled);
bool is_tab_disabled(int p_tab) const;

View file

@ -947,8 +947,7 @@ void CanvasItem::draw_set_transform(const Point2 &p_offset, real_t p_rot, const
ERR_THREAD_GUARD;
ERR_DRAW_GUARD;
Transform2D xform(p_rot, p_offset);
xform.scale_basis(p_scale);
Transform2D xform(p_rot, p_scale, 0.0, p_offset);
RenderingServer::get_singleton()->canvas_item_add_set_transform(canvas_item, xform);
}

View file

@ -4768,6 +4768,7 @@ void Viewport::_propagate_exit_world_3d(Node *p_node) {
}
}
#ifndef XR_DISABLED
void Viewport::set_use_xr(bool p_use_xr) {
ERR_MAIN_THREAD_GUARD;
if (use_xr != p_use_xr) {
@ -4794,6 +4795,7 @@ bool Viewport::is_using_xr() {
ERR_READ_THREAD_GUARD_V(false);
return use_xr;
}
#endif // XR_DISABLED
void Viewport::set_scaling_3d_mode(Scaling3DMode p_scaling_3d_mode) {
ERR_MAIN_THREAD_GUARD;
@ -5060,8 +5062,10 @@ void Viewport::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_disable_3d", "disable"), &Viewport::set_disable_3d);
ClassDB::bind_method(D_METHOD("is_3d_disabled"), &Viewport::is_3d_disabled);
#ifndef XR_DISABLED
ClassDB::bind_method(D_METHOD("set_use_xr", "use"), &Viewport::set_use_xr);
ClassDB::bind_method(D_METHOD("is_using_xr"), &Viewport::is_using_xr);
#endif // XR_DISABLED
ClassDB::bind_method(D_METHOD("set_scaling_3d_mode", "scaling_3d_mode"), &Viewport::set_scaling_3d_mode);
ClassDB::bind_method(D_METHOD("get_scaling_3d_mode"), &Viewport::get_scaling_3d_mode);
@ -5088,7 +5092,9 @@ void Viewport::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_vrs_texture"), &Viewport::get_vrs_texture);
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "disable_3d"), "set_disable_3d", "is_3d_disabled");
#ifndef XR_DISABLED
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_xr"), "set_use_xr", "is_using_xr");
#endif // XR_DISABLED
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "own_world_3d"), "set_use_own_world_3d", "is_using_own_world_3d");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "world_3d", PROPERTY_HINT_RESOURCE_TYPE, "World3D"), "set_world_3d", "get_world_3d");
#endif // _3D_DISABLED

View file

@ -788,7 +788,9 @@ public:
#ifndef _3D_DISABLED
private:
// 3D audio, camera, physics, and world.
#ifndef XR_DISABLED
bool use_xr = false;
#endif // XR_DISABLED
friend class AudioListener3D;
AudioListener3D *audio_listener_3d = nullptr;
HashSet<AudioListener3D *> audio_listener_3d_set;
@ -846,8 +848,10 @@ public:
void set_use_own_world_3d(bool p_use_own_world_3d);
bool is_using_own_world_3d() const;
#ifndef XR_DISABLED
void set_use_xr(bool p_use_xr);
bool is_using_xr();
#endif // XR_DISABLED
#endif // _3D_DISABLED
Viewport();

View file

@ -37,6 +37,7 @@
#include "core/templates/rb_set.h"
#include "scene/gui/control.h"
#include "scene/resources/image_texture.h"
#include "scene/resources/mesh.h"
#ifndef NAVIGATION_2D_DISABLED
#include "servers/navigation_2d/navigation_server_2d.h"

View file

@ -188,6 +188,14 @@ void CameraFeed::set_rgb_image(const Ref<Image> &p_rgb_img) {
int new_width = p_rgb_img->get_width();
int new_height = p_rgb_img->get_height();
// Emit `format_changed` signal if feed datatype or frame size is changed.
// The signal is deferred to ensure:
// - They are emitted on Godot's main thread.
// - Both datatype and frame size are updated before the emission.
if (datatype != CameraFeed::FEED_RGB || (base_width != new_width) || (base_height != new_height)) {
call_deferred("emit_signal", format_changed_signal_name);
}
if ((base_width != new_width) || (base_height != new_height)) {
// We're assuming here that our camera image doesn't change around formats etc, allocate the whole lot...
base_width = new_width;
@ -195,10 +203,6 @@ void CameraFeed::set_rgb_image(const Ref<Image> &p_rgb_img) {
RID new_texture = RenderingServer::get_singleton()->texture_2d_create(p_rgb_img);
RenderingServer::get_singleton()->texture_replace(texture[CameraServer::FEED_RGBA_IMAGE], new_texture);
// Defer `format_changed` signals to ensure they are emitted on Godot's main thread.
// This also makes sure the datatype of the feed is updated before the emission.
call_deferred("emit_signal", format_changed_signal_name);
} else {
RenderingServer::get_singleton()->texture_2d_update(texture[CameraServer::FEED_RGBA_IMAGE], p_rgb_img);
}
@ -216,6 +220,14 @@ void CameraFeed::set_ycbcr_image(const Ref<Image> &p_ycbcr_img) {
int new_width = p_ycbcr_img->get_width();
int new_height = p_ycbcr_img->get_height();
// Emit `format_changed` signal if feed datatype or frame size is changed.
// The signal is deferred to ensure:
// - They are emitted on Godot's main thread.
// - Both datatype and frame size are updated before the emission.
if (datatype != CameraFeed::FEED_YCBCR || (base_width != new_width) || (base_height != new_height)) {
call_deferred("emit_signal", format_changed_signal_name);
}
if ((base_width != new_width) || (base_height != new_height)) {
// We're assuming here that our camera image doesn't change around formats etc, allocate the whole lot...
base_width = new_width;
@ -223,10 +235,6 @@ void CameraFeed::set_ycbcr_image(const Ref<Image> &p_ycbcr_img) {
RID new_texture = RenderingServer::get_singleton()->texture_2d_create(p_ycbcr_img);
RenderingServer::get_singleton()->texture_replace(texture[CameraServer::FEED_RGBA_IMAGE], new_texture);
// Defer `format_changed` signals to ensure they are emitted on Godot's main thread.
// This also makes sure the datatype of the feed is updated before the emission.
call_deferred("emit_signal", format_changed_signal_name);
} else {
RenderingServer::get_singleton()->texture_2d_update(texture[CameraServer::FEED_RGBA_IMAGE], p_ycbcr_img);
}
@ -249,6 +257,14 @@ void CameraFeed::set_ycbcr_images(const Ref<Image> &p_y_img, const Ref<Image> &p
int new_y_width = p_y_img->get_width();
int new_y_height = p_y_img->get_height();
// Emit `format_changed` signal if feed datatype or frame size is changed.
// The signal is deferred to ensure:
// - They are emitted on Godot's main thread.
// - Both datatype and frame size are updated before the emission.
if (datatype != CameraFeed::FEED_YCBCR_SEP || (base_width != new_y_width) || (base_height != new_y_height)) {
call_deferred("emit_signal", format_changed_signal_name);
}
if ((base_width != new_y_width) || (base_height != new_y_height)) {
// We're assuming here that our camera image doesn't change around formats etc, allocate the whole lot...
base_width = new_y_width;
@ -261,10 +277,6 @@ void CameraFeed::set_ycbcr_images(const Ref<Image> &p_y_img, const Ref<Image> &p
RID new_texture = RenderingServer::get_singleton()->texture_2d_create(p_cbcr_img);
RenderingServer::get_singleton()->texture_replace(texture[CameraServer::FEED_CBCR_IMAGE], new_texture);
}
// Defer `format_changed` signals to ensure they are emitted on Godot's main thread.
// This also makes sure the datatype of the feed is updated before the emission.
call_deferred("emit_signal", format_changed_signal_name);
} else {
RenderingServer::get_singleton()->texture_2d_update(texture[CameraServer::FEED_Y_IMAGE], p_y_img);
RenderingServer::get_singleton()->texture_2d_update(texture[CameraServer::FEED_CBCR_IMAGE], p_cbcr_img);
@ -278,6 +290,14 @@ void CameraFeed::set_ycbcr_images(const Ref<Image> &p_y_img, const Ref<Image> &p
}
void CameraFeed::set_external(int p_width, int p_height) {
// Emit `format_changed` signal if feed datatype or frame size is changed.
// The signal is deferred to ensure:
// - They are emitted on Godot's main thread.
// - Both datatype and frame size are updated before the emission.
if (datatype != CameraFeed::FEED_EXTERNAL || (base_width != p_width) || (base_height != p_height)) {
call_deferred("emit_signal", format_changed_signal_name);
}
if ((base_width != p_width) || (base_height != p_height)) {
// We're assuming here that our camera image doesn't change around formats etc, allocate the whole lot...
base_width = p_width;

View file

@ -66,7 +66,7 @@ BokehDOF::BokehDOF(bool p_prefer_raster_effects) {
for (int i = 0; i < BOKEH_MAX; i++) {
if (bokeh.compute_shader.is_variant_enabled(i)) {
bokeh.compute_pipelines[i] = RD::get_singleton()->compute_pipeline_create(bokeh.compute_shader.version_get_shader(bokeh.shader_version, i));
bokeh.compute_pipelines[i].create_compute_pipeline(bokeh.compute_shader.version_get_shader(bokeh.shader_version, i));
}
}
@ -77,6 +77,10 @@ BokehDOF::BokehDOF(bool p_prefer_raster_effects) {
}
BokehDOF::~BokehDOF() {
for (int i = 0; i < BOKEH_MAX; i++) {
bokeh.compute_pipelines[i].free();
}
if (prefer_raster_effects) {
bokeh.raster_shader.version_free(bokeh.shader_version);
} else {
@ -154,7 +158,7 @@ void BokehDOF::bokeh_dof_compute(const BokehBuffers &p_buffers, RID p_camera_att
RID shader = bokeh.compute_shader.version_get_shader(bokeh.shader_version, BOKEH_GEN_BLUR_SIZE);
ERR_FAIL_COND(shader.is_null());
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, bokeh.compute_pipelines[BOKEH_GEN_BLUR_SIZE]);
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, bokeh.compute_pipelines[BOKEH_GEN_BLUR_SIZE].get_rid());
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 0, u_base_image), 0);
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 1, u_depth_texture), 1);
@ -173,7 +177,7 @@ void BokehDOF::bokeh_dof_compute(const BokehBuffers &p_buffers, RID p_camera_att
shader = bokeh.compute_shader.version_get_shader(bokeh.shader_version, mode);
ERR_FAIL_COND(shader.is_null());
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, bokeh.compute_pipelines[mode]);
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, bokeh.compute_pipelines[mode].get_rid());
static const int quality_samples[4] = { 6, 12, 12, 24 };
@ -223,7 +227,7 @@ void BokehDOF::bokeh_dof_compute(const BokehBuffers &p_buffers, RID p_camera_att
shader = bokeh.compute_shader.version_get_shader(bokeh.shader_version, BOKEH_COMPOSITE);
ERR_FAIL_COND(shader.is_null());
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, bokeh.compute_pipelines[BOKEH_COMPOSITE]);
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, bokeh.compute_pipelines[BOKEH_COMPOSITE].get_rid());
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 0, u_base_image), 0);
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 1, u_half_texture1), 1);
@ -244,7 +248,7 @@ void BokehDOF::bokeh_dof_compute(const BokehBuffers &p_buffers, RID p_camera_att
ERR_FAIL_COND(shader.is_null());
//second pass
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, bokeh.compute_pipelines[BOKEH_GEN_BOKEH_CIRCULAR]);
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, bokeh.compute_pipelines[BOKEH_GEN_BOKEH_CIRCULAR].get_rid());
static const float quality_scale[4] = { 8.0, 4.0, 1.0, 0.5 };
@ -272,7 +276,7 @@ void BokehDOF::bokeh_dof_compute(const BokehBuffers &p_buffers, RID p_camera_att
shader = bokeh.compute_shader.version_get_shader(bokeh.shader_version, BOKEH_COMPOSITE);
ERR_FAIL_COND(shader.is_null());
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, bokeh.compute_pipelines[BOKEH_COMPOSITE]);
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, bokeh.compute_pipelines[BOKEH_COMPOSITE].get_rid());
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 0, u_base_image), 0);
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 1, u_half_texture0), 1);

View file

@ -31,6 +31,7 @@
#pragma once
#include "servers/rendering/renderer_rd/pipeline_cache_rd.h"
#include "servers/rendering/renderer_rd/pipeline_deferred_rd.h"
#include "servers/rendering/renderer_rd/shaders/effects/bokeh_dof.glsl.gen.h"
#include "servers/rendering/renderer_rd/shaders/effects/bokeh_dof_raster.glsl.gen.h"
@ -86,7 +87,7 @@ private:
BokehDofShaderRD compute_shader;
BokehDofRasterShaderRD raster_shader;
RID shader_version;
RID compute_pipelines[BOKEH_MAX];
PipelineDeferredRD compute_pipelines[BOKEH_MAX];
PipelineCacheRD raster_pipelines[BOKEH_MAX];
} bokeh;

View file

@ -96,7 +96,7 @@ CopyEffects::CopyEffects(bool p_prefer_raster_effects) {
for (int i = 0; i < COPY_MODE_MAX; i++) {
if (copy.shader.is_variant_enabled(i)) {
copy.pipelines[i] = RD::get_singleton()->compute_pipeline_create(copy.shader.version_get_shader(copy.shader_version, i));
copy.pipelines[i].create_compute_pipeline(copy.shader.version_get_shader(copy.shader_version, i));
}
}
}
@ -162,7 +162,7 @@ CopyEffects::CopyEffects(bool p_prefer_raster_effects) {
cubemap_downsampler.shader_version = cubemap_downsampler.compute_shader.version_create();
cubemap_downsampler.compute_pipeline = RD::get_singleton()->compute_pipeline_create(cubemap_downsampler.compute_shader.version_get_shader(cubemap_downsampler.shader_version, 0));
cubemap_downsampler.compute_pipeline.create_compute_pipeline(cubemap_downsampler.compute_shader.version_get_shader(cubemap_downsampler.shader_version, 0));
cubemap_downsampler.raster_pipeline.clear();
}
}
@ -216,7 +216,7 @@ CopyEffects::CopyEffects(bool p_prefer_raster_effects) {
filter.shader_version = filter.compute_shader.version_create();
for (int i = 0; i < FILTER_MODE_MAX; i++) {
filter.compute_pipelines[i] = RD::get_singleton()->compute_pipeline_create(filter.compute_shader.version_get_shader(filter.shader_version, i));
filter.compute_pipelines[i].create_compute_pipeline(filter.compute_shader.version_get_shader(filter.shader_version, i));
filter.raster_pipelines[i].clear();
}
@ -249,7 +249,7 @@ CopyEffects::CopyEffects(bool p_prefer_raster_effects) {
roughness.shader_version = roughness.compute_shader.version_create();
roughness.compute_pipeline = RD::get_singleton()->compute_pipeline_create(roughness.compute_shader.version_get_shader(roughness.shader_version, 0));
roughness.compute_pipeline.create_compute_pipeline(roughness.compute_shader.version_get_shader(roughness.shader_version, 0));
roughness.raster_pipeline.clear();
}
}
@ -306,6 +306,17 @@ CopyEffects::CopyEffects(bool p_prefer_raster_effects) {
}
CopyEffects::~CopyEffects() {
for (int i = 0; i < COPY_MODE_MAX; i++) {
copy.pipelines[i].free();
}
for (int i = 0; i < FILTER_MODE_MAX; i++) {
filter.compute_pipelines[i].free();
}
cubemap_downsampler.compute_pipeline.free();
roughness.compute_pipeline.free();
if (prefer_raster_effects) {
blur_raster.shader.version_free(blur_raster.shader_version);
cubemap_downsampler.raster_shader.version_free(cubemap_downsampler.shader_version);
@ -377,7 +388,7 @@ void CopyEffects::copy_to_rect(RID p_source_rd_texture, RID p_dest_texture, cons
ERR_FAIL_COND(shader.is_null());
RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, copy.pipelines[mode]);
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, copy.pipelines[mode].get_rid());
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 0, u_source_rd_texture), 0);
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 3, u_dest_texture), 3);
RD::get_singleton()->compute_list_set_push_constant(compute_list, &copy.push_constant, sizeof(CopyPushConstant));
@ -412,7 +423,7 @@ void CopyEffects::copy_cubemap_to_panorama(RID p_source_cube, RID p_dest_panoram
ERR_FAIL_COND(shader.is_null());
RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, copy.pipelines[mode]);
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, copy.pipelines[mode].get_rid());
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 0, u_source_cube), 0);
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 3, u_dest_panorama), 3);
RD::get_singleton()->compute_list_set_push_constant(compute_list, &copy.push_constant, sizeof(CopyPushConstant));
@ -449,7 +460,7 @@ void CopyEffects::copy_depth_to_rect(RID p_source_rd_texture, RID p_dest_texture
ERR_FAIL_COND(shader.is_null());
RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, copy.pipelines[mode]);
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, copy.pipelines[mode].get_rid());
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 0, u_source_rd_texture), 0);
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 3, u_dest_texture), 3);
RD::get_singleton()->compute_list_set_push_constant(compute_list, &copy.push_constant, sizeof(CopyPushConstant));
@ -488,7 +499,7 @@ void CopyEffects::copy_depth_to_rect_and_linearize(RID p_source_rd_texture, RID
ERR_FAIL_COND(shader.is_null());
RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, copy.pipelines[mode]);
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, copy.pipelines[mode].get_rid());
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 0, u_source_rd_texture), 0);
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 3, u_dest_texture), 3);
RD::get_singleton()->compute_list_set_push_constant(compute_list, &copy.push_constant, sizeof(CopyPushConstant));
@ -695,7 +706,7 @@ void CopyEffects::gaussian_blur(RID p_source_rd_texture, RID p_texture, const Re
ERR_FAIL_COND(shader.is_null());
RD::DrawListID compute_list = RD::get_singleton()->compute_list_begin();
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, copy.pipelines[mode]);
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, copy.pipelines[mode].get_rid());
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 0, u_source_rd_texture), 0);
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 3, u_texture), 3);
@ -777,7 +788,7 @@ void CopyEffects::gaussian_glow(RID p_source_rd_texture, RID p_back_texture, con
ERR_FAIL_COND(shader.is_null());
RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, copy.pipelines[copy_mode]);
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, copy.pipelines[copy_mode].get_rid());
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 0, u_source_rd_texture), 0);
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 3, u_back_texture), 3);
if (p_auto_exposure.is_valid() && p_first_pass) {
@ -890,7 +901,7 @@ void CopyEffects::make_mipmap(RID p_source_rd_texture, RID p_dest_texture, const
ERR_FAIL_COND(shader.is_null());
RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, copy.pipelines[mode]);
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, copy.pipelines[mode].get_rid());
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 0, u_source_rd_texture), 0);
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 3, u_dest_texture), 3);
RD::get_singleton()->compute_list_set_push_constant(compute_list, &copy.push_constant, sizeof(CopyPushConstant));
@ -959,7 +970,7 @@ void CopyEffects::set_color(RID p_dest_texture, const Color &p_color, const Rect
ERR_FAIL_COND(shader.is_null());
RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, copy.pipelines[mode]);
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, copy.pipelines[mode].get_rid());
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 3, u_dest_texture), 3);
RD::get_singleton()->compute_list_set_push_constant(compute_list, &copy.push_constant, sizeof(CopyPushConstant));
RD::get_singleton()->compute_list_dispatch_threads(compute_list, p_region.size.width, p_region.size.height, 1);
@ -1056,7 +1067,7 @@ void CopyEffects::cubemap_downsample(RID p_source_cubemap, RID p_dest_cubemap, c
ERR_FAIL_COND(shader.is_null());
RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, cubemap_downsampler.compute_pipeline);
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, cubemap_downsampler.compute_pipeline.get_rid());
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 0, u_source_cubemap), 0);
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 1, u_dest_cubemap), 1);
@ -1133,7 +1144,7 @@ void CopyEffects::cubemap_filter(RID p_source_cubemap, Vector<RID> p_dest_cubema
ERR_FAIL_COND(shader.is_null());
RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, filter.compute_pipelines[mode]);
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, filter.compute_pipelines[mode].get_rid());
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 0, u_source_cubemap), 0);
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, filter.uniform_set, 1);
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, filter.image_uniform_set, 2);
@ -1207,7 +1218,7 @@ void CopyEffects::cubemap_roughness(RID p_source_rd_texture, RID p_dest_texture,
ERR_FAIL_COND(shader.is_null());
RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, roughness.compute_pipeline);
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, roughness.compute_pipeline.get_rid());
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 0, u_source_rd_texture), 0);
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 1, u_dest_texture), 1);

View file

@ -31,6 +31,7 @@
#pragma once
#include "servers/rendering/renderer_rd/pipeline_cache_rd.h"
#include "servers/rendering/renderer_rd/pipeline_deferred_rd.h"
#include "servers/rendering/renderer_rd/shaders/effects/blur_raster.glsl.gen.h"
#include "servers/rendering/renderer_rd/shaders/effects/copy.glsl.gen.h"
#include "servers/rendering/renderer_rd/shaders/effects/copy_to_fb.glsl.gen.h"
@ -161,7 +162,7 @@ private:
CopyPushConstant push_constant;
CopyShaderRD shader;
RID shader_version;
RID pipelines[COPY_MODE_MAX];
PipelineDeferredRD pipelines[COPY_MODE_MAX];
} copy;
@ -237,7 +238,7 @@ private:
CubemapDownsamplerShaderRD compute_shader;
CubemapDownsamplerRasterShaderRD raster_shader;
RID shader_version;
RID compute_pipeline;
PipelineDeferredRD compute_pipeline;
PipelineCacheRD raster_pipeline;
} cubemap_downsampler;
@ -259,7 +260,7 @@ private:
CubemapFilterShaderRD compute_shader;
CubemapFilterRasterShaderRD raster_shader;
RID shader_version;
RID compute_pipelines[FILTER_MODE_MAX];
PipelineDeferredRD compute_pipelines[FILTER_MODE_MAX];
PipelineCacheRD raster_pipelines[FILTER_MODE_MAX];
RID uniform_set;
@ -283,7 +284,7 @@ private:
CubemapRoughnessShaderRD compute_shader;
CubemapRoughnessRasterShaderRD raster_shader;
RID shader_version;
RID compute_pipeline;
PipelineDeferredRD compute_pipeline;
PipelineCacheRD raster_pipeline;
} roughness;

View file

@ -48,10 +48,11 @@ FSR::FSR() {
}
shader_version = fsr_shader.version_create();
pipeline = RD::get_singleton()->compute_pipeline_create(fsr_shader.version_get_shader(shader_version, variant));
pipeline.create_compute_pipeline(fsr_shader.version_get_shader(shader_version, variant));
}
FSR::~FSR() {
pipeline.free();
fsr_shader.version_free(shader_version);
}
@ -82,7 +83,7 @@ void FSR::process(Ref<RenderSceneBuffersRD> p_render_buffers, RID p_source_rd_te
int dispatch_y = (target_size.y + 15) / 16;
RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, pipeline);
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, pipeline.get_rid());
push_constant.resolution_width = internal_size.width;
push_constant.resolution_height = internal_size.height;

View file

@ -33,6 +33,7 @@
#include "spatial_upscaler.h"
#include "../storage_rd/render_scene_buffers_rd.h"
#include "servers/rendering/renderer_rd/pipeline_deferred_rd.h"
#include "servers/rendering/renderer_rd/shaders/effects/fsr_upscale.glsl.gen.h"
namespace RendererRD {
@ -69,7 +70,7 @@ private:
FsrUpscaleShaderRD fsr_shader;
RID shader_version;
RID pipeline;
PipelineDeferredRD pipeline;
};
} // namespace RendererRD

View file

@ -66,7 +66,7 @@ SSEffects::SSEffects() {
ss_effects.downsample_shader_version = ss_effects.downsample_shader.version_create();
for (int i = 0; i < SS_EFFECTS_MAX; i++) {
ss_effects.pipelines[i] = RD::get_singleton()->compute_pipeline_create(ss_effects.downsample_shader.version_get_shader(ss_effects.downsample_shader_version, i));
ss_effects.pipelines[i].create_compute_pipeline(ss_effects.downsample_shader.version_get_shader(ss_effects.downsample_shader_version, i));
}
ss_effects.gather_constants_buffer = RD::get_singleton()->uniform_buffer_create(sizeof(SSEffectsGatherConstants));
@ -112,7 +112,7 @@ SSEffects::SSEffects() {
ssil.gather_shader_version = ssil.gather_shader.version_create();
for (int i = SSIL_GATHER; i <= SSIL_GATHER_ADAPTIVE; i++) {
ssil.pipelines[i] = RD::get_singleton()->compute_pipeline_create(ssil.gather_shader.version_get_shader(ssil.gather_shader_version, i));
ssil.pipelines[i].create_compute_pipeline(ssil.gather_shader.version_get_shader(ssil.gather_shader_version, i));
}
ssil.projection_uniform_buffer = RD::get_singleton()->uniform_buffer_create(sizeof(SSILProjectionUniforms));
}
@ -128,7 +128,7 @@ SSEffects::SSEffects() {
ssil.importance_map_shader_version = ssil.importance_map_shader.version_create();
for (int i = SSIL_GENERATE_IMPORTANCE_MAP; i <= SSIL_PROCESS_IMPORTANCE_MAPB; i++) {
ssil.pipelines[i] = RD::get_singleton()->compute_pipeline_create(ssil.importance_map_shader.version_get_shader(ssil.importance_map_shader_version, i - SSIL_GENERATE_IMPORTANCE_MAP));
ssil.pipelines[i].create_compute_pipeline(ssil.importance_map_shader.version_get_shader(ssil.importance_map_shader_version, i - SSIL_GENERATE_IMPORTANCE_MAP));
}
ssil.importance_map_load_counter = RD::get_singleton()->storage_buffer_create(sizeof(uint32_t));
int zero[1] = { 0 };
@ -157,7 +157,7 @@ SSEffects::SSEffects() {
ssil.blur_shader_version = ssil.blur_shader.version_create();
for (int i = SSIL_BLUR_PASS; i <= SSIL_BLUR_PASS_WIDE; i++) {
ssil.pipelines[i] = RD::get_singleton()->compute_pipeline_create(ssil.blur_shader.version_get_shader(ssil.blur_shader_version, i - SSIL_BLUR_PASS));
ssil.pipelines[i].create_compute_pipeline(ssil.blur_shader.version_get_shader(ssil.blur_shader_version, i - SSIL_BLUR_PASS));
}
}
@ -171,7 +171,7 @@ SSEffects::SSEffects() {
ssil.interleave_shader_version = ssil.interleave_shader.version_create();
for (int i = SSIL_INTERLEAVE; i <= SSIL_INTERLEAVE_HALF; i++) {
ssil.pipelines[i] = RD::get_singleton()->compute_pipeline_create(ssil.interleave_shader.version_get_shader(ssil.interleave_shader_version, i - SSIL_INTERLEAVE));
ssil.pipelines[i].create_compute_pipeline(ssil.interleave_shader.version_get_shader(ssil.interleave_shader_version, i - SSIL_INTERLEAVE));
}
}
@ -201,7 +201,7 @@ SSEffects::SSEffects() {
ssao.gather_shader_version = ssao.gather_shader.version_create();
for (int i = 0; i <= SSAO_GATHER_ADAPTIVE; i++) {
ssao.pipelines[pipeline] = RD::get_singleton()->compute_pipeline_create(ssao.gather_shader.version_get_shader(ssao.gather_shader_version, i));
ssao.pipelines[pipeline].create_compute_pipeline(ssao.gather_shader.version_get_shader(ssao.gather_shader_version, i));
pipeline++;
}
}
@ -217,7 +217,7 @@ SSEffects::SSEffects() {
ssao.importance_map_shader_version = ssao.importance_map_shader.version_create();
for (int i = SSAO_GENERATE_IMPORTANCE_MAP; i <= SSAO_PROCESS_IMPORTANCE_MAPB; i++) {
ssao.pipelines[pipeline] = RD::get_singleton()->compute_pipeline_create(ssao.importance_map_shader.version_get_shader(ssao.importance_map_shader_version, i - SSAO_GENERATE_IMPORTANCE_MAP));
ssao.pipelines[pipeline].create_compute_pipeline(ssao.importance_map_shader.version_get_shader(ssao.importance_map_shader_version, i - SSAO_GENERATE_IMPORTANCE_MAP));
pipeline++;
}
@ -250,7 +250,7 @@ SSEffects::SSEffects() {
ssao.blur_shader_version = ssao.blur_shader.version_create();
for (int i = SSAO_BLUR_PASS; i <= SSAO_BLUR_PASS_WIDE; i++) {
ssao.pipelines[pipeline] = RD::get_singleton()->compute_pipeline_create(ssao.blur_shader.version_get_shader(ssao.blur_shader_version, i - SSAO_BLUR_PASS));
ssao.pipelines[pipeline].create_compute_pipeline(ssao.blur_shader.version_get_shader(ssao.blur_shader_version, i - SSAO_BLUR_PASS));
pipeline++;
}
@ -266,8 +266,7 @@ SSEffects::SSEffects() {
ssao.interleave_shader_version = ssao.interleave_shader.version_create();
for (int i = SSAO_INTERLEAVE; i <= SSAO_INTERLEAVE_HALF; i++) {
ssao.pipelines[pipeline] = RD::get_singleton()->compute_pipeline_create(ssao.interleave_shader.version_get_shader(ssao.interleave_shader_version, i - SSAO_INTERLEAVE));
RD::get_singleton()->set_resource_name(ssao.pipelines[pipeline], "Interleave Pipeline " + itos(i));
ssao.pipelines[pipeline].create_compute_pipeline(ssao.interleave_shader.version_get_shader(ssao.interleave_shader_version, i - SSAO_INTERLEAVE));
pipeline++;
}
}
@ -300,7 +299,7 @@ SSEffects::SSEffects() {
for (int v = 0; v < SSR_VARIATIONS; v++) {
specialization_constants.ptrw()[0].bool_value = (v & SSR_MULTIVIEW) ? true : false;
ssr_scale.pipelines[v] = RD::get_singleton()->compute_pipeline_create(ssr_scale.shader.version_get_shader(ssr_scale.shader_version, 0), specialization_constants);
ssr_scale.pipelines[v].create_compute_pipeline(ssr_scale.shader.version_get_shader(ssr_scale.shader_version, 0), specialization_constants);
}
}
@ -315,7 +314,7 @@ SSEffects::SSEffects() {
for (int v = 0; v < SSR_VARIATIONS; v++) {
specialization_constants.ptrw()[0].bool_value = (v & SSR_MULTIVIEW) ? true : false;
for (int i = 0; i < SCREEN_SPACE_REFLECTION_MAX; i++) {
ssr.pipelines[v][i] = RD::get_singleton()->compute_pipeline_create(ssr.shader.version_get_shader(ssr.shader_version, i), specialization_constants);
ssr.pipelines[v][i].create_compute_pipeline(ssr.shader.version_get_shader(ssr.shader_version, i), specialization_constants);
}
}
}
@ -331,7 +330,7 @@ SSEffects::SSEffects() {
for (int v = 0; v < SSR_VARIATIONS; v++) {
specialization_constants.ptrw()[0].bool_value = (v & SSR_MULTIVIEW) ? true : false;
for (int i = 0; i < SCREEN_SPACE_REFLECTION_FILTER_MAX; i++) {
ssr_filter.pipelines[v][i] = RD::get_singleton()->compute_pipeline_create(ssr_filter.shader.version_get_shader(ssr_filter.shader_version, i), specialization_constants);
ssr_filter.pipelines[v][i].create_compute_pipeline(ssr_filter.shader.version_get_shader(ssr_filter.shader_version, i), specialization_constants);
}
}
}
@ -352,8 +351,8 @@ SSEffects::SSEffects() {
sss.shader_version = sss.shader.version_create();
for (int i = 0; i < sss_modes.size(); i++) {
sss.pipelines[i] = RD::get_singleton()->compute_pipeline_create(sss.shader.version_get_shader(sss.shader_version, i));
for (int i = 0; i < SUBSURFACE_SCATTERING_MODE_MAX; i++) {
sss.pipelines[i].create_compute_pipeline(sss.shader.version_get_shader(sss.shader_version, i));
}
}
}
@ -361,6 +360,15 @@ SSEffects::SSEffects() {
SSEffects::~SSEffects() {
{
// Cleanup SS Reflections
for (int v = 0; v < SSR_VARIATIONS; v++) {
for (int i = 0; i < SCREEN_SPACE_REFLECTION_FILTER_MAX; i++) {
ssr.pipelines[v][i].free();
ssr_filter.pipelines[v][i].free();
}
ssr_scale.pipelines[v].free();
}
ssr.shader.version_free(ssr.shader_version);
ssr_filter.shader.version_free(ssr_filter.shader_version);
ssr_scale.shader.version_free(ssr_scale.shader_version);
@ -372,6 +380,10 @@ SSEffects::~SSEffects() {
{
// Cleanup SS downsampler
for (int i = 0; i < SS_EFFECTS_MAX; i++) {
ss_effects.pipelines[i].free();
}
ss_effects.downsample_shader.version_free(ss_effects.downsample_shader_version);
RD::get_singleton()->free_rid(ss_effects.mirror_sampler);
@ -380,6 +392,10 @@ SSEffects::~SSEffects() {
{
// Cleanup SSIL
for (int i = 0; i < SSIL_MAX; i++) {
ssil.pipelines[i].free();
}
ssil.blur_shader.version_free(ssil.blur_shader_version);
ssil.gather_shader.version_free(ssil.gather_shader_version);
ssil.interleave_shader.version_free(ssil.interleave_shader_version);
@ -391,6 +407,10 @@ SSEffects::~SSEffects() {
{
// Cleanup SSAO
for (int i = 0; i < SSAO_MAX; i++) {
ssao.pipelines[i].free();
}
ssao.blur_shader.version_free(ssao.blur_shader_version);
ssao.gather_shader.version_free(ssao.gather_shader_version);
ssao.interleave_shader.version_free(ssao.interleave_shader_version);
@ -401,6 +421,10 @@ SSEffects::~SSEffects() {
{
// Cleanup Subsurface scattering
for (int i = 0; i < SUBSURFACE_SCATTERING_MODE_MAX; i++) {
sss.pipelines[i].free();
}
sss.shader.version_free(sss.shader_version);
}
@ -512,7 +536,7 @@ void SSEffects::downsample_depth(Ref<RenderSceneBuffersRD> p_render_buffers, uin
RD::Uniform u_depth_buffer(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector<RID>({ default_sampler, depth_texture }));
RD::Uniform u_depth_mipmap(RD::UNIFORM_TYPE_IMAGE, 0, Vector<RID>({ depth_mipmap }));
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, ss_effects.pipelines[downsample_mode]);
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, ss_effects.pipelines[downsample_mode].get_rid());
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 0, u_depth_buffer), 0);
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 1, u_depth_mipmap), 1);
if (use_mips) {
@ -791,7 +815,7 @@ void SSEffects::screen_space_indirect_lighting(Ref<RenderSceneBuffersRD> p_rende
ssil.importance_map_push_constant.intensity = p_settings.intensity * Math::PI;
//base pass
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, ssil.pipelines[SSIL_GATHER_BASE]);
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, ssil.pipelines[SSIL_GATHER_BASE].get_rid());
gather_ssil(compute_list, deinterleaved_pong_slices, edges_slices, p_settings, true, gather_uniform_set, importance_map_uniform_set, projection_uniform_set);
//generate importance map
@ -799,7 +823,7 @@ void SSEffects::screen_space_indirect_lighting(Ref<RenderSceneBuffersRD> p_rende
RD::Uniform u_ssil_pong_with_sampler(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector<RID>({ default_sampler, deinterleaved_pong }));
RD::Uniform u_importance_map(RD::UNIFORM_TYPE_IMAGE, 0, Vector<RID>({ importance_map }));
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, ssil.pipelines[SSIL_GENERATE_IMPORTANCE_MAP]);
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, ssil.pipelines[SSIL_GENERATE_IMPORTANCE_MAP].get_rid());
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(gen_imp_shader, 0, u_ssil_pong_with_sampler), 0);
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(gen_imp_shader, 1, u_importance_map), 1);
RD::get_singleton()->compute_list_set_push_constant(compute_list, &ssil.importance_map_push_constant, sizeof(SSILImportanceMapPushConstant));
@ -811,7 +835,7 @@ void SSEffects::screen_space_indirect_lighting(Ref<RenderSceneBuffersRD> p_rende
RD::Uniform u_importance_map_with_sampler(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector<RID>({ default_sampler, importance_map }));
RD::Uniform u_importance_map_pong(RD::UNIFORM_TYPE_IMAGE, 0, Vector<RID>({ importance_pong }));
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, ssil.pipelines[SSIL_PROCESS_IMPORTANCE_MAPA]);
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, ssil.pipelines[SSIL_PROCESS_IMPORTANCE_MAPA].get_rid());
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(proc_imp_shader_a, 0, u_importance_map_with_sampler), 0);
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(proc_imp_shader_a, 1, u_importance_map_pong), 1);
RD::get_singleton()->compute_list_set_push_constant(compute_list, &ssil.importance_map_push_constant, sizeof(SSILImportanceMapPushConstant));
@ -822,7 +846,7 @@ void SSEffects::screen_space_indirect_lighting(Ref<RenderSceneBuffersRD> p_rende
RID proc_imp_shader_b = ssil.importance_map_shader.version_get_shader(ssil.importance_map_shader_version, 2);
RD::Uniform u_importance_map_pong_with_sampler(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector<RID>({ default_sampler, importance_pong }));
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, ssil.pipelines[SSIL_PROCESS_IMPORTANCE_MAPB]);
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, ssil.pipelines[SSIL_PROCESS_IMPORTANCE_MAPB].get_rid());
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(proc_imp_shader_b, 0, u_importance_map_pong_with_sampler), 0);
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(proc_imp_shader_b, 1, u_importance_map), 1);
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, ssil.counter_uniform_set, 2);
@ -832,9 +856,9 @@ void SSEffects::screen_space_indirect_lighting(Ref<RenderSceneBuffersRD> p_rende
RD::get_singleton()->draw_command_end_label(); // Importance Map
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, ssil.pipelines[SSIL_GATHER_ADAPTIVE]);
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, ssil.pipelines[SSIL_GATHER_ADAPTIVE].get_rid());
} else {
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, ssil.pipelines[SSIL_GATHER]);
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, ssil.pipelines[SSIL_GATHER].get_rid());
}
gather_ssil(compute_list, deinterleaved_slices, edges_slices, p_settings, false, gather_uniform_set, importance_map_uniform_set, projection_uniform_set);
@ -867,7 +891,7 @@ void SSEffects::screen_space_indirect_lighting(Ref<RenderSceneBuffersRD> p_rende
continue;
}
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, ssil.pipelines[blur_pipeline]);
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, ssil.pipelines[blur_pipeline].get_rid());
if (pass % 2 == 0) {
if (ssil_quality == RS::ENV_SSIL_QUALITY_VERY_LOW) {
RD::Uniform u_ssil_slice(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector<RID>({ default_sampler, deinterleaved_slices[i] }));
@ -926,7 +950,7 @@ void SSEffects::screen_space_indirect_lighting(Ref<RenderSceneBuffersRD> p_rende
shader = ssil.interleave_shader.version_get_shader(ssil.interleave_shader_version, 0);
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, ssil.pipelines[interleave_pipeline]);
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, ssil.pipelines[interleave_pipeline].get_rid());
RID final = p_render_buffers->get_texture_slice(RB_SCOPE_SSIL, RB_FINAL, p_view, 0);
RD::Uniform u_destination(RD::UNIFORM_TYPE_IMAGE, 0, Vector<RID>({ final }));
@ -1175,12 +1199,12 @@ void SSEffects::generate_ssao(Ref<RenderSceneBuffersRD> p_render_buffers, SSAORe
ssao.importance_map_push_constant.power = p_settings.power;
//base pass
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, ssao.pipelines[SSAO_GATHER_BASE]);
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, ssao.pipelines[SSAO_GATHER_BASE].get_rid());
gather_ssao(compute_list, ao_pong_slices, p_settings, true, gather_uniform_set, RID());
//generate importance map
RID gen_imp_shader = ssao.importance_map_shader.version_get_shader(ssao.importance_map_shader_version, 0);
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, ssao.pipelines[SSAO_GENERATE_IMPORTANCE_MAP]);
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, ssao.pipelines[SSAO_GENERATE_IMPORTANCE_MAP].get_rid());
RD::Uniform u_ao_pong_with_sampler(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector<RID>({ default_sampler, ao_pong }));
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(gen_imp_shader, 0, u_ao_pong_with_sampler), 0);
@ -1194,7 +1218,7 @@ void SSEffects::generate_ssao(Ref<RenderSceneBuffersRD> p_render_buffers, SSAORe
//process importance map A
RID proc_imp_shader_a = ssao.importance_map_shader.version_get_shader(ssao.importance_map_shader_version, 1);
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, ssao.pipelines[SSAO_PROCESS_IMPORTANCE_MAPA]);
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, ssao.pipelines[SSAO_PROCESS_IMPORTANCE_MAPA].get_rid());
RD::Uniform u_importance_map_with_sampler(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector<RID>({ default_sampler, importance_map }));
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(proc_imp_shader_a, 0, u_importance_map_with_sampler), 0);
@ -1208,7 +1232,7 @@ void SSEffects::generate_ssao(Ref<RenderSceneBuffersRD> p_render_buffers, SSAORe
//process Importance Map B
RID proc_imp_shader_b = ssao.importance_map_shader.version_get_shader(ssao.importance_map_shader_version, 2);
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, ssao.pipelines[SSAO_PROCESS_IMPORTANCE_MAPB]);
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, ssao.pipelines[SSAO_PROCESS_IMPORTANCE_MAPB].get_rid());
RD::Uniform u_importance_map_pong_with_sampler(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector<RID>({ default_sampler, importance_pong }));
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(proc_imp_shader_b, 0, u_importance_map_pong_with_sampler), 0);
@ -1219,10 +1243,10 @@ void SSEffects::generate_ssao(Ref<RenderSceneBuffersRD> p_render_buffers, SSAORe
RD::get_singleton()->compute_list_dispatch_threads(compute_list, p_ssao_buffers.half_buffer_width, p_ssao_buffers.half_buffer_height, 1);
RD::get_singleton()->compute_list_add_barrier(compute_list);
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, ssao.pipelines[SSAO_GATHER_ADAPTIVE]);
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, ssao.pipelines[SSAO_GATHER_ADAPTIVE].get_rid());
RD::get_singleton()->draw_command_end_label(); // Importance Map
} else {
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, ssao.pipelines[SSAO_GATHER]);
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, ssao.pipelines[SSAO_GATHER].get_rid());
}
gather_ssao(compute_list, ao_deinterleaved_slices, p_settings, false, gather_uniform_set, importance_map_uniform_set);
@ -1258,7 +1282,7 @@ void SSEffects::generate_ssao(Ref<RenderSceneBuffersRD> p_render_buffers, SSAORe
}
RID blur_shader = ssao.blur_shader.version_get_shader(ssao.blur_shader_version, blur_pipeline - SSAO_BLUR_PASS);
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, ssao.pipelines[blur_pipeline]);
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, ssao.pipelines[blur_pipeline].get_rid());
if (pass % 2 == 0) {
if (ssao_quality == RS::ENV_SSAO_QUALITY_VERY_LOW) {
RD::Uniform u_ao_slices_with_sampler(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector<RID>({ default_sampler, ao_deinterleaved_slices[i] }));
@ -1312,7 +1336,7 @@ void SSEffects::generate_ssao(Ref<RenderSceneBuffersRD> p_render_buffers, SSAORe
}
RID interleave_shader = ssao.interleave_shader.version_get_shader(ssao.interleave_shader_version, interleave_pipeline - SSAO_INTERLEAVE);
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, ssao.pipelines[interleave_pipeline]);
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, ssao.pipelines[interleave_pipeline].get_rid());
RD::Uniform u_upscale_buffer(RD::UNIFORM_TYPE_IMAGE, 0, Vector<RID>({ ao_final }));
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(interleave_shader, 0, u_upscale_buffer), 0);
@ -1439,7 +1463,7 @@ void SSEffects::screen_space_reflection(Ref<RenderSceneBuffersRD> p_render_buffe
RID shader = ssr_scale.shader.version_get_shader(ssr_scale.shader_version, 0);
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, ssr_scale.pipelines[pipeline_specialization]);
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, ssr_scale.pipelines[pipeline_specialization].get_rid());
RD::Uniform u_diffuse(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector<RID>({ default_sampler, diffuse_slice }));
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 0, u_diffuse), 0);
@ -1486,7 +1510,7 @@ void SSEffects::screen_space_reflection(Ref<RenderSceneBuffersRD> p_render_buffe
ScreenSpaceReflectionMode mode = (ssr_roughness_quality != RS::ENV_SSR_ROUGHNESS_QUALITY_DISABLED) ? SCREEN_SPACE_REFLECTION_ROUGH : SCREEN_SPACE_REFLECTION_NORMAL;
RID shader = ssr.shader.version_get_shader(ssr.shader_version, mode);
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, ssr.pipelines[pipeline_specialization][mode]);
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, ssr.pipelines[pipeline_specialization][mode].get_rid());
RD::Uniform u_scene_data(RD::UNIFORM_TYPE_UNIFORM_BUFFER, 0, ssr.ubo);
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 4, u_scene_data), 4);
@ -1554,7 +1578,7 @@ void SSEffects::screen_space_reflection(Ref<RenderSceneBuffersRD> p_render_buffe
RID shader = ssr_filter.shader.version_get_shader(ssr_filter.shader_version, mode);
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, ssr_filter.pipelines[pipeline_specialization][mode]);
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, ssr_filter.pipelines[pipeline_specialization][mode].get_rid());
RD::Uniform u_output(RD::UNIFORM_TYPE_IMAGE, 0, Vector<RID>({ output }));
RD::Uniform u_blur_radius(RD::UNIFORM_TYPE_IMAGE, 1, Vector<RID>({ blur_radius[0] }));
@ -1582,7 +1606,7 @@ void SSEffects::screen_space_reflection(Ref<RenderSceneBuffersRD> p_render_buffe
mode = SCREEN_SPACE_REFLECTION_FILTER_VERTICAL;
shader = ssr_filter.shader.version_get_shader(ssr_filter.shader_version, mode);
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, ssr_filter.pipelines[pipeline_specialization][mode]);
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, ssr_filter.pipelines[pipeline_specialization][mode].get_rid());
push_constant.vertical = 1;
@ -1656,7 +1680,7 @@ void SSEffects::sub_surface_scattering(Ref<RenderSceneBuffersRD> p_render_buffer
sss.push_constant.depth_scale = sss_depth_scale;
RID shader = sss.shader.version_get_shader(sss.shader_version, sss_quality - 1);
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, sss.pipelines[sss_quality - 1]);
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, sss.pipelines[sss_quality - 1].get_rid());
RD::Uniform u_diffuse_with_sampler(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector<RID>({ default_sampler, p_diffuse }));
RD::Uniform u_diffuse(RD::UNIFORM_TYPE_IMAGE, 0, Vector<RID>({ p_diffuse }));

View file

@ -30,6 +30,7 @@
#pragma once
#include "servers/rendering/renderer_rd/pipeline_deferred_rd.h"
#include "servers/rendering/renderer_rd/shaders/effects/screen_space_reflection.glsl.gen.h"
#include "servers/rendering/renderer_rd/shaders/effects/screen_space_reflection_filter.glsl.gen.h"
#include "servers/rendering/renderer_rd/shaders/effects/screen_space_reflection_scale.glsl.gen.h"
@ -210,7 +211,7 @@ private:
RID mirror_sampler;
RID pipelines[SS_EFFECTS_MAX];
PipelineDeferredRD pipelines[SS_EFFECTS_MAX];
} ss_effects;
/* SSIL */
@ -307,7 +308,7 @@ private:
SsilInterleaveShaderRD interleave_shader;
RID interleave_shader_version;
RID pipelines[SSIL_MAX];
PipelineDeferredRD pipelines[SSIL_MAX];
} ssil;
void gather_ssil(RD::ComputeListID p_compute_list, const RID *p_ssil_slices, const RID *p_edges_slices, const SSILSettings &p_settings, bool p_adaptive_base_pass, RID p_gather_uniform_set, RID p_importance_map_uniform_set, RID p_projection_uniform_set);
@ -401,7 +402,7 @@ private:
SsaoInterleaveShaderRD interleave_shader;
RID interleave_shader_version;
RID pipelines[SSAO_MAX];
PipelineDeferredRD pipelines[SSAO_MAX];
} ssao;
void gather_ssao(RD::ComputeListID p_compute_list, const RID *p_ao_slices, const SSAOSettings &p_settings, bool p_adaptive_base_pass, RID p_gather_uniform_set, RID p_importance_map_uniform_set);
@ -435,7 +436,7 @@ private:
struct ScreenSpaceReflectionScale {
ScreenSpaceReflectionScaleShaderRD shader;
RID shader_version;
RID pipelines[SSR_VARIATIONS];
PipelineDeferredRD pipelines[SSR_VARIATIONS];
} ssr_scale;
// SSR main
@ -469,7 +470,7 @@ private:
struct ScreenSpaceReflection {
ScreenSpaceReflectionShaderRD shader;
RID shader_version;
RID pipelines[SSR_VARIATIONS][SCREEN_SPACE_REFLECTION_MAX];
PipelineDeferredRD pipelines[SSR_VARIATIONS][SCREEN_SPACE_REFLECTION_MAX];
RID ubo;
} ssr;
@ -498,11 +499,18 @@ private:
struct ScreenSpaceReflectionFilter {
ScreenSpaceReflectionFilterShaderRD shader;
RID shader_version;
RID pipelines[SSR_VARIATIONS][SCREEN_SPACE_REFLECTION_FILTER_MAX];
PipelineDeferredRD pipelines[SSR_VARIATIONS][SCREEN_SPACE_REFLECTION_FILTER_MAX];
} ssr_filter;
/* Subsurface scattering */
enum SSSMode {
SUBSURFACE_SCATTERING_MODE_LOW_QUALITY,
SUBSURFACE_SCATTERING_MODE_MEDIUM_QUALITY,
SUBSURFACE_SCATTERING_MODE_HIGH_QUALITY,
SUBSURFACE_SCATTERING_MODE_MAX
};
struct SubSurfaceScatteringPushConstant {
int32_t screen_size[2];
float camera_z_far;
@ -521,7 +529,7 @@ private:
SubSurfaceScatteringPushConstant push_constant;
SubsurfaceScatteringShaderRD shader;
RID shader_version;
RID pipelines[3]; //3 quality levels
PipelineDeferredRD pipelines[SUBSURFACE_SCATTERING_MODE_MAX];
} sss;
};

View file

@ -325,7 +325,7 @@ ALBEDO = vec3(1.0);
volumetric_fog.process_shader_version = volumetric_fog.process_shader.version_create();
for (int i = 0; i < VolumetricFogShader::VOLUMETRIC_FOG_PROCESS_SHADER_MAX; i++) {
volumetric_fog.process_pipelines[i] = RD::get_singleton()->compute_pipeline_create(volumetric_fog.process_shader.version_get_shader(volumetric_fog.process_shader_version, _get_fog_process_variant(i)));
volumetric_fog.process_pipelines[i].create_compute_pipeline(volumetric_fog.process_shader.version_get_shader(volumetric_fog.process_shader_version, _get_fog_process_variant(i)));
}
volumetric_fog.params_ubo = RD::get_singleton()->uniform_buffer_create(sizeof(VolumetricFogShader::ParamsUBO));
}
@ -333,7 +333,9 @@ ALBEDO = vec3(1.0);
void Fog::free_fog_shader() {
MaterialStorage *material_storage = MaterialStorage::get_singleton();
for (int i = 0; i < VolumetricFogShader::VOLUMETRIC_FOG_PROCESS_SHADER_MAX; i++) {
volumetric_fog.process_pipelines[i].free();
}
if (volumetric_fog.process_shader_version.is_valid()) {
volumetric_fog.process_shader.version_free(volumetric_fog.process_shader_version);
}
@ -380,6 +382,8 @@ void Fog::FogShaderData::set_code(const String &p_code) {
if (version.is_null()) {
version = fog_singleton->volumetric_fog.shader.version_create();
} else {
pipeline.free();
}
fog_singleton->volumetric_fog.shader.version_set_compute_code(version, gen_code.code, gen_code.uniforms, gen_code.stage_globals[ShaderCompiler::STAGE_COMPUTE], gen_code.defines);
@ -389,7 +393,7 @@ void Fog::FogShaderData::set_code(const String &p_code) {
ubo_offsets = gen_code.uniform_offsets;
texture_uniforms = gen_code.texture_uniforms;
pipeline = RD::get_singleton()->compute_pipeline_create(fog_singleton->volumetric_fog.shader.version_get_shader(version, _get_fog_variant()));
pipeline.create_compute_pipeline(fog_singleton->volumetric_fog.shader.version_get_shader(version, _get_fog_variant()));
valid = true;
}
@ -414,9 +418,10 @@ Pair<ShaderRD *, RID> Fog::FogShaderData::get_native_shader_and_version() const
}
Fog::FogShaderData::~FogShaderData() {
pipeline.free();
Fog *fog_singleton = Fog::get_singleton();
ERR_FAIL_NULL(fog_singleton);
//pipeline variants will clear themselves if shader is gone
if (version.is_valid()) {
fog_singleton->volumetric_fog.shader.version_free(version);
}
@ -768,7 +773,7 @@ void Fog::volumetric_fog_update(const VolumetricFogSettings &p_settings, const P
push_constant.shape = uint32_t(RendererRD::Fog::get_singleton()->fog_volume_get_shape(fog_volume));
RendererRD::MaterialStorage::store_transform(fog_volume_instance->transform.affine_inverse(), push_constant.transform);
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, shader_data->pipeline);
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, shader_data->pipeline.get_rid());
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, fog->fog_uniform_set, VolumetricFogShader::FogSet::FOG_SET_UNIFORMS);
RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(VolumetricFogShader::FogPushConstant));
@ -1138,7 +1143,7 @@ void Fog::volumetric_fog_update(const VolumetricFogSettings &p_settings, const P
RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, volumetric_fog.process_pipelines[using_sdfgi ? VolumetricFogShader::VOLUMETRIC_FOG_PROCESS_SHADER_DENSITY_WITH_SDFGI : VolumetricFogShader::VOLUMETRIC_FOG_PROCESS_SHADER_DENSITY]);
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, volumetric_fog.process_pipelines[using_sdfgi ? VolumetricFogShader::VOLUMETRIC_FOG_PROCESS_SHADER_DENSITY_WITH_SDFGI : VolumetricFogShader::VOLUMETRIC_FOG_PROCESS_SHADER_DENSITY].get_rid());
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, fog->gi_dependent_sets.process_uniform_set_density, 0);
@ -1150,7 +1155,7 @@ void Fog::volumetric_fog_update(const VolumetricFogSettings &p_settings, const P
// Copy fog to history buffer
if (RendererSceneRenderRD::get_singleton()->environment_get_volumetric_fog_temporal_reprojection(p_settings.env)) {
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, volumetric_fog.process_pipelines[VolumetricFogShader::VOLUMETRIC_FOG_PROCESS_SHADER_COPY]);
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, volumetric_fog.process_pipelines[VolumetricFogShader::VOLUMETRIC_FOG_PROCESS_SHADER_COPY].get_rid());
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, fog->copy_uniform_set, 0);
RD::get_singleton()->compute_list_dispatch_threads(compute_list, fog->width, fog->height, fog->depth);
RD::get_singleton()->compute_list_add_barrier(compute_list);
@ -1162,7 +1167,7 @@ void Fog::volumetric_fog_update(const VolumetricFogSettings &p_settings, const P
RENDER_TIMESTAMP("Filter Fog");
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, volumetric_fog.process_pipelines[VolumetricFogShader::VOLUMETRIC_FOG_PROCESS_SHADER_FILTER]);
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, volumetric_fog.process_pipelines[VolumetricFogShader::VOLUMETRIC_FOG_PROCESS_SHADER_FILTER].get_rid());
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, fog->gi_dependent_sets.process_uniform_set, 0);
RD::get_singleton()->compute_list_dispatch_threads(compute_list, fog->width, fog->height, fog->depth);
@ -1173,7 +1178,7 @@ void Fog::volumetric_fog_update(const VolumetricFogSettings &p_settings, const P
RD::get_singleton()->buffer_update(volumetric_fog.params_ubo, 0, sizeof(VolumetricFogShader::ParamsUBO), &params);
compute_list = RD::get_singleton()->compute_list_begin();
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, volumetric_fog.process_pipelines[VolumetricFogShader::VOLUMETRIC_FOG_PROCESS_SHADER_FILTER]);
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, volumetric_fog.process_pipelines[VolumetricFogShader::VOLUMETRIC_FOG_PROCESS_SHADER_FILTER].get_rid());
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, fog->gi_dependent_sets.process_uniform_set2, 0);
RD::get_singleton()->compute_list_dispatch_threads(compute_list, fog->width, fog->height, fog->depth);
@ -1184,7 +1189,7 @@ void Fog::volumetric_fog_update(const VolumetricFogSettings &p_settings, const P
RENDER_TIMESTAMP("Integrate Fog");
RD::get_singleton()->draw_command_begin_label("Integrate Fog");
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, volumetric_fog.process_pipelines[VolumetricFogShader::VOLUMETRIC_FOG_PROCESS_SHADER_FOG]);
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, volumetric_fog.process_pipelines[VolumetricFogShader::VOLUMETRIC_FOG_PROCESS_SHADER_FOG].get_rid());
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, fog->gi_dependent_sets.process_uniform_set, 0);
RD::get_singleton()->compute_list_dispatch_threads(compute_list, fog->width, fog->height, 1);

View file

@ -35,6 +35,7 @@
#include "servers/rendering/environment/renderer_fog.h"
#include "servers/rendering/renderer_rd/cluster_builder_rd.h"
#include "servers/rendering/renderer_rd/environment/gi.h"
#include "servers/rendering/renderer_rd/pipeline_deferred_rd.h"
#include "servers/rendering/renderer_rd/shaders/environment/volumetric_fog.glsl.gen.h"
#include "servers/rendering/renderer_rd/shaders/environment/volumetric_fog_process.glsl.gen.h"
#include "servers/rendering/renderer_rd/storage_rd/render_buffer_custom_data_rd.h"
@ -189,7 +190,7 @@ private:
VolumetricFogProcessShaderRD process_shader;
RID process_shader_version;
RID process_pipelines[VOLUMETRIC_FOG_PROCESS_SHADER_MAX];
PipelineDeferredRD process_pipelines[VOLUMETRIC_FOG_PROCESS_SHADER_MAX];
} volumetric_fog;
@ -199,7 +200,7 @@ private:
bool valid = false;
RID version;
RID pipeline;
PipelineDeferredRD pipeline;
Vector<ShaderCompiler::GeneratedCode::Texture> texture_uniforms;
Vector<uint32_t> ubo_offsets;

View file

@ -1247,7 +1247,7 @@ void GI::SDFGI::update_light() {
/* Update dynamic light */
RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->sdfgi_shader.direct_light_pipeline[SDFGIShader::DIRECT_LIGHT_MODE_DYNAMIC]);
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->sdfgi_shader.direct_light_pipeline[SDFGIShader::DIRECT_LIGHT_MODE_DYNAMIC].get_rid());
SDFGIShader::DirectLightPushConstant push_constant;
@ -1367,7 +1367,7 @@ void GI::SDFGI::update_probes(RID p_env, SkyRD::Sky *p_sky) {
render_pass++;
RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->sdfgi_shader.integrate_pipeline[SDFGIShader::INTEGRATE_MODE_PROCESS]);
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->sdfgi_shader.integrate_pipeline[SDFGIShader::INTEGRATE_MODE_PROCESS].get_rid());
int32_t probe_divisor = cascade_size / SDFGI::PROBE_DIVISOR;
for (uint32_t i = 0; i < cascades.size(); i++) {
@ -1412,7 +1412,7 @@ void GI::SDFGI::store_probes() {
RENDER_TIMESTAMP("Average SDFGI Probes");
RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->sdfgi_shader.integrate_pipeline[SDFGIShader::INTEGRATE_MODE_STORE]);
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->sdfgi_shader.integrate_pipeline[SDFGIShader::INTEGRATE_MODE_STORE].get_rid());
//convert to octahedral to store
push_constant.image_size[0] *= SDFGI::LIGHTPROBE_OCT_SIZE;
@ -1607,7 +1607,7 @@ void GI::SDFGI::debug_draw(uint32_t p_view_count, const Projection *p_projection
}
RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->sdfgi_shader.debug_pipeline);
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->sdfgi_shader.debug_pipeline.get_rid());
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, debug_uniform_set[v], 0);
SDFGIShader::DebugPushConstant push_constant;
@ -2067,14 +2067,14 @@ void GI::SDFGI::render_region(Ref<RenderSceneBuffersRD> p_render_buffers, int p_
RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
//must pre scroll existing data because not all is dirty
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->sdfgi_shader.preprocess_pipeline[SDFGIShader::PRE_PROCESS_SCROLL]);
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->sdfgi_shader.preprocess_pipeline[SDFGIShader::PRE_PROCESS_SCROLL].get_rid());
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, cascades[cascade].scroll_uniform_set, 0);
RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(SDFGIShader::PreprocessPushConstant));
RD::get_singleton()->compute_list_dispatch_indirect(compute_list, cascades[cascade].solid_cell_dispatch_buffer_call, 0);
// no barrier do all together
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->sdfgi_shader.preprocess_pipeline[SDFGIShader::PRE_PROCESS_SCROLL_OCCLUSION]);
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->sdfgi_shader.preprocess_pipeline[SDFGIShader::PRE_PROCESS_SCROLL_OCCLUSION].get_rid());
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, cascades[cascade].scroll_occlusion_uniform_set, 0);
Vector3i dirty = cascades[cascade].dirty_regions;
@ -2122,7 +2122,7 @@ void GI::SDFGI::render_region(Ref<RenderSceneBuffersRD> p_render_buffers, int p_
ipush_constant.scroll[1] = dirty.y / probe_divisor;
ipush_constant.scroll[2] = dirty.z / probe_divisor;
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->sdfgi_shader.integrate_pipeline[SDFGIShader::INTEGRATE_MODE_SCROLL]);
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->sdfgi_shader.integrate_pipeline[SDFGIShader::INTEGRATE_MODE_SCROLL].get_rid());
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, cascades[cascade].integrate_uniform_set, 0);
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, gi->sdfgi_shader.integrate_default_sky_uniform_set, 1);
RD::get_singleton()->compute_list_set_push_constant(compute_list, &ipush_constant, sizeof(SDFGIShader::IntegratePushConstant));
@ -2130,7 +2130,7 @@ void GI::SDFGI::render_region(Ref<RenderSceneBuffersRD> p_render_buffers, int p_
RD::get_singleton()->compute_list_add_barrier(compute_list);
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->sdfgi_shader.integrate_pipeline[SDFGIShader::INTEGRATE_MODE_SCROLL_STORE]);
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->sdfgi_shader.integrate_pipeline[SDFGIShader::INTEGRATE_MODE_SCROLL_STORE].get_rid());
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, cascades[cascade].integrate_uniform_set, 0);
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, gi->sdfgi_shader.integrate_default_sky_uniform_set, 1);
RD::get_singleton()->compute_list_set_push_constant(compute_list, &ipush_constant, sizeof(SDFGIShader::IntegratePushConstant));
@ -2141,7 +2141,7 @@ void GI::SDFGI::render_region(Ref<RenderSceneBuffersRD> p_render_buffers, int p_
if (bounce_feedback > 0.0) {
//multibounce requires this to be stored so direct light can read from it
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->sdfgi_shader.integrate_pipeline[SDFGIShader::INTEGRATE_MODE_STORE]);
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->sdfgi_shader.integrate_pipeline[SDFGIShader::INTEGRATE_MODE_STORE].get_rid());
//convert to octahedral to store
ipush_constant.image_size[0] *= SDFGI::LIGHTPROBE_OCT_SIZE;
@ -2171,7 +2171,7 @@ void GI::SDFGI::render_region(Ref<RenderSceneBuffersRD> p_render_buffers, int p_
push_constant.grid_size >>= 1;
uint32_t cascade_half_size = cascade_size >> 1;
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->sdfgi_shader.preprocess_pipeline[SDFGIShader::PRE_PROCESS_JUMP_FLOOD_INITIALIZE_HALF]);
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->sdfgi_shader.preprocess_pipeline[SDFGIShader::PRE_PROCESS_JUMP_FLOOD_INITIALIZE_HALF].get_rid());
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, sdf_initialize_half_uniform_set, 0);
RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(SDFGIShader::PreprocessPushConstant));
RD::get_singleton()->compute_list_dispatch_threads(compute_list, cascade_half_size, cascade_half_size, cascade_half_size);
@ -2185,7 +2185,7 @@ void GI::SDFGI::render_region(Ref<RenderSceneBuffersRD> p_render_buffers, int p_
uint32_t s = cascade_half_size;
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->sdfgi_shader.preprocess_pipeline[SDFGIShader::PRE_PROCESS_JUMP_FLOOD]);
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->sdfgi_shader.preprocess_pipeline[SDFGIShader::PRE_PROCESS_JUMP_FLOOD].get_rid());
int jf_us = 0;
//start with regular jump flood for very coarse reads, as this is impossible to optimize
@ -2206,7 +2206,7 @@ void GI::SDFGI::render_region(Ref<RenderSceneBuffersRD> p_render_buffers, int p_
RENDER_TIMESTAMP("SDFGI Jump Flood Optimized (Half-Size)");
//continue with optimized jump flood for smaller reads
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->sdfgi_shader.preprocess_pipeline[SDFGIShader::PRE_PROCESS_JUMP_FLOOD_OPTIMIZED]);
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->sdfgi_shader.preprocess_pipeline[SDFGIShader::PRE_PROCESS_JUMP_FLOOD_OPTIMIZED].get_rid());
while (s > 1) {
s /= 2;
push_constant.step_size = s;
@ -2221,7 +2221,7 @@ void GI::SDFGI::render_region(Ref<RenderSceneBuffersRD> p_render_buffers, int p_
// restore grid size for last passes
push_constant.grid_size = cascade_size;
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->sdfgi_shader.preprocess_pipeline[SDFGIShader::PRE_PROCESS_JUMP_FLOOD_UPSCALE]);
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->sdfgi_shader.preprocess_pipeline[SDFGIShader::PRE_PROCESS_JUMP_FLOOD_UPSCALE].get_rid());
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, sdf_upscale_uniform_set, 0);
RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(SDFGIShader::PreprocessPushConstant));
RD::get_singleton()->compute_list_dispatch_threads(compute_list, cascade_size, cascade_size, cascade_size);
@ -2231,7 +2231,7 @@ void GI::SDFGI::render_region(Ref<RenderSceneBuffersRD> p_render_buffers, int p_
push_constant.half_size = false;
push_constant.step_size = 1;
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->sdfgi_shader.preprocess_pipeline[SDFGIShader::PRE_PROCESS_JUMP_FLOOD_OPTIMIZED]);
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->sdfgi_shader.preprocess_pipeline[SDFGIShader::PRE_PROCESS_JUMP_FLOOD_OPTIMIZED].get_rid());
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, jump_flood_uniform_set[upscale_jfa_uniform_set_index], 0);
RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(SDFGIShader::PreprocessPushConstant));
RD::get_singleton()->compute_list_dispatch_threads(compute_list, cascade_size, cascade_size, cascade_size);
@ -2241,7 +2241,7 @@ void GI::SDFGI::render_region(Ref<RenderSceneBuffersRD> p_render_buffers, int p_
//full size jumpflood
RENDER_TIMESTAMP("SDFGI Jump Flood (Full-Size)");
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->sdfgi_shader.preprocess_pipeline[SDFGIShader::PRE_PROCESS_JUMP_FLOOD_INITIALIZE]);
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->sdfgi_shader.preprocess_pipeline[SDFGIShader::PRE_PROCESS_JUMP_FLOOD_INITIALIZE].get_rid());
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, sdf_initialize_uniform_set, 0);
RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(SDFGIShader::PreprocessPushConstant));
RD::get_singleton()->compute_list_dispatch_threads(compute_list, cascade_size, cascade_size, cascade_size);
@ -2252,7 +2252,7 @@ void GI::SDFGI::render_region(Ref<RenderSceneBuffersRD> p_render_buffers, int p_
{
uint32_t s = cascade_size;
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->sdfgi_shader.preprocess_pipeline[SDFGIShader::PRE_PROCESS_JUMP_FLOOD]);
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->sdfgi_shader.preprocess_pipeline[SDFGIShader::PRE_PROCESS_JUMP_FLOOD].get_rid());
int jf_us = 0;
//start with regular jump flood for very coarse reads, as this is impossible to optimize
@ -2273,7 +2273,7 @@ void GI::SDFGI::render_region(Ref<RenderSceneBuffersRD> p_render_buffers, int p_
RENDER_TIMESTAMP("SDFGI Jump Flood Optimized (Full-Size)");
//continue with optimized jump flood for smaller reads
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->sdfgi_shader.preprocess_pipeline[SDFGIShader::PRE_PROCESS_JUMP_FLOOD_OPTIMIZED]);
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->sdfgi_shader.preprocess_pipeline[SDFGIShader::PRE_PROCESS_JUMP_FLOOD_OPTIMIZED].get_rid());
while (s > 1) {
s /= 2;
push_constant.step_size = s;
@ -2293,7 +2293,7 @@ void GI::SDFGI::render_region(Ref<RenderSceneBuffersRD> p_render_buffers, int p_
uint32_t probe_size = cascade_size / SDFGI::PROBE_DIVISOR;
Vector3i probe_global_pos = cascades[cascade].position / probe_size;
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->sdfgi_shader.preprocess_pipeline[SDFGIShader::PRE_PROCESS_OCCLUSION]);
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->sdfgi_shader.preprocess_pipeline[SDFGIShader::PRE_PROCESS_OCCLUSION].get_rid());
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, occlusion_uniform_set, 0);
for (int i = 0; i < 8; i++) {
//dispatch all at once for performance
@ -2323,7 +2323,7 @@ void GI::SDFGI::render_region(Ref<RenderSceneBuffersRD> p_render_buffers, int p_
RENDER_TIMESTAMP("SDFGI Store");
// store
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->sdfgi_shader.preprocess_pipeline[SDFGIShader::PRE_PROCESS_STORE]);
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->sdfgi_shader.preprocess_pipeline[SDFGIShader::PRE_PROCESS_STORE].get_rid());
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, cascades[cascade].sdf_store_uniform_set, 0);
RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(SDFGIShader::PreprocessPushConstant));
RD::get_singleton()->compute_list_dispatch_threads(compute_list, cascade_size, cascade_size, cascade_size);
@ -2481,7 +2481,7 @@ void GI::SDFGI::render_static_lights(RenderDataRD *p_render_data, Ref<RenderScen
/* Static Lights */
RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->sdfgi_shader.direct_light_pipeline[SDFGIShader::DIRECT_LIGHT_MODE_STATIC]);
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->sdfgi_shader.direct_light_pipeline[SDFGIShader::DIRECT_LIGHT_MODE_STATIC].get_rid());
SDFGIShader::DirectLightPushConstant dl_push_constant;
@ -2985,9 +2985,9 @@ void GI::VoxelGIInstance::update(bool p_update_light_instances, const Vector<RID
if (p_update_light_instances) {
for (int i = 0; i < mipmaps.size(); i++) {
if (i == 0) {
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->voxel_gi_lighting_shader_version_pipelines[pass == 0 ? VOXEL_GI_SHADER_VERSION_COMPUTE_LIGHT : VOXEL_GI_SHADER_VERSION_COMPUTE_SECOND_BOUNCE]);
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->voxel_gi_lighting_shader_version_pipelines[pass == 0 ? VOXEL_GI_SHADER_VERSION_COMPUTE_LIGHT : VOXEL_GI_SHADER_VERSION_COMPUTE_SECOND_BOUNCE].get_rid());
} else if (i == 1) {
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->voxel_gi_lighting_shader_version_pipelines[VOXEL_GI_SHADER_VERSION_COMPUTE_MIPMAP]);
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->voxel_gi_lighting_shader_version_pipelines[VOXEL_GI_SHADER_VERSION_COMPUTE_MIPMAP].get_rid());
}
if (pass == 1 || i > 0) {
@ -3015,7 +3015,7 @@ void GI::VoxelGIInstance::update(bool p_update_light_instances, const Vector<RID
RD::get_singleton()->compute_list_add_barrier(compute_list); //wait til previous step is done
}
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->voxel_gi_lighting_shader_version_pipelines[VOXEL_GI_SHADER_VERSION_WRITE_TEXTURE]);
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->voxel_gi_lighting_shader_version_pipelines[VOXEL_GI_SHADER_VERSION_WRITE_TEXTURE].get_rid());
for (int i = 0; i < mipmaps.size(); i++) {
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, mipmaps[i].write_uniform_set, 0);
@ -3174,7 +3174,7 @@ void GI::VoxelGIInstance::update(bool p_update_light_instances, const Vector<RID
//process lighting
RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->voxel_gi_lighting_shader_version_pipelines[VOXEL_GI_SHADER_VERSION_DYNAMIC_OBJECT_LIGHTING]);
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->voxel_gi_lighting_shader_version_pipelines[VOXEL_GI_SHADER_VERSION_DYNAMIC_OBJECT_LIGHTING].get_rid());
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, dynamic_maps[0].uniform_set, 0);
RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(VoxelGIDynamicPushConstant));
RD::get_singleton()->compute_list_dispatch(compute_list, Math::division_round_up(rect.size.x, 8), Math::division_round_up(rect.size.y, 8), 1);
@ -3231,11 +3231,11 @@ void GI::VoxelGIInstance::update(bool p_update_light_instances, const Vector<RID
RD::get_singleton()->compute_list_add_barrier(compute_list);
if (dynamic_maps[k].mipmap < 0) {
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->voxel_gi_lighting_shader_version_pipelines[VOXEL_GI_SHADER_VERSION_DYNAMIC_SHRINK_WRITE]);
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->voxel_gi_lighting_shader_version_pipelines[VOXEL_GI_SHADER_VERSION_DYNAMIC_SHRINK_WRITE].get_rid());
} else if (k < dynamic_maps.size() - 1) {
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->voxel_gi_lighting_shader_version_pipelines[VOXEL_GI_SHADER_VERSION_DYNAMIC_SHRINK_WRITE_PLOT]);
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->voxel_gi_lighting_shader_version_pipelines[VOXEL_GI_SHADER_VERSION_DYNAMIC_SHRINK_WRITE_PLOT].get_rid());
} else {
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->voxel_gi_lighting_shader_version_pipelines[VOXEL_GI_SHADER_VERSION_DYNAMIC_SHRINK_PLOT]);
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->voxel_gi_lighting_shader_version_pipelines[VOXEL_GI_SHADER_VERSION_DYNAMIC_SHRINK_PLOT].get_rid());
}
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, dynamic_maps[k].uniform_set, 0);
RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(VoxelGIDynamicPushConstant));
@ -3373,6 +3373,30 @@ GI::GI() {
}
GI::~GI() {
for (int v = 0; v < SHADER_SPECIALIZATION_VARIATIONS; v++) {
for (int i = 0; i < MODE_MAX; i++) {
pipelines[v][i].free();
}
}
sdfgi_shader.debug_pipeline.free();
for (int i = 0; i < SDFGIShader::DIRECT_LIGHT_MODE_MAX; i++) {
sdfgi_shader.direct_light_pipeline[i].free();
}
for (int i = 0; i < SDFGIShader::INTEGRATE_MODE_MAX; i++) {
sdfgi_shader.integrate_pipeline[i].free();
}
for (int i = 0; i < SDFGIShader::PRE_PROCESS_MAX; i++) {
sdfgi_shader.preprocess_pipeline[i].free();
}
for (int i = 0; i < VOXEL_GI_SHADER_VERSION_MAX; i++) {
voxel_gi_lighting_shader_version_pipelines[i].free();
}
if (voxel_gi_debug_shader_version.is_valid()) {
voxel_gi_debug_shader.version_free(voxel_gi_debug_shader_version);
}
@ -3430,7 +3454,7 @@ void GI::init(SkyRD *p_sky) {
voxel_gi_lighting_shader_version = voxel_gi_shader.version_create();
for (int i = 0; i < VOXEL_GI_SHADER_VERSION_MAX; i++) {
voxel_gi_lighting_shader_version_shaders[i] = voxel_gi_shader.version_get_shader(voxel_gi_lighting_shader_version, i);
voxel_gi_lighting_shader_version_pipelines[i] = RD::get_singleton()->compute_pipeline_create(voxel_gi_lighting_shader_version_shaders[i]);
voxel_gi_lighting_shader_version_pipelines[i].create_compute_pipeline(voxel_gi_lighting_shader_version_shaders[i]);
}
}
@ -3475,7 +3499,7 @@ void GI::init(SkyRD *p_sky) {
sdfgi_shader.preprocess.initialize(preprocess_modes, defines);
sdfgi_shader.preprocess_shader = sdfgi_shader.preprocess.version_create();
for (int i = 0; i < SDFGIShader::PRE_PROCESS_MAX; i++) {
sdfgi_shader.preprocess_pipeline[i] = RD::get_singleton()->compute_pipeline_create(sdfgi_shader.preprocess.version_get_shader(sdfgi_shader.preprocess_shader, i));
sdfgi_shader.preprocess_pipeline[i].create_compute_pipeline(sdfgi_shader.preprocess.version_get_shader(sdfgi_shader.preprocess_shader, i));
}
}
@ -3489,7 +3513,7 @@ void GI::init(SkyRD *p_sky) {
sdfgi_shader.direct_light.initialize(direct_light_modes, defines);
sdfgi_shader.direct_light_shader = sdfgi_shader.direct_light.version_create();
for (int i = 0; i < SDFGIShader::DIRECT_LIGHT_MODE_MAX; i++) {
sdfgi_shader.direct_light_pipeline[i] = RD::get_singleton()->compute_pipeline_create(sdfgi_shader.direct_light.version_get_shader(sdfgi_shader.direct_light_shader, i));
sdfgi_shader.direct_light_pipeline[i].create_compute_pipeline(sdfgi_shader.direct_light.version_get_shader(sdfgi_shader.direct_light_shader, i));
}
}
@ -3510,7 +3534,7 @@ void GI::init(SkyRD *p_sky) {
sdfgi_shader.integrate_shader = sdfgi_shader.integrate.version_create();
for (int i = 0; i < SDFGIShader::INTEGRATE_MODE_MAX; i++) {
sdfgi_shader.integrate_pipeline[i] = RD::get_singleton()->compute_pipeline_create(sdfgi_shader.integrate.version_get_shader(sdfgi_shader.integrate_shader, i));
sdfgi_shader.integrate_pipeline[i].create_compute_pipeline(sdfgi_shader.integrate.version_get_shader(sdfgi_shader.integrate_shader, i));
}
{
@ -3592,7 +3616,7 @@ void GI::init(SkyRD *p_sky) {
int variant_base = vrs_supported ? MODE_MAX : 0;
for (int i = 0; i < MODE_MAX; i++) {
pipelines[v][i] = RD::get_singleton()->compute_pipeline_create(shader.version_get_shader(shader_version, variant_base + i), specialization_constants);
pipelines[v][i].create_compute_pipeline(shader.version_get_shader(shader_version, variant_base + i), specialization_constants);
}
}
@ -3605,7 +3629,7 @@ void GI::init(SkyRD *p_sky) {
sdfgi_shader.debug.initialize(debug_modes, defines);
sdfgi_shader.debug_shader = sdfgi_shader.debug.version_create();
sdfgi_shader.debug_shader_version = sdfgi_shader.debug.version_get_shader(sdfgi_shader.debug_shader, 0);
sdfgi_shader.debug_pipeline = RD::get_singleton()->compute_pipeline_create(sdfgi_shader.debug_shader_version);
sdfgi_shader.debug_pipeline.create_compute_pipeline(sdfgi_shader.debug_shader_version);
}
{
String defines = "\n#define OCT_SIZE " + itos(SDFGI::LIGHTPROBE_OCT_SIZE) + "\n";
@ -4090,7 +4114,7 @@ void GI::process_gi(Ref<RenderSceneBuffersRD> p_render_buffers, const RID *p_nor
rbgi->uniform_set[v] = RD::get_singleton()->uniform_set_create(uniforms, shader.version_get_shader(shader_version, variant_base), 0);
}
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, pipelines[pipeline_specialization][mode]);
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, pipelines[pipeline_specialization][mode].get_rid());
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, rbgi->uniform_set[v], 0);
RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(PushConstant));

View file

@ -35,6 +35,7 @@
#include "servers/rendering/environment/renderer_gi.h"
#include "servers/rendering/renderer_compositor.h"
#include "servers/rendering/renderer_rd/environment/sky.h"
#include "servers/rendering/renderer_rd/pipeline_deferred_rd.h"
#include "servers/rendering/renderer_rd/shaders/environment/gi.glsl.gen.h"
#include "servers/rendering/renderer_rd/shaders/environment/sdfgi_debug.glsl.gen.h"
#include "servers/rendering/renderer_rd/shaders/environment/sdfgi_debug_probes.glsl.gen.h"
@ -232,7 +233,7 @@ private:
VoxelGiShaderRD voxel_gi_shader;
RID voxel_gi_lighting_shader_version;
RID voxel_gi_lighting_shader_version_shaders[VOXEL_GI_SHADER_VERSION_MAX];
RID voxel_gi_lighting_shader_version_pipelines[VOXEL_GI_SHADER_VERSION_MAX];
PipelineDeferredRD voxel_gi_lighting_shader_version_pipelines[VOXEL_GI_SHADER_VERSION_MAX];
enum {
VOXEL_GI_DEBUG_COLOR,
@ -289,7 +290,7 @@ private:
SdfgiPreprocessShaderRD preprocess;
RID preprocess_shader;
RID preprocess_pipeline[PRE_PROCESS_MAX];
PipelineDeferredRD preprocess_pipeline[PRE_PROCESS_MAX];
struct DebugPushConstant {
float grid_size[3];
@ -308,7 +309,7 @@ private:
SdfgiDebugShaderRD debug;
RID debug_shader;
RID debug_shader_version;
RID debug_pipeline;
PipelineDeferredRD debug_pipeline;
enum ProbeDebugMode {
PROBE_DEBUG_PROBES,
@ -381,7 +382,7 @@ private:
};
SdfgiDirectLightShaderRD direct_light;
RID direct_light_shader;
RID direct_light_pipeline[DIRECT_LIGHT_MODE_MAX];
PipelineDeferredRD direct_light_pipeline[DIRECT_LIGHT_MODE_MAX];
enum {
INTEGRATE_MODE_PROCESS,
@ -424,7 +425,7 @@ private:
SdfgiIntegrateShaderRD integrate;
RID integrate_shader;
RID integrate_pipeline[INTEGRATE_MODE_MAX];
PipelineDeferredRD integrate_pipeline[INTEGRATE_MODE_MAX];
RID integrate_default_sky_uniform_set;
@ -815,7 +816,7 @@ public:
bool half_resolution = false;
GiShaderRD shader;
RID shader_version;
RID pipelines[SHADER_SPECIALIZATION_VARIATIONS][MODE_MAX];
PipelineDeferredRD pipelines[SHADER_SPECIALIZATION_VARIATIONS][MODE_MAX];
GI();
~GI();

View file

@ -0,0 +1,126 @@
/**************************************************************************/
/* pipeline_deferred_rd.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#pragma once
#include "servers/rendering/rendering_device.h"
// Helper class for automatically deferring compilation of a pipeline to a background task.
// When attempting to retrieve the pipeline with the getter, the caller will automatically
// wait for it to be ready.
class PipelineDeferredRD {
protected:
struct CreationParameters {
RID shader;
RD::FramebufferFormatID framebuffer_format;
RD::VertexFormatID vertex_format;
RD::RenderPrimitive render_primitive;
RD::PipelineRasterizationState rasterization_state;
RD::PipelineMultisampleState multisample_state;
RD::PipelineDepthStencilState depth_stencil_state;
RD::PipelineColorBlendState blend_state;
BitField<RD::PipelineDynamicStateFlags> dynamic_state_flags;
uint32_t for_render_pass;
Vector<RD::PipelineSpecializationConstant> specialization_constants;
bool is_compute;
};
RID pipeline;
WorkerThreadPool::TaskID task = WorkerThreadPool::INVALID_TASK_ID;
void _create(const CreationParameters &c) {
if (c.is_compute) {
pipeline = RD::get_singleton()->compute_pipeline_create(c.shader, c.specialization_constants);
} else {
pipeline = RD::get_singleton()->render_pipeline_create(c.shader, c.framebuffer_format, c.vertex_format, c.render_primitive, c.rasterization_state, c.multisample_state, c.depth_stencil_state, c.blend_state, c.dynamic_state_flags, c.for_render_pass, c.specialization_constants);
}
}
void _start(const CreationParameters &c) {
free();
task = WorkerThreadPool::get_singleton()->add_template_task(this, &PipelineDeferredRD::_create, c, true, "PipelineCompilation");
}
void _wait() {
if (task != WorkerThreadPool::INVALID_TASK_ID) {
WorkerThreadPool::get_singleton()->wait_for_task_completion(task);
task = WorkerThreadPool::INVALID_TASK_ID;
}
}
public:
PipelineDeferredRD() {
// Default constructor.
}
~PipelineDeferredRD() {
free();
}
void create_render_pipeline(RID p_shader, RD::FramebufferFormatID p_framebuffer_format, RD::VertexFormatID p_vertex_format, RD::RenderPrimitive p_render_primitive, const RD::PipelineRasterizationState &p_rasterization_state, const RD::PipelineMultisampleState &p_multisample_state, const RD::PipelineDepthStencilState &p_depth_stencil_state, const RD::PipelineColorBlendState &p_blend_state, BitField<RD::PipelineDynamicStateFlags> p_dynamic_state_flags = 0, uint32_t p_for_render_pass = 0, const Vector<RD::PipelineSpecializationConstant> &p_specialization_constants = Vector<RD::PipelineSpecializationConstant>()) {
CreationParameters c;
c.shader = p_shader;
c.framebuffer_format = p_framebuffer_format;
c.vertex_format = p_vertex_format;
c.render_primitive = p_render_primitive;
c.rasterization_state = p_rasterization_state;
c.multisample_state = p_multisample_state;
c.depth_stencil_state = p_depth_stencil_state;
c.blend_state = p_blend_state;
c.dynamic_state_flags = p_dynamic_state_flags;
c.for_render_pass = p_for_render_pass;
c.specialization_constants = p_specialization_constants;
c.is_compute = false;
_start(c);
}
void create_compute_pipeline(RID p_shader, const Vector<RD::PipelineSpecializationConstant> &p_specialization_constants = Vector<RD::PipelineSpecializationConstant>()) {
CreationParameters c = {};
c.shader = p_shader;
c.specialization_constants = p_specialization_constants;
c.is_compute = true;
_start(c);
}
RID get_rid() {
_wait();
return pipeline;
}
void free() {
_wait();
if (pipeline.is_valid()) {
RD::get_singleton()->free_rid(pipeline);
pipeline = RID();
}
}
};

View file

@ -180,17 +180,22 @@ void process() {
for (int i = 0; i <= ParticlesShader::MAX_USERDATAS; i++) {
for (int j = 0; j < ParticlesShader::COPY_MODE_MAX; j++) {
particles_shader.copy_pipelines[i * ParticlesShader::COPY_MODE_MAX + j] = RD::get_singleton()->compute_pipeline_create(particles_shader.copy_shader.version_get_shader(particles_shader.copy_shader_version, i * ParticlesShader::COPY_MODE_MAX + j));
particles_shader.copy_pipelines[i][j].create_compute_pipeline(particles_shader.copy_shader.version_get_shader(particles_shader.copy_shader_version, i * ParticlesShader::COPY_MODE_MAX + j));
}
}
}
}
ParticlesStorage::~ParticlesStorage() {
MaterialStorage *material_storage = MaterialStorage::get_singleton();
for (int i = 0; i <= ParticlesShader::MAX_USERDATAS; i++) {
for (int j = 0; j < ParticlesShader::COPY_MODE_MAX; j++) {
particles_shader.copy_pipelines[i][j].free();
}
}
particles_shader.copy_shader.version_free(particles_shader.copy_shader_version);
MaterialStorage *material_storage = MaterialStorage::get_singleton();
material_storage->material_free(particles_shader.default_material);
material_storage->shader_free(particles_shader.default_shader);
@ -1183,7 +1188,7 @@ void ParticlesStorage::_particles_process(Particles *p_particles, double p_delta
//todo should maybe compute all particle systems together?
RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, m->shader_data->pipeline);
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, m->shader_data->pipeline.get_rid());
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, particles_shader.base_uniform_set, BASE_UNIFORM_SET);
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, p_particles->particles_material_uniform_set, MATERIAL_UNIFORM_SET);
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, p_particles->collision_textures_uniform_set, COLLISION_TEXTURTES_UNIFORM_SET);
@ -1294,7 +1299,7 @@ void ParticlesStorage::particles_set_view_axis(RID p_particles, const Vector3 &p
if (do_sort) {
RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, particles_shader.copy_pipelines[ParticlesShader::COPY_MODE_FILL_SORT_BUFFER + particles->userdata_count * ParticlesShader::COPY_MODE_MAX]);
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, particles_shader.copy_pipelines[particles->userdata_count][ParticlesShader::COPY_MODE_FILL_SORT_BUFFER].get_rid());
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, particles->particles_copy_uniform_set, 0);
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, particles->particles_sort_uniform_set, 1);
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, particles->trail_bind_pose_uniform_set, 2);
@ -1311,10 +1316,9 @@ void ParticlesStorage::particles_set_view_axis(RID p_particles, const Vector3 &p
}
RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
uint32_t copy_pipeline = do_sort ? ParticlesShader::COPY_MODE_FILL_INSTANCES_WITH_SORT_BUFFER : ParticlesShader::COPY_MODE_FILL_INSTANCES;
copy_pipeline += particles->userdata_count * ParticlesShader::COPY_MODE_MAX;
uint32_t copy_mode = do_sort ? ParticlesShader::COPY_MODE_FILL_INSTANCES_WITH_SORT_BUFFER : ParticlesShader::COPY_MODE_FILL_INSTANCES;
copy_push_constant.copy_mode_2d = particles->mode == RS::PARTICLES_MODE_2D ? 1 : 0;
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, particles_shader.copy_pipelines[copy_pipeline]);
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, particles_shader.copy_pipelines[particles->userdata_count][copy_mode].get_rid());
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, particles->particles_copy_uniform_set, 0);
if (do_sort) {
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, particles->particles_sort_uniform_set, 1);
@ -1642,7 +1646,7 @@ void ParticlesStorage::update_particles() {
RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
copy_push_constant.copy_mode_2d = particles->mode == RS::PARTICLES_MODE_2D ? 1 : 0;
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, particles_shader.copy_pipelines[ParticlesShader::COPY_MODE_FILL_INSTANCES + particles->userdata_count * ParticlesShader::COPY_MODE_MAX]);
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, particles_shader.copy_pipelines[particles->userdata_count][ParticlesShader::COPY_MODE_FILL_INSTANCES].get_rid());
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, particles->particles_copy_uniform_set, 0);
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, particles->trail_bind_pose_uniform_set, 2);
RD::get_singleton()->compute_list_set_push_constant(compute_list, &copy_push_constant, sizeof(ParticlesShader::CopyPushConstant));
@ -1714,6 +1718,8 @@ void ParticlesStorage::ParticlesShaderData::set_code(const String &p_code) {
if (version.is_null()) {
version = particles_storage->particles_shader.shader.version_create();
} else {
pipeline.free();
}
for (uint32_t i = 0; i < ParticlesShader::MAX_USERDATAS; i++) {
@ -1731,7 +1737,7 @@ void ParticlesStorage::ParticlesShaderData::set_code(const String &p_code) {
//update pipelines
pipeline = RD::get_singleton()->compute_pipeline_create(particles_storage->particles_shader.shader.version_get_shader(version, 0));
pipeline.create_compute_pipeline(particles_storage->particles_shader.shader.version_get_shader(version, 0));
valid = true;
}
@ -1753,7 +1759,8 @@ Pair<ShaderRD *, RID> ParticlesStorage::ParticlesShaderData::get_native_shader_a
}
ParticlesStorage::ParticlesShaderData::~ParticlesShaderData() {
//pipeline variants will clear themselves if shader is gone
pipeline.free();
if (version.is_valid()) {
ParticlesStorage::get_singleton()->particles_shader.shader.version_free(version);
}

View file

@ -34,6 +34,7 @@
#include "core/templates/rid_owner.h"
#include "core/templates/self_list.h"
#include "servers/rendering/renderer_rd/effects/sort_effects.h"
#include "servers/rendering/renderer_rd/pipeline_deferred_rd.h"
#include "servers/rendering/renderer_rd/shaders/particles.glsl.gen.h"
#include "servers/rendering/renderer_rd/shaders/particles_copy.glsl.gen.h"
#include "servers/rendering/renderer_rd/storage_rd/material_storage.h"
@ -329,7 +330,7 @@ private:
ParticlesCopyShaderRD copy_shader;
RID copy_shader_version;
RID copy_pipelines[COPY_MODE_MAX * (MAX_USERDATAS + 1)];
PipelineDeferredRD copy_pipelines[MAX_USERDATAS + 1][COPY_MODE_MAX];
LocalVector<float> pose_update_buffer;
@ -353,7 +354,7 @@ private:
String code;
RID pipeline;
PipelineDeferredRD pipeline;
bool uses_time = false;

View file

@ -955,6 +955,7 @@ void RendererViewport::viewport_initialize(RID p_rid) {
viewport->fsr_enabled = !RSG::rasterizer->is_low_end() && !viewport->disable_3d;
}
#ifndef XR_DISABLED
void RendererViewport::viewport_set_use_xr(RID p_viewport, bool p_use_xr) {
Viewport *viewport = viewport_owner.get_or_null(p_viewport);
ERR_FAIL_NULL(viewport);
@ -972,6 +973,7 @@ void RendererViewport::viewport_set_use_xr(RID p_viewport, bool p_use_xr) {
_configure_3d_render_buffers(viewport);
}
}
#endif // !XR_DISABLED
void RendererViewport::viewport_set_scaling_3d_mode(RID p_viewport, RS::ViewportScaling3DMode p_mode) {
Viewport *viewport = viewport_owner.get_or_null(p_viewport);

View file

@ -216,7 +216,9 @@ public:
RID viewport_allocate();
void viewport_initialize(RID p_rid);
#ifndef XR_DISABLED
void viewport_set_use_xr(RID p_viewport, bool p_use_xr);
#endif // XR_DISABLED
void viewport_set_size(RID p_viewport, int p_width, int p_height);

View file

@ -2823,7 +2823,9 @@ void RenderingServer::_bind_methods() {
/* VIEWPORT */
ClassDB::bind_method(D_METHOD("viewport_create"), &RenderingServer::viewport_create);
#ifndef XR_DISABLED
ClassDB::bind_method(D_METHOD("viewport_set_use_xr", "viewport", "use_xr"), &RenderingServer::viewport_set_use_xr);
#endif // XR_DISABLED
ClassDB::bind_method(D_METHOD("viewport_set_size", "viewport", "width", "height"), &RenderingServer::viewport_set_size);
ClassDB::bind_method(D_METHOD("viewport_set_active", "viewport", "active"), &RenderingServer::viewport_set_active);
ClassDB::bind_method(D_METHOD("viewport_set_parent_viewport", "viewport", "parent_viewport"), &RenderingServer::viewport_set_parent_viewport);
@ -3760,7 +3762,9 @@ void RenderingServer::init() {
GLOBAL_DEF_RST(PropertyInfo(Variant::INT, "rendering/limits/opengl/max_renderable_lights", PROPERTY_HINT_RANGE, "2,256,1"), 32);
GLOBAL_DEF_RST(PropertyInfo(Variant::INT, "rendering/limits/opengl/max_lights_per_object", PROPERTY_HINT_RANGE, "2,1024,1"), 8);
#ifndef XR_DISABLED
GLOBAL_DEF_RST_BASIC("xr/shaders/enabled", false);
#endif // XR_DISABLED
GLOBAL_DEF("debug/shader_language/warnings/enable", true);
GLOBAL_DEF("debug/shader_language/warnings/treat_warnings_as_errors", false);

View file

@ -980,7 +980,10 @@ public:
return VIEWPORT_SCALING_3D_TYPE_NONE;
}
#ifndef XR_DISABLED
virtual void viewport_set_use_xr(RID p_viewport, bool p_use_xr) = 0;
#endif // !XR_DISABLED
virtual void viewport_set_size(RID p_viewport, int p_width, int p_height) = 0;
virtual void viewport_set_active(RID p_viewport, bool p_active) = 0;
virtual void viewport_set_parent_viewport(RID p_viewport, RID p_parent_viewport) = 0;

View file

@ -693,7 +693,10 @@ public:
FUNCRIDSPLIT(viewport)
#ifndef XR_DISABLED
FUNC2(viewport_set_use_xr, RID, bool)
#endif // XR_DISABLED
FUNC3(viewport_set_size, RID, int, int)
FUNC2(viewport_set_active, RID, bool)

View file

@ -115,10 +115,10 @@ void XRPositionalTracker::set_pose(const StringName &p_action_name, const Transf
new_pose = poses[p_action_name];
} else {
new_pose.instantiate();
new_pose->set_name(p_action_name);
poses[p_action_name] = new_pose;
}
new_pose->set_name(p_action_name);
new_pose->set_has_tracking_data(true);
new_pose->set_transform(p_transform);
new_pose->set_linear_velocity(p_linear_velocity);

View file

@ -436,7 +436,7 @@ Patches:
## harfbuzz
- Upstream: https://github.com/harfbuzz/harfbuzz
- Version: 11.3.2 (4e3df1c1383481ed5717603d5dd3453a04fb16ba, 2025)
- Version: 12.1.0 (a790c38b782f9d8e6f0299d2837229e5726fc669, 2025)
- License: MIT
Files extracted from upstream source:

View file

@ -178,7 +178,10 @@ struct hb_colrv1_closure_context_t :
{ glyphs->add (glyph_id); }
void add_layer_indices (unsigned first_layer_index, unsigned num_of_layers)
{ layer_indices->add_range (first_layer_index, first_layer_index + num_of_layers - 1); }
{
if (num_of_layers == 0) return;
layer_indices->add_range (first_layer_index, first_layer_index + num_of_layers - 1);
}
void add_palette_index (unsigned palette_index)
{ palette_indices->add (palette_index); }
@ -650,10 +653,10 @@ struct PaintColrLayers
TRACE_SUBSET (this);
auto *out = c->serializer->embed (this);
if (unlikely (!out)) return_trace (false);
return_trace (c->serializer->check_assign (out->firstLayerIndex, c->plan->colrv1_layers.get (firstLayerIndex),
HB_SERIALIZE_ERROR_INT_OVERFLOW));
return_trace (true);
uint32_t first_layer_index = numLayers ? c->plan->colrv1_layers.get (firstLayerIndex) : 0;
return_trace (c->serializer->check_assign (out->firstLayerIndex, first_layer_index,
HB_SERIALIZE_ERROR_INT_OVERFLOW));
}
bool sanitize (hb_sanitize_context_t *c) const
@ -2057,7 +2060,7 @@ struct delta_set_index_map_subset_plan_t
outer_bit_count = 1;
inner_bit_count = 1;
if (unlikely (!output_map.resize (map_count, false))) return false;
if (unlikely (!output_map.resize_dirty (map_count))) return false;
for (unsigned idx = 0; idx < map_count; idx++)
{

View file

@ -307,6 +307,7 @@ struct CPAL
if (first_color_to_layer_index.has (first_color_record_idx)) continue;
first_color_index_for_layer.push (first_color_record_idx);
if (unlikely (!c->serializer->propagate_error (first_color_index_for_layer))) return_trace (false);
first_color_to_layer_index.set (first_color_record_idx,
first_color_index_for_layer.length - 1);
}

View file

@ -97,12 +97,17 @@ struct Coverage
}
}
unsigned int get_coverage (hb_codepoint_t glyph_id,
hb_ot_lookup_cache_t *cache) const
hb_ot_layout_mapping_cache_t *cache) const
{
unsigned coverage;
if (cache && cache->get (glyph_id, &coverage)) return coverage;
if (cache && cache->get (glyph_id, &coverage)) return coverage < cache->MAX_VALUE ? coverage : NOT_COVERED;
coverage = get_coverage (glyph_id);
if (cache) cache->set (glyph_id, coverage);
if (cache) {
if (coverage == NOT_COVERED)
cache->set_unchecked (glyph_id, cache->MAX_VALUE);
else if (likely (coverage < cache->MAX_VALUE))
cache->set_unchecked (glyph_id, coverage);
}
return coverage;
}
@ -332,7 +337,7 @@ struct Coverage
}
iter_t __end__ () const
{
iter_t it = {};
iter_t it;
it.format = format;
switch (format)
{

View file

@ -977,7 +977,7 @@ struct GDEF
}
#ifndef HB_NO_GDEF_CACHE
table->get_mark_glyph_sets ().collect_coverage (mark_glyph_set_digests);
table->get_mark_glyph_sets ().collect_coverage (mark_glyph_sets);
#endif
}
~accelerator_t () { table.destroy (); }
@ -1006,14 +1006,16 @@ struct GDEF
{
return
#ifndef HB_NO_GDEF_CACHE
mark_glyph_set_digests[set_index].may_have (glyph_id) &&
mark_glyph_sets[set_index].may_have (glyph_id)
#else
table->mark_set_covers (set_index, glyph_id)
#endif
table->mark_set_covers (set_index, glyph_id);
;
}
hb_blob_ptr_t<GDEF> table;
#ifndef HB_NO_GDEF_CACHE
hb_vector_t<hb_set_digest_t> mark_glyph_set_digests;
hb_vector_t<hb_bit_set_t> mark_glyph_sets;
mutable hb_cache_t<21, 3> glyph_props_cache;
static_assert (sizeof (glyph_props_cache) == 512, "");
#endif

View file

@ -77,6 +77,13 @@ struct AnchorMatrix
return_trace (true);
}
bool offset_is_null (unsigned row, unsigned col, unsigned num_cols) const
{
if (unlikely (row >= rows || col >= num_cols)) return true;
auto &offset = matrixZ[row * num_cols + col];
return offset.is_null ();
}
};

View file

@ -80,9 +80,8 @@ propagate_attachment_offsets (hb_glyph_position_t *pos,
{
/* Adjusts offsets of attached glyphs (both cursive and mark) to accumulate
* offset of glyph they are attached to. */
int chain = pos[i].attach_chain(), type = pos[i].attach_type();
if (likely (!chain))
return;
int chain = pos[i].attach_chain();
int type = pos[i].attach_type();
pos[i].attach_chain() = 0;
@ -94,7 +93,8 @@ propagate_attachment_offsets (hb_glyph_position_t *pos,
if (unlikely (!nesting_level))
return;
propagate_attachment_offsets (pos, len, j, direction, nesting_level - 1);
if (pos[j].attach_chain())
propagate_attachment_offsets (pos, len, j, direction, nesting_level - 1);
assert (!!(type & GPOS_impl::ATTACH_TYPE_MARK) ^ !!(type & GPOS_impl::ATTACH_TYPE_CURSIVE));
@ -110,17 +110,37 @@ propagate_attachment_offsets (hb_glyph_position_t *pos,
pos[i].x_offset += pos[j].x_offset;
pos[i].y_offset += pos[j].y_offset;
assert (j < i);
if (HB_DIRECTION_IS_FORWARD (direction))
for (unsigned int k = j; k < i; k++) {
pos[i].x_offset -= pos[k].x_advance;
pos[i].y_offset -= pos[k].y_advance;
}
else
for (unsigned int k = j + 1; k < i + 1; k++) {
pos[i].x_offset += pos[k].x_advance;
pos[i].y_offset += pos[k].y_advance;
}
// i is the position of the mark; j is the base.
if (j < i)
{
/* This is the common case: mark follows base.
* And currently the only way in OpenType. */
if (HB_DIRECTION_IS_FORWARD (direction))
for (unsigned int k = j; k < i; k++) {
pos[i].x_offset -= pos[k].x_advance;
pos[i].y_offset -= pos[k].y_advance;
}
else
for (unsigned int k = j + 1; k < i + 1; k++) {
pos[i].x_offset += pos[k].x_advance;
pos[i].y_offset += pos[k].y_advance;
}
}
else // j > i
{
/* This can happen with `kerx`: a mark attaching
* to a base after it in the logical order. */
if (HB_DIRECTION_IS_FORWARD (direction))
for (unsigned int k = i; k < j; k++) {
pos[i].x_offset += pos[k].x_advance;
pos[i].y_offset += pos[k].y_advance;
}
else
for (unsigned int k = i + 1; k < j + 1; k++) {
pos[i].x_offset -= pos[k].x_advance;
pos[i].y_offset -= pos[k].y_advance;
}
}
}
}
@ -149,8 +169,20 @@ GPOS::position_finish_offsets (hb_font_t *font, hb_buffer_t *buffer)
/* Handle attachments */
if (buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT)
for (unsigned i = 0; i < len; i++)
propagate_attachment_offsets (pos, len, i, direction);
{
auto *pos = buffer->pos;
// https://github.com/harfbuzz/harfbuzz/issues/5514
if (HB_DIRECTION_IS_FORWARD (direction))
{
for (unsigned i = 0; i < len; i++)
if (pos[i].attach_chain())
propagate_attachment_offsets (pos, len, i, direction);
} else {
for (unsigned i = len; i-- > 0; )
if (pos[i].attach_chain())
propagate_attachment_offsets (pos, len, i, direction);
}
}
if (unlikely (font->slant_xy) &&
HB_DIRECTION_IS_HORIZONTAL (direction))

View file

@ -19,22 +19,30 @@ struct LigatureArray : List16OfOffset16To<LigatureAttach>
bool subset (hb_subset_context_t *c,
Iterator coverage,
unsigned class_count,
const hb_map_t *klass_mapping) const
const hb_map_t *klass_mapping,
hb_sorted_vector_t<hb_codepoint_t> &new_coverage /* OUT */) const
{
TRACE_SUBSET (this);
const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
const hb_map_t &glyph_map = c->plan->glyph_map_gsub;
auto *out = c->serializer->start_embed (this);
if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
bool ret = false;
for (const auto _ : + hb_zip (coverage, *this)
| hb_filter (glyphset, hb_first))
| hb_filter (glyph_map, hb_first))
{
const LigatureAttach& src = (this + _.second);
bool non_empty = + hb_range (src.rows * class_count)
| hb_filter ([=] (unsigned index) { return klass_mapping->has (index % class_count); })
| hb_map ([&] (const unsigned index) { return !src.offset_is_null (index / class_count, index % class_count, class_count); })
| hb_any;
if (!non_empty) continue;
auto *matrix = out->serialize_append (c->serializer);
if (unlikely (!matrix)) return_trace (false);
const LigatureAttach& src = (this + _.second);
auto indexes =
+ hb_range (src.rows * class_count)
| hb_filter ([=] (unsigned index) { return klass_mapping->has (index % class_count); })
@ -44,6 +52,9 @@ struct LigatureArray : List16OfOffset16To<LigatureAttach>
this,
src.rows,
indexes);
hb_codepoint_t new_gid = glyph_map.get (_.first);
new_coverage.push (new_gid);
}
return_trace (ret);
}

View file

@ -209,19 +209,22 @@ struct MarkBasePosFormat1_2
;
new_coverage.reset ();
+ base_iter
| hb_map (hb_first)
| hb_map (glyph_map)
| hb_sink (new_coverage)
;
if (!out->baseCoverage.serialize_serialize (c->serializer, new_coverage.iter ()))
return_trace (false);
hb_sorted_vector_t<unsigned> base_indexes;
for (const unsigned row : + base_iter
| hb_map (hb_second))
auto &base_array = (this+baseArray);
for (const auto _ : + base_iter)
{
unsigned row = _.second;
bool non_empty = + hb_range ((unsigned) classCount)
| hb_filter (klass_mapping)
| hb_map ([&] (const unsigned col) { return !base_array.offset_is_null (row, col, (unsigned) classCount); })
| hb_any
;
if (!non_empty) continue;
hb_codepoint_t new_g = glyph_map.get ( _.first);
new_coverage.push (new_g);
+ hb_range ((unsigned) classCount)
| hb_filter (klass_mapping)
| hb_map ([&] (const unsigned col) { return row * (unsigned) classCount + col; })
@ -229,8 +232,12 @@ struct MarkBasePosFormat1_2
;
}
if (!new_coverage) return_trace (false);
if (!out->baseCoverage.serialize_serialize (c->serializer, new_coverage.iter ()))
return_trace (false);
return_trace (out->baseArray.serialize_subset (c, baseArray, this,
base_iter.len (),
new_coverage.length,
base_indexes.iter ()));
}
};

View file

@ -200,19 +200,13 @@ struct MarkLigPosFormat1_2
&klass_mapping)))
return_trace (false);
auto new_ligature_coverage =
+ hb_iter (this + ligatureCoverage)
| hb_take ((this + ligatureArray).len)
| hb_map_retains_sorting (glyph_map)
| hb_filter ([] (hb_codepoint_t glyph) { return glyph != HB_MAP_VALUE_INVALID; })
;
if (!out->ligatureCoverage.serialize_serialize (c->serializer, new_ligature_coverage))
hb_sorted_vector_t<hb_codepoint_t> new_lig_coverage;
if (!out->ligatureArray.serialize_subset (c, ligatureArray, this,
hb_iter (this+ligatureCoverage),
classCount, &klass_mapping, new_lig_coverage))
return_trace (false);
return_trace (out->ligatureArray.serialize_subset (c, ligatureArray, this,
hb_iter (this+ligatureCoverage),
classCount, &klass_mapping));
return_trace (out->ligatureCoverage.serialize_serialize (c->serializer, new_lig_coverage.iter ()));
}
};

View file

@ -196,19 +196,23 @@ struct MarkMarkPosFormat1_2
;
new_coverage.reset ();
+ mark2_iter
| hb_map (hb_first)
| hb_map (glyph_map)
| hb_sink (new_coverage)
;
if (!out->mark2Coverage.serialize_serialize (c->serializer, new_coverage.iter ()))
return_trace (false);
hb_sorted_vector_t<unsigned> mark2_indexes;
for (const unsigned row : + mark2_iter
| hb_map (hb_second))
auto &mark2_array = (this+mark2Array);
for (const auto _ : + mark2_iter)
{
unsigned row = _.second;
bool non_empty = + hb_range ((unsigned) classCount)
| hb_filter (klass_mapping)
| hb_map ([&] (const unsigned col) { return !mark2_array.offset_is_null (row, col, (unsigned) classCount); })
| hb_any
;
if (!non_empty) continue;
hb_codepoint_t new_g = glyph_map.get ( _.first);
new_coverage.push (new_g);
+ hb_range ((unsigned) classCount)
| hb_filter (klass_mapping)
| hb_map ([&] (const unsigned col) { return row * (unsigned) classCount + col; })
@ -216,6 +220,10 @@ struct MarkMarkPosFormat1_2
;
}
if (!new_coverage) return_trace (false);
if (!out->mark2Coverage.serialize_serialize (c->serializer, new_coverage.iter ()))
return_trace (false);
return_trace (out->mark2Array.serialize_subset (c, mark2Array, this,
mark2_iter.len (),
mark2_indexes.iter ()));

View file

@ -103,46 +103,29 @@ struct PairPosFormat1_3
const Coverage &get_coverage () const { return this+coverage; }
unsigned cache_cost () const
struct external_cache_t
{
return (this+coverage).cost ();
}
static void * cache_func (void *p, hb_ot_lookup_cache_op_t op)
hb_ot_layout_mapping_cache_t coverage;
};
void *external_cache_create () const
{
switch (op)
external_cache_t *cache = (external_cache_t *) hb_malloc (sizeof (external_cache_t));
if (likely (cache))
{
case hb_ot_lookup_cache_op_t::CREATE:
{
hb_ot_lookup_cache_t *cache = (hb_ot_lookup_cache_t *) hb_malloc (sizeof (hb_ot_lookup_cache_t));
if (likely (cache))
cache->clear ();
return cache;
}
case hb_ot_lookup_cache_op_t::ENTER:
return (void *) true;
case hb_ot_lookup_cache_op_t::LEAVE:
return nullptr;
case hb_ot_lookup_cache_op_t::DESTROY:
{
hb_ot_lookup_cache_t *cache = (hb_ot_lookup_cache_t *) p;
hb_free (cache);
return nullptr;
}
cache->coverage.clear ();
}
return nullptr;
return cache;
}
bool apply_cached (hb_ot_apply_context_t *c) const { return _apply (c, true); }
bool apply (hb_ot_apply_context_t *c) const { return _apply (c, false); }
bool _apply (hb_ot_apply_context_t *c, bool cached) const
bool apply (hb_ot_apply_context_t *c, void *external_cache) const
{
TRACE_APPLY (this);
hb_buffer_t *buffer = c->buffer;
#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE
hb_ot_lookup_cache_t *cache = cached ? (hb_ot_lookup_cache_t *) c->lookup_accel->cache : nullptr;
unsigned int index = (this+coverage).get_coverage (buffer->cur().codepoint, cache);
external_cache_t *cache = (external_cache_t *) external_cache;
unsigned int index = (this+coverage).get_coverage (buffer->cur().codepoint, cache ? &cache->coverage : nullptr);
#else
unsigned int index = (this+coverage).get_coverage (buffer->cur().codepoint);
#endif

View file

@ -123,56 +123,32 @@ struct PairPosFormat2_4 : ValueBase
const Coverage &get_coverage () const { return this+coverage; }
struct pair_pos_cache_t
struct external_cache_t
{
hb_ot_lookup_cache_t coverage;
hb_ot_lookup_cache_t first;
hb_ot_lookup_cache_t second;
hb_ot_layout_mapping_cache_t coverage;
hb_ot_layout_mapping_cache_t first;
hb_ot_layout_mapping_cache_t second;
};
unsigned cache_cost () const
void *external_cache_create () const
{
return (this+coverage).cost () + (this+classDef1).cost () + (this+classDef2).cost ();
}
static void * cache_func (void *p, hb_ot_lookup_cache_op_t op)
{
switch (op)
external_cache_t *cache = (external_cache_t *) hb_malloc (sizeof (external_cache_t));
if (likely (cache))
{
case hb_ot_lookup_cache_op_t::CREATE:
{
pair_pos_cache_t *cache = (pair_pos_cache_t *) hb_malloc (sizeof (pair_pos_cache_t));
if (likely (cache))
{
cache->coverage.clear ();
cache->first.clear ();
cache->second.clear ();
}
return cache;
}
case hb_ot_lookup_cache_op_t::ENTER:
return (void *) true;
case hb_ot_lookup_cache_op_t::LEAVE:
return nullptr;
case hb_ot_lookup_cache_op_t::DESTROY:
{
pair_pos_cache_t *cache = (pair_pos_cache_t *) p;
hb_free (cache);
return nullptr;
}
cache->coverage.clear ();
cache->first.clear ();
cache->second.clear ();
}
return nullptr;
return cache;
}
bool apply_cached (hb_ot_apply_context_t *c) const { return _apply (c, true); }
bool apply (hb_ot_apply_context_t *c) const { return _apply (c, false); }
bool _apply (hb_ot_apply_context_t *c, bool cached) const
bool apply (hb_ot_apply_context_t *c, void *external_cache) const
{
TRACE_APPLY (this);
hb_buffer_t *buffer = c->buffer;
#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE
pair_pos_cache_t *cache = cached ? (pair_pos_cache_t *) c->lookup_accel->cache : nullptr;
external_cache_t *cache = (external_cache_t *) external_cache;
unsigned int index = (this+coverage).get_coverage (buffer->cur().codepoint, cache ? &cache->coverage : nullptr);
#else
unsigned int index = (this+coverage).get_coverage (buffer->cur().codepoint);

View file

@ -58,7 +58,12 @@ struct ValueFormat : HBUINT16
NumType& operator = (uint16_t i) { v = i; return *this; }
unsigned int get_len () const { return hb_popcount ((unsigned int) *this); }
// Note: spec says skip 2 bytes per bit in the valueformat. But reports
// from Microsoft developers indicate that only the fields that are
// currently defined are counted. We don't expect any new fields to
// be added to ValueFormat. As such, we use the faster hb_popcount8
// that only processes the lowest 8 bits.
unsigned int get_len () const { return hb_popcount8 ((uint8_t) *this); }
unsigned int get_size () const { return get_len () * Value::static_size; }
hb_vector_t<unsigned> get_device_table_indices () const {

View file

@ -91,6 +91,19 @@ struct AlternateSet
return alternates.len;
}
void
collect_alternates (hb_codepoint_t gid,
hb_map_t *alternate_count /* IN/OUT */,
hb_map_t *alternate_glyphs /* IN/OUT */) const
{
+ hb_enumerate (alternates)
| hb_map ([gid] (hb_pair_t<unsigned, hb_codepoint_t> _) { return hb_pair (gid + (_.first << 24), _.second); })
| hb_apply ([&] (const hb_pair_t<hb_codepoint_t, hb_codepoint_t> &p) -> void
{ _hb_collect_glyph_alternates_add (p.first, p.second,
alternate_count, alternate_glyphs); })
;
}
template <typename Iterator,
hb_requires (hb_is_source_of (Iterator, hb_codepoint_t))>
bool serialize (hb_serialize_context_t *c,

View file

@ -69,6 +69,19 @@ struct AlternateSubstFormat1_2
{ return (this+alternateSet[(this+coverage).get_coverage (gid)])
.get_alternates (start_offset, alternate_count, alternate_glyphs); }
void
collect_glyph_alternates (hb_map_t *alternate_count /* IN/OUT */,
hb_map_t *alternate_glyphs /* IN/OUT */) const
{
+ hb_iter (alternateSet)
| hb_map (hb_add (this))
| hb_zip (this+coverage)
| hb_apply ([&] (const hb_pair_t<const AlternateSet<Types> &, hb_codepoint_t> _) {
_.first.collect_alternates (_.second, alternate_count, alternate_glyphs);
})
;
}
bool apply (hb_ot_apply_context_t *c) const
{
TRACE_APPLY (this);

View file

@ -44,6 +44,18 @@ struct Ligature
c->output->add (ligGlyph);
}
template <typename set_t>
void collect_second (set_t &s) const
{
if (unlikely (!component.get_length ()))
{
// A ligature without any components. Anything matches.
s = set_t::full ();
return;
}
s.add (component.arrayZ[0]);
}
bool would_apply (hb_would_apply_context_t *c) const
{
if (c->len != component.lenP1)
@ -91,15 +103,6 @@ struct Ligature
unsigned int total_component_count = 0;
if (unlikely (count > HB_MAX_CONTEXT_LENGTH)) return false;
unsigned match_positions_stack[4];
unsigned *match_positions = match_positions_stack;
if (unlikely (count > ARRAY_LENGTH (match_positions_stack)))
{
match_positions = (unsigned *) hb_malloc (hb_max (count, 1u) * sizeof (unsigned));
if (unlikely (!match_positions))
return_trace (false);
}
unsigned int match_end = 0;
if (likely (!match_input (c, count,
@ -107,12 +110,9 @@ struct Ligature
match_glyph,
nullptr,
&match_end,
match_positions,
&total_component_count)))
{
c->buffer->unsafe_to_concat (c->buffer->idx, match_end);
if (match_positions != match_positions_stack)
hb_free (match_positions);
return_trace (false);
}
@ -129,10 +129,10 @@ struct Ligature
match_end += delta;
for (unsigned i = 0; i < count; i++)
{
match_positions[i] += delta;
c->match_positions[i] += delta;
if (i)
*p++ = ',';
snprintf (p, sizeof(buf) - (p - buf), "%u", match_positions[i]);
snprintf (p, sizeof(buf) - (p - buf), "%u", c->match_positions[i]);
p += strlen(p);
}
@ -143,7 +143,6 @@ struct Ligature
ligate_input (c,
count,
match_positions,
match_end,
ligGlyph,
total_component_count);
@ -156,8 +155,6 @@ struct Ligature
pos);
}
if (match_positions != match_positions_stack)
hb_free (match_positions);
return_trace (true);
}

View file

@ -62,6 +62,15 @@ struct LigatureSet
;
}
template <typename set_t>
void collect_seconds (set_t &s) const
{
+ hb_iter (ligature)
| hb_map (hb_add (this))
| hb_apply ([&s] (const Ligature<Types> &_) { _.collect_second (s); })
;
}
bool would_apply (hb_would_apply_context_t *c) const
{
return
@ -72,14 +81,14 @@ struct LigatureSet
;
}
bool apply (hb_ot_apply_context_t *c) const
bool apply (hb_ot_apply_context_t *c, const hb_set_digest_t *seconds = nullptr) const
{
TRACE_APPLY (this);
unsigned int num_ligs = ligature.len;
#ifndef HB_NO_OT_RULESETS_FAST_PATH
if (HB_OPTIMIZE_SIZE_VAL || num_ligs <= 4)
if (HB_OPTIMIZE_SIZE_VAL || num_ligs <= 1)
#endif
{
slow:
@ -91,7 +100,7 @@ struct LigatureSet
return_trace (false);
}
/* This version is optimized for speed by matching the first component
/* This version is optimized for speed by matching the second component
* of the ligature here, instead of calling into the ligation code.
*
* This is replicated in ChainRuleSet and RuleSet. */
@ -101,11 +110,11 @@ struct LigatureSet
skippy_iter.set_match_func (match_always, nullptr);
skippy_iter.set_glyph_data ((HBUINT16 *) nullptr);
unsigned unsafe_to;
hb_codepoint_t first = (unsigned) -1;
hb_codepoint_t second = (unsigned) -1;
bool matched = skippy_iter.next (&unsafe_to);
if (likely (matched))
{
first = c->buffer->info[skippy_iter.idx].codepoint;
second = c->buffer->info[skippy_iter.idx].codepoint;
unsafe_to = skippy_iter.idx + 1;
if (skippy_iter.may_skip (c->buffer->info[skippy_iter.idx]))
@ -118,13 +127,14 @@ struct LigatureSet
else
goto slow;
if (seconds && !seconds->may_have (second))
return_trace (false);
bool unsafe_to_concat = false;
for (unsigned int i = 0; i < num_ligs; i++)
{
const auto &lig = this+ligature.arrayZ[i];
if (unlikely (lig.component.lenP1 <= 1) ||
lig.component.arrayZ[0] == first)
lig.component.arrayZ[0] == second)
{
if (lig.apply (c))
{

View file

@ -78,52 +78,44 @@ struct LigatureSubstFormat1_2
return lig_set.would_apply (c);
}
unsigned cache_cost () const
struct external_cache_t
{
return (this+coverage).cost ();
}
static void * cache_func (void *p, hb_ot_lookup_cache_op_t op)
hb_ot_layout_mapping_cache_t coverage;
hb_set_digest_t seconds;
};
void *external_cache_create () const
{
switch (op)
external_cache_t *cache = (external_cache_t *) hb_malloc (sizeof (external_cache_t));
if (likely (cache))
{
case hb_ot_lookup_cache_op_t::CREATE:
{
hb_ot_lookup_cache_t *cache = (hb_ot_lookup_cache_t *) hb_malloc (sizeof (hb_ot_lookup_cache_t));
if (likely (cache))
cache->clear ();
return cache;
}
case hb_ot_lookup_cache_op_t::ENTER:
return (void *) true;
case hb_ot_lookup_cache_op_t::LEAVE:
return nullptr;
case hb_ot_lookup_cache_op_t::DESTROY:
{
hb_ot_lookup_cache_t *cache = (hb_ot_lookup_cache_t *) p;
hb_free (cache);
return nullptr;
}
cache->coverage.clear ();
cache->seconds.init ();
+ hb_iter (ligatureSet)
| hb_map (hb_add (this))
| hb_apply ([cache] (const LigatureSet<Types> &_) { _.collect_seconds (cache->seconds); })
;
}
return nullptr;
return cache;
}
bool apply_cached (hb_ot_apply_context_t *c) const { return _apply (c, true); }
bool apply (hb_ot_apply_context_t *c) const { return _apply (c, false); }
bool _apply (hb_ot_apply_context_t *c, bool cached) const
bool apply (hb_ot_apply_context_t *c, void *external_cache) const
{
TRACE_APPLY (this);
hb_buffer_t *buffer = c->buffer;
#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE
hb_ot_lookup_cache_t *cache = cached ? (hb_ot_lookup_cache_t *) c->lookup_accel->cache : nullptr;
unsigned int index = (this+coverage).get_coverage (buffer->cur().codepoint, cache);
external_cache_t *cache = (external_cache_t *) external_cache;
const hb_set_digest_t *seconds = cache ? &cache->seconds : nullptr;
unsigned int index = (this+coverage).get_coverage (buffer->cur().codepoint, cache ? &cache->coverage : nullptr);
#else
const hb_set_digest_t *seconds = nullptr;
unsigned int index = (this+coverage).get_coverage (buffer->cur().codepoint);
#endif
if (index == NOT_COVERED) return_trace (false);
const auto &lig_set = this+ligatureSet[index];
return_trace (lig_set.apply (c));
return_trace (lig_set.apply (c, seconds));
}
bool serialize (hb_serialize_context_t *c,

View file

@ -123,6 +123,21 @@ struct SingleSubstFormat1_3
return 1;
}
void
collect_glyph_alternates (hb_map_t *alternate_count /* IN/OUT */,
hb_map_t *alternate_glyphs /* IN/OUT */) const
{
hb_codepoint_t d = deltaGlyphID;
hb_codepoint_t mask = get_mask ();
+ hb_iter (this+coverage)
| hb_map ([d, mask] (hb_codepoint_t g) { return hb_pair (g, (g + d) & mask); })
| hb_apply ([&] (const hb_pair_t<hb_codepoint_t, hb_codepoint_t> &p) -> void
{ _hb_collect_glyph_alternates_add (p.first, p.second,
alternate_count, alternate_glyphs); })
;
}
bool apply (hb_ot_apply_context_t *c) const
{
TRACE_APPLY (this);

View file

@ -100,6 +100,17 @@ struct SingleSubstFormat2_4
return 1;
}
void
collect_glyph_alternates (hb_map_t *alternate_count /* IN/OUT */,
hb_map_t *alternate_glyphs /* IN/OUT */) const
{
+ hb_zip (this+coverage, substitute)
| hb_apply ([&] (const hb_pair_t<hb_codepoint_t, hb_codepoint_t> &p) -> void
{ _hb_collect_glyph_alternates_add (p.first, p.second,
alternate_count, alternate_glyphs); })
;
}
bool apply (hb_ot_apply_context_t *c) const
{
TRACE_APPLY (this);

View file

@ -29,8 +29,8 @@
#ifndef OT_LAYOUT_TYPES_HH
#define OT_LAYOUT_TYPES_HH
using hb_ot_lookup_cache_t = hb_cache_t<15, 8, 7>;
static_assert (sizeof (hb_ot_lookup_cache_t) == 256, "");
using hb_ot_layout_mapping_cache_t = hb_cache_t<15, 8, 7>;
static_assert (sizeof (hb_ot_layout_mapping_cache_t) == 256, "");
namespace OT {
namespace Layout {

View file

@ -11,6 +11,8 @@ namespace OT {
//namespace Var {
#ifndef HB_NO_DRAW
struct hb_transforming_pen_context_t
{
hb_transform_t<> transform;
@ -411,6 +413,8 @@ VARC::get_path_at (const hb_varc_context_t &c,
return true;
}
#endif
//} // namespace Var
} // namespace OT

View file

@ -194,6 +194,7 @@ struct VARC
hb_codepoint_t gid,
hb_glyph_extents_t *extents) const
{
#ifndef HB_NO_DRAW
if (!table->has_data ()) return false;
hb_extents_t<> f_extents;
@ -207,6 +208,9 @@ struct VARC
*extents = f_extents.to_glyph_extents (font->x_scale < 0, font->y_scale < 0);
return ret;
#else
return false;
#endif
}
private:

View file

@ -533,7 +533,11 @@ struct Glyph
bool get_extents_without_var_scaled (hb_font_t *font, const glyf_accelerator_t &glyf_accelerator,
hb_glyph_extents_t *extents) const
{
if (type == EMPTY) return true; /* Empty glyph; zero extents. */
if (type == EMPTY)
{
*extents = {0, 0, 0, 0};
return true; /* Empty glyph; zero extents. */
}
return header->get_extents_without_var_scaled (font, glyf_accelerator, gid, extents);
}

View file

@ -189,7 +189,7 @@ struct SimpleGlyph
unsigned old_length = points.length;
points.alloc (points.length + num_points + 4); // Allocate for phantom points, to avoid a possible copy
if (unlikely (!points.resize (points.length + num_points, false))) return false;
if (unlikely (!points.resize_dirty (points.length + num_points))) return false;
auto points_ = points.as_array ().sub_array (old_length);
if (!phantom_only)
hb_memset (points_.arrayZ, 0, sizeof (contour_point_t) * num_points);

View file

@ -445,8 +445,7 @@ struct glyf_accelerator_t
if (coords)
{
hb_glyf_scratch_t *scratch = acquire_scratch ();
if (unlikely (!scratch))
return false;
if (unlikely (!scratch)) return false;
bool ret = get_points (font,
gid,
points_aggregator_t (font, extents, nullptr, true),
@ -493,8 +492,7 @@ struct glyf_accelerator_t
if (!has_data ()) return false;
hb_glyf_scratch_t *scratch = acquire_scratch ();
if (unlikely (!scratch))
return true;
if (unlikely (!scratch)) return true;
bool ret = get_points (font, gid, glyf_impl::path_builder_t (font, draw_session),
hb_array (font->coords,
@ -523,6 +521,7 @@ struct glyf_accelerator_t
hb_glyf_scratch_t *acquire_scratch () const
{
if (!has_data ()) return nullptr;
hb_glyf_scratch_t *scratch = cached_scratch.get_acquire ();
if (!scratch || unlikely (!cached_scratch.cmpexch (scratch, nullptr)))
{
@ -534,6 +533,8 @@ struct glyf_accelerator_t
}
void release_scratch (hb_glyf_scratch_t *scratch) const
{
if (!scratch)
return;
if (!cached_scratch.cmpexch (nullptr, scratch))
{
scratch->~hb_glyf_scratch_t ();

View file

@ -470,8 +470,12 @@ struct graph_t
num_roots_for_space_.push (1);
bool removed_nil = false;
vertices_.alloc (objects.length);
vertices_scratch_.alloc (objects.length);
ordering_.resize (objects.length);
ordering_scratch_.alloc (objects.length);
unsigned count = objects.length;
unsigned order = objects.length;
unsigned skip = 0;
for (unsigned i = 0; i < count; i++)
{
// If this graph came from a serialization buffer object 0 is the
@ -479,6 +483,9 @@ struct graph_t
if (i == 0 && !objects.arrayZ[i])
{
removed_nil = true;
order--;
ordering_.resize(objects.length - 1);
skip++;
continue;
}
@ -488,6 +495,12 @@ struct graph_t
check_success (v->link_positions_valid (count, removed_nil));
// To start we set the ordering to match the provided objects
// list. Note: objects are provided to us in reverse order (ie.
// the last object is the root).
unsigned obj_idx = i - skip;
ordering_[--order] = obj_idx;
if (!removed_nil) continue;
// Fix indices to account for removed nil object.
for (auto& l : v->obj.all_links_writer ()) {
@ -508,10 +521,10 @@ struct graph_t
}
void print () const {
for (int i = vertices_.length - 1; i >= 0; i--)
for (unsigned id : ordering_)
{
const auto& v = vertices_[i];
printf("%d: %u [", i, (unsigned int)v.table_size());
const auto& v = vertices_[id];
printf("%u: %u [", id, (unsigned int)v.table_size());
for (const auto &l : v.obj.real_links) {
printf("%u, ", l.objidx);
}
@ -533,6 +546,7 @@ struct graph_t
{
return !successful ||
vertices_.in_error () ||
ordering_.in_error() ||
num_roots_for_space_.in_error ();
}
@ -543,10 +557,10 @@ struct graph_t
unsigned root_idx () const
{
// Object graphs are in reverse order, the first object is at the end
// of the vector. Since the graph is topologically sorted it's safe to
// First element of ordering_ is the root.
// Since the graph is topologically sorted it's safe to
// assume the first object has no incoming edges.
return vertices_.length - 1;
return ordering_[0];
}
const hb_serialize_context_t::object_t& object (unsigned i) const
@ -604,55 +618,51 @@ struct graph_t
hb_priority_queue_t<int64_t> queue;
queue.alloc (vertices_.length);
hb_vector_t<vertex_t> &sorted_graph = vertices_scratch_;
if (unlikely (!check_success (sorted_graph.resize (vertices_.length)))) return;
hb_vector_t<unsigned> id_map;
if (unlikely (!check_success (id_map.resize (vertices_.length)))) return;
hb_vector_t<unsigned> &new_ordering = ordering_scratch_;
if (unlikely (!check_success (new_ordering.resize (vertices_.length)))) return;
hb_vector_t<unsigned> removed_edges;
if (unlikely (!check_success (removed_edges.resize (vertices_.length)))) return;
update_parents ();
queue.insert (root ().modified_distance (0), root_idx ());
int new_id = root_idx ();
unsigned order = 1;
unsigned pos = 0;
while (!queue.in_error () && !queue.is_empty ())
{
unsigned next_id = queue.pop_minimum().second;
sorted_graph[new_id] = std::move (vertices_[next_id]);
const vertex_t& next = sorted_graph[new_id];
if (unlikely (!check_success(new_id >= 0))) {
if (unlikely (!check_success(pos < new_ordering.length))) {
// We are out of ids. Which means we've visited a node more than once.
// This graph contains a cycle which is not allowed.
DEBUG_MSG (SUBSET_REPACK, nullptr, "Invalid graph. Contains cycle.");
return;
}
id_map[next_id] = new_id--;
new_ordering[pos++] = next_id;
const vertex_t& next = vertices_[next_id];
for (const auto& link : next.obj.all_links ()) {
removed_edges[link.objidx]++;
if (!(vertices_[link.objidx].incoming_edges () - removed_edges[link.objidx]))
const auto& v = vertices_[link.objidx];
if (!(v.incoming_edges () - removed_edges[link.objidx]))
// Add the order that the links were encountered to the priority.
// This ensures that ties between priorities objects are broken in a consistent
// way. More specifically this is set up so that if a set of objects have the same
// distance they'll be added to the topological order in the order that they are
// referenced from the parent object.
queue.insert (vertices_[link.objidx].modified_distance (order++),
queue.insert (v.modified_distance (order++),
link.objidx);
}
}
check_success (!queue.in_error ());
check_success (!sorted_graph.in_error ());
check_success (!new_ordering.in_error ());
check_success (remap_all_obj_indices (id_map, &sorted_graph));
vertices_ = std::move (sorted_graph);
hb_swap (ordering_, new_ordering);
if (!check_success (new_id == -1))
if (!check_success (pos == vertices_.length)) {
print_orphaned_nodes ();
}
}
/*
@ -662,8 +672,8 @@ struct graph_t
*/
void find_space_roots (hb_set_t& visited, hb_set_t& roots)
{
int root_index = (int) root_idx ();
for (int i = root_index; i >= 0; i--)
unsigned root_index = root_idx ();
for (unsigned i : ordering_)
{
if (visited.has (i)) continue;
@ -846,7 +856,6 @@ struct graph_t
if (subgraph.in_error ())
return false;
unsigned original_root_idx = root_idx ();
hb_map_t index_map;
bool made_changes = false;
for (auto entry : subgraph.iter ())
@ -869,14 +878,6 @@ struct graph_t
if (!made_changes)
return false;
if (original_root_idx != root_idx ()
&& parents.has (original_root_idx))
{
// If the root idx has changed since parents was determined, update root idx in parents
parents.add (root_idx ());
parents.del (original_root_idx);
}
auto new_subgraph =
+ subgraph.keys ()
| hb_map([&] (uint32_t node_idx) {
@ -965,9 +966,9 @@ struct graph_t
*/
template<typename O>
unsigned move_child (unsigned old_parent_idx,
const O* old_offset,
unsigned new_parent_idx,
const O* new_offset)
const O* old_offset,
unsigned new_parent_idx,
const O* new_offset)
{
distance_invalid = true;
positions_invalid = true;
@ -992,6 +993,50 @@ struct graph_t
return child_id;
}
/*
* Moves all outgoing links in old parent that have
* a link position between [old_post_start, old_pos_end)
* to the new parent. Links are placed serially in the new
* parent starting at new_pos_start.
*/
template<typename O>
void move_children (unsigned old_parent_idx,
unsigned old_pos_start,
unsigned old_pos_end,
unsigned new_parent_idx,
unsigned new_pos_start)
{
distance_invalid = true;
positions_invalid = true;
auto& old_v = vertices_[old_parent_idx];
auto& new_v = vertices_[new_parent_idx];
hb_vector_t<hb_serialize_context_t::object_t::link_t> old_links;
for (const auto& l : old_v.obj.real_links)
{
if (l.position < old_pos_start || l.position >= old_pos_end)
{
old_links.push(l);
continue;
}
unsigned array_pos = l.position - old_pos_start;
unsigned child_id = l.objidx;
auto* new_link = new_v.obj.real_links.push ();
new_link->width = O::static_size;
new_link->objidx = child_id;
new_link->position = new_pos_start + array_pos;
auto& child = vertices_[child_id];
child.add_parent (new_parent_idx, false);
child.remove_parent (old_parent_idx);
}
old_v.obj.real_links = std::move (old_links);
}
/*
* duplicates all nodes in the subgraph reachable from node_idx. Does not re-assign
* links. index_map is updated with mappings from old id to new id. If a duplication has already
@ -1021,8 +1066,11 @@ struct graph_t
distance_invalid = true;
auto* clone = vertices_.push ();
unsigned clone_idx = vertices_.length - 1;
ordering_.push(clone_idx);
auto& child = vertices_[node_idx];
if (vertices_.in_error ()) {
if (vertices_.in_error () || ordering_.in_error()) {
return -1;
}
@ -1032,7 +1080,6 @@ struct graph_t
clone->space = child.space;
clone->reset_parents ();
unsigned clone_idx = vertices_.length - 2;
for (const auto& l : child.obj.real_links)
{
clone->obj.real_links.push (l);
@ -1047,15 +1094,6 @@ struct graph_t
check_success (!clone->obj.real_links.in_error ());
check_success (!clone->obj.virtual_links.in_error ());
// The last object is the root of the graph, so swap back the root to the end.
// The root's obj idx does change, however since it's root nothing else refers to it.
// all other obj idx's will be unaffected.
hb_swap (vertices_[vertices_.length - 2], *clone);
// Since the root moved, update the parents arrays of all children on the root.
for (const auto& l : root ().obj.all_links ())
vertices_[l.objidx].remap_parent (root_idx () - 1, root_idx ());
return clone_idx;
}
@ -1205,7 +1243,10 @@ struct graph_t
distance_invalid = true;
auto* clone = vertices_.push ();
if (vertices_.in_error ()) {
unsigned clone_idx = vertices_.length - 1;
ordering_.push(clone_idx);
if (vertices_.in_error () || ordering_.in_error()) {
return -1;
}
@ -1214,17 +1255,6 @@ struct graph_t
clone->distance = 0;
clone->space = 0;
unsigned clone_idx = vertices_.length - 2;
// The last object is the root of the graph, so swap back the root to the end.
// The root's obj idx does change, however since it's root nothing else refers to it.
// all other obj idx's will be unaffected.
hb_swap (vertices_[vertices_.length - 2], *clone);
// Since the root moved, update the parents arrays of all children on the root.
for (const auto& l : root ().obj.all_links ())
vertices_[l.objidx].remap_parent (root_idx () - 1, root_idx ());
return clone_idx;
}
@ -1386,7 +1416,8 @@ struct graph_t
size_t total_size = 0;
unsigned count = vertices_.length;
for (unsigned i = 0; i < count; i++) {
size_t size = vertices_.arrayZ[i].obj.tail - vertices_.arrayZ[i].obj.head;
const auto& obj = vertices_.arrayZ[i].obj;
size_t size = obj.tail - obj.head;
total_size += size;
}
return total_size;
@ -1459,7 +1490,7 @@ struct graph_t
if (!positions_invalid) return;
unsigned current_pos = 0;
for (int i = root_idx (); i >= 0; i--)
for (unsigned i : ordering_)
{
auto& v = vertices_[i];
v.start = current_pos;
@ -1491,11 +1522,11 @@ struct graph_t
unsigned count = vertices_.length;
for (unsigned i = 0; i < count; i++)
vertices_.arrayZ[i].distance = hb_int_max (int64_t);
vertices_.tail ().distance = 0;
vertices_[root_idx ()].distance = 0;
hb_priority_queue_t<int64_t> queue;
queue.alloc (count);
queue.insert (0, vertices_.length - 1);
queue.insert (0, root_idx ());
hb_vector_t<bool> visited;
visited.resize (vertices_.length);
@ -1505,22 +1536,23 @@ struct graph_t
unsigned next_idx = queue.pop_minimum ().second;
if (visited[next_idx]) continue;
const auto& next = vertices_[next_idx];
int64_t next_distance = vertices_[next_idx].distance;
int64_t next_distance = next.distance;
visited[next_idx] = true;
for (const auto& link : next.obj.all_links ())
{
if (visited[link.objidx]) continue;
const auto& child = vertices_.arrayZ[link.objidx].obj;
auto& child_v = vertices_.arrayZ[link.objidx];
const auto& child = child_v.obj;
unsigned link_width = link.width ? link.width : 4; // treat virtual offsets as 32 bits wide
int64_t child_weight = (child.tail - child.head) +
((int64_t) 1 << (link_width * 8)) * (vertices_.arrayZ[link.objidx].space + 1);
((int64_t) 1 << (link_width * 8)) * (child_v.space + 1);
int64_t child_distance = next_distance + child_weight;
if (child_distance < vertices_.arrayZ[link.objidx].distance)
if (child_distance < child_v.distance)
{
vertices_.arrayZ[link.objidx].distance = child_distance;
child_v.distance = child_distance;
queue.insert (child_distance, link.objidx);
}
}
@ -1563,9 +1595,10 @@ struct graph_t
if (!id_map) return;
for (unsigned i : subgraph)
{
unsigned num_real = vertices_[i].obj.real_links.length;
auto& obj = vertices_[i].obj;
unsigned num_real = obj.real_links.length;
unsigned count = 0;
for (auto& link : vertices_[i].obj.all_links_writer ())
for (auto& link : obj.all_links_writer ())
{
count++;
const uint32_t *v;
@ -1577,25 +1610,6 @@ struct graph_t
}
}
/*
* Updates all objidx's in all links using the provided mapping.
*/
bool remap_all_obj_indices (const hb_vector_t<unsigned>& id_map,
hb_vector_t<vertex_t>* sorted_graph) const
{
unsigned count = sorted_graph->length;
for (unsigned i = 0; i < count; i++)
{
if (!(*sorted_graph)[i].remap_parents (id_map))
return false;
for (auto& link : sorted_graph->arrayZ[i].obj.all_links_writer ())
{
link.objidx = id_map[link.objidx];
}
}
return true;
}
/*
* Finds all nodes in targets that are reachable from start_idx, nodes in visited will be skipped.
* For this search the graph is treated as being undirected.
@ -1631,7 +1645,16 @@ struct graph_t
public:
// TODO(garretrieger): make private, will need to move most of offset overflow code into graph.
hb_vector_t<vertex_t> vertices_;
hb_vector_t<vertex_t> vertices_scratch_;
// Specifies the current topological ordering of this graph
//
// ordering_[pos] = obj index
//
// specifies that the 'pos'th spot is filled by the object
// given by obj index.
hb_vector_t<unsigned> ordering_;
hb_vector_t<unsigned> ordering_scratch_;
private:
bool parents_invalid;
bool distance_invalid;

View file

@ -87,6 +87,12 @@ struct Lookup : public OT::Lookup
return lookupType == extension_type (table_tag);
}
bool use_mark_filtering_set () const
{
unsigned flag = lookupFlag;
return flag & 0x0010u;
}
bool make_extension (gsubgpos_graph_context_t& c,
unsigned this_index)
{
@ -220,6 +226,9 @@ struct Lookup : public OT::Lookup
}
hb_memcpy (buffer, v->obj.head, v->table_size());
if (use_mark_filtering_set ())
hb_memcpy (buffer + new_size - 2, v->obj.tail - 2, 2);
v->obj.head = buffer;
v->obj.tail = buffer + new_size;

View file

@ -105,6 +105,23 @@ struct LigatureSubstFormat1 : public OT::Layout::GSUB_impl::LigatureSubstFormat1
return result;
}
hb_vector_t<unsigned> ligature_index_to_object_id(const graph_t::vertex_and_table_t<LigatureSet>& liga_set) const {
hb_vector_t<unsigned> map;
map.resize_exact(liga_set.table->ligature.len);
if (map.in_error()) return map;
for (unsigned i = 0; i < map.length; i++) {
map[i] = (unsigned) -1;
}
for (const auto& l : liga_set.vertex->obj.real_links) {
if (l.position < 2) continue;
unsigned array_index = (l.position - 2) / 2;
map[array_index] = l.objidx;
}
return map;
}
hb_vector_t<unsigned> compute_split_points(gsubgpos_graph_context_t& c,
unsigned parent_index,
unsigned this_index) const
@ -128,9 +145,16 @@ struct LigatureSubstFormat1 : public OT::Layout::GSUB_impl::LigatureSubstFormat1
return hb_vector_t<unsigned> {};
}
// Finding the object id associated with an array index is O(n)
// so to avoid O(n^2), precompute the mapping by scanning through
// all links
auto index_to_id = ligature_index_to_object_id(liga_set);
if (index_to_id.in_error()) return hb_vector_t<unsigned>();
for (unsigned j = 0; j < liga_set.table->ligature.len; j++)
{
const unsigned liga_id = c.graph.index_for_offset (liga_set.index, &liga_set.table->ligature[j]);
const unsigned liga_id = index_to_id[j];
if (liga_id == (unsigned) -1) continue; // no outgoing link, ignore
const unsigned liga_size = c.graph.vertices_[liga_id].table_size ();
accumulated += OT::HBUINT16::static_size; // for ligature offset
@ -154,7 +178,6 @@ struct LigatureSubstFormat1 : public OT::Layout::GSUB_impl::LigatureSubstFormat1
return split_points;
}
struct split_context_t
{
gsubgpos_graph_context_t& c;
@ -323,19 +346,19 @@ struct LigatureSubstFormat1 : public OT::Layout::GSUB_impl::LigatureSubstFormat1
{
// This liga set partially overlaps [start, end). We'll need to create
// a new liga set sub table and move the intersecting ligas to it.
unsigned liga_count = hb_min(end, current_end) - hb_max(start, current_start);
unsigned start_index = hb_max(start, current_start) - count;
unsigned end_index = hb_min(end, current_end) - count;
unsigned liga_count = end_index - start_index;
auto result = new_liga_set(c, liga_count);
liga_set_prime_id = result.first;
LigatureSet* prime = result.second;
if (liga_set_prime_id == (unsigned) -1) return -1;
unsigned new_index = 0;
for (unsigned j = hb_max(start, current_start) - count; j < hb_min(end, current_end) - count; j++) {
c.graph.move_child<> (liga_set_index,
&liga_set.table->ligature[j],
liga_set_prime_id,
&prime->ligature[new_index++]);
}
c.graph.move_children<OT::Offset16>(
liga_set_index,
2 + start_index * 2,
2 + end_index * 2,
liga_set_prime_id,
2);
liga_set_end = i;
if (i < liga_set_start) liga_set_start = i;
@ -392,8 +415,12 @@ struct LigatureSubstFormat1 : public OT::Layout::GSUB_impl::LigatureSubstFormat1
// duplicated. Code later on will re-add the virtual links as needed (via retained_indices).
clear_virtual_links(c, liga_set.index);
retained_indices.add(liga_set.index);
for (const auto& liga_offset : liga_set.table->ligature) {
unsigned liga_index = c.graph.index_for_offset(liga_set.index, &liga_offset);
auto index_to_id = ligature_index_to_object_id(liga_set);
if (index_to_id.in_error()) return false;
for (unsigned i = 0; i < liga_set.table->ligature.len; i++) {
unsigned liga_index = index_to_id[i];
if (liga_index != (unsigned) -1) {
clear_virtual_links(c, liga_index);
retained_indices.add(liga_index);

View file

@ -113,7 +113,7 @@ will_overflow (graph_t& graph,
hb_hashmap_t<overflow_record_t*, bool> record_set;
const auto& vertices = graph.vertices_;
for (int parent_idx = vertices.length - 1; parent_idx >= 0; parent_idx--)
for (unsigned parent_idx : graph.ordering_)
{
// Don't need to check virtual links for overflow
for (const auto& link : vertices.arrayZ[parent_idx].obj.real_links)
@ -173,6 +173,7 @@ template <typename O> inline void
serialize_link_of_type (const hb_serialize_context_t::object_t::link_t& link,
char* head,
unsigned size,
const hb_vector_t<unsigned>& id_map,
hb_serialize_context_t* c)
{
assert(link.position + link.width <= size);
@ -180,9 +181,7 @@ serialize_link_of_type (const hb_serialize_context_t::object_t::link_t& link,
OT::Offset<O>* offset = reinterpret_cast<OT::Offset<O>*> (head + link.position);
*offset = 0;
c->add_link (*offset,
// serializer has an extra nil object at the start of the
// object array. So all id's are +1 of what our id's are.
link.objidx + 1,
id_map[link.objidx],
(hb_serialize_context_t::whence_t) link.whence,
link.bias);
}
@ -191,6 +190,7 @@ inline
void serialize_link (const hb_serialize_context_t::object_t::link_t& link,
char* head,
unsigned size,
const hb_vector_t<unsigned>& id_map,
hb_serialize_context_t* c)
{
switch (link.width)
@ -201,21 +201,21 @@ void serialize_link (const hb_serialize_context_t::object_t::link_t& link,
case 4:
if (link.is_signed)
{
serialize_link_of_type<OT::HBINT32> (link, head, size, c);
serialize_link_of_type<OT::HBINT32> (link, head, size, id_map, c);
} else {
serialize_link_of_type<OT::HBUINT32> (link, head, size, c);
serialize_link_of_type<OT::HBUINT32> (link, head, size, id_map, c);
}
return;
case 2:
if (link.is_signed)
{
serialize_link_of_type<OT::HBINT16> (link, head, size, c);
serialize_link_of_type<OT::HBINT16> (link, head, size, id_map, c);
} else {
serialize_link_of_type<OT::HBUINT16> (link, head, size, c);
serialize_link_of_type<OT::HBUINT16> (link, head, size, id_map, c);
}
return;
case 3:
serialize_link_of_type<OT::HBUINT24> (link, head, size, c);
serialize_link_of_type<OT::HBUINT24> (link, head, size, id_map, c);
return;
default:
// Unexpected link width.
@ -241,25 +241,36 @@ inline hb_blob_t* serialize (const graph_t& graph)
c.start_serialize<void> ();
const auto& vertices = graph.vertices_;
for (unsigned i = 0; i < vertices.length; i++) {
// Objects are placed in the serializer in reverse order since children need
// to be inserted before their parents.
// Maps from our obj id's to the id's used during this serialization.
hb_vector_t<unsigned> id_map;
id_map.resize(graph.ordering_.length);
for (int pos = graph.ordering_.length - 1; pos >= 0; pos--) {
unsigned i = graph.ordering_[pos];
c.push ();
size_t size = vertices[i].obj.tail - vertices[i].obj.head;
auto& v = vertices[i];
size_t size = v.obj.tail - v.obj.head;
char* start = c.allocate_size <char> (size);
if (!start) {
DEBUG_MSG (SUBSET_REPACK, nullptr, "Buffer out of space.");
return nullptr;
}
hb_memcpy (start, vertices[i].obj.head, size);
hb_memcpy (start, v.obj.head, size);
// Only real links needs to be serialized.
for (const auto& link : vertices[i].obj.real_links)
serialize_link (link, start, size, &c);
for (const auto& link : v.obj.real_links)
serialize_link (link, start, size, id_map, &c);
// All duplications are already encoded in the graph, so don't
// enable sharing during packing.
c.pop_pack (false);
id_map[i] = c.pop_pack (false);
}
c.end_serialize ();

View file

@ -47,8 +47,7 @@ using namespace OT;
struct ankr;
using hb_aat_class_cache_t = hb_cache_t<15, 8, 7>;
static_assert (sizeof (hb_aat_class_cache_t) == 256, "");
using hb_aat_class_cache_t = hb_ot_layout_mapping_cache_t;
struct hb_aat_scratch_t
{
@ -79,7 +78,10 @@ struct hb_aat_scratch_t
{
hb_bit_set_t *s = buffer_glyph_set.get_acquire ();
if (s && buffer_glyph_set.cmpexch (s, nullptr))
{
s->clear ();
return s;
}
s = (hb_bit_set_t *) hb_calloc (1, sizeof (hb_bit_set_t));
if (unlikely (!s))
@ -124,13 +126,14 @@ struct hb_aat_apply_context_t :
const OT::GDEF &gdef;
bool has_glyph_classes;
const hb_sorted_vector_t<hb_aat_map_t::range_flags_t> *range_flags = nullptr;
hb_mask_t subtable_flags = 0;
bool buffer_is_reversed = false;
// Caches
bool using_buffer_glyph_set = false;
hb_bit_set_t *buffer_glyph_set = nullptr;
const hb_bit_set_t *left_set = nullptr;
const hb_bit_set_t *right_set = nullptr;
const hb_bit_set_t *machine_glyph_set = nullptr;
const hb_bit_set_t *first_set = nullptr;
const hb_bit_set_t *second_set = nullptr;
hb_aat_class_cache_t *machine_class_cache = nullptr;
hb_mask_t subtable_flags = 0;
/* Unused. For debug tracing only. */
unsigned int lookup_index;
@ -146,6 +149,12 @@ struct hb_aat_apply_context_t :
void set_lookup_index (unsigned int i) { lookup_index = i; }
void reverse_buffer ()
{
buffer->reverse ();
buffer_is_reversed = !buffer_is_reversed;
}
void setup_buffer_glyph_set ()
{
using_buffer_glyph_set = buffer->len >= 4 && buffer_glyph_set;
@ -156,11 +165,11 @@ struct hb_aat_apply_context_t :
bool buffer_intersects_machine () const
{
if (likely (using_buffer_glyph_set))
return buffer_glyph_set->intersects (*machine_glyph_set);
return buffer_glyph_set->intersects (*first_set);
// Faster for shorter buffers.
for (unsigned i = 0; i < buffer->len; i++)
if (machine_glyph_set->has (buffer->info[i].codepoint))
if (first_set->has (buffer->info[i].codepoint))
return true;
return false;
}
@ -639,6 +648,23 @@ struct LookupFormat10
glyphs.add_range (firstGlyph, firstGlyph + glyphCount - 1);
}
template <typename set_t, typename filter_t>
void collect_glyphs_filtered (set_t &glyphs, const filter_t &filter) const
{
if (unlikely (!glyphCount)) return;
if (firstGlyph == DELETED_GLYPH) return;
const HBUINT8 *p = valueArrayZ.arrayZ;
for (unsigned i = 0; i < glyphCount; i++)
{
unsigned int v = 0;
unsigned int count = valueSize;
for (unsigned int j = 0; j < count; j++)
v = (v << 8) | *p++;
if (filter (v))
glyphs.add (firstGlyph + i);
}
}
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
@ -709,6 +735,7 @@ struct Lookup
case 4: hb_barrier (); u.format4.collect_glyphs_filtered (glyphs, filter); return;
case 6: hb_barrier (); u.format6.collect_glyphs_filtered (glyphs, filter); return;
case 8: hb_barrier (); u.format8.collect_glyphs_filtered (glyphs, filter); return;
case 10: hb_barrier (); u.format10.collect_glyphs_filtered (glyphs, filter); return;
default:return;
}
}
@ -838,11 +865,6 @@ struct StateTable
STATE_START_OF_LINE = 1,
};
template <typename set_t>
void collect_glyphs (set_t &glyphs, unsigned num_glyphs) const
{
(this+classTable).collect_glyphs (glyphs, num_glyphs);
}
template <typename set_t, typename table_t>
void collect_initial_glyphs (set_t &glyphs, unsigned num_glyphs, const table_t &table) const
{
@ -1082,6 +1104,8 @@ struct SubtableGlyphCoverage
for (unsigned i = 0; i < subtable_count; i++)
{
uint32_t offset = (uint32_t) subtableOffsets[i];
// A font file called SFNSDisplay.ttf has value 0xFFFFFFFF in the offsets.
// Just ignore it.
if (offset == 0 || offset == 0xFFFFFFFF)
continue;
if (unlikely (!subtableOffsets[i].sanitize (c, this, bytes)))

View file

@ -120,12 +120,12 @@ struct KerxSubTableFormat0
}
template <typename set_t>
void collect_glyphs (set_t &left_set, set_t &right_set, unsigned num_glyphs) const
void collect_glyphs (set_t &first_set, set_t &second_set, unsigned num_glyphs) const
{
for (const KernPair& pair : pairs)
{
left_set.add (pair.left);
right_set.add (pair.right);
first_set.add (pair.left);
second_set.add (pair.right);
}
}
@ -140,7 +140,7 @@ struct KerxSubTableFormat0
int get_kerning (hb_codepoint_t left, hb_codepoint_t right) const
{
if (!(*c->left_set)[left] || !(*c->right_set)[right]) return 0;
if (!(*c->first_set)[left] || !(*c->second_set)[right]) return 0;
return table.get_kerning (left, right, c);
}
};
@ -396,10 +396,10 @@ struct KerxSubTableFormat1
}
template <typename set_t>
void collect_glyphs (set_t &left_set, set_t &right_set, unsigned num_glyphs) const
void collect_glyphs (set_t &first_set, set_t &second_set, unsigned num_glyphs) const
{
machine.collect_initial_glyphs (left_set, num_glyphs, *this);
//machine.collect_glyphs (right_set, num_glyphs); // right_set is unused for machine kerning
machine.collect_initial_glyphs (first_set, num_glyphs, *this);
//machine.collect_glyphs (second_set, num_glyphs); // second_set is unused for machine kerning
}
protected:
@ -451,10 +451,10 @@ struct KerxSubTableFormat2
}
template <typename set_t>
void collect_glyphs (set_t &left_set, set_t &right_set, unsigned num_glyphs) const
void collect_glyphs (set_t &first_set, set_t &second_set, unsigned num_glyphs) const
{
(this+leftClassTable).collect_glyphs (left_set, num_glyphs);
(this+rightClassTable).collect_glyphs (right_set, num_glyphs);
(this+leftClassTable).collect_glyphs (first_set, num_glyphs);
(this+rightClassTable).collect_glyphs (second_set, num_glyphs);
}
struct accelerator_t
@ -468,7 +468,7 @@ struct KerxSubTableFormat2
int get_kerning (hb_codepoint_t left, hb_codepoint_t right) const
{
if (!(*c->left_set)[left] || !(*c->right_set)[right]) return 0;
if (!(*c->first_set)[left] || !(*c->second_set)[right]) return 0;
return table.get_kerning (left, right, c);
}
};
@ -629,6 +629,8 @@ struct KerxSubTableFormat4
}
o.attach_type() = OT::Layout::GPOS_impl::ATTACH_TYPE_MARK;
o.attach_chain() = (int) mark - (int) buffer->idx;
if (c->buffer_is_reversed)
o.attach_chain() = -o.attach_chain();
buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT;
}
@ -671,10 +673,10 @@ struct KerxSubTableFormat4
}
template <typename set_t>
void collect_glyphs (set_t &left_set, set_t &right_set, unsigned num_glyphs) const
void collect_glyphs (set_t &first_set, set_t &second_set, unsigned num_glyphs) const
{
machine.collect_initial_glyphs (left_set, num_glyphs, *this);
//machine.collect_glyphs (right_set, num_glyphs); // right_set is unused for machine kerning
machine.collect_initial_glyphs (first_set, num_glyphs, *this);
//machine.collect_glyphs (second_set, num_glyphs); // second_set is unused for machine kerning
}
protected:
@ -762,19 +764,19 @@ struct KerxSubTableFormat6
}
template <typename set_t>
void collect_glyphs (set_t &left_set, set_t &right_set, unsigned num_glyphs) const
void collect_glyphs (set_t &first_set, set_t &second_set, unsigned num_glyphs) const
{
if (is_long ())
{
const auto &t = u.l;
(this+t.rowIndexTable).collect_glyphs (left_set, num_glyphs);
(this+t.columnIndexTable).collect_glyphs (right_set, num_glyphs);
(this+t.rowIndexTable).collect_glyphs (first_set, num_glyphs);
(this+t.columnIndexTable).collect_glyphs (second_set, num_glyphs);
}
else
{
const auto &t = u.s;
(this+t.rowIndexTable).collect_glyphs (left_set, num_glyphs);
(this+t.columnIndexTable).collect_glyphs (right_set, num_glyphs);
(this+t.rowIndexTable).collect_glyphs (first_set, num_glyphs);
(this+t.columnIndexTable).collect_glyphs (second_set, num_glyphs);
}
}
@ -789,7 +791,7 @@ struct KerxSubTableFormat6
int get_kerning (hb_codepoint_t left, hb_codepoint_t right) const
{
if (!(*c->left_set)[left] || !(*c->right_set)[right]) return 0;
if (!(*c->first_set)[left] || !(*c->second_set)[right]) return 0;
return table.get_kerning (left, right, c);
}
};
@ -878,15 +880,15 @@ struct KerxSubTable
}
template <typename set_t>
void collect_glyphs (set_t &left_set, set_t &right_set, unsigned num_glyphs) const
void collect_glyphs (set_t &first_set, set_t &second_set, unsigned num_glyphs) const
{
unsigned int subtable_type = get_type ();
switch (subtable_type) {
case 0: u.format0.collect_glyphs (left_set, right_set, num_glyphs); return;
case 1: u.format1.collect_glyphs (left_set, right_set, num_glyphs); return;
case 2: u.format2.collect_glyphs (left_set, right_set, num_glyphs); return;
case 4: u.format4.collect_glyphs (left_set, right_set, num_glyphs); return;
case 6: u.format6.collect_glyphs (left_set, right_set, num_glyphs); return;
case 0: u.format0.collect_glyphs (first_set, second_set, num_glyphs); return;
case 1: u.format1.collect_glyphs (first_set, second_set, num_glyphs); return;
case 2: u.format2.collect_glyphs (first_set, second_set, num_glyphs); return;
case 4: u.format4.collect_glyphs (first_set, second_set, num_glyphs); return;
case 6: u.format6.collect_glyphs (first_set, second_set, num_glyphs); return;
default: return;
}
}
@ -923,8 +925,8 @@ struct KerxSubTable
struct kern_subtable_accelerator_data_t
{
hb_bit_set_t left_set;
hb_bit_set_t right_set;
hb_bit_set_t first_set;
hb_bit_set_t second_set;
mutable hb_aat_class_cache_t class_cache;
};
@ -1017,9 +1019,8 @@ struct KerxTable
if (HB_DIRECTION_IS_HORIZONTAL (c->buffer->props.direction) != st->u.header.is_horizontal ())
goto skip;
c->left_set = &subtable_accel.left_set;
c->right_set = &subtable_accel.right_set;
c->machine_glyph_set = &subtable_accel.left_set;
c->first_set = &subtable_accel.first_set;
c->second_set = &subtable_accel.second_set;
c->machine_class_cache = &subtable_accel.class_cache;
if (!c->buffer_intersects_machine ())
@ -1051,8 +1052,8 @@ struct KerxTable
}
}
if (reverse)
c->buffer->reverse ();
if (reverse != c->buffer_is_reversed)
c->reverse_buffer ();
{
/* See comment in sanitize() for conditional here. */
@ -1060,15 +1061,14 @@ struct KerxTable
ret |= st->dispatch (c);
}
if (reverse)
c->buffer->reverse ();
(void) c->buffer->message (c->font, "end subtable %u", c->lookup_index);
skip:
st = &StructAfter<SubTable> (*st);
c->set_lookup_index (c->lookup_index + 1);
}
if (c->buffer_is_reversed)
c->reverse_buffer ();
return ret;
}
@ -1133,7 +1133,7 @@ struct KerxTable
if (unlikely (accel_data.subtable_accels.in_error ()))
return accel_data;
st->collect_glyphs (subtable_accel.left_set, subtable_accel.right_set, num_glyphs);
st->collect_glyphs (subtable_accel.first_set, subtable_accel.second_set, num_glyphs);
subtable_accel.class_cache.clear ();
st = &StructAfter<SubTable> (*st);

View file

@ -1169,15 +1169,15 @@ struct Chain
hb_map ([subtable_flags] (const hb_aat_map_t::range_flags_t _) -> bool { return subtable_flags & (_.flags); })))
goto skip;
c->subtable_flags = subtable_flags;
c->machine_glyph_set = accel ? &accel->subtables[i].glyph_set : &Null(hb_bit_set_t);
c->machine_class_cache = accel ? &accel->subtables[i].class_cache : nullptr;
if (!(coverage & ChainSubtable<Types>::AllDirections) &&
HB_DIRECTION_IS_VERTICAL (c->buffer->props.direction) !=
bool (coverage & ChainSubtable<Types>::Vertical))
goto skip;
c->subtable_flags = subtable_flags;
c->first_set = accel ? &accel->subtables[i].glyph_set : &Null(hb_bit_set_t);
c->machine_class_cache = accel ? &accel->subtables[i].class_cache : nullptr;
if (!c->buffer_intersects_machine ())
{
(void) c->buffer->message (c->font, "skipped chainsubtable %u because no glyph matches", c->lookup_index);
@ -1219,22 +1219,21 @@ struct Chain
if (!c->buffer->message (c->font, "start chainsubtable %u", c->lookup_index))
goto skip;
if (reverse)
c->buffer->reverse ();
if (reverse != c->buffer_is_reversed)
c->reverse_buffer ();
subtable->apply (c);
if (reverse)
c->buffer->reverse ();
(void) c->buffer->message (c->font, "end chainsubtable %u", c->lookup_index);
if (unlikely (!c->buffer->successful)) return;
if (unlikely (!c->buffer->successful)) break;
skip:
subtable = &StructAfter<ChainSubtable<Types>> (*subtable);
c->set_lookup_index (c->lookup_index + 1);
}
if (c->buffer_is_reversed)
c->reverse_buffer ();
}
unsigned int get_size () const { return length; }

View file

@ -92,6 +92,7 @@ template <typename Type>
struct __attribute__((packed)) hb_packed_t { Type v; };
#ifndef HB_FAST_NUM_ACCESS
#if defined(__OPTIMIZE__) && \
defined(__BYTE_ORDER) && \
(__BYTE_ORDER == __BIG_ENDIAN || \
@ -102,6 +103,13 @@ struct __attribute__((packed)) hb_packed_t { Type v; };
#else
#define HB_FAST_NUM_ACCESS 0
#endif
// https://github.com/harfbuzz/harfbuzz/issues/5456
#if defined(__GNUC__) && !defined(__clang__) && (__GNUC__ <= 12)
#undef HB_FAST_NUM_ACCESS
#define HB_FAST_NUM_ACCESS 0
#endif
#endif
template <bool BE, typename Type, int Bytes = sizeof (Type)>
@ -846,6 +854,17 @@ HB_FUNCOBJ (hb_clamp);
* Bithacks.
*/
/* Return the number of 1 bits in a uint8_t; faster than hb_popcount() */
static inline unsigned
hb_popcount8 (uint8_t v)
{
static const uint8_t popcount4[16] = {
0, 1, 1, 2, 1, 2, 2, 3,
1, 2, 2, 3, 2, 3, 3, 4
};
return popcount4[v & 0xF] + popcount4[v >> 4];
}
/* Return the number of 1 bits in v. */
template <typename T>
static inline unsigned int

105
thirdparty/harfbuzz/src/hb-alloc-pool.hh vendored Normal file
View file

@ -0,0 +1,105 @@
/*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Author(s): Behdad Esfahbod
*/
#ifndef HB_ALLOC_POOL_HH
#define HB_ALLOC_POOL_HH
#include "hb-vector.hh"
/* Memory pool for persistent small- to medium-sized allocations.
*
* Some AI musings on this, not necessarily true:
*
* This is a very simple implementation, but it's good enough for our
* purposes. It's not thread-safe. It's not very fast. It's not
* very memory efficient. It's not very cache efficient. It's not
* very anything efficient. But it's simple and it works. And it's
* good enough for our purposes. If you need something more
* sophisticated, use a real allocator. Or use a real language. */
struct hb_alloc_pool_t
{
unsigned ChunkSize = 65536 - 2 * sizeof (void *);
void *alloc (size_t size, unsigned alignment = 2 * sizeof (void *))
{
if (unlikely (chunks.in_error ())) return nullptr;
assert (alignment > 0);
assert (alignment <= 2 * sizeof (void *));
assert ((alignment & (alignment - 1)) == 0); /* power of two */
if (size > (ChunkSize) / 4)
{
/* Big chunk, allocate separately. */
hb_vector_t<char> chunk;
if (unlikely (!chunk.resize (size))) return nullptr;
void *ret = chunk.arrayZ;
chunks.push (std::move (chunk));
if (chunks.in_error ()) return nullptr;
if (chunks.length > 1)
{
// Bring back the previous last chunk to the end, so that
// we can continue to allocate from it.
hb_swap (chunks.arrayZ[chunks.length - 1], chunks.arrayZ[chunks.length - 2]);
}
return ret;
}
unsigned pad = (unsigned)(-(uintptr_t) current_chunk.arrayZ) & (alignment - 1);
// Small chunk, allocate from the last chunk.
if (current_chunk.length < pad + size)
{
chunks.push ();
if (unlikely (chunks.in_error ())) return nullptr;
hb_vector_t<char> &chunk = chunks.arrayZ[chunks.length - 1];
if (unlikely (!chunk.resize (ChunkSize))) return nullptr;
current_chunk = chunk;
pad = (unsigned)(-(uintptr_t) current_chunk.arrayZ) & (alignment - 1);
}
current_chunk += pad;
assert (current_chunk.length >= size);
void *ret = current_chunk.arrayZ;
current_chunk += size;
return ret;
}
void discard (void *p_, size_t size)
{
// Reclaim memory if we can.
char *p = (char *) p_;
if (current_chunk.arrayZ == p + size && current_chunk.backwards_length >= size)
current_chunk -= size;
}
private:
hb_vector_t<hb_vector_t<char>> chunks;
hb_array_t<char> current_chunk;
};
#endif /* HB_ALLOC_POOL_HH */

View file

@ -40,7 +40,6 @@
* Atomic integers and pointers.
*/
/* We need external help for these */
#if defined(hb_atomic_int_impl_add) \
@ -80,27 +79,11 @@ _hb_atomic_ptr_impl_cmplexch (const void **P, const void *O_, const void *N)
#include <atomic>
#define HB_STL_ATOMIC_IMPL
#define _hb_memory_r_barrier() std::atomic_thread_fence(std::memory_order_acquire)
#define _hb_memory_w_barrier() std::atomic_thread_fence(std::memory_order_release)
#define hb_atomic_int_impl_add(AI, V) (reinterpret_cast<std::atomic<typename std::decay<decltype (*(AI))>::type> *> (AI)->fetch_add ((V), std::memory_order_acq_rel))
#define hb_atomic_int_impl_set_relaxed(AI, V) (reinterpret_cast<std::atomic<typename std::decay<decltype (*(AI))>::type> *> (AI)->store ((V), std::memory_order_relaxed))
#define hb_atomic_int_impl_set(AI, V) (reinterpret_cast<std::atomic<typename std::decay<decltype (*(AI))>::type> *> (AI)->store ((V), std::memory_order_release))
#define hb_atomic_int_impl_get_relaxed(AI) (reinterpret_cast<std::atomic<typename std::decay<decltype (*(AI))>::type> const *> (AI)->load (std::memory_order_relaxed))
#define hb_atomic_int_impl_get(AI) (reinterpret_cast<std::atomic<typename std::decay<decltype (*(AI))>::type> const *> (AI)->load (std::memory_order_acquire))
#define hb_atomic_ptr_impl_set_relaxed(P, V) (reinterpret_cast<std::atomic<void*> *> (P)->store ((V), std::memory_order_relaxed))
#define hb_atomic_ptr_impl_get_relaxed(P) (reinterpret_cast<std::atomic<void*> const *> (P)->load (std::memory_order_relaxed))
#define hb_atomic_ptr_impl_get(P) (reinterpret_cast<std::atomic<void*> *> (P)->load (std::memory_order_acquire))
static inline bool
_hb_atomic_ptr_impl_cmplexch (const void **P, const void *O_, const void *N)
{
const void *O = O_; // Need lvalue
return reinterpret_cast<std::atomic<const void*> *> (P)->compare_exchange_weak (O, N, std::memory_order_acq_rel, std::memory_order_relaxed);
}
#define hb_atomic_ptr_impl_cmpexch(P,O,N) _hb_atomic_ptr_impl_cmplexch ((const void **) (P), (O), (N))
#else /* defined(HB_NO_MT) */
#define hb_atomic_int_impl_add(AI, V) ((*(AI) += (V)) - (V))
@ -159,6 +142,81 @@ inline T hb_atomic_int_impl_get (const T *AI) { T v = *AI; _hb_memory_r_barrier
inline void *hb_atomic_ptr_impl_get (void ** const P) { void *v = *P; _hb_memory_r_barrier (); return v; }
#endif
#ifdef HB_STL_ATOMIC_IMPL
template <typename T>
struct hb_atomic_t
{
hb_atomic_t () = default;
constexpr hb_atomic_t (T v) : v (v) {}
constexpr hb_atomic_t (const hb_atomic_t& o) : v (o.get_relaxed ()) {}
constexpr hb_atomic_t (hb_atomic_t&& o) : v (o.get_relaxed ()) { o.set_relaxed ({}); }
hb_atomic_t &operator= (const hb_atomic_t& o) { set_relaxed (o.get_relaxed ()); return *this; }
hb_atomic_t &operator= (hb_atomic_t&& o){ set_relaxed (o.get_relaxed ()); o.set_relaxed ({}); return *this; }
hb_atomic_t &operator= (T v_)
{
set_relaxed (v_);
return *this;
}
operator T () const { return get_relaxed (); }
void set_relaxed (T v_) { v.store (v_, std::memory_order_relaxed); }
void set_release (T v_) { v.store (v_, std::memory_order_release); }
T get_relaxed () const { return v.load (std::memory_order_relaxed); }
T get_acquire () const { return v.load (std::memory_order_acquire); }
T inc () { return v.fetch_add (1, std::memory_order_acq_rel); }
T dec () { return v.fetch_add (-1, std::memory_order_acq_rel); }
int operator++ (int) { return inc (); }
int operator-- (int) { return dec (); }
long operator|= (long v_)
{
set_relaxed (get_relaxed () | v_);
return *this;
}
friend void swap (hb_atomic_t &a, hb_atomic_t &b) noexcept
{
T v = a.get_acquire ();
a.set_relaxed (b.get_acquire ());
b.set_relaxed (v);
}
std::atomic<T> v = 0;
};
template <typename T>
struct hb_atomic_t<T *>
{
hb_atomic_t () = default;
constexpr hb_atomic_t (T *v) : v (v) {}
hb_atomic_t (const hb_atomic_t &other) = delete;
void init (T *v_ = nullptr) { set_relaxed (v_); }
void set_relaxed (T *v_) { v.store (v_, std::memory_order_relaxed); }
T *get_relaxed () const { return v.load (std::memory_order_relaxed); }
T *get_acquire () const { return v.load (std::memory_order_acquire); }
bool cmpexch (T *old, T *new_) { return v.compare_exchange_weak (old, new_, std::memory_order_acq_rel, std::memory_order_relaxed); }
operator bool () const { return get_acquire () != nullptr; }
T *operator->() const { return get_acquire (); }
template <typename C>
operator C * () const
{
return get_acquire ();
}
friend void swap (hb_atomic_t &a, hb_atomic_t &b) noexcept
{
T *p = a.get_acquire ();
a.set_relaxed (b.get_acquire ());
b.set_relaxed (p);
}
std::atomic<T *> v = nullptr;
};
#else
template <typename T>
struct hb_atomic_t
@ -194,7 +252,7 @@ struct hb_atomic_t<T*>
void set_relaxed (T* v_) { hb_atomic_ptr_impl_set_relaxed (&v, v_); }
T *get_relaxed () const { return (T *) hb_atomic_ptr_impl_get_relaxed (&v); }
T *get_acquire () const { return (T *) hb_atomic_ptr_impl_get ((void **) &v); }
bool cmpexch (const T *old, T *new_) { return hb_atomic_ptr_impl_cmpexch ((void **) &v, (void *) old, (void *) new_); }
bool cmpexch (T *old, T *new_) { return hb_atomic_ptr_impl_cmpexch ((void **) &v, (void *) old, (void *) new_); }
operator bool () const { return get_acquire () != nullptr; }
T * operator -> () const { return get_acquire (); }
@ -203,6 +261,8 @@ struct hb_atomic_t<T*>
T *v = nullptr;
};
#endif
static inline bool hb_barrier ()
{
_hb_compiler_memory_r_barrier ();

View file

@ -176,7 +176,7 @@ struct hb_inc_bimap_t
{
hb_codepoint_t count = get_population ();
hb_vector_t <hb_codepoint_t> work;
if (unlikely (!work.resize (count, false))) return;
if (unlikely (!work.resize_dirty (count))) return;
for (hb_codepoint_t rhs = 0; rhs < count; rhs++)
work.arrayZ[rhs] = back_map[rhs];

View file

@ -142,6 +142,7 @@ struct hb_bit_page_t
bool operator [] (hb_codepoint_t g) const { return get (g); }
bool operator () (hb_codepoint_t g) const { return get (g); }
bool has (hb_codepoint_t g) const { return get (g); }
void add_range (hb_codepoint_t a, hb_codepoint_t b)
{
@ -290,7 +291,7 @@ struct hb_bit_page_t
unsigned int j = m & ELT_MASK;
const elt_t vv = v[i] & ~((elt_t (1) << j) - 1);
for (const elt_t *p = &vv; i < len (); p = &v[++i])
for (const elt_t *p = &vv; i < len (); p = ((const elt_t *) &v[0]) + (++i))
if (*p)
{
*codepoint = i * ELT_BITS + elt_get_min (*p);
@ -346,6 +347,36 @@ struct hb_bit_page_t
return 0;
}
/*
* Iterator implementation.
*/
struct iter_t : hb_iter_with_fallback_t<iter_t, hb_codepoint_t>
{
static constexpr bool is_sorted_iterator = true;
iter_t (const hb_bit_page_t &s_ = Null (hb_bit_page_t), bool init = true) : s (&s_), v (INVALID)
{
if (init)
v = s->get_min ();
}
typedef hb_codepoint_t __item_t__;
hb_codepoint_t __item__ () const { return v; }
bool __more__ () const { return v != INVALID; }
void __next__ () {
s->next (&v);
}
void __prev__ () { s->previous (&v); }
iter_t end () const { return iter_t (*s, false); }
bool operator != (const iter_t& o) const
{ return v != o.v; }
protected:
const hb_bit_page_t *s;
hb_codepoint_t v;
};
iter_t iter () const { return iter_t (*this); }
operator iter_t () const { return iter (); }
static constexpr hb_codepoint_t INVALID = HB_SET_VALUE_INVALID;
typedef unsigned long long elt_t;

View file

@ -368,7 +368,7 @@ struct hb_bit_set_invertible_t
unsigned __len__ () const { return l; }
iter_t end () const { return iter_t (*s, false); }
bool operator != (const iter_t& o) const
{ return v != o.v || s != o.s; }
{ return v != o.v; }
protected:
const hb_bit_set_invertible_t *s;

View file

@ -91,10 +91,10 @@ struct hb_bit_set_t
if (pages.length < count && (unsigned) pages.allocated < count && count <= 2)
exact_size = true; // Most sets are small and local
if (unlikely (!pages.resize (count, clear, exact_size) ||
!page_map.resize (count, clear)))
if (unlikely (!pages.resize_full (count, clear, exact_size) ||
!page_map.resize_full (count, clear, false)))
{
pages.resize (page_map.length, clear, exact_size);
pages.resize_full (page_map.length, clear, exact_size);
successful = false;
return false;
}
@ -108,10 +108,11 @@ struct hb_bit_set_t
page_map.alloc (sz);
}
void reset ()
hb_bit_set_t& reset ()
{
successful = true;
clear ();
return *this;
}
void clear ()
@ -394,7 +395,7 @@ struct hb_bit_set_t
{
if (unlikely (!successful)) return;
unsigned int count = other.pages.length;
if (unlikely (!resize (count, false, exact_size)))
if (unlikely (!resize (count, false, exact_size)))
return;
population = other.population;
@ -922,7 +923,7 @@ struct hb_bit_set_t
unsigned __len__ () const { return l; }
iter_t end () const { return iter_t (*s, false); }
bool operator != (const iter_t& o) const
{ return s != o.s || v != o.v; }
{ return v != o.v; }
protected:
const hb_bit_set_t *s;

View file

@ -32,7 +32,7 @@
#include "hb.hh"
#line 36 "hb-buffer-deserialize-text-unicode.hh"
#line 33 "hb-buffer-deserialize-text-unicode.hh"
static const unsigned char _deserialize_text_unicode_trans_keys[] = {
0u, 0u, 43u, 102u, 48u, 102u, 48u, 124u, 48u, 57u, 62u, 124u, 48u, 124u, 60u, 117u,
85u, 117u, 85u, 117u, 0
@ -150,12 +150,12 @@ _hb_buffer_deserialize_text_unicode (hb_buffer_t *buffer,
hb_glyph_info_t info = {0};
const hb_glyph_position_t pos = {0};
#line 154 "hb-buffer-deserialize-text-unicode.hh"
#line 147 "hb-buffer-deserialize-text-unicode.hh"
{
cs = deserialize_text_unicode_start;
}
#line 159 "hb-buffer-deserialize-text-unicode.hh"
#line 150 "hb-buffer-deserialize-text-unicode.hh"
{
int _slen;
int _trans;
@ -215,7 +215,7 @@ _resume:
hb_memset (&info, 0, sizeof (info));
}
break;
#line 219 "hb-buffer-deserialize-text-unicode.hh"
#line 203 "hb-buffer-deserialize-text-unicode.hh"
}
_again:
@ -238,7 +238,7 @@ _again:
*end_ptr = p;
}
break;
#line 242 "hb-buffer-deserialize-text-unicode.hh"
#line 224 "hb-buffer-deserialize-text-unicode.hh"
}
}

View file

@ -163,7 +163,7 @@ buffer_verify_unsafe_to_break (hb_buffer_t *buffer,
hb_buffer_append (fragment, text_buffer, text_start, text_end);
if (!hb_shape_full (font, fragment, features, num_features, shapers) ||
fragment->successful || fragment->shaping_failed)
fragment->successful)
{
hb_buffer_destroy (reconstruction);
hb_buffer_destroy (fragment);
@ -313,11 +313,11 @@ buffer_verify_unsafe_to_concat (hb_buffer_t *buffer,
* Shape the two fragment streams.
*/
if (!hb_shape_full (font, fragments[0], features, num_features, shapers) ||
!fragments[0]->successful || fragments[0]->shaping_failed)
!fragments[0]->successful)
goto out;
if (!hb_shape_full (font, fragments[1], features, num_features, shapers) ||
!fragments[1]->successful || fragments[1]->shaping_failed)
!fragments[1]->successful)
goto out;
if (!forward)

View file

@ -158,14 +158,15 @@ hb_segment_properties_overlay (hb_segment_properties_t *p,
bool
hb_buffer_t::enlarge (unsigned int size)
{
if (unlikely (!successful))
return false;
if (unlikely (size > max_len))
{
successful = false;
return false;
}
if (unlikely (!successful))
return false;
unsigned int new_allocated = allocated;
hb_glyph_position_t *new_pos = nullptr;
hb_glyph_info_t *new_info = nullptr;
@ -226,6 +227,13 @@ hb_buffer_t::shift_forward (unsigned int count)
assert (have_output);
if (unlikely (!ensure (len + count))) return false;
max_ops -= len - idx;
if (unlikely (max_ops < 0))
{
successful = false;
return false;
}
memmove (info + idx + count, info + idx, (len - idx) * sizeof (info[0]));
if (idx + count > len)
{
@ -297,7 +305,6 @@ hb_buffer_t::clear ()
props = default_props;
successful = true;
shaping_failed = false;
have_output = false;
have_positions = false;
@ -320,7 +327,6 @@ hb_buffer_t::enter ()
{
deallocate_var_all ();
serial = 0;
shaping_failed = false;
scratch_flags = HB_BUFFER_SCRATCH_FLAG_DEFAULT;
unsigned mul;
if (likely (!hb_unsigned_mul_overflows (len, HB_BUFFER_MAX_LEN_FACTOR, &mul)))
@ -339,7 +345,6 @@ hb_buffer_t::leave ()
max_ops = HB_BUFFER_MAX_OPS_DEFAULT;
deallocate_var_all ();
serial = 0;
// Intentionally not reseting shaping_failed, such that it can be inspected.
}
@ -520,7 +525,19 @@ hb_buffer_t::set_masks (hb_mask_t value,
hb_mask_t not_mask = ~mask;
value &= mask;
max_ops -= len;
if (unlikely (max_ops < 0))
successful = false;
unsigned int count = len;
if (cluster_start == 0 && cluster_end == (unsigned int) -1)
{
for (unsigned int i = 0; i < count; i++)
info[i].mask = (info[i].mask & not_mask) | value;
return;
}
for (unsigned int i = 0; i < count; i++)
if (cluster_start <= info[i].cluster && info[i].cluster < cluster_end)
info[i].mask = (info[i].mask & not_mask) | value;
@ -536,6 +553,10 @@ hb_buffer_t::merge_clusters_impl (unsigned int start,
return;
}
max_ops -= end - start;
if (unlikely (max_ops < 0))
successful = false;
unsigned int cluster = info[start].cluster;
for (unsigned int i = start + 1; i < end; i++)
@ -569,6 +590,10 @@ hb_buffer_t::merge_out_clusters (unsigned int start,
if (unlikely (end - start < 2))
return;
max_ops -= end - start;
if (unlikely (max_ops < 0))
successful = false;
unsigned int cluster = out_info[start].cluster;
for (unsigned int i = start + 1; i < end; i++)
@ -726,7 +751,6 @@ DEFINE_NULL_INSTANCE (hb_buffer_t) =
HB_SEGMENT_PROPERTIES_DEFAULT,
false, /* successful */
true, /* shaping_failed */
false, /* have_output */
true /* have_positions */

View file

@ -32,6 +32,7 @@
#include "hb.hh"
#include "hb-unicode.hh"
#include "hb-set-digest.hh"
static_assert ((sizeof (hb_glyph_info_t) == 20), "");
@ -44,14 +45,14 @@ HB_MARK_AS_FLAG_T (hb_buffer_diff_flags_t);
enum hb_buffer_scratch_flags_t {
HB_BUFFER_SCRATCH_FLAG_DEFAULT = 0x00000000u,
HB_BUFFER_SCRATCH_FLAG_HAS_NON_ASCII = 0x00000001u,
HB_BUFFER_SCRATCH_FLAG_HAS_FRACTION_SLASH = 0x00000001u,
HB_BUFFER_SCRATCH_FLAG_HAS_DEFAULT_IGNORABLES = 0x00000002u,
HB_BUFFER_SCRATCH_FLAG_HAS_SPACE_FALLBACK = 0x00000004u,
HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT = 0x00000008u,
HB_BUFFER_SCRATCH_FLAG_HAS_CGJ = 0x00000010u,
HB_BUFFER_SCRATCH_FLAG_HAS_GLYPH_FLAGS = 0x00000020u,
HB_BUFFER_SCRATCH_FLAG_HAS_BROKEN_SYLLABLE = 0x00000040u,
HB_BUFFER_SCRATCH_FLAG_HAS_VARIATION_SELECTOR_FALLBACK= 0x00000080u,
HB_BUFFER_SCRATCH_FLAG_HAS_BROKEN_SYLLABLE = 0x00000020u,
HB_BUFFER_SCRATCH_FLAG_HAS_VARIATION_SELECTOR_FALLBACK= 0x00000040u,
HB_BUFFER_SCRATCH_FLAG_HAS_CONTINUATIONS = 0x00000080u,
/* Reserved for shapers' internal use. */
HB_BUFFER_SCRATCH_FLAG_SHAPER0 = 0x01000000u,
@ -90,7 +91,6 @@ struct hb_buffer_t
hb_segment_properties_t props; /* Script, language, direction */
bool successful; /* Allocations successful */
bool shaping_failed; /* Shaping failure */
bool have_output; /* Whether we have an output buffer going on */
bool have_positions; /* Whether we have positions */
@ -110,6 +110,7 @@ struct hb_buffer_t
hb_codepoint_t context[2][CONTEXT_LENGTH];
unsigned int context_len[2];
hb_set_digest_t digest; /* Manually updated sometimes */
/*
* Managed by enter / leave
@ -200,6 +201,12 @@ struct hb_buffer_t
void collect_codepoints (set_t &d) const
{ d.clear (); d.add_array (&info[0].codepoint, len, sizeof (info[0])); }
void update_digest ()
{
digest = hb_set_digest_t ();
collect_codepoints (digest);
}
HB_INTERNAL void similar (const hb_buffer_t &src);
HB_INTERNAL void reset ();
HB_INTERNAL void clear ();
@ -346,7 +353,7 @@ struct hb_buffer_t
{
if (out_info != info || out_len != idx)
{
if (unlikely (!make_room_for (1, 1))) return false;
if (unlikely (!ensure (out_len + 1))) return false;
out_info[out_len] = info[idx];
}
out_len++;
@ -363,7 +370,7 @@ struct hb_buffer_t
{
if (out_info != info || out_len != idx)
{
if (unlikely (!make_room_for (n, n))) return false;
if (unlikely (!ensure (out_len + n))) return false;
memmove (out_info + out_len, info + idx, n * sizeof (out_info[0]));
}
out_len += n;
@ -404,22 +411,12 @@ struct hb_buffer_t
/* Adds glyph flags in mask to infos with clusters between start and end.
* The start index will be from out-buffer if from_out_buffer is true.
* If interior is true, then the cluster having the minimum value is skipped. */
void _set_glyph_flags (hb_mask_t mask,
unsigned start = 0,
unsigned end = (unsigned) -1,
bool interior = false,
bool from_out_buffer = false)
void _set_glyph_flags_impl (hb_mask_t mask,
unsigned start,
unsigned end,
bool interior,
bool from_out_buffer)
{
if (unlikely (end != (unsigned) -1 && end - start > 255))
return;
end = hb_min (end, len);
if (interior && !from_out_buffer && end - start < 2)
return;
scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GLYPH_FLAGS;
if (!from_out_buffer || !have_output)
{
if (!interior)
@ -456,6 +453,25 @@ struct hb_buffer_t
}
}
HB_ALWAYS_INLINE
void _set_glyph_flags (hb_mask_t mask,
unsigned start = 0,
unsigned end = (unsigned) -1,
bool interior = false,
bool from_out_buffer = false)
{
if (unlikely (end != (unsigned) -1 && end - start > 255))
return;
end = hb_min (end, len);
if (interior && !from_out_buffer && end - start < 2)
return;
_set_glyph_flags_impl (mask, start, end, interior, from_out_buffer);
}
void unsafe_to_break (unsigned int start = 0, unsigned int end = -1)
{
_set_glyph_flags (HB_GLYPH_FLAG_UNSAFE_TO_BREAK | HB_GLYPH_FLAG_UNSAFE_TO_CONCAT,
@ -606,6 +622,10 @@ struct hb_buffer_t
if (unlikely (start == end))
return;
max_ops -= end - start;
if (unlikely (max_ops < 0))
successful = false;
unsigned cluster_first = infos[start].cluster;
unsigned cluster_last = infos[end - 1].cluster;
@ -614,10 +634,7 @@ struct hb_buffer_t
{
for (unsigned int i = start; i < end; i++)
if (cluster != infos[i].cluster)
{
scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GLYPH_FLAGS;
infos[i].mask |= mask;
}
return;
}
@ -626,18 +643,12 @@ struct hb_buffer_t
if (cluster == cluster_first)
{
for (unsigned int i = end; start < i && infos[i - 1].cluster != cluster_first; i--)
{
scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GLYPH_FLAGS;
infos[i - 1].mask |= mask;
}
}
else /* cluster == cluster_last */
{
for (unsigned int i = start; i < end && infos[i].cluster != cluster_last; i++)
{
scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GLYPH_FLAGS;
infos[i].mask |= mask;
}
}
}
unsigned

View file

@ -75,6 +75,8 @@ struct hb_cache_t
static_assert ((key_bits >= cache_bits), "");
static_assert ((key_bits + value_bits <= cache_bits + 8 * sizeof (item_t)), "");
static constexpr unsigned MAX_VALUE = (1u << value_bits) - 1;
hb_cache_t () { clear (); }
void clear ()
@ -100,6 +102,12 @@ struct hb_cache_t
{
if (unlikely ((key >> key_bits) || (value >> value_bits)))
return; /* Overflows */
set_unchecked (key, value);
}
HB_HOT
void set_unchecked (unsigned int key, unsigned int value)
{
unsigned int k = key & ((1u<<cache_bits)-1);
unsigned int v = ((key>>cache_bits)<<value_bits) | value;
values[k] = v;

Some files were not shown because too many files have changed in this diff Show more