HelloWorld!
This commit is contained in:
commit
f2f4830d57
26 changed files with 9404 additions and 0 deletions
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
.zig-cache/
|
||||||
|
zig-pkg/
|
||||||
69
build.zig
Normal file
69
build.zig
Normal file
|
|
@ -0,0 +1,69 @@
|
||||||
|
const std = @import("std");
|
||||||
|
|
||||||
|
pub fn build(b: *std.Build) void {
|
||||||
|
const target = b.standardTargetOptions(.{});
|
||||||
|
const optimize = b.standardOptimizeOption(.{});
|
||||||
|
|
||||||
|
const mod = b.addModule("platform", .{
|
||||||
|
.root_source_file = b.path("src/renderer.zig"),
|
||||||
|
|
||||||
|
.link_libc = true,
|
||||||
|
.link_libcpp = true,
|
||||||
|
|
||||||
|
.target = target,
|
||||||
|
.optimize = optimize,
|
||||||
|
});
|
||||||
|
|
||||||
|
const mod_tests = b.addTest(.{
|
||||||
|
.root_module = mod,
|
||||||
|
});
|
||||||
|
|
||||||
|
const run_mod_tests = b.addRunArtifact(mod_tests);
|
||||||
|
|
||||||
|
const test_step = b.step("test", "Run tests");
|
||||||
|
test_step.dependOn(&run_mod_tests.step);
|
||||||
|
|
||||||
|
//
|
||||||
|
// DEPENDENCIES
|
||||||
|
//
|
||||||
|
|
||||||
|
const app = b.dependency("app", .{
|
||||||
|
.target = target,
|
||||||
|
.optimize = optimize,
|
||||||
|
});
|
||||||
|
mod.addImport("app", app.module("app"));
|
||||||
|
|
||||||
|
const platform = b.dependency("platform", .{
|
||||||
|
.target = target,
|
||||||
|
.optimize = optimize,
|
||||||
|
});
|
||||||
|
mod.addImport("platform_plugin", platform.module("platform"));
|
||||||
|
|
||||||
|
//
|
||||||
|
// SYSTEM DEPENDENCIES
|
||||||
|
//
|
||||||
|
|
||||||
|
const sdl = b.addTranslateC(.{
|
||||||
|
.target = target,
|
||||||
|
.optimize = optimize,
|
||||||
|
.root_source_file = b.path("./src/vendors/sdl3/sdl.h"),
|
||||||
|
});
|
||||||
|
mod.addImport("sdl", sdl.createModule());
|
||||||
|
mod.linkSystemLibrary("SDL3", .{});
|
||||||
|
|
||||||
|
const sdl3_glue = b.addTranslateC(.{
|
||||||
|
.target = target,
|
||||||
|
.optimize = optimize,
|
||||||
|
.root_source_file = b.path("./src/vendors/sdl3_glue/sdl3webgpu.h"),
|
||||||
|
});
|
||||||
|
mod.addImport("sdl_glue", sdl3_glue.createModule());
|
||||||
|
mod.addCSourceFile(.{ .file = b.path("./src/vendors/sdl3_glue/sdl3webgpu.c") });
|
||||||
|
|
||||||
|
const wgpu = b.addTranslateC(.{
|
||||||
|
.target = target,
|
||||||
|
.optimize = optimize,
|
||||||
|
.root_source_file = b.path("./src/vendors/wgpu/wgpu.h"),
|
||||||
|
});
|
||||||
|
mod.addImport("wgpu", wgpu.createModule());
|
||||||
|
mod.linkSystemLibrary("wgpu_native", .{});
|
||||||
|
}
|
||||||
15
build.zig.zon
Normal file
15
build.zig.zon
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
.{
|
||||||
|
.name = .renderer,
|
||||||
|
.version = "0.0.1",
|
||||||
|
.dependencies = .{
|
||||||
|
.app = .{
|
||||||
|
.path = "../../app",
|
||||||
|
},
|
||||||
|
.platform = .{
|
||||||
|
.path = "../platform/",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
.minimum_zig_version = "0.16.0",
|
||||||
|
.paths = .{""},
|
||||||
|
.fingerprint = 0xf199a19cb1dc8f03,
|
||||||
|
}
|
||||||
0
src/component/camera.zig
Normal file
0
src/component/camera.zig
Normal file
1
src/component/root.zig
Normal file
1
src/component/root.zig
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
pub const Camera = @import("camera.zig");
|
||||||
40
src/plugin.zig
Normal file
40
src/plugin.zig
Normal file
|
|
@ -0,0 +1,40 @@
|
||||||
|
const App = @import("app");
|
||||||
|
const system = @import("system/root.zig");
|
||||||
|
const resource = @import("resource/root.zig");
|
||||||
|
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
pub const plugin: App.plugin.Plugin = .{
|
||||||
|
.name = "Renderer",
|
||||||
|
.description = "WebGPU Renderer",
|
||||||
|
.build = build,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
fn build(
|
||||||
|
_: *App.plugin.Plugin,
|
||||||
|
ctx: App.plugin.Context,
|
||||||
|
) !void {
|
||||||
|
// --- RESOURCES ---
|
||||||
|
try ctx.app.resources.set(resource.Instance{});
|
||||||
|
try ctx.app.resources.set(resource.Device{});
|
||||||
|
try ctx.app.resources.set(resource.window{});
|
||||||
|
|
||||||
|
// --- INIT ---
|
||||||
|
try ctx.app.schedules.addMany(App.stage.Init, &.{
|
||||||
|
system.instance.init,
|
||||||
|
system.window.init,
|
||||||
|
system.device.init,
|
||||||
|
});
|
||||||
|
|
||||||
|
// --- DEINIT ---
|
||||||
|
try ctx.app.schedules.addMany(App.stage.Deinit, &.{
|
||||||
|
system.device.deinit,
|
||||||
|
system.window.deinit,
|
||||||
|
system.instance.deinit,
|
||||||
|
});
|
||||||
|
|
||||||
|
// --- INPUT ---
|
||||||
|
try ctx.app.schedules.addMany(App.stage.Inputs, &.{});
|
||||||
|
}
|
||||||
45
src/renderer.zig
Normal file
45
src/renderer.zig
Normal file
|
|
@ -0,0 +1,45 @@
|
||||||
|
const std = @import("std");
|
||||||
|
const App = @import("app");
|
||||||
|
const Platform = @import("platform_plugin");
|
||||||
|
|
||||||
|
pub const plugin = @import("plugin.zig").plugin;
|
||||||
|
pub const system = @import("system/root.zig");
|
||||||
|
pub const resource = @import("resource/root.zig");
|
||||||
|
|
||||||
|
test "Main" {
|
||||||
|
// --- APP ---
|
||||||
|
var app: App = .init(std.testing.allocator);
|
||||||
|
defer app.deinit();
|
||||||
|
|
||||||
|
// --- ON ERROR ---
|
||||||
|
errdefer {
|
||||||
|
app.schedules.run(App.stage.Deinit, .{ .app = &app }) catch unreachable;
|
||||||
|
app.deinit();
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- ADD PLUGINS ---
|
||||||
|
try app.plugins.addMany(&.{
|
||||||
|
plugin,
|
||||||
|
Platform.plugin,
|
||||||
|
});
|
||||||
|
|
||||||
|
// --- BUILD ---
|
||||||
|
try app.plugins.build(.{
|
||||||
|
.app = &app,
|
||||||
|
});
|
||||||
|
|
||||||
|
// --- LIFETIME ---
|
||||||
|
try app.schedules.run(App.stage.Init, .{ .app = &app });
|
||||||
|
defer app.schedules.run(App.stage.Deinit, .{ .app = &app }) catch unreachable;
|
||||||
|
|
||||||
|
// --- MAIN LOOP ---
|
||||||
|
// while (!app.events.has(Platform.event.AppExit)) {
|
||||||
|
// try app.schedules.runMany(&.{
|
||||||
|
// App.stage.Inputs,
|
||||||
|
// App.stage.Update,
|
||||||
|
// App.stage.Draw,
|
||||||
|
// }, .{
|
||||||
|
// .app = &app,
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
}
|
||||||
4
src/resource/device.zig
Normal file
4
src/resource/device.zig
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
const wgpu = @import("wgpu");
|
||||||
|
|
||||||
|
raw: ?*wgpu.WGPUDeviceImpl = null,
|
||||||
|
queue: ?*wgpu.WGPUQueueImpl = null,
|
||||||
7
src/resource/instance.zig
Normal file
7
src/resource/instance.zig
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
const wgpu = @import("wgpu");
|
||||||
|
|
||||||
|
//
|
||||||
|
// FIELDS
|
||||||
|
//
|
||||||
|
|
||||||
|
raw: ?*wgpu.WGPUInstanceImpl = null,
|
||||||
4
src/resource/root.zig
Normal file
4
src/resource/root.zig
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
// --- CORE ---
|
||||||
|
pub const Instance = @import("instance.zig");
|
||||||
|
pub const Device = @import("device.zig");
|
||||||
|
pub const window = @import("window.zig");
|
||||||
13
src/resource/window.zig
Normal file
13
src/resource/window.zig
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
const sdl = @import("sdl");
|
||||||
|
const sdl_glue = @import("sdl_glue");
|
||||||
|
|
||||||
|
//
|
||||||
|
// FIELDS
|
||||||
|
//
|
||||||
|
|
||||||
|
title: []const u8 = "App",
|
||||||
|
width: u32 = 1280,
|
||||||
|
height: u32 = 720,
|
||||||
|
|
||||||
|
raw: ?*sdl.SDL_Window = null,
|
||||||
|
surface: ?*sdl_glue.WGPUSurfaceImpl = null,
|
||||||
233
src/system/device.zig
Normal file
233
src/system/device.zig
Normal file
|
|
@ -0,0 +1,233 @@
|
||||||
|
const std = @import("std");
|
||||||
|
const App = @import("app");
|
||||||
|
const wgpu = @import("wgpu");
|
||||||
|
const sdl_glue = @import("sdl_glue");
|
||||||
|
|
||||||
|
const Instance = @import("../resource/instance.zig");
|
||||||
|
const Device = @import("../resource/device.zig");
|
||||||
|
const Window = @import("../resource/window.zig");
|
||||||
|
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
const AdapterUserdata = struct {
|
||||||
|
adapter: ?*wgpu.WGPUAdapterImpl = null,
|
||||||
|
ended: bool = false,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
const DeviceUserdata = struct {
|
||||||
|
device: ?*wgpu.WGPUDeviceImpl = null,
|
||||||
|
ended: bool = false,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
pub fn init(ctx: App.scheduler.Context) !void {
|
||||||
|
// --- RESOURCES ---
|
||||||
|
const res = try ctx.app.resources.getMany(struct {
|
||||||
|
instance: *Instance,
|
||||||
|
window: *Window,
|
||||||
|
device: *Device,
|
||||||
|
});
|
||||||
|
|
||||||
|
//
|
||||||
|
// ADAPTER
|
||||||
|
//
|
||||||
|
|
||||||
|
// TODO: Mabe Mabe add other backends n stuff
|
||||||
|
var adapter_userdata: AdapterUserdata = .{};
|
||||||
|
_ = wgpu.wgpuInstanceRequestAdapter(
|
||||||
|
res.instance.raw,
|
||||||
|
&wgpu.WGPURequestAdapterOptions{
|
||||||
|
.backendType = wgpu.WGPUBackendType_Vulkan,
|
||||||
|
},
|
||||||
|
wgpu.WGPURequestAdapterCallbackInfo{
|
||||||
|
.callback = adapterCallback,
|
||||||
|
.userdata1 = &adapter_userdata,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
// --- ADAPTER ---
|
||||||
|
const adapter = if (adapter_userdata.adapter) |v| v else return error.NoAdapter;
|
||||||
|
defer wgpu.wgpuAdapterRelease(adapter);
|
||||||
|
|
||||||
|
// --- ON ERROR ---
|
||||||
|
errdefer {
|
||||||
|
wgpu.wgpuAdapterRelease(adapter);
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- GET LIMITS ---
|
||||||
|
var limits: wgpu.WGPULimits = .{};
|
||||||
|
switch (wgpu.wgpuAdapterGetLimits(adapter, &limits)) {
|
||||||
|
wgpu.WGPUStatus_Error => return error.FailedToGetAdapterLimits,
|
||||||
|
else => {},
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- GET INFO ---
|
||||||
|
var info: wgpu.WGPUAdapterInfo = .{};
|
||||||
|
switch (wgpu.wgpuAdapterGetInfo(adapter, &info)) {
|
||||||
|
wgpu.WGPUStatus_Error => return error.FailedToGetAdapterInfo,
|
||||||
|
else => {},
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- DEBUG LIMITS ---
|
||||||
|
std.debug.print("Adapter Limits:\n", .{});
|
||||||
|
std.debug.print("| Texture Dimentions: ({})1D, ({})2D, ({})3D, ({})Array Layers\n", .{
|
||||||
|
limits.maxTextureDimension1D,
|
||||||
|
limits.maxTextureDimension2D,
|
||||||
|
limits.maxTextureDimension3D,
|
||||||
|
limits.maxTextureArrayLayers,
|
||||||
|
});
|
||||||
|
|
||||||
|
// --- DEBUG INFO ---
|
||||||
|
std.debug.print("Adapter Info:\n", .{});
|
||||||
|
std.debug.print(
|
||||||
|
\\| Device: {s}
|
||||||
|
\\| Backend: {s}
|
||||||
|
\\
|
||||||
|
, .{
|
||||||
|
info.device.data,
|
||||||
|
switch (info.backendType) {
|
||||||
|
wgpu.WGPUBackendType_Vulkan => "Vulkan",
|
||||||
|
wgpu.WGPUBackendType_OpenGL => "OpenGL",
|
||||||
|
wgpu.WGPUBackendType_D3D11 => "D3D11",
|
||||||
|
wgpu.WGPUBackendType_D3D12 => "D3D12",
|
||||||
|
else => "idk", // TODO: idk 🥀
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
//
|
||||||
|
// DEVICE
|
||||||
|
//
|
||||||
|
|
||||||
|
// --- REQUEST DEVICE ---
|
||||||
|
var device_userdata: DeviceUserdata = .{};
|
||||||
|
_ = wgpu.wgpuAdapterRequestDevice(
|
||||||
|
adapter,
|
||||||
|
&wgpu.WGPUDeviceDescriptor{
|
||||||
|
.label = .{ .data = "MainDevice", .length = wgpu.WGPU_STRLEN },
|
||||||
|
.uncapturedErrorCallbackInfo = .{
|
||||||
|
.callback = uncapturedErrorCallback,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
.{
|
||||||
|
.callback = deviceCallback,
|
||||||
|
.userdata1 = &device_userdata,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
res.device.raw = device_userdata.device;
|
||||||
|
|
||||||
|
// --- ON ERROR ---
|
||||||
|
errdefer {
|
||||||
|
wgpu.wgpuDeviceRelease(res.device.raw);
|
||||||
|
res.device.raw = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- GET QUEUE ---
|
||||||
|
res.device.queue = wgpu.wgpuDeviceGetQueue(
|
||||||
|
res.device.raw,
|
||||||
|
) orelse return error.FailedToGetDeviceQueue;
|
||||||
|
|
||||||
|
var caps: sdl_glue.WGPUSurfaceCapabilities = .{};
|
||||||
|
_ = sdl_glue.wgpuSurfaceGetCapabilities(res.window.surface, @ptrCast(adapter), &caps); // TODO: Handle possible error
|
||||||
|
defer sdl_glue.wgpuSurfaceCapabilitiesFreeMembers(caps);
|
||||||
|
|
||||||
|
// --- CONFIGURE SURFACE ---
|
||||||
|
sdl_glue.wgpuSurfaceConfigure(
|
||||||
|
res.window.surface,
|
||||||
|
&sdl_glue.WGPUSurfaceConfiguration{
|
||||||
|
.device = @ptrCast(res.device.raw),
|
||||||
|
.format = caps.formats[0],
|
||||||
|
.width = res.window.width,
|
||||||
|
.height = res.window.height,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
pub fn deinit(ctx: App.scheduler.Context) !void {
|
||||||
|
// --- RESOURCES ---
|
||||||
|
const res = try ctx.app.resources.getMany(struct {
|
||||||
|
instance: *Instance,
|
||||||
|
device: *Device,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (res.device.queue) |queue| {
|
||||||
|
wgpu.wgpuQueueRelease(queue);
|
||||||
|
res.device.queue = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (res.device.raw) |raw| {
|
||||||
|
wgpu.wgpuDeviceRelease(raw);
|
||||||
|
res.device.raw = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
fn uncapturedErrorCallback(
|
||||||
|
_: [*c]const wgpu.WGPUDevice,
|
||||||
|
err_type: wgpu.WGPUErrorType,
|
||||||
|
message: wgpu.WGPUStringView,
|
||||||
|
_: ?*anyopaque,
|
||||||
|
_: ?*anyopaque,
|
||||||
|
) callconv(.c) void {
|
||||||
|
std.debug.print("[{s}] {s}\n", .{
|
||||||
|
switch (err_type) {
|
||||||
|
wgpu.WGPUErrorType_Validation => "\x1b[33VALIDATION\x1b[0m",
|
||||||
|
wgpu.WGPUErrorType_OutOfMemory => "\x1b[31OUT_OF_MEMORY\x1b[0m",
|
||||||
|
else => "IDK",
|
||||||
|
},
|
||||||
|
message.data,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
fn adapterCallback(
|
||||||
|
status: wgpu.WGPURequestAdapterStatus,
|
||||||
|
adapter: wgpu.WGPUAdapter,
|
||||||
|
message: wgpu.WGPUStringView,
|
||||||
|
raw_userdata: ?*anyopaque,
|
||||||
|
_: ?*anyopaque,
|
||||||
|
) callconv(.c) void {
|
||||||
|
// --- USERDATA ---
|
||||||
|
const userdata: *AdapterUserdata = @ptrCast(@alignCast(raw_userdata));
|
||||||
|
defer userdata.ended = true;
|
||||||
|
|
||||||
|
// --- STATUS ---
|
||||||
|
switch (status) {
|
||||||
|
wgpu.WGPURequestAdapterStatus_Success => userdata.adapter = adapter,
|
||||||
|
else => {
|
||||||
|
std.debug.print("Failed to get WebGPU adapter: {s}\n", .{
|
||||||
|
message.data,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
fn deviceCallback(
|
||||||
|
status: wgpu.WGPURequestDeviceStatus,
|
||||||
|
device: wgpu.WGPUDevice,
|
||||||
|
message: wgpu.WGPUStringView,
|
||||||
|
raw_userdata: ?*anyopaque,
|
||||||
|
_: ?*anyopaque,
|
||||||
|
) callconv(.c) void {
|
||||||
|
// --- USERDATA ---
|
||||||
|
const userdata: *DeviceUserdata = @ptrCast(@alignCast(raw_userdata));
|
||||||
|
defer userdata.ended = true;
|
||||||
|
|
||||||
|
// --- STATUS ---
|
||||||
|
switch (status) {
|
||||||
|
wgpu.WGPURequestDeviceStatus_Success => userdata.device = device,
|
||||||
|
else => {
|
||||||
|
std.debug.print("Failed to get WebGPU adapter: {s}\n", .{
|
||||||
|
message.data,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
29
src/system/instance.zig
Normal file
29
src/system/instance.zig
Normal file
|
|
@ -0,0 +1,29 @@
|
||||||
|
const std = @import("std");
|
||||||
|
const App = @import("app");
|
||||||
|
const wgpu = @import("wgpu");
|
||||||
|
const Instance = @import("../resource/instance.zig");
|
||||||
|
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
pub fn init(ctx: App.scheduler.Context) !void {
|
||||||
|
const instance = ctx.app.resources.getPtr(
|
||||||
|
Instance,
|
||||||
|
) orelse return;
|
||||||
|
|
||||||
|
instance.raw = wgpu.wgpuCreateInstance(
|
||||||
|
&wgpu.WGPUInstanceDescriptor{},
|
||||||
|
) orelse return error.WGPUInstance;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
pub fn deinit(ctx: App.scheduler.Context) !void {
|
||||||
|
const instance = ctx.app.resources.getPtr(
|
||||||
|
Instance,
|
||||||
|
) orelse return;
|
||||||
|
|
||||||
|
if (instance.raw) |raw| {
|
||||||
|
wgpu.wgpuInstanceRelease(raw);
|
||||||
|
instance.raw = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
4
src/system/root.zig
Normal file
4
src/system/root.zig
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
// --- CORE ---
|
||||||
|
pub const instance = @import("instance.zig");
|
||||||
|
pub const device = @import("device.zig");
|
||||||
|
pub const window = @import("window.zig");
|
||||||
50
src/system/window.zig
Normal file
50
src/system/window.zig
Normal file
|
|
@ -0,0 +1,50 @@
|
||||||
|
const App = @import("app");
|
||||||
|
const sdl = @import("sdl");
|
||||||
|
const sdl_glue = @import("sdl_glue");
|
||||||
|
|
||||||
|
const Instance = @import("../resource/instance.zig");
|
||||||
|
const Device = @import("../resource/device.zig");
|
||||||
|
const Window = @import("../resource/window.zig");
|
||||||
|
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
pub fn init(ctx: App.scheduler.Context) !void {
|
||||||
|
// --- WINDOW ---
|
||||||
|
const res = try ctx.app.resources.getMany(struct {
|
||||||
|
instance: *Instance,
|
||||||
|
window: *Window,
|
||||||
|
});
|
||||||
|
|
||||||
|
// --- HANDLE ---
|
||||||
|
res.window.raw = sdl.SDL_CreateWindow(
|
||||||
|
res.window.title.ptr,
|
||||||
|
@intCast(res.window.width),
|
||||||
|
@intCast(res.window.height),
|
||||||
|
sdl.SDL_WINDOW_RESIZABLE,
|
||||||
|
) orelse return error.CreateWindow;
|
||||||
|
|
||||||
|
// --- SURFACE ---
|
||||||
|
res.window.surface = sdl_glue.SDL_GetWGPUSurface(
|
||||||
|
@ptrCast(res.instance.raw),
|
||||||
|
@ptrCast(res.window.raw),
|
||||||
|
) orelse return error.GetSurface;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
pub fn deinit(ctx: App.scheduler.Context) !void {
|
||||||
|
const win = ctx.app.resources.getPtr(
|
||||||
|
Window,
|
||||||
|
) orelse return;
|
||||||
|
|
||||||
|
if (win.surface) |surface| {
|
||||||
|
sdl_glue.wgpuSurfaceUnconfigure(surface);
|
||||||
|
sdl_glue.wgpuSurfaceRelease(surface);
|
||||||
|
win.surface = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (win.raw) |raw| {
|
||||||
|
sdl.SDL_DestroyWindow(raw);
|
||||||
|
win.raw = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
0
src/template/asset.zig
Normal file
0
src/template/asset.zig
Normal file
0
src/template/camera_pass.zig
Normal file
0
src/template/camera_pass.zig
Normal file
0
src/template/draw_cmd.zig
Normal file
0
src/template/draw_cmd.zig
Normal file
286
src/template/registry.zig
Normal file
286
src/template/registry.zig
Normal file
|
|
@ -0,0 +1,286 @@
|
||||||
|
const std = @import("std");
|
||||||
|
const App = @import("app");
|
||||||
|
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
pub fn Registry(
|
||||||
|
comptime K: type,
|
||||||
|
comptime V: type,
|
||||||
|
) type {
|
||||||
|
return struct {
|
||||||
|
const Self = @This();
|
||||||
|
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
pub const Metadata = struct {
|
||||||
|
source: ?[]const u8 = null,
|
||||||
|
reload: ?*const fn (*V, App.scheduler.Context) anyerror!void = null,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
pub const Entry = struct {
|
||||||
|
key: K,
|
||||||
|
value: V,
|
||||||
|
};
|
||||||
|
|
||||||
|
//
|
||||||
|
// FIELDS
|
||||||
|
//
|
||||||
|
|
||||||
|
meta: std.ArrayList(Metadata),
|
||||||
|
lookup: std.AutoHashMap(K, usize),
|
||||||
|
entries: std.ArrayList(Entry),
|
||||||
|
alloc: std.mem.Allocator,
|
||||||
|
|
||||||
|
//
|
||||||
|
// LIFECYCLE
|
||||||
|
//
|
||||||
|
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
pub fn init(alloc: std.mem.Allocator) Self {
|
||||||
|
return .{
|
||||||
|
.meta = .empty,
|
||||||
|
.lookup = .init(alloc),
|
||||||
|
.entries = .empty,
|
||||||
|
.alloc = alloc,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
pub fn deinit(self: *Self) void {
|
||||||
|
self.meta.deinit(self.alloc);
|
||||||
|
self.lookup.deinit();
|
||||||
|
self.entries.deinit(self.alloc);
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// INSERTION
|
||||||
|
//
|
||||||
|
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
pub fn put(
|
||||||
|
self: *Self,
|
||||||
|
key: K,
|
||||||
|
value: V,
|
||||||
|
) !void {
|
||||||
|
if (self.lookup.contains(key)) return error.Duplicate;
|
||||||
|
try self.putNoDup(key, value, .{});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
/// Insert or replace
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
pub fn upsert(
|
||||||
|
self: *Self,
|
||||||
|
key: K,
|
||||||
|
value: V,
|
||||||
|
) !?V {
|
||||||
|
if (self.lookup.contains(key)) {
|
||||||
|
const idx = self.lookup.get(key).?;
|
||||||
|
const old = self.entries.items[idx].value;
|
||||||
|
self.entries.items[idx].value = value;
|
||||||
|
return old;
|
||||||
|
}
|
||||||
|
try self.putNoDup(key, value, .{});
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
/// Insert with metadata
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
pub fn putWith(
|
||||||
|
self: *Self,
|
||||||
|
key: K,
|
||||||
|
value: V,
|
||||||
|
metadata: Metadata,
|
||||||
|
) !void {
|
||||||
|
if (self.lookup.contains(key)) return error.Duplicate;
|
||||||
|
try self.putNoDup(key, value, metadata);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
fn putNoDup(
|
||||||
|
self: *Self,
|
||||||
|
key: K,
|
||||||
|
value: V,
|
||||||
|
metadata: Metadata,
|
||||||
|
) !void {
|
||||||
|
try self.entries.append(self.alloc, .{ .key = key, .value = value });
|
||||||
|
errdefer _ = self.entries.swapRemove(self.entries.items.len - 1);
|
||||||
|
|
||||||
|
try self.meta.append(self.alloc, metadata);
|
||||||
|
errdefer _ = self.meta.swapRemove(self.meta.items.len - 1);
|
||||||
|
|
||||||
|
try self.lookup.put(key, self.entries.items.len - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// REMOVAL
|
||||||
|
//
|
||||||
|
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
pub fn remove(self: *Self, key: K) bool {
|
||||||
|
const idx = self.lookup.get(key) orelse return false;
|
||||||
|
self.removeIndex(idx);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
pub fn removeLast(self: *Self) bool {
|
||||||
|
if (self.entries.items.len == 0) return false;
|
||||||
|
const last = self.entries.items.len - 1;
|
||||||
|
_ = self.lookup.remove(self.entries.items[last].key);
|
||||||
|
self.entries.swapRemove(last);
|
||||||
|
self.meta.swapRemove(last);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
fn removeIndex(self: *Self, idx: usize) void {
|
||||||
|
const last = self.entries.items.len - 1;
|
||||||
|
|
||||||
|
// --- UPDATE LOOKUP ---
|
||||||
|
if (idx != last) {
|
||||||
|
self.lookup.put(self.entries.items[last].key, idx) catch {};
|
||||||
|
}
|
||||||
|
|
||||||
|
_ = self.meta.swapRemove(idx);
|
||||||
|
_ = self.lookup.remove(self.entries.items[idx].key);
|
||||||
|
_ = self.entries.swapRemove(idx);
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// LOOKUP
|
||||||
|
//
|
||||||
|
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
pub fn contains(self: Self, key: K) bool {
|
||||||
|
return self.lookup.contains(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
pub fn get(self: Self, key: K) ?*const V {
|
||||||
|
const idx = self.lookup.get(key) orelse return null;
|
||||||
|
return &self.entries.items[idx].value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
pub fn getPtr(self: *Self, key: K) ?*V {
|
||||||
|
const idx = self.lookup.get(key) orelse return null;
|
||||||
|
return &self.entries.items[idx].value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
pub fn getEntry(self: Self, key: K) ?*const Entry {
|
||||||
|
const idx = self.lookup.get(key) orelse return null;
|
||||||
|
return &self.entries.items[idx];
|
||||||
|
}
|
||||||
|
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
pub fn getMetadata(self: Self, key: K) ?*const Metadata {
|
||||||
|
const idx = self.lookup.get(key) orelse return null;
|
||||||
|
return &self.meta.items[idx];
|
||||||
|
}
|
||||||
|
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
pub fn getPtrMetadata(self: *Self, key: K) ?*Metadata {
|
||||||
|
const idx = self.lookup.get(key) orelse return null;
|
||||||
|
return &self.meta.items[idx];
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// ITERATION
|
||||||
|
//
|
||||||
|
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
pub fn count(self: Self) usize {
|
||||||
|
return self.entries.items.len;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
pub fn values(self: Self) []const Entry {
|
||||||
|
return self.entries.items;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
/// Value, Metadata
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
pub fn iterator(self: *Self) Iterator {
|
||||||
|
return .{ .registry = self, .index = 0 };
|
||||||
|
}
|
||||||
|
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
pub const Iterator = struct {
|
||||||
|
registry: *Self,
|
||||||
|
index: usize,
|
||||||
|
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
pub fn next(it: *Iterator) ?struct { value: *V, meta: *Metadata } {
|
||||||
|
if (it.index >= it.registry.entries.items.len) return null;
|
||||||
|
defer it.index += 1;
|
||||||
|
return .{
|
||||||
|
.value = &it.registry.entries.items[it.index].value,
|
||||||
|
.meta = &it.registry.meta.items[it.index],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//
|
||||||
|
// IDK
|
||||||
|
//
|
||||||
|
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
pub fn reloadAll(
|
||||||
|
self: *Self,
|
||||||
|
ctx: App.scheduler.Context,
|
||||||
|
) anyerror!void {
|
||||||
|
var it = self.iterator();
|
||||||
|
while (it.next()) |entry| {
|
||||||
|
if (entry.meta.reload) |reload| try reload(entry.value, ctx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
pub fn deinitReverse(self: *Self) void {
|
||||||
|
while (self.entries.items.len > 0) {
|
||||||
|
_ = self.removeLast();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
pub fn clear(self: *Self) void {
|
||||||
|
self.meta.clearRetainingCapacity();
|
||||||
|
self.lookup.clearRetainingCapacity();
|
||||||
|
self.entries.clearRetainingCapacity();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
/// ----------------------------------------------------
|
||||||
|
pub fn clearAndFree(self: *Self) void {
|
||||||
|
self.meta.clearAndFree();
|
||||||
|
self.lookup.clearAndFree();
|
||||||
|
self.entries.clearAndFree();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
3
src/template/root.zig
Normal file
3
src/template/root.zig
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
pub const Registry = @import("registry.zig").Registry;
|
||||||
|
pub const CameraPass = @import("camera_pass.zig");
|
||||||
|
pub const DrawCMD = @import("draw_cmd.zig");
|
||||||
1
src/vendors/sdl3/sdl.h
vendored
Normal file
1
src/vendors/sdl3/sdl.h
vendored
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
#include <SDL3/SDL.h>
|
||||||
20
src/vendors/sdl3_glue/LICENSE.md
vendored
Normal file
20
src/vendors/sdl3_glue/LICENSE.md
vendored
Normal file
|
|
@ -0,0 +1,20 @@
|
||||||
|
MIT License
|
||||||
|
Copyright (c) 2022-2024 Élie Michel
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
174
src/vendors/sdl3_glue/sdl3webgpu.c
vendored
Normal file
174
src/vendors/sdl3_glue/sdl3webgpu.c
vendored
Normal file
|
|
@ -0,0 +1,174 @@
|
||||||
|
/**
|
||||||
|
* This is an extension of SDL3 for WebGPU, abstracting away the details of
|
||||||
|
* OS-specific operations.
|
||||||
|
*
|
||||||
|
* This file is part of the "Learn WebGPU for C++" book.
|
||||||
|
* https://eliemichel.github.io/LearnWebGPU
|
||||||
|
*
|
||||||
|
* Most of this code comes from the wgpu-native triangle example:
|
||||||
|
* https://github.com/gfx-rs/wgpu-native/blob/master/examples/triangle/main.c
|
||||||
|
*
|
||||||
|
* MIT License
|
||||||
|
* Copyright (c) 2022-2024 Elie Michel and the wgpu-native authors
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "sdl3webgpu.h"
|
||||||
|
|
||||||
|
#include "../wgpu/wgpu.h"
|
||||||
|
|
||||||
|
#if defined(SDL_PLATFORM_MACOS)
|
||||||
|
# include <Cocoa/Cocoa.h>
|
||||||
|
# include <Foundation/Foundation.h>
|
||||||
|
# include <QuartzCore/CAMetalLayer.h>
|
||||||
|
#elif defined(SDL_PLATFORM_IOS)
|
||||||
|
# include <UIKit/UIKit.h>
|
||||||
|
# include <Foundation/Foundation.h>
|
||||||
|
# include <QuartzCore/CAMetalLayer.h>
|
||||||
|
# include <Metal/Metal.h>
|
||||||
|
#elif defined(SDL_PLATFORM_WIN32)
|
||||||
|
# include <windows.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <SDL3/SDL.h>
|
||||||
|
|
||||||
|
WGPUSurface SDL_GetWGPUSurface(WGPUInstance instance, SDL_Window* window) {
|
||||||
|
SDL_PropertiesID props = SDL_GetWindowProperties(window);
|
||||||
|
|
||||||
|
#if defined(SDL_PLATFORM_MACOS)
|
||||||
|
{
|
||||||
|
id metal_layer = NULL;
|
||||||
|
NSWindow *ns_window = (__bridge NSWindow *)SDL_GetPointerProperty(props, SDL_PROP_WINDOW_COCOA_WINDOW_POINTER, NULL);
|
||||||
|
if (!ns_window) return NULL;
|
||||||
|
[ns_window.contentView setWantsLayer : YES];
|
||||||
|
metal_layer = [CAMetalLayer layer];
|
||||||
|
[ns_window.contentView setLayer : metal_layer];
|
||||||
|
|
||||||
|
WGPUSurfaceSourceMetalLayer fromMetalLayer;
|
||||||
|
fromMetalLayer.chain.sType = WGPUSType_SurfaceSourceMetalLayer;
|
||||||
|
fromMetalLayer.chain.next = NULL;
|
||||||
|
fromMetalLayer.layer = metal_layer;
|
||||||
|
|
||||||
|
WGPUSurfaceDescriptor surfaceDescriptor;
|
||||||
|
surfaceDescriptor.nextInChain = &fromMetalLayer.chain;
|
||||||
|
surfaceDescriptor.label = (WGPUStringView){ NULL, WGPU_STRLEN };
|
||||||
|
|
||||||
|
return wgpuInstanceCreateSurface(instance, &surfaceDescriptor);
|
||||||
|
}
|
||||||
|
#elif defined(SDL_PLATFORM_IOS)
|
||||||
|
{
|
||||||
|
UIWindow *ui_window = (__bridge UIWindow *)SDL_GetPointerProperty(props, SDL_PROP_WINDOW_UIKIT_WINDOW_POINTER, NULL);
|
||||||
|
if (!uiwindow) return NULL;
|
||||||
|
|
||||||
|
UIView* ui_view = ui_window.rootViewController.view;
|
||||||
|
CAMetalLayer* metal_layer = [CAMetalLayer new];
|
||||||
|
metal_layer.opaque = true;
|
||||||
|
metal_layer.frame = ui_view.frame;
|
||||||
|
metal_layer.drawableSize = ui_view.frame.size;
|
||||||
|
|
||||||
|
[ui_view.layer addSublayer: metal_layer];
|
||||||
|
|
||||||
|
WGPUSurfaceSourceMetalLayer fromMetalLayer;
|
||||||
|
fromMetalLayer.chain.sType = WGPUSType_SurfaceSourceMetalLayer;
|
||||||
|
fromMetalLayer.chain.next = NULL;
|
||||||
|
fromMetalLayer.layer = metal_layer;
|
||||||
|
|
||||||
|
WGPUSurfaceDescriptor surfaceDescriptor;
|
||||||
|
surfaceDescriptor.nextInChain = &fromMetalLayer.chain;
|
||||||
|
surfaceDescriptor.label = (WGPUStringView){ NULL, WGPU_STRLEN };
|
||||||
|
|
||||||
|
return wgpuInstanceCreateSurface(instance, &surfaceDescriptor);
|
||||||
|
}
|
||||||
|
#elif defined(SDL_PLATFORM_LINUX)
|
||||||
|
if (SDL_strcmp(SDL_GetCurrentVideoDriver(), "x11") == 0) {
|
||||||
|
void *x11_display = SDL_GetPointerProperty(props, SDL_PROP_WINDOW_X11_DISPLAY_POINTER, NULL);
|
||||||
|
uint64_t x11_window = SDL_GetNumberProperty(props, SDL_PROP_WINDOW_X11_WINDOW_NUMBER, 0);
|
||||||
|
if (!x11_display || !x11_window) return NULL;
|
||||||
|
|
||||||
|
WGPUSurfaceSourceXlibWindow fromXlibWindow;
|
||||||
|
fromXlibWindow.chain.sType = WGPUSType_SurfaceSourceXlibWindow;
|
||||||
|
fromXlibWindow.chain.next = NULL;
|
||||||
|
fromXlibWindow.display = x11_display;
|
||||||
|
fromXlibWindow.window = x11_window;
|
||||||
|
|
||||||
|
WGPUSurfaceDescriptor surfaceDescriptor;
|
||||||
|
surfaceDescriptor.nextInChain = &fromXlibWindow.chain;
|
||||||
|
surfaceDescriptor.label = (WGPUStringView){ NULL, WGPU_STRLEN };
|
||||||
|
|
||||||
|
return wgpuInstanceCreateSurface(instance, &surfaceDescriptor);
|
||||||
|
}
|
||||||
|
else if (SDL_strcmp(SDL_GetCurrentVideoDriver(), "wayland") == 0) {
|
||||||
|
void *wayland_display = SDL_GetPointerProperty(props, SDL_PROP_WINDOW_WAYLAND_DISPLAY_POINTER, NULL);
|
||||||
|
void *wayland_surface = SDL_GetPointerProperty(props, SDL_PROP_WINDOW_WAYLAND_SURFACE_POINTER, NULL);
|
||||||
|
if (!wayland_display || !wayland_surface) return NULL;
|
||||||
|
|
||||||
|
WGPUSurfaceSourceWaylandSurface fromWaylandSurface;
|
||||||
|
fromWaylandSurface.chain.sType = WGPUSType_SurfaceSourceWaylandSurface;
|
||||||
|
fromWaylandSurface.chain.next = NULL;
|
||||||
|
fromWaylandSurface.display = SDL_GetPointerProperty(props, SDL_PROP_WINDOW_WAYLAND_DISPLAY_POINTER, NULL);
|
||||||
|
fromWaylandSurface.surface = wayland_surface;
|
||||||
|
|
||||||
|
WGPUSurfaceDescriptor surfaceDescriptor;
|
||||||
|
surfaceDescriptor.nextInChain = &fromWaylandSurface.chain;
|
||||||
|
surfaceDescriptor.label = (WGPUStringView){ NULL, WGPU_STRLEN };
|
||||||
|
|
||||||
|
return wgpuInstanceCreateSurface(instance, &surfaceDescriptor);
|
||||||
|
}
|
||||||
|
#elif defined(SDL_PLATFORM_WIN32)
|
||||||
|
{
|
||||||
|
HWND hwnd = (HWND)SDL_GetPointerProperty(props, SDL_PROP_WINDOW_WIN32_HWND_POINTER, NULL);
|
||||||
|
if (!hwnd) return NULL;
|
||||||
|
HINSTANCE hinstance = GetModuleHandle(NULL);
|
||||||
|
|
||||||
|
WGPUSurfaceSourceWindowsHWND fromWindowsHWND;
|
||||||
|
fromWindowsHWND.chain.sType = WGPUSType_SurfaceSourceWindowsHWND;
|
||||||
|
fromWindowsHWND.chain.next = NULL;
|
||||||
|
fromWindowsHWND.hinstance = hinstance;
|
||||||
|
fromWindowsHWND.hwnd = hwnd;
|
||||||
|
|
||||||
|
WGPUSurfaceDescriptor surfaceDescriptor;
|
||||||
|
surfaceDescriptor.nextInChain = &fromWindowsHWND.chain;
|
||||||
|
surfaceDescriptor.label = (WGPUStringView){ NULL, WGPU_STRLEN };
|
||||||
|
|
||||||
|
return wgpuInstanceCreateSurface(instance, &surfaceDescriptor);
|
||||||
|
}
|
||||||
|
#elif defined(__EMSCRIPTEN__)
|
||||||
|
{
|
||||||
|
# ifdef WEBGPU_BACKEND_EMDAWNWEBGPU
|
||||||
|
WGPUEmscriptenSurfaceSourceCanvasHTMLSelector fromCanvasHTMLSelector;
|
||||||
|
fromCanvasHTMLSelector.chain.sType = WGPUSType_EmscriptenSurfaceSourceCanvasHTMLSelector;
|
||||||
|
# else
|
||||||
|
WGPUSurfaceDescriptorFromCanvasHTMLSelector fromCanvasHTMLSelector;
|
||||||
|
fromCanvasHTMLSelector.chain.sType = WGPUSType_SurfaceDescriptorFromCanvasHTMLSelector;
|
||||||
|
# endif
|
||||||
|
fromCanvasHTMLSelector.chain.next = NULL;
|
||||||
|
fromCanvasHTMLSelector.selector = "canvas";
|
||||||
|
|
||||||
|
WGPUSurfaceDescriptor surfaceDescriptor;
|
||||||
|
surfaceDescriptor.nextInChain = &fromCanvasHTMLSelector.chain;
|
||||||
|
surfaceDescriptor.label = NULL;
|
||||||
|
|
||||||
|
return wgpuInstanceCreateSurface(instance, &surfaceDescriptor);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
// TODO: See SDL_syswm.h for other possible enum values!
|
||||||
|
#error "Unsupported WGPU_TARGET"
|
||||||
|
#endif
|
||||||
|
}
|
||||||
49
src/vendors/sdl3_glue/sdl3webgpu.h
vendored
Normal file
49
src/vendors/sdl3_glue/sdl3webgpu.h
vendored
Normal file
|
|
@ -0,0 +1,49 @@
|
||||||
|
/**
|
||||||
|
* This is an extension of SDL3 for WebGPU, abstracting away the details of
|
||||||
|
* OS-specific operations.
|
||||||
|
*
|
||||||
|
* This file is part of the "Learn WebGPU for C++" book.
|
||||||
|
* https://eliemichel.github.io/LearnWebGPU
|
||||||
|
*
|
||||||
|
* MIT License
|
||||||
|
* Copyright (c) 2022-2024 Elie Michel and the wgpu-native authors
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _sdl3_webgpu_h_
|
||||||
|
#define _sdl3_webgpu_h_
|
||||||
|
|
||||||
|
#include "../wgpu/wgpu.h"
|
||||||
|
#include <SDL3/SDL.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a WGPUSurface from a SDL3 window.
|
||||||
|
*/
|
||||||
|
WGPUSurface SDL_GetWGPUSurface(WGPUInstance instance, SDL_Window* window);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // _sdl3_webgpu_h_
|
||||||
6768
src/vendors/wgpu/webgpu.h
vendored
Normal file
6768
src/vendors/wgpu/webgpu.h
vendored
Normal file
File diff suppressed because it is too large
Load diff
1587
src/vendors/wgpu/wgpu.h
vendored
Normal file
1587
src/vendors/wgpu/wgpu.h
vendored
Normal file
File diff suppressed because it is too large
Load diff
Loading…
Add table
Reference in a new issue