Skip to content

Commit

Permalink
use rgba32float for buffers
Browse files Browse the repository at this point in the history
  • Loading branch information
Vipitis committed Jun 7, 2024
1 parent a2457dc commit 43a3572
Show file tree
Hide file tree
Showing 2 changed files with 33 additions and 27 deletions.
33 changes: 12 additions & 21 deletions wgpu_shadertoy/passes.py
Original file line number Diff line number Diff line change
Expand Up @@ -477,19 +477,8 @@ def _finish_renderpass(self, device: wgpu.GPUDevice) -> None:
"entry_point": "main",
"targets": [
{
"format": wgpu.TextureFormat.bgra8unorm,
"blend": {
"color": (
wgpu.BlendFactor.one,
wgpu.BlendFactor.zero,
wgpu.BlendOperation.add,
),
"alpha": (
wgpu.BlendFactor.one,
wgpu.BlendFactor.zero,
wgpu.BlendOperation.add,
),
},
"format": self._format,
"blend": None, # maybe fine?
},
],
},
Expand All @@ -503,6 +492,7 @@ class ImageRenderPass(RenderPass):

def __init__(self, **kwargs):
super().__init__(**kwargs)
self._format = wgpu.TextureFormat.bgra8unorm
# TODO figure out if there is anything specific. Maybe the canvas stuff? perhaps that should stay in the main class...

def draw_image(self, device: wgpu.GPUDevice, present_context) -> None:
Expand Down Expand Up @@ -545,6 +535,7 @@ class BufferRenderPass(RenderPass):
def __init__(self, buffer_idx: str = "", **kwargs):
super().__init__(**kwargs)
self._buffer_idx = buffer_idx
self._format = wgpu.TextureFormat.rgba32float

@property
def buffer_idx(self) -> str:
Expand Down Expand Up @@ -573,7 +564,7 @@ def texture_size(self) -> tuple:

return self._texture_size

def _pad_columns(self, cols: int, alignment=64) -> int:
def _pad_columns(self, cols: int, alignment=16) -> int:
if cols % alignment != 0:
cols = (cols // alignment + 1) * alignment
return cols
Expand Down Expand Up @@ -608,7 +599,7 @@ def texture(self) -> wgpu.GPUTexture:
# creates the initial texture
self._texture = self.main._device.create_texture(
size=self.texture_size,
format=wgpu.TextureFormat.bgra8unorm,
format=self._format,
usage=wgpu.TextureUsage.COPY_SRC
| wgpu.TextureUsage.COPY_DST
| wgpu.TextureUsage.RENDER_ATTACHMENT
Expand Down Expand Up @@ -647,7 +638,7 @@ def draw_buffer(self, device: wgpu.GPUDevice) -> None:
# create a temporary texture as a render target
target_texture = device.create_texture(
size=self.texture_size,
format=wgpu.TextureFormat.bgra8unorm,
format=self._format,
usage=wgpu.TextureUsage.COPY_SRC | wgpu.TextureUsage.RENDER_ATTACHMENT,
)

Expand Down Expand Up @@ -702,7 +693,7 @@ def _download_texture(
size = self.texture_size

buffer = device.create_buffer(
size=(size[0] * size[1] * 4),
size=(size[0] * size[1] * 16),
usage=wgpu.BufferUsage.COPY_SRC | wgpu.BufferUsage.COPY_DST,
)
command_encoder.copy_texture_to_buffer(
Expand All @@ -714,14 +705,14 @@ def _download_texture(
{
"buffer": buffer,
"offset": 0,
"bytes_per_row": size[0] * 4,
"bytes_per_row": size[0] * 16,
"rows_per_image": size[1],
},
size,
)
device.queue.submit([command_encoder.finish()])
frame = device.queue.read_buffer(buffer)
frame = np.frombuffer(frame, dtype=np.uint8).reshape(size[1], size[0], 4)
frame = np.frombuffer(frame, dtype=np.float32).reshape(size[1], size[0], 4)
# redundant copy?
# self._last_frame = frame
return frame
Expand All @@ -739,7 +730,7 @@ def _upload_texture(self, data, device=None, command_encoder=None):
# create a new texture with the changed size?
new_texture = device.create_texture(
size=(data.shape[1], data.shape[0], 1),
format=wgpu.TextureFormat.bgra8unorm,
format=self._format,
usage=wgpu.TextureUsage.COPY_SRC
| wgpu.TextureUsage.RENDER_ATTACHMENT
| wgpu.TextureUsage.COPY_DST
Expand All @@ -755,7 +746,7 @@ def _upload_texture(self, data, device=None, command_encoder=None):
data,
{
"offset": 0,
"bytes_per_row": data.shape[1] * 4,
"bytes_per_row": data.shape[1] * 16,
"rows_per_image": data.shape[0],
},
(data.shape[1], data.shape[0], 1),
Expand Down
27 changes: 21 additions & 6 deletions wgpu_shadertoy/shadertoy.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@
from .api import shader_args_from_json, shadertoy_from_id
from .passes import BufferRenderPass, ImageRenderPass

# TODO: hacky solution, needs to be improved
_default_device = None


class UniformArray:
"""Convenience class to create a uniform array.
Expand Down Expand Up @@ -196,6 +199,23 @@ def shader_type(self) -> str:
"""
return self.image.shader_type

@property
def _device(self):
"""
copy and paste from wgpu.utils.device.get_default_device but with feature enabled
we need to enable float32-filterable for buffer textures.
"""
global _default_device

if _default_device is None:
import wgpu.backends.auto

adapter = wgpu.gpu.request_adapter(power_preference="high-performance")
_default_device = adapter.request_device(
required_features=["float32-filterable"]
)
return _default_device

@classmethod
def from_json(cls, dict_or_path, **kwargs):
"""Builds a `Shadertoy` instance from a JSON-like dict of Shadertoy.com shader data."""
Expand All @@ -220,8 +240,6 @@ def _prepare_canvas(self):
title=self.title, size=self.resolution, max_fps=60
)

self._device = wgpu.utils.device.get_default_device()

self._present_context = self._canvas.get_context()

# We use "bgra8unorm" not "bgra8unorm-srgb" here because we want to let the shader fully control the color-space.
Expand Down Expand Up @@ -306,10 +324,7 @@ def _draw_frame(self):

for buf in self.buffers.values():
if buf: # checks if not None?
buf.draw_buffer(
self._device
) # does this need kind of the target to write too?
# TODO: most of the code below here is for the image renderpass...
buf.draw_buffer(self._device)
self.image.draw_image(self._device, self._present_context)

self._canvas.request_draw()
Expand Down

0 comments on commit 43a3572

Please sign in to comment.