Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/windows/native/sun/java2d/d3d/D3DContext.cpp
32288 views
/*1* Copyright (c) 2007, 2008, 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();254255D3DPipelineManager::NotifyAdapterEventListeners(devCaps.AdapterOrdinal,256DEVICE_RESET);257258contextCaps = CAPS_EMPTY;259260SAFE_RELEASE(pSyncQuery);261SAFE_RELEASE(pStateBlock);262263if (pVCacher != NULL) {264pVCacher->ReleaseDefPoolResources();265}266if (pMaskCache != NULL) {267pMaskCache->ReleaseDefPoolResources();268}269if (pLCDGlyphCache != NULL) {270pLCDGlyphCache->ReleaseDefPoolResources();271}272if (pGrayscaleGlyphCache != NULL) {273pGrayscaleGlyphCache->ReleaseDefPoolResources();274}275if (pResourceMgr != NULL) {276if (pSyncRTRes != NULL) {277pResourceMgr->ReleaseResource(pSyncRTRes);278pSyncRTRes = NULL;279}280pResourceMgr->ReleaseDefPoolResources();281}282ZeroMemory(lastTexture, sizeof(lastTexture));283ZeroMemory(lastTextureColorState, sizeof(lastTextureColorState));284}285286void D3DContext::ReleaseContextResources()287{288J2dTraceLn1(J2D_TRACE_INFO,289"D3DContext::ReleaseContextResources: pd3dDevice = 0x%x",290pd3dDevice);291292ReleaseDefPoolResources();293294D3DPipelineManager::NotifyAdapterEventListeners(devCaps.AdapterOrdinal,295DEVICE_DISPOSED);296297// dispose shader lists298ShaderList_Dispose(&convolvePrograms);299ShaderList_Dispose(&rescalePrograms);300ShaderList_Dispose(&lookupPrograms);301ShaderList_Dispose(&basicGradPrograms);302ShaderList_Dispose(&linearGradPrograms);303ShaderList_Dispose(&radialGradPrograms);304305SAFE_DELETE(pLCDGlyphCache);306SAFE_DELETE(pGrayscaleGlyphCache);307308SAFE_RELEASE(lcdTextProgram);309SAFE_RELEASE(aaPgramProgram);310311SAFE_DELETE(pVCacher);312SAFE_DELETE(pMaskCache);313SAFE_DELETE(pResourceMgr);314}315316D3DContext::~D3DContext() {317J2dTraceLn2(J2D_TRACE_INFO,318"~D3DContext: pd3dDevice=0x%x, pd3dObject =0x%x",319pd3dDevice, pd3dObject);320ReleaseContextResources();321SAFE_RELEASE(pd3dDevice);322}323324HRESULT325D3DContext::InitDevice(IDirect3DDevice9 *pd3dDevice)326{327HRESULT res = S_OK;328329pd3dDevice->GetDeviceCaps(&devCaps);330331J2dRlsTraceLn1(J2D_TRACE_INFO,332"D3DContext::InitDevice: device %d", adapterOrdinal);333334// disable some of the unneeded and costly d3d functionality335pd3dDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);336pd3dDevice->SetRenderState(D3DRS_SPECULARENABLE, FALSE);337pd3dDevice->SetRenderState(D3DRS_LIGHTING, FALSE);338pd3dDevice->SetRenderState(D3DRS_CLIPPING, FALSE);339pd3dDevice->SetRenderState(D3DRS_ZENABLE, D3DZB_FALSE);340pd3dDevice->SetRenderState(D3DRS_ZWRITEENABLE, D3DZB_FALSE);341pd3dDevice->SetRenderState(D3DRS_COLORVERTEX, FALSE);342pd3dDevice->SetRenderState(D3DRS_STENCILENABLE, FALSE);343344// set the default texture addressing mode345pd3dDevice->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP);346pd3dDevice->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP);347348// REMIND: check supported filters with349// IDirect3D9::CheckDeviceFormat with D3DUSAGE_QUERY_FILTER350pd3dDevice->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_POINT);351pd3dDevice->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_POINT);352353// these states never change354pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_MODULATE);355pd3dDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE);356pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE);357pd3dDevice->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE);358pd3dDevice->SetTextureStageState(1, D3DTSS_ALPHAOP, D3DTOP_MODULATE);359pd3dDevice->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_MODULATE);360pd3dDevice->SetTextureStageState(1, D3DTSS_ALPHAARG2, D3DTA_CURRENT);361pd3dDevice->SetTextureStageState(1, D3DTSS_COLORARG2, D3DTA_CURRENT);362363// init the array of latest textures364ZeroMemory(lastTexture, sizeof(lastTexture));365ZeroMemory(lastTextureColorState, sizeof(lastTextureColorState));366367opState = STATE_CHANGE;368369if (pResourceMgr == NULL) {370res = D3DResourceManager::CreateInstance(this, &pResourceMgr);371} else {372res = pResourceMgr->Init(this);373}374RETURN_STATUS_IF_FAILED(res);375376if (pVCacher == NULL) {377res = D3DVertexCacher::CreateInstance(this, &pVCacher);378} else {379res = pVCacher->Init(this);380}381RETURN_STATUS_IF_FAILED(res);382383if (pMaskCache == NULL) {384res = D3DMaskCache::CreateInstance(this, &pMaskCache);385} else{386res = pMaskCache->Init(this);387}388RETURN_STATUS_IF_FAILED(res);389390if (pLCDGlyphCache != NULL) {391if (FAILED(res = pLCDGlyphCache->Init(this))) {392// we can live without the cache393SAFE_DELETE(pLCDGlyphCache);394res = S_OK;395}396}397398if (pGrayscaleGlyphCache != NULL) {399if (FAILED(res = pGrayscaleGlyphCache->Init(this))) {400// we can live without the cache401SAFE_DELETE(pGrayscaleGlyphCache);402res = S_OK;403}404}405406D3DMATRIX tx;407D3DUtils_SetIdentityMatrix(&tx);408pd3dDevice->SetTransform(D3DTS_WORLD, &tx);409bIsIdentityTx = TRUE;410411if (pSyncQuery == NULL) {412// this is allowed to fail, do not propagate the error413if (FAILED(pd3dDevice->CreateQuery(D3DQUERYTYPE_EVENT, &pSyncQuery))) {414J2dRlsTraceLn(J2D_TRACE_WARNING,415"D3DContext::InitDevice: sync query not available");416pSyncQuery = NULL;417}418}419if (pSyncRTRes == NULL) {420D3DFORMAT format;421if (FAILED(GetResourceManager()->422CreateRTSurface(32, 32, TRUE, TRUE, &format, &pSyncRTRes))) {423J2dRlsTraceLn(J2D_TRACE_WARNING,424"D3DContext::InitDevice: "425"error creating sync surface");426}427}428429bBeginScenePending = FALSE;430431J2dRlsTraceLn1(J2D_TRACE_INFO,432"D3DContext::InitDefice: successfully initialized device %d",433adapterOrdinal);434435return res;436}437438HRESULT439D3DContext::CheckAndResetDevice()440{441HRESULT res = E_FAIL;442443J2dTraceLn(J2D_TRACE_INFO, "D3DContext::CheckAndResetDevice");444445if (pd3dDevice != NULL) {446if (FAILED(res = pd3dDevice->TestCooperativeLevel())) {447if (res == D3DERR_DEVICELOST) {448J2dTraceLn1(J2D_TRACE_VERBOSE, " device %d is still lost",449adapterOrdinal);450// nothing to be done here, wait for D3DERR_DEVICENOTRESET451return res;452} else if (res == D3DERR_DEVICENOTRESET) {453J2dTraceLn1(J2D_TRACE_VERBOSE, " device %d needs to be reset",454adapterOrdinal);455res = ResetContext();456} else {457// some unexpected error458DebugPrintD3DError(res, "D3DContext::CheckAndResetDevice: "\459"unknown error %x from TestCooperativeLevel");460}461} else {462J2dTraceLn1(J2D_TRACE_VERBOSE, " device %d is not lost",463adapterOrdinal);464}465} else {466J2dTraceLn(J2D_TRACE_VERBOSE, " null device");467}468return res;469}470471HRESULT472D3DContext::ResetContext()473{474HRESULT res = E_FAIL;475476J2dRlsTraceLn(J2D_TRACE_INFO, "D3DContext::ResetContext");477if (pd3dDevice != NULL) {478D3DPRESENT_PARAMETERS newParams;479480newParams = curParams;481482if (newParams.Windowed) {483// reset to the current display mode if we're windowed,484// otherwise to the display mode we were in when the device485// was lost486newParams.BackBufferFormat = D3DFMT_UNKNOWN;487newParams.FullScreen_RefreshRateInHz = 0;488newParams.BackBufferWidth = 0;489newParams.BackBufferHeight = 0;490}491res = ConfigureContext(&newParams);492}493return res;494}495496HRESULT497D3DContext::ConfigureContext(D3DPRESENT_PARAMETERS *pNewParams)498{499J2dRlsTraceLn1(J2D_TRACE_INFO, "D3DContext::ConfigureContext device %d",500adapterOrdinal);501HRESULT res = S_OK;502D3DFORMAT stencilFormat;503HWND focusHWND = D3DPipelineManager::GetInstance()->GetCurrentFocusWindow();504D3DDEVTYPE devType = D3DPipelineManager::GetInstance()->GetDeviceType();505// this is needed so that we can find the stencil buffer format506if (pNewParams->BackBufferFormat == D3DFMT_UNKNOWN) {507D3DDISPLAYMODE dm;508509pd3dObject->GetAdapterDisplayMode(adapterOrdinal, &dm);510pNewParams->BackBufferFormat = dm.Format;511}512513stencilFormat =514D3DPipelineManager::GetInstance()->GetMatchingDepthStencilFormat(515adapterOrdinal,516pNewParams->BackBufferFormat, pNewParams->BackBufferFormat);517518pNewParams->EnableAutoDepthStencil = TRUE;519pNewParams->AutoDepthStencilFormat = stencilFormat;520521// do not set device window in the windowed mode, we use additional522// swap chains for rendering, the default chain is not used. otherwise523// our scratch focus window will be made visible524J2dTraceLn1(J2D_TRACE_VERBOSE, " windowed=%d",pNewParams->Windowed);525if (pNewParams->Windowed) {526pNewParams->hDeviceWindow = (HWND)0;527}528529// The focus window may change when we're entering/exiting the full-screen530// mode. It may either be set to the default focus window (when there are531// no more devices in fs mode), or to fs window for another device532// in fs mode. See D3DPipelineManager::GetCurrentFocusWindow.533if (pd3dDevice != NULL) {534D3DDEVICE_CREATION_PARAMETERS cParams;535pd3dDevice->GetCreationParameters(&cParams);536if (cParams.hFocusWindow != focusHWND) {537J2dTraceLn(J2D_TRACE_VERBOSE,538" focus window changed, need to recreate the device");539540// if fs -> windowed, first exit fs, then recreate, otherwise541// the screen might be left in a different display mode542if (pNewParams->Windowed && !curParams.Windowed) {543J2dTraceLn(J2D_TRACE_VERBOSE,544" exiting full-screen mode, reset the device");545curParams.Windowed = FALSE;546ReleaseDefPoolResources();547res = pd3dDevice->Reset(&curParams);548549if (FAILED(res)) {550DebugPrintD3DError(res, "D3DContext::ConfigureContext: "\551"cound not reset the device");552}553}554555// note that here we should release all device resources, not only556// thos in the default pool since the device is released557ReleaseContextResources();558SAFE_RELEASE(pd3dDevice);559}560}561562if (pd3dDevice != NULL) {563J2dTraceLn(J2D_TRACE_VERBOSE, " resetting the device");564565ReleaseDefPoolResources();566567if (pNewParams->PresentationInterval == D3DPRESENT_INTERVAL_IMMEDIATE &&568!IsImmediateIntervalSupported())569{570pNewParams->PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT;571}572573res = pd3dDevice->Reset(pNewParams);574if (FAILED(res)) {575DebugPrintD3DError(res,576"D3DContext::ConfigureContext: cound not reset the device");577return res;578}579J2dRlsTraceLn1(J2D_TRACE_INFO,580"D3DContext::ConfigureContext: successfully reset device: %d",581adapterOrdinal);582} else {583D3DCAPS9 d3dCaps;584DWORD dwBehaviorFlags;585586J2dTraceLn(J2D_TRACE_VERBOSE, " creating a new device");587588if (FAILED(res = pd3dObject->GetDeviceCaps(adapterOrdinal,589devType, &d3dCaps)))590{591DebugPrintD3DError(res,592"D3DContext::ConfigureContext: failed to get caps");593return res;594}595596if (pNewParams->PresentationInterval == D3DPRESENT_INTERVAL_IMMEDIATE &&597!(d3dCaps.PresentationIntervals & D3DPRESENT_INTERVAL_IMMEDIATE))598{599pNewParams->PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT;600}601602// not preserving fpu control word could cause issues (4860749)603dwBehaviorFlags = D3DCREATE_FPU_PRESERVE;604605J2dRlsTrace(J2D_TRACE_VERBOSE,606"[V] dwBehaviorFlags=D3DCREATE_FPU_PRESERVE|");607if (d3dCaps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT) {608J2dRlsTrace(J2D_TRACE_VERBOSE,609"D3DCREATE_HARDWARE_VERTEXPROCESSING");610dwBehaviorFlags |= D3DCREATE_HARDWARE_VERTEXPROCESSING;611} else {612J2dRlsTrace(J2D_TRACE_VERBOSE,613"D3DCREATE_SOFTWARE_VERTEXPROCESSING");614dwBehaviorFlags |= D3DCREATE_SOFTWARE_VERTEXPROCESSING;615}616// Handling focus changes by ourselves proved to be problematic,617// so we're reverting back to D3D handling618// dwBehaviorFlags |= D3DCREATE_NOWINDOWCHANGES;619J2dRlsTrace(J2D_TRACE_VERBOSE,"\n");620621if (FAILED(res = pd3dObject->CreateDevice(adapterOrdinal, devType,622focusHWND,623dwBehaviorFlags,624pNewParams, &pd3dDevice)))625{626DebugPrintD3DError(res,627"D3DContext::ConfigureContext: error creating d3d device");628return res;629}630J2dRlsTraceLn1(J2D_TRACE_INFO,631"D3DContext::ConfigureContext: successfully created device: %d",632adapterOrdinal);633bIsHWRasterizer = (devType == D3DDEVTYPE_HAL);634}635636curParams = *pNewParams;637// during the creation of the device d3d modifies this field, we reset638// it back to 0639curParams.Flags = 0;640641if (FAILED(res = InitDevice(pd3dDevice))) {642ReleaseContextResources();643return res;644}645646res = InitContextCaps();647648return res;649}650651HRESULT652D3DContext::InitContext()653{654J2dRlsTraceLn1(J2D_TRACE_INFO, "D3DContext::InitContext device %d",655adapterOrdinal);656657D3DPRESENT_PARAMETERS params;658ZeroMemory(¶ms, sizeof(D3DPRESENT_PARAMETERS));659660params.hDeviceWindow = 0;661params.Windowed = TRUE;662params.BackBufferCount = 1;663params.BackBufferFormat = D3DFMT_UNKNOWN;664params.SwapEffect = D3DSWAPEFFECT_DISCARD;665params.PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT;666667return ConfigureContext(¶ms);668}669670HRESULT671D3DContext::Sync()672{673HRESULT res = S_OK;674675J2dTraceLn(J2D_TRACE_INFO, "D3DContext::Sync");676677if (pSyncQuery != NULL) {678J2dTrace(J2D_TRACE_VERBOSE, " flushing the device queue..");679while (S_FALSE ==680(res = pSyncQuery->GetData(NULL, 0, D3DGETDATA_FLUSH))) ;681J2dTrace(J2D_TRACE_VERBOSE, ".. done\n");682}683if (pSyncRTRes != NULL) {684D3DLOCKED_RECT lr;685IDirect3DSurface9 *pSurface = pSyncRTRes->GetSurface();686if (SUCCEEDED(pSurface->LockRect(&lr, NULL, D3DLOCK_NOSYSLOCK))) {687pSurface->UnlockRect();688}689}690return res;691}692693HRESULT694D3DContext::SaveState()695{696HRESULT res;697698RETURN_STATUS_IF_NULL(pd3dDevice, S_OK);699700J2dTraceLn(J2D_TRACE_INFO, "D3DContext::SaveState");701702FlushVertexQueue();703UpdateState(STATE_CHANGE);704705if (pStateBlock != NULL) {706J2dTraceLn(J2D_TRACE_WARNING,707"D3DContext::SaveState: existing state block!");708SAFE_RELEASE(pStateBlock);709}710711if (SUCCEEDED(res =712pd3dDevice->CreateStateBlock(D3DSBT_ALL, &pStateBlock)))713{714J2dTraceLn(J2D_TRACE_VERBOSE, " created state block");715} else {716J2dTraceLn(J2D_TRACE_WARNING,717"D3DContext::SaveState: failed to create state block");718}719ZeroMemory(lastTexture, sizeof(lastTexture));720721return res;722}723724HRESULT725D3DContext::RestoreState()726{727HRESULT res = S_OK;728729J2dTraceLn(J2D_TRACE_INFO, "D3DContext::RestoreState");730731FlushVertexQueue();732UpdateState(STATE_CHANGE);733734if (pStateBlock != NULL) {735if (SUCCEEDED(res = pStateBlock->Apply())) {736J2dTraceLn(J2D_TRACE_VERBOSE, " restored device state");737} else {738J2dTraceLn(J2D_TRACE_WARNING,739"D3DContext::RestoreState: failed to restore state");740}741SAFE_RELEASE(pStateBlock);742} else {743J2dTraceLn(J2D_TRACE_WARNING,744"D3DContext::RestoreState: empty state block!");745}746ZeroMemory(lastTexture, sizeof(lastTexture));747748return res;749}750751#define POINT_FILTER_CAP (D3DPTFILTERCAPS_MAGFPOINT|D3DPTFILTERCAPS_MINFPOINT)752#define LINEAR_FILTER_CAP (D3DPTFILTERCAPS_MAGFLINEAR|D3DPTFILTERCAPS_MINFLINEAR)753754BOOL755D3DContext::IsStretchRectFilteringSupported(D3DTEXTUREFILTERTYPE fType)756{757if (fType == D3DTEXF_POINT) {758return ((devCaps.StretchRectFilterCaps & POINT_FILTER_CAP) != 0);759}760if (fType == D3DTEXF_LINEAR) {761return ((devCaps.StretchRectFilterCaps & LINEAR_FILTER_CAP) != 0);762}763return FALSE;764}765766BOOL767D3DContext::IsTextureFilteringSupported(D3DTEXTUREFILTERTYPE fType)768{769if (fType == D3DTEXF_POINT) {770return ((devCaps.TextureFilterCaps & POINT_FILTER_CAP) != 0);771}772if (fType == D3DTEXF_LINEAR) {773return ((devCaps.TextureFilterCaps & LINEAR_FILTER_CAP) != 0);774}775return FALSE;776}777778BOOL779D3DContext::IsTextureFormatSupported(D3DFORMAT format, DWORD usage)780{781HRESULT hr = pd3dObject->CheckDeviceFormat(adapterOrdinal,782devCaps.DeviceType,783curParams.BackBufferFormat,784usage,785D3DRTYPE_TEXTURE,786format);787return SUCCEEDED( hr );788}789790BOOL791D3DContext::IsDepthStencilBufferOk(D3DSURFACE_DESC *pTargetDesc)792{793IDirect3DSurface9 *pStencil;794J2dTraceLn(J2D_TRACE_INFO, "D3DContext::IsDepthStencilBufferOk");795796if (SUCCEEDED(pd3dDevice->GetDepthStencilSurface(&pStencil))) {797D3DSURFACE_DESC descStencil;798pStencil->GetDesc(&descStencil);799pStencil->Release();800801D3DDISPLAYMODE dm;802return803(SUCCEEDED(pd3dDevice->GetDisplayMode(0, &dm)) &&804pTargetDesc->Width <= descStencil.Width &&805pTargetDesc->Height <= descStencil.Height &&806SUCCEEDED(pd3dObject->CheckDepthStencilMatch(807adapterOrdinal,808devCaps.DeviceType,809dm.Format, pTargetDesc->Format,810descStencil.Format)));811}812J2dTraceLn(J2D_TRACE_VERBOSE,813" current stencil buffer is not compatible with new Render Target");814815return false;816}817818819820HRESULT821D3DContext::InitDepthStencilBuffer(D3DSURFACE_DESC *pTargetDesc)822{823HRESULT res;824IDirect3DSurface9 *pBB;825D3DDISPLAYMODE dm;826827J2dTraceLn(J2D_TRACE_INFO, "D3DContext::InitDepthStencilBuffer");828829if (FAILED(res = pd3dDevice->GetDisplayMode(0, &dm))) {830return res;831}832833D3DFORMAT newFormat =834D3DPipelineManager::GetInstance()->GetMatchingDepthStencilFormat(835adapterOrdinal, dm.Format, pTargetDesc->Format);836837res = pd3dDevice->CreateDepthStencilSurface(838pTargetDesc->Width, pTargetDesc->Height,839newFormat, D3DMULTISAMPLE_NONE, 0, false, &pBB, 0);840if (SUCCEEDED(res)) {841res = pd3dDevice->SetDepthStencilSurface(pBB);842pBB->Release();843}844845return res;846}847848849HRESULT850D3DContext::SetRenderTarget(IDirect3DSurface9 *pSurface)851{852static D3DMATRIX tx;853HRESULT res;854D3DSURFACE_DESC descNew;855IDirect3DSurface9 *pCurrentTarget;856857J2dTraceLn1(J2D_TRACE_INFO,858"D3DContext::SetRenderTarget: pSurface=0x%x",859pSurface);860861RETURN_STATUS_IF_NULL(pd3dDevice, E_FAIL);862RETURN_STATUS_IF_NULL(pSurface, E_FAIL);863864pSurface->GetDesc(&descNew);865866if (SUCCEEDED(res = pd3dDevice->GetRenderTarget(0, &pCurrentTarget))) {867if (pCurrentTarget != pSurface) {868FlushVertexQueue();869if (FAILED(res = pd3dDevice->SetRenderTarget(0, pSurface))) {870DebugPrintD3DError(res, "D3DContext::SetRenderTarget: "\871"error setting render target");872SAFE_RELEASE(pCurrentTarget);873return res;874}875876if (!IsDepthStencilBufferOk(&descNew)) {877if (FAILED(res = InitDepthStencilBuffer(&descNew))) {878SAFE_RELEASE(pCurrentTarget);879return res;880}881}882}883SAFE_RELEASE(pCurrentTarget);884}885// we set the transform even if the render target didn't change;886// this is because in some cases (fs mode) we use the default SwapChain of887// the device, and its render target will be the same as the device's, and888// we have to set the matrix correctly. This shouldn't be a performance889// issue as render target changes are relatively rare890D3DUtils_SetOrthoMatrixOffCenterLH(&tx,891(float)descNew.Width,892(float)descNew.Height);893pd3dDevice->SetTransform(D3DTS_PROJECTION, &tx);894895J2dTraceLn1(J2D_TRACE_VERBOSE, " current render target=0x%x", pSurface);896return res;897}898899HRESULT900D3DContext::ResetTransform()901{902HRESULT res = S_OK;903D3DMATRIX tx;904905J2dTraceLn(J2D_TRACE_INFO, "D3DContext::ResetTransform");906if (pd3dDevice == NULL) {907return E_FAIL;908}909910// no need for state change, just flush the queue911FlushVertexQueue();912913D3DUtils_SetIdentityMatrix(&tx);914if (FAILED(res = pd3dDevice->SetTransform(D3DTS_WORLD, &tx))) {915DebugPrintD3DError(res, "D3DContext::SetTransform failed");916}917bIsIdentityTx = TRUE;918return res;919}920921HRESULT922D3DContext::SetTransform(jdouble m00, jdouble m10,923jdouble m01, jdouble m11,924jdouble m02, jdouble m12)925{926HRESULT res = S_OK;927D3DMATRIX tx, tx1;928929J2dTraceLn(J2D_TRACE_INFO, "D3DContext::SetTransform");930if (pd3dDevice == NULL) {931return E_FAIL;932}933934// no need for state change, just flush the queue935FlushVertexQueue();936937// In order to correctly map texels to pixels we need to938// adjust geometry by -0.5f in the transformed space.939// In order to do that we first create a translated matrix940// and then concatenate it with the world transform.941//942// Note that we only use non-id transform with DrawTexture,943// the rest is rendered pre-transformed.944//945// The identity transform for textures is handled in946// D3DVertexCacher::DrawTexture() because shifting by -0.5 for id947// transform breaks lines rendering.948949ZeroMemory(&tx1, sizeof(D3DMATRIX));950951tx1._11 = (float)m00;952tx1._12 = (float)m10;953tx1._21 = (float)m01;954tx1._22 = (float)m11;955tx1._41 = (float)m02;956tx1._42 = (float)m12;957958tx1._33 = 1.0f;959tx1._44 = 1.0f;960961D3DUtils_SetIdentityMatrix(&tx);962tx._41 = -0.5f;963tx._42 = -0.5f;964D3DUtils_2DConcatenateM(&tx, &tx1);965966J2dTraceLn4(J2D_TRACE_VERBOSE,967" %5f %5f %5f %5f", tx._11, tx._12, tx._13, tx._14);968J2dTraceLn4(J2D_TRACE_VERBOSE,969" %5f %5f %5f %5f", tx._21, tx._22, tx._23, tx._24);970J2dTraceLn4(J2D_TRACE_VERBOSE,971" %5f %5f %5f %5f", tx._31, tx._32, tx._33, tx._34);972J2dTraceLn4(J2D_TRACE_VERBOSE,973" %5f %5f %5f %5f", tx._41, tx._42, tx._43, tx._44);974if (FAILED(res = pd3dDevice->SetTransform(D3DTS_WORLD, &tx))) {975DebugPrintD3DError(res, "D3DContext::SetTransform failed");976}977bIsIdentityTx = FALSE;978979return res;980}981982HRESULT983D3DContext::SetRectClip(int x1, int y1, int x2, int y2)984{985HRESULT res = S_OK;986D3DSURFACE_DESC desc;987IDirect3DSurface9 *pCurrentTarget;988989J2dTraceLn(J2D_TRACE_INFO, "D3DContext::SetRectClip");990J2dTraceLn4(J2D_TRACE_VERBOSE,991" x1=%-4d y1=%-4d x2=%-4d y2=%-4d",992x1, y1, x2, y2);993994RETURN_STATUS_IF_NULL(pd3dDevice, E_FAIL);995996// no need for state change, just flush the queue997FlushVertexQueue();998999pd3dDevice->SetRenderState(D3DRS_ZENABLE, D3DZB_FALSE);10001001res = pd3dDevice->GetRenderTarget(0, &pCurrentTarget);1002RETURN_STATUS_IF_FAILED(res);10031004pCurrentTarget->GetDesc(&desc);1005SAFE_RELEASE(pCurrentTarget);10061007if (x1 <= 0 && y1 <= 0 &&1008(UINT)x2 >= desc.Width && (UINT)y2 >= desc.Height)1009{1010J2dTraceLn(J2D_TRACE_VERBOSE,1011" disabling clip (== render target dimensions)");1012return pd3dDevice->SetRenderState(D3DRS_SCISSORTESTENABLE, FALSE);1013}10141015// clip to the dimensions of the target surface, otherwise1016// SetScissorRect will fail1017if (x1 < 0) x1 = 0;1018if (y1 < 0) y1 = 0;1019if ((UINT)x2 > desc.Width) x2 = desc.Width;1020if ((UINT)y2 > desc.Height) y2 = desc.Height;1021if (x1 > x2) x2 = x1 = 0;1022if (y1 > y2) y2 = y1 = 0;1023RECT newRect = { x1, y1, x2, y2 };1024if (SUCCEEDED(res = pd3dDevice->SetScissorRect(&newRect))) {1025res = pd3dDevice->SetRenderState(D3DRS_SCISSORTESTENABLE, TRUE);1026} else {1027DebugPrintD3DError(res, "Error setting scissor rect");1028J2dRlsTraceLn4(J2D_TRACE_ERROR,1029" x1=%-4d y1=%-4d x2=%-4d y2=%-4d",1030x1, y1, x2, y2);1031}10321033return res;1034}10351036HRESULT1037D3DContext::ResetClip()1038{1039J2dTraceLn(J2D_TRACE_INFO, "D3DContext::ResetClip");1040// no need for state change, just flush the queue1041FlushVertexQueue();1042pd3dDevice->SetRenderState(D3DRS_SCISSORTESTENABLE, FALSE);1043return pd3dDevice->SetRenderState(D3DRS_ZENABLE, D3DZB_FALSE);1044}10451046ClipType1047D3DContext::GetClipType()1048{1049// REMIND: this method could be optimized: we could keep the1050// clip state around when re/setting the clip instead of asking1051// every time.1052DWORD zEnabled = 0;1053DWORD stEnabled = 0;10541055J2dTraceLn(J2D_TRACE_INFO, "D3DContext::GetClipType");1056pd3dDevice->GetRenderState(D3DRS_SCISSORTESTENABLE, &stEnabled);1057if (stEnabled) {1058return CLIP_RECT;1059}1060pd3dDevice->GetRenderState(D3DRS_ZENABLE, &zEnabled);1061if (zEnabled) {1062return CLIP_SHAPE;1063}1064return CLIP_NONE;1065}106610671068/**1069* This method assumes that ::SetRenderTarget has already1070* been called. SetRenderTarget creates and attaches a1071* depth buffer to the target surface prior to setting it1072* as target surface to the device.1073*/1074DWORD dwAlphaSt, dwSrcBlendSt, dwDestBlendSt;1075D3DMATRIX tx, idTx;10761077HRESULT1078D3DContext::BeginShapeClip()1079{1080HRESULT res = S_OK;1081J2dTraceLn(J2D_TRACE_INFO, "D3DContext::BeginShapeClip");10821083UpdateState(STATE_CHANGE);10841085pd3dDevice->SetRenderState(D3DRS_SCISSORTESTENABLE, FALSE);10861087// save alpha blending state1088pd3dDevice->GetRenderState(D3DRS_ALPHABLENDENABLE, &dwAlphaSt);1089pd3dDevice->GetRenderState(D3DRS_SRCBLEND, &dwSrcBlendSt);1090pd3dDevice->GetRenderState(D3DRS_DESTBLEND, &dwDestBlendSt);10911092pd3dDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);1093pd3dDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ZERO);1094pd3dDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_ONE);10951096pd3dDevice->GetTransform(D3DTS_WORLD, &tx);1097D3DUtils_SetIdentityMatrix(&idTx);1098// translate the clip spans by 1.0f in z direction so that the1099// clip spans are rendered to the z buffer1100idTx._43 = 1.0f;1101pd3dDevice->SetTransform(D3DTS_WORLD, &idTx);11021103// The depth buffer is first cleared with zeroes, which is the farthest1104// plane from the viewer (our projection matrix is an inversed orthogonal1105// transform).1106// To set the clip we'll render the clip spans with Z coordinates of 1.0f1107// (the closest to the viewer). Since all rendering primitives1108// have their vertices' Z coordinate set to 0.0, they will effectively be1109// clipped because the Z depth test for them will fail (vertex with 1.01110// depth is closer than the one with 0.0f)1111pd3dDevice->SetRenderState(D3DRS_ZENABLE, D3DZB_TRUE);1112pd3dDevice->SetRenderState(D3DRS_ZWRITEENABLE, TRUE);1113pd3dDevice->SetRenderState(D3DRS_ZFUNC, D3DCMP_ALWAYS);1114pd3dDevice->Clear(0, NULL, D3DCLEAR_ZBUFFER, 0L, 0.0f, 0x0L);11151116//res = BeginScene(STATE_SHAPE_CLIPOP);11171118return res;1119}11201121HRESULT1122D3DContext::EndShapeClip()1123{1124HRESULT res;11251126// no need for state change, just flush the queue1127res = FlushVertexQueue();11281129// restore alpha blending state1130pd3dDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, dwAlphaSt);1131pd3dDevice->SetRenderState(D3DRS_SRCBLEND, dwSrcBlendSt);1132pd3dDevice->SetRenderState(D3DRS_DESTBLEND, dwDestBlendSt);11331134// resore the transform1135pd3dDevice->SetTransform(D3DTS_WORLD, &tx);11361137// Enable the depth buffer.1138// We disable further updates to the depth buffer: it should only1139// be updated in SetClip method.1140pd3dDevice->SetRenderState(D3DRS_ZWRITEENABLE, FALSE);1141pd3dDevice->SetRenderState(D3DRS_ZFUNC, D3DCMP_LESS);11421143return res;1144}11451146HRESULT1147D3DContext::UploadTileToTexture(D3DResource *pTextureRes, void *pixels,1148jint dstx, jint dsty,1149jint srcx, jint srcy,1150jint srcWidth, jint srcHeight,1151jint srcStride,1152TileFormat srcFormat,1153jint *pPixelsTouchedL,1154jint* pPixelsTouchedR)1155{1156#ifndef PtrAddBytes1157#define PtrAddBytes(p, b) ((void *) (((intptr_t) (p)) + (b)))1158#define PtrCoord(p, x, xinc, y, yinc) PtrAddBytes(p, \1159((ptrdiff_t)(y))*(yinc) + \1160((ptrdiff_t)(x))*(xinc))1161#endif // PtrAddBytes11621163HRESULT res = S_OK;1164IDirect3DTexture9 *pTexture = pTextureRes->GetTexture();1165D3DSURFACE_DESC *pDesc = pTextureRes->GetDesc();1166RECT r = { dstx, dsty, dstx+srcWidth, dsty+srcHeight };1167RECT *pR = &r;1168D3DLOCKED_RECT lockedRect;1169DWORD dwLockFlags = D3DLOCK_NOSYSLOCK;1170// these are only counted for LCD glyph uploads1171jint pixelsTouchedL = 0, pixelsTouchedR = 0;11721173J2dTraceLn(J2D_TRACE_INFO, "D3DContext::UploadTileToTexture");1174J2dTraceLn4(J2D_TRACE_VERBOSE,1175" rect={%-4d, %-4d, %-4d, %-4d}",1176r.left, r.top, r.right, r.bottom);11771178if (pDesc->Usage == D3DUSAGE_DYNAMIC) {1179// it is safe to lock with discard because we don't care about the1180// contents of dynamic textures and dstx,dsty for this case is1181// always 0,0 because we are uploading into a tile texture1182dwLockFlags |= D3DLOCK_DISCARD;1183pR = NULL;1184}11851186if (FAILED(res = pTexture->LockRect(0, &lockedRect, pR, dwLockFlags))) {1187DebugPrintD3DError(res,1188"D3DContext::UploadImageToTexture: could "\1189"not lock texture");1190return res;1191}11921193if (srcFormat == TILEFMT_1BYTE_ALPHA) {1194// either a MaskFill tile, or a grayscale glyph1195if (pDesc->Format == D3DFMT_A8) {1196void *pSrcPixels = PtrCoord(pixels, srcx, 1, srcy, srcStride);1197void *pDstPixels = lockedRect.pBits;1198do {1199memcpy(pDstPixels, pSrcPixels, srcWidth);1200pSrcPixels = PtrAddBytes(pSrcPixels, srcStride);1201pDstPixels = PtrAddBytes(pDstPixels, lockedRect.Pitch);1202} while (--srcHeight > 0);1203}1204else if (pDesc->Format == D3DFMT_A8R8G8B8) {1205jubyte *pSrcPixels = (jubyte*)1206PtrCoord(pixels, srcx, 1, srcy, srcStride);1207jint *pDstPixels = (jint*)lockedRect.pBits;1208for (int yy = 0; yy < srcHeight; yy++) {1209for (int xx = 0; xx < srcWidth; xx++) {1210// only need to set the alpha channel (the D3D texture1211// state will be setup in this case to replicate the1212// alpha channel as needed)1213pDstPixels[xx] = pSrcPixels[xx] << 24;1214}1215pSrcPixels = (jubyte*)PtrAddBytes(pSrcPixels, srcStride);1216pDstPixels = (jint*)PtrAddBytes(pDstPixels, lockedRect.Pitch);1217}1218}1219} else if (srcFormat == TILEFMT_3BYTE_RGB) {1220// LCD glyph with RGB order1221if (pDesc->Format == D3DFMT_R8G8B8) {1222jubyte *pSrcPixels = (jubyte*)1223PtrCoord(pixels, srcx, 3, srcy, srcStride);1224jubyte *pDstPixels = (jubyte*)lockedRect.pBits;1225for (int yy = 0; yy < srcHeight; yy++) {1226for (int xx = 0; xx < srcWidth*3; xx+=3) {1227// alpha channel is ignored in this case1228// (note that this is backwards from what one might1229// expect; it appears that D3DFMT_R8G8B8 is actually1230// laid out in BGR order in memory)1231pDstPixels[xx+0] = pSrcPixels[xx+2];1232pDstPixels[xx+1] = pSrcPixels[xx+1];1233pDstPixels[xx+2] = pSrcPixels[xx+0];1234}1235pixelsTouchedL +=1236(pDstPixels[0+0]|pDstPixels[0+1]|pDstPixels[0+2]) ? 1 : 0;1237jint i = 3*(srcWidth-1);1238pixelsTouchedR +=1239(pDstPixels[i+0]|pDstPixels[i+1]|pDstPixels[i+2]) ? 1 : 0;12401241pSrcPixels = (jubyte*)PtrAddBytes(pSrcPixels, srcStride);1242pDstPixels = (jubyte*)PtrAddBytes(pDstPixels, lockedRect.Pitch);1243}1244}1245else if (pDesc->Format == D3DFMT_A8R8G8B8) {1246jubyte *pSrcPixels = (jubyte*)1247PtrCoord(pixels, srcx, 3, srcy, srcStride);1248jint *pDstPixels = (jint*)lockedRect.pBits;1249for (int yy = 0; yy < srcHeight; yy++) {1250for (int dx = 0, sx = 0; dx < srcWidth; dx++, sx+=3) {1251// alpha channel is ignored in this case1252jubyte r = pSrcPixels[sx+0];1253jubyte g = pSrcPixels[sx+1];1254jubyte b = pSrcPixels[sx+2];1255pDstPixels[dx] = (r << 16) | (g << 8) | (b);1256}1257pixelsTouchedL += (pDstPixels[0] ? 1 : 0);1258pixelsTouchedR += (pDstPixels[srcWidth-1] ? 1 : 0);12591260pSrcPixels = (jubyte*)PtrAddBytes(pSrcPixels, srcStride);1261pDstPixels = (jint*)PtrAddBytes(pDstPixels, lockedRect.Pitch);1262}1263}1264} else if (srcFormat == TILEFMT_3BYTE_BGR) {1265// LCD glyph with BGR order1266if (pDesc->Format == D3DFMT_R8G8B8) {1267void *pSrcPixels = PtrCoord(pixels, srcx, 3, srcy, srcStride);1268void *pDstPixels = lockedRect.pBits;1269jubyte *pbDst;1270do {1271// alpha channel is ignored in this case1272// (note that this is backwards from what one might1273// expect; it appears that D3DFMT_R8G8B8 is actually1274// laid out in BGR order in memory)1275memcpy(pDstPixels, pSrcPixels, srcWidth * 3);12761277pbDst = (jubyte*)pDstPixels;1278pixelsTouchedL +=(pbDst[0+0]|pbDst[0+1]|pbDst[0+2]) ? 1 : 0;1279jint i = 3*(srcWidth-1);1280pixelsTouchedR +=(pbDst[i+0]|pbDst[i+1]|pbDst[i+2]) ? 1 : 0;12811282pSrcPixels = PtrAddBytes(pSrcPixels, srcStride);1283pDstPixels = PtrAddBytes(pDstPixels, lockedRect.Pitch);1284} while (--srcHeight > 0);1285}1286else if (pDesc->Format == D3DFMT_A8R8G8B8) {1287jubyte *pSrcPixels = (jubyte*)1288PtrCoord(pixels, srcx, 3, srcy, srcStride);1289jint *pDstPixels = (jint*)lockedRect.pBits;1290for (int yy = 0; yy < srcHeight; yy++) {1291for (int dx = 0, sx = 0; dx < srcWidth; dx++, sx+=3) {1292// alpha channel is ignored in this case1293jubyte b = pSrcPixels[sx+0];1294jubyte g = pSrcPixels[sx+1];1295jubyte r = pSrcPixels[sx+2];1296pDstPixels[dx] = (r << 16) | (g << 8) | (b);1297}1298pixelsTouchedL += (pDstPixels[0] ? 1 : 0);1299pixelsTouchedR += (pDstPixels[srcWidth-1] ? 1 : 0);13001301pSrcPixels = (jubyte*)PtrAddBytes(pSrcPixels, srcStride);1302pDstPixels = (jint*)PtrAddBytes(pDstPixels, lockedRect.Pitch);1303}1304}1305} else if (srcFormat == TILEFMT_4BYTE_ARGB_PRE) {1306// MaskBlit tile1307if (pDesc->Format == D3DFMT_A8R8G8B8) {1308void *pSrcPixels = PtrCoord(pixels, srcx, 4, srcy, srcStride);1309void *pDstPixels = lockedRect.pBits;1310do {1311memcpy(pDstPixels, pSrcPixels, srcWidth * 4);1312pSrcPixels = PtrAddBytes(pSrcPixels, srcStride);1313pDstPixels = PtrAddBytes(pDstPixels, lockedRect.Pitch);1314} while (--srcHeight > 0);1315}1316} else {1317// should not happen, no-op just in case...1318}13191320if (pPixelsTouchedL) {1321*pPixelsTouchedL = pixelsTouchedL;1322}1323if (pPixelsTouchedR) {1324*pPixelsTouchedR = pixelsTouchedR;1325}13261327return pTexture->UnlockRect(0);1328}13291330HRESULT1331D3DContext::InitLCDGlyphCache()1332{1333if (pLCDGlyphCache == NULL) {1334return D3DGlyphCache::CreateInstance(this, CACHE_LCD, &pLCDGlyphCache);1335}1336return S_OK;1337}13381339HRESULT1340D3DContext::InitGrayscaleGlyphCache()1341{1342if (pGrayscaleGlyphCache == NULL) {1343return D3DGlyphCache::CreateInstance(this, CACHE_GRAY,1344&pGrayscaleGlyphCache);1345}1346return S_OK;1347}13481349HRESULT1350D3DContext::ResetComposite()1351{1352J2dTraceLn(J2D_TRACE_INFO, "D3DContext::ResetComposite");13531354RETURN_STATUS_IF_NULL(pd3dDevice, E_FAIL);13551356HRESULT res = UpdateState(STATE_CHANGE);1357pd3dDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE);1358extraAlpha = 1.0f;1359return res;1360}13611362HRESULT1363D3DContext::SetAlphaComposite(jint rule, jfloat ea, jint flags)1364{1365HRESULT res;1366J2dTraceLn3(J2D_TRACE_INFO,1367"D3DContext::SetAlphaComposite: rule=%-1d ea=%f flags=%d",1368rule, ea, flags);13691370RETURN_STATUS_IF_NULL(pd3dDevice, E_FAIL);13711372res = UpdateState(STATE_CHANGE);13731374// we can safely disable blending when:1375// - comp is SrcNoEa or SrcOverNoEa, and1376// - the source is opaque1377// (turning off blending can have a large positive impact on performance)1378if ((rule == RULE_Src || rule == RULE_SrcOver) &&1379(ea == 1.0f) &&1380(flags & D3DC_SRC_IS_OPAQUE))1381{1382J2dTraceLn1(J2D_TRACE_VERBOSE,1383" disabling alpha comp rule=%-1d ea=1.0 src=opq)", rule);1384pd3dDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE);1385} else {1386J2dTraceLn2(J2D_TRACE_VERBOSE,1387" enabling alpha comp (rule=%-1d ea=%f)", rule, ea);1388pd3dDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);13891390pd3dDevice->SetRenderState(D3DRS_SRCBLEND,1391StdBlendRules[rule].src);1392pd3dDevice->SetRenderState(D3DRS_DESTBLEND,1393StdBlendRules[rule].dst);1394}13951396extraAlpha = ea;1397return res;1398}13991400#ifdef UPDATE_TX14011402// Note: this method of adjusting pixel to texel mapping proved to be1403// difficult to perfect. The current variation works great for id,1404// scale (including all kinds of flips) transforms, but not still not1405// for generic transforms.1406//1407// Since we currently only do DrawTexture with non-id transform we instead1408// adjust the geometry (see D3DVertexCacher::DrawTexture(), SetTransform())1409//1410// In order to enable this code path UpdateTextureTransforms needs to1411// be called in SetTexture(), SetTransform() and ResetTranform().1412HRESULT1413D3DContext::UpdateTextureTransforms(DWORD dwSamplerToUpdate)1414{1415HRESULT res = S_OK;1416DWORD dwSampler, dwMaxSampler;14171418if (dwSamplerToUpdate == -1) {1419// update all used samplers, dwMaxSampler will be set to max1420dwSampler = 0;1421dwSampler = MAX_USED_TEXTURE_SAMPLER;1422J2dTraceLn(J2D_TRACE_INFO, "D3DContext::UpdateTextureTransforms: "\1423"updating all samplers");1424} else {1425// update only given sampler, dwMaxSampler will be set to it as well1426dwSampler = dwSamplerToUpdate;1427dwMaxSampler = dwSamplerToUpdate;1428J2dTraceLn1(J2D_TRACE_INFO, "D3DContext::UpdateTextureTransforms: "\1429"updating sampler %d", dwSampler);1430}14311432do {1433D3DTRANSFORMSTATETYPE state =1434(D3DTRANSFORMSTATETYPE)(D3DTS_TEXTURE0 + dwSampler);1435IDirect3DTexture9 *pTexture = lastTexture[dwSampler];14361437if (pTexture != NULL) {1438D3DMATRIX mt, tx;1439D3DSURFACE_DESC texDesc;14401441pd3dDevice->GetTransform(D3DTS_WORLD, &tx);1442J2dTraceLn4(10,1443" %5f %5f %5f %5f", tx._11, tx._12, tx._13, tx._14);1444J2dTraceLn4(10,1445" %5f %5f %5f %5f", tx._21, tx._22, tx._23, tx._24);1446J2dTraceLn4(10,1447" %5f %5f %5f %5f", tx._31, tx._32, tx._33, tx._34);1448J2dTraceLn4(10,1449" %5f %5f %5f %5f", tx._41, tx._42, tx._43, tx._44);14501451// this formula works for scales and flips1452if (tx._11 == 0.0f) {1453tx._11 = tx._12;1454}1455if (tx._22 == 0.0f) {1456tx._22 = tx._21;1457}14581459pTexture->GetLevelDesc(0, &texDesc);14601461// shift by .5 texel, but take into account1462// the scale factor of the device transform14631464// REMIND: this approach is not entirely correct,1465// as it only takes into account the scale of the device1466// transform.1467mt._31 = (1.0f / (2.0f * texDesc.Width * tx._11));1468mt._32 = (1.0f / (2.0f * texDesc.Height * tx._22));1469J2dTraceLn2(J2D_TRACE_VERBOSE, " offsets: tx=%f ty=%f",1470mt._31, mt._32);14711472pd3dDevice->SetTextureStageState(dwSampler,1473D3DTSS_TEXTURETRANSFORMFLAGS,1474D3DTTFF_COUNT2);1475res = pd3dDevice->SetTransform(state, &mt);1476} else {1477res = pd3dDevice->SetTextureStageState(dwSampler,1478D3DTSS_TEXTURETRANSFORMFLAGS,1479D3DTTFF_DISABLE);1480}1481dwSampler++;1482} while (dwSampler <= dwMaxSampler);14831484return res;1485}1486#endif // UPDATE_TX14871488/**1489* We go into the pains of maintaining the list of set textures1490* instead of just calling GetTexture() and comparing the old one1491* with the new one because it's actually noticeably slower to call1492* GetTexture() (note that we'd have to then call Release() on the1493* texture since GetTexture() increases texture's ref. count).1494*/1495HRESULT1496D3DContext::SetTexture(IDirect3DTexture9 *pTexture, DWORD dwSampler)1497{1498HRESULT res = S_OK;1499J2dTraceLn(J2D_TRACE_INFO, "D3DContext::SetTexture");15001501if (dwSampler < 0 || dwSampler > MAX_USED_TEXTURE_SAMPLER) {1502J2dTraceLn1(J2D_TRACE_ERROR,1503"D3DContext::SetTexture: incorrect sampler: %d", dwSampler);1504return E_FAIL;1505}1506if (lastTexture[dwSampler] != pTexture) {1507if (FAILED(res = FlushVertexQueue())) {1508return res;1509}1510J2dTraceLn2(J2D_TRACE_VERBOSE,1511" new texture=0x%x on sampler %d", pTexture, dwSampler);1512res = pd3dDevice->SetTexture(dwSampler, pTexture);1513if (SUCCEEDED(res)) {1514lastTexture[dwSampler] = pTexture;1515// REMIND: see comment at UpdateTextureTransforms1516#ifdef UPDATE_TX1517res = UpdateTextureTransforms(dwSampler);1518#endif1519} else {1520lastTexture[dwSampler] = NULL;1521}1522}1523return res;1524}15251526HRESULT1527D3DContext::UpdateTextureColorState(DWORD dwState, DWORD dwSampler)1528{1529HRESULT res = S_OK;15301531if (dwState != lastTextureColorState[dwSampler]) {1532res = pd3dDevice->SetTextureStageState(dwSampler,1533D3DTSS_ALPHAARG1, dwState);1534res = pd3dDevice->SetTextureStageState(dwSampler,1535D3DTSS_COLORARG1, dwState);1536lastTextureColorState[dwSampler] = dwState;1537}15381539return res;1540}15411542HRESULT /*NOLOCK*/1543D3DContext::UpdateState(jbyte newState)1544{1545HRESULT res = S_OK;15461547if (opState == newState) {1548// The op is the same as last time, so we can return immediately.1549return res;1550} else if (opState != STATE_CHANGE) {1551res = FlushVertexQueue();1552}15531554switch (opState) {1555case STATE_MASKOP:1556pMaskCache->Disable();1557break;1558case STATE_GLYPHOP:1559D3DTR_DisableGlyphVertexCache(this);1560break;1561case STATE_TEXTUREOP:1562// optimization: certain state changes (those marked STATE_CHANGE)1563// are allowed while texturing is enabled.1564// In this case, we can allow previousOp to remain as it is and1565// then return early.1566if (newState == STATE_CHANGE) {1567return res;1568}1569// REMIND: not necessary if we are switching to MASKOP or GLYPHOP1570// (or a complex paint, for that matter), but would that be a1571// worthwhile optimization?1572SetTexture(NULL);1573break;1574case STATE_AAPGRAMOP:1575res = DisableAAParallelogramProgram();1576break;1577default:1578break;1579}15801581switch (newState) {1582case STATE_MASKOP:1583pMaskCache->Enable();1584UpdateTextureColorState(D3DTA_TEXTURE | D3DTA_ALPHAREPLICATE);1585break;1586case STATE_GLYPHOP:1587D3DTR_EnableGlyphVertexCache(this);1588UpdateTextureColorState(D3DTA_TEXTURE | D3DTA_ALPHAREPLICATE);1589break;1590case STATE_TEXTUREOP:1591UpdateTextureColorState(D3DTA_TEXTURE);1592break;1593case STATE_AAPGRAMOP:1594res = EnableAAParallelogramProgram();1595break;1596default:1597break;1598}15991600opState = newState;16011602return res;1603}16041605HRESULT D3DContext::FlushVertexQueue()1606{1607if (pVCacher != NULL) {1608return pVCacher->Render();1609}1610return E_FAIL;1611}16121613HRESULT D3DContext::BeginScene(jbyte newState)1614{1615if (!pd3dDevice) {1616return E_FAIL;1617} else {1618UpdateState(newState);1619if (!bBeginScenePending) {1620bBeginScenePending = TRUE;1621HRESULT res = pd3dDevice->BeginScene();1622J2dTraceLn(J2D_TRACE_INFO, "D3DContext::BeginScene");1623if (FAILED(res)) {1624// this will cause context reinitialization1625opState = STATE_CHANGE;1626}1627return res;1628}1629return S_OK;1630}1631}16321633HRESULT D3DContext::EndScene() {1634if (bBeginScenePending) {1635FlushVertexQueue();1636bBeginScenePending = FALSE;1637J2dTraceLn(J2D_TRACE_INFO, "D3DContext::EndScene");1638return pd3dDevice->EndScene();1639}1640return S_OK;1641}16421643/**1644* Compiles and links the given fragment shader program. If1645* successful, this function returns a handle to the newly created shader1646* program; otherwise returns 0.1647*/1648IDirect3DPixelShader9 *D3DContext::CreateFragmentProgram(DWORD **shaders,1649ShaderList *programs,1650jint flags)1651{1652DWORD *sourceCode;1653IDirect3DPixelShader9 *pProgram;16541655J2dTraceLn1(J2D_TRACE_INFO,1656"D3DContext::CreateFragmentProgram: flags=%d",1657flags);16581659sourceCode = shaders[flags];1660if (FAILED(pd3dDevice->CreatePixelShader(sourceCode, &pProgram))) {1661J2dRlsTraceLn(J2D_TRACE_ERROR,1662"D3DContext::CreateFragmentProgram: error creating program");1663return NULL;1664}16651666// add it to the cache1667ShaderList_AddProgram(programs, ptr_to_jlong(pProgram),16680 /*unused*/, 0 /*unused*/, flags);16691670return pProgram;1671}16721673/**1674* Locates and enables a fragment program given a list of shader programs1675* (ShaderInfos), using this context's state and flags as search1676* parameters. The "flags" parameter is a bitwise-or'd value that helps1677* differentiate one program for another; the interpretation of this value1678* varies depending on the type of shader (BufImgOp, Paint, etc) but here1679* it is only used to find another ShaderInfo with that same "flags" value.1680*/1681HRESULT D3DContext::EnableFragmentProgram(DWORD **shaders,1682ShaderList *programList,1683jint flags)1684{1685HRESULT res;1686jlong programID;1687IDirect3DPixelShader9 *pProgram;16881689J2dTraceLn(J2D_TRACE_INFO, "D3DContext::EnableFragmentProgram");16901691programID =1692ShaderList_FindProgram(programList,16930 /*unused*/, 0 /*unused*/, flags);16941695pProgram = (IDirect3DPixelShader9 *)jlong_to_ptr(programID);1696if (pProgram == NULL) {1697pProgram = CreateFragmentProgram(shaders, programList, flags);1698if (pProgram == NULL) {1699return E_FAIL;1700}1701}17021703if (FAILED(res = pd3dDevice->SetPixelShader(pProgram))) {1704J2dRlsTraceLn(J2D_TRACE_ERROR,1705"D3DContext::EnableFragmentProgram: error setting pixel shader");1706return res;1707}17081709return S_OK;1710}17111712HRESULT D3DContext::EnableBasicGradientProgram(jint flags)1713{1714return EnableFragmentProgram((DWORD **)gradShaders,1715&basicGradPrograms, flags);1716}17171718HRESULT D3DContext::EnableLinearGradientProgram(jint flags)1719{1720return EnableFragmentProgram((DWORD **)linearShaders,1721&linearGradPrograms, flags);1722}17231724HRESULT D3DContext::EnableRadialGradientProgram(jint flags)1725{1726return EnableFragmentProgram((DWORD **)radialShaders,1727&radialGradPrograms, flags);1728}17291730HRESULT D3DContext::EnableConvolveProgram(jint flags)1731{1732return EnableFragmentProgram((DWORD **)convolveShaders,1733&convolvePrograms, flags);1734}17351736HRESULT D3DContext::EnableRescaleProgram(jint flags)1737{1738return EnableFragmentProgram((DWORD **)rescaleShaders,1739&rescalePrograms, flags);1740}17411742HRESULT D3DContext::EnableLookupProgram(jint flags)1743{1744return EnableFragmentProgram((DWORD **)lookupShaders,1745&lookupPrograms, flags);1746}17471748HRESULT D3DContext::EnableLCDTextProgram()1749{1750HRESULT res;17511752J2dTraceLn(J2D_TRACE_INFO, "D3DContext::EnableLCDTextProgram");17531754if (lcdTextProgram == NULL) {1755if (FAILED(res = pd3dDevice->CreatePixelShader(lcdtext0,1756&lcdTextProgram)))1757{1758return res;1759}1760}17611762if (FAILED(res = pd3dDevice->SetPixelShader(lcdTextProgram))) {1763J2dRlsTraceLn(J2D_TRACE_ERROR,1764"D3DContext::EnableLCDTextProgram: error setting pixel shader");1765return res;1766}17671768return S_OK;1769}17701771HRESULT D3DContext::EnableAAParallelogramProgram()1772{1773HRESULT res;17741775J2dTraceLn(J2D_TRACE_INFO, "D3DContext::EnableAAParallelogramProgram");17761777if (aaPgramProgram == NULL) {1778if (FAILED(res = pd3dDevice->CreatePixelShader(aapgram0,1779&aaPgramProgram))) {1780DebugPrintD3DError(res, "D3DContext::EnableAAParallelogramProgram: "1781"error creating pixel shader");1782return res;1783}1784}17851786if (FAILED(res = pd3dDevice->SetPixelShader(aaPgramProgram))) {1787DebugPrintD3DError(res, "D3DContext::EnableAAParallelogramProgram: "1788"error setting pixel shader");1789return res;1790}17911792return S_OK;1793}17941795HRESULT D3DContext::DisableAAParallelogramProgram()1796{1797HRESULT res;17981799J2dTraceLn(J2D_TRACE_INFO, "D3DContext::DisableAAParallelogramProgram");18001801if (aaPgramProgram != NULL) {1802if (FAILED(res = pd3dDevice->SetPixelShader(NULL))) {1803DebugPrintD3DError(res,1804"D3DContext::DisableAAParallelogramProgram: "1805"error clearing pixel shader");1806return res;1807}1808}18091810return S_OK;1811}18121813BOOL D3DContext::IsAlphaRTSurfaceSupported()1814{1815HRESULT res = pd3dObject->CheckDeviceFormat(adapterOrdinal,1816devCaps.DeviceType,1817curParams.BackBufferFormat,1818D3DUSAGE_RENDERTARGET,1819D3DRTYPE_SURFACE,1820D3DFMT_A8R8G8B8);1821return SUCCEEDED(res);1822}18231824BOOL D3DContext::IsAlphaRTTSupported()1825{1826HRESULT res = pd3dObject->CheckDeviceFormat(adapterOrdinal,1827devCaps.DeviceType,1828curParams.BackBufferFormat,1829D3DUSAGE_RENDERTARGET,1830D3DRTYPE_TEXTURE,1831D3DFMT_A8R8G8B8);1832return SUCCEEDED(res);1833}18341835BOOL D3DContext::IsOpaqueRTTSupported()1836{1837HRESULT res = pd3dObject->CheckDeviceFormat(adapterOrdinal,1838devCaps.DeviceType,1839curParams.BackBufferFormat,1840D3DUSAGE_RENDERTARGET,1841D3DRTYPE_TEXTURE,1842curParams.BackBufferFormat);1843return SUCCEEDED(res);1844}18451846HRESULT D3DContext::InitContextCaps() {1847J2dTraceLn(J2D_TRACE_INFO, "D3DContext::InitContextCaps");1848J2dTraceLn1(J2D_TRACE_VERBOSE, " caps for adapter %d :", adapterOrdinal);18491850if (pd3dDevice == NULL || pd3dObject == NULL) {1851contextCaps = CAPS_EMPTY;1852J2dRlsTraceLn(J2D_TRACE_VERBOSE, " | CAPS_EMPTY");1853return E_FAIL;1854}18551856contextCaps = CAPS_DEVICE_OK;1857J2dRlsTraceLn(J2D_TRACE_VERBOSE, " | CAPS_DEVICE_OK");18581859if (IsAlphaRTSurfaceSupported()) {1860contextCaps |= CAPS_RT_PLAIN_ALPHA;1861J2dRlsTraceLn(J2D_TRACE_VERBOSE, " | CAPS_RT_PLAIN_ALPHA");1862}1863if (IsAlphaRTTSupported()) {1864contextCaps |= CAPS_RT_TEXTURE_ALPHA;1865J2dRlsTraceLn(J2D_TRACE_VERBOSE, " | CAPS_RT_TEXTURE_ALPHA");1866}1867if (IsOpaqueRTTSupported()) {1868contextCaps |= CAPS_RT_TEXTURE_OPAQUE;1869J2dRlsTraceLn(J2D_TRACE_VERBOSE, " | CAPS_RT_TEXTURE_OPAQUE");1870}1871if (IsPixelShader20Supported()) {1872contextCaps |= CAPS_LCD_SHADER | CAPS_BIOP_SHADER | CAPS_PS20;1873J2dRlsTraceLn(J2D_TRACE_VERBOSE,1874" | CAPS_LCD_SHADER | CAPS_BIOP_SHADER | CAPS_PS20");1875// Pre-PS3.0 video boards are very slow with the AA shader, so1876// we will require PS30 hw even though the shader is compiled for 2.0a1877// if (IsGradientInstructionExtensionSupported()) {1878// contextCaps |= CAPS_AA_SHADER;1879// J2dRlsTraceLn(J2D_TRACE_VERBOSE, " | CAPS_AA_SHADER");1880// }1881}1882if (IsPixelShader30Supported()) {1883if ((contextCaps & CAPS_AA_SHADER) == 0) {1884// This flag was not already mentioned above...1885J2dRlsTraceLn(J2D_TRACE_VERBOSE, " | CAPS_AA_SHADER");1886}1887contextCaps |= CAPS_PS30 | CAPS_AA_SHADER;1888J2dRlsTraceLn(J2D_TRACE_VERBOSE, " | CAPS_PS30");1889}1890if (IsMultiTexturingSupported()) {1891contextCaps |= CAPS_MULTITEXTURE;1892J2dRlsTraceLn(J2D_TRACE_VERBOSE, " | CAPS_MULTITEXTURE");1893}1894if (!IsPow2TexturesOnly()) {1895contextCaps |= CAPS_TEXNONPOW2;1896J2dRlsTraceLn(J2D_TRACE_VERBOSE, " | CAPS_TEXNONPOW2");1897}1898if (!IsSquareTexturesOnly()) {1899contextCaps |= CAPS_TEXNONSQUARE;1900J2dRlsTraceLn(J2D_TRACE_VERBOSE, " | CAPS_TEXNONSQUARE");1901}1902return S_OK;1903}190419051906