Skip to content

Commit

Permalink
Merge branch 'main' into baseenum
Browse files Browse the repository at this point in the history
  • Loading branch information
almarklein authored Sep 4, 2024
2 parents 7978a47 + dba9e11 commit 6172577
Show file tree
Hide file tree
Showing 11 changed files with 352 additions and 146 deletions.
55 changes: 47 additions & 8 deletions codegen/wgpu_native_patcher.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@
focuses on the API, here we focus on the C library usage.
"""

import re
from collections import defaultdict

from codegen.utils import print, blacken, Patcher
from codegen.hparser import get_h_parser
from codegen.idlparser import get_idl_parser
Expand Down Expand Up @@ -206,26 +209,62 @@ def apply(self, code):
hp = get_h_parser()
count = 0
detected = set()
generic_class_var_assignment = defaultdict(list)
generic_class_var_use = {}

for line, i in self.iter_lines():
if "lib.wgpu" in line or "libf.wgpu" in line:
start = line.index(".wgpu") + 1
end = line.index("(", start)
name = line[start:end]
if match := re.search(r"libf?\.(wgpu\w*)\(", line):
# standard function call
var_name = match.group(1)
indent = " " * (len(line) - len(line.lstrip()))
if "lib.wgpu" in line:
self.insert_line(
i, f"{indent}# FIXME: wgpu func calls must be done from libf"
)
if name not in hp.functions:
msg = f"unknown C function {name}"
if var_name not in hp.functions:
msg = f"unknown C function {var_name}"
self.insert_line(i, f"{indent}# FIXME: {msg}")
print(f"ERROR: {msg}")
else:
detected.add(name)
anno = hp.functions[name].replace(name, "f").strip(";")
detected.add(var_name)
anno = hp.functions[var_name].replace(var_name, "f").strip(";")
self.insert_line(i, indent + f"# H: " + anno)
count += 1
elif match := re.search(r"(_\w+_function) = libf?\.(wgpu\w*)", line):
# Assignment of libf function to a class variable. We'll point the
# annotation at the point of use.
var_name, lib_name = match.group(1, 2)
if lib_name not in hp.functions:
msg = f"unknown C function {lib_name}"
indent = " " * (len(line) - len(line.lstrip()))
self.insert_line(i, f"{indent}# FIXME: {msg}")
print(f"ERROR: {msg}")
else:
generic_class_var_assignment[var_name].append(lib_name)
elif match := re.search(r"type\(self\).(_\w+_function)", line):
# Calling the class variable. Keep track of where we are, so we can
# patch in the appropriate annotations.
var_name = match.group(1)
generic_class_var_use[var_name] = (line, i)

for var_name, (line, i) in generic_class_var_use.items():
indent = " " * (len(line) - len(line.lstrip()))
lib_names = generic_class_var_assignment.pop(var_name, ())
if not lib_names:
msg = f"There are no assignments to class field {var_name}"
self.insert_line(i, f"{indent}# FIXME: {msg}")
print(f"ERROR: {msg}")
detected.update(lib_names)
count += len(lib_names)
for lib_name in lib_names:
self.insert_line(
i, indent + f"# H: " + hp.functions[lib_name].strip(";")
)
# At this point, generic_class_var_assignment should be empty.
# If it is not, we've done an assignment to a class variable name, but have
# never used it.
for var_name, lib_names in generic_class_var_assignment.items():
print(f"ERROR: {var_name} assigned a value but it is never used")

print(f"Validated {count} C function calls")

Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from setuptools.command.bdist_wheel import bdist_wheel as _bdist_wheel

NAME = "wgpu"
SUMMARY = "Next generation GPU API for Python"
SUMMARY = "WebGPU for Python"

with open(f"{NAME}/__init__.py") as fh:
VERSION = re.search(r"__version__ = \"(.*?)\"", fh.read()).group(1)
Expand Down
61 changes: 40 additions & 21 deletions tests/renderutils.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ def render_to_texture(
depth_stencil_state=None,
depth_stencil_attachment=None,
renderpass_callback=lambda *args: None,
use_render_bundle=False,
):
# https://github.com/gfx-rs/wgpu-rs/blob/master/examples/capture/main.rs

Expand Down Expand Up @@ -139,6 +140,7 @@ def render_to_texture(
_ = render_pipeline.get_bind_group_layout(0)

command_encoder = device.create_command_encoder()
command_encoder.push_debug_group("command encoder")

color_attachment = color_attachment or {
"resolve_target": None,
Expand All @@ -147,36 +149,52 @@ def render_to_texture(
"store_op": wgpu.StoreOp.store,
}
color_attachment["view"] = current_texture_view
command_encoder.insert_debug_marker("Creating render pass")
render_pass = command_encoder.begin_render_pass(
color_attachments=[color_attachment],
depth_stencil_attachment=depth_stencil_attachment,
occlusion_query_set=None,
)
render_pass.push_debug_group("foo")

render_pass.insert_debug_marker("setting pipeline")
render_pass.set_pipeline(render_pipeline)
render_pass.insert_debug_marker("setting bind group")
if bind_group:
render_pass.set_bind_group(0, bind_group)
for slot, vbo in enumerate(vbos):
render_pass.insert_debug_marker(f"setting vbo {slot}")
render_pass.set_vertex_buffer(slot, vbo, 0, 0)
def encode_render_commands(encoder):
encoder.push_debug_group("foo")
encoder.insert_debug_marker("setting pipeline")
encoder.set_pipeline(render_pipeline)
encoder.insert_debug_marker("setting bind group")
if bind_group:
encoder.set_bind_group(0, bind_group)
for slot, vbo in enumerate(vbos):
encoder.insert_debug_marker(f"setting vbo {slot}")
encoder.set_vertex_buffer(slot, vbo, 0, 0)
encoder.insert_debug_marker("draw!")
if ibo is None:
if indirect_buffer is None:
encoder.draw(4, 1, 0, 0)
else:
encoder.draw_indirect(indirect_buffer, 0)
else:
encoder.set_index_buffer(ibo, wgpu.IndexFormat.uint32, 0, 0)
if indirect_buffer is None:
encoder.draw_indexed(6, 1, 0, 0, 0)
else:
encoder.draw_indexed_indirect(indirect_buffer, 0)
encoder.pop_debug_group()

# The callbacks are usually things that can't be done in a render bundle
render_pass.insert_debug_marker("invoking callback")
renderpass_callback(render_pass)
render_pass.insert_debug_marker("draw!")
if ibo is None:
if indirect_buffer is None:
render_pass.draw(4, 1, 0, 0)
else:
render_pass.draw_indirect(indirect_buffer, 0)

if not use_render_bundle:
encode_render_commands(render_pass)
else:
render_pass.set_index_buffer(ibo, wgpu.IndexFormat.uint32, 0, 0)
if indirect_buffer is None:
render_pass.draw_indexed(6, 1, 0, 0, 0)
else:
render_pass.draw_indexed_indirect(indirect_buffer, 0)
render_pass.pop_debug_group()
args = {"color_formats": [wgpu.TextureFormat.rgba8unorm]}
if depth_stencil_state:
args["depth_stencil_format"] = depth_stencil_state["format"]
render_bundle_encoder = device.create_render_bundle_encoder(**args)
encode_render_commands(render_bundle_encoder)
render_bundle = render_bundle_encoder.finish()
render_pass.execute_bundles([render_bundle])

render_pass.end()
command_encoder.copy_texture_to_buffer(
{"texture": texture, "mip_level": 0, "origin": (0, 0, 0)},
Expand All @@ -188,6 +206,7 @@ def render_to_texture(
},
(nx, ny, 1),
)
command_encoder.pop_debug_group()
device.queue.submit([command_encoder.finish()])

# Read the current data of the output buffer - numpy is much easier to work with
Expand Down
Loading

0 comments on commit 6172577

Please sign in to comment.