Skip to content

Commit c4096f2

Browse files
committed
Add command buffer recorder
1 parent b1a1a31 commit c4096f2

16 files changed

+661
-381
lines changed

generator/vk_codegen/source_CMakeLists.txt

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -57,11 +57,6 @@ target_include_directories(
5757

5858
lgl_set_build_options(${VK_LAYER})
5959

60-
target_compile_definitions(
61-
${VK_LAYER} PRIVATE
62-
$<$<PLATFORM_ID:Android>:VK_USE_PLATFORM_ANDROID_KHR=1>
63-
$<$<PLATFORM_ID:Android>:LGL_LOG_TAG="${LGL_LOG_TAG}">)
64-
6560
target_link_libraries(
6661
${VK_LAYER}
6762
lib_layer_framework

layer_gpu_timeline/docs/command_buffer_model.md

Lines changed: 58 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ performed.
2525

2626
* Set the current workload to a new render pass with the passed metadata.
2727

28-
**RENDERPASS_CONTINUE(const json\*):**
28+
**RENDERPASS_RESUME(const json\*):**
2929

3030
* Update the current workload, which must be a render pass, with extra
3131
draw count metadata.
@@ -72,13 +72,70 @@ real applications.
7272
The command stream for a secondary command buffer is inlined into the primary
7373
command buffer during recording.
7474

75+
### Recording sequence
76+
77+
When application records a new workload:
78+
79+
* A `tagID` is assigned and recorded using `vkCmdMarkerBegin()` label in the
80+
Vulkan command stream _before_ the new workload is written to the command
81+
stream.
82+
* If workload is using indirect parameters, then a transfer job to copy
83+
indirect parameters into a layer-owned buffer is emitted _before_ the new
84+
workload. No additional barrier is needed because application barriers must
85+
have already ensured that the indirect parameter buffer is valid.
86+
* A proxy workload object is created in the layer storing the assigned
87+
`tagID` and all settings that are known at command recording time.
88+
* A layer command stream command is recorded into the submit time stream
89+
indicating `<TYPE>_BEGIN` with a pointer to the proxy workload. Note that
90+
this JSON may be modified later for some workloads.
91+
* If workload is using indirect parameters, a layer command stream command is
92+
recorded into the resolve time stream, which will handle cleanup and
93+
emitting the `submitID.tagID` annex message for the indirect data.
94+
* If the command buffer is not ONE_TIME_SUBMIT, if any workload is using
95+
indirect parameters, or contains incomplete render passes, the command
96+
buffer is marked as needing a `submitID` wrapper.
97+
* The user command is written to the Vulkan command stream.
98+
99+
When application resumes a render pass workload:
100+
101+
* A `tagID` of zero is assigned, but not emitted to the command stream.
102+
* A layer command stream command is recorded into the submit time stream
103+
indicating `<TYPE>_RESUME` with a pointer to the proxy workload. Note that
104+
this JSON may be modified later for some workloads.
105+
* The user command is written to the Vulkan command stream.
106+
107+
When application ends a workload:
108+
109+
* For render pass workloads, any statistics accumulated since the last begin
110+
are rolled up into the proxy workload object.
111+
* For render pass workloads, the user command is written to the Vulkan
112+
command stream.
113+
* The command steam label scope is closed using `vkCmdMarkerEnd()`.
114+
75115
## Layer command playback
76116

77117
The persistent state for command playback belongs to the queues the command
78118
buffers are submitted to. The command stream bytecode is run by a bytecode
79119
interpreter associated with the state of the current queue, giving the
80120
interpreter access to the current `submitID` and queue debug label stack.
81121

122+
### Submitting sequence
123+
124+
For each command buffer in the user submit:
125+
126+
* If the command buffer needs a `submitID` we allocate a unique `submitID` and
127+
create two new command buffers that will wrap the user command buffer with an
128+
additional stack layer of debug label containing the `s<ID>` string. We will
129+
inject a layer command stream async command to handle freeing the command
130+
buffers.
131+
* The tool will process the submit-time layer commands, executing each command
132+
to either update some state or emit
133+
* If there are any async layer commands, either recorded in the command buffer
134+
or from the wrapping command buffers, we will need to add an async handler.
135+
This cannot safely use the user fence or depend on any user object lifetime,
136+
so we will add a layer-owned timeline semaphore to the submit which we can
137+
wait on to determine when it is safe trigger the async work.
138+
82139
## Future: Async commands
83140

84141
One of our longer-term goals is to be able to capture indirect parameters,

layer_gpu_timeline/source/layer_device_functions.hpp

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,16 @@
2727

2828
#include "framework/utils.hpp"
2929

30+
// Functions for device setup
31+
32+
/* See Vulkan API for documentation. */
33+
template <>
34+
VKAPI_ATTR void VKAPI_CALL layer_vkGetDeviceQueue<user_tag>(
35+
VkDevice device,
36+
uint32_t queueFamilyIndex,
37+
uint32_t queueIndex,
38+
VkQueue* pQueue);
39+
3040
// Functions for command pools
3141

3242
/* See Vulkan API for documentation. */
@@ -153,6 +163,21 @@ VKAPI_ATTR void VKAPI_CALL layer_vkCmdBeginRenderingKHR<user_tag>(
153163
VkCommandBuffer commandBuffer,
154164
const VkRenderingInfo* pRenderingInfo);
155165

166+
/* See Vulkan API for documentation. */
167+
template <>
168+
VKAPI_ATTR void VKAPI_CALL layer_vkCmdEndRenderPass<user_tag>(
169+
VkCommandBuffer commandBuffer);
170+
171+
/* See Vulkan API for documentation. */
172+
template <>
173+
VKAPI_ATTR void VKAPI_CALL layer_vkCmdEndRendering<user_tag>(
174+
VkCommandBuffer commandBuffer);
175+
176+
/* See Vulkan API for documentation. */
177+
template <>
178+
VKAPI_ATTR void VKAPI_CALL layer_vkCmdEndRenderingKHR<user_tag>(
179+
VkCommandBuffer commandBuffer);
180+
156181
// Functions for draw calls
157182

158183
/* See Vulkan API for documentation. */

layer_gpu_timeline/source/layer_device_functions_debug.cpp

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -44,9 +44,15 @@ VKAPI_ATTR void VKAPI_CALL layer_vkCmdDebugMarkerBeginEXT<user_tag>(
4444
std::unique_lock<std::mutex> lock { g_vulkanLock };
4545
auto* layer = Device::retrieve(commandBuffer);
4646

47-
// Release the lock to call into the driver
48-
lock.unlock();
49-
layer->driver.vkCmdDebugMarkerBeginEXT(commandBuffer, pMarkerInfo);
47+
auto& tracker = layer->getStateTracker();
48+
auto& cb = tracker.getCommandBuffer(commandBuffer);
49+
50+
// Increment the render pass counter in the tracker
51+
cb.debugMarkerBegin(pMarkerInfo->pMarkerName);
52+
53+
// Note that we do not call the driver for user labels - they are
54+
// emitted via the comms side-channel for each workload to avoid
55+
// polluting the driver tag labelling
5056
}
5157

5258
/* See Vulkan API for documentation. */
@@ -60,7 +66,13 @@ VKAPI_ATTR void VKAPI_CALL layer_vkCmdDebugMarkerEndEXT<user_tag>(
6066
std::unique_lock<std::mutex> lock { g_vulkanLock };
6167
auto* layer = Device::retrieve(commandBuffer);
6268

63-
// Release the lock to call into the driver
64-
lock.unlock();
65-
layer->driver.vkCmdDebugMarkerEndEXT(commandBuffer);
69+
auto& tracker = layer->getStateTracker();
70+
auto& cb = tracker.getCommandBuffer(commandBuffer);
71+
72+
// Increment the render pass counter in the tracker
73+
cb.debugMarkerEnd();
74+
75+
// Note that we do not call the driver for user labels - they are
76+
// emitted via the comms side-channel for each workload to avoid
77+
// polluting the driver tag labelling
6678
}

layer_gpu_timeline/source/layer_device_functions_queue.cpp

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,30 @@
3232

3333
extern std::mutex g_vulkanLock;
3434

35+
/* See Vulkan API for documentation. */
36+
template <>
37+
VKAPI_ATTR void VKAPI_CALL layer_vkGetDeviceQueue<user_tag>(
38+
VkDevice device,
39+
uint32_t queueFamilyIndex,
40+
uint32_t queueIndex,
41+
VkQueue* pQueue
42+
) {
43+
LAYER_TRACE(__func__);
44+
45+
// Hold the lock to access layer-wide global store
46+
std::unique_lock<std::mutex> lock { g_vulkanLock };
47+
auto* layer = Device::retrieve(device);
48+
49+
// Release the lock to call into the driver
50+
lock.unlock();
51+
layer->driver.vkGetDeviceQueue(device, queueFamilyIndex, queueIndex, pQueue);
52+
53+
// Retake the lock to access layer-wide global store
54+
lock.lock();
55+
auto& tracker = layer->getStateTracker();
56+
tracker.createQueue(*pQueue);
57+
}
58+
3559
/* See Vulkan API for documentation. */
3660
template<>
3761
VKAPI_ATTR VkResult VKAPI_CALL layer_vkQueuePresentKHR<user_tag>(

0 commit comments

Comments
 (0)