Path: blob/master/src/java.desktop/windows/native/libawt/java2d/d3d/D3DContext.cpp
41159 views
/*1* Copyright (c) 2007, 2019, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425#include "D3DPipeline.h"26#include "jlong.h"2728#include "GraphicsPrimitiveMgr.h"29#include "D3DContext.h"30#include "D3DSurfaceData.h"31#include "D3DBufImgOps.h"32#include "D3DPaints.h"33#include "D3DRenderQueue.h"34#include "D3DShaders.h"35#include "D3DTextRenderer.h"36#include "D3DPipelineManager.h"37#include "D3DGlyphCache.h"3839typedef struct {40D3DBLEND src;41D3DBLEND dst;42} D3DBlendRule;4344/**45* This table contains the standard blending rules (or Porter-Duff compositing46* factors) used in SetRenderState(), indexed by the rule constants from the47* AlphaComposite class.48*/49D3DBlendRule StdBlendRules[] = {50{ D3DBLEND_ZERO, D3DBLEND_ZERO }, /* 0 - Nothing */51{ D3DBLEND_ZERO, D3DBLEND_ZERO }, /* 1 - RULE_Clear */52{ D3DBLEND_ONE, D3DBLEND_ZERO }, /* 2 - RULE_Src */53{ D3DBLEND_ONE, D3DBLEND_INVSRCALPHA }, /* 3 - RULE_SrcOver */54{ D3DBLEND_INVDESTALPHA, D3DBLEND_ONE }, /* 4 - RULE_DstOver */55{ D3DBLEND_DESTALPHA, D3DBLEND_ZERO }, /* 5 - RULE_SrcIn */56{ D3DBLEND_ZERO, D3DBLEND_SRCALPHA }, /* 6 - RULE_DstIn */57{ D3DBLEND_INVDESTALPHA, D3DBLEND_ZERO }, /* 7 - RULE_SrcOut */58{ D3DBLEND_ZERO, D3DBLEND_INVSRCALPHA }, /* 8 - RULE_DstOut */59{ D3DBLEND_ZERO, D3DBLEND_ONE }, /* 9 - RULE_Dst */60{ D3DBLEND_DESTALPHA, D3DBLEND_INVSRCALPHA }, /*10 - RULE_SrcAtop */61{ D3DBLEND_INVDESTALPHA, D3DBLEND_SRCALPHA }, /*11 - RULE_DstAtop */62{ D3DBLEND_INVDESTALPHA, D3DBLEND_INVSRCALPHA }, /*12 - RULE_AlphaXor*/63};6465void66D3DUtils_SetOrthoMatrixOffCenterLH(D3DMATRIX *m,67float width, float height)68{69ZeroMemory(m, sizeof(D3DMATRIX));70m->_11 = 2.0f/width;71m->_22 = -2.0f/height;72m->_33 = 0.5f;73m->_44 = 1.0f;7475m->_41 = -1.0f;76m->_42 = 1.0f;77m->_43 = 0.5f;78}7980void81D3DUtils_SetIdentityMatrix(D3DMATRIX *m)82{83m->_12 = m->_13 = m->_14 = m->_21 = m->_23 = m->_24 = 0.0f;84m->_31 = m->_32 = m->_34 = m->_41 = m->_42 = m->_43 = 0.0f;85m->_11 = m->_22 = m->_33 = m->_44 = 1.0f;86}8788// the following methods are copies of the AffineTransform's class89// corresponding methods, with these changes to the indexes:90// 00 -> 1191// 11 -> 2292// 01 -> 2193// 10 -> 1294// 02 -> 4195// 12 -> 429697void98D3DUtils_2DConcatenateM(D3DMATRIX *m, D3DMATRIX *m1)99{100float M0, M1;101float T00, T10, T01, T11;102float T02, T12;103104T00 = m1->_11; T01 = m1->_21; T02 = m1->_41;105T10 = m1->_12; T11 = m1->_22; T12 = m1->_42;106107M0 = m->_11;108M1 = m->_21;109m->_11 = T00 * M0 + T10 * M1;110m->_21 = T01 * M0 + T11 * M1;111m->_41 += T02 * M0 + T12 * M1;112113M0 = m->_12;114M1 = m->_22;115m->_12 = T00 * M0 + T10 * M1;116m->_22 = T01 * M0 + T11 * M1;117m->_42 += T02 * M0 + T12 * M1;118}119120#ifdef UPDATE_TX121122void123D3DUtils_2DScaleM(D3DMATRIX *m, float sx, float sy)124{125m->_11 *= sx;126m->_22 *= sy;127}128129void130D3DUtils_2DInvertM(D3DMATRIX *m)131{132float M11, M21, M41;133float M12, M22, M42;134float det;135136M11 = m->_11; M21 = m->_21; M41 = m->_41;137M12 = m->_12; M22 = m->_22; M42 = m->_42;138det = M11 * M22 - M21 * M12;139if (fabs(det) <= 0.0000000001f) {140memset(m, 0, sizeof(D3DMATRIX));141return;142}143m->_11 = M22 / det;144m->_12 = -M12 / det;145m->_21 = -M21 / det;146m->_22 = M11 / det;147m->_41 = (M21 * M42 - M22 * M41) / det;148m->_42 = (M12 * M41 - M11 * M42) / det;149}150151void152D3DUtils_2DTranslateM(D3DMATRIX *m, float tx, float ty)153{154m->_41 = tx * m->_11 + ty * m->_21 + m->_41;155m->_42 = tx * m->_12 + ty * m->_22 + m->_42;156}157158void159D3DUtils_2DTransformXY(D3DMATRIX *m, float *px, float *py)160{161float x = *px;162float y = *py;163164*px = x * m->_11 + y * m->_21 + m->_41;165*py = x * m->_12 + y * m->_22 + m->_42;166}167168void169D3DUtils_2DInverseTransformXY(D3DMATRIX *m, float *px, float *py)170{171float x = *px, y = *py;172173x -= m->_41;174y -= m->_42;175176float det = m->_11 * m->_22 - m->_21 * m->_12;177if (fabs(det) < 0.0000000001f) {178*px = 0.0f;179*py = 0.0f;180} else {181*px = (x * m->_22 - y * m->_21) / det;182*py = (y * m->_11 - x * m->_12) / det;183}184}185186#endif // UPDATE_TX187188static void189D3DContext_DisposeShader(jlong programID)190{191IDirect3DPixelShader9 *shader =192(IDirect3DPixelShader9 *)jlong_to_ptr(programID);193194J2dTraceLn(J2D_TRACE_INFO, "D3DContext_DisposeShader");195196SAFE_RELEASE(shader);197}198199// static200HRESULT201D3DContext::CreateInstance(IDirect3D9 *pd3d9, UINT adapter, D3DContext **ppCtx)202{203HRESULT res;204*ppCtx = new D3DContext(pd3d9, adapter);205if (FAILED(res = (*ppCtx)->InitContext())) {206delete *ppCtx;207*ppCtx = NULL;208}209return res;210}211212D3DContext::D3DContext(IDirect3D9 *pd3d, UINT adapter)213{214J2dTraceLn(J2D_TRACE_INFO, "D3DContext::D3DContext");215J2dTraceLn1(J2D_TRACE_VERBOSE, " pd3d=0x%x", pd3d);216pd3dObject = pd3d;217pd3dDevice = NULL;218adapterOrdinal = adapter;219220pResourceMgr = NULL;221pMaskCache = NULL;222pVCacher = NULL;223224pSyncQuery = NULL;225pSyncRTRes = NULL;226pStateBlock = NULL;227228D3DC_INIT_SHADER_LIST(convolvePrograms, MAX_CONVOLVE);229D3DC_INIT_SHADER_LIST(rescalePrograms, MAX_RESCALE);230D3DC_INIT_SHADER_LIST(lookupPrograms, MAX_LOOKUP);231D3DC_INIT_SHADER_LIST(basicGradPrograms, 4);232D3DC_INIT_SHADER_LIST(linearGradPrograms, 8);233D3DC_INIT_SHADER_LIST(radialGradPrograms, 8);234235pLCDGlyphCache= NULL;236pGrayscaleGlyphCache= NULL;237lcdTextProgram = NULL;238aaPgramProgram = NULL;239240contextCaps = CAPS_EMPTY;241bBeginScenePending = FALSE;242243ZeroMemory(&devCaps, sizeof(D3DCAPS9));244ZeroMemory(&curParams, sizeof(curParams));245246extraAlpha = 1.0f;247}248249void D3DContext::ReleaseDefPoolResources()250{251J2dTraceLn(J2D_TRACE_INFO, "D3DContext::ReleaseDefPoolResources");252253EndScene();254255contextCaps = CAPS_EMPTY;256257SAFE_RELEASE(pSyncQuery);258SAFE_RELEASE(pStateBlock);259260if (pVCacher != NULL) {261pVCacher->ReleaseDefPoolResources();262}263if (pMaskCache != NULL) {264pMaskCache->ReleaseDefPoolResources();265}266if (pLCDGlyphCache != NULL) {267pLCDGlyphCache->ReleaseDefPoolResources();268}269if (pGrayscaleGlyphCache != NULL) {270pGrayscaleGlyphCache->ReleaseDefPoolResources();271}272if (pResourceMgr != NULL) {273if (pSyncRTRes != NULL) {274pResourceMgr->ReleaseResource(pSyncRTRes);275pSyncRTRes = NULL;276}277pResourceMgr->ReleaseDefPoolResources();278}279ZeroMemory(lastTexture, sizeof(lastTexture));280ZeroMemory(lastTextureColorState, sizeof(lastTextureColorState));281}282283void D3DContext::ReleaseContextResources()284{285J2dTraceLn1(J2D_TRACE_INFO,286"D3DContext::ReleaseContextResources: pd3dDevice = 0x%x",287pd3dDevice);288289ReleaseDefPoolResources();290291// dispose shader lists292ShaderList_Dispose(&convolvePrograms);293ShaderList_Dispose(&rescalePrograms);294ShaderList_Dispose(&lookupPrograms);295ShaderList_Dispose(&basicGradPrograms);296ShaderList_Dispose(&linearGradPrograms);297ShaderList_Dispose(&radialGradPrograms);298299SAFE_DELETE(pLCDGlyphCache);300SAFE_DELETE(pGrayscaleGlyphCache);301302SAFE_RELEASE(lcdTextProgram);303SAFE_RELEASE(aaPgramProgram);304305SAFE_DELETE(pVCacher);306SAFE_DELETE(pMaskCache);307SAFE_DELETE(pResourceMgr);308}309310D3DContext::~D3DContext() {311J2dTraceLn2(J2D_TRACE_INFO,312"~D3DContext: pd3dDevice=0x%x, pd3dObject =0x%x",313pd3dDevice, pd3dObject);314ReleaseContextResources();315SAFE_RELEASE(pd3dDevice);316}317318HRESULT319D3DContext::InitDevice(IDirect3DDevice9 *pd3dDevice)320{321HRESULT res = S_OK;322323pd3dDevice->GetDeviceCaps(&devCaps);324325J2dRlsTraceLn1(J2D_TRACE_INFO,326"D3DContext::InitDevice: device %d", adapterOrdinal);327328// disable some of the unneeded and costly d3d functionality329pd3dDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);330pd3dDevice->SetRenderState(D3DRS_SPECULARENABLE, FALSE);331pd3dDevice->SetRenderState(D3DRS_LIGHTING, FALSE);332pd3dDevice->SetRenderState(D3DRS_CLIPPING, FALSE);333pd3dDevice->SetRenderState(D3DRS_ZENABLE, D3DZB_FALSE);334pd3dDevice->SetRenderState(D3DRS_ZWRITEENABLE, D3DZB_FALSE);335pd3dDevice->SetRenderState(D3DRS_COLORVERTEX, FALSE);336pd3dDevice->SetRenderState(D3DRS_STENCILENABLE, FALSE);337338// set the default texture addressing mode339pd3dDevice->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP);340pd3dDevice->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP);341342// REMIND: check supported filters with343// IDirect3D9::CheckDeviceFormat with D3DUSAGE_QUERY_FILTER344pd3dDevice->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_POINT);345pd3dDevice->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_POINT);346347// these states never change348pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_MODULATE);349pd3dDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE);350pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE);351pd3dDevice->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE);352pd3dDevice->SetTextureStageState(1, D3DTSS_ALPHAOP, D3DTOP_MODULATE);353pd3dDevice->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_MODULATE);354pd3dDevice->SetTextureStageState(1, D3DTSS_ALPHAARG2, D3DTA_CURRENT);355pd3dDevice->SetTextureStageState(1, D3DTSS_COLORARG2, D3DTA_CURRENT);356357// init the array of latest textures358ZeroMemory(lastTexture, sizeof(lastTexture));359ZeroMemory(lastTextureColorState, sizeof(lastTextureColorState));360361opState = STATE_CHANGE;362363if (pResourceMgr == NULL) {364res = D3DResourceManager::CreateInstance(this, &pResourceMgr);365} else {366res = pResourceMgr->Init(this);367}368RETURN_STATUS_IF_FAILED(res);369370if (pVCacher == NULL) {371res = D3DVertexCacher::CreateInstance(this, &pVCacher);372} else {373res = pVCacher->Init(this);374}375RETURN_STATUS_IF_FAILED(res);376377if (pMaskCache == NULL) {378res = D3DMaskCache::CreateInstance(this, &pMaskCache);379} else{380res = pMaskCache->Init(this);381}382RETURN_STATUS_IF_FAILED(res);383384if (pLCDGlyphCache != NULL) {385if (FAILED(res = pLCDGlyphCache->Init(this))) {386// we can live without the cache387SAFE_DELETE(pLCDGlyphCache);388res = S_OK;389}390}391392if (pGrayscaleGlyphCache != NULL) {393if (FAILED(res = pGrayscaleGlyphCache->Init(this))) {394// we can live without the cache395SAFE_DELETE(pGrayscaleGlyphCache);396res = S_OK;397}398}399400D3DMATRIX tx;401D3DUtils_SetIdentityMatrix(&tx);402pd3dDevice->SetTransform(D3DTS_WORLD, &tx);403bIsIdentityTx = TRUE;404405if (pSyncQuery == NULL) {406// this is allowed to fail, do not propagate the error407if (FAILED(pd3dDevice->CreateQuery(D3DQUERYTYPE_EVENT, &pSyncQuery))) {408J2dRlsTraceLn(J2D_TRACE_WARNING,409"D3DContext::InitDevice: sync query not available");410pSyncQuery = NULL;411}412}413if (pSyncRTRes == NULL) {414D3DFORMAT format;415if (FAILED(GetResourceManager()->416CreateRTSurface(32, 32, TRUE, TRUE, &format, &pSyncRTRes))) {417J2dRlsTraceLn(J2D_TRACE_WARNING,418"D3DContext::InitDevice: "419"error creating sync surface");420}421}422423bBeginScenePending = FALSE;424425J2dRlsTraceLn1(J2D_TRACE_INFO,426"D3DContext::InitDefice: successfully initialized device %d",427adapterOrdinal);428429return res;430}431432HRESULT433D3DContext::CheckAndResetDevice()434{435HRESULT res = E_FAIL;436437J2dTraceLn(J2D_TRACE_INFO, "D3DContext::CheckAndResetDevice");438439if (pd3dDevice != NULL) {440if (FAILED(res = pd3dDevice->TestCooperativeLevel())) {441if (res == D3DERR_DEVICELOST) {442J2dTraceLn1(J2D_TRACE_VERBOSE, " device %d is still lost",443adapterOrdinal);444// nothing to be done here, wait for D3DERR_DEVICENOTRESET445return res;446} else if (res == D3DERR_DEVICENOTRESET) {447J2dTraceLn1(J2D_TRACE_VERBOSE, " device %d needs to be reset",448adapterOrdinal);449res = ResetContext();450} else {451// some unexpected error452DebugPrintD3DError(res, "D3DContext::CheckAndResetDevice: "\453"unknown error %x from TestCooperativeLevel");454}455} else {456J2dTraceLn1(J2D_TRACE_VERBOSE, " device %d is not lost",457adapterOrdinal);458}459} else {460J2dTraceLn(J2D_TRACE_VERBOSE, " null device");461}462return res;463}464465HRESULT466D3DContext::ResetContext()467{468HRESULT res = E_FAIL;469470J2dRlsTraceLn(J2D_TRACE_INFO, "D3DContext::ResetContext");471if (pd3dDevice != NULL) {472D3DPRESENT_PARAMETERS newParams;473474newParams = curParams;475476if (newParams.Windowed) {477// reset to the current display mode if we're windowed,478// otherwise to the display mode we were in when the device479// was lost480newParams.BackBufferFormat = D3DFMT_UNKNOWN;481newParams.FullScreen_RefreshRateInHz = 0;482newParams.BackBufferWidth = 0;483newParams.BackBufferHeight = 0;484}485res = ConfigureContext(&newParams);486}487return res;488}489490HRESULT491D3DContext::ConfigureContext(D3DPRESENT_PARAMETERS *pNewParams)492{493J2dRlsTraceLn1(J2D_TRACE_INFO, "D3DContext::ConfigureContext device %d",494adapterOrdinal);495HRESULT res = S_OK;496D3DFORMAT stencilFormat;497HWND focusHWND = D3DPipelineManager::GetInstance()->GetCurrentFocusWindow();498D3DDEVTYPE devType = D3DPipelineManager::GetInstance()->GetDeviceType();499// this is needed so that we can find the stencil buffer format500if (pNewParams->BackBufferFormat == D3DFMT_UNKNOWN) {501D3DDISPLAYMODE dm;502503pd3dObject->GetAdapterDisplayMode(adapterOrdinal, &dm);504pNewParams->BackBufferFormat = dm.Format;505}506507stencilFormat =508D3DPipelineManager::GetInstance()->GetMatchingDepthStencilFormat(509adapterOrdinal,510pNewParams->BackBufferFormat, pNewParams->BackBufferFormat);511512pNewParams->EnableAutoDepthStencil = TRUE;513pNewParams->AutoDepthStencilFormat = stencilFormat;514515// do not set device window in the windowed mode, we use additional516// swap chains for rendering, the default chain is not used. otherwise517// our scratch focus window will be made visible518J2dTraceLn1(J2D_TRACE_VERBOSE, " windowed=%d",pNewParams->Windowed);519if (pNewParams->Windowed) {520pNewParams->hDeviceWindow = (HWND)0;521}522523// The focus window may change when we're entering/exiting the full-screen524// mode. It may either be set to the default focus window (when there are525// no more devices in fs mode), or to fs window for another device526// in fs mode. See D3DPipelineManager::GetCurrentFocusWindow.527if (pd3dDevice != NULL) {528D3DDEVICE_CREATION_PARAMETERS cParams;529pd3dDevice->GetCreationParameters(&cParams);530if (cParams.hFocusWindow != focusHWND) {531J2dTraceLn(J2D_TRACE_VERBOSE,532" focus window changed, need to recreate the device");533534// if fs -> windowed, first exit fs, then recreate, otherwise535// the screen might be left in a different display mode536if (pNewParams->Windowed && !curParams.Windowed) {537J2dTraceLn(J2D_TRACE_VERBOSE,538" exiting full-screen mode, reset the device");539curParams.Windowed = FALSE;540ReleaseDefPoolResources();541res = pd3dDevice->Reset(&curParams);542543if (FAILED(res)) {544DebugPrintD3DError(res, "D3DContext::ConfigureContext: "\545"cound not reset the device");546}547}548549// note that here we should release all device resources, not only550// thos in the default pool since the device is released551ReleaseContextResources();552SAFE_RELEASE(pd3dDevice);553}554}555556if (pd3dDevice != NULL) {557J2dTraceLn(J2D_TRACE_VERBOSE, " resetting the device");558559ReleaseDefPoolResources();560561if (pNewParams->PresentationInterval == D3DPRESENT_INTERVAL_IMMEDIATE &&562!IsImmediateIntervalSupported())563{564pNewParams->PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT;565}566567res = pd3dDevice->Reset(pNewParams);568if (FAILED(res)) {569DebugPrintD3DError(res,570"D3DContext::ConfigureContext: cound not reset the device");571return res;572}573J2dRlsTraceLn1(J2D_TRACE_INFO,574"D3DContext::ConfigureContext: successfully reset device: %d",575adapterOrdinal);576} else {577D3DCAPS9 d3dCaps;578DWORD dwBehaviorFlags;579580J2dTraceLn(J2D_TRACE_VERBOSE, " creating a new device");581582if (FAILED(res = pd3dObject->GetDeviceCaps(adapterOrdinal,583devType, &d3dCaps)))584{585DebugPrintD3DError(res,586"D3DContext::ConfigureContext: failed to get caps");587return res;588}589590if (pNewParams->PresentationInterval == D3DPRESENT_INTERVAL_IMMEDIATE &&591!(d3dCaps.PresentationIntervals & D3DPRESENT_INTERVAL_IMMEDIATE))592{593pNewParams->PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT;594}595596// not preserving fpu control word could cause issues (4860749)597dwBehaviorFlags = D3DCREATE_FPU_PRESERVE;598599J2dRlsTrace(J2D_TRACE_VERBOSE,600"[V] dwBehaviorFlags=D3DCREATE_FPU_PRESERVE|");601if (d3dCaps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT) {602J2dRlsTrace(J2D_TRACE_VERBOSE,603"D3DCREATE_HARDWARE_VERTEXPROCESSING");604dwBehaviorFlags |= D3DCREATE_HARDWARE_VERTEXPROCESSING;605} else {606J2dRlsTrace(J2D_TRACE_VERBOSE,607"D3DCREATE_SOFTWARE_VERTEXPROCESSING");608dwBehaviorFlags |= D3DCREATE_SOFTWARE_VERTEXPROCESSING;609}610// Handling focus changes by ourselves proved to be problematic,611// so we're reverting back to D3D handling612// dwBehaviorFlags |= D3DCREATE_NOWINDOWCHANGES;613J2dRlsTrace(J2D_TRACE_VERBOSE,"\n");614615if (FAILED(res = pd3dObject->CreateDevice(adapterOrdinal, devType,616focusHWND,617dwBehaviorFlags,618pNewParams, &pd3dDevice)))619{620DebugPrintD3DError(res,621"D3DContext::ConfigureContext: error creating d3d device");622return res;623}624J2dRlsTraceLn1(J2D_TRACE_INFO,625"D3DContext::ConfigureContext: successfully created device: %d",626adapterOrdinal);627bIsHWRasterizer = (devType == D3DDEVTYPE_HAL);628}629630curParams = *pNewParams;631// during the creation of the device d3d modifies this field, we reset632// it back to 0633curParams.Flags = 0;634635if (FAILED(res = InitDevice(pd3dDevice))) {636ReleaseContextResources();637return res;638}639640res = InitContextCaps();641642return res;643}644645HRESULT646D3DContext::InitContext()647{648J2dRlsTraceLn1(J2D_TRACE_INFO, "D3DContext::InitContext device %d",649adapterOrdinal);650651D3DPRESENT_PARAMETERS params;652ZeroMemory(¶ms, sizeof(D3DPRESENT_PARAMETERS));653654params.hDeviceWindow = 0;655params.Windowed = TRUE;656params.BackBufferCount = 1;657params.BackBufferFormat = D3DFMT_UNKNOWN;658params.SwapEffect = D3DSWAPEFFECT_DISCARD;659params.PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT;660661return ConfigureContext(¶ms);662}663664HRESULT665D3DContext::Sync()666{667HRESULT res = S_OK;668669J2dTraceLn(J2D_TRACE_INFO, "D3DContext::Sync");670671if (pSyncQuery != NULL) {672J2dTrace(J2D_TRACE_VERBOSE, " flushing the device queue..");673while (S_FALSE ==674(res = pSyncQuery->GetData(NULL, 0, D3DGETDATA_FLUSH))) ;675J2dTrace(J2D_TRACE_VERBOSE, ".. done\n");676}677if (pSyncRTRes != NULL) {678D3DLOCKED_RECT lr;679IDirect3DSurface9 *pSurface = pSyncRTRes->GetSurface();680if (SUCCEEDED(pSurface->LockRect(&lr, NULL, D3DLOCK_NOSYSLOCK))) {681pSurface->UnlockRect();682}683}684return res;685}686687#define POINT_FILTER_CAP (D3DPTFILTERCAPS_MAGFPOINT|D3DPTFILTERCAPS_MINFPOINT)688#define LINEAR_FILTER_CAP (D3DPTFILTERCAPS_MAGFLINEAR|D3DPTFILTERCAPS_MINFLINEAR)689690BOOL691D3DContext::IsStretchRectFilteringSupported(D3DTEXTUREFILTERTYPE fType)692{693if (fType == D3DTEXF_POINT) {694return ((devCaps.StretchRectFilterCaps & POINT_FILTER_CAP) != 0);695}696if (fType == D3DTEXF_LINEAR) {697return ((devCaps.StretchRectFilterCaps & LINEAR_FILTER_CAP) != 0);698}699return FALSE;700}701702BOOL703D3DContext::IsTextureFilteringSupported(D3DTEXTUREFILTERTYPE fType)704{705if (fType == D3DTEXF_POINT) {706return ((devCaps.TextureFilterCaps & POINT_FILTER_CAP) != 0);707}708if (fType == D3DTEXF_LINEAR) {709return ((devCaps.TextureFilterCaps & LINEAR_FILTER_CAP) != 0);710}711return FALSE;712}713714BOOL715D3DContext::IsTextureFormatSupported(D3DFORMAT format, DWORD usage)716{717HRESULT hr = pd3dObject->CheckDeviceFormat(adapterOrdinal,718devCaps.DeviceType,719curParams.BackBufferFormat,720usage,721D3DRTYPE_TEXTURE,722format);723return SUCCEEDED( hr );724}725726BOOL727D3DContext::IsDepthStencilBufferOk(D3DSURFACE_DESC *pTargetDesc)728{729IDirect3DSurface9 *pStencil;730J2dTraceLn(J2D_TRACE_INFO, "D3DContext::IsDepthStencilBufferOk");731732if (SUCCEEDED(pd3dDevice->GetDepthStencilSurface(&pStencil))) {733D3DSURFACE_DESC descStencil;734pStencil->GetDesc(&descStencil);735pStencil->Release();736737D3DDISPLAYMODE dm;738return739(SUCCEEDED(pd3dDevice->GetDisplayMode(0, &dm)) &&740pTargetDesc->Width <= descStencil.Width &&741pTargetDesc->Height <= descStencil.Height &&742SUCCEEDED(pd3dObject->CheckDepthStencilMatch(743adapterOrdinal,744devCaps.DeviceType,745dm.Format, pTargetDesc->Format,746descStencil.Format)));747}748J2dTraceLn(J2D_TRACE_VERBOSE,749" current stencil buffer is not compatible with new Render Target");750751return false;752}753754755756HRESULT757D3DContext::InitDepthStencilBuffer(D3DSURFACE_DESC *pTargetDesc)758{759HRESULT res;760IDirect3DSurface9 *pBB;761D3DDISPLAYMODE dm;762763J2dTraceLn(J2D_TRACE_INFO, "D3DContext::InitDepthStencilBuffer");764765if (FAILED(res = pd3dDevice->GetDisplayMode(0, &dm))) {766return res;767}768769D3DFORMAT newFormat =770D3DPipelineManager::GetInstance()->GetMatchingDepthStencilFormat(771adapterOrdinal, dm.Format, pTargetDesc->Format);772773res = pd3dDevice->CreateDepthStencilSurface(774pTargetDesc->Width, pTargetDesc->Height,775newFormat, D3DMULTISAMPLE_NONE, 0, false, &pBB, 0);776if (SUCCEEDED(res)) {777res = pd3dDevice->SetDepthStencilSurface(pBB);778pBB->Release();779}780781return res;782}783784785HRESULT786D3DContext::SetRenderTarget(IDirect3DSurface9 *pSurface)787{788static D3DMATRIX tx;789HRESULT res;790D3DSURFACE_DESC descNew;791IDirect3DSurface9 *pCurrentTarget;792793J2dTraceLn1(J2D_TRACE_INFO,794"D3DContext::SetRenderTarget: pSurface=0x%x",795pSurface);796797RETURN_STATUS_IF_NULL(pd3dDevice, E_FAIL);798RETURN_STATUS_IF_NULL(pSurface, E_FAIL);799800pSurface->GetDesc(&descNew);801802if (SUCCEEDED(res = pd3dDevice->GetRenderTarget(0, &pCurrentTarget))) {803if (pCurrentTarget != pSurface) {804FlushVertexQueue();805if (FAILED(res = pd3dDevice->SetRenderTarget(0, pSurface))) {806DebugPrintD3DError(res, "D3DContext::SetRenderTarget: "\807"error setting render target");808SAFE_RELEASE(pCurrentTarget);809return res;810}811812if (!IsDepthStencilBufferOk(&descNew)) {813if (FAILED(res = InitDepthStencilBuffer(&descNew))) {814SAFE_RELEASE(pCurrentTarget);815return res;816}817}818}819SAFE_RELEASE(pCurrentTarget);820}821// we set the transform even if the render target didn't change;822// this is because in some cases (fs mode) we use the default SwapChain of823// the device, and its render target will be the same as the device's, and824// we have to set the matrix correctly. This shouldn't be a performance825// issue as render target changes are relatively rare826D3DUtils_SetOrthoMatrixOffCenterLH(&tx,827(float)descNew.Width,828(float)descNew.Height);829pd3dDevice->SetTransform(D3DTS_PROJECTION, &tx);830831J2dTraceLn1(J2D_TRACE_VERBOSE, " current render target=0x%x", pSurface);832return res;833}834835HRESULT836D3DContext::ResetTransform()837{838HRESULT res = S_OK;839D3DMATRIX tx;840841J2dTraceLn(J2D_TRACE_INFO, "D3DContext::ResetTransform");842if (pd3dDevice == NULL) {843return E_FAIL;844}845846// no need for state change, just flush the queue847FlushVertexQueue();848849D3DUtils_SetIdentityMatrix(&tx);850if (FAILED(res = pd3dDevice->SetTransform(D3DTS_WORLD, &tx))) {851DebugPrintD3DError(res, "D3DContext::SetTransform failed");852}853bIsIdentityTx = TRUE;854return res;855}856857HRESULT858D3DContext::SetTransform(jdouble m00, jdouble m10,859jdouble m01, jdouble m11,860jdouble m02, jdouble m12)861{862HRESULT res = S_OK;863D3DMATRIX tx, tx1;864865J2dTraceLn(J2D_TRACE_INFO, "D3DContext::SetTransform");866if (pd3dDevice == NULL) {867return E_FAIL;868}869870// no need for state change, just flush the queue871FlushVertexQueue();872873// In order to correctly map texels to pixels we need to874// adjust geometry by -0.5f in the transformed space.875// In order to do that we first create a translated matrix876// and then concatenate it with the world transform.877//878// Note that we only use non-id transform with DrawTexture,879// the rest is rendered pre-transformed.880//881// The identity transform for textures is handled in882// D3DVertexCacher::DrawTexture() because shifting by -0.5 for id883// transform breaks lines rendering.884885ZeroMemory(&tx1, sizeof(D3DMATRIX));886887tx1._11 = (float)m00;888tx1._12 = (float)m10;889tx1._21 = (float)m01;890tx1._22 = (float)m11;891tx1._41 = (float)m02;892tx1._42 = (float)m12;893894tx1._33 = 1.0f;895tx1._44 = 1.0f;896897D3DUtils_SetIdentityMatrix(&tx);898tx._41 = -0.5f;899tx._42 = -0.5f;900D3DUtils_2DConcatenateM(&tx, &tx1);901902J2dTraceLn4(J2D_TRACE_VERBOSE,903" %5f %5f %5f %5f", tx._11, tx._12, tx._13, tx._14);904J2dTraceLn4(J2D_TRACE_VERBOSE,905" %5f %5f %5f %5f", tx._21, tx._22, tx._23, tx._24);906J2dTraceLn4(J2D_TRACE_VERBOSE,907" %5f %5f %5f %5f", tx._31, tx._32, tx._33, tx._34);908J2dTraceLn4(J2D_TRACE_VERBOSE,909" %5f %5f %5f %5f", tx._41, tx._42, tx._43, tx._44);910if (FAILED(res = pd3dDevice->SetTransform(D3DTS_WORLD, &tx))) {911DebugPrintD3DError(res, "D3DContext::SetTransform failed");912}913bIsIdentityTx = FALSE;914915return res;916}917918HRESULT919D3DContext::SetRectClip(int x1, int y1, int x2, int y2)920{921HRESULT res = S_OK;922D3DSURFACE_DESC desc;923IDirect3DSurface9 *pCurrentTarget;924925J2dTraceLn(J2D_TRACE_INFO, "D3DContext::SetRectClip");926J2dTraceLn4(J2D_TRACE_VERBOSE,927" x1=%-4d y1=%-4d x2=%-4d y2=%-4d",928x1, y1, x2, y2);929930RETURN_STATUS_IF_NULL(pd3dDevice, E_FAIL);931932// no need for state change, just flush the queue933FlushVertexQueue();934935pd3dDevice->SetRenderState(D3DRS_ZENABLE, D3DZB_FALSE);936937res = pd3dDevice->GetRenderTarget(0, &pCurrentTarget);938RETURN_STATUS_IF_FAILED(res);939940pCurrentTarget->GetDesc(&desc);941SAFE_RELEASE(pCurrentTarget);942943if (x1 <= 0 && y1 <= 0 &&944(UINT)x2 >= desc.Width && (UINT)y2 >= desc.Height)945{946J2dTraceLn(J2D_TRACE_VERBOSE,947" disabling clip (== render target dimensions)");948return pd3dDevice->SetRenderState(D3DRS_SCISSORTESTENABLE, FALSE);949}950951// clip to the dimensions of the target surface, otherwise952// SetScissorRect will fail953if (x1 < 0) x1 = 0;954if (y1 < 0) y1 = 0;955if ((UINT)x2 > desc.Width) x2 = desc.Width;956if ((UINT)y2 > desc.Height) y2 = desc.Height;957if (x1 > x2) x2 = x1 = 0;958if (y1 > y2) y2 = y1 = 0;959RECT newRect = { x1, y1, x2, y2 };960if (SUCCEEDED(res = pd3dDevice->SetScissorRect(&newRect))) {961res = pd3dDevice->SetRenderState(D3DRS_SCISSORTESTENABLE, TRUE);962} else {963DebugPrintD3DError(res, "Error setting scissor rect");964J2dRlsTraceLn4(J2D_TRACE_ERROR,965" x1=%-4d y1=%-4d x2=%-4d y2=%-4d",966x1, y1, x2, y2);967}968969return res;970}971972HRESULT973D3DContext::ResetClip()974{975J2dTraceLn(J2D_TRACE_INFO, "D3DContext::ResetClip");976// no need for state change, just flush the queue977FlushVertexQueue();978pd3dDevice->SetRenderState(D3DRS_SCISSORTESTENABLE, FALSE);979return pd3dDevice->SetRenderState(D3DRS_ZENABLE, D3DZB_FALSE);980}981982ClipType983D3DContext::GetClipType()984{985// REMIND: this method could be optimized: we could keep the986// clip state around when re/setting the clip instead of asking987// every time.988DWORD zEnabled = 0;989DWORD stEnabled = 0;990991J2dTraceLn(J2D_TRACE_INFO, "D3DContext::GetClipType");992pd3dDevice->GetRenderState(D3DRS_SCISSORTESTENABLE, &stEnabled);993if (stEnabled) {994return CLIP_RECT;995}996pd3dDevice->GetRenderState(D3DRS_ZENABLE, &zEnabled);997if (zEnabled) {998return CLIP_SHAPE;999}1000return CLIP_NONE;1001}100210031004/**1005* This method assumes that ::SetRenderTarget has already1006* been called. SetRenderTarget creates and attaches a1007* depth buffer to the target surface prior to setting it1008* as target surface to the device.1009*/1010DWORD dwAlphaSt, dwSrcBlendSt, dwDestBlendSt;1011D3DMATRIX tx, idTx;10121013HRESULT1014D3DContext::BeginShapeClip()1015{1016HRESULT res = S_OK;1017J2dTraceLn(J2D_TRACE_INFO, "D3DContext::BeginShapeClip");10181019UpdateState(STATE_CHANGE);10201021pd3dDevice->SetRenderState(D3DRS_SCISSORTESTENABLE, FALSE);10221023// save alpha blending state1024pd3dDevice->GetRenderState(D3DRS_ALPHABLENDENABLE, &dwAlphaSt);1025pd3dDevice->GetRenderState(D3DRS_SRCBLEND, &dwSrcBlendSt);1026pd3dDevice->GetRenderState(D3DRS_DESTBLEND, &dwDestBlendSt);10271028pd3dDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);1029pd3dDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ZERO);1030pd3dDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_ONE);10311032pd3dDevice->GetTransform(D3DTS_WORLD, &tx);1033D3DUtils_SetIdentityMatrix(&idTx);1034// translate the clip spans by 1.0f in z direction so that the1035// clip spans are rendered to the z buffer1036idTx._43 = 1.0f;1037pd3dDevice->SetTransform(D3DTS_WORLD, &idTx);10381039// The depth buffer is first cleared with zeroes, which is the farthest1040// plane from the viewer (our projection matrix is an inversed orthogonal1041// transform).1042// To set the clip we'll render the clip spans with Z coordinates of 1.0f1043// (the closest to the viewer). Since all rendering primitives1044// have their vertices' Z coordinate set to 0.0, they will effectively be1045// clipped because the Z depth test for them will fail (vertex with 1.01046// depth is closer than the one with 0.0f)1047pd3dDevice->SetRenderState(D3DRS_ZENABLE, D3DZB_TRUE);1048pd3dDevice->SetRenderState(D3DRS_ZWRITEENABLE, TRUE);1049pd3dDevice->SetRenderState(D3DRS_ZFUNC, D3DCMP_ALWAYS);1050pd3dDevice->Clear(0, NULL, D3DCLEAR_ZBUFFER, 0L, 0.0f, 0x0L);10511052//res = BeginScene(STATE_SHAPE_CLIPOP);10531054return res;1055}10561057HRESULT1058D3DContext::EndShapeClip()1059{1060HRESULT res;10611062// no need for state change, just flush the queue1063res = FlushVertexQueue();10641065// restore alpha blending state1066pd3dDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, dwAlphaSt);1067pd3dDevice->SetRenderState(D3DRS_SRCBLEND, dwSrcBlendSt);1068pd3dDevice->SetRenderState(D3DRS_DESTBLEND, dwDestBlendSt);10691070// resore the transform1071pd3dDevice->SetTransform(D3DTS_WORLD, &tx);10721073// Enable the depth buffer.1074// We disable further updates to the depth buffer: it should only1075// be updated in SetClip method.1076pd3dDevice->SetRenderState(D3DRS_ZWRITEENABLE, FALSE);1077pd3dDevice->SetRenderState(D3DRS_ZFUNC, D3DCMP_LESS);10781079return res;1080}10811082HRESULT1083D3DContext::UploadTileToTexture(D3DResource *pTextureRes, void *pixels,1084jint dstx, jint dsty,1085jint srcx, jint srcy,1086jint srcWidth, jint srcHeight,1087jint srcStride,1088TileFormat srcFormat,1089jint *pPixelsTouchedL,1090jint* pPixelsTouchedR)1091{1092#ifndef PtrAddBytes1093#define PtrAddBytes(p, b) ((void *) (((intptr_t) (p)) + (b)))1094#define PtrCoord(p, x, xinc, y, yinc) PtrAddBytes(p, \1095((ptrdiff_t)(y))*(yinc) + \1096((ptrdiff_t)(x))*(xinc))1097#endif // PtrAddBytes10981099HRESULT res = S_OK;1100IDirect3DTexture9 *pTexture = pTextureRes->GetTexture();1101D3DSURFACE_DESC *pDesc = pTextureRes->GetDesc();1102RECT r = { dstx, dsty, dstx+srcWidth, dsty+srcHeight };1103RECT *pR = &r;1104D3DLOCKED_RECT lockedRect;1105DWORD dwLockFlags = D3DLOCK_NOSYSLOCK;1106// these are only counted for LCD glyph uploads1107jint pixelsTouchedL = 0, pixelsTouchedR = 0;11081109J2dTraceLn(J2D_TRACE_INFO, "D3DContext::UploadTileToTexture");1110J2dTraceLn4(J2D_TRACE_VERBOSE,1111" rect={%-4d, %-4d, %-4d, %-4d}",1112r.left, r.top, r.right, r.bottom);11131114if (pDesc->Usage == D3DUSAGE_DYNAMIC) {1115// it is safe to lock with discard because we don't care about the1116// contents of dynamic textures and dstx,dsty for this case is1117// always 0,0 because we are uploading into a tile texture1118dwLockFlags |= D3DLOCK_DISCARD;1119pR = NULL;1120}11211122if (FAILED(res = pTexture->LockRect(0, &lockedRect, pR, dwLockFlags))) {1123DebugPrintD3DError(res,1124"D3DContext::UploadImageToTexture: could "\1125"not lock texture");1126return res;1127}11281129if (srcFormat == TILEFMT_1BYTE_ALPHA) {1130// either a MaskFill tile, or a grayscale glyph1131if (pDesc->Format == D3DFMT_A8) {1132void *pSrcPixels = PtrCoord(pixels, srcx, 1, srcy, srcStride);1133void *pDstPixels = lockedRect.pBits;1134do {1135memcpy(pDstPixels, pSrcPixels, srcWidth);1136pSrcPixels = PtrAddBytes(pSrcPixels, srcStride);1137pDstPixels = PtrAddBytes(pDstPixels, lockedRect.Pitch);1138} while (--srcHeight > 0);1139}1140else if (pDesc->Format == D3DFMT_A8R8G8B8) {1141jubyte *pSrcPixels = (jubyte*)1142PtrCoord(pixels, srcx, 1, srcy, srcStride);1143jint *pDstPixels = (jint*)lockedRect.pBits;1144for (int yy = 0; yy < srcHeight; yy++) {1145for (int xx = 0; xx < srcWidth; xx++) {1146// only need to set the alpha channel (the D3D texture1147// state will be setup in this case to replicate the1148// alpha channel as needed)1149pDstPixels[xx] = pSrcPixels[xx] << 24;1150}1151pSrcPixels = (jubyte*)PtrAddBytes(pSrcPixels, srcStride);1152pDstPixels = (jint*)PtrAddBytes(pDstPixels, lockedRect.Pitch);1153}1154}1155} else if (srcFormat == TILEFMT_3BYTE_RGB) {1156// LCD glyph with RGB order1157if (pDesc->Format == D3DFMT_R8G8B8) {1158jubyte *pSrcPixels = (jubyte*)1159PtrCoord(pixels, srcx, 3, srcy, srcStride);1160jubyte *pDstPixels = (jubyte*)lockedRect.pBits;1161for (int yy = 0; yy < srcHeight; yy++) {1162for (int xx = 0; xx < srcWidth*3; xx+=3) {1163// alpha channel is ignored in this case1164// (note that this is backwards from what one might1165// expect; it appears that D3DFMT_R8G8B8 is actually1166// laid out in BGR order in memory)1167pDstPixels[xx+0] = pSrcPixels[xx+2];1168pDstPixels[xx+1] = pSrcPixels[xx+1];1169pDstPixels[xx+2] = pSrcPixels[xx+0];1170}1171pixelsTouchedL +=1172(pDstPixels[0+0]|pDstPixels[0+1]|pDstPixels[0+2]) ? 1 : 0;1173jint i = 3*(srcWidth-1);1174pixelsTouchedR +=1175(pDstPixels[i+0]|pDstPixels[i+1]|pDstPixels[i+2]) ? 1 : 0;11761177pSrcPixels = (jubyte*)PtrAddBytes(pSrcPixels, srcStride);1178pDstPixels = (jubyte*)PtrAddBytes(pDstPixels, lockedRect.Pitch);1179}1180}1181else if (pDesc->Format == D3DFMT_A8R8G8B8) {1182jubyte *pSrcPixels = (jubyte*)1183PtrCoord(pixels, srcx, 3, srcy, srcStride);1184jint *pDstPixels = (jint*)lockedRect.pBits;1185for (int yy = 0; yy < srcHeight; yy++) {1186for (int dx = 0, sx = 0; dx < srcWidth; dx++, sx+=3) {1187// alpha channel is ignored in this case1188jubyte r = pSrcPixels[sx+0];1189jubyte g = pSrcPixels[sx+1];1190jubyte b = pSrcPixels[sx+2];1191pDstPixels[dx] = (r << 16) | (g << 8) | (b);1192}1193pixelsTouchedL += (pDstPixels[0] ? 1 : 0);1194pixelsTouchedR += (pDstPixels[srcWidth-1] ? 1 : 0);11951196pSrcPixels = (jubyte*)PtrAddBytes(pSrcPixels, srcStride);1197pDstPixels = (jint*)PtrAddBytes(pDstPixels, lockedRect.Pitch);1198}1199}1200} else if (srcFormat == TILEFMT_3BYTE_BGR) {1201// LCD glyph with BGR order1202if (pDesc->Format == D3DFMT_R8G8B8) {1203void *pSrcPixels = PtrCoord(pixels, srcx, 3, srcy, srcStride);1204void *pDstPixels = lockedRect.pBits;1205jubyte *pbDst;1206do {1207// alpha channel is ignored in this case1208// (note that this is backwards from what one might1209// expect; it appears that D3DFMT_R8G8B8 is actually1210// laid out in BGR order in memory)1211memcpy(pDstPixels, pSrcPixels, srcWidth * 3);12121213pbDst = (jubyte*)pDstPixels;1214pixelsTouchedL +=(pbDst[0+0]|pbDst[0+1]|pbDst[0+2]) ? 1 : 0;1215jint i = 3*(srcWidth-1);1216pixelsTouchedR +=(pbDst[i+0]|pbDst[i+1]|pbDst[i+2]) ? 1 : 0;12171218pSrcPixels = PtrAddBytes(pSrcPixels, srcStride);1219pDstPixels = PtrAddBytes(pDstPixels, lockedRect.Pitch);1220} while (--srcHeight > 0);1221}1222else if (pDesc->Format == D3DFMT_A8R8G8B8) {1223jubyte *pSrcPixels = (jubyte*)1224PtrCoord(pixels, srcx, 3, srcy, srcStride);1225jint *pDstPixels = (jint*)lockedRect.pBits;1226for (int yy = 0; yy < srcHeight; yy++) {1227for (int dx = 0, sx = 0; dx < srcWidth; dx++, sx+=3) {1228// alpha channel is ignored in this case1229jubyte b = pSrcPixels[sx+0];1230jubyte g = pSrcPixels[sx+1];1231jubyte r = pSrcPixels[sx+2];1232pDstPixels[dx] = (r << 16) | (g << 8) | (b);1233}1234pixelsTouchedL += (pDstPixels[0] ? 1 : 0);1235pixelsTouchedR += (pDstPixels[srcWidth-1] ? 1 : 0);12361237pSrcPixels = (jubyte*)PtrAddBytes(pSrcPixels, srcStride);1238pDstPixels = (jint*)PtrAddBytes(pDstPixels, lockedRect.Pitch);1239}1240}1241} else if (srcFormat == TILEFMT_4BYTE_ARGB_PRE) {1242// MaskBlit tile1243if (pDesc->Format == D3DFMT_A8R8G8B8) {1244void *pSrcPixels = PtrCoord(pixels, srcx, 4, srcy, srcStride);1245void *pDstPixels = lockedRect.pBits;1246do {1247memcpy(pDstPixels, pSrcPixels, srcWidth * 4);1248pSrcPixels = PtrAddBytes(pSrcPixels, srcStride);1249pDstPixels = PtrAddBytes(pDstPixels, lockedRect.Pitch);1250} while (--srcHeight > 0);1251}1252} else {1253// should not happen, no-op just in case...1254}12551256if (pPixelsTouchedL) {1257*pPixelsTouchedL = pixelsTouchedL;1258}1259if (pPixelsTouchedR) {1260*pPixelsTouchedR = pixelsTouchedR;1261}12621263return pTexture->UnlockRect(0);1264}12651266HRESULT1267D3DContext::InitLCDGlyphCache()1268{1269if (pLCDGlyphCache == NULL) {1270return D3DGlyphCache::CreateInstance(this, CACHE_LCD, &pLCDGlyphCache);1271}1272return S_OK;1273}12741275HRESULT1276D3DContext::InitGrayscaleGlyphCache()1277{1278if (pGrayscaleGlyphCache == NULL) {1279return D3DGlyphCache::CreateInstance(this, CACHE_GRAY,1280&pGrayscaleGlyphCache);1281}1282return S_OK;1283}12841285HRESULT1286D3DContext::ResetComposite()1287{1288J2dTraceLn(J2D_TRACE_INFO, "D3DContext::ResetComposite");12891290RETURN_STATUS_IF_NULL(pd3dDevice, E_FAIL);12911292HRESULT res = UpdateState(STATE_CHANGE);1293pd3dDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE);1294extraAlpha = 1.0f;1295return res;1296}12971298HRESULT1299D3DContext::SetAlphaComposite(jint rule, jfloat ea, jint flags)1300{1301HRESULT res;1302J2dTraceLn3(J2D_TRACE_INFO,1303"D3DContext::SetAlphaComposite: rule=%-1d ea=%f flags=%d",1304rule, ea, flags);13051306RETURN_STATUS_IF_NULL(pd3dDevice, E_FAIL);13071308res = UpdateState(STATE_CHANGE);13091310// we can safely disable blending when:1311// - comp is SrcNoEa or SrcOverNoEa, and1312// - the source is opaque1313// (turning off blending can have a large positive impact on performance)1314if ((rule == RULE_Src || rule == RULE_SrcOver) &&1315(ea == 1.0f) &&1316(flags & D3DC_SRC_IS_OPAQUE))1317{1318J2dTraceLn1(J2D_TRACE_VERBOSE,1319" disabling alpha comp rule=%-1d ea=1.0 src=opq)", rule);1320pd3dDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE);1321} else {1322J2dTraceLn2(J2D_TRACE_VERBOSE,1323" enabling alpha comp (rule=%-1d ea=%f)", rule, ea);1324pd3dDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);13251326pd3dDevice->SetRenderState(D3DRS_SRCBLEND,1327StdBlendRules[rule].src);1328pd3dDevice->SetRenderState(D3DRS_DESTBLEND,1329StdBlendRules[rule].dst);1330}13311332extraAlpha = ea;1333return res;1334}13351336#ifdef UPDATE_TX13371338// Note: this method of adjusting pixel to texel mapping proved to be1339// difficult to perfect. The current variation works great for id,1340// scale (including all kinds of flips) transforms, but not still not1341// for generic transforms.1342//1343// Since we currently only do DrawTexture with non-id transform we instead1344// adjust the geometry (see D3DVertexCacher::DrawTexture(), SetTransform())1345//1346// In order to enable this code path UpdateTextureTransforms needs to1347// be called in SetTexture(), SetTransform() and ResetTranform().1348HRESULT1349D3DContext::UpdateTextureTransforms(DWORD dwSamplerToUpdate)1350{1351HRESULT res = S_OK;1352DWORD dwSampler, dwMaxSampler;13531354if (dwSamplerToUpdate == -1) {1355// update all used samplers, dwMaxSampler will be set to max1356dwSampler = 0;1357dwSampler = MAX_USED_TEXTURE_SAMPLER;1358J2dTraceLn(J2D_TRACE_INFO, "D3DContext::UpdateTextureTransforms: "\1359"updating all samplers");1360} else {1361// update only given sampler, dwMaxSampler will be set to it as well1362dwSampler = dwSamplerToUpdate;1363dwMaxSampler = dwSamplerToUpdate;1364J2dTraceLn1(J2D_TRACE_INFO, "D3DContext::UpdateTextureTransforms: "\1365"updating sampler %d", dwSampler);1366}13671368do {1369D3DTRANSFORMSTATETYPE state =1370(D3DTRANSFORMSTATETYPE)(D3DTS_TEXTURE0 + dwSampler);1371IDirect3DTexture9 *pTexture = lastTexture[dwSampler];13721373if (pTexture != NULL) {1374D3DMATRIX mt, tx;1375D3DSURFACE_DESC texDesc;13761377pd3dDevice->GetTransform(D3DTS_WORLD, &tx);1378J2dTraceLn4(10,1379" %5f %5f %5f %5f", tx._11, tx._12, tx._13, tx._14);1380J2dTraceLn4(10,1381" %5f %5f %5f %5f", tx._21, tx._22, tx._23, tx._24);1382J2dTraceLn4(10,1383" %5f %5f %5f %5f", tx._31, tx._32, tx._33, tx._34);1384J2dTraceLn4(10,1385" %5f %5f %5f %5f", tx._41, tx._42, tx._43, tx._44);13861387// this formula works for scales and flips1388if (tx._11 == 0.0f) {1389tx._11 = tx._12;1390}1391if (tx._22 == 0.0f) {1392tx._22 = tx._21;1393}13941395pTexture->GetLevelDesc(0, &texDesc);13961397// shift by .5 texel, but take into account1398// the scale factor of the device transform13991400// REMIND: this approach is not entirely correct,1401// as it only takes into account the scale of the device1402// transform.1403mt._31 = (1.0f / (2.0f * texDesc.Width * tx._11));1404mt._32 = (1.0f / (2.0f * texDesc.Height * tx._22));1405J2dTraceLn2(J2D_TRACE_VERBOSE, " offsets: tx=%f ty=%f",1406mt._31, mt._32);14071408pd3dDevice->SetTextureStageState(dwSampler,1409D3DTSS_TEXTURETRANSFORMFLAGS,1410D3DTTFF_COUNT2);1411res = pd3dDevice->SetTransform(state, &mt);1412} else {1413res = pd3dDevice->SetTextureStageState(dwSampler,1414D3DTSS_TEXTURETRANSFORMFLAGS,1415D3DTTFF_DISABLE);1416}1417dwSampler++;1418} while (dwSampler <= dwMaxSampler);14191420return res;1421}1422#endif // UPDATE_TX14231424/**1425* We go into the pains of maintaining the list of set textures1426* instead of just calling GetTexture() and comparing the old one1427* with the new one because it's actually noticeably slower to call1428* GetTexture() (note that we'd have to then call Release() on the1429* texture since GetTexture() increases texture's ref. count).1430*/1431HRESULT1432D3DContext::SetTexture(IDirect3DTexture9 *pTexture, DWORD dwSampler)1433{1434HRESULT res = S_OK;1435J2dTraceLn(J2D_TRACE_INFO, "D3DContext::SetTexture");14361437if (dwSampler < 0 || dwSampler > MAX_USED_TEXTURE_SAMPLER) {1438J2dTraceLn1(J2D_TRACE_ERROR,1439"D3DContext::SetTexture: incorrect sampler: %d", dwSampler);1440return E_FAIL;1441}1442if (lastTexture[dwSampler] != pTexture) {1443if (FAILED(res = FlushVertexQueue())) {1444return res;1445}1446J2dTraceLn2(J2D_TRACE_VERBOSE,1447" new texture=0x%x on sampler %d", pTexture, dwSampler);1448res = pd3dDevice->SetTexture(dwSampler, pTexture);1449if (SUCCEEDED(res)) {1450lastTexture[dwSampler] = pTexture;1451// REMIND: see comment at UpdateTextureTransforms1452#ifdef UPDATE_TX1453res = UpdateTextureTransforms(dwSampler);1454#endif1455} else {1456lastTexture[dwSampler] = NULL;1457}1458}1459return res;1460}14611462HRESULT1463D3DContext::UpdateTextureColorState(DWORD dwState, DWORD dwSampler)1464{1465HRESULT res = S_OK;14661467if (dwState != lastTextureColorState[dwSampler]) {1468res = pd3dDevice->SetTextureStageState(dwSampler,1469D3DTSS_ALPHAARG1, dwState);1470res = pd3dDevice->SetTextureStageState(dwSampler,1471D3DTSS_COLORARG1, dwState);1472lastTextureColorState[dwSampler] = dwState;1473}14741475return res;1476}14771478HRESULT /*NOLOCK*/1479D3DContext::UpdateState(jbyte newState)1480{1481HRESULT res = S_OK;14821483if (opState == newState) {1484// The op is the same as last time, so we can return immediately.1485return res;1486} else if (opState != STATE_CHANGE) {1487res = FlushVertexQueue();1488}14891490switch (opState) {1491case STATE_MASKOP:1492pMaskCache->Disable();1493break;1494case STATE_GLYPHOP:1495D3DTR_DisableGlyphVertexCache(this);1496break;1497case STATE_TEXTUREOP:1498// optimization: certain state changes (those marked STATE_CHANGE)1499// are allowed while texturing is enabled.1500// In this case, we can allow previousOp to remain as it is and1501// then return early.1502if (newState == STATE_CHANGE) {1503return res;1504}1505// REMIND: not necessary if we are switching to MASKOP or GLYPHOP1506// (or a complex paint, for that matter), but would that be a1507// worthwhile optimization?1508SetTexture(NULL);1509break;1510case STATE_AAPGRAMOP:1511res = DisableAAParallelogramProgram();1512break;1513default:1514break;1515}15161517switch (newState) {1518case STATE_MASKOP:1519pMaskCache->Enable();1520UpdateTextureColorState(D3DTA_TEXTURE | D3DTA_ALPHAREPLICATE);1521break;1522case STATE_GLYPHOP:1523D3DTR_EnableGlyphVertexCache(this);1524UpdateTextureColorState(D3DTA_TEXTURE | D3DTA_ALPHAREPLICATE);1525break;1526case STATE_TEXTUREOP:1527UpdateTextureColorState(D3DTA_TEXTURE);1528break;1529case STATE_AAPGRAMOP:1530res = EnableAAParallelogramProgram();1531break;1532default:1533break;1534}15351536opState = newState;15371538return res;1539}15401541HRESULT D3DContext::FlushVertexQueue()1542{1543if (pVCacher != NULL) {1544return pVCacher->Render();1545}1546return E_FAIL;1547}15481549HRESULT D3DContext::BeginScene(jbyte newState)1550{1551if (!pd3dDevice) {1552return E_FAIL;1553} else {1554UpdateState(newState);1555if (!bBeginScenePending) {1556bBeginScenePending = TRUE;1557HRESULT res = pd3dDevice->BeginScene();1558J2dTraceLn(J2D_TRACE_INFO, "D3DContext::BeginScene");1559if (FAILED(res)) {1560// this will cause context reinitialization1561opState = STATE_CHANGE;1562}1563return res;1564}1565return S_OK;1566}1567}15681569HRESULT D3DContext::EndScene() {1570if (bBeginScenePending) {1571FlushVertexQueue();1572bBeginScenePending = FALSE;1573J2dTraceLn(J2D_TRACE_INFO, "D3DContext::EndScene");1574return pd3dDevice->EndScene();1575}1576return S_OK;1577}15781579/**1580* Compiles and links the given fragment shader program. If1581* successful, this function returns a handle to the newly created shader1582* program; otherwise returns 0.1583*/1584IDirect3DPixelShader9 *D3DContext::CreateFragmentProgram(DWORD **shaders,1585ShaderList *programs,1586jint flags)1587{1588DWORD *sourceCode;1589IDirect3DPixelShader9 *pProgram;15901591J2dTraceLn1(J2D_TRACE_INFO,1592"D3DContext::CreateFragmentProgram: flags=%d",1593flags);15941595sourceCode = shaders[flags];1596if (FAILED(pd3dDevice->CreatePixelShader(sourceCode, &pProgram))) {1597J2dRlsTraceLn(J2D_TRACE_ERROR,1598"D3DContext::CreateFragmentProgram: error creating program");1599return NULL;1600}16011602// add it to the cache1603ShaderList_AddProgram(programs, ptr_to_jlong(pProgram),16040 /*unused*/, 0 /*unused*/, flags);16051606return pProgram;1607}16081609/**1610* Locates and enables a fragment program given a list of shader programs1611* (ShaderInfos), using this context's state and flags as search1612* parameters. The "flags" parameter is a bitwise-or'd value that helps1613* differentiate one program for another; the interpretation of this value1614* varies depending on the type of shader (BufImgOp, Paint, etc) but here1615* it is only used to find another ShaderInfo with that same "flags" value.1616*/1617HRESULT D3DContext::EnableFragmentProgram(DWORD **shaders,1618ShaderList *programList,1619jint flags)1620{1621HRESULT res;1622jlong programID;1623IDirect3DPixelShader9 *pProgram;16241625J2dTraceLn(J2D_TRACE_INFO, "D3DContext::EnableFragmentProgram");16261627programID =1628ShaderList_FindProgram(programList,16290 /*unused*/, 0 /*unused*/, flags);16301631pProgram = (IDirect3DPixelShader9 *)jlong_to_ptr(programID);1632if (pProgram == NULL) {1633pProgram = CreateFragmentProgram(shaders, programList, flags);1634if (pProgram == NULL) {1635return E_FAIL;1636}1637}16381639if (FAILED(res = pd3dDevice->SetPixelShader(pProgram))) {1640J2dRlsTraceLn(J2D_TRACE_ERROR,1641"D3DContext::EnableFragmentProgram: error setting pixel shader");1642return res;1643}16441645return S_OK;1646}16471648HRESULT D3DContext::EnableBasicGradientProgram(jint flags)1649{1650return EnableFragmentProgram((DWORD **)gradShaders,1651&basicGradPrograms, flags);1652}16531654HRESULT D3DContext::EnableLinearGradientProgram(jint flags)1655{1656return EnableFragmentProgram((DWORD **)linearShaders,1657&linearGradPrograms, flags);1658}16591660HRESULT D3DContext::EnableRadialGradientProgram(jint flags)1661{1662return EnableFragmentProgram((DWORD **)radialShaders,1663&radialGradPrograms, flags);1664}16651666HRESULT D3DContext::EnableConvolveProgram(jint flags)1667{1668return EnableFragmentProgram((DWORD **)convolveShaders,1669&convolvePrograms, flags);1670}16711672HRESULT D3DContext::EnableRescaleProgram(jint flags)1673{1674return EnableFragmentProgram((DWORD **)rescaleShaders,1675&rescalePrograms, flags);1676}16771678HRESULT D3DContext::EnableLookupProgram(jint flags)1679{1680return EnableFragmentProgram((DWORD **)lookupShaders,1681&lookupPrograms, flags);1682}16831684HRESULT D3DContext::EnableLCDTextProgram()1685{1686HRESULT res;16871688J2dTraceLn(J2D_TRACE_INFO, "D3DContext::EnableLCDTextProgram");16891690if (lcdTextProgram == NULL) {1691if (FAILED(res = pd3dDevice->CreatePixelShader(lcdtext0,1692&lcdTextProgram)))1693{1694return res;1695}1696}16971698if (FAILED(res = pd3dDevice->SetPixelShader(lcdTextProgram))) {1699J2dRlsTraceLn(J2D_TRACE_ERROR,1700"D3DContext::EnableLCDTextProgram: error setting pixel shader");1701return res;1702}17031704return S_OK;1705}17061707HRESULT D3DContext::EnableAAParallelogramProgram()1708{1709HRESULT res;17101711J2dTraceLn(J2D_TRACE_INFO, "D3DContext::EnableAAParallelogramProgram");17121713if (aaPgramProgram == NULL) {1714if (FAILED(res = pd3dDevice->CreatePixelShader(aapgram0,1715&aaPgramProgram))) {1716DebugPrintD3DError(res, "D3DContext::EnableAAParallelogramProgram: "1717"error creating pixel shader");1718return res;1719}1720}17211722if (FAILED(res = pd3dDevice->SetPixelShader(aaPgramProgram))) {1723DebugPrintD3DError(res, "D3DContext::EnableAAParallelogramProgram: "1724"error setting pixel shader");1725return res;1726}17271728return S_OK;1729}17301731HRESULT D3DContext::DisableAAParallelogramProgram()1732{1733HRESULT res;17341735J2dTraceLn(J2D_TRACE_INFO, "D3DContext::DisableAAParallelogramProgram");17361737if (aaPgramProgram != NULL) {1738if (FAILED(res = pd3dDevice->SetPixelShader(NULL))) {1739DebugPrintD3DError(res,1740"D3DContext::DisableAAParallelogramProgram: "1741"error clearing pixel shader");1742return res;1743}1744}17451746return S_OK;1747}17481749BOOL D3DContext::IsAlphaRTSurfaceSupported()1750{1751HRESULT res = pd3dObject->CheckDeviceFormat(adapterOrdinal,1752devCaps.DeviceType,1753curParams.BackBufferFormat,1754D3DUSAGE_RENDERTARGET,1755D3DRTYPE_SURFACE,1756D3DFMT_A8R8G8B8);1757return SUCCEEDED(res);1758}17591760BOOL D3DContext::IsAlphaRTTSupported()1761{1762HRESULT res = pd3dObject->CheckDeviceFormat(adapterOrdinal,1763devCaps.DeviceType,1764curParams.BackBufferFormat,1765D3DUSAGE_RENDERTARGET,1766D3DRTYPE_TEXTURE,1767D3DFMT_A8R8G8B8);1768return SUCCEEDED(res);1769}17701771BOOL D3DContext::IsOpaqueRTTSupported()1772{1773HRESULT res = pd3dObject->CheckDeviceFormat(adapterOrdinal,1774devCaps.DeviceType,1775curParams.BackBufferFormat,1776D3DUSAGE_RENDERTARGET,1777D3DRTYPE_TEXTURE,1778curParams.BackBufferFormat);1779return SUCCEEDED(res);1780}17811782HRESULT D3DContext::InitContextCaps() {1783J2dTraceLn(J2D_TRACE_INFO, "D3DContext::InitContextCaps");1784J2dTraceLn1(J2D_TRACE_VERBOSE, " caps for adapter %d :", adapterOrdinal);17851786if (pd3dDevice == NULL || pd3dObject == NULL) {1787contextCaps = CAPS_EMPTY;1788J2dRlsTraceLn(J2D_TRACE_VERBOSE, " | CAPS_EMPTY");1789return E_FAIL;1790}17911792contextCaps = CAPS_DEVICE_OK;1793J2dRlsTraceLn(J2D_TRACE_VERBOSE, " | CAPS_DEVICE_OK");17941795if (IsAlphaRTSurfaceSupported()) {1796contextCaps |= CAPS_RT_PLAIN_ALPHA;1797J2dRlsTraceLn(J2D_TRACE_VERBOSE, " | CAPS_RT_PLAIN_ALPHA");1798}1799if (IsAlphaRTTSupported()) {1800contextCaps |= CAPS_RT_TEXTURE_ALPHA;1801J2dRlsTraceLn(J2D_TRACE_VERBOSE, " | CAPS_RT_TEXTURE_ALPHA");1802}1803if (IsOpaqueRTTSupported()) {1804contextCaps |= CAPS_RT_TEXTURE_OPAQUE;1805J2dRlsTraceLn(J2D_TRACE_VERBOSE, " | CAPS_RT_TEXTURE_OPAQUE");1806}1807if (IsPixelShader20Supported()) {1808contextCaps |= CAPS_LCD_SHADER | CAPS_BIOP_SHADER | CAPS_PS20;1809J2dRlsTraceLn(J2D_TRACE_VERBOSE,1810" | CAPS_LCD_SHADER | CAPS_BIOP_SHADER | CAPS_PS20");1811// Pre-PS3.0 video boards are very slow with the AA shader, so1812// we will require PS30 hw even though the shader is compiled for 2.0a1813// if (IsGradientInstructionExtensionSupported()) {1814// contextCaps |= CAPS_AA_SHADER;1815// J2dRlsTraceLn(J2D_TRACE_VERBOSE, " | CAPS_AA_SHADER");1816// }1817}1818if (IsPixelShader30Supported()) {1819if ((contextCaps & CAPS_AA_SHADER) == 0) {1820// This flag was not already mentioned above...1821J2dRlsTraceLn(J2D_TRACE_VERBOSE, " | CAPS_AA_SHADER");1822}1823contextCaps |= CAPS_PS30 | CAPS_AA_SHADER;1824J2dRlsTraceLn(J2D_TRACE_VERBOSE, " | CAPS_PS30");1825}1826if (IsMultiTexturingSupported()) {1827contextCaps |= CAPS_MULTITEXTURE;1828J2dRlsTraceLn(J2D_TRACE_VERBOSE, " | CAPS_MULTITEXTURE");1829}1830if (!IsPow2TexturesOnly()) {1831contextCaps |= CAPS_TEXNONPOW2;1832J2dRlsTraceLn(J2D_TRACE_VERBOSE, " | CAPS_TEXNONPOW2");1833}1834if (!IsSquareTexturesOnly()) {1835contextCaps |= CAPS_TEXNONSQUARE;1836J2dRlsTraceLn(J2D_TRACE_VERBOSE, " | CAPS_TEXNONSQUARE");1837}1838return S_OK;1839}184018411842