WIP: Vulkan: Workbench #107886

Closed
Jeroen Bakker wants to merge 88 commits from Jeroen-Bakker:vulkan-draw-manager-workbench into main

When changing the target branch, be careful to rebase the branch in your fork to match. See documentation.
20 changed files with 132 additions and 37 deletions

View File

@ -710,7 +710,7 @@ static GHOST_TSuccess create_render_pass(VkDevice device,
colorAttachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
colorAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
colorAttachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
colorAttachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
colorAttachment.initialLayout = VK_IMAGE_LAYOUT_GENERAL;
colorAttachment.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
VkAttachmentReference colorAttachmentRef = {};

View File

@ -611,12 +611,6 @@ class USERPREF_PT_system_cycles_devices(SystemPanel, CenterAlignMixIn, Panel):
class USERPREF_PT_system_gpu_backend(SystemPanel, CenterAlignMixIn, Panel):
bl_label = "GPU Backend"
@classmethod
def poll(cls, _context):
# Only for Apple so far
import sys
return sys.platform == "darwin"
def draw_centered(self, context, layout):
import gpu
prefs = context.preferences

View File

@ -12,6 +12,8 @@
#include "IMB_imbuf_types.h"
#include "GPU_capabilities.h"
#include "BLI_math_matrix_types.hh"
#include "BLI_math_vector_types.hh"
@ -510,7 +512,9 @@ template<typename TextureMethod> class ScreenSpaceDrawingMode : public AbstractD
offset++;
}
}
IMB_gpu_clamp_half_float(&extracted_buffer);
if (!GPU_texture_clamp_to_half()) {
IMB_gpu_clamp_half_float(tile_buffer);
}
GPU_texture_update_sub(texture,
GPU_DATA_FLOAT,
@ -563,7 +567,9 @@ template<typename TextureMethod> class ScreenSpaceDrawingMode : public AbstractD
}
BKE_image_release_ibuf(image, tile_buffer, lock);
}
IMB_gpu_clamp_half_float(&texture_buffer);
if (!GPU_texture_clamp_to_half()) {
IMB_gpu_clamp_half_float(&texture_buffer);
}
GPU_texture_update(info.texture, GPU_DATA_FLOAT, texture_buffer.float_buffer.data);
imb_freerectImbuf_all(&texture_buffer);
}

View File

@ -56,6 +56,9 @@ bool GPU_shader_draw_parameters_support(void);
bool GPU_mem_stats_supported(void);
void GPU_mem_stats_get(int *totalmem, int *freemem);
/* Check if the active GPU backend automatically clamp values to fit in 16F. */
bool GPU_texture_clamp_to_half(void);
/**
* Return support for the active context + window.
*/

View File

@ -202,6 +202,11 @@ bool GPU_transform_feedback_support(void)
return GCaps.transform_feedback_support;
}
bool GPU_texture_clamp_to_half(void)
{
return GCaps.texture_clamp_to_half;
}
/** \} */
/* -------------------------------------------------------------------- */

View File

