Goal is to reduce the number of command buffer flushes by tracking what is happening in the different command queues. This is an initial step towards advanced queue-ing strategies. The new (intermediate) strategy records commands to different command buffers based on what they do. There is a command buffer for data transfers, compute pipelines and graphics pipelines. When a compute command is recorded it ensures that all graphic commands are finished. When a graphic command is recorded it ensures all compute commands are finished. When a graphic or compute command is scheduled all recorded data transfer commands are scheduled as well. Some improvements are expected as multiple compute and data transfers commands can now be scheduled at the same time and don't need to unbind and rebind render passes. Especially when using EEVEE-Next which is compute centric the performance change is visible for the user. Pull Request: https://projects.blender.org/blender/blender/pulls/114104
94 lines
2.8 KiB
C++
94 lines
2.8 KiB
C++
/* SPDX-FileCopyrightText: 2023 Blender Authors
|
|
*
|
|
* SPDX-License-Identifier: GPL-2.0-or-later */
|
|
|
|
/** \file
|
|
* \ingroup gpu
|
|
*
|
|
* Mimics old style OpenGL immediate mode drawing.
|
|
*/
|
|
|
|
#include "vk_immediate.hh"
|
|
#include "vk_data_conversion.hh"
|
|
#include "vk_state_manager.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_idx == 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_idx);
|
|
}
|
|
|
|
VKContext &context = *VKContext::get();
|
|
BLI_assert(context.shader == unwrap(shader));
|
|
VKStateManager &state_manager = context.state_manager_get();
|
|
state_manager.apply_state();
|
|
state_manager.apply_bindings();
|
|
vertex_attributes_.update_bindings(*this);
|
|
context.bind_graphics_pipeline(prim_type, vertex_attributes_);
|
|
vertex_attributes_.bind(context);
|
|
|
|
context.command_buffers_get().draw(0, vertex_idx, 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
|