Hello !
I don’t know if it’s coming from a problem with the vendor SDL3 bindings, if I’m doing something wrong or if I should ask the question directly in the SDL forums, but I’m getting errors when running a minimal program. I just followed step by step this tutorial and have almost exactly the same code, I’ve checked it over and over and don’t see any major difference : https://www.youtube.com/watch?v=tfc3vschDVw&t=1961s&pp=ygUJc2RsMyBvZGlu
I’ve tried to google the error that gets spammed in the console, without success, it seems to be at the sdl implementation level, but no one has reported it yet so I must be doing something wrong:
Validation Error: [ VUID-vkQueueSubmit-pSignalSemaphores-00067 ] | MessageID = 0x539277af
vkQueueSubmit(): pSubmits[0].pSignalSemaphores[0] (VkSemaphore 0x370000000037) is being signaled by VkQueue 0x1a84d4d31f0, but it may still be in use by VkSwapchainKHR 0x2f000000002f.
Here are the most recently acquired image indices: 0, 0, 1, 0, 0, [1], 0, 0.
(brackets mark the last use of VkSemaphore 0x370000000037 in a presentation operation)
Swapchain image 1 was presented but was not re-acquired, so VkSemaphore 0x370000000037 may still be in use and cannot be safely reused with image index 0.
Vulkan insight: One solution is to assign each image its own semaphore. This also handles the case where vkAcquireNextImageKHR returns the same index twice in a row. Here are some common methods to ensure that a semaphore passed to vkQueuePresentKHR is not in use and can be safely reused:
a) Use a separate semaphore per swapchain image. Index these semaphores using the index of the acquired image.
b) Consider the VK_EXT_swapchain_maintenance1 extension. It allows using a VkFence with the presentation operation.
The Vulkan spec states: Each binary semaphore element of the pSignalSemaphores member of any element of pSubmits must be unsignaled when the semaphore signal operation it defines is executed on the device (https://vulkan.lunarg.com/doc/view/1.4.313.2/windows/antora/spec/latest/chapters/cmdbuffers.html#VUID-vkQueueSubmit-pSignalSemaphores-00067)
Objects: 2
[0] VkSemaphore 0x370000000037
[1] VkQueue 0x1a84d4d31f0
Here are a few things I’ve noticed:
- it seems to appear after a few frames, I suppose something is not cleaned up properly at the end of a frame
- If I reduce the framerate with SDL_Delay, the problem seems to disappear, until I resize the window, at which point it fires once
- Despite the errors, the program works as expected
And here is the full code :
package main
import sdl "vendor:sdl3"
import "core:log"
import "base:runtime"
main_context: runtime.Context
v_shader_src := #load("../../shaders/test_shader.spv.vert")
f_shader_src := #load("../../shaders/test_shader.spv.frag")
main :: proc() {
context.logger = log.create_console_logger()
main_context = context
//sdl.SetLogPriorities(.VERBOSE)
sdl.SetLogOutputFunction(sdl_log, nil)
sdl_init_ok := sdl.Init(sdl.INIT_VIDEO)
assert(sdl_init_ok)
window := sdl.CreateWindow("Ether", 800, 600, sdl.WINDOW_RESIZABLE); assert(window != nil)
gpu := sdl.CreateGPUDevice({.SPIRV}, true, nil); assert(gpu != nil)
gpu_bound := sdl.ClaimWindowForGPUDevice(gpu, window); assert(gpu_bound)
swapchain_params_ok := sdl.SetGPUSwapchainParameters(gpu, window, .SDR_LINEAR, .VSYNC); assert(swapchain_params_ok)
v_shader := sdl.CreateGPUShader(gpu, {
code_size = len(v_shader_src),
code = raw_data(v_shader_src),
entrypoint = "main",
format = {.SPIRV},
stage = .VERTEX,
});
f_shader := sdl.CreateGPUShader(gpu, {
code_size = len(f_shader_src),
code = raw_data(f_shader_src),
entrypoint = "main",
format = {.SPIRV},
stage = .FRAGMENT,
});
pipeline := sdl.CreateGPUGraphicsPipeline(gpu, {
vertex_shader = v_shader,
fragment_shader = f_shader,
primitive_type = .TRIANGLELIST,
target_info = sdl.GPUGraphicsPipelineTargetInfo {
num_color_targets = 1,
color_target_descriptions = &(sdl.GPUColorTargetDescription {
format = sdl.GetGPUSwapchainTextureFormat(gpu, window),
})
},
})
ok: bool
sdl.ReleaseGPUShader(gpu, f_shader)
sdl.ReleaseGPUShader(gpu, v_shader)
last_time: u64 = sdl.GetTicks()
current_time: u64 = sdl.GetTicks()
main_loop: for {
event: sdl.Event
for sdl.PollEvent(&event) {
#partial switch event.type {
case .QUIT:
break main_loop
case .KEY_DOWN:
if event.key.scancode == .ESCAPE do break main_loop
}
}
current_time = sdl.GetTicks()
{
command_buffer := sdl.AcquireGPUCommandBuffer(gpu)
gpu_tex: ^sdl.GPUTexture = nil
ok = sdl.WaitAndAcquireGPUSwapchainTexture(command_buffer, window, &gpu_tex, nil, nil); assert(ok)
if gpu_tex != nil {
color_target := sdl.GPUColorTargetInfo {
texture = gpu_tex,
load_op = .CLEAR,
clear_color = {0, 0.2, 0.4, 1},
store_op = .STORE,
}
render_pass := sdl.BeginGPURenderPass(command_buffer, &color_target, 1, nil)
sdl.BindGPUGraphicsPipeline(render_pass, pipeline)
sdl.DrawGPUPrimitives(render_pass, 3, 1, 0, 0)
sdl.EndGPURenderPass(render_pass)
}
else do log.info("NOT RENDERING")
ok = sdl.SubmitGPUCommandBuffer(command_buffer); assert(ok)
}
}
}
sdl_log :: proc "c" (userdata: rawptr, category: sdl.LogCategory, priority: sdl.LogPriority, message: cstring) {
context = main_context
}
Any idea why it happens? Thanks in advance for your help!