Vulkan: Initial Graphics Pipeline #106224
|
@ -212,14 +212,17 @@ set(VULKAN_SRC
|
|||
vulkan/vk_drawlist.cc
|
||||
vulkan/vk_fence.cc
|
||||
vulkan/vk_framebuffer.cc
|
||||
vulkan/vk_immediate.cc
|
||||
vulkan/vk_index_buffer.cc
|
||||
vulkan/vk_memory.cc
|
||||
vulkan/vk_memory_layout.cc
|
||||
vulkan/vk_pipeline_state.cc
|
||||
vulkan/vk_pipeline.cc
|
||||
vulkan/vk_pixel_buffer.cc
|
||||
vulkan/vk_push_constants.cc
|
||||
vulkan/vk_query.cc
|
||||
vulkan/vk_resource_tracker.cc
|
||||
vulkan/vk_sampler.cc
|
||||
vulkan/vk_shader.cc
|
||||
vulkan/vk_shader_interface.cc
|
||||
vulkan/vk_shader_log.cc
|
||||
|
@ -227,6 +230,7 @@ set(VULKAN_SRC
|
|||
vulkan/vk_storage_buffer.cc
|
||||
vulkan/vk_texture.cc
|
||||
vulkan/vk_uniform_buffer.cc
|
||||
vulkan/vk_vertex_attribute_object.cc
|
||||
vulkan/vk_vertex_buffer.cc
|
||||
|
||||
vulkan/vk_backend.hh
|
||||
|
@ -243,14 +247,17 @@ set(VULKAN_SRC
|
|||
vulkan/vk_drawlist.hh
|
||||
vulkan/vk_fence.hh
|
||||
vulkan/vk_framebuffer.hh
|
||||
vulkan/vk_immediate.hh
|
||||
vulkan/vk_index_buffer.hh
|
||||
vulkan/vk_memory.hh
|
||||
vulkan/vk_memory_layout.hh
|
||||
vulkan/vk_pipeline_state.hh
|
||||
vulkan/vk_pipeline.hh
|
||||
vulkan/vk_pixel_buffer.hh
|
||||
vulkan/vk_push_constants.hh
|
||||
vulkan/vk_query.hh
|
||||
vulkan/vk_resource_tracker.hh
|
||||
vulkan/vk_sampler.hh
|
||||
vulkan/vk_shader.hh
|
||||
vulkan/vk_shader_interface.hh
|
||||
vulkan/vk_shader_log.hh
|
||||
|
@ -258,6 +265,7 @@ set(VULKAN_SRC
|
|||
vulkan/vk_storage_buffer.hh
|
||||
vulkan/vk_texture.hh
|
||||
vulkan/vk_uniform_buffer.hh
|
||||
vulkan/vk_vertex_attribute_object.hh
|
||||
vulkan/vk_vertex_buffer.hh
|
||||
)
|
||||
|
||||
|
|
|
@ -64,17 +64,8 @@ void VKBackend::samplers_update() {}
|
|||
void VKBackend::compute_dispatch(int groups_x_len, int groups_y_len, int groups_z_len)
|
||||
{
|
||||
VKContext &context = *VKContext::get();
|
||||
VKShader *shader = static_cast<VKShader *>(context.shader);
|
||||
context.bind_compute_pipeline();
|
||||
Jeroen-Bakker marked this conversation as resolved
|
||||
VKCommandBuffer &command_buffer = context.command_buffer_get();
|
||||
VKPipeline &pipeline = shader->pipeline_get();
|
||||
VKDescriptorSetTracker &descriptor_set = pipeline.descriptor_set_get();
|
||||
VKPushConstants &push_constants = pipeline.push_constants_get();
|
||||
|
||||
push_constants.update(context);
|
||||
descriptor_set.update(context);
|
||||
command_buffer.bind(*descriptor_set.active_descriptor_set(),
|
||||
shader->vk_pipeline_layout_get(),
|
||||
VK_PIPELINE_BIND_POINT_COMPUTE);
|
||||
command_buffer.dispatch(groups_x_len, groups_y_len, groups_z_len);
|
||||
}
|
||||
|
||||
|
|
|
@ -7,9 +7,42 @@
|
|||
|
||||
#include "vk_batch.hh"
|
||||
|
||||
#include "vk_context.hh"
|
||||
#include "vk_index_buffer.hh"
|
||||
#include "vk_vertex_attribute_object.hh"
|
||||
#include "vk_vertex_buffer.hh"
|
||||
|
||||
namespace blender::gpu {
|
||||
|
||||
void VKBatch::draw(int /*v_first*/, int /*v_count*/, int /*i_first*/, int /*i_count*/) {}
|
||||
void VKBatch::draw(int vertex_first, int vertex_count, int instance_first, int instance_count)
|
||||
Jeroen-Bakker marked this conversation as resolved
Outdated
Jeroen Bakker
commented
Use full names to make a difference between indexed and instanced. Use full names to make a difference between indexed and instanced.
|
||||
{
|
||||
/* Currently the pipeline is rebuild on each draw command. Clearing the dirty flag for
|
||||
* consistency with the internals of GPU module. */
|
||||
flag &= ~GPU_BATCH_DIRTY;
|
||||
|
||||
/* Finalize graphics pipeline */
|
||||
VKContext &context = *VKContext::get();
|
||||
context.state_manager->apply_state();
|
||||
VKVertexAttributeObject vao;
|
||||
vao.update_bindings(context, *this);
|
||||
context.bind_graphics_pipeline(prim_type, vao);
|
||||
|
||||
/* Bind geometry resources. */
|
||||
vao.bind(context);
|
||||
VKIndexBuffer *index_buffer = index_buffer_get();
|
||||
const bool draw_indexed = index_buffer != nullptr;
|
||||
if (draw_indexed) {
|
||||
index_buffer->upload_data();
|
||||
index_buffer->bind(context);
|
||||
context.command_buffer_get().draw(
|
||||
index_buffer->index_len_get(), instance_count, index_buffer->index_start_get(), vertex_first, instance_first);
|
||||
}
|
||||
else {
|
||||
context.command_buffer_get().draw(vertex_first, vertex_count, instance_first, instance_count);
|
||||
}
|
||||
|
||||
context.command_buffer_get().submit();
|
||||
}
|
||||
|
||||
void VKBatch::draw_indirect(GPUStorageBuf * /*indirect_buf*/, intptr_t /*offset*/) {}
|
||||
|
||||
|
@ -20,4 +53,19 @@ void VKBatch::multi_draw_indirect(GPUStorageBuf * /*indirect_buf*/,
|
|||
{
|
||||
}
|
||||
|
||||
VKVertexBuffer *VKBatch::vertex_buffer_get(int index)
|
||||
{
|
||||
return unwrap(verts_(index));
|
||||
}
|
||||
|
||||
VKVertexBuffer *VKBatch::instance_buffer_get(int index)
|
||||
{
|
||||
return unwrap(inst_(index));
|
||||
}
|
||||
|
||||
VKIndexBuffer *VKBatch::index_buffer_get()
|
||||
{
|
||||
return unwrap(unwrap(elem));
|
||||
}
|
||||
|
||||
} // namespace blender::gpu
|
||||
|
|
|
@ -10,15 +10,21 @@
|
|||
#include "gpu_batch_private.hh"
|
||||
|
||||
namespace blender::gpu {
|
||||
class VKVertexBuffer;
|
||||
class VKIndexBuffer;
|
||||
|
||||
class VKBatch : public Batch {
|
||||
public:
|
||||
void draw(int v_first, int v_count, int i_first, int i_count) override;
|
||||
void draw(int vertex_first, int vertex_count, int instance_first, int instance_count) override;
|
||||
void draw_indirect(GPUStorageBuf *indirect_buf, intptr_t offset) override;
|
||||
void multi_draw_indirect(GPUStorageBuf *indirect_buf,
|
||||
int count,
|
||||
intptr_t offset,
|
||||
intptr_t stride) override;
|
||||
|
||||
VKVertexBuffer *vertex_buffer_get(int index);
|
||||
VKVertexBuffer *instance_buffer_get(int index);
|
||||
VKIndexBuffer *index_buffer_get();
|
||||
};
|
||||
|
||||
} // namespace blender::gpu
|
||||
|
|
|
@ -61,4 +61,15 @@ class VKBuffer {
|
|||
void unmap();
|
||||
};
|
||||
|
||||
/**
|
||||
* Helper struct to enable buffers to be bound with an offset.
|
||||
*
|
||||
* VKImmediate mode uses a single VKBuffer with multiple vertex layouts. Those layouts are send to
|
||||
* the command buffer containing an offset.
|
||||
*/
|
||||
struct VKBufferWithOffset {
|
||||
VKBuffer &buffer;
|
||||
VkDeviceSize offset;
|
||||
};
|
||||
|
||||
} // namespace blender::gpu
|
||||
|
|
|
@ -38,6 +38,13 @@ void VKCommandBuffer::init(const VkDevice vk_device,
|
|||
submission_id_.reset();
|
||||
state.stage = Stage::Initial;
|
||||
|
||||
/* When a the last GHOST context is destroyed the device is deallocate. A moment later the GPU
|
||||
* context is destroyed. The first step is to activate it. Activating would retrieve the device
|
||||
* from GHOST which in that case is a VK_NULL_HANDLE.*/
|
||||
if (vk_device == VK_NULL_HANDLE) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (vk_fence_ == VK_NULL_HANDLE) {
|
||||
VK_ALLOCATION_CALLBACKS;
|
||||
VkFenceCreateInfo fenceInfo{};
|
||||
|
@ -95,6 +102,11 @@ void VKCommandBuffer::bind(const uint32_t binding,
|
|||
bind(binding, vertex_buffer.vk_handle(), offset);
|
||||
}
|
||||
|
||||
void VKCommandBuffer::bind(const uint32_t binding, const VKBufferWithOffset &vertex_buffer)
|
||||
{
|
||||
bind(binding, vertex_buffer.buffer.vk_handle(), vertex_buffer.offset);
|
||||
}
|
||||
|
||||
void VKCommandBuffer::bind(const uint32_t binding,
|
||||
const VkBuffer &vk_vertex_buffer,
|
||||
const VkDeviceSize offset)
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
|
||||
namespace blender::gpu {
|
||||
class VKBuffer;
|
||||
struct VKBufferWithOffset;
|
||||
class VKDescriptorSet;
|
||||
class VKFrameBuffer;
|
||||
class VKIndexBuffer;
|
||||
|
@ -141,6 +142,7 @@ class VKCommandBuffer : NonCopyable, NonMovable {
|
|||
const VKVertexBuffer &vertex_buffer,
|
||||
const VkDeviceSize offset);
|
||||
/* Bind the given buffer as a vertex buffer. */
|
||||
void bind(const uint32_t binding, const VKBufferWithOffset &vertex_buffer);
|
||||
void bind(const uint32_t binding, const VkBuffer &vk_vertex_buffer, const VkDeviceSize offset);
|
||||
void bind(const VKIndexBuffer &index_buffer, VkIndexType index_type);
|
||||
|
||||
|
|
|
@ -9,8 +9,11 @@
|
|||
|
||||
#include "vk_backend.hh"
|
||||
#include "vk_framebuffer.hh"
|
||||
#include "vk_immediate.hh"
|
||||
#include "vk_memory.hh"
|
||||
#include "vk_shader.hh"
|
||||
#include "vk_state_manager.hh"
|
||||
#include "vk_texture.hh"
|
||||
|
||||
#include "GHOST_C-api.h"
|
||||
|
||||
|
@ -29,6 +32,7 @@ VKContext::VKContext(void *ghost_window, void *ghost_context)
|
|||
}
|
||||
|
||||
state_manager = new VKStateManager();
|
||||
imm = new VKImmediate();
|
||||
|
||||
/* For off-screen contexts. Default frame-buffer is empty. */
|
||||
VKFrameBuffer *framebuffer = new VKFrameBuffer("back_left");
|
||||
|
@ -36,7 +40,11 @@ VKContext::VKContext(void *ghost_window, void *ghost_context)
|
|||
active_fb = framebuffer;
|
||||
}
|
||||
|
||||
VKContext::~VKContext() {}
|
||||
VKContext::~VKContext()
|
||||
{
|
||||
delete imm;
|
||||
imm = nullptr;
|
||||
}
|
||||
|
||||
void VKContext::sync_backbuffer()
|
||||
{
|
||||
|
@ -85,9 +93,15 @@ void VKContext::activate()
|
|||
is_active_ = true;
|
||||
|
||||
sync_backbuffer();
|
||||
|
||||
immActivate();
|
||||
}
|
||||
|
||||
void VKContext::deactivate() {}
|
||||
void VKContext::deactivate()
|
||||
{
|
||||
immDeactivate();
|
||||
is_active_ = false;
|
||||
}
|
||||
|
||||
void VKContext::begin_frame()
|
||||
{
|
||||
|
@ -106,9 +120,6 @@ void VKContext::flush()
|
|||
|
||||
void VKContext::finish()
|
||||
{
|
||||
if (has_active_framebuffer()) {
|
||||
deactivate_framebuffer();
|
||||
}
|
||||
command_buffer_.submit();
|
||||
}
|
||||
|
||||
|
@ -123,8 +134,17 @@ const VKStateManager &VKContext::state_manager_get() const
|
|||
return *static_cast<const VKStateManager *>(state_manager);
|
||||
}
|
||||
|
||||
VKStateManager &VKContext::state_manager_get()
|
||||
{
|
||||
return *static_cast<VKStateManager *>(state_manager);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Framebuffer
|
||||
* \{ */
|
||||
|
||||
void VKContext::activate_framebuffer(VKFrameBuffer &framebuffer)
|
||||
{
|
||||
if (has_active_framebuffer()) {
|
||||
|
@ -148,12 +168,47 @@ bool VKContext::has_active_framebuffer() const
|
|||
|
||||
void VKContext::deactivate_framebuffer()
|
||||
{
|
||||
BLI_assert(active_fb != nullptr);
|
||||
VKFrameBuffer *framebuffer = active_framebuffer_get();
|
||||
BLI_assert(framebuffer != nullptr);
|
||||
if (framebuffer->is_valid()) {
|
||||
command_buffer_.end_render_pass(*framebuffer);
|
||||
}
|
||||
active_fb = nullptr;
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Compute pipeline
|
||||
* \{ */
|
||||
|
||||
void VKContext::bind_compute_pipeline()
|
||||
{
|
||||
VKShader *shader = unwrap(this->shader);
|
||||
BLI_assert(shader);
|
||||
VKPipeline &pipeline = shader->pipeline_get();
|
||||
pipeline.update_and_bind(
|
||||
*this, shader->vk_pipeline_layout_get(), VK_PIPELINE_BIND_POINT_COMPUTE);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Graphics pipeline
|
||||
* \{ */
|
||||
|
||||
void VKContext::bind_graphics_pipeline(const GPUPrimType prim_type,
|
||||
const VKVertexAttributeObject &vertex_attribute_object)
|
||||
{
|
||||
VKShader *shader = unwrap(this->shader);
|
||||
BLI_assert(shader);
|
||||
shader->update_graphics_pipeline(*this, prim_type, vertex_attribute_object);
|
||||
|
||||
VKPipeline &pipeline = shader->pipeline_get();
|
||||
pipeline.update_and_bind(
|
||||
*this, shader->vk_pipeline_layout_get(), VK_PIPELINE_BIND_POINT_GRAPHICS);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
} // namespace blender::gpu
|
||||
|
|
|
@ -15,6 +15,8 @@
|
|||
|
||||
namespace blender::gpu {
|
||||
class VKFrameBuffer;
|
||||
class VKVertexAttributeObject;
|
||||
class VKBatch;
|
||||
class VKStateManager;
|
||||
|
||||
class VKContext : public Context, NonCopyable {
|
||||
|
@ -50,6 +52,9 @@ class VKContext : public Context, NonCopyable {
|
|||
void deactivate_framebuffer();
|
||||
VKFrameBuffer *active_framebuffer_get() const;
|
||||
|
||||
void bind_compute_pipeline();
|
||||
void bind_graphics_pipeline(const GPUPrimType prim_type,
|
||||
const VKVertexAttributeObject &vertex_attribute_object);
|
||||
void sync_backbuffer();
|
||||
|
||||
static VKContext *get(void)
|
||||
|
@ -63,6 +68,7 @@ class VKContext : public Context, NonCopyable {
|
|||
}
|
||||
|
||||
const VKStateManager &state_manager_get() const;
|
||||
VKStateManager &state_manager_get();
|
||||
};
|
||||
|
||||
} // namespace blender::gpu
|
||||
|
|
|
@ -118,6 +118,7 @@ void object_label(VkObjectType vk_object_type, uint64_t object_handle, const cha
|
|||
const VKDevice &device = VKBackend::get().device_get();
|
||||
const VKDebuggingTools &debugging_tools = device.debugging_tools_get();
|
||||
if (debugging_tools.enabled) {
|
||||
const VKDevice &device = VKBackend::get().device_get();
|
||||
VkDebugUtilsObjectNameInfoEXT info = {};
|
||||
info.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT;
|
||||
info.objectType = vk_object_type;
|
||||
|
|
|
@ -81,6 +81,7 @@ bool VKDescriptorPools::is_last_pool_active()
|
|||
std::unique_ptr<VKDescriptorSet> VKDescriptorPools::allocate(
|
||||
const VkDescriptorSetLayout &descriptor_set_layout)
|
||||
{
|
||||
BLI_assert(descriptor_set_layout != VK_NULL_HANDLE);
|
||||
VkDescriptorSetAllocateInfo allocate_info = {};
|
||||
VkDescriptorPool pool = active_pool_get();
|
||||
allocate_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
#include "vk_descriptor_set.hh"
|
||||
#include "vk_index_buffer.hh"
|
||||
#include "vk_sampler.hh"
|
||||
#include "vk_shader.hh"
|
||||
#include "vk_storage_buffer.hh"
|
||||
#include "vk_texture.hh"
|
||||
|
@ -27,7 +28,6 @@ VKDescriptorSet::~VKDescriptorSet()
|
|||
{
|
||||
if (vk_descriptor_set_ != VK_NULL_HANDLE) {
|
||||
/* Handle should be given back to the pool. */
|
||||
BLI_assert(VKContext::get());
|
||||
VKDevice &device = VKBackend::get().device_;
|
||||
device.descriptor_pools_get().free(*this);
|
||||
BLI_assert(vk_descriptor_set_ == VK_NULL_HANDLE);
|
||||
|
@ -81,7 +81,17 @@ void VKDescriptorSetTracker::image_bind(VKTexture &texture,
|
|||
{
|
||||
Binding &binding = ensure_location(location);
|
||||
binding.type = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
|
||||
binding.vk_image_view = texture.vk_image_view_handle();
|
||||
binding.texture = &texture;
|
||||
}
|
||||
|
||||
void VKDescriptorSetTracker::bind(VKTexture &texture,
|
||||
const VKDescriptorSet::Location location,
|
||||
VKSampler &sampler)
|
||||
{
|
||||
Binding &binding = ensure_location(location);
|
||||
binding.type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
|
||||
binding.texture = &texture;
|
||||
binding.vk_sampler = sampler.vk_handle();
|
||||
}
|
||||
|
||||
VKDescriptorSetTracker::Binding &VKDescriptorSetTracker::ensure_location(
|
||||
|
@ -101,6 +111,7 @@ VKDescriptorSetTracker::Binding &VKDescriptorSetTracker::ensure_location(
|
|||
|
||||
void VKDescriptorSetTracker::update(VKContext &context)
|
||||
{
|
||||
BLI_assert(layout_ != VK_NULL_HANDLE);
|
||||
tracked_resource_for(context, !bindings_.is_empty());
|
||||
std::unique_ptr<VKDescriptorSet> &descriptor_set = active_descriptor_set();
|
||||
VkDescriptorSet vk_descriptor_set = descriptor_set->vk_handle();
|
||||
|
@ -132,9 +143,12 @@ void VKDescriptorSetTracker::update(VKContext &context)
|
|||
if (!binding.is_image()) {
|
||||
continue;
|
||||
}
|
||||
/* When updating the descriptor sets the layout of the texture should already be updated. */
|
||||
binding.texture->layout_ensure(context, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
|
||||
VkDescriptorImageInfo image_info = {};
|
||||
image_info.imageView = binding.vk_image_view;
|
||||
image_info.imageLayout = VK_IMAGE_LAYOUT_GENERAL;
|
||||
image_info.sampler = binding.vk_sampler;
|
||||
image_info.imageView = binding.texture->vk_image_view_handle();
|
||||
image_info.imageLayout = binding.texture->current_layout_get();
|
||||
image_infos.append(image_info);
|
||||
|
||||
VkWriteDescriptorSet write_descriptor = {};
|
||||
|
@ -150,7 +164,6 @@ void VKDescriptorSetTracker::update(VKContext &context)
|
|||
BLI_assert_msg(image_infos.size() + buffer_infos.size() == descriptor_writes.size(),
|
||||
"Not all changes have been converted to a write descriptor. Check "
|
||||
"`Binding::is_buffer` and `Binding::is_image`.");
|
||||
|
||||
const VKDevice &device = VKBackend::get().device_get();
|
||||
vkUpdateDescriptorSets(
|
||||
device.device_get(), descriptor_writes.size(), descriptor_writes.data(), 0, nullptr);
|
||||
|
@ -158,7 +171,7 @@ void VKDescriptorSetTracker::update(VKContext &context)
|
|||
bindings_.clear();
|
||||
}
|
||||
|
||||
std::unique_ptr<VKDescriptorSet> VKDescriptorSetTracker::create_resource(VKContext &context)
|
||||
std::unique_ptr<VKDescriptorSet> VKDescriptorSetTracker::create_resource(VKContext & /*context*/)
|
||||
{
|
||||
VKDevice &device = VKBackend::get().device_;
|
||||
return device.descriptor_pools_get().allocate(layout_);
|
||||
|
|
|
@ -25,6 +25,7 @@ class VKTexture;
|
|||
class VKUniformBuffer;
|
||||
class VKVertexBuffer;
|
||||
class VKDescriptorSetTracker;
|
||||
class VKSampler;
|
||||
|
||||
/**
|
||||
* In vulkan shader resources (images and buffers) are grouped in descriptor sets.
|
||||
|
@ -117,7 +118,8 @@ class VKDescriptorSetTracker : protected VKResourceTracker<VKDescriptorSet> {
|
|||
VkBuffer vk_buffer = VK_NULL_HANDLE;
|
||||
VkDeviceSize buffer_size = 0;
|
||||
|
||||
VkImageView vk_image_view = VK_NULL_HANDLE;
|
||||
VKTexture *texture = nullptr;
|
||||
VkSampler vk_sampler = VK_NULL_HANDLE;
|
||||
|
||||
Binding()
|
||||
{
|
||||
|
@ -131,14 +133,17 @@ class VKDescriptorSetTracker : protected VKResourceTracker<VKDescriptorSet> {
|
|||
|
||||
bool is_image() const
|
||||
{
|
||||
return ELEM(type, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE);
|
||||
return ELEM(type,
|
||||
VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
|
||||
VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER) &&
|
||||
texture != nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
private:
|
||||
/** A list of bindings that needs to be updated. */
|
||||
Vector<Binding> bindings_;
|
||||
VkDescriptorSetLayout layout_;
|
||||
VkDescriptorSetLayout layout_ = VK_NULL_HANDLE;
|
||||
|
||||
public:
|
||||
VKDescriptorSetTracker() {}
|
||||
|
@ -149,7 +154,20 @@ class VKDescriptorSetTracker : protected VKResourceTracker<VKDescriptorSet> {
|
|||
void bind_as_ssbo(VKIndexBuffer &buffer, VKDescriptorSet::Location location);
|
||||
void bind(VKStorageBuffer &buffer, VKDescriptorSet::Location location);
|
||||
void bind(VKUniformBuffer &buffer, VKDescriptorSet::Location location);
|
||||
/* TODO: bind as image */
|
||||
void image_bind(VKTexture &texture, VKDescriptorSet::Location location);
|
||||
void bind(VKTexture &texture, VKDescriptorSet::Location location, VKSampler &sampler);
|
||||
|
||||
/**
|
||||
* Some shaders don't need any descriptor sets so we don't need to bind them.
|
||||
*
|
||||
* The result of this function determines if the descriptor set has any layout assigned.
|
||||
* TODO: we might want to make descriptor sets optional for pipelines.
|
||||
*/
|
||||
bool has_layout() const
|
||||
{
|
||||
return layout_ != VK_NULL_HANDLE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the descriptor set on the device.
|
||||
|
|
|
@ -503,8 +503,10 @@ void VKFrameBuffer::render_pass_free()
|
|||
VK_ALLOCATION_CALLBACKS
|
||||
|
||||
const VKDevice &device = VKBackend::get().device_get();
|
||||
vkDestroyRenderPass(device.device_get(), vk_render_pass_, vk_allocation_callbacks);
|
||||
vkDestroyFramebuffer(device.device_get(), vk_framebuffer_, vk_allocation_callbacks);
|
||||
if (device.is_initialized()) {
|
||||
vkDestroyRenderPass(device.device_get(), vk_render_pass_, vk_allocation_callbacks);
|
||||
vkDestroyFramebuffer(device.device_get(), vk_framebuffer_, vk_allocation_callbacks);
|
||||
}
|
||||
vk_render_pass_ = VK_NULL_HANDLE;
|
||||
vk_framebuffer_ = VK_NULL_HANDLE;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,88 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
* Copyright 2023 Blender Foundation */
|
||||
|
||||
/** \file
|
||||
* \ingroup gpu
|
||||
*
|
||||
* Mimics old style OpenGL immediate mode drawing.
|
||||
*/
|
||||
|
||||
#include "vk_immediate.hh"
|
||||
#include "vk_data_conversion.hh"
|
||||
|
||||
namespace blender::gpu {
|
||||
|
||||
VKImmediate::VKImmediate() {}
|
||||
VKImmediate::~VKImmediate() {}
|
||||
|
||||
uchar *VKImmediate::begin()
|
||||
{
|
||||
VKContext &context = *VKContext::get();
|
||||
const size_t bytes_needed = vertex_buffer_size(&vertex_format, vertex_len);
|
||||
const bool new_buffer_needed = !has_active_resource() || buffer_bytes_free() < bytes_needed;
|
||||
|
||||
std::unique_ptr<VKBuffer> &buffer = tracked_resource_for(context, new_buffer_needed);
|
||||
current_subbuffer_len_ = bytes_needed;
|
||||
|
||||
uchar *data = static_cast<uchar *>(buffer->mapped_memory_get());
|
||||
return data + subbuffer_offset_get();
|
||||
}
|
||||
|
||||
void VKImmediate::end()
|
||||
{
|
||||
BLI_assert_msg(prim_type != GPU_PRIM_NONE, "Illegal state: not between an immBegin/End pair.");
|
||||
if (vertex_len == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (conversion_needed(vertex_format)) {
|
||||
// Slow path
|
||||
/* Determine the start of the subbuffer. The `vertex_data` attribute changes when new vertices
|
||||
* are loaded.
|
||||
*/
|
||||
uchar *data = static_cast<uchar *>(active_resource()->mapped_memory_get()) +
|
||||
subbuffer_offset_get();
|
||||
convert_in_place(data, vertex_format, vertex_len);
|
||||
}
|
||||
|
||||
VKContext &context = *VKContext::get();
|
||||
BLI_assert(context.shader == unwrap(shader));
|
||||
context.state_manager->apply_state();
|
||||
vertex_attributes_.update_bindings(*this);
|
||||
context.bind_graphics_pipeline(prim_type, vertex_attributes_);
|
||||
vertex_attributes_.bind(context);
|
||||
|
||||
context.command_buffer_get().draw(0, vertex_len, 0, 1);
|
||||
buffer_offset_ += current_subbuffer_len_;
|
||||
current_subbuffer_len_ = 0;
|
||||
}
|
||||
|
||||
VkDeviceSize VKImmediate::subbuffer_offset_get()
|
||||
{
|
||||
return buffer_offset_;
|
||||
}
|
||||
|
||||
VkDeviceSize VKImmediate::buffer_bytes_free()
|
||||
{
|
||||
return active_resource()->size_in_bytes() - subbuffer_offset_get();
|
||||
}
|
||||
|
||||
static VkDeviceSize new_buffer_size(size_t sub_buffer_size)
|
||||
{
|
||||
return max_ii(sub_buffer_size, DEFAULT_INTERNAL_BUFFER_SIZE);
|
||||
}
|
||||
|
||||
std::unique_ptr<VKBuffer> VKImmediate::create_resource(VKContext & /*context*/)
|
||||
{
|
||||
const size_t bytes_needed = vertex_buffer_size(&vertex_format, vertex_len);
|
||||
std::unique_ptr<VKBuffer> result = std::make_unique<VKBuffer>();
|
||||
result->create(new_buffer_size(bytes_needed),
|
||||
GPU_USAGE_DYNAMIC,
|
||||
static_cast<VkBufferUsageFlagBits>(VK_BUFFER_USAGE_VERTEX_BUFFER_BIT |
|
||||
VK_BUFFER_USAGE_TRANSFER_DST_BIT));
|
||||
debug::object_label(result->vk_handle(), "Immediate");
|
||||
buffer_offset_ = 0;
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace blender::gpu
|
|
@ -0,0 +1,51 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
* Copyright 2023 Blender Foundation */
|
||||
|
||||
/** \file
|
||||
* \ingroup gpu
|
||||
*
|
||||
* Mimics old style OpenGL immediate mode drawing.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
#include "gpu_immediate_private.hh"
|
||||
#include "gpu_vertex_format_private.h"
|
||||
|
||||
#include "vk_buffer.hh"
|
||||
#include "vk_context.hh"
|
||||
#include "vk_mem_alloc.h"
|
||||
#include "vk_resource_tracker.hh"
|
||||
#include "vk_vertex_attribute_object.hh"
|
||||
|
||||
namespace blender::gpu {
|
||||
|
||||
/* Size of internal buffer. */
|
||||
constexpr size_t DEFAULT_INTERNAL_BUFFER_SIZE = (4 * 1024 * 1024);
|
||||
|
||||
class VKImmediate : public Immediate, VKResourceTracker<VKBuffer> {
|
||||
private:
|
||||
VKVertexAttributeObject vertex_attributes_;
|
||||
|
||||
VkDeviceSize buffer_offset_ = 0;
|
||||
VkDeviceSize current_subbuffer_len_ = 0;
|
||||
|
||||
public:
|
||||
VKImmediate();
|
||||
virtual ~VKImmediate();
|
||||
|
||||
uchar *begin(void) override;
|
||||
void end(void) override;
|
||||
|
||||
friend class VKVertexAttributeObject;
|
||||
|
||||
private:
|
||||
VkDeviceSize subbuffer_offset_get();
|
||||
VkDeviceSize buffer_bytes_free();
|
||||
|
||||
std::unique_ptr<VKBuffer> create_resource(VKContext &context) override;
|
||||
};
|
||||
|
||||
} // namespace blender::gpu
|
|
@ -7,26 +7,39 @@
|
|||
|
||||
#include "vk_pipeline.hh"
|
||||
#include "vk_backend.hh"
|
||||
#include "vk_batch.hh"
|
||||
#include "vk_context.hh"
|
||||
#include "vk_framebuffer.hh"
|
||||
#include "vk_memory.hh"
|
||||
#include "vk_state_manager.hh"
|
||||
#include "vk_vertex_attribute_object.hh"
|
||||
|
||||
namespace blender::gpu {
|
||||
|
||||
VKPipeline::VKPipeline(VkDescriptorSetLayout vk_descriptor_set_layout,
|
||||
VKPushConstants &&push_constants)
|
||||
: active_vk_pipeline_(VK_NULL_HANDLE),
|
||||
descriptor_set_(vk_descriptor_set_layout),
|
||||
push_constants_(std::move(push_constants))
|
||||
{
|
||||
}
|
||||
|
||||
VKPipeline::VKPipeline(VkPipeline vk_pipeline,
|
||||
VkDescriptorSetLayout vk_descriptor_set_layout,
|
||||
VKPushConstants &&push_constants)
|
||||
: vk_pipeline_(vk_pipeline),
|
||||
: active_vk_pipeline_(vk_pipeline),
|
||||
descriptor_set_(vk_descriptor_set_layout),
|
||||
push_constants_(std::move(push_constants))
|
||||
{
|
||||
vk_pipelines_.append(vk_pipeline);
|
||||
}
|
||||
|
||||
VKPipeline::~VKPipeline()
|
||||
{
|
||||
VK_ALLOCATION_CALLBACKS
|
||||
const VKDevice &device = VKBackend::get().device_get();
|
||||
if (vk_pipeline_ != VK_NULL_HANDLE) {
|
||||
vkDestroyPipeline(device.device_get(), vk_pipeline_, vk_allocation_callbacks);
|
||||
for (VkPipeline vk_pipeline : vk_pipelines_) {
|
||||
vkDestroyPipeline(device.device_get(), vk_pipeline, vk_allocation_callbacks);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -64,14 +77,137 @@ VKPipeline VKPipeline::create_compute_pipeline(
|
|||
return VKPipeline(vk_pipeline, descriptor_set_layout, std::move(push_constants));
|
||||
}
|
||||
|
||||
VKPipeline VKPipeline::create_graphics_pipeline(
|
||||
VkDescriptorSetLayout &descriptor_set_layout,
|
||||
const VKPushConstants::Layout &push_constants_layout)
|
||||
{
|
||||
VKPushConstants push_constants(&push_constants_layout);
|
||||
return VKPipeline(descriptor_set_layout, std::move(push_constants));
|
||||
}
|
||||
|
||||
VkPipeline VKPipeline::vk_handle() const
|
||||
{
|
||||
return vk_pipeline_;
|
||||
return active_vk_pipeline_;
|
||||
}
|
||||
|
||||
bool VKPipeline::is_valid() const
|
||||
{
|
||||
return vk_pipeline_ != VK_NULL_HANDLE;
|
||||
return active_vk_pipeline_ != VK_NULL_HANDLE;
|
||||
}
|
||||
|
||||
Jeroen Bakker
commented
Don't pass VKBatch, but Don't pass VKBatch, but `GPUPrimType`. This makes the function also usable when using immediate mode.
|
||||
void VKPipeline::finalize(VKContext &context,
|
||||
VkShaderModule vertex_module,
|
||||
VkShaderModule geometry_module,
|
||||
VkShaderModule fragment_module,
|
||||
VkPipelineLayout &pipeline_layout,
|
||||
const GPUPrimType prim_type,
|
||||
const VKVertexAttributeObject &vertex_attribute_object)
|
||||
{
|
||||
BLI_assert(vertex_module != VK_NULL_HANDLE);
|
||||
|
||||
VK_ALLOCATION_CALLBACKS
|
||||
|
||||
Vector<VkPipelineShaderStageCreateInfo> pipeline_stages;
|
||||
VkPipelineShaderStageCreateInfo vertex_stage_info = {};
|
||||
vertex_stage_info.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
|
||||
vertex_stage_info.stage = VK_SHADER_STAGE_VERTEX_BIT;
|
||||
vertex_stage_info.module = vertex_module;
|
||||
vertex_stage_info.pName = "main";
|
||||
pipeline_stages.append(vertex_stage_info);
|
||||
|
||||
if (geometry_module != VK_NULL_HANDLE) {
|
||||
VkPipelineShaderStageCreateInfo geometry_stage_info = {};
|
||||
geometry_stage_info.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
|
||||
geometry_stage_info.stage = VK_SHADER_STAGE_GEOMETRY_BIT;
|
||||
geometry_stage_info.module = geometry_module;
|
||||
geometry_stage_info.pName = "main";
|
||||
pipeline_stages.append(geometry_stage_info);
|
||||
}
|
||||
|
||||
if (fragment_module != VK_NULL_HANDLE) {
|
||||
VkPipelineShaderStageCreateInfo fragment_stage_info = {};
|
||||
fragment_stage_info.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
|
||||
fragment_stage_info.stage = VK_SHADER_STAGE_FRAGMENT_BIT;
|
||||
fragment_stage_info.module = fragment_module;
|
||||
fragment_stage_info.pName = "main";
|
||||
pipeline_stages.append(fragment_stage_info);
|
||||
}
|
||||
|
||||
VKFrameBuffer &framebuffer = *context.active_framebuffer_get();
|
||||
|
||||
VkGraphicsPipelineCreateInfo pipeline_create_info = {};
|
||||
pipeline_create_info.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
|
||||
pipeline_create_info.stageCount = pipeline_stages.size();
|
||||
pipeline_create_info.pStages = pipeline_stages.data();
|
||||
pipeline_create_info.layout = pipeline_layout;
|
||||
pipeline_create_info.renderPass = framebuffer.vk_render_pass_get();
|
||||
pipeline_create_info.subpass = 0;
|
||||
|
||||
/* Vertex input state. */
|
||||
VkPipelineVertexInputStateCreateInfo vertex_input_state = {};
|
||||
vertex_input_state.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
|
||||
vertex_input_state.vertexBindingDescriptionCount = vertex_attribute_object.bindings.size();
|
||||
vertex_input_state.pVertexBindingDescriptions = vertex_attribute_object.bindings.data();
|
||||
vertex_input_state.vertexAttributeDescriptionCount = vertex_attribute_object.attributes.size();
|
||||
vertex_input_state.pVertexAttributeDescriptions = vertex_attribute_object.attributes.data();
|
||||
pipeline_create_info.pVertexInputState = &vertex_input_state;
|
||||
|
||||
/* Input assembly state. */
|
||||
VkPipelineInputAssemblyStateCreateInfo pipeline_input_assembly = {};
|
||||
pipeline_input_assembly.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
|
||||
pipeline_input_assembly.topology = to_vk_primitive_topology(prim_type);
|
||||
pipeline_create_info.pInputAssemblyState = &pipeline_input_assembly;
|
||||
|
||||
/* Viewport state. */
|
||||
VkPipelineViewportStateCreateInfo viewport_state = {};
|
||||
viewport_state.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
|
||||
VkViewport viewport = framebuffer.vk_viewport_get();
|
||||
viewport_state.pViewports = &viewport;
|
||||
viewport_state.viewportCount = 1;
|
||||
VkRect2D scissor = framebuffer.vk_render_area_get();
|
||||
viewport_state.pScissors = &scissor;
|
||||
viewport_state.scissorCount = 1;
|
||||
pipeline_create_info.pViewportState = &viewport_state;
|
||||
|
||||
/* Multisample state. */
|
||||
VkPipelineMultisampleStateCreateInfo multisample_state = {};
|
||||
multisample_state.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
|
||||
multisample_state.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
|
||||
multisample_state.minSampleShading = 1.0f;
|
||||
pipeline_create_info.pMultisampleState = &multisample_state;
|
||||
|
||||
/* States from the state manager. */
|
||||
const VKPipelineStateManager &state_manager = state_manager_get();
|
||||
pipeline_create_info.pColorBlendState = &state_manager.pipeline_color_blend_state;
|
||||
pipeline_create_info.pRasterizationState = &state_manager.rasterization_state;
|
||||
pipeline_create_info.pDepthStencilState = &state_manager.depth_stencil_state;
|
||||
|
||||
const VKDevice &device = VKBackend::get().device_get();
|
||||
vkCreateGraphicsPipelines(device.device_get(),
|
||||
VK_NULL_HANDLE,
|
||||
1,
|
||||
&pipeline_create_info,
|
||||
vk_allocation_callbacks,
|
||||
&active_vk_pipeline_);
|
||||
/* TODO: we should cache several pipeline instances and detect pipelines we can reuse. This might
|
||||
* also be done using a VkPipelineCache. For now we just destroy any available pipeline so it
|
||||
* won't be overwritten by the newly created one. */
|
||||
vk_pipelines_.append(active_vk_pipeline_);
|
||||
debug::object_label(active_vk_pipeline_, "GraphicsPipeline");
|
||||
}
|
||||
|
||||
void VKPipeline::update_and_bind(VKContext &context,
|
||||
VkPipelineLayout vk_pipeline_layout,
|
||||
VkPipelineBindPoint vk_pipeline_bind_point)
|
||||
{
|
||||
VKCommandBuffer &command_buffer = context.command_buffer_get();
|
||||
command_buffer.bind(*this, vk_pipeline_bind_point);
|
||||
push_constants_.update(context);
|
||||
if (descriptor_set_.has_layout()) {
|
||||
descriptor_set_.update(context);
|
||||
command_buffer.bind(
|
||||
*descriptor_set_.active_descriptor_set(), vk_pipeline_layout, vk_pipeline_bind_point);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace blender::gpu
|
||||
|
|
|
@ -14,29 +14,49 @@
|
|||
|
||||
#include "vk_common.hh"
|
||||
#include "vk_descriptor_set.hh"
|
||||
#include "vk_pipeline_state.hh"
|
||||
#include "vk_push_constants.hh"
|
||||
|
||||
namespace blender::gpu {
|
||||
class VKContext;
|
||||
class VKShader;
|
||||
class VKVertexAttributeObject;
|
||||
class VKBatch;
|
||||
|
||||
/**
|
||||
* Pipeline can be a compute pipeline or a graphic pipeline.
|
||||
*
|
||||
* Compute pipelines can be constructed early on, but graphics
|
||||
* pipelines depends on the actual GPU state/context.
|
||||
*
|
||||
* - TODO: we should sanitize the interface. There we can also
|
||||
* use late construction for compute pipelines.
|
||||
*/
|
||||
class VKPipeline : NonCopyable {
|
||||
VkPipeline vk_pipeline_ = VK_NULL_HANDLE;
|
||||
/* Active pipeline handle. */
|
||||
VkPipeline active_vk_pipeline_ = VK_NULL_HANDLE;
|
||||
/** Keep track of all pipelines as they can still be in flight. */
|
||||
Vector<VkPipeline> vk_pipelines_;
|
||||
VKDescriptorSetTracker descriptor_set_;
|
||||
VKPushConstants push_constants_;
|
||||
VKPipelineStateManager state_manager_;
|
||||
|
||||
public:
|
||||
VKPipeline() = default;
|
||||
|
||||
virtual ~VKPipeline();
|
||||
VKPipeline(VkDescriptorSetLayout vk_descriptor_set_layout, VKPushConstants &&push_constants);
|
||||
VKPipeline(VkPipeline vk_pipeline,
|
||||
VkDescriptorSetLayout vk_descriptor_set_layout,
|
||||
VKPushConstants &&push_constants);
|
||||
VKPipeline &operator=(VKPipeline &&other)
|
||||
{
|
||||
vk_pipeline_ = other.vk_pipeline_;
|
||||
other.vk_pipeline_ = VK_NULL_HANDLE;
|
||||
active_vk_pipeline_ = other.active_vk_pipeline_;
|
||||
other.active_vk_pipeline_ = VK_NULL_HANDLE;
|
||||
descriptor_set_ = std::move(other.descriptor_set_);
|
||||
push_constants_ = std::move(other.push_constants_);
|
||||
vk_pipelines_ = std::move(other.vk_pipelines_);
|
||||
other.vk_pipelines_.clear();
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
@ -44,6 +64,8 @@ class VKPipeline : NonCopyable {
|
|||
VkDescriptorSetLayout &descriptor_set_layout,
|
||||
VkPipelineLayout &pipeline_layouts,
|
||||
const VKPushConstants::Layout &push_constants_layout);
|
||||
static VKPipeline create_graphics_pipeline(VkDescriptorSetLayout &descriptor_set_layout,
|
||||
const VKPushConstants::Layout &push_constants_layout);
|
||||
|
||||
VKDescriptorSetTracker &descriptor_set_get()
|
||||
{
|
||||
|
@ -55,8 +77,28 @@ class VKPipeline : NonCopyable {
|
|||
return push_constants_;
|
||||
}
|
||||
|
||||
VKPipelineStateManager &state_manager_get()
|
||||
{
|
||||
return state_manager_;
|
||||
}
|
||||
|
||||
VkPipeline vk_handle() const;
|
||||
bool is_valid() const;
|
||||
|
||||
void finalize(VKContext &context,
|
||||
VkShaderModule vertex_module,
|
||||
VkShaderModule geometry_module,
|
||||
VkShaderModule fragment_module,
|
||||
VkPipelineLayout &pipeline_layout,
|
||||
const GPUPrimType prim_type,
|
||||
const VKVertexAttributeObject &vertex_attribute_object);
|
||||
|
||||
/**
|
||||
* Update PushConstants, DescriptorSets and bind pipeline to command buffer.
|
||||
*/
|
||||
void update_and_bind(VKContext &context,
|
||||
VkPipelineLayout vk_pipeline_layout,
|
||||
VkPipelineBindPoint vk_pipeline_bind_point);
|
||||
};
|
||||
|
||||
} // namespace blender::gpu
|
||||
|
|
|
@ -0,0 +1,367 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
* Copyright 2023 Blender Foundation */
|
||||
|
||||
/** \file
|
||||
* \ingroup gpu
|
||||
*/
|
||||
|
||||
#include "vk_pipeline_state.hh"
|
||||
|
||||
namespace blender::gpu {
|
||||
VKPipelineStateManager::VKPipelineStateManager()
|
||||
{
|
||||
rasterization_state = {};
|
||||
rasterization_state.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
|
||||
rasterization_state.lineWidth = 1.0f;
|
||||
|
||||
pipeline_color_blend_state = {};
|
||||
pipeline_color_blend_state.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
|
||||
|
||||
depth_stencil_state = {};
|
||||
depth_stencil_state.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
|
||||
|
||||
/* TODO should be extracted from current framebuffer and should not be done here and now. */
|
||||
/* When the attachments differ the state should be forced. */
|
||||
VkPipelineColorBlendAttachmentState color_blend_attachment = {};
|
||||
color_blend_attachment.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT |
|
||||
VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
|
||||
color_blend_attachments.append(color_blend_attachment);
|
||||
pipeline_color_blend_state.attachmentCount = color_blend_attachments.size();
|
||||
pipeline_color_blend_state.pAttachments = color_blend_attachments.data();
|
||||
}
|
||||
|
||||
void VKPipelineStateManager::set_state(const GPUState &state, const GPUStateMutable &mutable_state)
|
||||
{
|
||||
GPUState changed = state ^ current_;
|
||||
if (changed.blend) {
|
||||
set_blend(static_cast<eGPUBlend>(state.blend));
|
||||
}
|
||||
if (changed.write_mask != 0) {
|
||||
set_write_mask((eGPUWriteMask)state.write_mask);
|
||||
}
|
||||
if (changed.depth_test != 0) {
|
||||
set_depth_test((eGPUDepthTest)state.depth_test);
|
||||
}
|
||||
if (changed.stencil_test != 0 || changed.stencil_op != 0) {
|
||||
set_stencil_test((eGPUStencilTest)state.stencil_test, (eGPUStencilOp)state.stencil_op);
|
||||
set_stencil_mask((eGPUStencilTest)state.stencil_test, mutable_state);
|
||||
}
|
||||
if (changed.clip_distances != 0) {
|
||||
set_clip_distances(state.clip_distances, current_.clip_distances);
|
||||
}
|
||||
if (changed.culling_test != 0) {
|
||||
set_backface_culling((eGPUFaceCullTest)state.culling_test);
|
||||
}
|
||||
if (changed.logic_op_xor != 0) {
|
||||
set_logic_op(state.logic_op_xor);
|
||||
}
|
||||
if (changed.invert_facing != 0) {
|
||||
set_facing(state.invert_facing);
|
||||
}
|
||||
if (changed.provoking_vert != 0) {
|
||||
set_provoking_vert((eGPUProvokingVertex)state.provoking_vert);
|
||||
}
|
||||
if (changed.shadow_bias != 0) {
|
||||
set_shadow_bias(state.shadow_bias);
|
||||
}
|
||||
current_ = state;
|
||||
}
|
||||
|
||||
void VKPipelineStateManager::force_state(const GPUState &state,
|
||||
const GPUStateMutable &mutable_state)
|
||||
{
|
||||
current_ = ~state;
|
||||
set_state(state, mutable_state);
|
||||
}
|
||||
|
||||
void VKPipelineStateManager::set_blend(const eGPUBlend blend)
|
||||
{
|
||||
VkPipelineColorBlendStateCreateInfo &cb = pipeline_color_blend_state;
|
||||
VkPipelineColorBlendAttachmentState &att_state = color_blend_attachments.last();
|
||||
|
||||
att_state.blendEnable = VK_TRUE;
|
||||
att_state.alphaBlendOp = VK_BLEND_OP_ADD;
|
||||
att_state.colorBlendOp = VK_BLEND_OP_ADD;
|
||||
att_state.srcColorBlendFactor = VK_BLEND_FACTOR_DST_ALPHA;
|
||||
att_state.dstColorBlendFactor = VK_BLEND_FACTOR_ONE;
|
||||
att_state.srcAlphaBlendFactor = VK_BLEND_FACTOR_ZERO;
|
||||
att_state.dstAlphaBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
|
||||
cb.blendConstants[0] = 1.0f;
|
||||
cb.blendConstants[1] = 1.0f;
|
||||
cb.blendConstants[2] = 1.0f;
|
||||
cb.blendConstants[3] = 1.0f;
|
||||
|
||||
switch (blend) {
|
||||
default:
|
||||
case GPU_BLEND_ALPHA:
|
||||
att_state.srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA;
|
||||
att_state.dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
|
||||
att_state.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE;
|
||||
att_state.dstAlphaBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
|
||||
break;
|
||||
|
||||
case GPU_BLEND_ALPHA_PREMULT:
|
||||
att_state.srcColorBlendFactor = VK_BLEND_FACTOR_ONE;
|
||||
att_state.dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
|
||||
att_state.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE;
|
||||
att_state.dstAlphaBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
|
||||
break;
|
||||
|
||||
case GPU_BLEND_ADDITIVE:
|
||||
att_state.srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA;
|
||||
att_state.dstColorBlendFactor = VK_BLEND_FACTOR_ONE;
|
||||
att_state.srcAlphaBlendFactor = VK_BLEND_FACTOR_ZERO;
|
||||
att_state.dstAlphaBlendFactor = VK_BLEND_FACTOR_ONE;
|
||||
break;
|
||||
|
||||
case GPU_BLEND_SUBTRACT:
|
||||
case GPU_BLEND_ADDITIVE_PREMULT:
|
||||
att_state.srcColorBlendFactor = VK_BLEND_FACTOR_ONE;
|
||||
att_state.dstColorBlendFactor = VK_BLEND_FACTOR_ONE;
|
||||
att_state.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE;
|
||||
att_state.dstAlphaBlendFactor = VK_BLEND_FACTOR_ONE;
|
||||
break;
|
||||
|
||||
case GPU_BLEND_MULTIPLY:
|
||||
att_state.srcColorBlendFactor = VK_BLEND_FACTOR_DST_COLOR;
|
||||
att_state.dstColorBlendFactor = VK_BLEND_FACTOR_ZERO;
|
||||
att_state.srcAlphaBlendFactor = VK_BLEND_FACTOR_DST_ALPHA;
|
||||
att_state.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO;
|
||||
break;
|
||||
|
||||
case GPU_BLEND_INVERT:
|
||||
att_state.srcColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_DST_COLOR;
|
||||
att_state.dstColorBlendFactor = VK_BLEND_FACTOR_ZERO;
|
||||
att_state.srcAlphaBlendFactor = VK_BLEND_FACTOR_ZERO;
|
||||
att_state.dstAlphaBlendFactor = VK_BLEND_FACTOR_ONE;
|
||||
break;
|
||||
|
||||
case GPU_BLEND_OIT:
|
||||
att_state.srcColorBlendFactor = VK_BLEND_FACTOR_ONE;
|
||||
att_state.dstColorBlendFactor = VK_BLEND_FACTOR_ONE;
|
||||
att_state.srcAlphaBlendFactor = VK_BLEND_FACTOR_ZERO;
|
||||
att_state.dstAlphaBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
|
||||
break;
|
||||
|
||||
case GPU_BLEND_BACKGROUND:
|
||||
att_state.srcColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_DST_ALPHA;
|
||||
att_state.dstColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA;
|
||||
att_state.srcAlphaBlendFactor = VK_BLEND_FACTOR_ZERO;
|
||||
att_state.dstAlphaBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
|
||||
break;
|
||||
|
||||
case GPU_BLEND_ALPHA_UNDER_PREMUL:
|
||||
att_state.srcColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_DST_ALPHA;
|
||||
att_state.dstColorBlendFactor = VK_BLEND_FACTOR_ONE;
|
||||
att_state.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_DST_ALPHA;
|
||||
att_state.dstAlphaBlendFactor = VK_BLEND_FACTOR_ONE;
|
||||
break;
|
||||
|
||||
case GPU_BLEND_CUSTOM:
|
||||
att_state.srcColorBlendFactor = VK_BLEND_FACTOR_ONE;
|
||||
att_state.dstColorBlendFactor = VK_BLEND_FACTOR_SRC1_COLOR;
|
||||
att_state.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE;
|
||||
att_state.dstAlphaBlendFactor = VK_BLEND_FACTOR_SRC1_ALPHA;
|
||||
break;
|
||||
}
|
||||
|
||||
if (blend == GPU_BLEND_SUBTRACT) {
|
||||
att_state.alphaBlendOp = VK_BLEND_OP_REVERSE_SUBTRACT;
|
||||
att_state.colorBlendOp = VK_BLEND_OP_REVERSE_SUBTRACT;
|
||||
}
|
||||
else {
|
||||
att_state.alphaBlendOp = VK_BLEND_OP_ADD;
|
||||
att_state.colorBlendOp = VK_BLEND_OP_ADD;
|
||||
}
|
||||
|
||||
if (blend != GPU_BLEND_NONE) {
|
||||
att_state.blendEnable = VK_TRUE;
|
||||
}
|
||||
else {
|
||||
att_state.blendEnable = VK_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
void VKPipelineStateManager::set_write_mask(const eGPUWriteMask write_mask)
|
||||
{
|
||||
depth_stencil_state.depthWriteEnable = (write_mask & GPU_WRITE_DEPTH) ? VK_TRUE : VK_FALSE;
|
||||
|
||||
VkPipelineColorBlendAttachmentState &att_state = color_blend_attachments.last();
|
||||
att_state.colorWriteMask = 0;
|
||||
|
||||
if ((write_mask & GPU_WRITE_RED) != 0) {
|
||||
att_state.colorWriteMask |= VK_COLOR_COMPONENT_R_BIT;
|
||||
}
|
||||
if ((write_mask & GPU_WRITE_GREEN) != 0) {
|
||||
att_state.colorWriteMask |= VK_COLOR_COMPONENT_G_BIT;
|
||||
}
|
||||
if ((write_mask & GPU_WRITE_BLUE) != 0) {
|
||||
att_state.colorWriteMask |= VK_COLOR_COMPONENT_B_BIT;
|
||||
}
|
||||
if ((write_mask & GPU_WRITE_ALPHA) != 0) {
|
||||
att_state.colorWriteMask |= VK_COLOR_COMPONENT_A_BIT;
|
||||
}
|
||||
}
|
||||
|
||||
void VKPipelineStateManager::set_depth_test(const eGPUDepthTest value)
|
||||
{
|
||||
switch (value) {
|
||||
case GPU_DEPTH_LESS:
|
||||
depth_stencil_state.depthCompareOp = VK_COMPARE_OP_LESS;
|
||||
break;
|
||||
case GPU_DEPTH_LESS_EQUAL:
|
||||
depth_stencil_state.depthCompareOp = VK_COMPARE_OP_LESS_OR_EQUAL;
|
||||
break;
|
||||
case GPU_DEPTH_EQUAL:
|
||||
depth_stencil_state.depthCompareOp = VK_COMPARE_OP_EQUAL;
|
||||
break;
|
||||
case GPU_DEPTH_GREATER:
|
||||
depth_stencil_state.depthCompareOp = VK_COMPARE_OP_GREATER;
|
||||
break;
|
||||
case GPU_DEPTH_GREATER_EQUAL:
|
||||
depth_stencil_state.depthCompareOp = VK_COMPARE_OP_GREATER_OR_EQUAL;
|
||||
break;
|
||||
case GPU_DEPTH_ALWAYS:
|
||||
default:
|
||||
depth_stencil_state.depthCompareOp = VK_COMPARE_OP_ALWAYS;
|
||||
break;
|
||||
}
|
||||
|
||||
if (value != GPU_DEPTH_NONE) {
|
||||
depth_stencil_state.depthTestEnable = VK_TRUE;
|
||||
}
|
||||
else {
|
||||
depth_stencil_state.depthTestEnable = VK_FALSE;
|
||||
depth_stencil_state.depthCompareOp = VK_COMPARE_OP_NEVER;
|
||||
}
|
||||
|
||||
depth_stencil_state.depthBoundsTestEnable = VK_TRUE;
|
||||
}
|
||||
|
||||
void VKPipelineStateManager::set_stencil_test(const eGPUStencilTest test,
|
||||
const eGPUStencilOp operation)
|
||||
{
|
||||
depth_stencil_state.front.compareOp = VK_COMPARE_OP_ALWAYS;
|
||||
depth_stencil_state.front.compareMask = 0;
|
||||
depth_stencil_state.front.reference = 0;
|
||||
|
||||
switch (operation) {
|
||||
case GPU_STENCIL_OP_REPLACE:
|
||||
depth_stencil_state.front.failOp = VK_STENCIL_OP_KEEP;
|
||||
depth_stencil_state.front.passOp = VK_STENCIL_OP_KEEP;
|
||||
depth_stencil_state.front.depthFailOp = VK_STENCIL_OP_REPLACE;
|
||||
depth_stencil_state.back = depth_stencil_state.front;
|
||||
break;
|
||||
|
||||
case GPU_STENCIL_OP_COUNT_DEPTH_PASS:
|
||||
depth_stencil_state.front.failOp = VK_STENCIL_OP_KEEP;
|
||||
depth_stencil_state.front.passOp = VK_STENCIL_OP_KEEP;
|
||||
depth_stencil_state.front.depthFailOp = VK_STENCIL_OP_DECREMENT_AND_WRAP;
|
||||
depth_stencil_state.back = depth_stencil_state.front;
|
||||
depth_stencil_state.back.depthFailOp = VK_STENCIL_OP_INCREMENT_AND_WRAP;
|
||||
break;
|
||||
|
||||
case GPU_STENCIL_OP_COUNT_DEPTH_FAIL:
|
||||
depth_stencil_state.front.failOp = VK_STENCIL_OP_KEEP;
|
||||
depth_stencil_state.front.passOp = VK_STENCIL_OP_INCREMENT_AND_WRAP;
|
||||
depth_stencil_state.front.depthFailOp = VK_STENCIL_OP_KEEP;
|
||||
depth_stencil_state.back = depth_stencil_state.front;
|
||||
depth_stencil_state.back.depthFailOp = VK_STENCIL_OP_DECREMENT_AND_WRAP;
|
||||
break;
|
||||
|
||||
case GPU_STENCIL_OP_NONE:
|
||||
default:
|
||||
depth_stencil_state.front.failOp = VK_STENCIL_OP_KEEP;
|
||||
depth_stencil_state.front.passOp = VK_STENCIL_OP_KEEP;
|
||||
depth_stencil_state.front.depthFailOp = VK_STENCIL_OP_KEEP;
|
||||
depth_stencil_state.back = depth_stencil_state.front;
|
||||
break;
|
||||
}
|
||||
|
||||
if (test != GPU_STENCIL_NONE) {
|
||||
depth_stencil_state.stencilTestEnable = VK_TRUE;
|
||||
}
|
||||
else {
|
||||
depth_stencil_state.stencilTestEnable = VK_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
void VKPipelineStateManager::set_stencil_mask(const eGPUStencilTest test,
|
||||
const GPUStateMutable &mutable_state)
|
||||
{
|
||||
depth_stencil_state.front.writeMask = static_cast<uint32_t>(mutable_state.stencil_write_mask);
|
||||
depth_stencil_state.front.reference = static_cast<uint32_t>(mutable_state.stencil_reference);
|
||||
|
||||
depth_stencil_state.front.compareOp = VK_COMPARE_OP_ALWAYS;
|
||||
depth_stencil_state.front.compareMask = static_cast<uint32_t>(
|
||||
mutable_state.stencil_compare_mask);
|
||||
|
||||
switch (test) {
|
||||
case GPU_STENCIL_NEQUAL:
|
||||
depth_stencil_state.front.compareOp = VK_COMPARE_OP_NOT_EQUAL;
|
||||
break;
|
||||
case GPU_STENCIL_EQUAL:
|
||||
depth_stencil_state.front.compareOp = VK_COMPARE_OP_EQUAL;
|
||||
break;
|
||||
case GPU_STENCIL_ALWAYS:
|
||||
depth_stencil_state.front.compareOp = VK_COMPARE_OP_ALWAYS;
|
||||
break;
|
||||
case GPU_STENCIL_NONE:
|
||||
default:
|
||||
depth_stencil_state.front.compareMask = 0x00;
|
||||
depth_stencil_state.front.compareOp = VK_COMPARE_OP_ALWAYS;
|
||||
return;
|
||||
}
|
||||
|
||||
depth_stencil_state.back = depth_stencil_state.front;
|
||||
}
|
||||
|
||||
void VKPipelineStateManager::set_clip_distances(const int /*new_dist_len*/,
|
||||
const int /*old_dist_len*/)
|
||||
{
|
||||
/* TODO: needs to be implemented. */
|
||||
}
|
||||
|
||||
void VKPipelineStateManager::set_logic_op(const bool enable)
|
||||
{
|
||||
if (enable) {
|
||||
pipeline_color_blend_state.logicOpEnable = VK_TRUE;
|
||||
pipeline_color_blend_state.logicOp = VK_LOGIC_OP_XOR;
|
||||
}
|
||||
else {
|
||||
pipeline_color_blend_state.logicOpEnable = VK_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
void VKPipelineStateManager::set_facing(const bool invert)
|
||||
{
|
||||
rasterization_state.frontFace = invert ? VK_FRONT_FACE_COUNTER_CLOCKWISE :
|
||||
VK_FRONT_FACE_CLOCKWISE;
|
||||
}
|
||||
|
||||
void VKPipelineStateManager::set_backface_culling(const eGPUFaceCullTest cull_test)
|
||||
{
|
||||
rasterization_state.cullMode = to_vk_cull_mode_flags(cull_test);
|
||||
}
|
||||
|
||||
void VKPipelineStateManager::set_provoking_vert(const eGPUProvokingVertex /*vert*/)
|
||||
{
|
||||
/* TODO: Requires VK_EXT_PROVOKING_VERTEX_EXTENSION_NAME, See:
|
||||
* https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPipelineRasterizationProvokingVertexStateCreateInfoEXT.html
|
||||
*/
|
||||
}
|
||||
|
||||
void VKPipelineStateManager::set_shadow_bias(const bool enable)
|
||||
{
|
||||
if (enable) {
|
||||
rasterization_state.depthBiasEnable = VK_TRUE;
|
||||
rasterization_state.depthBiasSlopeFactor = 2.f;
|
||||
rasterization_state.depthBiasConstantFactor = 1.f;
|
||||
rasterization_state.depthBiasClamp = 0.f;
|
||||
}
|
||||
else {
|
||||
rasterization_state.depthBiasEnable = VK_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace blender::gpu
|
|
@ -0,0 +1,46 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
* Copyright 2023 Blender Foundation */
|
||||
|
||||
/** \file
|
||||
* \ingroup gpu
|
||||
*/
|
||||
|
||||
#include "gpu_state_private.hh"
|
||||
|
||||
#include "vk_common.hh"
|
||||
|
||||
#include "BLI_vector.hh"
|
||||
|
||||
namespace blender::gpu {
|
||||
|
||||
class VKPipelineStateManager {
|
||||
private:
|
||||
GPUState current_;
|
||||
GPUStateMutable current_mutable_;
|
||||
|
||||
public:
|
||||
VkPipelineColorBlendStateCreateInfo pipeline_color_blend_state;
|
||||
Vector<VkPipelineColorBlendAttachmentState> color_blend_attachments;
|
||||
VkPipelineRasterizationStateCreateInfo rasterization_state;
|
||||
VkPipelineDepthStencilStateCreateInfo depth_stencil_state;
|
||||
|
||||
VKPipelineStateManager();
|
||||
|
||||
void set_state(const GPUState &state, const GPUStateMutable &mutable_state);
|
||||
void force_state(const GPUState &state, const GPUStateMutable &mutable_state);
|
||||
|
||||
private:
|
||||
void set_blend(eGPUBlend blend);
|
||||
void set_write_mask(eGPUWriteMask write_mask);
|
||||
void set_depth_test(eGPUDepthTest value);
|
||||
void set_stencil_test(eGPUStencilTest test, eGPUStencilOp operation);
|
||||
void set_stencil_mask(eGPUStencilTest test, const GPUStateMutable &mutable_state);
|
||||
void set_clip_distances(int new_dist_len, int old_dist_len);
|
||||
void set_logic_op(bool enable);
|
||||
void set_facing(bool invert);
|
||||
void set_backface_culling(eGPUFaceCullTest test);
|
||||
void set_provoking_vert(eGPUProvokingVertex vert);
|
||||
void set_shadow_bias(bool enable);
|
||||
};
|
||||
|
||||
} // namespace blender::gpu
|
|
@ -158,6 +158,14 @@ template<typename Resource> class VKResourceTracker : NonCopyable {
|
|||
*/
|
||||
virtual std::unique_ptr<Resource> create_resource(VKContext &context) = 0;
|
||||
|
||||
/**
|
||||
* Does this instance have an active resource.
|
||||
*/
|
||||
bool has_active_resource()
|
||||
{
|
||||
return !tracked_resources_.is_empty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the active resource of the tracker.
|
||||
*/
|
||||
|
|
|
@ -0,0 +1,45 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
* Copyright 2023 Blender Foundation */
|
||||
|
||||
/** \file
|
||||
* \ingroup gpu
|
||||
*/
|
||||
|
||||
#include "vk_sampler.hh"
|
||||
#include "vk_backend.hh"
|
||||
#include "vk_context.hh"
|
||||
#include "vk_memory.hh"
|
||||
|
||||
namespace blender::gpu {
|
||||
VKSampler::~VKSampler()
|
||||
{
|
||||
free();
|
||||
}
|
||||
|
||||
void VKSampler::create()
|
||||
{
|
||||
BLI_assert(vk_sampler_ == VK_NULL_HANDLE);
|
||||
|
||||
VK_ALLOCATION_CALLBACKS
|
||||
|
||||
VkSamplerCreateInfo sampler_info = {};
|
||||
sampler_info.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;
|
||||
const VKDevice &device = VKBackend::get().device_get();
|
||||
vkCreateSampler(device.device_get(), &sampler_info, vk_allocation_callbacks, &vk_sampler_);
|
||||
debug::object_label(vk_sampler_, "DummySampler");
|
||||
}
|
||||
|
||||
void VKSampler::free()
|
||||
{
|
||||
VK_ALLOCATION_CALLBACKS
|
||||
|
||||
if (vk_sampler_ != VK_NULL_HANDLE) {
|
||||
const VKDevice &device = VKBackend::get().device_get();
|
||||
if (device.device_get() != VK_NULL_HANDLE) {
|
||||
vkDestroySampler(device.device_get(), vk_sampler_, vk_allocation_callbacks);
|
||||
}
|
||||
vk_sampler_ = VK_NULL_HANDLE;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace blender::gpu
|
|
@ -0,0 +1,34 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
* Copyright 2023 Blender Foundation */
|
||||
|
||||
/** \file
|
||||
* \ingroup gpu
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "gpu_shader_private.hh"
|
||||
|
||||
#include "vk_common.hh"
|
||||
|
||||
#include "BLI_utility_mixins.hh"
|
||||
|
||||
namespace blender::gpu {
|
||||
class VKContext;
|
||||
|
||||
class VKSampler : public NonCopyable {
|
||||
VkSampler vk_sampler_ = VK_NULL_HANDLE;
|
||||
|
||||
public:
|
||||
virtual ~VKSampler();
|
||||
void create();
|
||||
void free();
|
||||
|
||||
VkSampler vk_handle()
|
||||
{
|
||||
BLI_assert(vk_sampler_ != VK_NULL_HANDLE);
|
||||
return vk_sampler_;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace blender::gpu
|
|
@ -578,7 +578,6 @@ VKShader::VKShader(const char *name) : Shader(name)
|
|||
VKShader::~VKShader()
|
||||
{
|
||||
VK_ALLOCATION_CALLBACKS
|
||||
|
||||
const VKDevice &device = VKBackend::get().device_get();
|
||||
if (vertex_module_ != VK_NULL_HANDLE) {
|
||||
vkDestroyShaderModule(device.device_get(), vertex_module_, vk_allocation_callbacks);
|
||||
|
@ -667,16 +666,18 @@ bool VKShader::finalize(const shader::ShaderCreateInfo *info)
|
|||
BLI_assert((fragment_module_ != VK_NULL_HANDLE && info->tf_type_ == GPU_SHADER_TFB_NONE) ||
|
||||
(fragment_module_ == VK_NULL_HANDLE && info->tf_type_ != GPU_SHADER_TFB_NONE));
|
||||
BLI_assert(compute_module_ == VK_NULL_HANDLE);
|
||||
result = finalize_graphics_pipeline(device.device_get());
|
||||
pipeline_ = VKPipeline::create_graphics_pipeline(layout_,
|
||||
vk_interface->push_constants_layout_get());
|
||||
result = true;
|
||||
}
|
||||
else {
|
||||
BLI_assert(vertex_module_ == VK_NULL_HANDLE);
|
||||
BLI_assert(geometry_module_ == VK_NULL_HANDLE);
|
||||
BLI_assert(fragment_module_ == VK_NULL_HANDLE);
|
||||
BLI_assert(compute_module_ != VK_NULL_HANDLE);
|
||||
compute_pipeline_ = VKPipeline::create_compute_pipeline(
|
||||
pipeline_ = VKPipeline::create_compute_pipeline(
|
||||
compute_module_, layout_, pipeline_layout_, vk_interface->push_constants_layout_get());
|
||||
result = compute_pipeline_.is_valid();
|
||||
result = pipeline_.is_valid();
|
||||
}
|
||||
|
||||
if (result) {
|
||||
|
@ -688,36 +689,6 @@ bool VKShader::finalize(const shader::ShaderCreateInfo *info)
|
|||
return result;
|
||||
}
|
||||
|
||||
bool VKShader::finalize_graphics_pipeline(VkDevice /*vk_device */)
|
||||
{
|
||||
Vector<VkPipelineShaderStageCreateInfo> pipeline_stages;
|
||||
VkPipelineShaderStageCreateInfo vertex_stage_info = {};
|
||||
vertex_stage_info.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
|
||||
vertex_stage_info.stage = VK_SHADER_STAGE_VERTEX_BIT;
|
||||
vertex_stage_info.module = vertex_module_;
|
||||
vertex_stage_info.pName = "main";
|
||||
pipeline_stages.append(vertex_stage_info);
|
||||
|
||||
if (geometry_module_ != VK_NULL_HANDLE) {
|
||||
VkPipelineShaderStageCreateInfo geo_stage_info = {};
|
||||
geo_stage_info.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
|
||||
geo_stage_info.stage = VK_SHADER_STAGE_GEOMETRY_BIT;
|
||||
geo_stage_info.module = geometry_module_;
|
||||
geo_stage_info.pName = "main";
|
||||
pipeline_stages.append(geo_stage_info);
|
||||
}
|
||||
if (fragment_module_ != VK_NULL_HANDLE) {
|
||||
VkPipelineShaderStageCreateInfo fragment_stage_info = {};
|
||||
fragment_stage_info.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
|
||||
fragment_stage_info.stage = VK_SHADER_STAGE_FRAGMENT_BIT;
|
||||
fragment_stage_info.module = fragment_module_;
|
||||
fragment_stage_info.pName = "main";
|
||||
pipeline_stages.append(fragment_stage_info);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool VKShader::finalize_pipeline_layout(VkDevice vk_device,
|
||||
const VKShaderInterface &shader_interface)
|
||||
{
|
||||
|
@ -958,26 +929,27 @@ bool VKShader::transform_feedback_enable(GPUVertBuf *)
|
|||
|
||||
void VKShader::transform_feedback_disable() {}
|
||||
|
||||
void VKShader::update_graphics_pipeline(VKContext &context,
|
||||
const GPUPrimType prim_type,
|
||||
const VKVertexAttributeObject &vertex_attribute_object)
|
||||
{
|
||||
BLI_assert(is_graphics_shader());
|
||||
pipeline_get().finalize(context,
|
||||
vertex_module_,
|
||||
geometry_module_,
|
||||
fragment_module_,
|
||||
pipeline_layout_,
|
||||
prim_type,
|
||||
vertex_attribute_object);
|
||||
}
|
||||
|
||||
void VKShader::bind()
|
||||
{
|
||||
VKContext *context = VKContext::get();
|
||||
|
||||
if (is_compute_shader()) {
|
||||
context->command_buffer_get().bind(compute_pipeline_, VK_PIPELINE_BIND_POINT_COMPUTE);
|
||||
}
|
||||
else {
|
||||
BLI_assert_unreachable();
|
||||
}
|
||||
/* Intentionally empty. Binding of the pipeline are done just before drawing/dispatching.
|
||||
* See #VKPipeline.update_and_bind */
|
||||
}
|
||||
|
||||
void VKShader::unbind()
|
||||
{
|
||||
if (is_compute_shader()) {
|
||||
}
|
||||
else {
|
||||
BLI_assert_unreachable();
|
||||
}
|
||||
}
|
||||
void VKShader::unbind() {}
|
||||
|
||||
void VKShader::uniform_float(int location, int comp_len, int array_size, const float *data)
|
||||
{
|
||||
|
@ -1217,7 +1189,7 @@ int VKShader::program_handle_get() const
|
|||
|
||||
VKPipeline &VKShader::pipeline_get()
|
||||
{
|
||||
return compute_pipeline_;
|
||||
return pipeline_;
|
||||
}
|
||||
|
||||
const VKShaderInterface &VKShader::interface_get() const
|
||||
|
|
|
@ -28,7 +28,7 @@ class VKShader : public Shader {
|
|||
bool compilation_failed_ = false;
|
||||
VkDescriptorSetLayout layout_ = VK_NULL_HANDLE;
|
||||
VkPipelineLayout pipeline_layout_ = VK_NULL_HANDLE;
|
||||
VKPipeline compute_pipeline_;
|
||||
VKPipeline pipeline_;
|
||||
|
||||
public:
|
||||
VKShader(const char *name);
|
||||
|
@ -70,6 +70,10 @@ class VKShader : public Shader {
|
|||
|
||||
const VKShaderInterface &interface_get() const;
|
||||
|
||||
void update_graphics_pipeline(VKContext &context,
|
||||
const GPUPrimType prim_type,
|
||||
const VKVertexAttributeObject &vertex_attribute_object);
|
||||
|
||||
private:
|
||||
Vector<uint32_t> compile_glsl_to_spirv(Span<const char *> sources, shaderc_shader_kind kind);
|
||||
void build_shader_module(Span<uint32_t> spirv_module, VkShaderModule *r_shader_module);
|
||||
|
@ -80,7 +84,6 @@ class VKShader : public Shader {
|
|||
const VKShaderInterface &shader_interface,
|
||||
const shader::ShaderCreateInfo &info);
|
||||
bool finalize_pipeline_layout(VkDevice vk_device, const VKShaderInterface &shader_interface);
|
||||
bool finalize_graphics_pipeline(VkDevice vk_device);
|
||||
|
||||
bool is_graphics_shader() const
|
||||
{
|
||||
|
@ -93,4 +96,14 @@ class VKShader : public Shader {
|
|||
}
|
||||
};
|
||||
|
||||
static inline VKShader &unwrap(Shader &shader)
|
||||
{
|
||||
return static_cast<VKShader &>(shader);
|
||||
}
|
||||
|
||||
static inline VKShader *unwrap(Shader *shader)
|
||||
{
|
||||
return static_cast<VKShader *>(shader);
|
||||
}
|
||||
|
||||
} // namespace blender::gpu
|
||||
|
|
|
@ -6,12 +6,67 @@
|
|||
*/
|
||||
|
||||
#include "vk_state_manager.hh"
|
||||
#include "vk_context.hh"
|
||||
#include "vk_pipeline.hh"
|
||||
#include "vk_shader.hh"
|
||||
#include "vk_texture.hh"
|
||||
|
||||
namespace blender::gpu {
|
||||
void VKStateManager::apply_state() {}
|
||||
#include "GPU_capabilities.h"
|
||||
|
||||
void VKStateManager::force_state() {}
|
||||
namespace blender::gpu {
|
||||
|
||||
VKStateManager::VKStateManager()
|
||||
{
|
||||
sampler_.create();
|
||||
constexpr int max_bindings = 16;
|
||||
image_bindings_ = Array<ImageBinding>(max_bindings);
|
||||
image_bindings_.fill(ImageBinding());
|
||||
texture_bindings_ = Array<ImageBinding>(max_bindings);
|
||||
texture_bindings_.fill(ImageBinding());
|
||||
uniform_buffer_bindings_ = Array<UniformBufferBinding>(max_bindings);
|
||||
uniform_buffer_bindings_.fill(UniformBufferBinding());
|
||||
}
|
||||
|
||||
void VKStateManager::apply_state()
|
||||
{
|
||||
VKContext &context = *VKContext::get();
|
||||
if (context.shader) {
|
||||
VKShader &shader = unwrap(*context.shader);
|
||||
VKPipeline &pipeline = shader.pipeline_get();
|
||||
pipeline.state_manager_get().set_state(state, mutable_state);
|
||||
|
||||
for (int binding : IndexRange(image_bindings_.size())) {
|
||||
if (image_bindings_[binding].texture == nullptr) {
|
||||
continue;
|
||||
}
|
||||
image_bindings_[binding].texture->image_bind(binding);
|
||||
}
|
||||
|
||||
for (int binding : IndexRange(image_bindings_.size())) {
|
||||
if (texture_bindings_[binding].texture == nullptr) {
|
||||
continue;
|
||||
}
|
||||
texture_bindings_[binding].texture->bind(binding, sampler_);
|
||||
}
|
||||
|
||||
for (int binding : IndexRange(uniform_buffer_bindings_.size())) {
|
||||
if (uniform_buffer_bindings_[binding].buffer == nullptr) {
|
||||
continue;
|
||||
}
|
||||
uniform_buffer_bindings_[binding].buffer->bind(
|
||||
binding, shader::ShaderCreateInfo::Resource::BindType::UNIFORM_BUFFER);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void VKStateManager::force_state()
|
||||
{
|
||||
VKContext &context = *VKContext::get();
|
||||
BLI_assert(context.shader);
|
||||
VKShader &shader = unwrap(*context.shader);
|
||||
VKPipeline &pipeline = shader.pipeline_get();
|
||||
pipeline.state_manager_get().force_state(state, mutable_state);
|
||||
}
|
||||
|
||||
void VKStateManager::issue_barrier(eGPUBarrier /*barrier_bits*/)
|
||||
{
|
||||
|
@ -22,21 +77,69 @@ void VKStateManager::issue_barrier(eGPUBarrier /*barrier_bits*/)
|
|||
command_buffer.submit();
|
||||
}
|
||||
|
||||
void VKStateManager::texture_bind(Texture * /*tex*/, GPUSamplerState /*sampler*/, int /*unit*/) {}
|
||||
void VKStateManager::texture_bind(Texture *tex, GPUSamplerState /*sampler*/, int unit)
|
||||
{
|
||||
VKTexture *texture = unwrap(tex);
|
||||
texture_bindings_[unit].texture = texture;
|
||||
}
|
||||
|
||||
void VKStateManager::texture_unbind(Texture * /*tex*/) {}
|
||||
void VKStateManager::texture_unbind(Texture *tex)
|
||||
{
|
||||
VKTexture *texture = unwrap(tex);
|
||||
for (ImageBinding &binding : texture_bindings_) {
|
||||
if (binding.texture == texture) {
|
||||
binding.texture = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void VKStateManager::texture_unbind_all() {}
|
||||
void VKStateManager::texture_unbind_all()
|
||||
{
|
||||
for (ImageBinding &binding : texture_bindings_) {
|
||||
if (binding.texture != nullptr) {
|
||||
binding.texture = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void VKStateManager::image_bind(Texture *tex, int binding)
|
||||
{
|
||||
VKTexture *texture = unwrap(tex);
|
||||
texture->image_bind(binding);
|
||||
image_bindings_[binding].texture = texture;
|
||||
}
|
||||
|
||||
void VKStateManager::image_unbind(Texture * /*tex*/) {}
|
||||
void VKStateManager::image_unbind(Texture *tex)
|
||||
{
|
||||
VKTexture *texture = unwrap(tex);
|
||||
for (ImageBinding &binding : image_bindings_) {
|
||||
if (binding.texture == texture) {
|
||||
binding.texture = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void VKStateManager::image_unbind_all() {}
|
||||
void VKStateManager::image_unbind_all()
|
||||
{
|
||||
for (ImageBinding &binding : texture_bindings_) {
|
||||
if (binding.texture != nullptr) {
|
||||
binding.texture = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void VKStateManager::uniform_buffer_bind(VKUniformBuffer *uniform_buffer, int slot)
|
||||
{
|
||||
uniform_buffer_bindings_[slot].buffer = uniform_buffer;
|
||||
}
|
||||
|
||||
void VKStateManager::uniform_buffer_unbind(VKUniformBuffer *uniform_buffer)
|
||||
{
|
||||
for (UniformBufferBinding &binding : uniform_buffer_bindings_) {
|
||||
if (binding.buffer == uniform_buffer) {
|
||||
binding.buffer = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void VKStateManager::texture_unpack_row_length_set(uint len)
|
||||
{
|
||||
|
|
|
@ -9,11 +9,33 @@
|
|||
|
||||
#include "gpu_state_private.hh"
|
||||
|
||||
#include "BLI_array.hh"
|
||||
|
||||
#include "vk_sampler.hh"
|
||||
|
||||
namespace blender::gpu {
|
||||
class VKTexture;
|
||||
class VKUniformBuffer;
|
||||
|
||||
class VKStateManager : public StateManager {
|
||||
uint texture_unpack_row_length_;
|
||||
/* Dummy sampler for now.*/
|
||||
VKSampler sampler_;
|
||||
|
||||
uint texture_unpack_row_length_ = 0;
|
||||
|
||||
struct ImageBinding {
|
||||
VKTexture *texture = nullptr;
|
||||
};
|
||||
struct UniformBufferBinding {
|
||||
VKUniformBuffer *buffer = nullptr;
|
||||
};
|
||||
Array<ImageBinding> image_bindings_;
|
||||
Array<ImageBinding> texture_bindings_;
|
||||
Array<UniformBufferBinding> uniform_buffer_bindings_;
|
||||
|
||||
public:
|
||||
VKStateManager();
|
||||
|
||||
void apply_state() override;
|
||||
void force_state() override;
|
||||
|
||||
|
@ -27,6 +49,9 @@ class VKStateManager : public StateManager {
|
|||
void image_unbind(Texture *tex) override;
|
||||
void image_unbind_all() override;
|
||||
|
||||
void uniform_buffer_bind(VKUniformBuffer *uniform_buffer, int slot);
|
||||
void uniform_buffer_unbind(VKUniformBuffer *uniform_buffer);
|
||||
|
||||
void texture_unpack_row_length_set(uint len) override;
|
||||
|
||||
/**
|
||||
|
|
|
@ -229,6 +229,16 @@ static VkImageUsageFlagBits to_vk_image_usage(const eGPUTextureUsage usage,
|
|||
result = static_cast<VkImageUsageFlagBits>(result | VK_IMAGE_USAGE_TRANSFER_SRC_BIT);
|
||||
}
|
||||
|
||||
/* Disable some usages based on the given format flag to support more devices. */
|
||||
if (format_flag & GPU_FORMAT_SRGB) {
|
||||
/* NVIDIA devices don't create SRGB textures when it storage bit is set. */
|
||||
result = static_cast<VkImageUsageFlagBits>(result & ~VK_IMAGE_USAGE_STORAGE_BIT);
|
||||
}
|
||||
if (format_flag & (GPU_FORMAT_DEPTH | GPU_FORMAT_STENCIL)) {
|
||||
/* NVIDIA devices don't create depth textures when it storage bit is set. */
|
||||
result = static_cast<VkImageUsageFlagBits>(result & ~VK_IMAGE_USAGE_STORAGE_BIT);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -311,6 +321,24 @@ bool VKTexture::allocate()
|
|||
return result == VK_SUCCESS;
|
||||
}
|
||||
|
||||
// TODO: move texture/image bindings to shader.
|
||||
void VKTexture::bind(int unit, VKSampler &sampler)
|
||||
Jeroen Bakker
commented
This should be done as part of this change. This should be done as part of this change.
|
||||
{
|
||||
if (!is_allocated()) {
|
||||
allocate();
|
||||
}
|
||||
VKContext &context = *VKContext::get();
|
||||
VKShader *shader = static_cast<VKShader *>(context.shader);
|
||||
const VKShaderInterface &shader_interface = shader->interface_get();
|
||||
const std::optional<VKDescriptorSet::Location> location =
|
||||
shader_interface.descriptor_set_location(
|
||||
shader::ShaderCreateInfo::Resource::BindType::SAMPLER, unit);
|
||||
if (location) {
|
||||
VKDescriptorSetTracker &descriptor_set = shader->pipeline_get().descriptor_set_get();
|
||||
descriptor_set.bind(*this, *location, sampler);
|
||||
}
|
||||
}
|
||||
|
||||
void VKTexture::image_bind(int binding)
|
||||
{
|
||||
if (!is_allocated()) {
|
||||
|
|
|
@ -12,6 +12,8 @@
|
|||
|
||||
namespace blender::gpu {
|
||||
|
||||
class VKSampler;
|
||||
|
||||
class VKTexture : public Texture {
|
||||
VkImage vk_image_ = VK_NULL_HANDLE;
|
||||
VkImageView vk_image_view_ = VK_NULL_HANDLE;
|
||||
|
@ -25,6 +27,7 @@ class VKTexture : public Texture {
|
|||
|
||||
public:
|
||||
VKTexture(const char *name) : Texture(name) {}
|
||||
|
||||
virtual ~VKTexture() override;
|
||||
|
||||
void init(VkImage vk_image, VkImageLayout layout);
|
||||
|
@ -46,7 +49,9 @@ class VKTexture : public Texture {
|
|||
/* TODO(fclem): Legacy. Should be removed at some point. */
|
||||
uint gl_bindcode_get() const override;
|
||||
|
||||
void bind(int unit, VKSampler &sampler);
|
||||
void image_bind(int location);
|
||||
|
||||
VkImage vk_image_handle() const
|
||||
{
|
||||
BLI_assert(vk_image_ != VK_NULL_HANDLE);
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#include "vk_context.hh"
|
||||
#include "vk_shader.hh"
|
||||
#include "vk_shader_interface.hh"
|
||||
#include "vk_state_manager.hh"
|
||||
|
||||
namespace blender::gpu {
|
||||
|
||||
|
@ -54,7 +55,9 @@ void VKUniformBuffer::bind(int slot, shader::ShaderCreateInfo::Resource::BindTyp
|
|||
|
||||
void VKUniformBuffer::bind(int slot)
|
||||
{
|
||||
bind(slot, shader::ShaderCreateInfo::Resource::BindType::UNIFORM_BUFFER);
|
||||
/* Uniform buffers can be bound without an shader. */
|
||||
VKContext &context = *VKContext::get();
|
||||
context.state_manager_get().uniform_buffer_bind(this, slot);
|
||||
}
|
||||
|
||||
void VKUniformBuffer::bind_as_ssbo(int slot)
|
||||
|
@ -62,6 +65,10 @@ void VKUniformBuffer::bind_as_ssbo(int slot)
|
|||
bind(slot, shader::ShaderCreateInfo::Resource::BindType::STORAGE_BUFFER);
|
||||
}
|
||||
|
||||
void VKUniformBuffer::unbind() {}
|
||||
void VKUniformBuffer::unbind()
|
||||
{
|
||||
VKContext &context = *VKContext::get();
|
||||
context.state_manager_get().uniform_buffer_unbind(this);
|
||||
}
|
||||
|
||||
} // namespace blender::gpu
|
||||
|
|
|
@ -25,6 +25,7 @@ class VKUniformBuffer : public UniformBuf, NonCopyable {
|
|||
void clear_to_zero() override;
|
||||
void bind(int slot) override;
|
||||
void bind_as_ssbo(int slot) override;
|
||||
void bind(int slot, shader::ShaderCreateInfo::Resource::BindType bind_type);
|
||||
void unbind() override;
|
||||
|
||||
VkBuffer vk_handle() const
|
||||
|
@ -39,7 +40,6 @@ class VKUniformBuffer : public UniformBuf, NonCopyable {
|
|||
|
||||
private:
|
||||
void allocate();
|
||||
void bind(int slot, shader::ShaderCreateInfo::Resource::BindType bind_type);
|
||||
};
|
||||
|
||||
} // namespace blender::gpu
|
||||
|
|
|
@ -0,0 +1,198 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
* Copyright 2023 Blender Foundation. All rights reserved. */
|
||||
|
||||
#include "vk_vertex_attribute_object.hh"
|
||||
|
||||
#include "vk_batch.hh"
|
||||
#include "vk_context.hh"
|
||||
#include "vk_immediate.hh"
|
||||
#include "vk_shader.hh"
|
||||
#include "vk_shader_interface.hh"
|
||||
#include "vk_vertex_buffer.hh"
|
||||
|
||||
#include "BLI_array.hh"
|
||||
|
||||
namespace blender::gpu {
|
||||
VKVertexAttributeObject::VKVertexAttributeObject()
|
||||
{
|
||||
clear();
|
||||
}
|
||||
|
||||
void VKVertexAttributeObject::clear()
|
||||
{
|
||||
is_valid = false;
|
||||
info.pNext = NULL;
|
||||
bindings.clear();
|
||||
attributes.clear();
|
||||
vbos.clear();
|
||||
buffers.clear();
|
||||
}
|
||||
|
||||
VKVertexAttributeObject &VKVertexAttributeObject::operator=(const VKVertexAttributeObject &other)
|
||||
{
|
||||
if (this == &other) {
|
||||
return *this;
|
||||
}
|
||||
|
||||
is_valid = other.is_valid;
|
||||
info = other.info;
|
||||
bindings.clear();
|
||||
bindings.extend(other.bindings);
|
||||
attributes.clear();
|
||||
attributes.extend(other.attributes);
|
||||
vbos.clear();
|
||||
vbos.extend(other.vbos);
|
||||
buffers.clear();
|
||||
buffers.extend(other.buffers);
|
||||
return *this;
|
||||
}
|
||||
|
||||
void VKVertexAttributeObject::bind(VKContext &context)
|
||||
{
|
||||
Array<bool> visited_bindings(bindings.size());
|
||||
visited_bindings.fill(false);
|
||||
|
||||
for (VkVertexInputAttributeDescription attribute : attributes) {
|
||||
if (visited_bindings[attribute.binding]) {
|
||||
continue;
|
||||
}
|
||||
visited_bindings[attribute.binding] = true;
|
||||
|
||||
/* Bind VBOS from batches. */
|
||||
if (attribute.binding < vbos.size()) {
|
||||
BLI_assert(vbos[attribute.binding]);
|
||||
VKVertexBuffer &vbo = *vbos[attribute.binding];
|
||||
vbo.upload();
|
||||
context.command_buffer_get().bind(attribute.binding, vbo, 0);
|
||||
}
|
||||
|
||||
/* Bind dynamic buffers from immediate mode. */
|
||||
if (attribute.binding < buffers.size()) {
|
||||
VKBufferWithOffset &buffer = buffers[attribute.binding];
|
||||
context.command_buffer_get().bind(attribute.binding, buffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void VKVertexAttributeObject::update_bindings(const VKContext &context, VKBatch &batch)
|
||||
{
|
||||
clear();
|
||||
const VKShaderInterface &interface = unwrap(context.shader)->interface_get();
|
||||
AttributeMask occupied_attributes = 0;
|
||||
|
||||
for (int v = 0; v < GPU_BATCH_INST_VBO_MAX_LEN; v++) {
|
||||
VKVertexBuffer *vbo = batch.instance_buffer_get(v);
|
||||
if (vbo) {
|
||||
update_bindings(
|
||||
vbo->format, vbo, nullptr, vbo->vertex_len, interface, occupied_attributes, true);
|
||||
}
|
||||
}
|
||||
for (int v = 0; v < GPU_BATCH_VBO_MAX_LEN; v++) {
|
||||
VKVertexBuffer *vbo = batch.vertex_buffer_get(v);
|
||||
if (vbo) {
|
||||
update_bindings(
|
||||
vbo->format, vbo, nullptr, vbo->vertex_len, interface, occupied_attributes, false);
|
||||
}
|
||||
}
|
||||
|
||||
is_valid = true;
|
||||
|
||||
BLI_assert(interface.enabled_attr_mask_ == occupied_attributes);
|
||||
}
|
||||
|
||||
void VKVertexAttributeObject::update_bindings(VKImmediate &immediate)
|
||||
{
|
||||
clear();
|
||||
const VKShaderInterface &interface = unwrap(unwrap(immediate.shader))->interface_get();
|
||||
AttributeMask occupied_attributes = 0;
|
||||
|
||||
VKBufferWithOffset immediate_buffer = {*immediate.active_resource(),
|
||||
immediate.subbuffer_offset_get()};
|
||||
|
||||
update_bindings(immediate.vertex_format,
|
||||
nullptr,
|
||||
&immediate_buffer,
|
||||
immediate.vertex_len,
|
||||
interface,
|
||||
occupied_attributes,
|
||||
false);
|
||||
is_valid = true;
|
||||
BLI_assert(interface.enabled_attr_mask_ == occupied_attributes);
|
||||
}
|
||||
|
||||
void VKVertexAttributeObject::update_bindings(const GPUVertFormat &vertex_format,
|
||||
VKVertexBuffer *vertex_buffer,
|
||||
VKBufferWithOffset *immediate_vertex_buffer,
|
||||
const int64_t vertex_len,
|
||||
const VKShaderInterface &interface,
|
||||
AttributeMask &r_occupied_attributes,
|
||||
const bool use_instancing)
|
||||
{
|
||||
BLI_assert(vertex_buffer || immediate_vertex_buffer);
|
||||
BLI_assert(!(vertex_buffer && immediate_vertex_buffer));
|
||||
|
||||
if (vertex_format.attr_len <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t offset = 0;
|
||||
uint32_t stride = vertex_format.stride;
|
||||
|
||||
for (uint32_t attribute_index = 0; attribute_index < vertex_format.attr_len; attribute_index++) {
|
||||
const GPUVertAttr &attribute = vertex_format.attrs[attribute_index];
|
||||
if (vertex_format.deinterleaved) {
|
||||
offset += ((attribute_index == 0) ? 0 : vertex_format.attrs[attribute_index - 1].size) *
|
||||
vertex_len;
|
||||
stride = attribute.size;
|
||||
}
|
||||
else {
|
||||
offset = attribute.offset;
|
||||
}
|
||||
|
||||
const uint32_t binding = bindings.size();
|
||||
|
||||
bool attribute_used_by_shader = false;
|
||||
for (uint32_t name_index = 0; name_index < attribute.name_len; name_index++) {
|
||||
const char *name = GPU_vertformat_attr_name_get(&vertex_format, &attribute, name_index);
|
||||
const ShaderInput *shader_input = interface.attr_get(name);
|
||||
if (shader_input == nullptr || shader_input->location == -1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Don't overwrite attributes that are already occupied. */
|
||||
AttributeMask attribute_mask = 1 << shader_input->location;
|
||||
if (r_occupied_attributes & attribute_mask) {
|
||||
continue;
|
||||
}
|
||||
r_occupied_attributes |= attribute_mask;
|
||||
attribute_used_by_shader = true;
|
||||
|
||||
VkVertexInputAttributeDescription attribute_description = {};
|
||||
attribute_description.binding = binding;
|
||||
attribute_description.location = shader_input->location;
|
||||
attribute_description.offset = offset;
|
||||
attribute_description.format = to_vk_format(
|
||||
static_cast<GPUVertCompType>(attribute.comp_type),
|
||||
attribute.size,
|
||||
static_cast<GPUVertFetchMode>(attribute.fetch_mode));
|
||||
attributes.append(attribute_description);
|
||||
}
|
||||
|
||||
if (attribute_used_by_shader) {
|
||||
VkVertexInputBindingDescription vk_binding_descriptor = {};
|
||||
vk_binding_descriptor.binding = binding;
|
||||
vk_binding_descriptor.stride = stride;
|
||||
vk_binding_descriptor.inputRate = use_instancing ? VK_VERTEX_INPUT_RATE_INSTANCE :
|
||||
VK_VERTEX_INPUT_RATE_VERTEX;
|
||||
bindings.append(vk_binding_descriptor);
|
||||
if (vertex_buffer) {
|
||||
vbos.append(vertex_buffer);
|
||||
}
|
||||
if (immediate_vertex_buffer) {
|
||||
buffers.append(*immediate_vertex_buffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace blender::gpu
|
|
@ -0,0 +1,58 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
* Copyright 2023 Blender Foundation. All rights reserved. */
|
||||
|
||||
/** \file
|
||||
* \ingroup gpu
|
||||
*/
|
||||
|
||||
#include "vk_buffer.hh"
|
||||
#include "vk_common.hh"
|
||||
|
||||
#include "BLI_vector.hh"
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace blender::gpu {
|
||||
|
||||
class VKVertexBuffer;
|
||||
class VKContext;
|
||||
class VKBatch;
|
||||
class VKShaderInterface;
|
||||
class VKImmediate;
|
||||
|
||||
using AttributeMask = uint16_t;
|
||||
|
||||
struct VKVertexAttributeObject {
|
||||
bool is_valid = false;
|
||||
VkPipelineVertexInputStateCreateInfo info = {
|
||||
VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, NULL};
|
||||
|
||||
Vector<VkVertexInputBindingDescription> bindings;
|
||||
Vector<VkVertexInputAttributeDescription> attributes;
|
||||
/* Used for batches. */
|
||||
Vector<VKVertexBuffer *> vbos;
|
||||
/* Used for immediate mode. */
|
||||
Vector<VKBufferWithOffset> buffers;
|
||||
|
||||
VKVertexAttributeObject();
|
||||
void clear();
|
||||
|
||||
void bind(VKContext &context);
|
||||
|
||||
// Copy assignment operator.
|
||||
VKVertexAttributeObject &operator=(const VKVertexAttributeObject &other);
|
||||
|
||||
void update_bindings(const VKContext &context, VKBatch &batch);
|
||||
void update_bindings(VKImmediate &immediate);
|
||||
|
||||
private:
|
||||
void update_bindings(const GPUVertFormat &vertex_format,
|
||||
VKVertexBuffer *vertex_buffer,
|
||||
VKBufferWithOffset *immediate_vertex_buffer,
|
||||
const int64_t vertex_len,
|
||||
const VKShaderInterface &interface,
|
||||
AttributeMask &r_occupied_attributes,
|
||||
const bool use_instancing);
|
||||
};
|
||||
|
||||
} // namespace blender::gpu
|
|
@ -56,6 +56,7 @@ void VKVertexBuffer::acquire_data()
|
|||
}
|
||||
|
||||
/* Discard previous data if any. */
|
||||
/* TODO: Use mapped memory. */
|
||||
MEM_SAFE_FREE(data);
|
||||
data = (uchar *)MEM_mallocN(sizeof(uchar) * this->size_alloc_get(), __func__);
|
||||
}
|
||||
|
|
|
@ -28,6 +28,7 @@ class VKVertexBuffer : public VertBuf {
|
|||
|
||||
VkBuffer vk_handle() const
|
||||
{
|
||||
BLI_assert(buffer_.is_allocated());
|
||||
return buffer_.vk_handle();
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Add late binding of compute pipeline