blob: 9732d4d046b80fa56ff6ae57c425666492c6aa69 [file] [log] [blame]
/*
* Copyright (c) 2007, 2009, 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 "D3DPipeline.h"
#include <jlong.h>
#include "D3DSurfaceData.h"
#include "D3DPipelineManager.h"
#include "Trace.h"
#include "awt_Toolkit.h"
#include "awt_Window.h"
#include "awt_BitmapUtil.h"
#include "D3DRenderQueue.h"
// REMIND: move to awt_Component.h
extern "C" HWND AwtComponent_GetHWnd(JNIEnv *env, jlong pData);
/* This looks weird. but since some AWT headers need to be included,
* we end up with AWT's alloc.h macro definition of ExceptionOccurred.
* The reasons for that re-defintion do not apply to this code, so undef it.
*/
#undef ExceptionOccurred
/**
* Initializes nativeWidth/Height fields of the SurfaceData object with
* dimensions on the native surface.
*/
void D3DSD_SetNativeDimensions(JNIEnv *env, D3DSDOps *d3dsdo) {
jobject sdObject;
jint width, height;
RETURN_IF_NULL(sdObject = env->NewLocalRef(d3dsdo->sdOps.sdObject));
if (d3dsdo->pResource != NULL) {
width = d3dsdo->pResource->GetDesc()->Width;
height = d3dsdo->pResource->GetDesc()->Height;
} else {
width = d3dsdo->width;
height = d3dsdo->height;
}
JNU_SetFieldByName(env, NULL, sdObject, "nativeWidth", "I", width);
if (!(env->ExceptionOccurred())) {
JNU_SetFieldByName(env, NULL, sdObject, "nativeHeight", "I", height);
}
env->DeleteLocalRef(sdObject);
}
void D3DSD_Flush(void *pData)
{
J2dTraceLn(J2D_TRACE_INFO, "D3DSD_Flush");
RETURN_IF_NULL(pData);
D3DSDOps *d3dsdo = (D3DSDOps*)pData;
if (d3dsdo->pResource != NULL) {
D3DContext *pCtx;
D3DPipelineManager *pMgr;
d3dsdo->pResource->SetSDOps(NULL);
if ((pMgr = D3DPipelineManager::GetInstance()) != NULL &&
SUCCEEDED(pMgr->GetD3DContext(d3dsdo->adapter, &pCtx)))
{
if (pCtx->GetResourceManager()) {
pCtx->GetResourceManager()->ReleaseResource(d3dsdo->pResource);
}
}
d3dsdo->pResource = NULL;
}
}
void
D3DSD_MarkLost(void *pData)
{
D3DSDOps *d3dsdo;
jobject sdObject;
JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
J2dTraceLn(J2D_TRACE_INFO, "D3DSD_MarkLost");
RETURN_IF_NULL(pData);
d3dsdo = (D3DSDOps*)pData;
RETURN_IF_NULL(sdObject = env->NewLocalRef(d3dsdo->sdOps.sdObject));
JNU_CallMethodByName(env, NULL, sdObject,
"setSurfaceLost", "(Z)V", JNI_TRUE);
env->DeleteLocalRef(sdObject);
}
// ------------ generic SurfaceData.h functions ----------------
void
D3DSD_Dispose(JNIEnv *env, SurfaceDataOps *ops)
{
D3DSDOps *d3dsdo = (D3DSDOps *)ops;
RETURN_IF_NULL(d3dsdo);
JNU_CallStaticMethodByName(env, NULL, "sun/java2d/d3d/D3DSurfaceData",
"dispose", "(J)V",
ptr_to_jlong(ops));
}
/**
* This is the implementation of the general surface LockFunc defined in
* SurfaceData.h.
*/
jint
D3DSD_Lock(JNIEnv *env,
SurfaceDataOps *ops,
SurfaceDataRasInfo *pRasInfo,
jint lockflags)
{
JNU_ThrowInternalError(env, "D3DSD_Lock not implemented!");
return SD_FAILURE;
}
/**
* This is the implementation of the general GetRasInfoFunc defined in
* SurfaceData.h.
*/
void
D3DSD_GetRasInfo(JNIEnv *env,
SurfaceDataOps *ops,
SurfaceDataRasInfo *pRasInfo)
{
JNU_ThrowInternalError(env, "D3DSD_GetRasInfo not implemented!");
}
/**
* This is the implementation of the general surface UnlockFunc defined in
* SurfaceData.h.
*/
void
D3DSD_Unlock(JNIEnv *env,
SurfaceDataOps *ops,
SurfaceDataRasInfo *pRasInfo)
{
JNU_ThrowInternalError(env, "D3DSD_Unlock not implemented!");
}
// ------------ D3DSurfaceData's JNI methods ----------------
extern "C" {
/*
* Class: sun_java2d_d3d_D3DSurfaceData
* Method: initOps
* Signature: (III)V
*/
JNIEXPORT void
JNICALL Java_sun_java2d_d3d_D3DSurfaceData_initOps
(JNIEnv *env, jobject d3dsd, jint gdiScreen, jint width, jint height)
{
D3DPipelineManager *pMgr;
D3DSDOps *d3dsdo = (D3DSDOps *)SurfaceData_InitOps(env, d3dsd,
sizeof(D3DSDOps));
J2dTraceLn(J2D_TRACE_INFO, "D3DSurfaceData_initOps");
if (d3dsdo == NULL) {
JNU_ThrowOutOfMemoryError(env, "creating native d3d ops");
return;
}
d3dsdo->sdOps.Lock = D3DSD_Lock;
d3dsdo->sdOps.GetRasInfo = D3DSD_GetRasInfo;
d3dsdo->sdOps.Unlock = D3DSD_Unlock;
d3dsdo->sdOps.Dispose = D3DSD_Dispose;
d3dsdo->xoff = 0;
d3dsdo->yoff = 0;
d3dsdo->width = width;
d3dsdo->height = height;
d3dsdo->pResource = NULL;
d3dsdo->adapter =
(pMgr = D3DPipelineManager::GetInstance()) == NULL ?
D3DADAPTER_DEFAULT :
pMgr->GetAdapterOrdinalForScreen(gdiScreen);
}
/*
* Class: sun_java2d_d3d_D3DSurfaceData
* Method: initTexture
* Signature: (JZZ)Z
*/
JNIEXPORT jboolean
JNICALL Java_sun_java2d_d3d_D3DSurfaceData_initTexture
(JNIEnv *env, jobject d3dsd,
jlong pData, jboolean isRTT, jboolean isOpaque)
{
HRESULT res;
D3DSDOps *d3dsdo;
D3DContext *pCtx;
D3DPipelineManager *pMgr;
D3DFORMAT format;
J2dTraceLn(J2D_TRACE_INFO, "D3DSurfaceData_initTexture");
RETURN_STATUS_IF_NULL(d3dsdo = (D3DSDOps *)jlong_to_ptr(pData), JNI_FALSE);
RETURN_STATUS_IF_NULL(pMgr = D3DPipelineManager::GetInstance(), JNI_FALSE);
if (FAILED(res = pMgr->GetD3DContext(d3dsdo->adapter, &pCtx))) {
D3DRQ_MarkLostIfNeeded(res, d3dsdo);
return JNI_FALSE;
}
RETURN_STATUS_IF_NULL(pCtx->GetResourceManager(), JNI_FALSE);
pCtx->GetResourceManager()->ReleaseResource(d3dsdo->pResource);
d3dsdo->pResource = NULL;
if (isRTT && isOpaque) {
format = pCtx->GetPresentationParams()->BackBufferFormat;
} else {
format = D3DFMT_UNKNOWN;
}
res = pCtx->GetResourceManager()->
CreateTexture(d3dsdo->width, d3dsdo->height,
isRTT, isOpaque,
&format, 0/*usage*/, &d3dsdo->pResource);
if (SUCCEEDED(res)) {
J2dTraceLn1(J2D_TRACE_VERBOSE,
" created texture pResource=%x", d3dsdo->pResource);
d3dsdo->pResource->SetSDOps(d3dsdo);
} else {
D3DRQ_MarkLostIfNeeded(res, d3dsdo);
}
D3DSD_SetNativeDimensions(env, d3dsdo);
return SUCCEEDED(res);
}
/*
* Class: sun_java2d_d3d_D3DSurfaceData
* Method: initPlain
* Signature: (JZ)Z
*/
JNIEXPORT jboolean JNICALL
Java_sun_java2d_d3d_D3DSurfaceData_initRTSurface
(JNIEnv *env, jobject d3dsd, jlong pData, jboolean isOpaque)
{
HRESULT res;
D3DSDOps *d3dsdo;
D3DContext *pCtx;
D3DPipelineManager *pMgr;
D3DFORMAT format = D3DFMT_UNKNOWN;
J2dTraceLn(J2D_TRACE_INFO, "D3DSurfaceData_initRTSurface");
RETURN_STATUS_IF_NULL(d3dsdo = (D3DSDOps *)jlong_to_ptr(pData), JNI_FALSE);
RETURN_STATUS_IF_NULL(pMgr = D3DPipelineManager::GetInstance(), JNI_FALSE);
if (FAILED(res = pMgr->GetD3DContext(d3dsdo->adapter, &pCtx))) {
D3DRQ_MarkLostIfNeeded(res, d3dsdo);
return JNI_FALSE;
}
RETURN_STATUS_IF_NULL(pCtx->GetResourceManager(), JNI_FALSE);
pCtx->GetResourceManager()->ReleaseResource(d3dsdo->pResource);
d3dsdo->pResource = NULL;
res = pCtx->GetResourceManager()->
CreateRTSurface(d3dsdo->width, d3dsdo->height,
isOpaque, FALSE /*lockable*/,
&format, &d3dsdo->pResource);
if (SUCCEEDED(res)) {
J2dTraceLn1(J2D_TRACE_VERBOSE, " created RT surface pResource=0x%x",
d3dsdo->pResource);
d3dsdo->pResource->SetSDOps(d3dsdo);
} else {
D3DRQ_MarkLostIfNeeded(res, d3dsdo);
}
D3DSD_SetNativeDimensions(env, d3dsdo);
return SUCCEEDED(res);
}
/*
* Class: sun_java2d_d3d_D3DSurfaceData
* Method: initFlipBackbuffer
* Signature: (JJIZ)Z
*/
JNIEXPORT jboolean
JNICALL Java_sun_java2d_d3d_D3DSurfaceData_initFlipBackbuffer
(JNIEnv *env, jobject d3dsd, jlong pData, jlong pPeerData,
jint numBuffers, jint swapEffect,
jint vSyncType)
{
HRESULT res;
D3DSDOps *d3dsdo;
D3DContext *pCtx;
D3DPipelineManager *pMgr;
HWND hWnd;
UINT presentationInterval;
AwtComponent *pPeer;
RECT r = { 0, 0, 0, 0 };
J2dTraceLn(J2D_TRACE_INFO, "D3DSurfaceData_initFlipBackbuffer");
RETURN_STATUS_IF_NULL(d3dsdo = (D3DSDOps *)jlong_to_ptr(pData), JNI_FALSE);
RETURN_STATUS_IF_NULL(pMgr = D3DPipelineManager::GetInstance(), JNI_FALSE);
RETURN_STATUS_IF_NULL(pPeer = (AwtComponent *)jlong_to_ptr(pPeerData),
JNI_FALSE);
hWnd = pPeer->GetHWnd();
if (!IsWindow(hWnd)) {
J2dTraceLn(J2D_TRACE_WARNING,
"D3DSurfaceData_initFlipBackbuffer: disposed component");
return JNI_FALSE;
}
pPeer->GetInsets(&r);
d3dsdo->xoff = -r.left;
d3dsdo->yoff = -r.top;
if (FAILED(res = pMgr->GetD3DContext(d3dsdo->adapter, &pCtx))) {
D3DRQ_MarkLostIfNeeded(res, d3dsdo);
return JNI_FALSE;
}
RETURN_STATUS_IF_NULL(pCtx->GetResourceManager(), JNI_FALSE);
pCtx->GetResourceManager()->ReleaseResource(d3dsdo->pResource);
d3dsdo->pResource = NULL;
d3dsdo->swapEffect = (D3DSWAPEFFECT)swapEffect;
// in full-screen mode we should v-sync
if (pCtx->GetPresentationParams()->Windowed) {
if (vSyncType == VSYNC_ON) {
presentationInterval = D3DPRESENT_INTERVAL_ONE;
J2dTraceLn(J2D_TRACE_VERBOSE,
" windowed, forced interval: ONE");
} else {
presentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
J2dTraceLn(J2D_TRACE_VERBOSE,
" windowed, default interval: IMMEDIATE");
}
// REMIND: this is a workaround for the current issue
// we have with non-copy flip chains: since we can not specify
// the dest rectangle for Present for these modes, the result of
// Present(NULL, NULL) is scaled to the client area.
if (d3dsdo->xoff != 0 || d3dsdo->yoff != 0) {
d3dsdo->swapEffect = D3DSWAPEFFECT_COPY;
}
} else {
if (vSyncType == VSYNC_OFF) {
presentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
J2dTraceLn(J2D_TRACE_VERBOSE,
" full-screen, forced interval: IMMEDIATE");
} else {
presentationInterval = D3DPRESENT_INTERVAL_ONE;
J2dTraceLn(J2D_TRACE_VERBOSE,
" full-screen, default interval: ONE");
}
}
res = pCtx->GetResourceManager()->
CreateSwapChain(hWnd, numBuffers,
d3dsdo->width, d3dsdo->height,
d3dsdo->swapEffect, presentationInterval,
&d3dsdo->pResource);
if (SUCCEEDED(res)) {
J2dTraceLn1(J2D_TRACE_VERBOSE, " created swap chain pResource=0x%x",
d3dsdo->pResource);
d3dsdo->pResource->SetSDOps(d3dsdo);
} else {
D3DRQ_MarkLostIfNeeded(res, d3dsdo);
}
D3DSD_SetNativeDimensions(env, d3dsdo);
return SUCCEEDED(res);
}
/*
* Class: sun_java2d_d3d_D3DSurfaceData
* Method: dbGetPixelNative
* Signature: (JII)I
*/
JNIEXPORT jint JNICALL Java_sun_java2d_d3d_D3DSurfaceData_dbGetPixelNative
(JNIEnv *env, jclass clazz, jlong pData, jint x, jint y)
{
HRESULT res;
D3DSDOps *d3dsdo;
D3DContext *pCtx;
D3DPipelineManager *pMgr;
D3DResource *pLockableRes;
jint pixel = 0;
J2dTraceLn(J2D_TRACE_INFO, "D3DSurfaceData_dbGetPixelNative");
RETURN_STATUS_IF_NULL(d3dsdo = (D3DSDOps *)jlong_to_ptr(pData), pixel);
RETURN_STATUS_IF_NULL(d3dsdo->pResource, pixel);
RETURN_STATUS_IF_NULL(pMgr = D3DPipelineManager::GetInstance(), pixel);
if (FAILED(res = pMgr->GetD3DContext(d3dsdo->adapter, &pCtx))) {
D3DRQ_MarkLostIfNeeded(res, d3dsdo);
return pixel;
}
RETURN_STATUS_IF_NULL(pCtx->GetResourceManager(), 0);
IDirect3DDevice9 *pd3dDevice = pCtx->Get3DDevice();
IDirect3DSurface9 *pSrc = d3dsdo->pResource->GetSurface();
D3DFORMAT srcFmt = d3dsdo->pResource->GetDesc()->Format;
pCtx->UpdateState(STATE_OTHEROP);
res = pCtx->GetResourceManager()->
GetLockableRTSurface(1, 1, srcFmt, &pLockableRes);
if (SUCCEEDED(res)) {
IDirect3DSurface9 *pTmpSurface;
RECT srcRect = { x, y, x+1, y+1};
RECT dstRect = { 0l, 0l, 1, 1 };
pTmpSurface = pLockableRes->GetSurface();
res = pd3dDevice->StretchRect(pSrc, &srcRect, pTmpSurface, &dstRect,
D3DTEXF_NONE);
if (SUCCEEDED(res)) {
D3DLOCKED_RECT lRect;
res = pTmpSurface->LockRect(&lRect, &dstRect, D3DLOCK_NOSYSLOCK);
if (SUCCEEDED(res)) {
if (srcFmt == D3DFMT_X8R8G8B8) {
pixel = *(jint*)lRect.pBits;
} else {
pixel = *(unsigned short*)lRect.pBits;
}
pTmpSurface->UnlockRect();
}
}
}
D3DRQ_MarkLostIfNeeded(res, d3dsdo);
return pixel;
}
/*
* Class: sun_java2d_d3d_D3DSurfaceData
* Method: dbSetPixelNative
* Signature: (JIII)V
*/
JNIEXPORT void JNICALL Java_sun_java2d_d3d_D3DSurfaceData_dbSetPixelNative
(JNIEnv *env, jclass clazz, jlong pData, jint x, jint y, jint pixel)
{
HRESULT res;
D3DSDOps *d3dsdo;
D3DResource *pLockableRes;
D3DContext *pCtx;
D3DPipelineManager *pMgr;
J2dTraceLn(J2D_TRACE_INFO, "D3DSurfaceData_dbSetPixelNative");
RETURN_IF_NULL(d3dsdo = (D3DSDOps *)jlong_to_ptr(pData));
RETURN_IF_NULL(d3dsdo->pResource);
RETURN_IF_NULL(pMgr = D3DPipelineManager::GetInstance());
if (FAILED(res = pMgr->GetD3DContext(d3dsdo->adapter, &pCtx))) {
D3DRQ_MarkLostIfNeeded(res, d3dsdo);
return;
}
RETURN_IF_NULL(pCtx->GetResourceManager());
IDirect3DDevice9 *pd3dDevice = pCtx->Get3DDevice();
IDirect3DSurface9 *pSrc = d3dsdo->pResource->GetSurface();
D3DFORMAT srcFmt = d3dsdo->pResource->GetDesc()->Format;
pCtx->UpdateState(STATE_OTHEROP);
res = pCtx->GetResourceManager()->
GetLockableRTSurface(1, 1, srcFmt, &pLockableRes);
if (SUCCEEDED(res)) {
IDirect3DSurface9 *pTmpSurface;
D3DLOCKED_RECT lRect;
RECT srcRect = { 0l, 0l, 1, 1 };
RECT dstRect = { x, y, x+1, y+1};
pTmpSurface = pLockableRes->GetSurface();
res = pTmpSurface->LockRect(&lRect, &srcRect, D3DLOCK_NOSYSLOCK);
if (SUCCEEDED(res)) {
if (srcFmt == D3DFMT_X8R8G8B8) {
*(jint*)lRect.pBits = pixel;
} else {
*(unsigned short*)lRect.pBits = (unsigned short)pixel;
}
pTmpSurface->UnlockRect();
res = pd3dDevice->StretchRect(pTmpSurface, &srcRect, pSrc, &dstRect,
D3DTEXF_NONE);
}
}
D3DRQ_MarkLostIfNeeded(res, d3dsdo);
}
/*
* Class: sun_java2d_d3d_D3DSurfaceData
* Method: getNativeResourceNative
* Signature: (JI)J
*/
JNIEXPORT jlong JNICALL
Java_sun_java2d_d3d_D3DSurfaceData_getNativeResourceNative
(JNIEnv *env, jclass d3sdc, jlong pData, jint resType)
{
D3DSDOps *d3dsdo;
J2dTraceLn(J2D_TRACE_INFO, "D3DSurfaceData_getNativeResourceNative")
RETURN_STATUS_IF_NULL(d3dsdo = (D3DSDOps *)jlong_to_ptr(pData), 0L);
if (resType == D3D_DEVICE_RESOURCE) {
HRESULT res;
D3DPipelineManager *pMgr;
D3DContext *pCtx;
RETURN_STATUS_IF_NULL(pMgr = D3DPipelineManager::GetInstance(), 0L);
if (FAILED(res = pMgr->GetD3DContext(d3dsdo->adapter, &pCtx))) {
D3DRQ_MarkLostIfNeeded(res, d3dsdo);
return 0L;
}
return ptr_to_jlong(pCtx->Get3DDevice());
}
RETURN_STATUS_IF_NULL(d3dsdo->pResource, 0L);
if (resType == RT_PLAIN || resType == RT_TEXTURE) {
return ptr_to_jlong(d3dsdo->pResource->GetSurface());
}
if (resType == TEXTURE) {
return ptr_to_jlong(d3dsdo->pResource->GetTexture());
}
if (resType == FLIP_BACKBUFFER) {
return ptr_to_jlong(d3dsdo->pResource->GetSwapChain());
}
return 0L;
}
/*
* Class: sun_java2d_d3d_D3DSurfaceData
* Method: updateWindowAccelImpl
* Signature: (JJII)Z
*/
JNIEXPORT jboolean
JNICALL Java_sun_java2d_d3d_D3DSurfaceData_updateWindowAccelImpl
(JNIEnv *env, jclass clazz, jlong pd3dsd, jlong pData, jint w, jint h)
{
HRESULT res;
AwtWindow *window;
HBITMAP hBitmap = NULL;
D3DSDOps *d3dsdo;
D3DResource *pSrcRes;
D3DContext *pCtx;
D3DPipelineManager *pMgr;
D3DResource *pLockableRes = NULL;
IDirect3DSurface9 *pTmpSurface = NULL;
IDirect3DDevice9 *pd3dDevice = NULL;
D3DLOCKED_RECT lockedRect;
J2dTraceLn(J2D_TRACE_ERROR, "D3DSurfaceData_updateWindowAccelImpl");
if (w <= 0 || h <= 0) {
return JNI_TRUE;
}
RETURN_STATUS_IF_NULL(window = (AwtWindow *)jlong_to_ptr(pData), JNI_FALSE);
RETURN_STATUS_IF_NULL(d3dsdo = (D3DSDOps *)jlong_to_ptr(pd3dsd), JNI_FALSE);
RETURN_STATUS_IF_NULL(pMgr = D3DPipelineManager::GetInstance(), JNI_FALSE);
RETURN_STATUS_IF_NULL(pSrcRes = d3dsdo->pResource, JNI_FALSE);
if (FAILED(res = pMgr->GetD3DContext(d3dsdo->adapter, &pCtx))) {
D3DRQ_MarkLostIfNeeded(res, d3dsdo);
return JNI_FALSE;
}
RETURN_STATUS_IF_NULL(pd3dDevice = pCtx->Get3DDevice(), JNI_FALSE);
pCtx->UpdateState(STATE_OTHEROP);
res = pCtx->GetResourceManager()->
GetBlitOSPSurface(pSrcRes->GetDesc()->Width,
pSrcRes->GetDesc()->Height,
pSrcRes->GetDesc()->Format,
&pLockableRes);
if (FAILED(res)) {
D3DRQ_MarkLostIfNeeded(res, d3dsdo);
return JNI_FALSE;
}
pTmpSurface = pLockableRes->GetSurface();
res = pd3dDevice->GetRenderTargetData(pSrcRes->GetSurface(), pTmpSurface);
if (FAILED(res)) {
D3DRQ_MarkLostIfNeeded(res, d3dsdo);
return JNI_FALSE;
}
res = pTmpSurface->LockRect(&lockedRect, NULL, D3DLOCK_NOSYSLOCK);
if (SUCCEEDED(res)) {
hBitmap =
BitmapUtil::CreateBitmapFromARGBPre(w, h,
lockedRect.Pitch,
(int*)lockedRect.pBits);
pTmpSurface->UnlockRect();
}
RETURN_STATUS_IF_NULL(hBitmap, JNI_FALSE);
window->UpdateWindow(env, NULL, w, h, hBitmap);
// hBitmap is released in UpdateWindow
return JNI_TRUE;
}
}