diff --git a/Makefile b/Makefile index 49889b4..4938859 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,5 @@ -OS := $(shell uname -s) +OS ?= $(shell uname -s) +rwildcard=$(wildcard $1$2) $(foreach d,$(wildcard $1*),$(call rwildcard,$d/,$2)) ifeq ($(OS),Darwin) CC := clang SED := gsed @@ -6,13 +7,16 @@ endif ifeq ($(OS),Linux) CC := gcc endif +ifeq ($(OS),Windows_NT) +CC := cl +endif ifndef CC $(error Unsupported target OS '$(OS)') endif ifndef SED SED := sed endif -SOURCES := $(shell find source -name '*.d') +SOURCES := $(call rwildcard,source/,*.d) LIBS_PATH := lib .DEFAULT_GOAL := docs @@ -21,45 +25,36 @@ all: docs ################################################# # Subprojects ################################################# +# wgpu-native binaries ships with static libraries 🎉 ifeq ($(OS),Darwin) -LIB_WGPU_EXT := dylib + LIB_WGPU := libwgpu_native.a endif ifeq ($(OS),Linux) -LIB_WGPU_EXT := so + LIB_WGPU := libwgpu_native.a endif -ifndef LIB_WGPU_EXT -$(error Unsupported target OS '$(OS)') +ifeq ($(OS),Windows_NT) + LIB_WGPU := wgpu_native.lib +endif +ifndef LIB_WGPU + $(error Unsupported target OS '$(OS)') endif -LIB_WGPU_SOURCE := subprojects/wgpu/libwgpu.$(LIB_WGPU_EXT) -LIB_WGPU := lib/libwgpu.$(LIB_WGPU_EXT) -wgpu: $(LIB_WGPU) +LIB_WGPU_SOURCE := subprojects/wgpu +wgpu: lib/$(LIB_WGPU) .PHONY: wgpu $(LIB_WGPU_SOURCE): subprojects/wgpu.Makefile @make -C subprojects -f wgpu.Makefile -$(LIB_WGPU): $(LIB_WGPU_SOURCE) +lib/$(LIB_WGPU): $(LIB_WGPU_SOURCE) +ifeq ($(OS),Windows_NT) + @if not exist lib mkdir lib + @xcopy $(subst /,\\,$(LIB_WGPU_SOURCE))\\$(LIB_WGPU) lib /y >NUL +else @mkdir -p lib - @cp $(LIB_WGPU_SOURCE) lib/. + @cp $(LIB_WGPU_SOURCE)/$(LIB_WGPU) lib/. +endif ################################################# -# Examples +# Test Coverage ################################################# -example_utils_SOURCES := $(shell find examples/utils/source -name '*.d') -EXAMPLES := bin/cube bin/headless bin/triangle -examples: $(EXAMPLES) -.PHONY: examples - -cube_SOURCES := $(example_utils_SOURCES) $(shell find examples/cube/source -name '*.d') -bin/cube: $(SOURCES) $(cube_SOURCES) examples/cube/dub.json - cd examples/cube && dub build - -headless_SOURCES := $(shell find examples/headless/source -name '*.d') -bin/headless: $(SOURCES) $(headless_SOURCES) examples/headless/dub.json - cd examples/headless && dub build - -triangle_SOURCES := $(shell find examples/triangle/source -name '*.d') -bin/triangle: $(SOURCES) $(triangle_SOURCES) examples/triangle/dub.json - cd examples/triangle && dub build - cover: $(SOURCES) dub test --build=unittest-cov @@ -88,18 +83,30 @@ docs/sitemap.xml: $(SOURCES) @echo Done docs: docs/sitemap.xml +ifeq ($(OS),Windows_NT) + $(error Build documentation on *nix!) +endif .PHONY: docs +clean: +ifneq ($(OS),Windows_NT) clean: clean-docs - rm -rf bin lib +else + $(error Build documentation on *nix!) +endif dub clean + @rm -rf bin lib @echo "Cleaning code coverage reports..." - rm -f -- *.lst + @rm -f -- *.lst .PHONY: clean +DOCS_HTML := $(call rwildcard,docs/,*.html) clean-docs: +ifeq ($(OS),Windows_NT) + $(error Build documentation on *nix!) +endif @echo "Cleaning generated documentation..." @rm -f docs.json @rm -f docs/sitemap.xml docs/file_hashes.json - @rm -rf `find docs -name '*.html'` + @rm -rf $(DOCS_HTML) .PHONY: clean-docs diff --git a/README.md b/README.md index 3a82551..2d77ad2 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ D bindings to [wgpu-native](https://github.com/gfx-rs/wgpu-native) as an idiomatic wrapper around the library. -Targets wgpu-native [`v0.10.4.1`](https://github.com/gfx-rs/wgpu-native/releases/tag/v0.10.4.1). +Targets wgpu-native [`v0.17.0.2`](https://github.com/gfx-rs/wgpu-native/releases/tag/v0.17.0.2). ## Usage diff --git a/dub.json b/dub.json index cded27d..640fadb 100644 --- a/dub.json +++ b/dub.json @@ -7,6 +7,7 @@ "license": "MIT", "copyright": "Copyright © 2020-2023, Chance Snow", "subPackages": [ + "examples/enumerate", "examples/headless", "examples/triangle", "examples/cube" @@ -24,8 +25,8 @@ }, "systemDependencies-linux": "vulkan >= 1.1.0, patchelf", "systemDependencies-osx": "metal >= 2", - "systemDependencies-windows": "DirectX >= 11", - "preGenerateCommands-posix": [ + "systemDependencies-windows": "vulkan >= 1.1.0 or DirectX >= 11", + "preGenerateCommands": [ "make wgpu" ], "dflags": [ @@ -34,33 +35,30 @@ ], "configurations": [ { - "name": "library", - "lflags-posix": [ - "-L$PACKAGE_DIR/lib" - ] + "name": "library" }, { "name": "unittest", - "lflags-posix": [ - "-Llib" - ], "postBuildCommands-linux": [ "echo Fixing up libwgpu so path...", "patchelf --set-rpath '$$ORIGIN' bin/wgpu-d-test-unittest" ], "postBuildCommands-osx": [ "echo Fixing up libwgpu dylib path...", - "install_name_tool -change /Users/runner/work/wgpu-native/wgpu-native/target/x86_64-apple-darwin/debug/deps/libwgpu_native.dylib @executable_path/libwgpu.dylib bin/wgpu-d-test-unittest" + "install_name_tool -change /Users/runner/work/wgpu-native/wgpu-native/target/x86_64-apple-darwin/debug/deps/libwgpu_native.dylib @executable_path/libwgpu_native.dylib bin/wgpu-d-test-unittest" ] } ], - "libs": [ - "wgpu" - ], - "copyFiles-linux": [ - "lib/libwgpu.so" - ], - "copyFiles-osx": [ - "lib/libwgpu.dylib" + "lflags-posix": ["-L$WGPU_D_PACKAGE_DIR/lib"], + "lflags-windows": ["/LIBPATH:$WGPU_D_PACKAGE_DIR/subprojects/wgpu"], + "libs": ["wgpu_native"], + "libs-windows": [ + "d3dcompiler", + "ws2_32", + "advapi32", + "user32", + "userenv", + "bcrypt", + "ntdll" ] } diff --git a/examples/cube/dub.json b/examples/cube/dub.json index 1ae9860..6c85391 100644 --- a/examples/cube/dub.json +++ b/examples/cube/dub.json @@ -24,6 +24,6 @@ ], "postBuildCommands-osx": [ "echo Fixing up libwgpu dylib path...", - "install_name_tool -change /Users/runner/work/wgpu-native/wgpu-native/target/x86_64-apple-darwin/debug/deps/libwgpu_native.dylib @executable_path/../lib/libwgpu.dylib `find $PACKAGE_DIR/../../bin -name '*cube'`" + "install_name_tool -change /Users/runner/work/wgpu-native/wgpu-native/target/x86_64-apple-darwin/debug/deps/libwgpu_native.dylib @executable_path/../lib/libwgpu_native.dylib `find $PACKAGE_DIR/../../bin -name '*cube'`" ] } diff --git a/examples/enumerate/.gitignore b/examples/enumerate/.gitignore new file mode 100644 index 0000000..926194f --- /dev/null +++ b/examples/enumerate/.gitignore @@ -0,0 +1,15 @@ +.dub +docs.json +__dummy.html +docs/ +/headless +headless.so +headless.dylib +headless.dll +headless.a +headless.lib +headless-test-* +*.exe +*.o +*.obj +*.lst diff --git a/examples/enumerate/dub.json b/examples/enumerate/dub.json new file mode 100644 index 0000000..40f831a --- /dev/null +++ b/examples/enumerate/dub.json @@ -0,0 +1,24 @@ +{ + "name": "enumerate", + "description": "Enumerate GPU adapters example", + "authors": [ + "Chance Snow" + ], + "license": "MIT", + "copyright": "Copyright © 2023, Chance Snow", + "targetType": "executable", + "targetPath": "../../bin", + "dependencies": { + "wgpu-d": { + "path": "../.." + } + }, + "preBuildCommands-osx": [ + "echo Fixing up libwgpu dylib path...", + "rm -f `find $PACKAGE_DIR/../../bin -name '*enumerate'`" + ], + "postBuildCommands-osx": [ + "echo Fixing up libwgpu dylib path...", + "install_name_tool -change /Users/runner/work/wgpu-native/wgpu-native/target/x86_64-apple-darwin/debug/deps/libwgpu_native.dylib @executable_path/../lib/libwgpu_native.dylib `find $PACKAGE_DIR/../../bin -name '*enumerate'`" + ] +} diff --git a/examples/enumerate/source/app.d b/examples/enumerate/source/app.d new file mode 100644 index 0000000..d5df954 --- /dev/null +++ b/examples/enumerate/source/app.d @@ -0,0 +1,46 @@ +import std.conv : text, to; +import std.stdio; +import std.string : fromStringz; + +import wgpu.api; + +// Adapted from https://github.com/gfx-rs/wgpu-rs/blob/f6123e4fe89f74754093c07b476099623b76dd08/examples/capture/main.rs +void main() { + writeln("Enumerating Device Adapters Example"); + + auto instance = Instance.create(); + assert(instance.id, "Could not create WebGPU instance."); + + writefln("Preferred backend type? %s", cast(BackendType) instance.report.backendType); + auto adapters = instance.adapters; + writefln("Found %d suitable adapters:", adapters.length); + for (int i = 0; i < adapters.length; i++) { + auto adapter = adapters[i]; + auto props = adapter.properties; + writefln("Adapter %d", i); + writefln("\tvendorID: %u", props.vendorID); + writefln("\tvendorName: %s", props.vendorName.fromStringz.to!string); + writefln("\tarchitecture: %s", props.architecture.fromStringz.to!string); + writefln("\tdeviceID: %u", props.deviceID); + writefln("\tname: %s", props.name.fromStringz.to!string); + writefln("\tdriverDescription: %s", props.driverDescription.fromStringz.to!string); + writefln("\tadapterType: %s", cast(AdapterType) props.adapterType); + writefln("\tbackendType: %s", cast(BackendType) props.backendType); + writeln(); + adapter.destroy(); + } + + auto adapter = instance.requestAdapter(PowerPreference.lowPower, BackendType.d3d12 | BackendType.vulkan); + assert(adapter.ready, "Adapter instance was not initialized: Adapter status: " ~ adapter.status.text); + writefln("Adapter limits:\n%s", adapter.limits.toString); + writeln(); + + auto device = adapter.requestDevice(adapter.limits); + assert(device.ready, "Device is not ready: Device status: " ~ device.status.text); + writefln("Device limits:\n%s", device.limits.toString); + writeln(); + + device.destroy(); + adapter.destroy(); + instance.destroy(); +} diff --git a/examples/headless/dub.json b/examples/headless/dub.json index 71cc565..58e42bd 100644 --- a/examples/headless/dub.json +++ b/examples/headless/dub.json @@ -20,6 +20,6 @@ ], "postBuildCommands-osx": [ "echo Fixing up libwgpu dylib path...", - "install_name_tool -change /Users/runner/work/wgpu-native/wgpu-native/target/x86_64-apple-darwin/debug/deps/libwgpu_native.dylib @executable_path/../lib/libwgpu.dylib `find $PACKAGE_DIR/../../bin -name '*headless'`" + "install_name_tool -change /Users/runner/work/wgpu-native/wgpu-native/target/x86_64-apple-darwin/debug/deps/libwgpu_native.dylib @executable_path/../lib/libwgpu_native.dylib `find $PACKAGE_DIR/../../bin -name '*headless'`" ] } diff --git a/examples/headless/source/app.d b/examples/headless/source/app.d index ac3fb59..b8355ce 100644 --- a/examples/headless/source/app.d +++ b/examples/headless/source/app.d @@ -1,3 +1,4 @@ +import std.conv : text; import std.stdio; import wgpu.api; @@ -6,14 +7,14 @@ import wgpu.api; void main() { writeln("Headless (windowless) Example"); - auto adapter = Instance.requestAdapter(PowerPreference.lowPower); - assert(adapter.ready, "Adapter instance was not initialized"); - writefln("Adapter properties: %s", adapter.properties); - writefln("Adapter limits: %s", adapter.limits); + auto instance = Instance.create(); + assert(instance.id, "Could not create WebGPU instance."); + + auto adapter = instance.requestAdapter(PowerPreference.lowPower); + assert(adapter.ready, "Adapter instance was not initialized: Adapter status: " ~ adapter.status.text); auto device = adapter.requestDevice(adapter.limits); - assert(device.ready, "Device is not ready"); - writefln("Device limits: %s", device.limits); + assert(device.ready, "Device is not ready: Device status: " ~ device.status.text); const width = 400; const height = 300; diff --git a/examples/triangle/dub.json b/examples/triangle/dub.json index 9eef82a..29b7cbc 100644 --- a/examples/triangle/dub.json +++ b/examples/triangle/dub.json @@ -19,7 +19,7 @@ "subConfigurations": { "bindbc-glfw": "static" }, - "preGenerateCommands-posix": [ + "preGenerateCommands": [ "make -C subprojects -f glfw.Makefile" ], "preBuildCommands-osx": [ @@ -27,16 +27,18 @@ ], "postBuildCommands-osx": [ "echo Fixing up libwgpu dylib path...", - "install_name_tool -change /Users/runner/work/wgpu-native/wgpu-native/target/x86_64-apple-darwin/debug/deps/libwgpu_native.dylib @executable_path/lib/libwgpu.dylib `find $PACKAGE_DIR/../../bin -name '*triangle'`" + "install_name_tool -change /Users/runner/work/wgpu-native/wgpu-native/target/x86_64-apple-darwin/debug/deps/libwgpu_native.dylib @executable_path/lib/libwgpu_native.dylib `find $PACKAGE_DIR/../../bin -name '*triangle'`" ], "libs": ["glfw3"], "libs-linux": [ "X11" ], + "libs-windows": ["gdi32"], "lflags-posix": ["-L$PACKAGE_DIR/subprojects/glfw/src"], "lflags-osx": [ "-framework", "AppKit", "-framework", "Metal", "-framework", "QuartzCore" - ] + ], + "lflags-windows": ["/LIBPATH:$PACKAGE_DIR/subprojects/glfw/src"] } diff --git a/examples/triangle/source/app.d b/examples/triangle/source/app.d index a1ee312..781c0c6 100644 --- a/examples/triangle/source/app.d +++ b/examples/triangle/source/app.d @@ -20,40 +20,37 @@ extern(C) void wgpu_glfw_error_callback(int error, const char* description) noth } } -enum string triangleShader = `[[stage(vertex)]] -fn vs_main([[builtin(vertex_index)]] in_vertex_index: u32) -> [[builtin(position)]] vec4 { +enum string triangleShader = `@vertex +fn vs_main(@builtin(vertex_index) in_vertex_index: u32) -> @builtin(position) vec4f { let x = f32(i32(in_vertex_index) - 1); let y = f32(i32(in_vertex_index & 1u) * 2 - 1); - return vec4(x, y, 0.0, 1.0); + return vec4f(x, y, 0.0, 1.0); } -[[stage(fragment)]] -fn fs_main() -> [[location(0)]] vec4 { - return vec4(1.0, 0.0, 1.0, 1.0); +@fragment +fn fs_main() -> @location(0) vec4f { + return vec4f(1.0, 0.0, 0.0, 1.0); }`; enum string fullScreenQuadShader = `struct VertexOutput { - [[builtin(position)]] clip_position: vec4; - [[location(0)]] tex_coords: vec2; + @builtin(position) clip_position: vec4f; + @location(0) tex_coords: vec2f; }; -[[stage(vertex)]] -fn vs_main([[builtin(vertex_index)]] in_vertex_index: u32) -> VertexOutput { - var out: VertexOutput; +@vertex +fn vs_main(@builtin(vertex_index) in_vertex_index: u32) -> VertexOutput { let x = f32(i32(in_vertex_index) - 1); let y = f32(i32(in_vertex_index & 1u) * 2 - 1); - out.clip_position = vec4(x, y, 0.0, 1.0); - out.tex_coords = vec2(x, y); - return out; + return VertexOutput(vec4f(x, y, 0.0, 1.0), vec2f(x, y)); } -[[group(0), binding(0)]] -var t_diffuse: texture_2d; -[[group(0), binding(1)]] -var s_diffuse: sampler; +@group(0) @binding(0) +var diffuse: texture_2d; +@group(0) @binding(1) +var diffuseSampler: sampler; -[[stage(fragment)]] -fn fs_main(in: VertexOutput) -> [[location(0)]] vec4 { - return textureSample(t_diffuse, s_diffuse, in.tex_coords); +@fragment +fn fs_main(in: VertexOutput) -> @location(0) vec4f { + return textureSample(diffuse, diffuseSampler, in.tex_coords); }`; // Adapted from https://github.com/gfx-rs/wgpu-native/blob/v0.10.4.1/examples/triangle/main.c @@ -63,6 +60,8 @@ void main() { import std.string : toStringz; import std.typecons : Yes; + // Create GLFW window + const title = "Triangle Example"; title.writeln; @@ -82,6 +81,11 @@ void main() { assert(window !is null, "Could not create window:\n\t" ~ lastError); glfwSetWindowSizeLimits(window, 640, 480, GLFW_DONT_CARE, GLFW_DONT_CARE); + // Create WebGPU resources + + auto instance = Instance.create(); + assert(instance.id, "Could not create WebGPU instance."); + Surface surface; version (OSX) { import std.exception : enforce; @@ -90,20 +94,24 @@ void main() { auto metalLayer = CAMetalLayer.classOf.layer; nativeWindow.contentView.wantsLayer = true; nativeWindow.contentView.layer = metalLayer; - surface = Surface.fromMetalLayer(metalLayer.asId); + surface = Surface.fromMetalLayer(instance, metalLayer.asId); + } else { + version (Linux) surface = Surface.fromXlib(instance, glfwGetX11Display().enforce, glfwGetX11Window(window).enforce); + else { + version (Windows) { + import core.sys.windows.windows : GetModuleHandleA; + surface = Surface.fromWindowsHwnd(instance, GetModuleHandleA(null), glfwGetWin32Window(window)); + } + else static assert(0, "Unsupported target platform"); + } } - else version (Linux) surface = Surface.fromXlib(assert(glfwGetX11Display()), assert(glfwGetX11Window(window))); - // TODO: Integrate with Windows platform, i.e. Surface.fromWindowsHwnd - else static assert(0, "Unsupported target platform"); assert(surface.id !is null, "Could not create native surface"); - auto adapter = Instance.requestAdapter(surface, PowerPreference.lowPower); + auto adapter = instance.requestAdapter(surface, PowerPreference.lowPower); assert(adapter.ready, "Adapter instance was not initialized"); - writefln("Adapter properties: %s", adapter.properties); auto device = adapter.requestDevice(adapter.limits); assert(device.ready, "Device is not ready"); - writefln("Device limits: %s", device.limits); auto swapChainFormat = surface.preferredFormat(adapter); auto swapChain = device.createSwapChain( @@ -296,6 +304,12 @@ auto bindDelegate(Func, string file = __FILE__, size_t line = __LINE__)(Func f) return &func; } +version (Windows) { + import core.sys.windows.windows : HWND; + // FIXME: What's wrong with https://github.com/BindBC/bindbc-glfw/blob/6529ce4f67f69839a93de5e0bbe1150fab30d633/source/bindbc/glfw/bindstatic.d#L172 + extern(C) @nogc nothrow HWND glfwGetWin32Window(GLFWwindow* window); +} + // mac OS interop with the Objective-C Runtime version (OSX) { import core.attribute : selector; diff --git a/examples/triangle/subprojects/glfw.Makefile b/examples/triangle/subprojects/glfw.Makefile index 28fdb91..bfd2f73 100644 --- a/examples/triangle/subprojects/glfw.Makefile +++ b/examples/triangle/subprojects/glfw.Makefile @@ -1,5 +1,25 @@ VERSION := 3.3.6 +ifeq ($(OS),Windows_NT) + +.DEFAULT_GOAL := glfw/src/glfw3.lib + +ARCHIVE_ZIP := $(shell echo %USERPROFILE%/AppData/Local/Temp/glfw-$(VERSION).zip) +# See https://stackoverflow.com/a/7487697/1363247 +glfw: + @echo Downloading GLFW sources... + @curl -L https://github.com/glfw/glfw/releases/download/$(VERSION)/glfw-$(VERSION).zip --output $(ARCHIVE_ZIP) + @echo Unzipping GLFW sources... + @tar -xf $(ARCHIVE_ZIP) -C . + robocopy glfw-3.3.6 glfw /move /e /NFL /NDL /NJH /nc /ns /np + @rmdir glfw-3.3.6 /s /q +glfw/src/glfw3.lib: glfw + @echo Building GLFW... + cmake -B glfw glfw -DCMAKE_BUILD_TYPE=Release -DUSE_MSVC_RUNTIME_LIBRARY_DLL=OFF -DGLFW_BUILD_TESTS=OFF -DGLFW_BUILD_EXAMPLES=OFF -DGLFW_BUILD_DOCS=OFF -G"Unix Makefiles" + make -C glfw + +else + .DEFAULT_GOAL := glfw/src/libglfw3.a glfw/src/libglfw3.a: @@ -10,5 +30,6 @@ glfw/src/libglfw3.a: @mv glfw-3.3.6 glfw @echo "Building GLFW…" @cd glfw && \ - cmake . -DGLFW_BUILD_TESTS=OFF -DGLFW_BUILD_EXAMPLES=OFF -DGLFW_BUILD_DOCS=OFF && \ + cmake -B glfw glfw -DCMAKE_BUILD_TYPE=Release -DGLFW_BUILD_TESTS=OFF -DGLFW_BUILD_EXAMPLES=OFF -DGLFW_BUILD_DOCS=OFF -G"Unix Makefiles" make +endif diff --git a/examples/utils/dub.json b/examples/utils/dub.json index 54c745a..2a50f6a 100644 --- a/examples/utils/dub.json +++ b/examples/utils/dub.json @@ -19,17 +19,19 @@ "subConfigurations": { "bindbc-glfw": "static" }, - "preGenerateCommands-posix": [ + "preGenerateCommands": [ "make -C subprojects -f glfw.Makefile" ], "libs": ["glfw3"], "libs-linux": [ "X11" ], + "libs-windows": ["gdi32"], "lflags-posix": ["-L$PACKAGE_DIR/subprojects/glfw/src"], "lflags-osx": [ "-framework", "AppKit", "-framework", "Metal", "-framework", "QuartzCore" - ] + ], + "lflags-windows": ["/LIBPATH:$PACKAGE_DIR/subprojects/glfw/src"] } diff --git a/source/wgpu/api.d b/source/wgpu/api.d index 76d2fea..17f5fc6 100644 --- a/source/wgpu/api.d +++ b/source/wgpu/api.d @@ -41,19 +41,25 @@ static const uint MAX_MIP_LEVELS = 16; /// Maximum number of vertex buffers. static const uint MAX_VERTEX_BUFFERS = 16; -// Opaque Pointers +// Section: Opaque Pointers + // TODO: Implement a wrapper around `WGPUQuerySet` alias QuerySet = WGPUQuerySet; // TODO: Because dealing with, "What if this debug label goes out of scope and gets GC'd?" is becoming a headache, convert offending `struct`ures (those with complex wrappers that aren't simply opaque pointers) to classes to reap those reference semantics: https://forum.dlang.org/post/ixfpxfdmnahtytftwald@forum.dlang.org // TODO: Also, for the aforementioned class conversions, ensure `id` handles and constructors whose types with `Device`-only member initializers are `package` private. +/// alias ChainedStruct = WGPUChainedStruct; +/// alias ChainedStructOut = WGPUChainedStructOut; +/// alias AdapterProperties = WGPUAdapterProperties; /// See_Also: wgpu::BindGroupEntry alias BindGroupEntry = WGPUBindGroupEntry; +/// alias BlendComponent = WGPUBlendComponent; +/// alias BufferBindingLayout = WGPUBufferBindingLayout; /// Describes a `Buffer`. alias BufferDescriptor = WGPUBufferDescriptor; @@ -66,12 +72,15 @@ alias Color = WGPUColor; alias CommandBufferDescriptor = WGPUCommandBufferDescriptor; /// Describes a `CommandEncoder`. alias CommandEncoderDescriptor = WGPUCommandEncoderDescriptor; +/// alias CompilationMessage = WGPUCompilationMessage; -/// Describes a `ComputePass`. -alias ComputePassDescriptor = WGPUComputePassDescriptor; +/// +alias ComputePassTimestampWrite = WGPUComputePassTimestampWrite; +/// alias ConstantEntry = WGPUConstantEntry; /// Extent of a texture related operation. alias Extent3d = WGPUExtent3D; +/// alias InstanceDescriptor = WGPUInstanceDescriptor; /// Represents the sets of limits an adapter/device supports. /// @@ -95,20 +104,67 @@ alias InstanceDescriptor = WGPUInstanceDescriptor; /// $(LI wgpu::Limits ) /// ) alias Limits = WGPULimits; + +string toString(Limits limits) { + import std.algorithm : joiner; + import std.array : array; + import std.format : format; + + return [ + "max texture dimension 1D: %u".format(limits.maxTextureDimension1D), + "max texture dimension 2D: %u".format(limits.maxTextureDimension2D), + "max texture dimension 3D: %u".format(limits.maxTextureDimension3D), + "max texture array layers: %u".format(limits.maxTextureArrayLayers), + "max bind groups: %u".format(limits.maxBindGroups), + "max bindings per bind group: %u".format(limits.maxBindingsPerBindGroup), + "max dynamic uniform buffers per pipeline layout: %u".format(limits.maxDynamicUniformBuffersPerPipelineLayout), + "max dynamic storage buffers per pipeline layout: %u".format(limits.maxDynamicStorageBuffersPerPipelineLayout), + "max sampled textures per shader stage: %u".format(limits.maxSampledTexturesPerShaderStage), + "max samplers per shader stage: %u".format(limits.maxSamplersPerShaderStage), + "max storage buffers per shader stage: %u".format(limits.maxStorageBuffersPerShaderStage), + "max storage textures per shader stage: %u".format(limits.maxStorageTexturesPerShaderStage), + "max uniform buffers per shader stage: %u".format(limits.maxUniformBuffersPerShaderStage), + "max uniform buffer binding size: %u bytes".format(limits.maxUniformBufferBindingSize), + "max storage buffer binding size: %u bytes".format(limits.maxStorageBufferBindingSize), + "min uniform buffer offset alignment: %u bytes".format(limits.minUniformBufferOffsetAlignment), + "min storage buffer offset alignment: %u bytes".format(limits.minStorageBufferOffsetAlignment), + "max vertex buffers: %u".format(limits.maxVertexBuffers), + "max buffer size: %u bytes".format(limits.maxBufferSize), + "max vertex attributes: %u".format(limits.maxVertexAttributes), + "max vertex buffer array stride: %u bytes".format(limits.maxVertexBufferArrayStride), + "max inter stage shader components: %u".format(limits.maxInterStageShaderComponents), + "max inter stage shader variables: %u".format(limits.maxInterStageShaderVariables), + "max color attachments: %u".format(limits.maxColorAttachments), + "max color attachment bytes per sample: %u".format(limits.maxColorAttachmentBytesPerSample), + "max compute workgroup storage size: %u bytes".format(limits.maxComputeWorkgroupStorageSize), + "max compute invocations per workgroup: %u".format(limits.maxComputeInvocationsPerWorkgroup), + "max compute workgroup size x: %u".format(limits.maxComputeWorkgroupSizeX), + "max compute workgroup size y: %u".format(limits.maxComputeWorkgroupSizeY), + "max compute workgroup size z: %u".format(limits.maxComputeWorkgroupSizeZ), + "max compute workgroups per dimension: %u".format(limits.maxComputeWorkgroupsPerDimension), + ].joiner("\n").array.to!string; +} + /// Origin of a copy to/from a texture. alias Origin3d = WGPUOrigin3D; /// Describes a `PipelineLayout`. alias PipelineLayoutDescriptor = WGPUPipelineLayoutDescriptor; /// -alias PrimitiveDepthClampingState = WGPUPrimitiveDepthClampingState; +alias PrimitiveDepthClipControl = WGPUPrimitiveDepthClipControl; /// alias QuerySetDescriptor = WGPUQuerySetDescriptor; /// +alias QueueDescriptor = WGPUQueueDescriptor; +/// alias RenderBundleDescriptor = WGPURenderBundleDescriptor; /// alias RenderBundleEncoderDescriptor = WGPURenderBundleEncoderDescriptor; /// Describes a depth stencil attachment to a `RenderPass`. alias RenderPassDepthStencilAttachment = WGPURenderPassDepthStencilAttachment; +/// +alias RenderPassDescriptorMaxDrawCount = WGPURenderPassDescriptorMaxDrawCount; +/// +alias RenderPassTimestampWrite = WGPURenderPassTimestampWrite; /// Additional information required when requesting an adapter. /// See_Also: wgpu::RequestAdapterOptions alias RequestAdapterOptions = WGPURequestAdapterOptions; @@ -117,11 +173,13 @@ alias SamplerBindingLayout = WGPUSamplerBindingLayout; /// Describes a `Sampler`. alias SamplerDescriptor = WGPUSamplerDescriptor; /// +alias ShaderModuleCompilationHint = WGPUShaderModuleCompilationHint; +/// alias ShaderModuleDescriptor = WGPUShaderModuleDescriptor; /// -alias ShaderModuleSPIRVDescriptor = WGPUShaderModuleSPIRVDescriptor; +alias ShaderModuleSpirvDescriptor = WGPUShaderModuleSPIRVDescriptor; /// -alias ShaderModuleWGSLDescriptor = WGPUShaderModuleWGSLDescriptor; +alias ShaderModuleWgslDescriptor = WGPUShaderModuleWGSLDescriptor; /// alias StencilFaceState = WGPUStencilFaceState; /// @@ -129,13 +187,19 @@ alias StorageTextureBindingLayout = WGPUStorageTextureBindingLayout; /// alias SurfaceDescriptor = WGPUSurfaceDescriptor; /// -alias SurfaceDescriptorFromCanvasHTMLSelector = WGPUSurfaceDescriptorFromCanvasHTMLSelector; +alias SurfaceDescriptorFromAndroidNativeWindow = WGPUSurfaceDescriptorFromAndroidNativeWindow; +/// +alias SurfaceDescriptorFromCanvasHtmlSelector = WGPUSurfaceDescriptorFromCanvasHTMLSelector; /// alias SurfaceDescriptorFromMetalLayer = WGPUSurfaceDescriptorFromMetalLayer; /// -alias SurfaceDescriptorFromWindowsHWND = WGPUSurfaceDescriptorFromWindowsHWND; +alias SurfaceDescriptorFromWaylandSurface = WGPUSurfaceDescriptorFromWaylandSurface; /// -alias SurfaceDescriptorFromXlib = WGPUSurfaceDescriptorFromXlib; +alias SurfaceDescriptorFromWindowsHwnd = WGPUSurfaceDescriptorFromWindowsHWND; +/// +alias SurfaceDescriptorFromXcbWindow = WGPUSurfaceDescriptorFromXcbWindow; +/// +alias SurfaceDescriptorFromXlibWindow = WGPUSurfaceDescriptorFromXlibWindow; /// Describes a `SwapChain`. alias SwapChainDescriptor = WGPUSwapChainDescriptor; /// @@ -159,11 +223,15 @@ alias BindGroupLayoutEntry = WGPUBindGroupLayoutEntry; alias BlendState = WGPUBlendState; /// alias CompilationInfo = WGPUCompilationInfo; +/// Describes a `ComputePass`. +alias ComputePassDescriptor = WGPUComputePassDescriptor; // TODO: View of a buffer which can be used to copy to/from a texture. /// View of a texture which can be used to copy to/from a buffer. alias ImageCopyBuffer = WGPUImageCopyBuffer; /// View of a texture which can be used to copy to/from a texture. alias ImageCopyTexture = WGPUImageCopyTexture; +/// +alias ProgrammableStageDescriptor = WGPUProgrammableStageDescriptor; /// Describes a color attachment to a `RenderPass`. alias RenderPassColorAttachment = WGPURenderPassColorAttachment; /// Describes a `Texture`. @@ -178,9 +246,6 @@ alias RenderPassDescriptor = WGPURenderPassDescriptor; /// Describes a `RenderPipeline`. /// See_Also: wgpu::RenderPipelineDescriptor alias RenderPipelineDescriptor = WGPURenderPipelineDescriptor; -// TODO: Wrap this into `Instance.requestAdapter` -/// -alias AdapterExtras = WGPUAdapterExtras; //static assert(false, std.traits.fullyQualifiedName!WGPUAdapterType); @@ -372,25 +437,33 @@ class FragmentState { extern (C) private void wgpu_request_adapter_callback( WGPURequestAdapterStatus status, WGPUAdapter id, const char* message, void* data ) { - assert(status == RequestAdapterStatus.success.asOriginalType); - assert(data !is null); + debug import std.stdio : write; + + assert(data !is null, "No adapter handle!"); auto adapter = cast(Adapter*) data; + adapter.status = cast(RequestAdapterStatus) status; + // TODO: Use the user-registered wgpu logging method instead + debug if (message !is null) message.fromStringz.to!string.write; + + if (status != RequestAdapterStatus.success.asOriginalType) return; assert(id !is null); adapter.id = id; - debug import std.stdio : writeln; - debug if (message !is null) message.fromStringz.to!string.writeln; } extern (C) private void wgpu_request_device_callback( WGPURequestDeviceStatus status, WGPUDevice id, const char* message, void* data ) { - assert(status == RequestDeviceStatus.success.asOriginalType); - assert(data !is null); + debug import std.stdio : write; + + assert(data !is null, "No device handle!"); auto device = cast(Device) data; + device.status = cast(RequestDeviceStatus) status; + // TODO: Use the user-registered wgpu logging method instead + debug if (message !is null) message.fromStringz.to!string.write; + + if (status != RequestDeviceStatus.success.asOriginalType) return; assert(id !is null); device.id = id; - debug import std.stdio : writeln; - debug if (message !is null) message.fromStringz.to!string.writeln; } /// Context for all other wgpu objects. Instance of wgpu. @@ -408,21 +481,50 @@ struct Instance { this.id = id; } + /// Release the given handle. + void destroy() { + if (id !is null) wgpuInstanceRelease(id); + id = null; + } + /// Create a new instance of wgpu. - static Instance create() { - assert(0, "Unimplemented in wgpu-native!"); - // auto desc = InstanceDescriptor(); - // return Instance(wgpuCreateInstance(&desc)); + /// Params: + /// backends = Controls from which backends wgpu will choose during instantiation. + static Instance create(InstanceBackend backends = InstanceBackend.primary) { + const WGPUInstanceExtras extras = { + chain: WGPUChainedStruct(null, cast(WGPUSType) WGPUNativeSType.WGPUSType_InstanceExtras), + backends: backends, + // TODO: WGPUDx12Compiler dx12ShaderCompiler, + // TODO: const char * dxilPath, + // TODO: const char * dxcPath, + }; + auto desc = InstanceDescriptor(cast(ChainedStruct*) &extras); + return Instance(wgpuCreateInstance(&desc)); + } + + /// + auto @property report() { + WGPUGlobalReport report; + wgpuGenerateReport(this.id, &report); + return report; } /// Retrieves all available `Adapter`s that match the given `Backends`. /// /// Params: /// backends = Backends from which to enumerate adapters. - static @property Adapter[] adapters(BackendType backends = BackendType._null) { + /// See_Also: wgpu::Instance.enumerate_adapters + @property Adapter[] adapters(InstanceBackend backends = InstanceBackend.all) { + import std.algorithm : map; + import std.array : array; + assert(backends >= 0); - assert(0, "Unimplemented!"); - // TODO: Implement adapter enumerator as a custom range + auto options = WGPUInstanceEnumerateAdapterOptions(null, backends); + + size_t count = wgpuInstanceEnumerateAdapters(this.id, &options, null); + auto adapters = new WGPUAdapter[count]; + wgpuInstanceEnumerateAdapters(this.id, &options, cast(WGPUAdapter*) adapters.ptr); + return adapters.map!(id => Adapter(id)).array; } /// Retrieves a new Adapter, asynchronously. @@ -431,29 +533,30 @@ struct Instance { /// /// Remarks: /// Use `Adapter.ready` to determine whether an Adapter was successfully requested. - static Adapter requestAdapter( - PowerPreference powerPreference = PowerPreference.highPerformance, + Adapter requestAdapter( + PowerPreference powerPreference = PowerPreference.undefined, + BackendType backendType = BackendType.undefined, Flag!"forceFallbackAdapter" forceFallbackAdapter = No.forceFallbackAdapter ) { return requestAdapter( - RequestAdapterOptions(null, /* compatibleSurface: */ null, powerPreference, forceFallbackAdapter) + RequestAdapterOptions(null, /* compatibleSurface: */ null, powerPreference, backendType, forceFallbackAdapter) ); } /// ditto - static Adapter requestAdapter( - const Surface compatibleSurface, PowerPreference powerPreference = PowerPreference.highPerformance, + Adapter requestAdapter( + const Surface compatibleSurface, PowerPreference powerPreference = PowerPreference.undefined, + BackendType backendType = BackendType.undefined, Flag!"forceFallbackAdapter" forceFallbackAdapter = No.forceFallbackAdapter ) @trusted { assert(compatibleSurface.id !is null, "Given compatible surface is not valid"); - return requestAdapter( - RequestAdapterOptions(null, cast(WGPUSurface) compatibleSurface.id, powerPreference, forceFallbackAdapter) - ); + return requestAdapter(RequestAdapterOptions( + null, cast(WGPUSurface) compatibleSurface.id, powerPreference, backendType, forceFallbackAdapter + )); } /// ditto - static Adapter requestAdapter(RequestAdapterOptions options) @trusted { + Adapter requestAdapter(RequestAdapterOptions options) @trusted { Adapter adapter; - wgpuInstanceRequestAdapter(null, &options, &wgpu_request_adapter_callback, &adapter); - assert(adapter.ready); + wgpuInstanceRequestAdapter(this.id, &options, &wgpu_request_adapter_callback, &adapter); return adapter; } } @@ -466,6 +569,8 @@ struct Adapter { /// Handle identifier. WGPUAdapter id; + /// + RequestAdapterStatus status = RequestAdapterStatus.unknown; /// Whether this Adapter handle has finished being requested and is ready for use. bool ready() @property const { @@ -525,12 +630,12 @@ struct Adapter { auto device = new Device(label); const WGPUDeviceExtras extras = { chain: WGPUChainedStruct(null, cast(WGPUSType) WGPUNativeSType.WGPUSType_DeviceExtras), - label: device.label.toStringz, tracePath: tracePath is null ? null : tracePath.toStringz }; WGPURequiredLimits requiredLimits = { limits: limits }; WGPUDeviceDescriptor desc = { nextInChain: cast(ChainedStruct*) &extras, + label: device.label.toStringz, requiredLimits: &requiredLimits }; wgpuAdapterRequestDevice(id, &desc, &wgpu_request_device_callback, cast(void*) device); @@ -544,6 +649,8 @@ struct Adapter { /// See_Also: wgpu::Device class Device { package WGPUDevice id; + /// + RequestDeviceStatus status = RequestDeviceStatus.unknown; /// Label for this Device. string label; @@ -554,7 +661,7 @@ class Device { /// Release the given handle. void destroy() { - if (ready) wgpuDeviceDrop(id); + if (ready) wgpuDeviceRelease(id); id = null; } @@ -596,9 +703,22 @@ class Device { /// Check for resource cleanups and mapping callbacks. /// Params: /// forceWait = Whether or not the call should block. - void poll(Flag!"forceWait" forceWait = No.forceWait) @trusted const { + /// Returns: `true` if the queue is empty, or `false` if there are more queue submissions still in flight. + bool poll(Flag!"forceWait" forceWait = No.forceWait) @trusted const { + assert(id !is null); + return wgpuDevicePoll(cast(WGPUDevice) id, forceWait, null); + } + + /// Check for resource cleanups and mapping callbacks. + /// Params: + /// queue = The `Queue` to poll. + /// submissionIndex + /// forceWait = Whether or not the call should block. + /// Returns: `true` if the queue is empty, or `false` if there are more queue submissions still in flight. + bool poll(Queue queue, ulong submissionIndex, Flag!"forceWait" forceWait = No.forceWait) @trusted const { assert(id !is null); - wgpuDevicePoll(cast(WGPUDevice) id, forceWait); + auto wrappedSubmissionIndex = WGPUWrappedSubmissionIndex(queue.id, submissionIndex); + return wgpuDevicePoll(cast(WGPUDevice) id, forceWait, &wrappedSubmissionIndex); } /// Creates a shader module from SPIR-V source code. @@ -607,7 +727,7 @@ class Device { ShaderModule createShaderModule(const byte[] spv) @trusted { // TODO: assert SPIR-V magic number is at the beginning of the stream // TODO: assert input is not longer than `size_t.max` - const ShaderModuleSPIRVDescriptor spirv = { + const ShaderModuleSpirvDescriptor spirv = { chain: WGPUChainedStruct(null, cast(WGPUSType) SType.shaderModuleSpirvDescriptor), codeSize: spv.length.to!uint, code: spv.to!(uint[]).ptr, @@ -620,9 +740,9 @@ class Device { /// /// Shader modules are used to define programmable stages of a pipeline. ShaderModule createShaderModule(string wgsl) @trusted const { - const ShaderModuleWGSLDescriptor wgslDesc = { + const ShaderModuleWgslDescriptor wgslDesc = { chain: WGPUChainedStruct(null, cast(WGPUSType) SType.shaderModuleWgslDescriptor), - source: wgsl.toStringz, + code: wgsl.toStringz, }; auto desc = ShaderModuleDescriptor(cast(ChainedStruct*) &wgslDesc.chain); assert(id !is null); @@ -853,7 +973,8 @@ class Device { /// minFilter = How to filter the texture when it needs to be minified/made smaller. /// mipmapFilter = How to filter between mip map levels. Sampler createSampler( - AddressMode addressMode, FilterMode magFilter, FilterMode minFilter, FilterMode mipmapFilter = FilterMode.nearest + AddressMode addressMode, FilterMode magFilter, FilterMode minFilter, + MipmapFilterMode mipmapFilter = MipmapFilterMode.nearest ) { SamplerDescriptor desc = { addressModeU: addressMode, @@ -902,15 +1023,6 @@ struct Surface { version (OSX) { /// Create a new `Surface` from a Metal layer. - static Surface fromMetalLayer(void* layer, string label = null) { - auto metalLayer = SurfaceDescriptorFromMetalLayer( - ChainedStruct(null, cast(WGPUSType) SType.surfaceDescriptorFromMetalLayer.asOriginalType), - layer - ); - auto desc = SurfaceDescriptor(cast(ChainedStruct*) &metalLayer, label is null ? null : label.toStringz); - return Surface(wgpuInstanceCreateSurface(null, &desc)); - } - /// ditto static Surface fromMetalLayer(Instance instance, void* layer, string label = null) { auto metalLayer = SurfaceDescriptorFromMetalLayer( ChainedStruct(null, cast(WGPUSType) SType.surfaceDescriptorFromMetalLayer.asOriginalType), @@ -921,21 +1033,10 @@ struct Surface { } } else version (D_Ddoc) { /// Create a new `Surface` from a Metal layer. - static Surface fromMetalLayer(void* layer, string label = null); - /// ditto static Surface fromMetalLayer(Instance instance, void* layer, string label = null); } version (Windows) { /// Create a new `Surface` from a Windows window handle. - static Surface fromWindowsHwnd(void* _hinstance, void* hwnd, string label = null) { - auto windowsHwnd = SurfaceDescriptorFromWindowsHwnd( - ChainedStruct(null, cast(WGPUSType) SType.surfaceDescriptorFromWindowsHwnd.asOriginalType), - _hinstance, hwnd - ); - auto desc = SurfaceDescriptor(cast(ChainedStruct*) &windowsHwnd, label is null ? null : label.toStringz); - return Surface(wgpuInstanceCreateSurface(null, &desc)); - } - /// ditto static Surface fromWindowsHwnd(Instance instance, void* _hinstance, void* hwnd, string label = null) { auto windowsHwnd = SurfaceDescriptorFromWindowsHwnd( ChainedStruct(null, cast(WGPUSType) SType.surfaceDescriptorFromWindowsHwnd.asOriginalType), @@ -946,21 +1047,10 @@ struct Surface { } } else version (D_Ddoc) { /// Create a new `Surface` from a Windows window handle. - static Surface fromWindowsHwnd(void* _hinstance, void* hwnd, string label = null); - /// ditto static Surface fromWindowsHwnd(Instance instance, void* _hinstance, void* hwnd, string label = null); } version (linux) { /// Create a new `Surface` from a Xlib window handle. - static Surface fromXlib(void* display, uint window, string label = null) { - auto xlib = SurfaceDescriptorFromXlib( - ChainedStruct(null, cast(WGPUSType) SType.surfaceDescriptorFromXlib.asOriginalType), - display, window - ); - auto desc = SurfaceDescriptor(cast(ChainedStruct*) &xlib, label is null ? null : label.toStringz); - return Surface(wgpuInstanceCreateSurface(null, &desc)); - } - /// ditto static Surface fromXlib(Instance instance, void* display, uint window, string label = null) { auto xlib = SurfaceDescriptorFromXlib( ChainedStruct(null, cast(WGPUSType) SType.surfaceDescriptorFromXlib.asOriginalType), @@ -971,8 +1061,6 @@ struct Surface { } } else version (D_Ddoc) { /// Create a new `Surface` from a Xlib window handle. - static Surface fromXlib(void* display, uint window, string label = null); - /// ditto static Surface fromXlib(Instance instance, void* display, uint window, string label = null); } // TODO: Support Wayland with a `linux-wayland` version config once upstream wgpu-native supports it @@ -1333,12 +1421,51 @@ class Texture { case TextureFormat.bc6hrgbFloat: case TextureFormat.bc7rgbaUnorm: case TextureFormat.bc7rgbaUnormSrgb: + case TextureFormat.etc2Rgb8Unorm: + case TextureFormat.etc2Rgb8UnormSrgb: + case TextureFormat.etc2Rgb8A1Unorm: + case TextureFormat.etc2Rgb8A1UnormSrgb: + case TextureFormat.etc2Rgba8Unorm: + case TextureFormat.etc2Rgba8UnormSrgb: + case TextureFormat.eacR11Unorm: + case TextureFormat.eacR11Snorm: + case TextureFormat.eacRg11Unorm: + case TextureFormat.eacRg11Snorm: + case TextureFormat.astc4x4Unorm: + case TextureFormat.astc4x4UnormSrgb: + case TextureFormat.astc5x4Unorm: + case TextureFormat.astc5x4UnormSrgb: + case TextureFormat.astc5x5Unorm: + case TextureFormat.astc5x5UnormSrgb: + case TextureFormat.astc6x5Unorm: + case TextureFormat.astc6x5UnormSrgb: + case TextureFormat.astc6x6Unorm: + case TextureFormat.astc6x6UnormSrgb: + case TextureFormat.astc8x5Unorm: + case TextureFormat.astc8x5UnormSrgb: + case TextureFormat.astc8x6Unorm: + case TextureFormat.astc8x6UnormSrgb: + case TextureFormat.astc8x8Unorm: + case TextureFormat.astc8x8UnormSrgb: + case TextureFormat.astc10x5Unorm: + case TextureFormat.astc10x5UnormSrgb: + case TextureFormat.astc10x6Unorm: + case TextureFormat.astc10x6UnormSrgb: + case TextureFormat.astc10x8Unorm: + case TextureFormat.astc10x8UnormSrgb: + case TextureFormat.astc10x10Unorm: + case TextureFormat.astc10x10UnormSrgb: + case TextureFormat.astc12x10Unorm: + case TextureFormat.astc12x10UnormSrgb: + case TextureFormat.astc12x12Unorm: + case TextureFormat.astc12x12UnormSrgb: // FIXME: Supply pixel compression ratios for these texture formats assert(0, "Unknown compression ratio of " ~ descriptor.format.stringof); - // QUESTION: Depth formats of _at least_ 24 bits, therefore there's no guarenteed block size? + // QUESTION: Depth formats of _at least_ 24 bits, therefore there's no guaranteed block size? case TextureFormat.undefined: case TextureFormat.depth16Unorm: case TextureFormat.depth32Float: + case TextureFormat.depth32FloatStencil8: case TextureFormat.depth24Plus: case TextureFormat.depth24PlusStencil8: case TextureFormat.force32: @@ -1389,7 +1516,8 @@ class Texture { null, 0, // Offset paddedBytesPerRow, - size.depthOrArrayLayers == 1 ? 0 : rowsPerImage, + // FIXME: Make sure this is corect + size.depthOrArrayLayers * rowsPerImage, ); } @@ -1417,6 +1545,10 @@ class Texture { TextureViewDescriptor desc = { label: descriptor.label, format: descriptor.format, + baseMipLevel: 0, + mipLevelCount: descriptor.mipLevelCount, + baseArrayLayer: 0, + arrayLayerCount: size.depthOrArrayLayers, dimension: dimension.viewDimension(size.depthOrArrayLayers), aspect: TextureAspect.all, }; @@ -1463,7 +1595,7 @@ struct TextureView { /// Release the handle to this texture view. void destroy() { - if (id !is null) wgpuTextureViewDrop(id); + if (id !is null) wgpuTextureViewRelease(id); id = null; } @@ -1555,7 +1687,7 @@ struct ShaderModule { /// Release the handle to this shader. void destroy() { - if (id !is null) wgpuShaderModuleDrop(id); + if (id !is null) wgpuShaderModuleRelease(id); id = null; } } @@ -1751,7 +1883,7 @@ class RenderPipeline { /// Release the given handle. void destroy() { - if (id !is null) wgpuRenderPipelineDrop(id); + if (id !is null) wgpuRenderPipelineRelease(id); id = null; } } @@ -1826,7 +1958,7 @@ struct RenderPass { /// void end() { - wgpuRenderPassEncoderEndPass(instance); + wgpuRenderPassEncoderEnd(instance); } // TODO: void wgpuRenderPassEncoderBeginOcclusionQuery(WGPURenderPassEncoder renderPassEncoder, uint32_t queryIndex); @@ -1965,7 +2097,7 @@ struct ComputePipeline { /// Release the given handle. void destroy() { - if (id !is null) wgpuComputePipelineDrop(id); + if (id !is null) wgpuComputePipelineRelease(id); id = null; } @@ -1996,7 +2128,7 @@ struct ComputePass { /// /// x, y and z denote the number of work groups to dispatch in each dimension. void dispatch(const uint x, const uint y, const uint z) { - wgpuComputePassEncoderDispatch(instance, x, y, z); + wgpuComputePassEncoderDispatchWorkgroups(instance, x, y, z); } // TODO: void wgpuComputePassEncoderDispatchIndirect(WGPUComputePassEncoder computePassEncoder, WGPUBuffer indirectBuffer, uint64_t indirectOffset); diff --git a/source/wgpu/enums.d b/source/wgpu/enums.d index dd16c47..cf854fe 100644 --- a/source/wgpu/enums.d +++ b/source/wgpu/enums.d @@ -32,23 +32,59 @@ enum AddressMode : WGPUAddressMode { } /// +enum InstanceBackend : WGPUInstanceBackend { + /// + vulkan = WGPUInstanceBackend_Vulkan, + /// + gl = WGPUInstanceBackend_GL, + /// + metal = WGPUInstanceBackend_Metal, + /// + dx12 = WGPUInstanceBackend_DX12, + /// + dx11 = WGPUInstanceBackend_DX11, + /// + browserWebGPU = WGPUInstanceBackend_BrowserWebGPU, + /// + primary = WGPUInstanceBackend_Primary, + /// + secondary = WGPUInstanceBackend_Secondary, + /// + all = WGPUInstanceBackend_Force32, + /// + none = WGPUInstanceBackend_None, + force32 = cast(WGPUInstanceBackend) 0x7FFFFFFF +} + +/// Represents the graphics backends that wgpu can use. +/// See_Also: wgpu::Backends enum BackendType : WGPUBackendType { /// - _null, + undefined = WGPUBackendType_Undefined, + /// + _null = WGPUBackendType_Null, + /// + webGPU = WGPUBackendType_WebGPU, + /// + d3d11 = WGPUBackendType_D3D11, /// - webGPU, + d3d12 = WGPUBackendType_D3D12, /// - d3d11, + metal = WGPUBackendType_Metal, /// - d3d12, + vulkan = WGPUBackendType_Vulkan, /// - metal, + openGL = WGPUBackendType_OpenGL, /// - vulkan, + openGLES = WGPUBackendType_OpenGLES, + /// All the graphics APIs that for which wgpu offers first tier support. /// - openGL, + /// Vulkan, Metal, DirectX 12, and Browser WebGPU + primary = cast(WGPUBackendType) (BackendType.vulkan | BackendType.metal | BackendType.d3d12 | BackendType.webGPU), + /// All the graphics APIs that for which wgpu offers second tier support. /// - openGLES, + /// That is, OpenGL and DirectX 11. These may be unsupported or are still experimental. + secondary = cast(WGPUBackendType) (BackendType.openGL | BackendType.openGLES | BackendType.d3d11), force32 = cast(WGPUBackendType) 0x7FFFFFFF } @@ -258,6 +294,15 @@ enum FilterMode : WGPUFilterMode { force32 = cast(WGPUFilterMode) 0x7FFFFFFF } +/// +enum MipmapFilterMode : WGPUMipmapFilterMode { + /// + nearest, + /// + linear, + force32 = cast(WGPUMipmapFilterMode) 0x7FFFFFFF +} + /// Specifies the vertex order for faces to be considered front-facing. enum FrontFace : WGPUFrontFace { /// Clockwise ordered faces will be considered front-facing. @@ -282,6 +327,8 @@ enum IndexFormat : WGPUIndexFormat { /// enum LoadOp : WGPULoadOp { + /// + undefined, /// clear, /// @@ -306,6 +353,8 @@ enum PipelineStatisticName : WGPUPipelineStatisticName { /// enum PowerPreference : WGPUPowerPreference { + /// + undefined, /// lowPower, /// @@ -404,7 +453,7 @@ enum SType : WGPUSType { /// surfaceDescriptorFromMetalLayer, /// - surfaceDescriptorFromWindowsHWND, + surfaceDescriptorFromWindowsHwnd, /// surfaceDescriptorFromXlib, /// @@ -463,6 +512,8 @@ enum StorageTextureAccess : WGPUStorageTextureAccess { /// enum StoreOp : WGPUStoreOp { + /// + undefined, /// store, /// @@ -481,19 +532,6 @@ enum TextureAspect : WGPUTextureAspect { force32 = cast(WGPUTextureAspect) 0x7FFFFFFF } -/// -enum TextureComponentType : WGPUTextureComponentType { - /// - _float, - /// - sint, - /// - _uint, - /// - depthComparison, - force32 = cast(WGPUTextureComponentType) 0x7FFFFFFF -} - /// enum TextureDimension : WGPUTextureDimension { /// @@ -592,6 +630,8 @@ enum TextureFormat : WGPUTextureFormat { /// depth32Float, /// + depth32FloatStencil8, + /// bc1rgbaUnorm, /// bc1rgbaUnormSrgb, @@ -619,6 +659,82 @@ enum TextureFormat : WGPUTextureFormat { bc7rgbaUnorm, /// bc7rgbaUnormSrgb, + /// + etc2Rgb8Unorm, + /// + etc2Rgb8UnormSrgb, + /// + etc2Rgb8A1Unorm, + /// + etc2Rgb8A1UnormSrgb, + /// + etc2Rgba8Unorm, + /// + etc2Rgba8UnormSrgb, + /// + eacR11Unorm, + /// + eacR11Snorm, + /// + eacRg11Unorm, + /// + eacRg11Snorm, + /// + astc4x4Unorm, + /// + astc4x4UnormSrgb, + /// + astc5x4Unorm, + /// + astc5x4UnormSrgb, + /// + astc5x5Unorm, + /// + astc5x5UnormSrgb, + /// + astc6x5Unorm, + /// + astc6x5UnormSrgb, + /// + astc6x6Unorm, + /// + astc6x6UnormSrgb, + /// + astc8x5Unorm, + /// + astc8x5UnormSrgb, + /// + astc8x6Unorm, + /// + astc8x6UnormSrgb, + /// + astc8x8Unorm, + /// + astc8x8UnormSrgb, + /// + astc10x5Unorm, + /// + astc10x5UnormSrgb, + /// + astc10x6Unorm, + /// + astc10x6UnormSrgb, + /// + astc10x8Unorm, + /// + astc10x8UnormSrgb, + /// + astc10x10Unorm, + /// + astc10x10UnormSrgb, + /// + astc12x10Unorm, + /// + astc12x10UnormSrgb, + /// + astc12x12Unorm, + /// + astc12x12UnormSrgb, force32 = cast(WGPUTextureFormat) 0x7FFFFFFF } diff --git a/subprojects/wgpu.Makefile b/subprojects/wgpu.Makefile index 0041571..4db5ce4 100644 --- a/subprojects/wgpu.Makefile +++ b/subprojects/wgpu.Makefile @@ -1,30 +1,61 @@ -# See https://github.com/gfx-rs/wgpu-native/tree/v0.10.4.1 -VERSION := v0.10.4.1 -OS := $(shell uname -s) -ARCH := $(shell uname -m) +# See https://github.com/gfx-rs/wgpu-native/tree/v0.17.0.2 +VERSION := v0.17.0.2 +OS ?= $(shell uname -s) +ifeq ($(OS),Windows_NT) + ifeq ($(PROCESSOR_ARCHITEW6432),AMD64) + ARCH := x86_64 + else + ifeq ($(PROCESSOR_ARCHITECTURE),AMD64) + ARCH := x86_64 + endif + ifeq ($(PROCESSOR_ARCHITECTURE),x86) + ARCH := i686 + endif + endif + ifndef ARCH + $(error Unsupported target CPU architecture: $(OS)) + endif +endif +ARCH ?= $(shell uname -m) +# wgpu-native binaries ships with static libraries 🎉 ifeq ($(OS),Darwin) - RELEASE := macos - LIB_WGPU_EXT := dylib + RELEASE := macos + LIB_WGPU := libwgpu_native.a endif ifeq ($(OS),Linux) - RELEASE := linux - LIB_WGPU_EXT := so + RELEASE := linux + LIB_WGPU := libwgpu_native.a +endif +ifeq ($(OS),Windows_NT) + RELEASE := windows + LIB_WGPU := wgpu_native.lib endif -# TODO: Add Windows support ifndef RELEASE - $(error Unsupported WebGPU target OS: $(OS)) + $(error Unsupported WebGPU target OS: $(OS)) endif CONFIG ?= debug +.DEFAULT_GOAL := wgpu/$(LIB_WGPU) + BINARY_ARCHIVE := https://github.com/gfx-rs/wgpu-native/releases/download/$(VERSION)/wgpu-$(RELEASE)-$(ARCH)-$(CONFIG).zip $(info Using $(CONFIG) wgpu-native@$(VERSION) from: $(BINARY_ARCHIVE)) +ifeq ($(OS),Windows_NT) + ARCHIVE_ZIP := $(shell echo %USERPROFILE%/AppData/Local/Temp/wgpu.zip) +else + ARCHIVE_ZIP := /tmp/wgpu.zip +endif +$(ARCHIVE_ZIP): + @echo Downloading WebGPU Native binaries... + @curl -L $(BINARY_ARCHIVE) --output $(ARCHIVE_ZIP) -.DEFAULT_GOAL := wgpu/wgpu.h -wgpu/libwgpu.$(LIB_WGPU_EXT): +wgpu/$(LIB_WGPU): $(ARCHIVE_ZIP) wgpu/wgpu.h: - @echo "Downloading WebGPU Native binaries…" - @curl -L $(BINARY_ARCHIVE) --output /tmp/wgpu.zip - @echo "Unzipping WebGPU Native binaries…" - @unzip -q /tmp/wgpu.zip -d wgpu + @echo Unzipping WebGPU Native binaries... +ifeq ($(OS),Windows_NT) + @if not exist wgpu mkdir wgpu + @tar -xf $(ARCHIVE_ZIP) -C wgpu +else + @unzip -q $(ARCHIVE_ZIP) -d wgpu +endif