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
Original file line number Diff line number Diff line change
@@ -1,39 +1,49 @@
import shaderCode from './shader.wgsl'

export default function getComputeSDF(device: GPUDevice, buffersToDestroy: GPUBuffer[]) {
export default function getComputeShape(device: GPUDevice, buffersToDestroy: GPUBuffer[]) {
const shaderModule = device.createShaderModule({
label: 'compute SDF shader',
label: 'computeShape shader',
code: shaderCode,
})

const pipeline = device.createComputePipeline({
label: 'compute SDF pipeline',
label: 'computeShape pipeline',
layout: 'auto',
compute: {
module: shaderModule,
},
})

return function drawShape(
return function computeShape(
passEncoder: GPUComputePassEncoder,
curvesDataView: DataView,
distanceScaleFactor: number,
texture: GPUTexture
) {
const curvesBuffer = device.createBuffer({
label: 'drawShape curves buffer',
label: 'computeShape curves buffer',
size: curvesDataView.byteLength,
usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST,
})
device.queue.writeBuffer(curvesBuffer, 0, curvesDataView)
buffersToDestroy.push(curvesBuffer)

const uniformBuffer = device.createBuffer({
label: 'computeShape uniform buffer',
size: 4 /*scale*/ + 12 /*padding*/,
usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,
})
device.queue.writeBuffer(uniformBuffer, 0, new Float32Array([distanceScaleFactor]))
buffersToDestroy.push(uniformBuffer)

passEncoder.setPipeline(pipeline)

const bindGroup = device.createBindGroup({
layout: pipeline.getBindGroupLayout(0),
entries: [
{ binding: 0, resource: texture.createView() },
{ binding: 1, resource: { buffer: curvesBuffer } },
{ binding: 2, resource: { buffer: uniformBuffer } },
],
})

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,13 @@ struct CubicBezier {
p3: vec2f,
};

struct Uniforms {
distance_scale: f32,
};

@group(0) @binding(0) var tex: texture_storage_2d<rgba32float, write>;
@group(0) @binding(1) var<storage, read> curves: array<vec2f>;
@group(0) @binding(2) var<uniform> u: Uniforms;

@compute @workgroup_size(1) fn cs(
@builtin(global_invocation_id) id : vec3u
Expand All @@ -18,7 +23,7 @@ struct CubicBezier {
let shape_info = evaluate_shape(pos);

textureStore(tex, id.xy, vec4f(
shape_info.signed_distance,
shape_info.signed_distance * u.distance_scale,
shape_info.t,
shape_info.angle,
1.0
Expand Down
6 changes: 3 additions & 3 deletions src/WebGPU/programs/initPrograms.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import getPickTriangle from './pickTriangle/getProgram'
import getDrawMSDF from './drawMSDF/getProgram'
import getDrawShape from './drawShape/getProgram'
import getPickShape from './pickShape/getProgram'
import getComputeSDF from './computeSDF/getProgram'
import getComputeShape from './computeShape/getProgram'

export let drawTriangle: ReturnType<typeof getDrawTriangle>
export let drawBezier: ReturnType<typeof getDrawBezier>
Expand All @@ -24,7 +24,7 @@ export let pickTriangle: ReturnType<typeof getPickTriangle>
export let drawMSDF: ReturnType<typeof getDrawMSDF>
export let drawShape: ReturnType<typeof getDrawShape>
export let pickShape: ReturnType<typeof getPickShape>
export let computeSDF: ReturnType<typeof getComputeSDF>
export let computeShape: ReturnType<typeof getComputeShape>

export let canvasMatrixBuffer: GPUBuffer
export let pickCanvasMatrixBuffer: GPUBuffer
Expand Down Expand Up @@ -56,7 +56,7 @@ export default function initPrograms(device: GPUDevice, presentationFormat: GPUT
drawMSDF = getDrawMSDF(device, presentationFormat, canvasMatrixBuffer)
drawShape = getDrawShape(device, presentationFormat, canvasMatrixBuffer, buffersToDestroy)
pickShape = getPickShape(device, pickCanvasMatrixBuffer, buffersToDestroy)
computeSDF = getComputeSDF(device, buffersToDestroy)
computeShape = getComputeShape(device, buffersToDestroy)

return function cleanup() {
buffersToDestroy.forEach((buffer) => buffer.destroy())
Expand Down
7 changes: 6 additions & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,12 @@ export default async function initCreator(
const projectWidth = canvas.clientWidth / 2
const projectHeight = canvas.clientHeight / 2

Logic.initState(projectWidth, projectHeight, device.limits.maxTextureDimension2D)
Logic.initState(
projectWidth,
projectHeight,
device.limits.maxTextureDimension2D,
device.limits.maxBufferSize
)
// rotation doesnt work
const context = canvas.getContext('webgpu')
if (!context) throw Error('WebGPU from canvas needs to be always provided')
Expand Down
30 changes: 30 additions & 0 deletions src/logic/get_sdf_texture_size.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
const PointUV = @import("types.zig").PointUV;
const TextureSize = @import("types.zig").TextureSize;
const shared = @import("shared.zig");

pub fn get_sdf_texture_size(bounds: [4]PointUV) TextureSize {
var width = bounds[0].distance(bounds[1]);
var height = bounds[0].distance(bounds[3]);

if (width > shared.texture_max_size) {
const ratio = shared.texture_max_size / width;
width = shared.texture_max_size;
height *= ratio;
}

if (height > shared.texture_max_size) {
const ratio = shared.texture_max_size / height;
height = shared.texture_max_size;
width *= ratio;
}

const sdf_texture_size = width * height * 16;
if (sdf_texture_size > shared.max_buffer_size) {
const max_pixels = shared.max_buffer_size / 16.0;
const ratio = @sqrt(max_pixels / (width * height));
width *= ratio;
height *= ratio;
}

return TextureSize{ .w = @intFromFloat(width), .h = @intFromFloat(height) };
}
10 changes: 8 additions & 2 deletions src/logic/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,12 @@ type PointerDataView = {
}

declare module '*.zig' {
export const initState: (width: number, height: number, max_texture_size: number) => void
export const initState: (
width: number,
height: number,
max_texture_size: number,
max_buffer_size: number
) => void
export const addImage: (maybe_asset_id: number, points: PointUV[], texture_id: number) => void
export const addShape: (
maybe_asset_id: number,
Expand Down Expand Up @@ -91,6 +96,7 @@ declare module '*.zig' {
curves_data: ArrayPointerDataView,
width: number,
height: number,
distance_scale: number,
texture_id: number
) => void
draw_shape: (
Expand All @@ -109,7 +115,7 @@ declare module '*.zig' {
export const connectCreateSdfTexture: (cb: () => number) => void
export const connectCacheCallbacks: (
create_cache_texture: () => number,
start_cache: (texture_dd: number, box: BoundingBox, width: number, height: number) => void,
start_cache: (texture_id: number, box: BoundingBox, width: number, height: number) => void,
end_cache: VoidFunction
) => void

Expand Down
75 changes: 40 additions & 35 deletions src/logic/index.zig
Original file line number Diff line number Diff line change
@@ -1,20 +1,22 @@
const std = @import("std");
const types = @import("./types.zig");
const images = @import("./images.zig");
const types = @import("types.zig");
const images = @import("images.zig");
const Line = @import("line.zig");
const Triangle = @import("triangle.zig");
const TransformUI = @import("./transform_ui.zig");
const TransformUI = @import("transform_ui.zig");
const zigar = @import("zigar");
const Msdf = @import("./msdf.zig");
const Msdf = @import("msdf.zig");
const shapes = @import("./shapes/shapes.zig");
const squares = @import("squares.zig");
const bounding_box = @import("shapes/bounding_box.zig");
const shared = @import("./shared.zig");
const shared = @import("shared.zig");
const get_sdf_texture_size = @import("get_sdf_texture_size.zig").get_sdf_texture_size;
const Utils = @import("utils.zig");

const WebGpuPrograms = struct {
draw_texture: *const fn (images.DrawVertex, u32) void,
draw_triangle: *const fn ([]const Triangle.DrawInstance) void,
compute_shape: *const fn ([]const types.Point, f32, f32, u32) void,
compute_shape: *const fn ([]const types.Point, u32, u32, f32, u32) void,
draw_shape: *const fn ([]const types.PointUV, shapes.Uniform, u32) void,
draw_msdf: *const fn ([]const Msdf.DrawInstance, u32) void,
pick_texture: *const fn ([]const images.PickVertex, u32) void,
Expand Down Expand Up @@ -113,8 +115,9 @@ var state = State{
.last_pointer_coords = types.Point{ .x = 0.0, .y = 0.0 },
};

pub fn initState(width: f32, height: f32, texture_max_size: f32) void {
_ = texture_max_size; // autofix
pub fn initState(width: f32, height: f32, texture_max_size: f32, max_buffer_size: f32) void {
shared.texture_max_size = texture_max_size;
shared.max_buffer_size = max_buffer_size;
state.width = width;
state.height = height;
state.assets = std.AutoArrayHashMap(u32, Asset).init(std.heap.page_allocator);
Expand All @@ -125,24 +128,16 @@ pub fn updateRenderScale(scale: f32) !void {
shared.render_scale = scale;

var iterator = state.assets.iterator();

var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
defer arena.deinit();
const allocator = arena.allocator();
_ = allocator; // autofix

while (iterator.next()) |asset| {
switch (asset.value_ptr.*) {
.img => {},
.shape => |*shape| {
_ = shape; // autofix
// if (shape.cache.valid) {
// if it's valid, then lets update, if it's invalid, then is gonna be updated anyway(with correct fresh data)
// if (shape.updateTextureSize()) {
// std.debug.print("texture size has changed, updating shape cache\n", .{});
// try shape.drawTextureCache(allocator);
// }
// }
const bounds = shape.getBoundsWithPadding(1 / shared.render_scale);
const new_size = get_sdf_texture_size(bounds);

if (new_size.w > shape.sdf_size.w or new_size.h > shape.sdf_size.h) {
shape.outdated_sdf = true;
}
},
}
}
Expand Down Expand Up @@ -279,7 +274,6 @@ fn updateSelectedAsset(id: u32) !void {
try commitChanges();

state.selected_asset_id = id;
shapes.resetState();
on_asset_select_cb(id);
}

Expand Down Expand Up @@ -330,14 +324,16 @@ pub fn onPointerUp() !void {
}
} else if (state.tool == Tool.DrawShape) {
try checkAssetsUpdate(true);
shapes.onReleasePointer();
if (getSelectedShape()) |shape| {
shape.onReleasePointer();
}
}
}

pub fn onPointerMove(x: f32, y: f32) !void {
if (state.tool == Tool.DrawShape) {
if (getSelectedShape()) |shape| {
try shape.updatePointPreview(x, y);
try shape.updatePointPreview(types.Point{ .x = x, .y = y });
}
return;
}
Expand Down Expand Up @@ -394,7 +390,7 @@ fn updateShapeCache(shape: *shapes.Shape) !void {
pub fn commitChanges() !void {
if (state.tool == Tool.DrawShape) {
if (getSelectedShape()) |shape| {
try updateShapeCache(shape);
shape.update_preview_point(null);
}

shapes.resetState();
Expand Down Expand Up @@ -527,14 +523,26 @@ pub fn calculateShapesSDF() !void {
switch (asset.value_ptr.*) {
.img => {},
.shape => |*shape| {
const option_points = try shape.getDrawVertexData(allocator, shape.id == state.selected_asset_id);

if (!shape.outdated_sdf) {
continue;
}
const option_points = try shape.getNewSdfPoint(allocator);
if (option_points) |points| {
const bounds = shape.getBoundsWithPadding();
const bounds = shape.getBoundsWithPadding(1 / shared.render_scale);
const init_width = bounds[0].distance(bounds[1]);
shape.sdf_size = get_sdf_texture_size(bounds);
const scale = @as(f32, @floatFromInt(shape.sdf_size.w)) / init_width;

for (points) |*point| {
point.x *= scale;
point.y *= scale;
}

web_gpu_programs.compute_shape(
points,
bounds[0].distance(bounds[1]),
bounds[0].distance(bounds[3]),
shape.sdf_size.w,
shape.sdf_size.h,
1 / scale,
shape.texture_id,
);
}
Expand Down Expand Up @@ -578,10 +586,7 @@ pub fn renderDraw() !void {

if (state.tool == Tool.DrawShape) {
if (getSelectedShape()) |shape| {
const vertex_data = try shape.getSkeletonDrawVertexData(
allocator,
shape.id == state.selected_asset_id,
);
const vertex_data = try shape.getSkeletonDrawVertexData(allocator);
web_gpu_programs.draw_triangle(vertex_data);
web_gpu_programs.draw_shape(&shape.getDrawBounds(), shapes.getSkeletonUniform(), shape.texture_id);
}
Expand Down
2 changes: 1 addition & 1 deletion src/logic/shapes/paths.zig
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ pub const Path = struct {
point.y - size / 2.0,
size,
size,
SKELETON_POINT_SIZE / 2.0,
size / 2.0,
[_]u8{ 0, 0, 255, 255 },
);
}
Expand Down
Loading