## Description

This PR is for review and integration of Direct3D 12 Rendering Pipeline into 
JavaFX mainline. We released three Early Access (EA) versions of this 
implementation while keeping the development ongoing on [JavaFX 
Sandbox](https://github.com/openjdk/jfx-sandbox/tree/direct3d12) and reached a 
stage where it is ready to be integrated into mainline. Any further work and 
potential fixes will be done on mainline.

At the time of writing, this PR is identical to the [JavaFX Sandbox D3D12 
branch](https://github.com/openjdk/jfx-sandbox/tree/direct3d12) with only one 
difference - the Sandbox defaults to D3D12 backend. This PR, however, does 
*NOT* change the default rendering pipeline on Windows. D3D9 remains the 
default rendering pipeline and D3D12 is optional - it can be selected by 
providing `-Dprism.order=d3d12`. To verify which pipeline is actually in use 
`-Dprism.verbose=true` is recommended.

## Details

Below are general changes introduced by the backend:

### JSL changes

- Introduced `HLSL6Backend` class which translates JSL shader code into HLSL6 
code. D3D12 introduced HLSL Shader Level 6 support and won't support existing 
HLSL shaders used with D3D9, as those are compiled for unsupported Shader Level 
3.
- D3D12-specific shaders are kept in 
`modules/javafx.graphics/src/main/native-prism-d3d12/hlsl6`
- Shader compilation is done with DXC instead of FXC (FXC does not support 
SL6). DXC is bundled in Windows SDK which JavaFX already integrates with.
- Backend also generates C++ headers with Shader resource binding information, 
used by the native-side

### Build changes

- Added new build tasks for generation and compilation of HLSL6 shaders for 
D3D12
- Added tasks to compile D3D12 native backend code

### Prism changes

- Added D3D12-specific Java classes (package `com.sun.prism.d3d12`) and a 
Java-to-JNI layer (package `com.sun.prism.d3d12.ni`)
  - Java implementation is mostly similar to D3D9 implementation, with only 
some minor changes needed to accommodate slightly different presentation 
behavior of the new runtime
  - JNI interface is relatively high level to reduce the amount of JNI calls 
for performance
- Added a native Prism backend implementation using D3D12 runtime (stored in 
`modules/javafx.graphics/src/main/native-prism-d3d12`)
  - Written in C++ 20
  - Uses only interfaces available via Windows API with no third-party 
libraries - WinAPI, Windows COM interface system and "barebones" Direct3D 12 
API/runtime
  - Native layer entry-points are kept in `D3D12` namespace and stored in 
`(...)/native-prism-d3d12`
    - Responsible of exposing JNI entry point implementations and translating 
JNI primitives into C++ types/objects
    - Each `com.sun.prism.d3d12.ni` Java class has its respective C++ class as 
an entry point with 1:1 Java->C++ method mapping
    - C++-side allocates a shared_ptr instance and passes over a pointer 
address to Java objects
    - Designed to stay as close as possible to object-oriented design principles
  - Internal classes used by the entry points are kept in `D3D12::Internal` 
namespace and stored in `(...)/native-prism-d3d12/internal`
    - Contains `RenderingContext` class which imitates old API behavior - 
brings abstraction level closer to D3D12 API
    - `RenderingContext` prepares payloads and executes them on the 
`RenderThread`
    - Also contains other common mechanisms and classes that are shared across 
the backend - `Matrix`, `JNIBuffer`, `JNIString` etc
  - RenderThread implementation kept in `D3D12::RenderThread` namespace and 
stored in `(...)/native-prism-d3d12/render-thread`
    - Preparation of GPU workloads and recording D3D12 Command Lists takes a 
lot of CPU time, which causes low performance on machines with stronger dGPUs - 
dGPU will be done with its workload way faster than CPU can prepare the next 
one. `RenderThread` offloads this work to a separate CPU thread which allows to 
improve (and in some cases surpass - YMMV) D3D9 performance
    - Contains classes used inside the `RenderThread` to low-level manage D3D12 
resources and data needed for rendering
  - Shader implementation kept in `D3D12::Shaders` namespace and stored in 
`(...)/native-prism-d3d12/shaders`
    - Contains abstract `Shader` class and implementations depending on what 
type of Shader the backend works with
    - Integrates with C++ headers generated by JSLC on build time to know what 
Shaders to expect and what resources to bind for them
    - Four types of Shaders supported so far:
      - `NativeShader` - integrates with Java-side `D3D12Shader` class to 
provide Prism/Decora shader support
      - `InternalShader` - integrates with internal backend shaders (ex. 
Passthrough, Phong) kept in `hlsl6` directory
      - `BlitPixelShader` - simple Pixel shader used to provide Blit 
functionality (not provided by D3D12 API)
      - `MipmapGenComputeShader` - Compute shader used for texture mipmap 
generation (not provided by D3D12 API)

### RenderPerfTest changes

- Added new test cases which check for some edge cases missed earlier - `Label` 
and `RandomSizeText`
- Added support for running multiple tests in one launch
- Improved test result and error reporting

## Testing

Testing was done on different Windows hardware - some laptops with weaker 
integrated GPUs, one PC with dedicated NVidia GPU unit + community testing done 
during EA phase. All testing done on latest available Windows 11 26H2 version.
- Functional testing:
  - All headful tests pass on D3D12 pipeline in both Release and Debug
  - Verified samples: Ensemble and Toys
- Performance testing:
  -  Tested with `RenderPerfTest`
      - On iGPU machines all tests match/surpass D3D9 backend.
      - On dGPU machine (7950X, 4080S) many tests match/surpass D3D9 backend, 
but some are within the 80-85% range. Those will be addressed later on and are 
now tracked by [JDK-8388012](https://bugs.openjdk.org/browse/JDK-8388012).
  - Tested with recent update to `3DLighting`:
    - On iGPU, with 5000 meshes and 3 point lights - performance is ~114% of 
D3D9 (240FPS on 12 vs 210FPS on 9 with current master)

## Properties

D3D12 backend can be configured and tested using some known and new Java 
properties:
- `prism.verbose` - Adds verbose logging
- `prism.debug` - Adds debug logging, requires build with `-PCONF=DebugNative`
- `prism.d3d12.dred` - Adds D3D12 DRED breadcrumbs for debugging device crashes
- `prism.d3d12.colorLogs` - Pretty-colors logs on console depending on severity
- `prism.d3d12.fileLog` - Adds log output to a new file in current working 
directory

Below properties require debug logging to be enabled (`prism.debug` property + 
build in `DebugNative`):
- `prism.d3d12.trace` - Adds memory allocation/free trace logging
- `prism.d3d12.printShaderLoad` - Adds information on Shader resources when 
Shaders are loaded
- `prism.d3d12.debugLayers` - Enables Debug Validation Layers from D3D12 SDK, 
which will run extra API conformity checks.
- `prism.d3d12.gpuDebug` - Enables GPU debugging from D3D12 SDK, which will run 
additional on-GPU checks at a major performance cost. Requires 
`prism.d3d12.debugLayers`.
- `prism.d3d12.breakOnError` - Enables triggering a debug assertion upon Debug 
Layer errors. Requires `prism.d3d12.debugLayers`.

## Final notes to reviewers

- To test this pipeline you *MUST* provide `-Dprism.order=d3d12`
- There is no Glass or higher-level changes other than necessary one-line 
additions (ex. support for new Shader Model version in Decora). However, it is 
recommended to also test these changes with D3D9.
- Known issues are tagged in JBS with `javafx-d3d12` tag and can be found here: 
https://bugs.openjdk.org/issues/?filter=51118

---------
- [x] I confirm that I make this contribution in accordance with the [OpenJDK 
Interim AI Policy](https://openjdk.org/legal/ai).

-------------

Commit messages:
 - Implement Direct3D12 Rendering Pipeline

Changes: https://git.openjdk.org/jfx/pull/2346/files
  Webrev: https://webrevs.openjdk.org/?repo=jfx&pr=2346&range=00
  Issue: https://bugs.openjdk.org/browse/JDK-8394770
  Stats: 25167 lines in 155 files changed: 25048 ins; 6 del; 113 mod
  Patch: https://git.openjdk.org/jfx/pull/2346.diff
  Fetch: git fetch https://git.openjdk.org/jfx.git pull/2346/head:pull/2346

PR: https://git.openjdk.org/jfx/pull/2346

Reply via email to