Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
2274619
core: clear texture
aaf2tbz Oct 12, 2026
fb150ac
core: multi bind
aaf2tbz Oct 12, 2026
61e06df
core: query results into buffers
aaf2tbz Oct 12, 2026
41d048b
core: stencil8 textures and mirror clamp to edge
aaf2tbz Oct 12, 2026
f37709a
shader: enhanced layouts
aaf2tbz Oct 12, 2026
1b7a7ac
core: GL 4.5 uniform limits
aaf2tbz Oct 12, 2026
b19ecac
core(dsa): direct state access
aaf2tbz Oct 12, 2026
2bafa02
core: cull distances
aaf2tbz Oct 12, 2026
872ee63
core: GL 4.5 sub-image reads, inverted conditional rendering, 4.4/4.5…
aaf2tbz Oct 12, 2026
a241057
core: arbitrary sampler border colours; cull distance fixes
aaf2tbz Oct 12, 2026
7a7e18f
core: clear multisample textures
aaf2tbz Oct 12, 2026
cbf2208
shader: enhanced layouts conformance (KHR-Single-GL46)
aaf2tbz Oct 12, 2026
4f09f6c
shader: arrays of arrays (KHR-Single-GL46 arrays_of_arrays_gl)
aaf2tbz Oct 12, 2026
be2d1db
core: report OpenGL 4.4; GL_AMD_pinned_memory
aaf2tbz Oct 12, 2026
7bf4873
core: report OpenGL 4.5
aaf2tbz Oct 12, 2026
eb147e4
core: GL 4.6 draw parameters, indirect counts, statistics and overflo…
aaf2tbz Oct 12, 2026
17743be
core: SPIR-V shaders (ARB_gl_spirv, ARB_spirv_extensions)
aaf2tbz Oct 12, 2026
a451696
core: report OpenGL 4.6
aaf2tbz Oct 12, 2026
09e7fcb
wine: standalone Wine module (no Wine patches)
aaf2tbz Oct 12, 2026
a222f63
wine: retire the Wine patches; the module is the integration
aaf2tbz Oct 12, 2026
7b47ed5
core: images a stage only reads or only writes leave Metal's read_wri…
aaf2tbz Oct 12, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/ISSUE_TEMPLATE/bug-report.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ body:
options:
- MetalSharp
- Release package in MetalSharp's Wine
- My own Wine build with patches/wine
- Wine module installed into my own Wine (install-wine-module.sh)
validations:
required: true
- type: input
Expand Down
2 changes: 1 addition & 1 deletion .github/PULL_REQUEST_TEMPLATE.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,4 @@
- [ ] No code that recognises Khronos CTS tests or shaders
- [ ] Generated docs regenerated with `scripts/docs/generate.py`, not edited by hand
- [ ] `scripts/update-checksums.sh` run after adding, removing or changing files
- [ ] `patches/wine` still applies to `wine-11.17`, if it changed
- [ ] The Wine fixtures pass with the module, if `src/wine` changed
47 changes: 47 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -82,3 +82,50 @@ jobs:

- name: Check the architecture
run: test "$(/usr/bin/lipo -archs build/host/libwinemetalgl.dylib)" = arm64

wine-module:
name: Wine module (x86_64 + i386 PE, x86_64 unix)
runs-on: macos-15
env:
LLVM_MINGW: llvm-mingw-20260922-ucrt-macos-universal
LLVM_MINGW_SHA256: 52e5f5a7b131021d0c39a37a38fa380a1da7885cd04bd61afd0cd4ecfb8bc1f3
WINE_SHA256: c07a6857933c1fc60dff5448d79f39c92481c1e9db5aa628db9d0358446e0701
steps:
- name: Check out source
uses: actions/checkout@v4

