Commit f1b93ac7 authored by Roman Sedaikin's avatar Roman Sedaikin

Reinit render target/surface/canvas only when the SkiaLayer is resized (DirectX).

parent 0158424b
...@@ -90,11 +90,31 @@ class Renderer( ...@@ -90,11 +90,31 @@ class Renderer(
var canvas: Canvas? = null var canvas: Canvas? = null
override fun onRender(canvas: Canvas, width: Int, height: Int, nanoTime: Long) { override fun onRender(canvas: Canvas, width: Int, height: Int, nanoTime: Long) {
this.canvas = canvas // this.canvas = canvas
val contentScale = layer.contentScale // val contentScale = layer.contentScale
canvas.scale(contentScale, contentScale) // canvas.scale(contentScale, contentScale)
displayScene(this, (width / contentScale).toInt(), (height / contentScale).toInt(), nanoTime) // displayScene(this, (width / contentScale).toInt(), (height / contentScale).toInt(), nanoTime)
layer.needRedraw() // layer.needRedraw()
//////////////////////////////////////////////////
val pictureRecorder = PictureRecorder()
val pictureCanvas = pictureRecorder.beginRecording(
Rect.makeLTRB(
0f,
0f,
100f,
100f
)
)
pictureCanvas.drawLine(0f, 0f, 100f, 100f, Paint())
val picture = pictureRecorder.finishRecordingAsPicture()
canvas.drawPicture(
picture,
null,
Paint() // if we replace it by null, everything will be normal
)
canvas.drawLine(100f, 0f, 0f, 100f, Paint())
//////////////////////////////////////////////////
} }
} }
......
...@@ -33,32 +33,27 @@ const int BuffersCount = 2; ...@@ -33,32 +33,27 @@ const int BuffersCount = 2;
// with the current Swing/Skia integration. // with the current Swing/Skia integration.
// If PC has other graphics cards suitable for DirectX12, one of them will be used. Otherwise, // If PC has other graphics cards suitable for DirectX12, one of them will be used. Otherwise,
// rendering will falls back to OpenGL. // rendering will falls back to OpenGL.
const std::vector<std::wstring> adapterBlacklist { const std::vector<std::wstring> adapterBlacklist{
L"Microsoft Basic Render Driver", L"Microsoft Basic Render Driver",
L"Intel(R) HD Graphics 520", L"Intel(R) HD Graphics 520",
L"Intel(R) HD Graphics 530", L"Intel(R) HD Graphics 530",
L"NVIDIA GeForce GTX 750 Ti", L"NVIDIA GeForce GTX 750 Ti",
L"NVIDIA GeForce GTX 960M", L"NVIDIA GeForce GTX 960M",
L"NVIDIA Quadro M2000M" }; L"NVIDIA Quadro M2000M"};
class DirectXDevice class DirectXDevice
{ {
public: public:
HWND window;
GrD3DBackendContext backendContext; GrD3DBackendContext backendContext;
gr_cp<ID3D12Device> device; gr_cp<ID3D12Device> device;
gr_cp<IDXGISwapChain3> swapChain; gr_cp<IDXGISwapChain3> swapChain;
gr_cp<ID3D12CommandQueue> queue; gr_cp<ID3D12CommandQueue> queue;
gr_cp<ID3D12Resource> buffers[BuffersCount];
gr_cp<ID3D12Fence> fence; gr_cp<ID3D12Fence> fence;
uint64_t fenceValues[BuffersCount];
HANDLE fenceEvent = NULL; HANDLE fenceEvent = NULL;
uint64_t fenceValue; unsigned int bufferIndex;
unsigned int bufferIndex = 0;
unsigned int bufferWidth = 0;
unsigned int bufferHeight = 0;
bool isSizeEqualTo(unsigned int width, unsigned int height)
{
return width == bufferWidth && height == bufferHeight;
}
~DirectXDevice() ~DirectXDevice()
{ {
...@@ -66,6 +61,10 @@ public: ...@@ -66,6 +61,10 @@ public:
{ {
CloseHandle(fenceEvent); CloseHandle(fenceEvent);
} }
for (int i = 0; i < BuffersCount; i++)
{
buffers[i].reset(nullptr);
}
fence.reset(nullptr); fence.reset(nullptr);
swapChain.reset(nullptr); swapChain.reset(nullptr);
queue.reset(nullptr); queue.reset(nullptr);
...@@ -76,20 +75,20 @@ public: ...@@ -76,20 +75,20 @@ public:
extern "C" extern "C"
{ {
HRESULT D3D12CreateDevice( HRESULT D3D12CreateDevice(
IUnknown *pAdapter, IUnknown *pAdapter,
D3D_FEATURE_LEVEL MinimumFeatureLevel, D3D_FEATURE_LEVEL MinimumFeatureLevel,
REFIID riid, REFIID riid,
void **ppDevice void **ppDevice)
) { {
typedef HRESULT (*D3D12CreateDevice_t)( typedef HRESULT (*D3D12CreateDevice_t)(
IUnknown *pAdapter, IUnknown * pAdapter,
D3D_FEATURE_LEVEL MinimumFeatureLevel, D3D_FEATURE_LEVEL MinimumFeatureLevel,
REFIID riid, REFIID riid,
void **ppDevice void **ppDevice);
);
static D3D12CreateDevice_t impl = nullptr; static D3D12CreateDevice_t impl = nullptr;
if (!impl) { if (!impl)
{
auto d3d12dll = LoadLibrary(TEXT("D3D12.dll")); auto d3d12dll = LoadLibrary(TEXT("D3D12.dll"));
if (!d3d12dll) if (!d3d12dll)
return E_NOTIMPL; return E_NOTIMPL;
...@@ -98,22 +97,22 @@ HRESULT D3D12CreateDevice( ...@@ -98,22 +97,22 @@ HRESULT D3D12CreateDevice(
return E_NOTIMPL; return E_NOTIMPL;
} }
return impl(pAdapter, MinimumFeatureLevel, riid, ppDevice); return impl(pAdapter, MinimumFeatureLevel, riid, ppDevice);
} }
HRESULT D3D12SerializeRootSignature( HRESULT D3D12SerializeRootSignature(
const D3D12_ROOT_SIGNATURE_DESC *pRootSignature, const D3D12_ROOT_SIGNATURE_DESC *pRootSignature,
D3D_ROOT_SIGNATURE_VERSION Version, D3D_ROOT_SIGNATURE_VERSION Version,
ID3DBlob **ppBlob, ID3DBlob **ppBlob,
ID3DBlob **ppErrorBlob ID3DBlob **ppErrorBlob)
) { {
typedef HRESULT (*D3D12SerializeRootSignature_t)( typedef HRESULT (*D3D12SerializeRootSignature_t)(
const D3D12_ROOT_SIGNATURE_DESC *pRootSignature, const D3D12_ROOT_SIGNATURE_DESC *pRootSignature,
D3D_ROOT_SIGNATURE_VERSION Version, D3D_ROOT_SIGNATURE_VERSION Version,
ID3DBlob **ppBlob, ID3DBlob **ppBlob,
ID3DBlob **ppErrorBlob ID3DBlob **ppErrorBlob);
);
static D3D12SerializeRootSignature_t impl = nullptr; static D3D12SerializeRootSignature_t impl = nullptr;
if (!impl) { if (!impl)
{
auto d3d12dll = LoadLibrary(TEXT("D3D12.dll")); auto d3d12dll = LoadLibrary(TEXT("D3D12.dll"));
if (!d3d12dll) if (!d3d12dll)
return E_NOTIMPL; return E_NOTIMPL;
...@@ -122,18 +121,18 @@ HRESULT D3D12SerializeRootSignature( ...@@ -122,18 +121,18 @@ HRESULT D3D12SerializeRootSignature(
return E_NOTIMPL; return E_NOTIMPL;
} }
return impl(pRootSignature, Version, ppBlob, ppErrorBlob); return impl(pRootSignature, Version, ppBlob, ppErrorBlob);
} }
HRESULT CreateDXGIFactory1( HRESULT CreateDXGIFactory1(
REFIID riid, REFIID riid,
void **ppFactory void **ppFactory)
) { {
typedef HRESULT (*CreateDXGIFactory1_t)( typedef HRESULT (*CreateDXGIFactory1_t)(
REFIID riid, REFIID riid,
void **ppFactory void **ppFactory);
);
static CreateDXGIFactory1_t impl = nullptr; static CreateDXGIFactory1_t impl = nullptr;
if (!impl) { if (!impl)
{
auto dxgidll = LoadLibrary(TEXT("Dxgi.dll")); auto dxgidll = LoadLibrary(TEXT("Dxgi.dll"));
if (!dxgidll) if (!dxgidll)
return E_NOTIMPL; return E_NOTIMPL;
...@@ -142,20 +141,20 @@ HRESULT CreateDXGIFactory1( ...@@ -142,20 +141,20 @@ HRESULT CreateDXGIFactory1(
return E_NOTIMPL; return E_NOTIMPL;
} }
return impl(riid, ppFactory); return impl(riid, ppFactory);
} }
HRESULT CreateDXGIFactory2( HRESULT CreateDXGIFactory2(
UINT Flags, UINT Flags,
REFIID riid, REFIID riid,
void **ppFactory void **ppFactory)
) { {
typedef HRESULT (*CreateDXGIFactory2_t)( typedef HRESULT (*CreateDXGIFactory2_t)(
UINT Flags, UINT Flags,
REFIID riid, REFIID riid,
void **ppFactory void **ppFactory);
);
static CreateDXGIFactory2_t impl = nullptr; static CreateDXGIFactory2_t impl = nullptr;
if (!impl) { if (!impl)
{
auto dxgidll = LoadLibrary(TEXT("Dxgi.dll")); auto dxgidll = LoadLibrary(TEXT("Dxgi.dll"));
if (!dxgidll) if (!dxgidll)
return E_NOTIMPL; return E_NOTIMPL;
...@@ -164,9 +163,9 @@ HRESULT CreateDXGIFactory2( ...@@ -164,9 +163,9 @@ HRESULT CreateDXGIFactory2(
return E_NOTIMPL; return E_NOTIMPL;
} }
return impl(Flags, riid, ppFactory); return impl(Flags, riid, ppFactory);
} }
HRESULT D3DCompile( HRESULT D3DCompile(
LPCVOID pSrcData, LPCVOID pSrcData,
SIZE_T SrcDataSize, SIZE_T SrcDataSize,
LPCSTR pSourceName, LPCSTR pSourceName,
...@@ -177,8 +176,8 @@ HRESULT D3DCompile( ...@@ -177,8 +176,8 @@ HRESULT D3DCompile(
UINT Flags1, UINT Flags1,
UINT Flags2, UINT Flags2,
ID3DBlob **ppCode, ID3DBlob **ppCode,
ID3DBlob **ppErrorMsgs ID3DBlob **ppErrorMsgs)
) { {
typedef HRESULT (*D3DCompile_t)( typedef HRESULT (*D3DCompile_t)(
LPCVOID pSrcData, LPCVOID pSrcData,
SIZE_T SrcDataSize, SIZE_T SrcDataSize,
...@@ -190,10 +189,10 @@ HRESULT D3DCompile( ...@@ -190,10 +189,10 @@ HRESULT D3DCompile(
UINT Flags1, UINT Flags1,
UINT Flags2, UINT Flags2,
ID3DBlob **ppCode, ID3DBlob **ppCode,
ID3DBlob **ppErrorMsgs ID3DBlob **ppErrorMsgs);
);
static D3DCompile_t impl = nullptr; static D3DCompile_t impl = nullptr;
if (!impl) { if (!impl)
{
auto d3dcompilerdll = LoadLibrary(TEXT("d3dcompiler_47.dll")); auto d3dcompilerdll = LoadLibrary(TEXT("d3dcompiler_47.dll"));
if (!d3dcompilerdll) if (!d3dcompilerdll)
return E_NOTIMPL; return E_NOTIMPL;
...@@ -202,48 +201,15 @@ HRESULT D3DCompile( ...@@ -202,48 +201,15 @@ HRESULT D3DCompile(
return E_NOTIMPL; return E_NOTIMPL;
} }
return impl(pSrcData, SrcDataSize, pSourceName, pDefines, pInclude, pEntrypoint, pTarget, Flags1, Flags2, ppCode, ppErrorMsgs); return impl(pSrcData, SrcDataSize, pSourceName, pDefines, pInclude, pEntrypoint, pTarget, Flags1, Flags2, ppCode, ppErrorMsgs);
}
JNIEXPORT jlong JNICALL Java_org_jetbrains_skiko_redrawer_Direct3DRedrawer_makeDirectXContext(
JNIEnv* env, jobject redrawer, jlong devicePtr)
{
DirectXDevice *d3dDevice = fromJavaPointer<DirectXDevice*>(devicePtr);
GrD3DBackendContext backendContext = d3dDevice->backendContext;
return toJavaPointer(GrDirectContext::MakeDirect3D(backendContext).release());
} }
JNIEXPORT jlong JNICALL Java_org_jetbrains_skiko_redrawer_Direct3DRedrawer_makeDirectXRenderTarget( bool isBlacklisted(IDXGIAdapter1 *hardwareAdapter)
JNIEnv * env, jobject redrawer, jlong devicePtr, jint width, jint height)
{
DirectXDevice *d3dDevice = fromJavaPointer<DirectXDevice*>(devicePtr);
if (!d3dDevice->isSizeEqualTo(width, height))
{
GR_D3D_CALL_ERRCHECK(d3dDevice->swapChain->ResizeBuffers(BuffersCount, width, height, DXGI_FORMAT_R8G8B8A8_UNORM, 0));
d3dDevice->bufferWidth = width;
d3dDevice->bufferHeight = height;
}
d3dDevice->bufferIndex = d3dDevice->swapChain->GetCurrentBackBufferIndex();
ID3D12Resource* buffer;
GR_D3D_CALL_ERRCHECK(d3dDevice->swapChain->GetBuffer(d3dDevice->bufferIndex, IID_PPV_ARGS(&buffer)));
GrD3DTextureResourceInfo info(buffer,
nullptr,
D3D12_RESOURCE_STATE_PRESENT,
DXGI_FORMAT_R8G8B8A8_UNORM,
1,
1,
0);
GrBackendRenderTarget* renderTarget = new GrBackendRenderTarget(width, height, info);
return toJavaPointer(renderTarget);
}
bool isBlacklisted(IDXGIAdapter1* hardwareAdapter)
{ {
DXGI_ADAPTER_DESC1 desc; DXGI_ADAPTER_DESC1 desc;
hardwareAdapter->GetDesc1(&desc); hardwareAdapter->GetDesc1(&desc);
std::wstring currentAdapterName(desc.Description); std::wstring currentAdapterName(desc.Description);
for (std::wstring name : adapterBlacklist) { for (std::wstring name : adapterBlacklist)
{
if (currentAdapterName == name) if (currentAdapterName == name)
{ {
fwprintf(stderr, L"Graphics card: %s is blacklisted.\n", name.c_str()); fwprintf(stderr, L"Graphics card: %s is blacklisted.\n", name.c_str());
...@@ -312,13 +278,21 @@ HRESULT D3DCompile( ...@@ -312,13 +278,21 @@ HRESULT D3DCompile(
d3dDevice->backendContext.fAdapter = hardwareAdapter; d3dDevice->backendContext.fAdapter = hardwareAdapter;
d3dDevice->backendContext.fDevice = device; d3dDevice->backendContext.fDevice = device;
d3dDevice->backendContext.fQueue = queue; d3dDevice->backendContext.fQueue = queue;
d3dDevice->backendContext.fProtectedContext = GrProtected::kNo;
d3dDevice->device = device; d3dDevice->device = device;
d3dDevice->queue = queue; d3dDevice->queue = queue;
d3dDevice->window = (HWND)windowHandle;
// Make the swapchain return toJavaPointer(d3dDevice);
HWND fWindow = (HWND)windowHandle; }
JNIEXPORT void JNICALL Java_org_jetbrains_skiko_redrawer_Direct3DRedrawer_initSwapChain(
JNIEnv *env, jobject redrawer, jlong devicePtr)
{
DirectXDevice *d3dDevice = fromJavaPointer<DirectXDevice *>(devicePtr);
// Make the swapchain
gr_cp<IDXGIFactory4> swapChainFactory; gr_cp<IDXGIFactory4> swapChainFactory;
GR_D3D_CALL_ERRCHECK(CreateDXGIFactory2(0, IID_PPV_ARGS(&swapChainFactory))); GR_D3D_CALL_ERRCHECK(CreateDXGIFactory2(0, IID_PPV_ARGS(&swapChainFactory)));
...@@ -326,71 +300,145 @@ HRESULT D3DCompile( ...@@ -326,71 +300,145 @@ HRESULT D3DCompile(
swapChainDesc.BufferCount = BuffersCount; swapChainDesc.BufferCount = BuffersCount;
swapChainDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; swapChainDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL; swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD;
swapChainDesc.SampleDesc.Count = 1; swapChainDesc.SampleDesc.Count = 1;
swapChainDesc.SampleDesc.Quality = 0;
swapChainDesc.Scaling = DXGI_SCALING_NONE; swapChainDesc.Scaling = DXGI_SCALING_NONE;
DXGI_SWAP_CHAIN_FULLSCREEN_DESC swapChainFSDesc = {};
swapChainFSDesc.Windowed = TRUE;
gr_cp<IDXGISwapChain1> swapChain; gr_cp<IDXGISwapChain1> swapChain;
GR_D3D_CALL_ERRCHECK(swapChainFactory->CreateSwapChainForHwnd(d3dDevice->queue.get(), fWindow, &swapChainDesc, &swapChainFSDesc, nullptr, &swapChain)); GR_D3D_CALL_ERRCHECK(swapChainFactory->CreateSwapChainForHwnd(d3dDevice->queue.get(), d3dDevice->window, &swapChainDesc, nullptr, nullptr, &swapChain));
GR_D3D_CALL_ERRCHECK(swapChainFactory->MakeWindowAssociation(d3dDevice->window, DXGI_MWA_NO_ALT_ENTER));
GR_D3D_CALL_ERRCHECK(swapChain->QueryInterface(IID_PPV_ARGS(&d3dDevice->swapChain))); GR_D3D_CALL_ERRCHECK(swapChain->QueryInterface(IID_PPV_ARGS(&d3dDevice->swapChain)));
GR_D3D_CALL_ERRCHECK(d3dDevice->device->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&d3dDevice->fence)));
d3dDevice->fenceEvent = CreateEvent(nullptr, FALSE, FALSE, nullptr);
RECT windowRect;
GetWindowRect(d3dDevice->window, &windowRect);
unsigned int w = windowRect.right - windowRect.left;
unsigned int h = windowRect.bottom - windowRect.top;
GR_D3D_CALL_ERRCHECK(d3dDevice->swapChain->ResizeBuffers(BuffersCount, w, h, DXGI_FORMAT_R8G8B8A8_UNORM, 0));
swapChainFactory.reset(nullptr);
swapChainFactory.reset(nullptr); swapChainFactory.reset(nullptr);
}
return toJavaPointer(d3dDevice); JNIEXPORT void JNICALL Java_org_jetbrains_skiko_redrawer_Direct3DRedrawer_initFence(
JNIEnv *env, jobject redrawer, jlong devicePtr)
{
DirectXDevice *d3dDevice = fromJavaPointer<DirectXDevice *>(devicePtr);
for (int i = 0; i < BuffersCount; i++)
{
d3dDevice->fenceValues[i] = 10000;
}
GR_D3D_CALL_ERRCHECK(d3dDevice->device->CreateFence(d3dDevice->fenceValues[0],
D3D12_FENCE_FLAG_NONE,
IID_PPV_ARGS(&d3dDevice->fence)));
d3dDevice->fenceEvent = CreateEvent(nullptr, FALSE, FALSE, nullptr);
SkASSERT(d3dDevice->fenceEvent);
}
JNIEXPORT jlong JNICALL Java_org_jetbrains_skiko_redrawer_Direct3DRedrawer_makeDirectXContext(
JNIEnv *env, jobject redrawer, jlong devicePtr)
{
DirectXDevice *d3dDevice = fromJavaPointer<DirectXDevice *>(devicePtr);
GrD3DBackendContext backendContext = d3dDevice->backendContext;
return toJavaPointer(GrDirectContext::MakeDirect3D(backendContext).release());
}
JNIEXPORT jlong JNICALL Java_org_jetbrains_skiko_redrawer_Direct3DRedrawer_makeDirectXSurface(
JNIEnv *env, jobject redrawer, jlong devicePtr, jlong contextPtr, jint width, jint height, jint index)
{
DirectXDevice *d3dDevice = fromJavaPointer<DirectXDevice *>(devicePtr);
GrDirectContext *context = fromJavaPointer<GrDirectContext *>(contextPtr);
GrD3DTextureResourceInfo info(nullptr,
nullptr,
D3D12_RESOURCE_STATE_PRESENT,
DXGI_FORMAT_R8G8B8A8_UNORM,
1,
1,
0);
GR_D3D_CALL_ERRCHECK(d3dDevice->swapChain->GetBuffer(index, IID_PPV_ARGS(&d3dDevice->buffers[index])));
info.fResource = d3dDevice->buffers[index];
SkSurfaceProps surfaceProps(0, kRGB_H_SkPixelGeometry);
GrBackendTexture backendTexture((int)d3dDevice->buffers[index]->GetDesc().Width, (int)d3dDevice->buffers[index]->GetDesc().Height, info);
return toJavaPointer(SkSurface::MakeFromBackendTexture(
context, backendTexture, kTopLeft_GrSurfaceOrigin, 0,
kRGBA_8888_SkColorType, SkColorSpace::MakeSRGB(), &surfaceProps)
.release());
} }
JNIEXPORT void JNICALL Java_org_jetbrains_skiko_redrawer_Direct3DRedrawer_resizeBuffers( JNIEXPORT void JNICALL Java_org_jetbrains_skiko_redrawer_Direct3DRedrawer_resizeBuffers(
JNIEnv *env, jobject redrawer, jlong devicePtr, jint width, jint height) JNIEnv *env, jobject redrawer, jlong devicePtr, jint width, jint height)
{ {
DirectXDevice *d3dDevice = fromJavaPointer<DirectXDevice*>(devicePtr); DirectXDevice *d3dDevice = fromJavaPointer<DirectXDevice *>(devicePtr);
if (!d3dDevice->isSizeEqualTo(width, height)) for (int i = 0; i < BuffersCount; i++)
{ {
GR_D3D_CALL_ERRCHECK(d3dDevice->swapChain->ResizeBuffers(BuffersCount, width, height, DXGI_FORMAT_R8G8B8A8_UNORM, 0)); if (d3dDevice->fence->GetCompletedValue() < d3dDevice->fenceValues[i])
d3dDevice->bufferWidth = width; {
d3dDevice->bufferHeight = height; GR_D3D_CALL_ERRCHECK(d3dDevice->fence->SetEventOnCompletion(d3dDevice->fenceValues[i], d3dDevice->fenceEvent));
WaitForSingleObjectEx(d3dDevice->fenceEvent, INFINITE, FALSE);
}
d3dDevice->buffers[i].reset(nullptr);
} }
GR_D3D_CALL_ERRCHECK(d3dDevice->swapChain->ResizeBuffers(BuffersCount, width, height, DXGI_FORMAT_R8G8B8A8_UNORM, 0));
} }
JNIEXPORT void JNICALL Java_org_jetbrains_skiko_redrawer_Direct3DRedrawer_finishFrame( JNIEXPORT void JNICALL Java_org_jetbrains_skiko_redrawer_Direct3DRedrawer_finishFrame(
JNIEnv *env, jobject redrawer, jlong devicePtr, jlong contextPtr, jlong surfacePtr, jboolean isVsyncEnabled) JNIEnv *env, jobject redrawer, jlong devicePtr, jlong contextPtr, jlong surfacePtr, jboolean isVsyncEnabled)
{ {
DirectXDevice *d3dDevice = fromJavaPointer<DirectXDevice*>(devicePtr); DirectXDevice *d3dDevice = fromJavaPointer<DirectXDevice *>(devicePtr);
SkSurface *surface = fromJavaPointer<SkSurface*>(surfacePtr); SkSurface *surface = fromJavaPointer<SkSurface *>(surfacePtr);
GrDirectContext *fContext = fromJavaPointer<GrDirectContext*>(contextPtr); GrDirectContext *context = fromJavaPointer<GrDirectContext *>(contextPtr);
surface->flushAndSubmit(); surface->flushAndSubmit(true);
surface->flush(SkSurface::BackendSurfaceAccess::kPresent, GrFlushInfo()); surface->flush(SkSurface::BackendSurfaceAccess::kPresent, GrFlushInfo());
fContext->flush({}); context->flush({});
fContext->submit(true); context->submit(true);
// 1 value in [Present(1, 0)] enables vblank wait so this is how vertical sync works in DirectX. // 1 value in [Present(1, 0)] enables vblank wait so this is how vertical sync works in DirectX.
const UINT64 fenceValue = d3dDevice->fenceValues[d3dDevice->bufferIndex];
GR_D3D_CALL_ERRCHECK(d3dDevice->swapChain->Present((int)isVsyncEnabled, 0)); GR_D3D_CALL_ERRCHECK(d3dDevice->swapChain->Present((int)isVsyncEnabled, 0));
GR_D3D_CALL_ERRCHECK(d3dDevice->queue->Signal(d3dDevice->fence.get(), fenceValue));
}
const UINT64 fence = d3dDevice->fenceValue; JNIEXPORT void JNICALL Java_org_jetbrains_skiko_redrawer_Direct3DRedrawer_disposeDevice(
GR_D3D_CALL_ERRCHECK(d3dDevice->queue->Signal(d3dDevice->fence.get(), fence)); JNIEnv *env, jobject redrawer, jlong devicePtr, jlong contextPtr)
d3dDevice->fenceValue++;
if (d3dDevice->fence->GetCompletedValue() < fence)
{ {
GR_D3D_CALL_ERRCHECK(d3dDevice->fence->SetEventOnCompletion(fence, d3dDevice->fenceEvent)); DirectXDevice *d3dDevice = fromJavaPointer<DirectXDevice *>(devicePtr);
GrDirectContext *context = fromJavaPointer<GrDirectContext *>(contextPtr);
context->flush({});
context->submit(true);
for (int i = 0; i < BuffersCount; i++)
{
if (d3dDevice->fence->GetCompletedValue() < d3dDevice->fenceValues[i])
{
GR_D3D_CALL_ERRCHECK(d3dDevice->fence->SetEventOnCompletion(d3dDevice->fenceValues[i], d3dDevice->fenceEvent));
WaitForSingleObjectEx(d3dDevice->fenceEvent, INFINITE, FALSE); WaitForSingleObjectEx(d3dDevice->fenceEvent, INFINITE, FALSE);
} }
} }
JNIEXPORT void JNICALL Java_org_jetbrains_skiko_redrawer_Direct3DRedrawer_disposeDevice( delete d3dDevice;
}
JNIEXPORT jint JNICALL Java_org_jetbrains_skiko_redrawer_Direct3DRedrawer_getBufferIndex(
JNIEnv *env, jobject redrawer, jlong devicePtr) JNIEnv *env, jobject redrawer, jlong devicePtr)
{ {
DirectXDevice *d3dDevice = fromJavaPointer<DirectXDevice*>(devicePtr); DirectXDevice *d3dDevice = fromJavaPointer<DirectXDevice *>(devicePtr);
delete d3dDevice; const UINT64 fenceValue = d3dDevice->fenceValues[d3dDevice->bufferIndex];
d3dDevice->bufferIndex = d3dDevice->swapChain->GetCurrentBackBufferIndex();
if (d3dDevice->fence->GetCompletedValue() < fenceValue)
{
GR_D3D_CALL_ERRCHECK(d3dDevice->fence->SetEventOnCompletion(fenceValue, d3dDevice->fenceEvent));
WaitForSingleObjectEx(d3dDevice->fenceEvent, INFINITE, FALSE);
}
d3dDevice->fenceValues[d3dDevice->bufferIndex] = fenceValue + 1;
return d3dDevice->bufferIndex;
} }
JNIEXPORT jstring JNICALL Java_org_jetbrains_skiko_redrawer_Direct3DRedrawer_getAdapterName(JNIEnv * env, jobject redrawer, jlong devicePtr) { JNIEXPORT jstring JNICALL Java_org_jetbrains_skiko_redrawer_Direct3DRedrawer_getAdapterName(JNIEnv *env, jobject redrawer, jlong devicePtr)
DirectXDevice *d3dDevice = fromJavaPointer<DirectXDevice*>(devicePtr); {
DirectXDevice *d3dDevice = fromJavaPointer<DirectXDevice *>(devicePtr);
DXGI_ADAPTER_DESC1 desc; DXGI_ADAPTER_DESC1 desc;
d3dDevice->backendContext.fAdapter->GetDesc1(&desc); d3dDevice->backendContext.fAdapter->GetDesc1(&desc);
...@@ -400,8 +448,9 @@ HRESULT D3DCompile( ...@@ -400,8 +448,9 @@ HRESULT D3DCompile(
return result; return result;
} }
JNIEXPORT jlong JNICALL Java_org_jetbrains_skiko_redrawer_Direct3DRedrawer_getAdapterMemorySize(JNIEnv * env, jobject redrawer, jlong devicePtr) { JNIEXPORT jlong JNICALL Java_org_jetbrains_skiko_redrawer_Direct3DRedrawer_getAdapterMemorySize(JNIEnv *env, jobject redrawer, jlong devicePtr)
DirectXDevice *d3dDevice = fromJavaPointer<DirectXDevice*>(devicePtr); {
DirectXDevice *d3dDevice = fromJavaPointer<DirectXDevice *>(devicePtr);
DXGI_ADAPTER_DESC1 desc; DXGI_ADAPTER_DESC1 desc;
d3dDevice->backendContext.fAdapter->GetDesc1(&desc); d3dDevice->backendContext.fAdapter->GetDesc1(&desc);
......
...@@ -47,7 +47,7 @@ internal abstract class ContextHandler(val layer: SkiaLayer) { ...@@ -47,7 +47,7 @@ internal abstract class ContextHandler(val layer: SkiaLayer) {
destroyContext() destroyContext()
} }
fun disposeCanvas() { open fun disposeCanvas() {
surface?.close() surface?.close()
renderTarget?.close() renderTarget?.close()
} }
......
...@@ -10,6 +10,9 @@ import org.jetbrains.skiko.redrawer.Direct3DRedrawer ...@@ -10,6 +10,9 @@ import org.jetbrains.skiko.redrawer.Direct3DRedrawer
import java.lang.ref.Reference import java.lang.ref.Reference
internal class Direct3DContextHandler(layer: SkiaLayer) : ContextHandler(layer) { internal class Direct3DContextHandler(layer: SkiaLayer) : ContextHandler(layer) {
private val bufferCount = 2
private var surfaces: Array<Surface?> = arrayOfNulls(bufferCount)
val directXRedrawer: Direct3DRedrawer val directXRedrawer: Direct3DRedrawer
get() = layer.redrawer!! as Direct3DRedrawer get() = layer.redrawer!! as Direct3DRedrawer
...@@ -22,7 +25,6 @@ internal class Direct3DContextHandler(layer: SkiaLayer) : ContextHandler(layer) ...@@ -22,7 +25,6 @@ internal class Direct3DContextHandler(layer: SkiaLayer) : ContextHandler(layer)
throw Exception("Failed to create DirectX12 device.") throw Exception("Failed to create DirectX12 device.")
} }
context = directXRedrawer.makeContext(device) context = directXRedrawer.makeContext(device)
val printDeviceEnabled = System.getProperty("skiko.hardwareInfo.enabled") == "true"
if (System.getProperty("skiko.hardwareInfo.enabled") == "true") { if (System.getProperty("skiko.hardwareInfo.enabled") == "true") {
println(hardwareInfo()) println(hardwareInfo())
} }
...@@ -34,28 +36,51 @@ internal class Direct3DContextHandler(layer: SkiaLayer) : ContextHandler(layer) ...@@ -34,28 +36,51 @@ internal class Direct3DContextHandler(layer: SkiaLayer) : ContextHandler(layer)
return true return true
} }
override fun initCanvas() { private var currentWidth = 0
disposeCanvas() private var currentHeight = 0
private fun isSizeChanged(width: Int, height: Int): Boolean {
if (width != currentWidth || height != currentHeight) {
currentWidth = width
currentHeight = height
return true
}
return false
}
private var isD3DInited = false
override fun initCanvas() {
val scale = layer.contentScale val scale = layer.contentScale
val w = (layer.width * scale).toInt().coerceAtLeast(0) val w = (layer.width * scale).toInt().coerceAtLeast(0)
val h = (layer.height * scale).toInt().coerceAtLeast(0) val h = (layer.height * scale).toInt().coerceAtLeast(0)
renderTarget = directXRedrawer.makeRenderTarget(device, w, h) if (isSizeChanged(w, h)) {
disposeCanvas()
context?.flush()
surface = Surface.makeFromBackendRenderTarget( if (!isD3DInited) {
context!!, directXRedrawer.initSwapChain(device)
renderTarget!!, } else {
SurfaceOrigin.TOP_LEFT, directXRedrawer.resizeBuffers(device, w, h)
SurfaceColorFormat.RGBA_8888, }
ColorSpace.getSRGB()
) try {
for (bufferIndex in 0..bufferCount - 1) {
surfaces[bufferIndex] = directXRedrawer.makeSurface(device, Native.getPtr(context!!), w, h, bufferIndex)
}
} finally {
Reference.reachabilityFence(context!!)
}
if (!isD3DInited) {
isD3DInited = true
directXRedrawer.initFence(device)
}
}
surface = surfaces[directXRedrawer.getBufferIndex(device)]
canvas = surface!!.canvas canvas = surface!!.canvas
} }
override fun flush() { override fun flush() {
super.flush()
try { try {
directXRedrawer.finishFrame( directXRedrawer.finishFrame(
device, device,
...@@ -69,8 +94,18 @@ internal class Direct3DContextHandler(layer: SkiaLayer) : ContextHandler(layer) ...@@ -69,8 +94,18 @@ internal class Direct3DContextHandler(layer: SkiaLayer) : ContextHandler(layer)
} }
override fun destroyContext() { override fun destroyContext() {
try {
directXRedrawer.disposeDevice(device, Native.getPtr(context!!))
} finally {
Reference.reachabilityFence(context!!)
}
context?.close() context?.close()
directXRedrawer.disposeDevice(device) }
override fun disposeCanvas() {
for (bufferIndex in 0..bufferCount - 1) {
surfaces[bufferIndex]?.close()
}
} }
override fun hardwareInfo(): String { override fun hardwareInfo(): String {
......
...@@ -3,7 +3,7 @@ package org.jetbrains.skiko.redrawer ...@@ -3,7 +3,7 @@ package org.jetbrains.skiko.redrawer
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.swing.Swing import kotlinx.coroutines.swing.Swing
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import org.jetbrains.skija.BackendRenderTarget import org.jetbrains.skija.Surface
import org.jetbrains.skija.DirectContext import org.jetbrains.skija.DirectContext
import org.jetbrains.skiko.FrameDispatcher import org.jetbrains.skiko.FrameDispatcher
import org.jetbrains.skiko.SkiaLayer import org.jetbrains.skiko.SkiaLayer
...@@ -60,8 +60,8 @@ internal class Direct3DRedrawer( ...@@ -60,8 +60,8 @@ internal class Direct3DRedrawer(
makeDirectXContext(device) makeDirectXContext(device)
) )
fun makeRenderTarget(device: Long, width: Int, height: Int) = BackendRenderTarget( fun makeSurface(device: Long, context: Long, width: Int, height: Int, index: Int) = Surface(
makeDirectXRenderTarget(device, width, height) makeDirectXSurface(device, context, width, height, index)
) )
fun createDevice(): Long = createDirectXDevice(layer.windowHandle) fun createDevice(): Long = createDirectXDevice(layer.windowHandle)
...@@ -72,10 +72,13 @@ internal class Direct3DRedrawer( ...@@ -72,10 +72,13 @@ internal class Direct3DRedrawer(
external fun createDirectXDevice(windowHandle: Long): Long external fun createDirectXDevice(windowHandle: Long): Long
external fun makeDirectXContext(device: Long): Long external fun makeDirectXContext(device: Long): Long
external fun makeDirectXRenderTarget(device: Long, width: Int, height: Int): Long external fun makeDirectXSurface(device: Long, context: Long, width: Int, height: Int, index: Int): Long
external fun resizeBuffers(device: Long, width: Int, height: Int) external fun resizeBuffers(device: Long, width: Int, height: Int)
private external fun finishFrame(device: Long, context: Long, surface: Long, isVsyncEnabled: Boolean) private external fun finishFrame(device: Long, context: Long, surface: Long, isVsyncEnabled: Boolean)
external fun disposeDevice(device: Long) external fun disposeDevice(device: Long, context: Long)
external fun getBufferIndex(device: Long): Int
external fun initSwapChain(device: Long)
external fun initFence(device: Long)
external fun getAdapterName(device: Long): String external fun getAdapterName(device: Long): String
external fun getAdapterMemorySize(device: Long): Long external fun getAdapterMemorySize(device: Long): Long
} }
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