1
1

Compare commits

..

692 Commits

Author SHA1 Message Date
6fc81d6bca Merge branch 'master' into xr-controller-support 2021-10-03 12:22:05 +09:00
85e1f28fca Fix controller model loading for no stb image 2021-10-03 12:16:07 +09:00
c4f65fa5da Cleanup
- Use doxygen style comments
- Improve comment for XR region type
- Improve RNA descriptions for XR nav location/rotation/scale
- Split controller draw callback into separate model and aim functions
2021-10-03 12:11:10 +09:00
d3afe0c126 Geometry Nodes: Resample Curve Fields Update
This update of the Resample Curve node allows a field to populate the
count or length input of the node depending on the current mode. The
field is evaluated on the spline domain.

Differential Revision: https://developer.blender.org/D12735
2021-10-02 21:45:51 -05:00
e863e05697 Data Transfer: Remove unnecessary noisy error message
I've seen requests to remove this or complaints about this error message
quite frequently. In lots of production files it's just always going off.
It's not an actionable warning, and since "slow" is relative, it isn't
always even correct.

Differential Revision: https://developer.blender.org/D12694
2021-10-02 20:33:15 -05:00
b57b4dfab1 Cleanup: clang-format 2021-10-03 12:13:29 +11:00
f49dff97d4 Cleanup: spelling in strings 2021-10-03 12:13:29 +11:00
74f45ed9c5 Cleanup: spelling in comments 2021-10-03 12:13:29 +11:00
Jarrett Johnson
c5c94e3eae Geometry Nodes: Add Rotate Euler Node
This commit introduces the Rotate Euler function node which modifies
an input euler rotation. The node replaces the "Point Rotate" node.

Addresses T91375.

Differential Revision: https://developer.blender.org/D12531
2021-10-02 20:04:45 -05:00
34cf33eb12 Geometry Nodes: Switch Node Fields Update
This update of the Switch node allows for field compatible types
to be switched through the node. This includes the following:

Float, Int, Bool, String, Vector, and Color

The remaining types are processed with the orginal code:

Geometry, Object, Collection, Texture, and Material

Because the old types require a diffent "switch" socket than the
field types, versioning for old files is included to move links
of those types to a new switch socket. Once fields of other types
are supported, this node can be updated to support them as well.

Differential Revision: https://developer.blender.org/D12642
2021-10-02 17:34:47 -05:00
Leon Leno
54927caf4f Geometry Nodes: Add side and fill segments to Cone/Cylinder nodes
This commit extends the 'Cone' and 'Cylinder' mesh primitive nodes,
with two inputs to control the segments along the side and in the fill.
This makes the nodes more flexible and brings them more in line with
the improved cube node.

Differential Revision: https://developer.blender.org/D12463
2021-10-02 17:29:25 -05:00
12e8c78353 Fix T91888: Pivot point settings shown in timeline
Added to timeline by accident in f9e0981976.
2021-10-01 23:26:59 +02:00
1476d35870 Geometry Nodes: Set Handle Type Node Field Update
This update of the Set Handle Type node allows for a bool field to be
used as the selection of the affected control point handles for
bezier splines. If no bezier splines are provided a info message is
shown.

Differential Revision: https://developer.blender.org/D12526
2021-10-01 14:22:24 -05:00
1fb364491b Geometry Nodes: Set Spline Type Node Field Update
This update of the Set Spline Type node allows for a bool field to be
used as the selection of the affected splines.

Differential Revision: https://developer.blender.org/D12522
2021-10-01 11:59:29 -05:00
eacdc0ab4a VSE: Draw active strips with a different color in the preview window 2021-10-01 18:03:18 +02:00
dc30a9087c Geometry Nodes: Spline Length Input Node
The Spline Length Input node provides a field containing the
length of the current evaluated spline to the Point and Spline
domains.

Differential Revision: https://developer.blender.org/D12706
2021-10-01 09:58:49 -05:00
9e456ca695 Asset Browser: expose current catalog ID in RNA
Add read-only access to the active catalog ID via
`context.space_data.params.catalog_id` in the Asset Browser context.

The UUID is exposed as string to Python.
2021-10-01 16:47:16 +02:00
aae96176e8 Geometry Nodes: Curve Subdivide Node with Fields
The curve subdivide node can now take an int field to specify the
number of subdivisions to make at each curve segment.

Reviewed by: Hans Goudey
Differential Revision: https://developer.blender.org/D12534
2021-10-01 09:43:04 -05:00
e1952c541a Cleanup: unused function declaration
This should have been removed during the recent velocity attribute
refactor.
2021-10-01 16:41:50 +02:00
Johan Walles
fb820496f5 Tracking: Sort motion tracking tracks by start and end frames
Enable sorting motion tracking tracks by start / end times.

Help identifying what cases reconstructed camera jumps, based
on information about whether any track starts/ends at the frame.

Based on revision eb0eb54d96.

{F10563305}

Reviewed By: sergey

Differential Revision: https://developer.blender.org/D12621
2021-10-01 16:29:38 +02:00
f497e471f8 Asset Catalogs: always have an Asset Catalog Tree available
Always create an `AssetCatalogTree` in the `AssetCatalogService`. This
ensures that newly-created catalogs are immediately visible in the UI
(because they insert themselves into an already-existing tree).
2021-10-01 16:15:50 +02:00
3be4cb5b27 Cleanup: Asset Catalog Test, fix clang-tidy warnings
No functional changes.
2021-10-01 15:24:04 +02:00
56ce51d1f7 Asset Catalogs: add catalog filter for the asset browser
Given an "active catalog" (i.e. the one selected in the UI), construct
an `AssetCatalogFilter` instance. This filter can determine whether an
asset should be shown or not. It returns `true` when The asset's catalog
ID is:

- the active catalog,
- an alias of the active catalog (so different UUID that maps to the
  same path),
- a sub-catalog of the active catalog.

Not yet hooked up to the UI.
2021-10-01 15:22:05 +02:00
1c7ce7e0b4 Cleanup: asset catalogs, make function const
Declare `AssetCatalogService::find_catalog()` as `const`, as it's not
requiring modification off the service object.

No functional changes.
2021-10-01 15:22:05 +02:00
271210126e Fix T91834: Appending objects with shape keys into new file is broken.
Recent append refactor 'broke' this, we need special recursive care and
handling of those nasty shpae keys... again.
2021-10-01 14:49:04 +02:00
f9acf21063 Python API Docs: add an example of Bone.convert_local_to_pose usage.
The use case for this method is quite obscure and difficult to
understand without an example. Despite how big looks, this is
actually the simplest example that makes sense.
2021-10-01 15:47:30 +03:00
bdc66c9569 GPU: set 'GL_PACK_ALIGNMENT' 1 as default
This fixes T91828.

The current value of `GL_PACK_ALIGNMENT` may result in crash in the `gpu` module if the buffer is not aligned.

Differential Revision: https://developer.blender.org/D12720
2021-10-01 09:11:37 -03:00
eb3a8fb4e8 Fix T91872: incorrect socket inspection on group nodes
This bug was introduced in rBef45399f3be0955ba8.
2021-10-01 13:21:03 +02:00
798e593002 Fix T87189: Copy/pasting IDs does not handle properly instantiation.
Copy/Paste uses its own code path for ID linking, which was not setting
`LIB_TAG_DOIT` for proper instantiation later on.

Would be nice the make this logic closer to the rest of the link/append
code at some point, but for now this fix will do.
2021-10-01 12:21:08 +02:00
21c29480c3 Fix paste code linking 'direct' IDs with 'INDIRECT' flag.
No idea why this was done that way (it originate from initial paste
commit, rB12b642062c6f).

But the IDs 'selected' as direct paste in `BLO_library_link_copypaste`
should be 'directly' linked, it's similar case to actual append of
selected IDs by the user.

Related to T87189.
2021-10-01 12:21:08 +02:00
928d644895 Append: Fix appended objects potentially auto-instantiated in more than one collection.
Related to T87189.
2021-10-01 12:21:08 +02:00
af0b7925db Fix T87536: incorrect socket types in reroute nodes
This refactors and fixes the code that propagates socket types
through reroute nodes. In my tests it is faster than the previous
code. The difference becomes larger the more reroute nodes
there are, because the old code had O(n^2) runtime, while the
new code runs in linear time.

Differential Revision: https://developer.blender.org/D12716
2021-10-01 11:42:00 +02:00
7843cd63d8 Fix T91839: incorrect active vertex group index
Differential Revision: https://developer.blender.org/D12712
2021-10-01 11:36:10 +02:00
ae4b45145c Cleanup: Asset Catalog Paths, move default constructor to header file
No functional changes.
2021-10-01 10:58:33 +02:00
2e6c6426d3 Asset Catalogs: test that missing catalogs are created once
Add asset catalogs test, to ensure missing catalogs are only created once,
and not for every originally defined catalog.

No functional changes to Blender (the code was already doing the right
thing).
2021-10-01 10:58:16 +02:00
bdb7d262aa Cleanup: clang-tidy warnings 2021-10-01 16:20:31 +10:00
b559fb178e Gizmo: hide 2D gizmos while transforming
Hide gizmos in the sequencer & UV editor while transforming.
2021-10-01 16:19:12 +10:00
4485dc483c Cleanup: use C-style comments, nullptr for C++
Minor changes extracted from D6408
2021-10-01 10:45:09 +10:00
Vitor Boschi
3a59ddb292 Fix: Incorrect warning in curve to mesh node with instances
The node was setting a warning when used with instances on input,
even though it worked fine.

Differential Revision: https://developer.blender.org/D12718
2021-09-30 18:27:58 -05:00
66fe1c79f3 Compositor: Fix Composite node using alpha when "Use Alpha" is off
Alpha input was not receiving the final composite canvas 
as preferred causing a Translate operation being inserted 
for centering. This resulted in a transparent background.
The issue only affects Full Frame mode.
2021-09-30 23:56:53 +02:00
e2df5c8a56 Compositor: Fix Flip node not flipping translation on Full Frame
To match tiled implementation, flip center should not be translated
when canvas has offset. Instead the canvas offset needs to be flipped.
2021-09-30 23:56:53 +02:00
f3274bfa70 Compositor: Fix Dilate/Erode node crash with Step option
It was writing the buffer out of bounds.
Only "Full Frame" mode was affected.
2021-09-30 23:56:53 +02:00
4569d9c0c3 Compositor: Fix Movie Distortion node rendering an empty image
Input area of interest calculation was incorrect because `m_margin`
was uninitialized.
Only "Full Frame" mode was affected.
2021-09-30 23:10:27 +02:00
Pratik Borhade
33dc584b37 Fix T91285: Bad tooltip for VSE Slip operator
This patch is created to change the tooltip for Slip Strip Contents
As per the present info, only active strip will be affected.
But in reality selected strips can be trimmed with this operator.

Word Trim changed to Slip in tooltip

Reviewed By: campbellbarton

Differential Revision: https://developer.blender.org/D12450
2021-09-30 21:11:09 +02:00
Josef Raschen
213554f24a VSE: Add ASC CDL color correction method
Add Offset/Slope/Power controls to the color balance modifier. This is
already available in compositor.

Reviewed By: sergey, ISS

Differential Revision: https://developer.blender.org/D12575
2021-09-30 21:09:47 +02:00
8d60ac2bb0 Cleanup: Fix unused variable warning 2021-09-30 14:01:56 -05:00
Brecht Van Lommel
1a134c4c30 Cycles: refactor API for render output
* Add OutputDriver, replacing function callbacks in Session.
* Add PathTraceTile, replacing tile access methods in Session.
* Add more detailed comments about how this driver should be implemented.
* Add OIIOOutputDriver for Cycles standalone to output an image.

Differential Revision: https://developer.blender.org/D12627
2021-09-30 20:53:27 +02:00
a754e35198 Cycles: refactor API for GPU display
* Split GPUDisplay into two classes. PathTraceDisplay to implement the Cycles side,
  and DisplayDriver to implement the host application side. The DisplayDriver is now
  a fully abstract base class, embedded in the PathTraceDisplay.
* Move copy_pixels_to_texture implementation out of the host side into the Cycles side,
  since it can be implemented in terms of the texture buffer mapping.
* Move definition of DeviceGraphicsInteropDestination into display driver header, so
  that we do not need to expose private device headers in the public API.
* Add more detailed comments about how the DisplayDriver should be implemented.

The "driver" terminology might not be obvious, but is also used in other renderers.

Differential Revision: https://developer.blender.org/D12626
2021-09-30 20:48:08 +02:00
ac582056e2 Geometry Nodes: Swap order of geometry proximity inputs
"Target" is the most important, so it goes at the top.
2021-09-30 13:41:55 -05:00
Charlie Jolly
be70827e6f Nodes: Add Float Curve for GN and Shader nodes.
Replacement for float curve in legacy Attribute Curve Map node.

Float Curve defaults to [0.0-1.0] range.

Reviewed By: JacquesLucke, brecht

Differential Revision: https://developer.blender.org/D12683
2021-09-30 19:24:40 +01:00
827e30bd15 Geometry Nodes: Change default for mesh to points node
While "Vertices" may be less useful since mesh vertices are already
points, the output is more easily understandable, so it's a better
default.
2021-09-30 11:53:48 -05:00
6cff1d6480 Fix T91734: Crash snapping mesh if a beveled curve is present
`BKE_mesh_boundbox_get` cannot be called for objects of type Curve.

The BoundBox however does not match the object seen in the scene.
This will be dealt with in another commit.
2021-09-30 02:48:02 -03:00
dd3391dd99 Asset Catalogs: create missing parent catalogs
For every known catalog, ensure its parent catalog also exists. This
ensures that assets can be assigned to parent catalogs, even when they
didn't exist in the Catalog Definition File yet.
2021-09-30 17:34:58 +02:00
4389067929 Fix possible use-after-free in drag-drop handling logic
Would happen when there were multiple drag items in parallel. There was
a listbase constructed with twice the same item, even though that item
would be deleted after it was handled the first time.
2021-09-30 16:39:09 +02:00
4ee2d9df42 UI: Support easy dropping into/onto rows in new tree-view API
Adds an easy way to add drop support for tree-view rows.

Most of the work is handled by the tree-view UI code. The tree items can
simply override a few functions (`can_drop()`, `on_drop()`,
`drop_tooltip()`) to implement their custom drop behavior.

While dragging over a tree-view item that can be dropped into/onto, the
item can show a custom and dynamic tooltip explaining what's gonna
happen on drop.

This isn't used yet, but will soon be for asset catalogs.

See documentation here:
https://wiki.blender.org/wiki/Source/Interface/Views#Further_Customizations
2021-09-30 16:39:09 +02:00
42ce88f15c Cleanup: remove CatalogPath alias
The `CatalogPath` name was an alias for `std::string`, so that it could
be easily switched over to something else. This happened in the previous
commit (switched to `AssetCatalogPath`), so the alias is no longer
necessary.

This commit removes the `CatalogPath` alias.

No functional changes.
2021-09-30 16:34:30 +02:00
628fab696c Asset Catalog: introduce AssetCatalogPath class
So far we have used `std::string` for asset catalog paths. Some
operations are better described on a dedicated class for this, though.
This commits switches catalog paths from using `std::string` to a
dedicated `blender::bke::AssetCatalogPath` class.

The `using CatalogPath = AssetCatalogPath` alias is still there, and
will be removed in a following cleanup commit.

New `AssetCatalogPath` code reviewed by @severin in D12710.
2021-09-30 16:29:14 +02:00
5d42ea0369 GPencil: Change default template for better contrast in header
Patch created by Pablo Vazquez

This change darkens the header area a bit to create more contrast with the texts.

Differential Revision: https://developer.blender.org/D12711
2021-09-30 16:14:44 +02:00
d754d85845 Fix RigidBodyWorld copy using NO_MAIN instead of COW flag for cache handling.
We only want to share caches in case of CoW copying for the depsgraph,
not for regular `NO_MAIN` data.
2021-09-30 16:00:29 +02:00
1a72744ddc Fix T90246: Full Copy'ing a scene confuses physics in the original scene.
Handling of RigidBody data in duplicate of scenes/collections was very
wrong. This commit:
 - Add handling of duplication of RB collections when fully duplicating
   a scene.
 - Fix Object duplication trying to add duplicated RB objects to
   matching RBW collections.

While the later behavior is desired when only duplicated objects, when
duplicating their collections and/or scenes it is actually very bad, as
it would add back new object duplicates to old (RBW) collections.
2021-09-30 16:00:29 +02:00
779ea49af7 Cleanup: move node_common.c to c++
Buildbot compiled without problems.
2021-09-30 15:44:08 +02:00
07c5d02a11 Asset Browser: Support activating catalogs in the "Current File" library
If the "Current File" asset library is selected in the Asset Browser,
now asssets are filtered based on the active asset catalog. Previously
it would just show all assets. This was marked as a TODO in the code
already.

Maniphest Task: https://developer.blender.org/T91820
2021-09-30 15:23:13 +02:00
3453b22b1e Fix: Curve to Mesh node outputs original curve
It should only output the new mesh (and potentially instances
that are processed separately).
2021-09-30 13:33:21 +02:00
9628ef4135 Fix: wrong field input deduplication with Material Selection node 2021-09-30 12:51:09 +02:00
80d7cac22d Fix T91773: improve numerical stability in Curve Spiral node 2021-09-30 12:33:34 +02:00
ae0f944a57 Fix Cycles viewport flickering
Caused by a lack of synchronization between update process which sets
clear flag and the draw code checking the flag outside of a lock.
2021-09-30 11:44:53 +02:00
5f632f9f6e Fix color width regression in 66e24ce35b
Color buttons were drawing single icon width.
2021-09-30 17:45:09 +10:00
af13168a3f Cleanup: remove unused SpaceImage.curtile 2021-09-30 17:32:48 +10:00
e9dac3eab8 Cleanup: reduce Sequence size by 8 bytes
Also use int8_t for color tag.
2021-09-30 17:32:46 +10:00
fdcae48663 Cleanup: isolate UDIM parameters into a struct
Passing multiple UDIM arguments into the packing function
is awkward especially since the caller may not be using UDIM.

Use an argument to store UDIM packing parameters which can be NULL,
which operates without any UDIM support.

Add a function that extracts these parameters out of the image space
allowing for multiple functions to take UDIM parameters in the future.
2021-09-30 17:32:45 +10:00
2c2516bfc9 Fix(unreported): LineArt curve objects garbled result.
This is caused by line art loading curve objects twice from curve and converted mesh instances (when instance option is on). Now only load mesh when instance option is on.
2021-09-30 13:30:10 +08:00
66e24ce35b Fix menu width regression in c7d94a7827
Icon only popup buttons needed to be adjusted too,
add an uiTextIconPadFactor.icon_only to support this.
2021-09-30 12:43:52 +10:00
84dcf12ceb UI: Increase Area Resize Edge Hit Size
This patch increases the size of the Area BORDERPADDING a bit to make
it easier to hit the edges when initiating area resizing.

See D11925 for details and examples.

Differential Revision: https://developer.blender.org/D11925

Reviewed by Campbell Barton
2021-09-29 15:05:58 -07:00
81f552e9ad Geometry Nodes: Expose Bezier handle positions as an attribute
This commit exposes left and right bezier handles as an attribute.
Interaction basically works like edit mode. If you move an aligned
handle, it also moves the opposite handle of the control point.
The difference is that you can't edit "Auto" or "Vector" handles,
you have to first use the "Set Handle Type" node. That gives the handle
types a bit more meaning in the node tree-- changing them in edit mod
is more like a "UI override".

The attributes are named `handle_start` and `handle_end`,
which is the same name used in the curve RNA API.

A new virtual array implementation is added which handles the case of
splines that don't have these attributes, and it also calls two new
functions on `BezierSpline` to set the handle position accounting
for aligned handles.

The virtual arrays and attribute providers will be refactored
(probably templated) in the future, as a next step after the last
built-in curve attribute provider has landed.

Differential Revision: https://developer.blender.org/D12005
2021-09-29 15:29:29 -05:00
cd03f5b6e5 Add RNA path funcs for VolumeRender & VolumeDisplay
Without proper RNA paths, Alt-click editing properties on multiple
selected objects doesn not work (as well as the 'Copy To Selected'
operator).

Fixes T91806.

Maniphest Tasks: T91806

Differential Revision: https://developer.blender.org/D12700
2021-09-29 21:39:56 +02:00
0cddbcf1d7 Fix T91803: Freestyle rendering as pass broken after recent changes 2021-09-29 21:14:37 +02:00
a2e321aa6d Cleanup: Compositor: Migrate most converter nodes to new socket builder
This migrates most nodes except for the switch view node.
This node requires dynamic sockets so its implementation will be more involved.
2021-09-29 14:48:30 -04:00
d3d021601d Nodes: Fix Split View missing identifier
Mistake from rB84251acfcc4534059d6ccd6682f8e37d529b9063
2021-09-29 14:48:30 -04:00
19785cb022 Fix Cycles CPU performance regression after recent change for intersections size
This struct is much bigger now, and does not actually need to be fully zero
initialized.
2021-09-29 20:25:16 +02:00
Himanshi Kalra
22c61e8060 Tests: Disable tests for non-compiled libraries
This diff disables tests for Boolean, subdivision surface and volume
when GMP, Opensubdiv and Openvdb are not compiled respectively.
It also changes the existing file structure and adds sub-folders for
boolean and subdivison tests. The volume folder only has one test and
is as unchanged structure-wise.

Reviewed By: JacquesLucke, LazyDodo

Differential Revision: https://developer.blender.org/D12448
2021-09-29 23:52:52 +05:30
6f23e4484d Fix non-finite curve normal causing Cycles to crash
Similar to the previous change in the area: need to avoid ray
point and direction becoming a non-finite value.

Use the view direction when the geometrical normal can not be
calculated.

Collaboration and sanity inspiration with Brecht!

Differential Revision: https://developer.blender.org/D12703
2021-09-29 19:49:59 +02:00
1d478851f8 GPencil: Avoid double depsgraph tag
The eval data is updated at the end of the function and this call just adds a calculation not used.
2021-09-29 19:21:54 +02:00
214baf5422 Assets: Enable recursive reading for the asset view template as well
This makes asset view templates, e.g. as used by the Pose Library add-on
use recursive asset loading, see

Also works around an issue that made assets not show up at all anymore
since fc7beac8d6. I'm creating a separate report for that regression,
but in the Asset Browser and Viewer it shouldn't be apparent currently.
2021-09-29 18:51:10 +02:00
45a312fd8f Fix build failure on Windows + wrong buffer size
Was using `NAME_MAX` which is defined in `limits.h`, which again may be
implicitly included by the compiler. Intend was to use the Blender
define `MAX_NAME`.
2021-09-29 17:49:42 +02:00
9d9f205dc4 Asset Browser: Initial Asset Catalog UI
The Asset Browser now displays a tree with asset catalogs in the left
sidebar.
This replaces the asset categories. It uses the new UI tree-view API
(https://wiki.blender.org/wiki/Source/Interface/Views#Tree-View).
Buttons are displayed for adding and removing of catalogs. Parent items
can be collapsed, but the collapsed/uncollapsed state is not stored in
files yet.
Note that edits to catalogs (e.g. new or removed catalogs) are only
written to the asset library's catalog definition files when saving a
.blend.

In the "Current File" asset library, we try to show asset catalogs from
a parent asset library, or if that fails, from the directory the file is
stored in. See adaf4f56e1.

There are plenty of TODOs and smaller glitches to be fixed still. Plus a
UI polishing pass should be done.

Important missing UI features:
* Dragging assets into catalogs (WIP, close to being ready).
* Renaming catalogs
* Proper handling of catalogs in the "Current File" asset library
  (currently not working well).

The "Current File" asset library is especially limited still. Since this
is the only place where you can assign assets to a catalog, this makes
the catalogs very cumbersome in general. To assign an asset to a
catalog, one has to manually copy the Catalog ID (a random hash like
number) to the asset metadata through a temporary UI in the Asset
Browser Sidebar. These limitations should be addressed over the next few
days, they are high priority.

Differential Revision: https://developer.blender.org/D12670
2021-09-29 17:15:23 +02:00
df9120b365 Fix T89864: Adding an asset referencing other objects adds it to scene but only adds data-blocks of referenced objects.
Link/append code needs proper access to scene/view3d data to handle
collections/objects instantiation.

Note that this is a temporary hack more than a proper fix, which would require
a deeper redesign of drag&drop code.

Also note that this will not handle 'properly' (i.e. as user would
expect it) cases like implicitely appended parent objects, in that only
the explicitely appended object will be dropped to the nes location, the
others will remain at their original coordinates.

Differential Revision: https://developer.blender.org/D12696
2021-09-29 17:10:42 +02:00
6aac892fad Cleanup: Enforce C linkage for internal File Browser header
This will be used by C++ code in the upcoming asset catalog UI commit.
2021-09-29 16:59:48 +02:00
367775ac6a Fix Cycles use of uninitialized value in volume stack intersection on CPU
Could cause an actual bug but probability is low in practice.
2021-09-29 16:37:32 +02:00
4d4113adc2 Cycles: record large number of transparent shadow intersections on CPU
So we can do fewer intersection calls, only on the GPU do we need to save
memory and do this in small steps.

Ref T87836
2021-09-29 16:37:32 +02:00
fe070fe33b Fix Cycles crash in certain hair configurations
The issue was caused by hair shader setup setting normal to a non
finite value, which then gets used to create a ray with non-finite
direction, making BVH traversal to run out of stack memory.

Happens with 150_0040_A.lighting.blend frame 112 of the Sprites
project.

Differential Revision: https://developer.blender.org/D12692
2021-09-29 16:14:23 +02:00
901fa96b7f Keymap: New preference to open folders on single click in file browser
Introduce a new keymap preference to navigate into folders by clicking on them once instead of twice.
Makes browsing folders faster albeit non-standard, so keeping this off by default for now.

Does not affect Industry Compatible or other keymaps.

It is still the possible to right-click to open context menu, hold Ctrl or Shift to select multiple items:

{F10651030, size=full}

----

Keymap preference:

{F10652759, size=full}

Part of T91537

Reviewed By: fsiddi, campbellbarton

Differential Revision: https://developer.blender.org/D12667
2021-09-29 15:57:57 +02:00
1f4545dc9c Cleanup: else-after-return 2021-09-29 15:48:16 +02:00
b80ed8396d Fix T89164: Sculpt "Smooth" brush crash with zero pressure
Caused by {rB3e5431fdf439}

Issue is that sculpting could start with using `SCULPT_smooth` and
(because of the Pressure sensitivity dropping to zero) code would switch
to `SCULPT_enhance_details_brush` at strength zero.
Issue with this though is that this can be in the middle or end of a
stroke and the necessary `ss->cache->detail_directions` are only
initialized for the first brush step (see
`SCULPT_stroke_is_first_brush_step` in `SCULPT_enhance_details_brush`).
With these missing, it could only go downhill from there.

Suggest to prevent the "mode-flip" from `SCULPT_smooth` to
`SCULPT_enhance_details_brush` (happening solely because of pressure
strength) by changing the condition.
Now do `SCULPT_enhance_details_brush` only if strength is **below** zero
and `SCULPT_smooth` else (flipping from enhance_details to regular smooth
is fine).

If inverting the brush in the middle of the stroke will be supported at
some point, the codepath of `smooth` would have to inform the cache that
invert changed and detail_directions would have to be initialized then
(even if not at the start of the stroke).

Maniphest Tasks: T89164

Differential Revision: https://developer.blender.org/D12676
2021-09-29 15:07:45 +02:00
c33a005297 Texts in Outliner dont activate
Texts in Outliner dont activate on selecting (Text Editor did not change
to selected text) which is a bit inconsistent to other ID types.

ref T90862

Maniphest Tasks: T90862

Differential Revision: https://developer.blender.org/D12412
2021-09-29 15:07:13 +02:00
ef29bf9023 Assets: Expose option to reuse data-block data when appending
With 794c2828af & f48a4aa0f9 it's possible to reuse possibly
expensive, nested data of a data-block when appending. E.g. the
texture of a material, or the mesh of an object. Without this it's easy
to bloat memory and the file size. Duplicated textures also cause
unnecessary shader recompilations.

The feature was intended to be the new default behavior for the Asset
Browser, but it wasn't actually added to the UI yet. This patch adds a
new import type option to the Asset Browser. So from the menu in the
header, you can now choose between:

* Link
* Append
* Append (Reuse Data)

The latter is the new default.

Maniphest Task: https://developer.blender.org/T91741

Differential Revision: https://developer.blender.org/D12647

Reviewed by: Sybren Stüvel, Bastien Montagne
2021-09-29 15:02:38 +02:00
Falk David
5cebcb415e VSE: Add color tags to strips
This patch adds color tags to VSE strips, an overlay option to toggle the colors
on and off, a section in the theme settings to define the 9 possible colors and
two ways of changing the color tag through the UI. You can change the color
through the right-click context menu, or in the strip side panel next to the
strip name.

Color tags are defined in user preferences and they can be disabled in overlay
settings.

Reviewed By: campbellbarton, ISS

Differential Revision: https://developer.blender.org/D12405
2021-09-29 14:34:01 +02:00
ffb9577ac9 Cycles: Ensure finite displacement and background evaluation
Avoids possible numerical issues in the path tracing kernel, which
is most important for displacement as non-finite values in BVH can
lead to infinite node recursion during traversal.

Differential Revision: https://developer.blender.org/D12690
2021-09-29 14:06:10 +02:00
731325a022 Cycles: Make sure GPU transfer is finished prior display update
Noticed while looking into flickering issues in viewport.

Doesn't seem to solve the flicker issue for me, but is something
what is supposed to be happening anyway.

Differential Revision: https://developer.blender.org/D12673
2021-09-29 14:05:51 +02:00
adaf4f56e1 Support loading catalogs in the Current File asset library
When the Asset Browser shows the "Current File" asset library, now it
also attempts to load an asset catalog definition file from location of
the current .blend file. This happens as follows:
* First, see if the file is inside of an asset library that is "mounted" in the
  Preferences. Load the catalogs from there if so.
* Otherwise, if the file is saved, load the catalogs from the directory the
  file is saved in.
* If the file is not saved, no catalogs will be loaded.

Unit tests are being worked on in D12689.

Creating catalogs from the "Current File" asset library still doesn't work, as
the asset catalog service doesn't construct an in-memory catalog definition
file in that case yet.

Differential Revision: https://developer.blender.org/D12675
2021-09-29 13:18:44 +02:00
Gaia Clary
78b9a8c7b9 Add an option to silence bpy.ops.anim.keyframe_delete_v3d when used in Addons
The issues:

1.) When we want to remove keyframes from a range of frames in an
action,
then we can use bpy.ops.anim.keyframe_delete_v3d to remove the keys
frame by frame. However, whenever the operator hits a frame with no
keyframes, then it generates an error. While when it hits a frame
with keyframes, then it reports the numbner of removed keys.

This creates a lot of unnecessary noise in the Blender console.

2.) Furthermore a related issue is that WM_event_add_notifier() is
called also when no frames where removed. This seems to significantly
slow down the removal of keyframes in a range of frames at least
when i use vscode for debugging.

A proposal for improvement:
This patch adds an attribute 'confirm_success' which controls
if the operator reports back what it did (or did not) while
executing. Silent mode would then be called like this:

bpy.ops.anim.keyframe_delete_v3d(confirm_success=False)

Note: confirm_success is True by default so this patchj does not
change the behavior of Blender, it only gives the option to scripts.

3.) Personal note:
I have chosen the attribute name to be equal as it is used
in other related operators. However i rather would rename the
attribute to "verbose" (preferred) or "with_confirm". But i let this
to be decided by the reviewers. Thanks for your time to review!

Reviewed By: campbellbarton

Differential Revision: https://developer.blender.org/D12629
2021-09-29 13:09:17 +02:00
6351c73b75 Fix T88954: Rearranging of modifiers for linked objects no longer works.
There would be no modifier set in context in drag and drop case, in that
case try to get active modifier from active object instead.
2021-09-29 12:53:57 +02:00
0c32e3b312 Fix T91756: String to Curve node produces NaN when size is zero 2021-09-29 12:40:36 +02:00
4cf4bb2664 UI: swap tool and regular header
Swap the tool-header and header order so the tool-header
so the header is always next to the window edge.

Note that files saved in 3.0 will have overlapping headers when opened
in any version of Blender before this commit.

Reviewed By: Severin, fsiddi

Maniphest Tasks: T91536

Ref D12631
2021-09-29 20:03:47 +10:00
eabb134840 Fix T91802: vertex color layer name collides with itself
Vertex colors are already included in `mesh.attributes`. So they don't
have to be added to the collision checks separately.
2021-09-29 11:01:17 +02:00
24a965bb16 Fix T91767: crash when instancing geometry coming from modifier
The issue was that the `GeometrySet` that comes from the modifier does
not have full ownership of the mesh for legacy reasons to avoid copies.
Calling `ensure_owns_direct_data` makes sure that the geometry set
actually owns the geometry so that it can be instanced.
2021-09-29 10:55:32 +02:00
f51bef75f4 Geometry Nodes: instance on points in instances
For consistency with other nodes, we also want to process
all instances in the Points input independently. This allows
for more efficient instancing of many objects but also leads
to nested instancing. All instances are processed in their
local space, so that instances don't have to be realized.

Differential Revision: https://developer.blender.org/D12660
2021-09-29 10:10:12 +02:00
8cbec0beb2 Fix/bypass doversion for wire new colors
Some cases were not covered by the original doversion in
4a0ddeb62b. For now we make it always change the wire color regardless
of whether it was changed before or not.

This do a subversion bump.
2021-09-29 09:58:55 +02:00
Siddhartha Jejurkar
a285299ebb UV: Pack to closest/active UDIM
Implements T78397
Extends the functionality of pack islands operator to allow packing UVs
to either the closest or active UDIM tile.
This provides 2 new options for packing UVs :

* Closest UDIM: Selected UVs will be packed to the UDIM tile they were
  placed on. If not present on a valid UDIM tile, the UVs will be packed
  to the closest UDIM in UV space
* Active UDIM: Selected UVs will be packed to the active UDIM image tile
  In case, no image is present in the UV editor, then UVs will be packed
  to the tile on the UDIM grid where the 2D cursor is located.

Reviewed By: campbellbarton

Maniphest Tasks: T78397

Ref D12680
2021-09-29 17:53:09 +10:00
Siddhartha Jejurkar
bf06f76be6 UV Editor: Grid and snapping improvements
Implements T89789, T89792, custom grid (described as dynamic grid in
T78389) and UV grid snapping (T78391)
Replaces the default UV editor grid with 2 new types of grid :

* Custom grid: Allows the user to create an NxN grid, where the value
  of N is specified by the user.
* Subdividing grid: Subdivides the UV editor grid when the user
  zooms in the viewport and vice versa when zooming out.

UV snapping improvements :
* Increment snapping: Increment values for snapping are calculated based
  on which grid type is being used in the UV editor
  (subdividing or custom). In general the increment value is equal to
  the distance between 2 visible grid lines.
* Absolute grid snap: New toggle added to increment snapping option in
  the UV editor, allows UV grid snapping during translation.

Reviewed By: campbellbarton

Ref D12684
2021-09-29 17:48:35 +10:00
008ae26712 Fix T91237: Wrong Editors could sync animation 'Visible Range'
This was reported for the Outliner.

It was possible to set 'show_locked_time' on any space (via python, not
sure if there are other ways to achieve this).
Navigating in an animation editor obviously ruined the layout in certain
Editors that are not made for this.

Now restrict syncing to editors that support it well (the ones that have
this setting exposed in their menus) and prevent setting this in RNA.

Maniphest Tasks: T91237

Differential Revision: https://developer.blender.org/D12512
2021-09-29 09:12:47 +02:00
eddc3f5bc8 Cleanup: Add constructor for AttributeFieldInput 2021-09-28 23:19:33 -05:00
756c22bb41 Cleanup: Compositor: Migrate color nodes to new socket builder 2021-09-29 00:09:41 -04:00
d1220f795f UI: Update Levels Nodes
- Instead of making the enum expanded leave it in menu form.
- Use full words instead of letters.

Differential Revision: https://developer.blender.org/D12686
2021-09-28 21:36:15 -04:00
8e40bb2dea Nodes: Fix compositor viewer nodes having wrong alpha channel
Default should be black image with an alpha value of 1.
2021-09-28 20:33:42 -04:00
84251acfcc Cleanup: Compositor: Migrate most output nodes to new socket builder
This migrates most nodes except for the file output node.
This node requires dynamic sockets so its implementation will be more involved.
2021-09-28 20:13:42 -04:00
e81533b25e Cleanup: Simplify compositor Z Combine operation conversion 2021-09-28 18:46:10 -04:00
f0f70729b1 Fix: Knife undo with no cut segments left
Now if a user presses the knife tool undo key when there are no more cut segments to undo, the operator exits. Previously, it did nothing.
2021-09-28 23:09:54 +01:00
7f5d62dfc6 Cleanup: Make format 2021-09-28 18:03:33 -04:00
4a48482247 Cleanup: Compositor: Migrate most input nodes to new socket builder
This migrates most nodes except for the image/render layer nodes.
These nodes require dynamic sockets so their implementation will be more involved.
2021-09-28 18:00:14 -04:00
960b21e1d7 Cleanup: sort cmake file lists 2021-09-29 07:30:34 +10:00
6dceaafe5a Cleanup: trailing space, newlines at EOF 2021-09-29 07:30:34 +10:00
b524153d61 Cleanup: use C comments for plain text 2021-09-29 07:30:34 +10:00
79290f5160 Cleanup: spelling in comments 2021-09-29 07:29:15 +10:00
efe3a13b55 Cleanup: Removed redundant if macro 2021-09-28 21:57:42 +01:00
9f0a3a99ab Geometry Nodes: Fields version of attribute proximity node
Add a fields-aware implementation of the attribute proximity node.
The Source position is an implicit position field, but can be
connected with a position input node with alterations before use.
The target input and mode function the same as the original node.

Patch by Johnny Matthews with edits from Hans Goudey (@HooglyBoogly).

Differential Revision: https://developer.blender.org/D12635
2021-09-28 15:21:36 -05:00
283d76a70d Compositor: Full frame Glare node
Part of T88150.
2021-09-28 22:00:17 +02:00
0830211c95 Cleanup: Remove XRange and YRange in Compositor
Mostly unused and originally meant for areas with positive values.
With canvas compositing areas position may be negative.
2021-09-28 22:00:17 +02:00
f84fb12f5d Compositor: Add support for canvas compositing
This commit adds functionality for operations that require pixel
translation or resizing on "Full Frame" mode, allowing to adjust
their canvas. It fixes most cropping issues in translate, scale,
rotate and transform nodes by adjusting their canvas to the result,
instead of the input canvas.

Operations output buffer is still always on (0,0) position for
easier image algorithm implementation, even when the
canvas is not.

Current limitations (will be addressed on bcon2):
- Displayed translation in Viewer node is limited to 6000px.
- When scaling up the canvas size is limited to the
 scene resolution size x 1.5 . From that point it crops.

If none of these limitations are hit, the Viewer node displays
the full input with any translation.

Differential Revision: https://developer.blender.org/D12466
2021-09-28 22:00:17 +02:00
76377f0176 Compositor: Replace resolution concept by canvas
This is a code refactor in preparation of supporting canvas
compositing. See {D12466}.

No functional changes, all canvases are at (0,0) position matching
tiled implementation.

Differential Revision: https://developer.blender.org/D12465
2021-09-28 22:00:16 +02:00
2ecd963d87 Fix error in previous commit
`v_other` -> `v_step`
2021-09-28 16:57:49 -03:00
5cdb2aadfc Fix flag wrongly set in 'BM_face_split_edgenet_connect_islands'
Sometimes the `use_partial_connect` option could trigger the assert:
```
BLI_assert(!BM_elem_flag_test(l_iter->v, VERT_NOT_IN_STACK));
```

This can happen when `v_delimit->e` is not part of edgenet, so `v_other` will not have the flag.
2021-09-28 16:54:23 -03:00
Aaron Carlisle
c7a7c3f5e5 Cleanup: convert compositor nodes to c++
- Many cleanups of to use list base
- Some variable changes

These change is needed to migrate to the new socket builder API

Reviewed By: manzanilla

Differential Revision: https://developer.blender.org/D12366
2021-09-28 15:30:23 -04:00
87e315c237 Cleanup: Sort node types alphabetically 2021-09-28 14:20:29 -05:00
Johnny Matthews
85aac0ef6a Geometry Nodes: Field version of curve reverse node
The updated version has a selection input as a field
and does not realize instances implicitly.

Differential Revision: https://developer.blender.org/D12506
2021-09-28 13:53:20 -05:00
cc653c9b02 Fix potential render tests error with invalid utf-8 characters
In general should not happen, but better to report the actual error instead
of the Python test code failing.
2021-09-28 20:50:38 +02:00
95fca22bfe Geometry Nodes: Remove experimental option for fields
This enables fields as the official workflow for geometry nodes.
While many features are converted to use fields rather than the old
attribute workflow, many are not yet converted. In that case, the
unconverted nodes are still accessible with an experimental option.
In the coming weeks the rest of the nodes will be converted.

Differential Revision: https://developer.blender.org/D12672
2021-09-28 13:22:52 -05:00
86ec9d79ec Fix build without Cycles HIP device 2021-09-28 20:00:55 +02:00
e45ffce5fa Geometry Nodes: Use factor slider for distribution density factor
Though the factor isn't so useful to adjust by itself, and is mostly
useful when used with a field connected, the slider from 0 to 1 can
help to make it clear that it's just used as a multiplier for the max
density after distribution.

Differential Revision: https://developer.blender.org/D12654
2021-09-28 12:44:50 -05:00
Erik Abrahamsson
faedfd5740 Fix VS2017 compile error in String to Curves node
Because of a bug in VS2017 codecvt is replaced with Blender
BLI functions to convert from UTF8 to UTF32.

Differential Revision: https://developer.blender.org/D12655
2021-09-28 12:37:56 -05:00
Brian Savery
044a77352f Cycles: add HIP device support for AMD GPUs
NOTE: this feature is not ready for user testing, and not yet enabled in daily
builds. It is being merged now for easier collaboration on development.

HIP is a heterogenous compute interface allowing C++ code to be executed on
GPUs similar to CUDA. It is intended to bring back AMD GPU rendering support
on Windows and Linux.

https://github.com/ROCm-Developer-Tools/HIP.

As of the time of writing, it should compile and run on Linux with existing
HIP compilers and driver runtimes. Publicly available compilers and drivers
for Windows will come later.

See task T91571 for more details on the current status and work remaining
to be done.

Credits:

Sayak Biswas (AMD)
Arya Rafii (AMD)
Brian Savery (AMD)

Differential Revision: https://developer.blender.org/D12578
2021-09-28 19:18:55 +02:00
262b211856 Geometry Nodes: Mesh Point Cloud Conversion Nodes
This commit adds nodes to do direct conversion between meshes and point
clouds in geometry nodes. The conversion from mesh to points is helpful
to instance once per face, or once per edge, which was previously only
possibly with ugly work-arounds. Fields can be evaluated on the mesh
to pass them to the points with the attribute capture node.

The other conversion, point cloud to mesh vertices, is a bit less
obvious, though it is still a common request from users. It's helpful
for flexibility when passing data around, better visualization in the
viewport (and in the future, cycles), and the simplicity of points.

This is a step towards T91754, where point clouds are currently
combined with meshes when outputing to the next modifier after geometry
nodes. Since we're removing the implicit behavior for realizing
instances, it feels natural to use an explicit node to convert points
to vertices too.

Differential Revision: https://developer.blender.org/D12657
2021-09-28 12:14:13 -05:00
797064544e Geometry Nodes: Only show attribute toggle for field inputs
Change the toggle to switch between an attribute and a single value to
only display for inputs that are fields, as determined statically by
the field inferencing added in rB61f3d4eb7c7db7. This means the field
inferencing must be calculated on file load, since it's used in the UI.

Differential Revision: https://developer.blender.org/D12623
2021-09-28 12:05:42 -05:00
44e4f077a9 Geometry Nodes: Run nodes once on unique instance data
As described in T91672, often it can be much more efficient to run each
node only on the unique geometry of the instances, rather than realizing
all instances and potentially processing redundant data. Sometimes the
performance difference can be completely smooth vs. completely unusable.

Geometry nodes used to hide that choice from users by always realizing
instances, but recently we have decided to expose it. So this commit
makes nodes run once per unique reference in the entire tree of nested
instances in their input geometries, continuing the work started in
rB0559971ab377 and rBf94164d89629f0d2. For the old behavior, a realize
instances node can be added before the nodes, which is done in the
versioning code.

Differential Revision: https://developer.blender.org/D12656
2021-09-28 11:36:28 -05:00
b32b38b380 Fix T89400: Possible to delete objects used by overrides of collections.
This should not be allowed in general, added some initial call to check
when user is allowed to delete a data to search for mandatory override
usages...
2021-09-28 18:30:33 +02:00
f35ea668a1 Geometry Nodes: Move more nodes to legacy
- Curve to Points: Needs output sockets
- Curve Endpoitns: Needs the same output sockets
- Edge Split: Should have a selection input instead
- Subdivision Surface: Should not use "crease" implicitly
All new versions of these nodes should also not implicitly
realize instances.
2021-09-28 11:03:12 -05:00
e694165123 VSE: fix versioning code to the new maximum zoom level (128)
Since we bumped the number of channels to 128, I forgot to doversion the
editors. So new files (new editors) would have this right, but not
existing files.

Fixup to: 8fecc2a852
2021-09-28 17:58:41 +02:00
6ee2f2da96 Cleanup: asset catalog, remove obsolete TODO
No functional changes.
2021-09-28 17:47:34 +02:00
10d926cd4a Cleanup: asset catalogs, move file header definition to constant
Define the standard catalog definition file header in a constant,
separating it from the function that writes the entire file.

No functional changes.
2021-09-28 17:47:34 +02:00
3acf3e9e2f Geometry Nodes: don't realize instances in Instance on Points node
Part of T91672.
2021-09-28 17:46:32 +02:00
330a04d7c7 Fix T91393: Duplicating an action with python crashes Blender.
Own mistake when making NLA overridable, instead of assuming things
about the ID owner of the animation data being processed, properly
return and use the one found by `ED_actedit_animdata_from_context`.
2021-09-28 17:41:40 +02:00
53fa4801a0 Fix: Fluid/Cloth/DynamicPaint: Only share pointcaches in CoW case.
Particle copying code was already properly sharing pointcache between
orig data and its copy only when `LIB_ID_COPY_SET_COPIED_ON_WRITE` is
set, do the same for the other point cache users.

Using `LIB_ID_CREATE_NO_MAIN` here is waaaaaaay to much wide scope for
such a dangerous/advanced behavior, that kind of things has to be
strictly restricted in scope.
2021-09-28 17:41:40 +02:00
34ba6968b2 Cleanup: asset catalog service, remove obsolete write_to_disk function
Remove `AssetCatalogService::write_to_disk()` function. It has been
superseded by `write_to_disk_on_blendfile_save()`; the handful of test
functions that called the old function have been adjusted to use the
new one.

No functional changes to Blender itself.
2021-09-28 17:32:58 +02:00
f17ca53cdd Fix wrong update with shadow catcher and transparent film
This change fixes an issue when scene has a shadow catcher and film is
configured to be transparent. Starting viewport render and making the
background non-transparent will cause bad memory access (wrong render
and possibly crash).

Film passes depends on transparency of background, so check for this.

Demo file: F10650585

Differential Revision: https://developer.blender.org/D12666
2021-09-28 17:06:16 +02:00
640c4ace0b Cycles: Disable tile-level denoising
Only do denoising on the full-frame result. Saves render time.

Can re-consider in the future when/if we'll want to support
denoising during rendering (similar to viewport) to allow artists
to stop rendering when they see image to be good enough. Until
there is a design for that workflow stick to a more time efficient
rendering.

Differential Revision: https://developer.blender.org/D12662
2021-09-28 17:05:47 +02:00
ff7e67afd5 Geometry Nodes: Dashed lines for function flow
Use dashes to represent the function flow (while keeping continuous
lines for the data-flow).

It is important to tell both flows apart (the data and the function
 flow). The sockets help with that, the noodles help this further.

The "data flow" is evaluated at every single node. A user can inspect
the output sockets of those nodes and have a glimpse at their values.

The "function flow" (nodes) however is only evaluated in the geometry
nodes. The noodles are not transporting data in the same sense of the
"data flow". All that can be inspected are the attributes the functions
depend on.

Having this clearly communicated should help users to inspect the
nodetrees, read and understand the different flows in the same tree.

---

Known limitations:

At the moment the dash lines are not equidistant:

* It would be nice to get the "uv.x" to be resampled for the bezier curve
so the dashes are equally distributed in the curve.

* Using distance between the P3 and P0 instead of the real bezier curve
length seems to be fine.

---

Full disclaimer:

Changes with that much of a visual impact tend to be controversial. So
far the main feedback is that dashed lines can be associated to broken
link, and that there are better ways to represent the flows (or
different information that should be visually represented).

I'm fully aware of that. However dashed lines are already used in the
viewport and outliner to indicate (hierarchical) relation. Besides,
other approaches (double-lines, having the data flow to be more
distinct, ...) didn't pan out in the end (or didn't look as good as
this).

---

Impact in other editors:

The compositor uses mostly a "data flow" nodetree, so no change is
expected there.

The shader nodetree is one that could but doesn't have to change its
visual language.

The shader nodetree uses mostly "function flow" with some "data flow" nodes.
One can argue that it should be adapted to follow the
same pattern as geometry nodes (with the new noodles and the diamond
sockets). Oh the other hand, a shader nodetree has a single context.
When a node depends on the "UV", there is only one UV at a time for the
entire nodetree. So it can also be treated as a psedo "data flow"
nodetree if we want to avoid too many changes in other parts of Blender.

Differential Revision: https://developer.blender.org/D12602
2021-09-28 17:03:03 +02:00
728ae33f37 Cycles: Improve handling of tile file error
Expose them to the interface, and stop rendering as soon as possible.

Differential Revision: https://developer.blender.org/D12617
2021-09-28 16:58:27 +02:00
52a702468a Asset Catalog Service: add function to change catalog path
Add `AssetCatalogService::update_catalog_path()` to change the catalog
path of the given catalog, and also change the path of all the catalogs
contained within the given catalog.

Rebuilds the tree structure for the UI, but does not save the new catalog
definitions to disk.

No user-facing changes, just backend preparation for UI work.
2021-09-28 16:09:12 +02:00
d2004326a1 Geometry Nodes: remove empty mesh component in distribute node output 2021-09-28 15:52:31 +02:00
3e78c9e5bb Fix T91766: NLA Editor - Segmentation fault on strip resize
NLA and Dope Sheet use a specific transform operation to scale.

Unlike the conventional resize operation, `TIME_SCALE` operates on `td->val`.

This is a bit outside the convention of transform operators.

The expected thing in this case would be to work in `td->loc` and use the conventional resize operator.

But for now, to fix the problem, use `td->loc` in the `TIME_SCALE` operation.

This commit also brings a cleanup in the style of some comments and removing unnecessary `memset`.
2021-09-28 10:24:02 -03:00
3674347849 Assets: Clear Asset operator variants for clearing/setting Fake User
The Clear Asset operator (`ASSET_OT_clear`) now clears the Fake User.
This makes it symmetrical with the Mark Asset (`ASSET_OT_mark`)
operator, which sets Fake User to ensure assets are always saved to
disk.

Clear Asset now also has a `set_fake_user` boolean option, which allows
users to Clear Asset and set Fake User in one go.

The asset browser now shows these options in the context menu:
- Clear Asset: also clears Fake User. This makes it possible to actually
  remove assets from the blend file without leaving the Asset Browser.
- Clear Asset (Set Fake User): keeps the Fake User bit set. This makes
  it possible to "hide" the asset from the asset browser, without
  loosing the actual data.

Internally, the `ED_asset_clear_id(id)` function now always clears the
Fake User bit. If it was intended that this bit was kept set, it's up to
the caller to explicitly call `id_fake_user_set(id)` afterwards.

Manifest Task: T90844

Reviewed By: Severin

Differential Revision: https://developer.blender.org/D12663
2021-09-28 15:04:55 +02:00
73b2ecb297 Cleanup: typo in comment
Noticed by @david_black in D12392, thx!
2021-09-28 14:37:06 +02:00
Vitor Boschi da Silva
9490db1ad2 Cleanup: remove unused variable
As the title says

Reviewed By: lichtwerk, campbellbarton

Differential Revision: https://developer.blender.org/D12665
2021-09-28 14:29:02 +02:00
6a745e54f6 Cleanup: remove incorrect assert
The method works perfectly fine when `resource` is empty.
2021-09-28 13:32:22 +02:00
5d160dec3b Geometry Nodes: move legacy nodes to separate folder
Previously, we were moving them one by one. It's a lot easier
to just move all files at the same time.
2021-09-28 11:31:46 +02:00
b3431a8846 Fix Drivers Editor showing playhead on the X Axis
Currently the Drivers Editor shows this (the blue thing can be dragged
to change frame):
{F10647661}

But the Drivers Editors X axis is the output of the driver [which can be
further tweaked by the curve] not time(frame).
So it seems better to not mix them here, it is just confusing to have
two different units on one axis.
Especially since what we really want to look at in X (the drivers output
value) can be in a totally unrelated range compared to frames, so e.g.
we might be interested in a drivers range from 0.0 to 1.0 and a
framerange of 100 to 200, so putting this on one axis just does not make
sense. Better to use a separate timeline for this.

Note 2.79 also did not do this.

Maniphest Tasks: T91157

Differential Revision: https://developer.blender.org/D12392
2021-09-28 11:14:44 +02:00
6f29801f1b Fix Drivers Editor not hiding vertical part of cursor
When "Show Cursor" is unchecked, the Drivers Editor would still display
the vertical line representing the cursor x.

Probably overseen in {rB65072499c65a} (historically the vertical line
could represent either the current frame of the cursor X in drawing, but
this is now much more separate).

There is no point in seeing part of the cursor in the Drivers Editor if
this is disabled.

Also correct outdated comments.

ref. T91157

Maniphest Tasks: T91157

Differential Revision: https://developer.blender.org/D12391
2021-09-28 11:14:44 +02:00
b91946780c Path util: BLI_path_contains() case-insensitive on Windows
Make `BLI_path_contains()` case-insensitive on Windows. This behaviour
is dependent on the platform Blender is running on, like the rest of
BLI_path, and not on the style of paths (Windows-style paths will be
treated case-sensitively when Blender is running on Linux/macOS).
2021-09-28 11:05:45 +02:00
741fa8180c Fix T91679: Crash when saving bordered render as multilayer exr
The related issue which is fixed by this change is the missing noisy
image pass when denoising and border render is used,

Need to allocate passes after the passes has been copied from the
original render result.
2021-09-28 10:49:01 +02:00
e5ff9f3615 Cleanup: Move VSE channels check into own util function
Differential Revision: https://developer.blender.org/D12661
2021-09-28 10:44:39 +02:00
a64782b133 VSE: Implement sanity check for files with more channels than supported
This is a follow up to 8fecc2a852.

This makes sure future .blend files that have more channels than the
limit won't break Blender.

It can be backported to LTS.

This is part of https://developer.blender.org/D12645

Differential Revision: https://developer.blender.org/D12648
2021-09-28 10:23:13 +02:00
7cd43a9d28 Fix: field inferencing fails when there are undefined nodes 2021-09-28 10:19:16 +02:00
def8fd6330 Cleanup: support moving InstanceReference 2021-09-28 10:17:49 +02:00
e7b9423623 Geometry Nodes: multi-threading when modifying multiple geometry sets
Differential Revision: https://developer.blender.org/D12652
2021-09-28 10:17:00 +02:00
c7d94a7827 UI: avoid excessive padding for labels in headers
Labels in headers reserved space for an icon even when no icon was used.

This is caused by the shared function ui_text_icon_width adding 1.5x
a buttons X-units width the the width of the string.

Menu buttons detected this and subtracted the extra padding.

Instead of adding the same workaround for labels,
add ui_text_icon_width_ex that takes a padding argument.

Add presets for 'default', 'compact' and 'none' to avoid duplicating
padding values.

This allows removal of hard-coded label scaling for the add-object tool.
2021-09-28 14:36:52 +10:00
986d60490c Asset Browser: Allow World assets to be drag/dropped onto the viewport
While World data has always been able to be marked as an asset, there
was no way to actually use them from the asset browser. This change
allows users to drag-drop world assets onto the Viewport and have them
appended/linked to their scene.

Differential Revision: https://developer.blender.org/D12566
2021-09-27 21:00:17 -07:00
c53ffda8a4 Cleanup: Fix incorrect comments 2021-09-27 13:29:53 -05:00
f94164d896 Geometry Nodes: Do not realize instances in the material assign node
Only run the node once for every unique geometry set in the input's
instance heirarchy. This can massively improve performance when
there are many instances, but it will mean that the result is the same
for every instance. For the previous behavior, a "Realize Instances"
node can be used before this one.

This node can be changed without versioning since the old material
assign node was already deprecated and replaced.
2021-09-27 13:22:44 -05:00
5d70a4d7ee Geometry Nodes: Move output attribute names to a subpanel
In a sub-panel it will be clearer that they are outputs, since they
just look like more inputs now. Unfortunately it is not possible to
make sub-panels display conditionally currently, so the output
sub-panel will always be visible whether or not it is empty.

Differential Revision: https://developer.blender.org/D12653
2021-09-27 13:04:58 -05:00
e6aabcae14 Fix part of T91516: Cycles not rendering geometry nodes instances
Part of the fix is by Jacques. This fixes the most obvious case, but it's
still not clear how to deal with non-mesh geometry instances or how to handle
motion blur for such instances.
2021-09-27 19:49:43 +02:00
50b7253257 Cleanup: fix (harmless) uninitialized variable usage 2021-09-27 19:49:43 +02:00
8da23fd5aa Constraints: change default Stretch To rotation type to Swing.
As also explained in D6134, in most case of Stretch To usage in
rigs, it is desirable to use swing rotation, either via the old
method of pairing the constraint with Damped Track, or via the
Swing rotation type introduced in 2.82. This is for instance true
for all usages of the constraint in Rigify.

The reason can be understood by realizing that unlike order-
dependent euler rotations, swing is not biased to an axis, and
isn't affected by gimbal lock effects at merely 90 degrees
of rotation (it has only one singularity at 180 degrees).

Thus it makes sense to change the default for newly created
constraints to the Swing mode. This has no backward compatibility
concerns except for old tutorials and rig generation scripts.

Differential Revision: https://developer.blender.org/D12643
2021-09-27 20:45:03 +03:00
8967bcb755 Update RNA to user manual url mappings 2021-09-27 13:42:41 -04:00
847d355cab File/Asset Browser: Don't deselect other items when dragging
Basically this enables the select-tweaking behavior as per the
guidelines:
https://wiki.blender.org/wiki/Human_Interface_Guidelines/Selection#Select-tweaking.

We use this in most other other editors that allow selecting and
dragging multiple items. But besides the consistency improvement, this
is important if we want to support dragging multiple assets (or files)
in future. We want to support this at least for dragging multiple assets
into an asset catalog for the upcoming asset catalog UI.
2021-09-27 18:52:16 +02:00
c76ccd85be Cleanup: incorrect null check in asset library
Found by clang tidy (P2439).
2021-09-27 18:42:19 +02:00
11bfbc3337 Fix: Incorrect node socket name after recent refactor
Caused by rBc99cb814520480379
2021-09-27 11:21:33 -05:00
c75c08a737 Geometry Nodes: Distribute points once per instance reference
With this commit, the distribute points on faces node runs only
once for every unique mesh in its input. That means if there are
100 instances of the same mesh, it will only run once.

This basically reverts rB84a4f2ae68d408301. The optimization there
didn't end up being worth it in the end, since it complicates code
quite a lot. It's also incompatible with this method of dealing with
instances, and it breaks field evaluation for instances, where we would
have to make sure to handle each instance transform properly otherwise,
evaluating the field separately for every instance.

Differential Revision: https://developer.blender.org/D12630
2021-09-27 11:16:25 -05:00
efa9667c09 Cleanup: Asset catalogs, fix clang-tidy warning
Change `auto &catalog` to `const auto &catalog`.

No functional changes.
2021-09-27 18:14:44 +02:00
10061ee18a Asset Catalogs: write catalogs to disk when saving the blend file
The Asset Catalog Definition File is now saved whenever the blend file
is saved. The location of the CDF depends on where the blend file is
saved, and whether previously a CDF was already loaded, according to the
following rules. The first matching rule wins:

1. Already loaded a CDF from disk? -> Always write to that file.
2. The directory containing the blend file has a
   `blender_assets.cats.txt` file? -> Merge with & write to that file.
3. The directory containing the blend file is part of an asset library,
   as per the user's preferences? -> Merge with & write to
   `${ASSET_LIBRARY_ROOT}/blender_assets.cats.txt`
4. Create a new file `blender_assets.cats.txt` next to the blend file.
2021-09-27 18:14:21 +02:00
90aa0a5256 BKE Preferences: find asset library containing a path
Add `BKE_preferences_asset_library_containing_path(&U, some_path)` that
finds the asset library that contains the given path.

This is a simple linear search, returning the first asset library that
matches. There is no smartness when it comes to nested asset libraries
(like returning the library with the best-matching path), although this
could be a useful feature to add later.
2021-09-27 18:10:47 +02:00
aafbe111fc BLI Path: add function BLI_path_contains()
Add function `BLI_path_contains(container, containee)` that returns true
if and only `container` contains `containee`.

Paths are normalised and converted to native path separators before
comparing. Relative paths are *not* made absolute, to simplify the
function call; if this is necessary the caller has to do this conversion
first.
2021-09-27 18:10:47 +02:00
6578db57cd Fix T91691: Selecting "Remove unused slots" in Materials panel removes slots that are assigned to particle systems/hair.
`BKE_object_material_slot_used` would only check obdata usages, but
particle settings can also (weirdly enough) use objects' material slots.

So now, as its name suggests, `BKE_object_material_slot_used` does take
an object as parameter, and also checks for potential slot usage from
psys in the object.
2021-09-27 18:09:20 +02:00
824733ea47 Assets: Additions/fixes to the catalog system in preparation for the UI
* Fixes missing update of the catalog tree when adding catalogs.
* Adds iterators for the catalogs, needed for UI code.
* Store catalog ID in the catalog tree items, needed for UI code.
* Other smaller API additions for the UI.
* Improve comments and smaller cleanups.

New functions are covered with unit tests.

Differential Revision: https://developer.blender.org/D12618

Reviewed by: Sybren Stüvel
2021-09-27 17:49:31 +02:00
5bea5e25d5 Fix T91728: Cycles render artifacts with motion blur and object attributes 2021-09-27 17:40:03 +02:00
0559971ab3 Geometry Nodes: add utility to process all instances separately
This adds a new `GeometrySet::modify_geometry_sets` method that can be
used to update each sub-geometry-set separately without making any
instances real.

Differential Revision: https://developer.blender.org/D12650
2021-09-27 17:35:45 +02:00
2189dfd6e2 Cycles: Rework OptiX visibility flags handling
Before the visibility test against the visibility flags was performed in an any-hit program in OptiX
(called `__anyhit__kernel_optix_visibility_test`), which was using the `__prim_visibility` array.
This is not entirely correct however, since `__prim_visibility` is filled with the merged visibility
flags of all objects that reference that primitive, so if one object uses different visibility flags
than another object, but they both are instances of the same geometry, they would appear the same
way. The reason that the any-hit program was used rather than the OptiX instance visibility mask is
that the latter is currently limited to 8 bits only, which is not sufficient to contain all Cycles
visibility flags (12 bits).

To mostly fix the problem with multiple instances and different visibility flags, I changed things to
use the OptiX instance visibility mask for a subset of the Cycles visibility flags (`PATH_RAY_CAMERA`
to `PATH_RAY_VOLUME_SCATTER`, which fit into 8 bits) and only fall back to the visibility test any-hit
program if that isn't enough (e.g. the ray visibility mask exceeds 8 bits or when using the built-in
curves from OptiX, since the any-hit program is then also used to skip the curve endcaps).

This may also improve performance in some cases, since by default OptiX can now perform the normal
scene intersection trace calls entirely on RT cores without having to jump back to the SM on every
hit to execute the any-hit program.

Fixes T89801

Differential Revision: https://developer.blender.org/D12604
2021-09-27 17:12:43 +02:00
7270ba011c Fix two issues with recent new Append code.
* ID pointer returned by `wm_file_link_append_datablock_ex` was
  improperly extracted from `WMLinkAppendDataItem` before append step.

* Code deleting linked IDs when their local matching version was re-used
  did not properly clear `LIB_TAG_DOIT` beforehand.
2021-09-27 16:36:07 +02:00
4a0ddeb62b Nodes: Change wire color to increase contrast
If the theme used by the user did not touch the wire or the wire outline
colors this will update them as well.

This was supposed to be a part of a bigger UI theme change for 3.0. But
it was expedited because of the recent change in line thickness for the
noodles (2bd0205215).

Theme change by Pablo Vazquez.

Differential Revision: https://developer.blender.org/D12649
2021-09-27 16:09:40 +02:00
3d2ce25afd Geometry Nodes: support creating new attributes in modifier
This patch allows passing a field to the modifier as output. In the
modifier, the user can choose an attribute name. The attribute
will be filled with values computed by the field. This only works
for realized mesh/curve/point data. As mentioned in T91376, the
output domain is selected in the node group itself. We might want
to add this functionality to the modifier later as well, but not now.

Differential Revision: https://developer.blender.org/D12644
2021-09-27 15:39:47 +02:00
43167a2c25 Fix T90570: Constraint validity not updated with library overrides.
For some reason was assuming setting a property in RNA would call its
update callback if any, but this actually needs to be done separately.

So add this call to `rna_property_override_operation_apply`.
2021-09-27 15:33:58 +02:00
5949d598bc RNA: Make is clear that Scene parameter of update callback may be NULL.
There are cases where there is no way to ensure we do have/know about an
active scene. Further more, this should not be required to perform
'real' updates on data, only to perform additional special handling in
current scene (mostly related to editing tools, UI, etc.).

This pointer is actually almost never used in practice, and half of its current
 usages are fairly close to abuse of the system (like calls to
`ED_gpencil_tag_scene_gpencil` or `BKE_rigidbody_cache_reset`).

This commit ensures that the few places using this 'active scene' pointer are
safely handling the `NULL` case, and clearly document the fact that a
NULL scene pointer is valid.
2021-09-27 15:33:58 +02:00
b077f0684e RNA: Fix bad usages of scene pointer in Update callbacks.
Scene passed to the update callback is the active scene it //may// not
be that actual ID owner of the affected data (although in practice it
should always be currently).
2021-09-27 15:33:58 +02:00
a6b53ef994 Cycles: print name of kernels on errors in CUDA queue, for debugging 2021-09-27 15:24:12 +02:00
2bd0205215 Geometry Nodes: make field links thinner than other links
This makes it easier to spot which links contain fields and which
contain data. Actually, the patch makes all other links a bit thicker.
However, with soon-to-be-implemented theme changes, the
perceived thickness will be the same as before.

This is part of T91563.

Differential Revision: https://developer.blender.org/D12646
2021-09-27 15:10:28 +02:00
8fecc2a852 Increase VSE strip channels limit from 32 to 128
The original limit dates back from 2002 when Blender went open source.
After that many years some productions (e.g., Sprite Fright) are already
experiencing limitations for complex edits.

The future plans is to support an initial shorter (2?) number of
channels with support to "unlimited" channels.

Finally, I'm bumping the minimum file requirement since files with more
than 32 channels won't work well in old Blender versions.

In a future commit I will implement a sanitization so that we only read (and write)
128 channels. Making sure future changes of this number won't corrupt Blender.

Differential Revision: https://developer.blender.org/D12645
2021-09-27 14:58:03 +02:00
Peter Fog
0419c74ae8 VSE: Clamp resulting frame in multiply mode
The clamp added will ensure immediate speed direction change on
changing to/from positive/negative speed factor when using the Speed
effect strip's Multiply mode.

Reviewed By: ISS, sergey

Differential Revision: https://developer.blender.org/D12462
2021-09-27 14:41:56 +02:00
4a562f5077 Fix T91714: Cycles direct/indirect clamp distinction not working correctly 2021-09-27 14:25:22 +02:00
2a0db195c9 Fix viewport roll working wrong
Mistake in own {rB69893ef27c91}.
Was mixing screen on region coordinates.
2021-09-27 14:19:38 +02:00
e87783a5ec Cleanup: spelling in comments 2021-09-27 21:04:34 +10:00
95af9317f0 Cleanup: remove unnecessary use of MEM_SAFE_FREE macro 2021-09-27 21:04:34 +10:00
2c2e1b3d61 Fix T81922: Pose bones F-Curves hidden for unselected objects
Whilst in pose-mode, the selection filter only includes other objects in
pose-mode instead of the object selection.

This makes sense as the selection of the pose bones what the user as
acting on in the 3D view.
The object selection only makes sense to use in object mode.

Reviewed By: sybren

Maniphest Tasks: T81922

Ref D12494
2021-09-27 21:04:34 +10:00
32ffb858d6 Keymap: resolve conflict with use_alt_cursor/Ctrl-LMB to add/extrude
While the option allows tools be be activated on press instead of tweak,
this meant box-select was catching Ctrl-LMB which is also used for
add/extrude in edit mode.

Resolve this by always using tweak for selection tools,
only supporting activation on press for other tools.

Note that this doesn't impact the default configuration.
2021-09-27 21:04:34 +10:00
c618075541 Cleanup: make format 2021-09-27 12:43:54 +02:00
a13b9d20b5 Cleanup: Move asset library remove function next to add function
Better to keep such related operations close together in code.
2021-09-27 12:32:21 +02:00
d90f542b04 Cleanup: Remove function declaration without definition
There is no function definition for this declaration. Instead there is
`BKE_preferences_asset_library_remove()`.
2021-09-27 12:31:06 +02:00
5d5504d8a4 3DView: ability to cancel out of viewport roll
This adds the ability to cancel out of the roll using ESC or RMB
(which is not common for viewops -- but makes sense in the case of roll
I think). This resets the view as well as potential locked cameras to
the original orientations (but does not remove potential autokeys --
which no transform does on cancel btw.)

Maniphest Tasks: T89883

Differential Revision: https://developer.blender.org/D12582
2021-09-27 11:54:25 +02:00
69893ef27c 3DView: Use "real" angle for viewport roll
Since its introduction in {rB5c569d227b64}, the view roll was based on
horizontal movement only. Using a "real" angle not only feels more
natural but also has the benefit of getting more precission the further
away from the center you are (just like regular rotation, brush/stencil
rotation etc.). A similar thing has already been implemented in the
Grease Pencil Tools Addon, now make the blender standard roll the same.

Since this is not using the transform system, we are still lacking a
line in the viewport (this could be added but since this is always based
on the center of the view we dont necessarily need this), as well as the
additional Shift-extra-precission behavior.

Fixes T89883

Maniphest Tasks: T89883

Differential Revision: https://developer.blender.org/D12582
2021-09-27 11:53:26 +02:00
8dcddbcc07 Fix T91711: Blender 3.0 - The Rain demo scene breaks (Proxy to Override auto conversion).
Proxy conversion is a fairly particular case of liboverride creation, in
which remapping all local usages of linked data probably makes more
sense, rather than only doing so whitin the overridden 'group' of IDs.
2021-09-27 11:11:43 +02:00
30ef197c7b Kernel: allow unregistering BKE callback functions
Introduce `BKE_callback_remove()`, which undoes the effect of
`BKE_callback_add()`. It also respects `funcstore->alloc` by freeing the
removed `funcstore` when needed.

This allows for shorter-lived objects in memory to unregister their
callbacks at the end of their lifespan.

`BKE_callback_global_finalize()` has been adjusted so that the
responsibility "remove a callback" is given to one function only.

Reviewed by: campbellbarton

Differential Revision: https://developer.blender.org/D12625
2021-09-27 10:57:23 +02:00
617954c143 Geometry Nodes: new Instance on Points node
This adds a new Instance on Points node that is a replacement
for the old Point Instance node. Contrary to the old node,
it does not have a mode to instance objects or collections
directly. Instead, the node has to be used with an Object/
Collection Info to achieve the same effect.

Rotation and scale of the instances can be adjusted in the node
directly or can be controlled with a field to get some variation
between instances.

The node supports placing different instances on different points.
The user has control over which instance is placed on which point
using an Instance Index input. If that functionality is used, the
Instance Geometry has to contain multiple instances that can are
instanced separately.

Differential Revision: https://developer.blender.org/D12478
2021-09-27 10:17:17 +02:00
547f7d23ca Geometry Nodes: support outputting collection children as instances
This adds two new input sockets to the Collection Info node:
* `Separate Children`: When turned off, the entire collection is output as a single
  collection instance (same behavior as before). When turned on, each child of
  the collection is output as a separate instance (children can be objects and collections).
  Toggling this input should not change the visual transforms of the output geometry.
* `Reset Children`: Only used when `Separate Children` is on. When used, the transforms
  of the instances are reset to the origin. This is useful when one wants to e.g. instance
  the collection children separately in the upcoming instancing node.

Part of D12478.
2021-09-27 10:17:17 +02:00
William Leeson
f3ace5aa80 Fixes T91632 by stopping the sample correlation between dimensions which was causing rendering artifacts on simple scenes.
Fix T91632: Stops the sample correlation between dimensions which was causing rendering artefacts on simple scenes.

This is done by increasing the amount of jitter the Cranley Patterson Rotation is allowed to add. Also, it uses the y dimension of the of the sample table for 1D sampling which causes further decorrelation between dimensions. As an additional measure the x and y dimensions are swapped randomly to provide further decorrelation.

Maniphest Tasks: T91632

Differential Revision: https://developer.blender.org/D12610
2021-09-27 09:54:37 +02:00
fe49904646 Fix: wrong socket shape in Vector input node 2021-09-27 09:34:17 +02:00
ddb0dc2527 Fix knife tool missing refresh changing the lock axes 2021-09-27 16:28:01 +10:00
10a26d583d Fix knife tool using an invalid event value check
The events value was checked without checking the expected modal state.
2021-09-27 16:28:01 +10:00
Lasse Foster
037e66999a FIX: T91697 Eevee Generated texture coordinates completly missing
This patch fixes Eevee-regression https://developer.blender.org/T91697

Reviewed By: jbakker

Differential Revision: https://developer.blender.org/D12634
2021-09-27 08:07:23 +02:00
d2dda0e8b9 Fix T91694: VSE crashes when creating new scene
Crash happened due to NULL dereference. Add NULL checks.
2021-09-27 06:58:07 +02:00
Peter Fog
ad3e5d2bf5 VSE: Expose Zoom to Fit in all display modes
Zoom to Fit is working in all display modes, but was only exposed in
Image mode. This patch exposes it in all Image modes.

Reviewed By: ISS

Differential Revision: https://developer.blender.org/D12632
2021-09-27 04:40:05 +02:00
f9e0981976 Fix T91666: Missing pivot point in VSE
Add pivot point setting for combined timeline and preview mode.
2021-09-27 04:20:37 +02:00
d046a1f2fa Functions: fail early when multi-function throws an exception
Multi-functions are not allowed to throw exceptions that are not
caught in the same multi-function. Previously, it was difficult to
backtrack a crash to a previously thrown exception.
2021-09-26 23:28:14 +02:00
1cd8a438bb Cleanup: simplify field evaluation 2021-09-26 23:28:14 +02:00
88a2b054da Fix T91732: crash in Set Position node on empty mesh 2021-09-26 23:28:14 +02:00
93b36fad68 Knife: Expose XYZ axis locking in modal keymap
A small quality of life improvement that will allow users to change the keys used for axis locking.
2021-09-26 22:18:24 +01:00
80f7bc6d8e LineArt: Smooth tolerance value for chaining.
smooth out jaggy lines with a given threshold. For each point in a stroke, the ones with in a given distance of its previous segment will be removed,
thus "zig-zag" artefacts can be cleaned up.

Reviewed By: Antonio Vazquez (antoniov)

Differential Revision: https://developer.blender.org/D12050
2021-09-26 19:43:12 +08:00
505422220d Cleanup: use override/final for derived classes.
This will help detecting missing API changes. Those keywords were added
on classes which did not already use them. Also added missing
`accepts_object_type()` on NURBS reader.
2021-09-25 09:31:00 +02:00
43394e41a8 Fix Alembic point cloud streaming.
Point clouds are not imported and read anymore. This was caused by an
API change in rB128eb6cbe928e58dfee1c64f340fd8d663134c26 which was not
applied to `AbcPointsReader`. It did not cause a compile error as the
base class as a default implementation for this method.
2021-09-25 09:31:00 +02:00
ab09844be8 Cleanup: typos in code and comments.
No functional changes.
2021-09-25 09:31:00 +02:00
a3027fb094 Fix T91662: VSE Image overlay is drawn for backdrop
Don't draw image overlay in timeline, image manipulation only works in
preview.
2021-09-24 21:18:03 +02:00
b314d3e787 Fix T91639: Cycles crash rendering high resolution images with multiple passes
We were writing large 2048x2048 tiles into EXR files, which appears to cause
integer overflow inside the OpenEXR library when there are multiple passes. Now
use smaller tiles in the image file, while still rendering large tiles.

This adds the requirement that the render tile size must be a multiple of 128
or be smaller than 128, this is adjusted automatically.
2021-09-24 21:08:14 +02:00
2dd3968335 Geometry Nodes: Add versioning and legacy warning for random float node 2021-09-24 14:06:41 -05:00
Johnny Matthews
536f9eb82e Geometry Nodes: Random Value Node
This node replaces the deprecated Attribute Randomize node, populating
a vector, float, integer or boolean field with random values. Vector,
float, and integer have min/max settings, which are also field aware.
The boolean type has a probability value for controlling what portion
of the output should be true. All four types have a field seed input
which is implicitly driven by the index, otherwise, all values would
be the same "random" value.

The Random Float node is now deprecated like other nodes, since it is
redundant with this node.

Differential Revision: https://developer.blender.org/D12603
2021-09-24 14:03:42 -05:00
c87e6b23be Assets: Read catalogs immediately when loading a library
Until now, the asset catalogs would only show up after all assets from
the library were loaded. Now the catalogs are read first, which makes
them appear pretty much immediately. This makes the UI more responsive
and feel less heavy.

I added a dedicated file-list type for asset libraries now. While not
necessarily needed, I prefer that so asset library specific stuff can be
handled in there.
2021-09-24 20:17:04 +02:00
Erik Abrahamsson
be16794ba1 Geometry Nodes: String to Curves Node
This commit adds a node that generates a text paragraph as curve
instances. The inputs on the node control the overall shape of the
paragraph, and other nodes can be used to move the individual instances
afterwards. To output more than one line, the "Special Characters" node
can be used.

The node outputs instances instead of real geometry so that it doesn't
have to duplicate work for every character afterwards. This is much
more efficient, because all of the curve evaluation and nodes like fill
curve don't have to repeat the same calculation for every instance of
the same character.

In the future, the instances component will support attributes, and the
node can output attribute fields like "Word Index" and "Line Index".

Differential Revision: https://developer.blender.org/D11522
2021-09-24 12:41:49 -05:00
Erik Abrahamsson
5c0017e85a Geometry Nodes: Special string characters node
This patch adds a new node called "Special Characters" with two string
outputs: "Line Break" and "Tab". This is necessary because the newline
character cannot be easily typed with a keyboard, but is necessary for
the string to curve node.

Differential Revision: https://developer.blender.org/D12620
2021-09-24 11:00:21 -05:00
bdb8ee9717 Fix Cycles memory leak in baking, after recent changes 2021-09-24 17:46:34 +02:00
Johnny Matthews
ef45399f3b Nodes: initial support for socket tooltips
This adds initial limited support for socket tooltips. It's limited
in a couple of ways for now:
* Only works when hovering over the socket shape, not when hovering
  over the value in the socket.
* Only works for built-in nodes that already use the new node
  declaration system. This can later be extended to support pynodes.

Those limitations are well worth it for now, given that the
implementation is quite simple and the impact on usability is quite
large. More complex updates to the layout system, that would allow
showing socket tooltips in the nodes, can be done later. With the
current implementation we can at least start writing tooltips for
geometry nodes now.

This commit already adds tooltips for the Cylinder node as an example.

Differential Revision: https://developer.blender.org/D12607
2021-09-24 17:13:40 +02:00
4a2c63f4bd Nodes: hide socket value when input is a field implicitly 2021-09-24 16:42:20 +02:00
90b410fe74 Fix: field evaluation crash when the domain size is zero 2021-09-24 16:42:20 +02:00
25d4de92fa Cleanup: UUID, add some documenting comments
No functional changes.
2021-09-24 16:34:25 +02:00
c0db8e3b41 Fix T91660: Cycles remaining render time does not take into account time limit 2021-09-24 16:34:15 +02:00
585998987a Cycles: some steps towards getting standalone compiling again
Render output and display still need to be rewritten to work with the new
system.
2021-09-24 16:34:14 +02:00
ab8f24811d Cleanup: remove unused device code and includes 2021-09-24 16:34:14 +02:00
9cf593f305 GPencil: Reorganize list of modifiers
As we have a now a new `Modify` column, we move some modifers to this column.
2021-09-24 16:27:58 +02:00
45e432b894 GPencil: Change Proximity distance properties to distance type
This keep consistency with mesh modifer.
2021-09-24 16:16:40 +02:00
ede14b3856 GPencil: Invert weight in Weight Proximity modifier
In meshes modifer the Lowest is 0 and Highest is 1.0 and this was working inverted for grease pencil. Now, it works equals to meshes modifier.

Also changed the tooltip to keep consistency with meshes modifier.
2021-09-24 16:16:40 +02:00
95ec6e4dd3 Geometry Nodes: make index field more reusable
Some inputs will be the index field implicitly, so we want this
class to be available outside of `node_geo_input_index.cc`.
2021-09-24 16:03:07 +02:00
1a1c546124 Fix T91240: Object duplication was duplicating its action twice.
Weird that this was not reported before, this was creating a lot of
extra actions everytime...
2021-09-24 15:25:49 +02:00
e1e380ba38 Asset Catalogs: write catalogs sorted by path & UUID
When writing asset catalog definition files, order the catalogs by
(path, UUID). This ensures that every write produces the same file, playing
nice with versioning / synchronisation systems.
2021-09-24 14:42:48 +02:00
ab9644382d UUID: add less-than operator
Add `operator<` to C++ class to allow lexicographic ordering of UUIDs.

This will be necessary when writing asset catalogs to disk in a predictable
(i.e. ordered) manner.
2021-09-24 14:42:48 +02:00
2b9ca0f112 Codestyle: Add brackets around body of if statements. 2021-09-24 13:38:03 +02:00
7e904139a3 Nodes: make dot in socket shape circular
Previously, it was a diamond shape when the overall
shape was a diamond.
2021-09-24 13:33:28 +02:00
2b5733ff01 Fix T91192: Context.copy() crashes on file load
The `ui_list` lookup from 87c1c8112f
didn't account for the region being unset.
2021-09-24 21:10:02 +10:00
dfe01628b0 Cleanup: old-style-declaration warning 2021-09-24 21:10:01 +10:00
e8c6e32348 Asset Catalogs: fix trailing slash test case
The "path with trailing slash" test catalog was using the same path as
another catalog, which meant it was ignored after doing the path
cleanup. It's now different in the test file in SVN, so it'll actually
show up in the test.
2021-09-24 12:53:14 +02:00
59387aabe8 LibOverride: deprecate Proxies: Remove 'Make Proxy' operator. 2021-09-24 12:40:04 +02:00
501b0190d6 LibOverride: Deprecate Proxies: Add auto-conversion on file load.
This commit also add an experimental userPreferences to prevent proxies
conversions on file load, and reporting for amount of coverted proxies
(and possible issues).

Note that potentially linked proxies from other libraries are not
hamdled here (this feature seems to be broken anyway in master
currently?).
2021-09-24 12:40:04 +02:00
cdcdd2c479 LibOverride: Add utils to convert all proxies to overrides. 2021-09-24 12:40:03 +02:00
e7ae2840a5 Geometry Nodes: new Distribute Points on Faces node
This adds a replacement for the deprecated Point Distribute node.

Arguments for the name change can be found in T91155.
Descriptions of the sockets are available in D12536.

Thanks to Jarrett Johnson for the initial patch!

Differential Revision: https://developer.blender.org/D12536
2021-09-24 11:50:02 +02:00
d8a5b768f0 BLI: expose more noise hash functions in header
This is a follow up of the previous commit.
These functions are useful for other areas of Blender as well.
2021-09-24 11:24:15 +02:00
bc27bafa54 BLI: make noise hash functions available in header 2021-09-24 10:55:23 +02:00
7ca48a3814 Fix: incorrect socket shape for noise texture input 2021-09-24 10:55:23 +02:00
f8a0e102cf Weightpaint Gradient tool: expose falloff to the UI
By default, we'll always get a falloff like this from the tool:
{F10559413}

But in the context of using vertexgroups in modifiers/modeling, a choice
on how the gradient falloff of the Weightpaint Gradient tool is shaped
would be desirable:
"real" linear:
{F10559416}
Custom:
{F10559421}
{F10559428}

The way the Weightpaint gradient tool works is a bit outside the usual
tools that use brushes [even though it creates a brush on the fly in
`WPGradient_userData`].
However, it does not have an entry in `eBrushWeightPaintTool` and adding
one there does not play nice for the same reasons (not "really" being
integrated in the brush-based tools).

So in order to expose the brush curve in the UI, we would have to do one
of the following:
- [1] try to use `VIEW3D_PT_tools_brush_falloff`, for this to work:
-- make all kinds of exception in python super classes [`FalloffPanel`,
`BrushPanel`, `UnifiedPaintPanel`, ... -- including making real entries
in `eBrushWeightPaintTool`] to get a proper tool mode and...
-- .. to also make sure Falloff Shape and Front-Face Falloff are not
available [which the tool seems to just not support in its current form]
- [2] just have a simple, contained panel for this tool alone

This patch implements [2] and adds it as part of the ToolDef (could also
be done in `VIEW3D_HT_tool_header`, but again, I think this is nice to
keep separate from the usual tools)
{F10559482}
{F10559485}

Testfile:
{F10559442}

Fixes T91636

Maniphest Tasks: T91636

Differential Revision: https://developer.blender.org/D12614
2021-09-24 10:52:12 +02:00
3ac342dc6d Cleanup: clang format 2021-09-24 10:45:36 +02:00
9a45a4c525 Cleanup: asset catalogs, fix clang-tidy warning
Remove unnecessary call to `std::string::c_str()`.

No functional changes.
2021-09-24 10:29:52 +02:00
e161f39660 Cleanup: clang-tidy 2021-09-24 10:25:16 +02:00
Jeroen Bakker
fc7beac8d6 FileBrowser: Reduce Overhead Browsing Libraries.
When Browsing libraries the asset files were opened multiple times.
once to determine the needed groups to query and once for each
group to query the items in the group. For file browsing this makes sense
but for asset browsing this can be reduced.

This patch will load the asset files recursively and only opens them once.
Another change is that only the assets are requested and not filtered out
later in the process.

This patch is needed to simplify the library indexing. Where
we need access to the full library content.

## The numbers ##

Benchmarked by adding scenes of the spring open movie to the default
asset library. Refreshing the asset library would recursively load all the files
there.

| **8bc27c508a** | Processed 317 'directories/libraries' | 7.573986s |
| **Patch** | Processed 42 'directories/libraries' | 0.821013s |

{F10442811}

Reviewed By: mont29, Severin

Maniphest Tasks: T91406

Differential Revision: https://developer.blender.org/D12499
2021-09-24 08:41:40 +02:00
Jeroen Bakker
6a88f83d67 Hair Info Length Attribute
Goal is to add the length attribute to the Hair Info node, for better control over color gradients or similar along the hair.

Reviewed By: #eevee_viewport, brecht

Differential Revision: https://developer.blender.org/D10481
2021-09-24 07:44:22 +02:00
0f764ade1a Fix T91661: Vector rotate output socket diconnects on file load
An incorrect name was used in the socket declaration refactor.
2021-09-23 23:56:15 -05:00
0e039749e3 Fix: Incorrect field visualization for some shader nodes
These need to be tagged as function nodes in their declaration.
2021-09-23 22:23:14 -05:00
bc65c7d0e5 Cleanup: spelling in comments 2021-09-24 11:31:23 +10:00
599d96e8f9 UI: keymap preference tweaks
- Expose option to use shortcuts to activate tools as an enum.
- "Emulate 3 Button Mouse" now disables preferences
  that depend on Alt-LMB.
2021-09-24 11:07:01 +10:00
bffda4185d Cleanup: group convenience assignments in the keymap 2021-09-24 11:07:01 +10:00
26141664f0 Fix: Curve fill node doesn't fill real geometry with instances
A misplaced return in the middle of the function made it so
the node didn't fill real geometry.
2021-09-23 17:45:41 -05:00
f7608276e3 Audaspace: port bugfix from upstream.
Fixes T91615: Instant crash when dragging video file into video editor sequencer
2021-09-23 23:27:49 +02:00
61f3d4eb7c Geometry Nodes: Initial socket visualization for fields.
This implements the update logic for the vizualization of which
sockets pass data or constants directly, and which pass functions.
The socket shapes may still have to be updated. That should be
done separately, because it might be a bit more involved, because
socket shapes are currently linked to keyframe shapes. Currently
the circle and diamond shapes are used with the following meanings:

 - Input Sockets:
    - Circle: Required to be a single value.
    - Diamond: This input supports fields.
 - Output Sockets:
    - Circle: This output is a single value.
    - Diamond: This output may be a field.

Connecting a field to a circle input socket is an error, since a
field cannot be converted to a single value. If the socket shape
is a diamond with a dot in the middle, it means it is currently
a single value, but could be a field.

In addition to socket shapes, the intention is to draw node links
differently based on the field status. However, the exact method for
conveying that isn't decided yet.

Differential Revision: https://developer.blender.org/D12584
2021-09-23 15:21:31 -05:00
c1b925f7ff Fix build error caused by typo 2021-09-23 15:20:57 -05:00
1bdaf0ebec Fix T91638: image editor Open Cached Render not loading some passes
Previously this was only loading built-in render passes. Now instead of trying
to load the scene render passes, load whatever passes exist in the cache file.
2021-09-23 20:45:42 +02:00
Charlie Jolly
7fb2b50e5d Fix: Build issue with MSVC
header for std::function was not included

reported/fixed by Charlie on chat
2021-09-23 12:33:27 -06:00
fc2255135e Paint: prevent RenderResults and Viewers where unappropriate
Using a RenderResult (or a Viewer) was never really working (think you
cant get a real ImBuff from these) -- cannot use it as a clone, stencil
or canvas [Single Image paint texture slot].

In the case of using it as a 2D paint clone image this would also crash
[due to the Image Editor drawing refactor in 2.91].

Now [in the spirit of T73182 / D11179], prevent using these where
unappropriate by using rna pointer polling functions.

Also add a security check for the 2D paint clone image crash in case a
stencil ImBuff cannot be provided for some reason, but generally old
files are now patched in do_versions_after_linking_300 (thx @brecht!).

Fixes T91625.

Maniphest Tasks: T91625

Differential Revision: https://developer.blender.org/D12609
2021-09-23 20:11:45 +02:00
b8a30c7664 Cleanup: Use const in previously committed function 2021-09-23 19:39:26 +02:00
323fd80aad UI: Tree-View API for easy creation of tree UIs
This follows three main targets:

* Make creation of new tree UIs easy.
* Groundwork to generalize tree UIs (so e.g. Outliner, animation
  channels, asset catalogs and spreadsheet data-sets don't have to
  re-implement basic tree UI code) or even other data-view UIs.
* Better separate data and UI state. E.g. with this, tree-item selection
  or the open/collapsed state can be stored on the UI level, rather than
  in data. (Asset Catalogs need this, storing UI state info in them is
  not an option.)

In addition, the design should be well testable and could even be
exposed to Python.

Note that things will likely change in master still. E.g. the actually
resulting UI isn't very nice visually yet.

The design is documented here:
https://wiki.blender.org/wiki/Source/Interface/Views

Differential Revision: https://developer.blender.org/D12573
2021-09-23 19:33:54 +02:00
eb0eb54d96 Fix D12533: Simplify curve object to mesh conversion
This patch simplifies the curve object to mesh conversion
used by the object convert operator and exporters.

The existing code had a convoluted model of ownership, and did quite
a bit of unnecessary work. It also assumed that curve objects always
evaluated to a mesh, which is not the case anymore.

Now the code checks if the object it receives is evaluated. If so,
it can simply return a copy of the evaluated mesh (or convert the
evaluated curve wire edges to a mesh if there was no evaluated mesh).
If the object isn't evaluated, it uses a temporary copy of the object
with modifiers removed to create the mesh in the same way.

This follows up on the recent changes to curve evaluation,
namely that the result is always either a mesh or a wire curve.

Differential Revision: https://developer.blender.org/D12533
2021-09-23 11:41:46 -05:00
ed541de29d Fix T91626: Cycles sss behind fully transparent object renders differently 2021-09-23 18:32:30 +02:00
354c3eee40 Cycles: improve Auto Tile option description
Ref T91645
2021-09-23 18:32:30 +02:00
0a8a726014 bUUID: make it explicit the default constructor produces the nil value
The implicit default constructor zeroes all plain data fields, and now
this behaviour is explicit & tested for in a unit test.
2021-09-23 18:27:19 +02:00
18a4dc869d Cleanup: UUID, fix clang-tidy warnings
Use explicit `uint32_t` instead of `uint`, add a missing end-of-namespace
comment, and change `auto` to `const auto *`.

No functional changes.
2021-09-23 18:27:19 +02:00
502543e46b Geometry Nodes: remove old method to iterate over attributes
The previous commit added a new method to the same in a better way.
2021-09-23 17:59:44 +02:00
38af29df5c Geometry Nodes: simplify looping over attributes in geometry set
This adds three new methods:
* `InstancesComponent::foreach_reference_as_geometry(...)`
* `GeometrySet::attribute_foreach(...)`
* `GeometrySet::gather_attributes_for_propagation(...)`

The goal is that these iteration primitives can be used in places
where we use more specialized iterators currently.

Differential Revision: https://developer.blender.org/D12613
2021-09-23 17:59:44 +02:00
105115da9f UUID: add != operator for comparing UUIDs
Make it possible to unit test with `EXPECT_NE(uuid1, uuid2)`.
2021-09-23 17:58:20 +02:00
bd63944a73 UUID: place C++ code in correct namespace
Put the `bUUID` class in the `blender` namespace, instead of the
`blender::bke` namespace.

As a result, some C++ code now correctly uses the C++ class, where
previously it would use the C struct and use implicit casting where
necessary. As a result, support for initializer lists had to be
explicitly coded and in another place an explicit `::bUUID` was
necessary to avoid ambiguity.
2021-09-23 17:58:20 +02:00
942fc9f467 Cleanup: bUUID, document the constructors
No functional changes.
2021-09-23 17:58:20 +02:00
93997f9d0a Cleanup: asset catalogs, correct assertion message
There is no such thing as a "relative path" when it comes to asset catalog
paths (they're always absolute).

No functional changes.
2021-09-23 17:58:20 +02:00
d7f803f522 Fix T91641: crash rendering with 16k environment map in Cycles
Protect against integer overflow.
2021-09-23 17:48:16 +02:00
6279efbb78 Fix Cycles compiler warning on GCC 11
For shadow rays there are no closures, leave out the closure merging code
there to avoid warnings about accessing closure memory that does not exist.
2021-09-23 17:48:16 +02:00
d0493796a6 Cleanup: Remove hardcoded values and rename keyframe shape shaders
No functional change.

The shader is complicated by itself, having hardcoded values makes it
even more cryptic.

I also renamed the shader because the shader is not for the keyfarme diamond only,
but for all the keyframe shapes.

Differential Revision: https://developer.blender.org/D12615
2021-09-23 17:41:11 +02:00
f11bcb5a80 Fix T91557: Texture Paint Stencil doesnt use assigned UV Layer
Choosing a UV layer would actually affect the overlay in the viewport
and also painting with the mask brush was in that UV space, but the
resulting stencil mask was always applied with the active UV (not the
explicitly selected stencil UV -- the one one is looking at in the
viewport!) to painting.

This has been like that as far as I have checked back (at least 2.79b),
I am surprised this has not come up before, but it does not seem to make
sense at all...

Now use the UV specified for the stencil layer when applying the mask for
painting, so it corresponds to the stencil mask one is looking at in the
viewport.

Maniphest Tasks: T91557

Differential Revision: https://developer.blender.org/D12583
2021-09-23 16:56:03 +02:00
490425d56e Asset Catalogs: explicit version number in catalog definition files
Declare the current format used for asset catalog definition files as
version 1, and write that to the files. Files without that version number
will be rejected.

This makes it much easier to move to different versions later, with the
opportunity to do versioning on file load.

The version is not associated with any version of Blender, but a separate
integer that's simply incremented when a non-backward-compatible change
happens.
2021-09-23 16:06:25 +02:00
aa2493e2e7 Fix unused variable warning in release builds
The variable is only used in debug builds.
2021-09-23 15:04:41 +02:00
Sybren A. Stüvel
9b12b23d0b Assets: add Asset Catalog system
Catalogs work like directories on disk (without hard-/symlinks), in that
an asset is only contained in one catalog.

See T90066 for design considerations.

#### Known Limitations

Only a single catalog definition file (CDF), is supported, at
`${ASSET_LIBRARY_ROOT}/blender_assets.cats.txt`. In the future this is
to be expanded to support arbitrary CDFs (like one per blend file, one
per subdirectory, etc.).

The current implementation is based on the asset browser, which in
practice means that the asset browser owns the `AssetCatalogService`
instance for the selected asset library. In the future these instances
will be accessible via a less UI-bound asset system.

The UI is still very rudimentary, only showing the catalog ID for the
currently selected asset. Most notably, the loaded catalogs are not
shown yet. The UI is being implemented and will be merged soon.

#### Catalog Identifiers

Catalogs are internally identified by UUID. In older designs this was a
human-readable name, which has the problem that it has to be kept in
sync with its semantics (so when renaming a catalog from X to Y, the
UUID can be kept the same).

Since UUIDs don't communicate any human-readable information, the
mapping from catalog UUID to its path (stored in the Catalog Definition
File, CDF) is critical for understanding which asset is stored in which
human-readable catalog. To make this less critical, and to allow manual
data reconstruction after a CDF is lost/corrupted, each catalog also has
a "simple name" that's stored along with the UUID. This is also stored
on each asset, next to the catalog UUID.

#### Writing to Disk

Before saving asset catalogs to disk, the to-be-overwritten file gets
inspected. Any new catalogs that are found thre are loaded to memory
before writing the catalogs back to disk:

- Changed catalog path: in-memory data wins
- Catalogs deleted on disk: they are recreated based on in-memory data
- Catalogs deleted in memory: deleted on disk as well
- New catalogs on disk: are loaded and thus survive the overwriting

#### Tree Design

This implements the initial tree structure to load catalogs into. See
T90608, and the basic design in T90066.

Reviewed By: Severin

Maniphest Tasks: T91552

Differential Revision: https://developer.blender.org/D12589
2021-09-23 15:00:45 +02:00
222fd1abf0 Asset Browser: Disable metadata editing for external asset libraries
Buttons to edit asset metadata are now disabled for assets from an
external library (i.e. assets not stored in the current .blend file).
Their tooltips explain why they are disabled.

Had to do some RNA trickery to disable the metadata properties at RNA
level, not at UI script level.
The basic idea is:
* Local data-block assets set the data-block as owning ID for the asset
  metadata RNA pointer now.
* That way we can use the owner ID to see where the metadata belongs to
  and decide if it's editable that way.
* Additionaly, some Python operators needed better polling so they show
  as grayed out, and don't just fail.

One important thing: Custom properties of the metadata can still be
edited. The edits won't be saved however. Would be nice to disable that,
but it's currently not supported on BPY/IDProperty/RNA level.

Addresses T82943.

Differential Revision: https://developer.blender.org/D12127
2021-09-23 14:46:13 +02:00
059d01d42e Fileops: call BLI_path_slash_native() in BLI_dir_create_recursive()
Make the Windows version of `BLI_dir_create_recursive()` call
`BLI_path_slash_native()` before it tries to handle the path. This
should make it possible to call it with non-native path separators.

This change was provided by our Windows platform maintainer @LazyDodo in
P2414, so I assume he agrees with this change.
2021-09-23 14:42:14 +02:00
83975965a7 Keymap: RMB select option to place cursor on Alt-LMB
This allows most tools to activate on press, removing a small but
noticeable distance between the initial press and detection of a drag
event.

Gizmo tweak no longer actives when Alt is held, to avoid conflicting
with cursor placement.

This has the advantage that the gizmo doesn't get in the way when Alt
is used for activating tools or placing the cursor.
2021-09-23 22:10:56 +10:00
88692baace WM: gestures now activate immediately on mouse press
Some gestures were activating immediately on tweak events,
extend this to mouse-press and click-drag.

Without this change, box-select for example wouldn't be automatically
activated on mouse-press.
2021-09-23 22:08:02 +10:00
b659d1a560 Cleanup: spelling in comments 2021-09-23 22:08:02 +10:00
d431b91995 Cleanup: assign variable for LMB select 2021-09-23 22:06:47 +10:00
4d2ca33a8a LibLink: Modify WM API to link/append one ID to take flag parameter.
There is no reason to lock behavior into a specific configuration in
those calls, make them properly configurable like the rest of the
link/append code.

This also enable users of those functions to activate 'ID reuse'
behavior.
2021-09-23 13:48:41 +02:00
aadb7ef071 Geometry Nodes: add utility to print an attribute id. 2021-09-23 13:46:26 +02:00
e86cf55667 Fix T91629: Crash in "Open Cached Render" function 2021-09-23 13:03:36 +02:00
f48a4aa0f9 LibLink Append: Expose 'reuse ID' through new BLO flag, and add basic tests.
Option is now available to append operator, alsthough hidden and
disabled by default.
2021-09-23 12:56:05 +02:00
cb173d05dc LibLink Append: Fix 'reused ID' case keeping linked data around.
When we re-use a local ID, we need to delete the matching linked data.
2021-09-23 12:54:23 +02:00
6f53988e7a Cleanup: proper handling of LIB_TAG_DOIT in append code. 2021-09-23 12:46:51 +02:00
ce96a75c2c Cleanup: eBLOLibLinkFlags: Add 'space' between APPEND flags and INSTANCE ones. 2021-09-23 12:45:40 +02:00
3558ae3b6c Cleanup: Silence unused var warning in release builds. 2021-09-23 12:30:07 +02:00
b63f777950 Add missing GPencil IDTYPE_FLAGS_APPEND_IS_REUSABLE flag.
Forgot that one in rB794c2828af60.

Noted by Antonio Vazquez (@antoniov), thanks.
2021-09-23 11:28:39 +02:00
b801e86f8b Append: Reuse local data: remove limitation on directly selected data.
in asset context, when user drag & drop a material several time, they
would still expect to re-use existing one instead of getting new copies
of it, even if this material is directly appended (and not an indirect
dependency of an object e.g.).
2021-09-23 11:15:58 +02:00
3042994c91 Link/Append: Refactor flags.
Flags controlling link/append code are split between two enums, one in
`DNA_space_types.h` and one in `BLO_readfile.h`.

This commit:
 - Moves flags exclusively used in WM and BLO code to `eBLOLibLinkFlags`
   in `BLO_readfile.h`. Flags in `eFileSel_Params_Flag` from
   `DNA_space_types.h` are now only the ones effectively used by the
   file browser editor code too.
 - Fixes some internal utils in `readfile.c` still taking `short` flag
   parameter instead of proper `int` one.

NOTE: there are a few other flags that could probably be moved to
`eBLOLibLinkFlags` (at the very least `FILE_LINK`, probably also
`FILE_AUTOSELECT` and `FILE_ACTIVE_COLLECTION`), since those are not
effectively used by the file browser, and control linking/appending
behavior, not filebrowser behavior.

However for now think it's safer to not touch that.
2021-09-23 11:01:00 +02:00
12924ed573 Fix last Cycles tile highlighted while file from disk is being processed 2021-09-23 10:41:06 +02:00
a351023bd5 Fix default surface resolution U/V mis-match
The resolution for surfaces was 12 for U, 4 for V,
where both should have been set to 4.

Regression in 9a076dd95a
2021-09-23 15:54:32 +10:00
754d56dcc1 Cleanup: spelling in comments 2021-09-23 15:42:44 +10:00
bf948b2cef Custom Properties: Rewrite edit operator, improve UX
This commit changes the custom property edit operator to make editing
different properties types more obvious and expose more of the data,
made more easily possible by the recent UI data refactor.

Previously, the operator guessed the type you wanted based on what you
wrote in a text box. That was problematic, you couldn't make a string
property with a value of `1234`, and you had to know about the Python
syntax for lists in order to create an array property. It was also slow
and error prone; it was too easy to make a typo.

Improvements compared to the old operator:
 - A type drop-down to choose between the property types.
 - Step and precision values are exposed.
 - Buttons that have the correct type based on the property.
 - String properties no longer display min, max, etc. buttons.
 - Generally works in more cases. The old operator tended to break.
 - Choose array length with a slider.
 - Easy to choose to use python evaluation when necessary.
 - Code is commented, split up, and much easier to understand.

The custom property's value is purposefully not exposed, since the Edit
operator is for changing the property's metadata now, rather than the
value itself. Though in the "Python" mode the value is still available.

More improvements are possible in the future, like exposing different
subtypes, and improving the UI of the custom properties panel.

Differential Revision: https://developer.blender.org/D12435
2021-09-22 21:57:33 -05:00
dda9762a16 Remove old TinyGLTF files 2021-09-22 19:38:33 -07:00
fa23369373 Merge branch 'master' into xr-controller-support 2021-09-22 19:24:20 -07:00
1ef02d8f4b Update with changes from D10948, D12472 2021-09-22 19:16:52 -07:00
6e77afe6ec Applying patch D12600, GSOC Knife Tools branch
This adds constrained angle mode improvements,
snapping to global and local orientation,
visible distance and angle measurements,
undo capability,
x-ray mode,
multi-object edit mode.

See https://developer.blender.org/D12600 for more details.

Note: this project moved some of the default keymappings
around a bit, as discussed with users in the thread
https://devtalk.blender.org/t/gsoc-2021-knife-tool-improvements-feedback/19047
We'll change the manual documentation in the next couple of days.
2021-09-22 21:23:44 -04:00
a78d3c5261 Fix: T91602 ffmpeg crash
Issue caused by our patch in rB1af722b81912
we replaced an array with a memory allocation
but we forgot to update the assert which now
used an invalid method to calculate the array
size.

SVN libs will have to be updated before
T91602 will be fixed for end users.
2021-09-22 17:29:23 -06:00
79bcc19240 Cleanup: Move more shader nodes to socket declaration API
I had to add `no_muted_links` to the declaration API. The name could
change there, but I think it's more obvious than "internal"
2021-09-22 17:34:09 -05:00
6fb4c8f040 Fix: Incorrect socket names after previous commit 2021-09-22 16:58:29 -05:00
c99cb81452 Cleanup: Use new node socket declaration API for some shader nodes
This converts socket declarations for most shader nodes that had already
been converted to C++, but skips those that needed a special flag.
2021-09-22 14:39:09 -05:00
bd01f4761c GPencil: Fix compiler warnings 2021-09-22 21:17:04 +02:00
ee49991999 Cleanup: Silence missing switch case warning 2021-09-22 12:00:21 -07:00
6611f2cb74 Fix T91607: GPencil Tint modifier "apply" removes the effect 2021-09-22 20:07:35 +02:00
f893dea586 BLI: support initializing empty FunctionRef with nullptr
This may sometimes be desired because it is more explicitely
shows that the `FunctionRef` will be empty.
2021-09-22 19:55:44 +02:00
02bde2c1d5 Cleanup: add using declarations 2021-09-22 19:45:47 +02:00
a28ec92088 BLI: avoid warning when copying empty StringRef 2021-09-22 19:45:18 +02:00
188de4bc31 BLI: initialize MutableSpan in default constructor 2021-09-22 19:44:58 +02:00
bd1c4a781f Geometry Nodes: fix evaluating field to span 2021-09-22 18:45:11 +02:00
3180c6b4a7 Cleanup: Themes: Remove invalid theme option
`font_kerning_style` was removed in rBa1e91fbef3dc9a5d5c8456cd9a887aac1bdb652c
2021-09-22 12:33:12 -04:00
e1a0983b3c Fix T91608: Cycles crash with tile size 0 2021-09-22 18:12:46 +02:00
4068b6b5a7 Fix T91598: Decreasing sample count causes viewport to reset
Differential Revision: https://developer.blender.org/D12601
2021-09-22 18:09:06 +02:00
Chandrapal Singh
5033310e8a UI: Add description for Batch rename
Added description for Batch rename which pop-ups when
hovering the mouse over "Batch rename" inside the edit menu.

Fixes T91390

Reviewed By: Blendify

Maniphest Tasks: T91390

Differential Revision: https://developer.blender.org/D12594
2021-09-22 11:35:29 -04:00
ac68b08c5b Fix T91592: Negative Cycles remaining render time
For the default startup was showing -14:-08.-48 as a remaining time.

Was an integer overflow when specifying total number of pixel-samples.
2021-09-22 17:30:00 +02:00
bc1e675bb9 Fix T91603: Cycles crash when volume becomes visible
Making object which uses volume shader invisible will mark the shader
as not having a volume, forcing re-compilation of the shader to bring
it back to a consistent state.

The compilation is happening as part of scene update, which needs to
know kernel features. So there is a feedback loop.

Use more relaxed way of knowing whether there is a volume in the
shader for the kernel features, which doesn't require shader to be
compiled first.

Solves issues from the report, but potentially causes extra memory
allocated if the volume part of graph is fully optimized out. This
downside is solvable, but would need to split scene update into two
steps (the one which requires on kernel, and the one which does not).
It will be an interesting project to tackle, but for a bug fix is
better to use simpler solution.
2021-09-22 17:10:06 +02:00
1eba32c3e9 Fix T91576: Cycles attribute node with name N for smooth normal no longer working
There was an optimization to remove duplicate storage of normals as attributes
when using normal maps. However for named attributes like this we still need to
store the attribute.

Don't request normal attribute from the normal map node now, instead of skipping it
in the geometry code.
2021-09-22 17:05:31 +02:00
4762a9b09f GPencil: Fix unreported missing material panel for new Scene
When a new scene is created, the paint pointers are not available before using them, so the python panel exits because the pointer was None.

Now, the pointer is checked in order to display the materials panel as expected.
2021-09-22 17:05:21 +02:00
794c2828af Initial implementation of local ID re-use when appending.
This commit adds to ID struct a new optional 'weak reference' to a
linked ID (in the form of a blend file library path and full ID name).

This can then be used on next append to try to find a matching local ID
instead of re-making the linked data local again.

Ref. T90545

NOTE: ID re-use will be disabled for regular append for the time being
(3.0 release), and only used for assets. Therefore, this commit should
not change anything user-wise.

Differential Revision: https://developer.blender.org/D12545
2021-09-22 16:55:39 +02:00
707bcd5693 Cleanup: make format 2021-09-22 16:55:09 +02:00
dilithjay
0d350e0193 Geometry Nodes: Curve Fillet Node
This node can be used to fillet splines at control points to
create a circular arc.
The implementation roughly follows T89227's design.

The node works in two main modes: Bezier and Poly
* Bezier: Creates a circular arc at vertices by changing
handle lengths (applicable only for Bezier splines).
* Poly: Creates a circular arc by creating vertices (as
many as defined by the Count fields input) along
the arc (applicable for all spline types).

In both modes, the radius of the created arc is defined
by the Radius fields input.
The Limit Radius attribute can be enabled to prevent
overlapping when the defined radius exceeds the maximum
possible radius for a given point.

Reviewed By: Hans Goudey

Differential Revision: https://developer.blender.org/D12115
2021-09-22 20:11:12 +05:30
204b01a254 Fix T91590: Cycles specular baking not using smooth normal 2021-09-22 16:08:45 +02:00
e57ce464c2 Fix T91600: Cycles viewport not updaing on metaball changes 2021-09-22 16:08:45 +02:00
53e7c64be7 Fix T91597: Cycles volume scatter visibility on lights not working 2021-09-22 16:08:45 +02:00
368b56c9a1 GPencil: Split Weight modifier in two to make more consistent
The old modifier had two modes, but it is better to keep separated as meshes.

The UI has changed to be more consistent, including a new column type of modifiers.

Note: The logic has not changed with the previous version of the modifier, just is a split on two modifiers..

Reviewed By: mendio, pablovazquez

Differential Revision: https://developer.blender.org/D12586
2021-09-22 15:54:34 +02:00
9f6313498a Fix missing samples count pass when using tiles
Samples count pass is normalized to the overall number of samples.
This means that we need to store actual value of the samples in the
tile buffer file.

A bit annoying to pull all those settings to BufferParams and need
to find a more generic solution, but for now this is easiest and a
quickest solution.

Differential Revision: https://developer.blender.org/D12597
2021-09-22 15:07:55 +02:00
Christoph Lendenfeld
f7a492d460 Animation: Pose Slide Operator - Blend to Neighbour
Adds a new operator to the pose slider tools that blends the
current pose with the neighbouring poses in the timeline.
The operator can be called in pose mode with Shift+Alt+E
or from the "pose" menu under "In betweens/Blend to Neighbour"

Reviewed by: Sybren A. Stüvel
Differential Revision: https://developer.blender.org/D9137#inline-105214
Ref: D9137
2021-09-22 14:02:19 +01:00
a6f6c421ef Cleanup: pep8 for the default keymap
Mainly line lengths & indentation.
2021-09-22 22:50:16 +10:00
f7f5024c95 Keymap: support use_key_activate_tools for annotate 2021-09-22 22:38:28 +10:00
9add7c35cc Fix (unreported) crash in outliner after recent changes to ID management core code.
Outliner tree building code abuse the `ID.newid` pointer to store non-ID
data. While this is bad and should be fixed at some point, for the time
being at the very least do not use ID BKE API to deal with this pointer
in that specific case, this needs its own proper code.
2021-09-22 14:37:00 +02:00
2526a355bc Fix bad image drawing during rendering on certain GPUs
Reported by Thomas DInges: the default cube render in Cycles has jagged
edges during rendering. Happens on AMD Radeon RX 5500 XT.

Force linear interpolation at zoom level 1 and less.

Reviewed by @fclem
2021-09-22 14:28:56 +02:00
7633548d60 Revert "Make knife drawing anti aliased (Monkey work based on D11333)"
This reverts commit 96027b2d15.

The patch asserts on different occasions and needs more work.
2021-09-22 13:50:05 +02:00
2884ae971a Custom Properties: fix the tooltip field not initialized in edit dialog.
Initializing the description property was completely forgotten.
It also seems it may be missing sometimes, so use `get`.

Also, clean values when there is no data, and correctly use
the return value of `get_value_eval` in one instance.
2021-09-22 13:22:42 +03:00
90b485845c Keymap: set the default filepath exporting keymaps
Use the key-config name for the file name.
2021-09-22 17:47:52 +10:00
ba313f8a74 Fix crash duplicating sequencer area
Error in 997b5fe45d.
2021-09-22 17:37:10 +10:00
719451f840 Cleanup: use template for hide/reveal keymap items 2021-09-22 17:17:04 +10:00
c0f55400eb Keymap: support use_key_activate_tools for selection tools
Also support sequencer transform tools.
2021-09-22 17:17:04 +10:00
c75e6bcea2 Keymap: add fallback keymap for sequencer tools
This quiets error messages, fall-back tool preference needs to be
further developed.
2021-09-22 17:17:04 +10:00
Jeroen Bakker
0c59386110 Blender Libraries: Add JSON Library.
Several areas within blender can benefit a JSON reader/writer library.
Areas like the asset browser, XR and grease pencil.

After looking at the available options we selected nlohmann's JSON for
modern C++ library. It is actively maintained for over 10 years and
flexible.

This patch only adds the header only implementation of the library so it
can be used by different areas. The asset browser project is planning to
add a small abstraction layer so it will be easier to switch between
several different serialization formats. This is currently in
development in D12544.

In cases the abstraction layer can be an overhead and undesired to be used.
In this case the header file can be directly included.

Reviewed By: Severin

Maniphest Tasks: T91430

Differential Revision: https://developer.blender.org/D12567
2021-09-22 09:07:09 +02:00
Jake
4c156cba21 EEVEE fix gloss low roughness error
Up lower clamp on spec_angle to prevent NaN from being generated on intel GPUs at low roughness.

Fixes T88754

Reviewed By: fclem

Maniphest Tasks: T88754

Differential Revision: https://developer.blender.org/D12508
2021-09-22 08:22:23 +02:00
3fa6426392 Extern: Add TinyGLTF to load XR controller model
The XR_MSFT_controller_model OpenXR extension provides a glTF
controller model that can be displayed to users during a VR session.
There are plans to support this in D10948, which will greatly improve
VR immersion when using a compatible OpenXR runtime.

TinyGLTF (https://github.com/syoyo/tinygltf) was agreed upon as a
simple and sufficient solution for loading this glTF controller model,
which will be performed at the GHOST abstraction layer. Although by
default it has two additional dependencies, stb and json, stb can be
excluded by defining TINYGLTF_NO_STB_IMAGE and
TINYGLTF_NO_STB_IMAGE_WRITE whereas json will be added as a separate
extern lib in D12567.

Reviewed By: Severin

Differential Revision: https://developer.blender.org/D12344
2021-09-21 22:59:10 -07:00
4d66cbd140 Cleanup: spelling in comments 2021-09-22 14:54:01 +10:00
77061a5621 Cleanup: incompatible-pointer-types warning 2021-09-22 14:46:32 +10:00
4d881d9dad Geometry Nodes: Curve Parameter Node
This commit adds a field input node that outputs the fraction of the
total length of the spline on each control point. This is useful for
anything that involves varying a value depending on how far along
the spline it is.

It also works when evaluated on the spline domain, where it outputs
the fraction of the total length of all of the splines at the start.

The operation isn't as well defined for NURB splines for the reasons
noted in the code comment. That can be said explicitly in the docs.

Differential Revision: https://developer.blender.org/D12548
2021-09-21 17:38:37 -05:00
41e3bf8a8e Geometry Nodes: Add legacy warning and "View Legacy" operator
This commit adds warning messages to "legacy" nodes that will be
removed in the future. The warning is shown in the node header, but
it is not printed in the terminal or displayed in the modifier. It is
also not propogated to node groups, but that is a more general task.

If the modifier's node tree has executed a deprecated node, it will
display a warning and a "Search" button that will select the nodes and
pan to them in the node editor. This doesn't open child node trees and
select nodes in there, because I want to keep this operator simple and
avoid wasting a lot of time perfecting this behavior.

Differential Revision: https://developer.blender.org/D12454
2021-09-21 17:17:40 -05:00
8324ac8457 Audaspace: porting upstream pulseaudio fixes.
Fixes T89045 and T91057.
2021-09-21 22:20:34 +02:00
af95542df3 UUIDs: rename UUID to bUUID
Rename the `UUID` struct to `bUUID`. This avoids a symbol clash on
Windows, which also defines `UUID`. This only pops up when a `UUID`
field is used in the DNA code, which is why it wasn't a problem before
(it will be once D12589 lands).

No functional changes.
2021-09-21 21:54:53 +02:00
6d162d35e2 Geometry Nodes: Fill instances separately in the curve fill node
With this commit, each referenced instance data will be converted to
a geometry instances and processed separately. This should result in
a large speedup when the instances component has many insances
referring to the same data.

This change can act as a blueprint for other nodes that need to
implement similar behavior. It adds some helper functions on the
instances component to make that easier.

Thanks to Erik Abrahamsson for a proof of concept patch.

Differential Revision: https://developer.blender.org/D12572
2021-09-21 14:20:54 -05:00
Erik Abrahamsson
29e3545194 Geometry Nodes: String manipulation nodes
This patch adds four new nodes to a new "Text" category:
 - String Length: Outputs length of a string
 - String Substring: Outputs part of a string
 - Value to String: Converts a value to a string
 - String Join: Concatenates multiple strings with a delimiter

The initial use case of these nodes is the upcoming string to curve
node. However, they could also be used to calculate dynamic attribute
names, or with string attributes in the future.

Differential Revision: https://developer.blender.org/D12532
2021-09-21 14:11:32 -05:00
05ce5276db Geometry nodes: Output curve normals from the normal node
The code is basically the same as rB4d51af68adb273.
2021-09-21 13:39:46 -05:00
4d51af68ad Geometry Nodes: Curve tangent node
This node outputs the direction vector, or tangent of a curve at every
control point. For poly splines this is simply the evaluated tangents,
so it all works very simply. For Bezier splines it uses the tangent at
the evaluated point corresponding to each control point, and NURBS
are interpereted as poly splines built from their control points.

Internally the node is called "Input Tangent" to simplify using it for
mesh tangents as well in the future like the "Normal" node.

Differential Revision: https://developer.blender.org/D12581
2021-09-21 13:11:39 -05:00
29b13fa3ca Cleanup: Clang-tidy warnings 2021-09-21 20:02:46 +02:00
499dbb626a UI: Style drag-drop indicators as tooltips
Currently, the drop indicator colors are hardcoded to white text on semi-transparent black background.
This patch makes the drop indicator use the tooltip theme settings, as they serve a similar purpose.

{F10530482, size=full}

All built-in themes seem to work well and got improved readability.

Reviewed By: HooglyBoogly

Differential Revision: https://developer.blender.org/D12588
2021-09-21 19:53:42 +02:00
b37d36a60f Fix: Add versioning for geometry nodes attribute input toggle
rB8e21d528cab98 neglected to add versioning to add the new
"use_attribute" and "attribute_name" properties to the modifier input
list. Though they are added if the modifier's interface is updated, that
doesn't happen when the file is loaded, so patch adds them manually.
Another solution would be calling `MOD_nodes_update_interface`,
but that would require including the modifiers module.

Differential Revision: https://developer.blender.org/D12535
2021-09-21 12:42:47 -05:00
3642e17428 Cleanup: Move curve to mesh node implementation to blenkernel
I plan to use this for curve object data conversion to mesh in D12533,
and possibly for the implicit curve to mesh conversion in the curve
and text object modifier stack in the future.

Differential Revision: https://developer.blender.org/D12585
2021-09-21 11:56:54 -05:00
fde9c3bc74 Fix: Incorrect versioning for float IDProperty default array
The versioning has to have different behavior for when the old default
value had a float type rather than a double type. Also use memcpy
rather than dupalloc, since it's a bit clearer.
2021-09-21 11:20:34 -05:00
66dbe6e55a Cleanup: else-after-return 2021-09-21 17:55:39 +02:00
3c1e75a230 Functions: make asserts more correct
It is valid to e.g. copy construct an integer in the same place,
because it is a trivial type. It does not work for types like std::string.

This fixes a crash reported in D12584 where it would copy a buffer
into itself. We should probably also avoid doing this copy alltogether
but that can be done separately.
2021-09-21 17:51:15 +02:00
2df7d1ebce Cleanup: mention UUID_STRING_LEN in comment
Mention that `UUID_STRING_LEN` exists in the documentation of
`BLI_uuid_format()`.

No functional changes.
2021-09-21 17:50:23 +02:00
49ab38bf54 Fix T91534: GPencil interpolate Sequence fails if stroke has 0 points
In some cases the stroke has 0 points and this must be skipped in the interpolation.
2021-09-21 17:29:27 +02:00
Henrik Dick (weasel)
2e6a735385 GPencil: Curvature support for length modifier
Extend the stroke following an approximated circluar/helical curve.

This can be used as an effect for lineart or on its own as helix generator.

Reviewed By: Sebastian Parborg (zeddb), Hans Goudey (HooglyBoogly), YimingWu (NicksBest), Antonio Vazquez (antoniov), Henrik Dick (weasel)

Differential Revision: https://developer.blender.org/D11668

# 请为您的变更输入提交说明。以 '#' 开始的行将被忽略,而一个空的提交
# 说明将会终止提交。
#
# 位于分支 master
# 您的分支与上游分支 'origin/master' 一致。
#
# 要提交的变更:
#	修改:     source/blender/blenkernel/BKE_gpencil_geom.h
#	修改:     source/blender/blenkernel/intern/gpencil_geom.cc
#	修改:     source/blender/gpencil_modifiers/intern/MOD_gpencillength.c
#	修改:     source/blender/makesdna/DNA_gpencil_modifier_defaults.h
#	修改:     source/blender/makesdna/DNA_gpencil_modifier_types.h
#	修改:     source/blender/makesrna/intern/rna_gpencil_modifier.c
#
2021-09-21 23:03:21 +08:00
84f98e28e3 Fix T87801: Eevee ambient occlusion is incorrect on M1 macMini
The issue was caused by `textureSize()` returning the size of the level 0
even when the min texture level is higher than 0.

Using a uniform to pass the correct size fixes the issue.

This issue also affected the downsampling of radiance for reflections and
refractions.

This does not affect anything other than the recusive downsampling shaders.
2021-09-21 16:39:17 +02:00
33955231f3 Fix T91458: Displaying dope-sheet with sequencer keyframes crashes
Error in e6194e7357.
2021-09-22 00:06:17 +10:00
a25cd206c6 Cleanup ClangTidy warning.
Different parameter name in function declaration and implementation.
2021-09-21 15:56:05 +02:00
Urko
96027b2d15 Make knife drawing anti aliased (Monkey work based on D11333)
Knife tool.

Make the drawing anti aliased and consistent by using
3D_POLYLINE/3D_POINT shaders, and making sure alpha
blending is on.

Monkey work based on [[ https://developer.blender.org/D11333 | D11333 ]]
done by  [[ https://developer.blender.org/p/krash/ | Anthony Edlin (krash)]]

Reviewed By: jbakker

Differential Revision: https://developer.blender.org/D12287
2021-09-21 15:40:09 +02:00
0803119725 Cycles: merge of cycles-x branch, a major update to the renderer
This includes much improved GPU rendering performance, viewport interactivity,
new shadow catcher, revamped sampling settings, subsurface scattering anisotropy,
new GPU volume sampling, improved PMJ sampling pattern, and more.

Some features have also been removed or changed, breaking backwards compatibility.
Including the removal of the OpenCL backend, for which alternatives are under
development.

Release notes and code docs:
https://wiki.blender.org/wiki/Reference/Release_Notes/3.0/Cycles
https://wiki.blender.org/wiki/Source/Render/Cycles

Credits:
* Sergey Sharybin
* Brecht Van Lommel
* Patrick Mours (OptiX backend)
* Christophe Hery (subsurface scattering anisotropy)
* William Leeson (PMJ sampling pattern)
* Alaska (various fixes and tweaks)
* Thomas Dinges (various fixes)

For the full commit history, see the cycles-x branch. This squashes together
all the changes since intermediate changes would often fail building or tests.

Ref T87839, T87837, T87836
Fixes T90734, T89353, T80267, T80267, T77185, T69800
2021-09-21 14:55:54 +02:00
fa6b1007ba Fix script_load_keymap failure from c9d9bfa84a
Scanning the keymap hierarchy (used in the preferences),
caused the test to fail.

Don't attempt add fallback keymaps for dynamic keymap callbacks.
2021-09-21 22:19:40 +10:00
69928307c5 Cleanup: Silence unused variable warning 2021-09-21 14:18:31 +02:00
Aditya Y Jeppu
997b5fe45d VSE strip thumbnails
Draw thumbnails as strip overlay. This works for movie and image strips.
To draw thumbnails, this overlay has to be enabled and strips must be
tall enough.

The thumbnails are loaded from source file using separate thread and
stored in cache.

Drawing code uses only images stored in cache, and if any is missing,
background rendering job is started. If job can not render thumbnail,
to prevent endless loop of creating job for missing image it sets
`SEQ_FLAG_SKIP_THUMBNAILS` bit of `Sequence` flag.

To prevent visual glitches during timeline panning and zooming, `View2D`
flag `V2D_IS_NAVIGATING` is implemented. If bit is set, drawing code
will look for set of evenly distributed thumbnails that should be
guaranteed to exist and also set of previously displayed thumbnails.
Due to volatile nature of cache these thumbnails can be missing anyway,
in which case no new thumbnails will be drawn for particular strip.

Cache capacity is limited to 5000 thumbnails and performs cleanup of
non visible images when limit is reached.

ref T89143

Reviewed By: ISS

Differential Revision: https://developer.blender.org/D12266
2021-09-21 10:55:04 +02:00
fa2c1698b0 VSE: Image transform tools
Add tools for image manipulation in sequencer preview region.

This includes:
- Translate, rotate and resize operators, tools and gizmos
- Origin for image transformation
- Median point and individual origins pivot modes
- Select and Box select operator works in preview
- Image overlay drawing

ref T90156

Reviewed By: campbellbarton

Differential Revision: https://developer.blender.org/D12105
2021-09-21 10:55:04 +02:00
26f9b1ef49 LibOverride: make view_layer API parameter optional.
This is used to find a valid collection in which to instantiate stray
objects and collections.

In some cases there will be no such active view layer, in which case we
can consider using the Scene's master collections children hierarchy
instead to find a valid instantiated parent collection for those stray
data.
2021-09-21 10:43:34 +02:00
f5c6029cc5 Keymap: preference for keys to set the active tool
With "Keys Activate Tools" preference enabled, keys such as G/R/S
activate the move/rotate/scale tool instead of the modal operator.

Addresses T83692.
2021-09-21 18:24:12 +10:00
8b8a678cdf Keymap: preference for Alt-LMB to use the active tool
With the LMB select key-map some tools required clicking on a gizmo.
With this preference it's possible to hold Alt and click anywhere.

Addresses T83689.
2021-09-21 18:24:07 +10:00
c9d9bfa84a Keymap: preference for fallback-tool with RMB select
Expose a key-map preference "Fallback Tool (RMB)",
disabled by default.

The right mouse button uses the fallback tool
(currently visible selection tool in the toolbar),
instead of always tweaking.

When any selection tool is active, right mouse always tweaks.

To enable fallback selection on RMB, set the "Right Mouse Select Action"
to "Selection Tool".

Internal changes:

- Add fall-back key-maps, separate key-maps needed for when the tool is
  run as a fall-back. This is needed so RMB-select can support fall-back
  tools, so left-mouse can be used when it's the active tool and RMB
  can be used as a fall-back action when another tool is active.
- Add options field to tools so tools without gizmos can enable the
  full-back tool keymap.
- Support multiple key-maps for keymap handlers.
- Fall-back keymaps now co-exist with the tool-keymaps.
  So both keymaps may be active at once - using different mouse buttons.
  When gizmos are in use, a highlighted gizmo prioritizes the
  tool-keymap over the fall-back keymap.

Resolves T83690.

Reviewed By: JulienKaspar

Ref D12493
2021-09-21 18:14:11 +10:00
52bfa750e7 WM: only return PASS_THROUGH on PRESS for selection operators
Some selection operators return (PASS_THROUGH & FINISHED) so the tweak
event isn't suppressed from the PRESS event having been handled.

This is now restricted to events with a PRESS action.
Without this, using CLICK for selection was passing the event through
which could run other actions unintentionally.
2021-09-21 17:26:21 +10:00
5eb505e368 Cleanup: Remove debugging change, add comments 2021-09-20 20:37:49 -05:00
17021adcea Geometry Nodes: Curve Sample Node
This node allows sampling positions, tangents, and normals at any
arbitrary point along a curve. The curve can include multiple splines,
all are taken into account. The node does not yet support transferring
generic attributes like radius, because some more general tooling will
make that much more feasible and useful in different scenarios.

This is a field node, so it is evaluated in the context of a data-flow
node like "Set Position". One nice thing about that is it can easily
be used to move an entire geometry like the follow path constraint.

The point along the curve is chosen either with a factor of the total
length of the curve, or a length into the curve, the same choice used
in the curve trim node.

Differential Revision: https://developer.blender.org/D12565
2021-09-20 20:23:26 -05:00
9e939a614e Functions: Fix incorrect assert for unused output
Since the variable for an output parameter can be null,
it is incorrect to use it later on in a reference.
2021-09-20 20:22:52 -05:00
4472a11017 Fix: Crash with single point bezier spline auto handles
There's no way to calculate auto or vector handles when there is
only one point, and returning early allows avoiding checking for
that case later on.
2021-09-20 20:20:39 -05:00
Victor-Louis De Gusseme
05f3f11d55 Geometry Nodes: Attribute Statistic Node
This nodes evaluates a field on a geometry and outputs various
statistics about the entire data set, like min, max, or even
the standard deviation. It works for float and vector types currently,
though more types could be supported in the future.

 - All statistics are calculated element-wise for vectors.
 - "Product" was not added since the result could very easily overflow.
 - The "Size" output was not added since it isn't specific to an
   attribute and would fit better in another node.

The implementation shares work as much as possible when multiple
statistics are needed.

This node has been in development since the beginning of this year,
with additions from Johnny Matthews and Hans Goudey.

Differential Revision: https://developer.blender.org/D10202
2021-09-20 18:39:39 -05:00
13a4bccdb1 Asset Browser: Redraw sidebars on mode switches
There may be mode specific panels for some assets in the navigation or
the asset metadata sidebar. For example the pose library will likely do
this. So let the regions redraw on mode changes.
2021-09-20 22:10:03 +02:00
15471d9bed Update RNA to user manual url mappings 2021-09-20 13:40:31 -04:00
e43ecca016 Tests: measure time per frame in animation performance benchmark
Instead of a fixed number of frames, so that benchmarking takes about the
same time on any machine.
2021-09-20 19:03:22 +02:00
3b8d702a2f Geometry Nodes: use implicit position input in noise node
This is the same behavior as in shader nodes.
2021-09-20 19:01:08 +02:00
32a4c7f188 Geometry Nodes: implicit position input in Set Position node
This change makes the Set Position node do nothing by default.
Before, the geometry would always disappear, because it all points
would be moved to (0, 0, 0).

Differential Revision: https://developer.blender.org/D12553
2021-09-20 18:56:30 +02:00
a79c33e8f8 UI: Change "Favorites" to "Bookmarks"
Change of File Browser "Favorites" section header in source list
(T panel) to "Bookmarks" to maintain consistency with all the other
bookmark-related text and operations.

See D10262 for more information and alternatives considered.

Differential Revision: https://developer.blender.org/D10262

Reviewed by Julian Eisel
2021-09-20 07:42:17 -07:00
7cb65e4581 Cleanup: Refactor VSE overlay settings
Move overlay flags into SequencerPreviewOverlay and
SequencerTimelineOverlay structs.

Reviewed By: campbellbarton

Differential Revision: https://developer.blender.org/D12569
2021-09-20 16:30:15 +02:00
9642447faf GPencil: Fix error in previous commit
By error I commited the previous version.
2021-09-20 15:37:54 +02:00
c5c189a158 GPencil: Change Rotation tooltip
The tooltip was not clear about in what shading modes  works.

Related to T91467
2021-09-20 15:32:27 +02:00
eaad219ee7 Cleanup: spelling (correct c5c8c68eec)
"iff" was intended as "if and only if". while exact use of abbreviations
isn't clear cut, I assumed this was a typo & it's not used anywhere
else in source/, expand to "only if" (suggested by Sybren).
2021-09-20 22:31:13 +10:00
da4796ebf7 Build: change make update to not print errors regarding submodule branches
Instead of trying to checkout non-existent branches and getting confusing fatal
error prints, check if the branch exists first.

Ref D12560
2021-09-20 14:05:56 +02:00
fc4f82d200 Geometry Nodes: support Noise Texture node
This makes the Noise Texture node available in geometry nodes.
It should behave the same as in shader node, with the exception
that it does not have an implicit position input yet. That will
be added separately.

Differential Revision: https://developer.blender.org/D12467
2021-09-20 13:12:25 +02:00
8c7c4549d1 Geometry Nodes: support Set Position node on instances
Previously, the node would always realize instances implicitly.
Now it can change the position of entire instances.
The Realize Instances node can be used before if the old
behavior is required.

Differential Revision: https://developer.blender.org/D12555
2021-09-20 12:49:28 +02:00
11e11c41f2 make_update: Fix case where a sub-module would not have required branch.
Issue revealed by rB546314fc9669 change, also error itself exited before
that commit.

Now we do accept git command to fail when trying to checkout the
specified branch from sub-modules, and only actually error in case the
fall-back branch (aka master) cannot be properly checked out.

Thanks fot Ray molenkamp (@LazyDodo) for report and initial patch
(D12560).
2021-09-20 12:44:01 +02:00
7da9da2b27 Geometry Nodes: new Realize Instances node
This node has a simple geometry input and output.
If the input geometry contains instances, they will be realized
into actual geometry. When there are many instances, this can
be very slow and memory intensive. Generally, instances should
only be made real when necessary, e.g. when every instance
should be deformed independently.

Differential Revision: https://developer.blender.org/D12556
2021-09-20 12:37:52 +02:00
029d042e85 UUID: add nil value for UUIDs
Add `BLI_uuid_nil()` that returns the nil UUID (used to indicate "not
set") and `BLI_uuid_is_nil(uuid)` to do an equality test with the nil
value.
2021-09-20 12:15:37 +02:00
07b482c2ff UUID: fix seeding the RNG clock on macOS
On Apple machines, call `clock_gettime()` instead of `timespec_get()`.

macOS only introduced `timespec_get()` in version 10.15 (introduced
approx two years ago, so in 2019), even though the function is from C11.
2021-09-20 12:10:25 +02:00
1e3c5fdb85 Cleanup: UUID, prevent "missing braces" warning on macOS
Add braces around initialization of sub-objects, as per the warning
suggestion on macOS.

No functional changes.
2021-09-20 12:10:25 +02:00
4eba920d15 UUID: include 'seconds' field of current time in RNG seed
XOR the 'seconds' and 'nanoseconds' fields of the current time to seed the
RNG used for generating random UUIDs. This ensures a better seed just in
case the clock as no sub-second resolution.
2021-09-20 12:10:25 +02:00
1f51672d71 Fix T91511: GPencil weight_get and Vertex Groups not working at expected
The API was checking the number of total weights with the first point of the stroke and this was not valid because each point can have different number of weight elemnts,
2021-09-20 11:10:39 +02:00
738f1dbeff UI: rename "Save Screenshot (Area => Editor)"
The term "area" isn't normally exposed in the UI.
2021-09-20 19:03:07 +10:00
c5c8c68eec Cleanup: spelling 2021-09-20 16:44:28 +10:00
c773443845 Fix: Incorrect default values for the curve trim node
The default end factor should be 1. The proper value for the default end
length is somewhat arbitrary, but it shouldn't be zero.
2021-09-19 22:08:11 -05:00
f973e0b75a Fix: Spline length calculation fails with no evaluated points
The case that checked whether there were evaluated edges was incorrect,
since two points are needed for an edge. Then also avoid running the
accumulation for an empty span.
2021-09-19 19:01:24 -05:00
c9e835fec1 Fix build error after previous commit
Incorrect renaming and use of enum after search and replace.
2021-09-19 18:59:01 -05:00
25aa943e8c Cleanup: Fix/improve variable names and comments 2021-09-19 18:54:03 -05:00
276eebb274 Compositor: Add OIDN prefiltering option to Denoise node
It's equivalent to the OpenImageDenoise prefiltering option in Cycles.
See D12043.

Prefilter modes:
- None: No prefiltering, use when guiding passes are noise-free.
- Fast: Denoise image and guiding passes together. Improves quality when
guiding passes are noisy using least amount of extra processing time.
- Accurate: Prefilter noisy guiding passes before denoising image.
Improves quality when guiding passes are noisy using extra
processing time.

Reviewed By: #compositing, jbakker, sergey

Differential Revision: https://developer.blender.org/D12342
2021-09-19 21:13:51 +02:00
f256bfb3e2 Compositor: Fix crash exporting buffers on debug
ImBuf allocates 4 channels, use copying to support buffers
with 1 and 3 channels.
2021-09-19 21:13:45 +02:00
942c471ce9 Compositor: Fix Alpha Over node ignoring emissive colors
It was an issue on Full Frame mode only.
2021-09-19 21:13:40 +02:00
257c7753e9 Cleanup: Rename curve node enums
The enum called "interpolate" was really a choice of methods for mapping
inputs to positions on the curve, whereas the "sample" enum was used to
define a way to create a whole set of new points from the curve, without
any input parameters. The "re-sample" vs. "sample" naming makes that
distinction better.
2021-09-19 01:20:06 -05:00
69697fcca9 Revert "GPencil: Curvature support for length modifier."
Reason for revert: accidental push of a intermediate change locally.

This reverts commit 25e548c96b.
2021-09-19 13:19:32 +08:00
25e548c96b GPencil: Curvature support for length modifier. 2021-09-19 13:01:24 +08:00
bdbc7e12a0 Audaspace: added audio file streams functionality.
On the blender side this commit fixes importing video files with audio
and video streams that do not share the same start time and duration.

Differential Revision: https://developer.blender.org/D12353
2021-09-18 21:45:33 +02:00
970c928f27 Py API Docs: Fix audio docs example
After new AUD API changes from 2.8x what "buffer" function used to do
has now become "cache" function (it caches a sound into RAM). Therefore,
the basic aud example should call this new "cache" function instead of
"buffer" function.

Thanks to Michael-Z-Freeman for pointing out.
2021-09-18 19:28:55 +02:00
2618df7d03 Cleanup: add missing includes 2021-09-18 13:36:20 +02:00
136e357d8d Cleanup: typo 2021-09-18 13:35:05 +02:00
a229a9dd64 Fix T91461: Pose Library name filter not working
since `AssetHandle` does not have a `name_property`
(`RNA_def_struct_name_property`), and the UIList is just using the
default `uilist_filter_items_default` it simply cannot filter on names
(`RNA_struct_name_get_alloc` wont succeed).

Adding a name_property also wont work since `AssetHandle` inherits
`PropertyGroup` (which already sets name_property).

So this adds a (temporary) hack exception for RNA_AssetHandle in
uilist_filter_items_default until the design of `AssetHandle` progresses
further.

thx @Severin for additional feedback

Maniphest Tasks: T91461

Differential Revision: https://developer.blender.org/D12541
2021-09-18 08:13:24 +02:00
6d7113c363 Merge branch 'master' into xr-controller-support 2021-09-10 17:57:57 +09:00
33306067da Update based on D10948 2021-09-10 17:23:56 +09:00
ff5733ef2f Merge branch 'master' into xr-controller-support 2021-09-02 13:39:59 +09:00
c996926c05 Remove XrSessionState.reset_navigation() RNA func
Function was unnecessary since XrSessionState.reset_to_base_pose()
will also reset navigation deltas.
2021-09-02 13:27:55 +09:00
593621fdfb Merge branch 'master' into xr-controller-support 2021-08-31 18:05:42 +09:00
07a92c616f XR: Add reset navigation operator
Resets XR navigation deltas relative to session base pose. Primarily
useful for undoing elevation/scale changes. Will be added to the
default VR actions.
2021-08-31 17:58:22 +09:00
99ce2f3e4d XR: Replace invoke/modal_3d for XR operators
Special 3D-to-2D handling (as invoke/modal_3d is used for) is not
necessary for regular XR operators, so they can use the normal
invoke/modal callbacks.
2021-08-31 17:48:29 +09:00
c8c782fbf4 Cleanup: remove unused struct member, null checks 2021-08-31 17:42:55 +09:00
0f1ef110a4 Merge branch 'master' into xr-controller-support 2021-08-26 19:29:20 +09:00
5fd158bb87 XR: Refactor motion capture objects
This refactors the feature of binding objects to controllers
and recording auto-keyframes, or "motion capture objects", by
providing a more complete API for managing objects and moving the
implementation out of wm_xr_session.c and into its own file
(wm_xr_mocap.c).

In addition, motion capture objects are now stored as a dynamic array
instead of a fixed array, which was previously hard-coded for
specific devices. Each entry in this dynamic array is uniquely
identified by an Object pointer and is mapped to a VR device via an
OpenXR user path. For example, an object can be bound to the headset
via "/user/head", and the left controller via "/user/hand/left".
2021-08-26 19:23:14 +09:00
21a24aa61e Fix view3d.toggle_shading() not updating VR view
Reason was that the WM notifier did not set the NS_VIEW3D_SHADING
subtype, which the VR view listens for for a shading update.

In the case of view3d.toggle_xray(), a notifier was absent
altogether.
2021-08-26 18:55:50 +09:00
c9a4c29589 Cleanup: remove unnecessary #ifdefs 2021-08-26 18:36:29 +09:00
a063d58080 Merge branch 'master' into xr-controller-support 2021-08-20 20:50:24 +09:00
f58bebf688 XR: Fix controller model world transforms
Fixes incorrect display of Reverb G2 controller model/animated parts.

Thanks to Werner Trunk for help with debugging.
2021-08-20 20:46:15 +09:00
ba79625f9e Merge branch 'master' into xr-controller-support 2021-08-16 18:57:48 +09:00
72381da800 XR: Don't store controller node world transforms
Removes unnecessary storage of world space transforms for controller
model nodes. Now, only local space transforms are stored and the
world transforms are calculated from these local transforms when
needed.
2021-08-16 18:55:36 +09:00
9d68c34a75 Merge branch 'master' into xr-controller-support 2021-08-16 12:04:19 +09:00
e41cc8162a Merge branch 'master' into xr-controller-support 2021-08-15 15:21:01 +09:00
1990bb921f XR: Support dynamic controller model components
Updating the transforms, or "animating", supported controller
model parts (trigger, grip, thumbstick, etc.) provides better visual
feedback for the user and adds little overhead due to caching of node
transforms/indices.
2021-08-15 15:18:34 +09:00
567c22f0d8 Merge branch 'master' into xr-controller-support 2021-08-13 07:28:34 +09:00
be0a272d91 XR: Fix crash/assert on loading controller model
When calculating controller model component transforms from glTF node
data, it was previously wrongly assumed that the glTF nodes would
always contain transform matrix values. However, nodes can instead
store their transforms as separate translation/rotation/scale values,
in which case the transform matrix needs to be explicitly calculated.
This was the case for the Reverb G2 controller models using the
Windows Mixed Reality runtime.

Special thanks to Werner Trunk for help with testing/debugging.
2021-08-13 06:44:50 +09:00
5f5289512c XR: Improve "Invalid stage ref space" warning
Originally mentioned that absolute tracking was disabled, which is
wrong because absolute tracking (skipping application of eye offsets)
is always available, although it may not give the expected result of
persistent tracking origins across sessions if the stage space is
unavailable (hence the need for a warning).

Now, the warning makes no mention of absolute tracking, instead
informing the user that the local space fallback will be used and
that they should define tracking bounds via the XR runtime if they
wish to use the stage space.
2021-08-13 06:23:01 +09:00
05c3e5c433 Cleanup
- Remove unused wmSurface.is_xr member
- Rename "actionmap" to "action_set" in wmXrActionData
- Use BLI_findstring()
- Add modifications note to tinygltf readme
2021-08-08 13:17:18 +09:00
9f6b8bc3a1 Re-update pipeline config
Accidentally updated wrong submodule in previous commit.
2021-08-07 20:55:00 +09:00
d870b85dab Update pipeline config 2021-08-07 20:46:41 +09:00
2f4712841a Merge branch 'master' into xr-controller-support 2021-08-07 18:36:55 +09:00
6dec69daa8 XR: Fix crash on file read with active session
Add null check for runtime data since it could already have been
freed via wm_xr_exit() prior to the session exit callback.
2021-08-07 18:31:12 +09:00
be7653fe52 Cleanup: remove unnecessary double pointer usage 2021-08-07 17:30:27 +09:00
c600251eae XR: Use regular window queues for XR events
Removes special queueing of events to the XR surface, which was
originally done to bypass filtering by mouse region when
invoking/executing XR operators.

Now, finding an appropriate region for XR events will simply be done in
the regular window event handling by checking the event type and
skipping mouse-specific processing.
2021-08-07 17:04:34 +09:00
d2c4094425 Merge branch 'master' into xr-controller-support 2021-08-06 16:20:44 +09:00
14fc1c73e8 Update with changes from D10943 2021-08-06 15:58:41 +09:00
ef07af330a Add missing unused variable 2021-08-02 17:00:57 +09:00
9561a0a0a3 Merge branch 'master' into xr-controller-support 2021-08-02 16:56:42 +09:00
9f5089b67a XR: Simplify action creation API
By passing an XrActionMap struct instead of individual action
parameters, action creation from Python can be reduced to a simple
call to XrSessionState.create_action_set().

This will also set any controller pose actions and optionally the
active action set for the session.
2021-08-02 16:53:04 +09:00
f34cb9f8bf Merge branch 'master' into xr-controller-support 2021-07-29 13:13:12 +09:00
5a640b94b4 Cleanup: use LISTBASE_FOREACH_INDEX macro 2021-07-29 13:12:30 +09:00
9025f2adc6 XR: Fix action map load/save
Forgot to add action bindings list.
2021-07-29 13:10:43 +09:00
d5989308fb Fix build warnings 2021-07-28 13:40:12 +09:00
8a103470c9 Merge branch 'master' into xr-controller-support 2021-07-28 13:08:26 +09:00
be59b7699e XR: Fix crash on close with active session
Fixes an issue introduced in 99beac7b3f due to duplicate call to
wm_xr_session_data_free().
2021-07-28 13:06:41 +09:00
6b67760bd8 XR: Refactor action maps, bindings
This removes the previous limitation of one interaction profile
(device) per action map by moving the profiles to action bindings.
By doing so, there is no longer the need for users to manually select
an action map, as the XR runtime will automatically select the most
appropriate profile.

An additional DNA action map layer, "XrActionMapBinding", was also
added to store profiles and input-specific properties for actions,
allowing for flexible inputs across devices.
2021-07-28 13:02:37 +09:00
fb3154447b Fix build warnings 2021-07-24 19:10:19 +09:00
c56b73277e Merge branch 'master' into xr-controller-support 2021-07-24 18:20:19 +09:00
99beac7b3f XR: Use dynamic arrays for eye, controller data
Makes API/functionality more adaptable to different systems.
2021-07-24 18:08:29 +09:00
c4c4b1a03d XR: Move controller batch creation to draw func
Ensures that a valid GPU context is available during batch creation,
which fixes potential access violation issues.
2021-07-24 15:51:23 +09:00
af90b8aaa3 Update with changes from master
36c0649d32, c41b93bda5
2021-07-24 14:23:07 +09:00
2c5241ad01 Merge branch 'master' into xr-controller-support 2021-07-22 17:36:49 +09:00
6daab062b4 Fix build errors/warnings on some platforms 2021-07-22 17:35:14 +09:00
4b3aaa76bd Merge branch 'master' into xr-controller-support 2021-07-22 15:36:54 +09:00
707bc260d8 XR: Add basic controller model drawing
Uses the OpenXR XR_MSFT_controller_model extension to load a glTF
model provided by the XR runtime. The model's vertex data is then
used to create a GPUBatch in the XR session state. Finally, this
batch is drawn via an XR surface draw callback.

Currently does not use the model's texture data, but this can be
supported in the future.
2021-07-22 15:31:36 +09:00
5b45070024 XR: Refactor controller poses
Separates controller poses into two components, "grip" and "aim",
which are both required to accurately represent the controllers
without manual offsets.

Following their OpenXR definitions, the grip pose represents the
user's hand when holding the controller, and the aim pose represents
the controller's aiming source.
2021-07-22 00:58:17 +09:00
bd8b3f57df Fix build warnings 2021-07-09 13:58:12 +09:00
4040ebd1ff Merge branch 'master' into xr-controller-support 2021-07-09 11:28:47 +09:00
3feb3a4707 XR: Fix grab interp/offsets for parented objects 2021-07-09 11:23:02 +09:00
aa92c23430 Merge branch 'master' into xr-controller-support 2021-07-07 20:04:13 +09:00
7863f2fbe0 XR: Add teleport offset option 2021-07-07 19:22:36 +09:00
872484dfaa XR: Fix action state querying from Python
Credit: Jacob Merrill
2021-07-07 19:22:10 +09:00
1185259db8 Merge branch 'master' into xr-controller-support 2021-07-04 15:48:26 +09:00
1f1589b4df XR: Show selection/controller overlays by default 2021-07-04 15:42:55 +09:00
6ee46d5e83 XR: Fix mirror view not matching navigation
Forgot to update eye poses with viewer pose.
2021-07-04 15:40:38 +09:00
a177eb3dd2 Merge branch 'master' into xr-controller-support 2021-07-03 13:06:04 +09:00
f7d42065eb XR: Fix render artifacts with viewport denoising
Addresses T76003. When using VR with Eevee and viewport denoising,
scene geometry could sometimes be occluded for one eye. Solution was,
as Clement suggested, to use a separate GPUViewport/GPUOffscreen for
each VR view instead of reusing a single one for rendering.
2021-07-03 13:05:32 +09:00
7a7ee11f13 XR: Direction lock, frame based speed fly options 2021-07-03 13:05:10 +09:00
5465112930 Cleanup: RNA text 2021-07-03 13:04:49 +09:00
f89f63eefd Merge branch 'master' into xr-controller-support 2021-07-02 18:17:29 +09:00
714224ee1f XR: Support haptic feedback for actions
Adds haptic settings to float (button) actions that can be used to
apply haptics when an action is active. Users can configure the
duration, frequency, and amplitude of the feedback as well as when
it will be applied (press, release, press/release, or repeat).

The haptic output path/target is specified via the name of an
existing action of type "haptic". This allows float actions to target
the same output paths without the need for multiple haptic actions.
2021-07-02 18:10:34 +09:00
1184da2974 XR: Add cubic interpolation option for fly speed 2021-07-02 18:09:46 +09:00
e8926d40c8 XR: Add option to raycast from viewer pose
Useful when using a gamepad or for systems without motion
controllers.
2021-07-02 18:07:55 +09:00
004034f8c5 XR: Fix grab transform for parented objects 2021-07-02 17:59:14 +09:00
7b867dd00a Merge branch 'master' into xr-controller-support 2021-06-26 19:33:17 +09:00
e022f99e5c XR: Allow multiple modal actions at a time
This was disabled before since modal handlers for action operators
could receive events from other actions and exit prematurely. Now,
the XR operators check for events with the matching operator and
properties to avoid this. In addition, a list of active modal actions
is stored in the session state so that duplicate operators can be
filtered out when dispatching events.
2021-06-26 19:25:52 +09:00
80c80f5e18 XR: Use prior nav data to calculate viewer pose
Fixes an issue where draw callbacks were not drawn correctly if an
operator changed the navigation. Now, the navigation transforms are
saved before dispatching action events and are later used to
calculate the viewer/controller poses.
2021-06-26 19:11:48 +09:00
0d6c6a6787 Merge branch 'master' into xr-controller-support 2021-06-23 20:35:06 +09:00
e3cab5c206 XR: Add fly navigation operator
Navigates the scene by moving/turning relative to navigation space
or the XR viewer/controller. Users can select from a variety of
these modes as well as specify the min/max speed and whether to lock
elevation.

Also: pass float threshold to XR action events.
2021-06-23 20:30:32 +09:00
8ace7897a8 XR: Update controller data again in viewer update
This is needed to draw the controllers with correct transforms in the
event that an operator changed the navigation.
2021-06-23 20:24:31 +09:00
e5089d3924 Merge branch 'master' into xr-controller-support 2021-06-19 18:18:39 +09:00
65804b203e XR: Add location/rotation locks for navigation 2021-06-19 18:12:43 +09:00
2a768ffe43 Merge branch 'master' into xr-controller-support 2021-06-18 21:36:13 +09:00
2585d7f1b8 XR: Add grab navigation operator
Similar to the XR grab transform operator but applies deltas to the
navigation matrix instead of objects. Supports bimanual interaction
for viewer/navigation scaling and locks for rotation and scale.
2021-06-18 21:32:18 +09:00
eed31613e5 XR: Smooth transition between modal actions
Although only one modal action is allowed at a time, if another
modal action is pressed when the current modal action ends, then
transition immediately to that one.
2021-06-18 21:26:38 +09:00
6732d31f18 XR: Fixes/adjustments when viewer scale != 1.0
This corrects some clipping and shading issues when a scale factor
is applied to the XR viewmat. Also fixes the viewer pose calculation
with VR navigation.
2021-06-18 21:22:15 +09:00
1bd403430d Remove duplicate file
Was renamed to "wm_xr_action.c".
2021-06-18 21:14:13 +09:00
9926553255 Merge branch 'master' into xr-controller-support 2021-06-12 19:32:20 +09:00
0c92bf5e37 XR: Fix viewer pose and teleport calculation 2021-06-12 19:28:07 +09:00
9ce38d17ed XR: Add bimanual scale mode for grab operator
Also renamed operator to "Transform Grab".
2021-06-12 19:25:42 +09:00
40741a8942 Merge branch 'master' into xr-controller-support 2021-06-11 21:05:57 +09:00
eeb948f428 XR: Add axis region, bimanual action flags
The axis flags allow binding actions to certain regions of an input
axis (positive or negative). In this way, two different actions can
be bound to the input path "/input/thumbstick/x" without overlapping.

The bimanual flag signifies that the action depends on inputs from
both of its subaction paths, and both states, if available, will then
be passed to the operator. This will be used in the future for
two-handed navigation and transform.
2021-06-11 20:48:41 +09:00
9c3ac44c89 Merge branch 'master' into xr-controller-support 2021-06-08 19:35:24 +09:00
819a7e7900 Update pipeline config 2021-06-08 19:31:24 +09:00
5544ffabd5 Merge branch 'master' into xr-controller-support 2021-06-08 13:52:45 +09:00
2a3b8880e3 Fix build warnings 2021-06-08 13:51:22 +09:00
05f5d2791f Merge branch 'master' into xr-controller-support 2021-06-04 19:18:44 +09:00
29702c6d8b XR: Add teleport navigation operator
Mostly the same as the XR raycast select operator. Users can
optionally constrain the result to specific axes, for example to
achieve "elevation snapping" behavior by constraining to the Z-axis.

Credit to KISKA for the elevation snapping concept.
2021-06-04 19:10:53 +09:00
36463a16bb XR: Add initial navigation support
Adds navigation transforms (pose, scale) to the XR session state
that will be applied to the viewer/controller poses.

Users can access these transforms via Python
(xr_session_state.navigation_location/rotation/scale) to use with
custom operators.
2021-06-04 19:01:50 +09:00
b57cc27ec9 Fix build errors on some platforms 2021-05-26 18:13:35 +09:00
8b53855371 Clang format 2021-05-26 18:12:14 +09:00
af1c2869a6 Merge branch 'master' into xr-controller-support 2021-05-26 17:34:35 +09:00
9df2fae994 XR: Enable controller profile extensions 2021-05-26 17:08:35 +09:00
daf5570c42 Cleanup GHOST_Xr 2021-05-26 17:06:14 +09:00
795ae6433d XR: Change raycast color 2021-05-26 17:05:19 +09:00
1e8b3692b9 XR: Deactivate draw callbacks on session end 2021-05-26 17:04:39 +09:00
544c6fd1b6 Merge branch 'master' into xr-controller-support 2021-05-18 22:14:12 +09:00
963a6c3c12 Update addons submodule 2021-05-18 22:13:22 +09:00
f799fc3033 Merge branch 'master' into temp-xr-actions-D9124 2021-05-18 19:28:04 +09:00
5a786038cb Fix RNA error 2021-05-18 19:14:34 +09:00
7343845d7b Update with changes from D10943 2021-05-18 18:47:17 +09:00
ce5fc090a8 Move customdata wrapper to GHOST_Util.h 2021-05-16 03:13:07 +09:00
2fa8e2686e Rename "threshold" to "float_threshold" 2021-05-16 03:12:56 +09:00
f89460a872 Use RAII customdata wrapper for ctor exceptions 2021-05-16 01:09:39 +09:00
8c8bc114b8 Fix errors/warnings on Linux, gcc 2021-05-15 22:15:06 +09:00
11a63417ea Update with changes from D10942
- GHOST_XrException: Use std::string instead of const char*
- GHOST_XrActionProfile: Move default dtor declaration to header
- GHOST_XrActionSet/Action: Fix mem leak on exception in ctor
2021-05-15 10:58:53 +09:00
ed869a2609 Revert changes to wm_xr_controller_pose_to_mat() 2021-05-15 08:45:16 +09:00
79ed8f21f7 Fix merge-related error 2021-05-14 22:02:58 +09:00
a5d1f3e4c5 Merge branch 'master' into temp-xr-actions-D9124 2021-05-14 21:36:39 +09:00
7c05339597 Update with changes from D10942
Mainly cleanup-related but also adds wmXrPose and wmXrActionState
structs to replace float[7] and void* uses, respectively.
2021-05-14 21:32:23 +09:00
cd3030bb8d Fix RNG_TYPE_LEN value 2021-05-14 21:30:16 +09:00
5677c02954 Pass context to wm_xr_session_actions_update()
Restores motion capture object autokeying functionality.
2021-05-03 11:07:00 +09:00
3e7524b52b Clang format 2021-05-03 11:04:07 +09:00
c34d0fbee2 Update with changes from D10942
Except for motion capture object autokeying (will be added again once
a good way to get the blender context from wm_xr_session is found),
functionality remains the same as before.
2021-04-30 19:54:03 +09:00
63f0dcf6b7 Merge branch 'master' into temp-xr-actions-D9124 2021-04-29 15:36:47 +09:00
517a3cdad1 Adjust CMakeLists, fix typo 2021-04-29 15:32:27 +09:00
585f98784c Merge branch 'master' into xr-actions-D9124 2021-04-10 13:28:17 +09:00
c9c052aae0 Merge branch 'master' into xr-actions-D9124 2021-03-21 20:37:56 +09:00
9cfc8ebcc9 XR: Add op_name property to XrActionMapItem
Improves readability over operator ID string when displaying action
properties.
2021-03-21 20:37:05 +09:00
dfc8860502 Revert edit to blender_default.py
Leftover from keymap->actionmap refactor.
2021-03-21 20:12:32 +09:00
97c8878753 Fix warnings on Linux / gcc 2021-03-14 19:54:43 +09:00
49707f5d83 Merge branch 'master' into xr-actions-D9124 2021-03-14 19:14:50 +09:00
334114d287 XR: Cleanup after actionmap refactoring
Aside from general cleanup, changed that only user actionconfigs and
the builtin user config can be saved to blend files (the builtin
default and addon configs are excluded).
2021-03-14 19:02:34 +09:00
034dd0d702 XR: Move actions from keymaps to actionmaps
Previously, properties for XR actions were stored in keymaps but they
are now stored in a separate XR "actionmaps" system. Although the
actionmap system/API has many similarities to the keymaps, it is
significantly less complex since it does not involve any diff-ing of
default/addon/user configurations (at least at the moment).

Another big distinction between keymaps and actionmaps is that
actionmaps and properties are saved to blend files. This allows users
to set up a VR scene with actions and properties and share working
versions with others, without the need to import/export config files.
However, actionmap import/export is also supported via the addon.

There is still a fair amount of refactoring left to do but at least
this commit removes XR involvement from the keymaps while preserving
most of the existing XR action functionality (i.e. default actions
and user-configurable actions).
2021-03-07 21:40:38 +09:00
d8cf5e7f4d Merge branch 'master' into xr-actions-D9124 2021-03-07 18:54:26 +09:00
854d115d68 XR: "deselect_all" by default for raycast select 2021-03-07 18:33:19 +09:00
886cba7fe8 Fix build error when disabling WITH_XR_OPENXR 2021-03-07 18:29:46 +09:00
f21eb52ecc Merge branch 'master' into xr-actions-D9124 2021-02-16 20:15:34 +09:00
81944920a7 Fix build error on Linux / gcc 2021-02-16 20:12:57 +09:00
cf12206311 Merge branch 'master' into xr-actions-D9124 2021-02-09 00:44:48 +09:00
247267dee4 XR: Use common functions for modal_3d operators
Reduces the amount of similar code for XR invoke_3d/modal_3d
operators that manipulate view3d params.
2021-02-09 00:11:49 +09:00
2370781389 Add TODO for merging into master 2021-02-08 23:57:52 +09:00
1aecb31acc Merge branch 'master' into xr-actions-D9124 2021-01-31 23:53:02 +09:00
2092d39dfd Fix merge-related error 2021-01-31 23:51:36 +09:00
412ea63063 Merge branch 'master' into xr-actions-D9124 2021-01-31 22:31:07 +09:00
0f236af817 XR: Remove remaining use of GHOST types in RNA
It might be good to have a WM equivalent for GHOST_XrPose (e.g.
wmXrPose) since converting from location/rotation or float[7] to
GHOST_XrPose can be pretty awkward.
2021-01-31 22:07:13 +09:00
798c33ab3b XR: Start refactoring internal API
Remove unnecessary data from GHOST types and mostly eliminate use of
GHOST types at RNA level. At the WM level, action creation functions
deal with single actions (instead of multiple actions at once) to
simplify the API.
2021-01-30 12:17:50 +09:00
a87b142e51 Fix build errors after merge
Also fixes incorrect use of RNA_def_struct_name_property().
2021-01-17 19:19:41 +09:00
2ddf55f358 Merge branch 'master' into xr-actions-D9124 2021-01-17 18:45:20 +09:00
84f821f271 Merge branch 'master' into xr-actions-D9124 2020-12-13 13:52:25 +09:00
29ed6a6872 Merge branch 'master' into xr-actions-D9124 2020-11-26 13:32:35 +09:00
78563e9bf1 XR: Add "controller draw style" session setting
Allows users to choose their preferred controller visualization
(controller local axes or -Z axis ray). The enum can be extended in
the future for additional visualizations.
2020-11-25 22:57:33 +09:00
8916a04df8 XR: Restore XR object transforms at session end
If an object was constrained to a headset/controller pose during the
session, then its original transform will be restored at session end
to prevent unwanted changes to the scene. This will also occur when
toggling the constraint or changing the constrained object.
2020-11-25 22:51:58 +09:00
c9f0da5b20 XR: Adjust raycast select property behavior
Combinations of properties (extend/deselect/toggle/deselect on empty)
now match view3d.select behavior.
2020-11-25 22:32:43 +09:00
f7a72a238b Merge branch 'master' into xr-actions-D9124 2020-11-23 16:17:12 +09:00
c8db91fc93 XR: Only allow one active modal action/subaction
Prevents unwanted behavior when a modal operator is bound to multiple
inputs (e.g. when an action has multiple subaction paths). Can be
refactored in the future to support "bimanual" interaction for some
operators.
2020-11-23 16:16:41 +09:00
e089ad2b4b Merge branch 'master' into xr-actions-D9124 2020-11-22 19:40:36 +09:00
6c67d808b7 XR: Add raycast option to ignore non-selectables
Useful when user does not want non-selectable objects to block
selectable objects in raycast result.
2020-11-22 19:35:16 +09:00
d3e352a7ec Keymap I/O: Add "exec" versions of import/export
The new "exec" functions are added for the sake of the VR Scene
Inspection add-on and do not affect the behavior of the existing
keymap I/O functions.

keyconfig_export_as_data_exec() enables exporting a specified keymap
instead of all user-modified keymaps. The VR add-on uses this to
selectively export the "XR Session" add-on keymap.

keyconfig_import_as_data_exec() enables adding keymap data to an
existing keyconfig instead of creating a new keyconfig. The VR add-on
uses this to add the "XR Session" keymap to the add-on keyconfig.
2020-11-22 18:52:17 +09:00
4423ab787b XR: Improve error logs when creating actions
Include action set name in case multiple action sets have an action
with the same name.
2020-11-22 18:29:14 +09:00
57f7e1ff97 Merge branch 'master' into xr-actions-D9124 2020-11-16 18:15:35 +09:00
f8ad9c696e Merge branch 'master' into xr-actions-D9124 2020-11-15 23:52:40 +09:00
79733505bf XR: Enable switching action sets during session
Since xrSuggestInteractionProfileBindings() overwrites any existing
profile bindings, the solution is to suggest bindings from all action
sets at the same time (done just before attaching action sets to the
session).
2020-11-15 23:46:40 +09:00
b4a21355d7 Cleanup: Comments 2020-11-15 23:38:37 +09:00
d685b9ca57 Cleanup: comments, variables 2020-11-14 22:22:46 +09:00
d3b07d5ad5 XR: Support axis (vector2f) input actions 2020-11-14 15:52:41 +09:00
86faaaa934 XR: Improve raycast select in edit mode
Limit raycast test to selected objects.
2020-11-14 15:50:56 +09:00
4d5f104faf Merge branch 'master' into xr-actions-D9124 2020-11-14 01:45:59 +09:00
6fdf493028 XR: Support mesh editing with grab operator
Uses similar mechanics as object mode, but interpolation and offsets
are not yet supported.
2020-11-14 01:26:50 +09:00
43dd6ba330 XR: Ensure mesh object for edit mode raycast 2020-11-14 01:23:09 +09:00
423619fd3d Increase line width for controllers / raycast 2020-11-14 01:10:31 +09:00
6489002982 XR: Remove Z-up conversion for pose actions
Not applying an implicit Z-up conversion for OpenXR coordinates may
be better since poses may have different orientations / tracking
spaces. Users can instead apply custom pose offsets via the UI /
Python API if necessary.
2020-11-14 01:08:28 +09:00
634812e579 Merge branch 'master' into xr-actions-D9124 2020-11-11 23:42:43 +09:00
8ccdd43fc1 XR: Implement XR grab operator
Transforms selected objects' location / rotation relative to a
controller's pose. Very basic compared to the existing transform
operators (which can also be used in VR via modal_3d), but provides
a more natural interaction in VR.
2020-11-11 23:30:24 +09:00
78d7dbbad9 Merge branch 'master' into xr-actions-D9124 2020-11-08 22:55:44 +09:00
4ec85983af XR: Remove controller overlay object
Object was originally meant to visualize the controller and be drawn
by the overlay engine, however it was unused since controllers are
now drawn via draw handlers. It might be added again in the future
for drawing more complex controller geometry.
2020-11-07 21:08:17 +09:00
dc0b81bc99 XR: Add XR region type to View3D space type
Enables add-ons to draw to the XR surface and mirror window by
adding a View3D draw handler of region type 'XR' and draw type
'POST_VIEW'. Also allows individual toggling of controller drawing
and custom overlays.
2020-11-07 19:04:36 +09:00
f6e71179fe XR: Draw controller overlays in mirror view 2020-11-07 17:44:56 +09:00
36bdbe6ce3 XR: Store multiple paths in GHOST_XrActionBinding
Facilitates action binding creation debugging by narrowing
errors down to an interaction profile and action.
2020-11-07 16:46:33 +09:00
5f7285d4af XR: Check for valid stage reference space bounds
Even if the stage reference space is supported by the XR runtime, the
bounds may be invalid (0, 0) if the user did not define a tracking
space via the runtime's UI. In this case, fall back to the local
tracking space.
2020-11-07 15:19:38 +09:00
1625bb3e71 Merge branch 'master' into xr-actions-D9124 2020-11-06 23:58:06 +09:00
a399445b3c XR: Fix projection selection in edit mode
Use window region dimensions instead of XR surface dimensions. Add
winrct offset for box select.
2020-11-06 23:56:31 +09:00
f32d320e90 XR: Fix raycast deselect empty for edit mode 2020-11-06 23:42:28 +09:00
78cd4e8cee Merge branch 'master' into xr-actions-D9124 2020-11-06 21:48:15 +09:00
848c87c6d9 Fix errors after merge 2020-11-06 21:46:56 +09:00
f5ff515085 Merge branch 'master' into xr-actions-D9124 2020-11-06 21:40:58 +09:00
07a7c88918 XR: Use stage ref space for absolute tracking 2020-11-06 21:31:43 +09:00
48ec546911 XR: Add axis property to raycast select operator
Allows users to adjust the raycast axis to fit different poses and
controllers.
2020-11-06 17:13:17 +09:00
8335da48f9 Cleanup: Comments 2020-11-06 17:08:42 +09:00
8fae3debf3 Merge branch 'master' into xr-actions-D9124 2020-11-05 22:33:39 +09:00
2ed0965e97 XR: Add "absolute tracking" session setting
Enables users to define the tracking origin in a way that is not
linked to the headset position. Instead, the tracking values given by
the XR runtime are left unadjusted and a user can manually calibrate
an "origin" landmark object to adjust to their real world space.

Can be useful for applications that use external tracking systems
and those that primarily only need to use controllers (e.g. for
motion capture).
2020-11-05 22:31:34 +09:00
2b338373d7 XR: Ensure valid region for invoking operators
Check for a valid v3d, even if the area / region uses a viewport.
2020-11-04 21:33:14 +09:00
c565bb8985 XR: Use TransInfo viewmat for transform modal_3d
Fixes static variable TODO.
2020-11-04 21:30:03 +09:00
03bb02337f XR: Compare absolute input value with threshold
Trackpad / thumbstick input values range from -1 to 1, so the
absolute value must be compared against the input threshold.
2020-11-04 21:24:43 +09:00
618df6b0b7 Fix build warnings on Linux / gcc 2020-11-04 21:13:42 +09:00
0c246b2b52 Merge branch 'master' into xr-actions-D9124 2020-11-03 18:50:07 +09:00
ff2dcdb447 XR: Implement XR constraints toggle operator
Useful for quickly playing back recorded animations without
overwriting existing data.
2020-11-03 18:47:11 +09:00
73daf1f721 XR: Support auto keying XR constraint objects
If specified, headset / controller objects will auto key on animation
playback. This can be useful for virtual camera applications.
2020-11-03 17:37:41 +09:00
9c28e6e62f XR: Fix crash when reading "constraint" objects
Pointers were not being relinked from file.
2020-11-03 10:46:42 +09:00
9c288d3e20 Merge branch 'master' into xr-actions-D9124 2020-11-02 00:09:10 +09:00
86f76f46f9 XR: Remove view space limitation for transform op
Not needed now that XR supports calling operators with properties.
2020-11-02 00:04:53 +09:00
498804edc8 XR: Implement raycast select operator
Uses the same raycast method as Scene.ray_cast() and works in object
and edit mode. Although it gives users an alternative to the existing
projection-based VR selection method, it is limited to objects with
real geometry (i.e. meshes).
2020-11-01 23:50:46 +09:00
3d24ef827c Merge branch 'master' into xr-actions-D9124 2020-10-31 23:38:14 +09:00
c8be04b7f8 Cleanup: Rename controller pose properties
Makes naming consistent with controller#_object session settings.
2020-10-31 23:31:33 +09:00
58ecc0d1bf XR: Add "constraint" objects to session settings
These objects (3 in total, corresponding to headset and left/right
controllers) will have their location and rotation determined by the
associated XR pose. This provides a way for add-ons to achieve
this "VR constraint" behavior without the need to constantly query
pose information.
2020-10-31 23:00:43 +09:00
1a6d76c5c7 Remove unused parameter 2020-10-31 22:27:00 +09:00
a1333cf2c3 Merge branch 'master' into xr-actions-D9124 2020-10-29 23:51:32 +09:00
9be27de831 XR: Improve error handling / messages
Originally thought that not terminating the session for certain "non-
fatal" errors (e.g. an incorrect action path) would make sense.
However, realized that error messages can pile up this way and it
is better for user feedback and debugging to always exit the session
when encountering an OpenXR-level error.
2020-10-29 23:49:59 +09:00
a90bfa17a9 XR: Include action set name in XR event data
Needed to match keymap items with XR events.
2020-10-29 21:01:49 +09:00
d72fafd62a Merge branch 'master' into xr-actions-D9124 2020-10-28 01:05:45 +09:00
62c5f71da1 XR: Add XR identifiers to key config I/O
Allows XR action properties to be shared with others.
2020-10-28 01:04:01 +09:00
09377b4c9c Merge branch 'master' into xr-actions-D9124 2020-10-27 02:17:20 +09:00
b596d70a1f Apply formatting 2020-10-27 02:05:24 +09:00
1d86e1ff46 XR: Support operator properties for actions
Pointers to op properties are stored in the XR session state as
IDProperty* and applied upon op execution. The actual properties
themselves are stored as key map items (new "XR" and "XR Session"
key maps were added to the blender default key maps).

The "XR" key map is intended to store op properties for action sets
that are saved in add-on (e.g. the VR Scene Inspection add-on) prefs.
The "XR Session" key map is intended to store op properties for scene
action sets, with these properties used for the XR session.

In this way, scene action sets can configure properties without
worrying about overwriting properties for action sets saved in prefs.
2020-10-27 01:54:03 +09:00
3e0acdfe94 Fix build error when disabling WITH_XR_OPENXR 2020-10-27 01:30:47 +09:00
a6c5a1a2dc Merge branch 'master' into xr-actions-D9124 2020-10-21 23:59:08 +09:00
ceab20d5e5 Cleanup: Comment style 2020-10-21 23:57:09 +09:00
cb75a83df0 XR: Draw controllers via draw handler
Callbacks for controllers and other custom drawing will be registered
with the XR surface's region type (RGN_TYPE_XR_DISPLAY) and called
post-view.
2020-10-21 23:47:29 +09:00
db1cdcdafe Merge branch 'master' into xr-actions-D9124 2020-10-20 00:59:21 +09:00
297decbe1f XR: Add input threshold for float actions
Fixes button release events not being sent due to non-zero state.
2020-10-20 00:52:49 +09:00
8af91a18e0 XR: Support basic transform operators
Uses same invoke_3d / modal_3d approach as select operators.
2020-10-20 00:48:29 +09:00
9ec8ca2d55 Merge branch 'master' into xr-actions-D9124 2020-10-19 01:06:04 +09:00
5561fbf1f8 XR: Apply VR clip settings when selecting
Fixes projection matrix calculation for GPU select.
2020-10-19 01:04:04 +09:00
de026d1395 Remove unused function
Was meant to be removed in 2eb44677.
2020-10-18 15:31:15 +09:00
07e5488c61 Merge branch 'master' into xr-actions-D9124 2020-10-18 15:18:51 +09:00
2eb44677dd Fix build error when disabling WITH_XR_OPENXR 2020-10-18 15:11:12 +09:00
3e33c89828 Fix build error on Linux / gcc 2020-10-18 15:06:12 +09:00
f2385a3f05 Merge branch 'master' into xr-actions-D9124
# Conflicts:
#	source/blender/windowmanager/intern/wm_event_system.c
2020-10-17 23:42:47 +09:00
f6a7d5336b XR: Add "selection eye" session setting
The "selection eye" is the XR eye (view) used for 3D-to-2D projection.
Its parameters are used to override the window view when selecting
with VR controllers.
2020-10-17 11:59:50 +09:00
336c8a628a Merge branch 'master' into xr-actions-D9124 2020-10-15 00:43:31 +09:00
66e22a2ed7 Operators: Add modal_3d() and implement for box select
This follows the same logic as invoke_3d(). That is, we wrap an
operator's modal() with modal_3d() and project 3D controller coords to
2D mouse coords.
2020-10-15 00:41:34 +09:00
6920906f75 XR: Remove "replace existing" param from action bindings creation
Since action bindings are only created once at the beginning of an XR
session, overwriting all existing bindings will not be needed.
2020-10-15 00:23:48 +09:00
ae1d8f4c35 Fix: Use correct add-on branch for 'make update'
Credit to Julian Eisel for the fix.
2020-10-14 08:47:14 +09:00
e0eafd2757 XR: Add selection outline offscreen draw flag 2020-10-13 21:39:03 +09:00
5e8d3f6d28 Operators: Add invoke_3d() and implement for VIEW3D_OT_select 2020-10-13 21:39:03 +09:00
090c1b7dda Disable XR object saving and (for now) creation 2020-10-13 21:39:03 +09:00
f126ce2d5b Add safety checks when accessing XR window and controller objects. 2020-10-13 21:39:03 +09:00
3b3955d9e2 Update comment. 2020-10-13 21:39:03 +09:00
9c9081bf83 Fix annotations not being shown in XR view. 2020-10-13 21:39:03 +09:00
cfc5c1b46d Improve error logging and controller data management. 2020-10-13 21:39:03 +09:00
45194962c1 Add wm_xr_operators.c. 2020-10-13 21:39:03 +09:00
921510f34f Add xr overlay and controller object. 2020-10-13 21:39:02 +09:00
d7083de46d Update controller data when setting controller pose action. 2020-10-13 21:39:02 +09:00
b44173754f Fix condition for processing xr actions. 2020-10-13 21:39:02 +09:00
e0da725075 Add basic controller visualization.
Differential Revision: https://developer.blender.org/D9124
2020-10-13 21:39:02 +09:00
1724 changed files with 119280 additions and 103560 deletions

View File

@@ -263,7 +263,6 @@ ForEachMacros:
- SET_SLOT_PROBING_BEGIN
- MAP_SLOT_PROBING_BEGIN
- VECTOR_SET_SLOT_PROBING_BEGIN
- TGSET_ITER
StatementMacros:
- PyObject_HEAD

View File

@@ -403,7 +403,7 @@ option(WITH_CYCLES_CUDA_BINARIES "Build Cycles CUDA binaries" OFF)
option(WITH_CYCLES_CUBIN_COMPILER "Build cubins with nvrtc based compiler instead of nvcc" OFF)
option(WITH_CYCLES_CUDA_BUILD_SERIAL "Build cubins one after another (useful on machines with limited RAM)" OFF)
mark_as_advanced(WITH_CYCLES_CUDA_BUILD_SERIAL)
set(CYCLES_TEST_DEVICES CPU CACHE STRING "Run regression tests on the specified device types (CPU CUDA OPTIX OPENCL)" )
set(CYCLES_TEST_DEVICES CPU CACHE STRING "Run regression tests on the specified device types (CPU CUDA OPTIX)" )
set(CYCLES_CUDA_BINARIES_ARCH sm_30 sm_35 sm_37 sm_50 sm_52 sm_60 sm_61 sm_70 sm_75 sm_86 compute_75 CACHE STRING "CUDA architectures to build binaries for")
mark_as_advanced(CYCLES_CUDA_BINARIES_ARCH)
unset(PLATFORM_DEFAULT)
@@ -418,12 +418,10 @@ mark_as_advanced(WITH_CYCLES_DEBUG_NAN)
mark_as_advanced(WITH_CYCLES_NATIVE_ONLY)
option(WITH_CYCLES_DEVICE_CUDA "Enable Cycles CUDA compute support" ON)
option(WITH_CYCLES_DEVICE_OPTIX "Enable Cycles OptiX support" OFF)
option(WITH_CYCLES_DEVICE_OPENCL "Enable Cycles OpenCL compute support" ON)
option(WITH_CYCLES_NETWORK "Enable Cycles compute over network support (EXPERIMENTAL and unfinished)" OFF)
option(WITH_CYCLES_DEVICE_OPTIX "Enable Cycles OptiX support" ON)
option(WITH_CYCLES_DEVICE_HIP "Enable Cycles HIP support" OFF)
mark_as_advanced(WITH_CYCLES_DEVICE_HIP)
mark_as_advanced(WITH_CYCLES_DEVICE_CUDA)
mark_as_advanced(WITH_CYCLES_DEVICE_OPENCL)
mark_as_advanced(WITH_CYCLES_NETWORK)
option(WITH_CUDA_DYNLOAD "Dynamically load CUDA libraries at runtime" ON)
mark_as_advanced(WITH_CUDA_DYNLOAD)
@@ -578,12 +576,6 @@ if(CMAKE_COMPILER_IS_GNUCC OR CMAKE_C_COMPILER_ID MATCHES "Clang")
[HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\LLVM\\LLVM;]/lib/clang/7.0.0/lib/windows
[HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\LLVM\\LLVM;]/lib/clang/6.0.0/lib/windows
)
find_library(
COMPILER_ASAN_LIBRARY_THUNK NAMES clang_rt.asan_dll_thunk-x86_64
PATHS
[HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\LLVM\\LLVM;]/lib/clang/7.0.0/lib/windows
[HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\LLVM\\LLVM;]/lib/clang/6.0.0/lib/windows
)
elseif(APPLE)
execute_process(COMMAND ${CMAKE_CXX_COMPILER}
-print-file-name=lib
@@ -604,7 +596,6 @@ if(CMAKE_COMPILER_IS_GNUCC OR CMAKE_C_COMPILER_ID MATCHES "Clang")
)
endif()
mark_as_advanced(COMPILER_ASAN_LIBRARY_THUNK)
mark_as_advanced(COMPILER_ASAN_LIBRARY)
endif()
endif()
@@ -832,6 +823,11 @@ if(NOT WITH_CUDA_DYNLOAD)
endif()
endif()
if(WITH_CYCLES_DEVICE_HIP)
# Currently HIP must be dynamically loaded, this may change in future toolkits
set(WITH_HIP_DYNLOAD ON)
endif()
#-----------------------------------------------------------------------------
# Check check if submodules are cloned
@@ -925,9 +921,9 @@ if(NOT CMAKE_BUILD_TYPE MATCHES "Release")
unset(_list_COMPILER_ASAN_CFLAGS)
unset(_is_CONFIG_DEBUG)
elseif(COMPILER_ASAN_LIBRARY)
set(PLATFORM_LINKLIBS "${PLATFORM_LINKLIBS};\"${COMPILER_ASAN_LIBRARY}\" \"${COMPILER_ASAN_LIBRARY_THUNK}\"")
set(PLATFORM_LINKFLAGS "\"${COMPILER_ASAN_LIBRARY}\" \"${COMPILER_ASAN_LIBRARY_THUNK}\" ${COMPILER_ASAN_LINKER_FLAGS}")
set(PLATFORM_LINKFLAGS_DEBUG "\"${COMPILER_ASAN_LIBRARY}\" \"${COMPILER_ASAN_LIBRARY_THUNK}\" ${COMPILER_ASAN_LINKER_FLAGS}")
set(PLATFORM_LINKLIBS "${PLATFORM_LINKLIBS};${COMPILER_ASAN_LIBRARY}")
set(PLATFORM_LINKFLAGS "${COMPILER_ASAN_LIBRARY} ${COMPILER_ASAN_LINKER_FLAGS}")
set(PLATFORM_LINKFLAGS_DEBUG "${COMPILER_ASAN_LIBRARY} ${COMPILER_ASAN_LINKER_FLAGS}")
endif()
endif()
endif()
@@ -1861,6 +1857,9 @@ elseif(WITH_CYCLES_STANDALONE)
if(WITH_CUDA_DYNLOAD)
add_subdirectory(extern/cuew)
endif()
if(WITH_HIP_DYNLOAD)
add_subdirectory(extern/hipew)
endif()
if(NOT WITH_SYSTEM_GLEW)
add_subdirectory(extern/glew)
endif()

View File

@@ -70,16 +70,18 @@
}
--- a/libavcodec/rl.c
+++ b/libavcodec/rl.c
@@ -71,7 +71,7 @@ av_cold void ff_rl_init(RLTable *rl,
@@ -71,17 +71,19 @@
av_cold void ff_rl_init_vlc(RLTable *rl, unsigned static_size)
{
int i, q;
- VLC_TYPE table[1500][2] = {{0}};
+ VLC_TYPE (*table)[2] = av_calloc(sizeof(VLC_TYPE), 1500 * 2);
VLC vlc = { .table = table, .table_allocated = static_size };
av_assert0(static_size <= FF_ARRAY_ELEMS(table));
- av_assert0(static_size <= FF_ARRAY_ELEMS(table));
+ av_assert0(static_size < 1500);
init_vlc(&vlc, 9, rl->n + 1, &rl->table_vlc[0][1], 4, 2, &rl->table_vlc[0][0], 4, 2, INIT_VLC_USE_NEW_STATIC);
@@ -80,8 +80,10 @@ av_cold void ff_rl_init_vlc(RLTable *rl, unsigned static_size)
for (q = 0; q < 32; q++) {
int qmul = q * 2;
int qadd = (q - 1) | 1;
@@ -91,7 +93,7 @@
if (q == 0) {
qmul = 1;
@@ -113,4 +115,5 @@ av_cold void ff_rl_init_vlc(RLTable *rl, unsigned static_size)
@@ -113,4 +115,5 @@
rl->rl_vlc[q][i].run = run;
}
}

View File

@@ -33,11 +33,23 @@ FIND_PATH(OPTIX_INCLUDE_DIR
include
)
IF(EXISTS "${OPTIX_INCLUDE_DIR}/optix.h")
FILE(STRINGS "${OPTIX_INCLUDE_DIR}/optix.h" _optix_version REGEX "^#define OPTIX_VERSION[ \t].*$")
STRING(REGEX MATCHALL "[0-9]+" _optix_version ${_optix_version})
MATH(EXPR _optix_version_major "${_optix_version} / 10000")
MATH(EXPR _optix_version_minor "(${_optix_version} % 10000) / 100")
MATH(EXPR _optix_version_patch "${_optix_version} % 100")
SET(OPTIX_VERSION "${_optix_version_major}.${_optix_version_minor}.${_optix_version_patch}")
ENDIF()
# handle the QUIETLY and REQUIRED arguments and set OPTIX_FOUND to TRUE if
# all listed variables are TRUE
INCLUDE(FindPackageHandleStandardArgs)
FIND_PACKAGE_HANDLE_STANDARD_ARGS(OptiX DEFAULT_MSG
OPTIX_INCLUDE_DIR)
FIND_PACKAGE_HANDLE_STANDARD_ARGS(OptiX
REQUIRED_VARS OPTIX_INCLUDE_DIR
VERSION_VAR OPTIX_VERSION)
IF(OPTIX_FOUND)
SET(OPTIX_INCLUDE_DIRS ${OPTIX_INCLUDE_DIR})
@@ -45,6 +57,7 @@ ENDIF()
MARK_AS_ADVANCED(
OPTIX_INCLUDE_DIR
OPTIX_VERSION
)
UNSET(_optix_SEARCH_DIRS)

View File

@@ -5,7 +5,7 @@
update-code:
git:
submodules:
- branch: master
- branch: xr-controller-support
commit_id: HEAD
path: release/scripts/addons
- branch: master
@@ -55,7 +55,7 @@ buildbot:
cuda11:
version: '11.4.1'
optix:
version: '7.1.0'
version: '7.3.0'
cmake:
default:
version: any

View File

@@ -178,7 +178,7 @@ def submodules_update(args, release_version, branch):
branch = branch_fallback
submodules = [
("release/scripts/addons", branch, branch_fallback),
("release/scripts/addons", "xr-controller-support", branch_fallback),
("release/scripts/addons_contrib", branch, branch_fallback),
("release/datafiles/locale", branch, branch_fallback),
("source/tools", branch, branch_fallback),
@@ -200,15 +200,20 @@ def submodules_update(args, release_version, branch):
if msg:
skip_msg += submodule_path + " skipped: " + msg + "\n"
else:
if make_utils.git_branch(args.git_command) != submodule_branch:
call([args.git_command, "fetch", "origin"])
call([args.git_command, "checkout", submodule_branch])
call([args.git_command, "pull", "--rebase", "origin", submodule_branch])
# If we cannot find the specified branch for this submodule, fallback to default one (aka master).
if make_utils.git_branch(args.git_command) != submodule_branch:
call([args.git_command, "fetch", "origin"])
call([args.git_command, "checkout", submodule_branch_fallback])
call([args.git_command, "pull", "--rebase", "origin", submodule_branch_fallback])
# Find a matching branch that exists.
call([args.git_command, "fetch", "origin"])
if make_utils.git_branch_exists(args.git_command, submodule_branch):
pass
elif make_utils.git_branch_exists(args.git_command, submodule_branch_fallback):
submodule_branch = submodule_branch_fallback
else:
submodule_branch = None
# Switch to branch and pull.
if submodule_branch:
if make_utils.git_branch(args.git_command) != submodule_branch:
call([args.git_command, "checkout", submodule_branch])
call([args.git_command, "pull", "--rebase", "origin", submodule_branch])
finally:
os.chdir(cwd)

View File

@@ -8,14 +8,19 @@ import subprocess
import sys
def call(cmd, exit_on_error=True):
print(" ".join(cmd))
def call(cmd, exit_on_error=True, silent=False):
if not silent:
print(" ".join(cmd))
# Flush to ensure correct order output on Windows.
sys.stdout.flush()
sys.stderr.flush()
retcode = subprocess.call(cmd)
if silent:
retcode = subprocess.call(cmd, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
else:
retcode = subprocess.call(cmd)
if exit_on_error and retcode != 0:
sys.exit(retcode)
return retcode
@@ -38,6 +43,11 @@ def check_output(cmd, exit_on_error=True):
return output.strip()
def git_branch_exists(git_command, branch):
return call([git_command, "rev-parse", "--verify", branch], exit_on_error=False, silent=True) == 0 or \
call([git_command, "rev-parse", "--verify", "remotes/origin/" + branch], exit_on_error=False, silent=True) == 0
def git_branch(git_command):
# Get current branch name.
try:

View File

@@ -14,7 +14,7 @@ sound = aud.Sound('music.ogg')
# play the audio, this return a handle to control play/pause
handle = device.play(sound)
# if the audio is not too big and will be used often you can buffer it
sound_buffered = aud.Sound.buffer(sound)
sound_buffered = aud.Sound.cache(sound)
handle_buffered = device.play(sound_buffered)
# stop the sounds (otherwise they play until their ends)

View File

@@ -0,0 +1,40 @@
"""
This method enables conversions between Local and Pose space for bones in
the middle of updating the armature without having to update dependencies
after each change, by manually carrying updated matrices in a recursive walk.
"""
def set_pose_matrices(obj, matrix_map):
"Assign pose space matrices of all bones at once, ignoring constraints."
def rec(pbone, parent_matrix):
matrix = matrix_map[pbone.name]
## Instead of:
# pbone.matrix = matrix
# bpy.context.view_layer.update()
# Compute and assign local matrix, using the new parent matrix
if pbone.parent:
pbone.matrix_basis = pbone.bone.convert_local_to_pose(
matrix,
pbone.bone.matrix_local,
parent_matrix=parent_matrix,
parent_matrix_local=pbone.parent.bone.matrix_local,
invert=True
)
else:
pbone.matrix_basis = pbone.bone.convert_local_to_pose(
matrix,
pbone.bone.matrix_local,
invert=True
)
# Recursively process children, passing the new matrix through
for child in pbone.children:
rec(child, matrix)
# Scan all bone trees from their roots
for pbone in obj.pose.bones:
if not pbone.parent:
rec(pbone, None)

View File

@@ -67,9 +67,12 @@ endif()
if(WITH_CYCLES OR WITH_COMPOSITOR OR WITH_OPENSUBDIV)
add_subdirectory(clew)
if(WITH_CUDA_DYNLOAD)
if((WITH_CYCLES_DEVICE_CUDA OR WITH_CYCLES_DEVICE_OPTIX) AND WITH_CUDA_DYNLOAD)
add_subdirectory(cuew)
endif()
if(WITH_CYCLES_DEVICE_HIP AND WITH_HIP_DYNLOAD)
add_subdirectory(hipew)
endif()
endif()
if(WITH_GHOST_X11 AND WITH_GHOST_XDND)

View File

@@ -389,7 +389,7 @@
// Does the compiler support result_of?
#ifndef EIGEN_HAS_STD_RESULT_OF
#if __cplusplus < 201703L && EIGEN_MAX_CPP_VER>=11 && ((__has_feature(cxx_lambdas) || (defined(__cplusplus) && __cplusplus >= 201103L && __cplusplus)))
#if EIGEN_MAX_CPP_VER>=11 && ((__has_feature(cxx_lambdas) || (defined(__cplusplus) && __cplusplus >= 201103L)))
#define EIGEN_HAS_STD_RESULT_OF 1
#else
#define EIGEN_HAS_STD_RESULT_OF 0

View File

@@ -129,6 +129,7 @@ set(SRC
src/util/Barrier.cpp
src/util/Buffer.cpp
src/util/BufferReader.cpp
src/util/RingBuffer.cpp
src/util/StreamBuffer.cpp
src/util/ThreadPool.cpp
)
@@ -152,6 +153,7 @@ set(PUBLIC_HDR
include/devices/ThreadedDevice.h
include/Exception.h
include/file/File.h
include/file/FileInfo.h
include/file/FileManager.h
include/file/FileWriter.h
include/file/IFileInput.h
@@ -244,6 +246,7 @@ set(PUBLIC_HDR
include/util/BufferReader.h
include/util/ILockable.h
include/util/Math3D.h
include/util/RingBuffer.h
include/util/StreamBuffer.h
include/util/ThreadPool.h
)
@@ -960,7 +963,10 @@ endif()
if(BUILD_DEMOS)
include_directories(${INCLUDE})
set(DEMOS audaplay audaconvert audaremap signalgen randsounds dynamicmusic playbackmanager)
set(DEMOS audainfo audaplay audaconvert audaremap signalgen randsounds dynamicmusic playbackmanager)
add_executable(audainfo demos/audainfo.cpp)
target_link_libraries(audainfo audaspace)
add_executable(audaplay demos/audaplay.cpp)
target_link_libraries(audaplay audaspace)

View File

@@ -221,7 +221,7 @@ AUD_API void AUD_Device_setListenerVelocity(AUD_Device* device, const float valu
AUD_API double AUD_Device_getRate(AUD_Device* device)
{
auto dev = device ? *device : DeviceManager::getDevice();
return dev ? dev->getSpecs().rate : 0.0;
return dev->getSpecs().rate;
}
AUD_API float AUD_Device_getSpeedOfSound(AUD_Device* device)

View File

@@ -39,7 +39,7 @@ extern AUD_API void AUD_PlaybackManager_free(AUD_PlaybackManager* manager);
* Plays a sound through the playback manager, adding it into a category.
* \param manager The PlaybackManager object.
* \param sound The sound to be played.
* \param catKey The key of the category into which the sound will be added. If it doesn't exist a new one will be creatd.
* \param catKey The key of the category into which the sound will be added. If it doesn't exist a new one will be created.
*/
extern AUD_API void AUD_PlaybackManager_play(AUD_PlaybackManager* manager, AUD_Sound* sound, unsigned int catKey);

View File

@@ -94,6 +94,40 @@ AUD_API int AUD_Sound_getLength(AUD_Sound* sound)
return (*sound)->createReader()->getLength();
}
AUD_API int AUD_Sound_getFileStreams(AUD_Sound* sound, AUD_StreamInfo **stream_infos)
{
assert(sound);
std::shared_ptr<File> file = std::dynamic_pointer_cast<File>(*sound);
if(file)
{
try
{
auto streams = file->queryStreams();
size_t size = sizeof(AUD_StreamInfo) * streams.size();
if(!size)
{
*stream_infos = nullptr;
return 0;
}
*stream_infos = reinterpret_cast<AUD_StreamInfo*>(std::malloc(size));
std::memcpy(*stream_infos, streams.data(), size);
return streams.size();
}
catch(Exception&)
{
}
}
*stream_infos = nullptr;
return 0;
}
AUD_API sample_t* AUD_Sound_data(AUD_Sound* sound, int* length, AUD_Specs* specs)
{
assert(sound);
@@ -252,6 +286,12 @@ AUD_API AUD_Sound* AUD_Sound_bufferFile(unsigned char* buffer, int size)
return new AUD_Sound(new File(buffer, size));
}
AUD_API AUD_Sound* AUD_Sound_bufferFileStream(unsigned char* buffer, int size, int stream)
{
assert(buffer);
return new AUD_Sound(new File(buffer, size, stream));
}
AUD_API AUD_Sound* AUD_Sound_cache(AUD_Sound* sound)
{
assert(sound);
@@ -272,6 +312,12 @@ AUD_API AUD_Sound* AUD_Sound_file(const char* filename)
return new AUD_Sound(new File(filename));
}
AUD_API AUD_Sound* AUD_Sound_fileStream(const char* filename, int stream)
{
assert(filename);
return new AUD_Sound(new File(filename, stream));
}
AUD_API AUD_Sound* AUD_Sound_sawtooth(float frequency, AUD_SampleRate rate)
{
return new AUD_Sound(new Sawtooth(frequency, rate));

View File

@@ -36,7 +36,15 @@ extern AUD_API AUD_Specs AUD_Sound_getSpecs(AUD_Sound* sound);
* \return The length of the sound in samples.
* \note This function creates a reader from the sound and deletes it again.
*/
extern AUD_API int AUD_getLength(AUD_Sound* sound);
extern AUD_API int AUD_Sound_getLength(AUD_Sound* sound);
/**
* Retrieves the stream infos of a sound file.
* \param sound The sound to retrieve from which must be a file sound.
* \param infos A pointer to a AUD_StreamInfo array that will be allocated and must afterwards be freed by the caller.
* \return The number of items in the infos array.
*/
extern AUD_API int AUD_Sound_getFileStreams(AUD_Sound* sound, AUD_StreamInfo** stream_infos);
/**
* Reads a sound's samples into memory.
@@ -89,6 +97,15 @@ extern AUD_API AUD_Sound* AUD_Sound_buffer(sample_t* data, int length, AUD_Specs
*/
extern AUD_API AUD_Sound* AUD_Sound_bufferFile(unsigned char* buffer, int size);
/**
* Loads a sound file from a memory buffer.
* \param buffer The buffer which contains the sound file.
* \param size The size of the buffer.
* \param stream The index of the audio stream within the file if it contains multiple audio streams.
* \return A handle of the sound file.
*/
extern AUD_API AUD_Sound* AUD_Sound_bufferFileStream(unsigned char* buffer, int size, int stream);
/**
* Caches a sound into a memory buffer.
* \param sound The sound to cache.
@@ -103,6 +120,14 @@ extern AUD_API AUD_Sound* AUD_Sound_cache(AUD_Sound* sound);
*/
extern AUD_API AUD_Sound* AUD_Sound_file(const char* filename);
/**
* Loads a sound file.
* \param filename The filename of the sound file.
* \param stream The index of the audio stream within the file if it contains multiple audio streams.
* \return A handle of the sound file.
*/
extern AUD_API AUD_Sound* AUD_Sound_fileStream(const char* filename, int stream);
/**
* Creates a sawtooth sound.
* \param frequency The frequency of the generated sawtooth sound.

View File

@@ -86,7 +86,6 @@ AUD_API AUD_SoundInfo AUD_getInfo(AUD_Sound* sound)
info.specs.channels = AUD_CHANNELS_INVALID;
info.specs.rate = AUD_RATE_INVALID;
info.length = 0.0f;
info.start_offset = 0.0f;
try
{
@@ -96,7 +95,6 @@ AUD_API AUD_SoundInfo AUD_getInfo(AUD_Sound* sound)
{
info.specs = convSpecToC(reader->getSpecs());
info.length = reader->getLength() / (float) info.specs.rate;
info.start_offset = reader->getStartOffset();
}
}
catch(Exception&)
@@ -109,7 +107,7 @@ AUD_API AUD_SoundInfo AUD_getInfo(AUD_Sound* sound)
AUD_API float* AUD_readSoundBuffer(const char* filename, float low, float high,
float attack, float release, float threshold,
int accumulate, int additive, int square,
float sthreshold, double samplerate, int* length)
float sthreshold, double samplerate, int* length, int stream)
{
Buffer buffer;
DeviceSpecs specs;
@@ -117,7 +115,7 @@ AUD_API float* AUD_readSoundBuffer(const char* filename, float low, float high,
specs.rate = (SampleRate)samplerate;
std::shared_ptr<ISound> sound;
std::shared_ptr<ISound> file = std::shared_ptr<ISound>(new File(filename));
std::shared_ptr<ISound> file = std::shared_ptr<ISound>(new File(filename, stream));
int position = 0;
@@ -247,7 +245,7 @@ AUD_API int AUD_readSound(AUD_Sound* sound, float* buffer, int length, int sampl
buffer[i * 3] = min;
buffer[i * 3 + 1] = max;
buffer[i * 3 + 2] = sqrt(power / len); // RMS
buffer[i * 3 + 2] = std::sqrt(power / len);
if(overallmax < max)
overallmax = max;

View File

@@ -37,7 +37,7 @@ extern AUD_API float* AUD_readSoundBuffer(const char* filename, float low, float
float attack, float release, float threshold,
int accumulate, int additive, int square,
float sthreshold, double samplerate,
int* length);
int* length, int stream);
/**
* Pauses a playing sound after a specific amount of time.

View File

@@ -176,5 +176,17 @@ typedef struct
{
AUD_Specs specs;
float length;
double start_offset;
} AUD_SoundInfo;
/// Specification of a sound source.
typedef struct
{
/// Start time in seconds.
double start;
/// Duration in seconds. May be estimated or 0 if unknown.
double duration;
/// Audio data parameters.
AUD_DeviceSpecs specs;
} AUD_StreamInfo;

View File

@@ -89,10 +89,11 @@ Sound_new(PyTypeObject* type, PyObject* args, PyObject* kwds)
self = (Sound*)type->tp_alloc(type, 0);
if(self != nullptr)
{
static const char* kwlist[] = {"filename", nullptr};
static const char* kwlist[] = {"filename", "stream", nullptr};
const char* filename = nullptr;
int stream = 0;
if(!PyArg_ParseTupleAndKeywords(args, kwds, "s:Sound", const_cast<char**>(kwlist), &filename))
if(!PyArg_ParseTupleAndKeywords(args, kwds, "s|i:Sound", const_cast<char**>(kwlist), &filename, &stream))
{
Py_DECREF(self);
return nullptr;
@@ -100,7 +101,7 @@ Sound_new(PyTypeObject* type, PyObject* args, PyObject* kwds)
try
{
self->sound = new std::shared_ptr<ISound>(new File(filename));
self->sound = new std::shared_ptr<ISound>(new File(filename, stream));
}
catch(Exception& e)
{
@@ -407,8 +408,9 @@ static PyObject *
Sound_file(PyTypeObject* type, PyObject* args)
{
const char* filename = nullptr;
int stream = 0;
if(!PyArg_ParseTuple(args, "s:file", &filename))
if(!PyArg_ParseTuple(args, "s|i:file", &filename, &stream))
return nullptr;
Sound* self;
@@ -418,7 +420,7 @@ Sound_file(PyTypeObject* type, PyObject* args)
{
try
{
self->sound = new std::shared_ptr<ISound>(new File(filename));
self->sound = new std::shared_ptr<ISound>(new File(filename, stream));
}
catch(Exception& e)
{

View File

@@ -70,12 +70,6 @@ public:
*/
virtual int getPosition() const=0;
/**
* Returns the start offset the sound should have to line up with related sources.
* \return The required start offset in seconds.
*/
virtual double getStartOffset() const { return 0.0;}
/**
* Returns the specification of the reader.
* \return The Specs structure.

View File

@@ -23,9 +23,11 @@
*/
#include "ISound.h"
#include "FileInfo.h"
#include <string>
#include <memory>
#include <vector>
AUD_NAMESPACE_BEGIN
@@ -48,6 +50,14 @@ private:
*/
std::shared_ptr<Buffer> m_buffer;
/**
* The index of the stream within the file if it contains multiple.
* The first audio stream in the file has index 0 and the index increments by one
* for every other audio stream in the file. Other types of streams in the file
* do not count.
*/
int m_stream;
// delete copy constructor and operator=
File(const File&) = delete;
File& operator=(const File&) = delete;
@@ -57,16 +67,25 @@ public:
* Creates a new sound.
* The file is read from the file system using the given path.
* \param filename The sound file path.
* \param stream The index of the audio stream within the file if it contains multiple audio streams.
*/
File(std::string filename);
File(std::string filename, int stream = 0);
/**
* Creates a new sound.
* The file is read from memory using the supplied buffer.
* \param buffer The buffer to read from.
* \param size The size of the buffer.
* \param stream The index of the audio stream within the file if it contains multiple audio streams.
*/
File(const data_t* buffer, int size);
File(const data_t* buffer, int size, int stream = 0);
/**
* Queries the streams of the file.
* \return A vector with as many streams as there are in the file.
* \exception Exception Thrown if the file specified cannot be read.
*/
std::vector<StreamInfo> queryStreams();
virtual std::shared_ptr<IReader> createReader();
};

View File

@@ -0,0 +1,42 @@
/*******************************************************************************
* Copyright 2009-2016 Jörg Müller
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
#pragma once
/**
* @file FileInfo.h
* @ingroup file
* The FileInfo data structures.
*/
#include "respec/Specification.h"
AUD_NAMESPACE_BEGIN
/// Specification of a sound source.
struct StreamInfo
{
/// Start time in seconds.
double start;
/// Duration in seconds. May be estimated or 0 if unknown.
double duration;
/// Audio data parameters.
DeviceSpecs specs;
};
AUD_NAMESPACE_END

View File

@@ -22,12 +22,14 @@
* The FileManager class.
*/
#include "FileInfo.h"
#include "respec/Specification.h"
#include "IWriter.h"
#include <list>
#include <memory>
#include <string>
#include <vector>
AUD_NAMESPACE_BEGIN
@@ -66,18 +68,36 @@ public:
/**
* Creates a file reader for the given filename if a registed IFileInput is able to read it.
* @param filename The path to the file.
* @param stream The index of the audio stream within the file if it contains multiple audio streams.
* @return The reader created.
* @exception Exception If no file input can read the file an exception is thrown.
*/
static std::shared_ptr<IReader> createReader(std::string filename);
static std::shared_ptr<IReader> createReader(std::string filename, int stream = 0);
/**
* Creates a file reader for the given buffer if a registed IFileInput is able to read it.
* @param buffer The buffer to read the file from.
* @param stream The index of the audio stream within the file if it contains multiple audio streams.
* @return The reader created.
* @exception Exception If no file input can read the file an exception is thrown.
*/
static std::shared_ptr<IReader> createReader(std::shared_ptr<Buffer> buffer);
static std::shared_ptr<IReader> createReader(std::shared_ptr<Buffer> buffer, int stream = 0);
/**
* Queries the streams of a sound file.
* \param filename Path to the file to be read.
* \return A vector with as many streams as there are in the file.
* \exception Exception Thrown if the file specified cannot be read.
*/
static std::vector<StreamInfo> queryStreams(std::string filename);
/**
* Queries the streams of a sound file.
* \param buffer The in-memory file buffer.
* \return A vector with as many streams as there are in the file.
* \exception Exception Thrown if the file specified cannot be read.
*/
static std::vector<StreamInfo> queryStreams(std::shared_ptr<Buffer> buffer);
/**
* Creates a file writer that writes a sound to the given file path.

View File

@@ -23,9 +23,11 @@
*/
#include "Audaspace.h"
#include "FileInfo.h"
#include <memory>
#include <string>
#include <vector>
AUD_NAMESPACE_BEGIN
@@ -48,18 +50,36 @@ public:
/**
* Creates a reader for a file to be read.
* \param filename Path to the file to be read.
* \param stream The index of the audio stream within the file if it contains multiple audio streams.
* \return The reader that reads the file.
* \exception Exception Thrown if the file specified cannot be read.
*/
virtual std::shared_ptr<IReader> createReader(std::string filename)=0;
virtual std::shared_ptr<IReader> createReader(std::string filename, int stream = 0)=0;
/**
* Creates a reader for a file to be read from memory.
* \param buffer The in-memory file buffer.
* \param stream The index of the audio stream within the file if it contains multiple audio streams.
* \return The reader that reads the file.
* \exception Exception Thrown if the file specified cannot be read.
*/
virtual std::shared_ptr<IReader> createReader(std::shared_ptr<Buffer> buffer)=0;
virtual std::shared_ptr<IReader> createReader(std::shared_ptr<Buffer> buffer, int stream = 0)=0;
/**
* Queries the streams of a sound file.
* \param filename Path to the file to be read.
* \return A vector with as many streams as there are in the file.
* \exception Exception Thrown if the file specified cannot be read.
*/
virtual std::vector<StreamInfo> queryStreams(std::string filename)=0;
/**
* Queries the streams of a sound file.
* \param buffer The in-memory file buffer.
* \return A vector with as many streams as there are in the file.
* \exception Exception Thrown if the file specified cannot be read.
*/
virtual std::vector<StreamInfo> queryStreams(std::shared_ptr<Buffer> buffer)=0;
};
AUD_NAMESPACE_END

View File

@@ -67,4 +67,4 @@ public:
virtual void read(int& length, bool& eos, sample_t* buffer);
};
AUD_NAMESPACE_END
AUD_NAMESPACE_END

View File

@@ -0,0 +1,97 @@
/*******************************************************************************
* Copyright 2009-2021 Jörg Müller
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
#pragma once
/**
* @file RingBuffer.h
* @ingroup util
* The RingBuffer class.
*/
#include "Audaspace.h"
#include "Buffer.h"
#include <cstddef>
AUD_NAMESPACE_BEGIN
/**
* This class is a simple ring buffer in RAM which is 32 Byte aligned and provides
* functionality for concurrent reading and writting without locks.
*/
class AUD_API RingBuffer
{
private:
/// The buffer storing the actual data.
Buffer m_buffer;
/// The reading pointer.
volatile size_t m_read;
/// The writing pointer.
volatile size_t m_write;
// delete copy constructor and operator=
RingBuffer(const RingBuffer&) = delete;
RingBuffer& operator=(const RingBuffer&) = delete;
public:
/**
* Creates a new ring buffer.
* \param size The size of the buffer in bytes.
*/
RingBuffer(int size = 0);
/**
* Returns the pointer to the ring buffer in memory.
*/
sample_t* getBuffer() const;
/**
* Returns the size of the ring buffer in bytes.
*/
int getSize() const;
size_t getReadSize() const;
size_t getWriteSize() const;
size_t read(data_t* target, size_t size);
size_t write(data_t* source, size_t size);
/**
* Resets the ring buffer to a state where nothing has been written or read.
*/
void reset();
/**
* Resizes the ring buffer.
* \param size The new size of the ring buffer, measured in bytes.
*/
void resize(int size);
/**
* Makes sure the ring buffer has a minimum size.
* If size is >= current size, nothing will happen.
* Otherwise the ring buffer is resized with keep as parameter.
* \param size The new minimum size of the ring buffer, measured in bytes.
*/
void assureSize(int size);
};
AUD_NAMESPACE_END

View File

@@ -87,17 +87,11 @@ public:
* \param args The arguments of the task.
* \return A future of the same type as the return type of the task.
*/
#if __cplusplus > 201703L
template<class T, class... Args>
std::future<typename std::invoke_result<T, Args...>::type> enqueue(T&& t, Args&&... args)
{
using pkgdTask = std::packaged_task<typename std::invoke_result<T, Args...>::type()>;
#else
template<class T, class... Args>
std::future<typename std::result_of<T(Args...)>::type> enqueue(T&& t, Args&&... args)
{
using pkgdTask = std::packaged_task<typename std::result_of<T(Args...)>::type()>;
#endif
std::shared_ptr<pkgdTask> task = std::make_shared<pkgdTask>(std::bind(std::forward<T>(t), std::forward<Args>(args)...));
auto result = task->get_future();

View File

@@ -35,14 +35,24 @@ void FFMPEG::registerPlugin()
FileManager::registerOutput(plugin);
}
std::shared_ptr<IReader> FFMPEG::createReader(std::string filename)
std::shared_ptr<IReader> FFMPEG::createReader(std::string filename, int stream)
{
return std::shared_ptr<IReader>(new FFMPEGReader(filename));
return std::shared_ptr<IReader>(new FFMPEGReader(filename, stream));
}
std::shared_ptr<IReader> FFMPEG::createReader(std::shared_ptr<Buffer> buffer)
std::shared_ptr<IReader> FFMPEG::createReader(std::shared_ptr<Buffer> buffer, int stream)
{
return std::shared_ptr<IReader>(new FFMPEGReader(buffer));
return std::shared_ptr<IReader>(new FFMPEGReader(buffer, stream));
}
std::vector<StreamInfo> FFMPEG::queryStreams(std::string filename)
{
return FFMPEGReader(filename).queryStreams();
}
std::vector<StreamInfo> FFMPEG::queryStreams(std::shared_ptr<Buffer> buffer)
{
return FFMPEGReader(buffer).queryStreams();
}
std::shared_ptr<IWriter> FFMPEG::createWriter(std::string filename, DeviceSpecs specs, Container format, Codec codec, unsigned int bitrate)

View File

@@ -52,8 +52,10 @@ public:
*/
static void registerPlugin();
virtual std::shared_ptr<IReader> createReader(std::string filename);
virtual std::shared_ptr<IReader> createReader(std::shared_ptr<Buffer> buffer);
virtual std::shared_ptr<IReader> createReader(std::string filename, int stream = 0);
virtual std::shared_ptr<IReader> createReader(std::shared_ptr<Buffer> buffer, int stream = 0);
virtual std::vector<StreamInfo> queryStreams(std::string filename);
virtual std::vector<StreamInfo> queryStreams(std::shared_ptr<Buffer> buffer);
virtual std::shared_ptr<IWriter> createWriter(std::string filename, DeviceSpecs specs, Container format, Codec codec, unsigned int bitrate);
};

View File

@@ -31,6 +31,25 @@ AUD_NAMESPACE_BEGIN
#define FFMPEG_OLD_CODE
#endif
SampleFormat FFMPEGReader::convertSampleFormat(AVSampleFormat format)
{
switch(av_get_packed_sample_fmt(format))
{
case AV_SAMPLE_FMT_U8:
return FORMAT_U8;
case AV_SAMPLE_FMT_S16:
return FORMAT_S16;
case AV_SAMPLE_FMT_S32:
return FORMAT_S32;
case AV_SAMPLE_FMT_FLT:
return FORMAT_FLOAT32;
case AV_SAMPLE_FMT_DBL:
return FORMAT_FLOAT64;
default:
AUD_THROW(FileException, "FFMPEG sample format unknown.");
}
}
int FFMPEGReader::decode(AVPacket& packet, Buffer& buffer)
{
int buf_size = buffer.getSize();
@@ -68,7 +87,7 @@ int FFMPEGReader::decode(AVPacket& packet, Buffer& buffer)
for(int i = 0; i < m_frame->nb_samples; i++)
{
std::memcpy(((data_t*)buffer.getBuffer()) + buf_pos + ((m_codecCtx->channels * i) + channel) * single_size,
m_frame->data[channel] + i * single_size, single_size);
m_frame->data[channel] + i * single_size, single_size);
}
}
}
@@ -109,7 +128,7 @@ int FFMPEGReader::decode(AVPacket& packet, Buffer& buffer)
for(int i = 0; i < m_frame->nb_samples; i++)
{
std::memcpy(((data_t*)buffer.getBuffer()) + buf_pos + ((m_codecCtx->channels * i) + channel) * single_size,
m_frame->data[channel] + i * single_size, single_size);
m_frame->data[channel] + i * single_size, single_size);
}
}
}
@@ -123,13 +142,10 @@ int FFMPEGReader::decode(AVPacket& packet, Buffer& buffer)
return buf_pos;
}
void FFMPEGReader::init()
void FFMPEGReader::init(int stream)
{
m_position = 0;
m_start_offset = 0.0f;
m_pkgbuf_left = 0;
m_st_time = 0;
m_duration = 0;
if(avformat_find_stream_info(m_formatCtx, nullptr) < 0)
AUD_THROW(FileException, "File couldn't be read, ffmpeg couldn't find the stream info.");
@@ -137,43 +153,22 @@ void FFMPEGReader::init()
// find audio stream and codec
m_stream = -1;
double dur_sec = 0;
for(unsigned int i = 0; i < m_formatCtx->nb_streams; i++)
{
#ifdef FFMPEG_OLD_CODE
if(m_formatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO)
if((m_formatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO)
#else
if(m_formatCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO)
if((m_formatCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO)
#endif
&& (m_stream < 0))
{
AVStream *audio_stream = m_formatCtx->streams[i];
double audio_timebase = av_q2d(audio_stream->time_base);
if (audio_stream->start_time != AV_NOPTS_VALUE)
if(stream == 0)
{
m_st_time = audio_stream->start_time;
}
int64_t ctx_start_time = 0;
if (m_formatCtx->start_time != AV_NOPTS_VALUE) {
ctx_start_time = m_formatCtx->start_time;
}
m_start_offset = m_st_time * audio_timebase - (double)ctx_start_time / AV_TIME_BASE;
if(audio_stream->duration != AV_NOPTS_VALUE)
{
dur_sec = audio_stream->duration * audio_timebase;
m_stream=i;
break;
}
else
{
/* If the audio starts after the stream start time, subract this from the total duration. */
dur_sec = (double)m_formatCtx->duration / AV_TIME_BASE - m_start_offset;
}
m_stream=i;
break;
stream--;
}
}
@@ -242,10 +237,9 @@ void FFMPEGReader::init()
}
m_specs.rate = (SampleRate) m_codecCtx->sample_rate;
m_duration = lround(dur_sec * m_codecCtx->sample_rate);
}
FFMPEGReader::FFMPEGReader(std::string filename) :
FFMPEGReader::FFMPEGReader(std::string filename, int stream) :
m_pkgbuf(),
m_formatCtx(nullptr),
m_codecCtx(nullptr),
@@ -259,7 +253,7 @@ FFMPEGReader::FFMPEGReader(std::string filename) :
try
{
init();
init(stream);
}
catch(Exception&)
{
@@ -268,7 +262,7 @@ FFMPEGReader::FFMPEGReader(std::string filename) :
}
}
FFMPEGReader::FFMPEGReader(std::shared_ptr<Buffer> buffer) :
FFMPEGReader::FFMPEGReader(std::shared_ptr<Buffer> buffer, int stream) :
m_pkgbuf(),
m_codecCtx(nullptr),
m_frame(nullptr),
@@ -295,7 +289,7 @@ FFMPEGReader::FFMPEGReader(std::shared_ptr<Buffer> buffer) :
try
{
init();
init(stream);
}
catch(Exception&)
{
@@ -318,6 +312,51 @@ FFMPEGReader::~FFMPEGReader()
avformat_close_input(&m_formatCtx);
}
std::vector<StreamInfo> FFMPEGReader::queryStreams()
{
std::vector<StreamInfo> result;
for(unsigned int i = 0; i < m_formatCtx->nb_streams; i++)
{
#ifdef FFMPEG_OLD_CODE
if(m_formatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO)
#else
if(m_formatCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO)
#endif
{
StreamInfo info;
double time_base = av_q2d(m_formatCtx->streams[i]->time_base);
if(m_formatCtx->streams[i]->start_time != AV_NOPTS_VALUE)
info.start = m_formatCtx->streams[i]->start_time * time_base;
else
info.start = 0;
if(m_formatCtx->streams[i]->duration != AV_NOPTS_VALUE)
info.duration = m_formatCtx->streams[i]->duration * time_base;
else if(m_formatCtx->duration != AV_NOPTS_VALUE)
info.duration = double(m_formatCtx->duration) / AV_TIME_BASE - info.start;
else
info.duration = 0;
#ifdef FFMPEG_OLD_CODE
info.specs.channels = Channels(m_formatCtx->streams[i]->codec->channels);
info.specs.rate = m_formatCtx->streams[i]->codec->sample_rate;
info.specs.format = convertSampleFormat(m_formatCtx->streams[i]->codec->sample_fmt);
#else
info.specs.channels = Channels(m_formatCtx->streams[i]->codecpar->channels);
info.specs.rate = m_formatCtx->streams[i]->codecpar->sample_rate;
info.specs.format = convertSampleFormat(AVSampleFormat(m_formatCtx->streams[i]->codecpar->format));
#endif
result.emplace_back(info);
}
}
return result;
}
int FFMPEGReader::read_packet(void* opaque, uint8_t* buf, int buf_size)
{
FFMPEGReader* reader = reinterpret_cast<FFMPEGReader*>(opaque);
@@ -368,18 +407,16 @@ void FFMPEGReader::seek(int position)
{
if(position >= 0)
{
double pts_time_base =
av_q2d(m_formatCtx->streams[m_stream]->time_base);
double pts_time_base = av_q2d(m_formatCtx->streams[m_stream]->time_base);
uint64_t seek_pts = (((uint64_t)position) / ((uint64_t)m_specs.rate)) / pts_time_base;
uint64_t st_time = m_formatCtx->streams[m_stream]->start_time;
uint64_t seek_pos = (uint64_t)(position / (pts_time_base * m_specs.rate));
if(m_st_time != AV_NOPTS_VALUE) {
seek_pts += m_st_time;
}
if(st_time != AV_NOPTS_VALUE)
seek_pos += st_time;
// a value < 0 tells us that seeking failed
if(av_seek_frame(m_formatCtx, m_stream, seek_pts,
AVSEEK_FLAG_BACKWARD | AVSEEK_FLAG_ANY) >= 0)
if(av_seek_frame(m_formatCtx, m_stream, seek_pos, AVSEEK_FLAG_BACKWARD | AVSEEK_FLAG_ANY) >= 0)
{
avcodec_flush_buffers(m_codecCtx);
m_position = position;
@@ -400,7 +437,7 @@ void FFMPEGReader::seek(int position)
if(packet.pts != AV_NOPTS_VALUE)
{
// calculate real position, and read to frame!
m_position = (packet.pts - m_st_time) * pts_time_base * m_specs.rate;
m_position = (packet.pts - (st_time != AV_NOPTS_VALUE ? st_time : 0)) * pts_time_base * m_specs.rate;
if(m_position < position)
{
@@ -430,8 +467,25 @@ void FFMPEGReader::seek(int position)
int FFMPEGReader::getLength() const
{
auto stream = m_formatCtx->streams[m_stream];
double time_base = av_q2d(stream->time_base);
double duration;
if(stream->duration != AV_NOPTS_VALUE)
duration = stream->duration * time_base;
else if(m_formatCtx->duration != AV_NOPTS_VALUE)
{
duration = float(m_formatCtx->duration) / AV_TIME_BASE;
if(stream->start_time != AV_NOPTS_VALUE)
duration -= stream->start_time * time_base;
}
else
duration = -1;
// return approximated remaning size
return m_duration - m_position;
return (int)(duration * m_codecCtx->sample_rate) - m_position;
}
int FFMPEGReader::getPosition() const
@@ -439,11 +493,6 @@ int FFMPEGReader::getPosition() const
return m_position;
}
double FFMPEGReader::getStartOffset() const
{
return m_start_offset;
}
Specs FFMPEGReader::getSpecs() const
{
return m_specs.specs;
@@ -480,13 +529,11 @@ void FFMPEGReader::read(int& length, bool& eos, sample_t* buffer)
// decode the package
pkgbuf_pos = decode(packet, m_pkgbuf);
if (packet.pts >= m_st_time) {
// copy to output buffer
data_size = std::min(pkgbuf_pos, left * sample_size);
m_convert((data_t*) buf, (data_t*) m_pkgbuf.getBuffer(), data_size / AUD_FORMAT_SIZE(m_specs.format));
buf += data_size / AUD_FORMAT_SIZE(m_specs.format);
left -= data_size / sample_size;
}
// copy to output buffer
data_size = std::min(pkgbuf_pos, left * sample_size);
m_convert((data_t*) buf, (data_t*) m_pkgbuf.getBuffer(), data_size / AUD_FORMAT_SIZE(m_specs.format));
buf += data_size / AUD_FORMAT_SIZE(m_specs.format);
left -= data_size / sample_size;
}
av_packet_unref(&packet);
}

View File

@@ -29,9 +29,11 @@
#include "respec/ConverterFunctions.h"
#include "IReader.h"
#include "util/Buffer.h"
#include "file/FileInfo.h"
#include <string>
#include <memory>
#include <vector>
struct AVCodecContext;
extern "C" {
@@ -54,22 +56,6 @@ private:
*/
int m_position;
/**
* The start offset in seconds relative to the media container start time.
* IE how much the sound should be delayed to be kept in sync with the rest of the containter streams.
*/
double m_start_offset;
/**
* The start time pts of the stream. All packets before this timestamp shouldn't be played back (only decoded).
*/
int64_t m_st_time;
/**
* The duration of the audio stream in samples.
*/
int64_t m_duration;
/**
* The specification of the audio data.
*/
@@ -135,6 +121,13 @@ private:
*/
bool m_tointerleave;
/**
* Converts an ffmpeg sample format to an audaspace one.
* \param format The AVSampleFormat sample format.
* \return The sample format as SampleFormat.
*/
AUD_LOCAL static SampleFormat convertSampleFormat(AVSampleFormat format);
/**
* Decodes a packet into the given buffer.
* \param packet The AVPacket to decode.
@@ -145,8 +138,9 @@ private:
/**
* Initializes the object.
* \param stream The index of the audio stream within the file if it contains multiple audio streams.
*/
AUD_LOCAL void init();
AUD_LOCAL void init(int stream);
// delete copy constructor and operator=
FFMPEGReader(const FFMPEGReader&) = delete;
@@ -156,24 +150,33 @@ public:
/**
* Creates a new reader.
* \param filename The path to the file to be read.
* \param stream The index of the audio stream within the file if it contains multiple audio streams.
* \exception Exception Thrown if the file specified does not exist or
* cannot be read with ffmpeg.
*/
FFMPEGReader(std::string filename);
FFMPEGReader(std::string filename, int stream = 0);
/**
* Creates a new reader.
* \param buffer The buffer to read from.
* \param stream The index of the audio stream within the file if it contains multiple audio streams.
* \exception Exception Thrown if the buffer specified cannot be read
* with ffmpeg.
*/
FFMPEGReader(std::shared_ptr<Buffer> buffer);
FFMPEGReader(std::shared_ptr<Buffer> buffer, int stream = 0);
/**
* Destroys the reader and closes the file.
*/
virtual ~FFMPEGReader();
/**
* Queries the streams of a sound file.
* \return A vector with as many streams as there are in the file.
* \exception Exception Thrown if the file specified cannot be read.
*/
virtual std::vector<StreamInfo> queryStreams();
/**
* Reads data to a memory buffer.
* This function is used for avio only.
@@ -198,7 +201,6 @@ public:
virtual void seek(int position);
virtual int getLength() const;
virtual int getPosition() const;
virtual double getStartOffset() const;
virtual Specs getSpecs() const;
virtual void read(int& length, bool& eos, sample_t* buffer);
};

View File

@@ -32,16 +32,26 @@ void SndFile::registerPlugin()
FileManager::registerOutput(plugin);
}
std::shared_ptr<IReader> SndFile::createReader(std::string filename)
std::shared_ptr<IReader> SndFile::createReader(std::string filename, int stream)
{
return std::shared_ptr<IReader>(new SndFileReader(filename));
}
std::shared_ptr<IReader> SndFile::createReader(std::shared_ptr<Buffer> buffer)
std::shared_ptr<IReader> SndFile::createReader(std::shared_ptr<Buffer> buffer, int stream)
{
return std::shared_ptr<IReader>(new SndFileReader(buffer));
}
std::vector<StreamInfo> SndFile::queryStreams(std::string filename)
{
return SndFileReader(filename).queryStreams();
}
std::vector<StreamInfo> SndFile::queryStreams(std::shared_ptr<Buffer> buffer)
{
return SndFileReader(buffer).queryStreams();
}
std::shared_ptr<IWriter> SndFile::createWriter(std::string filename, DeviceSpecs specs, Container format, Codec codec, unsigned int bitrate)
{
return std::shared_ptr<IWriter>(new SndFileWriter(filename, specs, format, codec, bitrate));

View File

@@ -52,8 +52,10 @@ public:
*/
static void registerPlugin();
virtual std::shared_ptr<IReader> createReader(std::string filename);
virtual std::shared_ptr<IReader> createReader(std::shared_ptr<Buffer> buffer);
virtual std::shared_ptr<IReader> createReader(std::string filename, int stream = 0);
virtual std::shared_ptr<IReader> createReader(std::shared_ptr<Buffer> buffer, int stream = 0);
virtual std::vector<StreamInfo> queryStreams(std::string filename);
virtual std::vector<StreamInfo> queryStreams(std::shared_ptr<Buffer> buffer);
virtual std::shared_ptr<IWriter> createWriter(std::string filename, DeviceSpecs specs, Container format, Codec codec, unsigned int bitrate);
};

View File

@@ -118,6 +118,21 @@ SndFileReader::~SndFileReader()
sf_close(m_sndfile);
}
std::vector<StreamInfo> SndFileReader::queryStreams()
{
std::vector<StreamInfo> result;
StreamInfo info;
info.start = 0;
info.duration = double(getLength()) / m_specs.rate;
info.specs.specs = m_specs;
info.specs.format = FORMAT_FLOAT32;
result.emplace_back(info);
return result;
}
bool SndFileReader::isSeekable() const
{
return m_seekable;

View File

@@ -28,9 +28,12 @@
* The SndFileReader class.
*/
#include "file/FileInfo.h"
#include <string>
#include <sndfile.h>
#include <memory>
#include <vector>
AUD_NAMESPACE_BEGIN
@@ -96,6 +99,7 @@ public:
/**
* Creates a new reader.
* \param filename The path to the file to be read.
* \param stream The index of the audio stream within the file if it contains multiple audio streams.
* \exception Exception Thrown if the file specified does not exist or
* cannot be read with libsndfile.
*/
@@ -104,6 +108,7 @@ public:
/**
* Creates a new reader.
* \param buffer The buffer to read from.
* \param stream The index of the audio stream within the file if it contains multiple audio streams.
* \exception Exception Thrown if the buffer specified cannot be read
* with libsndfile.
*/
@@ -114,6 +119,13 @@ public:
*/
virtual ~SndFileReader();
/**
* Queries the streams of a sound file.
* \return A vector with as many streams as there are in the file.
* \exception Exception Thrown if the file specified cannot be read.
*/
virtual std::vector<StreamInfo> queryStreams();
virtual bool isSeekable() const;
virtual void seek(int position);
virtual int getLength() const;

View File

@@ -23,95 +23,121 @@
AUD_NAMESPACE_BEGIN
PulseAudioDevice::PulseAudioSynchronizer::PulseAudioSynchronizer(PulseAudioDevice *device) :
m_device(device)
{
}
double PulseAudioDevice::PulseAudioSynchronizer::getPosition(std::shared_ptr<IHandle> handle)
{
pa_usec_t latency;
int negative;
AUD_pa_stream_get_latency(m_device->m_stream, &latency, &negative);
double delay = m_device->m_ring_buffer.getReadSize() / (AUD_SAMPLE_SIZE(m_device->m_specs) * m_device->m_specs.rate) + latency * 1.0e-6;
return handle->getPosition() - delay;
}
void PulseAudioDevice::updateRingBuffer()
{
unsigned int samplesize = AUD_SAMPLE_SIZE(m_specs);
std::unique_lock<std::mutex> lock(m_mixingLock);
Buffer buffer;
while(m_valid)
{
size_t size = m_ring_buffer.getWriteSize();
size_t sample_count = size / samplesize;
if(sample_count > 0)
{
size = sample_count * samplesize;
buffer.assureSize(size);
mix(reinterpret_cast<data_t*>(buffer.getBuffer()), sample_count);
m_ring_buffer.write(reinterpret_cast<data_t*>(buffer.getBuffer()), size);
}
m_mixingCondition.wait(lock);
}
}
void PulseAudioDevice::PulseAudio_state_callback(pa_context *context, void *data)
{
PulseAudioDevice* device = (PulseAudioDevice*)data;
std::lock_guard<ILockable> lock(*device);
device->m_state = AUD_pa_context_get_state(context);
AUD_pa_threaded_mainloop_signal(device->m_mainloop, 0);
}
void PulseAudioDevice::PulseAudio_request(pa_stream *stream, size_t total_bytes, void *data)
{
PulseAudioDevice* device = (PulseAudioDevice*)data;
void* buffer;
data_t* buffer;
size_t sample_size = AUD_DEVICE_SAMPLE_SIZE(device->m_specs);
while(total_bytes > 0)
{
size_t num_bytes = total_bytes;
AUD_pa_stream_begin_write(stream, &buffer, &num_bytes);
AUD_pa_stream_begin_write(stream, reinterpret_cast<void**>(&buffer), &num_bytes);
device->mix((data_t*)buffer, num_bytes / AUD_DEVICE_SAMPLE_SIZE(device->m_specs));
size_t readsamples = device->m_ring_buffer.getReadSize();
AUD_pa_stream_write(stream, buffer, num_bytes, nullptr, 0, PA_SEEK_RELATIVE);
readsamples = std::min(readsamples, size_t(num_bytes)) / sample_size;
device->m_ring_buffer.read(buffer, readsamples * sample_size);
if(readsamples * sample_size < num_bytes)
std::memset(buffer + readsamples * sample_size, 0, num_bytes - readsamples * sample_size);
if(device->m_mixingLock.try_lock())
{
device->m_mixingCondition.notify_all();
device->m_mixingLock.unlock();
}
AUD_pa_stream_write(stream, reinterpret_cast<void*>(buffer), num_bytes, nullptr, 0, PA_SEEK_RELATIVE);
total_bytes -= num_bytes;
}
}
void PulseAudioDevice::PulseAudio_underflow(pa_stream *stream, void *data)
void PulseAudioDevice::playing(bool playing)
{
PulseAudioDevice* device = (PulseAudioDevice*)data;
m_playback = playing;
DeviceSpecs specs = device->getSpecs();
if(++device->m_underflows > 4 && device->m_buffersize < AUD_DEVICE_SAMPLE_SIZE(specs) * specs.rate * 2)
{
device->m_buffersize <<= 1;
device->m_underflows = 0;
pa_buffer_attr buffer_attr;
buffer_attr.fragsize = -1U;
buffer_attr.maxlength = -1U;
buffer_attr.minreq = -1U;
buffer_attr.prebuf = -1U;
buffer_attr.tlength = device->m_buffersize;
AUD_pa_stream_set_buffer_attr(stream, &buffer_attr, nullptr, nullptr);
}
}
void PulseAudioDevice::runMixingThread()
{
for(;;)
{
{
std::lock_guard<ILockable> lock(*this);
if(shouldStop())
{
AUD_pa_stream_cork(m_stream, 1, nullptr, nullptr);
AUD_pa_stream_flush(m_stream, nullptr, nullptr);
doStop();
return;
}
}
if(AUD_pa_stream_is_corked(m_stream))
AUD_pa_stream_cork(m_stream, 0, nullptr, nullptr);
// similar to AUD_pa_mainloop_iterate(m_mainloop, false, nullptr); except with a longer timeout
AUD_pa_mainloop_prepare(m_mainloop, 1 << 14);
AUD_pa_mainloop_poll(m_mainloop);
AUD_pa_mainloop_dispatch(m_mainloop);
}
AUD_pa_threaded_mainloop_lock(m_mainloop);
AUD_pa_stream_cork(m_stream, playing ? 0 : 1, nullptr, nullptr);
AUD_pa_threaded_mainloop_unlock(m_mainloop);
}
PulseAudioDevice::PulseAudioDevice(std::string name, DeviceSpecs specs, int buffersize) :
m_synchronizer(this),
m_playback(false),
m_state(PA_CONTEXT_UNCONNECTED),
m_valid(true),
m_underflows(0)
{
m_mainloop = AUD_pa_mainloop_new();
m_mainloop = AUD_pa_threaded_mainloop_new();
m_context = AUD_pa_context_new(AUD_pa_mainloop_get_api(m_mainloop), name.c_str());
AUD_pa_threaded_mainloop_lock(m_mainloop);
m_context = AUD_pa_context_new(AUD_pa_threaded_mainloop_get_api(m_mainloop), name.c_str());
if(!m_context)
{
AUD_pa_mainloop_free(m_mainloop);
AUD_pa_threaded_mainloop_unlock(m_mainloop);
AUD_pa_threaded_mainloop_free(m_mainloop);
AUD_THROW(DeviceException, "Could not connect to PulseAudio.");
}
@@ -120,21 +146,26 @@ PulseAudioDevice::PulseAudioDevice(std::string name, DeviceSpecs specs, int buff
AUD_pa_context_connect(m_context, nullptr, PA_CONTEXT_NOFLAGS, nullptr);
AUD_pa_threaded_mainloop_start(m_mainloop);
while(m_state != PA_CONTEXT_READY)
{
switch(m_state)
{
case PA_CONTEXT_FAILED:
case PA_CONTEXT_TERMINATED:
AUD_pa_threaded_mainloop_unlock(m_mainloop);
AUD_pa_threaded_mainloop_stop(m_mainloop);
AUD_pa_context_disconnect(m_context);
AUD_pa_context_unref(m_context);
AUD_pa_mainloop_free(m_mainloop);
AUD_pa_threaded_mainloop_free(m_mainloop);
AUD_THROW(DeviceException, "Could not connect to PulseAudio.");
break;
default:
AUD_pa_mainloop_iterate(m_mainloop, true, nullptr);
AUD_pa_threaded_mainloop_wait(m_mainloop);
break;
}
}
@@ -182,16 +213,18 @@ PulseAudioDevice::PulseAudioDevice(std::string name, DeviceSpecs specs, int buff
if(!m_stream)
{
AUD_pa_threaded_mainloop_unlock(m_mainloop);
AUD_pa_threaded_mainloop_stop(m_mainloop);
AUD_pa_context_disconnect(m_context);
AUD_pa_context_unref(m_context);
AUD_pa_mainloop_free(m_mainloop);
AUD_pa_threaded_mainloop_free(m_mainloop);
AUD_THROW(DeviceException, "Could not create PulseAudio stream.");
}
AUD_pa_stream_set_write_callback(m_stream, PulseAudio_request, this);
AUD_pa_stream_set_underflow_callback(m_stream, PulseAudio_underflow, this);
buffersize *= AUD_DEVICE_SAMPLE_SIZE(m_specs);
m_buffersize = buffersize;
@@ -204,31 +237,53 @@ PulseAudioDevice::PulseAudioDevice(std::string name, DeviceSpecs specs, int buff
buffer_attr.prebuf = -1U;
buffer_attr.tlength = buffersize;
if(AUD_pa_stream_connect_playback(m_stream, nullptr, &buffer_attr, static_cast<pa_stream_flags_t>(PA_STREAM_START_CORKED | PA_STREAM_INTERPOLATE_TIMING | PA_STREAM_ADJUST_LATENCY | PA_STREAM_AUTO_TIMING_UPDATE), nullptr, nullptr) < 0)
m_ring_buffer.resize(buffersize);
if(AUD_pa_stream_connect_playback(m_stream, nullptr, &buffer_attr, static_cast<pa_stream_flags_t>(PA_STREAM_INTERPOLATE_TIMING | PA_STREAM_ADJUST_LATENCY | PA_STREAM_AUTO_TIMING_UPDATE), nullptr, nullptr) < 0)
{
AUD_pa_threaded_mainloop_unlock(m_mainloop);
AUD_pa_threaded_mainloop_stop(m_mainloop);
AUD_pa_context_disconnect(m_context);
AUD_pa_context_unref(m_context);
AUD_pa_mainloop_free(m_mainloop);
AUD_pa_threaded_mainloop_free(m_mainloop);
AUD_THROW(DeviceException, "Could not connect PulseAudio stream.");
}
AUD_pa_threaded_mainloop_unlock(m_mainloop);
create();
m_mixingThread = std::thread(&PulseAudioDevice::updateRingBuffer, this);
}
PulseAudioDevice::~PulseAudioDevice()
{
stopMixingThread();
m_valid = false;
m_mixingLock.lock();
m_mixingCondition.notify_all();
m_mixingLock.unlock();
m_mixingThread.join();
AUD_pa_threaded_mainloop_stop(m_mainloop);
AUD_pa_context_disconnect(m_context);
AUD_pa_context_unref(m_context);
AUD_pa_mainloop_free(m_mainloop);
AUD_pa_threaded_mainloop_free(m_mainloop);
destroy();
}
ISynchronizer *PulseAudioDevice::getSynchronizer()
{
return &m_synchronizer;
}
class PulseAudioDeviceFactory : public IDeviceFactory
{
private:

View File

@@ -26,7 +26,11 @@
* The PulseAudioDevice class.
*/
#include "devices/ThreadedDevice.h"
#include "devices/SoftwareDevice.h"
#include "util/RingBuffer.h"
#include <condition_variable>
#include <thread>
#include <pulse/pulseaudio.h>
@@ -35,17 +39,65 @@ AUD_NAMESPACE_BEGIN
/**
* This device plays back through PulseAudio, the simple direct media layer.
*/
class AUD_PLUGIN_API PulseAudioDevice : public ThreadedDevice
class AUD_PLUGIN_API PulseAudioDevice : public SoftwareDevice
{
private:
pa_mainloop* m_mainloop;
class PulseAudioSynchronizer : public DefaultSynchronizer
{
PulseAudioDevice* m_device;
public:
PulseAudioSynchronizer(PulseAudioDevice* device);
virtual double getPosition(std::shared_ptr<IHandle> handle);
};
/// Synchronizer.
PulseAudioSynchronizer m_synchronizer;
/**
* Whether there is currently playback.
*/
volatile bool m_playback;
pa_threaded_mainloop* m_mainloop;
pa_context* m_context;
pa_stream* m_stream;
pa_context_state_t m_state;
/**
* The mixing ring buffer.
*/
RingBuffer m_ring_buffer;
/**
* Whether the device is valid.
*/
bool m_valid;
int m_buffersize;
uint32_t m_underflows;
/**
* The mixing thread.
*/
std::thread m_mixingThread;
/**
* Mutex for mixing.
*/
std::mutex m_mixingLock;
/**
* Condition for mixing.
*/
std::condition_variable m_mixingCondition;
/**
* Updates the ring buffer.
*/
AUD_LOCAL void updateRingBuffer();
/**
* Reports the state of the PulseAudio server connection.
* \param context The PulseAudio context.
@@ -61,23 +113,13 @@ private:
*/
AUD_LOCAL static void PulseAudio_request(pa_stream* stream, size_t total_bytes, void* data);
/**
* Reports an underflow from the PulseAudio server.
* Automatically adjusts the latency if this happens too often.
* @param stream The PulseAudio stream.
* \param data The PulseAudio device.
*/
AUD_LOCAL static void PulseAudio_underflow(pa_stream* stream, void* data);
/**
* Streaming thread main function.
*/
AUD_LOCAL void runMixingThread();
// delete copy constructor and operator=
PulseAudioDevice(const PulseAudioDevice&) = delete;
PulseAudioDevice& operator=(const PulseAudioDevice&) = delete;
protected:
virtual void playing(bool playing);
public:
/**
* Opens the PulseAudio audio device for playback.
@@ -93,6 +135,8 @@ public:
*/
virtual ~PulseAudioDevice();
virtual ISynchronizer* getSynchronizer();
/**
* Registers this plugin.
*/

View File

@@ -25,6 +25,7 @@ PULSEAUDIO_SYMBOL(pa_stream_begin_write);
PULSEAUDIO_SYMBOL(pa_stream_connect_playback);
PULSEAUDIO_SYMBOL(pa_stream_cork);
PULSEAUDIO_SYMBOL(pa_stream_flush);
PULSEAUDIO_SYMBOL(pa_stream_get_latency);
PULSEAUDIO_SYMBOL(pa_stream_is_corked);
PULSEAUDIO_SYMBOL(pa_stream_new);
PULSEAUDIO_SYMBOL(pa_stream_set_buffer_attr);
@@ -39,3 +40,13 @@ PULSEAUDIO_SYMBOL(pa_mainloop_iterate);
PULSEAUDIO_SYMBOL(pa_mainloop_prepare);
PULSEAUDIO_SYMBOL(pa_mainloop_poll);
PULSEAUDIO_SYMBOL(pa_mainloop_dispatch);
PULSEAUDIO_SYMBOL(pa_threaded_mainloop_free);
PULSEAUDIO_SYMBOL(pa_threaded_mainloop_get_api);
PULSEAUDIO_SYMBOL(pa_threaded_mainloop_lock);
PULSEAUDIO_SYMBOL(pa_threaded_mainloop_new);
PULSEAUDIO_SYMBOL(pa_threaded_mainloop_signal);
PULSEAUDIO_SYMBOL(pa_threaded_mainloop_start);
PULSEAUDIO_SYMBOL(pa_threaded_mainloop_stop);
PULSEAUDIO_SYMBOL(pa_threaded_mainloop_unlock);
PULSEAUDIO_SYMBOL(pa_threaded_mainloop_wait);

View File

@@ -23,23 +23,31 @@
AUD_NAMESPACE_BEGIN
File::File(std::string filename) :
m_filename(filename)
File::File(std::string filename, int stream) :
m_filename(filename), m_stream(stream)
{
}
File::File(const data_t* buffer, int size) :
m_buffer(new Buffer(size))
File::File(const data_t* buffer, int size, int stream) :
m_buffer(new Buffer(size)), m_stream(stream)
{
std::memcpy(m_buffer->getBuffer(), buffer, size);
}
std::vector<StreamInfo> File::queryStreams()
{
if(m_buffer.get())
return FileManager::queryStreams(m_buffer);
else
return FileManager::queryStreams(m_filename);
}
std::shared_ptr<IReader> File::createReader()
{
if(m_buffer.get())
return FileManager::createReader(m_buffer);
return FileManager::createReader(m_buffer, m_stream);
else
return FileManager::createReader(m_filename);
return FileManager::createReader(m_filename, m_stream);
}
AUD_NAMESPACE_END

View File

@@ -43,13 +43,13 @@ void FileManager::registerOutput(std::shared_ptr<aud::IFileOutput> output)
outputs().push_back(output);
}
std::shared_ptr<IReader> FileManager::createReader(std::string filename)
std::shared_ptr<IReader> FileManager::createReader(std::string filename, int stream)
{
for(std::shared_ptr<IFileInput> input : inputs())
{
try
{
return input->createReader(filename);
return input->createReader(filename, stream);
}
catch(Exception&) {}
}
@@ -57,13 +57,41 @@ std::shared_ptr<IReader> FileManager::createReader(std::string filename)
AUD_THROW(FileException, "The file couldn't be read with any installed file reader.");
}
std::shared_ptr<IReader> FileManager::createReader(std::shared_ptr<Buffer> buffer)
std::shared_ptr<IReader> FileManager::createReader(std::shared_ptr<Buffer> buffer, int stream)
{
for(std::shared_ptr<IFileInput> input : inputs())
{
try
{
return input->createReader(buffer);
return input->createReader(buffer, stream);
}
catch(Exception&) {}
}
AUD_THROW(FileException, "The file couldn't be read with any installed file reader.");
}
std::vector<StreamInfo> FileManager::queryStreams(std::string filename)
{
for(std::shared_ptr<IFileInput> input : inputs())
{
try
{
return input->queryStreams(filename);
}
catch(Exception&) {}
}
AUD_THROW(FileException, "The file couldn't be read with any installed file reader.");
}
std::vector<StreamInfo> FileManager::queryStreams(std::shared_ptr<Buffer> buffer)
{
for(std::shared_ptr<IFileInput> input : inputs())
{
try
{
return input->queryStreams(buffer);
}
catch(Exception&) {}
}

View File

@@ -57,4 +57,4 @@ void VolumeReader::read(int& length, bool& eos, sample_t* buffer)
buffer[i] = buffer[i] * m_volumeStorage->getVolume();
}
AUD_NAMESPACE_END
AUD_NAMESPACE_END

137
extern/audaspace/src/util/RingBuffer.cpp vendored Normal file
View File

@@ -0,0 +1,137 @@
/*******************************************************************************
* Copyright 2009-2021 Jörg Müller
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
#include "util/RingBuffer.h"
#include <algorithm>
#include <cstring>
#include <cstdlib>
#define ALIGNMENT 32
#define ALIGN(a) (a + ALIGNMENT - ((long long)a & (ALIGNMENT-1)))
AUD_NAMESPACE_BEGIN
RingBuffer::RingBuffer(int size) :
m_buffer(size),
m_read(0),
m_write(0)
{
}
sample_t* RingBuffer::getBuffer() const
{
return m_buffer.getBuffer();
}
int RingBuffer::getSize() const
{
return m_buffer.getSize();
}
size_t RingBuffer::getReadSize() const
{
size_t read = m_read;
size_t write = m_write;
if(read > write)
return write + getSize() - read;
else
return write - read;
}
size_t RingBuffer::getWriteSize() const
{
size_t read = m_read;
size_t write = m_write;
if(read > write)
return read - write - 1;
else
return read + getSize() - write - 1;
}
size_t RingBuffer::read(data_t* target, size_t size)
{
size = std::min(size, getReadSize());
data_t* buffer = reinterpret_cast<data_t*>(m_buffer.getBuffer());
if(m_read + size > m_buffer.getSize())
{
size_t read_first = m_buffer.getSize() - m_read;
size_t read_second = size - read_first;
std::memcpy(target, buffer + m_read, read_first);
std::memcpy(target + read_first, buffer, read_second);
m_read = read_second;
}
else
{
std::memcpy(target, buffer + m_read, size);
m_read += size;
}
return size;
}
size_t RingBuffer::write(data_t* source, size_t size)
{
size = std::min(size, getWriteSize());
data_t* buffer = reinterpret_cast<data_t*>(m_buffer.getBuffer());
if(m_write + size > m_buffer.getSize())
{
size_t write_first = m_buffer.getSize() - m_write;
size_t write_second = size - write_first;
std::memcpy(buffer + m_write, source, write_first);
std::memcpy(buffer, source + write_first, write_second);
m_write = write_second;
}
else
{
std::memcpy(buffer + m_write, source, size);
m_write += size;
}
return size;
}
void RingBuffer::reset()
{
m_read = 0;
m_write = 0;
}
void RingBuffer::resize(int size)
{
m_buffer.resize(size);
reset();
}
void RingBuffer::assureSize(int size)
{
m_buffer.assureSize(size);
reset();
}
AUD_NAMESPACE_END

View File

@@ -645,7 +645,8 @@ typedef enum CUdevice_P2PAttribute_enum {
CU_DEVICE_P2P_ATTRIBUTE_PERFORMANCE_RANK = 0x01,
CU_DEVICE_P2P_ATTRIBUTE_ACCESS_SUPPORTED = 0x02,
CU_DEVICE_P2P_ATTRIBUTE_NATIVE_ATOMIC_SUPPORTED = 0x03,
CU_DEVICE_P2P_ATTRIBUTE_ARRAY_ACCESS_ACCESS_SUPPORTED = 0x04,
CU_DEVICE_P2P_ATTRIBUTE_ACCESS_ACCESS_SUPPORTED = 0x04,
CU_DEVICE_P2P_ATTRIBUTE_CUDA_ARRAY_ACCESS_SUPPORTED = 0x04,
} CUdevice_P2PAttribute;
typedef void (CUDA_CB *CUstreamCallback)(CUstream hStream, CUresult status, void* userData);

39
extern/hipew/CMakeLists.txt vendored Normal file
View File

@@ -0,0 +1,39 @@
# ***** BEGIN GPL LICENSE BLOCK *****
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# The Original Code is Copyright (C) 2021, Blender Foundation
# All rights reserved.
# ***** END GPL LICENSE BLOCK *****
set(INC
.
include
)
set(INC_SYS
)
set(SRC
src/hipew.c
include/hipew.h
)
set(LIB
)
blender_add_lib(extern_hipew "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")

1207
extern/hipew/include/hipew.h vendored Normal file

File diff suppressed because it is too large Load Diff

533
extern/hipew/src/hipew.c vendored Normal file
View File

@@ -0,0 +1,533 @@
/*
* Copyright 2011-2021 Blender Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License
*/
#ifdef _MSC_VER
# if _MSC_VER < 1900
# define snprintf _snprintf
# endif
# define popen _popen
# define pclose _pclose
# define _CRT_SECURE_NO_WARNINGS
#endif
#include <hipew.h>
#include <assert.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#ifdef _WIN32
# define WIN32_LEAN_AND_MEAN
# define VC_EXTRALEAN
# include <windows.h>
/* Utility macros. */
typedef HMODULE DynamicLibrary;
# define dynamic_library_open(path) LoadLibraryA(path)
# define dynamic_library_close(lib) FreeLibrary(lib)
# define dynamic_library_find(lib, symbol) GetProcAddress(lib, symbol)
#else
# include <dlfcn.h>
typedef void* DynamicLibrary;
# define dynamic_library_open(path) dlopen(path, RTLD_NOW)
# define dynamic_library_close(lib) dlclose(lib)
# define dynamic_library_find(lib, symbol) dlsym(lib, symbol)
#endif
#define _LIBRARY_FIND_CHECKED(lib, name) \
name = (t##name *)dynamic_library_find(lib, #name); \
assert(name);
#define _LIBRARY_FIND(lib, name) \
name = (t##name *)dynamic_library_find(lib, #name);
#define HIP_LIBRARY_FIND_CHECKED(name) \
_LIBRARY_FIND_CHECKED(hip_lib, name)
#define HIP_LIBRARY_FIND(name) _LIBRARY_FIND(hip_lib, name)
static DynamicLibrary hip_lib;
/* Function definitions. */
thipGetErrorName *hipGetErrorName;
thipInit *hipInit;
thipDriverGetVersion *hipDriverGetVersion;
thipGetDevice *hipGetDevice;
thipGetDeviceCount *hipGetDeviceCount;
thipDeviceGetName *hipDeviceGetName;
thipDeviceGetAttribute *hipDeviceGetAttribute;
thipDeviceComputeCapability *hipDeviceComputeCapability;
thipDevicePrimaryCtxRetain *hipDevicePrimaryCtxRetain;
thipDevicePrimaryCtxRelease *hipDevicePrimaryCtxRelease;
thipDevicePrimaryCtxSetFlags *hipDevicePrimaryCtxSetFlags;
thipDevicePrimaryCtxGetState *hipDevicePrimaryCtxGetState;
thipDevicePrimaryCtxReset *hipDevicePrimaryCtxReset;
thipCtxCreate *hipCtxCreate;
thipCtxDestroy *hipCtxDestroy;
thipCtxPushCurrent *hipCtxPushCurrent;
thipCtxPopCurrent *hipCtxPopCurrent;
thipCtxSetCurrent *hipCtxSetCurrent;
thipCtxGetCurrent *hipCtxGetCurrent;
thipCtxGetDevice *hipCtxGetDevice;
thipCtxGetFlags *hipCtxGetFlags;
thipCtxSynchronize *hipCtxSynchronize;
thipDeviceSynchronize *hipDeviceSynchronize;
thipCtxGetCacheConfig *hipCtxGetCacheConfig;
thipCtxSetCacheConfig *hipCtxSetCacheConfig;
thipCtxGetSharedMemConfig *hipCtxGetSharedMemConfig;
thipCtxSetSharedMemConfig *hipCtxSetSharedMemConfig;
thipCtxGetApiVersion *hipCtxGetApiVersion;
thipModuleLoad *hipModuleLoad;
thipModuleLoadData *hipModuleLoadData;
thipModuleLoadDataEx *hipModuleLoadDataEx;
thipModuleUnload *hipModuleUnload;
thipModuleGetFunction *hipModuleGetFunction;
thipModuleGetGlobal *hipModuleGetGlobal;
thipModuleGetTexRef *hipModuleGetTexRef;
thipMemGetInfo *hipMemGetInfo;
thipMalloc *hipMalloc;
thipMemAllocPitch *hipMemAllocPitch;
thipFree *hipFree;
thipMemGetAddressRange *hipMemGetAddressRange;
thipHostMalloc *hipHostMalloc;
thipHostFree *hipHostFree;
thipHostGetDevicePointer *hipHostGetDevicePointer;
thipHostGetFlags *hipHostGetFlags;
thipMallocManaged *hipMallocManaged;
thipDeviceGetByPCIBusId *hipDeviceGetByPCIBusId;
thipDeviceGetPCIBusId *hipDeviceGetPCIBusId;
thipMemcpyPeer *hipMemcpyPeer;
thipMemcpyHtoD *hipMemcpyHtoD;
thipMemcpyDtoH *hipMemcpyDtoH;
thipMemcpyDtoD *hipMemcpyDtoD;
thipDrvMemcpy2DUnaligned *hipDrvMemcpy2DUnaligned;
thipMemcpyParam2D *hipMemcpyParam2D;
thipDrvMemcpy3D *hipDrvMemcpy3D;
thipMemcpyHtoDAsync *hipMemcpyHtoDAsync;
thipMemcpyDtoHAsync *hipMemcpyDtoHAsync;
thipMemcpyParam2DAsync *hipMemcpyParam2DAsync;
thipDrvMemcpy3DAsync *hipDrvMemcpy3DAsync;
thipMemsetD8 *hipMemsetD8;
thipMemsetD16 *hipMemsetD16;
thipMemsetD32 *hipMemsetD32;
thipMemsetD8Async *hipMemsetD8Async;
thipMemsetD16Async *hipMemsetD16Async;
thipMemsetD32Async *hipMemsetD32Async;
thipArrayCreate *hipArrayCreate;
thipArrayDestroy *hipArrayDestroy;
thipArray3DCreate *hipArray3DCreate;
thipStreamCreateWithFlags *hipStreamCreateWithFlags;
thipStreamCreateWithPriority *hipStreamCreateWithPriority;
thipStreamGetPriority *hipStreamGetPriority;
thipStreamGetFlags *hipStreamGetFlags;
thipStreamWaitEvent *hipStreamWaitEvent;
thipStreamAddCallback *hipStreamAddCallback;
thipStreamQuery *hipStreamQuery;
thipStreamSynchronize *hipStreamSynchronize;
thipStreamDestroy *hipStreamDestroy;
thipEventCreateWithFlags *hipEventCreateWithFlags;
thipEventRecord *hipEventRecord;
thipEventQuery *hipEventQuery;
thipEventSynchronize *hipEventSynchronize;
thipEventDestroy *hipEventDestroy;
thipEventElapsedTime *hipEventElapsedTime;
thipFuncGetAttribute *hipFuncGetAttribute;
thipFuncSetCacheConfig *hipFuncSetCacheConfig;
thipModuleLaunchKernel *hipModuleLaunchKernel;
thipDrvOccupancyMaxActiveBlocksPerMultiprocessor *hipDrvOccupancyMaxActiveBlocksPerMultiprocessor;
thipDrvOccupancyMaxActiveBlocksPerMultiprocessorWithFlags *hipDrvOccupancyMaxActiveBlocksPerMultiprocessorWithFlags;
thipModuleOccupancyMaxPotentialBlockSize *hipModuleOccupancyMaxPotentialBlockSize;
thipTexRefSetArray *hipTexRefSetArray;
thipTexRefSetAddress *hipTexRefSetAddress;
thipTexRefSetAddress2D *hipTexRefSetAddress2D;
thipTexRefSetFormat *hipTexRefSetFormat;
thipTexRefSetAddressMode *hipTexRefSetAddressMode;
thipTexRefSetFilterMode *hipTexRefSetFilterMode;
thipTexRefSetFlags *hipTexRefSetFlags;
thipTexRefGetAddress *hipTexRefGetAddress;
thipTexRefGetArray *hipTexRefGetArray;
thipTexRefGetAddressMode *hipTexRefGetAddressMode;
thipTexObjectCreate *hipTexObjectCreate;
thipTexObjectDestroy *hipTexObjectDestroy;
thipDeviceCanAccessPeer *hipDeviceCanAccessPeer;
thipCtxEnablePeerAccess *hipCtxEnablePeerAccess;
thipCtxDisablePeerAccess *hipCtxDisablePeerAccess;
thipDeviceGetP2PAttribute *hipDeviceGetP2PAttribute;
thipGraphicsUnregisterResource *hipGraphicsUnregisterResource;
thipGraphicsMapResources *hipGraphicsMapResources;
thipGraphicsUnmapResources *hipGraphicsUnmapResources;
thipGraphicsResourceGetMappedPointer *hipGraphicsResourceGetMappedPointer;
thipGraphicsGLRegisterBuffer *hipGraphicsGLRegisterBuffer;
thipGLGetDevices *hipGLGetDevices;
static DynamicLibrary dynamic_library_open_find(const char **paths) {
int i = 0;
while (paths[i] != NULL) {
DynamicLibrary lib = dynamic_library_open(paths[i]);
if (lib != NULL) {
return lib;
}
++i;
}
return NULL;
}
/* Implementation function. */
static void hipewHipExit(void) {
if (hip_lib != NULL) {
/* Ignore errors. */
dynamic_library_close(hip_lib);
hip_lib = NULL;
}
}
static int hipewHipInit(void) {
/* Library paths. */
#ifdef _WIN32
/* Expected in c:/windows/system or similar, no path needed. */
const char *hip_paths[] = {"amdhip64.dll", NULL};
#elif defined(__APPLE__)
/* Default installation path. */
const char *hip_paths[] = {"", NULL};
#else
const char *hip_paths[] = {"/opt/rocm/hip/lib/libamdhip64.so", NULL};
#endif
static int initialized = 0;
static int result = 0;
int error, driver_version;
if (initialized) {
return result;
}
initialized = 1;
error = atexit(hipewHipExit);
if (error) {
result = HIPEW_ERROR_ATEXIT_FAILED;
return result;
}
/* Load library. */
hip_lib = dynamic_library_open_find(hip_paths);
if (hip_lib == NULL) {
result = HIPEW_ERROR_OPEN_FAILED;
return result;
}
/* Fetch all function pointers. */
HIP_LIBRARY_FIND_CHECKED(hipGetErrorName);
HIP_LIBRARY_FIND_CHECKED(hipInit);
HIP_LIBRARY_FIND_CHECKED(hipDriverGetVersion);
HIP_LIBRARY_FIND_CHECKED(hipGetDevice);
HIP_LIBRARY_FIND_CHECKED(hipGetDeviceCount);
HIP_LIBRARY_FIND_CHECKED(hipDeviceGetName);
HIP_LIBRARY_FIND_CHECKED(hipDeviceGetAttribute);
HIP_LIBRARY_FIND_CHECKED(hipDeviceComputeCapability);
HIP_LIBRARY_FIND_CHECKED(hipDevicePrimaryCtxRetain);
HIP_LIBRARY_FIND_CHECKED(hipDevicePrimaryCtxRelease);
HIP_LIBRARY_FIND_CHECKED(hipDevicePrimaryCtxSetFlags);
HIP_LIBRARY_FIND_CHECKED(hipDevicePrimaryCtxGetState);
HIP_LIBRARY_FIND_CHECKED(hipDevicePrimaryCtxReset);
HIP_LIBRARY_FIND_CHECKED(hipCtxCreate);
HIP_LIBRARY_FIND_CHECKED(hipCtxDestroy);
HIP_LIBRARY_FIND_CHECKED(hipCtxPushCurrent);
HIP_LIBRARY_FIND_CHECKED(hipCtxPopCurrent);
HIP_LIBRARY_FIND_CHECKED(hipCtxSetCurrent);
HIP_LIBRARY_FIND_CHECKED(hipCtxGetCurrent);
HIP_LIBRARY_FIND_CHECKED(hipCtxGetDevice);
HIP_LIBRARY_FIND_CHECKED(hipCtxGetFlags);
HIP_LIBRARY_FIND_CHECKED(hipCtxSynchronize);
HIP_LIBRARY_FIND_CHECKED(hipDeviceSynchronize);
HIP_LIBRARY_FIND_CHECKED(hipCtxGetCacheConfig);
HIP_LIBRARY_FIND_CHECKED(hipCtxSetCacheConfig);
HIP_LIBRARY_FIND_CHECKED(hipCtxGetSharedMemConfig);
HIP_LIBRARY_FIND_CHECKED(hipCtxSetSharedMemConfig);
HIP_LIBRARY_FIND_CHECKED(hipCtxGetApiVersion);
HIP_LIBRARY_FIND_CHECKED(hipModuleLoad);
HIP_LIBRARY_FIND_CHECKED(hipModuleLoadData);
HIP_LIBRARY_FIND_CHECKED(hipModuleLoadDataEx);
HIP_LIBRARY_FIND_CHECKED(hipModuleUnload);
HIP_LIBRARY_FIND_CHECKED(hipModuleGetFunction);
HIP_LIBRARY_FIND_CHECKED(hipModuleGetGlobal);
HIP_LIBRARY_FIND_CHECKED(hipModuleGetTexRef);
HIP_LIBRARY_FIND_CHECKED(hipMemGetInfo);
HIP_LIBRARY_FIND_CHECKED(hipMalloc);
HIP_LIBRARY_FIND_CHECKED(hipMemAllocPitch);
HIP_LIBRARY_FIND_CHECKED(hipFree);
HIP_LIBRARY_FIND_CHECKED(hipMemGetAddressRange);
HIP_LIBRARY_FIND_CHECKED(hipHostMalloc);
HIP_LIBRARY_FIND_CHECKED(hipHostFree);
HIP_LIBRARY_FIND_CHECKED(hipHostGetDevicePointer);
HIP_LIBRARY_FIND_CHECKED(hipHostGetFlags);
HIP_LIBRARY_FIND_CHECKED(hipMallocManaged);
HIP_LIBRARY_FIND_CHECKED(hipDeviceGetByPCIBusId);
HIP_LIBRARY_FIND_CHECKED(hipDeviceGetPCIBusId);
HIP_LIBRARY_FIND_CHECKED(hipMemcpyPeer);
HIP_LIBRARY_FIND_CHECKED(hipMemcpyHtoD);
HIP_LIBRARY_FIND_CHECKED(hipMemcpyDtoH);
HIP_LIBRARY_FIND_CHECKED(hipMemcpyDtoD);
HIP_LIBRARY_FIND_CHECKED(hipMemcpyParam2D);
HIP_LIBRARY_FIND_CHECKED(hipDrvMemcpy3D);
HIP_LIBRARY_FIND_CHECKED(hipMemcpyHtoDAsync);
HIP_LIBRARY_FIND_CHECKED(hipMemcpyDtoHAsync);
HIP_LIBRARY_FIND_CHECKED(hipDrvMemcpy2DUnaligned);
HIP_LIBRARY_FIND_CHECKED(hipMemcpyParam2DAsync);
HIP_LIBRARY_FIND_CHECKED(hipDrvMemcpy3DAsync);
HIP_LIBRARY_FIND_CHECKED(hipMemsetD8);
HIP_LIBRARY_FIND_CHECKED(hipMemsetD16);
HIP_LIBRARY_FIND_CHECKED(hipMemsetD32);
HIP_LIBRARY_FIND_CHECKED(hipMemsetD8Async);
HIP_LIBRARY_FIND_CHECKED(hipMemsetD16Async);
HIP_LIBRARY_FIND_CHECKED(hipMemsetD32Async);
HIP_LIBRARY_FIND_CHECKED(hipArrayCreate);
HIP_LIBRARY_FIND_CHECKED(hipArrayDestroy);
HIP_LIBRARY_FIND_CHECKED(hipArray3DCreate);
HIP_LIBRARY_FIND_CHECKED(hipStreamCreateWithFlags);
HIP_LIBRARY_FIND_CHECKED(hipStreamCreateWithPriority);
HIP_LIBRARY_FIND_CHECKED(hipStreamGetPriority);
HIP_LIBRARY_FIND_CHECKED(hipStreamGetFlags);
HIP_LIBRARY_FIND_CHECKED(hipStreamWaitEvent);
HIP_LIBRARY_FIND_CHECKED(hipStreamAddCallback);
HIP_LIBRARY_FIND_CHECKED(hipStreamQuery);
HIP_LIBRARY_FIND_CHECKED(hipStreamSynchronize);
HIP_LIBRARY_FIND_CHECKED(hipStreamDestroy);
HIP_LIBRARY_FIND_CHECKED(hipEventCreateWithFlags);
HIP_LIBRARY_FIND_CHECKED(hipEventRecord);
HIP_LIBRARY_FIND_CHECKED(hipEventQuery);
HIP_LIBRARY_FIND_CHECKED(hipEventSynchronize);
HIP_LIBRARY_FIND_CHECKED(hipEventDestroy);
HIP_LIBRARY_FIND_CHECKED(hipEventElapsedTime);
HIP_LIBRARY_FIND_CHECKED(hipFuncGetAttribute);
HIP_LIBRARY_FIND_CHECKED(hipFuncSetCacheConfig);
HIP_LIBRARY_FIND_CHECKED(hipModuleLaunchKernel);
HIP_LIBRARY_FIND_CHECKED(hipModuleOccupancyMaxPotentialBlockSize);
HIP_LIBRARY_FIND_CHECKED(hipTexRefSetArray);
HIP_LIBRARY_FIND_CHECKED(hipTexRefSetAddress);
HIP_LIBRARY_FIND_CHECKED(hipTexRefSetAddress2D);
HIP_LIBRARY_FIND_CHECKED(hipTexRefSetFormat);
HIP_LIBRARY_FIND_CHECKED(hipTexRefSetAddressMode);
HIP_LIBRARY_FIND_CHECKED(hipTexRefSetFilterMode);
HIP_LIBRARY_FIND_CHECKED(hipTexRefSetFlags);
HIP_LIBRARY_FIND_CHECKED(hipTexRefGetAddress);
HIP_LIBRARY_FIND_CHECKED(hipTexRefGetAddressMode);
HIP_LIBRARY_FIND_CHECKED(hipTexObjectCreate);
HIP_LIBRARY_FIND_CHECKED(hipTexObjectDestroy);
HIP_LIBRARY_FIND_CHECKED(hipDeviceCanAccessPeer);
HIP_LIBRARY_FIND_CHECKED(hipCtxEnablePeerAccess);
HIP_LIBRARY_FIND_CHECKED(hipCtxDisablePeerAccess);
HIP_LIBRARY_FIND_CHECKED(hipDeviceGetP2PAttribute);
#ifdef _WIN32
HIP_LIBRARY_FIND_CHECKED(hipGraphicsUnregisterResource);
HIP_LIBRARY_FIND_CHECKED(hipGraphicsMapResources);
HIP_LIBRARY_FIND_CHECKED(hipGraphicsUnmapResources);
HIP_LIBRARY_FIND_CHECKED(hipGraphicsResourceGetMappedPointer);
HIP_LIBRARY_FIND_CHECKED(hipGraphicsGLRegisterBuffer);
HIP_LIBRARY_FIND_CHECKED(hipGLGetDevices);
#endif
result = HIPEW_SUCCESS;
return result;
}
int hipewInit(hipuint32_t flags) {
int result = HIPEW_SUCCESS;
if (flags & HIPEW_INIT_HIP) {
result = hipewHipInit();
if (result != HIPEW_SUCCESS) {
return result;
}
}
return result;
}
const char *hipewErrorString(hipError_t result) {
switch (result) {
case hipSuccess: return "No errors";
case hipErrorInvalidValue: return "Invalid value";
case hipErrorOutOfMemory: return "Out of memory";
case hipErrorNotInitialized: return "Driver not initialized";
case hipErrorDeinitialized: return "Driver deinitialized";
case hipErrorProfilerDisabled: return "Profiler disabled";
case hipErrorProfilerNotInitialized: return "Profiler not initialized";
case hipErrorProfilerAlreadyStarted: return "Profiler already started";
case hipErrorProfilerAlreadyStopped: return "Profiler already stopped";
case hipErrorNoDevice: return "No HIP-capable device available";
case hipErrorInvalidDevice: return "Invalid device";
case hipErrorInvalidImage: return "Invalid kernel image";
case hipErrorInvalidContext: return "Invalid context";
case hipErrorContextAlreadyCurrent: return "Context already current";
case hipErrorMapFailed: return "Map failed";
case hipErrorUnmapFailed: return "Unmap failed";
case hipErrorArrayIsMapped: return "Array is mapped";
case hipErrorAlreadyMapped: return "Already mapped";
case hipErrorNoBinaryForGpu: return "No binary for GPU";
case hipErrorAlreadyAcquired: return "Already acquired";
case hipErrorNotMapped: return "Not mapped";
case hipErrorNotMappedAsArray: return "Mapped resource not available for access as an array";
case hipErrorNotMappedAsPointer: return "Mapped resource not available for access as a pointer";
case hipErrorECCNotCorrectable: return "Uncorrectable ECC error detected";
case hipErrorUnsupportedLimit: return "hipLimit_t not supported by device";
case hipErrorContextAlreadyInUse: return "Context already in use";
case hipErrorPeerAccessUnsupported: return "Peer access unsupported";
case hipErrorInvalidKernelFile: return "Invalid ptx";
case hipErrorInvalidGraphicsContext: return "Invalid graphics context";
case hipErrorInvalidSource: return "Invalid source";
case hipErrorFileNotFound: return "File not found";
case hipErrorSharedObjectSymbolNotFound: return "Link to a shared object failed to resolve";
case hipErrorSharedObjectInitFailed: return "Shared object initialization failed";
case hipErrorOperatingSystem: return "Operating system";
case hipErrorInvalidHandle: return "Invalid handle";
case hipErrorNotFound: return "Not found";
case hipErrorNotReady: return "HIP not ready";
case hipErrorIllegalAddress: return "Illegal address";
case hipErrorLaunchOutOfResources: return "Launch exceeded resources";
case hipErrorLaunchTimeOut: return "Launch exceeded timeout";
case hipErrorPeerAccessAlreadyEnabled: return "Peer access already enabled";
case hipErrorPeerAccessNotEnabled: return "Peer access not enabled";
case hipErrorSetOnActiveProcess: return "Primary context active";
case hipErrorAssert: return "Assert";
case hipErrorHostMemoryAlreadyRegistered: return "Host memory already registered";
case hipErrorHostMemoryNotRegistered: return "Host memory not registered";
case hipErrorLaunchFailure: return "Launch failed";
case hipErrorCooperativeLaunchTooLarge: return "Cooperative launch too large";
case hipErrorNotSupported: return "Not supported";
case hipErrorUnknown: return "Unknown error";
default: return "Unknown HIP error value";
}
}
static void path_join(const char *path1,
const char *path2,
int maxlen,
char *result) {
#if defined(WIN32) || defined(_WIN32)
const char separator = '\\';
#else
const char separator = '/';
#endif
int n = snprintf(result, maxlen, "%s%c%s", path1, separator, path2);
if (n != -1 && n < maxlen) {
result[n] = '\0';
}
else {
result[maxlen - 1] = '\0';
}
}
static int path_exists(const char *path) {
struct stat st;
if (stat(path, &st)) {
return 0;
}
return 1;
}
const char *hipewCompilerPath(void) {
#ifdef _WIN32
const char *hipPath = getenv("HIP_ROCCLR_HOME");
const char *windowsCommand = "perl ";
const char *executable = "bin/hipcc";
static char hipcc[65536];
static char finalCommand[65536];
if(hipPath) {
path_join(hipPath, executable, sizeof(hipcc), hipcc);
if(path_exists(hipcc)) {
snprintf(finalCommand, sizeof(hipcc), "%s %s", windowsCommand, hipcc);
return finalCommand;
} else {
printf("Could not find hipcc. Make sure HIP_ROCCLR_HOME points to the directory holding /bin/hipcc");
}
}
#else
const char *hipPath = "opt/rocm/hip/bin";
const char *executable = "hipcc";
static char hipcc[65536];
if(hipPath) {
path_join(hipPath, executable, sizeof(hipcc), hipcc);
if(path_exists(hipcc)){
return hipcc;
}
}
#endif
{
#ifdef _WIN32
FILE *handle = popen("where hipcc", "r");
#else
FILE *handle = popen("which hipcc", "r");
#endif
if (handle) {
char buffer[4096] = {0};
int len = fread(buffer, 1, sizeof(buffer) - 1, handle);
buffer[len] = '\0';
pclose(handle);
if (buffer[0]) {
return "hipcc";
}
}
}
return NULL;
}
int hipewCompilerVersion(void) {
const char *path = hipewCompilerPath();
const char *marker = "Hip compilation tools, release ";
FILE *pipe;
int major, minor;
char *versionstr;
char buf[128];
char output[65536] = "\0";
char command[65536] = "\0";
if (path == NULL) {
return 0;
}
/* get --version output */
strcat(command, "\"");
strncat(command, path, sizeof(command) - 1);
strncat(command, "\" --version", sizeof(command) - strlen(path) - 1);
pipe = popen(command, "r");
if (!pipe) {
fprintf(stderr, "HIP: failed to run compiler to retrieve version");
return 0;
}
while (!feof(pipe)) {
if (fgets(buf, sizeof(buf), pipe) != NULL) {
strncat(output, buf, sizeof(output) - strlen(output) - 1);
}
}
pclose(pipe);
return 40;
}

5
extern/json/README.blender vendored Normal file
View File

@@ -0,0 +1,5 @@
Project: JSON
URL: https://github.com/nlohmann/json/
License: MIT License
Upstream version: 3.10.2
Local modifications: None

26640
extern/json/include/json.hpp vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -67,7 +67,7 @@ SET(LEMON_ENABLE_ILOG YES CACHE STRING "Enable ILOG (CPLEX) solver backend.")
SET(LEMON_ENABLE_COIN YES CACHE STRING "Enable COIN solver backend.")
SET(LEMON_ENABLE_SOPLEX YES CACHE STRING "Enable SoPlex solver backend.")
IF(LEMON_ENABLE_GLPK)
IF(LEMON_ENABLE_GLPK)
FIND_PACKAGE(GLPK 4.33)
ENDIF(LEMON_ENABLE_GLPK)
IF(LEMON_ENABLE_ILOG)

View File

@@ -4,7 +4,7 @@ FIND_PATH(ILOG_ROOT_DIR
PATHS /opt/ibm/ILOG /usr/local/ibm/ILOG /usr/local/ILOG /usr/local/ilog
PATHS "$ENV{HOME}/ILOG" "$ENV{HOME}/.local/ILOG"
PATHS "$ENV{HOME}/ibm/ILOG" "$ENV{HOME}/.local/ibm/ILOG"
PATHS "C:/Program Files/IBM/ILOG"
PATHS "C:/Program Files/IBM/ILOG"
PATH_SUFFIXES "CPLEX_Studio126" "CPLEX_Studio125"
"CPLEX_Studio124" "CPLEX_Studio123" "CPLEX_Studio122"
NO_DEFAULT_PATH

View File

@@ -16,4 +16,3 @@ LINK_DIRECTORIES(
# ADD_EXECUTABLE(myprog myprog-main.cc)
# TARGET_LINK_LIBRARIES(myprog lemon)

View File

@@ -88,4 +88,3 @@ INSTALL(
FILES ${CMAKE_CURRENT_BINARY_DIR}/lemon.pc
DESTINATION lib/pkgconfig
)

View File

@@ -10,7 +10,6 @@
#include <fstream>
#include <unordered_map>
#include <functional>
namespace qflow {
@@ -70,7 +69,7 @@ void load(const char* filename, MatrixXd& V, MatrixXi& F)
};
/// Hash function for obj_vertex
struct obj_vertexHash : std::function<size_t(obj_vertex)> {
struct obj_vertexHash {
std::size_t operator()(const obj_vertex &v) const {
size_t hash = std::hash<uint32_t>()(v.p);
hash = hash * 37 + std::hash<uint32_t>()(v.uv);

6
extern/tinygltf/README.blender vendored Normal file
View File

@@ -0,0 +1,6 @@
Project: TinyGLTF
URL: https://github.com/syoyo/tinygltf
License: MIT
Upstream version: 2.5.0, 19a41d20ec0
Local modifications:
* Silence "enum value not handled in switch" warnings due to JSON dependency.

7761
extern/tinygltf/tiny_gltf.h vendored Normal file

File diff suppressed because it is too large Load Diff

Binary file not shown.

View File

@@ -49,27 +49,27 @@
/* Unsigned */
ATOMIC_INLINE uint64_t atomic_add_and_fetch_uint64(uint64_t *p, uint64_t x)
{
return (uint64_t)(InterlockedExchangeAdd64((int64_t *)p, (int64_t)x) + (int64_t)x);
return InterlockedExchangeAdd64((int64_t *)p, (int64_t)x) + x;
}
ATOMIC_INLINE uint64_t atomic_sub_and_fetch_uint64(uint64_t *p, uint64_t x)
{
return (uint64_t)(InterlockedExchangeAdd64((int64_t *)p, -((int64_t)x)) - (int64_t)x);
return InterlockedExchangeAdd64((int64_t *)p, -((int64_t)x)) - x;
}
ATOMIC_INLINE uint64_t atomic_cas_uint64(uint64_t *v, uint64_t old, uint64_t _new)
{
return (uint64_t)(InterlockedCompareExchange64((int64_t *)v, _new, old));
return InterlockedCompareExchange64((int64_t *)v, _new, old);
}
ATOMIC_INLINE uint64_t atomic_fetch_and_add_uint64(uint64_t *p, uint64_t x)
{
return (uint64_t)InterlockedExchangeAdd64((int64_t *)p, (int64_t)x);
return InterlockedExchangeAdd64((int64_t *)p, (int64_t)x);
}
ATOMIC_INLINE uint64_t atomic_fetch_and_sub_uint64(uint64_t *p, uint64_t x)
{
return (uint64_t)InterlockedExchangeAdd64((int64_t *)p, -((int64_t)x));
return InterlockedExchangeAdd64((int64_t *)p, -((int64_t)x));
}
/* Signed */
@@ -103,32 +103,32 @@ ATOMIC_INLINE int64_t atomic_fetch_and_sub_int64(int64_t *p, int64_t x)
/* Unsigned */
ATOMIC_INLINE uint32_t atomic_add_and_fetch_uint32(uint32_t *p, uint32_t x)
{
return (uint32_t)InterlockedExchangeAdd(p, x) + x;
return InterlockedExchangeAdd(p, x) + x;
}
ATOMIC_INLINE uint32_t atomic_sub_and_fetch_uint32(uint32_t *p, uint32_t x)
{
return (uint32_t)InterlockedExchangeAdd(p, -((int32_t)x)) - x;
return InterlockedExchangeAdd(p, -((int32_t)x)) - x;
}
ATOMIC_INLINE uint32_t atomic_cas_uint32(uint32_t *v, uint32_t old, uint32_t _new)
{
return (uint32_t)InterlockedCompareExchange((long *)v, _new, old);
return InterlockedCompareExchange((long *)v, _new, old);
}
ATOMIC_INLINE uint32_t atomic_fetch_and_add_uint32(uint32_t *p, uint32_t x)
{
return (uint32_t)InterlockedExchangeAdd(p, x);
return InterlockedExchangeAdd(p, x);
}
ATOMIC_INLINE uint32_t atomic_fetch_and_or_uint32(uint32_t *p, uint32_t x)
{
return (uint32_t)InterlockedOr((long *)p, x);
return InterlockedOr((long *)p, x);
}
ATOMIC_INLINE uint32_t atomic_fetch_and_and_uint32(uint32_t *p, uint32_t x)
{
return (uint32_t)InterlockedAnd((long *)p, x);
return InterlockedAnd((long *)p, x);
}
/* Signed */
@@ -205,9 +205,9 @@ ATOMIC_INLINE uint8_t atomic_fetch_and_or_uint8(uint8_t *p, uint8_t b)
ATOMIC_INLINE int8_t atomic_fetch_and_and_int8(int8_t *p, int8_t b)
{
#if (LG_SIZEOF_PTR == 8 || LG_SIZEOF_INT == 8)
return (int8_t)InterlockedAnd8((char *)p, (char)b);
return InterlockedAnd8((char *)p, (char)b);
#else
return (int8_t)_InterlockedAnd8((char *)p, (char)b);
return _InterlockedAnd8((char *)p, (char)b);
#endif
}
@@ -215,9 +215,9 @@ ATOMIC_INLINE int8_t atomic_fetch_and_and_int8(int8_t *p, int8_t b)
ATOMIC_INLINE int8_t atomic_fetch_and_or_int8(int8_t *p, int8_t b)
{
#if (LG_SIZEOF_PTR == 8 || LG_SIZEOF_INT == 8)
return (int8_t)InterlockedOr8((char *)p, (char)b);
return InterlockedOr8((char *)p, (char)b);
#else
return (int8_t)_InterlockedOr8((char *)p, (char)b);
return _InterlockedOr8((char *)p, (char)b);
#endif
}

View File

@@ -247,7 +247,7 @@ if(WITH_CYCLES_OSL)
endif()
if(WITH_CYCLES_DEVICE_OPTIX)
find_package(OptiX)
find_package(OptiX 7.3.0)
if(OPTIX_FOUND)
add_definitions(-DWITH_OPTIX)
@@ -286,11 +286,18 @@ if(WITH_OPENSUBDIV)
)
endif()
if(WITH_OPENIMAGEDENOISE)
add_definitions(-DWITH_OPENIMAGEDENOISE)
add_definitions(-DOIDN_STATIC_LIB)
include_directories(
SYSTEM
${OPENIMAGEDENOISE_INCLUDE_DIRS}
)
endif()
if(WITH_CYCLES_STANDALONE)
set(WITH_CYCLES_DEVICE_OPENCL TRUE)
set(WITH_CYCLES_DEVICE_CUDA TRUE)
# Experimental and unfinished.
set(WITH_CYCLES_NETWORK FALSE)
set(WITH_CYCLES_DEVICE_HIP TRUE)
endif()
# TODO(sergey): Consider removing it, only causes confusion in interface.
set(WITH_CYCLES_DEVICE_MULTI TRUE)
@@ -386,18 +393,12 @@ if(WITH_CYCLES_BLENDER)
add_subdirectory(blender)
endif()
if(WITH_CYCLES_NETWORK)
add_definitions(-DWITH_NETWORK)
endif()
if(WITH_CYCLES_STANDALONE OR WITH_CYCLES_NETWORK OR WITH_CYCLES_CUBIN_COMPILER)
add_subdirectory(app)
endif()
add_subdirectory(app)
add_subdirectory(bvh)
add_subdirectory(device)
add_subdirectory(doc)
add_subdirectory(graph)
add_subdirectory(integrator)
add_subdirectory(kernel)
add_subdirectory(render)
add_subdirectory(subd)

View File

@@ -64,6 +64,8 @@ if(WITH_CYCLES_STANDALONE)
cycles_standalone.cpp
cycles_xml.cpp
cycles_xml.h
oiio_output_driver.cpp
oiio_output_driver.h
)
add_executable(cycles ${SRC} ${INC} ${INC_SYS})
unset(SRC)
@@ -73,7 +75,7 @@ if(WITH_CYCLES_STANDALONE)
if(APPLE)
if(WITH_OPENCOLORIO)
set_property(TARGET cycles APPEND_STRING PROPERTY LINK_FLAGS " -framework IOKit")
set_property(TARGET cycles APPEND_STRING PROPERTY LINK_FLAGS " -framework IOKit -framework Carbon")
endif()
if(WITH_OPENIMAGEDENOISE AND "${CMAKE_OSX_ARCHITECTURES}" STREQUAL "arm64")
# OpenImageDenoise uses BNNS from the Accelerate framework.
@@ -90,24 +92,6 @@ if(WITH_CYCLES_STANDALONE)
endif()
endif()
#####################################################################
# Cycles network server executable
#####################################################################
if(WITH_CYCLES_NETWORK)
set(SRC
cycles_server.cpp
)
add_executable(cycles_server ${SRC})
target_link_libraries(cycles_server ${LIBRARIES})
cycles_target_link_libraries(cycles_server)
if(UNIX AND NOT APPLE)
set_target_properties(cycles_server PROPERTIES INSTALL_RPATH $ORIGIN/lib)
endif()
unset(SRC)
endif()
#####################################################################
# Cycles cubin compiler executable
#####################################################################

View File

@@ -36,6 +36,9 @@
#include "util/util_unique_ptr.h"
#include "util/util_version.h"
#include "app/cycles_xml.h"
#include "app/oiio_output_driver.h"
#ifdef WITH_CYCLES_STANDALONE_GUI
# include "util/util_view.h"
#endif
@@ -53,7 +56,8 @@ struct Options {
SessionParams session_params;
bool quiet;
bool show_help, interactive, pause;
string output_path;
string output_filepath;
string output_pass;
} options;
static void session_print(const string &str)
@@ -89,30 +93,6 @@ static void session_print_status()
session_print(status);
}
static bool write_render(const uchar *pixels, int w, int h, int channels)
{
string msg = string_printf("Writing image %s", options.output_path.c_str());
session_print(msg);
unique_ptr<ImageOutput> out = unique_ptr<ImageOutput>(ImageOutput::create(options.output_path));
if (!out) {
return false;
}
ImageSpec spec(w, h, channels, TypeDesc::UINT8);
if (!out->open(options.output_path, spec)) {
return false;
}
/* conversion for different top/bottom convention */
out->write_image(
TypeDesc::UINT8, pixels + (h - 1) * w * channels, AutoStride, -w * channels, AutoStride);
out->close();
return true;
}
static BufferParams &session_buffer_params()
{
static BufferParams buffer_params;
@@ -126,7 +106,7 @@ static BufferParams &session_buffer_params()
static void scene_init()
{
options.scene = new Scene(options.scene_params, options.session->device);
options.scene = options.session->scene;
/* Read XML */
xml_read_file(options.scene, options.filepath.c_str());
@@ -147,8 +127,13 @@ static void scene_init()
static void session_init()
{
options.session_params.write_render_cb = write_render;
options.session = new Session(options.session_params);
options.output_pass = "combined";
options.session = new Session(options.session_params, options.scene_params);
if (!options.output_filepath.empty()) {
options.session->set_output_driver(make_unique<OIIOOutputDriver>(
options.output_filepath, options.output_pass, session_print));
}
if (options.session_params.background && !options.quiet)
options.session->progress.set_update_callback(function_bind(&session_print_status));
@@ -159,9 +144,13 @@ static void session_init()
/* load scene */
scene_init();
options.session->scene = options.scene;
options.session->reset(session_buffer_params(), options.session_params.samples);
/* add pass for output. */
Pass *pass = options.scene->create_node<Pass>();
pass->set_name(ustring(options.output_pass.c_str()));
pass->set_type(PASS_COMBINED);
options.session->reset(options.session_params, session_buffer_params());
options.session->start();
}
@@ -223,9 +212,7 @@ static void display_info(Progress &progress)
static void display()
{
static DeviceDrawParams draw_params = DeviceDrawParams();
options.session->draw(session_buffer_params(), draw_params);
options.session->draw();
display_info(options.session->progress);
}
@@ -255,7 +242,7 @@ static void motion(int x, int y, int button)
options.session->scene->camera->need_flags_update = true;
options.session->scene->camera->need_device_update = true;
options.session->reset(session_buffer_params(), options.session_params.samples);
options.session->reset(options.session_params, session_buffer_params());
}
}
@@ -272,7 +259,7 @@ static void resize(int width, int height)
options.session->scene->camera->need_flags_update = true;
options.session->scene->camera->need_device_update = true;
options.session->reset(session_buffer_params(), options.session_params.samples);
options.session->reset(options.session_params, session_buffer_params());
}
}
@@ -284,7 +271,7 @@ static void keyboard(unsigned char key)
/* Reset */
else if (key == 'r')
options.session->reset(session_buffer_params(), options.session_params.samples);
options.session->reset(options.session_params, session_buffer_params());
/* Cancel */
else if (key == 27) // escape
@@ -321,7 +308,7 @@ static void keyboard(unsigned char key)
options.session->scene->camera->need_flags_update = true;
options.session->scene->camera->need_device_update = true;
options.session->reset(session_buffer_params(), options.session_params.samples);
options.session->reset(options.session_params, session_buffer_params());
}
/* Set Max Bounces */
@@ -347,7 +334,7 @@ static void keyboard(unsigned char key)
options.session->scene->integrator->set_max_bounce(bounce);
options.session->reset(session_buffer_params(), options.session_params.samples);
options.session->reset(options.session_params, session_buffer_params());
}
}
#endif
@@ -362,11 +349,13 @@ static int files_parse(int argc, const char *argv[])
static void options_parse(int argc, const char **argv)
{
options.width = 0;
options.height = 0;
options.width = 1024;
options.height = 512;
options.filepath = "";
options.session = NULL;
options.quiet = false;
options.session_params.use_auto_tile = false;
options.session_params.tile_size = 0;
/* device names */
string device_names = "";
@@ -412,7 +401,7 @@ static void options_parse(int argc, const char **argv)
&options.session_params.samples,
"Number of samples to render",
"--output %s",
&options.output_path,
&options.output_filepath,
"File path to write output image",
"--threads %d",
&options.session_params.threads,
@@ -423,12 +412,9 @@ static void options_parse(int argc, const char **argv)
"--height %d",
&options.height,
"Window height in pixel",
"--tile-width %d",
&options.session_params.tile_size.x,
"Tile width in pixels",
"--tile-height %d",
&options.session_params.tile_size.y,
"Tile height in pixels",
"--tile-size %d",
&options.session_params.tile_size,
"Tile size in pixels",
"--list-devices",
&list,
"List information about all available devices",
@@ -490,8 +476,9 @@ static void options_parse(int argc, const char **argv)
options.session_params.background = true;
#endif
/* Use progressive rendering */
options.session_params.progressive = true;
if (options.session_params.tile_size > 0) {
options.session_params.use_auto_tile = true;
}
/* find matching device */
DeviceType device_type = Device::type_from_string(devicename.c_str());
@@ -527,9 +514,6 @@ static void options_parse(int argc, const char **argv)
fprintf(stderr, "No file path specified\n");
exit(EXIT_FAILURE);
}
/* For smoother Viewport */
options.session_params.start_resolution = 64;
}
CCL_NAMESPACE_END

View File

@@ -333,6 +333,7 @@ static void xml_read_shader_graph(XMLReadState &state, Shader *shader, xml_node
}
snode = (ShaderNode *)node_type->create(node_type);
snode->set_owner(graph);
}
xml_read_node(graph_reader, snode, node);
@@ -703,7 +704,7 @@ void xml_read_file(Scene *scene, const char *filepath)
xml_read_include(state, path_filename(filepath));
scene->params.bvh_type = SceneParams::BVH_STATIC;
scene->params.bvh_type = BVH_TYPE_STATIC;
}
CCL_NAMESPACE_END

View File

@@ -0,0 +1,71 @@
/*
* Copyright 2021 Blender Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "app/oiio_output_driver.h"
CCL_NAMESPACE_BEGIN
OIIOOutputDriver::OIIOOutputDriver(const string_view filepath,
const string_view pass,
LogFunction log)
: filepath_(filepath), pass_(pass), log_(log)
{
}
OIIOOutputDriver::~OIIOOutputDriver()
{
}
void OIIOOutputDriver::write_render_tile(const Tile &tile)
{
/* Only write the full buffer, no intermediate tiles. */
if (!(tile.size == tile.full_size)) {
return;
}
log_(string_printf("Writing image %s", filepath_.c_str()));
unique_ptr<ImageOutput> image_output(ImageOutput::create(filepath_));
if (image_output == nullptr) {
log_("Failed to create image file");
return;
}
const int width = tile.size.x;
const int height = tile.size.y;
ImageSpec spec(width, height, 4, TypeDesc::FLOAT);
if (!image_output->open(filepath_, spec)) {
log_("Failed to create image file");
return;
}
vector<float> pixels(width * height * 4);
if (!tile.get_pass_pixels(pass_, 4, pixels.data())) {
log_("Failed to read render pass pixels");
return;
}
/* Manipulate offset and stride to convert from bottom-up to top-down convention. */
image_output->write_image(TypeDesc::FLOAT,
pixels.data() + (height - 1) * width * 4,
AutoStride,
-width * 4 * sizeof(float),
AutoStride);
image_output->close();
}
CCL_NAMESPACE_END

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2019 Blender Foundation
* Copyright 2021 Blender Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,16 +14,29 @@
* limitations under the License.
*/
#include "render/output_driver.h"
#include "util/util_function.h"
#include "util/util_image.h"
#include "util/util_string.h"
#include "util/util_unique_ptr.h"
#include "util/util_vector.h"
CCL_NAMESPACE_BEGIN
ccl_device void kernel_adaptive_filter_y(KernelGlobals *kg)
{
int pixel_index = ccl_global_id(1) * ccl_global_size(0) + ccl_global_id(0);
if (pixel_index < kernel_split_params.tile.w &&
kernel_split_params.tile.start_sample + kernel_split_params.tile.num_samples >=
kernel_data.integrator.adaptive_min_samples) {
int x = kernel_split_params.tile.x + pixel_index;
kernel_do_adaptive_filter_y(kg, x, &kernel_split_params.tile);
}
}
class OIIOOutputDriver : public OutputDriver {
public:
typedef function<void(const string &)> LogFunction;
OIIOOutputDriver(const string_view filepath, const string_view pass, LogFunction log);
virtual ~OIIOOutputDriver();
void write_render_tile(const Tile &tile) override;
protected:
string filepath_;
string pass_;
LogFunction log_;
};
CCL_NAMESPACE_END

View File

@@ -31,12 +31,14 @@ set(INC_SYS
set(SRC
blender_camera.cpp
blender_device.cpp
blender_display_driver.cpp
blender_image.cpp
blender_geometry.cpp
blender_light.cpp
blender_mesh.cpp
blender_object.cpp
blender_object_cull.cpp
blender_output_driver.cpp
blender_particles.cpp
blender_curves.cpp
blender_logging.cpp
@@ -50,9 +52,11 @@ set(SRC
CCL_api.h
blender_device.h
blender_display_driver.h
blender_id_map.h
blender_image.h
blender_object_cull.h
blender_output_driver.h
blender_sync.h
blender_session.h
blender_texture.h
@@ -93,14 +97,9 @@ set(ADDON_FILES
add_definitions(${GL_DEFINITIONS})
if(WITH_CYCLES_DEVICE_OPENCL)
add_definitions(-DWITH_OPENCL)
if(WITH_CYCLES_DEVICE_HIP)
add_definitions(-DWITH_HIP)
endif()
if(WITH_CYCLES_NETWORK)
add_definitions(-DWITH_NETWORK)
endif()
if(WITH_MOD_FLUID)
add_definitions(-DWITH_FLUID)
endif()

View File

@@ -58,7 +58,6 @@ class CyclesRender(bpy.types.RenderEngine):
bl_use_eevee_viewport = True
bl_use_preview = True
bl_use_exclude_layers = True
bl_use_save_buffers = True
bl_use_spherical_stereo = True
bl_use_custom_freestyle = True
bl_use_alembic_procedural = True
@@ -85,6 +84,12 @@ class CyclesRender(bpy.types.RenderEngine):
def render(self, depsgraph):
engine.render(self, depsgraph)
def render_frame_finish(self):
engine.render_frame_finish(self)
def draw(self, context, depsgraph):
engine.draw(self, depsgraph, context.space_data)
def bake(self, depsgraph, obj, pass_type, pass_filter, width, height):
engine.bake(self, depsgraph, obj, pass_type, pass_filter, width, height)
@@ -98,7 +103,7 @@ class CyclesRender(bpy.types.RenderEngine):
engine.sync(self, depsgraph, context.blend_data)
def view_draw(self, context, depsgraph):
engine.draw(self, depsgraph, context.region, context.space_data, context.region_data)
engine.view_draw(self, depsgraph, context.region, context.space_data, context.region_data)
def update_script_node(self, node):
if engine.with_osl():

View File

@@ -18,62 +18,17 @@
from __future__ import annotations
def _is_using_buggy_driver():
import gpu
# We need to be conservative here because in multi-GPU systems display card
# might be quite old, but others one might be just good.
#
# So We shouldn't disable possible good dedicated cards just because display
# card seems weak. And instead we only blacklist configurations which are
# proven to cause problems.
if gpu.platform.vendor_get() == "ATI Technologies Inc.":
import re
version = gpu.platform.version_get()
if version.endswith("Compatibility Profile Context"):
# Old HD 4xxx and 5xxx series drivers did not have driver version
# in the version string, but those cards do not quite work and
# causing crashes.
return True
regex = re.compile(".*Compatibility Profile Context ([0-9]+(\\.[0-9]+)+)$")
if not regex.match(version):
# Skip cards like FireGL
return False
version = regex.sub("\\1", version).split('.')
return int(version[0]) == 8
return False
def _workaround_buggy_drivers():
if _is_using_buggy_driver():
import _cycles
if hasattr(_cycles, "opencl_disable"):
print("Cycles: OpenGL driver known to be buggy, disabling OpenCL platform.")
_cycles.opencl_disable()
def _configure_argument_parser():
import argparse
# No help because it conflicts with general Python scripts argument parsing
parser = argparse.ArgumentParser(description="Cycles Addon argument parser",
add_help=False)
parser.add_argument("--cycles-resumable-num-chunks",
help="Number of chunks to split sample range into",
default=None)
parser.add_argument("--cycles-resumable-current-chunk",
help="Current chunk of samples range to render",
default=None)
parser.add_argument("--cycles-resumable-start-chunk",
help="Start chunk to render",
default=None)
parser.add_argument("--cycles-resumable-end-chunk",
help="End chunk to render",
default=None)
parser.add_argument("--cycles-print-stats",
help="Print rendering statistics to stderr",
action='store_true')
parser.add_argument("--cycles-device",
help="Set the device to use for Cycles, overriding user preferences and the scene setting."
"Valid options are 'CPU', 'CUDA', 'OPTIX' or 'OPENCL'."
"Valid options are 'CPU', 'CUDA', 'OPTIX', or 'HIP'"
"Additionally, you can append '+CPU' to any GPU type for hybrid rendering.",
default=None)
return parser
@@ -89,21 +44,6 @@ def _parse_command_line():
parser = _configure_argument_parser()
args, _ = parser.parse_known_args(argv[argv.index("--") + 1:])
if args.cycles_resumable_num_chunks is not None:
if args.cycles_resumable_current_chunk is not None:
import _cycles
_cycles.set_resumable_chunk(
int(args.cycles_resumable_num_chunks),
int(args.cycles_resumable_current_chunk),
)
elif args.cycles_resumable_start_chunk is not None and \
args.cycles_resumable_end_chunk:
import _cycles
_cycles.set_resumable_chunk_range(
int(args.cycles_resumable_num_chunks),
int(args.cycles_resumable_start_chunk),
int(args.cycles_resumable_end_chunk),
)
if args.cycles_print_stats:
import _cycles
_cycles.enable_print_stats()
@@ -118,23 +58,11 @@ def init():
import _cycles
import os.path
# Workaround possibly buggy legacy drivers which crashes on the OpenCL
# device enumeration.
#
# This checks are not really correct because they might still fail
# in the case of multiple GPUs. However, currently buggy drivers
# are really old and likely to be used in single GPU systems only
# anyway.
#
# Can't do it in the background mode, so we hope OpenCL is no enabled
# in the user preferences.
if not bpy.app.background:
_workaround_buggy_drivers()
path = os.path.dirname(__file__)
user_path = os.path.dirname(os.path.abspath(bpy.utils.user_resource('CONFIG', path='')))
temp_path = bpy.app.tempdir
_cycles.init(path, user_path, bpy.app.background)
_cycles.init(path, user_path, temp_path, bpy.app.background)
_parse_command_line()
@@ -177,6 +105,25 @@ def render(engine, depsgraph):
_cycles.render(engine.session, depsgraph.as_pointer())
def render_frame_finish(engine):
if not engine.session:
return
import _cycles
_cycles.render_frame_finish(engine.session)
def draw(engine, depsgraph, space_image):
if not engine.session:
return
depsgraph_ptr = depsgraph.as_pointer()
space_image_ptr = space_image.as_pointer()
screen_ptr = space_image.id_data.as_pointer()
import _cycles
_cycles.draw(engine.session, depsgraph_ptr, screen_ptr, space_image_ptr)
def bake(engine, depsgraph, obj, pass_type, pass_filter, width, height):
import _cycles
session = getattr(engine, "session", None)
@@ -204,14 +151,14 @@ def sync(engine, depsgraph, data):
_cycles.sync(engine.session, depsgraph.as_pointer())
def draw(engine, depsgraph, region, v3d, rv3d):
def view_draw(engine, depsgraph, region, v3d, rv3d):
import _cycles
depsgraph = depsgraph.as_pointer()
v3d = v3d.as_pointer()
rv3d = rv3d.as_pointer()
# draw render image
_cycles.draw(engine.session, depsgraph, v3d, rv3d)
_cycles.view_draw(engine.session, depsgraph, v3d, rv3d)
def available_devices():
@@ -224,11 +171,6 @@ def with_osl():
return _cycles.with_osl
def with_network():
import _cycles
return _cycles.with_network
def system_info():
import _cycles
return _cycles.system_info()
@@ -243,6 +185,7 @@ def list_render_passes(scene, srl):
# Data passes.
if srl.use_pass_z: yield ("Depth", "Z", 'VALUE')
if srl.use_pass_mist: yield ("Mist", "Z", 'VALUE')
if srl.use_pass_position: yield ("Position", "XYZ", 'VECTOR')
if srl.use_pass_normal: yield ("Normal", "XYZ", 'VECTOR')
if srl.use_pass_vector: yield ("Vector", "XYZW", 'VECTOR')
if srl.use_pass_uv: yield ("UV", "UVA", 'VECTOR')
@@ -265,6 +208,7 @@ def list_render_passes(scene, srl):
if srl.use_pass_environment: yield ("Env", "RGB", 'COLOR')
if srl.use_pass_shadow: yield ("Shadow", "RGB", 'COLOR')
if srl.use_pass_ambient_occlusion: yield ("AO", "RGB", 'COLOR')
if crl.use_pass_shadow_catcher: yield ("Shadow Catcher", "RGB", 'COLOR')
# Debug passes.
if crl.pass_debug_render_time: yield ("Debug Render Time", "X", 'VALUE')
@@ -283,30 +227,20 @@ def list_render_passes(scene, srl):
yield ("CryptoAsset" + '{:02d}'.format(i), "RGBA", 'COLOR')
# Denoising passes.
if (scene.cycles.use_denoising and crl.use_denoising) or crl.denoising_store_passes:
if scene.cycles.use_denoising and crl.use_denoising:
yield ("Noisy Image", "RGBA", 'COLOR')
if crl.denoising_store_passes:
yield ("Denoising Normal", "XYZ", 'VECTOR')
yield ("Denoising Albedo", "RGB", 'COLOR')
yield ("Denoising Depth", "Z", 'VALUE')
if scene.cycles.denoiser == 'NLM':
yield ("Denoising Shadowing", "X", 'VALUE')
yield ("Denoising Variance", "RGB", 'COLOR')
yield ("Denoising Intensity", "X", 'VALUE')
clean_options = ("denoising_diffuse_direct", "denoising_diffuse_indirect",
"denoising_glossy_direct", "denoising_glossy_indirect",
"denoising_transmission_direct", "denoising_transmission_indirect")
if any(getattr(crl, option) for option in clean_options):
yield ("Denoising Clean", "RGB", 'COLOR')
if crl.use_pass_shadow_catcher:
yield ("Noisy Shadow Catcher", "RGBA", 'COLOR')
if crl.denoising_store_passes:
yield ("Denoising Normal", "XYZ", 'VECTOR')
yield ("Denoising Albedo", "RGB", 'COLOR')
# Custom AOV passes.
for aov in srl.aovs:
if aov.type == 'VALUE':
yield (aov.name, "X", 'VALUE')
else:
yield (aov.name, "RGBA", 'COLOR')
yield (aov.name, "RGB", 'COLOR')
def register_passes(engine, scene, view_layer):

View File

@@ -60,32 +60,48 @@ class AddPresetSampling(AddPresetBase, Operator):
]
preset_values = [
"cycles.use_adaptive_sampling",
"cycles.samples",
"cycles.preview_samples",
"cycles.aa_samples",
"cycles.preview_aa_samples",
"cycles.diffuse_samples",
"cycles.glossy_samples",
"cycles.transmission_samples",
"cycles.ao_samples",
"cycles.mesh_light_samples",
"cycles.subsurface_samples",
"cycles.volume_samples",
"cycles.use_square_samples",
"cycles.progressive",
"cycles.seed",
"cycles.sample_clamp_direct",
"cycles.sample_clamp_indirect",
"cycles.sample_all_lights_direct",
"cycles.sample_all_lights_indirect",
"cycles.adaptive_threshold",
"cycles.adaptive_min_samples",
"cycles.time_limit",
"cycles.use_denoising",
"cycles.denoiser",
"cycles.denoising_input_passes",
"cycles.denoising_prefilter",
]
preset_subdir = "cycles/sampling"
class AddPresetViewportSampling(AddPresetBase, Operator):
'''Add a Viewport Sampling Preset'''
bl_idname = "render.cycles_viewport_sampling_preset_add"
bl_label = "Add Viewport Sampling Preset"
preset_menu = "CYCLES_PT_viewport_sampling_presets"
preset_defines = [
"cycles = bpy.context.scene.cycles"
]
preset_values = [
"cycles.use_preview_adaptive_sampling",
"cycles.preview_samples",
"cycles.preview_adaptive_threshold",
"cycles.preview_adaptive_min_samples",
"cycles.use_preview_denoising",
"cycles.preview_denoiser",
"cycles.preview_denoising_input_passes",
"cycles.preview_denoising_prefilter",
"cycles.preview_denoising_start_sample",
]
preset_subdir = "cycles/viewport_sampling"
classes = (
AddPresetIntegrator,
AddPresetSampling,
AddPresetViewportSampling,
)

View File

@@ -39,11 +39,6 @@ enum_devices = (
('GPU', "GPU Compute", "Use GPU compute device for rendering, configured in the system tab in the user preferences"),
)
from _cycles import with_network
if with_network:
enum_devices += (('NETWORK', "Networked Device", "Use networked device for rendering"),)
del with_network
enum_feature_set = (
('SUPPORTED', "Supported", "Only use finished and supported features"),
('EXPERIMENTAL', "Experimental", "Use experimental and incomplete features that might be broken or change in the future", 'ERROR', 1),
@@ -84,15 +79,6 @@ enum_curve_shape = (
('THICK', "3D Curves", "Render hair as 3D curve, for accurate results when viewing hair close up"),
)
enum_tile_order = (
('CENTER', "Center", "Render from center to the edges"),
('RIGHT_TO_LEFT', "Right to Left", "Render from right to left"),
('LEFT_TO_RIGHT', "Left to Right", "Render from left to right"),
('TOP_TO_BOTTOM', "Top to Bottom", "Render from top to bottom"),
('BOTTOM_TO_TOP', "Bottom to Top", "Render from bottom to top"),
('HILBERT_SPIRAL', "Hilbert Spiral", "Render in a Hilbert Spiral"),
)
enum_use_layer_samples = (
('USE', "Use", "Per render layer number of samples override scene samples"),
('BOUNDED', "Bounded", "Bound per render layer number of samples by global samples"),
@@ -101,15 +87,9 @@ enum_use_layer_samples = (
enum_sampling_pattern = (
('SOBOL', "Sobol", "Use Sobol random sampling pattern"),
('CORRELATED_MUTI_JITTER', "Correlated Multi-Jitter", "Use Correlated Multi-Jitter random sampling pattern"),
('PROGRESSIVE_MUTI_JITTER', "Progressive Multi-Jitter", "Use Progressive Multi-Jitter random sampling pattern"),
)
enum_integrator = (
('BRANCHED_PATH', "Branched Path Tracing", "Path tracing integrator that branches on the first bounce, giving more control over the number of light and material samples"),
('PATH', "Path Tracing", "Pure path tracing integrator"),
)
enum_volume_sampling = (
('DISTANCE', "Distance", "Use distance sampling, best for dense volumes with lights far away"),
('EQUIANGULAR', "Equiangular", "Use equiangular sampling, best for volumes with low density with light inside or near the volume"),
@@ -131,7 +111,7 @@ enum_device_type = (
('CPU', "CPU", "CPU", 0),
('CUDA', "CUDA", "CUDA", 1),
('OPTIX', "OptiX", "OptiX", 3),
('OPENCL', "OpenCL", "OpenCL", 2)
("HIP", "HIP", "HIP", 4)
)
enum_texture_limit = (
@@ -145,38 +125,45 @@ enum_texture_limit = (
('8192', "8192", "Limit texture size to 8192 pixels", 7),
)
# NOTE: Identifiers are expected to be an upper case version of identifiers from `Pass::get_type_enum()`
enum_view3d_shading_render_pass = (
('', "General", ""),
('COMBINED', "Combined", "Show the Combined Render pass", 1),
('EMISSION', "Emission", "Show the Emission render pass", 33),
('BACKGROUND', "Background", "Show the Background render pass", 34),
('AO', "Ambient Occlusion", "Show the Ambient Occlusion render pass", 35),
('COMBINED', "Combined", "Show the Combined Render pass"),
('EMISSION', "Emission", "Show the Emission render pass"),
('BACKGROUND', "Background", "Show the Background render pass"),
('AO', "Ambient Occlusion", "Show the Ambient Occlusion render pass"),
('SHADOW', "Shadow", "Show the Shadow render pass"),
('SHADOW_CATCHER', "Shadow Catcher", "Show the Shadow Catcher render pass"),
('', "Light", ""),
('DIFFUSE_DIRECT', "Diffuse Direct", "Show the Diffuse Direct render pass", 38),
('DIFFUSE_INDIRECT', "Diffuse Indirect", "Show the Diffuse Indirect render pass", 39),
('DIFFUSE_COLOR', "Diffuse Color", "Show the Diffuse Color render pass", 40),
('DIFFUSE_DIRECT', "Diffuse Direct", "Show the Diffuse Direct render pass"),
('DIFFUSE_INDIRECT', "Diffuse Indirect", "Show the Diffuse Indirect render pass"),
('DIFFUSE_COLOR', "Diffuse Color", "Show the Diffuse Color render pass"),
('GLOSSY_DIRECT', "Glossy Direct", "Show the Glossy Direct render pass", 41),
('GLOSSY_INDIRECT', "Glossy Indirect", "Show the Glossy Indirect render pass", 42),
('GLOSSY_COLOR', "Glossy Color", "Show the Glossy Color render pass", 43),
('GLOSSY_DIRECT', "Glossy Direct", "Show the Glossy Direct render pass"),
('GLOSSY_INDIRECT', "Glossy Indirect", "Show the Glossy Indirect render pass"),
('GLOSSY_COLOR', "Glossy Color", "Show the Glossy Color render pass"),
('', "", ""),
('TRANSMISSION_DIRECT', "Transmission Direct", "Show the Transmission Direct render pass", 44),
('TRANSMISSION_INDIRECT', "Transmission Indirect", "Show the Transmission Indirect render pass", 45),
('TRANSMISSION_COLOR', "Transmission Color", "Show the Transmission Color render pass", 46),
('TRANSMISSION_DIRECT', "Transmission Direct", "Show the Transmission Direct render pass"),
('TRANSMISSION_INDIRECT', "Transmission Indirect", "Show the Transmission Indirect render pass"),
('TRANSMISSION_COLOR', "Transmission Color", "Show the Transmission Color render pass"),
('VOLUME_DIRECT', "Volume Direct", "Show the Volume Direct render pass", 50),
('VOLUME_INDIRECT', "Volume Indirect", "Show the Volume Indirect render pass", 51),
('VOLUME_DIRECT', "Volume Direct", "Show the Volume Direct render pass"),
('VOLUME_INDIRECT', "Volume Indirect", "Show the Volume Indirect render pass"),
('', "Data", ""),
('NORMAL', "Normal", "Show the Normal render pass", 3),
('UV', "UV", "Show the UV render pass", 4),
('MIST', "Mist", "Show the Mist render pass", 32),
('POSITION', "Position", "Show the Position render pass"),
('NORMAL', "Normal", "Show the Normal render pass"),
('UV', "UV", "Show the UV render pass"),
('MIST', "Mist", "Show the Mist render pass"),
('DENOISING_ALBEDO', "Denoising Albedo", "Albedo pass used by denoiser"),
('DENOISING_NORMAL', "Denoising Normal", "Normal pass used by denoiser"),
('SAMPLE_COUNT', "Sample Count", "Per-pixel number of samples"),
)
@@ -208,18 +195,23 @@ def enum_preview_denoiser(self, context):
def enum_denoiser(self, context):
items = [('NLM', "NLM", "Cycles native non-local means denoiser, running on any compute device", 1)]
items = []
items += enum_optix_denoiser(self, context)
items += enum_openimagedenoise_denoiser(self, context)
return items
enum_denoising_input_passes = (
('RGB', "Color", "Use only color as input", 1),
('RGB_ALBEDO', "Color + Albedo", "Use color and albedo data as input", 2),
('RGB_ALBEDO_NORMAL', "Color + Albedo + Normal", "Use color, albedo and normal data as input", 3),
('RGB', "None", "Don't use utility passes for denoising", 1),
('RGB_ALBEDO', "Albedo", "Use albedo pass for denoising", 2),
('RGB_ALBEDO_NORMAL', "Albedo and Normal", "Use albedo and normal passes for denoising", 3),
)
enum_denoising_prefilter = (
('NONE', "None", "No prefiltering, use when guiding passes are noise-free", 1),
('FAST', "Fast", "Denoise color and guiding passes together. Improves quality when guiding passes are noisy using least amount of extra processing time", 2),
('ACCURATE', "Accurate", "Prefilter noisy guiding passes before denoising color. Improves quality when guiding passes are noisy using extra processing time", 3),
)
def update_render_passes(self, context):
scene = context.scene
@@ -252,13 +244,6 @@ class CyclesRenderSettings(bpy.types.PropertyGroup):
description="Use Open Shading Language (CPU rendering only)",
)
progressive: EnumProperty(
name="Integrator",
description="Method to sample lights and materials",
items=enum_integrator,
default='PATH',
)
preview_pause: BoolProperty(
name="Pause Preview",
description="Pause all viewport preview renders",
@@ -268,110 +253,88 @@ class CyclesRenderSettings(bpy.types.PropertyGroup):
use_denoising: BoolProperty(
name="Use Denoising",
description="Denoise the rendered image",
default=False,
default=True,
update=update_render_passes,
)
denoiser: EnumProperty(
name="Denoiser",
description="Denoise the image with the selected denoiser. "
"For denoising the image after rendering",
items=enum_denoiser,
default=4, # Use integer to avoid error in builds without OpenImageDenoise.
update=update_render_passes,
)
denoising_prefilter: EnumProperty(
name="Denoising Prefilter",
description="Prefilter noisy guiding (albedo and normal) passes to improve denoising quality when using OpenImageDenoiser",
items=enum_denoising_prefilter,
default='ACCURATE',
)
denoising_input_passes: EnumProperty(
name="Denoising Input Passes",
description="Passes used by the denoiser to distinguish noise from shader and geometry detail",
items=enum_denoising_input_passes,
default='RGB_ALBEDO_NORMAL',
)
use_preview_denoising: BoolProperty(
name="Use Viewport Denoising",
description="Denoise the image in the 3D viewport",
default=False,
)
denoiser: EnumProperty(
name="Denoiser",
description="Denoise the image with the selected denoiser. "
"For denoising the image after rendering, denoising data render passes "
"also adapt to the selected denoiser",
items=enum_denoiser,
default=1,
update=update_render_passes,
)
preview_denoiser: EnumProperty(
name="Viewport Denoiser",
description="Denoise the image after each preview update with the selected denoiser",
items=enum_preview_denoiser,
default=0,
)
use_square_samples: BoolProperty(
name="Square Samples",
description="Square sampling values for easier artist control",
default=False,
preview_denoising_prefilter: EnumProperty(
name="Viewport Denoising Prefilter",
description="Prefilter noisy guiding (albedo and normal) passes to improve denoising quality when using OpenImageDenoiser",
items=enum_denoising_prefilter,
default='FAST',
)
preview_denoising_input_passes: EnumProperty(
name="Viewport Denoising Input Passes",
description="Passes used by the denoiser to distinguish noise from shader and geometry detail",
items=enum_denoising_input_passes,
default='RGB_ALBEDO',
)
preview_denoising_start_sample: IntProperty(
name="Start Denoising",
description="Sample to start denoising the preview at",
min=0, max=(1 << 24),
default=1,
)
samples: IntProperty(
name="Samples",
description="Number of samples to render for each pixel",
min=1, max=(1 << 24),
default=128,
default=4096,
)
preview_samples: IntProperty(
name="Viewport Samples",
description="Number of samples to render in the viewport, unlimited if 0",
min=0, max=(1 << 24),
default=32,
)
aa_samples: IntProperty(
name="AA Samples",
description="Number of antialiasing samples to render for each pixel",
min=1, max=2097151,
default=128,
)
preview_aa_samples: IntProperty(
name="AA Samples",
description="Number of antialiasing samples to render in the viewport, unlimited if 0",
min=0, max=2097151,
default=32,
default=1024,
)
diffuse_samples: IntProperty(
name="Diffuse Samples",
description="Number of diffuse bounce samples to render for each AA sample",
min=1, max=1024,
default=1,
)
glossy_samples: IntProperty(
name="Glossy Samples",
description="Number of glossy bounce samples to render for each AA sample",
min=1, max=1024,
default=1,
)
transmission_samples: IntProperty(
name="Transmission Samples",
description="Number of transmission bounce samples to render for each AA sample",
min=1, max=1024,
default=1,
)
ao_samples: IntProperty(
name="Ambient Occlusion Samples",
description="Number of ambient occlusion samples to render for each AA sample",
min=1, max=1024,
default=1,
)
mesh_light_samples: IntProperty(
name="Mesh Light Samples",
description="Number of mesh emission light samples to render for each AA sample",
min=1, max=1024,
default=1,
)
subsurface_samples: IntProperty(
name="Subsurface Samples",
description="Number of subsurface scattering samples to render for each AA sample",
min=1, max=1024,
default=1,
)
volume_samples: IntProperty(
name="Volume Samples",
description="Number of volume scattering samples to render for each AA sample",
min=1, max=1024,
default=1,
time_limit: FloatProperty(
name="Time Limit",
description="Limit the render time (excluding synchronization time)."
"Zero disables the limit",
min=0.0,
default=0.0,
step=100.0,
unit='TIME_ABSOLUTE',
)
sampling_pattern: EnumProperty(
name="Sampling Pattern",
description="Random sampling pattern used by the integrator",
items=enum_sampling_pattern,
default='SOBOL',
default='PROGRESSIVE_MUTI_JITTER',
)
use_layer_samples: EnumProperty(
@@ -381,17 +344,6 @@ class CyclesRenderSettings(bpy.types.PropertyGroup):
default='USE',
)
sample_all_lights_direct: BoolProperty(
name="Sample All Direct Lights",
description="Sample all lights (for direct samples), rather than randomly picking one",
default=True,
)
sample_all_lights_indirect: BoolProperty(
name="Sample All Indirect Lights",
description="Sample all lights (for indirect samples), rather than randomly picking one",
default=True,
)
light_sampling_threshold: FloatProperty(
name="Light Sampling Threshold",
description="Probabilistically terminate light samples when the light contribution is below this threshold (more noise but faster rendering). "
@@ -403,19 +355,39 @@ class CyclesRenderSettings(bpy.types.PropertyGroup):
use_adaptive_sampling: BoolProperty(
name="Use Adaptive Sampling",
description="Automatically reduce the number of samples per pixel based on estimated noise level",
default=False,
default=True,
)
adaptive_threshold: FloatProperty(
name="Adaptive Sampling Threshold",
description="Noise level step to stop sampling at, lower values reduce noise at the cost of render time. Zero for automatic setting based on number of AA samples",
min=0.0, max=1.0,
default=0.0,
soft_min=0.001,
default=0.01,
precision=4,
)
adaptive_min_samples: IntProperty(
name="Adaptive Min Samples",
description="Minimum AA samples for adaptive sampling, to discover noisy features before stopping sampling. Zero for automatic setting based on number of AA samples",
description="Minimum AA samples for adaptive sampling, to discover noisy features before stopping sampling. Zero for automatic setting based on noise threshold",
min=0, max=4096,
default=0,
)
use_preview_adaptive_sampling: BoolProperty(
name="Use Adaptive Sampling",
description="Automatically reduce the number of samples per pixel based on estimated noise level, for viewport renders",
default=True,
)
preview_adaptive_threshold: FloatProperty(
name="Adaptive Sampling Threshold",
description="Noise level step to stop sampling at, lower values reduce noise at the cost of render time. Zero for automatic setting based on number of AA samples, for viewport renders",
min=0.0, max=1.0,
soft_min=0.001,
default=0.1,
precision=4,
)
preview_adaptive_min_samples: IntProperty(
name="Adaptive Min Samples",
description="Minimum AA samples for adaptive sampling, to discover noisy features before stopping sampling. Zero for automatic setting based on noise threshold, for viewport renders",
min=0, max=4096,
default=0,
)
@@ -632,53 +604,6 @@ class CyclesRenderSettings(bpy.types.PropertyGroup):
default=10.0,
)
debug_tile_size: IntProperty(
name="Tile Size",
description="",
min=1, max=4096,
default=1024,
)
preview_start_resolution: IntProperty(
name="Start Resolution",
description="Resolution to start rendering preview at, "
"progressively increasing it to the full viewport size",
min=8, max=16384,
default=64,
subtype='PIXEL'
)
preview_denoising_start_sample: IntProperty(
name="Start Denoising",
description="Sample to start denoising the preview at",
min=0, max=(1 << 24),
default=1,
)
preview_denoising_input_passes: EnumProperty(
name="Viewport Input Passes",
description="Passes used by the denoiser to distinguish noise from shader and geometry detail",
items=enum_denoising_input_passes,
default='RGB_ALBEDO',
)
debug_reset_timeout: FloatProperty(
name="Reset timeout",
description="",
min=0.01, max=10.0,
default=0.1,
)
debug_cancel_timeout: FloatProperty(
name="Cancel timeout",
description="",
min=0.01, max=10.0,
default=0.1,
)
debug_text_timeout: FloatProperty(
name="Text timeout",
description="",
min=0.01, max=10.0,
default=1.0,
)
debug_bvh_type: EnumProperty(
name="Viewport BVH Type",
description="Choose between faster updates, or faster render",
@@ -701,38 +626,24 @@ class CyclesRenderSettings(bpy.types.PropertyGroup):
default=0,
min=0, max=16,
)
tile_order: EnumProperty(
name="Tile Order",
description="Tile order for rendering",
items=enum_tile_order,
default='HILBERT_SPIRAL',
options=set(), # Not animatable!
)
use_progressive_refine: BoolProperty(
name="Progressive Refine",
description="Instead of rendering each tile until it is finished, "
"refine the whole image progressively "
"(this renders somewhat slower, "
"but time can be saved by manually stopping the render when the noise is low enough)",
default=False,
)
bake_type: EnumProperty(
name="Bake Type",
default='COMBINED',
description="Type of pass to bake",
items=(
('COMBINED', "Combined", ""),
('AO', "Ambient Occlusion", ""),
('SHADOW', "Shadow", ""),
('NORMAL', "Normal", ""),
('UV', "UV", ""),
('ROUGHNESS', "Roughness", ""),
('EMIT', "Emit", ""),
('ENVIRONMENT', "Environment", ""),
('DIFFUSE', "Diffuse", ""),
('GLOSSY', "Glossy", ""),
('TRANSMISSION', "Transmission", ""),
('COMBINED', "Combined", "", 0),
('AO', "Ambient Occlusion", "", 1),
('SHADOW', "Shadow", "", 2),
('POSITION', "Position", "", 11),
('NORMAL', "Normal", "", 3),
('UV', "UV", "", 4),
('ROUGHNESS', "Roughness", "", 5),
('EMIT', "Emit", "", 6),
('ENVIRONMENT', "Environment", "", 7),
('DIFFUSE', "Diffuse", "", 8),
('GLOSSY', "Glossy", "", 9),
('TRANSMISSION', "Transmission", "", 10),
),
)
@@ -827,6 +738,18 @@ class CyclesRenderSettings(bpy.types.PropertyGroup):
min=0, max=1024,
)
use_auto_tile: BoolProperty(
name="Auto Tiles",
description="Automatically render high resolution images in tiles to reduce memory usage, using the specified tile size. Tiles are cached to disk while rendering to save memory",
default=True,
)
tile_size: IntProperty(
name="Tile Size",
default=2048,
description="",
min=8, max=16384,
)
# Various fine-tuning debug flags
def _devices_update_callback(self, context):
@@ -844,45 +767,13 @@ class CyclesRenderSettings(bpy.types.PropertyGroup):
items=enum_bvh_layouts,
default='EMBREE',
)
debug_use_cpu_split_kernel: BoolProperty(name="Split Kernel", default=False)
debug_use_cuda_adaptive_compile: BoolProperty(name="Adaptive Compile", default=False)
debug_use_cuda_split_kernel: BoolProperty(name="Split Kernel", default=False)
debug_optix_cuda_streams: IntProperty(name="CUDA Streams", default=1, min=1)
debug_optix_curves_api: BoolProperty(name="Native OptiX Curve Primitive", default=False)
debug_opencl_kernel_type: EnumProperty(
name="OpenCL Kernel Type",
default='DEFAULT',
items=(
('DEFAULT', "Default", ""),
('MEGA', "Mega", ""),
('SPLIT', "Split", ""),
),
update=CyclesRenderSettings._devices_update_callback
)
debug_opencl_device_type: EnumProperty(
name="OpenCL Device Type",
default='ALL',
items=(
('NONE', "None", ""),
('ALL', "All", ""),
('DEFAULT', "Default", ""),
('CPU', "CPU", ""),
('GPU', "GPU", ""),
('ACCELERATOR', "Accelerator", ""),
),
update=CyclesRenderSettings._devices_update_callback
)
debug_use_opencl_debug: BoolProperty(name="Debug OpenCL", default=False)
debug_opencl_mem_limit: IntProperty(
name="Memory limit",
default=0,
description="Artificial limit on OpenCL memory usage in MB (0 to disable limit)"
debug_use_optix_debug: BoolProperty(
name="OptiX Module Debug",
description="Load OptiX module in debug mode: lower logging verbosity level, enable validations, and lower optimization level",
default=False
)
@classmethod
@@ -1031,12 +922,6 @@ class CyclesLightSettings(bpy.types.PropertyGroup):
description="Light casts shadows",
default=True,
)
samples: IntProperty(
name="Samples",
description="Number of light samples to render for each AA sample",
min=1, max=10000,
default=1,
)
max_bounces: IntProperty(
name="Max Bounces",
description="Maximum number of bounces the light will contribute to the render",
@@ -1084,12 +969,6 @@ class CyclesWorldSettings(bpy.types.PropertyGroup):
min=4, max=8192,
default=1024,
)
samples: IntProperty(
name="Samples",
description="Number of light samples to render for each AA sample",
min=1, max=10000,
default=1,
)
max_bounces: IntProperty(
name="Max Bounces",
description="Maximum number of bounces the background light will contribute to the render",
@@ -1343,91 +1222,25 @@ class CyclesRenderLayerSettings(bpy.types.PropertyGroup):
update=update_render_passes,
)
use_pass_shadow_catcher: BoolProperty(
name="Shadow Catcher",
description="Pass containing shadows and light which is to be multiplied into backdrop",
default=False,
update=update_render_passes,
)
use_denoising: BoolProperty(
name="Use Denoising",
description="Denoise the rendered image",
default=True,
update=update_render_passes,
)
denoising_diffuse_direct: BoolProperty(
name="Diffuse Direct",
description="Denoise the direct diffuse lighting",
default=True,
)
denoising_diffuse_indirect: BoolProperty(
name="Diffuse Indirect",
description="Denoise the indirect diffuse lighting",
default=True,
)
denoising_glossy_direct: BoolProperty(
name="Glossy Direct",
description="Denoise the direct glossy lighting",
default=True,
)
denoising_glossy_indirect: BoolProperty(
name="Glossy Indirect",
description="Denoise the indirect glossy lighting",
default=True,
)
denoising_transmission_direct: BoolProperty(
name="Transmission Direct",
description="Denoise the direct transmission lighting",
default=True,
)
denoising_transmission_indirect: BoolProperty(
name="Transmission Indirect",
description="Denoise the indirect transmission lighting",
default=True,
)
denoising_strength: FloatProperty(
name="Denoising Strength",
description="Controls neighbor pixel weighting for the denoising filter (lower values preserve more detail, but aren't as smooth)",
min=0.0, max=1.0,
default=0.5,
)
denoising_feature_strength: FloatProperty(
name="Denoising Feature Strength",
description="Controls removal of noisy image feature passes (lower values preserve more detail, but aren't as smooth)",
min=0.0, max=1.0,
default=0.5,
)
denoising_radius: IntProperty(
name="Denoising Radius",
description="Size of the image area that's used to denoise a pixel (higher values are smoother, but might lose detail and are slower)",
min=1, max=25,
default=8,
subtype="PIXEL",
)
denoising_relative_pca: BoolProperty(
name="Relative Filter",
description="When removing pixels that don't carry information, use a relative threshold instead of an absolute one (can help to reduce artifacts, but might cause detail loss around edges)",
default=False,
)
denoising_store_passes: BoolProperty(
name="Store Denoising Passes",
description="Store the denoising feature passes and the noisy image. The passes adapt to the denoiser selected for rendering",
default=False,
update=update_render_passes,
)
denoising_neighbor_frames: IntProperty(
name="Neighbor Frames",
description="Number of neighboring frames to use for denoising animations (more frames produce smoother results at the cost of performance)",
min=0, max=7,
default=0,
)
denoising_optix_input_passes: EnumProperty(
name="Input Passes",
description="Passes used by the denoiser to distinguish noise from shader and geometry detail",
items=enum_denoising_input_passes,
default='RGB_ALBEDO',
)
denoising_openimagedenoise_input_passes: EnumProperty(
name="Input Passes",
description="Passes used by the denoiser to distinguish noise from shader and geometry detail",
items=enum_denoising_input_passes,
default='RGB_ALBEDO_NORMAL',
)
@classmethod
def register(cls):
@@ -1454,14 +1267,16 @@ class CyclesPreferences(bpy.types.AddonPreferences):
def get_device_types(self, context):
import _cycles
has_cuda, has_optix, has_opencl = _cycles.get_device_types()
has_cuda, has_optix, has_hip = _cycles.get_device_types()
list = [('NONE', "None", "Don't use compute device", 0)]
if has_cuda:
list.append(('CUDA', "CUDA", "Use CUDA for GPU acceleration", 1))
if has_optix:
list.append(('OPTIX', "OptiX", "Use OptiX for GPU acceleration", 3))
if has_opencl:
list.append(('OPENCL', "OpenCL", "Use OpenCL for GPU acceleration", 2))
if has_hip:
list.append(('HIP', "HIP", "Use HIP for GPU acceleration", 4))
return list
compute_device_type: EnumProperty(
@@ -1486,7 +1301,7 @@ class CyclesPreferences(bpy.types.AddonPreferences):
def update_device_entries(self, device_list):
for device in device_list:
if not device[1] in {'CUDA', 'OPTIX', 'OPENCL', 'CPU'}:
if not device[1] in {'CUDA', 'OPTIX', 'CPU', 'HIP'}:
continue
# Try to find existing Device entry
entry = self.find_existing_device_entry(device)
@@ -1520,22 +1335,23 @@ class CyclesPreferences(bpy.types.AddonPreferences):
elif entry.type == 'CPU':
cpu_devices.append(entry)
# Extend all GPU devices with CPU.
if compute_device_type in {'CUDA', 'OPTIX', 'OPENCL'}:
if compute_device_type != 'CPU' and compute_device_type != 'HIP':
devices.extend(cpu_devices)
return devices
# For backwards compatibility, only returns CUDA and OpenCL but still
# refreshes all devices.
def get_devices(self, compute_device_type=''):
# Refresh device list. This does not happen automatically on Blender
# startup due to unstable OpenCL implementations that can cause crashes.
def refresh_devices(self):
import _cycles
# Ensure `self.devices` is not re-allocated when the second call to
# get_devices_for_type is made, freeing items from the first list.
for device_type in ('CUDA', 'OPTIX', 'OPENCL'):
for device_type in ('CUDA', 'OPTIX', 'HIP'):
self.update_device_entries(_cycles.available_devices(device_type))
cuda_devices = self.get_devices_for_type('CUDA')
opencl_devices = self.get_devices_for_type('OPENCL')
return cuda_devices, opencl_devices
# Deprecated: use refresh_devices instead.
def get_devices(self, compute_device_type=''):
self.refresh_devices()
return None
def get_num_gpu_devices(self):
import _cycles
@@ -1601,6 +1417,10 @@ class CyclesView3DShadingSettings(bpy.types.PropertyGroup):
items=enum_view3d_shading_render_pass,
default='COMBINED',
)
show_active_pixels: BoolProperty(
name="Show Active Pixels",
description="When using adaptive sampling highlight pixels which are being sampled",
)
def register():

View File

@@ -34,6 +34,12 @@ class CYCLES_PT_sampling_presets(PresetPanel, Panel):
preset_add_operator = "render.cycles_sampling_preset_add"
COMPAT_ENGINES = {'CYCLES'}
class CYCLES_PT_viewport_sampling_presets(PresetPanel, Panel):
bl_label = "Viewport Sampling Presets"
preset_subdir = "cycles/viewport_sampling"
preset_operator = "script.execute_preset"
preset_add_operator = "render.cycles_viewport_sampling_preset_add"
COMPAT_ENGINES = {'CYCLES'}
class CYCLES_PT_integrator_presets(PresetPanel, Panel):
bl_label = "Integrator Presets"
@@ -54,6 +60,15 @@ class CyclesButtonsPanel:
return context.engine in cls.COMPAT_ENGINES
class CyclesDebugButtonsPanel(CyclesButtonsPanel):
@classmethod
def poll(cls, context):
prefs = bpy.context.preferences
return (CyclesButtonsPanel.poll(context)
and prefs.experimental.use_cycles_debug
and prefs.view.show_developer_ui)
# Adapt properties editor panel to display in node editor. We have to
# copy the class rather than inherit due to the way bpy registration works.
def node_panel(cls):
@@ -78,30 +93,23 @@ def use_cpu(context):
return (get_device_type(context) == 'NONE' or cscene.device == 'CPU')
def use_opencl(context):
cscene = context.scene.cycles
return (get_device_type(context) == 'OPENCL' and cscene.device == 'GPU')
def use_cuda(context):
cscene = context.scene.cycles
return (get_device_type(context) == 'CUDA' and cscene.device == 'GPU')
def use_hip(context):
cscene = context.scene.cycles
return (get_device_type(context) == 'HIP' and cscene.device == 'GPU')
def use_optix(context):
cscene = context.scene.cycles
return (get_device_type(context) == 'OPTIX' and cscene.device == 'GPU')
def use_branched_path(context):
cscene = context.scene.cycles
return (cscene.progressive == 'BRANCHED_PATH' and not use_optix(context))
def use_sample_all_lights(context):
cscene = context.scene.cycles
@@ -115,55 +123,93 @@ def show_device_active(context):
return context.preferences.addons[__package__].preferences.has_active_device()
def draw_samples_info(layout, context):
cscene = context.scene.cycles
integrator = cscene.progressive
def get_effective_preview_denoiser(context):
scene = context.scene
cscene = scene.cycles
# Calculate sample values
if integrator == 'PATH':
aa = cscene.samples
if cscene.use_square_samples:
aa = aa * aa
else:
aa = cscene.aa_samples
d = cscene.diffuse_samples
g = cscene.glossy_samples
t = cscene.transmission_samples
ao = cscene.ao_samples
ml = cscene.mesh_light_samples
sss = cscene.subsurface_samples
vol = cscene.volume_samples
if cscene.preview_denoiser != "AUTO":
return cscene.preview_denoiser
if cscene.use_square_samples:
aa = aa * aa
d = d * d
g = g * g
t = t * t
ao = ao * ao
ml = ml * ml
sss = sss * sss
vol = vol * vol
if context.preferences.addons[__package__].preferences.get_devices_for_type('OPTIX'):
return 'OPTIX'
return 'OIDN'
# Draw interface
# Do not draw for progressive, when Square Samples are disabled
if use_branched_path(context) or (cscene.use_square_samples and integrator == 'PATH'):
col = layout.column(align=True)
col.scale_y = 0.6
col.label(text="Total Samples:")
col.separator()
if integrator == 'PATH':
col.label(text="%s AA" % aa)
else:
col.label(text="%s AA, %s Diffuse, %s Glossy, %s Transmission" %
(aa, d * aa, g * aa, t * aa))
col.separator()
col.label(text="%s AO, %s Mesh Light, %s Subsurface, %s Volume" %
(ao * aa, ml * aa, sss * aa, vol * aa))
class CYCLES_RENDER_PT_sampling(CyclesButtonsPanel, Panel):
bl_label = "Sampling"
def draw(self, context):
pass
class CYCLES_RENDER_PT_sampling_viewport(CyclesButtonsPanel, Panel):
bl_label = "Viewport"
bl_parent_id = "CYCLES_RENDER_PT_sampling"
def draw_header_preset(self, context):
CYCLES_PT_viewport_sampling_presets.draw_panel_header(self.layout)
def draw(self, context):
layout = self.layout
scene = context.scene
cscene = scene.cycles
layout.use_property_split = True
layout.use_property_decorate = False
heading = layout.column(align=True, heading="Noise Threshold")
row = heading.row(align=True)
row.prop(cscene, "use_preview_adaptive_sampling", text="")
sub = row.row()
sub.active = cscene.use_preview_adaptive_sampling
sub.prop(cscene, "preview_adaptive_threshold", text="")
if cscene.use_preview_adaptive_sampling:
col = layout.column(align=True)
col.prop(cscene, "preview_samples", text=" Max Samples")
col.prop(cscene, "preview_adaptive_min_samples", text="Min Samples")
else:
layout.prop(cscene, "preview_samples", text="Samples")
class CYCLES_RENDER_PT_sampling_viewport_denoise(CyclesButtonsPanel, Panel):
bl_label = "Denoise"
bl_parent_id = 'CYCLES_RENDER_PT_sampling_viewport'
bl_options = {'DEFAULT_CLOSED'}
def draw_header(self, context):
scene = context.scene
cscene = scene.cycles
self.layout.prop(context.scene.cycles, "use_preview_denoising", text="")
def draw(self, context):
layout = self.layout
layout.use_property_split = True
layout.use_property_decorate = False
scene = context.scene
cscene = scene.cycles
col = layout.column()
col.active = cscene.use_preview_denoising
col.prop(cscene, "preview_denoiser", text="Denoiser")
col.prop(cscene, "preview_denoising_input_passes", text="Passes")
effective_preview_denoiser = get_effective_preview_denoiser(context)
if effective_preview_denoiser == 'OPENIMAGEDENOISE':
col.prop(cscene, "preview_denoising_prefilter", text="Prefilter")
col.prop(cscene, "preview_denoising_start_sample", text="Start Sample")
class CYCLES_RENDER_PT_sampling_render(CyclesButtonsPanel, Panel):
bl_label = "Render"
bl_parent_id = "CYCLES_RENDER_PT_sampling"
def draw_header_preset(self, context):
CYCLES_PT_sampling_presets.draw_panel_header(self.layout)
@@ -176,64 +222,32 @@ class CYCLES_RENDER_PT_sampling(CyclesButtonsPanel, Panel):
layout.use_property_split = True
layout.use_property_decorate = False
if not use_optix(context):
layout.prop(cscene, "progressive")
if not use_branched_path(context):
col = layout.column(align=True)
col.prop(cscene, "samples", text="Render")
col.prop(cscene, "preview_samples", text="Viewport")
else:
col = layout.column(align=True)
col.prop(cscene, "aa_samples", text="Render")
col.prop(cscene, "preview_aa_samples", text="Viewport")
if not use_branched_path(context):
draw_samples_info(layout, context)
class CYCLES_RENDER_PT_sampling_sub_samples(CyclesButtonsPanel, Panel):
bl_label = "Sub Samples"
bl_parent_id = "CYCLES_RENDER_PT_sampling"
@classmethod
def poll(cls, context):
return use_branched_path(context)
def draw(self, context):
layout = self.layout
layout.use_property_split = True
layout.use_property_decorate = False
scene = context.scene
cscene = scene.cycles
heading = layout.column(align=True, heading="Noise Threshold")
row = heading.row(align=True)
row.prop(cscene, "use_adaptive_sampling", text="")
sub = row.row()
sub.active = cscene.use_adaptive_sampling
sub.prop(cscene, "adaptive_threshold", text="")
col = layout.column(align=True)
col.prop(cscene, "diffuse_samples", text="Diffuse")
col.prop(cscene, "glossy_samples", text="Glossy")
col.prop(cscene, "transmission_samples", text="Transmission")
col.prop(cscene, "ao_samples", text="AO")
sub = col.row(align=True)
sub.active = use_sample_all_lights(context)
sub.prop(cscene, "mesh_light_samples", text="Mesh Light")
col.prop(cscene, "subsurface_samples", text="Subsurface")
col.prop(cscene, "volume_samples", text="Volume")
draw_samples_info(layout, context)
if cscene.use_adaptive_sampling:
col.prop(cscene, "samples", text=" Max Samples")
col.prop(cscene, "adaptive_min_samples", text="Min Samples")
else:
col.prop(cscene, "samples", text="Samples")
col.prop(cscene, "time_limit")
class CYCLES_RENDER_PT_sampling_adaptive(CyclesButtonsPanel, Panel):
bl_label = "Adaptive Sampling"
bl_parent_id = "CYCLES_RENDER_PT_sampling"
class CYCLES_RENDER_PT_sampling_render_denoise(CyclesButtonsPanel, Panel):
bl_label = "Denoise"
bl_parent_id = 'CYCLES_RENDER_PT_sampling_render'
bl_options = {'DEFAULT_CLOSED'}
def draw_header(self, context):
layout = self.layout
scene = context.scene
cscene = scene.cycles
layout.prop(cscene, "use_adaptive_sampling", text="")
self.layout.prop(context.scene.cycles, "use_denoising", text="")
def draw(self, context):
layout = self.layout
@@ -243,53 +257,12 @@ class CYCLES_RENDER_PT_sampling_adaptive(CyclesButtonsPanel, Panel):
scene = context.scene
cscene = scene.cycles
layout.active = cscene.use_adaptive_sampling
col = layout.column(align=True)
col.prop(cscene, "adaptive_threshold", text="Noise Threshold")
col.prop(cscene, "adaptive_min_samples", text="Min Samples")
class CYCLES_RENDER_PT_sampling_denoising(CyclesButtonsPanel, Panel):
bl_label = "Denoising"
bl_parent_id = "CYCLES_RENDER_PT_sampling"
bl_options = {'DEFAULT_CLOSED'}
def draw(self, context):
layout = self.layout
layout.use_property_split = True
layout.use_property_decorate = False
scene = context.scene
cscene = scene.cycles
heading = layout.column(align=True, heading="Render")
row = heading.row(align=True)
row.prop(cscene, "use_denoising", text="")
sub = row.row()
sub.active = cscene.use_denoising
for view_layer in scene.view_layers:
if view_layer.cycles.denoising_store_passes:
sub.active = True
sub.prop(cscene, "denoiser", text="")
layout.separator()
heading = layout.column(align=False, heading="Viewport")
row = heading.row(align=True)
row.prop(cscene, "use_preview_denoising", text="")
sub = row.row()
sub.active = cscene.use_preview_denoising
sub.prop(cscene, "preview_denoiser", text="")
sub = heading.row(align=True)
sub.active = cscene.use_preview_denoising
sub.prop(cscene, "preview_denoising_start_sample", text="Start Sample")
sub = heading.row(align=True)
sub.active = cscene.use_preview_denoising
sub.prop(cscene, "preview_denoising_input_passes", text="Input Passes")
col = layout.column()
col.active = cscene.use_denoising
col.prop(cscene, "denoiser", text="Denoiser")
col.prop(cscene, "denoising_input_passes", text="Passes")
if cscene.denoiser == 'OPENIMAGEDENOISE':
col.prop(cscene, "denoising_prefilter", text="Prefilter")
class CYCLES_RENDER_PT_sampling_advanced(CyclesButtonsPanel, Panel):
@@ -313,8 +286,6 @@ class CYCLES_RENDER_PT_sampling_advanced(CyclesButtonsPanel, Panel):
col.active = not(cscene.use_adaptive_sampling)
col.prop(cscene, "sampling_pattern", text="Pattern")
layout.prop(cscene, "use_square_samples")
layout.separator()
col = layout.column(align=True)
@@ -322,11 +293,6 @@ class CYCLES_RENDER_PT_sampling_advanced(CyclesButtonsPanel, Panel):
col.prop(cscene, "min_transparent_bounces")
col.prop(cscene, "light_sampling_threshold", text="Light Threshold")
if cscene.progressive != 'PATH' and use_branched_path(context):
col = layout.column(align=True)
col.prop(cscene, "sample_all_lights_direct")
col.prop(cscene, "sample_all_lights_indirect")
for view_layer in scene.view_layers:
if view_layer.samples > 0:
layout.separator()
@@ -334,62 +300,6 @@ class CYCLES_RENDER_PT_sampling_advanced(CyclesButtonsPanel, Panel):
break
class CYCLES_RENDER_PT_sampling_total(CyclesButtonsPanel, Panel):
bl_label = "Total Samples"
bl_parent_id = "CYCLES_RENDER_PT_sampling"
@classmethod
def poll(cls, context):
scene = context.scene
cscene = scene.cycles
if cscene.use_square_samples:
return True
return cscene.progressive != 'PATH' and use_branched_path(context)
def draw(self, context):
layout = self.layout
cscene = context.scene.cycles
integrator = cscene.progressive
# Calculate sample values
if integrator == 'PATH':
aa = cscene.samples
if cscene.use_square_samples:
aa = aa * aa
else:
aa = cscene.aa_samples
d = cscene.diffuse_samples
g = cscene.glossy_samples
t = cscene.transmission_samples
ao = cscene.ao_samples
ml = cscene.mesh_light_samples
sss = cscene.subsurface_samples
vol = cscene.volume_samples
if cscene.use_square_samples:
aa = aa * aa
d = d * d
g = g * g
t = t * t
ao = ao * ao
ml = ml * ml
sss = sss * sss
vol = vol * vol
col = layout.column(align=True)
col.scale_y = 0.6
if integrator == 'PATH':
col.label(text="%s AA" % aa)
else:
col.label(text="%s AA, %s Diffuse, %s Glossy, %s Transmission" %
(aa, d * aa, g * aa, t * aa))
col.separator()
col.label(text="%s AO, %s Mesh Light, %s Subsurface, %s Volume" %
(ao * aa, ml * aa, sss * aa, vol * aa))
class CYCLES_RENDER_PT_subdivision(CyclesButtonsPanel, Panel):
bl_label = "Subdivision"
bl_options = {'DEFAULT_CLOSED'}
@@ -548,6 +458,8 @@ class CYCLES_RENDER_PT_light_paths_fast_gi(CyclesButtonsPanel, Panel):
layout.use_property_split = True
layout.use_property_decorate = False
layout.active = cscene.use_fast_gi
col = layout.column(align=True)
col.prop(cscene, "ao_bounces", text="Viewport Bounces")
col.prop(cscene, "ao_bounces_render", text="Render Bounces")
@@ -706,8 +618,8 @@ class CYCLES_RENDER_PT_performance_threads(CyclesButtonsPanel, Panel):
sub.prop(rd, "threads")
class CYCLES_RENDER_PT_performance_tiles(CyclesButtonsPanel, Panel):
bl_label = "Tiles"
class CYCLES_RENDER_PT_performance_memory(CyclesButtonsPanel, Panel):
bl_label = "Memory"
bl_parent_id = "CYCLES_RENDER_PT_performance"
def draw(self, context):
@@ -716,19 +628,13 @@ class CYCLES_RENDER_PT_performance_tiles(CyclesButtonsPanel, Panel):
layout.use_property_decorate = False
scene = context.scene
rd = scene.render
cscene = scene.cycles
col = layout.column()
sub = col.column(align=True)
sub.prop(rd, "tile_x", text="Tiles X")
sub.prop(rd, "tile_y", text="Y")
col.prop(cscene, "tile_order", text="Order")
col.prop(cscene, "use_auto_tile")
sub = col.column()
sub.active = not rd.use_save_buffers and not cscene.use_adaptive_sampling
sub.prop(cscene, "use_progressive_refine")
sub.active = cscene.use_auto_tile
sub.prop(cscene, "tile_size")
class CYCLES_RENDER_PT_performance_acceleration_structure(CyclesButtonsPanel, Panel):
@@ -778,7 +684,6 @@ class CYCLES_RENDER_PT_performance_final_render(CyclesButtonsPanel, Panel):
col = layout.column()
col.prop(rd, "use_save_buffers")
col.prop(rd, "use_persistent_data", text="Persistent Data")
@@ -797,7 +702,6 @@ class CYCLES_RENDER_PT_performance_viewport(CyclesButtonsPanel, Panel):
col = layout.column()
col.prop(rd, "preview_pixel_size", text="Pixel Size")
col.prop(cscene, "preview_start_resolution", text="Start Pixels")
class CYCLES_RENDER_PT_filter(CyclesButtonsPanel, Panel):
@@ -818,7 +722,6 @@ class CYCLES_RENDER_PT_filter(CyclesButtonsPanel, Panel):
col = layout.column(heading="Include")
col.prop(view_layer, "use_sky", text="Environment")
col.prop(view_layer, "use_ao", text="Ambient Occlusion")
col.prop(view_layer, "use_solid", text="Surfaces")
col.prop(view_layer, "use_strand", text="Hair")
col.prop(view_layer, "use_volumes", text="Volumes")
@@ -827,6 +730,9 @@ class CYCLES_RENDER_PT_filter(CyclesButtonsPanel, Panel):
sub = col.row()
sub.prop(view_layer, "use_motion_blur", text="Motion Blur")
sub.active = rd.use_motion_blur
sub = col.row()
sub.prop(view_layer.cycles, 'use_denoising', text='Denoising')
sub.active = scene.cycles.use_denoising
class CYCLES_RENDER_PT_override(CyclesButtonsPanel, Panel):
@@ -872,6 +778,7 @@ class CYCLES_RENDER_PT_passes_data(CyclesButtonsPanel, Panel):
col.prop(view_layer, "use_pass_combined")
col.prop(view_layer, "use_pass_z")
col.prop(view_layer, "use_pass_mist")
col.prop(view_layer, "use_pass_position")
col.prop(view_layer, "use_pass_normal")
sub = col.column()
sub.active = not rd.use_motion_blur
@@ -928,6 +835,7 @@ class CYCLES_RENDER_PT_passes_light(CyclesButtonsPanel, Panel):
col.prop(view_layer, "use_pass_environment")
col.prop(view_layer, "use_pass_shadow")
col.prop(view_layer, "use_pass_ambient_occlusion", text="Ambient Occlusion")
col.prop(cycles_view_layer, "use_pass_shadow_catcher")
class CYCLES_RENDER_PT_passes_crypto(CyclesButtonsPanel, ViewLayerCryptomattePanel, Panel):
@@ -942,70 +850,6 @@ class CYCLES_RENDER_PT_passes_aov(CyclesButtonsPanel, ViewLayerAOVPanel):
bl_parent_id = "CYCLES_RENDER_PT_passes"
class CYCLES_RENDER_PT_denoising(CyclesButtonsPanel, Panel):
bl_label = "Denoising"
bl_context = "view_layer"
bl_options = {'DEFAULT_CLOSED'}
@classmethod
def poll(cls, context):
cscene = context.scene.cycles
return CyclesButtonsPanel.poll(context) and cscene.use_denoising
def draw_header(self, context):
scene = context.scene
view_layer = context.view_layer
cycles_view_layer = view_layer.cycles
layout = self.layout
layout.prop(cycles_view_layer, "use_denoising", text="")
def draw(self, context):
layout = self.layout
layout.use_property_split = True
layout.use_property_decorate = False
scene = context.scene
view_layer = context.view_layer
cycles_view_layer = view_layer.cycles
denoiser = scene.cycles.denoiser
layout.active = denoiser != 'NONE' and cycles_view_layer.use_denoising
col = layout.column()
if denoiser == 'OPTIX':
col.prop(cycles_view_layer, "denoising_optix_input_passes")
return
elif denoiser == 'OPENIMAGEDENOISE':
col.prop(cycles_view_layer, "denoising_openimagedenoise_input_passes")
return
col.prop(cycles_view_layer, "denoising_radius", text="Radius")
col = layout.column()
col.prop(cycles_view_layer, "denoising_strength", slider=True, text="Strength")
col.prop(cycles_view_layer, "denoising_feature_strength", slider=True, text="Feature Strength")
col.prop(cycles_view_layer, "denoising_relative_pca")
layout.separator()
col = layout.column()
col.active = cycles_view_layer.use_denoising or cycles_view_layer.denoising_store_passes
row = col.row(heading="Diffuse", align=True)
row.prop(cycles_view_layer, "denoising_diffuse_direct", text="Direct", toggle=True)
row.prop(cycles_view_layer, "denoising_diffuse_indirect", text="Indirect", toggle=True)
row = col.row(heading="Glossy", align=True)
row.prop(cycles_view_layer, "denoising_glossy_direct", text="Direct", toggle=True)
row.prop(cycles_view_layer, "denoising_glossy_indirect", text="Indirect", toggle=True)
row = col.row(heading="Transmission", align=True)
row.prop(cycles_view_layer, "denoising_transmission_direct", text="Direct", toggle=True)
row.prop(cycles_view_layer, "denoising_transmission_indirect", text="Indirect", toggle=True)
class CYCLES_PT_post_processing(CyclesButtonsPanel, Panel):
bl_label = "Post Processing"
bl_options = {'DEFAULT_CLOSED'}
@@ -1417,10 +1261,6 @@ class CYCLES_LIGHT_PT_light(CyclesButtonsPanel, Panel):
if not (light.type == 'AREA' and clamp.is_portal):
sub = col.column()
if use_branched_path(context):
subsub = sub.row(align=True)
subsub.active = use_sample_all_lights(context)
subsub.prop(clamp, "samples")
sub.prop(clamp, "max_bounces")
sub = col.column(align=True)
@@ -1526,34 +1366,6 @@ class CYCLES_WORLD_PT_volume(CyclesButtonsPanel, Panel):
panel_node_draw(layout, world, 'OUTPUT_WORLD', 'Volume')
class CYCLES_WORLD_PT_ambient_occlusion(CyclesButtonsPanel, Panel):
bl_label = "Ambient Occlusion"
bl_context = "world"
bl_options = {'DEFAULT_CLOSED'}
@classmethod
def poll(cls, context):
return context.world and CyclesButtonsPanel.poll(context)
def draw_header(self, context):
light = context.world.light_settings
self.layout.prop(light, "use_ambient_occlusion", text="")
def draw(self, context):
layout = self.layout
layout.use_property_split = True
layout.use_property_decorate = False
light = context.world.light_settings
scene = context.scene
col = layout.column()
sub = col.column()
sub.active = light.use_ambient_occlusion or scene.render.use_simplify
sub.prop(light, "ao_factor", text="Factor")
col.prop(light, "distance", text="Distance")
class CYCLES_WORLD_PT_mist(CyclesButtonsPanel, Panel):
bl_label = "Mist Pass"
bl_context = "world"
@@ -1650,10 +1462,6 @@ class CYCLES_WORLD_PT_settings_surface(CyclesButtonsPanel, Panel):
subsub = sub.row(align=True)
subsub.active = cworld.sampling_method == 'MANUAL'
subsub.prop(cworld, "sample_map_resolution")
if use_branched_path(context):
subsub = sub.column(align=True)
subsub.active = use_sample_all_lights(context)
subsub.prop(cworld, "samples")
sub.prop(cworld, "max_bounces")
@@ -1677,8 +1485,7 @@ class CYCLES_WORLD_PT_settings_volume(CyclesButtonsPanel, Panel):
col = layout.column()
sub = col.column()
sub.active = use_cpu(context)
sub.prop(cworld, "volume_sampling", text="Sampling")
col.prop(cworld, "volume_sampling", text="Sampling")
col.prop(cworld, "volume_interpolation", text="Interpolation")
col.prop(cworld, "homogeneous_volume", text="Homogeneous")
sub = col.column()
@@ -1817,8 +1624,7 @@ class CYCLES_MATERIAL_PT_settings_volume(CyclesButtonsPanel, Panel):
col = layout.column()
sub = col.column()
sub.active = use_cpu(context)
sub.prop(cmat, "volume_sampling", text="Sampling")
col.prop(cmat, "volume_sampling", text="Sampling")
col.prop(cmat, "volume_interpolation", text="Interpolation")
col.prop(cmat, "homogeneous_volume", text="Homogeneous")
sub = col.column()
@@ -1845,9 +1651,6 @@ class CYCLES_RENDER_PT_bake(CyclesButtonsPanel, Panel):
cbk = scene.render.bake
rd = scene.render
if use_optix(context):
layout.label(text="Baking is performed using CUDA instead of OptiX", icon='INFO')
if rd.use_bake_multires:
layout.operator("object.bake_image", icon='RENDER_STILL')
layout.prop(rd, "use_bake_multires")
@@ -1905,7 +1708,6 @@ class CYCLES_RENDER_PT_bake_influence(CyclesButtonsPanel, Panel):
col.prop(cbk, "use_pass_diffuse")
col.prop(cbk, "use_pass_glossy")
col.prop(cbk, "use_pass_transmission")
col.prop(cbk, "use_pass_ambient_occlusion")
col.prop(cbk, "use_pass_emit")
elif cscene.bake_type in {'DIFFUSE', 'GLOSSY', 'TRANSMISSION'}:
@@ -1989,19 +1791,12 @@ class CYCLES_RENDER_PT_bake_output(CyclesButtonsPanel, Panel):
layout.prop(cbk, "use_clear", text="Clear Image")
class CYCLES_RENDER_PT_debug(CyclesButtonsPanel, Panel):
class CYCLES_RENDER_PT_debug(CyclesDebugButtonsPanel, Panel):
bl_label = "Debug"
bl_context = "render"
bl_options = {'DEFAULT_CLOSED'}
COMPAT_ENGINES = {'CYCLES'}
@classmethod
def poll(cls, context):
prefs = bpy.context.preferences
return (CyclesButtonsPanel.poll(context)
and prefs.experimental.use_cycles_debug
and prefs.view.show_developer_ui)
def draw(self, context):
layout = self.layout
@@ -2018,29 +1813,18 @@ class CYCLES_RENDER_PT_debug(CyclesButtonsPanel, Panel):
row.prop(cscene, "debug_use_cpu_avx", toggle=True)
row.prop(cscene, "debug_use_cpu_avx2", toggle=True)
col.prop(cscene, "debug_bvh_layout")
col.prop(cscene, "debug_use_cpu_split_kernel")
col.separator()
col = layout.column()
col.label(text="CUDA Flags:")
col.prop(cscene, "debug_use_cuda_adaptive_compile")
col.prop(cscene, "debug_use_cuda_split_kernel")
col.separator()
col = layout.column()
col.label(text="OptiX Flags:")
col.prop(cscene, "debug_optix_cuda_streams")
col.prop(cscene, "debug_optix_curves_api")
col.separator()
col = layout.column()
col.label(text="OpenCL Flags:")
col.prop(cscene, "debug_opencl_device_type", text="Device")
col.prop(cscene, "debug_use_opencl_debug", text="Debug")
col.prop(cscene, "debug_opencl_mem_limit")
col.prop(cscene, "debug_use_optix_debug")
col.separator()
@@ -2141,20 +1925,22 @@ class CYCLES_RENDER_PT_simplify_culling(CyclesButtonsPanel, Panel):
sub.prop(cscene, "distance_cull_margin", text="")
class CYCLES_VIEW3D_PT_shading_render_pass(Panel):
class CyclesShadingButtonsPanel(CyclesButtonsPanel):
bl_space_type = 'VIEW_3D'
bl_region_type = 'HEADER'
bl_label = "Render Pass"
bl_parent_id = 'VIEW3D_PT_shading'
COMPAT_ENGINES = {'CYCLES'}
@classmethod
def poll(cls, context):
return (
context.engine in cls.COMPAT_ENGINES and
CyclesButtonsPanel.poll(context) and
context.space_data.shading.type == 'RENDERED'
)
class CYCLES_VIEW3D_PT_shading_render_pass(CyclesShadingButtonsPanel, Panel):
bl_label = "Render Pass"
def draw(self, context):
shading = context.space_data.shading
@@ -2162,6 +1948,26 @@ class CYCLES_VIEW3D_PT_shading_render_pass(Panel):
layout.prop(shading.cycles, "render_pass", text="")
class CYCLES_VIEW3D_PT_shading_debug(CyclesDebugButtonsPanel,
CyclesShadingButtonsPanel,
Panel):
bl_label = "Debug"
@classmethod
def poll(cls, context):
return (
CyclesDebugButtonsPanel.poll(context) and
CyclesShadingButtonsPanel.poll(context)
)
def draw(self, context):
shading = context.space_data.shading
layout = self.layout
layout.active = context.scene.cycles.use_preview_adaptive_sampling
layout.prop(shading.cycles, "show_active_pixels")
class CYCLES_VIEW3D_PT_shading_lighting(Panel):
bl_space_type = 'VIEW_3D'
bl_region_type = 'HEADER'
@@ -2275,11 +2081,13 @@ def get_panels():
classes = (
CYCLES_PT_sampling_presets,
CYCLES_PT_viewport_sampling_presets,
CYCLES_PT_integrator_presets,
CYCLES_RENDER_PT_sampling,
CYCLES_RENDER_PT_sampling_sub_samples,
CYCLES_RENDER_PT_sampling_adaptive,
CYCLES_RENDER_PT_sampling_denoising,
CYCLES_RENDER_PT_sampling_viewport,
CYCLES_RENDER_PT_sampling_viewport_denoise,
CYCLES_RENDER_PT_sampling_render,
CYCLES_RENDER_PT_sampling_render_denoise,
CYCLES_RENDER_PT_sampling_advanced,
CYCLES_RENDER_PT_light_paths,
CYCLES_RENDER_PT_light_paths_max_bounces,
@@ -2296,6 +2104,7 @@ classes = (
CYCLES_VIEW3D_PT_simplify_greasepencil,
CYCLES_VIEW3D_PT_shading_lighting,
CYCLES_VIEW3D_PT_shading_render_pass,
CYCLES_VIEW3D_PT_shading_debug,
CYCLES_RENDER_PT_motion_blur,
CYCLES_RENDER_PT_motion_blur_curve,
CYCLES_RENDER_PT_film,
@@ -2303,7 +2112,7 @@ classes = (
CYCLES_RENDER_PT_film_transparency,
CYCLES_RENDER_PT_performance,
CYCLES_RENDER_PT_performance_threads,
CYCLES_RENDER_PT_performance_tiles,
CYCLES_RENDER_PT_performance_memory,
CYCLES_RENDER_PT_performance_acceleration_structure,
CYCLES_RENDER_PT_performance_final_render,
CYCLES_RENDER_PT_performance_viewport,
@@ -2314,7 +2123,6 @@ classes = (
CYCLES_RENDER_PT_passes_aov,
CYCLES_RENDER_PT_filter,
CYCLES_RENDER_PT_override,
CYCLES_RENDER_PT_denoising,
CYCLES_PT_post_processing,
CYCLES_CAMERA_PT_dof,
CYCLES_CAMERA_PT_dof_aperture,
@@ -2333,7 +2141,6 @@ classes = (
CYCLES_WORLD_PT_preview,
CYCLES_WORLD_PT_surface,
CYCLES_WORLD_PT_volume,
CYCLES_WORLD_PT_ambient_occlusion,
CYCLES_WORLD_PT_mist,
CYCLES_WORLD_PT_ray_visibility,
CYCLES_WORLD_PT_settings,

View File

@@ -109,7 +109,7 @@ def do_versions(self):
library_versions.setdefault(library.version, []).append(library)
# Do versioning per library, since they might have different versions.
max_need_versioning = (2, 93, 7)
max_need_versioning = (3, 0, 25)
for version, libraries in library_versions.items():
if version > max_need_versioning:
continue
@@ -166,10 +166,6 @@ def do_versions(self):
if not cscene.is_property_set("filter_type"):
cscene.pixel_filter_type = 'GAUSSIAN'
# Tile Order
if not cscene.is_property_set("tile_order"):
cscene.tile_order = 'CENTER'
if version <= (2, 76, 10):
cscene = scene.cycles
if cscene.is_property_set("filter_type"):
@@ -186,10 +182,6 @@ def do_versions(self):
if version <= (2, 79, 0):
cscene = scene.cycles
# Default changes
if not cscene.is_property_set("aa_samples"):
cscene.aa_samples = 4
if not cscene.is_property_set("preview_aa_samples"):
cscene.preview_aa_samples = 4
if not cscene.is_property_set("blur_glossy"):
cscene.blur_glossy = 0.0
if not cscene.is_property_set("sample_clamp_indirect"):
@@ -203,7 +195,6 @@ def do_versions(self):
view_layer.use_pass_cryptomatte_material = cview_layer.get("use_pass_crypto_material", False)
view_layer.use_pass_cryptomatte_asset = cview_layer.get("use_pass_crypto_asset", False)
view_layer.pass_cryptomatte_depth = cview_layer.get("pass_crypto_depth", 6)
view_layer.use_pass_cryptomatte_accurate = cview_layer.get("pass_crypto_accurate", True)
if version <= (2, 93, 7):
if scene.render.engine == 'CYCLES':
@@ -229,6 +220,35 @@ def do_versions(self):
cscene.ao_bounces = 1
cscene.ao_bounces_render = 1
if version <= (3, 0, 25):
cscene = scene.cycles
# Default changes.
if not cscene.is_property_set("samples"):
cscene.samples = 128
if not cscene.is_property_set("preview_samples"):
cscene.preview_samples = 32
if not cscene.is_property_set("use_adaptive_sampling"):
cscene.use_adaptive_sampling = False
cscene.use_preview_adaptive_sampling = False
if not cscene.is_property_set("use_denoising"):
cscene.use_denoising = False
if not cscene.is_property_set("use_preview_denoising"):
cscene.use_preview_denoising = False
if not cscene.is_property_set("sampling_pattern"):
cscene.sampling_pattern = 'PROGRESSIVE_MUTI_JITTER'
# Removal of square samples.
cscene = scene.cycles
use_square_samples = cscene.get("use_square_samples", False)
if use_square_samples:
cscene.samples *= cscene.samples
cscene.preview_samples *= cscene.preview_samples
for layer in scene.view_layers:
layer.samples *= layer.samples
cscene["use_square_samples"] = False
# Lamps
for light in bpy.data.lights:
if light.library not in libraries:
@@ -249,10 +269,6 @@ def do_versions(self):
if version <= (2, 76, 9):
cworld = world.cycles
# World MIS Samples
if not cworld.is_property_set("samples"):
cworld.samples = 4
# World MIS Resolution
if not cworld.is_property_set("sample_map_resolution"):
cworld.sample_map_resolution = 256

View File

@@ -894,12 +894,8 @@ void BlenderSync::sync_view(BL::SpaceView3D &b_v3d,
}
}
BufferParams BlenderSync::get_buffer_params(BL::SpaceView3D &b_v3d,
BL::RegionView3D &b_rv3d,
Camera *cam,
int width,
int height,
const bool use_denoiser)
BufferParams BlenderSync::get_buffer_params(
BL::SpaceView3D &b_v3d, BL::RegionView3D &b_rv3d, Camera *cam, int width, int height)
{
BufferParams params;
bool use_border = false;
@@ -931,11 +927,6 @@ BufferParams BlenderSync::get_buffer_params(BL::SpaceView3D &b_v3d,
params.height = height;
}
PassType display_pass = update_viewport_display_passes(b_v3d, params.passes);
/* Can only denoise the combined image pass */
params.denoising_data_pass = display_pass == PASS_COMBINED && use_denoiser;
return params;
}

View File

@@ -283,10 +283,13 @@ static void ExportCurveSegments(Scene *scene, Hair *hair, ParticleCurveData *CDa
return;
Attribute *attr_intercept = NULL;
Attribute *attr_length = NULL;
Attribute *attr_random = NULL;
if (hair->need_attribute(scene, ATTR_STD_CURVE_INTERCEPT))
attr_intercept = hair->attributes.add(ATTR_STD_CURVE_INTERCEPT);
if (hair->need_attribute(scene, ATTR_STD_CURVE_LENGTH))
attr_length = hair->attributes.add(ATTR_STD_CURVE_LENGTH);
if (hair->need_attribute(scene, ATTR_STD_CURVE_RANDOM))
attr_random = hair->attributes.add(ATTR_STD_CURVE_RANDOM);
@@ -336,6 +339,10 @@ static void ExportCurveSegments(Scene *scene, Hair *hair, ParticleCurveData *CDa
num_curve_keys++;
}
if (attr_length != NULL) {
attr_length->add(CData->curve_length[curve]);
}
if (attr_random != NULL) {
attr_random->add(hash_uint2_to_float(num_curves, 0));
}
@@ -657,11 +664,15 @@ static void export_hair_curves(Scene *scene, Hair *hair, BL::Hair b_hair)
/* Add requested attributes. */
Attribute *attr_intercept = NULL;
Attribute *attr_length = NULL;
Attribute *attr_random = NULL;
if (hair->need_attribute(scene, ATTR_STD_CURVE_INTERCEPT)) {
attr_intercept = hair->attributes.add(ATTR_STD_CURVE_INTERCEPT);
}
if (hair->need_attribute(scene, ATTR_STD_CURVE_LENGTH)) {
attr_length = hair->attributes.add(ATTR_STD_CURVE_LENGTH);
}
if (hair->need_attribute(scene, ATTR_STD_CURVE_RANDOM)) {
attr_random = hair->attributes.add(ATTR_STD_CURVE_RANDOM);
}
@@ -714,6 +725,10 @@ static void export_hair_curves(Scene *scene, Hair *hair, BL::Hair b_hair)
}
}
if (attr_length) {
attr_length->add(length);
}
/* Random number per curve. */
if (attr_random != NULL) {
attr_random->add(hash_uint2_to_float(b_curve.index(), 0));

View File

@@ -25,8 +25,8 @@ CCL_NAMESPACE_BEGIN
enum ComputeDevice {
COMPUTE_DEVICE_CPU = 0,
COMPUTE_DEVICE_CUDA = 1,
COMPUTE_DEVICE_OPENCL = 2,
COMPUTE_DEVICE_OPTIX = 3,
COMPUTE_DEVICE_HIP = 4,
COMPUTE_DEVICE_NUM
};
@@ -68,13 +68,6 @@ DeviceInfo blender_device_info(BL::Preferences &b_preferences, BL::Scene &b_scen
device = Device::get_multi_device(devices, threads, background);
}
}
else if (get_enum(cscene, "device") == 2) {
/* Find network device. */
vector<DeviceInfo> devices = Device::available_devices(DEVICE_MASK_NETWORK);
if (!devices.empty()) {
device = devices.front();
}
}
else if (get_enum(cscene, "device") == 1) {
/* Test if we are using GPU devices. */
ComputeDevice compute_device = (ComputeDevice)get_enum(
@@ -89,8 +82,8 @@ DeviceInfo blender_device_info(BL::Preferences &b_preferences, BL::Scene &b_scen
else if (compute_device == COMPUTE_DEVICE_OPTIX) {
mask |= DEVICE_MASK_OPTIX;
}
else if (compute_device == COMPUTE_DEVICE_OPENCL) {
mask |= DEVICE_MASK_OPENCL;
else if (compute_device == COMPUTE_DEVICE_HIP) {
mask |= DEVICE_MASK_HIP;
}
vector<DeviceInfo> devices = Device::available_devices(mask);

View File

@@ -0,0 +1,754 @@
/*
* Copyright 2021 Blender Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "blender/blender_display_driver.h"
#include "device/device.h"
#include "util/util_logging.h"
#include "util/util_opengl.h"
extern "C" {
struct RenderEngine;
bool RE_engine_has_render_context(struct RenderEngine *engine);
void RE_engine_render_context_enable(struct RenderEngine *engine);
void RE_engine_render_context_disable(struct RenderEngine *engine);
bool DRW_opengl_context_release();
void DRW_opengl_context_activate(bool drw_state);
void *WM_opengl_context_create();
void WM_opengl_context_activate(void *gl_context);
void WM_opengl_context_dispose(void *gl_context);
void WM_opengl_context_release(void *context);
}
CCL_NAMESPACE_BEGIN
/* --------------------------------------------------------------------
* BlenderDisplayShader.
*/
unique_ptr<BlenderDisplayShader> BlenderDisplayShader::create(BL::RenderEngine &b_engine,
BL::Scene &b_scene)
{
if (b_engine.support_display_space_shader(b_scene)) {
return make_unique<BlenderDisplaySpaceShader>(b_engine, b_scene);
}
return make_unique<BlenderFallbackDisplayShader>();
}
int BlenderDisplayShader::get_position_attrib_location()
{
if (position_attribute_location_ == -1) {
const uint shader_program = get_shader_program();
position_attribute_location_ = glGetAttribLocation(shader_program, position_attribute_name);
}
return position_attribute_location_;
}
int BlenderDisplayShader::get_tex_coord_attrib_location()
{
if (tex_coord_attribute_location_ == -1) {
const uint shader_program = get_shader_program();
tex_coord_attribute_location_ = glGetAttribLocation(shader_program, tex_coord_attribute_name);
}
return tex_coord_attribute_location_;
}
/* --------------------------------------------------------------------
* BlenderFallbackDisplayShader.
*/
/* TODO move shaders to standalone .glsl file. */
static const char *FALLBACK_VERTEX_SHADER =
"#version 330\n"
"uniform vec2 fullscreen;\n"
"in vec2 texCoord;\n"
"in vec2 pos;\n"
"out vec2 texCoord_interp;\n"
"\n"
"vec2 normalize_coordinates()\n"
"{\n"
" return (vec2(2.0) * (pos / fullscreen)) - vec2(1.0);\n"
"}\n"
"\n"
"void main()\n"
"{\n"
" gl_Position = vec4(normalize_coordinates(), 0.0, 1.0);\n"
" texCoord_interp = texCoord;\n"
"}\n\0";
static const char *FALLBACK_FRAGMENT_SHADER =
"#version 330\n"
"uniform sampler2D image_texture;\n"
"in vec2 texCoord_interp;\n"
"out vec4 fragColor;\n"
"\n"
"void main()\n"
"{\n"
" fragColor = texture(image_texture, texCoord_interp);\n"
"}\n\0";
static void shader_print_errors(const char *task, const char *log, const char *code)
{
LOG(ERROR) << "Shader: " << task << " error:";
LOG(ERROR) << "===== shader string ====";
stringstream stream(code);
string partial;
int line = 1;
while (getline(stream, partial, '\n')) {
if (line < 10) {
LOG(ERROR) << " " << line << " " << partial;
}
else {
LOG(ERROR) << line << " " << partial;
}
line++;
}
LOG(ERROR) << log;
}
static int compile_fallback_shader(void)
{
const struct Shader {
const char *source;
const GLenum type;
} shaders[2] = {{FALLBACK_VERTEX_SHADER, GL_VERTEX_SHADER},
{FALLBACK_FRAGMENT_SHADER, GL_FRAGMENT_SHADER}};
const GLuint program = glCreateProgram();
for (int i = 0; i < 2; i++) {
const GLuint shader = glCreateShader(shaders[i].type);
string source_str = shaders[i].source;
const char *c_str = source_str.c_str();
glShaderSource(shader, 1, &c_str, NULL);
glCompileShader(shader);
GLint compile_status;
glGetShaderiv(shader, GL_COMPILE_STATUS, &compile_status);
if (!compile_status) {
GLchar log[5000];
GLsizei length = 0;
glGetShaderInfoLog(shader, sizeof(log), &length, log);
shader_print_errors("compile", log, c_str);
return 0;
}
glAttachShader(program, shader);
}
/* Link output. */
glBindFragDataLocation(program, 0, "fragColor");
/* Link and error check. */
glLinkProgram(program);
/* TODO(sergey): Find a way to nicely de-duplicate the error checking. */
GLint link_status;
glGetProgramiv(program, GL_LINK_STATUS, &link_status);
if (!link_status) {
GLchar log[5000];
GLsizei length = 0;
/* TODO(sergey): Is it really program passed to glGetShaderInfoLog? */
glGetShaderInfoLog(program, sizeof(log), &length, log);
shader_print_errors("linking", log, FALLBACK_VERTEX_SHADER);
shader_print_errors("linking", log, FALLBACK_FRAGMENT_SHADER);
return 0;
}
return program;
}
void BlenderFallbackDisplayShader::bind(int width, int height)
{
create_shader_if_needed();
if (!shader_program_) {
return;
}
glUseProgram(shader_program_);
glUniform1i(image_texture_location_, 0);
glUniform2f(fullscreen_location_, width, height);
}
void BlenderFallbackDisplayShader::unbind()
{
}
uint BlenderFallbackDisplayShader::get_shader_program()
{
return shader_program_;
}
void BlenderFallbackDisplayShader::create_shader_if_needed()
{
if (shader_program_ || shader_compile_attempted_) {
return;
}
shader_compile_attempted_ = true;
shader_program_ = compile_fallback_shader();
if (!shader_program_) {
return;
}
glUseProgram(shader_program_);
image_texture_location_ = glGetUniformLocation(shader_program_, "image_texture");
if (image_texture_location_ < 0) {
LOG(ERROR) << "Shader doesn't contain the 'image_texture' uniform.";
destroy_shader();
return;
}
fullscreen_location_ = glGetUniformLocation(shader_program_, "fullscreen");
if (fullscreen_location_ < 0) {
LOG(ERROR) << "Shader doesn't contain the 'fullscreen' uniform.";
destroy_shader();
return;
}
}
void BlenderFallbackDisplayShader::destroy_shader()
{
glDeleteProgram(shader_program_);
shader_program_ = 0;
}
/* --------------------------------------------------------------------
* BlenderDisplaySpaceShader.
*/
BlenderDisplaySpaceShader::BlenderDisplaySpaceShader(BL::RenderEngine &b_engine,
BL::Scene &b_scene)
: b_engine_(b_engine), b_scene_(b_scene)
{
DCHECK(b_engine_.support_display_space_shader(b_scene_));
}
void BlenderDisplaySpaceShader::bind(int /*width*/, int /*height*/)
{
b_engine_.bind_display_space_shader(b_scene_);
}
void BlenderDisplaySpaceShader::unbind()
{
b_engine_.unbind_display_space_shader();
}
uint BlenderDisplaySpaceShader::get_shader_program()
{
if (!shader_program_) {
glGetIntegerv(GL_CURRENT_PROGRAM, reinterpret_cast<int *>(&shader_program_));
}
if (!shader_program_) {
LOG(ERROR) << "Error retrieving shader program for display space shader.";
}
return shader_program_;
}
/* --------------------------------------------------------------------
* BlenderDisplayDriver.
*/
BlenderDisplayDriver::BlenderDisplayDriver(BL::RenderEngine &b_engine, BL::Scene &b_scene)
: b_engine_(b_engine), display_shader_(BlenderDisplayShader::create(b_engine, b_scene))
{
/* Create context while on the main thread. */
gl_context_create();
}
BlenderDisplayDriver::~BlenderDisplayDriver()
{
gl_resources_destroy();
}
/* --------------------------------------------------------------------
* Update procedure.
*/
bool BlenderDisplayDriver::update_begin(const Params &params,
int texture_width,
int texture_height)
{
/* Note that it's the responsibility of BlenderDisplayDriver to ensure updating and drawing
* the texture does not happen at the same time. This is achieved indirectly.
*
* When enabling the OpenGL context, it uses an internal mutex lock DST.gl_context_lock.
* This same lock is also held when do_draw() is called, which together ensure mutual
* exclusion.
*
* This locking is not performed on the Cycles side, because that would cause lock inversion. */
if (!gl_context_enable()) {
return false;
}
if (gl_render_sync_) {
glWaitSync((GLsync)gl_render_sync_, 0, GL_TIMEOUT_IGNORED);
}
if (!gl_texture_resources_ensure()) {
gl_context_disable();
return false;
}
/* Update texture dimensions if needed. */
if (texture_.width != texture_width || texture_.height != texture_height) {
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture_.gl_id);
glTexImage2D(
GL_TEXTURE_2D, 0, GL_RGBA16F, texture_width, texture_height, 0, GL_RGBA, GL_HALF_FLOAT, 0);
texture_.width = texture_width;
texture_.height = texture_height;
glBindTexture(GL_TEXTURE_2D, 0);
/* Texture did change, and no pixel storage was provided. Tag for an explicit zeroing out to
* avoid undefined content. */
texture_.need_clear = true;
}
/* Update PBO dimensions if needed.
*
* NOTE: Allocate the PBO for the the size which will fit the final render resolution (as in,
* at a resolution divider 1. This was we don't need to recreate graphics interoperability
* objects which are costly and which are tied to the specific underlying buffer size.
* The downside of this approach is that when graphics interoperability is not used we are
* sending too much data to GPU when resolution divider is not 1. */
/* TODO(sergey): Investigate whether keeping the PBO exact size of the texture makes non-interop
* mode faster. */
const int buffer_width = params.full_size.x;
const int buffer_height = params.full_size.y;
if (texture_.buffer_width != buffer_width || texture_.buffer_height != buffer_height) {
const size_t size_in_bytes = sizeof(half4) * buffer_width * buffer_height;
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, texture_.gl_pbo_id);
glBufferData(GL_PIXEL_UNPACK_BUFFER, size_in_bytes, 0, GL_DYNAMIC_DRAW);
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
texture_.buffer_width = buffer_width;
texture_.buffer_height = buffer_height;
}
/* New content will be provided to the texture in one way or another, so mark this in a
* centralized place. */
texture_.need_update = true;
return true;
}
void BlenderDisplayDriver::update_end()
{
gl_upload_sync_ = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
glFlush();
gl_context_disable();
}
/* --------------------------------------------------------------------
* Texture buffer mapping.
*/
half4 *BlenderDisplayDriver::map_texture_buffer()
{
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, texture_.gl_pbo_id);
half4 *mapped_rgba_pixels = reinterpret_cast<half4 *>(
glMapBuffer(GL_PIXEL_UNPACK_BUFFER, GL_WRITE_ONLY));
if (!mapped_rgba_pixels) {
LOG(ERROR) << "Error mapping BlenderDisplayDriver pixel buffer object.";
}
if (texture_.need_clear) {
const int64_t texture_width = texture_.width;
const int64_t texture_height = texture_.height;
memset(reinterpret_cast<void *>(mapped_rgba_pixels),
0,
texture_width * texture_height * sizeof(half4));
texture_.need_clear = false;
}
return mapped_rgba_pixels;
}
void BlenderDisplayDriver::unmap_texture_buffer()
{
glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER);
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
}
/* --------------------------------------------------------------------
* Graphics interoperability.
*/
BlenderDisplayDriver::GraphicsInterop BlenderDisplayDriver::graphics_interop_get()
{
GraphicsInterop interop_dst;
interop_dst.buffer_width = texture_.buffer_width;
interop_dst.buffer_height = texture_.buffer_height;
interop_dst.opengl_pbo_id = texture_.gl_pbo_id;
interop_dst.need_clear = texture_.need_clear;
texture_.need_clear = false;
return interop_dst;
}
void BlenderDisplayDriver::graphics_interop_activate()
{
gl_context_enable();
}
void BlenderDisplayDriver::graphics_interop_deactivate()
{
gl_context_disable();
}
/* --------------------------------------------------------------------
* Drawing.
*/
void BlenderDisplayDriver::clear()
{
texture_.need_clear = true;
}
void BlenderDisplayDriver::set_zoom(float zoom_x, float zoom_y)
{
zoom_ = make_float2(zoom_x, zoom_y);
}
void BlenderDisplayDriver::draw(const Params &params)
{
/* See do_update_begin() for why no locking is required here. */
const bool transparent = true; // TODO(sergey): Derive this from Film.
if (!gl_draw_resources_ensure()) {
return;
}
if (use_gl_context_) {
gl_context_mutex_.lock();
}
if (texture_.need_clear) {
/* Texture is requested to be cleared and was not yet cleared.
*
* Do early return which should be equivalent of drawing all-zero texture.
* Watch out for the lock though so that the clear happening during update is properly
* synchronized here. */
gl_context_mutex_.unlock();
return;
}
if (gl_upload_sync_) {
glWaitSync((GLsync)gl_upload_sync_, 0, GL_TIMEOUT_IGNORED);
}
if (transparent) {
glEnable(GL_BLEND);
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
}
display_shader_->bind(params.full_size.x, params.full_size.y);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture_.gl_id);
/* Trick to keep sharp rendering without jagged edges on all GPUs.
*
* The idea here is to enforce driver to use linear interpolation when the image is not zoomed
* in.
* For the render result with a resolution divider in effect we always use nearest interpolation.
*
* Use explicit MIN assignment to make sure the driver does not have an undefined behavior at
* the zoom level 1. The MAG filter is always NEAREST. */
const float zoomed_width = params.size.x * zoom_.x;
const float zoomed_height = params.size.y * zoom_.y;
if (texture_.width != params.size.x || texture_.height != params.size.y) {
/* Resolution divider is different from 1, force nearest interpolation. */
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
}
else if (zoomed_width - params.size.x > 0.5f || zoomed_height - params.size.y > 0.5f) {
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
}
else {
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
}
glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer_);
texture_update_if_needed();
vertex_buffer_update(params);
/* TODO(sergey): Does it make sense/possible to cache/reuse the VAO? */
GLuint vertex_array_object;
glGenVertexArrays(1, &vertex_array_object);
glBindVertexArray(vertex_array_object);
const int texcoord_attribute = display_shader_->get_tex_coord_attrib_location();
const int position_attribute = display_shader_->get_position_attrib_location();
glEnableVertexAttribArray(texcoord_attribute);
glEnableVertexAttribArray(position_attribute);
glVertexAttribPointer(
texcoord_attribute, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (const GLvoid *)0);
glVertexAttribPointer(position_attribute,
2,
GL_FLOAT,
GL_FALSE,
4 * sizeof(float),
(const GLvoid *)(sizeof(float) * 2));
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindTexture(GL_TEXTURE_2D, 0);
glDeleteVertexArrays(1, &vertex_array_object);
display_shader_->unbind();
if (transparent) {
glDisable(GL_BLEND);
}
gl_render_sync_ = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
glFlush();
if (use_gl_context_) {
gl_context_mutex_.unlock();
}
}
void BlenderDisplayDriver::gl_context_create()
{
/* When rendering in viewport there is no render context available via engine.
* Check whether own context is to be created here.
*
* NOTE: If the `b_engine_`'s context is not available, we are expected to be on a main thread
* here. */
use_gl_context_ = !RE_engine_has_render_context(
reinterpret_cast<RenderEngine *>(b_engine_.ptr.data));
if (use_gl_context_) {
const bool drw_state = DRW_opengl_context_release();
gl_context_ = WM_opengl_context_create();
if (gl_context_) {
/* On Windows an old context is restored after creation, and subsequent release of context
* generates a Win32 error. Harmless for users, but annoying to have possible misleading
* error prints in the console. */
#ifndef _WIN32
WM_opengl_context_release(gl_context_);
#endif
}
else {
LOG(ERROR) << "Error creating OpenGL context.";
}
DRW_opengl_context_activate(drw_state);
}
}
bool BlenderDisplayDriver::gl_context_enable()
{
if (use_gl_context_) {
if (!gl_context_) {
return false;
}
gl_context_mutex_.lock();
WM_opengl_context_activate(gl_context_);
return true;
}
RE_engine_render_context_enable(reinterpret_cast<RenderEngine *>(b_engine_.ptr.data));
return true;
}
void BlenderDisplayDriver::gl_context_disable()
{
if (use_gl_context_) {
if (gl_context_) {
WM_opengl_context_release(gl_context_);
gl_context_mutex_.unlock();
}
return;
}
RE_engine_render_context_disable(reinterpret_cast<RenderEngine *>(b_engine_.ptr.data));
}
void BlenderDisplayDriver::gl_context_dispose()
{
if (gl_context_) {
const bool drw_state = DRW_opengl_context_release();
WM_opengl_context_activate(gl_context_);
WM_opengl_context_dispose(gl_context_);
DRW_opengl_context_activate(drw_state);
}
}
bool BlenderDisplayDriver::gl_draw_resources_ensure()
{
if (!texture_.gl_id) {
/* If there is no texture allocated, there is nothing to draw. Inform the draw call that it can
* can not continue. Note that this is not an unrecoverable error, so once the texture is known
* we will come back here and create all the GPU resources needed for draw. */
return false;
}
if (gl_draw_resource_creation_attempted_) {
return gl_draw_resources_created_;
}
gl_draw_resource_creation_attempted_ = true;
if (!vertex_buffer_) {
glGenBuffers(1, &vertex_buffer_);
if (!vertex_buffer_) {
LOG(ERROR) << "Error creating vertex buffer.";
return false;
}
}
gl_draw_resources_created_ = true;
return true;
}
void BlenderDisplayDriver::gl_resources_destroy()
{
gl_context_enable();
if (vertex_buffer_ != 0) {
glDeleteBuffers(1, &vertex_buffer_);
}
if (texture_.gl_pbo_id) {
glDeleteBuffers(1, &texture_.gl_pbo_id);
texture_.gl_pbo_id = 0;
}
if (texture_.gl_id) {
glDeleteTextures(1, &texture_.gl_id);
texture_.gl_id = 0;
}
gl_context_disable();
gl_context_dispose();
}
bool BlenderDisplayDriver::gl_texture_resources_ensure()
{
if (texture_.creation_attempted) {
return texture_.is_created;
}
texture_.creation_attempted = true;
DCHECK(!texture_.gl_id);
DCHECK(!texture_.gl_pbo_id);
/* Create texture. */
glGenTextures(1, &texture_.gl_id);
if (!texture_.gl_id) {
LOG(ERROR) << "Error creating texture.";
return false;
}
/* Configure the texture. */
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture_.gl_id);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glBindTexture(GL_TEXTURE_2D, 0);
/* Create PBO for the texture. */
glGenBuffers(1, &texture_.gl_pbo_id);
if (!texture_.gl_pbo_id) {
LOG(ERROR) << "Error creating texture pixel buffer object.";
return false;
}
/* Creation finished with a success. */
texture_.is_created = true;
return true;
}
void BlenderDisplayDriver::texture_update_if_needed()
{
if (!texture_.need_update) {
return;
}
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, texture_.gl_pbo_id);
glTexSubImage2D(
GL_TEXTURE_2D, 0, 0, 0, texture_.width, texture_.height, GL_RGBA, GL_HALF_FLOAT, 0);
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
texture_.need_update = false;
}
void BlenderDisplayDriver::vertex_buffer_update(const Params &params)
{
/* Invalidate old contents - avoids stalling if the buffer is still waiting in queue to be
* rendered. */
glBufferData(GL_ARRAY_BUFFER, 16 * sizeof(float), NULL, GL_STREAM_DRAW);
float *vpointer = reinterpret_cast<float *>(glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY));
if (!vpointer) {
return;
}
vpointer[0] = 0.0f;
vpointer[1] = 0.0f;
vpointer[2] = params.full_offset.x;
vpointer[3] = params.full_offset.y;
vpointer[4] = 1.0f;
vpointer[5] = 0.0f;
vpointer[6] = (float)params.size.x + params.full_offset.x;
vpointer[7] = params.full_offset.y;
vpointer[8] = 1.0f;
vpointer[9] = 1.0f;
vpointer[10] = (float)params.size.x + params.full_offset.x;
vpointer[11] = (float)params.size.y + params.full_offset.y;
vpointer[12] = 0.0f;
vpointer[13] = 1.0f;
vpointer[14] = params.full_offset.x;
vpointer[15] = (float)params.size.y + params.full_offset.y;
glUnmapBuffer(GL_ARRAY_BUFFER);
}
CCL_NAMESPACE_END

View File

@@ -0,0 +1,210 @@
/*
* Copyright 2021 Blender Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#include <atomic>
#include "MEM_guardedalloc.h"
#include "RNA_blender_cpp.h"
#include "render/display_driver.h"
#include "util/util_thread.h"
#include "util/util_unique_ptr.h"
CCL_NAMESPACE_BEGIN
/* Base class of shader used for display driver rendering. */
class BlenderDisplayShader {
public:
static constexpr const char *position_attribute_name = "pos";
static constexpr const char *tex_coord_attribute_name = "texCoord";
/* Create shader implementation suitable for the given render engine and scene configuration. */
static unique_ptr<BlenderDisplayShader> create(BL::RenderEngine &b_engine, BL::Scene &b_scene);
BlenderDisplayShader() = default;
virtual ~BlenderDisplayShader() = default;
virtual void bind(int width, int height) = 0;
virtual void unbind() = 0;
/* Get attribute location for position and texture coordinate respectively.
* NOTE: The shader needs to be bound to have access to those. */
virtual int get_position_attrib_location();
virtual int get_tex_coord_attrib_location();
protected:
/* Get program of this display shader.
* NOTE: The shader needs to be bound to have access to this. */
virtual uint get_shader_program() = 0;
/* Cached values of various OpenGL resources. */
int position_attribute_location_ = -1;
int tex_coord_attribute_location_ = -1;
};
/* Implementation of display rendering shader used in the case when render engine does not support
* display space shader. */
class BlenderFallbackDisplayShader : public BlenderDisplayShader {
public:
virtual void bind(int width, int height) override;
virtual void unbind() override;
protected:
virtual uint get_shader_program() override;
void create_shader_if_needed();
void destroy_shader();
uint shader_program_ = 0;
int image_texture_location_ = -1;
int fullscreen_location_ = -1;
/* Shader compilation attempted. Which means, that if the shader program is 0 then compilation or
* linking has failed. Do not attempt to re-compile the shader. */
bool shader_compile_attempted_ = false;
};
class BlenderDisplaySpaceShader : public BlenderDisplayShader {
public:
BlenderDisplaySpaceShader(BL::RenderEngine &b_engine, BL::Scene &b_scene);
virtual void bind(int width, int height) override;
virtual void unbind() override;
protected:
virtual uint get_shader_program() override;
BL::RenderEngine b_engine_;
BL::Scene &b_scene_;
/* Cached values of various OpenGL resources. */
uint shader_program_ = 0;
};
/* Display driver implementation which is specific for Blender viewport integration. */
class BlenderDisplayDriver : public DisplayDriver {
public:
BlenderDisplayDriver(BL::RenderEngine &b_engine, BL::Scene &b_scene);
~BlenderDisplayDriver();
virtual void graphics_interop_activate() override;
virtual void graphics_interop_deactivate() override;
virtual void clear() override;
void set_zoom(float zoom_x, float zoom_y);
protected:
virtual bool update_begin(const Params &params, int texture_width, int texture_height) override;
virtual void update_end() override;
virtual half4 *map_texture_buffer() override;
virtual void unmap_texture_buffer() override;
virtual GraphicsInterop graphics_interop_get() override;
virtual void draw(const Params &params) override;
/* Helper function which allocates new GPU context. */
void gl_context_create();
bool gl_context_enable();
void gl_context_disable();
void gl_context_dispose();
/* Make sure texture is allocated and its initial configuration is performed. */
bool gl_texture_resources_ensure();
/* Ensure all runtime GPU resources needed for drawing are allocated.
* Returns true if all resources needed for drawing are available. */
bool gl_draw_resources_ensure();
/* Destroy all GPU resources which are being used by this object. */
void gl_resources_destroy();
/* Update GPU texture dimensions and content if needed (new pixel data was provided).
*
* NOTE: The texture needs to be bound. */
void texture_update_if_needed();
/* Update vertex buffer with new coordinates of vertex positions and texture coordinates.
* This buffer is used to render texture in the viewport.
*
* NOTE: The buffer needs to be bound. */
void vertex_buffer_update(const Params &params);
BL::RenderEngine b_engine_;
/* OpenGL context which is used the render engine doesn't have its own. */
void *gl_context_ = nullptr;
/* The when Blender RenderEngine side context is not available and the DisplayDriver is to create
* its own context. */
bool use_gl_context_ = false;
/* Mutex used to guard the `gl_context_`. */
thread_mutex gl_context_mutex_;
/* Texture which contains pixels of the render result. */
struct {
/* Indicates whether texture creation was attempted and succeeded.
* Used to avoid multiple attempts of texture creation on GPU issues or GPU context
* misconfiguration. */
bool creation_attempted = false;
bool is_created = false;
/* OpenGL resource IDs of the texture itself and Pixel Buffer Object (PBO) used to write
* pixels to it.
*
* NOTE: Allocated on the engine's context. */
uint gl_id = 0;
uint gl_pbo_id = 0;
/* Is true when new data was written to the PBO, meaning, the texture might need to be resized
* and new data is to be uploaded to the GPU. */
bool need_update = false;
/* Content of the texture is to be filled with zeroes. */
std::atomic<bool> need_clear = true;
/* Dimensions of the texture in pixels. */
int width = 0;
int height = 0;
/* Dimensions of the underlying PBO. */
int buffer_width = 0;
int buffer_height = 0;
} texture_;
unique_ptr<BlenderDisplayShader> display_shader_;
/* Special track of whether GPU resources were attempted to be created, to avoid attempts of
* their re-creation on failure on every redraw. */
bool gl_draw_resource_creation_attempted_ = false;
bool gl_draw_resources_created_ = false;
/* Vertex buffer which hold vertices of a triangle fan which is textures with the texture
* holding the render result. */
uint vertex_buffer_ = 0;
void *gl_render_sync_ = nullptr;
void *gl_upload_sync_ = nullptr;
float2 zoom_ = make_float2(1.0f, 1.0f);
};
CCL_NAMESPACE_END

View File

@@ -80,7 +80,11 @@ Geometry *BlenderSync::sync_geometry(BL::Depsgraph &b_depsgraph,
{
/* Test if we can instance or if the object is modified. */
Geometry::Type geom_type = determine_geom_type(b_ob_info, use_particle_hair);
GeometryKey key(b_ob_info.object_data, geom_type);
BL::ID b_key_id = (b_ob_info.is_real_object_data() &&
BKE_object_is_modified(b_ob_info.real_object)) ?
b_ob_info.real_object :
b_ob_info.object_data;
GeometryKey key(b_key_id.ptr.data, geom_type);
/* Find shader indices. */
array<Node *> used_shaders = find_used_shaders(b_ob_info.iter_object);
@@ -110,7 +114,7 @@ Geometry *BlenderSync::sync_geometry(BL::Depsgraph &b_depsgraph,
}
else {
/* Test if we need to update existing geometry. */
sync = geometry_map.update(geom, b_ob_info.object_data);
sync = geometry_map.update(geom, b_key_id);
}
if (!sync) {

View File

@@ -125,17 +125,10 @@ void BlenderSync::sync_light(BL::Object &b_parent,
light->set_shader(static_cast<Shader *>(used_shaders[0]));
/* shadow */
PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles");
PointerRNA clight = RNA_pointer_get(&b_light.ptr, "cycles");
light->set_cast_shadow(get_boolean(clight, "cast_shadow"));
light->set_use_mis(get_boolean(clight, "use_multiple_importance_sampling"));
int samples = get_int(clight, "samples");
if (get_boolean(cscene, "use_square_samples"))
light->set_samples(samples * samples);
else
light->set_samples(samples);
light->set_max_bounces(get_int(clight, "max_bounces"));
if (b_ob_info.real_object != b_ob_info.iter_object) {
@@ -155,10 +148,12 @@ void BlenderSync::sync_light(BL::Object &b_parent,
/* visibility */
uint visibility = object_ray_visibility(b_ob_info.real_object);
light->set_use_camera((visibility & PATH_RAY_CAMERA) != 0);
light->set_use_diffuse((visibility & PATH_RAY_DIFFUSE) != 0);
light->set_use_glossy((visibility & PATH_RAY_GLOSSY) != 0);
light->set_use_transmission((visibility & PATH_RAY_TRANSMIT) != 0);
light->set_use_scatter((visibility & PATH_RAY_VOLUME_SCATTER) != 0);
light->set_is_shadow_catcher(b_ob_info.real_object.is_shadow_catcher());
/* tag */
light->tag_update(scene);
@@ -169,7 +164,6 @@ void BlenderSync::sync_background_light(BL::SpaceView3D &b_v3d, bool use_portal)
BL::World b_world = b_scene.world();
if (b_world) {
PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles");
PointerRNA cworld = RNA_pointer_get(&b_world.ptr, "cycles");
enum SamplingMethod { SAMPLING_NONE = 0, SAMPLING_AUTOMATIC, SAMPLING_MANUAL, SAMPLING_NUM };
@@ -197,12 +191,6 @@ void BlenderSync::sync_background_light(BL::SpaceView3D &b_v3d, bool use_portal)
/* force enable light again when world is resynced */
light->set_is_enabled(true);
int samples = get_int(cworld, "samples");
if (get_boolean(cscene, "use_square_samples"))
light->set_samples(samples * samples);
else
light->set_samples(samples);
light->tag_update(scene);
light_map.set_recalc(b_world);
}
@@ -211,7 +199,7 @@ void BlenderSync::sync_background_light(BL::SpaceView3D &b_v3d, bool use_portal)
world_map = b_world.ptr.data;
world_recalc = false;
viewport_parameters = BlenderViewportParameters(b_v3d);
viewport_parameters = BlenderViewportParameters(b_v3d, use_developer_ui);
}
CCL_NAMESPACE_END

View File

@@ -568,7 +568,7 @@ void BlenderSync::sync_objects(BL::Depsgraph &b_depsgraph,
/* object loop */
bool cancel = false;
bool use_portal = false;
const bool show_lights = BlenderViewportParameters(b_v3d).use_scene_lights;
const bool show_lights = BlenderViewportParameters(b_v3d, use_developer_ui).use_scene_lights;
BL::ViewLayer b_view_layer = b_depsgraph.view_layer_eval();
BL::Depsgraph::object_instances_iterator b_instance_iter;

View File

@@ -0,0 +1,127 @@
/*
* Copyright 2021 Blender Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "blender/blender_output_driver.h"
CCL_NAMESPACE_BEGIN
BlenderOutputDriver::BlenderOutputDriver(BL::RenderEngine &b_engine) : b_engine_(b_engine)
{
}
BlenderOutputDriver::~BlenderOutputDriver()
{
}
bool BlenderOutputDriver::read_render_tile(const Tile &tile)
{
/* Get render result. */
BL::RenderResult b_rr = b_engine_.begin_result(tile.offset.x,
tile.offset.y,
tile.size.x,
tile.size.y,
tile.layer.c_str(),
tile.view.c_str());
/* Can happen if the intersected rectangle gives 0 width or height. */
if (b_rr.ptr.data == NULL) {
return false;
}
BL::RenderResult::layers_iterator b_single_rlay;
b_rr.layers.begin(b_single_rlay);
/* layer will be missing if it was disabled in the UI */
if (b_single_rlay == b_rr.layers.end()) {
return false;
}
BL::RenderLayer b_rlay = *b_single_rlay;
vector<float> pixels(tile.size.x * tile.size.y * 4);
/* Copy each pass.
* TODO:copy only the required ones for better performance? */
for (BL::RenderPass &b_pass : b_rlay.passes) {
tile.set_pass_pixels(b_pass.name(), b_pass.channels(), (float *)b_pass.rect());
}
b_engine_.end_result(b_rr, false, false, false);
return true;
}
bool BlenderOutputDriver::update_render_tile(const Tile &tile)
{
/* Use final write for preview renders, otherwise render result wouldn't be be updated
* quickly on Blender side. For all other cases we use the display driver. */
if (b_engine_.is_preview()) {
write_render_tile(tile);
return true;
}
else {
/* Don't highlight full-frame tile. */
if (!(tile.size == tile.full_size)) {
b_engine_.tile_highlight_clear_all();
b_engine_.tile_highlight_set(tile.offset.x, tile.offset.y, tile.size.x, tile.size.y, true);
}
return false;
}
}
void BlenderOutputDriver::write_render_tile(const Tile &tile)
{
b_engine_.tile_highlight_clear_all();
/* Get render result. */
BL::RenderResult b_rr = b_engine_.begin_result(tile.offset.x,
tile.offset.y,
tile.size.x,
tile.size.y,
tile.layer.c_str(),
tile.view.c_str());
/* Can happen if the intersected rectangle gives 0 width or height. */
if (b_rr.ptr.data == NULL) {
return;
}
BL::RenderResult::layers_iterator b_single_rlay;
b_rr.layers.begin(b_single_rlay);
/* Layer will be missing if it was disabled in the UI. */
if (b_single_rlay == b_rr.layers.end()) {
return;
}
BL::RenderLayer b_rlay = *b_single_rlay;
vector<float> pixels(tile.size.x * tile.size.y * 4);
/* Copy each pass. */
for (BL::RenderPass &b_pass : b_rlay.passes) {
if (!tile.get_pass_pixels(b_pass.name(), b_pass.channels(), &pixels[0])) {
memset(&pixels[0], 0, pixels.size() * sizeof(float));
}
b_pass.rect(&pixels[0]);
}
b_engine_.end_result(b_rr, true, false, true);
}
CCL_NAMESPACE_END

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2019 Blender Foundation
* Copyright 2021 Blender Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,17 +14,27 @@
* limitations under the License.
*/
#pragma once
#include "MEM_guardedalloc.h"
#include "RNA_blender_cpp.h"
#include "render/output_driver.h"
CCL_NAMESPACE_BEGIN
ccl_device void kernel_adaptive_filter_x(KernelGlobals *kg)
{
int pixel_index = ccl_global_id(1) * ccl_global_size(0) + ccl_global_id(0);
if (pixel_index < kernel_split_params.tile.h &&
kernel_split_params.tile.start_sample + kernel_split_params.tile.num_samples >=
kernel_data.integrator.adaptive_min_samples) {
int y = kernel_split_params.tile.y + pixel_index;
kernel_do_adaptive_filter_x(kg, y, &kernel_split_params.tile);
}
}
class BlenderOutputDriver : public OutputDriver {
public:
BlenderOutputDriver(BL::RenderEngine &b_engine);
~BlenderOutputDriver();
virtual void write_render_tile(const Tile &tile) override;
virtual bool update_render_tile(const Tile &tile) override;
virtual bool read_render_tile(const Tile &tile) override;
protected:
BL::RenderEngine b_engine_;
};
CCL_NAMESPACE_END

View File

@@ -45,10 +45,6 @@
# include <OSL/oslquery.h>
#endif
#ifdef WITH_OPENCL
# include "device/device_intern.h"
#endif
CCL_NAMESPACE_BEGIN
namespace {
@@ -72,12 +68,10 @@ PyObject *pyunicode_from_string(const char *str)
/* Synchronize debug flags from a given Blender scene.
* Return truth when device list needs invalidation.
*/
bool debug_flags_sync_from_scene(BL::Scene b_scene)
static void debug_flags_sync_from_scene(BL::Scene b_scene)
{
DebugFlagsRef flags = DebugFlags();
PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles");
/* Backup some settings for comparison. */
DebugFlags::OpenCL::DeviceType opencl_device_type = flags.opencl.device_type;
/* Synchronize shared flags. */
flags.viewport_static_bvh = get_enum(cscene, "debug_bvh_type");
/* Synchronize CPU flags. */
@@ -87,50 +81,19 @@ bool debug_flags_sync_from_scene(BL::Scene b_scene)
flags.cpu.sse3 = get_boolean(cscene, "debug_use_cpu_sse3");
flags.cpu.sse2 = get_boolean(cscene, "debug_use_cpu_sse2");
flags.cpu.bvh_layout = (BVHLayout)get_enum(cscene, "debug_bvh_layout");
flags.cpu.split_kernel = get_boolean(cscene, "debug_use_cpu_split_kernel");
/* Synchronize CUDA flags. */
flags.cuda.adaptive_compile = get_boolean(cscene, "debug_use_cuda_adaptive_compile");
flags.cuda.split_kernel = get_boolean(cscene, "debug_use_cuda_split_kernel");
/* Synchronize OptiX flags. */
flags.optix.cuda_streams = get_int(cscene, "debug_optix_cuda_streams");
flags.optix.curves_api = get_boolean(cscene, "debug_optix_curves_api");
/* Synchronize OpenCL device type. */
switch (get_enum(cscene, "debug_opencl_device_type")) {
case 0:
flags.opencl.device_type = DebugFlags::OpenCL::DEVICE_NONE;
break;
case 1:
flags.opencl.device_type = DebugFlags::OpenCL::DEVICE_ALL;
break;
case 2:
flags.opencl.device_type = DebugFlags::OpenCL::DEVICE_DEFAULT;
break;
case 3:
flags.opencl.device_type = DebugFlags::OpenCL::DEVICE_CPU;
break;
case 4:
flags.opencl.device_type = DebugFlags::OpenCL::DEVICE_GPU;
break;
case 5:
flags.opencl.device_type = DebugFlags::OpenCL::DEVICE_ACCELERATOR;
break;
}
/* Synchronize other OpenCL flags. */
flags.opencl.debug = get_boolean(cscene, "debug_use_opencl_debug");
flags.opencl.mem_limit = ((size_t)get_int(cscene, "debug_opencl_mem_limit")) * 1024 * 1024;
return flags.opencl.device_type != opencl_device_type;
flags.optix.use_debug = get_boolean(cscene, "debug_use_optix_debug");
}
/* Reset debug flags to default values.
* Return truth when device list needs invalidation.
*/
bool debug_flags_reset()
static void debug_flags_reset()
{
DebugFlagsRef flags = DebugFlags();
/* Backup some settings for comparison. */
DebugFlags::OpenCL::DeviceType opencl_device_type = flags.opencl.device_type;
flags.reset();
return flags.opencl.device_type != opencl_device_type;
}
} /* namespace */
@@ -175,18 +138,20 @@ static const char *PyC_UnicodeAsByte(PyObject *py_str, PyObject **coerce)
static PyObject *init_func(PyObject * /*self*/, PyObject *args)
{
PyObject *path, *user_path;
PyObject *path, *user_path, *temp_path;
int headless;
if (!PyArg_ParseTuple(args, "OOi", &path, &user_path, &headless)) {
return NULL;
if (!PyArg_ParseTuple(args, "OOOi", &path, &user_path, &temp_path, &headless)) {
return nullptr;
}
PyObject *path_coerce = NULL, *user_path_coerce = NULL;
PyObject *path_coerce = nullptr, *user_path_coerce = nullptr, *temp_path_coerce = nullptr;
path_init(PyC_UnicodeAsByte(path, &path_coerce),
PyC_UnicodeAsByte(user_path, &user_path_coerce));
PyC_UnicodeAsByte(user_path, &user_path_coerce),
PyC_UnicodeAsByte(temp_path, &temp_path_coerce));
Py_XDECREF(path_coerce);
Py_XDECREF(user_path_coerce);
Py_XDECREF(temp_path_coerce);
BlenderSession::headless = headless;
@@ -299,6 +264,50 @@ static PyObject *render_func(PyObject * /*self*/, PyObject *args)
Py_RETURN_NONE;
}
static PyObject *render_frame_finish_func(PyObject * /*self*/, PyObject *args)
{
PyObject *pysession;
if (!PyArg_ParseTuple(args, "O", &pysession)) {
return nullptr;
}
BlenderSession *session = (BlenderSession *)PyLong_AsVoidPtr(pysession);
/* Allow Blender to execute other Python scripts. */
python_thread_state_save(&session->python_thread_state);
session->render_frame_finish();
python_thread_state_restore(&session->python_thread_state);
Py_RETURN_NONE;
}
static PyObject *draw_func(PyObject * /*self*/, PyObject *args)
{
PyObject *py_session, *py_graph, *py_screen, *py_space_image;
if (!PyArg_ParseTuple(args, "OOOO", &py_session, &py_graph, &py_screen, &py_space_image)) {
return nullptr;
}
BlenderSession *session = (BlenderSession *)PyLong_AsVoidPtr(py_session);
ID *b_screen = (ID *)PyLong_AsVoidPtr(py_screen);
PointerRNA b_space_image_ptr;
RNA_pointer_create(b_screen,
&RNA_SpaceImageEditor,
pylong_as_voidptr_typesafe(py_space_image),
&b_space_image_ptr);
BL::SpaceImageEditor b_space_image(b_space_image_ptr);
session->draw(b_space_image);
Py_RETURN_NONE;
}
/* pixel_array and result passed as pointers */
static PyObject *bake_func(PyObject * /*self*/, PyObject *args)
{
@@ -336,7 +345,7 @@ static PyObject *bake_func(PyObject * /*self*/, PyObject *args)
Py_RETURN_NONE;
}
static PyObject *draw_func(PyObject * /*self*/, PyObject *args)
static PyObject *view_draw_func(PyObject * /*self*/, PyObject *args)
{
PyObject *pysession, *pygraph, *pyv3d, *pyrv3d;
@@ -350,7 +359,7 @@ static PyObject *draw_func(PyObject * /*self*/, PyObject *args)
int viewport[4];
glGetIntegerv(GL_VIEWPORT, viewport);
session->draw(viewport[2], viewport[3]);
session->view_draw(viewport[2], viewport[3]);
}
Py_RETURN_NONE;
@@ -697,40 +706,6 @@ static PyObject *system_info_func(PyObject * /*self*/, PyObject * /*value*/)
return pyunicode_from_string(system_info.c_str());
}
#ifdef WITH_OPENCL
static PyObject *opencl_disable_func(PyObject * /*self*/, PyObject * /*value*/)
{
VLOG(2) << "Disabling OpenCL platform.";
DebugFlags().opencl.device_type = DebugFlags::OpenCL::DEVICE_NONE;
Py_RETURN_NONE;
}
static PyObject *opencl_compile_func(PyObject * /*self*/, PyObject *args)
{
PyObject *sequence = PySequence_Fast(args, "Arguments must be a sequence");
if (sequence == NULL) {
Py_RETURN_FALSE;
}
vector<string> parameters;
for (Py_ssize_t i = 0; i < PySequence_Fast_GET_SIZE(sequence); i++) {
PyObject *item = PySequence_Fast_GET_ITEM(sequence, i);
PyObject *item_as_string = PyObject_Str(item);
const char *parameter_string = PyUnicode_AsUTF8(item_as_string);
parameters.push_back(parameter_string);
Py_DECREF(item_as_string);
}
Py_DECREF(sequence);
if (device_opencl_compile_kernel(parameters)) {
Py_RETURN_TRUE;
}
else {
Py_RETURN_FALSE;
}
}
#endif
static bool image_parse_filepaths(PyObject *pyfilepaths, vector<string> &filepaths)
{
if (PyUnicode_Check(pyfilepaths)) {
@@ -762,6 +737,10 @@ static bool image_parse_filepaths(PyObject *pyfilepaths, vector<string> &filepat
static PyObject *denoise_func(PyObject * /*self*/, PyObject *args, PyObject *keywords)
{
#if 1
(void)args;
(void)keywords;
#else
static const char *keyword_list[] = {
"preferences", "scene", "view_layer", "input", "output", "tile_size", "samples", NULL};
PyObject *pypreferences, *pyscene, *pyviewlayer;
@@ -835,7 +814,7 @@ static PyObject *denoise_func(PyObject * /*self*/, PyObject *args, PyObject *key
}
/* Create denoiser. */
Denoiser denoiser(device);
DenoiserPipeline denoiser(device);
denoiser.params = params;
denoiser.input = input;
denoiser.output = output;
@@ -852,6 +831,7 @@ static PyObject *denoise_func(PyObject * /*self*/, PyObject *args, PyObject *key
PyErr_SetString(PyExc_ValueError, denoiser.error.c_str());
return NULL;
}
#endif
Py_RETURN_NONE;
}
@@ -903,10 +883,7 @@ static PyObject *debug_flags_update_func(PyObject * /*self*/, PyObject *args)
RNA_id_pointer_create((ID *)PyLong_AsVoidPtr(pyscene), &sceneptr);
BL::Scene b_scene(sceneptr);
if (debug_flags_sync_from_scene(b_scene)) {
VLOG(2) << "Tagging device list for update.";
Device::tag_update();
}
debug_flags_sync_from_scene(b_scene);
VLOG(2) << "Debug flags set to:\n" << DebugFlags();
@@ -917,10 +894,7 @@ static PyObject *debug_flags_update_func(PyObject * /*self*/, PyObject *args)
static PyObject *debug_flags_reset_func(PyObject * /*self*/, PyObject * /*args*/)
{
if (debug_flags_reset()) {
VLOG(2) << "Tagging device list for update.";
Device::tag_update();
}
debug_flags_reset();
if (debug_flags_set) {
VLOG(2) << "Debug flags reset to:\n" << DebugFlags();
debug_flags_set = false;
@@ -928,84 +902,6 @@ static PyObject *debug_flags_reset_func(PyObject * /*self*/, PyObject * /*args*/
Py_RETURN_NONE;
}
static PyObject *set_resumable_chunk_func(PyObject * /*self*/, PyObject *args)
{
int num_resumable_chunks, current_resumable_chunk;
if (!PyArg_ParseTuple(args, "ii", &num_resumable_chunks, &current_resumable_chunk)) {
Py_RETURN_NONE;
}
if (num_resumable_chunks <= 0) {
fprintf(stderr, "Cycles: Bad value for number of resumable chunks.\n");
abort();
Py_RETURN_NONE;
}
if (current_resumable_chunk < 1 || current_resumable_chunk > num_resumable_chunks) {
fprintf(stderr, "Cycles: Bad value for current resumable chunk number.\n");
abort();
Py_RETURN_NONE;
}
VLOG(1) << "Initialized resumable render: "
<< "num_resumable_chunks=" << num_resumable_chunks << ", "
<< "current_resumable_chunk=" << current_resumable_chunk;
BlenderSession::num_resumable_chunks = num_resumable_chunks;
BlenderSession::current_resumable_chunk = current_resumable_chunk;
printf("Cycles: Will render chunk %d of %d\n", current_resumable_chunk, num_resumable_chunks);
Py_RETURN_NONE;
}
static PyObject *set_resumable_chunk_range_func(PyObject * /*self*/, PyObject *args)
{
int num_chunks, start_chunk, end_chunk;
if (!PyArg_ParseTuple(args, "iii", &num_chunks, &start_chunk, &end_chunk)) {
Py_RETURN_NONE;
}
if (num_chunks <= 0) {
fprintf(stderr, "Cycles: Bad value for number of resumable chunks.\n");
abort();
Py_RETURN_NONE;
}
if (start_chunk < 1 || start_chunk > num_chunks) {
fprintf(stderr, "Cycles: Bad value for start chunk number.\n");
abort();
Py_RETURN_NONE;
}
if (end_chunk < 1 || end_chunk > num_chunks) {
fprintf(stderr, "Cycles: Bad value for start chunk number.\n");
abort();
Py_RETURN_NONE;
}
if (start_chunk > end_chunk) {
fprintf(stderr, "Cycles: End chunk should be higher than start one.\n");
abort();
Py_RETURN_NONE;
}
VLOG(1) << "Initialized resumable render: "
<< "num_resumable_chunks=" << num_chunks << ", "
<< "start_resumable_chunk=" << start_chunk << "end_resumable_chunk=" << end_chunk;
BlenderSession::num_resumable_chunks = num_chunks;
BlenderSession::start_resumable_chunk = start_chunk;
BlenderSession::end_resumable_chunk = end_chunk;
printf("Cycles: Will render chunks %d to %d of %d\n", start_chunk, end_chunk, num_chunks);
Py_RETURN_NONE;
}
static PyObject *clear_resumable_chunk_func(PyObject * /*self*/, PyObject * /*value*/)
{
VLOG(1) << "Clear resumable render";
BlenderSession::num_resumable_chunks = 0;
BlenderSession::current_resumable_chunk = 0;
Py_RETURN_NONE;
}
static PyObject *enable_print_stats_func(PyObject * /*self*/, PyObject * /*args*/)
{
BlenderSession::print_render_stats = true;
@@ -1015,16 +911,16 @@ static PyObject *enable_print_stats_func(PyObject * /*self*/, PyObject * /*args*
static PyObject *get_device_types_func(PyObject * /*self*/, PyObject * /*args*/)
{
vector<DeviceType> device_types = Device::available_types();
bool has_cuda = false, has_optix = false, has_opencl = false;
bool has_cuda = false, has_optix = false, has_hip = false;
foreach (DeviceType device_type, device_types) {
has_cuda |= (device_type == DEVICE_CUDA);
has_optix |= (device_type == DEVICE_OPTIX);
has_opencl |= (device_type == DEVICE_OPENCL);
has_hip |= (device_type == DEVICE_HIP);
}
PyObject *list = PyTuple_New(3);
PyTuple_SET_ITEM(list, 0, PyBool_FromLong(has_cuda));
PyTuple_SET_ITEM(list, 1, PyBool_FromLong(has_optix));
PyTuple_SET_ITEM(list, 2, PyBool_FromLong(has_opencl));
PyTuple_SET_ITEM(list, 2, PyBool_FromLong(has_hip));
return list;
}
@@ -1044,15 +940,15 @@ static PyObject *set_device_override_func(PyObject * /*self*/, PyObject *arg)
if (override == "CPU") {
BlenderSession::device_override = DEVICE_MASK_CPU;
}
else if (override == "OPENCL") {
BlenderSession::device_override = DEVICE_MASK_OPENCL;
}
else if (override == "CUDA") {
BlenderSession::device_override = DEVICE_MASK_CUDA;
}
else if (override == "OPTIX") {
BlenderSession::device_override = DEVICE_MASK_OPTIX;
}
else if (override == "HIP") {
BlenderSession::device_override = DEVICE_MASK_HIP;
}
else {
printf("\nError: %s is not a valid Cycles device.\n", override.c_str());
Py_RETURN_FALSE;
@@ -1072,8 +968,10 @@ static PyMethodDef methods[] = {
{"create", create_func, METH_VARARGS, ""},
{"free", free_func, METH_O, ""},
{"render", render_func, METH_VARARGS, ""},
{"bake", bake_func, METH_VARARGS, ""},
{"render_frame_finish", render_frame_finish_func, METH_VARARGS, ""},
{"draw", draw_func, METH_VARARGS, ""},
{"bake", bake_func, METH_VARARGS, ""},
{"view_draw", view_draw_func, METH_VARARGS, ""},
{"sync", sync_func, METH_VARARGS, ""},
{"reset", reset_func, METH_VARARGS, ""},
#ifdef WITH_OSL
@@ -1082,10 +980,6 @@ static PyMethodDef methods[] = {
#endif
{"available_devices", available_devices_func, METH_VARARGS, ""},
{"system_info", system_info_func, METH_NOARGS, ""},
#ifdef WITH_OPENCL
{"opencl_disable", opencl_disable_func, METH_NOARGS, ""},
{"opencl_compile", opencl_compile_func, METH_VARARGS, ""},
#endif
/* Standalone denoising */
{"denoise", (PyCFunction)denoise_func, METH_VARARGS | METH_KEYWORDS, ""},
@@ -1098,11 +992,6 @@ static PyMethodDef methods[] = {
/* Statistics. */
{"enable_print_stats", enable_print_stats_func, METH_NOARGS, ""},
/* Resumable render */
{"set_resumable_chunk", set_resumable_chunk_func, METH_VARARGS, ""},
{"set_resumable_chunk_range", set_resumable_chunk_range_func, METH_VARARGS, ""},
{"clear_resumable_chunk", clear_resumable_chunk_func, METH_NOARGS, ""},
/* Compute Device selection */
{"get_device_types", get_device_types_func, METH_VARARGS, ""},
{"set_device_override", set_device_override_func, METH_O, ""},
@@ -1153,14 +1042,6 @@ void *CCL_python_module_init()
PyModule_AddStringConstant(mod, "osl_version_string", "unknown");
#endif
#ifdef WITH_NETWORK
PyModule_AddObject(mod, "with_network", Py_True);
Py_INCREF(Py_True);
#else /* WITH_NETWORK */
PyModule_AddObject(mod, "with_network", Py_False);
Py_INCREF(Py_False);
#endif /* WITH_NETWORK */
#ifdef WITH_EMBREE
PyModule_AddObject(mod, "with_embree", Py_True);
Py_INCREF(Py_True);

View File

@@ -38,9 +38,12 @@
#include "util/util_hash.h"
#include "util/util_logging.h"
#include "util/util_murmurhash.h"
#include "util/util_path.h"
#include "util/util_progress.h"
#include "util/util_time.h"
#include "blender/blender_display_driver.h"
#include "blender/blender_output_driver.h"
#include "blender/blender_session.h"
#include "blender/blender_sync.h"
#include "blender/blender_util.h"
@@ -49,10 +52,6 @@ CCL_NAMESPACE_BEGIN
DeviceTypeMask BlenderSession::device_override = DEVICE_MASK_ALL;
bool BlenderSession::headless = false;
int BlenderSession::num_resumable_chunks = 0;
int BlenderSession::current_resumable_chunk = 0;
int BlenderSession::start_resumable_chunk = 0;
int BlenderSession::end_resumable_chunk = 0;
bool BlenderSession::print_render_stats = false;
BlenderSession::BlenderSession(BL::RenderEngine &b_engine,
@@ -73,7 +72,8 @@ BlenderSession::BlenderSession(BL::RenderEngine &b_engine,
width(0),
height(0),
preview_osl(preview_osl),
python_thread_state(NULL)
python_thread_state(NULL),
use_developer_ui(false)
{
/* offline render */
background = true;
@@ -103,7 +103,9 @@ BlenderSession::BlenderSession(BL::RenderEngine &b_engine,
width(width),
height(height),
preview_osl(false),
python_thread_state(NULL)
python_thread_state(NULL),
use_developer_ui(b_userpref.experimental().use_cycles_debug() &&
b_userpref.view().show_developer_ui())
{
/* 3d view render */
background = false;
@@ -119,10 +121,10 @@ BlenderSession::~BlenderSession()
void BlenderSession::create_session()
{
SessionParams session_params = BlenderSync::get_session_params(
const SessionParams session_params = BlenderSync::get_session_params(
b_engine, b_userpref, b_scene, background);
SceneParams scene_params = BlenderSync::get_scene_params(b_scene, background);
bool session_pause = BlenderSync::get_session_pause(b_scene, background);
const SceneParams scene_params = BlenderSync::get_scene_params(b_scene, background);
const bool session_pause = BlenderSync::get_session_pause(b_scene, background);
/* reset status/progress */
last_status = "";
@@ -131,20 +133,18 @@ void BlenderSession::create_session()
start_resize_time = 0.0;
/* create session */
session = new Session(session_params);
session->scene = scene;
session = new Session(session_params, scene_params);
session->progress.set_update_callback(function_bind(&BlenderSession::tag_redraw, this));
session->progress.set_cancel_callback(function_bind(&BlenderSession::test_cancel, this));
session->set_pause(session_pause);
/* create scene */
scene = new Scene(scene_params, session->device);
scene = session->scene;
scene->name = b_scene.name();
session->scene = scene;
/* create sync */
sync = new BlenderSync(b_engine, b_data, b_scene, scene, !background, session->progress);
sync = new BlenderSync(
b_engine, b_data, b_scene, scene, !background, use_developer_ui, session->progress);
BL::Object b_camera_override(b_engine.camera_override());
if (b_v3d) {
sync->sync_view(b_v3d, b_rv3d, width, height);
@@ -154,13 +154,27 @@ void BlenderSession::create_session()
}
/* set buffer parameters */
BufferParams buffer_params = BlenderSync::get_buffer_params(
b_v3d, b_rv3d, scene->camera, width, height, session_params.denoising.use);
session->reset(buffer_params, session_params.samples);
const BufferParams buffer_params = BlenderSync::get_buffer_params(
b_v3d, b_rv3d, scene->camera, width, height);
session->reset(session_params, buffer_params);
b_engine.use_highlight_tiles(session_params.progressive_refine == false);
/* Create GPU display.
* TODO(sergey): Investigate whether DisplayDriver can be used for the preview as well. */
if (!b_engine.is_preview() && !headless) {
unique_ptr<BlenderDisplayDriver> display_driver = make_unique<BlenderDisplayDriver>(b_engine,
b_scene);
display_driver_ = display_driver.get();
session->set_display_driver(move(display_driver));
}
update_resumable_tile_manager(session_params.samples);
/* Viewport and preview (as in, material preview) does not do tiled rendering, so can inform
* engine that no tracking of the tiles state is needed.
* The offline rendering will make a decision when tile is being written. The penalty of asking
* the engine to keep track of tiles state is minimal, so there is nothing to worry about here
* about possible single-tiled final render. */
if (!b_engine.is_preview() && !b_v3d) {
b_engine.use_highlight_tiles(true);
}
}
void BlenderSession::reset_session(BL::BlendData &b_data, BL::Depsgraph &b_depsgraph)
@@ -202,9 +216,9 @@ void BlenderSession::reset_session(BL::BlendData &b_data, BL::Depsgraph &b_depsg
return;
}
SessionParams session_params = BlenderSync::get_session_params(
const SessionParams session_params = BlenderSync::get_session_params(
b_engine, b_userpref, b_scene, background);
SceneParams scene_params = BlenderSync::get_scene_params(b_scene, background);
const SceneParams scene_params = BlenderSync::get_scene_params(b_scene, background);
if (scene->params.modified(scene_params) || session->params.modified(session_params) ||
!this->b_render.use_persistent_data()) {
@@ -220,8 +234,6 @@ void BlenderSession::reset_session(BL::BlendData &b_data, BL::Depsgraph &b_depsg
session->progress.reset();
session->tile_manager.set_tile_order(session_params.tile_order);
/* peak memory usage should show current render peak, not peak for all renders
* made by this render session
*/
@@ -230,7 +242,8 @@ void BlenderSession::reset_session(BL::BlendData &b_data, BL::Depsgraph &b_depsg
if (is_new_session) {
/* Sync object should be re-created for new scene. */
delete sync;
sync = new BlenderSync(b_engine, b_data, b_scene, scene, !background, session->progress);
sync = new BlenderSync(
b_engine, b_data, b_scene, scene, !background, use_developer_ui, session->progress);
}
else {
/* Sync recalculations to do just the required updates. */
@@ -242,171 +255,35 @@ void BlenderSession::reset_session(BL::BlendData &b_data, BL::Depsgraph &b_depsg
BL::SpaceView3D b_null_space_view3d(PointerRNA_NULL);
BL::RegionView3D b_null_region_view3d(PointerRNA_NULL);
BufferParams buffer_params = BlenderSync::get_buffer_params(b_null_space_view3d,
b_null_region_view3d,
scene->camera,
width,
height,
session_params.denoising.use);
session->reset(buffer_params, session_params.samples);
b_engine.use_highlight_tiles(session_params.progressive_refine == false);
const BufferParams buffer_params = BlenderSync::get_buffer_params(
b_null_space_view3d, b_null_region_view3d, scene->camera, width, height);
session->reset(session_params, buffer_params);
/* reset time */
start_resize_time = 0.0;
{
thread_scoped_lock lock(draw_state_.mutex);
draw_state_.last_pass_index = -1;
}
}
void BlenderSession::free_session()
{
session->cancel();
if (session) {
session->cancel(true);
}
delete sync;
sync = nullptr;
delete session;
session = nullptr;
}
static ShaderEvalType get_shader_type(const string &pass_type)
void BlenderSession::full_buffer_written(string_view filename)
{
const char *shader_type = pass_type.c_str();
/* data passes */
if (strcmp(shader_type, "NORMAL") == 0)
return SHADER_EVAL_NORMAL;
else if (strcmp(shader_type, "UV") == 0)
return SHADER_EVAL_UV;
else if (strcmp(shader_type, "ROUGHNESS") == 0)
return SHADER_EVAL_ROUGHNESS;
else if (strcmp(shader_type, "DIFFUSE_COLOR") == 0)
return SHADER_EVAL_DIFFUSE_COLOR;
else if (strcmp(shader_type, "GLOSSY_COLOR") == 0)
return SHADER_EVAL_GLOSSY_COLOR;
else if (strcmp(shader_type, "TRANSMISSION_COLOR") == 0)
return SHADER_EVAL_TRANSMISSION_COLOR;
else if (strcmp(shader_type, "EMIT") == 0)
return SHADER_EVAL_EMISSION;
/* light passes */
else if (strcmp(shader_type, "AO") == 0)
return SHADER_EVAL_AO;
else if (strcmp(shader_type, "COMBINED") == 0)
return SHADER_EVAL_COMBINED;
else if (strcmp(shader_type, "SHADOW") == 0)
return SHADER_EVAL_SHADOW;
else if (strcmp(shader_type, "DIFFUSE") == 0)
return SHADER_EVAL_DIFFUSE;
else if (strcmp(shader_type, "GLOSSY") == 0)
return SHADER_EVAL_GLOSSY;
else if (strcmp(shader_type, "TRANSMISSION") == 0)
return SHADER_EVAL_TRANSMISSION;
/* extra */
else if (strcmp(shader_type, "ENVIRONMENT") == 0)
return SHADER_EVAL_ENVIRONMENT;
else
return SHADER_EVAL_BAKE;
}
static BL::RenderResult begin_render_result(BL::RenderEngine &b_engine,
int x,
int y,
int w,
int h,
const char *layername,
const char *viewname)
{
return b_engine.begin_result(x, y, w, h, layername, viewname);
}
static void end_render_result(BL::RenderEngine &b_engine,
BL::RenderResult &b_rr,
bool cancel,
bool highlight,
bool do_merge_results)
{
b_engine.end_result(b_rr, (int)cancel, (int)highlight, (int)do_merge_results);
}
void BlenderSession::do_write_update_render_tile(RenderTile &rtile,
bool do_update_only,
bool do_read_only,
bool highlight)
{
int x = rtile.x - session->tile_manager.params.full_x;
int y = rtile.y - session->tile_manager.params.full_y;
int w = rtile.w;
int h = rtile.h;
/* get render result */
BL::RenderResult b_rr = begin_render_result(
b_engine, x, y, w, h, b_rlay_name.c_str(), b_rview_name.c_str());
/* can happen if the intersected rectangle gives 0 width or height */
if (b_rr.ptr.data == NULL) {
return;
}
BL::RenderResult::layers_iterator b_single_rlay;
b_rr.layers.begin(b_single_rlay);
/* layer will be missing if it was disabled in the UI */
if (b_single_rlay == b_rr.layers.end())
return;
BL::RenderLayer b_rlay = *b_single_rlay;
if (do_read_only) {
/* copy each pass */
for (BL::RenderPass &b_pass : b_rlay.passes) {
/* find matching pass type */
PassType pass_type = BlenderSync::get_pass_type(b_pass);
int components = b_pass.channels();
rtile.buffers->set_pass_rect(
pass_type, components, (float *)b_pass.rect(), rtile.num_samples);
}
end_render_result(b_engine, b_rr, false, false, false);
}
else if (do_update_only) {
/* Sample would be zero at initial tile update, which is only needed
* to tag tile form blender side as IN PROGRESS for proper highlight
* no buffers should be sent to blender yet. For denoise we also
* keep showing the noisy buffers until denoise is done. */
bool merge = (rtile.sample != 0) && (rtile.task != RenderTile::DENOISE);
if (merge) {
update_render_result(b_rlay, rtile);
}
end_render_result(b_engine, b_rr, true, highlight, merge);
}
else {
/* Write final render result. */
write_render_result(b_rlay, rtile);
end_render_result(b_engine, b_rr, false, false, true);
}
}
void BlenderSession::read_render_tile(RenderTile &rtile)
{
do_write_update_render_tile(rtile, false, true, false);
}
void BlenderSession::write_render_tile(RenderTile &rtile)
{
do_write_update_render_tile(rtile, false, false, false);
}
void BlenderSession::update_render_tile(RenderTile &rtile, bool highlight)
{
/* use final write for preview renders, otherwise render result wouldn't be
* be updated in blender side
* would need to be investigated a bit further, but for now shall be fine
*/
if (!b_engine.is_preview())
do_write_update_render_tile(rtile, true, false, highlight);
else
do_write_update_render_tile(rtile, false, false, false);
full_buffer_files_.emplace_back(filename);
}
static void add_cryptomatte_layer(BL::RenderResult &b_rr, string name, string manifest)
@@ -430,12 +307,15 @@ void BlenderSession::stamp_view_layer_metadata(Scene *scene, const string &view_
to_string(session->params.samples).c_str());
/* Store ranged samples information. */
/* TODO(sergey): Need to bring this information back. */
#if 0
if (session->tile_manager.range_num_samples != -1) {
b_rr.stamp_data_add_field((prefix + "range_start_sample").c_str(),
to_string(session->tile_manager.range_start_sample).c_str());
b_rr.stamp_data_add_field((prefix + "range_num_samples").c_str(),
to_string(session->tile_manager.range_num_samples).c_str());
}
#endif
/* Write cryptomatte metadata. */
if (scene->film->get_cryptomatte_passes() & CRYPT_OBJECT) {
@@ -474,39 +354,35 @@ void BlenderSession::render(BL::Depsgraph &b_depsgraph_)
return;
}
/* set callback to write out render results */
session->write_render_tile_cb = function_bind(&BlenderSession::write_render_tile, this, _1);
session->update_render_tile_cb = function_bind(
&BlenderSession::update_render_tile, this, _1, _2);
/* Create driver to write out render results. */
session->set_output_driver(make_unique<BlenderOutputDriver>(b_engine));
session->full_buffer_written_cb = [&](string_view filename) { full_buffer_written(filename); };
BL::ViewLayer b_view_layer = b_depsgraph.view_layer_eval();
/* get buffer parameters */
SessionParams session_params = BlenderSync::get_session_params(
b_engine, b_userpref, b_scene, background, b_view_layer);
const SessionParams session_params = BlenderSync::get_session_params(
b_engine, b_userpref, b_scene, background);
BufferParams buffer_params = BlenderSync::get_buffer_params(
b_v3d, b_rv3d, scene->camera, width, height, session_params.denoising.use);
b_v3d, b_rv3d, scene->camera, width, height);
/* temporary render result to find needed passes and views */
BL::RenderResult b_rr = begin_render_result(
b_engine, 0, 0, 1, 1, b_view_layer.name().c_str(), NULL);
BL::RenderResult b_rr = b_engine.begin_result(0, 0, 1, 1, b_view_layer.name().c_str(), NULL);
BL::RenderResult::layers_iterator b_single_rlay;
b_rr.layers.begin(b_single_rlay);
BL::RenderLayer b_rlay = *b_single_rlay;
b_rlay_name = b_view_layer.name();
/* Update denoising parameters. */
session->set_denoising(session_params.denoising);
{
thread_scoped_lock lock(draw_state_.mutex);
b_rlay_name = b_view_layer.name();
/* Signal that the display pass is to be updated. */
draw_state_.last_pass_index = -1;
}
/* Compute render passes and film settings. */
vector<Pass> passes = sync->sync_render_passes(
b_scene, b_rlay, b_view_layer, session_params.adaptive_sampling, session_params.denoising);
/* Set buffer params, using film settings from sync_render_passes. */
buffer_params.passes = passes;
buffer_params.denoising_data_pass = scene->film->get_denoising_data_pass();
buffer_params.denoising_clean_pass = scene->film->get_denoising_clean_pass();
buffer_params.denoising_prefiltered_pass = scene->film->get_denoising_prefiltered_pass();
sync->sync_render_passes(b_rlay, b_view_layer);
BL::RenderResult::views_iterator b_view_iter;
@@ -520,6 +396,9 @@ void BlenderSession::render(BL::Depsgraph &b_depsgraph_)
++b_view_iter, ++view_index) {
b_rview_name = b_view_iter->name();
buffer_params.layer = b_view_layer.name();
buffer_params.view = b_rview_name;
/* set the current view */
b_engine.active_view_set(b_rview_name.c_str());
@@ -549,20 +428,16 @@ void BlenderSession::render(BL::Depsgraph &b_depsgraph_)
}
/* Update number of samples per layer. */
int samples = sync->get_layer_samples();
bool bound_samples = sync->get_layer_bound_samples();
int effective_layer_samples;
const int samples = sync->get_layer_samples();
const bool bound_samples = sync->get_layer_bound_samples();
if (samples != 0 && (!bound_samples || (samples < session_params.samples)))
effective_layer_samples = samples;
else
effective_layer_samples = session_params.samples;
/* Update tile manager if we're doing resumable render. */
update_resumable_tile_manager(effective_layer_samples);
SessionParams effective_session_params = session_params;
if (samples != 0 && (!bound_samples || (samples < session_params.samples))) {
effective_session_params.samples = samples;
}
/* Update session itself. */
session->reset(buffer_params, effective_layer_samples);
session->reset(effective_session_params, buffer_params);
/* render */
if (!b_engine.is_preview() && background && print_render_stats) {
@@ -586,65 +461,155 @@ void BlenderSession::render(BL::Depsgraph &b_depsgraph_)
stamp_view_layer_metadata(scene, b_rlay_name);
/* free result without merging */
end_render_result(b_engine, b_rr, true, true, false);
b_engine.end_result(b_rr, true, false, false);
/* When tiled rendering is used there will be no "write" done for the tile. Forcefully clear
* highlighted tiles now, so that the highlight will be removed while processing full frame from
* file. */
b_engine.tile_highlight_clear_all();
double total_time, render_time;
session->progress.get_time(total_time, render_time);
VLOG(1) << "Total render time: " << total_time;
VLOG(1) << "Render time (without synchronization): " << render_time;
/* clear callback */
session->write_render_tile_cb = function_null;
session->update_render_tile_cb = function_null;
}
static int bake_pass_filter_get(const int pass_filter)
void BlenderSession::render_frame_finish()
{
int flag = BAKE_FILTER_NONE;
/* Processing of all layers and views is done. Clear the strings so that we can communicate
* progress about reading files and denoising them. */
b_rlay_name = "";
b_rview_name = "";
if ((pass_filter & BL::BakeSettings::pass_filter_DIRECT) != 0)
flag |= BAKE_FILTER_DIRECT;
if ((pass_filter & BL::BakeSettings::pass_filter_INDIRECT) != 0)
flag |= BAKE_FILTER_INDIRECT;
if ((pass_filter & BL::BakeSettings::pass_filter_COLOR) != 0)
flag |= BAKE_FILTER_COLOR;
if (!b_render.use_persistent_data()) {
/* Free the sync object so that it can properly dereference nodes from the scene graph before
* the graph is freed. */
delete sync;
sync = nullptr;
if ((pass_filter & BL::BakeSettings::pass_filter_DIFFUSE) != 0)
flag |= BAKE_FILTER_DIFFUSE;
if ((pass_filter & BL::BakeSettings::pass_filter_GLOSSY) != 0)
flag |= BAKE_FILTER_GLOSSY;
if ((pass_filter & BL::BakeSettings::pass_filter_TRANSMISSION) != 0)
flag |= BAKE_FILTER_TRANSMISSION;
session->device_free();
}
if ((pass_filter & BL::BakeSettings::pass_filter_EMIT) != 0)
flag |= BAKE_FILTER_EMISSION;
if ((pass_filter & BL::BakeSettings::pass_filter_AO) != 0)
flag |= BAKE_FILTER_AO;
for (string_view filename : full_buffer_files_) {
session->process_full_buffer_from_disk(filename);
if (check_and_report_session_error()) {
break;
}
}
return flag;
for (string_view filename : full_buffer_files_) {
path_remove(filename);
}
/* Clear driver. */
session->set_output_driver(nullptr);
session->full_buffer_written_cb = function_null;
}
static PassType bake_type_to_pass(const string &bake_type_str, const int bake_filter)
{
const char *bake_type = bake_type_str.c_str();
/* data passes */
if (strcmp(bake_type, "POSITION") == 0) {
return PASS_POSITION;
}
else if (strcmp(bake_type, "NORMAL") == 0) {
return PASS_NORMAL;
}
else if (strcmp(bake_type, "UV") == 0) {
return PASS_UV;
}
else if (strcmp(bake_type, "ROUGHNESS") == 0) {
return PASS_ROUGHNESS;
}
else if (strcmp(bake_type, "EMIT") == 0) {
return PASS_EMISSION;
}
/* light passes */
else if (strcmp(bake_type, "AO") == 0) {
return PASS_AO;
}
else if (strcmp(bake_type, "COMBINED") == 0) {
return PASS_COMBINED;
}
else if (strcmp(bake_type, "SHADOW") == 0) {
return PASS_SHADOW;
}
else if (strcmp(bake_type, "DIFFUSE") == 0) {
if ((bake_filter & BL::BakeSettings::pass_filter_DIRECT) &&
bake_filter & BL::BakeSettings::pass_filter_INDIRECT) {
return PASS_DIFFUSE;
}
else if (bake_filter & BL::BakeSettings::pass_filter_DIRECT) {
return PASS_DIFFUSE_DIRECT;
}
else if (bake_filter & BL::BakeSettings::pass_filter_INDIRECT) {
return PASS_DIFFUSE_INDIRECT;
}
else {
return PASS_DIFFUSE_COLOR;
}
}
else if (strcmp(bake_type, "GLOSSY") == 0) {
if ((bake_filter & BL::BakeSettings::pass_filter_DIRECT) &&
bake_filter & BL::BakeSettings::pass_filter_INDIRECT) {
return PASS_GLOSSY;
}
else if (bake_filter & BL::BakeSettings::pass_filter_DIRECT) {
return PASS_GLOSSY_DIRECT;
}
else if (bake_filter & BL::BakeSettings::pass_filter_INDIRECT) {
return PASS_GLOSSY_INDIRECT;
}
else {
return PASS_GLOSSY_COLOR;
}
}
else if (strcmp(bake_type, "TRANSMISSION") == 0) {
if ((bake_filter & BL::BakeSettings::pass_filter_DIRECT) &&
bake_filter & BL::BakeSettings::pass_filter_INDIRECT) {
return PASS_TRANSMISSION;
}
else if (bake_filter & BL::BakeSettings::pass_filter_DIRECT) {
return PASS_TRANSMISSION_DIRECT;
}
else if (bake_filter & BL::BakeSettings::pass_filter_INDIRECT) {
return PASS_TRANSMISSION_INDIRECT;
}
else {
return PASS_TRANSMISSION_COLOR;
}
}
/* extra */
else if (strcmp(bake_type, "ENVIRONMENT") == 0) {
return PASS_BACKGROUND;
}
return PASS_COMBINED;
}
void BlenderSession::bake(BL::Depsgraph &b_depsgraph_,
BL::Object &b_object,
const string &pass_type,
const int pass_filter,
const string &bake_type,
const int bake_filter,
const int bake_width,
const int bake_height)
{
b_depsgraph = b_depsgraph_;
ShaderEvalType shader_type = get_shader_type(pass_type);
int bake_pass_filter = bake_pass_filter_get(pass_filter);
/* Initialize bake manager, before we load the baking kernels. */
scene->bake_manager->set(scene, b_object.name(), shader_type, bake_pass_filter);
scene->bake_manager->set(scene, b_object.name());
/* Passes are identified by name, so in order to return the combined pass we need to set the
* name. */
Pass::add(PASS_COMBINED, scene->passes, "Combined");
/* Add render pass that we want to bake, and name it Combined so that it is
* used as that on the Blender side. */
Pass *pass = scene->create_node<Pass>();
pass->set_name(ustring("Combined"));
pass->set_type(bake_type_to_pass(bake_type, bake_filter));
pass->set_include_albedo((bake_filter & BL::BakeSettings::pass_filter_COLOR));
session->read_bake_tile_cb = function_bind(&BlenderSession::read_render_tile, this, _1);
session->write_render_tile_cb = function_bind(&BlenderSession::write_render_tile, this, _1);
session->set_display_driver(nullptr);
session->set_output_driver(make_unique<BlenderOutputDriver>(b_engine));
if (!session->progress.get_cancel()) {
/* Sync scene. */
@@ -667,18 +632,15 @@ void BlenderSession::bake(BL::Depsgraph &b_depsgraph_,
if (object_found && !session->progress.get_cancel()) {
/* Get session and buffer parameters. */
SessionParams session_params = BlenderSync::get_session_params(
const SessionParams session_params = BlenderSync::get_session_params(
b_engine, b_userpref, b_scene, background);
session_params.progressive_refine = false;
BufferParams buffer_params;
buffer_params.width = bake_width;
buffer_params.height = bake_height;
buffer_params.passes = scene->passes;
/* Update session. */
session->tile_manager.set_samples(session_params.samples);
session->reset(buffer_params, session_params.samples);
session->reset(session_params, buffer_params);
session->progress.set_update_callback(
function_bind(&BlenderSession::update_bake_progress, this));
@@ -690,71 +652,7 @@ void BlenderSession::bake(BL::Depsgraph &b_depsgraph_,
session->wait();
}
session->read_bake_tile_cb = function_null;
session->write_render_tile_cb = function_null;
}
void BlenderSession::do_write_update_render_result(BL::RenderLayer &b_rlay,
RenderTile &rtile,
bool do_update_only)
{
RenderBuffers *buffers = rtile.buffers;
/* copy data from device */
if (!buffers->copy_from_device())
return;
float exposure = scene->film->get_exposure();
vector<float> pixels(rtile.w * rtile.h * 4);
/* Adjust absolute sample number to the range. */
int sample = rtile.sample;
const int range_start_sample = session->tile_manager.range_start_sample;
if (range_start_sample != -1) {
sample -= range_start_sample;
}
if (!do_update_only) {
/* copy each pass */
for (BL::RenderPass &b_pass : b_rlay.passes) {
int components = b_pass.channels();
/* Copy pixels from regular render passes. */
bool read = buffers->get_pass_rect(b_pass.name(), exposure, sample, components, &pixels[0]);
/* If denoising pass, */
if (!read) {
int denoising_offset = BlenderSync::get_denoising_pass(b_pass);
if (denoising_offset >= 0) {
read = buffers->get_denoising_pass_rect(
denoising_offset, exposure, sample, components, &pixels[0]);
}
}
if (!read) {
memset(&pixels[0], 0, pixels.size() * sizeof(float));
}
b_pass.rect(&pixels[0]);
}
}
else {
/* copy combined pass */
BL::RenderPass b_combined_pass(b_rlay.passes.find_by_name("Combined", b_rview_name.c_str()));
if (buffers->get_pass_rect("Combined", exposure, sample, 4, &pixels[0]))
b_combined_pass.rect(&pixels[0]);
}
}
void BlenderSession::write_render_result(BL::RenderLayer &b_rlay, RenderTile &rtile)
{
do_write_update_render_result(b_rlay, rtile, false);
}
void BlenderSession::update_render_result(BL::RenderLayer &b_rlay, RenderTile &rtile)
{
do_write_update_render_result(b_rlay, rtile, true);
session->set_output_driver(nullptr);
}
void BlenderSession::synchronize(BL::Depsgraph &b_depsgraph_)
@@ -764,19 +662,19 @@ void BlenderSession::synchronize(BL::Depsgraph &b_depsgraph_)
return;
/* on session/scene parameter changes, we recreate session entirely */
SessionParams session_params = BlenderSync::get_session_params(
const SessionParams session_params = BlenderSync::get_session_params(
b_engine, b_userpref, b_scene, background);
SceneParams scene_params = BlenderSync::get_scene_params(b_scene, background);
bool session_pause = BlenderSync::get_session_pause(b_scene, background);
const SceneParams scene_params = BlenderSync::get_scene_params(b_scene, background);
const bool session_pause = BlenderSync::get_session_pause(b_scene, background);
if (session->params.modified(session_params) || scene->params.modified(scene_params)) {
free_session();
create_session();
}
/* increase samples, but never decrease */
/* increase samples and render time, but never decrease */
session->set_samples(session_params.samples);
session->set_denoising_start_sample(session_params.denoising.start_sample);
session->set_time_limit(session_params.time_limit);
session->set_pause(session_pause);
/* copy recalc flags, outside of mutex so we can decide to do the real
@@ -808,21 +706,12 @@ void BlenderSession::synchronize(BL::Depsgraph &b_depsgraph_)
sync->sync_camera(b_render, b_camera_override, width, height, "");
/* get buffer parameters */
BufferParams buffer_params = BlenderSync::get_buffer_params(
b_v3d, b_rv3d, scene->camera, width, height, session_params.denoising.use);
if (!buffer_params.denoising_data_pass) {
session_params.denoising.use = false;
}
session->set_denoising(session_params.denoising);
/* Update film if denoising data was enabled or disabled. */
scene->film->set_denoising_data_pass(buffer_params.denoising_data_pass);
const BufferParams buffer_params = BlenderSync::get_buffer_params(
b_v3d, b_rv3d, scene->camera, width, height);
/* reset if needed */
if (scene->need_reset()) {
session->reset(buffer_params, session_params.samples);
session->reset(session_params, buffer_params);
/* After session reset, so device is not accessing image data anymore. */
builtin_images_load();
@@ -839,7 +728,44 @@ void BlenderSession::synchronize(BL::Depsgraph &b_depsgraph_)
session->start();
}
bool BlenderSession::draw(int w, int h)
void BlenderSession::draw(BL::SpaceImageEditor &space_image)
{
if (!session || !session->scene) {
/* Offline render drawing does not force the render engine update, which means it's possible
* that the Session is not created yet. */
return;
}
thread_scoped_lock lock(draw_state_.mutex);
const int pass_index = space_image.image_user().multilayer_pass();
if (pass_index != draw_state_.last_pass_index) {
BL::RenderPass b_display_pass(b_engine.pass_by_index_get(b_rlay_name.c_str(), pass_index));
if (!b_display_pass) {
return;
}
Scene *scene = session->scene;
thread_scoped_lock lock(scene->mutex);
const Pass *pass = Pass::find(scene->passes, b_display_pass.name());
if (!pass) {
return;
}
scene->film->set_display_pass(pass->get_type());
draw_state_.last_pass_index = pass_index;
}
BL::Array<float, 2> zoom = space_image.zoom();
display_driver_->set_zoom(zoom[0], zoom[1]);
session->draw();
}
void BlenderSession::view_draw(int w, int h)
{
/* pause in redraw in case update is not being called due to final render */
session->set_pause(BlenderSync::get_session_pause(b_scene, background));
@@ -885,14 +811,14 @@ bool BlenderSession::draw(int w, int h)
/* reset if requested */
if (reset) {
SessionParams session_params = BlenderSync::get_session_params(
const SessionParams session_params = BlenderSync::get_session_params(
b_engine, b_userpref, b_scene, background);
BufferParams buffer_params = BlenderSync::get_buffer_params(
b_v3d, b_rv3d, scene->camera, width, height, session_params.denoising.use);
bool session_pause = BlenderSync::get_session_pause(b_scene, background);
const BufferParams buffer_params = BlenderSync::get_buffer_params(
b_v3d, b_rv3d, scene->camera, width, height);
const bool session_pause = BlenderSync::get_session_pause(b_scene, background);
if (session_pause == false) {
session->reset(buffer_params, session_params.samples);
session->reset(session_params, buffer_params);
start_resize_time = 0.0;
}
}
@@ -905,18 +831,7 @@ bool BlenderSession::draw(int w, int h)
update_status_progress();
/* draw */
BufferParams buffer_params = BlenderSync::get_buffer_params(
b_v3d, b_rv3d, scene->camera, width, height, session->params.denoising.use);
DeviceDrawParams draw_params;
if (session->params.display_buffer_linear) {
draw_params.bind_display_space_shader_cb = function_bind(
&BL::RenderEngine::bind_display_space_shader, &b_engine, b_scene);
draw_params.unbind_display_space_shader_cb = function_bind(
&BL::RenderEngine::unbind_display_space_shader, &b_engine);
}
return !session->draw(buffer_params, draw_params);
session->draw();
}
void BlenderSession::get_status(string &status, string &substatus)
@@ -924,11 +839,6 @@ void BlenderSession::get_status(string &status, string &substatus)
session->progress.get_status(status, substatus);
}
void BlenderSession::get_kernel_status(string &kernel_status)
{
session->progress.get_kernel_status(kernel_status);
}
void BlenderSession::get_progress(float &progress, double &total_time, double &render_time)
{
session->progress.get_time(total_time, render_time);
@@ -947,7 +857,7 @@ void BlenderSession::update_bake_progress()
void BlenderSession::update_status_progress()
{
string timestatus, status, substatus, kernel_status;
string timestatus, status, substatus;
string scene_status = "";
float progress;
double total_time, remaining_time = 0, render_time;
@@ -955,11 +865,11 @@ void BlenderSession::update_status_progress()
float mem_peak = (float)session->stats.mem_peak / 1024.0f / 1024.0f;
get_status(status, substatus);
get_kernel_status(kernel_status);
get_progress(progress, total_time, render_time);
if (progress > 0)
remaining_time = (1.0 - (double)progress) * (render_time / (double)progress);
if (progress > 0) {
remaining_time = session->get_estimated_remaining_time();
}
if (background) {
if (scene)
@@ -980,14 +890,12 @@ void BlenderSession::update_status_progress()
status = " | " + status;
if (substatus.size() > 0)
status += " | " + substatus;
if (kernel_status.size() > 0)
status += " | " + kernel_status;
}
double current_time = time_dt();
/* When rendering in a window, redraw the status at least once per second to keep the elapsed and
* remaining time up-to-date. For headless rendering, only report when something significant
* changes to keep the console output readable. */
/* When rendering in a window, redraw the status at least once per second to keep the elapsed
* and remaining time up-to-date. For headless rendering, only report when something
* significant changes to keep the console output readable. */
if (status != last_status || (!headless && (current_time - last_status_time) > 1.0)) {
b_engine.update_stats("", (timestatus + scene_status + status).c_str());
b_engine.update_memory_stats(mem_used, mem_peak);
@@ -999,20 +907,27 @@ void BlenderSession::update_status_progress()
last_progress = progress;
}
if (session->progress.get_error()) {
string error = session->progress.get_error_message();
if (error != last_error) {
/* TODO(sergey): Currently C++ RNA API doesn't let us to
* use mnemonic name for the variable. Would be nice to
* have this figured out.
*
* For until then, 1 << 5 means RPT_ERROR.
*/
b_engine.report(1 << 5, error.c_str());
b_engine.error_set(error.c_str());
last_error = error;
}
check_and_report_session_error();
}
bool BlenderSession::check_and_report_session_error()
{
if (!session->progress.get_error()) {
return false;
}
const string error = session->progress.get_error_message();
if (error != last_error) {
/* TODO(sergey): Currently C++ RNA API doesn't let us to use mnemonic name for the variable.
* Would be nice to have this figured out.
*
* For until then, 1 << 5 means RPT_ERROR. */
b_engine.report(1 << 5, error.c_str());
b_engine.error_set(error.c_str());
last_error = error;
}
return true;
}
void BlenderSession::tag_update()
@@ -1048,56 +963,6 @@ void BlenderSession::test_cancel()
session->progress.set_cancel("Cancelled");
}
void BlenderSession::update_resumable_tile_manager(int num_samples)
{
const int num_resumable_chunks = BlenderSession::num_resumable_chunks,
current_resumable_chunk = BlenderSession::current_resumable_chunk;
if (num_resumable_chunks == 0) {
return;
}
if (num_resumable_chunks > num_samples) {
fprintf(stderr,
"Cycles warning: more sample chunks (%d) than samples (%d), "
"this will cause some samples to be included in multiple chunks.\n",
num_resumable_chunks,
num_samples);
}
const float num_samples_per_chunk = (float)num_samples / num_resumable_chunks;
float range_start_sample, range_num_samples;
if (current_resumable_chunk != 0) {
/* Single chunk rendering. */
range_start_sample = num_samples_per_chunk * (current_resumable_chunk - 1);
range_num_samples = num_samples_per_chunk;
}
else {
/* Ranged-chunks. */
const int num_chunks = end_resumable_chunk - start_resumable_chunk + 1;
range_start_sample = num_samples_per_chunk * (start_resumable_chunk - 1);
range_num_samples = num_chunks * num_samples_per_chunk;
}
/* Round after doing the multiplications with num_chunks and num_samples_per_chunk
* to allow for many small chunks. */
int rounded_range_start_sample = (int)floorf(range_start_sample + 0.5f);
int rounded_range_num_samples = max((int)floorf(range_num_samples + 0.5f), 1);
/* Make sure we don't overshoot. */
if (rounded_range_start_sample + rounded_range_num_samples > num_samples) {
rounded_range_num_samples = num_samples - rounded_range_num_samples;
}
VLOG(1) << "Samples range start is " << range_start_sample << ", "
<< "number of samples to render is " << range_num_samples;
scene->integrator->set_start_sample(rounded_range_start_sample);
session->tile_manager.range_start_sample = rounded_range_start_sample;
session->tile_manager.range_num_samples = rounded_range_num_samples;
}
void BlenderSession::free_blender_memory_if_possible()
{
if (!background) {

View File

@@ -29,12 +29,11 @@
CCL_NAMESPACE_BEGIN
class BlenderDisplayDriver;
class BlenderSync;
class ImageMetaData;
class Scene;
class Session;
class RenderBuffers;
class RenderTile;
class BlenderSession {
public:
@@ -62,6 +61,8 @@ class BlenderSession {
/* offline render */
void render(BL::Depsgraph &b_depsgraph);
void render_frame_finish();
void bake(BL::Depsgraph &b_depsgrah,
BL::Object &b_object,
const string &pass_type,
@@ -69,24 +70,16 @@ class BlenderSession {
const int bake_width,
const int bake_height);
void write_render_result(BL::RenderLayer &b_rlay, RenderTile &rtile);
void write_render_tile(RenderTile &rtile);
void read_render_tile(RenderTile &rtile);
/* update functions are used to update display buffer only after sample was rendered
* only needed for better visual feedback */
void update_render_result(BL::RenderLayer &b_rlay, RenderTile &rtile);
void update_render_tile(RenderTile &rtile, bool highlight);
void full_buffer_written(string_view filename);
/* interactive updates */
void synchronize(BL::Depsgraph &b_depsgraph);
/* drawing */
bool draw(int w, int h);
void draw(BL::SpaceImageEditor &space_image);
void view_draw(int w, int h);
void tag_redraw();
void tag_update();
void get_status(string &status, string &substatus);
void get_kernel_status(string &kernel_status);
void get_progress(float &progress, double &total_time, double &render_time);
void test_cancel();
void update_status_progress();
@@ -104,8 +97,7 @@ class BlenderSession {
BL::RenderSettings b_render;
BL::Depsgraph b_depsgraph;
/* NOTE: Blender's scene might become invalid after call
* free_blender_memory_if_possible().
*/
* #free_blender_memory_if_possible(). */
BL::Scene b_scene;
BL::SpaceView3D b_v3d;
BL::RegionView3D b_rv3d;
@@ -123,6 +115,8 @@ class BlenderSession {
void *python_thread_state;
bool use_developer_ui;
/* Global state which is common for all render sessions created from Blender.
* Usually denotes command line arguments.
*/
@@ -134,41 +128,33 @@ class BlenderSession {
*/
static bool headless;
/* ** Resumable render ** */
/* Overall number of chunks in which the sample range is to be divided. */
static int num_resumable_chunks;
/* Current resumable chunk index to render. */
static int current_resumable_chunk;
/* Alternative to single-chunk rendering to render a range of chunks. */
static int start_resumable_chunk;
static int end_resumable_chunk;
static bool print_render_stats;
protected:
void stamp_view_layer_metadata(Scene *scene, const string &view_layer_name);
void do_write_update_render_result(BL::RenderLayer &b_rlay,
RenderTile &rtile,
bool do_update_only);
void do_write_update_render_tile(RenderTile &rtile,
bool do_update_only,
bool do_read_only,
bool highlight);
/* Check whether session error happened.
* If so, it is reported to the render engine and true is returned.
* Otherwise false is returned. */
bool check_and_report_session_error();
void builtin_images_load();
/* Update tile manager to reflect resumable render settings. */
void update_resumable_tile_manager(int num_samples);
/* Is used after each render layer synchronization is done with the goal
* of freeing render engine data which is held from Blender side (for
* example, dependency graph).
*/
void free_blender_memory_if_possible();
struct {
thread_mutex mutex;
int last_pass_index = -1;
} draw_state_;
/* NOTE: The BlenderSession references the display driver. */
BlenderDisplayDriver *display_driver_ = nullptr;
vector<string> full_buffer_files_;
};
CCL_NAMESPACE_END

View File

@@ -17,6 +17,7 @@
#include "render/background.h"
#include "render/colorspace.h"
#include "render/graph.h"
#include "render/integrator.h"
#include "render/light.h"
#include "render/nodes.h"
#include "render/osl.h"
@@ -278,7 +279,7 @@ static ShaderNode *add_node(Scene *scene,
array<float3> curve_mapping_curves;
float min_x, max_x;
curvemapping_color_to_array(mapping, curve_mapping_curves, RAMP_TABLE_SIZE, true);
curvemapping_minmax(mapping, true, &min_x, &max_x);
curvemapping_minmax(mapping, 4, &min_x, &max_x);
curves->set_min_x(min_x);
curves->set_max_x(max_x);
curves->set_curves(curve_mapping_curves);
@@ -291,12 +292,25 @@ static ShaderNode *add_node(Scene *scene,
array<float3> curve_mapping_curves;
float min_x, max_x;
curvemapping_color_to_array(mapping, curve_mapping_curves, RAMP_TABLE_SIZE, false);
curvemapping_minmax(mapping, false, &min_x, &max_x);
curvemapping_minmax(mapping, 3, &min_x, &max_x);
curves->set_min_x(min_x);
curves->set_max_x(max_x);
curves->set_curves(curve_mapping_curves);
node = curves;
}
else if (b_node.is_a(&RNA_ShaderNodeFloatCurve)) {
BL::ShaderNodeFloatCurve b_curve_node(b_node);
BL::CurveMapping mapping(b_curve_node.mapping());
FloatCurveNode *curve = graph->create_node<FloatCurveNode>();
array<float> curve_mapping_curve;
float min_x, max_x;
curvemapping_float_to_array(mapping, curve_mapping_curve, RAMP_TABLE_SIZE);
curvemapping_minmax(mapping, 1, &min_x, &max_x);
curve->set_min_x(min_x);
curve->set_max_x(max_x);
curve->set_curve(curve_mapping_curve);
node = curve;
}
else if (b_node.is_a(&RNA_ShaderNodeValToRGB)) {
RGBRampNode *ramp = graph->create_node<RGBRampNode>();
BL::ShaderNodeValToRGB b_ramp_node(b_node);
@@ -475,17 +489,11 @@ static ShaderNode *add_node(Scene *scene,
SubsurfaceScatteringNode *subsurface = graph->create_node<SubsurfaceScatteringNode>();
switch (b_subsurface_node.falloff()) {
case BL::ShaderNodeSubsurfaceScattering::falloff_CUBIC:
subsurface->set_falloff(CLOSURE_BSSRDF_CUBIC_ID);
break;
case BL::ShaderNodeSubsurfaceScattering::falloff_GAUSSIAN:
subsurface->set_falloff(CLOSURE_BSSRDF_GAUSSIAN_ID);
break;
case BL::ShaderNodeSubsurfaceScattering::falloff_BURLEY:
subsurface->set_falloff(CLOSURE_BSSRDF_BURLEY_ID);
case BL::ShaderNodeSubsurfaceScattering::falloff_RANDOM_WALK_FIXED_RADIUS:
subsurface->set_method(CLOSURE_BSSRDF_RANDOM_WALK_FIXED_RADIUS_ID);
break;
case BL::ShaderNodeSubsurfaceScattering::falloff_RANDOM_WALK:
subsurface->set_falloff(CLOSURE_BSSRDF_RANDOM_WALK_ID);
subsurface->set_method(CLOSURE_BSSRDF_RANDOM_WALK_ID);
break;
}
@@ -597,11 +605,11 @@ static ShaderNode *add_node(Scene *scene,
break;
}
switch (b_principled_node.subsurface_method()) {
case BL::ShaderNodeBsdfPrincipled::subsurface_method_BURLEY:
principled->set_subsurface_method(CLOSURE_BSSRDF_PRINCIPLED_ID);
case BL::ShaderNodeBsdfPrincipled::subsurface_method_RANDOM_WALK_FIXED_RADIUS:
principled->set_subsurface_method(CLOSURE_BSSRDF_RANDOM_WALK_FIXED_RADIUS_ID);
break;
case BL::ShaderNodeBsdfPrincipled::subsurface_method_RANDOM_WALK:
principled->set_subsurface_method(CLOSURE_BSSRDF_PRINCIPLED_RANDOM_WALK_ID);
principled->set_subsurface_method(CLOSURE_BSSRDF_RANDOM_WALK_ID);
break;
}
node = principled;
@@ -1360,10 +1368,11 @@ void BlenderSync::sync_materials(BL::Depsgraph &b_depsgraph, bool update_all)
void BlenderSync::sync_world(BL::Depsgraph &b_depsgraph, BL::SpaceView3D &b_v3d, bool update_all)
{
Background *background = scene->background;
Integrator *integrator = scene->integrator;
BL::World b_world = b_scene.world();
BlenderViewportParameters new_viewport_parameters(b_v3d);
BlenderViewportParameters new_viewport_parameters(b_v3d, use_developer_ui);
if (world_recalc || update_all || b_world.ptr.data != world_map ||
viewport_parameters.shader_modified(new_viewport_parameters)) {
@@ -1455,9 +1464,8 @@ void BlenderSync::sync_world(BL::Depsgraph &b_depsgraph, BL::SpaceView3D &b_v3d,
/* AO */
BL::WorldLighting b_light = b_world.light_settings();
background->set_use_ao(b_light.use_ambient_occlusion());
background->set_ao_factor(b_light.ao_factor());
background->set_ao_distance(b_light.distance());
integrator->set_ao_factor(b_light.ao_factor());
integrator->set_ao_distance(b_light.distance());
/* visibility */
PointerRNA cvisibility = RNA_pointer_get(&b_world.ptr, "cycles_visibility");
@@ -1472,9 +1480,8 @@ void BlenderSync::sync_world(BL::Depsgraph &b_depsgraph, BL::SpaceView3D &b_v3d,
background->set_visibility(visibility);
}
else {
background->set_use_ao(false);
background->set_ao_factor(0.0f);
background->set_ao_distance(FLT_MAX);
integrator->set_ao_factor(1.0f);
integrator->set_ao_distance(10.0f);
}
shader->set_graph(graph);
@@ -1496,7 +1503,6 @@ void BlenderSync::sync_world(BL::Depsgraph &b_depsgraph, BL::SpaceView3D &b_v3d,
background->set_use_shader(view_layer.use_background_shader ||
viewport_parameters.use_custom_shader());
background->set_use_ao(background->get_use_ao() && view_layer.use_background_ao);
background->tag_update(scene);
}

View File

@@ -53,6 +53,7 @@ BlenderSync::BlenderSync(BL::RenderEngine &b_engine,
BL::Scene &b_scene,
Scene *scene,
bool preview,
bool use_developer_ui,
Progress &progress)
: b_engine(b_engine),
b_data(b_data),
@@ -68,6 +69,7 @@ BlenderSync::BlenderSync(BL::RenderEngine &b_engine,
scene(scene),
preview(preview),
experimental(false),
use_developer_ui(use_developer_ui),
dicing_rate(1.0f),
max_subdivisions(12),
progress(progress),
@@ -224,7 +226,7 @@ void BlenderSync::sync_recalc(BL::Depsgraph &b_depsgraph, BL::SpaceView3D &b_v3d
}
if (b_v3d) {
BlenderViewportParameters new_viewport_parameters(b_v3d);
BlenderViewportParameters new_viewport_parameters(b_v3d, use_developer_ui);
if (viewport_parameters.shader_modified(new_viewport_parameters)) {
world_recalc = true;
@@ -251,9 +253,13 @@ void BlenderSync::sync_data(BL::RenderSettings &b_render,
BL::ViewLayer b_view_layer = b_depsgraph.view_layer_eval();
/* TODO(sergey): This feels weak to pass view layer to the integrator, and even weaker to have an
* implicit check on whether it is a background render or not. What is the nicer thing here? */
const bool background = !b_v3d;
sync_view_layer(b_view_layer);
sync_integrator();
sync_film(b_v3d);
sync_integrator(b_view_layer, background);
sync_film(b_view_layer, b_v3d);
sync_shaders(b_depsgraph, b_v3d);
sync_images();
@@ -280,7 +286,7 @@ void BlenderSync::sync_data(BL::RenderSettings &b_render,
/* Integrator */
void BlenderSync::sync_integrator()
void BlenderSync::sync_integrator(BL::ViewLayer &b_view_layer, bool background)
{
PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles");
@@ -328,59 +334,24 @@ void BlenderSync::sync_integrator()
integrator->set_motion_blur(view_layer.use_motion_blur);
}
integrator->set_method((Integrator::Method)get_enum(
cscene, "progressive", Integrator::NUM_METHODS, Integrator::PATH));
integrator->set_sample_all_lights_direct(get_boolean(cscene, "sample_all_lights_direct"));
integrator->set_sample_all_lights_indirect(get_boolean(cscene, "sample_all_lights_indirect"));
integrator->set_light_sampling_threshold(get_float(cscene, "light_sampling_threshold"));
SamplingPattern sampling_pattern = (SamplingPattern)get_enum(
cscene, "sampling_pattern", SAMPLING_NUM_PATTERNS, SAMPLING_PATTERN_SOBOL);
int adaptive_min_samples = INT_MAX;
if (RNA_boolean_get(&cscene, "use_adaptive_sampling")) {
sampling_pattern = SAMPLING_PATTERN_PMJ;
adaptive_min_samples = get_int(cscene, "adaptive_min_samples");
integrator->set_adaptive_threshold(get_float(cscene, "adaptive_threshold"));
}
else {
integrator->set_adaptive_threshold(0.0f);
}
integrator->set_sampling_pattern(sampling_pattern);
int diffuse_samples = get_int(cscene, "diffuse_samples");
int glossy_samples = get_int(cscene, "glossy_samples");
int transmission_samples = get_int(cscene, "transmission_samples");
int ao_samples = get_int(cscene, "ao_samples");
int mesh_light_samples = get_int(cscene, "mesh_light_samples");
int subsurface_samples = get_int(cscene, "subsurface_samples");
int volume_samples = get_int(cscene, "volume_samples");
if (get_boolean(cscene, "use_square_samples")) {
integrator->set_diffuse_samples(diffuse_samples * diffuse_samples);
integrator->set_glossy_samples(glossy_samples * glossy_samples);
integrator->set_transmission_samples(transmission_samples * transmission_samples);
integrator->set_ao_samples(ao_samples * ao_samples);
integrator->set_mesh_light_samples(mesh_light_samples * mesh_light_samples);
integrator->set_subsurface_samples(subsurface_samples * subsurface_samples);
integrator->set_volume_samples(volume_samples * volume_samples);
adaptive_min_samples = min(adaptive_min_samples * adaptive_min_samples, INT_MAX);
if (preview) {
integrator->set_use_adaptive_sampling(
RNA_boolean_get(&cscene, "use_preview_adaptive_sampling"));
integrator->set_adaptive_threshold(get_float(cscene, "preview_adaptive_threshold"));
integrator->set_adaptive_min_samples(get_int(cscene, "preview_adaptive_min_samples"));
}
else {
integrator->set_diffuse_samples(diffuse_samples);
integrator->set_glossy_samples(glossy_samples);
integrator->set_transmission_samples(transmission_samples);
integrator->set_ao_samples(ao_samples);
integrator->set_mesh_light_samples(mesh_light_samples);
integrator->set_subsurface_samples(subsurface_samples);
integrator->set_volume_samples(volume_samples);
integrator->set_use_adaptive_sampling(RNA_boolean_get(&cscene, "use_adaptive_sampling"));
integrator->set_adaptive_threshold(get_float(cscene, "adaptive_threshold"));
integrator->set_adaptive_min_samples(get_int(cscene, "adaptive_min_samples"));
}
integrator->set_adaptive_min_samples(adaptive_min_samples);
if (get_boolean(cscene, "use_fast_gi")) {
if (preview) {
integrator->set_ao_bounces(get_int(cscene, "ao_bounces"));
@@ -393,20 +364,38 @@ void BlenderSync::sync_integrator()
integrator->set_ao_bounces(0);
}
/* UPDATE_NONE as we don't want to tag the integrator as modified, just tag dependent things */
const DenoiseParams denoise_params = get_denoise_params(b_scene, b_view_layer, background);
integrator->set_use_denoise(denoise_params.use);
/* Only update denoiser parameters if the denoiser is actually used. This allows to tweak
* denoiser parameters before enabling it without render resetting on every change. The downside
* is that the interface and the integrator are technically out of sync. */
if (denoise_params.use) {
integrator->set_denoiser_type(denoise_params.type);
integrator->set_denoise_start_sample(denoise_params.start_sample);
integrator->set_use_denoise_pass_albedo(denoise_params.use_pass_albedo);
integrator->set_use_denoise_pass_normal(denoise_params.use_pass_normal);
integrator->set_denoiser_prefilter(denoise_params.prefilter);
}
/* UPDATE_NONE as we don't want to tag the integrator as modified (this was done by the
* set calls above), but we need to make sure that the dependent things are tagged. */
integrator->tag_update(scene, Integrator::UPDATE_NONE);
}
/* Film */
void BlenderSync::sync_film(BL::SpaceView3D &b_v3d)
void BlenderSync::sync_film(BL::ViewLayer &b_view_layer, BL::SpaceView3D &b_v3d)
{
PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles");
PointerRNA crl = RNA_pointer_get(&b_view_layer.ptr, "cycles");
Film *film = scene->film;
if (b_v3d) {
film->set_display_pass(update_viewport_display_passes(b_v3d, scene->passes));
const BlenderViewportParameters new_viewport_parameters(b_v3d, use_developer_ui);
film->set_display_pass(new_viewport_parameters.display_pass);
film->set_show_active_pixels(new_viewport_parameters.show_active_pixels);
}
film->set_exposure(get_float(cscene, "film_exposure"));
@@ -434,6 +423,15 @@ void BlenderSync::sync_film(BL::SpaceView3D &b_v3d)
break;
}
}
/* Blender viewport does not support proper shadow catcher compositing, so force an approximate
* mode to improve visual feedback. */
if (b_v3d) {
film->set_use_approximate_shadow_catcher(true);
}
else {
film->set_use_approximate_shadow_catcher(!get_boolean(crl, "use_pass_shadow_catcher"));
}
}
/* Render Layer */
@@ -444,7 +442,6 @@ void BlenderSync::sync_view_layer(BL::ViewLayer &b_view_layer)
/* Filter. */
view_layer.use_background_shader = b_view_layer.use_sky();
view_layer.use_background_ao = b_view_layer.use_ao();
/* Always enable surfaces for baking, otherwise there is nothing to bake to. */
view_layer.use_surfaces = b_view_layer.use_solid() || scene->bake_manager->get_baking();
view_layer.use_hair = b_view_layer.use_strand();
@@ -464,10 +461,7 @@ void BlenderSync::sync_view_layer(BL::ViewLayer &b_view_layer)
if (use_layer_samples != 2) {
int samples = b_view_layer.samples();
if (get_boolean(cscene, "use_square_samples"))
view_layer.samples = samples * samples;
else
view_layer.samples = samples;
view_layer.samples = samples;
}
}
@@ -499,7 +493,8 @@ void BlenderSync::sync_images()
}
/* Passes */
PassType BlenderSync::get_pass_type(BL::RenderPass &b_pass)
static PassType get_blender_pass_type(BL::RenderPass &b_pass)
{
string name = b_pass.name();
#define MAP_PASS(passname, passtype) \
@@ -507,10 +502,15 @@ PassType BlenderSync::get_pass_type(BL::RenderPass &b_pass)
return passtype; \
} \
((void)0)
/* NOTE: Keep in sync with defined names from DNA_scene_types.h */
MAP_PASS("Combined", PASS_COMBINED);
MAP_PASS("Noisy Image", PASS_COMBINED);
MAP_PASS("Depth", PASS_DEPTH);
MAP_PASS("Mist", PASS_MIST);
MAP_PASS("Position", PASS_POSITION);
MAP_PASS("Normal", PASS_NORMAL);
MAP_PASS("IndexOB", PASS_OBJECT_ID);
MAP_PASS("UV", PASS_UV);
@@ -539,118 +539,92 @@ PassType BlenderSync::get_pass_type(BL::RenderPass &b_pass)
MAP_PASS("BakePrimitive", PASS_BAKE_PRIMITIVE);
MAP_PASS("BakeDifferential", PASS_BAKE_DIFFERENTIAL);
MAP_PASS("Denoising Normal", PASS_DENOISING_NORMAL);
MAP_PASS("Denoising Albedo", PASS_DENOISING_ALBEDO);
MAP_PASS("Shadow Catcher", PASS_SHADOW_CATCHER);
MAP_PASS("Noisy Shadow Catcher", PASS_SHADOW_CATCHER);
MAP_PASS("Debug Render Time", PASS_RENDER_TIME);
MAP_PASS("AdaptiveAuxBuffer", PASS_ADAPTIVE_AUX_BUFFER);
MAP_PASS("Debug Sample Count", PASS_SAMPLE_COUNT);
if (string_startswith(name, cryptomatte_prefix)) {
return PASS_CRYPTOMATTE;
}
#undef MAP_PASS
return PASS_NONE;
}
int BlenderSync::get_denoising_pass(BL::RenderPass &b_pass)
static Pass *pass_add(Scene *scene,
PassType type,
const char *name,
PassMode mode = PassMode::DENOISED)
{
string name = b_pass.name();
Pass *pass = scene->create_node<Pass>();
if (name == "Noisy Image")
return DENOISING_PASS_PREFILTERED_COLOR;
pass->set_type(type);
pass->set_name(ustring(name));
pass->set_mode(mode);
if (name.substr(0, 10) != "Denoising ") {
return -1;
}
name = name.substr(10);
#define MAP_PASS(passname, offset) \
if (name == passname) { \
return offset; \
} \
((void)0)
MAP_PASS("Normal", DENOISING_PASS_PREFILTERED_NORMAL);
MAP_PASS("Albedo", DENOISING_PASS_PREFILTERED_ALBEDO);
MAP_PASS("Depth", DENOISING_PASS_PREFILTERED_DEPTH);
MAP_PASS("Shadowing", DENOISING_PASS_PREFILTERED_SHADOWING);
MAP_PASS("Variance", DENOISING_PASS_PREFILTERED_VARIANCE);
MAP_PASS("Intensity", DENOISING_PASS_PREFILTERED_INTENSITY);
MAP_PASS("Clean", DENOISING_PASS_CLEAN);
#undef MAP_PASS
return -1;
return pass;
}
vector<Pass> BlenderSync::sync_render_passes(BL::Scene &b_scene,
BL::RenderLayer &b_rlay,
BL::ViewLayer &b_view_layer,
bool adaptive_sampling,
const DenoiseParams &denoising)
void BlenderSync::sync_render_passes(BL::RenderLayer &b_rlay, BL::ViewLayer &b_view_layer)
{
vector<Pass> passes;
PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles");
/* loop over passes */
/* Delete all existing passes. */
set<Pass *> clear_passes(scene->passes.begin(), scene->passes.end());
scene->delete_nodes(clear_passes);
/* Always add combined pass. */
pass_add(scene, PASS_COMBINED, "Combined");
/* Blender built-in data and light passes. */
for (BL::RenderPass &b_pass : b_rlay.passes) {
PassType pass_type = get_pass_type(b_pass);
const PassType pass_type = get_blender_pass_type(b_pass);
if (pass_type == PASS_NONE) {
LOG(ERROR) << "Unknown pass " << b_pass.name();
continue;
}
if (pass_type == PASS_MOTION &&
(b_view_layer.use_motion_blur() && b_scene.render().use_motion_blur())) {
continue;
}
if (pass_type != PASS_NONE)
Pass::add(pass_type, passes, b_pass.name().c_str());
pass_add(scene, pass_type, b_pass.name().c_str());
}
PointerRNA crl = RNA_pointer_get(&b_view_layer.ptr, "cycles");
int denoising_flags = 0;
if (denoising.use || denoising.store_passes) {
if (denoising.type == DENOISER_NLM) {
#define MAP_OPTION(name, flag) \
if (!get_boolean(crl, name)) { \
denoising_flags |= flag; \
} \
((void)0)
MAP_OPTION("denoising_diffuse_direct", DENOISING_CLEAN_DIFFUSE_DIR);
MAP_OPTION("denoising_diffuse_indirect", DENOISING_CLEAN_DIFFUSE_IND);
MAP_OPTION("denoising_glossy_direct", DENOISING_CLEAN_GLOSSY_DIR);
MAP_OPTION("denoising_glossy_indirect", DENOISING_CLEAN_GLOSSY_IND);
MAP_OPTION("denoising_transmission_direct", DENOISING_CLEAN_TRANSMISSION_DIR);
MAP_OPTION("denoising_transmission_indirect", DENOISING_CLEAN_TRANSMISSION_IND);
#undef MAP_OPTION
}
b_engine.add_pass("Noisy Image", 4, "RGBA", b_view_layer.name().c_str());
}
scene->film->set_denoising_flags(denoising_flags);
if (denoising.store_passes) {
b_engine.add_pass("Denoising Normal", 3, "XYZ", b_view_layer.name().c_str());
b_engine.add_pass("Denoising Albedo", 3, "RGB", b_view_layer.name().c_str());
b_engine.add_pass("Denoising Depth", 1, "Z", b_view_layer.name().c_str());
if (denoising.type == DENOISER_NLM) {
b_engine.add_pass("Denoising Shadowing", 1, "X", b_view_layer.name().c_str());
b_engine.add_pass("Denoising Variance", 3, "RGB", b_view_layer.name().c_str());
b_engine.add_pass("Denoising Intensity", 1, "X", b_view_layer.name().c_str());
}
if (scene->film->get_denoising_flags() & DENOISING_CLEAN_ALL_PASSES) {
b_engine.add_pass("Denoising Clean", 3, "RGB", b_view_layer.name().c_str());
}
}
/* Debug passes. */
if (get_boolean(crl, "pass_debug_render_time")) {
b_engine.add_pass("Debug Render Time", 1, "X", b_view_layer.name().c_str());
Pass::add(PASS_RENDER_TIME, passes, "Debug Render Time");
pass_add(scene, PASS_RENDER_TIME, "Debug Render Time");
}
if (get_boolean(crl, "pass_debug_sample_count")) {
b_engine.add_pass("Debug Sample Count", 1, "X", b_view_layer.name().c_str());
Pass::add(PASS_SAMPLE_COUNT, passes, "Debug Sample Count");
pass_add(scene, PASS_SAMPLE_COUNT, "Debug Sample Count");
}
/* Cycles specific passes. */
if (get_boolean(crl, "use_pass_volume_direct")) {
b_engine.add_pass("VolumeDir", 3, "RGB", b_view_layer.name().c_str());
Pass::add(PASS_VOLUME_DIRECT, passes, "VolumeDir");
pass_add(scene, PASS_VOLUME_DIRECT, "VolumeDir");
}
if (get_boolean(crl, "use_pass_volume_indirect")) {
b_engine.add_pass("VolumeInd", 3, "RGB", b_view_layer.name().c_str());
Pass::add(PASS_VOLUME_INDIRECT, passes, "VolumeInd");
pass_add(scene, PASS_VOLUME_INDIRECT, "VolumeInd");
}
if (get_boolean(crl, "use_pass_shadow_catcher")) {
b_engine.add_pass("Shadow Catcher", 3, "RGB", b_view_layer.name().c_str());
pass_add(scene, PASS_SHADOW_CATCHER, "Shadow Catcher");
}
/* Cryptomatte stores two ID/weight pairs per RGBA layer.
@@ -662,7 +636,7 @@ vector<Pass> BlenderSync::sync_render_passes(BL::Scene &b_scene,
for (int i = 0; i < crypto_depth; i++) {
string passname = cryptomatte_prefix + string_printf("Object%02d", i);
b_engine.add_pass(passname.c_str(), 4, "RGBA", b_view_layer.name().c_str());
Pass::add(PASS_CRYPTOMATTE, passes, passname.c_str());
pass_add(scene, PASS_CRYPTOMATTE, passname.c_str());
}
cryptomatte_passes = (CryptomatteType)(cryptomatte_passes | CRYPT_OBJECT);
}
@@ -670,7 +644,7 @@ vector<Pass> BlenderSync::sync_render_passes(BL::Scene &b_scene,
for (int i = 0; i < crypto_depth; i++) {
string passname = cryptomatte_prefix + string_printf("Material%02d", i);
b_engine.add_pass(passname.c_str(), 4, "RGBA", b_view_layer.name().c_str());
Pass::add(PASS_CRYPTOMATTE, passes, passname.c_str());
pass_add(scene, PASS_CRYPTOMATTE, passname.c_str());
}
cryptomatte_passes = (CryptomatteType)(cryptomatte_passes | CRYPT_MATERIAL);
}
@@ -678,22 +652,33 @@ vector<Pass> BlenderSync::sync_render_passes(BL::Scene &b_scene,
for (int i = 0; i < crypto_depth; i++) {
string passname = cryptomatte_prefix + string_printf("Asset%02d", i);
b_engine.add_pass(passname.c_str(), 4, "RGBA", b_view_layer.name().c_str());
Pass::add(PASS_CRYPTOMATTE, passes, passname.c_str());
pass_add(scene, PASS_CRYPTOMATTE, passname.c_str());
}
cryptomatte_passes = (CryptomatteType)(cryptomatte_passes | CRYPT_ASSET);
}
if (b_view_layer.use_pass_cryptomatte_accurate() && cryptomatte_passes != CRYPT_NONE) {
cryptomatte_passes = (CryptomatteType)(cryptomatte_passes | CRYPT_ACCURATE);
}
scene->film->set_cryptomatte_passes(cryptomatte_passes);
if (adaptive_sampling) {
Pass::add(PASS_ADAPTIVE_AUX_BUFFER, passes);
if (!get_boolean(crl, "pass_debug_sample_count")) {
Pass::add(PASS_SAMPLE_COUNT, passes);
/* Denoising passes. */
const bool use_denoising = get_boolean(cscene, "use_denoising") &&
get_boolean(crl, "use_denoising");
const bool store_denoising_passes = get_boolean(crl, "denoising_store_passes");
if (use_denoising) {
b_engine.add_pass("Noisy Image", 4, "RGBA", b_view_layer.name().c_str());
pass_add(scene, PASS_COMBINED, "Noisy Image", PassMode::NOISY);
if (get_boolean(crl, "use_pass_shadow_catcher")) {
b_engine.add_pass("Noisy Shadow Catcher", 3, "RGB", b_view_layer.name().c_str());
pass_add(scene, PASS_SHADOW_CATCHER, "Noisy Shadow Catcher", PassMode::NOISY);
}
}
if (store_denoising_passes) {
b_engine.add_pass("Denoising Normal", 3, "XYZ", b_view_layer.name().c_str());
pass_add(scene, PASS_DENOISING_NORMAL, "Denoising Normal", PassMode::NOISY);
b_engine.add_pass("Denoising Albedo", 3, "RGB", b_view_layer.name().c_str());
pass_add(scene, PASS_DENOISING_ALBEDO, "Denoising Albedo", PassMode::NOISY);
}
/* Custom AOV passes. */
BL::ViewLayer::aovs_iterator b_aov_iter;
for (b_view_layer.aovs.begin(b_aov_iter); b_aov_iter != b_view_layer.aovs.end(); ++b_aov_iter) {
BL::AOV b_aov(*b_aov_iter);
@@ -706,28 +691,15 @@ vector<Pass> BlenderSync::sync_render_passes(BL::Scene &b_scene,
if (is_color) {
b_engine.add_pass(name.c_str(), 4, "RGBA", b_view_layer.name().c_str());
Pass::add(PASS_AOV_COLOR, passes, name.c_str());
pass_add(scene, PASS_AOV_COLOR, name.c_str());
}
else {
b_engine.add_pass(name.c_str(), 1, "X", b_view_layer.name().c_str());
Pass::add(PASS_AOV_VALUE, passes, name.c_str());
pass_add(scene, PASS_AOV_VALUE, name.c_str());
}
}
scene->film->set_denoising_data_pass(denoising.use || denoising.store_passes);
scene->film->set_denoising_clean_pass(scene->film->get_denoising_flags() &
DENOISING_CLEAN_ALL_PASSES);
scene->film->set_denoising_prefiltered_pass(denoising.store_passes &&
denoising.type == DENOISER_NLM);
scene->film->set_pass_alpha_threshold(b_view_layer.pass_alpha_threshold());
if (!Pass::equals(passes, scene->passes)) {
scene->film->tag_passes_update(scene, passes);
scene->film->tag_modified();
scene->integrator->tag_update(scene, Integrator::UPDATE_ALL);
}
return passes;
}
void BlenderSync::free_data_after_sync(BL::Depsgraph &b_depsgraph)
@@ -773,9 +745,9 @@ SceneParams BlenderSync::get_scene_params(BL::Scene &b_scene, bool background)
params.shadingsystem = SHADINGSYSTEM_OSL;
if (background || DebugFlags().viewport_static_bvh)
params.bvh_type = SceneParams::BVH_STATIC;
params.bvh_type = BVH_TYPE_STATIC;
else
params.bvh_type = SceneParams::BVH_DYNAMIC;
params.bvh_type = BVH_TYPE_DYNAMIC;
params.use_bvh_spatial_split = RNA_boolean_get(&cscene, "debug_use_spatial_splits");
params.use_bvh_unaligned_nodes = RNA_boolean_get(&cscene, "debug_use_hair_bvh");
@@ -818,8 +790,7 @@ bool BlenderSync::get_session_pause(BL::Scene &b_scene, bool background)
SessionParams BlenderSync::get_session_params(BL::RenderEngine &b_engine,
BL::Preferences &b_preferences,
BL::Scene &b_scene,
bool background,
BL::ViewLayer b_view_layer)
bool background)
{
SessionParams params;
PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles");
@@ -827,7 +798,8 @@ SessionParams BlenderSync::get_session_params(BL::RenderEngine &b_engine,
/* feature set */
params.experimental = (get_enum(cscene, "feature_set") != 0);
/* Background */
/* Headless and background rendering. */
params.headless = BlenderSession::headless;
params.background = background;
/* Device */
@@ -836,111 +808,26 @@ SessionParams BlenderSync::get_session_params(BL::RenderEngine &b_engine,
/* samples */
int samples = get_int(cscene, "samples");
int aa_samples = get_int(cscene, "aa_samples");
int preview_samples = get_int(cscene, "preview_samples");
int preview_aa_samples = get_int(cscene, "preview_aa_samples");
if (get_boolean(cscene, "use_square_samples")) {
aa_samples = aa_samples * aa_samples;
preview_aa_samples = preview_aa_samples * preview_aa_samples;
samples = samples * samples;
preview_samples = preview_samples * preview_samples;
}
if (get_enum(cscene, "progressive") == 0 && params.device.has_branched_path) {
if (background) {
params.samples = aa_samples;
}
else {
params.samples = preview_aa_samples;
if (params.samples == 0)
params.samples = INT_MAX;
}
if (background) {
params.samples = samples;
}
else {
if (background) {
params.samples = samples;
}
else {
params.samples = preview_samples;
if (params.samples == 0)
params.samples = INT_MAX;
}
params.samples = preview_samples;
if (params.samples == 0)
params.samples = INT_MAX;
}
/* Clamp samples. */
params.samples = min(params.samples, Integrator::MAX_SAMPLES);
/* Adaptive sampling. */
params.adaptive_sampling = RNA_boolean_get(&cscene, "use_adaptive_sampling");
/* tiles */
const bool is_cpu = (params.device.type == DEVICE_CPU);
if (!is_cpu && !background) {
/* currently GPU could be much slower than CPU when using tiles,
* still need to be investigated, but meanwhile make it possible
* to work in viewport smoothly
*/
int debug_tile_size = get_int(cscene, "debug_tile_size");
params.tile_size = make_int2(debug_tile_size, debug_tile_size);
}
else {
int tile_x = b_engine.tile_x();
int tile_y = b_engine.tile_y();
params.tile_size = make_int2(tile_x, tile_y);
}
if ((BlenderSession::headless == false) && background) {
params.tile_order = (TileOrder)get_enum(cscene, "tile_order");
}
else {
params.tile_order = TILE_BOTTOM_TO_TOP;
}
/* Denoising */
params.denoising = get_denoise_params(b_scene, b_view_layer, background);
if (params.denoising.use) {
/* Add additional denoising devices if we are rendering and denoising
* with different devices. */
params.device.add_denoising_devices(params.denoising.type);
/* Check if denoiser is supported by device. */
if (!(params.device.denoisers & params.denoising.type)) {
params.denoising.use = false;
}
}
/* Viewport Performance */
params.start_resolution = get_int(cscene, "preview_start_resolution");
params.pixel_size = b_engine.get_preview_pixel_size(b_scene);
/* other parameters */
params.cancel_timeout = (double)get_float(cscene, "debug_cancel_timeout");
params.reset_timeout = (double)get_float(cscene, "debug_reset_timeout");
params.text_timeout = (double)get_float(cscene, "debug_text_timeout");
/* progressive refine */
BL::RenderSettings b_r = b_scene.render();
params.progressive_refine = b_engine.is_preview() ||
get_boolean(cscene, "use_progressive_refine");
if (b_r.use_save_buffers() || params.adaptive_sampling)
params.progressive_refine = false;
if (background) {
if (params.progressive_refine)
params.progressive = true;
else
params.progressive = false;
params.start_resolution = INT_MAX;
params.pixel_size = 1;
}
else
params.progressive = true;
/* shading system - scene level needs full refresh */
const bool shadingsystem = RNA_boolean_get(&cscene, "shading_system");
@@ -950,19 +837,30 @@ SessionParams BlenderSync::get_session_params(BL::RenderEngine &b_engine,
else if (shadingsystem == 1)
params.shadingsystem = SHADINGSYSTEM_OSL;
/* Color management. */
params.display_buffer_linear = b_engine.support_display_space_shader(b_scene);
if (b_engine.is_preview()) {
/* For preview rendering we're using same timeout as
* blender's job update.
*/
params.progressive_update_timeout = 0.1;
/* Time limit. */
if (background) {
params.time_limit = get_float(cscene, "time_limit");
}
else {
/* For the viewport it kind of makes more sense to think in terms of the noise floor, which is
* usually higher than acceptable level for the final frame. */
/* TODO: It might be useful to support time limit in the viewport as well, but needs some
* extra thoughts and input. */
params.time_limit = 0.0;
}
/* Profiling. */
params.use_profiling = params.device.has_profiling && !b_engine.is_preview() && background &&
BlenderSession::print_render_stats;
if (background) {
params.use_auto_tile = RNA_boolean_get(&cscene, "use_auto_tile");
params.tile_size = max(get_int(cscene, "tile_size"), 8);
}
else {
params.use_auto_tile = false;
}
return params;
}
@@ -970,33 +868,34 @@ DenoiseParams BlenderSync::get_denoise_params(BL::Scene &b_scene,
BL::ViewLayer &b_view_layer,
bool background)
{
enum DenoiserInput {
DENOISER_INPUT_RGB = 1,
DENOISER_INPUT_RGB_ALBEDO = 2,
DENOISER_INPUT_RGB_ALBEDO_NORMAL = 3,
DENOISER_INPUT_NUM,
};
DenoiseParams denoising;
PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles");
int input_passes = -1;
if (background) {
/* Final Render Denoising */
denoising.use = get_boolean(cscene, "use_denoising");
denoising.type = (DenoiserType)get_enum(cscene, "denoiser", DENOISER_NUM, DENOISER_NONE);
denoising.prefilter = (DenoiserPrefilter)get_enum(
cscene, "denoising_prefilter", DENOISER_PREFILTER_NUM, DENOISER_PREFILTER_NONE);
input_passes = (DenoiserInput)get_enum(
cscene, "denoising_input_passes", DENOISER_INPUT_NUM, DENOISER_INPUT_RGB_ALBEDO_NORMAL);
if (b_view_layer) {
PointerRNA clayer = RNA_pointer_get(&b_view_layer.ptr, "cycles");
if (!get_boolean(clayer, "use_denoising")) {
denoising.use = false;
}
denoising.radius = get_int(clayer, "denoising_radius");
denoising.strength = get_float(clayer, "denoising_strength");
denoising.feature_strength = get_float(clayer, "denoising_feature_strength");
denoising.relative_pca = get_boolean(clayer, "denoising_relative_pca");
denoising.input_passes = (DenoiserInput)get_enum(
clayer,
(denoising.type == DENOISER_OPTIX) ? "denoising_optix_input_passes" :
"denoising_openimagedenoise_input_passes",
DENOISER_INPUT_NUM,
DENOISER_INPUT_RGB_ALBEDO_NORMAL);
denoising.store_passes = get_boolean(clayer, "denoising_store_passes");
}
}
else {
@@ -1004,10 +903,12 @@ DenoiseParams BlenderSync::get_denoise_params(BL::Scene &b_scene,
denoising.use = get_boolean(cscene, "use_preview_denoising");
denoising.type = (DenoiserType)get_enum(
cscene, "preview_denoiser", DENOISER_NUM, DENOISER_NONE);
denoising.prefilter = (DenoiserPrefilter)get_enum(
cscene, "preview_denoising_prefilter", DENOISER_PREFILTER_NUM, DENOISER_PREFILTER_FAST);
denoising.start_sample = get_int(cscene, "preview_denoising_start_sample");
denoising.input_passes = (DenoiserInput)get_enum(
cscene, "preview_denoising_input_passes", DENOISER_INPUT_NUM, (int)denoising.input_passes);
input_passes = (DenoiserInput)get_enum(
cscene, "preview_denoising_input_passes", DENOISER_INPUT_NUM, DENOISER_INPUT_RGB_ALBEDO);
/* Auto select fastest denoiser. */
if (denoising.type == DENOISER_NONE) {
@@ -1023,6 +924,27 @@ DenoiseParams BlenderSync::get_denoise_params(BL::Scene &b_scene,
}
}
switch (input_passes) {
case DENOISER_INPUT_RGB:
denoising.use_pass_albedo = false;
denoising.use_pass_normal = false;
break;
case DENOISER_INPUT_RGB_ALBEDO:
denoising.use_pass_albedo = true;
denoising.use_pass_normal = false;
break;
case DENOISER_INPUT_RGB_ALBEDO_NORMAL:
denoising.use_pass_albedo = true;
denoising.use_pass_normal = true;
break;
default:
LOG(ERROR) << "Unhandled input passes enum " << input_passes;
break;
}
return denoising;
}

View File

@@ -60,6 +60,7 @@ class BlenderSync {
BL::Scene &b_scene,
Scene *scene,
bool preview,
bool use_developer_ui,
Progress &progress);
~BlenderSync();
@@ -75,12 +76,8 @@ class BlenderSync {
int height,
void **python_thread_state);
void sync_view_layer(BL::ViewLayer &b_view_layer);
vector<Pass> sync_render_passes(BL::Scene &b_scene,
BL::RenderLayer &b_render_layer,
BL::ViewLayer &b_view_layer,
bool adaptive_sampling,
const DenoiseParams &denoising);
void sync_integrator();
void sync_render_passes(BL::RenderLayer &b_render_layer, BL::ViewLayer &b_view_layer);
void sync_integrator(BL::ViewLayer &b_view_layer, bool background);
void sync_camera(BL::RenderSettings &b_render,
BL::Object &b_override,
int width,
@@ -98,22 +95,13 @@ class BlenderSync {
/* get parameters */
static SceneParams get_scene_params(BL::Scene &b_scene, bool background);
static SessionParams get_session_params(
BL::RenderEngine &b_engine,
BL::Preferences &b_userpref,
BL::Scene &b_scene,
bool background,
BL::ViewLayer b_view_layer = BL::ViewLayer(PointerRNA_NULL));
static SessionParams get_session_params(BL::RenderEngine &b_engine,
BL::Preferences &b_userpref,
BL::Scene &b_scene,
bool background);
static bool get_session_pause(BL::Scene &b_scene, bool background);
static BufferParams get_buffer_params(BL::SpaceView3D &b_v3d,
BL::RegionView3D &b_rv3d,
Camera *cam,
int width,
int height,
const bool use_denoiser);
static PassType get_pass_type(BL::RenderPass &b_pass);
static int get_denoising_pass(BL::RenderPass &b_pass);
static BufferParams get_buffer_params(
BL::SpaceView3D &b_v3d, BL::RegionView3D &b_rv3d, Camera *cam, int width, int height);
private:
static DenoiseParams get_denoise_params(BL::Scene &b_scene,
@@ -131,7 +119,7 @@ class BlenderSync {
int width,
int height,
void **python_thread_state);
void sync_film(BL::SpaceView3D &b_v3d);
void sync_film(BL::ViewLayer &b_view_layer, BL::SpaceView3D &b_v3d);
void sync_view();
/* Shader */
@@ -245,6 +233,7 @@ class BlenderSync {
Scene *scene;
bool preview;
bool experimental;
bool use_developer_ui;
float dicing_rate;
int max_subdivisions;
@@ -253,7 +242,6 @@ class BlenderSync {
RenderLayerInfo()
: material_override(PointerRNA_NULL),
use_background_shader(true),
use_background_ao(true),
use_surfaces(true),
use_hair(true),
use_volumes(true),
@@ -266,7 +254,6 @@ class BlenderSync {
string name;
BL::Material material_override;
bool use_background_shader;
bool use_background_ao;
bool use_surfaces;
bool use_hair;
bool use_volumes;

View File

@@ -90,26 +90,27 @@ static inline BL::Mesh object_to_mesh(BL::BlendData & /*data*/,
}
#endif
BL::Mesh mesh(PointerRNA_NULL);
if (b_ob_info.object_data.is_a(&RNA_Mesh)) {
/* TODO: calc_undeformed is not used. */
mesh = BL::Mesh(b_ob_info.object_data);
BL::Mesh mesh = (b_ob_info.object_data.is_a(&RNA_Mesh)) ? BL::Mesh(b_ob_info.object_data) :
BL::Mesh(PointerRNA_NULL);
/* Make a copy to split faces if we use autosmooth, otherwise not needed.
* Also in edit mode do we need to make a copy, to ensure data layers like
* UV are not empty. */
if (mesh.is_editmode() ||
(mesh.use_auto_smooth() && subdivision_type == Mesh::SUBDIVISION_NONE)) {
if (b_ob_info.is_real_object_data()) {
if (mesh) {
/* Make a copy to split faces if we use autosmooth, otherwise not needed.
* Also in edit mode do we need to make a copy, to ensure data layers like
* UV are not empty. */
if (mesh.is_editmode() ||
(mesh.use_auto_smooth() && subdivision_type == Mesh::SUBDIVISION_NONE)) {
BL::Depsgraph depsgraph(PointerRNA_NULL);
mesh = b_ob_info.real_object.to_mesh(false, depsgraph);
}
}
else {
BL::Depsgraph depsgraph(PointerRNA_NULL);
assert(b_ob_info.is_real_object_data());
mesh = b_ob_info.real_object.to_mesh(false, depsgraph);
}
}
else {
BL::Depsgraph depsgraph(PointerRNA_NULL);
if (b_ob_info.is_real_object_data()) {
mesh = b_ob_info.real_object.to_mesh(false, depsgraph);
}
/* TODO: what to do about non-mesh geometry instances? */
}
#if 0
@@ -170,12 +171,11 @@ static inline void curvemap_minmax_curve(/*const*/ BL::CurveMap &curve, float *m
}
static inline void curvemapping_minmax(/*const*/ BL::CurveMapping &cumap,
bool rgb_curve,
int num_curves,
float *min_x,
float *max_x)
{
// const int num_curves = cumap.curves.length(); /* Gives linking error so far. */
const int num_curves = rgb_curve ? 4 : 3;
*min_x = FLT_MAX;
*max_x = -FLT_MAX;
for (int i = 0; i < num_curves; ++i) {
@@ -195,6 +195,28 @@ static inline void curvemapping_to_array(BL::CurveMapping &cumap, array<float> &
}
}
static inline void curvemapping_float_to_array(BL::CurveMapping &cumap,
array<float> &data,
int size)
{
float min = 0.0f, max = 1.0f;
curvemapping_minmax(cumap, 1, &min, &max);
const float range = max - min;
cumap.update();
BL::CurveMap map = cumap.curves[0];
data.resize(size);
for (int i = 0; i < size; i++) {
float t = min + (float)i / (float)(size - 1) * range;
data[i] = cumap.evaluate(map, t);
}
}
static inline void curvemapping_color_to_array(BL::CurveMapping &cumap,
array<float3> &data,
int size,
@@ -213,7 +235,8 @@ static inline void curvemapping_color_to_array(BL::CurveMapping &cumap,
*
* There might be some better estimations here tho.
*/
curvemapping_minmax(cumap, rgb_curve, &min_x, &max_x);
const int num_curves = rgb_curve ? 4 : 3;
curvemapping_minmax(cumap, num_curves, &min_x, &max_x);
const float range_x = max_x - min_x;

View File

@@ -17,6 +17,8 @@
#include "blender_viewport.h"
#include "blender_util.h"
#include "render/pass.h"
#include "util/util_logging.h"
CCL_NAMESPACE_BEGIN
@@ -26,11 +28,12 @@ BlenderViewportParameters::BlenderViewportParameters()
studiolight_rotate_z(0.0f),
studiolight_intensity(1.0f),
studiolight_background_alpha(1.0f),
display_pass(PASS_COMBINED)
display_pass(PASS_COMBINED),
show_active_pixels(false)
{
}
BlenderViewportParameters::BlenderViewportParameters(BL::SpaceView3D &b_v3d)
BlenderViewportParameters::BlenderViewportParameters(BL::SpaceView3D &b_v3d, bool use_developer_ui)
: BlenderViewportParameters()
{
if (!b_v3d) {
@@ -55,7 +58,25 @@ BlenderViewportParameters::BlenderViewportParameters(BL::SpaceView3D &b_v3d)
}
/* Film. */
display_pass = (PassType)get_enum(cshading, "render_pass", -1, -1);
/* Lookup display pass based on the enum identifier.
* This is because integer values of python enum are not aligned with the passes definition in
* the kernel. */
display_pass = PASS_COMBINED;
const string display_pass_identifier = get_enum_identifier(cshading, "render_pass");
if (!display_pass_identifier.empty()) {
const ustring pass_type_identifier(string_to_lower(display_pass_identifier));
const NodeEnum *pass_type_enum = Pass::get_type_enum();
if (pass_type_enum->exists(pass_type_identifier)) {
display_pass = static_cast<PassType>((*pass_type_enum)[pass_type_identifier]);
}
}
if (use_developer_ui) {
show_active_pixels = get_boolean(cshading, "show_active_pixels");
}
}
bool BlenderViewportParameters::shader_modified(const BlenderViewportParameters &other) const
@@ -69,7 +90,7 @@ bool BlenderViewportParameters::shader_modified(const BlenderViewportParameters
bool BlenderViewportParameters::film_modified(const BlenderViewportParameters &other) const
{
return display_pass != other.display_pass;
return display_pass != other.display_pass || show_active_pixels != other.show_active_pixels;
}
bool BlenderViewportParameters::modified(const BlenderViewportParameters &other) const
@@ -82,18 +103,4 @@ bool BlenderViewportParameters::use_custom_shader() const
return !(use_scene_world && use_scene_lights);
}
PassType update_viewport_display_passes(BL::SpaceView3D &b_v3d, vector<Pass> &passes)
{
if (b_v3d) {
const BlenderViewportParameters viewport_parameters(b_v3d);
const PassType display_pass = viewport_parameters.display_pass;
passes.clear();
Pass::add(display_pass, passes);
return display_pass;
}
return PASS_NONE;
}
CCL_NAMESPACE_END

View File

@@ -39,9 +39,10 @@ class BlenderViewportParameters {
/* Film. */
PassType display_pass;
bool show_active_pixels;
BlenderViewportParameters();
explicit BlenderViewportParameters(BL::SpaceView3D &b_v3d);
BlenderViewportParameters(BL::SpaceView3D &b_v3d, bool use_developer_ui);
/* Check whether any of shading related settings are different from the given parameters. */
bool shader_modified(const BlenderViewportParameters &other) const;
@@ -57,8 +58,6 @@ class BlenderViewportParameters {
bool use_custom_shader() const;
};
PassType update_viewport_display_passes(BL::SpaceView3D &b_v3d, vector<Pass> &passes);
CCL_NAMESPACE_END
#endif

View File

@@ -832,18 +832,18 @@ BVHNode *BVHBuild::create_leaf_node(const BVHRange &range, const vector<BVHRefer
typedef StackAllocator<256, float2> LeafTimeStackAllocator;
typedef StackAllocator<256, BVHReference> LeafReferenceStackAllocator;
vector<int, LeafStackAllocator> p_type[PRIMITIVE_NUM_TOTAL];
vector<int, LeafStackAllocator> p_index[PRIMITIVE_NUM_TOTAL];
vector<int, LeafStackAllocator> p_object[PRIMITIVE_NUM_TOTAL];
vector<float2, LeafTimeStackAllocator> p_time[PRIMITIVE_NUM_TOTAL];
vector<BVHReference, LeafReferenceStackAllocator> p_ref[PRIMITIVE_NUM_TOTAL];
vector<int, LeafStackAllocator> p_type[PRIMITIVE_NUM];
vector<int, LeafStackAllocator> p_index[PRIMITIVE_NUM];
vector<int, LeafStackAllocator> p_object[PRIMITIVE_NUM];
vector<float2, LeafTimeStackAllocator> p_time[PRIMITIVE_NUM];
vector<BVHReference, LeafReferenceStackAllocator> p_ref[PRIMITIVE_NUM];
/* TODO(sergey): In theory we should be able to store references. */
vector<BVHReference, LeafReferenceStackAllocator> object_references;
uint visibility[PRIMITIVE_NUM_TOTAL] = {0};
uint visibility[PRIMITIVE_NUM] = {0};
/* NOTE: Keep initialization in sync with actual number of primitives. */
BoundBox bounds[PRIMITIVE_NUM_TOTAL] = {
BoundBox bounds[PRIMITIVE_NUM] = {
BoundBox::empty, BoundBox::empty, BoundBox::empty, BoundBox::empty};
int ob_num = 0;
int num_new_prims = 0;
@@ -877,7 +877,7 @@ BVHNode *BVHBuild::create_leaf_node(const BVHRange &range, const vector<BVHRefer
* TODO(sergey): With some pointer trickery we can write directly to the
* destination buffers for the non-spatial split BVH.
*/
BVHNode *leaves[PRIMITIVE_NUM_TOTAL + 1] = {NULL};
BVHNode *leaves[PRIMITIVE_NUM + 1] = {NULL};
int num_leaves = 0;
size_t start_index = 0;
vector<int, LeafStackAllocator> local_prim_type, local_prim_index, local_prim_object;
@@ -888,7 +888,7 @@ BVHNode *BVHBuild::create_leaf_node(const BVHRange &range, const vector<BVHRefer
if (need_prim_time) {
local_prim_time.resize(num_new_prims);
}
for (int i = 0; i < PRIMITIVE_NUM_TOTAL; ++i) {
for (int i = 0; i < PRIMITIVE_NUM; ++i) {
int num = (int)p_type[i].size();
if (num != 0) {
assert(p_type[i].size() == p_index[i].size());

View File

@@ -37,10 +37,10 @@
/* Kernel includes are necessary so that the filter function for Embree can access the packed BVH.
*/
# include "kernel/bvh/bvh_embree.h"
# include "kernel/kernel_compat_cpu.h"
# include "kernel/kernel_globals.h"
# include "kernel/bvh/bvh_util.h"
# include "kernel/device/cpu/compat.h"
# include "kernel/device/cpu/globals.h"
# include "kernel/kernel_random.h"
# include "kernel/split/kernel_split_data_types.h"
# include "render/hair.h"
# include "render/mesh.h"
@@ -73,46 +73,69 @@ static void rtc_filter_occluded_func(const RTCFilterFunctionNArguments *args)
const RTCRay *ray = (RTCRay *)args->ray;
RTCHit *hit = (RTCHit *)args->hit;
CCLIntersectContext *ctx = ((IntersectContext *)args->context)->userRayExt;
KernelGlobals *kg = ctx->kg;
const KernelGlobals *kg = ctx->kg;
switch (ctx->type) {
case CCLIntersectContext::RAY_SHADOW_ALL: {
/* Append the intersection to the end of the array. */
if (ctx->num_hits < ctx->max_hits) {
Intersection current_isect;
kernel_embree_convert_hit(kg, ray, hit, &current_isect);
for (size_t i = 0; i < ctx->max_hits; ++i) {
Intersection current_isect;
kernel_embree_convert_hit(kg, ray, hit, &current_isect);
/* If no transparent shadows, all light is blocked. */
const int flags = intersection_get_shader_flags(kg, &current_isect);
if (!(flags & (SD_HAS_TRANSPARENT_SHADOW)) || ctx->max_hits == 0) {
ctx->opaque_hit = true;
return;
}
/* Test if we need to record this transparent intersection. */
if (ctx->num_hits < ctx->max_hits || ray->tfar < ctx->max_t) {
/* Skip already recorded intersections. */
int num_recorded_hits = min(ctx->num_hits, ctx->max_hits);
for (int i = 0; i < num_recorded_hits; ++i) {
if (current_isect.object == ctx->isect_s[i].object &&
current_isect.prim == ctx->isect_s[i].prim && current_isect.t == ctx->isect_s[i].t) {
/* This intersection was already recorded, skip it. */
*args->valid = 0;
break;
return;
}
}
Intersection *isect = &ctx->isect_s[ctx->num_hits];
++ctx->num_hits;
*isect = current_isect;
int prim = kernel_tex_fetch(__prim_index, isect->prim);
int shader = 0;
if (kernel_tex_fetch(__prim_type, isect->prim) & PRIMITIVE_ALL_TRIANGLE) {
shader = kernel_tex_fetch(__tri_shader, prim);
}
else {
float4 str = kernel_tex_fetch(__curves, prim);
shader = __float_as_int(str.z);
}
int flag = kernel_tex_fetch(__shaders, shader & SHADER_MASK).flags;
/* If no transparent shadows, all light is blocked. */
if (flag & (SD_HAS_TRANSPARENT_SHADOW)) {
/* This tells Embree to continue tracing. */
*args->valid = 0;
/* If maximum number of hits was reached, replace the intersection with the
* highest distance. We want to find the N closest intersections. */
int isect_index = num_recorded_hits;
if (num_recorded_hits + 1 >= ctx->max_hits) {
float max_t = ctx->isect_s[0].t;
int max_recorded_hit = 0;
for (int i = 1; i < num_recorded_hits; ++i) {
if (ctx->isect_s[i].t > max_t) {
max_recorded_hit = i;
max_t = ctx->isect_s[i].t;
}
}
if (num_recorded_hits >= ctx->max_hits) {
isect_index = max_recorded_hit;
}
/* Limit the ray distance and stop counting hits beyond this.
* TODO: is there some way we can tell Embree to stop intersecting beyond
* this distance when max number of hits is reached?. Or maybe it will
* become irrelevant if we make max_hits a very high number on the CPU. */
ctx->max_t = max(current_isect.t, max_t);
}
ctx->isect_s[isect_index] = current_isect;
}
else {
/* Increase the number of hits beyond ray.max_hits
* so that the caller can detect this as opaque. */
++ctx->num_hits;
}
/* Always increase the number of hits, even beyond ray.max_hits so that
* the caller can detect this as and consider it opaque, or trace another
* ray. */
++ctx->num_hits;
/* This tells Embree to continue tracing. */
*args->valid = 0;
break;
}
case CCLIntersectContext::RAY_LOCAL:
@@ -190,7 +213,7 @@ static void rtc_filter_occluded_func(const RTCFilterFunctionNArguments *args)
if (ctx->num_hits < ctx->max_hits) {
Intersection current_isect;
kernel_embree_convert_hit(kg, ray, hit, &current_isect);
for (size_t i = 0; i < ctx->max_hits; ++i) {
for (size_t i = 0; i < ctx->num_hits; ++i) {
if (current_isect.object == ctx->isect_s[i].object &&
current_isect.prim == ctx->isect_s[i].prim && current_isect.t == ctx->isect_s[i].t) {
/* This intersection was already recorded, skip it. */
@@ -329,7 +352,7 @@ void BVHEmbree::build(Progress &progress, Stats *stats, RTCDevice rtc_device_)
scene = NULL;
}
const bool dynamic = params.bvh_type == SceneParams::BVH_DYNAMIC;
const bool dynamic = params.bvh_type == BVH_TYPE_DYNAMIC;
scene = rtcNewScene(rtc_device);
const RTCSceneFlags scene_flags = (dynamic ? RTC_SCENE_FLAG_DYNAMIC : RTC_SCENE_FLAG_NONE) |

View File

@@ -31,6 +31,27 @@ CCL_NAMESPACE_BEGIN
*/
typedef KernelBVHLayout BVHLayout;
/* Type of BVH, in terms whether it is supported dynamic updates of meshes
* or whether modifying geometry requires full BVH rebuild.
*/
enum BVHType {
/* BVH supports dynamic updates of geometry.
*
* Faster for updating BVH tree when doing modifications in viewport,
* but slower for rendering.
*/
BVH_TYPE_DYNAMIC = 0,
/* BVH tree is calculated for specific scene, updates in geometry
* requires full tree rebuild.
*
* Slower to update BVH tree when modifying objects in viewport, also
* slower to build final BVH tree but gives best possible render speed.
*/
BVH_TYPE_STATIC = 1,
BVH_NUM_TYPES,
};
/* Names bitflag type to denote which BVH layouts are supported by
* particular area.
*

View File

@@ -287,9 +287,6 @@ if(CYCLES_STANDALONE_REPOSITORY)
endif()
set(__boost_packages filesystem regex system thread date_time)
if(WITH_CYCLES_NETWORK)
list(APPEND __boost_packages serialization)
endif()
if(WITH_CYCLES_OSL)
list(APPEND __boost_packages wave)
endif()
@@ -535,4 +532,13 @@ if(WITH_CYCLES_CUDA_BINARIES OR NOT WITH_CUDA_DYNLOAD)
endif()
endif()
###########################################################################
# HIP
###########################################################################
if(NOT WITH_HIP_DYNLOAD)
set(WITH_HIP_DYNLOAD ON)
endif()
unset(_cycles_lib_dir)

View File

@@ -156,10 +156,16 @@ macro(cycles_target_link_libraries target)
${PLATFORM_LINKLIBS}
)
if(WITH_CUDA_DYNLOAD)
target_link_libraries(${target} extern_cuew)
else()
target_link_libraries(${target} ${CUDA_CUDA_LIBRARY})
if(WITH_CYCLES_DEVICE_CUDA OR WITH_CYCLES_DEVICE_OPTIX)
if(WITH_CUDA_DYNLOAD)
target_link_libraries(${target} extern_cuew)
else()
target_link_libraries(${target} ${CUDA_CUDA_LIBRARY})
endif()
endif()
if(WITH_CYCLES_DEVICE_HIP AND WITH_HIP_DYNLOAD)
target_link_libraries(${target} extern_hipew)
endif()
if(CYCLES_STANDALONE_REPOSITORY)

View File

@@ -22,91 +22,139 @@ set(INC_SYS
../../../extern/clew/include
)
if(WITH_CUDA_DYNLOAD)
if(WITH_CYCLES_DEVICE_OPTIX OR WITH_CYCLES_DEVICE_CUDA)
if(WITH_CUDA_DYNLOAD)
list(APPEND INC
../../../extern/cuew/include
)
add_definitions(-DWITH_CUDA_DYNLOAD)
else()
list(APPEND INC_SYS
${CUDA_TOOLKIT_INCLUDE}
)
add_definitions(-DCYCLES_CUDA_NVCC_EXECUTABLE="${CUDA_NVCC_EXECUTABLE}")
endif()
endif()
if(WITH_CYCLES_DEVICE_HIP AND WITH_HIP_DYNLOAD)
list(APPEND INC
../../../extern/cuew/include
../../../extern/hipew/include
)
add_definitions(-DWITH_CUDA_DYNLOAD)
else()
list(APPEND INC_SYS
${CUDA_TOOLKIT_INCLUDE}
)
add_definitions(-DCYCLES_CUDA_NVCC_EXECUTABLE="${CUDA_NVCC_EXECUTABLE}")
add_definitions(-DWITH_HIP_DYNLOAD)
endif()
set(SRC
device.cpp
device_cpu.cpp
device_cuda.cpp
device_denoising.cpp
device_dummy.cpp
device_denoise.cpp
device_graphics_interop.cpp
device_kernel.cpp
device_memory.cpp
device_multi.cpp
device_opencl.cpp
device_optix.cpp
device_split_kernel.cpp
device_task.cpp
device_queue.cpp
)
set(SRC_CPU
cpu/device.cpp
cpu/device.h
cpu/device_impl.cpp
cpu/device_impl.h
cpu/kernel.cpp
cpu/kernel.h
cpu/kernel_function.h
cpu/kernel_thread_globals.cpp
cpu/kernel_thread_globals.h
)
set(SRC_CUDA
cuda/device_cuda.h
cuda/device_cuda_impl.cpp
cuda/device.cpp
cuda/device.h
cuda/device_impl.cpp
cuda/device_impl.h
cuda/graphics_interop.cpp
cuda/graphics_interop.h
cuda/kernel.cpp
cuda/kernel.h
cuda/queue.cpp
cuda/queue.h
cuda/util.cpp
cuda/util.h
)
set(SRC_OPENCL
opencl/device_opencl.h
opencl/device_opencl_impl.cpp
opencl/memory_manager.h
opencl/memory_manager.cpp
opencl/opencl_util.cpp
set(SRC_HIP
hip/device.cpp
hip/device.h
hip/device_impl.cpp
hip/device_impl.h
hip/graphics_interop.cpp
hip/graphics_interop.h
hip/kernel.cpp
hip/kernel.h
hip/queue.cpp
hip/queue.h
hip/util.cpp
hip/util.h
)
if(WITH_CYCLES_NETWORK)
list(APPEND SRC
device_network.cpp
)
endif()
set(SRC_DUMMY
dummy/device.cpp
dummy/device.h
)
set(SRC_MULTI
multi/device.cpp
multi/device.h
)
set(SRC_OPTIX
optix/device.cpp
optix/device.h
optix/device_impl.cpp
optix/device_impl.h
optix/queue.cpp
optix/queue.h
optix/util.h
)
set(SRC_HEADERS
device.h
device_denoising.h
device_denoise.h
device_graphics_interop.h
device_memory.h
device_intern.h
device_network.h
device_split_kernel.h
device_task.h
device_kernel.h
device_queue.h
)
set(LIB
cycles_render
cycles_kernel
cycles_util
${CYCLES_GL_LIBRARIES}
)
if(WITH_CUDA_DYNLOAD)
if(WITH_CYCLES_DEVICE_OPTIX OR WITH_CYCLES_DEVICE_CUDA)
if(WITH_CUDA_DYNLOAD)
list(APPEND LIB
extern_cuew
)
else()
list(APPEND LIB
${CUDA_CUDA_LIBRARY}
)
endif()
endif()
if(WITH_CYCLES_DEVICE_HIP AND WITH_HIP_DYNLOAD)
list(APPEND LIB
extern_cuew
)
else()
list(APPEND LIB
${CUDA_CUDA_LIBRARY}
extern_hipew
)
endif()
add_definitions(${GL_DEFINITIONS})
if(WITH_CYCLES_NETWORK)
add_definitions(-DWITH_NETWORK)
endif()
if(WITH_CYCLES_DEVICE_OPENCL)
list(APPEND LIB
extern_clew
)
add_definitions(-DWITH_OPENCL)
endif()
if(WITH_CYCLES_DEVICE_CUDA)
add_definitions(-DWITH_CUDA)
endif()
if(WITH_CYCLES_DEVICE_HIP)
add_definitions(-DWITH_HIP)
endif()
if(WITH_CYCLES_DEVICE_OPTIX)
add_definitions(-DWITH_OPTIX)
endif()
@@ -115,18 +163,28 @@ if(WITH_CYCLES_DEVICE_MULTI)
endif()
if(WITH_OPENIMAGEDENOISE)
add_definitions(-DWITH_OPENIMAGEDENOISE)
add_definitions(-DOIDN_STATIC_LIB)
list(APPEND INC_SYS
${OPENIMAGEDENOISE_INCLUDE_DIRS}
)
list(APPEND LIB
${OPENIMAGEDENOISE_LIBRARIES}
${TBB_LIBRARIES}
)
endif()
include_directories(${INC})
include_directories(SYSTEM ${INC_SYS})
cycles_add_library(cycles_device "${LIB}" ${SRC} ${SRC_CUDA} ${SRC_OPENCL} ${SRC_HEADERS})
cycles_add_library(cycles_device "${LIB}"
${SRC}
${SRC_CPU}
${SRC_CUDA}
${SRC_HIP}
${SRC_DUMMY}
${SRC_MULTI}
${SRC_OPTIX}
${SRC_HEADERS}
)
source_group("cpu" FILES ${SRC_CPU})
source_group("cuda" FILES ${SRC_CUDA})
source_group("dummy" FILES ${SRC_DUMMY})
source_group("multi" FILES ${SRC_MULTI})
source_group("optix" FILES ${SRC_OPTIX})
source_group("common" FILES ${SRC} ${SRC_HEADERS})

View File

@@ -0,0 +1,64 @@
/*
* Copyright 2011-2013 Blender Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "device/cpu/device.h"
#include "device/cpu/device_impl.h"
/* Used for `info.denoisers`. */
/* TODO(sergey): The denoisers are probably to be moved completely out of the device into their
* own class. But until then keep API consistent with how it used to work before. */
#include "util/util_openimagedenoise.h"
CCL_NAMESPACE_BEGIN
Device *device_cpu_create(const DeviceInfo &info, Stats &stats, Profiler &profiler)
{
return new CPUDevice(info, stats, profiler);
}
void device_cpu_info(vector<DeviceInfo> &devices)
{
DeviceInfo info;
info.type = DEVICE_CPU;
info.description = system_cpu_brand_string();
info.id = "CPU";
info.num = 0;
info.has_osl = true;
info.has_half_images = true;
info.has_nanovdb = true;
info.has_profiling = true;
if (openimagedenoise_supported()) {
info.denoisers |= DENOISER_OPENIMAGEDENOISE;
}
devices.insert(devices.begin(), info);
}
string device_cpu_capabilities()
{
string capabilities = "";
capabilities += system_cpu_support_sse2() ? "SSE2 " : "";
capabilities += system_cpu_support_sse3() ? "SSE3 " : "";
capabilities += system_cpu_support_sse41() ? "SSE41 " : "";
capabilities += system_cpu_support_avx() ? "AVX " : "";
capabilities += system_cpu_support_avx2() ? "AVX2" : "";
if (capabilities[capabilities.size() - 1] == ' ')
capabilities.resize(capabilities.size() - 1);
return capabilities;
}
CCL_NAMESPACE_END

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2011-2015 Blender Foundation
* Copyright 2011-2021 Blender Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,13 +14,22 @@
* limitations under the License.
*/
#include "kernel/kernel_compat_opencl.h"
#include "kernel/split/kernel_split_common.h"
#include "kernel/split/kernel_buffer_update.h"
#pragma once
#define KERNEL_NAME buffer_update
#define LOCALS_TYPE unsigned int
#include "kernel/kernels/opencl/kernel_split_function.h"
#undef KERNEL_NAME
#undef LOCALS_TYPE
#include "util/util_string.h"
#include "util/util_vector.h"
CCL_NAMESPACE_BEGIN
class Device;
class DeviceInfo;
class Profiler;
class Stats;
Device *device_cpu_create(const DeviceInfo &info, Stats &stats, Profiler &profiler);
void device_cpu_info(vector<DeviceInfo> &devices);
string device_cpu_capabilities();
CCL_NAMESPACE_END

View File

@@ -0,0 +1,332 @@
/*
* Copyright 2011-2021 Blender Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "device/cpu/device_impl.h"
#include <stdlib.h>
#include <string.h>
/* So ImathMath is included before our kernel_cpu_compat. */
#ifdef WITH_OSL
/* So no context pollution happens from indirectly included windows.h */
# include "util/util_windows.h"
# include <OSL/oslexec.h>
#endif
#ifdef WITH_EMBREE
# include <embree3/rtcore.h>
#endif
#include "device/cpu/kernel.h"
#include "device/cpu/kernel_thread_globals.h"
#include "device/device.h"
// clang-format off
#include "kernel/device/cpu/compat.h"
#include "kernel/device/cpu/globals.h"
#include "kernel/device/cpu/kernel.h"
#include "kernel/kernel_types.h"
#include "kernel/osl/osl_shader.h"
#include "kernel/osl/osl_globals.h"
// clang-format on
#include "bvh/bvh_embree.h"
#include "render/buffers.h"
#include "util/util_debug.h"
#include "util/util_foreach.h"
#include "util/util_function.h"
#include "util/util_logging.h"
#include "util/util_map.h"
#include "util/util_openimagedenoise.h"
#include "util/util_optimization.h"
#include "util/util_progress.h"
#include "util/util_system.h"
#include "util/util_task.h"
#include "util/util_thread.h"
CCL_NAMESPACE_BEGIN
CPUDevice::CPUDevice(const DeviceInfo &info_, Stats &stats_, Profiler &profiler_)
: Device(info_, stats_, profiler_), texture_info(this, "__texture_info", MEM_GLOBAL)
{
/* Pick any kernel, all of them are supposed to have same level of microarchitecture
* optimization. */
VLOG(1) << "Will be using " << kernels.integrator_init_from_camera.get_uarch_name()
<< " kernels.";
if (info.cpu_threads == 0) {
info.cpu_threads = TaskScheduler::num_threads();
}
#ifdef WITH_OSL
kernel_globals.osl = &osl_globals;
#endif
#ifdef WITH_EMBREE
embree_device = rtcNewDevice("verbose=0");
#endif
need_texture_info = false;
}
CPUDevice::~CPUDevice()
{
#ifdef WITH_EMBREE
rtcReleaseDevice(embree_device);
#endif
texture_info.free();
}
bool CPUDevice::show_samples() const
{
return (info.cpu_threads == 1);
}
BVHLayoutMask CPUDevice::get_bvh_layout_mask() const
{
BVHLayoutMask bvh_layout_mask = BVH_LAYOUT_BVH2;
#ifdef WITH_EMBREE
bvh_layout_mask |= BVH_LAYOUT_EMBREE;
#endif /* WITH_EMBREE */
return bvh_layout_mask;
}
bool CPUDevice::load_texture_info()
{
if (!need_texture_info) {
return false;
}
texture_info.copy_to_device();
need_texture_info = false;
return true;
}
void CPUDevice::mem_alloc(device_memory &mem)
{
if (mem.type == MEM_TEXTURE) {
assert(!"mem_alloc not supported for textures.");
}
else if (mem.type == MEM_GLOBAL) {
assert(!"mem_alloc not supported for global memory.");
}
else {
if (mem.name) {
VLOG(1) << "Buffer allocate: " << mem.name << ", "
<< string_human_readable_number(mem.memory_size()) << " bytes. ("
<< string_human_readable_size(mem.memory_size()) << ")";
}
if (mem.type == MEM_DEVICE_ONLY) {
assert(!mem.host_pointer);
size_t alignment = MIN_ALIGNMENT_CPU_DATA_TYPES;
void *data = util_aligned_malloc(mem.memory_size(), alignment);
mem.device_pointer = (device_ptr)data;
}
else {
mem.device_pointer = (device_ptr)mem.host_pointer;
}
mem.device_size = mem.memory_size();
stats.mem_alloc(mem.device_size);
}
}
void CPUDevice::mem_copy_to(device_memory &mem)
{
if (mem.type == MEM_GLOBAL) {
global_free(mem);
global_alloc(mem);
}
else if (mem.type == MEM_TEXTURE) {
tex_free((device_texture &)mem);
tex_alloc((device_texture &)mem);
}
else {
if (!mem.device_pointer) {
mem_alloc(mem);
}
/* copy is no-op */
}
}
void CPUDevice::mem_copy_from(
device_memory & /*mem*/, size_t /*y*/, size_t /*w*/, size_t /*h*/, size_t /*elem*/)
{
/* no-op */
}
void CPUDevice::mem_zero(device_memory &mem)
{
if (!mem.device_pointer) {
mem_alloc(mem);
}
if (mem.device_pointer) {
memset((void *)mem.device_pointer, 0, mem.memory_size());
}
}
void CPUDevice::mem_free(device_memory &mem)
{
if (mem.type == MEM_GLOBAL) {
global_free(mem);
}
else if (mem.type == MEM_TEXTURE) {
tex_free((device_texture &)mem);
}
else if (mem.device_pointer) {
if (mem.type == MEM_DEVICE_ONLY) {
util_aligned_free((void *)mem.device_pointer);
}
mem.device_pointer = 0;
stats.mem_free(mem.device_size);
mem.device_size = 0;
}
}
device_ptr CPUDevice::mem_alloc_sub_ptr(device_memory &mem, size_t offset, size_t /*size*/)
{
return (device_ptr)(((char *)mem.device_pointer) + mem.memory_elements_size(offset));
}
void CPUDevice::const_copy_to(const char *name, void *host, size_t size)
{
#if WITH_EMBREE
if (strcmp(name, "__data") == 0) {
assert(size <= sizeof(KernelData));
// Update scene handle (since it is different for each device on multi devices)
KernelData *const data = (KernelData *)host;
data->bvh.scene = embree_scene;
}
#endif
kernel_const_copy(&kernel_globals, name, host, size);
}
void CPUDevice::global_alloc(device_memory &mem)
{
VLOG(1) << "Global memory allocate: " << mem.name << ", "
<< string_human_readable_number(mem.memory_size()) << " bytes. ("
<< string_human_readable_size(mem.memory_size()) << ")";
kernel_global_memory_copy(&kernel_globals, mem.name, mem.host_pointer, mem.data_size);
mem.device_pointer = (device_ptr)mem.host_pointer;
mem.device_size = mem.memory_size();
stats.mem_alloc(mem.device_size);
}
void CPUDevice::global_free(device_memory &mem)
{
if (mem.device_pointer) {
mem.device_pointer = 0;
stats.mem_free(mem.device_size);
mem.device_size = 0;
}
}
void CPUDevice::tex_alloc(device_texture &mem)
{
VLOG(1) << "Texture allocate: " << mem.name << ", "
<< string_human_readable_number(mem.memory_size()) << " bytes. ("
<< string_human_readable_size(mem.memory_size()) << ")";
mem.device_pointer = (device_ptr)mem.host_pointer;
mem.device_size = mem.memory_size();
stats.mem_alloc(mem.device_size);
const uint slot = mem.slot;
if (slot >= texture_info.size()) {
/* Allocate some slots in advance, to reduce amount of re-allocations. */
texture_info.resize(slot + 128);
}
texture_info[slot] = mem.info;
texture_info[slot].data = (uint64_t)mem.host_pointer;
need_texture_info = true;
}
void CPUDevice::tex_free(device_texture &mem)
{
if (mem.device_pointer) {
mem.device_pointer = 0;
stats.mem_free(mem.device_size);
mem.device_size = 0;
need_texture_info = true;
}
}
void CPUDevice::build_bvh(BVH *bvh, Progress &progress, bool refit)
{
#ifdef WITH_EMBREE
if (bvh->params.bvh_layout == BVH_LAYOUT_EMBREE ||
bvh->params.bvh_layout == BVH_LAYOUT_MULTI_OPTIX_EMBREE) {
BVHEmbree *const bvh_embree = static_cast<BVHEmbree *>(bvh);
if (refit) {
bvh_embree->refit(progress);
}
else {
bvh_embree->build(progress, &stats, embree_device);
}
if (bvh->params.top_level) {
embree_scene = bvh_embree->scene;
}
}
else
#endif
Device::build_bvh(bvh, progress, refit);
}
const CPUKernels *CPUDevice::get_cpu_kernels() const
{
return &kernels;
}
void CPUDevice::get_cpu_kernel_thread_globals(
vector<CPUKernelThreadGlobals> &kernel_thread_globals)
{
/* Ensure latest texture info is loaded into kernel globals before returning. */
load_texture_info();
kernel_thread_globals.clear();
void *osl_memory = get_cpu_osl_memory();
for (int i = 0; i < info.cpu_threads; i++) {
kernel_thread_globals.emplace_back(kernel_globals, osl_memory, profiler);
}
}
void *CPUDevice::get_cpu_osl_memory()
{
#ifdef WITH_OSL
return &osl_globals;
#else
return NULL;
#endif
}
bool CPUDevice::load_kernels(const uint /*kernel_features*/)
{
return true;
}
CCL_NAMESPACE_END

View File

@@ -0,0 +1,102 @@
/*
* Copyright 2011-2021 Blender Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
/* So ImathMath is included before our kernel_cpu_compat. */
#ifdef WITH_OSL
/* So no context pollution happens from indirectly included windows.h */
# include "util/util_windows.h"
# include <OSL/oslexec.h>
#endif
#ifdef WITH_EMBREE
# include <embree3/rtcore.h>
#endif
#include "device/cpu/kernel.h"
#include "device/device.h"
#include "device/device_memory.h"
// clang-format off
#include "kernel/device/cpu/compat.h"
#include "kernel/device/cpu/kernel.h"
#include "kernel/device/cpu/globals.h"
#include "kernel/osl/osl_shader.h"
#include "kernel/osl/osl_globals.h"
// clang-format on
CCL_NAMESPACE_BEGIN
class CPUDevice : public Device {
public:
KernelGlobals kernel_globals;
device_vector<TextureInfo> texture_info;
bool need_texture_info;
#ifdef WITH_OSL
OSLGlobals osl_globals;
#endif
#ifdef WITH_EMBREE
RTCScene embree_scene = NULL;
RTCDevice embree_device;
#endif
CPUKernels kernels;
CPUDevice(const DeviceInfo &info_, Stats &stats_, Profiler &profiler_);
~CPUDevice();
virtual bool show_samples() const override;
virtual BVHLayoutMask get_bvh_layout_mask() const override;
/* Returns true if the texture info was copied to the device (meaning, some more
* re-initialization might be needed). */
bool load_texture_info();
virtual void mem_alloc(device_memory &mem) override;
virtual void mem_copy_to(device_memory &mem) override;
virtual void mem_copy_from(
device_memory &mem, size_t y, size_t w, size_t h, size_t elem) override;
virtual void mem_zero(device_memory &mem) override;
virtual void mem_free(device_memory &mem) override;
virtual device_ptr mem_alloc_sub_ptr(device_memory &mem,
size_t offset,
size_t /*size*/) override;
virtual void const_copy_to(const char *name, void *host, size_t size) override;
void global_alloc(device_memory &mem);
void global_free(device_memory &mem);
void tex_alloc(device_texture &mem);
void tex_free(device_texture &mem);
void build_bvh(BVH *bvh, Progress &progress, bool refit) override;
virtual const CPUKernels *get_cpu_kernels() const override;
virtual void get_cpu_kernel_thread_globals(
vector<CPUKernelThreadGlobals> &kernel_thread_globals) override;
virtual void *get_cpu_osl_memory() override;
protected:
virtual bool load_kernels(uint /*kernel_features*/) override;
};
CCL_NAMESPACE_END

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