Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

## Unreleased

- Use Siwin's platform ABI fixes and reusable X11 visual/XCB helpers.
Pin upstream Siwin with merged [#58](https://github.com/levovix0/siwin/pull/58).
- Accept Siwin's `uint64` Vulkan surfaces without losing their upper bits;
retain pointer inputs for other window backends.
- Mark recursive fragment and diagnostic render trees acyclic; rely on Nim
inference for other render data. Document the downward ownership contract.
- Add cross-thread ARC/ORC render-data coverage and fragment-cycle rejection
Expand Down
3 changes: 2 additions & 1 deletion figdraw.nimble
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,8 @@ feature "surfer":
requires "xkb#b4d50f4cccad1cd9e39d2f5a5e1fef2710edcc31"
# TODO: Put this in surfer's manifest.
feature "siwin":
requires "siwin >= 1.1.2"
# Merged platform ABI fixes and X11 helpers: Siwin #56, #57, and #58.
requires "gh:levovix0/siwin#78bb49c7fd7e5e14590f567e1ccbb07eb5ab6739"
feature "vulkan":
requires "https://github.com/planetis-m/vulkan#b223dc9"
feature "metal":
Expand Down
21 changes: 10 additions & 11 deletions src/figdraw/vulkan/vulkan_context.nim
Original file line number Diff line number Diff line change
Expand Up @@ -421,10 +421,10 @@ proc createPresentSurface(ctx: VulkanContext) =
let fnPtr = vkGetInstanceProcAddrNative(ctx.instance, "vkCreateXcbSurfaceKHR")
if fnPtr.isNil:
raise newException(ValueError, "vkCreateXcbSurfaceKHR unavailable")
let xcbConn = XGetXCBConnection(ctx.presentXlibDisplay)
let xcbConn = x11XcbConnection(ctx.presentXlibDisplay)
if xcbConn.isNil:
raise newException(
ValueError, "XGetXCBConnection returned nil for Vulkan XCB surface"
ValueError, "X11-XCB connection unavailable for Vulkan XCB surface"
)
let vkCreateXcbSurfaceKHRNative = cast[VkCreateXcbSurfaceKHRNativeProc](fnPtr)
var createInfo = VkXcbSurfaceCreateInfoKHRNative(
Expand Down Expand Up @@ -1814,12 +1814,11 @@ proc ensureGpuRuntime(ctx: VulkanContext) =
vendorId = ctx.driverInfo.vendorId,
swapchainProfile = $ctx.activeSwapchainProfile

var queueCreateInfos =
@[
newVkDeviceQueueCreateInfo(
queueFamilyIndex = ctx.queueFamily, queuePriorities = [1.0'f32]
)
]
var queueCreateInfos = @[
newVkDeviceQueueCreateInfo(
queueFamilyIndex = ctx.queueFamily, queuePriorities = [1.0'f32]
)
]
if ctx.presentQueueFamily != ctx.queueFamily:
queueCreateInfos.add(
newVkDeviceQueueCreateInfo(
Expand Down Expand Up @@ -4209,12 +4208,12 @@ proc instanceHandle*(ctx: VulkanContext): pointer =

proc setExternalSurface*(
ctx: VulkanContext,
surface: pointer,
surface: pointer | uint64,
target: PresentTargetKind,
ownedByContext = false,
) =
if surface.isNil:
raise newException(ValueError, "External Vulkan surface pointer is nil")
if cast[uint64](surface) == 0:
raise newException(ValueError, "External Vulkan surface handle is zero")
ctx.clearPresentTarget()
ctx.presentTargetKind = target
ctx.instanceSurfaceHint = ctx.presentTargetKind
Expand Down
13 changes: 10 additions & 3 deletions src/figdraw/vulkan/vulkan_utils.nim
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,12 @@ type
transferSrcEnabled*: bool

when defined(linux) or defined(bsd):
when defined(features.figdraw.siwin):
import siwin/platforms/x11/x11api as siX11Api

proc x11XcbConnection*(display: pointer): pointer =
siX11Api.x11XcbConnection(cast[siX11Api.PDisplay](display))

type VkXlibSurfaceCreateInfoKHRNative* {.bycopy.} = object
sType*: VkStructureType
pNext*: pointer
Expand Down Expand Up @@ -80,9 +86,10 @@ when defined(linux) or defined(bsd):
pSurface: ptr VkSurfaceKHR,
): VkResult {.cdecl.}

proc XGetXCBConnection*(
display: pointer
): pointer {.cdecl, dynlib: "libX11-xcb.so.1", importc.}
when not defined(features.figdraw.siwin):
proc x11XcbConnection*(
display: pointer
): pointer {.cdecl, dynlib: "libX11-xcb.so.1", importc: "XGetXCBConnection".}

proc findGraphicsQueueFamily*(vk: VulkanDispatch, device: VkPhysicalDevice): int =
let families = vk.getQueueFamilyProperties(device)
Expand Down
42 changes: 13 additions & 29 deletions src/figdraw/windowing/siwinshim.nim
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,9 @@ when defined(linux) or defined(bsd):
import std/importutils
privateAccess siWaylandWindow.WindowWayland
when UseOpenGlFallback:
import x11/x as x11Types except Window
import x11/[xlib, xutil]
import siwin/platforms/x11/glx as siX11Glx
import siwin/platforms/x11/windowOpengl as siX11OpenGlWindow
import siwin/platforms/x11/x11api as siX11Api
import siwin/platforms/wayland/egl as siWaylandEgl
from siwin/platforms/wayland/protocol import Wl_surface, commit
import siwin/platforms/wayland/windowOpengl as siWaylandOpenGlWindow
Expand Down Expand Up @@ -467,8 +466,8 @@ when UseVulkanBackend and UseOpenGlFallback and (defined(linux) or defined(bsd))
initialized: bool
case kind: SiwinOpenGlFallbackKind
of sogfX11:
x11Display: PDisplay
x11Drawable: x11Types.Drawable
x11Display: siX11Api.PDisplay
x11Drawable: siX11Api.Drawable
x11Context: siX11Glx.GlxContext
of sogfWayland:
waylandNativeDisplay: pointer
Expand Down Expand Up @@ -578,8 +577,8 @@ when UseVulkanBackend and UseOpenGlFallback and (defined(linux) or defined(bsd))
let
fallback = SiwinOpenGlFallbackState(window: window, kind: sogfX11)
x11Window = siX11Window.WindowX11(window)
display = cast[PDisplay](x11Window.nativeDisplayHandle())
drawable = x11Types.Drawable(x11Window.nativeWindowHandle())
display = cast[siX11Api.PDisplay](x11Window.nativeDisplayHandle())
drawable = siX11Api.Drawable(x11Window.nativeWindowHandle())
renderer.backendState.openGlFallback = fallback
fallback.x11Display = display
fallback.x11Drawable = drawable
Expand Down Expand Up @@ -627,22 +626,8 @@ when UseVulkanBackend and UseOpenGlFallback and (defined(linux) or defined(bsd))
of sogfX11:
let initializeOpenGl = not fallback.initialized
if initializeOpenGl:
var attributes: XWindowAttributes
if fallback.x11Display.XGetWindowAttributes(
fallback.x11Drawable, attributes.addr
) == 0:
raise newException(ValueError, "Failed to query X11 window visual")
var
visualTemplate = XVisualInfo(visualid: XVisualIDFromVisual(attributes.visual))
visualCount: cint
let visualInfos = fallback.x11Display.XGetVisualInfo(
VisualIDMask.clong, visualTemplate.addr, visualCount.addr
)
if visualInfos.isNil or visualCount <= 0:
raise newException(ValueError, "Failed to resolve X11 visual for OpenGL")
defer:
discard XFree(visualInfos)
fallback.x11Context = fallback.x11Display.newGlxContext(visualInfos)
var visualInfo = fallback.x11Display.getWindowVisualInfo(fallback.x11Drawable)
fallback.x11Context = fallback.x11Display.newGlxContext(visualInfo.addr)
fallback.initialized = true
fallback.x11Display.makeCurrent(fallback.x11Drawable, fallback.x11Context)
if siX11Glx.cGlxCurrentContext().isNil:
Expand Down Expand Up @@ -846,16 +831,15 @@ proc setupBackend*(renderer: FigRenderer, window: Window) =
vkCtx.setPresentMetalLayer(renderer.backendState.vulkanMetalLayer.layer)
hasPresentTarget = true
elif defined(linux) or defined(bsd):
var surface: pointer = nil
let surface = cast[uint64](window.vulkanSurface())
if window of siX11Window.WindowX11SoftwareRendering:
siX11Window.WindowX11SoftwareRendering(window).setSoftwarePresentEnabled(
false
)
if window of siWaylandWindow.WindowWaylandSoftwareRendering:
siWaylandWindow.WindowWaylandSoftwareRendering(window).softwarePresentEnabled =
false
surface = window.vulkanSurface()
if not surface.isNil:
if surface != 0:
if window of siWaylandWindow.WindowWayland:
vkCtx.setExternalSurface(
surface, presentTargetWayland, ownedByContext = true
Expand All @@ -867,18 +851,18 @@ proc setupBackend*(renderer: FigRenderer, window: Window) =
)
hasPresentTarget = true
elif defined(windows):
let surface = window.vulkanSurface()
if not surface.isNil:
let surface = cast[uint64](window.vulkanSurface())
if surface != 0:
vkCtx.setExternalSurface(surface, presentTargetWin32, ownedByContext = true)
hasPresentTarget = true
when defined(linux) or defined(bsd):
if surface.isNil and window of siX11Window.WindowX11:
if surface == 0 and window of siX11Window.WindowX11:
let x11Window = siX11Window.WindowX11(window)
vkCtx.setPresentXlibTarget(
x11Window.nativeDisplayHandle(), x11Window.nativeWindowHandle()
)
hasPresentTarget = true
elif surface.isNil and window of siWaylandWindow.WindowWayland:
elif surface == 0 and window of siWaylandWindow.WindowWayland:
let waylandWindow = siWaylandWindow.WindowWayland(window)
vkCtx.setPresentWaylandTarget(
waylandWindow.nativeWaylandDisplayHandle(),
Expand Down
35 changes: 35 additions & 0 deletions tests/tsiwin_fallback_window.nim
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ import siwin/platforms
import figdraw/figrender
import figdraw/windowing/siwinshim

when defined(linux) or defined(bsd):
import siwin/platforms/x11/x11api as xlib
from figdraw/vulkan/vulkan_utils import nil

suite "Siwin OpenGL fallback window selection":
test "forced OpenGL always creates an OpenGL window":
check usesOpenGlWindowForVulkanFallback(Platform.x11, true)
Expand All @@ -27,3 +31,34 @@ suite "Siwin OpenGL fallback window selection":
)
else:
skip()

test "a missing optional XCB bridge returns nil":
when (defined(linux) or defined(bsd)) and defined(features.figdraw.siwin):
let original = xlib.XGetXCBConnection
defer:
xlib.XGetXCBConnection = original
xlib.XGetXCBConnection = nil
check vulkan_utils.x11XcbConnection(nil) == nil
else:
skip()

test "Siwin visual queries and XCB bridge accept an existing Xlib display":
when defined(linux) or defined(bsd):
if not xlib.x11Available():
skip()
else:
let display = xlib.XOpenDisplay(nil)
if display == nil:
skip()
else:
defer:
discard xlib.XCloseDisplay(display)
let visual = xlib.getWindowVisualInfo(display, xlib.XRootWindow(display, 0))
check visual.visual != nil
check visual.depth > 0
if xlib.x11XcbAvailable():
check vulkan_utils.x11XcbConnection(cast[pointer](display)) != nil
else:
check vulkan_utils.x11XcbConnection(cast[pointer](display)) == nil
else:
skip()
16 changes: 16 additions & 0 deletions tests/tvulkan_frame_resources.nim
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,22 @@ when UseVulkanBackend:
copyMem(result.addr, mapped, 4)
ctx.vk.unmapMemory(ctx.device, buffer.allocation)

suite "Vulkan external surfaces":
test "accepts integer and pointer handles without losing their upper bits":
let ctx = newContext(atlasSize = 64, maxQuads = 8)
defer:
ctx.clearPresentTarget()
when sizeof(VkSurfaceKHR) == 8:
let handle = 0x123456789ABCDEF0'u64
ctx.setExternalSurface(handle, presentTargetXlib)
check cast[uint64](ctx.surface) == handle
ctx.setExternalSurface(cast[pointer](handle), presentTargetWayland)
check cast[uint64](ctx.surface) == handle
expect ValueError:
ctx.setExternalSurface(0'u64, presentTargetXlib)
expect ValueError:
ctx.setExternalSurface(nil, presentTargetXlib)

suite "Vulkan atlas packing":
test "Vulkan failures remain exceptions in every build mode":
expect VulkanError:
Expand Down
Loading