Unverified Commit 5a29cb59 authored by Ivan Matkov's avatar Ivan Matkov Committed by GitHub

Transparency support for D3D swap chain (#837)

* Transparency support for D3D swap chain

* Store composition objects in DirectXDevice

* Fix AWT transparent sample
parent f4c5a4ec
...@@ -40,7 +40,7 @@ fun createWindow(title: String, exitOnClose: Boolean) = SwingUtilities.invokeLat ...@@ -40,7 +40,7 @@ fun createWindow(title: String, exitOnClose: Boolean) = SwingUtilities.invokeLat
window.defaultCloseOperation = window.defaultCloseOperation =
if (exitOnClose) WindowConstants.EXIT_ON_CLOSE else WindowConstants.DISPOSE_ON_CLOSE if (exitOnClose) WindowConstants.EXIT_ON_CLOSE else WindowConstants.DISPOSE_ON_CLOSE
window.background = Color.GREEN window.background = Color.GREEN
window.contentPane = skiaLayer window.contentPane.add(skiaLayer)
// Create menu. // Create menu.
val menuBar = JMenuBar() val menuBar = JMenuBar()
...@@ -120,11 +120,33 @@ fun createWindow(title: String, exitOnClose: Boolean) = SwingUtilities.invokeLat ...@@ -120,11 +120,33 @@ fun createWindow(title: String, exitOnClose: Boolean) = SwingUtilities.invokeLat
// Window transparency // Window transparency
if (System.getProperty("skiko.transparency") == "true") { if (System.getProperty("skiko.transparency") == "true") {
window.isUndecorated = true window.isUndecorated = true
// On Windows we don't set transparent background to avoid event input issues (JDK specific)
if (hostOs != OS.Windows) { /**
* There is a hack inside skiko OpenGL and Software redrawers for Windows that makes current
* window transparent without setting `background` to JDK's window. It's done by getting native
* component parent and calling `DwmEnableBlurBehindWindow`.
*
* FIXME: Make OpenGL work inside transparent window (background == Color(0, 0, 0, 0)) without this hack.
*
* See `enableTransparentWindow` (skiko/src/awtMain/cpp/windows/window_util.cc)
*/
if (hostOs != OS.Windows || skiaLayer.renderApi == GraphicsApi.DIRECT3D) {
window.background = Color(0, 0, 0, 0) window.background = Color(0, 0, 0, 0)
} }
skiaLayer.transparency = true skiaLayer.transparency = true
/*
* Windows makes clicks on transparent pixels fall through, but it doesn't work
* with GPU accelerated rendering since this check requires having access to pixels from CPU.
*
* JVM doesn't allow override this behaviour with low-level windows methods, so hack this in this way.
* Based on tests, it doesn't affect resulting pixel color.
*/
if (hostOs == OS.Windows) {
val contentPane = window.contentPane as JComponent
contentPane.background = Color(0, 0, 0, 1)
contentPane.isOpaque = true
}
} else { } else {
skiaLayer.background = Color.LIGHT_GRAY skiaLayer.background = Color.LIGHT_GRAY
} }
......
...@@ -20,6 +20,9 @@ ...@@ -20,6 +20,9 @@
#include <dxgi1_4.h> #include <dxgi1_4.h>
#include <dxgi1_6.h> #include <dxgi1_6.h>
#include <dcomp.h>
#pragma comment(lib, "dcomp.lib")
const int BuffersCount = 2; const int BuffersCount = 2;
class DirectXDevice class DirectXDevice
...@@ -32,6 +35,9 @@ public: ...@@ -32,6 +35,9 @@ public:
gr_cp<ID3D12CommandQueue> queue; gr_cp<ID3D12CommandQueue> queue;
gr_cp<ID3D12Resource> buffers[BuffersCount]; gr_cp<ID3D12Resource> buffers[BuffersCount];
gr_cp<ID3D12Fence> fence; gr_cp<ID3D12Fence> fence;
gr_cp<IDCompositionDevice> dcDevice;
gr_cp<IDCompositionTarget> dcTarget;
gr_cp<IDCompositionVisual> dcVisual;
uint64_t fenceValues[BuffersCount]; uint64_t fenceValues[BuffersCount];
HANDLE fenceEvent = NULL; HANDLE fenceEvent = NULL;
unsigned int bufferIndex; unsigned int bufferIndex;
...@@ -53,24 +59,36 @@ public: ...@@ -53,24 +59,36 @@ public:
} }
void initSwapChain() { void initSwapChain() {
RECT windowRect;
GetClientRect(window, &windowRect);
UINT width = windowRect.right - windowRect.left;
UINT height = windowRect.bottom - windowRect.top;
gr_cp<IDXGIFactory4> swapChainFactory4; gr_cp<IDXGIFactory4> swapChainFactory4;
gr_cp<IDXGISwapChain1> swapChain1; gr_cp<IDXGISwapChain1> swapChain1;
CreateDXGIFactory2(0, IID_PPV_ARGS(&swapChainFactory4)); CreateDXGIFactory2(0, IID_PPV_ARGS(&swapChainFactory4));
DXGI_SWAP_CHAIN_DESC1 swapChainDesc = {}; DXGI_SWAP_CHAIN_DESC1 swapChainDesc = {};
swapChainDesc.BufferCount = BuffersCount; swapChainDesc.Width = width;
swapChainDesc.Height = height;
swapChainDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; swapChainDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
swapChainDesc.SampleDesc.Count = 1;
swapChainDesc.SampleDesc.Quality = 0;
swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
swapChainDesc.BufferCount = BuffersCount;
swapChainDesc.Scaling = DXGI_SCALING_STRETCH;
swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD; swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD;
swapChainDesc.SampleDesc.Count = 1; swapChainDesc.AlphaMode = DXGI_ALPHA_MODE_PREMULTIPLIED;
swapChainDesc.Scaling = DXGI_SCALING_NONE; swapChainFactory4->CreateSwapChainForComposition(queue.get(), &swapChainDesc, nullptr, &swapChain1);
swapChainFactory4->CreateSwapChainForHwnd(queue.get(), window, &swapChainDesc, nullptr, nullptr, &swapChain1);
DCompositionCreateDevice(0, IID_PPV_ARGS(&dcDevice));
dcDevice->CreateTargetForHwnd(window, true, &dcTarget);
dcDevice->CreateVisual(&dcVisual);
dcVisual->SetContent(swapChain1.get());
dcTarget->SetRoot(dcVisual.get());
dcDevice->Commit();
swapChainFactory4->MakeWindowAssociation(window, DXGI_MWA_NO_ALT_ENTER); swapChainFactory4->MakeWindowAssociation(window, DXGI_MWA_NO_ALT_ENTER);
swapChain1->QueryInterface(IID_PPV_ARGS(&swapChain)); swapChain1->QueryInterface(IID_PPV_ARGS(&swapChain));
RECT windowRect;
GetWindowRect(window, &windowRect);
unsigned int w = windowRect.right - windowRect.left;
unsigned int h = windowRect.bottom - windowRect.top;
swapChain->ResizeBuffers(BuffersCount, w, h, DXGI_FORMAT_R8G8B8A8_UNORM, 0);
swapChainFactory4.reset(nullptr); swapChainFactory4.reset(nullptr);
} }
}; };
...@@ -292,6 +310,7 @@ extern "C" ...@@ -292,6 +310,7 @@ extern "C"
return 0; return 0;
} }
HWND hWnd = fromJavaPointer<HWND>(contentHandle);
DirectXDevice *d3dDevice = new DirectXDevice(); DirectXDevice *d3dDevice = new DirectXDevice();
d3dDevice->backendContext.fAdapter = adapter; d3dDevice->backendContext.fAdapter = adapter;
d3dDevice->backendContext.fDevice = device; d3dDevice->backendContext.fDevice = device;
...@@ -300,13 +319,11 @@ extern "C" ...@@ -300,13 +319,11 @@ extern "C"
d3dDevice->device = device; d3dDevice->device = device;
d3dDevice->queue = queue; d3dDevice->queue = queue;
d3dDevice->window = (HWND)contentHandle; d3dDevice->window = hWnd;
if (transparency) { if (transparency) {
//TODO: current swapChain does not support transparency const LONG style = GetWindowLong(hWnd, GWL_EXSTYLE);
return 0; SetWindowLong(hWnd, GWL_EXSTYLE, style | WS_EX_TRANSPARENT);
// HWND wnd = GetAncestor(d3dDevice->window, GA_PARENT);
// enableTransparentWindow(wnd);
} }
return toJavaPointer(d3dDevice); return toJavaPointer(d3dDevice);
......
package org.jetbrains.skiko.redrawer package org.jetbrains.skiko.redrawer
import kotlinx.coroutines.asCoroutineDispatcher
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import org.jetbrains.skia.DirectContext import org.jetbrains.skia.DirectContext
import org.jetbrains.skia.Surface import org.jetbrains.skia.Surface
import org.jetbrains.skia.SurfaceProps import org.jetbrains.skia.SurfaceProps
import org.jetbrains.skia.impl.interopScope
import org.jetbrains.skia.impl.InteropPointer import org.jetbrains.skia.impl.InteropPointer
import org.jetbrains.skia.impl.interopScope
import org.jetbrains.skiko.* import org.jetbrains.skiko.*
import org.jetbrains.skiko.context.Direct3DContextHandler import org.jetbrains.skiko.context.Direct3DContextHandler
......
...@@ -27,6 +27,7 @@ expect open class SkiaLayer { ...@@ -27,6 +27,7 @@ expect open class SkiaLayer {
* If rendering is full screen. * If rendering is full screen.
*/ */
var fullscreen: Boolean var fullscreen: Boolean
/** /**
* If transparency is enabled. * If transparency is enabled.
*/ */
......
...@@ -59,6 +59,11 @@ JNIEXPORT void JNICALL Java_org_jetbrains_skiko_context_Direct3DContextHandler_f ...@@ -59,6 +59,11 @@ JNIEXPORT void JNICALL Java_org_jetbrains_skiko_context_Direct3DContextHandler_f
skikoUnimplemented("Java_org_jetbrains_skiko_context_Direct3DContextHandler_flush"); skikoUnimplemented("Java_org_jetbrains_skiko_context_Direct3DContextHandler_flush");
} }
JNIEXPORT jlong JNICALL Java_org_jetbrains_skiko_redrawer_Direct3DRedrawer_chooseAdapter(JNIEnv *env, jobject redrawer, jint adapterPriority) {
skikoUnimplemented("Java_org_jetbrains_skiko_redrawer_Direct3DRedrawer_chooseAdapter");
return 0;
}
JNIEXPORT jlong JNICALL Java_org_jetbrains_skiko_redrawer_Direct3DRedrawer_createDirectXDevice( JNIEXPORT jlong JNICALL Java_org_jetbrains_skiko_redrawer_Direct3DRedrawer_createDirectXDevice(
JNIEnv *env, jobject redrawer, jint adapterPriority, jlong contentHandle, jboolean transparency) { JNIEnv *env, jobject redrawer, jint adapterPriority, jlong contentHandle, jboolean transparency) {
skikoUnimplemented("Java_org_jetbrains_skiko_redrawer_Direct3DRedrawer_createDirectXDevice"); skikoUnimplemented("Java_org_jetbrains_skiko_redrawer_Direct3DRedrawer_createDirectXDevice");
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment