2023-08-16 00:20:26 +10:00
|
|
|
/* SPDX-FileCopyrightText: 2023 Blender Authors
|
2023-05-31 16:19:06 +02:00
|
|
|
*
|
|
|
|
|
* SPDX-License-Identifier: GPL-2.0-or-later */
|
2023-02-21 15:03:12 +01:00
|
|
|
|
|
|
|
|
/** \file
|
|
|
|
|
* \ingroup gpu
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#pragma once
|
|
|
|
|
|
|
|
|
|
#include "vk_common.hh"
|
2023-03-24 07:47:50 +01:00
|
|
|
#include "vk_resource_tracker.hh"
|
2023-03-06 12:28:55 +01:00
|
|
|
|
|
|
|
|
#include "BLI_utility_mixins.hh"
|
2023-02-21 15:03:12 +01:00
|
|
|
|
|
|
|
|
namespace blender::gpu {
|
2023-08-29 15:05:08 +02:00
|
|
|
class VKDevice;
|
2023-02-21 15:03:12 +01:00
|
|
|
|
2023-02-27 21:44:59 +11:00
|
|
|
/** Command buffer to keep track of the life-time of a command buffer. */
|
2023-02-21 15:03:12 +01:00
|
|
|
class VKCommandBuffer : NonCopyable, NonMovable {
|
2023-11-16 15:03:47 +01:00
|
|
|
/**
|
|
|
|
|
* Not owning handle to the command pool that created this command buffer. The command pool is
|
|
|
|
|
* owned by #VKCommandBuffers.
|
|
|
|
|
*/
|
|
|
|
|
VkCommandPool vk_command_pool_ = VK_NULL_HANDLE;
|
2023-02-21 15:03:12 +01:00
|
|
|
VkCommandBuffer vk_command_buffer_ = VK_NULL_HANDLE;
|
|
|
|
|
|
2023-04-25 15:32:41 +02:00
|
|
|
private:
|
|
|
|
|
enum class Stage {
|
|
|
|
|
Initial,
|
|
|
|
|
Recording,
|
|
|
|
|
BetweenRecordingAndSubmitting,
|
|
|
|
|
Submitted,
|
|
|
|
|
Executed,
|
|
|
|
|
};
|
|
|
|
|
/*
|
|
|
|
|
* Some vulkan command require an active frame buffer. Others require no active frame-buffer. As
|
|
|
|
|
* our current API does not provide a solution for this we need to keep track of the actual state
|
|
|
|
|
* and do the changes when recording the next command.
|
|
|
|
|
*
|
|
|
|
|
* This is a temporary solution to get things rolling.
|
|
|
|
|
* TODO: In a future solution we should decide the scope of a command buffer.
|
|
|
|
|
*
|
|
|
|
|
* - command buffer per draw command.
|
|
|
|
|
* - minimize command buffers and track render passes.
|
|
|
|
|
* - add custom encoder to also track resource usages.
|
|
|
|
|
*
|
2023-04-26 12:01:23 +10:00
|
|
|
* Currently I expect the custom encoder has to be done eventually. But want to keep postponing
|
2023-04-25 15:32:41 +02:00
|
|
|
* the custom encoder for now to collect more use cases it should solve. (first pixel drawn on
|
|
|
|
|
* screen).
|
|
|
|
|
*
|
|
|
|
|
* Some command can also be encoded in another way when encoded as a first command. For example
|
2023-04-26 12:01:23 +10:00
|
|
|
* clearing a frame-buffer textures isn't allowed inside a render pass, but clearing the
|
|
|
|
|
* frame-buffer textures via ops is allowed. When clearing a frame-buffer texture directly after
|
2023-04-25 15:32:41 +02:00
|
|
|
* beginning a render pass could be re-encoded to do this in the same command.
|
|
|
|
|
*
|
|
|
|
|
* So for now we track the state and temporary switch to another state if the command requires
|
|
|
|
|
* it.
|
|
|
|
|
*/
|
|
|
|
|
struct {
|
|
|
|
|
/**
|
|
|
|
|
* Current stage of the command buffer to keep track of inconsistencies & incorrect usage.
|
|
|
|
|
*/
|
|
|
|
|
Stage stage = Stage::Initial;
|
|
|
|
|
|
2023-10-30 14:21:14 +01:00
|
|
|
/**
|
|
|
|
|
* The number of command added to the command buffer since last submission.
|
|
|
|
|
*/
|
|
|
|
|
uint64_t recorded_command_counts = 0;
|
2023-04-25 15:32:41 +02:00
|
|
|
} state;
|
2023-10-30 14:21:14 +01:00
|
|
|
|
2023-04-25 15:32:41 +02:00
|
|
|
bool is_in_stage(Stage stage)
|
|
|
|
|
{
|
|
|
|
|
return state.stage == stage;
|
|
|
|
|
}
|
|
|
|
|
void stage_set(Stage stage)
|
|
|
|
|
{
|
|
|
|
|
state.stage = stage;
|
|
|
|
|
}
|
|
|
|
|
std::string to_string(Stage stage)
|
|
|
|
|
{
|
|
|
|
|
switch (stage) {
|
|
|
|
|
case Stage::Initial:
|
|
|
|
|
return "INITIAL";
|
|
|
|
|
case Stage::Recording:
|
|
|
|
|
return "RECORDING";
|
|
|
|
|
case Stage::BetweenRecordingAndSubmitting:
|
|
|
|
|
return "BEFORE_SUBMIT";
|
|
|
|
|
case Stage::Submitted:
|
|
|
|
|
return "SUBMITTED";
|
|
|
|
|
case Stage::Executed:
|
|
|
|
|
return "EXECUTED";
|
|
|
|
|
}
|
|
|
|
|
return "UNKNOWN";
|
|
|
|
|
}
|
|
|
|
|
void stage_transfer(Stage stage_from, Stage stage_to)
|
|
|
|
|
{
|
|
|
|
|
BLI_assert(is_in_stage(stage_from));
|
2023-05-02 15:52:53 +02:00
|
|
|
UNUSED_VARS_NDEBUG(stage_from);
|
2023-04-25 15:32:41 +02:00
|
|
|
#if 0
|
|
|
|
|
printf(" *** Transfer stage from %s to %s\n",
|
|
|
|
|
to_string(stage_from).c_str(),
|
|
|
|
|
to_string(stage_to).c_str());
|
|
|
|
|
#endif
|
|
|
|
|
stage_set(stage_to);
|
|
|
|
|
}
|
|
|
|
|
|
2023-02-21 15:03:12 +01:00
|
|
|
public:
|
|
|
|
|
virtual ~VKCommandBuffer();
|
2023-08-29 15:05:08 +02:00
|
|
|
bool is_initialized() const;
|
2023-11-16 15:03:47 +01:00
|
|
|
void init(VkCommandPool vk_command_pool, VkCommandBuffer vk_command_buffer);
|
2023-02-21 15:03:12 +01:00
|
|
|
void begin_recording();
|
|
|
|
|
void end_recording();
|
2023-11-16 15:03:47 +01:00
|
|
|
void free();
|
2023-04-26 08:09:28 +02:00
|
|
|
|
2023-02-21 15:03:12 +01:00
|
|
|
/**
|
2023-10-30 14:21:14 +01:00
|
|
|
* Receive the vulkan handle of the command buffer.
|
2023-02-21 15:03:12 +01:00
|
|
|
*/
|
2023-10-30 14:21:14 +01:00
|
|
|
VkCommandBuffer vk_command_buffer() const
|
2023-03-24 07:47:50 +01:00
|
|
|
{
|
2023-10-30 14:21:14 +01:00
|
|
|
return vk_command_buffer_;
|
2023-03-24 07:47:50 +01:00
|
|
|
}
|
|
|
|
|
|
2023-10-30 14:21:14 +01:00
|
|
|
bool has_recorded_commands() const
|
|
|
|
|
{
|
|
|
|
|
return state.recorded_command_counts != 0;
|
|
|
|
|
}
|
2023-04-25 15:32:41 +02:00
|
|
|
|
2023-10-30 14:21:14 +01:00
|
|
|
void command_recorded()
|
|
|
|
|
{
|
|
|
|
|
state.recorded_command_counts++;
|
|
|
|
|
}
|
2023-04-25 15:32:41 +02:00
|
|
|
|
2023-10-30 14:21:14 +01:00
|
|
|
void commands_submitted();
|
2023-02-21 15:03:12 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
} // namespace blender::gpu
|