WIP: Vulkan: Workbench #107886
|
@ -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 = {};
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
*/
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
|
|
|
@ -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). */
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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.
|
||||
*
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -16,6 +16,7 @@ namespace blender::gpu {
|
|||
class VKFrameBuffer;
|
||||
|
||||
class VKPipelineStateManager {
|
||||
|
||||
private:
|
||||
GPUState current_;
|
||||
GPUStateMutable current_mutable_;
|
||||
|
|
|
@ -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() {}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include "vk_buffer.hh"
|
||||
|
||||
namespace blender::gpu {
|
||||
class VKTexture;
|
||||
|
||||
class VKVertexBuffer : public VertBuf {
|
||||
VKBuffer buffer_;
|
||||
|
|
Loading…
Reference in New Issue