/* * 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 #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; } }