| /* |
| * Copyright 2005-2006 Sun Microsystems, Inc. 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. Sun designates this |
| * particular file as subject to the "Classpath" exception as provided |
| * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, |
| * CA 95054 USA or visit www.sun.com if you need additional information or |
| * have any questions. |
| */ |
| |
| #include "sun_java2d_d3d_D3DContext.h" |
| #include "jlong.h" |
| #include "jni_util.h" |
| #include "Trace.h" |
| |
| #include "ddrawUtils.h" |
| #include "awt_Win32GraphicsDevice.h" |
| #include "sun_java2d_SunGraphics2D.h" |
| |
| #include "GraphicsPrimitiveMgr.h" |
| |
| #include "RegistryKey.h" |
| #include "WindowsFlags.h" |
| |
| #include "Win32SurfaceData.h" |
| #include "D3DSurfaceData.h" |
| #include "D3DUtils.h" |
| #include "D3DContext.h" |
| #include "D3DRuntimeTest.h" |
| |
| #include "IntDcm.h" |
| #include "IntArgb.h" |
| #include "Region.h" |
| |
| typedef struct { |
| D3DBLEND src; |
| D3DBLEND dst; |
| } D3DBlendRule; |
| |
| /** |
| * This table contains the standard blending rules (or Porter-Duff compositing |
| * factors) used in SetRenderState(), indexed by the rule constants from the |
| * AlphaComposite class. |
| */ |
| D3DBlendRule StdBlendRules[] = { |
| { D3DBLEND_ZERO, D3DBLEND_ZERO }, /* 0 - Nothing */ |
| { D3DBLEND_ZERO, D3DBLEND_ZERO }, /* 1 - RULE_Clear */ |
| { D3DBLEND_ONE, D3DBLEND_ZERO }, /* 2 - RULE_Src */ |
| { D3DBLEND_ONE, D3DBLEND_INVSRCALPHA }, /* 3 - RULE_SrcOver */ |
| { D3DBLEND_INVDESTALPHA, D3DBLEND_ONE }, /* 4 - RULE_DstOver */ |
| { D3DBLEND_DESTALPHA, D3DBLEND_ZERO }, /* 5 - RULE_SrcIn */ |
| { D3DBLEND_ZERO, D3DBLEND_SRCALPHA }, /* 6 - RULE_DstIn */ |
| { D3DBLEND_INVDESTALPHA, D3DBLEND_ZERO }, /* 7 - RULE_SrcOut */ |
| { D3DBLEND_ZERO, D3DBLEND_INVSRCALPHA }, /* 8 - RULE_DstOut */ |
| { D3DBLEND_ZERO, D3DBLEND_ONE }, /* 9 - RULE_Dst */ |
| { D3DBLEND_DESTALPHA, D3DBLEND_INVSRCALPHA }, /*10 - RULE_SrcAtop */ |
| { D3DBLEND_INVDESTALPHA, D3DBLEND_SRCALPHA }, /*11 - RULE_DstAtop */ |
| { D3DBLEND_INVDESTALPHA, D3DBLEND_INVSRCALPHA }, /*12 - RULE_AlphaXor*/ |
| }; |
| |
| /** |
| * D3DContext |
| */ |
| D3DContext* D3DContext::CreateD3DContext(DDraw *ddObject, DXObject* dxObject) |
| { |
| J2dTraceLn(J2D_TRACE_INFO, "D3DContext::CreateD3DContext"); |
| // create and test the d3d context |
| D3DContext *d3dContext = new D3DContext(ddObject, dxObject); |
| // if there was a failure while creating or testing the device, |
| // dispose of it and return NULL |
| if (!(d3dContext->GetDeviceCaps() & J2D_D3D_ENABLED_OK)) { |
| delete d3dContext; |
| d3dContext = NULL; |
| } |
| return d3dContext; |
| } |
| |
| D3DContext::D3DContext(DDraw *ddObject, DXObject* dxObject) |
| { |
| GetExclusiveAccess(); |
| J2dRlsTraceLn(J2D_TRACE_INFO, "D3DContext::D3DContext"); |
| J2dTraceLn2(J2D_TRACE_VERBOSE, " ddObject=0x%d dxObject=0x%x", |
| ddObject, dxObject); |
| d3dDevice = NULL; |
| d3dObject = NULL; |
| ddTargetSurface = NULL; |
| lpMaskTexture = NULL; |
| lpGlyphCacheTexture = NULL; |
| glyphCache = NULL; |
| glyphCacheAvailable = TRUE; |
| deviceCaps = J2D_D3D_FAILURE; |
| bBeginScenePending = FALSE; |
| jD3DContext = NULL; |
| |
| this->dxObject = dxObject; |
| this->ddObject = ddObject; |
| |
| if (SUCCEEDED(dxObject->CreateD3DObject(&d3dObject))) { |
| |
| // The device type we choose to use doesn't change over time |
| pDeviceGUID = D3DUtils_SelectDeviceGUID(d3dObject); |
| if (pDeviceGUID) { |
| bIsHWRasterizer = (*pDeviceGUID == IID_IDirect3DHALDevice || |
| *pDeviceGUID == IID_IDirect3DTnLHalDevice); |
| CreateD3DDevice(); |
| } else { |
| J2dRlsTraceLn(J2D_TRACE_ERROR, |
| "D3CCoD3DContext::D3DContext: Can't find "\ |
| "suitable D3D device"); |
| } |
| } else { |
| J2dRlsTraceLn(J2D_TRACE_ERROR, |
| "D3DContext::D3DContext: Can't "\ |
| "create IDirect3D7 interface"); |
| } |
| |
| compState = sun_java2d_SunGraphics2D_COMP_ISCOPY; |
| extraAlpha = 1.0f; |
| colorPixel = 0xffffffff; |
| |
| ReleaseExclusiveAccess(); |
| } |
| |
| void D3DContext::SetJavaContext(JNIEnv *env, jobject newD3Dc) { |
| GetExclusiveAccess(); |
| |
| // Only bother if the new D3DContext object is different |
| // from the one we already have reference to. |
| if (env->IsSameObject(newD3Dc, jD3DContext) == FALSE) { |
| J2dTraceLn(J2D_TRACE_VERBOSE, "D3DContext:SetJavaContext: "\ |
| "setting new java context object"); |
| // invalidate the old context, since we've got a new one |
| InvalidateIfTarget(env, ddTargetSurface); |
| |
| if (jD3DContext != NULL) { |
| env->DeleteWeakGlobalRef(jD3DContext); |
| } |
| // set the new java-level context object |
| jD3DContext = env->NewWeakGlobalRef(newD3Dc); |
| } |
| ReleaseExclusiveAccess(); |
| } |
| |
| void D3DContext::Release3DDevice() { |
| GetExclusiveAccess(); |
| J2dTraceLn1(J2D_TRACE_INFO, |
| "D3DContext::Release3DDevice: d3dDevice = 0x%x", |
| d3dDevice); |
| |
| // make sure we do EndScene if one is pending |
| FlushD3DQueueForTarget(ddTargetSurface); |
| |
| // Let the java-level object know that the context |
| // state is no longer valid, forcing it to be reinitialized |
| // later. |
| JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); |
| InvalidateIfTarget(env, ddTargetSurface); |
| |
| // We don't need to release it since we didn't create it |
| ddTargetSurface = NULL; |
| |
| // disable the use of this context until we ensure the capabilities |
| // of the new device and run the tests |
| deviceCaps = J2D_D3D_FAILURE; |
| |
| if (lpMaskTexture != NULL) { |
| lpMaskTexture->Release(); |
| delete lpMaskTexture; |
| lpMaskTexture = NULL; |
| } |
| |
| // reset the depth buffer format |
| memset(&depthBufferFormat, 0, sizeof(depthBufferFormat)); |
| |
| if (d3dDevice) { |
| // setting the texture increases its reference number, so |
| // we should reset the textures for all stages to make sure |
| // they're released |
| for (int stage = 0; stage <= MAX_USED_TEXTURE_STAGE; stage++) { |
| d3dDevice->SetTexture(stage, NULL); |
| lastTexture[stage] = NULL; |
| } |
| d3dDevice->Release(); |
| d3dDevice = NULL; |
| } |
| ReleaseExclusiveAccess(); |
| } |
| |
| D3DContext::~D3DContext() { |
| J2dTraceLn2(J2D_TRACE_INFO, |
| "~D3DContext: d3dDevice=0x%x, d3dObject =0x%x", |
| d3dDevice, d3dObject); |
| GetExclusiveAccess(); |
| if (lpGlyphCacheTexture != NULL) { |
| lpGlyphCacheTexture->Release(); |
| delete lpGlyphCacheTexture; |
| lpGlyphCacheTexture = NULL; |
| } |
| Release3DDevice(); |
| if (d3dObject != NULL) { |
| d3dObject->Release(); |
| d3dObject = NULL; |
| } |
| ReleaseExclusiveAccess(); |
| } |
| |
| HRESULT |
| D3DContext::InitD3DDevice(IDirect3DDevice7 *d3dDevice) |
| { |
| HRESULT res = D3D_OK; |
| J2dRlsTraceLn1(J2D_TRACE_INFO, |
| "D3DContext::InitD3DDevice: d3dDevice=Ox%x", d3dDevice); |
| |
| d3dDevice->GetCaps(&d3dDevDesc); |
| // disable some of the unneeded and costly d3d functionality |
| d3dDevice->SetRenderState(D3DRENDERSTATE_CULLMODE, D3DCULL_NONE); |
| d3dDevice->SetRenderState(D3DRENDERSTATE_TEXTUREPERSPECTIVE, FALSE); |
| d3dDevice->SetRenderState(D3DRENDERSTATE_SPECULARENABLE, FALSE); |
| d3dDevice->SetRenderState(D3DRENDERSTATE_LIGHTING, FALSE); |
| d3dDevice->SetRenderState(D3DRENDERSTATE_CLIPPING, FALSE); |
| d3dDevice->SetRenderState(D3DRENDERSTATE_ZENABLE, D3DZB_FALSE); |
| d3dDevice->SetRenderState(D3DRENDERSTATE_COLORVERTEX, FALSE); |
| d3dDevice->SetRenderState(D3DRENDERSTATE_STENCILENABLE, FALSE); |
| |
| d3dDevice->SetTextureStageState(0, D3DTSS_MAGFILTER, D3DTFG_POINT); |
| d3dDevice->SetTextureStageState(0, D3DTSS_MINFILTER, D3DTFG_POINT); |
| |
| // these states never change |
| d3dDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_MODULATE); |
| d3dDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE); |
| d3dDevice->SetTextureStageState(0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE); |
| d3dDevice->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE); |
| // init the array of latest textures |
| memset(&lastTexture, 0, sizeof(lastTexture)); |
| // this will force the state initialization on first UpdateState |
| opState = STATE_UNDEFINED; |
| |
| D3DMATRIX tx; |
| D3DUtils_SetIdentityMatrix(&tx); |
| d3dDevice->SetTransform(D3DTRANSFORMSTATE_WORLD, &tx); |
| |
| bBeginScenePending = FALSE; |
| |
| D3DUtils_SetupTextureFormats(d3dDevice, textureTable); |
| |
| // REMIND: debugging: allows testing the argb path in |
| // UploadImageToTexture on devices with alpha texture support |
| if ((getenv("J2D_D3D_NOALPHATEXTURE") != NULL) || |
| FAILED(res = D3DUtils_FindMaskTileTextureFormat(d3dDevice, |
| &maskTileTexFormat))) |
| { |
| // use ARGB if can't find alpha texture (or in case argb |
| // was specifically requested) |
| J2dTraceLn(J2D_TRACE_VERBOSE, |
| "D3DContext::InitD3DDevice: "\ |
| "Using IntARBG instead of Alpha texture"); |
| if (textureTable[TR_TRANSLUCENT_IDX][DEPTH32_IDX].pfType != PF_INVALID) |
| { |
| memcpy(&maskTileTexFormat, |
| &textureTable[TR_TRANSLUCENT_IDX][DEPTH32_IDX].pddpf, |
| sizeof(maskTileTexFormat)); |
| res = D3D_OK; |
| } |
| } else { |
| J2dTraceLn(J2D_TRACE_VERBOSE, |
| "D3DContext::InitD3DDevice: Found Alpha-texture format"); |
| } |
| return res; |
| } |
| |
| HRESULT |
| D3DContext::CreateAndTestD3DDevice(DxCapabilities *dxCaps) |
| { |
| J2dRlsTraceLn(J2D_TRACE_INFO, "D3DContext::CreateAndTestD3DDevice"); |
| HRESULT res; |
| if (pDeviceGUID == NULL) { |
| J2dRlsTraceLn(J2D_TRACE_ERROR, |
| "D3DContext::CreateAndTestD3DDevice: "\ |
| "No usable d3d device"); |
| deviceCaps = J2D_D3D_FAILURE; |
| return DDERR_GENERIC; |
| } |
| |
| Release3DDevice(); |
| |
| // Create a temp surface so we can use it when creating a device |
| DXSurface *target = NULL; |
| if (FAILED(res = CreateSurface(NULL, 10, 10, 32, TR_OPAQUE, |
| D3D_PLAIN_SURFACE|D3D_RENDER_TARGET, |
| &target, NULL))) |
| { |
| DebugPrintDirectDrawError(res, |
| "D3DContext::CreateAndTestD3DDevice: "\ |
| "can't create scratch surface"); |
| return res; |
| } |
| |
| if (FAILED(res = d3dObject->CreateDevice(*pDeviceGUID, |
| target->GetDDSurface(), |
| &d3dDevice))) |
| { |
| DebugPrintDirectDrawError(res, |
| "D3DContext::CreateAndTestD3DDevice: "\ |
| "error creating d3d device"); |
| } else if (FAILED(res = InitD3DDevice(d3dDevice))) { |
| DebugPrintDirectDrawError(res, |
| "D3DContext::CreateAndTestD3DDevice: "\ |
| "error initializing D3D device"); |
| } else { |
| J2dRlsTraceLn(J2D_TRACE_VERBOSE, |
| "D3DContext::CreateAndTestD3DDevice: "\ |
| "D3D device creation/initialization successful"); |
| // the device is successfully created and initialized, |
| // now run some tests on it |
| deviceCaps = TestD3DDevice(ddObject, this, dxCaps); |
| } |
| |
| // We can safely dispose the scratch surface here |
| if (target != NULL) { |
| target->Release(); |
| delete target; |
| } |
| |
| return res; |
| } |
| |
| void |
| D3DContext::CreateD3DDevice() |
| { |
| GetExclusiveAccess(); |
| J2dRlsTraceLn(J2D_TRACE_INFO, "D3DContext::CreateD3DDevice"); |
| // this is a weird way of getting a handle on the ddInstance |
| HMONITOR hMonitor = dxObject->GetHMonitor(); |
| DxCapabilities *dxCaps = |
| AwtWin32GraphicsDevice::GetDxCapsForDevice(hMonitor); |
| |
| int d3dCapsValidity = dxCaps->GetD3dCapsValidity(); |
| // Always run the test unless we crashed doing so the last time. |
| // The reasons: |
| // - the user may have disabled d3d acceleration in the display panel |
| // since the last run |
| // - the user may have installed the new drivers, which may cause BSODs |
| // - if the test had failed previously because of quality issues, the |
| // new driver may have fixed the problem, but we'd never know since we |
| // never try again |
| // - user (or developer, rather) may have specified a |
| // different rasterizer via env. variable |
| if (d3dCapsValidity != J2D_ACCEL_TESTING) { |
| dxCaps->SetD3dCapsValidity(J2D_ACCEL_TESTING); |
| |
| // this will create the device, test it and set the |
| // deviceCaps |
| CreateAndTestD3DDevice(dxCaps); |
| |
| dxCaps->SetD3dDeviceCaps(deviceCaps); |
| dxCaps->SetD3dCapsValidity(J2D_ACCEL_SUCCESS); |
| } |
| int requiredResults = forceD3DUsage ? |
| J2D_D3D_REQUIRED_RESULTS : J2D_D3D_DESIRED_RESULTS; |
| |
| #ifdef DEBUG |
| J2dTraceLn(J2D_TRACE_VERBOSE, "CreateD3DDevice: requested caps:"); |
| PrintD3DCaps(requiredResults); |
| J2dTraceLn(J2D_TRACE_VERBOSE, " caps supported by the device:"); |
| PrintD3DCaps(deviceCaps); |
| J2dTraceLn(J2D_TRACE_VERBOSE, " missing caps:"); |
| PrintD3DCaps(requiredResults & ~deviceCaps); |
| #endif // DEBUG |
| |
| if ((deviceCaps & requiredResults) != requiredResults) { |
| if (!(deviceCaps & J2D_D3D_HW_OK)) { |
| // disable d3d for all devices, because we've encountered |
| // known bad hardware. See comment in TestForBadHardware(). |
| J2dRlsTraceLn(J2D_TRACE_ERROR, |
| "CreateD3DDevice: bad hardware found,"\ |
| " disabling d3d for all devices."); |
| SetD3DEnabledFlag(NULL, FALSE, FALSE); |
| } else { |
| J2dRlsTraceLn(J2D_TRACE_ERROR, |
| "CreateD3DDevice: tests FAILED, d3d disabled."); |
| } |
| // REMIND: the first time the context initialization fails, |
| // deviceUseD3D is set to FALSE in DDrawObjectStruct, and because of |
| // this we never attempt to initialize it again later. |
| // For example, if the app switches to a display mode where |
| // d3d is not supported, we disable d3d, but it stays disabled |
| // even when the display mode is switched back to a supported one. |
| // May be we should disable it only in case of a hard error. |
| ddObject->DisableD3D(); |
| Release3DDevice(); |
| } else { |
| deviceCaps |= J2D_D3D_ENABLED_OK; |
| J2dRlsTraceLn1(J2D_TRACE_INFO, |
| "CreateD3DDevice: tests PASSED, "\ |
| "d3d enabled (forced: %s).", |
| forceD3DUsage ? "yes" : "no"); |
| } |
| |
| ReleaseExclusiveAccess(); |
| } |
| |
| HRESULT |
| D3DContext::SetRenderTarget(DDrawSurface *ddSurface) |
| { |
| static D3DVIEWPORT7 vp = { 0, 0, 0, 0, 0.0f, 1.0f }; |
| static D3DMATRIX tx; |
| BOOL bSetProjectionMatrix = FALSE; |
| HRESULT res = DDERR_GENERIC; |
| GetExclusiveAccess(); |
| |
| J2dTraceLn2(J2D_TRACE_INFO, |
| "D3DContext::SetRenderTarget: old=0x%x new=0x%x", |
| ddTargetSurface, ddSurface); |
| |
| ddTargetSurface = NULL; |
| |
| DXSurface *dxSurface = NULL; |
| if (d3dDevice == NULL || ddSurface == NULL || |
| (dxSurface = ddSurface->GetDXSurface()) == NULL) |
| { |
| ReleaseExclusiveAccess(); |
| J2dTraceLn3(J2D_TRACE_WARNING, |
| "D3DContext::SetRenderTarget invalid state:"\ |
| "d3dDevice=0x%x ddSurface=0x%x dxSurface=0x%x", |
| d3dDevice, ddSurface, dxSurface); |
| return res; |
| } |
| |
| if (FAILED(res = ddSurface->IsLost())) { |
| ReleaseExclusiveAccess(); |
| DebugPrintDirectDrawError(res, "D3DContext::SetRenderTarget: "\ |
| "target surface (and/or depth buffer) lost"); |
| return res; |
| } |
| |
| ForceEndScene(); |
| |
| if (FAILED(res = d3dDevice->SetRenderTarget(dxSurface->GetDDSurface(), 0))) |
| { |
| ReleaseExclusiveAccess(); |
| DebugPrintDirectDrawError(res, "D3DContext::SetRenderTarget: "\ |
| "error setting render target"); |
| return res; |
| } |
| |
| int width = dxSurface->GetWidth(); |
| int height = dxSurface->GetHeight(); |
| // set the projection matrix if the the dimensions of the new |
| // rendertarget are different from the old one. |
| if (FAILED(d3dDevice->GetViewport(&vp)) || |
| (int)vp.dwWidth != width || (int)vp.dwHeight != height) |
| { |
| bSetProjectionMatrix = TRUE; |
| } |
| |
| vp.dwX = vp.dwY = 0; |
| vp.dwWidth = width; |
| vp.dwHeight = height; |
| vp.dvMinZ = 0.0f; |
| vp.dvMaxZ = 1.0f; |
| |
| if (FAILED(res = d3dDevice->SetViewport(&vp))) { |
| DebugPrintDirectDrawError(res, "D3DContext::SetRenderTarget: "\ |
| "error setting viewport"); |
| ReleaseExclusiveAccess(); |
| return res; |
| } |
| |
| if (bSetProjectionMatrix) { |
| D3DUtils_SetOrthoMatrixOffCenterLH(&tx, (float)width, (float)height); |
| res = d3dDevice->SetTransform(D3DTRANSFORMSTATE_PROJECTION, &tx); |
| } |
| |
| if (SUCCEEDED(res)) { |
| ddTargetSurface = ddSurface; |
| J2dTraceLn1(J2D_TRACE_VERBOSE, |
| "D3DContext::SetRenderTarget: succeeded, "\ |
| "new target=0x%x", ddTargetSurface); |
| } else { |
| DebugPrintDirectDrawError(res, "D3DContext::SetRenderTarget: failed"); |
| } |
| |
| ReleaseExclusiveAccess(); |
| return res; |
| } |
| |
| HRESULT |
| D3DContext::SetTransform(jobject xform, |
| jdouble m00, jdouble m10, |
| jdouble m01, jdouble m11, |
| jdouble m02, jdouble m12) |
| { |
| GetExclusiveAccess(); |
| |
| J2dTraceLn(J2D_TRACE_INFO, "D3DContext::SetTransform"); |
| if (d3dDevice == NULL) { |
| ReleaseExclusiveAccess(); |
| return DDERR_GENERIC; |
| } |
| HRESULT res = D3D_OK; |
| D3DMATRIX tx; |
| |
| if (xform == NULL) { |
| J2dTraceLn(J2D_TRACE_VERBOSE, " disabling transform"); |
| D3DUtils_SetIdentityMatrix(&tx); |
| } else { |
| J2dTraceLn(J2D_TRACE_VERBOSE, " enabling transform"); |
| |
| // copy values from AffineTransform object into native matrix array |
| memset(&tx, 0, sizeof(D3DMATRIX)); |
| tx._11 = (float)m00; |
| tx._12 = (float)m10; |
| tx._21 = (float)m01; |
| tx._22 = (float)m11; |
| // The -0.5 adjustment is needed to correctly align texels to |
| // pixels with orgthogonal projection matrix. |
| // Note that we readjust vertex coordinates for cases |
| // when we don't do texture mapping or use D3DPT_LINESTRIP. |
| tx._41 = (float)m02-0.5f; |
| tx._42 = (float)m12-0.5f; |
| |
| tx._33 = 1.0f; |
| tx._44 = 1.0f; |
| } |
| |
| J2dTraceLn(J2D_TRACE_VERBOSE, " setting new tx matrix"); |
| J2dTraceLn4(J2D_TRACE_VERBOSE, |
| " %5f %5f %5f %5f", tx._11, tx._12, tx._13, tx._14); |
| J2dTraceLn4(J2D_TRACE_VERBOSE, |
| " %5f %5f %5f %5f", tx._21, tx._22, tx._23, tx._24); |
| J2dTraceLn4(J2D_TRACE_VERBOSE, |
| " %5f %5f %5f %5f", tx._31, tx._32, tx._33, tx._34); |
| J2dTraceLn4(J2D_TRACE_VERBOSE, |
| " %5f %5f %5f %5f", tx._41, tx._42, tx._43, tx._44); |
| if (FAILED(res = d3dDevice->SetTransform(D3DTRANSFORMSTATE_WORLD, &tx))) { |
| DebugPrintDirectDrawError(res, "D3DContext::SetTransform failed"); |
| } |
| |
| ReleaseExclusiveAccess(); |
| return res; |
| } |
| |
| /** |
| * This method assumes that ::SetRenderTarget has already |
| * been called. SetRenderTarget creates and attaches a |
| * depth buffer to the target surface prior to setting it |
| * as target surface to the device. |
| */ |
| HRESULT |
| D3DContext::SetClip(JNIEnv *env, jobject clip, |
| jboolean isRect, |
| int x1, int y1, |
| int x2, int y2) |
| { |
| HRESULT res; |
| static J2D_XY_VERTEX clipRect[] = { |
| #ifdef USE_SINGLE_VERTEX_FORMAT |
| { 0.0f, 0.0f, 1.0f, 0xffffffff, 0.0f, 0.0f }, |
| { 0.0f, 0.0f, 1.0f, 0xffffffff, 0.0f, 0.0f }, |
| { 0.0f, 0.0f, 1.0f, 0xffffffff, 0.0f, 0.0f }, |
| { 0.0f, 0.0f, 1.0f, 0xffffffff, 0.0f, 0.0f } |
| #else |
| // Note that we use D3DFVF_XYZ vertex format |
| // implies 0xffffffff diffuse color, so we don't |
| // have to specify it. |
| { 0.0f, 0.0f, 1.0f }, |
| { 0.0f, 0.0f, 1.0f }, |
| { 0.0f, 0.0f, 1.0f }, |
| { 0.0f, 0.0f, 1.0f }, |
| #endif // USE_SINGLE_VERTEX_FORMAT |
| }; |
| static J2DXY_HEXA spanVx[MAX_CACHED_SPAN_VX_NUM]; |
| |
| J2dTraceLn(J2D_TRACE_INFO, "D3DContext::SetClip"); |
| J2dTraceLn5(J2D_TRACE_VERBOSE, |
| " x1=%-4d y1=%-4d x2=%-4d y2=%-4d isRect=%-2d", |
| x1, y1, x2, y2, isRect); |
| GetExclusiveAccess(); |
| // the target surface must already be set |
| if (d3dDevice == NULL || ddTargetSurface == NULL) { |
| ReleaseExclusiveAccess(); |
| return DDERR_GENERIC; |
| } |
| |
| |
| // Must do EndScene prior to setting a new clip, otherwise the |
| // primitives which are already in the pipeline will be rendered with |
| // the new clip when we do EndScene. |
| ForceEndScene(); |
| |
| if (clip == NULL) { |
| J2dTraceLn(J2D_TRACE_VERBOSE, |
| "D3DContext::SetClip: disabling clip (== NULL)"); |
| res = d3dDevice->SetRenderState(D3DRENDERSTATE_ZENABLE, D3DZB_FALSE); |
| ReleaseExclusiveAccess(); |
| return res; |
| } else if (isRect) { |
| // optimization: disable depth buffer if the clip is equal to |
| // the size of the viewport |
| int w = ddTargetSurface->GetDXSurface()->GetWidth(); |
| int h = ddTargetSurface->GetDXSurface()->GetHeight(); |
| if (x1 == 0 && y1 == 0 && x2 == w && y2 == h) { |
| J2dTraceLn(J2D_TRACE_VERBOSE, |
| "D3DContext::SetClip: disabling clip (== viewport)"); |
| res = d3dDevice->SetRenderState(D3DRENDERSTATE_ZENABLE, D3DZB_FALSE); |
| ReleaseExclusiveAccess(); |
| return res; |
| } |
| } |
| |
| // save the old settings |
| DWORD dwAlphaSt, dwSrcBlendSt, dwDestBlendSt; |
| d3dDevice->GetRenderState(D3DRENDERSTATE_ALPHABLENDENABLE, &dwAlphaSt); |
| d3dDevice->GetRenderState(D3DRENDERSTATE_SRCBLEND, &dwSrcBlendSt); |
| d3dDevice->GetRenderState(D3DRENDERSTATE_DESTBLEND, &dwDestBlendSt); |
| |
| d3dDevice->SetRenderState(D3DRENDERSTATE_ALPHABLENDENABLE, TRUE); |
| d3dDevice->SetRenderState(D3DRENDERSTATE_SRCBLEND, D3DBLEND_ZERO); |
| d3dDevice->SetRenderState(D3DRENDERSTATE_DESTBLEND, D3DBLEND_ONE); |
| |
| // disable texturing |
| if (lastTexture[0] != NULL) { |
| // note that we do not restore the texture after we set the clip, |
| // it will be reset the next time a texturing operation is performed |
| SetTexture(NULL); |
| } |
| |
| D3DMATRIX tx, idTx; |
| d3dDevice->GetTransform(D3DTRANSFORMSTATE_WORLD, &tx); |
| D3DUtils_SetIdentityMatrix(&idTx); |
| d3dDevice->SetTransform(D3DTRANSFORMSTATE_WORLD, &idTx); |
| |
| // The depth buffer is first cleared with zeroes, which is the farthest |
| // plane from the viewer (our projection matrix is an inversed orthogonal |
| // transform). |
| // To set the clip we'll render the clip spans with Z coordinates of 1.0f |
| // (the closest to the viewer). Since all rendering primitives |
| // have their vertices' Z coordinate set to 0.0, they will effectively be |
| // clipped because the Z depth test for them will fail (vertex with 1.0 |
| // depth is closer than the one with 0.0f) |
| d3dDevice->SetRenderState(D3DRENDERSTATE_ZENABLE, D3DZB_TRUE); |
| d3dDevice->SetRenderState(D3DRENDERSTATE_ZWRITEENABLE, TRUE); |
| d3dDevice->SetRenderState(D3DRENDERSTATE_ZFUNC, D3DCMP_ALWAYS); |
| d3dDevice->Clear(0, NULL, D3DCLEAR_ZBUFFER, 0L, 0.0f, 0x0L); |
| |
| float fx1, fy1, fx2, fy2; |
| if (SUCCEEDED(d3dDevice->BeginScene())) { |
| if (isRect) { |
| fx1 = (float)x1; fy1 = (float)y1; |
| fx2 = (float)x2; fy2 = (float)y2; |
| D3DU_INIT_VERTEX_QUAD_XY(clipRect, fx1, fy1, fx2, fy2); |
| res = d3dDevice->DrawPrimitive(D3DPT_TRIANGLEFAN, D3DFVF_XY_VERTEX, |
| clipRect, 4, NULL); |
| } else { |
| RegionData clipInfo; |
| Region_GetInfo(env, clip, &clipInfo); |
| SurfaceDataBounds span; |
| J2DXY_HEXA *pHexa = (J2DXY_HEXA*)spanVx; |
| jint numOfCachedSpans = 0; |
| |
| Region_StartIteration(env, &clipInfo); |
| while (Region_NextIteration(&clipInfo, &span)) { |
| fx1 = (float)(span.x1); fy1 = (float)(span.y1); |
| fx2 = (float)(span.x2); fy2 = (float)(span.y2); |
| D3DU_INIT_VERTEX_XYZ_6(*pHexa, fx1, fy1, fx2, fy2, 1.0f); |
| numOfCachedSpans++; |
| pHexa = (J2DXY_HEXA*)PtrAddBytes(pHexa, sizeof(J2DXY_HEXA)); |
| if (numOfCachedSpans >= MAX_CACHED_SPAN_VX_NUM) { |
| res = d3dDevice->DrawPrimitive(D3DPT_TRIANGLELIST, |
| D3DFVF_XY_VERTEX, |
| (void*)spanVx, |
| 6*numOfCachedSpans, NULL); |
| numOfCachedSpans = 0; |
| pHexa = (J2DXY_HEXA*)spanVx; |
| if (FAILED(res)) { |
| break; |
| } |
| } |
| } |
| if (numOfCachedSpans > 0) { |
| res = d3dDevice->DrawPrimitive(D3DPT_TRIANGLELIST, |
| D3DFVF_XY_VERTEX, |
| (void*)spanVx, |
| 6*numOfCachedSpans, NULL); |
| } |
| Region_EndIteration(env, &clipInfo); |
| } |
| res = d3dDevice->EndScene(); |
| } |
| |
| // reset the transform |
| d3dDevice->SetTransform(D3DTRANSFORMSTATE_WORLD, &tx); |
| |
| // reset the alpha compositing |
| d3dDevice->SetRenderState(D3DRENDERSTATE_ALPHABLENDENABLE, dwAlphaSt); |
| d3dDevice->SetRenderState(D3DRENDERSTATE_SRCBLEND, dwSrcBlendSt); |
| d3dDevice->SetRenderState(D3DRENDERSTATE_DESTBLEND, dwDestBlendSt); |
| |
| // Setup the depth buffer. |
| // We disable further updates to the depth buffer: it should only |
| // be updated in SetClip method. |
| d3dDevice->SetRenderState(D3DRENDERSTATE_ZWRITEENABLE, FALSE); |
| d3dDevice->SetRenderState(D3DRENDERSTATE_ZFUNC, D3DCMP_LESS); |
| |
| ReleaseExclusiveAccess(); |
| return res; |
| } |
| |
| DXSurface * |
| D3DContext::GetMaskTexture() |
| { |
| if (lpMaskTexture != NULL) { |
| // This in theory should never happen since |
| // we're using managed textures, but in case |
| // we switch to using something else. |
| if (FAILED(lpMaskTexture->IsLost())) { |
| lpMaskTexture->Restore(); |
| } |
| return lpMaskTexture; |
| } |
| InitMaskTileTexture(); |
| return lpMaskTexture; |
| } |
| |
| |
| HRESULT |
| D3DContext::InitMaskTileTexture() |
| { |
| HRESULT res; |
| |
| J2dTraceLn(J2D_TRACE_INFO, "D3DContext::InitMaskTileTexture"); |
| if (lpMaskTexture != NULL) { |
| lpMaskTexture->Release(); |
| } |
| lpMaskTexture = NULL; |
| |
| DWORD caps2 = 0, caps = DDSCAPS_TEXTURE; |
| if (bIsHWRasterizer) { |
| caps2 = DDSCAPS2_TEXTUREMANAGE; |
| } else { |
| caps |= DDSCAPS_SYSTEMMEMORY; |
| } |
| |
| if (FAILED(res = |
| dxObject->CreateSurface(DDSD_WIDTH|DDSD_HEIGHT|DDSD_CAPS| |
| DDSD_PIXELFORMAT|DDSD_TEXTURESTAGE, |
| caps, |
| caps2, |
| &maskTileTexFormat, |
| D3DSD_MASK_TILE_SIZE, D3DSD_MASK_TILE_SIZE, |
| (DXSurface **)&lpMaskTexture, 0))) |
| { |
| // in case we want to do something here later.. |
| DebugPrintDirectDrawError(res, |
| "D3DContext::InitMaskTileTexture: "\ |
| "failed to create mask tile texture"); |
| } |
| return res; |
| } |
| |
| HRESULT |
| D3DContext::UploadImageToTexture(DXSurface *texture, jubyte *pixels, |
| jint dstx, jint dsty, |
| jint srcx, jint srcy, |
| jint srcWidth, jint srcHeight, |
| jint srcStride) |
| { |
| HRESULT res = D3D_OK; |
| SurfaceDataRasInfo rasInfo; |
| |
| |
| RECT r = { dstx, dsty, dstx+srcWidth, dsty+srcHeight }; |
| J2dTraceLn(J2D_TRACE_INFO, "D3DContext::UploadImageToTexture"); |
| J2dTraceLn4(J2D_TRACE_VERBOSE, |
| " rect={%-4d, %-4d, %-4d, %-4d}", |
| r.left, r.top, r.right, r.bottom); |
| // REMIND: it may be faster to lock for NULL instead of |
| // rect, need to test later. |
| if (FAILED(res = texture->Lock(&r, &rasInfo, |
| DDLOCK_WAIT|DDLOCK_NOSYSLOCK, NULL))) |
| { |
| DebugPrintDirectDrawError(res, |
| "D3DContext::UploadImageToTexture: could "\ |
| "not lock texture"); |
| return res; |
| } |
| |
| if (rasInfo.pixelStride == 1) { |
| // 8bpp alpha texture |
| void *pSrcPixels = PtrCoord(pixels, srcx, 1, srcy, srcStride); |
| void *pDstPixels = rasInfo.rasBase; |
| do { |
| memcpy(pDstPixels, pSrcPixels, srcWidth); |
| pSrcPixels = PtrAddBytes(pSrcPixels, srcStride); |
| pDstPixels = PtrAddBytes(pDstPixels, rasInfo.scanStride); |
| } while (--srcHeight > 0); |
| } else { |
| // ARGB texture |
| jubyte *pSrcPixels = (jubyte*)PtrCoord(pixels, srcx, 1, srcy, srcStride); |
| jint *pDstPixels = (jint*)rasInfo.rasBase; |
| for (int yy = 0; yy < srcHeight; yy++) { |
| for (int xx = 0; xx < srcWidth; xx++) { |
| jubyte pix = pSrcPixels[xx]; |
| StoreIntArgbFrom4ByteArgb(pDstPixels, 0, xx, |
| pix, pix, pix, pix); |
| } |
| pSrcPixels = (jubyte*)PtrAddBytes(pSrcPixels, srcStride); |
| pDstPixels = (jint*)PtrAddBytes(pDstPixels, rasInfo.scanStride); |
| } |
| } |
| return texture->Unlock(&r); |
| } |
| |
| HRESULT |
| D3DContext::InitGlyphCache() |
| { |
| HRESULT res = D3D_OK; |
| |
| if (glyphCache != NULL) { |
| return D3D_OK; |
| } |
| |
| if (!glyphCacheAvailable) { |
| return DDERR_GENERIC; |
| } |
| |
| J2dTraceLn(J2D_TRACE_INFO, "D3DContext::InitGlyphCache"); |
| |
| // init glyph cache data structure |
| glyphCache = AccelGlyphCache_Init(D3D_GCACHE_WIDTH, |
| D3D_GCACHE_HEIGHT, |
| D3D_GCACHE_CELL_WIDTH, |
| D3D_GCACHE_CELL_HEIGHT, |
| NULL); |
| if (glyphCache == NULL) { |
| J2dRlsTraceLn(J2D_TRACE_ERROR, |
| "D3DContext::InitGlyphCache: "\ |
| "could not init D3D glyph cache"); |
| glyphCacheAvailable = FALSE; |
| return DDERR_GENERIC; |
| } |
| |
| DWORD caps2 = 0, caps = DDSCAPS_TEXTURE; |
| if (bIsHWRasterizer) { |
| caps2 = DDSCAPS2_TEXTUREMANAGE; |
| } else { |
| caps |= DDSCAPS_SYSTEMMEMORY; |
| } |
| if (FAILED(res = |
| dxObject->CreateSurface(DDSD_WIDTH|DDSD_HEIGHT|DDSD_CAPS| |
| DDSD_PIXELFORMAT|DDSD_TEXTURESTAGE, |
| caps, |
| caps2, |
| &maskTileTexFormat, |
| D3D_GCACHE_WIDTH, D3D_GCACHE_HEIGHT, |
| (DXSurface **)&lpGlyphCacheTexture, 0))) |
| { |
| DebugPrintDirectDrawError(res, |
| "D3DContext::InitGlyphCache: glyph cache "\ |
| "texture creation failed"); |
| glyphCacheAvailable = FALSE; |
| return res; |
| } |
| return res; |
| } |
| |
| HRESULT |
| D3DContext::GlyphCacheAdd(JNIEnv *env, GlyphInfo *glyph) |
| { |
| HRESULT res = D3D_OK; |
| if (!glyphCacheAvailable || glyph->image == NULL) { |
| return DDERR_GENERIC; |
| } |
| |
| AccelGlyphCache_AddGlyph(glyphCache, glyph); |
| |
| if (glyph->cellInfo != NULL) { |
| // store glyph image in texture cell |
| res = UploadImageToTexture(lpGlyphCacheTexture, (jubyte*)glyph->image, |
| glyph->cellInfo->x, glyph->cellInfo->y, |
| 0, 0, |
| glyph->width, glyph->height, |
| glyph->width); |
| } |
| |
| return res; |
| } |
| |
| void |
| D3DContext::SetColor(jint eargb, jint flags) |
| { |
| J2dTraceLn2(J2D_TRACE_INFO, |
| "D3DContext::SetColor: eargb=%08x flags=%d", eargb, flags); |
| |
| /* |
| * The colorPixel field is a 32-bit ARGB premultiplied color |
| * value. The incoming eargb field is a 32-bit ARGB value |
| * that is not premultiplied. If the alpha is not 1.0 (255) |
| * then we need to premultiply the color components before |
| * storing it in the colorPixel field. |
| */ |
| jint a = (eargb >> 24) & 0xff; |
| |
| if (a == 0xff) { |
| colorPixel = eargb; |
| } else { |
| jint a2 = a + (a >> 7); |
| jint r = (((eargb >> 16) & 0xff) * a2) >> 8; |
| jint g = (((eargb >> 8) & 0xff) * a2) >> 8; |
| jint b = (((eargb ) & 0xff) * a2) >> 8; |
| colorPixel = (a << 24) | (r << 16) | (g << 8) | (b << 0); |
| } |
| J2dTraceLn1(J2D_TRACE_VERBOSE, " updated color: colorPixel=%08x", |
| colorPixel); |
| } |
| |
| void |
| D3DContext::ResetComposite() |
| { |
| J2dTraceLn(J2D_TRACE_INFO, "D3DContext::ResetComposite"); |
| GetExclusiveAccess(); |
| if (d3dDevice == NULL) { |
| ReleaseExclusiveAccess(); |
| return; |
| } |
| d3dDevice->SetRenderState(D3DRENDERSTATE_ALPHABLENDENABLE, TRUE); |
| compState = sun_java2d_SunGraphics2D_COMP_ISCOPY; |
| extraAlpha = 1.0f; |
| ReleaseExclusiveAccess(); |
| } |
| |
| void |
| D3DContext::SetAlphaComposite(jint rule, jfloat ea, jint flags) |
| { |
| J2dTraceLn3(J2D_TRACE_INFO, |
| "D3DContext::SetAlphaComposite: rule=%-1d ea=%f flags=%d", |
| rule, ea, flags); |
| GetExclusiveAccess(); |
| |
| if (d3dDevice == NULL) { |
| ReleaseExclusiveAccess(); |
| return; |
| } |
| |
| // we can safely disable blending when: |
| // - comp is SrcNoEa or SrcOverNoEa, and |
| // - the source is opaque |
| // (turning off blending can have a large positive impact on |
| // performance); |
| if ((rule == RULE_Src || rule == RULE_SrcOver) && |
| (ea == 1.0f) && |
| (flags & D3DC_SRC_IS_OPAQUE)) |
| { |
| J2dTraceLn1(J2D_TRACE_VERBOSE, |
| " disabling alpha comp rule=%-1d ea=1.0 src=opq)", rule); |
| d3dDevice->SetRenderState(D3DRENDERSTATE_ALPHABLENDENABLE, FALSE); |
| } else { |
| J2dTraceLn2(J2D_TRACE_VERBOSE, |
| " enabling alpha comp (rule=%-1d ea=%f)", rule, ea); |
| d3dDevice->SetRenderState(D3DRENDERSTATE_ALPHABLENDENABLE, TRUE); |
| |
| d3dDevice->SetRenderState(D3DRENDERSTATE_SRCBLEND, |
| StdBlendRules[rule].src); |
| d3dDevice->SetRenderState(D3DRENDERSTATE_DESTBLEND, |
| StdBlendRules[rule].dst); |
| } |
| |
| // update state |
| compState = sun_java2d_SunGraphics2D_COMP_ALPHA; |
| extraAlpha = ea; |
| |
| if (extraAlpha == 1.0f) { |
| blitPolygonPixel = 0xffffffff; |
| } else { |
| // the 0xffffffff pixel needs to be premultiplied by extraAlpha |
| jint ea = (jint)(extraAlpha * 255.0f + 0.5f) & 0xff; |
| blitPolygonPixel = (ea << 24) | (ea << 16) | (ea << 8) | (ea << 0); |
| } |
| |
| ReleaseExclusiveAccess(); |
| } |
| |
| HRESULT D3DContext::CreateSurface(JNIEnv *env, jint width, jint height, |
| jint depth, jint transparency, |
| jint d3dSurfaceType, |
| DXSurface **dxSurface, jint* pType) |
| { |
| DWORD dwFlags = 0, ddsCaps = 0, ddsCaps2 = 0; |
| D3DTextureTableCell *cell = NULL; |
| DXSurface *lpRetSurface = NULL; |
| HRESULT res; |
| |
| GetExclusiveAccess(); |
| |
| dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH; |
| |
| if (d3dSurfaceType & D3D_TEXTURE_SURFACE) { |
| ddsCaps |= DDSCAPS_TEXTURE; |
| dwFlags |= DDSD_PIXELFORMAT | DDSD_TEXTURESTAGE; |
| |
| jint trIdx = D3D_TR_IDX(transparency); |
| jint depthIdx = D3D_DEPTH_IDX(depth); |
| cell = &textureTable[trIdx][depthIdx]; |
| if (cell->pfType == PF_INVALID) { |
| ReleaseExclusiveAccess(); |
| J2dTraceLn2(J2D_TRACE_ERROR, |
| "D3DContext::CreateSurface: no texture "\ |
| "pixel format for depth: %d transparency=%d", |
| depth, transparency); |
| return DDERR_NOTFOUND; |
| } |
| if (pType != NULL) *pType = cell->pfType; |
| if (d3dSurfaceType & D3D_RENDER_TARGET) { |
| // RTT is requested => must be allocated non-managed and |
| // non-systemmemory pool. |
| // REMIND: must check if this is supported by |
| // the device, as it may not have a local video memory, only AGP |
| // may be we should just use VIDEOMEMORY |
| // NOTE: this will likely fail if the device is not accelerated |
| ddsCaps |= DDSCAPS_LOCALVIDMEM; |
| } else { |
| // This is a normal texture, allocate in managed pool if the device |
| // is accelerated, otherwise must use system memory. |
| if (bIsHWRasterizer) { |
| ddsCaps2 |= DDSCAPS2_TEXTUREMANAGE; |
| } else { |
| ddsCaps |= DDSCAPS_SYSTEMMEMORY; |
| } |
| } |
| |
| if (IsPow2TexturesOnly()) { |
| jint w, h; |
| for (w = 1; width > w; w <<= 1); |
| for (h = 1; height > h; h <<= 1); |
| width = w; |
| height = h; |
| } |
| if (IsSquareTexturesOnly()) { |
| if (width > height) { |
| height = width; |
| } else { |
| width = height; |
| } |
| } |
| |
| DWORD dwRatio = GetMaxTextureAspectRatio(); |
| // Note: Reference rasterizer returns ratio '0', |
| // which presumably means 'any'. |
| if ((DWORD)width > GetMaxTextureWidth() || |
| (DWORD)height > GetMaxTextureHeight() || |
| (DWORD)width < GetMinTextureWidth() || |
| (DWORD)height < GetMinTextureHeight() || |
| ((dwRatio > 0) && ((DWORD)(width/height) > dwRatio || |
| (DWORD)(height/width) > dwRatio))) |
| { |
| ReleaseExclusiveAccess(); |
| J2dRlsTraceLn2(J2D_TRACE_ERROR, |
| "D3DContext::CreateSurface: failed to create"\ |
| " texture: dimensions %dx%d not supported.", |
| width, height); |
| J2dRlsTraceLn5(J2D_TRACE_ERROR, |
| " Supported texture dimensions: %dx%d-%dxd% "\ |
| " with max ratio %f.", |
| GetMinTextureWidth(), GetMinTextureHeight(), |
| GetMaxTextureWidth(), GetMaxTextureHeight(), |
| GetMaxTextureAspectRatio()); |
| return D3DERR_TEXTURE_BADSIZE; |
| } |
| } else if (d3dSurfaceType & D3D_PLAIN_SURFACE) { |
| ddsCaps |= DDSCAPS_OFFSCREENPLAIN | |
| (bIsHWRasterizer ? DDSCAPS_VIDEOMEMORY : DDSCAPS_SYSTEMMEMORY); |
| } else if (d3dSurfaceType & D3D_ATTACHED_SURFACE) { |
| // can't handle this for now |
| J2dRlsTraceLn(J2D_TRACE_ERROR, |
| "D3DContext::CreateSurface: Can't create attached"\ |
| " surfaces using this code path yet"); |
| ReleaseExclusiveAccess(); |
| return DDERR_GENERIC; |
| } |
| if (d3dSurfaceType & D3D_RENDER_TARGET) { |
| ddsCaps |= DDSCAPS_3DDEVICE; |
| } |
| |
| if (SUCCEEDED(res = dxObject->CreateSurface(dwFlags, ddsCaps, ddsCaps2, |
| (cell != NULL) ? |
| &cell->pddpf : NULL, |
| width, height, |
| &lpRetSurface, |
| 0/*backbuffers*/))) |
| { |
| if (d3dSurfaceType & D3D_RENDER_TARGET) { |
| if (FAILED(res = AttachDepthBuffer(lpRetSurface))) { |
| lpRetSurface->Release(); |
| delete lpRetSurface; |
| ReleaseExclusiveAccess(); |
| return res; |
| } |
| // Attempt to set the new surface as a temporary render target; |
| // in some cases this may fail. For example, if undocumented maximum |
| // Direct3D target surface dimensions were exceeded (2048 in some |
| // cases). |
| if (d3dDevice != NULL) { |
| FlushD3DQueueForTarget(NULL); |
| |
| IDirectDrawSurface7 *lpDDSurface = NULL; |
| HRESULT res1 = d3dDevice->GetRenderTarget(&lpDDSurface); |
| |
| // we are holding a lock for the context, so we can |
| // change/restore the current render target safely |
| res = d3dDevice->SetRenderTarget(lpRetSurface->GetDDSurface(), 0); |
| if (SUCCEEDED(res1) && lpDDSurface != NULL) { |
| d3dDevice->SetRenderTarget(lpDDSurface, 0); |
| } |
| if (FAILED(res)) { |
| DebugPrintDirectDrawError(res, |
| "D3DContext::CreateSurface: cannot set new surface as "\ |
| "temp. render target"); |
| lpRetSurface->Release(); |
| delete lpRetSurface; |
| ReleaseExclusiveAccess(); |
| return res; |
| } |
| } |
| } |
| *dxSurface = lpRetSurface; |
| } else { |
| DebugPrintDirectDrawError(res, |
| "D3DContext::CreateSurface: error"\ |
| " creating surface"); |
| } |
| |
| ReleaseExclusiveAccess(); |
| return res; |
| } |
| |
| HRESULT |
| D3DContext::AttachDepthBuffer(DXSurface *dxSurface) |
| { |
| HRESULT res; |
| |
| J2dTraceLn(J2D_TRACE_INFO, "D3DContext::AttachDepthBuffer"); |
| |
| if (dxSurface == NULL) { |
| return DDERR_GENERIC; |
| } |
| |
| GetExclusiveAccess(); |
| |
| // initialize the depth buffer format it needed |
| if (depthBufferFormat.dwSize == 0) { |
| // Some hardware has a restriction that the target surface and the |
| // attached depth buffer must have the same bit depth, so we should |
| // attempt to find a depth pixel format with the same depth as |
| // the target. |
| DWORD prefDepth = dxSurface->ddsd.ddpfPixelFormat.dwRGBBitCount; |
| if (FAILED(res = D3DUtils_FindDepthBufferFormat(d3dObject, |
| prefDepth, |
| &depthBufferFormat, |
| pDeviceGUID))) |
| { |
| DebugPrintDirectDrawError(res, |
| "D3DContext::AttachDepthBuffer: "\ |
| "can't find depth buffer format"); |
| ReleaseExclusiveAccess(); |
| return res; |
| } |
| } |
| if (FAILED(res = dxSurface->AttachDepthBuffer(dxObject, |
| bIsHWRasterizer, |
| &depthBufferFormat))) |
| { |
| DebugPrintDirectDrawError(res, |
| "D3DContext::AttachDepthBuffer: "\ |
| "can't attach depth buffer or it is lost"); |
| } |
| |
| ReleaseExclusiveAccess(); |
| return res; |
| } |
| |
| /** |
| * We go into the pains of maintaining the list of set textures |
| * instead of just calling GetTexture() and comparing the old one |
| * with the new one because it's actually noticeably slower to call |
| * GetTexture() (note that we'd have to then call Release() on the |
| * texture since GetTexture() increases texture's ref. count). |
| */ |
| HRESULT /*NOLOCK*/ |
| D3DContext::SetTexture(DXSurface *dxSurface, DWORD dwStage) |
| { |
| HRESULT res = D3D_OK; |
| IDirectDrawSurface7 *newTexture = |
| dxSurface == NULL ? NULL : dxSurface->GetDDSurface(); |
| |
| if (dwStage < 0 || dwStage > MAX_USED_TEXTURE_STAGE) { |
| J2dTraceLn1(J2D_TRACE_ERROR, |
| "D3DContext::SetTexture: incorrect stage: %d", dwStage); |
| return DDERR_GENERIC; |
| } |
| if (lastTexture[dwStage] != newTexture) { |
| J2dTraceLn1(J2D_TRACE_VERBOSE, |
| "D3DContext::SetTexture: new texture=0x%x", newTexture); |
| res = d3dDevice->SetTexture(dwStage, newTexture); |
| lastTexture[dwStage] = SUCCEEDED(res) ? newTexture : NULL; |
| } |
| return res; |
| } |
| |
| void |
| D3DContext::FlushD3DQueueForTarget(DDrawSurface *ddSurface) |
| { |
| GetExclusiveAccess(); |
| J2dTraceLn2(J2D_TRACE_VERBOSE, |
| "D3DContext::FlushD3DQueueForTarget surface=0x%x target=0x%x", |
| ddSurface, ddTargetSurface); |
| |
| if ((ddSurface == ddTargetSurface || ddSurface == NULL) && |
| d3dDevice != NULL) |
| { |
| ForceEndScene(); |
| } |
| ReleaseExclusiveAccess(); |
| } |
| |
| void |
| D3DContext::InvalidateIfTarget(JNIEnv *env, DDrawSurface *ddSurface) |
| { |
| GetExclusiveAccess(); |
| if ((ddSurface == ddTargetSurface) && d3dDevice != NULL && |
| jD3DContext != NULL) |
| { |
| J2dTraceLn(J2D_TRACE_VERBOSE, |
| "D3DContext:InvalidateIfTarget: invalidating java context"); |
| |
| jobject jD3DContext_tmp = env->NewLocalRef(jD3DContext); |
| if (jD3DContext_tmp != NULL) { |
| JNU_CallMethodByName(env, NULL, jD3DContext_tmp, |
| "invalidateContext", "()V"); |
| env->DeleteLocalRef(jD3DContext_tmp); |
| } |
| } |
| ReleaseExclusiveAccess(); |
| } |
| |
| void /*NOLOCK*/ |
| D3DContext::UpdateState(jbyte newState) |
| { |
| // Try to minimize context switching by only changing |
| // attributes when necessary. |
| if (newState != opState) { |
| // if the new context is texture rendering |
| if (newState & STATE_TEXTURE) { |
| // we can be here because of two reasons: |
| // old context wasn't STATE_TEXTURE or |
| // the new STATE_TEXTURE_STAGE is different |
| |
| // do the appropriate texture stage setup if needed |
| DWORD dwAA1, dwCA1; |
| BOOL bUpdateStateNeeded = FALSE; |
| if ((newState & STATE_TEXTURE_STAGE_MASK) && |
| !(opState & STATE_TEXTURE_STAGE_MASK)) |
| { |
| // setup mask rendering |
| dwAA1 = (D3DTA_TEXTURE|D3DTA_ALPHAREPLICATE); |
| dwCA1 = (D3DTA_TEXTURE|D3DTA_ALPHAREPLICATE); |
| bUpdateStateNeeded = TRUE; |
| J2dTraceLn(J2D_TRACE_VERBOSE, |
| "UpdateState: STATE_TEXTURE_STAGE_MASK"); |
| } else if ((newState & STATE_TEXTURE_STAGE_BLIT) && |
| !(opState & STATE_TEXTURE_STAGE_BLIT)) |
| { |
| // setup blit rendering |
| dwAA1 = D3DTA_TEXTURE; |
| dwCA1 = D3DTA_TEXTURE; |
| bUpdateStateNeeded = TRUE; |
| J2dTraceLn(J2D_TRACE_VERBOSE, |
| "UpdateState: STATE_TEXTURE_STAGE_BLIT"); |
| } |
| |
| // this optimization makes sense because if the state |
| // is changing from non-texture to texture, we don't necessarily |
| // need to update the texture stage state |
| if (bUpdateStateNeeded) { |
| d3dDevice->SetTextureStageState(0, D3DTSS_ALPHAARG1, dwAA1); |
| d3dDevice->SetTextureStageState(0, D3DTSS_COLORARG1, dwCA1); |
| } else { |
| J2dTraceLn2(J2D_TRACE_WARNING, |
| "UpdateState: no context changes were made! "\ |
| "current=0x%x new=0x%x", opState, newState); |
| } |
| } else { |
| J2dTraceLn(J2D_TRACE_VERBOSE, |
| "UpdateState: STATE_RENDEROP"); |
| // if switching from a texture rendering state |
| if (opState & STATE_TEXTURE) { |
| // disable texture rendering |
| // we don't need to change texture stage states |
| // because they're irrelevant if the texture |
| // is not set |
| // REMIND: another possible optimiziation: instead of |
| // setting texture to NULL, change the texture stage state |
| SetTexture(NULL); |
| } |
| } |
| opState = newState; |
| } |
| } |
| |
| HRESULT D3DContext::BeginScene(jbyte newState) |
| { |
| if (!d3dDevice) { |
| return DDERR_GENERIC; |
| } else { |
| UpdateState(newState); |
| if (!bBeginScenePending) { |
| bBeginScenePending = TRUE; |
| #ifdef DEBUG |
| endSceneQueueDepth = 0; |
| #endif /* DEBUG */ |
| HRESULT res = d3dDevice->BeginScene(); |
| J2dTraceLn(J2D_TRACE_INFO, "D3DContext::BeginScene"); |
| if (FAILED(res)) { |
| // this will cause context reinitialization |
| opState = STATE_UNDEFINED; |
| } |
| return res; |
| } |
| return D3D_OK; |
| } |
| } |
| |
| HRESULT D3DContext::EndScene(HRESULT ddResult) { |
| if (FAILED(ddResult)) { |
| return ForceEndScene(); |
| } |
| #ifdef DEBUG |
| endSceneQueueDepth++; |
| #endif /* DEBUG */ |
| return D3D_OK; |
| } |
| |
| HRESULT D3DContext::ForceEndScene() { |
| if (bBeginScenePending) { |
| bBeginScenePending = FALSE; |
| J2dTraceLn(J2D_TRACE_INFO, "D3DContext::ForceEndScene"); |
| #ifdef DEBUG |
| J2dTraceLn1(J2D_TRACE_VERBOSE, " queue depth=%d", |
| endSceneQueueDepth); |
| endSceneQueueDepth = 0; |
| #endif /* DEBUG */ |
| return d3dDevice->EndScene(); |
| } |
| return D3D_OK; |
| } |
| |
| /** |
| * Utility function: checks the result, calls RestoreSurface |
| * on the destination surface, and throws InvalidPipeException. |
| */ |
| static void |
| D3DContext_CheckResult(JNIEnv *env, HRESULT res, jlong pDest) { |
| J2dTraceLn(J2D_TRACE_INFO, "D3DContext_CheckResult"); |
| if (FAILED(res)) { |
| J2dTraceLn(J2D_TRACE_ERROR, |
| "D3DContext_CheckResult: failed, restoring dest surface"); |
| Win32SDOps *dstOps = (Win32SDOps *)jlong_to_ptr(pDest); |
| if (dstOps != NULL) { |
| // RestoreSurface for surfaces associated |
| // with VolatileImages only marks them lost, not |
| // attempting to restore. This is done later |
| // when VolatileImage.validate() is called. |
| dstOps->RestoreSurface(env, dstOps); |
| |
| // if this is an "unexpected" error, disable acceleration |
| // of this image to avoid an infinite recreate/render/error loop |
| if (res != DDERR_SURFACELOST && res != DDERR_INVALIDMODE && |
| res != DDERR_GENERIC && res != DDERR_WASSTILLDRAWING && |
| res != DDERR_SURFACEBUSY) |
| { |
| jobject sdObject = env->NewLocalRef(dstOps->sdOps.sdObject); |
| if (sdObject != NULL) { |
| JNU_CallMethodByName(env, NULL, sdObject, |
| "disableD3D", "()V"); |
| env->DeleteLocalRef(sdObject); |
| } |
| } |
| |
| } |
| SurfaceData_ThrowInvalidPipeException(env, "Surface Lost"); |
| } |
| } |
| |
| /* |
| * Class: sun_java2d_d3d_D3DContext |
| * Method: setTransform |
| * Signature: (JLLjava/awt/geom/AffineTransform;DDDDDD)V |
| */ |
| JNIEXPORT void JNICALL Java_sun_java2d_d3d_D3DContext_setTransform |
| (JNIEnv *env, jobject d3dc, jlong pCtx, jlong pDest, jobject xform, |
| jdouble m00, jdouble m10, |
| jdouble m01, jdouble m11, |
| jdouble m02, jdouble m12) |
| { |
| D3DContext *pd3dc = (D3DContext *)jlong_to_ptr(pCtx); |
| |
| J2dTraceLn(J2D_TRACE_INFO, "D3DContext_setTransform"); |
| if (pd3dc != NULL) { |
| HRESULT res = pd3dc->SetTransform(xform, |
| m00, m10, |
| m01, m11, |
| m02, m12); |
| D3DContext_CheckResult(env, res, pDest); |
| } |
| } |
| |
| /* |
| * Class: sun_java2d_d3d_D3DContext |
| * Method: resetTransform |
| * Signature: (JLL)V |
| */ |
| JNIEXPORT void JNICALL Java_sun_java2d_d3d_D3DContext_resetTransform |
| (JNIEnv *env, jobject d3dc, jlong pCtx, jlong pDest) |
| { |
| D3DContext *pd3dc = (D3DContext *)jlong_to_ptr(pCtx); |
| |
| J2dTraceLn(J2D_TRACE_INFO, "D3DContext_resetTransform"); |
| if (pd3dc != NULL) { |
| HRESULT res = pd3dc->SetTransform(NULL, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0); |
| D3DContext_CheckResult(env, res, pDest); |
| } |
| } |
| |
| /* |
| * Class: sun_java2d_d3d_D3DContext |
| * Method: setClip |
| * Signature: (JLLsun/java2d/pipe/Region;ZIIII)V |
| */ |
| JNIEXPORT void JNICALL Java_sun_java2d_d3d_D3DContext_setClip |
| (JNIEnv *env, jobject d3dc, jlong pCtx, jlong pDest, |
| jobject clip, jboolean isRect, |
| jint x1, jint y1, jint x2, jint y2) |
| { |
| D3DContext *pd3dc = (D3DContext *)jlong_to_ptr(pCtx); |
| |
| J2dTraceLn(J2D_TRACE_INFO, "D3DContext_setClip"); |
| if (pd3dc != NULL) { |
| HRESULT res = pd3dc->SetClip(env, clip, isRect, x1, y1, x2, y2); |
| D3DContext_CheckResult(env, res, pDest); |
| } |
| } |
| |
| /* |
| * Class: sun_java2d_d3d_D3DContext |
| * Method: resetClip |
| * Signature: (JLLsun/java2d/pipe/Region;Z)V |
| */ |
| JNIEXPORT void JNICALL Java_sun_java2d_d3d_D3DContext_resetClip |
| (JNIEnv *env, jobject d3dc, jlong pCtx, jlong pDest) |
| { |
| D3DContext *pd3dc = (D3DContext *)jlong_to_ptr(pCtx); |
| |
| J2dTraceLn(J2D_TRACE_INFO, "D3DContext_resetClip"); |
| if (pd3dc != NULL) { |
| HRESULT res = pd3dc->SetClip(env, NULL, JNI_FALSE, 0, 0, 0, 0); |
| D3DContext_CheckResult(env, res, pDest); |
| } |
| } |
| |
| /* |
| * Class: sun_java2d_d3d_D3DContext |
| * Method: setRenderTarget |
| * Signature: (JJ)V |
| */ |
| JNIEXPORT void JNICALL Java_sun_java2d_d3d_D3DContext_setRenderTarget |
| (JNIEnv *env, jobject d3dc, jlong pCtx, jlong pDest) |
| { |
| D3DContext *pd3dc = (D3DContext *)jlong_to_ptr(pCtx); |
| Win32SDOps *dstOps = (Win32SDOps *)jlong_to_ptr(pDest); |
| |
| J2dTraceLn(J2D_TRACE_INFO, "D3DContext_setRenderTarget"); |
| if (pd3dc != NULL && dstOps != NULL) { |
| HRESULT res = pd3dc->SetRenderTarget(dstOps->lpSurface); |
| D3DContext_CheckResult(env, res, pDest); |
| } |
| } |
| |
| /* |
| * Class: sun_java2d_d3d_D3DContext |
| * Method: setColor |
| * Signature: (JII)V |
| */ |
| JNIEXPORT void JNICALL |
| Java_sun_java2d_d3d_D3DContext_setColor(JNIEnv *env, jobject oc, |
| jlong pCtx, |
| jint pixel, jint flags) |
| { |
| D3DContext *d3dc = (D3DContext *)jlong_to_ptr(pCtx); |
| |
| J2dTraceLn(J2D_TRACE_INFO, "D3DContext_setColor"); |
| if (d3dc != NULL) { |
| d3dc->SetColor(pixel, flags); |
| } |
| } |
| |
| /* |
| * Class: sun_java2d_d3d_D3DContext |
| * Method: setAlphaComposite |
| * Signature: (JIFI)V |
| */ |
| JNIEXPORT void JNICALL |
| Java_sun_java2d_d3d_D3DContext_setAlphaComposite(JNIEnv *env, jobject oc, |
| jlong pCtx, |
| jint rule, |
| jfloat extraAlpha, |
| jint flags) |
| { |
| D3DContext *d3dc = (D3DContext *)jlong_to_ptr(pCtx); |
| |
| J2dTraceLn(J2D_TRACE_INFO, "D3DContext_setAlphaComposite"); |
| if (d3dc != NULL) { |
| d3dc->SetAlphaComposite(rule, extraAlpha, flags); |
| } |
| |
| } |
| |
| JNIEXPORT void JNICALL |
| Java_sun_java2d_d3d_D3DContext_resetComposite(JNIEnv *env, jobject oc, |
| jlong pCtx) |
| { |
| D3DContext *d3dc = (D3DContext *)jlong_to_ptr(pCtx); |
| |
| J2dTraceLn(J2D_TRACE_INFO, "D3DContext_resetComposite"); |
| if (d3dc != NULL) { |
| d3dc->ResetComposite(); |
| } |
| } |
| |
| /* |
| * Class: sun_java2d_d3d_D3DContext |
| * Method: initNativeContext |
| * Signature: (I)J |
| */ |
| JNIEXPORT jlong JNICALL |
| Java_sun_java2d_d3d_D3DContext_initNativeContext |
| (JNIEnv *env, jobject d3dc, jint screen) |
| { |
| J2dTraceLn1(J2D_TRACE_INFO, "D3DContext_initNativeContext screen=%d", |
| screen); |
| |
| HMONITOR hMon = (HMONITOR)AwtWin32GraphicsDevice::GetMonitor(screen); |
| DDrawObjectStruct *tmpDdInstance = GetDDInstanceForDevice(hMon); |
| D3DContext *d3dContext = NULL; |
| |
| if (tmpDdInstance != NULL && tmpDdInstance->ddObject != NULL) { |
| AwtToolkit::GetInstance().SendMessage(WM_AWT_D3D_CREATE_DEVICE, |
| (WPARAM)tmpDdInstance->ddObject, |
| NULL); |
| d3dContext = tmpDdInstance->ddObject->GetD3dContext(); |
| } |
| J2dTraceLn1(J2D_TRACE_VERBOSE, |
| "D3DContext_initNativeContext created d3dContext=0x%x", |
| d3dContext); |
| |
| return ptr_to_jlong(d3dContext); |
| } |
| |
| /* |
| * Class: sun_java2d_d3d_D3DContext |
| * Method: getNativeDeviceCaps |
| * Signature: (J)I |
| */ |
| JNIEXPORT jint JNICALL Java_sun_java2d_d3d_D3DContext_getNativeDeviceCaps |
| (JNIEnv *env, jobject d3dc, jlong pCtx) |
| { |
| D3DContext *d3dContext = (D3DContext *)jlong_to_ptr(pCtx); |
| |
| J2dTraceLn(J2D_TRACE_INFO, "D3DContext_getNativeDeviceCaps"); |
| if (d3dContext != NULL) { |
| d3dContext->SetJavaContext(env, d3dc); |
| return (jint)d3dContext->GetDeviceCaps(); |
| } |
| return J2D_D3D_FAILURE; |
| } |