Skip to content

Commit

Permalink
Manual GLFW integration (#480)
Browse files Browse the repository at this point in the history
* work on manual glfw closed loop

* working glfw example

* lint with newer versions of flake8 and black

* restore test file

* add comments

* convert some comments to docstrings

* rename file
  • Loading branch information
Korijn committed Apr 11, 2024
1 parent e8bef7d commit 72094b0
Show file tree
Hide file tree
Showing 3 changed files with 122 additions and 32 deletions.
15 changes: 10 additions & 5 deletions examples/triangle.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,15 +74,15 @@ async def main_async(canvas):
return _main(canvas, device)


def _main(canvas, device):
def setup_draw(context, device):
"""Setup context and device for drawing a triangle and return draw callback"""
shader = device.create_shader_module(code=shader_source)

# No bind group and layout, we should not create empty ones.
pipeline_layout = device.create_pipeline_layout(bind_group_layouts=[])

present_context = canvas.get_context()
render_texture_format = present_context.get_preferred_format(device.adapter)
present_context.configure(device=device, format=render_texture_format)
render_texture_format = context.get_preferred_format(device.adapter)
context.configure(device=device, format=render_texture_format)

render_pipeline = device.create_render_pipeline(
layout=pipeline_layout,
Expand Down Expand Up @@ -122,7 +122,7 @@ def _main(canvas, device):
)

def draw_frame():
current_texture = present_context.get_current_texture()
current_texture = context.get_current_texture()
command_encoder = device.create_command_encoder()

render_pass = command_encoder.begin_render_pass(
Expand All @@ -143,6 +143,11 @@ def draw_frame():
render_pass.end()
device.queue.submit([command_encoder.finish()])

return draw_frame


def _main(canvas, device):
draw_frame = setup_draw(canvas.get_context(), device)
canvas.request_draw(draw_frame)
return device

Expand Down
77 changes: 77 additions & 0 deletions examples/triangle_glfw_direct.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
"""
Direct integration of glfw and wgpu-py without using the
wgpu.gui Canvas abstraction/class hierarchy.
Demonstration for hardcore users that need total low-level
control.
# run_example = false
"""

import sys
from pathlib import Path

import glfw

from wgpu.backends.wgpu_native import GPUCanvasContext
from wgpu.gui.glfw import get_surface_info, get_physical_size
from wgpu.utils.device import get_default_device


sys.path.insert(0, str(Path(__file__).parent))

from triangle import setup_draw # noqa: E402


class GlfwCanvas:
"""Minimal canvas interface implementation to support GPUCanvasContext"""

def __init__(self, window):
self._window = window

def get_surface_info(self):
"""get window and display id, includes some triage to deal with OS differences"""
return get_surface_info(self._window)

def get_physical_size(self):
"""get framebuffer size in integer pixels"""
return get_physical_size(self._window)


def main():
# get the gpu device/adapter combo
device = get_default_device()

# create a window with glfw
glfw.init()
# disable automatic API selection, we are not using opengl
glfw.window_hint(glfw.CLIENT_API, glfw.NO_API)
glfw.window_hint(glfw.RESIZABLE, True)
window = glfw.create_window(640, 480, "glfw window", None, None)

# create a WGPU context
canvas = GlfwCanvas(window)
context = GPUCanvasContext(canvas)

# drawing logic
draw_frame = setup_draw(context, device)

# render loop
while True:
# draw a frame
draw_frame()
# present the frame to the screen
context.present()
# process inputs
glfw.poll_events()

# break on close
if glfw.window_should_close(window):
break

# dispose all resources and quit
glfw.terminate()


if __name__ == "__main__":
main()
62 changes: 35 additions & 27 deletions wgpu/gui/glfw.py
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,39 @@
}


def get_surface_info(window):
if sys.platform.startswith("win"):
return {
"platform": "windows",
"window": int(glfw.get_win32_window(window)),
}
elif sys.platform.startswith("darwin"):
return {
"platform": "cocoa",
"window": int(glfw.get_cocoa_window(window)),
}
elif sys.platform.startswith("linux"):
if is_wayland:
return {
"platform": "wayland",
"window": int(glfw.get_wayland_window(window)),
"display": int(glfw.get_wayland_display()),
}
else:
return {
"platform": "x11",
"window": int(glfw.get_x11_window(window)),
"display": int(glfw.get_x11_display()),
}
else:
raise RuntimeError(f"Cannot get GLFW surafce info on {sys.platform}.")


def get_physical_size(window):
psize = glfw.get_framebuffer_size(window)
return int(psize[0]), int(psize[1])


class GlfwWgpuCanvas(WgpuAutoGui, WgpuCanvasBase):
"""A glfw window providing a wgpu canvas."""

Expand Down Expand Up @@ -212,8 +245,7 @@ def _determine_size(self):
# on some systems and in logical-pixels on other, we use the
# framebuffer size and pixel ratio to derive the logical size.
pixel_ratio = get_window_content_scale(self._window)[0]
psize = glfw.get_framebuffer_size(self._window)
psize = int(psize[0]), int(psize[1])
psize = get_physical_size(self._window)

self._pixel_ratio = pixel_ratio
self._physical_size = psize
Expand Down Expand Up @@ -266,31 +298,7 @@ def _set_logical_size(self, new_logical_size):
# API

def get_surface_info(self):
if sys.platform.startswith("win"):
return {
"platform": "windows",
"window": int(glfw.get_win32_window(self._window)),
}
elif sys.platform.startswith("darwin"):
return {
"platform": "cocoa",
"window": int(glfw.get_cocoa_window(self._window)),
}
elif sys.platform.startswith("linux"):
if is_wayland:
return {
"platform": "wayland",
"window": int(glfw.get_wayland_window(self._window)),
"display": int(glfw.get_wayland_display()),
}
else:
return {
"platform": "x11",
"window": int(glfw.get_x11_window(self._window)),
"display": int(glfw.get_x11_display()),
}
else:
raise RuntimeError(f"Cannot get GLFW surafce info on {sys.platform}.")
return get_surface_info(self._window)

def get_pixel_ratio(self):
return self._pixel_ratio
Expand Down

0 comments on commit 72094b0

Please sign in to comment.