blob: b7a6bf24a9e0e0258b795402263f6d6effff8794 [file] [log] [blame]
/*
* Copyright (c) 2007, 2008, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
#include "sun_java2d_d3d_D3DGraphicsDevice.h"
#include "D3DGraphicsDevice.h"
#include "D3DPipelineManager.h"
#include "D3DRenderQueue.h"
#include "Trace.h"
#include "awt_Toolkit.h"
#include "awt_Window.h"
extern jobject CreateDisplayMode(JNIEnv* env, jint width, jint height,
jint bitDepth, jint refreshRate);
extern void addDisplayMode(JNIEnv* env, jobject arrayList, jint width,
jint height, jint bitDepth, jint refreshRate);
void InitD3D(void *pReturn)
{
J2dTraceLn(J2D_TRACE_INFO, "InitD3D");
jboolean *pRet = (jboolean *)pReturn;
D3DPipelineManager *pMgr = D3DPipelineManager::CreateInstance();
if (pMgr == NULL) {
J2dTraceLn(J2D_TRACE_ERROR, "InitD3D: could not create or init d3d");
*pRet = JNI_FALSE;
} else {
J2dTraceLn(J2D_TRACE_INFO, "InitD3D: successfully initialized d3d");
*pRet = JNI_TRUE;
}
}
extern "C" {
/*
* Class: sun_java2d_d3d_D3DGraphicsDevice
* Method: initD3D
* Signature: ()Z
*/
JNIEXPORT jboolean JNICALL Java_sun_java2d_d3d_D3DGraphicsDevice_initD3D
(JNIEnv *env, jclass)
{
J2dTraceLn(J2D_TRACE_INFO, "D3DGD_initD3D");
jboolean result = JNI_FALSE;
AwtToolkit::GetInstance().InvokeFunction(InitD3D, &result);
J2dTraceLn1(J2D_TRACE_INFO, "D3DGD_initD3D: result=%x", result);
return result;
}
/*
* Class: sun_java2d_d3d_D3DGraphicsDevice
* Method: getDeviceIdNative
* Signature: (I)Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_sun_java2d_d3d_D3DGraphicsDevice_getDeviceIdNative
(JNIEnv *env, jclass d3dsdc, jint gdiScreen)
{
D3DPipelineManager *pMgr;
UINT adapter;
D3DADAPTER_IDENTIFIER9 aid;
IDirect3D9 *pd3d9;
J2dTraceLn(J2D_TRACE_INFO, "D3DGD_getDeviceIdNative");
pMgr = D3DPipelineManager::GetInstance();
RETURN_STATUS_IF_NULL(pMgr, NULL);
pd3d9 = pMgr->GetD3DObject();
RETURN_STATUS_IF_NULL(pd3d9, NULL);
adapter = pMgr->GetAdapterOrdinalForScreen(gdiScreen);
if (FAILED(pd3d9->GetAdapterIdentifier(adapter, 0, &aid))) {
return NULL;
}
// ('%d.' will take no more than 6+1 chars since we are printing a WORD)
// AAAA&BBBB MAX_DEVICE_IDENTIFIER_STRING (%d.%d.%d.%d)0
size_t len = (4+1+4 +1+MAX_DEVICE_IDENTIFIER_STRING+1 +1+(6+1)*4+1 +1);
WCHAR *pAdapterId = new WCHAR[len];
RETURN_STATUS_IF_NULL(pAdapterId, NULL);
_snwprintf(pAdapterId, len, L"%x&%x %S (%d.%d.%d.%d)",
0xffff & aid.VendorId, 0xffff & aid.DeviceId, aid.Description,
HIWORD(aid.DriverVersion.HighPart),
LOWORD(aid.DriverVersion.HighPart),
HIWORD(aid.DriverVersion.LowPart),
LOWORD(aid.DriverVersion.LowPart));
// _snwprintf doesn't add 0 at the end if the formatted string didn't fit
// in the buffer so we have to make sure it is null terminated
pAdapterId[len-1] = (WCHAR)0;
J2dTraceLn1(J2D_TRACE_VERBOSE, " id=%S", pAdapterId);
jstring ret = JNU_NewStringPlatform(env, pAdapterId);
delete pAdapterId;
return ret;
}
/*
* Class: sun_java2d_d3d_D3DGraphicsDevice
* Method: getDeviceCapsNative
* Signature: (I)I
*/
JNIEXPORT jint JNICALL
Java_sun_java2d_d3d_D3DGraphicsDevice_getDeviceCapsNative
(JNIEnv *env, jclass d3dsdc, jint gdiScreen)
{
D3DPipelineManager *pMgr;
D3DContext *pCtx;
UINT adapter;
J2dRlsTraceLn(J2D_TRACE_INFO, "D3DGD_getDeviceCapsNative");
pMgr = D3DPipelineManager::GetInstance();
RETURN_STATUS_IF_NULL(pMgr, CAPS_EMPTY);
adapter = pMgr->GetAdapterOrdinalForScreen(gdiScreen);
if (FAILED(pMgr->GetD3DContext(adapter, &pCtx))) {
J2dRlsTraceLn1(J2D_TRACE_ERROR,
"D3DGD_getDeviceCapsNative: device %d disabled", adapter);
return CAPS_EMPTY;
}
return pCtx->GetContextCaps();
}
/*
* Class: sun_java2d_d3d_D3DGraphicsDevice
* Method: enterFullScreenExclusiveNative
* Signature: (IJ)V
*/
JNIEXPORT jboolean JNICALL
Java_sun_java2d_d3d_D3DGraphicsDevice_enterFullScreenExclusiveNative
(JNIEnv *env, jclass gdc, jint gdiScreen, jlong window)
{
HRESULT res;
D3DPipelineManager *pMgr;
D3DContext *pCtx;
HWND hWnd;
AwtWindow *w;
D3DPRESENT_PARAMETERS newParams, *pCurParams;
D3DDISPLAYMODE dm;
UINT adapter;
J2dTraceLn(J2D_TRACE_INFO, "D3DGD_enterFullScreenExclusiveNative");
RETURN_STATUS_IF_NULL(pMgr = D3DPipelineManager::GetInstance(), JNI_FALSE);
adapter = pMgr->GetAdapterOrdinalForScreen(gdiScreen);
if (FAILED(res = pMgr->GetD3DContext(adapter, &pCtx))) {
D3DRQ_MarkLostIfNeeded(res, D3DRQ_GetCurrentDestination());
return JNI_FALSE;
}
w = (AwtWindow *)AwtComponent::GetComponent((HWND)window);
if (w == NULL || !::IsWindow(hWnd = w->GetTopLevelHWnd())) {
J2dTraceLn(J2D_TRACE_WARNING,
"D3DGD_enterFullScreenExclusiveNative: disposed window");
return JNI_FALSE;
}
// REMIND: should we also move the non-topleve window from
// being on top here (it's moved to front in GraphicsDevice.setFSW())?
pCtx->Get3DObject()->GetAdapterDisplayMode(adapter, &dm);
pCurParams = pCtx->GetPresentationParams();
// let the mananger know that we're entering the fs mode, it will
// set the proper current focus window for us, which ConfigureContext will
// use when creating the device
pMgr->SetFSFocusWindow(adapter, hWnd);
newParams = *pCurParams;
newParams.hDeviceWindow = hWnd;
newParams.Windowed = FALSE;
newParams.BackBufferCount = 1;
newParams.BackBufferFormat = dm.Format;
newParams.FullScreen_RefreshRateInHz = dm.RefreshRate;
newParams.BackBufferWidth = dm.Width;
newParams.BackBufferHeight = dm.Height;
newParams.PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT;
newParams.SwapEffect = D3DSWAPEFFECT_DISCARD;
res = pCtx->ConfigureContext(&newParams);
D3DRQ_MarkLostIfNeeded(res, D3DRQ_GetCurrentDestination());
return SUCCEEDED(res);
}
/*
* Class: sun_java2d_d3d_D3DGraphicsDevice
* Method: exitFullScreenExclusiveNative
* Signature: (I)V
*/
JNIEXPORT jboolean JNICALL
Java_sun_java2d_d3d_D3DGraphicsDevice_exitFullScreenExclusiveNative
(JNIEnv *env, jclass gdc, jint gdiScreen)
{
HRESULT res;
D3DPipelineManager *pMgr;
D3DContext *pCtx;
D3DPRESENT_PARAMETERS newParams, *pCurParams;
UINT adapter;
J2dTraceLn(J2D_TRACE_INFO, "D3DGD_exitFullScreenExclusiveNative");
RETURN_STATUS_IF_NULL(pMgr = D3DPipelineManager::GetInstance(), JNI_FALSE);
adapter = pMgr->GetAdapterOrdinalForScreen(gdiScreen);
if (FAILED(res = pMgr->GetD3DContext(adapter, &pCtx))) {
D3DRQ_MarkLostIfNeeded(res, D3DRQ_GetCurrentDestination());
return JNI_FALSE;
}
pCurParams = pCtx->GetPresentationParams();
newParams = *pCurParams;
// we're exiting fs, the device window can be 0
newParams.hDeviceWindow = 0;
newParams.Windowed = TRUE;
newParams.BackBufferFormat = D3DFMT_UNKNOWN;
newParams.BackBufferCount = 1;
newParams.FullScreen_RefreshRateInHz = 0;
newParams.BackBufferWidth = 0;
newParams.BackBufferHeight = 0;
newParams.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
newParams.SwapEffect = D3DSWAPEFFECT_COPY;
res = pCtx->ConfigureContext(&newParams);
D3DRQ_MarkLostIfNeeded(res, D3DRQ_GetCurrentDestination());
// exited fs, update current focus window
// note that we call this after this adapter exited fs mode so that
// the rest of the adapters can be reset
pMgr->SetFSFocusWindow(adapter, 0);
return SUCCEEDED(res);
}
/*
* Class: sun_java2d_d3d_D3DGraphicsDevice
* Method: configDisplayModeNative
* Signature: (IJIIII)V
*/
JNIEXPORT void JNICALL
Java_sun_java2d_d3d_D3DGraphicsDevice_configDisplayModeNative
(JNIEnv *env, jclass gdc, jint gdiScreen, jlong window,
jint width, jint height, jint bitDepth, jint refreshRate)
{
HRESULT res;
D3DPipelineManager *pMgr;
D3DContext *pCtx;
D3DPRESENT_PARAMETERS newParams, *pCurParams;
UINT adapter;
J2dTraceLn(J2D_TRACE_INFO, "D3DGD_configDisplayModeNative");
RETURN_IF_NULL(pMgr = D3DPipelineManager::GetInstance());
adapter = pMgr->GetAdapterOrdinalForScreen(gdiScreen);
if (FAILED(res = pMgr->GetD3DContext(adapter, &pCtx))) {
D3DRQ_MarkLostIfNeeded(res, D3DRQ_GetCurrentDestination());
return;
}
pCurParams = pCtx->GetPresentationParams();
newParams = *pCurParams;
newParams.BackBufferWidth = width;
newParams.BackBufferHeight = height;
newParams.FullScreen_RefreshRateInHz = refreshRate;
newParams.PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT;
// we leave the swap effect so that it's more likely
// to be the one user selected initially
// newParams.SwapEffect = D3DSWAPEFFECT_DISCARD;
if (bitDepth == 32) {
newParams.BackBufferFormat = D3DFMT_X8R8G8B8;
} else if (bitDepth == 16) {
UINT modeNum;
D3DDISPLAYMODE mode;
IDirect3D9 *pd3d9;
UINT modesCount;
RETURN_IF_NULL(pd3d9 = pMgr->GetD3DObject());
modesCount = pd3d9->GetAdapterModeCount(adapter, D3DFMT_R5G6B5);
if (modesCount == 0) {
modesCount = pd3d9->GetAdapterModeCount(adapter, D3DFMT_X1R5G5B5);
}
newParams.BackBufferFormat = D3DFMT_UNKNOWN;
for (modeNum = 0; modeNum < modesCount; modeNum++) {
if (SUCCEEDED(pd3d9->EnumAdapterModes(adapter, D3DFMT_R5G6B5,
modeNum, &mode)))
{
if (mode.Width == width && mode.Height == height &&
mode.RefreshRate == refreshRate)
{
// prefer 565 over 555
if (mode.Format == D3DFMT_R5G6B5) {
newParams.BackBufferFormat = D3DFMT_R5G6B5;
break;
} else if (mode.Format == D3DFMT_X1R5G5B5) {
newParams.BackBufferFormat = D3DFMT_X1R5G5B5;
}
}
}
}
if (newParams.BackBufferFormat == D3DFMT_UNKNOWN) {
J2dRlsTraceLn(J2D_TRACE_ERROR,
"D3DGD_configDisplayModeNative: no 16-bit formats");
return;
}
} else {
J2dRlsTraceLn1(J2D_TRACE_ERROR,
"D3DGD_configDisplayModeNative: unsupported depth: %d",
bitDepth);
return;
}
J2dTraceLn4(J2D_TRACE_VERBOSE, " changing to dm: %dx%dx%d@%d",
newParams.BackBufferWidth, newParams.BackBufferHeight,
bitDepth, refreshRate);
J2dTraceLn1(J2D_TRACE_VERBOSE, " selected backbuffer format: %d",
newParams.BackBufferFormat);
res = pCtx->ConfigureContext(&newParams);
if (SUCCEEDED(res)) {
// the full screen window doesn't receive WM_SIZE event when
// the display mode changes (it does get resized though) so we need to
// generate the event ourselves
::SendMessage(newParams.hDeviceWindow, WM_SIZE, width, height);
}
D3DRQ_MarkLostIfNeeded(res, D3DRQ_GetCurrentDestination());
}
/*
* Class: sun_java2d_d3d_D3DGraphicsDevice
* Method: getCurrentDisplayModeNative
* Signature: (I)Ljava/awt/DisplayMode;
*/
JNIEXPORT jobject JNICALL
Java_sun_java2d_d3d_D3DGraphicsDevice_getCurrentDisplayModeNative
(JNIEnv *env, jclass gdc, jint gdiScreen)
{
D3DPipelineManager *pMgr;
IDirect3D9 *pd3d9;
jobject ret = NULL;
D3DDISPLAYMODE mode;
UINT adapter;
J2dTraceLn(J2D_TRACE_INFO, "D3DGD_getCurrentDisplayModeNative");
RETURN_STATUS_IF_NULL(pMgr = D3DPipelineManager::GetInstance(), NULL);
RETURN_STATUS_IF_NULL(pd3d9 = pMgr->GetD3DObject(), NULL);
adapter = pMgr->GetAdapterOrdinalForScreen(gdiScreen);
if (SUCCEEDED(pd3d9->GetAdapterDisplayMode(adapter, &mode))) {
int bitDepth = -1;
// these are the only three valid screen formats
switch (mode.Format) {
case D3DFMT_X8R8G8B8: bitDepth = 32; break;
case D3DFMT_R5G6B5:
case D3DFMT_X1R5G5B5: bitDepth = 16; break;
}
J2dTraceLn4(J2D_TRACE_VERBOSE,
" current dm: %dx%dx%d@%d",
mode.Width, mode.Height, bitDepth, mode.RefreshRate);
ret = CreateDisplayMode(env, mode.Width, mode.Height, bitDepth,
mode.RefreshRate);
}
return ret;
}
/*
* Class: sun_java2d_d3d_D3DGraphicsDevice
* Method: enumDisplayModesNative
* Signature: (ILjava/util/ArrayList;)V
*/
JNIEXPORT void JNICALL
Java_sun_java2d_d3d_D3DGraphicsDevice_enumDisplayModesNative
(JNIEnv *env, jclass gdc, jint gdiScreen, jobject arrayList)
{
D3DPipelineManager *pMgr;
IDirect3D9 *pd3d9;
jobject ret = NULL;
D3DDISPLAYMODE mode;
UINT formatNum, modeNum, modesCount;
UINT adapter;
// EnumAdapterModes treats 555 and 565 formats as equivalents
static D3DFORMAT formats[] =
{ D3DFMT_X8R8G8B8, D3DFMT_R5G6B5 };
J2dTraceLn(J2D_TRACE_INFO, "D3DGD_enumDisplayModesNative");
RETURN_IF_NULL(pMgr = D3DPipelineManager::GetInstance());
RETURN_IF_NULL(pd3d9 = pMgr->GetD3DObject());
adapter = pMgr->GetAdapterOrdinalForScreen(gdiScreen);
for (formatNum = 0; formatNum < 3; formatNum++) {
modesCount = pd3d9->GetAdapterModeCount(adapter, formats[formatNum]);
for (modeNum = 0; modeNum < modesCount; modeNum++) {
if (SUCCEEDED(pd3d9->EnumAdapterModes(adapter, formats[formatNum],
modeNum, &mode)))
{
int bitDepth = -1;
// these are the only three valid screen formats,
// 30-bit is returned as X8R8G8B8
switch (mode.Format) {
case D3DFMT_X8R8G8B8: bitDepth = 32; break;
case D3DFMT_R5G6B5:
case D3DFMT_X1R5G5B5: bitDepth = 16; break;
}
J2dTraceLn4(J2D_TRACE_VERBOSE, " found dm: %dx%dx%d@%d",
mode.Width, mode.Height, bitDepth,mode.RefreshRate);
addDisplayMode(env, arrayList, mode.Width, mode.Height,
bitDepth, mode.RefreshRate);
}
}
}
}
/*
* Class: sun_java2d_d3d_D3DGraphicsDevice
* Method: getAvailableAcceleratedMemoryNative
* Signature: (I)J
*/
JNIEXPORT jlong JNICALL
Java_sun_java2d_d3d_D3DGraphicsDevice_getAvailableAcceleratedMemoryNative
(JNIEnv *env, jclass gdc, jint gdiScreen)
{
// REMIND: looks like Direct3D provides information about texture memory
// only via IDirect3DDevice9::GetAvailableTextureMem, however, it
// seems to report the same amount as direct draw used to.
HRESULT res;
D3DPipelineManager *pMgr;
D3DContext *pCtx;
IDirect3DDevice9 *pd3dDevice;
UINT adapter;
J2dTraceLn(J2D_TRACE_INFO, "D3DGD_getAvailableAcceleratedMemoryNative");
RETURN_STATUS_IF_NULL(pMgr = D3DPipelineManager::GetInstance(), 0L);
adapter = pMgr->GetAdapterOrdinalForScreen(gdiScreen);
if (FAILED(res = pMgr->GetD3DContext(adapter, &pCtx))) {
D3DRQ_MarkLostIfNeeded(res, D3DRQ_GetCurrentDestination());
return 0L;
}
RETURN_STATUS_IF_NULL(pd3dDevice = pCtx->Get3DDevice(), 0L);
UINT mem = pd3dDevice->GetAvailableTextureMem();
J2dTraceLn1(J2D_TRACE_VERBOSE, " available memory=%d", mem);
return mem;
}
/*
* Class: sun_java2d_d3d_D3DGraphicsDevice
* Method: isD3DAvailableOnDeviceNative
* Signature: (I)Z
*/
JNIEXPORT jboolean JNICALL
Java_sun_java2d_d3d_D3DGraphicsDevice_isD3DAvailableOnDeviceNative
(JNIEnv *env, jclass gdc, jint gdiScreen)
{
HRESULT res;
D3DPipelineManager *pMgr;
D3DContext *pCtx;
UINT adapter;
J2dTraceLn(J2D_TRACE_INFO, "D3DGD_isD3DAvailableOnDeviceNative");
RETURN_STATUS_IF_NULL(pMgr = D3DPipelineManager::GetInstance(), JNI_FALSE);
adapter = pMgr->GetAdapterOrdinalForScreen(gdiScreen);
if (FAILED(res = pMgr->GetD3DContext(adapter, &pCtx))) {
D3DRQ_MarkLostIfNeeded(res, D3DRQ_GetCurrentDestination());
return JNI_FALSE;
}
return JNI_TRUE;
}
} // extern "C"