@ -57,6 +57,7 @@ struct GPUCapabilities {
bool use_hq_normals_workaround = false;
bool clear_viewport_workaround = false;
/* Vulkan related workarounds. */
bool texture_clamp_to_half = false;
/* Metal related workarounds. */
/* Minimum per-vertex stride in bytes (For a vertex buffer). */

View File

@ -199,6 +199,7 @@ void VKBackend::capabilities_init(VKDevice &device)
GCaps.compute_shader_support = true;
GCaps.shader_storage_buffer_objects_support = true;
GCaps.shader_image_load_store_support = true;
GCaps.texture_clamp_to_half = true;
GCaps.max_texture_size = max_ii(limits.maxImageDimension1D, limits.maxImageDimension2D);
GCaps.max_texture_3d_size = limits.maxImageDimension3D;

View File

@ -11,12 +11,12 @@
#include "vk_context.hh"
#include "vk_index_buffer.hh"
#include "vk_state_manager.hh"
#include "vk_storage_buffer.hh"
#include "vk_vertex_attribute_object.hh"
#include "vk_vertex_buffer.hh"
namespace blender::gpu {
void VKBatch::draw(int vertex_first, int vertex_count, int instance_first, int instance_count)
void VKBatch::draw_setup()
{
/* Currently the pipeline is rebuild on each draw command. Clearing the dirty flag for
* consistency with the internals of GPU module. */
@ -38,26 +38,53 @@ void VKBatch::draw(int vertex_first, int vertex_count, int instance_first, int i
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*/) {}
void VKBatch::multi_draw_indirect(GPUStorageBuf * /*indirect_buf*/,
int /*count*/,
intptr_t /*offset*/,
intptr_t /*stride*/)
void VKBatch::draw(int vertex_first, int vertex_count, int instance_first, int instance_count)
{
draw_setup();
VKContext &context = *VKContext::get();
VKCommandBuffer &command_buffer = context.command_buffer_get();
VKIndexBuffer *index_buffer = index_buffer_get();
const bool draw_indexed = index_buffer != nullptr;
if (draw_indexed) {
command_buffer.draw_indexed(index_buffer->index_len_get(),
instance_count,
index_buffer->index_start_get(),
vertex_first,
instance_first);
}
else {
command_buffer.draw(vertex_first, vertex_count, instance_first, instance_count);
}
command_buffer.submit();
}
void VKBatch::draw_indirect(GPUStorageBuf *indirect_buf, intptr_t offset)
{
multi_draw_indirect(indirect_buf, 1, offset, 0);
}
void VKBatch::multi_draw_indirect(GPUStorageBuf *indirect_buf,
int count,
intptr_t offset,
intptr_t stride)
{
draw_setup();
VKStorageBuffer &indirect_buffer = *unwrap(unwrap(indirect_buf));
VKContext &context = *VKContext::get();
const bool draw_indexed = index_buffer_get() != nullptr;
VKCommandBuffer &command_buffer = context.command_buffer_get();
if (draw_indexed) {
command_buffer.draw_indexed_indirect(indirect_buffer, offset, count, stride);
}
else {
command_buffer.draw_indirect(indirect_buffer, offset, count, stride);
}
command_buffer.submit();
}
VKVertexBuffer *VKBatch::vertex_buffer_get(int index)

View File

@ -26,6 +26,9 @@ class VKBatch : public Batch {
VKVertexBuffer *vertex_buffer_get(int index);
VKVertexBuffer *instance_buffer_get(int index);
VKIndexBuffer *index_buffer_get();
private:
void draw_setup();
};
} // namespace blender::gpu

View File

@ -131,7 +131,9 @@ void VKBuffer::unmap()
BLI_assert(is_mapped());
const VKDevice &device = VKBackend::get().device_get();
VmaAllocator allocator = device.mem_allocator_get();
vmaUnmapMemory(allocator, allocation_);
if (allocator != VK_NULL_HANDLE) {
vmaUnmapMemory(allocator, allocation_);
}
mapped_memory_ = nullptr;
}
@ -143,7 +145,9 @@ bool VKBuffer::free()
const VKDevice &device = VKBackend::get().device_get();
VmaAllocator allocator = device.mem_allocator_get();
vmaDestroyBuffer(allocator, vk_buffer_, allocation_);
if (allocator != VK_NULL_HANDLE) {
vmaDestroyBuffer(allocator, vk_buffer_, allocation_);
}
return true;
}

View File

