Files
test2/source/blender/gpu/vulkan/vk_state_manager.cc
Clément Foucault 00a8d006fe GPU: Move Polyline shader to primitive expansion
This port is not so straightforward.

This shader is used in different configurations and is
available to python bindings. So we need to keep
compatibility with different attributes configurations.

This is why attributes are loaded per component and a
uniform sets the length of the component.

Since this shader can be used from both the imm and batch
API, we need to inject some workarounds to bind the buffers
correctly.

The end result is still less versatile than the previous
metal workaround (i.e.: more attribute fetch mode supported),
but it is also way less code.

### Limitations:
The new shader has some limitation:
- Both `color` and `pos` attributes need to be `F32`.
- Each attribute needs to be 4byte aligned.
- Fetch type needs to be `GPU_FETCH_FLOAT`.
- Primitive type needs to be `GPU_PRIM_LINES`, `GPU_PRIM_LINE_STRIP` or `GPU_PRIM_LINE_LOOP`.
- If drawing using an index buffer, it must contain no primitive restart.

Rel #127493

Co-authored-by: Jeroen Bakker <jeroen@blender.org>
Pull Request: https://projects.blender.org/blender/blender/pulls/129315
2024-11-27 17:37:04 +01:00

168 lines
4.4 KiB
C++

/* SPDX-FileCopyrightText: 2023 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup gpu
*/
#include "vk_state_manager.hh"
#include "vk_context.hh"
#include "vk_index_buffer.hh"
#include "vk_shader.hh"
#include "vk_storage_buffer.hh"
#include "vk_texture.hh"
#include "vk_vertex_buffer.hh"
#include "GPU_capabilities.hh"
namespace blender::gpu {
void VKStateManager::apply_state()
{
/* Intentionally empty. State is polled during pipeline creation and doesn't need to be applied.
* If this leads to issues we should have an active state. */
}
void VKStateManager::force_state()
{
/* Intentionally empty. State is polled during pipeline creation and is always forced. */
}
void VKStateManager::issue_barrier(eGPUBarrier barrier_bits)
{
/**
* Workaround for EEVEE ThicknessFromShadow shader.
*
* EEVEE light evaluation uses layered sub-pass tracking. Currently, the tracking supports
* transitioning a layer to a different layout once per rendering scope. When using the thickness
* from shadow, the layers need to be transitioned twice: once to image load/store for the
* thickness from shadow shader and then to a sampler for the light evaluation shader. We work
* around this limitation by suspending the rendering.
*
* The reason we need to suspend the rendering is that Vulkan, by default, doesn't support layout
* transitions between the begin and end of rendering. By suspending the render, the graph will
* create a new node group that allows the necessary image layout transition.
*
* This limitation could also be addressed in the render graph scheduler, but that would be quite
* a hassle to track and might not be worth the effort.
*/
if (bool(barrier_bits & GPU_BARRIER_SHADER_IMAGE_ACCESS)) {
VKContext &context = *VKContext::get();
context.rendering_end();
}
}
void VKStateManager::texture_bind(Texture *texture, GPUSamplerState sampler, int binding)
{
textures_.bind(BindSpaceTextures::Type::Texture, texture, sampler, binding);
is_dirty = true;
}
void VKStateManager::texture_unbind(Texture *texture)
{
textures_.unbind(texture);
is_dirty = true;
}
void VKStateManager::texture_unbind_all()
{
textures_.unbind_all();
is_dirty = true;
}
void VKStateManager::image_bind(Texture *tex, int binding)
{
VKTexture *texture = unwrap(tex);
images_.bind(texture, binding);
is_dirty = true;
}
void VKStateManager::image_unbind(Texture *tex)
{
VKTexture *texture = unwrap(tex);
images_.unbind(texture);
is_dirty = true;
}
void VKStateManager::image_unbind_all()
{
images_.unbind_all();
is_dirty = true;
}
void VKStateManager::uniform_buffer_bind(VKUniformBuffer *uniform_buffer, int binding)
{
uniform_buffers_.bind(uniform_buffer, binding);
is_dirty = true;
}
void VKStateManager::uniform_buffer_unbind(VKUniformBuffer *uniform_buffer)
{
uniform_buffers_.unbind(uniform_buffer);
is_dirty = true;
}
void VKStateManager::uniform_buffer_unbind_all()
{
uniform_buffers_.unbind_all();
is_dirty = true;
}
void VKStateManager::unbind_from_all_namespaces(void *resource)
{
uniform_buffers_.unbind(resource);
storage_buffers_.unbind(resource);
images_.unbind(resource);
textures_.unbind(resource);
is_dirty = true;
}
void VKStateManager::texel_buffer_bind(VKVertexBuffer &vertex_buffer, int binding)
{
textures_.bind(BindSpaceTextures::Type::VertexBuffer,
&vertex_buffer,
GPUSamplerState::default_sampler(),
binding);
is_dirty = true;
}
void VKStateManager::texel_buffer_unbind(VKVertexBuffer &vertex_buffer)
{
textures_.unbind(&vertex_buffer);
is_dirty = true;
}
void VKStateManager::storage_buffer_bind(BindSpaceStorageBuffers::Type resource_type,
void *resource,
int binding,
VkDeviceSize offset)
{
storage_buffers_.bind(resource_type, resource, binding, offset);
is_dirty = true;
}
void VKStateManager::storage_buffer_unbind(void *resource)
{
storage_buffers_.unbind(resource);
is_dirty = true;
}
void VKStateManager::storage_buffer_unbind_all()
{
storage_buffers_.unbind_all();
is_dirty = true;
}
void VKStateManager::texture_unpack_row_length_set(uint len)
{
texture_unpack_row_length_ = len;
}
uint VKStateManager::texture_unpack_row_length_get() const
{
return texture_unpack_row_length_;
}
} // namespace blender::gpu