- name: Fetch llvm-mingw and the Wine 11.0 headers
run: |
mkdir -p "$RUNNER_TEMP/deps"
cd "$RUNNER_TEMP/deps"
curl -fsSL -o llvm-mingw.tar.xz "https://github.com/mstorsjo/llvm-mingw/releases/download/20260922/$LLVM_MINGW.tar.xz"
echo "$LLVM_MINGW_SHA256 llvm-mingw.tar.xz" | shasum -a 256 -c -
tar -xJf llvm-mingw.tar.xz
curl -fsSL -o wine.tar.xz https://dl.winehq.org/wine/source/11.0/wine-11.0.tar.xz
echo "$WINE_SHA256 wine.tar.xz" | shasum -a 256 -c -
tar -xJf wine.tar.xz wine-11.0/include
echo "$RUNNER_TEMP/deps/$LLVM_MINGW/bin" >> "$GITHUB_PATH"

- name: Build the module
run: sh scripts/build-wine-module.sh "$RUNNER_TEMP/deps/wine-11.0"

- name: Check the module
run: |
m=build/wine-module
test "$(/usr/bin/lipo -archs $m/x86_64-unix/winemetalgl.so)" = x86_64
nm -gU $m/x86_64-unix/winemetalgl.so | grep -q ' ___wine_unix_call_funcs$'
nm -gU $m/x86_64-unix/winemetalgl.so | grep -q ' ___wine_unix_call_wow64_funcs$'
for arch in x86_64 i386; do
dd if=$m/$arch-windows/winemetalgl.dll bs=1 skip=64 count=16 2>/dev/null | grep -q 'Wine builtin DLL'
test -s $m/$arch-windows/opengl32.dll
done

