| /* |
| * Copyright (c) 2007, 2016, 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 "GraphicsPrimitiveMgr.h" |
| #include "D3DContext.h" |
| #include "D3DSurfaceData.h" |
| #include "D3DBufImgOps.h" |
| #include "D3DPaints.h" |
| #include "D3DRenderQueue.h" |
| #include "D3DShaders.h" |
| #include "D3DTextRenderer.h" |
| #include "D3DPipelineManager.h" |
| #include "D3DGlyphCache.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*/ |
| }; |
| |
| void |
| D3DUtils_SetOrthoMatrixOffCenterLH(D3DMATRIX *m, |
| float width, float height) |
| { |
| ZeroMemory(m, sizeof(D3DMATRIX)); |
| m->_11 = 2.0f/width; |
| m->_22 = -2.0f/height; |
| m->_33 = 0.5f; |
| m->_44 = 1.0f; |
| |
| m->_41 = -1.0f; |
| m->_42 = 1.0f; |
| m->_43 = 0.5f; |
| } |
| |
| void |
| D3DUtils_SetIdentityMatrix(D3DMATRIX *m) |
| { |
| m->_12 = m->_13 = m->_14 = m->_21 = m->_23 = m->_24 = 0.0f; |
| m->_31 = m->_32 = m->_34 = m->_41 = m->_42 = m->_43 = 0.0f; |
| m->_11 = m->_22 = m->_33 = m->_44 = 1.0f; |
| } |
| |
| // the following methods are copies of the AffineTransform's class |
| // corresponding methods, with these changes to the indexes: |
| // 00 -> 11 |
| // 11 -> 22 |
| // 01 -> 21 |
| // 10 -> 12 |
| // 02 -> 41 |
| // 12 -> 42 |
| |
| void |
| D3DUtils_2DConcatenateM(D3DMATRIX *m, D3DMATRIX *m1) |
| { |
| float M0, M1; |
| float T00, T10, T01, T11; |
| float T02, T12; |
| |
| T00 = m1->_11; T01 = m1->_21; T02 = m1->_41; |
| T10 = m1->_12; T11 = m1->_22; T12 = m1->_42; |
| |
| M0 = m->_11; |
| M1 = m->_21; |
| m->_11 = T00 * M0 + T10 * M1; |
| m->_21 = T01 * M0 + T11 * M1; |
| m->_41 += T02 * M0 + T12 * M1; |
| |
| M0 = m->_12; |
| M1 = m->_22; |
| m->_12 = T00 * M0 + T10 * M1; |
| m->_22 = T01 * M0 + T11 * M1; |
| m->_42 += T02 * M0 + T12 * M1; |
| } |
| |
| #ifdef UPDATE_TX |
| |
| void |
| D3DUtils_2DScaleM(D3DMATRIX *m, float sx, float sy) |
| { |
| m->_11 *= sx; |
| m->_22 *= sy; |
| } |
| |
| void |
| D3DUtils_2DInvertM(D3DMATRIX *m) |
| { |
| float M11, M21, M41; |
| float M12, M22, M42; |
| float det; |
| |
| M11 = m->_11; M21 = m->_21; M41 = m->_41; |
| M12 = m->_12; M22 = m->_22; M42 = m->_42; |
| det = M11 * M22 - M21 * M12; |
| if (fabs(det) <= 0.0000000001f) { |
| memset(m, 0, sizeof(D3DMATRIX)); |
| return; |
| } |
| m->_11 = M22 / det; |
| m->_12 = -M12 / det; |
| m->_21 = -M21 / det; |
| m->_22 = M11 / det; |
| m->_41 = (M21 * M42 - M22 * M41) / det; |
| m->_42 = (M12 * M41 - M11 * M42) / det; |
| } |
| |
| void |
| D3DUtils_2DTranslateM(D3DMATRIX *m, float tx, float ty) |
| { |
| m->_41 = tx * m->_11 + ty * m->_21 + m->_41; |
| m->_42 = tx * m->_12 + ty * m->_22 + m->_42; |
| } |
| |
| void |
| D3DUtils_2DTransformXY(D3DMATRIX *m, float *px, float *py) |
| { |
| float x = *px; |
| float y = *py; |
| |
| *px = x * m->_11 + y * m->_21 + m->_41; |
| *py = x * m->_12 + y * m->_22 + m->_42; |
| } |
| |
| void |
| D3DUtils_2DInverseTransformXY(D3DMATRIX *m, float *px, float *py) |
| { |
| float x = *px, y = *py; |
| |
| x -= m->_41; |
| y -= m->_42; |
| |
| float det = m->_11 * m->_22 - m->_21 * m->_12; |
| if (fabs(det) < 0.0000000001f) { |
| *px = 0.0f; |
| *py = 0.0f; |
| } else { |
| *px = (x * m->_22 - y * m->_21) / det; |
| *py = (y * m->_11 - x * m->_12) / det; |
| } |
| } |
| |
| #endif // UPDATE_TX |
| |
| static void |
| D3DContext_DisposeShader(jlong programID) |
| { |
| IDirect3DPixelShader9 *shader = |
| (IDirect3DPixelShader9 *)jlong_to_ptr(programID); |
| |
| J2dTraceLn(J2D_TRACE_INFO, "D3DContext_DisposeShader"); |
| |
| SAFE_RELEASE(shader); |
| } |
| |
| // static |
| HRESULT |
| D3DContext::CreateInstance(IDirect3D9 *pd3d9, UINT adapter, D3DContext **ppCtx) |
| { |
| HRESULT res; |
| *ppCtx = new D3DContext(pd3d9, adapter); |
| if (FAILED(res = (*ppCtx)->InitContext())) { |
| delete *ppCtx; |
| *ppCtx = NULL; |
| } |
| return res; |
| } |
| |
| D3DContext::D3DContext(IDirect3D9 *pd3d, UINT adapter) |
| { |
| J2dTraceLn(J2D_TRACE_INFO, "D3DContext::D3DContext"); |
| J2dTraceLn1(J2D_TRACE_VERBOSE, " pd3d=0x%x", pd3d); |
| pd3dObject = pd3d; |
| pd3dDevice = NULL; |
| adapterOrdinal = adapter; |
| |
| pResourceMgr = NULL; |
| pMaskCache = NULL; |
| pVCacher = NULL; |
| |
| pSyncQuery = NULL; |
| pSyncRTRes = NULL; |
| pStateBlock = NULL; |
| |
| D3DC_INIT_SHADER_LIST(convolvePrograms, MAX_CONVOLVE); |
| D3DC_INIT_SHADER_LIST(rescalePrograms, MAX_RESCALE); |
| D3DC_INIT_SHADER_LIST(lookupPrograms, MAX_LOOKUP); |
| D3DC_INIT_SHADER_LIST(basicGradPrograms, 4); |
| D3DC_INIT_SHADER_LIST(linearGradPrograms, 8); |
| D3DC_INIT_SHADER_LIST(radialGradPrograms, 8); |
| |
| pLCDGlyphCache= NULL; |
| pGrayscaleGlyphCache= NULL; |
| lcdTextProgram = NULL; |
| aaPgramProgram = NULL; |
| |
| contextCaps = CAPS_EMPTY; |
| bBeginScenePending = FALSE; |
| |
| ZeroMemory(&devCaps, sizeof(D3DCAPS9)); |
| ZeroMemory(&curParams, sizeof(curParams)); |
| |
| extraAlpha = 1.0f; |
| } |
| |
| void D3DContext::ReleaseDefPoolResources() |
| { |
| J2dTraceLn(J2D_TRACE_INFO, "D3DContext::ReleaseDefPoolResources"); |
| |
| EndScene(); |
| |
| contextCaps = CAPS_EMPTY; |
| |
| SAFE_RELEASE(pSyncQuery); |
| SAFE_RELEASE(pStateBlock); |
| |
| if (pVCacher != NULL) { |
| pVCacher->ReleaseDefPoolResources(); |
| } |
| if (pMaskCache != NULL) { |
| pMaskCache->ReleaseDefPoolResources(); |
| } |
| if (pLCDGlyphCache != NULL) { |
| pLCDGlyphCache->ReleaseDefPoolResources(); |
| } |
| if (pGrayscaleGlyphCache != NULL) { |
| pGrayscaleGlyphCache->ReleaseDefPoolResources(); |
| } |
| if (pResourceMgr != NULL) { |
| if (pSyncRTRes != NULL) { |
| pResourceMgr->ReleaseResource(pSyncRTRes); |
| pSyncRTRes = NULL; |
| } |
| pResourceMgr->ReleaseDefPoolResources(); |
| } |
| ZeroMemory(lastTexture, sizeof(lastTexture)); |
| ZeroMemory(lastTextureColorState, sizeof(lastTextureColorState)); |
| } |
| |
| void D3DContext::ReleaseContextResources() |
| { |
| J2dTraceLn1(J2D_TRACE_INFO, |
| "D3DContext::ReleaseContextResources: pd3dDevice = 0x%x", |
| pd3dDevice); |
| |
| ReleaseDefPoolResources(); |
| |
| // dispose shader lists |
| ShaderList_Dispose(&convolvePrograms); |
| ShaderList_Dispose(&rescalePrograms); |
| ShaderList_Dispose(&lookupPrograms); |
| ShaderList_Dispose(&basicGradPrograms); |
| ShaderList_Dispose(&linearGradPrograms); |
| ShaderList_Dispose(&radialGradPrograms); |
| |
| SAFE_DELETE(pLCDGlyphCache); |
| SAFE_DELETE(pGrayscaleGlyphCache); |
| |
| SAFE_RELEASE(lcdTextProgram); |
| SAFE_RELEASE(aaPgramProgram); |
| |
| SAFE_DELETE(pVCacher); |
| SAFE_DELETE(pMaskCache); |
| SAFE_DELETE(pResourceMgr); |
| } |
| |
| D3DContext::~D3DContext() { |
| J2dTraceLn2(J2D_TRACE_INFO, |
| "~D3DContext: pd3dDevice=0x%x, pd3dObject =0x%x", |
| pd3dDevice, pd3dObject); |
| ReleaseContextResources(); |
| SAFE_RELEASE(pd3dDevice); |
| } |
| |
| HRESULT |
| D3DContext::InitDevice(IDirect3DDevice9 *pd3dDevice) |
| { |
| HRESULT res = S_OK; |
| |
| pd3dDevice->GetDeviceCaps(&devCaps); |
| |
| J2dRlsTraceLn1(J2D_TRACE_INFO, |
| "D3DContext::InitDevice: device %d", adapterOrdinal); |
| |
| // disable some of the unneeded and costly d3d functionality |
| pd3dDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE); |
| pd3dDevice->SetRenderState(D3DRS_SPECULARENABLE, FALSE); |
| pd3dDevice->SetRenderState(D3DRS_LIGHTING, FALSE); |
| pd3dDevice->SetRenderState(D3DRS_CLIPPING, FALSE); |
| pd3dDevice->SetRenderState(D3DRS_ZENABLE, D3DZB_FALSE); |
| pd3dDevice->SetRenderState(D3DRS_ZWRITEENABLE, D3DZB_FALSE); |
| pd3dDevice->SetRenderState(D3DRS_COLORVERTEX, FALSE); |
| pd3dDevice->SetRenderState(D3DRS_STENCILENABLE, FALSE); |
| |
| // set the default texture addressing mode |
| pd3dDevice->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP); |
| pd3dDevice->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP); |
| |
| // REMIND: check supported filters with |
| // IDirect3D9::CheckDeviceFormat with D3DUSAGE_QUERY_FILTER |
| pd3dDevice->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_POINT); |
| pd3dDevice->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_POINT); |
| |
| // these states never change |
| pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_MODULATE); |
| pd3dDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE); |
| pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE); |
| pd3dDevice->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE); |
| pd3dDevice->SetTextureStageState(1, D3DTSS_ALPHAOP, D3DTOP_MODULATE); |
| pd3dDevice->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_MODULATE); |
| pd3dDevice->SetTextureStageState(1, D3DTSS_ALPHAARG2, D3DTA_CURRENT); |
| pd3dDevice->SetTextureStageState(1, D3DTSS_COLORARG2, D3DTA_CURRENT); |
| |
| // init the array of latest textures |
| ZeroMemory(lastTexture, sizeof(lastTexture)); |
| ZeroMemory(lastTextureColorState, sizeof(lastTextureColorState)); |
| |
| opState = STATE_CHANGE; |
| |
| if (pResourceMgr == NULL) { |
| res = D3DResourceManager::CreateInstance(this, &pResourceMgr); |
| } else { |
| res = pResourceMgr->Init(this); |
| } |
| RETURN_STATUS_IF_FAILED(res); |
| |
| if (pVCacher == NULL) { |
| res = D3DVertexCacher::CreateInstance(this, &pVCacher); |
| } else { |
| res = pVCacher->Init(this); |
| } |
| RETURN_STATUS_IF_FAILED(res); |
| |
| if (pMaskCache == NULL) { |
| res = D3DMaskCache::CreateInstance(this, &pMaskCache); |
| } else{ |
| res = pMaskCache->Init(this); |
| } |
| RETURN_STATUS_IF_FAILED(res); |
| |
| if (pLCDGlyphCache != NULL) { |
| if (FAILED(res = pLCDGlyphCache->Init(this))) { |
| // we can live without the cache |
| SAFE_DELETE(pLCDGlyphCache); |
| res = S_OK; |
| } |
| } |
| |
| if (pGrayscaleGlyphCache != NULL) { |
| if (FAILED(res = pGrayscaleGlyphCache->Init(this))) { |
| // we can live without the cache |
| SAFE_DELETE(pGrayscaleGlyphCache); |
| res = S_OK; |
| } |
| } |
| |
| D3DMATRIX tx; |
| D3DUtils_SetIdentityMatrix(&tx); |
| pd3dDevice->SetTransform(D3DTS_WORLD, &tx); |
| bIsIdentityTx = TRUE; |
| |
| if (pSyncQuery == NULL) { |
| // this is allowed to fail, do not propagate the error |
| if (FAILED(pd3dDevice->CreateQuery(D3DQUERYTYPE_EVENT, &pSyncQuery))) { |
| J2dRlsTraceLn(J2D_TRACE_WARNING, |
| "D3DContext::InitDevice: sync query not available"); |
| pSyncQuery = NULL; |
| } |
| } |
| if (pSyncRTRes == NULL) { |
| D3DFORMAT format; |
| if (FAILED(GetResourceManager()-> |
| CreateRTSurface(32, 32, TRUE, TRUE, &format, &pSyncRTRes))) { |
| J2dRlsTraceLn(J2D_TRACE_WARNING, |
| "D3DContext::InitDevice: " |
| "error creating sync surface"); |
| } |
| } |
| |
| bBeginScenePending = FALSE; |
| |
| J2dRlsTraceLn1(J2D_TRACE_INFO, |
| "D3DContext::InitDefice: successfully initialized device %d", |
| adapterOrdinal); |
| |
| return res; |
| } |
| |
| HRESULT |
| D3DContext::CheckAndResetDevice() |
| { |
| HRESULT res = E_FAIL; |
| |
| J2dTraceLn(J2D_TRACE_INFO, "D3DContext::CheckAndResetDevice"); |
| |
| if (pd3dDevice != NULL) { |
| if (FAILED(res = pd3dDevice->TestCooperativeLevel())) { |
| if (res == D3DERR_DEVICELOST) { |
| J2dTraceLn1(J2D_TRACE_VERBOSE, " device %d is still lost", |
| adapterOrdinal); |
| // nothing to be done here, wait for D3DERR_DEVICENOTRESET |
| return res; |
| } else if (res == D3DERR_DEVICENOTRESET) { |
| J2dTraceLn1(J2D_TRACE_VERBOSE, " device %d needs to be reset", |
| adapterOrdinal); |
| res = ResetContext(); |
| } else { |
| // some unexpected error |
| DebugPrintD3DError(res, "D3DContext::CheckAndResetDevice: "\ |
| "unknown error %x from TestCooperativeLevel"); |
| } |
| } else { |
| J2dTraceLn1(J2D_TRACE_VERBOSE, " device %d is not lost", |
| adapterOrdinal); |
| } |
| } else { |
| J2dTraceLn(J2D_TRACE_VERBOSE, " null device"); |
| } |
| return res; |
| } |
| |
| HRESULT |
| D3DContext::ResetContext() |
| { |
| HRESULT res = E_FAIL; |
| |
| J2dRlsTraceLn(J2D_TRACE_INFO, "D3DContext::ResetContext"); |
| if (pd3dDevice != NULL) { |
| D3DPRESENT_PARAMETERS newParams; |
| |
| newParams = curParams; |
| |
| if (newParams.Windowed) { |
| // reset to the current display mode if we're windowed, |
| // otherwise to the display mode we were in when the device |
| // was lost |
| newParams.BackBufferFormat = D3DFMT_UNKNOWN; |
| newParams.FullScreen_RefreshRateInHz = 0; |
| newParams.BackBufferWidth = 0; |
| newParams.BackBufferHeight = 0; |
| } |
| res = ConfigureContext(&newParams); |
| } |
| return res; |
| } |
| |
| HRESULT |
| D3DContext::ConfigureContext(D3DPRESENT_PARAMETERS *pNewParams) |
| { |
| J2dRlsTraceLn1(J2D_TRACE_INFO, "D3DContext::ConfigureContext device %d", |
| adapterOrdinal); |
| HRESULT res = S_OK; |
| D3DFORMAT stencilFormat; |
| HWND focusHWND = D3DPipelineManager::GetInstance()->GetCurrentFocusWindow(); |
| D3DDEVTYPE devType = D3DPipelineManager::GetInstance()->GetDeviceType(); |
| // this is needed so that we can find the stencil buffer format |
| if (pNewParams->BackBufferFormat == D3DFMT_UNKNOWN) { |
| D3DDISPLAYMODE dm; |
| |
| pd3dObject->GetAdapterDisplayMode(adapterOrdinal, &dm); |
| pNewParams->BackBufferFormat = dm.Format; |
| } |
| |
| stencilFormat = |
| D3DPipelineManager::GetInstance()->GetMatchingDepthStencilFormat( |
| adapterOrdinal, |
| pNewParams->BackBufferFormat, pNewParams->BackBufferFormat); |
| |
| pNewParams->EnableAutoDepthStencil = TRUE; |
| pNewParams->AutoDepthStencilFormat = stencilFormat; |
| |
| // do not set device window in the windowed mode, we use additional |
| // swap chains for rendering, the default chain is not used. otherwise |
| // our scratch focus window will be made visible |
| J2dTraceLn1(J2D_TRACE_VERBOSE, " windowed=%d",pNewParams->Windowed); |
| if (pNewParams->Windowed) { |
| pNewParams->hDeviceWindow = (HWND)0; |
| } |
| |
| // The focus window may change when we're entering/exiting the full-screen |
| // mode. It may either be set to the default focus window (when there are |
| // no more devices in fs mode), or to fs window for another device |
| // in fs mode. See D3DPipelineManager::GetCurrentFocusWindow. |
| if (pd3dDevice != NULL) { |
| D3DDEVICE_CREATION_PARAMETERS cParams; |
| pd3dDevice->GetCreationParameters(&cParams); |
| if (cParams.hFocusWindow != focusHWND) { |
| J2dTraceLn(J2D_TRACE_VERBOSE, |
| " focus window changed, need to recreate the device"); |
| |
| // if fs -> windowed, first exit fs, then recreate, otherwise |
| // the screen might be left in a different display mode |
| if (pNewParams->Windowed && !curParams.Windowed) { |
| J2dTraceLn(J2D_TRACE_VERBOSE, |
| " exiting full-screen mode, reset the device"); |
| curParams.Windowed = FALSE; |
| ReleaseDefPoolResources(); |
| res = pd3dDevice->Reset(&curParams); |
| |
| if (FAILED(res)) { |
| DebugPrintD3DError(res, "D3DContext::ConfigureContext: "\ |
| "cound not reset the device"); |
| } |
| } |
| |
| // note that here we should release all device resources, not only |
| // thos in the default pool since the device is released |
| ReleaseContextResources(); |
| SAFE_RELEASE(pd3dDevice); |
| } |
| } |
| |
| if (pd3dDevice != NULL) { |
| J2dTraceLn(J2D_TRACE_VERBOSE, " resetting the device"); |
| |
| ReleaseDefPoolResources(); |
| |
| if (pNewParams->PresentationInterval == D3DPRESENT_INTERVAL_IMMEDIATE && |
| !IsImmediateIntervalSupported()) |
| { |
| pNewParams->PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT; |
| } |
| |
| res = pd3dDevice->Reset(pNewParams); |
| if (FAILED(res)) { |
| DebugPrintD3DError(res, |
| "D3DContext::ConfigureContext: cound not reset the device"); |
| return res; |
| } |
| J2dRlsTraceLn1(J2D_TRACE_INFO, |
| "D3DContext::ConfigureContext: successfully reset device: %d", |
| adapterOrdinal); |
| } else { |
| D3DCAPS9 d3dCaps; |
| DWORD dwBehaviorFlags; |
| |
| J2dTraceLn(J2D_TRACE_VERBOSE, " creating a new device"); |
| |
| if (FAILED(res = pd3dObject->GetDeviceCaps(adapterOrdinal, |
| devType, &d3dCaps))) |
| { |
| DebugPrintD3DError(res, |
| "D3DContext::ConfigureContext: failed to get caps"); |
| return res; |
| } |
| |
| if (pNewParams->PresentationInterval == D3DPRESENT_INTERVAL_IMMEDIATE && |
| !(d3dCaps.PresentationIntervals & D3DPRESENT_INTERVAL_IMMEDIATE)) |
| { |
| pNewParams->PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT; |
| } |
| |
| // not preserving fpu control word could cause issues (4860749) |
| dwBehaviorFlags = D3DCREATE_FPU_PRESERVE; |
| |
| J2dRlsTrace(J2D_TRACE_VERBOSE, |
| "[V] dwBehaviorFlags=D3DCREATE_FPU_PRESERVE|"); |
| if (d3dCaps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT) { |
| J2dRlsTrace(J2D_TRACE_VERBOSE, |
| "D3DCREATE_HARDWARE_VERTEXPROCESSING"); |
| dwBehaviorFlags |= D3DCREATE_HARDWARE_VERTEXPROCESSING; |
| } else { |
| J2dRlsTrace(J2D_TRACE_VERBOSE, |
| "D3DCREATE_SOFTWARE_VERTEXPROCESSING"); |
| dwBehaviorFlags |= D3DCREATE_SOFTWARE_VERTEXPROCESSING; |
| } |
| // Handling focus changes by ourselves proved to be problematic, |
| // so we're reverting back to D3D handling |
| // dwBehaviorFlags |= D3DCREATE_NOWINDOWCHANGES; |
| J2dRlsTrace(J2D_TRACE_VERBOSE,"\n"); |
| |
| if (FAILED(res = pd3dObject->CreateDevice(adapterOrdinal, devType, |
| focusHWND, |
| dwBehaviorFlags, |
| pNewParams, &pd3dDevice))) |
| { |
| DebugPrintD3DError(res, |
| "D3DContext::ConfigureContext: error creating d3d device"); |
| return res; |
| } |
| J2dRlsTraceLn1(J2D_TRACE_INFO, |
| "D3DContext::ConfigureContext: successfully created device: %d", |
| adapterOrdinal); |
| bIsHWRasterizer = (devType == D3DDEVTYPE_HAL); |
| } |
| |
| curParams = *pNewParams; |
| // during the creation of the device d3d modifies this field, we reset |
| // it back to 0 |
| curParams.Flags = 0; |
| |
| if (FAILED(res = InitDevice(pd3dDevice))) { |
| ReleaseContextResources(); |
| return res; |
| } |
| |
| res = InitContextCaps(); |
| |
| return res; |
| } |
| |
| HRESULT |
| D3DContext::InitContext() |
| { |
| J2dRlsTraceLn1(J2D_TRACE_INFO, "D3DContext::InitContext device %d", |
| adapterOrdinal); |
| |
| D3DPRESENT_PARAMETERS params; |
| ZeroMemory(¶ms, sizeof(D3DPRESENT_PARAMETERS)); |
| |
| params.hDeviceWindow = 0; |
| params.Windowed = TRUE; |
| params.BackBufferCount = 1; |
| params.BackBufferFormat = D3DFMT_UNKNOWN; |
| params.SwapEffect = D3DSWAPEFFECT_DISCARD; |
| params.PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT; |
| |
| return ConfigureContext(¶ms); |
| } |
| |
| HRESULT |
| D3DContext::Sync() |
| { |
| HRESULT res = S_OK; |
| |
| J2dTraceLn(J2D_TRACE_INFO, "D3DContext::Sync"); |
| |
| if (pSyncQuery != NULL) { |
| J2dTrace(J2D_TRACE_VERBOSE, " flushing the device queue.."); |
| while (S_FALSE == |
| (res = pSyncQuery->GetData(NULL, 0, D3DGETDATA_FLUSH))) ; |
| J2dTrace(J2D_TRACE_VERBOSE, ".. done\n"); |
| } |
| if (pSyncRTRes != NULL) { |
| D3DLOCKED_RECT lr; |
| IDirect3DSurface9 *pSurface = pSyncRTRes->GetSurface(); |
| if (SUCCEEDED(pSurface->LockRect(&lr, NULL, D3DLOCK_NOSYSLOCK))) { |
| pSurface->UnlockRect(); |
| } |
| } |
| return res; |
| } |
| |
| HRESULT |
| D3DContext::SaveState() |
| { |
| HRESULT res; |
| |
| RETURN_STATUS_IF_NULL(pd3dDevice, S_OK); |
| |
| J2dTraceLn(J2D_TRACE_INFO, "D3DContext::SaveState"); |
| |
| FlushVertexQueue(); |
| UpdateState(STATE_CHANGE); |
| |
| if (pStateBlock != NULL) { |
| J2dTraceLn(J2D_TRACE_WARNING, |
| "D3DContext::SaveState: existing state block!"); |
| SAFE_RELEASE(pStateBlock); |
| } |
| |
| if (SUCCEEDED(res = |
| pd3dDevice->CreateStateBlock(D3DSBT_ALL, &pStateBlock))) |
| { |
| J2dTraceLn(J2D_TRACE_VERBOSE, " created state block"); |
| } else { |
| J2dTraceLn(J2D_TRACE_WARNING, |
| "D3DContext::SaveState: failed to create state block"); |
| } |
| ZeroMemory(lastTexture, sizeof(lastTexture)); |
| |
| return res; |
| } |
| |
| HRESULT |
| D3DContext::RestoreState() |
| { |
| HRESULT res = S_OK; |
| |
| J2dTraceLn(J2D_TRACE_INFO, "D3DContext::RestoreState"); |
| |
| FlushVertexQueue(); |
| UpdateState(STATE_CHANGE); |
| |
| if (pStateBlock != NULL) { |
| if (SUCCEEDED(res = pStateBlock->Apply())) { |
| J2dTraceLn(J2D_TRACE_VERBOSE, " restored device state"); |
| } else { |
| J2dTraceLn(J2D_TRACE_WARNING, |
| "D3DContext::RestoreState: failed to restore state"); |
| } |
| SAFE_RELEASE(pStateBlock); |
| } else { |
| J2dTraceLn(J2D_TRACE_WARNING, |
| "D3DContext::RestoreState: empty state block!"); |
| } |
| ZeroMemory(lastTexture, sizeof(lastTexture)); |
| |
| return res; |
| } |
| |
| #define POINT_FILTER_CAP (D3DPTFILTERCAPS_MAGFPOINT|D3DPTFILTERCAPS_MINFPOINT) |
| #define LINEAR_FILTER_CAP (D3DPTFILTERCAPS_MAGFLINEAR|D3DPTFILTERCAPS_MINFLINEAR) |
| |
| BOOL |
| D3DContext::IsStretchRectFilteringSupported(D3DTEXTUREFILTERTYPE fType) |
| { |
| if (fType == D3DTEXF_POINT) { |
| return ((devCaps.StretchRectFilterCaps & POINT_FILTER_CAP) != 0); |
| } |
| if (fType == D3DTEXF_LINEAR) { |
| return ((devCaps.StretchRectFilterCaps & LINEAR_FILTER_CAP) != 0); |
| } |
| return FALSE; |
| } |
| |
| BOOL |
| D3DContext::IsTextureFilteringSupported(D3DTEXTUREFILTERTYPE fType) |
| { |
| if (fType == D3DTEXF_POINT) { |
| return ((devCaps.TextureFilterCaps & POINT_FILTER_CAP) != 0); |
| } |
| if (fType == D3DTEXF_LINEAR) { |
| return ((devCaps.TextureFilterCaps & LINEAR_FILTER_CAP) != 0); |
| } |
| return FALSE; |
| } |
| |
| BOOL |
| D3DContext::IsTextureFormatSupported(D3DFORMAT format, DWORD usage) |
| { |
| HRESULT hr = pd3dObject->CheckDeviceFormat(adapterOrdinal, |
| devCaps.DeviceType, |
| curParams.BackBufferFormat, |
| usage, |
| D3DRTYPE_TEXTURE, |
| format); |
| return SUCCEEDED( hr ); |
| } |
| |
| BOOL |
| D3DContext::IsDepthStencilBufferOk(D3DSURFACE_DESC *pTargetDesc) |
| { |
| IDirect3DSurface9 *pStencil; |
| J2dTraceLn(J2D_TRACE_INFO, "D3DContext::IsDepthStencilBufferOk"); |
| |
| if (SUCCEEDED(pd3dDevice->GetDepthStencilSurface(&pStencil))) { |
| D3DSURFACE_DESC descStencil; |
| pStencil->GetDesc(&descStencil); |
| pStencil->Release(); |
| |
| D3DDISPLAYMODE dm; |
| return |
| (SUCCEEDED(pd3dDevice->GetDisplayMode(0, &dm)) && |
| pTargetDesc->Width <= descStencil.Width && |
| pTargetDesc->Height <= descStencil.Height && |
| SUCCEEDED(pd3dObject->CheckDepthStencilMatch( |
| adapterOrdinal, |
| devCaps.DeviceType, |
| dm.Format, pTargetDesc->Format, |
| descStencil.Format))); |
| } |
| J2dTraceLn(J2D_TRACE_VERBOSE, |
| " current stencil buffer is not compatible with new Render Target"); |
| |
| return false; |
| } |
| |
| |
| |
| HRESULT |
| D3DContext::InitDepthStencilBuffer(D3DSURFACE_DESC *pTargetDesc) |
| { |
| HRESULT res; |
| IDirect3DSurface9 *pBB; |
| D3DDISPLAYMODE dm; |
| |
| J2dTraceLn(J2D_TRACE_INFO, "D3DContext::InitDepthStencilBuffer"); |
| |
| if (FAILED(res = pd3dDevice->GetDisplayMode(0, &dm))) { |
| return res; |
| } |
| |
| D3DFORMAT newFormat = |
| D3DPipelineManager::GetInstance()->GetMatchingDepthStencilFormat( |
| adapterOrdinal, dm.Format, pTargetDesc->Format); |
| |
| res = pd3dDevice->CreateDepthStencilSurface( |
| pTargetDesc->Width, pTargetDesc->Height, |
| newFormat, D3DMULTISAMPLE_NONE, 0, false, &pBB, 0); |
| if (SUCCEEDED(res)) { |
| res = pd3dDevice->SetDepthStencilSurface(pBB); |
| pBB->Release(); |
| } |
| |
| return res; |
| } |
| |
| |
| HRESULT |
| D3DContext::SetRenderTarget(IDirect3DSurface9 *pSurface) |
| { |
| static D3DMATRIX tx; |
| HRESULT res; |
| D3DSURFACE_DESC descNew; |
| IDirect3DSurface9 *pCurrentTarget; |
| |
| J2dTraceLn1(J2D_TRACE_INFO, |
| "D3DContext::SetRenderTarget: pSurface=0x%x", |
| pSurface); |
| |
| RETURN_STATUS_IF_NULL(pd3dDevice, E_FAIL); |
| RETURN_STATUS_IF_NULL(pSurface, E_FAIL); |
| |
| pSurface->GetDesc(&descNew); |
| |
| if (SUCCEEDED(res = pd3dDevice->GetRenderTarget(0, &pCurrentTarget))) { |
| if (pCurrentTarget != pSurface) { |
| FlushVertexQueue(); |
| if (FAILED(res = pd3dDevice->SetRenderTarget(0, pSurface))) { |
| DebugPrintD3DError(res, "D3DContext::SetRenderTarget: "\ |
| "error setting render target"); |
| SAFE_RELEASE(pCurrentTarget); |
| return res; |
| } |
| |
| if (!IsDepthStencilBufferOk(&descNew)) { |
| if (FAILED(res = InitDepthStencilBuffer(&descNew))) { |
| SAFE_RELEASE(pCurrentTarget); |
| return res; |
| } |
| } |
| } |
| SAFE_RELEASE(pCurrentTarget); |
| } |
| // we set the transform even if the render target didn't change; |
| // this is because in some cases (fs mode) we use the default SwapChain of |
| // the device, and its render target will be the same as the device's, and |
| // we have to set the matrix correctly. This shouldn't be a performance |
| // issue as render target changes are relatively rare |
| D3DUtils_SetOrthoMatrixOffCenterLH(&tx, |
| (float)descNew.Width, |
| (float)descNew.Height); |
| pd3dDevice->SetTransform(D3DTS_PROJECTION, &tx); |
| |
| J2dTraceLn1(J2D_TRACE_VERBOSE, " current render target=0x%x", pSurface); |
| return res; |
| } |
| |
| HRESULT |
| D3DContext::ResetTransform() |
| { |
| HRESULT res = S_OK; |
| D3DMATRIX tx; |
| |
| J2dTraceLn(J2D_TRACE_INFO, "D3DContext::ResetTransform"); |
| if (pd3dDevice == NULL) { |
| return E_FAIL; |
| } |
| |
| // no need for state change, just flush the queue |
| FlushVertexQueue(); |
| |
| D3DUtils_SetIdentityMatrix(&tx); |
| if (FAILED(res = pd3dDevice->SetTransform(D3DTS_WORLD, &tx))) { |
| DebugPrintD3DError(res, "D3DContext::SetTransform failed"); |
| } |
| bIsIdentityTx = TRUE; |
| return res; |
| } |
| |
| HRESULT |
| D3DContext::SetTransform(jdouble m00, jdouble m10, |
| jdouble m01, jdouble m11, |
| jdouble m02, jdouble m12) |
| { |
| HRESULT res = S_OK; |
| D3DMATRIX tx, tx1; |
| |
| J2dTraceLn(J2D_TRACE_INFO, "D3DContext::SetTransform"); |
| if (pd3dDevice == NULL) { |
| return E_FAIL; |
| } |
| |
| // no need for state change, just flush the queue |
| FlushVertexQueue(); |
| |
| // In order to correctly map texels to pixels we need to |
| // adjust geometry by -0.5f in the transformed space. |
| // In order to do that we first create a translated matrix |
| // and then concatenate it with the world transform. |
| // |
| // Note that we only use non-id transform with DrawTexture, |
| // the rest is rendered pre-transformed. |
| // |
| // The identity transform for textures is handled in |
| // D3DVertexCacher::DrawTexture() because shifting by -0.5 for id |
| // transform breaks lines rendering. |
| |
| ZeroMemory(&tx1, sizeof(D3DMATRIX)); |
| |
| tx1._11 = (float)m00; |
| tx1._12 = (float)m10; |
| tx1._21 = (float)m01; |
| tx1._22 = (float)m11; |
| tx1._41 = (float)m02; |
| tx1._42 = (float)m12; |
| |
| tx1._33 = 1.0f; |
| tx1._44 = 1.0f; |
| |
| D3DUtils_SetIdentityMatrix(&tx); |
| tx._41 = -0.5f; |
| tx._42 = -0.5f; |
| D3DUtils_2DConcatenateM(&tx, &tx1); |
| |
| 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 = pd3dDevice->SetTransform(D3DTS_WORLD, &tx))) { |
| DebugPrintD3DError(res, "D3DContext::SetTransform failed"); |
| } |
| bIsIdentityTx = FALSE; |
| |
| return res; |
| } |
| |
| HRESULT |
| D3DContext::SetRectClip(int x1, int y1, int x2, int y2) |
| { |
| HRESULT res = S_OK; |
| D3DSURFACE_DESC desc; |
| IDirect3DSurface9 *pCurrentTarget; |
| |
| J2dTraceLn(J2D_TRACE_INFO, "D3DContext::SetRectClip"); |
| J2dTraceLn4(J2D_TRACE_VERBOSE, |
| " x1=%-4d y1=%-4d x2=%-4d y2=%-4d", |
| x1, y1, x2, y2); |
| |
| RETURN_STATUS_IF_NULL(pd3dDevice, E_FAIL); |
| |
| // no need for state change, just flush the queue |
| FlushVertexQueue(); |
| |
| pd3dDevice->SetRenderState(D3DRS_ZENABLE, D3DZB_FALSE); |
| |
| res = pd3dDevice->GetRenderTarget(0, &pCurrentTarget); |
| RETURN_STATUS_IF_FAILED(res); |
| |
| pCurrentTarget->GetDesc(&desc); |
| SAFE_RELEASE(pCurrentTarget); |
| |
| if (x1 <= 0 && y1 <= 0 && |
| (UINT)x2 >= desc.Width && (UINT)y2 >= desc.Height) |
| { |
| J2dTraceLn(J2D_TRACE_VERBOSE, |
| " disabling clip (== render target dimensions)"); |
| return pd3dDevice->SetRenderState(D3DRS_SCISSORTESTENABLE, FALSE); |
| } |
| |
| // clip to the dimensions of the target surface, otherwise |
| // SetScissorRect will fail |
| if (x1 < 0) x1 = 0; |
| if (y1 < 0) y1 = 0; |
| if ((UINT)x2 > desc.Width) x2 = desc.Width; |
| if ((UINT)y2 > desc.Height) y2 = desc.Height; |
| if (x1 > x2) x2 = x1 = 0; |
| if (y1 > y2) y2 = y1 = 0; |
| RECT newRect = { x1, y1, x2, y2 }; |
| if (SUCCEEDED(res = pd3dDevice->SetScissorRect(&newRect))) { |
| res = pd3dDevice->SetRenderState(D3DRS_SCISSORTESTENABLE, TRUE); |
| } else { |
| DebugPrintD3DError(res, "Error setting scissor rect"); |
| J2dRlsTraceLn4(J2D_TRACE_ERROR, |
| " x1=%-4d y1=%-4d x2=%-4d y2=%-4d", |
| x1, y1, x2, y2); |
| } |
| |
| return res; |
| } |
| |
| HRESULT |
| D3DContext::ResetClip() |
| { |
| J2dTraceLn(J2D_TRACE_INFO, "D3DContext::ResetClip"); |
| // no need for state change, just flush the queue |
| FlushVertexQueue(); |
| pd3dDevice->SetRenderState(D3DRS_SCISSORTESTENABLE, FALSE); |
| return pd3dDevice->SetRenderState(D3DRS_ZENABLE, D3DZB_FALSE); |
| } |
| |
| ClipType |
| D3DContext::GetClipType() |
| { |
| // REMIND: this method could be optimized: we could keep the |
| // clip state around when re/setting the clip instead of asking |
| // every time. |
| DWORD zEnabled = 0; |
| DWORD stEnabled = 0; |
| |
| J2dTraceLn(J2D_TRACE_INFO, "D3DContext::GetClipType"); |
| pd3dDevice->GetRenderState(D3DRS_SCISSORTESTENABLE, &stEnabled); |
| if (stEnabled) { |
| return CLIP_RECT; |
| } |
| pd3dDevice->GetRenderState(D3DRS_ZENABLE, &zEnabled); |
| if (zEnabled) { |
| return CLIP_SHAPE; |
| } |
| return CLIP_NONE; |
| } |
| |
| |
| /** |
| * 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. |
| */ |
| DWORD dwAlphaSt, dwSrcBlendSt, dwDestBlendSt; |
| D3DMATRIX tx, idTx; |
| |
| HRESULT |
| D3DContext::BeginShapeClip() |
| { |
| HRESULT res = S_OK; |
| J2dTraceLn(J2D_TRACE_INFO, "D3DContext::BeginShapeClip"); |
| |
| UpdateState(STATE_CHANGE); |
| |
| pd3dDevice->SetRenderState(D3DRS_SCISSORTESTENABLE, FALSE); |
| |
| // save alpha blending state |
| pd3dDevice->GetRenderState(D3DRS_ALPHABLENDENABLE, &dwAlphaSt); |
| pd3dDevice->GetRenderState(D3DRS_SRCBLEND, &dwSrcBlendSt); |
| pd3dDevice->GetRenderState(D3DRS_DESTBLEND, &dwDestBlendSt); |
| |
| pd3dDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE); |
| pd3dDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ZERO); |
| pd3dDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_ONE); |
| |
| pd3dDevice->GetTransform(D3DTS_WORLD, &tx); |
| D3DUtils_SetIdentityMatrix(&idTx); |
| // translate the clip spans by 1.0f in z direction so that the |
| // clip spans are rendered to the z buffer |
| idTx._43 = 1.0f; |
| pd3dDevice->SetTransform(D3DTS_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) |
| pd3dDevice->SetRenderState(D3DRS_ZENABLE, D3DZB_TRUE); |
| pd3dDevice->SetRenderState(D3DRS_ZWRITEENABLE, TRUE); |
| pd3dDevice->SetRenderState(D3DRS_ZFUNC, D3DCMP_ALWAYS); |
| pd3dDevice->Clear(0, NULL, D3DCLEAR_ZBUFFER, 0L, 0.0f, 0x0L); |
| |
| //res = BeginScene(STATE_SHAPE_CLIPOP); |
| |
| return res; |
| } |
| |
| HRESULT |
| D3DContext::EndShapeClip() |
| { |
| HRESULT res; |
| |
| // no need for state change, just flush the queue |
| res = FlushVertexQueue(); |
| |
| // restore alpha blending state |
| pd3dDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, dwAlphaSt); |
| pd3dDevice->SetRenderState(D3DRS_SRCBLEND, dwSrcBlendSt); |
| pd3dDevice->SetRenderState(D3DRS_DESTBLEND, dwDestBlendSt); |
| |
| // resore the transform |
| pd3dDevice->SetTransform(D3DTS_WORLD, &tx); |
| |
| // Enable the depth buffer. |
| // We disable further updates to the depth buffer: it should only |
| // be updated in SetClip method. |
| pd3dDevice->SetRenderState(D3DRS_ZWRITEENABLE, FALSE); |
| pd3dDevice->SetRenderState(D3DRS_ZFUNC, D3DCMP_LESS); |
| |
| return res; |
| } |
| |
| HRESULT |
| D3DContext::UploadTileToTexture(D3DResource *pTextureRes, void *pixels, |
| jint dstx, jint dsty, |
| jint srcx, jint srcy, |
| jint srcWidth, jint srcHeight, |
| jint srcStride, |
| TileFormat srcFormat, |
| jint *pPixelsTouchedL, |
| jint* pPixelsTouchedR) |
| { |
| #ifndef PtrAddBytes |
| #define PtrAddBytes(p, b) ((void *) (((intptr_t) (p)) + (b))) |
| #define PtrCoord(p, x, xinc, y, yinc) PtrAddBytes(p, (y)*(yinc) + (x)*(xinc)) |
| #endif // PtrAddBytes |
| |
| HRESULT res = S_OK; |
| IDirect3DTexture9 *pTexture = pTextureRes->GetTexture(); |
| D3DSURFACE_DESC *pDesc = pTextureRes->GetDesc(); |
| RECT r = { dstx, dsty, dstx+srcWidth, dsty+srcHeight }; |
| RECT *pR = &r; |
| D3DLOCKED_RECT lockedRect; |
| DWORD dwLockFlags = D3DLOCK_NOSYSLOCK; |
| // these are only counted for LCD glyph uploads |
| jint pixelsTouchedL = 0, pixelsTouchedR = 0; |
| |
| J2dTraceLn(J2D_TRACE_INFO, "D3DContext::UploadTileToTexture"); |
| J2dTraceLn4(J2D_TRACE_VERBOSE, |
| " rect={%-4d, %-4d, %-4d, %-4d}", |
| r.left, r.top, r.right, r.bottom); |
| |
| if (pDesc->Usage == D3DUSAGE_DYNAMIC) { |
| // it is safe to lock with discard because we don't care about the |
| // contents of dynamic textures and dstx,dsty for this case is |
| // always 0,0 because we are uploading into a tile texture |
| dwLockFlags |= D3DLOCK_DISCARD; |
| pR = NULL; |
| } |
| |
| if (FAILED(res = pTexture->LockRect(0, &lockedRect, pR, dwLockFlags))) { |
| DebugPrintD3DError(res, |
| "D3DContext::UploadImageToTexture: could "\ |
| "not lock texture"); |
| return res; |
| } |
| |
| if (srcFormat == TILEFMT_1BYTE_ALPHA) { |
| // either a MaskFill tile, or a grayscale glyph |
| if (pDesc->Format == D3DFMT_A8) { |
| void *pSrcPixels = PtrCoord(pixels, srcx, 1, srcy, srcStride); |
| void *pDstPixels = lockedRect.pBits; |
| do { |
| memcpy(pDstPixels, pSrcPixels, srcWidth); |
| pSrcPixels = PtrAddBytes(pSrcPixels, srcStride); |
| pDstPixels = PtrAddBytes(pDstPixels, lockedRect.Pitch); |
| } while (--srcHeight > 0); |
| } |
| else if (pDesc->Format == D3DFMT_A8R8G8B8) { |
| jubyte *pSrcPixels = (jubyte*) |
| PtrCoord(pixels, srcx, 1, srcy, srcStride); |
| jint *pDstPixels = (jint*)lockedRect.pBits; |
| for (int yy = 0; yy < srcHeight; yy++) { |
| for (int xx = 0; xx < srcWidth; xx++) { |
| // only need to set the alpha channel (the D3D texture |
| // state will be setup in this case to replicate the |
| // alpha channel as needed) |
| pDstPixels[xx] = pSrcPixels[xx] << 24; |
| } |
| pSrcPixels = (jubyte*)PtrAddBytes(pSrcPixels, srcStride); |
| pDstPixels = (jint*)PtrAddBytes(pDstPixels, lockedRect.Pitch); |
| } |
| } |
| } else if (srcFormat == TILEFMT_3BYTE_RGB) { |
| // LCD glyph with RGB order |
| if (pDesc->Format == D3DFMT_R8G8B8) { |
| jubyte *pSrcPixels = (jubyte*) |
| PtrCoord(pixels, srcx, 3, srcy, srcStride); |
| jubyte *pDstPixels = (jubyte*)lockedRect.pBits; |
| for (int yy = 0; yy < srcHeight; yy++) { |
| for (int xx = 0; xx < srcWidth*3; xx+=3) { |
| // alpha channel is ignored in this case |
| // (note that this is backwards from what one might |
| // expect; it appears that D3DFMT_R8G8B8 is actually |
| // laid out in BGR order in memory) |
| pDstPixels[xx+0] = pSrcPixels[xx+2]; |
| pDstPixels[xx+1] = pSrcPixels[xx+1]; |
| pDstPixels[xx+2] = pSrcPixels[xx+0]; |
| } |
| pixelsTouchedL += |
| (pDstPixels[0+0]|pDstPixels[0+1]|pDstPixels[0+2]) ? 1 : 0; |
| jint i = 3*(srcWidth-1); |
| pixelsTouchedR += |
| (pDstPixels[i+0]|pDstPixels[i+1]|pDstPixels[i+2]) ? 1 : 0; |
| |
| pSrcPixels = (jubyte*)PtrAddBytes(pSrcPixels, srcStride); |
| pDstPixels = (jubyte*)PtrAddBytes(pDstPixels, lockedRect.Pitch); |
| } |
| } |
| else if (pDesc->Format == D3DFMT_A8R8G8B8) { |
| jubyte *pSrcPixels = (jubyte*) |
| PtrCoord(pixels, srcx, 3, srcy, srcStride); |
| jint *pDstPixels = (jint*)lockedRect.pBits; |
| for (int yy = 0; yy < srcHeight; yy++) { |
| for (int dx = 0, sx = 0; dx < srcWidth; dx++, sx+=3) { |
| // alpha channel is ignored in this case |
| jubyte r = pSrcPixels[sx+0]; |
| jubyte g = pSrcPixels[sx+1]; |
| jubyte b = pSrcPixels[sx+2]; |
| pDstPixels[dx] = (r << 16) | (g << 8) | (b); |
| } |
| pixelsTouchedL += (pDstPixels[0] ? 1 : 0); |
| pixelsTouchedR += (pDstPixels[srcWidth-1] ? 1 : 0); |
| |
| pSrcPixels = (jubyte*)PtrAddBytes(pSrcPixels, srcStride); |
| pDstPixels = (jint*)PtrAddBytes(pDstPixels, lockedRect.Pitch); |
| } |
| } |
| } else if (srcFormat == TILEFMT_3BYTE_BGR) { |
| // LCD glyph with BGR order |
| if (pDesc->Format == D3DFMT_R8G8B8) { |
| void *pSrcPixels = PtrCoord(pixels, srcx, 3, srcy, srcStride); |
| void *pDstPixels = lockedRect.pBits; |
| jubyte *pbDst; |
| do { |
| // alpha channel is ignored in this case |
| // (note that this is backwards from what one might |
| // expect; it appears that D3DFMT_R8G8B8 is actually |
| // laid out in BGR order in memory) |
| memcpy(pDstPixels, pSrcPixels, srcWidth * 3); |
| |
| pbDst = (jubyte*)pDstPixels; |
| pixelsTouchedL +=(pbDst[0+0]|pbDst[0+1]|pbDst[0+2]) ? 1 : 0; |
| jint i = 3*(srcWidth-1); |
| pixelsTouchedR +=(pbDst[i+0]|pbDst[i+1]|pbDst[i+2]) ? 1 : 0; |
| |
| pSrcPixels = PtrAddBytes(pSrcPixels, srcStride); |
| pDstPixels = PtrAddBytes(pDstPixels, lockedRect.Pitch); |
| } while (--srcHeight > 0); |
| } |
| else if (pDesc->Format == D3DFMT_A8R8G8B8) { |
| jubyte *pSrcPixels = (jubyte*) |
| PtrCoord(pixels, srcx, 3, srcy, srcStride); |
| jint *pDstPixels = (jint*)lockedRect.pBits; |
| for (int yy = 0; yy < srcHeight; yy++) { |
| for (int dx = 0, sx = 0; dx < srcWidth; dx++, sx+=3) { |
| // alpha channel is ignored in this case |
| jubyte b = pSrcPixels[sx+0]; |
| jubyte g = pSrcPixels[sx+1]; |
| jubyte r = pSrcPixels[sx+2]; |
| pDstPixels[dx] = (r << 16) | (g << 8) | (b); |
| } |
| pixelsTouchedL += (pDstPixels[0] ? 1 : 0); |
| pixelsTouchedR += (pDstPixels[srcWidth-1] ? 1 : 0); |
| |
| pSrcPixels = (jubyte*)PtrAddBytes(pSrcPixels, srcStride); |
| pDstPixels = (jint*)PtrAddBytes(pDstPixels, lockedRect.Pitch); |
| } |
| } |
| } else if (srcFormat == TILEFMT_4BYTE_ARGB_PRE) { |
| // MaskBlit tile |
| if (pDesc->Format == D3DFMT_A8R8G8B8) { |
| void *pSrcPixels = PtrCoord(pixels, srcx, 4, srcy, srcStride); |
| void *pDstPixels = lockedRect.pBits; |
| do { |
| memcpy(pDstPixels, pSrcPixels, srcWidth * 4); |
| pSrcPixels = PtrAddBytes(pSrcPixels, srcStride); |
| pDstPixels = PtrAddBytes(pDstPixels, lockedRect.Pitch); |
| } while (--srcHeight > 0); |
| } |
| } else { |
| // should not happen, no-op just in case... |
| } |
| |
| if (pPixelsTouchedL) { |
| *pPixelsTouchedL = pixelsTouchedL; |
| } |
| if (pPixelsTouchedR) { |
| *pPixelsTouchedR = pixelsTouchedR; |
| } |
| |
| return pTexture->UnlockRect(0); |
| } |
| |
| HRESULT |
| D3DContext::InitLCDGlyphCache() |
| { |
| if (pLCDGlyphCache == NULL) { |
| return D3DGlyphCache::CreateInstance(this, CACHE_LCD, &pLCDGlyphCache); |
| } |
| return S_OK; |
| } |
| |
| HRESULT |
| D3DContext::InitGrayscaleGlyphCache() |
| { |
| if (pGrayscaleGlyphCache == NULL) { |
| return D3DGlyphCache::CreateInstance(this, CACHE_GRAY, |
| &pGrayscaleGlyphCache); |
| } |
| return S_OK; |
| } |
| |
| HRESULT |
| D3DContext::ResetComposite() |
| { |
| J2dTraceLn(J2D_TRACE_INFO, "D3DContext::ResetComposite"); |
| |
| RETURN_STATUS_IF_NULL(pd3dDevice, E_FAIL); |
| |
| HRESULT res = UpdateState(STATE_CHANGE); |
| pd3dDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE); |
| extraAlpha = 1.0f; |
| return res; |
| } |
| |
| HRESULT |
| D3DContext::SetAlphaComposite(jint rule, jfloat ea, jint flags) |
| { |
| HRESULT res; |
| J2dTraceLn3(J2D_TRACE_INFO, |
| "D3DContext::SetAlphaComposite: rule=%-1d ea=%f flags=%d", |
| rule, ea, flags); |
| |
| RETURN_STATUS_IF_NULL(pd3dDevice, E_FAIL); |
| |
| res = UpdateState(STATE_CHANGE); |
| |
| // 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); |
| pd3dDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE); |
| } else { |
| J2dTraceLn2(J2D_TRACE_VERBOSE, |
| " enabling alpha comp (rule=%-1d ea=%f)", rule, ea); |
| pd3dDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE); |
| |
| pd3dDevice->SetRenderState(D3DRS_SRCBLEND, |
| StdBlendRules[rule].src); |
| pd3dDevice->SetRenderState(D3DRS_DESTBLEND, |
| StdBlendRules[rule].dst); |
| } |
| |
| extraAlpha = ea; |
| return res; |
| } |
| |
| #ifdef UPDATE_TX |
| |
| // Note: this method of adjusting pixel to texel mapping proved to be |
| // difficult to perfect. The current variation works great for id, |
| // scale (including all kinds of flips) transforms, but not still not |
| // for generic transforms. |
| // |
| // Since we currently only do DrawTexture with non-id transform we instead |
| // adjust the geometry (see D3DVertexCacher::DrawTexture(), SetTransform()) |
| // |
| // In order to enable this code path UpdateTextureTransforms needs to |
| // be called in SetTexture(), SetTransform() and ResetTranform(). |
| HRESULT |
| D3DContext::UpdateTextureTransforms(DWORD dwSamplerToUpdate) |
| { |
| HRESULT res = S_OK; |
| DWORD dwSampler, dwMaxSampler; |
| |
| if (dwSamplerToUpdate == -1) { |
| // update all used samplers, dwMaxSampler will be set to max |
| dwSampler = 0; |
| dwSampler = MAX_USED_TEXTURE_SAMPLER; |
| J2dTraceLn(J2D_TRACE_INFO, "D3DContext::UpdateTextureTransforms: "\ |
| "updating all samplers"); |
| } else { |
| // update only given sampler, dwMaxSampler will be set to it as well |
| dwSampler = dwSamplerToUpdate; |
| dwMaxSampler = dwSamplerToUpdate; |
| J2dTraceLn1(J2D_TRACE_INFO, "D3DContext::UpdateTextureTransforms: "\ |
| "updating sampler %d", dwSampler); |
| } |
| |
| do { |
| D3DTRANSFORMSTATETYPE state = |
| (D3DTRANSFORMSTATETYPE)(D3DTS_TEXTURE0 + dwSampler); |
| IDirect3DTexture9 *pTexture = lastTexture[dwSampler]; |
| |
| if (pTexture != NULL) { |
| D3DMATRIX mt, tx; |
| D3DSURFACE_DESC texDesc; |
| |
| pd3dDevice->GetTransform(D3DTS_WORLD, &tx); |
| J2dTraceLn4(10, |
| " %5f %5f %5f %5f", tx._11, tx._12, tx._13, tx._14); |
| J2dTraceLn4(10, |
| " %5f %5f %5f %5f", tx._21, tx._22, tx._23, tx._24); |
| J2dTraceLn4(10, |
| " %5f %5f %5f %5f", tx._31, tx._32, tx._33, tx._34); |
| J2dTraceLn4(10, |
| " %5f %5f %5f %5f", tx._41, tx._42, tx._43, tx._44); |
| |
| // this formula works for scales and flips |
| if (tx._11 == 0.0f) { |
| tx._11 = tx._12; |
| } |
| if (tx._22 == 0.0f) { |
| tx._22 = tx._21; |
| } |
| |
| pTexture->GetLevelDesc(0, &texDesc); |
| |
| // shift by .5 texel, but take into account |
| // the scale factor of the device transform |
| |
| // REMIND: this approach is not entirely correct, |
| // as it only takes into account the scale of the device |
| // transform. |
| mt._31 = (1.0f / (2.0f * texDesc.Width * tx._11)); |
| mt._32 = (1.0f / (2.0f * texDesc.Height * tx._22)); |
| J2dTraceLn2(J2D_TRACE_VERBOSE, " offsets: tx=%f ty=%f", |
| mt._31, mt._32); |
| |
| pd3dDevice->SetTextureStageState(dwSampler, |
| D3DTSS_TEXTURETRANSFORMFLAGS, |
| D3DTTFF_COUNT2); |
| res = pd3dDevice->SetTransform(state, &mt); |
| } else { |
| res = pd3dDevice->SetTextureStageState(dwSampler, |
| D3DTSS_TEXTURETRANSFORMFLAGS, |
| D3DTTFF_DISABLE); |
| } |
| dwSampler++; |
| } while (dwSampler <= dwMaxSampler); |
| |
| return res; |
| } |
| #endif // UPDATE_TX |
| |
| /** |
| * 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 |
| D3DContext::SetTexture(IDirect3DTexture9 *pTexture, DWORD dwSampler) |
| { |
| HRESULT res = S_OK; |
| J2dTraceLn(J2D_TRACE_INFO, "D3DContext::SetTexture"); |
| |
| if (dwSampler < 0 || dwSampler > MAX_USED_TEXTURE_SAMPLER) { |
| J2dTraceLn1(J2D_TRACE_ERROR, |
| "D3DContext::SetTexture: incorrect sampler: %d", dwSampler); |
| return E_FAIL; |
| } |
| if (lastTexture[dwSampler] != pTexture) { |
| if (FAILED(res = FlushVertexQueue())) { |
| return res; |
| } |
| J2dTraceLn2(J2D_TRACE_VERBOSE, |
| " new texture=0x%x on sampler %d", pTexture, dwSampler); |
| res = pd3dDevice->SetTexture(dwSampler, pTexture); |
| if (SUCCEEDED(res)) { |
| lastTexture[dwSampler] = pTexture; |
| // REMIND: see comment at UpdateTextureTransforms |
| #ifdef UPDATE_TX |
| res = UpdateTextureTransforms(dwSampler); |
| #endif |
| } else { |
| lastTexture[dwSampler] = NULL; |
| } |
| } |
| return res; |
| } |
| |
| HRESULT |
| D3DContext::UpdateTextureColorState(DWORD dwState, DWORD dwSampler) |
| { |
| HRESULT res = S_OK; |
| |
| if (dwState != lastTextureColorState[dwSampler]) { |
| res = pd3dDevice->SetTextureStageState(dwSampler, |
| D3DTSS_ALPHAARG1, dwState); |
| res = pd3dDevice->SetTextureStageState(dwSampler, |
| D3DTSS_COLORARG1, dwState); |
| lastTextureColorState[dwSampler] = dwState; |
| } |
| |
| return res; |
| } |
| |
| HRESULT /*NOLOCK*/ |
| D3DContext::UpdateState(jbyte newState) |
| { |
| HRESULT res = S_OK; |
| |
| if (opState == newState) { |
| // The op is the same as last time, so we can return immediately. |
| return res; |
| } else if (opState != STATE_CHANGE) { |
| res = FlushVertexQueue(); |
| } |
| |
| switch (opState) { |
| case STATE_MASKOP: |
| pMaskCache->Disable(); |
| break; |
| case STATE_GLYPHOP: |
| D3DTR_DisableGlyphVertexCache(this); |
| break; |
| case STATE_TEXTUREOP: |
| // optimization: certain state changes (those marked STATE_CHANGE) |
| // are allowed while texturing is enabled. |
| // In this case, we can allow previousOp to remain as it is and |
| // then return early. |
| if (newState == STATE_CHANGE) { |
| return res; |
| } |
| // REMIND: not necessary if we are switching to MASKOP or GLYPHOP |
| // (or a complex paint, for that matter), but would that be a |
| // worthwhile optimization? |
| SetTexture(NULL); |
| break; |
| case STATE_AAPGRAMOP: |
| res = DisableAAParallelogramProgram(); |
| break; |
| default: |
| break; |
| } |
| |
| switch (newState) { |
| case STATE_MASKOP: |
| pMaskCache->Enable(); |
| UpdateTextureColorState(D3DTA_TEXTURE | D3DTA_ALPHAREPLICATE); |
| break; |
| case STATE_GLYPHOP: |
| D3DTR_EnableGlyphVertexCache(this); |
| UpdateTextureColorState(D3DTA_TEXTURE | D3DTA_ALPHAREPLICATE); |
| break; |
| case STATE_TEXTUREOP: |
| UpdateTextureColorState(D3DTA_TEXTURE); |
| break; |
| case STATE_AAPGRAMOP: |
| res = EnableAAParallelogramProgram(); |
| break; |
| default: |
| break; |
| } |
| |
| opState = newState; |
| |
| return res; |
| } |
| |
| HRESULT D3DContext::FlushVertexQueue() |
| { |
| if (pVCacher != NULL) { |
| return pVCacher->Render(); |
| } |
| return E_FAIL; |
| } |
| |
| HRESULT D3DContext::BeginScene(jbyte newState) |
| { |
| if (!pd3dDevice) { |
| return E_FAIL; |
| } else { |
| UpdateState(newState); |
| if (!bBeginScenePending) { |
| bBeginScenePending = TRUE; |
| HRESULT res = pd3dDevice->BeginScene(); |
| J2dTraceLn(J2D_TRACE_INFO, "D3DContext::BeginScene"); |
| if (FAILED(res)) { |
| // this will cause context reinitialization |
| opState = STATE_CHANGE; |
| } |
| return res; |
| } |
| return S_OK; |
| } |
| } |
| |
| HRESULT D3DContext::EndScene() { |
| if (bBeginScenePending) { |
| FlushVertexQueue(); |
| bBeginScenePending = FALSE; |
| J2dTraceLn(J2D_TRACE_INFO, "D3DContext::EndScene"); |
| return pd3dDevice->EndScene(); |
| } |
| return S_OK; |
| } |
| |
| /** |
| * Compiles and links the given fragment shader program. If |
| * successful, this function returns a handle to the newly created shader |
| * program; otherwise returns 0. |
| */ |
| IDirect3DPixelShader9 *D3DContext::CreateFragmentProgram(DWORD **shaders, |
| ShaderList *programs, |
| jint flags) |
| { |
| DWORD *sourceCode; |
| IDirect3DPixelShader9 *pProgram; |
| |
| J2dTraceLn1(J2D_TRACE_INFO, |
| "D3DContext::CreateFragmentProgram: flags=%d", |
| flags); |
| |
| sourceCode = shaders[flags]; |
| if (FAILED(pd3dDevice->CreatePixelShader(sourceCode, &pProgram))) { |
| J2dRlsTraceLn(J2D_TRACE_ERROR, |
| "D3DContext::CreateFragmentProgram: error creating program"); |
| return NULL; |
| } |
| |
| // add it to the cache |
| ShaderList_AddProgram(programs, ptr_to_jlong(pProgram), |
| 0 /*unused*/, 0 /*unused*/, flags); |
| |
| return pProgram; |
| } |
| |
| /** |
| * Locates and enables a fragment program given a list of shader programs |
| * (ShaderInfos), using this context's state and flags as search |
| * parameters. The "flags" parameter is a bitwise-or'd value that helps |
| * differentiate one program for another; the interpretation of this value |
| * varies depending on the type of shader (BufImgOp, Paint, etc) but here |
| * it is only used to find another ShaderInfo with that same "flags" value. |
| */ |
| HRESULT D3DContext::EnableFragmentProgram(DWORD **shaders, |
| ShaderList *programList, |
| jint flags) |
| { |
| HRESULT res; |
| jlong programID; |
| IDirect3DPixelShader9 *pProgram; |
| |
| J2dTraceLn(J2D_TRACE_INFO, "D3DContext::EnableFragmentProgram"); |
| |
| programID = |
| ShaderList_FindProgram(programList, |
| 0 /*unused*/, 0 /*unused*/, flags); |
| |
| pProgram = (IDirect3DPixelShader9 *)jlong_to_ptr(programID); |
| if (pProgram == NULL) { |
| pProgram = CreateFragmentProgram(shaders, programList, flags); |
| if (pProgram == NULL) { |
| return E_FAIL; |
| } |
| } |
| |
| if (FAILED(res = pd3dDevice->SetPixelShader(pProgram))) { |
| J2dRlsTraceLn(J2D_TRACE_ERROR, |
| "D3DContext::EnableFragmentProgram: error setting pixel shader"); |
| return res; |
| } |
| |
| return S_OK; |
| } |
| |
| HRESULT D3DContext::EnableBasicGradientProgram(jint flags) |
| { |
| return EnableFragmentProgram((DWORD **)gradShaders, |
| &basicGradPrograms, flags); |
| } |
| |
| HRESULT D3DContext::EnableLinearGradientProgram(jint flags) |
| { |
| return EnableFragmentProgram((DWORD **)linearShaders, |
| &linearGradPrograms, flags); |
| } |
| |
| HRESULT D3DContext::EnableRadialGradientProgram(jint flags) |
| { |
| return EnableFragmentProgram((DWORD **)radialShaders, |
| &radialGradPrograms, flags); |
| } |
| |
| HRESULT D3DContext::EnableConvolveProgram(jint flags) |
| { |
| return EnableFragmentProgram((DWORD **)convolveShaders, |
| &convolvePrograms, flags); |
| } |
| |
| HRESULT D3DContext::EnableRescaleProgram(jint flags) |
| { |
| return EnableFragmentProgram((DWORD **)rescaleShaders, |
| &rescalePrograms, flags); |
| } |
| |
| HRESULT D3DContext::EnableLookupProgram(jint flags) |
| { |
| return EnableFragmentProgram((DWORD **)lookupShaders, |
| &lookupPrograms, flags); |
| } |
| |
| HRESULT D3DContext::EnableLCDTextProgram() |
| { |
| HRESULT res; |
| |
| J2dTraceLn(J2D_TRACE_INFO, "D3DContext::EnableLCDTextProgram"); |
| |
| if (lcdTextProgram == NULL) { |
| if (FAILED(res = pd3dDevice->CreatePixelShader(lcdtext0, |
| &lcdTextProgram))) |
| { |
| return res; |
| } |
| } |
| |
| if (FAILED(res = pd3dDevice->SetPixelShader(lcdTextProgram))) { |
| J2dRlsTraceLn(J2D_TRACE_ERROR, |
| "D3DContext::EnableLCDTextProgram: error setting pixel shader"); |
| return res; |
| } |
| |
| return S_OK; |
| } |
| |
| HRESULT D3DContext::EnableAAParallelogramProgram() |
| { |
| HRESULT res; |
| |
| J2dTraceLn(J2D_TRACE_INFO, "D3DContext::EnableAAParallelogramProgram"); |
| |
| if (aaPgramProgram == NULL) { |
| if (FAILED(res = pd3dDevice->CreatePixelShader(aapgram0, |
| &aaPgramProgram))) { |
| DebugPrintD3DError(res, "D3DContext::EnableAAParallelogramProgram: " |
| "error creating pixel shader"); |
| return res; |
| } |
| } |
| |
| if (FAILED(res = pd3dDevice->SetPixelShader(aaPgramProgram))) { |
| DebugPrintD3DError(res, "D3DContext::EnableAAParallelogramProgram: " |
| "error setting pixel shader"); |
| return res; |
| } |
| |
| return S_OK; |
| } |
| |
| HRESULT D3DContext::DisableAAParallelogramProgram() |
| { |
| HRESULT res; |
| |
| J2dTraceLn(J2D_TRACE_INFO, "D3DContext::DisableAAParallelogramProgram"); |
| |
| if (aaPgramProgram != NULL) { |
| if (FAILED(res = pd3dDevice->SetPixelShader(NULL))) { |
| DebugPrintD3DError(res, |
| "D3DContext::DisableAAParallelogramProgram: " |
| "error clearing pixel shader"); |
| return res; |
| } |
| } |
| |
| return S_OK; |
| } |
| |
| BOOL D3DContext::IsAlphaRTSurfaceSupported() |
| { |
| HRESULT res = pd3dObject->CheckDeviceFormat(adapterOrdinal, |
| devCaps.DeviceType, |
| curParams.BackBufferFormat, |
| D3DUSAGE_RENDERTARGET, |
| D3DRTYPE_SURFACE, |
| D3DFMT_A8R8G8B8); |
| return SUCCEEDED(res); |
| } |
| |
| BOOL D3DContext::IsAlphaRTTSupported() |
| { |
| HRESULT res = pd3dObject->CheckDeviceFormat(adapterOrdinal, |
| devCaps.DeviceType, |
| curParams.BackBufferFormat, |
| D3DUSAGE_RENDERTARGET, |
| D3DRTYPE_TEXTURE, |
| D3DFMT_A8R8G8B8); |
| return SUCCEEDED(res); |
| } |
| |
| BOOL D3DContext::IsOpaqueRTTSupported() |
| { |
| HRESULT res = pd3dObject->CheckDeviceFormat(adapterOrdinal, |
| devCaps.DeviceType, |
| curParams.BackBufferFormat, |
| D3DUSAGE_RENDERTARGET, |
| D3DRTYPE_TEXTURE, |
| curParams.BackBufferFormat); |
| return SUCCEEDED(res); |
| } |
| |
| HRESULT D3DContext::InitContextCaps() { |
| J2dTraceLn(J2D_TRACE_INFO, "D3DContext::InitContextCaps"); |
| J2dTraceLn1(J2D_TRACE_VERBOSE, " caps for adapter %d :", adapterOrdinal); |
| |
| if (pd3dDevice == NULL || pd3dObject == NULL) { |
| contextCaps = CAPS_EMPTY; |
| J2dRlsTraceLn(J2D_TRACE_VERBOSE, " | CAPS_EMPTY"); |
| return E_FAIL; |
| } |
| |
| contextCaps = CAPS_DEVICE_OK; |
| J2dRlsTraceLn(J2D_TRACE_VERBOSE, " | CAPS_DEVICE_OK"); |
| |
| if (IsAlphaRTSurfaceSupported()) { |
| contextCaps |= CAPS_RT_PLAIN_ALPHA; |
| J2dRlsTraceLn(J2D_TRACE_VERBOSE, " | CAPS_RT_PLAIN_ALPHA"); |
| } |
| if (IsAlphaRTTSupported()) { |
| contextCaps |= CAPS_RT_TEXTURE_ALPHA; |
| J2dRlsTraceLn(J2D_TRACE_VERBOSE, " | CAPS_RT_TEXTURE_ALPHA"); |
| } |
| if (IsOpaqueRTTSupported()) { |
| contextCaps |= CAPS_RT_TEXTURE_OPAQUE; |
| J2dRlsTraceLn(J2D_TRACE_VERBOSE, " | CAPS_RT_TEXTURE_OPAQUE"); |
| } |
| if (IsPixelShader20Supported()) { |
| contextCaps |= CAPS_LCD_SHADER | CAPS_BIOP_SHADER | CAPS_PS20; |
| J2dRlsTraceLn(J2D_TRACE_VERBOSE, |
| " | CAPS_LCD_SHADER | CAPS_BIOP_SHADER | CAPS_PS20"); |
| // Pre-PS3.0 video boards are very slow with the AA shader, so |
| // we will require PS30 hw even though the shader is compiled for 2.0a |
| // if (IsGradientInstructionExtensionSupported()) { |
| // contextCaps |= CAPS_AA_SHADER; |
| // J2dRlsTraceLn(J2D_TRACE_VERBOSE, " | CAPS_AA_SHADER"); |
| // } |
| } |
| if (IsPixelShader30Supported()) { |
| if ((contextCaps & CAPS_AA_SHADER) == 0) { |
| // This flag was not already mentioned above... |
| J2dRlsTraceLn(J2D_TRACE_VERBOSE, " | CAPS_AA_SHADER"); |
| } |
| contextCaps |= CAPS_PS30 | CAPS_AA_SHADER; |
| J2dRlsTraceLn(J2D_TRACE_VERBOSE, " | CAPS_PS30"); |
| } |
| if (IsMultiTexturingSupported()) { |
| contextCaps |= CAPS_MULTITEXTURE; |
| J2dRlsTraceLn(J2D_TRACE_VERBOSE, " | CAPS_MULTITEXTURE"); |
| } |
| if (!IsPow2TexturesOnly()) { |
| contextCaps |= CAPS_TEXNONPOW2; |
| J2dRlsTraceLn(J2D_TRACE_VERBOSE, " | CAPS_TEXNONPOW2"); |
| } |
| if (!IsSquareTexturesOnly()) { |
| contextCaps |= CAPS_TEXNONSQUARE; |
| J2dRlsTraceLn(J2D_TRACE_VERBOSE, " | CAPS_TEXNONSQUARE"); |
| } |
| return S_OK; |
| } |