29 | 29 |
queue: vk.Queue,
|
30 | 30 |
family_index: u32,
|
31 | 31 |
command_pool: vk.CommandPool,
|
32 | |
swapchain: ?Swapchain,
|
|
32 |
swapchain: Swapchain,
|
|
33 |
|
|
34 |
dg_device: dg.IRenderDeviceVk_Wrapper,
|
|
35 |
dg_ctx: dg.IDeviceContext_Wrapper,
|
33 | 36 |
|
34 | 37 |
allocator: *Allocator,
|
35 | 38 |
|
|
38 | 41 |
xri: xr.InstanceDispatch,
|
39 | 42 |
instance: xr.Instance,
|
40 | 43 |
system: xr.SystemId,
|
41 | |
) !*Graphics {
|
42 | |
var self = try allocator.create(Graphics);
|
43 | |
errdefer allocator.destroy(self);
|
|
44 |
) !Graphics {
|
|
45 |
var self: Graphics = undefined;
|
44 | 46 |
|
45 | 47 |
self.xri = xri;
|
46 | 48 |
self.allocator = allocator;
|
|
63 | 65 |
const zero = [_:0]u8{};
|
64 | 66 |
const instance_extensions = [_][*:0]const u8{
|
65 | 67 |
"VK_EXT_debug_utils",
|
|
68 |
"VK_KHR_get_physical_device_properties2",
|
|
69 |
"VK_KHR_surface",
|
66 | 70 |
};
|
67 | 71 |
|
68 | 72 |
const instance_create_info = vk.InstanceCreateInfo{
|
|
132 | 136 |
};
|
133 | 137 |
|
134 | 138 |
// CREATE DEVICE
|
|
139 |
const device_extensions = [_][*:0]const u8{
|
|
140 |
"VK_KHR_spirv_1_4",
|
|
141 |
|
|
142 |
"VK_KHR_swapchain",
|
|
143 |
"VK_KHR_maintenance1",
|
|
144 |
|
|
145 |
"VK_KHR_8bit_storage",
|
|
146 |
"VK_KHR_16bit_storage",
|
|
147 |
"VK_KHR_storage_buffer_storage_class",
|
|
148 |
};
|
135 | 149 |
|
136 | 150 |
const device_create_info = vk.DeviceCreateInfo{
|
137 | 151 |
.flags = .{},
|
|
139 | 153 |
.p_queue_create_infos = &queue_create_info,
|
140 | 154 |
.enabled_layer_count = 0,
|
141 | 155 |
.pp_enabled_layer_names = undefined,
|
142 | |
.enabled_extension_count = 0,
|
143 | |
.pp_enabled_extension_names = undefined,
|
|
156 |
.enabled_extension_count = device_extensions.len,
|
|
157 |
.pp_enabled_extension_names = device_extensions[0..],
|
144 | 158 |
.p_enabled_features = null,
|
145 | 159 |
};
|
146 | 160 |
|
|
173 | 187 |
}, null);
|
174 | 188 |
errdefer self.vkd.destroyCommandPool(self.device, self.command_pool, null);
|
175 | 189 |
|
176 | |
self.swapchain = null;
|
177 | |
|
178 | 190 |
return self;
|
179 | 191 |
}
|
180 | 192 |
|
181 | |
pub fn init_swapchain(
|
182 | |
self: *Graphics,
|
183 | |
session: xr.Session,
|
184 | |
config: []xr.ViewConfigurationView,
|
185 | |
) !void {
|
|
193 |
pub fn createSwapchain(self: *Graphics, session: xr.Session, configs: []const xr.ViewConfigurationView) !void {
|
186 | 194 |
const factory = dg.IEngineFactoryVk_Wrapper.wrap(dg.Diligent_GetEngineFactoryVk());
|
187 | |
std.debug.print("factory: {}\n", .{factory});
|
188 | 195 |
|
189 | 196 |
const create_info = dg.EngineVkCreateInfo{
|
190 | 197 |
._EngineCreateInfo = .{
|
|
195 | 202 |
.DebugMessageCallback = null,
|
196 | 203 |
},
|
197 | 204 |
.NumCommandsToFlushCmdBuffer = 2048,
|
198 | |
// 8192, 1024, 8192, 8192, 1024, 4096, 4096, 1024, 1024, 256, 256
|
199 | |
.MainDescriptorPoolSize = mem.zeroes(dg.VulkanDescriptorPoolSize),
|
200 | |
// 2048, 256, 2048, 2048, 256, 1024, 1024, 256, 256, 64, 64
|
201 | |
.DynamicDescriptorPoolSize = mem.zeroes(dg.VulkanDescriptorPoolSize),
|
|
205 |
.MainDescriptorPoolSize = .{
|
|
206 |
.MaxDescriptorSets = 8192,
|
|
207 |
.NumSeparateSamplerDescriptors = 1024,
|
|
208 |
.NumCombinedSamplerDescriptors = 8192,
|
|
209 |
.NumSampledImageDescriptors = 8192,
|
|
210 |
.NumStorageImageDescriptors = 1024,
|
|
211 |
.NumUniformBufferDescriptors = 4096,
|
|
212 |
.NumStorageBufferDescriptors = 4096,
|
|
213 |
.NumUniformTexelBufferDescriptors = 1024,
|
|
214 |
.NumStorageTexelBufferDescriptors = 1024,
|
|
215 |
.NumInputAttachmentDescriptors = 256,
|
|
216 |
.NumAccelStructDescriptors = 256,
|
|
217 |
},
|
|
218 |
.DynamicDescriptorPoolSize = .{
|
|
219 |
.MaxDescriptorSets = 2048,
|
|
220 |
.NumSeparateSamplerDescriptors = 256,
|
|
221 |
.NumCombinedSamplerDescriptors = 2048,
|
|
222 |
.NumSampledImageDescriptors = 2048,
|
|
223 |
.NumStorageImageDescriptors = 256,
|
|
224 |
.NumUniformBufferDescriptors = 1024,
|
|
225 |
.NumStorageBufferDescriptors = 1024,
|
|
226 |
.NumUniformTexelBufferDescriptors = 256,
|
|
227 |
.NumStorageTexelBufferDescriptors = 256,
|
|
228 |
.NumInputAttachmentDescriptors = 64,
|
|
229 |
.NumAccelStructDescriptors = 64,
|
|
230 |
},
|
202 | 231 |
.DeviceLocalMemoryPageSize = 16 << 20,
|
203 | 232 |
.HostVisibleMemoryPageSize = 16 << 20,
|
204 | 233 |
.DeviceLocalMemoryReserveSize = 256 << 20,
|
|
216 | 245 |
};
|
217 | 246 |
var device: ?*dg.IRenderDevice = null;
|
218 | 247 |
var context: ?*dg.IDeviceContext = null;
|
219 | |
try factory.AttachToVulkanDevice(
|
|
248 |
factory.AttachToVulkanDevice(
|
220 | 249 |
&@intToPtr(*dg.VkInstance_T, @enumToInt(self.instance)),
|
221 | 250 |
&@intToPtr(*dg.VkPhysicalDevice_T, @enumToInt(self.physical_device)),
|
222 | 251 |
&@intToPtr(*dg.VkDevice_T, @enumToInt(self.device)),
|
|
227 | 256 |
&context,
|
228 | 257 |
);
|
229 | 258 |
|
230 | |
const swapchain = try Swapchain.init(self, session, config[0]);
|
231 | |
errdefer swapchain.deinit();
|
232 | |
self.swapchain = swapchain;
|
233 | |
|
234 | |
var dg_swapchain: ?*dg.ISwapChain = undefined;
|
235 | |
const swap_desc = dg.SwapChainDesc{
|
236 | |
.Width = @intCast(u32, swapchain.image_rect.extent.width),
|
237 | |
.Height = @intCast(u32, swapchain.image_rect.extent.height),
|
238 | |
.ColorBufferFormat = dg.TEX_FORMAT_RGBA8_UNORM,
|
239 | |
.DepthBufferFormat = dg.TEX_FORMAT_D32_FLOAT,
|
240 | |
.Usage = dg.SWAP_CHAIN_USAGE_RENDER_TARGET,
|
241 | |
.PreTransform = dg.SURFACE_TRANSFORM_OPTIMAL,
|
242 | |
.BufferCount = @intCast(u32, swapchain.images.len),
|
243 | |
.DefaultDepthValue = 1,
|
244 | |
.DefaultStencilValue = 0,
|
245 | |
.IsPrimary = true,
|
246 | |
};
|
247 | |
const callbacks = dg.SwapChainImageCallbacks{
|
248 | |
.Cookie = self,
|
249 | |
.ImageCallbackAcquire = @This().acquire,
|
250 | |
.ImageCallbackRelease = @This().release,
|
251 | |
};
|
252 | |
try factory.CreateSwapChainVk(
|
253 | |
device,
|
254 | |
context,
|
255 | |
&swap_desc,
|
256 | |
@intCast(u32, swapchain.images.len),
|
257 | |
@ptrCast(**dg.VkImage_T, swapchain.images.ptr),
|
258 | |
&callbacks,
|
259 | |
&dg_swapchain,
|
260 | |
);
|
|
259 |
self.dg_device = dg.IRenderDeviceVk_Wrapper.wrap(@ptrCast(?*dg.IRenderDeviceVk, device));
|
|
260 |
self.dg_ctx = dg.IDeviceContext_Wrapper.wrap(context);
|
|
261 |
|
|
262 |
try Swapchain.init(&self.swapchain, self, factory, session, configs);
|
261 | 263 |
}
|
262 | 264 |
|
263 | 265 |
pub fn deinit(self: *const Graphics) void {
|
264 | |
if (self.swapchain) |swapchain| {
|
265 | |
swapchain.deinit();
|
266 | |
}
|
|
266 |
self.swapchain.deinit();
|
267 | 267 |
|
268 | 268 |
self.vkd.destroyCommandPool(self.device, self.command_pool, null);
|
269 | 269 |
self.vkd.destroyDevice(self.device, null);
|
|
272 | 272 |
self.allocator.destroy(self);
|
273 | 273 |
}
|
274 | 274 |
|
275 | |
fn acquire(c_self: ?*c_void, index: [*c]u32) callconv(.C) dg.VkResult {
|
276 | |
const self = @ptrCast(*Graphics, @alignCast(@alignOf(Graphics), c_self));
|
277 | |
|
278 | |
if (self.swapchain) |swapchain| {
|
279 | |
index.* = self.xri.acquireSwapchainImage(
|
280 | |
swapchain.handle,
|
281 | |
&xr.SwapchainImageAcquireInfo.empty(),
|
282 | |
) catch @panic("error acquiring image");
|
283 | |
_ = self.xri.waitSwapchainImage(swapchain.handle, .{ .timeout = -1 }) catch {};
|
284 | |
return .VK_SUCCESS;
|
285 | |
}
|
286 | |
|
287 | |
return .VK_ERROR_UNKNOWN;
|
288 | |
}
|
289 | |
|
290 | |
fn release(c_self: ?*c_void) callconv(.C) void {
|
291 | |
const self = @ptrCast(*Graphics, @alignCast(@alignOf(Graphics), c_self));
|
292 | |
|
293 | |
if (self.swapchain) |swapchain| {
|
294 | |
_ = self.xri.releaseSwapchainImage(
|
295 | |
swapchain.handle,
|
296 | |
&xr.SwapchainImageReleaseInfo.empty(),
|
297 | |
) catch {};
|
298 | |
}
|
299 | |
}
|
300 | |
|
301 | |
fn debug_callback(
|
|
275 |
pub fn lockQueue(self: *const Graphics) void {
|
|
276 |
_ = self.dg_device.LockCommandQueue(0);
|
|
277 |
}
|
|
278 |
|
|
279 |
pub fn unlockQueue(self: *const Graphics) void {
|
|
280 |
self.dg_device.UnlockCommandQueue(0);
|
|
281 |
}
|
|
282 |
|
|
283 |
pub fn setupDebugging(self: *Graphics) !void {
|
|
284 |
if (self.vki.vkCreateDebugUtilsMessengerEXT) |pfn| {
|
|
285 |
var messenger: vk.c.VkDebugUtilsMessengerEXT = undefined;
|
|
286 |
const messenger_create_info = vk.c.VkDebugUtilsMessengerCreateInfoEXT{
|
|
287 |
.sType = .VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT,
|
|
288 |
.pNext = null,
|
|
289 |
.flags = 0,
|
|
290 |
.messageSeverity = 0x1110,
|
|
291 |
.messageType = 0x3,
|
|
292 |
.pfnUserCallback = @This().debug_cb,
|
|
293 |
.pUserData = @as(*c_void, self),
|
|
294 |
};
|
|
295 |
|
|
296 |
_ = pfn(
|
|
297 |
@intToPtr(vk.c.VkInstance, @enumToInt(self.instance)),
|
|
298 |
&messenger_create_info,
|
|
299 |
null,
|
|
300 |
&messenger,
|
|
301 |
);
|
|
302 |
} else {
|
|
303 |
return error.FunctionUnsupported;
|
|
304 |
}
|
|
305 |
}
|
|
306 |
|
|
307 |
pub fn getBinding(self: *const Graphics) xr.GraphicsBindingVulkan2KHR {
|
|
308 |
return .{
|
|
309 |
.instance = self.instance,
|
|
310 |
.device = self.device,
|
|
311 |
.physical_device = self.physical_device,
|
|
312 |
.queue_family_index = self.family_index,
|
|
313 |
.queue_index = 0,
|
|
314 |
};
|
|
315 |
}
|
|
316 |
|
|
317 |
fn debug_cb(
|
302 | 318 |
msg_severity: vk.c.VkDebugUtilsMessageSeverityFlagBitsEXT,
|
303 | 319 |
msg_type: vk.c.VkDebugUtilsMessageTypeFlagsEXT,
|
304 | 320 |
c_data: ?*const vk.c.VkDebugUtilsMessengerCallbackDataEXT,
|
|
318 | 334 |
}
|
319 | 335 |
return 0;
|
320 | 336 |
}
|
321 | |
|
322 | |
pub fn setup_debugging(self: *Graphics) !void {
|
323 | |
if (self.vki.vkCreateDebugUtilsMessengerEXT) |pfn| {
|
324 | |
var messenger: vk.c.VkDebugUtilsMessengerEXT = undefined;
|
325 | |
const messenger_create_info = vk.c.VkDebugUtilsMessengerCreateInfoEXT{
|
326 | |
.sType = .VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT,
|
327 | |
.pNext = null,
|
328 | |
.flags = 0,
|
329 | |
.messageSeverity = 0x1110,
|
330 | |
.messageType = 0x3,
|
331 | |
.pfnUserCallback = @This().debug_callback,
|
332 | |
.pUserData = @as(*c_void, self),
|
333 | |
};
|
334 | |
|
335 | |
_ = pfn(
|
336 | |
@intToPtr(vk.c.VkInstance, @enumToInt(self.instance)),
|
337 | |
&messenger_create_info,
|
338 | |
null,
|
339 | |
&messenger,
|
340 | |
);
|
341 | |
} else {
|
342 | |
return error.FunctionUnsupported;
|
343 | |
}
|
344 | |
}
|
345 | |
|
346 | |
pub fn get_binding(self: *const Graphics) xr.GraphicsBindingVulkan2KHR {
|
347 | |
return .{
|
348 | |
.instance = self.instance,
|
349 | |
.device = self.device,
|
350 | |
.physical_device = self.physical_device,
|
351 | |
.queue_family_index = self.family_index,
|
352 | |
.queue_index = 0,
|
353 | |
};
|
354 | |
}
|
355 | 337 |
};
|
356 | 338 |
|
357 | 339 |
pub const Swapchain = struct {
|
358 | 340 |
handle: xr.Swapchain,
|
359 | |
images: []vk.Image,
|
360 | |
image_rect: xr.Rect2Di,
|
|
341 |
dg_handle: dg.ISwapChainVk_Wrapper,
|
|
342 |
image_rects: []xr.Rect2Di,
|
361 | 343 |
|
362 | 344 |
graphics: *const Graphics,
|
363 | 345 |
|
364 | 346 |
pub fn init(
|
|
347 |
self: *Swapchain,
|
365 | 348 |
gfx: *const Graphics,
|
|
349 |
factory: dg.IEngineFactoryVk_Wrapper,
|
366 | 350 |
session: xr.Session,
|
367 | |
config: xr.ViewConfigurationView,
|
368 | |
) !Swapchain {
|
|
351 |
configs: []const xr.ViewConfigurationView,
|
|
352 |
) !void {
|
|
353 |
const config = configs[0];
|
|
354 |
const view_count = @intCast(u32, configs.len);
|
|
355 |
for (configs[1..]) |c| {
|
|
356 |
if (c.recommended_swapchain_sample_count != config.recommended_swapchain_sample_count) {
|
|
357 |
return error.ViewCfgDiffer;
|
|
358 |
}
|
|
359 |
if (c.recommended_image_rect_width != config.recommended_image_rect_width) {
|
|
360 |
return error.ViewCfgDiffer;
|
|
361 |
}
|
|
362 |
if (c.recommended_image_rect_height != config.recommended_image_rect_height) {
|
|
363 |
return error.ViewCfgDiffer;
|
|
364 |
}
|
|
365 |
}
|
|
366 |
|
369 | 367 |
// xri.enumerateSwapchainFormats(...);
|
370 | 368 |
const swapchain = try gfx.xri.createSwapchain(session, .{
|
371 | 369 |
.create_flags = .{},
|
372 | 370 |
.usage_flags = .{
|
373 | 371 |
.color_attachment_bit = true,
|
374 | |
// .depth_stencil_attachment_bit = true,
|
375 | 372 |
.transfer_dst_bit = true,
|
376 | 373 |
.sampled_bit = true,
|
377 | 374 |
},
|
378 | |
.format = @enumToInt(vk.Format.r8g8b8a8_unorm),
|
|
375 |
.format = @enumToInt(vk.Format.r8g8b8a8_srgb),
|
379 | 376 |
.sample_count = config.recommended_swapchain_sample_count,
|
380 | |
.width = config.recommended_image_rect_width * 2,
|
381 | |
.height = config.recommended_image_rect_height,
|
|
377 |
.width = config.recommended_image_rect_width,
|
|
378 |
.height = config.recommended_image_rect_height * view_count,
|
382 | 379 |
.face_count = 1,
|
383 | 380 |
.array_size = 1,
|
384 | 381 |
.mip_count = 1,
|
|
395 | 392 |
xr_images.ptr,
|
396 | 393 |
));
|
397 | 394 |
|
398 | |
const command_buffers = try gfx.allocator.alloc(vk.CommandBuffer, xr_images.len);
|
399 | |
errdefer gfx.allocator.free(command_buffers);
|
400 | |
|
401 | |
try gfx.vkd.allocateCommandBuffers(gfx.device, .{
|
402 | |
.command_pool = gfx.command_pool,
|
403 | |
.command_buffer_count = image_count,
|
404 | |
.level = .primary,
|
405 | |
}, command_buffers.ptr);
|
406 | |
|
407 | 395 |
const images = try gfx.allocator.alloc(vk.Image, xr_images.len);
|
|
396 |
defer gfx.allocator.free(images);
|
|
397 |
|
|
398 |
const image_rects = try gfx.allocator.alloc(xr.Rect2Di, xr_images.len);
|
408 | 399 |
errdefer gfx.allocator.free(images);
|
409 | 400 |
|
410 | |
for (images) |*image, i| {
|
411 | |
image.* = xr_images[i].image;
|
412 | |
}
|
413 | |
|
414 | |
std.debug.print("created swapchain {}x{}, SS{}, {} images\n", .{
|
415 | |
config.recommended_image_rect_width,
|
416 | |
config.recommended_image_rect_height,
|
417 | |
config.recommended_swapchain_sample_count,
|
418 | |
images.len,
|
419 | |
});
|
420 | |
|
421 | |
return Swapchain{
|
422 | |
.handle = swapchain,
|
423 | |
.image_rect = .{
|
424 | |
.offset = .{},
|
|
401 |
for (xr_images) |xr_image, i| {
|
|
402 |
images[i] = xr_image.image;
|
|
403 |
image_rects[i] = .{
|
|
404 |
.offset = .{
|
|
405 |
.y = @intCast(i32, config.recommended_image_rect_height) * @intCast(i32, i),
|
|
406 |
},
|
425 | 407 |
.extent = .{
|
426 | 408 |
.width = @intCast(i32, config.recommended_image_rect_width),
|
427 | 409 |
.height = @intCast(i32, config.recommended_image_rect_height),
|
428 | 410 |
},
|
429 | |
},
|
430 | |
.images = images,
|
|
411 |
};
|
|
412 |
}
|
|
413 |
|
|
414 |
const swap_desc = dg.SwapChainDesc{
|
|
415 |
.Width = config.recommended_image_rect_width,
|
|
416 |
.Height = config.recommended_image_rect_height * view_count,
|
|
417 |
.ColorBufferFormat = dg.TEX_FORMAT_RGBA8_UNORM_SRGB,
|
|
418 |
.DepthBufferFormat = dg.TEX_FORMAT_D32_FLOAT,
|
|
419 |
.Usage = dg.SWAP_CHAIN_USAGE_RENDER_TARGET,
|
|
420 |
.PreTransform = dg.SURFACE_TRANSFORM_OPTIMAL,
|
|
421 |
.BufferCount = @intCast(u32, images.len),
|
|
422 |
.DefaultDepthValue = 1,
|
|
423 |
.DefaultStencilValue = 0,
|
|
424 |
.IsPrimary = true,
|
|
425 |
};
|
|
426 |
const callbacks = dg.SwapChainImageCallbacks{
|
|
427 |
.Cookie = self,
|
|
428 |
.ImageCallbackAcquire = @This().acquire_cb,
|
|
429 |
.ImageCallbackRelease = @This().release_cb,
|
|
430 |
};
|
|
431 |
|
|
432 |
var dg_swapchain: ?*dg.ISwapChain = undefined;
|
|
433 |
factory.CreateSwapChainVk(
|
|
434 |
@ptrCast(*dg.IRenderDevice, gfx.dg_device.ptr),
|
|
435 |
gfx.dg_ctx.ptr,
|
|
436 |
&swap_desc,
|
|
437 |
@intCast(u32, images.len),
|
|
438 |
@ptrCast(**dg.VkImage_T, images.ptr),
|
|
439 |
&callbacks,
|
|
440 |
&dg_swapchain,
|
|
441 |
);
|
|
442 |
|
|
443 |
std.debug.print("created swapchain {}x{}*{}, SS{}, {} images\n", .{
|
|
444 |
config.recommended_image_rect_width,
|
|
445 |
config.recommended_image_rect_height,
|
|
446 |
view_count,
|
|
447 |
config.recommended_swapchain_sample_count,
|
|
448 |
images.len,
|
|
449 |
});
|
|
450 |
|
|
451 |
self.* = .{
|
|
452 |
.handle = swapchain,
|
|
453 |
.dg_handle = dg.ISwapChainVk_Wrapper.wrap(@ptrCast([*c]dg.ISwapChainVk, dg_swapchain)),
|
|
454 |
.image_rects = image_rects,
|
431 | 455 |
|
432 | 456 |
.graphics = gfx,
|
433 | 457 |
};
|
434 | 458 |
}
|
435 | 459 |
|
436 | |
pub fn deinit(self: Swapchain) void {
|
|
460 |
pub fn deinit(self: *const Swapchain) void {
|
437 | 461 |
const gfx = self.graphics;
|
438 | 462 |
|
439 | |
gfx.allocator.free(self.images);
|
|
463 |
gfx.allocator.free(self.image_rects);
|
440 | 464 |
gfx.xri.destroySwapchain(self.handle) catch {};
|
441 | 465 |
}
|
|
466 |
|
|
467 |
pub fn acquireImage(self: *const Swapchain) !void {
|
|
468 |
const result = self.dg_handle.AcquireNextImage();
|
|
469 |
if (result != .VK_SUCCESS) {
|
|
470 |
return error.Unknown;
|
|
471 |
}
|
|
472 |
}
|
|
473 |
|
|
474 |
pub fn presentImage(self: *const Swapchain) void {
|
|
475 |
self.dg_handle.PresentImage();
|
|
476 |
}
|
|
477 |
|
|
478 |
fn acquire_cb(c_self: ?*c_void, index: [*c]u32) callconv(.C) dg.VkResult {
|
|
479 |
const self = @ptrCast(*Swapchain, @alignCast(@alignOf(Swapchain), c_self));
|
|
480 |
const xri = &self.graphics.xri;
|
|
481 |
|
|
482 |
index.* = xri.acquireSwapchainImage(
|
|
483 |
self.handle,
|
|
484 |
&xr.SwapchainImageAcquireInfo.empty(),
|
|
485 |
) catch return .VK_ERROR_UNKNOWN;
|
|
486 |
|
|
487 |
_ = xri.waitSwapchainImage(self.handle, .{ .timeout = -1 }) catch {};
|
|
488 |
|
|
489 |
return .VK_SUCCESS;
|
|
490 |
}
|
|
491 |
|
|
492 |
fn release_cb(c_self: ?*c_void) callconv(.C) void {
|
|
493 |
const self = @ptrCast(*Swapchain, @alignCast(@alignOf(Swapchain), c_self));
|
|
494 |
|
|
495 |
_ = self.graphics.xri.releaseSwapchainImage(
|
|
496 |
self.handle,
|
|
497 |
&xr.SwapchainImageReleaseInfo.empty(),
|
|
498 |
) catch {};
|
|
499 |
}
|
442 | 500 |
};
|