@ -13,6 +13,7 @@
#include "vk_index_buffer.hh"
#include "vk_memory.hh"
#include "vk_pipeline.hh"
#include "vk_storage_buffer.hh"
#include "vk_texture.hh"
#include "vk_vertex_buffer.hh"
@ -258,7 +259,7 @@ void VKCommandBuffer::draw(int v_first, int v_count, int i_first, int i_count)
state.draw_counts++;
}
void VKCommandBuffer::draw(
void VKCommandBuffer::draw_indexed(
int index_count, int instance_count, int first_index, int vertex_offset, int first_instance)
{
validate_framebuffer_exists();
@ -268,6 +269,28 @@ void VKCommandBuffer::draw(
state.draw_counts++;
}
void VKCommandBuffer::draw_indirect(const VKStorageBuffer &buffer,
VkDeviceSize offset,
uint32_t draw_count,
uint32_t stride)
{
validate_framebuffer_exists();
ensure_active_framebuffer();
vkCmdDrawIndirect(vk_command_buffer_, buffer.vk_handle(), offset, draw_count, stride);
state.draw_counts++;
}
void VKCommandBuffer::draw_indexed_indirect(const VKStorageBuffer &buffer,
VkDeviceSize offset,
uint32_t draw_count,
uint32_t stride)
{
validate_framebuffer_exists();
ensure_active_framebuffer();
vkCmdDrawIndexedIndirect(vk_command_buffer_, buffer.vk_handle(), offset, draw_count, stride);
state.draw_counts++;
}
void VKCommandBuffer::pipeline_barrier(VkPipelineStageFlags source_stages,
VkPipelineStageFlags destination_stages)
{

View File

@ -23,6 +23,7 @@ class VKPipeline;
class VKPushConstants;
class VKTexture;
class VKVertexBuffer;
class VKStorageBuffer;
/** Command buffer to keep track of the life-time of a command buffer. */
class VKCommandBuffer : NonCopyable, NonMovable {
@ -188,8 +189,16 @@ class VKCommandBuffer : NonCopyable, NonMovable {
void fill(VKBuffer &buffer, uint32_t data);
void draw(int v_first, int v_count, int i_first, int i_count);
void draw(
void draw_indexed(
int index_count, int instance_count, int first_index, int vertex_offset, int first_instance);
void draw_indirect(const VKStorageBuffer &buffer,
VkDeviceSize offset,
uint32_t draw_count,
uint32_t stride);
void draw_indexed_indirect(const VKStorageBuffer &buffer,
VkDeviceSize offset,
uint32_t draw_count,
uint32_t stride);
/**
* Stop recording commands, encode + send the recordings to Vulkan, wait for the until the

View File

@ -58,9 +58,12 @@ VkImageAspectFlagBits to_vk_image_aspect_flag_bits(const eGPUTextureFormat forma
case GPU_DEPTH_COMPONENT32F:
case GPU_DEPTH_COMPONENT24:
case GPU_DEPTH_COMPONENT16:
return VK_IMAGE_ASPECT_DEPTH_BIT;
case GPU_DEPTH32F_STENCIL8:
case GPU_DEPTH24_STENCIL8:
return VK_IMAGE_ASPECT_DEPTH_BIT;
return static_cast<VkImageAspectFlagBits>(VK_IMAGE_ASPECT_DEPTH_BIT |
VK_IMAGE_ASPECT_STENCIL_BIT);
/* Texture only formats. */
case GPU_RGB32UI:

View File

@ -243,6 +243,7 @@ static ConversionType type_of_conversion_uint(eGPUTextureFormat device_format)
case GPU_RG32UI:
case GPU_R32UI:
case GPU_DEPTH_COMPONENT24:
case GPU_DEPTH24_STENCIL8:
return ConversionType::PASS_THROUGH;
case GPU_RGBA16UI:
@ -284,7 +285,6 @@ static ConversionType type_of_conversion_uint(eGPUTextureFormat device_format)
case GPU_RGB10_A2:
case GPU_RGB10_A2UI:
case GPU_R11F_G11F_B10F:
case GPU_DEPTH24_STENCIL8:
case GPU_SRGB8_A8:
case GPU_RGBA8_SNORM:
case GPU_RGBA16_SNORM:

View File

@ -169,6 +169,7 @@ class VKDescriptorSetTracker : protected VKResourceTracker<VKDescriptorSet> {
void bind(VKTexture &texture, VKDescriptorSet::Location location, VKSampler &sampler);
/* Bind as uniform texel buffer. */
void bind(VKVertexBuffer &vertex_buffer, VKDescriptorSet::Location location);
/**
* Some shaders don't need any descriptor sets so we don't need to bind them.
*

View File

@ -470,8 +470,11 @@ void VKFrameBuffer::render_pass_create()
render_pass_info.pSubpasses = &subpass;
const VKDevice &device = VKBackend::get().device_get();
vkCreateRenderPass(
VkResult result = vkCreateRenderPass(
device.device_get(), &render_pass_info, vk_allocation_callbacks, &vk_render_pass_);
if (result != VK_SUCCESS) {
BLI_assert_unreachable();
}
/* We might want to split frame-buffer and render pass. */
VkFramebufferCreateInfo framebuffer_create_info = {};
@ -483,8 +486,11 @@ void VKFrameBuffer::render_pass_create()
framebuffer_create_info.height = height_;
framebuffer_create_info.layers = 1;
vkCreateFramebuffer(
result = vkCreateFramebuffer(
device.device_get(), &framebuffer_create_info, vk_allocation_callbacks, &vk_framebuffer_);
if (result != VK_SUCCESS) {
BLI_assert_unreachable();
}
}
void VKFrameBuffer::render_pass_free()

View File

@ -16,6 +16,7 @@ namespace blender::gpu {
class VKFrameBuffer;
class VKPipelineStateManager {
private:
GPUState current_;
GPUStateMutable current_mutable_;

View File

@ -32,6 +32,7 @@ void VKStorageBuffer::allocate()
void VKStorageBuffer::bind(int slot)
{
/* TODO: move Storage buffer bindings to state manager to reuse bindings.*/
VKContext &context = *VKContext::get();
if (!buffer_.is_allocated()) {
allocate();
@ -41,8 +42,9 @@ void VKStorageBuffer::bind(int slot)
const std::optional<VKDescriptorSet::Location> location =
shader_interface.descriptor_set_location(
shader::ShaderCreateInfo::Resource::BindType::STORAGE_BUFFER, slot);
BLI_assert_msg(location, "Locations to SSBOs should always exist.");
shader->pipeline_get().descriptor_set_get().bind(*this, *location);
if (location) {
shader->pipeline_get().descriptor_set_get().bind(*this, *location);
}
}
void VKStorageBuffer::unbind() {}

View File

@ -49,4 +49,9 @@ class VKStorageBuffer : public StorageBuf {
void allocate();
};
static inline VKStorageBuffer *unwrap(StorageBuf *storage_buffer)
{
return static_cast<VKStorageBuffer *>(storage_buffer);
}
} // namespace blender::gpu

View File

@ -13,6 +13,7 @@
#include "vk_buffer.hh"
namespace blender::gpu {
class VKTexture;
class VKVertexBuffer : public VertBuf {
VKBuffer buffer_;