[Bug]: Windows peer reports Direct2D as an available renderer under Wine but never selects it
Detailed steps on how to reproduce the bug
The Windows peer's renderer selection contradicts its own public API when juce_isRunningInWine() is true.
Component::createNewPeer hard-selects index 0 (juce_Windowing_windows.cpp, develop @ a18ae60e46, 2026-08-27):
extern bool juce_isRunningInWine();
ComponentPeer* Component::createNewPeer (int styleFlags, void* parentHWND)
{
const auto renderer = juce_isRunningInWine() ? 0 : 1;
return new HWNDComponentPeer { *this, styleFlags, (HWND) parentHWND, false, renderer };
}getAvailableRenderingEngines() and setCurrentRenderingEngine() in the same file know nothing about that condition — both are unconditional over contextDescriptorList<GDIRenderContext, D2DRenderContext>.
I built a minimal JUCE 8.0.15 GUI app (MinGW cross-compile) that logs the peer's renderer API and then calls setCurrentRenderingEngine(). Run under Wine with wine_get_version left visible. The tree is the 8.0.15 tag plus nine small MinGW compile fixes (__uuidof on interface types instead of variables, one header-signature argument, a missing CLSID definition, CPUID); none of them touch renderer or image-type selection:
--- renderer API state as reported by JUCE ---
getAvailableRenderingEngines(): Software Renderer | Direct2D (count=2)
getCurrentRenderingEngine(): 0 -> Software Renderer
calling setCurrentRenderingEngine(1)
getCurrentRenderingEngine() after call: 1 -> Direct2D
RESULT: switch ACCEPTEDSo at run time, under Wine:
getAvailableRenderingEngines()advertises Direct2D as available.createNewPeernever selects it.setCurrentRenderingEngine (1)accepts it and builds theD2DRenderContext.
Counting d2d1 entry points with WINEDEBUG=+d2d over identical 40-second runs of that app confirms the switch is real and not just a change of name:
setCurrentRenderingEngine |
d2d1 calls | of which d2d_device_context_* |
|---|---|---|
| not called (peer's own choice) | 28 | 0 |
(0) — Software Renderer |
28 | 0 |
(1) — Direct2D |
889 | 590 |
Either Direct2D is unusable in this configuration, in which case (1) and (3) should not offer or accept it; or it is usable, in which case (2) is the odd one out. Right now the API asserts both.
There is a second, related asymmetry. NativeImageType::create (juce_Direct2DImage_windows.cpp) applies the same detection:
if (! juce_isRunningInWine())
{
...
return new Direct2DPixelData (format, width, height, clearImage);
}
return new SoftwarePixelData { format, width, height, clearImage };That one has no peer, and so no equivalent of setCurrentRenderingEngine — Direct2DPixelData is not reachable through the public API (the class lives in a native header the module does not export). A caller who switches the peer to Direct2D through the public API still gets software-backed images, so the two halves of the decision can disagree with each other.
What is the expected behaviour?
That the renderer API agrees with itself. Either:
getAvailableRenderingEngines()omits Direct2D andsetCurrentRenderingEnginerejects it while the forced selection is in effect, so the constraint is visible through the public API andNativeImageType::createis consistent with it; or- the forced selection in
createNewPeeracts as a default rather than an override, so that a caller who explicitly asks for Direct2D — which the API already lets them do — gets it consistently, images included.
Which of the two is right is your call. The current state is that getAvailableRenderingEngines() reports a renderer that createNewPeer will never pick and that NativeImageType::create will never honour.
For context: 5179690ff7 ("Restore Wine functionality") introduced the forced selection between 8.0.12 and 8.0.13. This is not a request to support Wine, and the default behaviour introduced there is not in question — only that one selection path bypasses the API that describes it.
Operating systems
Windows
What versions of the operating systems?
Observed on Linux under a Wine build based on 11.0 stable (giang17/wine, d2d1-dcomp-11.0, which implements the Direct2D 1.3 surface the renderer needs), which is where juce_isRunningInWine() returns true. The API behaviour above does not depend on that build — setCurrentRenderingEngine constructs the context unconditionally — but the d2d1 call counts do. The inconsistency is in the Windows peer itself; on Windows the predicate is simply always false, so it is latent there.
Architectures
x86_64
Stacktrace
No response
Plug-in formats (if applicable)
Standalone
Plug-in host applications (DAWs) (if applicable)
No response
Testing on the develop branch
The bug is present on the develop branch (read in the source at a18ae60e46; the run-time test above was built from the 8.0.15 tag, where the functions involved are the same)
Code of Conduct
- I agree to follow the Code of Conduct
Source: juce-framework/JUCE