This PR implements dynamic viewport state for the Vulkan gpu backend.
By doing so, it fixes#130914.
The following high-level changes were made:
1. The pipeline pool no longer uses the viewport and scissor
states to identify graphics pipelines, only the number of viewports
and the number of scissors. Graphics pipelines are configured with
dynamic viewport and scissor states upon construction.
2. The desired viewport and scissor configurations for drawing are set
in the data of the draw nodes in the render graph.
3. The draw nodes use these viewport and scissors settings in
`build_commands`. If the viewport and scissor settings have changed
between nodes, then vkCmdSetViewport and vkCmdSetScissor commands
are sent to the command buffer.
4. Tests are updated to verify that set_viewport and set_scissor commands
are executed the correct number of times. (Also note that I needed to
#136987 in order to avoid skipping some Vulkan tests).
See the attached screencast for verification. The number of graphics pipelines
no longer grow when resizing the viewport.
Pull Request: https://projects.blender.org/blender/blender/pulls/137002
This PR implements a new the threading model for building render graphs
based on tests performed last month. For out workload multithreaded
command building will block in the driver or device. So better to use a
single thread for command building.
Details of the internal working is documented at https://developer.blender.org/docs/features/gpu/vulkan/render_graph/
- When a context is activated on a thread the context asks for a
render graph it can use by calling `VKDevice::render_graph_new`.
- Parts of the GPU backend that requires GPU commands will add a
specific render graph node to the render graph. The nodes also
contains a reference to all resources it needs including the
access it needs and the image layout.
- When the context is flushed the render graph is submitted to the
device by calling `VKDevice::render_graph_submit`.
- The device puts the render graph in `VKDevice::submission_pool`.
- There is a single background thread that gets the next render
graph to send to the GPU (`VKDevice::submission_runner`).
- Reorder the commands of the render graph to comply with Vulkan
specific command order rules and reducing possible bottlenecks.
(`VKScheduler`)
- Generate the required barriers `VKCommandBuilder::groups_extract_barriers`.
This is a separate step to reduce resource locking giving other
threads access to the resource states when they are building
the render graph nodes.
- GPU commands and pipeline barriers are recorded to a VkCommandBuffer.
(`VKCommandBuilder::record_commands`)
- When completed the command buffer can be submitted to the device
queue. `vkQueueSubmit`
- Render graphs that have been submitted can be reused by a next
thread. This is done by pushing the render graph to the
`VKDevice::unused_render_graphs` queue.
Pull Request: https://projects.blender.org/blender/blender/pulls/132681
Images used to be tracked with ownership in order to reset swap chain
images to its original layout. This isn't used anymore as we always mark
them in VK_IMAGE_LAYOUT_UNDEFINED to make the first pipeline barrier a
nop.
This change reduces unneeded complexity and safe a few CPU cycles.
Pull Request: https://projects.blender.org/blender/blender/pulls/133197
Initial design had a more complex use case for render graphs.
They are not really used and will not in the near term. This PR
removes some code that doesn't do a thing
Pull Request: https://projects.blender.org/blender/blender/pulls/133047
This will add support for `VK_KHR_dynamic_rendering_local_read` when supported.
The extension allows reading from an attachment that has been written to by a
previous command.
Per platform optimizations still need to happen in future changes. Change will
be limited to Qualcomm devices (in a future commit).
On Qualcomm devices this provides an uplift of 16% when using shader_balls.blend
Pull Request: https://projects.blender.org/blender/blender/pulls/131053
Reduces the number of times a graphic context needs to be paused/resumed.
The scheduler reorders the nodes to put these initial data transfer nodes
to the start of the nodes that are about to be submitted.
Pull Request: https://projects.blender.org/blender/blender/pulls/131502
When copying from/to depth stencil images the aspect of the image was
set incorrectly. It pointed to only one aspect of the full image when
building resource links, which could lead to incorrect decisions in the
driver.
Found when researching #131269
Pull Request: https://projects.blender.org/blender/blender/pulls/131298
Copying editors to the swap chain is done by a series of draw and copy.
When doing draw, copy, draw the swap chain layout was not matching the
draw command as it resumed previous rendering.
This is solved by validating the pipeline barriers when resuming rendering.
There are also other cases that required this which have been updated.
Pull Request: https://projects.blender.org/blender/blender/pulls/130721
Dynamic rendering is a Vulkan 1.3 feature. Most platforms have support
for them, but there are several legacy platforms that don't support dynamic
rendering or have driver bugs that don't allow us to use it.
This change will make dynamic rendering optional allowing legacy
platforms to use Vulkan.
**Limitations**
`GPU_LOADACTION_CLEAR` is implemented as clear attachments.
Render passes do support load clear, but adding support to it would
add complexity as it required multiple pipeline variations to support
suspend/resume rendering. It isn't clear when which variation should
be used what lead to compiling to many pipelines and branches in the
codebase. Using clear attachments doesn't require the complexity
for what is expected to be only used by platforms not supported by
the GPU vendors.
Subpass inputs and dual source blending are not supported as
Subpass inputs can alter the exact binding location of attachments.
Fixing this would add code complexity that is not used.
Ref: #129063
**Current state**

Pull Request: https://projects.blender.org/blender/blender/pulls/129062
When using cycles in the viewport there it uses render threads and
workers to update the viewport. All threads can record commands to the
queue and needs to be synchronized. This didn't happen leading to
incorrect renders.
Detected when researching #128608
Pull Request: https://projects.blender.org/blender/blender/pulls/128975
Related to #126974, which removed command reordering due to some
EEVEE/framebuffer requirements. However buffer can still be reordered
without any artifacts.
Update buffers are common operations and are often isolated; safe to
move them outside the rendering scope.
Pull Request: https://projects.blender.org/blender/blender/pulls/128538
This change adds the option to update a buffer via the render
graph via `vkCmdUpdateBuffer`. This is only enabled for
uniform buffers as they are small and aligned/sized correctly.
Pull Request: https://projects.blender.org/blender/blender/pulls/128416
Solved by not supporting complex reordering at this moment. It
is currently better to focus on quality and add back performance
later. During tests I didn't detect any user noticeable performance
degradation. Could also be because we support rendering
suspending/resuming.
Fixes artifacts in EEVEE volumes and raytracing.
Pull Request: https://projects.blender.org/blender/blender/pulls/126974
EEVEE can bind layers of a texture that is also used as an attachment. When binding
the image layout of these specific layers can be different that the image layout of
the whole image.
This fixes the known synchronization issues inside EEVEE. wasp_bot, tree_creature and
wanderer scenes can be rendered without any synchronization issue reported by the
Vulkan validation layers.
Design task: #124214
When beginning to render the attachments are being evaluated. If there is an arrayed
texture (with multiple layers) the individual layers of that texture can be tracked
during until the rendering is ended.
When the same texture is bound to a shader it will be a different layer (otherwise
there is a feedback loop, which isn't allowed). The bound layers will typically need
a different layout the transition to the new layout is executed and recorded. When
the rendering ends, the layers are transitioned back to the layout the texture is
expected in.
It can happen that a layer is used multiple times during the same rendering. In
that case the rendering should be suspended to perform the transition. Image layout
transitions are not allowed during rendering.
There is one place where a layer needs to be transited multiple times that is when
EEVEE wants to extract the thickness from the shadow. The thickness is stored inside
the gbuffer_normal which is also used as an attachment. Eval then samples the thickness
from the gbuffer_normal as a sampler. To work around this issue we suspend the rendering
when a `GPU_BARRIER_SHADER_IMAGE_ACCESS` is signaled.
Pull Request: https://projects.blender.org/blender/blender/pulls/124407
When copying the depth aspect of a depth+stencil image the incorrect
barriers where created. The barrier needs to have the full aspect, even
when we only copy a single aspect from the image.
Pull Request: https://projects.blender.org/blender/blender/pulls/123890
This PR adds drawing support to the render graph. It adds support for
draw, indirect draw, indexed draw and indexed indirect draw.
Draw commands can only be executed within a rendering scope. Data
transfer commands and dispatch commands cannot be executed within a
rendering scope. Blender can still send in commands in any order and
the render graph needs to find out the best order to minimize context
switches (rendering/begin/end). This is the responsibility of the
scheduler.
The scheduler will push data transfer and dispatch commands outside the
rendering scope:
- data transfer and dispatch commands at the beginning are done before
the rendering begin.
- data transfer and dispatch commands at the end are done after the
rendering end.
- data transfer and dispatches in between draw commands will be pushed
to the beginning if they are not yet being used.
- for all other data transfer and dispatch commands the rendering is
suspenderd and will be continued afterwards.
Within a rendering context it is not allowed to perform synchronization
commands. Any synchronization commands inside a rendering scope will be
performed before the rendering scope begins. Nodes are now organized
in groups to simplify the code around this area.
Pull Request: https://projects.blender.org/blender/blender/pulls/123168
When synchonizing the image for presentation the incorrect access
mask was used. This PR changes the access mask from data transfer
write to memory write. The data transfer write is not allowed to
change the image layout.
Pull Request: https://projects.blender.org/blender/blender/pulls/122138
This PR implements debug groups in the render graph. Each node contains
a reference to the debug group they belong to. During scheduling the
nodes can be reordered and the correct debug group needs to be
activated.
This is done by keeping track of the current debug group. When a
different debug group is needed, the needed ends/begins are added
to the command buffer.
This mechanism also cleans up debug groups that are not used at all
as they don't have any nodes associated to it.
Pull Request: https://projects.blender.org/blender/blender/pulls/122054
Compute tests were failing due to recent changes.
* Incorrect image layout was used for writable image bindings.
* Incorrect pipeline stage was used for indirect command buffers.
Pull Request: https://projects.blender.org/blender/blender/pulls/121744
There is an implementation flaw in the render graph where local pointers
cannot be updated, but the data it refers to can be reallocated to
another location.
The cause of this is that the nodes use an union, which can only contain
simple constructed structs (eg memcpy). this union is stored in a vector
and can relocate the union. Any local pointers can (and will) become
invalid.
This PR is a quick fix by updating the pointers just before sending
them to the command buffer. In future a better fox needs to be done
as part of #121649.
Pull Request: https://projects.blender.org/blender/blender/pulls/121723
The render graph tests initialized a command buffer wrapper that
requires a working device. The wrapper was not used, but when
destructing it would try to deallocate the command buffer, which
cannot be done as that requires a working device as well.
This PR removes the unneeded command buffer wrappers in the test
cases.
Result isn't consistent on Windows platform due to copying structs with arrays.
This is a quick fix and will be looked at next week. The code isn't used at this moment.
Pull Request: https://projects.blender.org/blender/blender/pulls/121670
Adds support for clear attachments to the render graph.
Clearing attachments require that the command buffer is
being set for rendering (vkCmdBeginRendering).
**What works**
- Clear attachments are working with dynamic rendering and the render graph
- `GPUVulkanTest.framebuffer_clear_color_single_attachment`
- `GPUVulkanTest.framebuffer_clear_color_multiple_attachments`
- `GPUVulkanTest.framebuffer_clear_multiple_color_multiple_attachments`
- `GPUVulkanTest.framebuffer_scissor_test`
- `GPUVulkanTest.framebuffer_clear_depth`
**What still needs to be addressed**
When a command buffer is rendering it cannot do any pipeline
barriers. For clearing attachments this isn't needed, but when
we address drawing we might need to register drawing resource
dependencies to the dependency list of the begin rendering node.
This will be solved when drawing will be implemented. [#121648]
The begin rendering node is large as it has to store data for
framebuffers with 8 color attachments as well. This might
become an overhead and we could solve this by splicing the
data of larger nodes into 2 lists. This will be addressed
after we are able to draw a screen so we can collect data
on this topic. [#121649]
Pull Request: https://projects.blender.org/blender/blender/pulls/121073
Add dispatch indirect node. Also refactored the dispatch (direct) node
so more logic could be reused. The context only stores a `VKResourceAccessInfo`
struct which is reused by both the dispatch and dispatch indirect node.
Pull Request: https://projects.blender.org/blender/blender/pulls/120993
This PR implements render graph for VKTexture. During the
implementation some tweaks to the render graph was done
to support depth and stencil textures.
The render graph will record the image aspect being used
for each node. This will then be used to generate barriers
for the correct aspect.
Also fixes an issue that uploading of array textures didn't
allocate a large enough staging buffer.
Pull Request: https://projects.blender.org/blender/blender/pulls/120821
**Design Task**: blender/blender#118330
This PR adds the core of the render graph. The render graph isn't used.
Current implementation of the Vulkan Backend is slow by design. We
focused on stability, before performance. With the new introduced render
graph the focus will shift to performance and keep the stability at where
it is.
Some highlights:
- Every context will get its own render graph. (`VKRenderGraph`).
- Resources (and resource state tracking) is device specific (`VKResourceStateTracker`).
- No node reordering / sub graph execution has been implemented. Currently
All nodes in the graph is executed in the order they were added. (`VKScheduler`).
- The links inside the graph describe the resources the nodes read from (input links)
or writes to (output links)
- When resources are written to a resource stamp is incremented allowing keeping
track of which nodes needs which stamp of a resource.
- At each link the access information (how does the node accesses the resource)
and image layout (for image resources) are stored. This allows the render graph
to find out how a resource was used in the past and will be used in the future.
That is important to construct pipeline barriers that don't stall the whole GPU.
# Defined nodes
This implementation has nodes for:
- Blit image
- Clear color image
- Copy buffers to buffers
- Copy buffers to images
- Copy images to images
- Copy images to buffers
- Dispatch compute shader
- Fill buffers
- Synchronization
Each node has a node info, create info and data struct. The create info
contains all data to construct the node, including the links of the graph.
The data struct only contains the data stored inside the node. The node info
contains the node specific implementation.
> NOTE: Other nodes will be added after this PR lands to main.
# Resources
Before a render graph can be used, the resources should be registered
to `VKResourceStateTracker`. In the final implementation this will be owned by
the `VKDevice`. Registration of resources can be done by calling
`VKResources.add_buffer` or `VKResources.add_image`.
# Render graph
Nodes can be added to the render graph. When adding a node its read/
write dependencies are extracted and converted into links (`VKNodeInfo.
build_links`).
When the caller wants to have a resource up to date the functions
`VKRenderGraph.submit_for_read` or `VKRenderGraph.submit_for_present`
can be called.
These functions will select and order the nodes that are needed
and convert them to `vkCmd*` commands. These commands include pipeline
barrier and image layout transitions.
The `vkCmd` are recorded into a command buffer which is sent to the
device queue.
## Walking the graph
Walking the render graph isn't implemented yet. The idea is to have a
`Map<ResourceWithStamp, Vector<NodeHandle>> consumers` and
`Map<ResourceWithStamp, NodeHandle> producers`. These attributes can
be stored in the render graph and created when building the links, or
can be created inside the VKScheduler as a variable. The exact detail
which one would be better is unclear as there aren't any users yet. At
the moment the scheduler would need them we need to figure out the best
way to store and retrieve the consumers/producers.
# Unit tests
The render graph can be tested by enabling `WITH_GTEST` and use
`vk_render_graph` as a filter.
```
bin/tests/blender_test --gtest_filter="vk_render_graph*"
```
Pull Request: https://projects.blender.org/blender/blender/pulls/120427