Skip to content

Commit e631589

Browse files
committed
Initial support for Windows
1 parent b4d7f4d commit e631589

File tree

7 files changed

+141
-50
lines changed

7 files changed

+141
-50
lines changed

samples/src/main/java/io/github/bahaa/webgpu/samples/SampleBase.java

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import io.github.bahaa.webgpu.api.model.*;
55
import io.github.bahaa.webgpu.samples.platform.macos.appkit.NSWindow;
66
import io.github.bahaa.webgpu.samples.platform.macos.ca.CAMetalLayer;
7+
import io.github.bahaa.webgpu.samples.platform.windwos.Windows;
78
import io.github.bahaa.webgpu.tools.LibraryLoader;
89
import io.github.bahaa.webgpu.tools.Platform;
910

@@ -17,6 +18,7 @@
1718

1819
import static io.github.bahaa.webgpu.samples.glfw.ffm.glfw3_h.*;
1920
import static io.github.bahaa.webgpu.samples.glfw.ffm.glfw3native_h.glfwGetCocoaWindow;
21+
import static io.github.bahaa.webgpu.samples.glfw.ffm.glfw3native_h.glfwGetWin32Window;
2022
import static java.lang.foreign.MemorySegment.NULL;
2123

2224
public abstract class SampleBase {
@@ -136,7 +138,8 @@ private void configureSurface(final Surface surface, final Device device,
136138

137139
protected Surface createSurface(final MemorySegment window, final Instance instance) {
138140
return switch (Platform.currentOS()) {
139-
case WINDOWS, LINUX -> throw new UnsupportedOperationException("Not supported yet.");
141+
case LINUX -> throw new UnsupportedOperationException("Not supported yet.");
142+
case WINDOWS -> createWindowsSurface(window, instance);
140143
case MACOS -> createMetalSurface(window, instance);
141144
case OTHER -> throw new UnsupportedOperationException("Unknown operating system!");
142145
};
@@ -185,4 +188,17 @@ private Surface createMetalSurface(final MemorySegment window, final Instance in
185188
.build()
186189
);
187190
}
191+
192+
private Surface createWindowsSurface(final MemorySegment window, final Instance instance) {
193+
final var hwnd = glfwGetWin32Window(window);
194+
final var hinstance = Windows.getModuleHandle(NULL);
195+
196+
return instance.createSurface(SurfaceDescriptor.builder()
197+
.source(SurfaceSource.windowsHWND()
198+
.hwnd(hwnd)
199+
.hinstance(hinstance)
200+
.build())
201+
.build()
202+
);
203+
}
188204
}

samples/src/main/java/io/github/bahaa/webgpu/samples/glfw/ffm/glfw3native_h.java

Lines changed: 26 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -9,45 +9,34 @@
99
public class glfw3native_h extends glfw3_h {
1010

1111
/**
12-
* Function descriptor for:
1312
* {@snippet lang = c:
1413
* int glfwGetCocoaWindow()
1514
*}
1615
*/
17-
public static FunctionDescriptor glfwGetCocoaWindow$descriptor() {
18-
return glfwGetCocoaWindow.DESC;
19-
}
20-
21-
/**
22-
* Downcall method handle for:
23-
* {@snippet lang = c:
24-
* int glfwGetCocoaWindow()
25-
*}
26-
*/
27-
public static MethodHandle glfwGetCocoaWindow$handle() {
28-
return glfwGetCocoaWindow.HANDLE;
29-
}
30-
31-
/**
32-
* Address for:
33-
* {@snippet lang = c:
34-
* int glfwGetCocoaWindow()
35-
*}
36-
*/
37-
public static MemorySegment glfwGetCocoaWindow$address() {
38-
return glfwGetCocoaWindow.ADDR;
16+
public static MemorySegment glfwGetCocoaWindow(final MemorySegment window) {
17+
final var mh$ = glfwGetCocoaWindow.HANDLE;
18+
try {
19+
if (TRACE_DOWNCALLS) {
20+
traceDowncall("glfwGetCocoaWindow");
21+
}
22+
return (MemorySegment) mh$.invokeExact(window);
23+
} catch (final Error | RuntimeException ex) {
24+
throw ex;
25+
} catch (final Throwable ex$) {
26+
throw new AssertionError("should not reach here", ex$);
27+
}
3928
}
4029

4130
/**
4231
* {@snippet lang = c:
43-
* int glfwGetCocoaWindow()
32+
* int glfwGetWin32Window()
4433
*}
4534
*/
46-
public static MemorySegment glfwGetCocoaWindow(final MemorySegment window) {
47-
final var mh$ = glfwGetCocoaWindow.HANDLE;
35+
public static MemorySegment glfwGetWin32Window(final MemorySegment window) {
36+
final var mh$ = glfwGetWin32Window.HANDLE;
4837
try {
4938
if (TRACE_DOWNCALLS) {
50-
traceDowncall("glfwGetCocoaWindow");
39+
traceDowncall("glfwGetWin32Window");
5140
}
5241
return (MemorySegment) mh$.invokeExact(window);
5342
} catch (final Error | RuntimeException ex) {
@@ -66,4 +55,14 @@ private enum glfwGetCocoaWindow {
6655

6756
public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle(ADDR, DESC);
6857
}
58+
59+
private enum glfwGetWin32Window {
60+
;
61+
public static final FunctionDescriptor DESC = FunctionDescriptor.of(
62+
glfw3_h.C_POINTER, glfw3_h.C_POINTER);
63+
64+
public static final MemorySegment ADDR = SYMBOL_LOOKUP.findOrThrow("glfwGetWin32Window");
65+
66+
public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle(ADDR, DESC);
67+
}
6968
}

samples/src/main/java/io/github/bahaa/webgpu/samples/platfrom/PlatformException.java renamed to samples/src/main/java/io/github/bahaa/webgpu/samples/platform/PlatformException.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package io.github.bahaa.webgpu.samples.platfrom;
1+
package io.github.bahaa.webgpu.samples.platform;
22

33
public class PlatformException extends RuntimeException {
44
public PlatformException(final String message) {

samples/src/main/java/io/github/bahaa/webgpu/samples/platform/macos/runtime/Runtime.java

Lines changed: 20 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
package io.github.bahaa.webgpu.samples.platform.macos.runtime;
22

3-
import io.github.bahaa.webgpu.samples.platfrom.PlatformException;
3+
import io.github.bahaa.webgpu.samples.platform.PlatformException;
44

55
import java.lang.foreign.*;
66
import java.lang.invoke.MethodHandle;
@@ -98,77 +98,76 @@ public static MemorySegment classCreateInstance(final MemorySegment clazz, final
9898
}
9999
}
100100

101-
private static class Meta {
102-
private static final String LIB_OBJC = "libobjc.A.dylib";
103-
101+
private enum Meta {
102+
;
103+
static final Arena LIBRARY_ARENA = Arena.ofAuto();
104+
private static final String LIB_OBJC = "objc.A";
105+
static final SymbolLookup SYMBOL_LOOKUP = SymbolLookup
106+
.libraryLookup(System.mapLibraryName(LIB_OBJC), LIBRARY_ARENA)
107+
.or(SymbolLookup.loaderLookup())
108+
.or(Linker.nativeLinker().defaultLookup());
104109
private static final MethodHandle objc_getClass;
105110
private static final MethodHandle sel_registerName;
106-
107111
private static final MethodHandle object_dispose;
108-
109112
private static final MethodHandle objc_msgSend;
110113
private static final MethodHandle objc_msgSendByte;
111114
private static final MethodHandle objc_msgSendInt;
112115
private static final MethodHandle objc_msgSendLong;
113116
private static final MethodHandle objc_msgSendFloat;
114117
private static final MethodHandle objc_msgSendAddr;
115118
private static final MethodHandle objc_msgSendAddrAddrAddr;
116-
117119
private static final MethodHandle class_createInstance;
118120

119121
static {
120-
final var arena = Arena.ofAuto();
121-
122122
final var linker = Linker.nativeLinker();
123-
final var objc = SymbolLookup.libraryLookup(LIB_OBJC, arena);
124123

125-
objc_getClass = linker.downcallHandle(objc.find("objc_getClass").orElseThrow(),
124+
objc_getClass = linker.downcallHandle(SYMBOL_LOOKUP.find("objc_getClass").orElseThrow(),
126125
FunctionDescriptor.of(ValueLayout.ADDRESS, ValueLayout.ADDRESS));
127126

128-
sel_registerName = linker.downcallHandle(objc.find("sel_registerName").orElseThrow(),
127+
sel_registerName = linker.downcallHandle(SYMBOL_LOOKUP.find("sel_registerName").orElseThrow(),
129128
FunctionDescriptor.of(ValueLayout.ADDRESS, ValueLayout.ADDRESS));
130129

131-
object_dispose = linker.downcallHandle(objc.find("object_dispose").orElseThrow(),
130+
object_dispose = linker.downcallHandle(SYMBOL_LOOKUP.find("object_dispose").orElseThrow(),
132131
FunctionDescriptor.ofVoid(ValueLayout.ADDRESS));
133132

134133
objc_msgSend = linker.downcallHandle(
135-
objc.find("objc_msgSend").orElseThrow(),
134+
SYMBOL_LOOKUP.find("objc_msgSend").orElseThrow(),
136135
FunctionDescriptor.of(ValueLayout.ADDRESS, ValueLayout.ADDRESS, ValueLayout.ADDRESS),
137136
Linker.Option.critical(false));
138137

139138
objc_msgSendByte = linker.downcallHandle(
140-
objc.find("objc_msgSend").orElseThrow(),
139+
SYMBOL_LOOKUP.find("objc_msgSend").orElseThrow(),
141140
FunctionDescriptor.of(ValueLayout.ADDRESS, ValueLayout.ADDRESS, ValueLayout.ADDRESS, ValueLayout.JAVA_BYTE),
142141
Linker.Option.critical(false));
143142

144143
objc_msgSendInt = linker.downcallHandle(
145-
objc.find("objc_msgSend").orElseThrow(),
144+
SYMBOL_LOOKUP.find("objc_msgSend").orElseThrow(),
146145
FunctionDescriptor.of(ValueLayout.ADDRESS, ValueLayout.ADDRESS, ValueLayout.ADDRESS, ValueLayout.JAVA_INT),
147146
Linker.Option.critical(false));
148147

149148
objc_msgSendLong = linker.downcallHandle(
150-
objc.find("objc_msgSend").orElseThrow(),
149+
SYMBOL_LOOKUP.find("objc_msgSend").orElseThrow(),
151150
FunctionDescriptor.of(ValueLayout.ADDRESS, ValueLayout.ADDRESS, ValueLayout.ADDRESS, ValueLayout.JAVA_LONG),
152151
Linker.Option.critical(false));
153152

154153
objc_msgSendFloat = linker.downcallHandle(
155-
objc.find("objc_msgSend").orElseThrow(),
154+
SYMBOL_LOOKUP.find("objc_msgSend").orElseThrow(),
156155
FunctionDescriptor.of(ValueLayout.ADDRESS, ValueLayout.ADDRESS, ValueLayout.ADDRESS, ValueLayout.JAVA_FLOAT),
157156
Linker.Option.critical(false));
158157

159158
objc_msgSendAddr = linker.downcallHandle(
160-
objc.find("objc_msgSend").orElseThrow(),
159+
SYMBOL_LOOKUP.find("objc_msgSend").orElseThrow(),
161160
FunctionDescriptor.of(ValueLayout.ADDRESS, ValueLayout.ADDRESS, ValueLayout.ADDRESS, ValueLayout.ADDRESS),
162161
Linker.Option.critical(false));
163162

164163
objc_msgSendAddrAddrAddr = linker.downcallHandle(
165-
objc.find("objc_msgSend").orElseThrow(),
164+
SYMBOL_LOOKUP.find("objc_msgSend").orElseThrow(),
166165
FunctionDescriptor.of(ValueLayout.ADDRESS, ValueLayout.ADDRESS, ValueLayout.ADDRESS,
167166
ValueLayout.ADDRESS, ValueLayout.ADDRESS, ValueLayout.ADDRESS),
168167
Linker.Option.critical(false));
169168

170169
class_createInstance = linker.downcallHandle(
171-
objc.find("class_createInstance").orElseThrow(),
170+
SYMBOL_LOOKUP.find("class_createInstance").orElseThrow(),
172171
FunctionDescriptor.of(ValueLayout.ADDRESS, ValueLayout.ADDRESS, ValueLayout.JAVA_INT),
173172
Linker.Option.critical(false));
174173
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
package io.github.bahaa.webgpu.samples.platform.windwos;
2+
3+
import io.github.bahaa.webgpu.samples.platform.PlatformException;
4+
5+
import java.lang.foreign.*;
6+
import java.lang.invoke.MethodHandle;
7+
8+
public enum Windows {
9+
;
10+
11+
public static MemorySegment getModuleHandle(final MemorySegment lpModuleName) {
12+
try {
13+
return (MemorySegment) Meta.GetModuleHandle.invokeExact(lpModuleName);
14+
} catch (final Throwable e) {
15+
throw new PlatformException(e);
16+
}
17+
}
18+
19+
private enum Meta {
20+
;
21+
static final Arena LIBRARY_ARENA = Arena.ofAuto();
22+
23+
static final SymbolLookup SYMBOL_LOOKUP = SymbolLookup
24+
.libraryLookup(System.mapLibraryName("Kernel32"), LIBRARY_ARENA)
25+
.or(SymbolLookup.loaderLookup())
26+
.or(Linker.nativeLinker().defaultLookup());
27+
28+
private static final MethodHandle GetModuleHandle;
29+
30+
static {
31+
final var linker = Linker.nativeLinker();
32+
33+
GetModuleHandle = linker.downcallHandle(SYMBOL_LOOKUP.find("GetModuleHandleW").orElseThrow(),
34+
FunctionDescriptor.of(ValueLayout.ADDRESS, ValueLayout.ADDRESS));
35+
}
36+
}
37+
}

webgpu/src/main/java/io/github/bahaa/webgpu/api/model/SurfaceSource.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,8 @@ public interface SurfaceSource extends StructBlueprint {
55
static SurfaceSourceMetalLayer.Builder metalLayer() {
66
return SurfaceSourceMetalLayer.builder();
77
}
8+
9+
static SurfaceSourceWindowsHWND.Builder windowsHWND() {
10+
return SurfaceSourceWindowsHWND.builder();
11+
}
812
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
package io.github.bahaa.webgpu.api.model;
2+
3+
import io.github.bahaa.webgpu.ffm.WGPUChainedStruct;
4+
import io.github.bahaa.webgpu.ffm.WGPUSurfaceSourceWindowsHWND;
5+
import io.helidon.builder.api.Prototype;
6+
7+
import java.lang.foreign.Arena;
8+
import java.lang.foreign.MemorySegment;
9+
10+
import static java.lang.foreign.MemorySegment.NULL;
11+
12+
@Prototype.Blueprint
13+
interface SurfaceSourceWindowsHWNDBlueprint extends SurfaceSource {
14+
15+
MemorySegment hinstance();
16+
17+
MemorySegment hwnd();
18+
19+
@Override
20+
default MemorySegment toSegment(final Arena arena) {
21+
final var struct = WGPUSurfaceSourceWindowsHWND.allocate(arena);
22+
updateSegment(arena, struct);
23+
return struct;
24+
}
25+
26+
@Override
27+
default void updateSegment(final Arena arena, final MemorySegment struct) {
28+
WGPUSurfaceSourceWindowsHWND.hinstance(struct, hinstance());
29+
WGPUSurfaceSourceWindowsHWND.hwnd(struct, hwnd());
30+
31+
final var chain = WGPUSurfaceSourceWindowsHWND.chain(struct);
32+
33+
WGPUChainedStruct.next(chain, NULL);
34+
WGPUChainedStruct.sType(chain, SType.SURFACE_SOURCE_WINDOWS_HWND.value());
35+
}
36+
}

0 commit comments

Comments
 (0)