- name: Upload the module
uses: actions/upload-artifact@v4
with:
name: winemetalgl-wine-module
path: |
build/wine-module/x86_64-windows/*.dll
build/wine-module/i386-windows/*.dll
build/wine-module/x86_64-unix/winemetalgl.so
if-no-files-found: error
18 changes: 13 additions & 5 deletions .github/workflows/gl33-conformance.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ on:
workflow_dispatch:
inputs:
wine_runtime:
description: Absolute path to the Wine installation on the self-hosted runner
description: Absolute path to a Wine 11.x installation on the self-hosted runner (llvm-mingw on PATH)
required: true
type: string
cts_executable:
Expand Down Expand Up @@ -41,26 +41,34 @@ jobs:
- name: Check out source
uses: actions/checkout@v4

- name: Build the core and stage it into the Wine runtime
- name: Build the core and the Wine module and install them
env:
WINE_RUNTIME: ${{ inputs.wine_runtime }}
TEMPLATE_PREFIX: ${{ inputs.template_prefix }}
run: |
set -eu
./scripts/build.sh
./scripts/stage-wine.sh "$WINE_RUNTIME/lib/wine/x86_64-unix"
./scripts/build-wine-module.sh "$WINE_RUNTIME"
# The template prefix gets the forwarding opengl32.dll and its override.
template=${TEMPLATE_PREFIX:-$RUNNER_TEMP/prefix-template}
if test ! -d "$template"; then
WINEPREFIX="$template" WINEARCH=wow64 WINEDLLOVERRIDES="mscoree,mshtml=" "$WINE_RUNTIME/bin/wine" wineboot -u
WINEPREFIX="$template" "$WINE_RUNTIME/bin/wineserver" -w
fi
./scripts/install-wine-module.sh "$WINE_RUNTIME" "$template"
echo "TEMPLATE=$template" >> "$GITHUB_ENV"

- name: Run KHR-GL33
env:
WINE_RUNTIME: ${{ inputs.wine_runtime }}
CTS_EXECUTABLE: ${{ inputs.cts_executable }}
TEMPLATE_PREFIX: ${{ inputs.template_prefix }}
CONFIG: ${{ inputs.config }}
FILTER: ${{ inputs.filter }}
SHARDS: ${{ inputs.shards }}
run: |
set -eu
args="--wine $WINE_RUNTIME --cts $CTS_EXECUTABLE --config $CONFIG --shards $SHARDS --out $RUNNER_TEMP/results.txt"
test -z "$TEMPLATE_PREFIX" || args="$args --template $TEMPLATE_PREFIX"
args="$args --template $TEMPLATE"
test -z "$FILTER" || args="$args --filter $FILTER"
# --strict: any Fail, Crash, Timeout, InternalError or Missing case fails the job.
status=0
Expand Down
6 changes: 4 additions & 2 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,8 @@ find_library(QUARTZCORE_FRAMEWORK QuartzCore REQUIRED)

# ---------------------------------------------------------------------------
# WineMetalGL core: the OpenGL implementation on Metal. Built as
# libwinemetalgl.dylib, which winemac.drv loads from its own directory
# (patches/wine).
# libwinemetalgl.dylib, which the Wine module's winemetalgl.so loads from its
# own directory (src/wine, scripts/build-wine-module.sh).

find_package(Python3 REQUIRED COMPONENTS Interpreter)
set(WMGL_GEN_DIR "${CMAKE_CURRENT_BINARY_DIR}/generated")
Expand Down Expand Up @@ -84,13 +84,15 @@ add_library(wmgl_portable STATIC
src/core/format/formats.cpp
src/core/format/pixel_transfer.cpp
src/core/format/vertex_decode.cpp
src/core/shader/border.cpp
src/core/shader/compiler.cpp
src/core/shader/fp64.cpp
src/core/shader/geometry.cpp
src/core/shader/transform_feedback.cpp
src/core/shader/glsl_upgrade.cpp
src/core/shader/tessellation.cpp
src/core/tess/tessellator.cpp
src/core/shader/spirv_input.cpp
src/core/shader/spirv_passes.cpp
src/core/shader/subroutines.cpp
src/core/util/log.cpp
Expand Down
13 changes: 7 additions & 6 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@ build/host/wmgl_host_tests && build/host/wmgl_gpu_tests
./scripts/check-forbidden-identifiers.sh
```

Changes that reach Wine (WGL, contexts, surfaces, `patches/wine`) also need
the Wine fixtures (`tests/wine/probe-opengl-wow64.sh`). Changes to core
Changes that reach Wine (WGL, contexts, surfaces, the Wine module in
`src/wine`) also need the Wine fixtures (`tests/wine/probe-opengl-wow64.sh`). Changes to core
rendering or GL state that could move conformance results also need the
affected Khronos CTS lists, in `mustpass.xml` configurations 1 to 4.

Expand All @@ -53,9 +53,9 @@ affected Khronos CTS lists, in `mustpass.xml` configurations 1 to 4.
`scripts/update-checksums.sh` so `MANIFEST.txt` and `SHA256SUMS` match.
- **No Apple OpenGL.** The core must not link OpenGL.framework, and it exports
only the driver ABI in `include/winemetalgl/driver.h`.
- **Wine patches apply to Wine 11.17.** `patches/wine/wine-11.17` must keep
applying cleanly to the `wine-11.17` release; regenerate them with
`git diff` from a patched tree rather than editing them.
- **No Wine changes.** The Wine module (`src/wine`) builds against the headers
of an unmodified Wine 11.x and installs next to Wine's own modules; it must
not need a patched or rebuilt Wine.

## Code

Expand All @@ -78,6 +78,7 @@ affected Khronos CTS lists, in `mustpass.xml` configurations 1 to 4.

## License

WineMetalGL is LGPL-3.0-or-later; the Wine patches in `patches/wine` are
WineMetalGL is LGPL-3.0-or-later; the files of the Wine module adapted from
Wine (`src/wine/pe/wgl_formats.c`, `src/wine/pe/wgl_fonts.c`) are
LGPL-2.1-or-later, like Wine. By contributing you agree that your changes are
licensed under the same terms.
18 changes: 11 additions & 7 deletions DEPENDENCIES.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,11 @@ Local changes to vendored sources (each marked `WineMetalGL:` in the code):
- glslang `glslang/MachineIndependent/linkValidate.cpp`, `checkStageIO`: the
Vulkan "every input has a matching output" check skips built-in blocks
(`gl_PerVertex`) and redeclared built-in inputs (`gl_ClipDistance`), which
GL provides implicitly, and inputs the stage never reads, which GL does
not require to be written.
GL provides implicitly, and inputs (and input blocks) the stage never
reads, which GL does not require to be written.
- glslang `glslang/MachineIndependent/linkValidate.cpp`, `addUsedLocation`:
vertex shader inputs may alias locations under the relaxed Vulkan rules
WineMetalGL's OpenGL code generation uses, as they may in OpenGL.
- glslang `glslang/MachineIndependent/linkValidate.cpp`, `isIoResizeArray`:
per-patch tessellation evaluation inputs (`patch in`) are not arrayed per
vertex, so `patch` arrays match their control-stage outputs at link time.
Expand Down Expand Up @@ -77,9 +80,10 @@ Local changes to vendored sources (each marked `WineMetalGL:` in the code):
locations it spans (`getExplicitUniformLocations`), for the linker's GL 4.3
uniform location assignment; the Vulkan rules drop the qualifier.
- glslang `glslang/MachineIndependent/ParseHelper.cpp`,
`vkRelaxedRemapUniformVariable`: an unsized uniform array takes its size
from its initializer before the Vulkan rules drop the initializer (the
values are applied from the default block, `applyUniformInitializers`).
`vkRelaxedRemapUniformVariable`: an unsized uniform array (any dimension
of an array of arrays) takes its sizes from its initializer before the
Vulkan rules drop the initializer (the values are applied from the default
block, `applyUniformInitializers`).
- SPIRV-Cross `spirv_glsl.cpp`, `bitcast_expression`, and `spirv_msl.cpp`,
`emit_atomic_func_op`: atomic operands are read unpacked, so an element of a
scalar array in a std140 block (padded to a vector) is passed as a scalar.
Expand Down Expand Up @@ -109,8 +113,8 @@ The built dylib dynamically links only Apple system frameworks and libraries
libobjc); it never links OpenGL.framework (`scripts/verify-source.sh` and CI
check this).

Wine integration requires the Wine patch series in `patches/wine/`, applied to
a Wine 11.17 source tree (`patches/wine/README.md`).
The Wine module (`src/wine`) builds against the headers of an unmodified
Wine 11.x (`scripts/build-wine-module.sh`); its PE side needs llvm-mingw.

Test tooling that is not vendored: the Khronos VK-GL-CTS (commit `1942832`,
built with `tests/cts/windows/build.sh` and `tests/cts/native/build.sh`),
Expand Down
28 changes: 24 additions & 4 deletions MANIFEST.txt
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ docs/api-coverage.json
docs/building.md
docs/conformance.md
docs/decisions/0001-gl-implementation-strategy.md
docs/decisions/0002-gl4-architecture.md
docs/games.md
docs/performance.md
docs/release.md
Expand All @@ -32,21 +33,19 @@ LICENSES/SPIRV-Cross-Khronos-Free-Use.txt
LICENSES/tessellator-MIT.txt
LICENSES/Wine-LGPL-2.1.txt
MANIFEST.txt
patches/wine/README.md
patches/wine/wine-11.17/0001-opengl-wgl-fixes.patch
patches/wine/wine-11.17/0002-winemac-winemetalgl-core.patch
README.md
scripts/build-wine-module.sh
scripts/build.sh
scripts/check-forbidden-identifiers.sh
scripts/cts/diff.py
scripts/cts/results.py
scripts/cts/run.py
scripts/cts/summary.py
scripts/docs/generate.py
scripts/install-wine-module.sh
scripts/stage-arm64-core.sh
scripts/stage-host-libs.sh
scripts/stage-release.sh
scripts/stage-wine.sh
scripts/traces/benchmark.py
scripts/traces/replay.py
scripts/update-checksums.sh
Expand All @@ -60,6 +59,7 @@ src/core/api/compute.mm
src/core/api/copy_image.mm
src/core/api/debug.mm
src/core/api/draw.mm
src/core/api/dsa.mm
src/core/api/fixed_attrib.mm
src/core/api/fixed_get.mm
src/core/api/fixed_raster.mm
Expand Down Expand Up @@ -123,6 +123,8 @@ src/core/proc_table.h
src/core/program.h
src/core/program.mm
src/core/query.h
src/core/shader/border.cpp
src/core/shader/border.h
src/core/shader/compiler.cpp
src/core/shader/compiler.h
src/core/shader/fp64_library.inc
Expand All @@ -133,6 +135,8 @@ src/core/shader/geometry.cpp
src/core/shader/geometry.h
src/core/shader/glsl_upgrade.cpp
src/core/shader/glsl_upgrade.h
src/core/shader/spirv_input.cpp
src/core/shader/spirv_input.h
src/core/shader/spirv_passes.cpp
src/core/shader/spirv_passes.h
src/core/shader/subroutines.cpp
Expand All @@ -158,6 +162,18 @@ src/core/util/name_table.h
src/core/util/ref.h
src/core/util/version.h
src/core/version.mm
src/wine/include/wmgl_gltypes.h
src/wine/include/wmgl_wine.h
src/wine/pe/wgl_fonts.c
src/wine/pe/wgl_formats.c
src/wine/pe/winemetalgl.c
src/wine/pe/wmgl_pe.h
src/wine/unix/unix_main.c
src/wine/unix/unix_wgl.c
src/wine/unix/unix_window.m
src/wine/unix/unix_wow64.c
src/wine/unix/wmgl_unix.h
src/wine/unix/wmgl_window.h
tests/cts/baseline/gl30-cfg1-native.txt
tests/cts/baseline/gl30-cfg1-wine.txt
tests/cts/baseline/gl30-cfg2-native.txt
Expand Down Expand Up @@ -285,6 +301,8 @@ tests/gpu/framebuffer_tests.cpp
tests/gpu/geometry_tests.cpp
tests/gpu/gl4_tests.cpp
tests/gpu/gl43_tests.cpp
tests/gpu/gl44_tests.cpp
tests/gpu/gl46_tests.cpp
tests/gpu/gpu.h
tests/gpu/main.cpp
tests/gpu/pipeline_tests.cpp
Expand All @@ -304,6 +322,7 @@ tests/host/shader_tests.cpp
tests/host/test.h
tests/wine/core_triangle.c
tests/wine/cts_wgl_sequence.c
tests/wine/fixture_version.h
tests/wine/fixtures.txt
tests/wine/opengl_1d.c
tests/wine/opengl_blend.c
Expand Down Expand Up @@ -372,6 +391,7 @@ third_party/khronos/REVISION
third_party/khronos/wgl.xml
tools/gen/extensions.txt
tools/gen/gl_gen.py
tools/gen/wine_gen.py
vendor/glslang/_config.yml
vendor/glslang/.clang-format
vendor/glslang/.gitattributes
Expand Down
41 changes: 24 additions & 17 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,22 +1,27 @@
# WineMetalGL

WineMetalGL is an OpenGL implementation on Metal for Wine on macOS 15 or newer.
Wine's macOS driver (`winemac.drv`) loads it instead of Apple's OpenGL, so
Windows programs get OpenGL 4.3 contexts, core or compatibility profile:
geometry and tessellation shaders, double precision, transform feedback with
vertex streams, separate shader objects, viewport arrays, image load/store,
atomic counters, compute shaders, shader storage buffers and texture views.
Contexts created without a core-profile request (which Apple's OpenGL caps at
2.1) get the full 4.3 compatibility profile:
fixed-function vertex and fragment processing, immediate mode, display lists,
client arrays, legacy GLSL built-ins and the legacy pixel paths, together with
every 3.x and 4.x feature. It runs x86_64 and i386
It installs into an unmodified Wine 11.x as a Wine module of its own, and
gives Windows programs OpenGL 4.6 contexts, core or compatibility profile,
instead of Apple's OpenGL: geometry and tessellation shaders, double
precision, transform feedback with vertex streams, separate shader objects,
viewport arrays, image load/store, atomic counters, compute shaders, shader
storage buffers, texture views, buffer storage, multi-bind, direct state
access, clip control, cull distances, SPIR-V shaders, indirect draw counts
and pipeline statistics queries. Contexts created without a core-profile
request (which Apple's OpenGL caps at 2.1) get the full 4.6 compatibility
profile: fixed-function vertex and fragment processing, immediate mode,
display lists, client arrays, legacy GLSL built-ins and the legacy pixel
paths, together with every 3.x and 4.x feature. It runs x86_64 and i386
Windows programs together in a WoW64 prefix.

The library, `libwinemetalgl.dylib`, has no dependency on Apple's OpenGL. It
The core, `libwinemetalgl.dylib`, has no dependency on Apple's OpenGL. It
compiles GLSL with glslang and SPIRV-Cross to the Metal Shading Language and
implements the GL state machine, resources and draws on Metal. Wine reaches
it through the small driver ABI in `include/winemetalgl/driver.h`.
implements the GL state machine, resources and draws on Metal. The Wine
module (`winemetalgl.dll` and `winemetalgl.so`, with a forwarding
`opengl32.dll` in the prefix) carries WGL and every GL call to it through the
driver ABI in `include/winemetalgl/driver.h`; Wine itself is not patched or
rebuilt ([Build it yourself](docs/building.md#the-wine-module)).

## Proof Of Concept

Expand Down Expand Up @@ -56,13 +61,14 @@ OpenGL 1.0 to 2.1 are implemented by WineMetalGL itself, as its compatibility pr
OpenGL version, configuration and runner, with the reason for each failing
case.
- [Unsupported](docs/unsupported.md): what WineMetalGL does not support and
why: OpenGL 4.3 and later, the gaps in the compatibility profile, what the
why: the gaps in the compatibility profile, what the
Unsupported % counts, the failing CTS cases, and every case the CTS reports
NotSupported.
- [Test suite](docs/testing.md): each test suite, how to run it, and roughly
how long it takes.
- [Build it yourself](docs/building.md): building the core and a Wine 11.17
that loads it, and checking that a program uses it.
- [Build it yourself](docs/building.md): building the core and the Wine
module, installing them into a Wine 11.x, and checking that a program uses
them.
- [Performance](docs/performance.md): frame times against Apple's OpenGL.

Also: the [game corpus](docs/games.md) results, [releasing](docs/release.md),
Expand All @@ -79,6 +85,7 @@ General Public License, version 3 or (at your option) any later version
Public License version 3 in [`LICENSES/GPL-3.0.txt`](LICENSES/GPL-3.0.txt).
Releases up to 2.1.0 were published under the MIT License.

The Wine patches in `patches/wine` are LGPL-2.1-or-later, like Wine
The files of the Wine module adapted from Wine (`src/wine/pe/wgl_formats.c`,
`src/wine/pe/wgl_fonts.c`) are LGPL-2.1-or-later, like Wine
(`LICENSES/Wine-LGPL-2.1.txt`). The vendored glslang and SPIRV-Cross keep
their own licenses (`LICENSES/`).
2 changes: 1 addition & 1 deletion SECURITY.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ GL and WGL call. In scope:
writes, use-after-free, integer overflows in sizes and offsets);
- input that crashes or hangs the host process or the GPU beyond the program
that sent it;
- problems in the Wine patches in `patches/wine` or in the release packages.
- problems in the Wine module in `src/wine` or in the release packages.

Out of scope, and better reported where they belong:

Expand Down
Loading
Loading