alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

Java example source code file (D3DContext.cpp)

This example Java source code file (D3DContext.cpp) is included in the alvinalexander.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Learn more about this Java project at its project page.

Java - Java tags/keywords

debugprintd3derror, e_fail, failed, false, flushvertexqueue, hresult, j2drlstraceln, j2dtraceln, j2dtraceln1, null, s_ok, safe_release, succeeded, zeromemory

The D3DContext.cpp Java example source code

/*
 * Copyright (c) 2007, 2008, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */

#include "D3DPipeline.h"
#include "jlong.h"

#include "GraphicsPrimitiveMgr.h"
#include "D3DContext.h"
#include "D3DSurfaceData.h"
#include "D3DBufImgOps.h"
#include "D3DPaints.h"
#include "D3DRenderQueue.h"
#include "D3DShaders.h"
#include "D3DTextRenderer.h"
#include "D3DPipelineManager.h"
#include "D3DGlyphCache.h"

typedef struct {
    D3DBLEND src;
    D3DBLEND dst;
} D3DBlendRule;

/**
 * This table contains the standard blending rules (or Porter-Duff compositing
 * factors) used in SetRenderState(), indexed by the rule constants from the
 * AlphaComposite class.
 */
D3DBlendRule StdBlendRules[] = {
    { D3DBLEND_ZERO,         D3DBLEND_ZERO        }, /* 0 - Nothing      */
    { D3DBLEND_ZERO,         D3DBLEND_ZERO        }, /* 1 - RULE_Clear   */
    { D3DBLEND_ONE,          D3DBLEND_ZERO        }, /* 2 - RULE_Src     */
    { D3DBLEND_ONE,          D3DBLEND_INVSRCALPHA }, /* 3 - RULE_SrcOver */
    { D3DBLEND_INVDESTALPHA, D3DBLEND_ONE         }, /* 4 - RULE_DstOver */
    { D3DBLEND_DESTALPHA,    D3DBLEND_ZERO        }, /* 5 - RULE_SrcIn   */
    { D3DBLEND_ZERO,         D3DBLEND_SRCALPHA    }, /* 6 - RULE_DstIn   */
    { D3DBLEND_INVDESTALPHA, D3DBLEND_ZERO        }, /* 7 - RULE_SrcOut  */
    { D3DBLEND_ZERO,         D3DBLEND_INVSRCALPHA }, /* 8 - RULE_DstOut  */
    { D3DBLEND_ZERO,         D3DBLEND_ONE         }, /* 9 - RULE_Dst     */
    { D3DBLEND_DESTALPHA,    D3DBLEND_INVSRCALPHA }, /*10 - RULE_SrcAtop */
    { D3DBLEND_INVDESTALPHA, D3DBLEND_SRCALPHA    }, /*11 - RULE_DstAtop */
    { D3DBLEND_INVDESTALPHA, D3DBLEND_INVSRCALPHA }, /*12 - RULE_AlphaXor*/
};

void
D3DUtils_SetOrthoMatrixOffCenterLH(D3DMATRIX *m,
                                   float width, float height)
{
    ZeroMemory(m, sizeof(D3DMATRIX));
    m->_11 =  2.0f/width;
    m->_22 = -2.0f/height;
    m->_33 =  0.5f;
    m->_44 =  1.0f;

    m->_41 = -1.0f;
    m->_42 =  1.0f;
    m->_43 =  0.5f;
}

void
D3DUtils_SetIdentityMatrix(D3DMATRIX *m)
{
    m->_12 = m->_13 = m->_14 = m->_21 = m->_23 = m->_24 = 0.0f;
    m->_31 = m->_32 = m->_34 = m->_41 = m->_42 = m->_43 = 0.0f;
    m->_11 = m->_22 = m->_33 = m->_44 = 1.0f;
}

// the following methods are copies of the AffineTransform's class
// corresponding methods, with these changes to the indexes:
// 00 -> 11
// 11 -> 22
// 01 -> 21
// 10 -> 12
// 02 -> 41
// 12 -> 42

void
D3DUtils_2DConcatenateM(D3DMATRIX *m, D3DMATRIX *m1)
{
    float M0, M1;
    float T00, T10, T01, T11;
    float T02, T12;

    T00 = m1->_11; T01 = m1->_21; T02 = m1->_41;
    T10 = m1->_12; T11 = m1->_22; T12 = m1->_42;

    M0 = m->_11;
    M1 = m->_21;
    m->_11  = T00 * M0 + T10 * M1;
    m->_21  = T01 * M0 + T11 * M1;
    m->_41 += T02 * M0 + T12 * M1;

    M0 = m->_12;
    M1 = m->_22;
    m->_12  = T00 * M0 + T10 * M1;
    m->_22  = T01 * M0 + T11 * M1;
    m->_42 += T02 * M0 + T12 * M1;
}

#ifdef UPDATE_TX

void
D3DUtils_2DScaleM(D3DMATRIX *m, float sx, float sy)
{
    m->_11 *= sx;
    m->_22 *= sy;
}

void
D3DUtils_2DInvertM(D3DMATRIX *m)
{
    float M11, M21, M41;
    float M12, M22, M42;
    float det;

    M11 = m->_11; M21 = m->_21; M41 = m->_41;
    M12 = m->_12; M22 = m->_22; M42 = m->_42;
    det = M11 * M22 - M21 * M12;
    if (fabs(det) <= 0.0000000001f) {
        memset(m, 0, sizeof(D3DMATRIX));
        return;
    }
    m->_11 =  M22 / det;
    m->_12 = -M12 / det;
    m->_21 = -M21 / det;
    m->_22 =  M11 / det;
    m->_41 = (M21 * M42 - M22 * M41) / det;
    m->_42 = (M12 * M41 - M11 * M42) / det;
}

void
D3DUtils_2DTranslateM(D3DMATRIX *m, float tx, float ty)
{
    m->_41 = tx * m->_11 + ty * m->_21 + m->_41;
    m->_42 = tx * m->_12 + ty * m->_22 + m->_42;
}

void
D3DUtils_2DTransformXY(D3DMATRIX *m, float *px, float *py)
{
    float x = *px;
    float y = *py;

    *px = x * m->_11 + y * m->_21 + m->_41;
    *py = x * m->_12 + y * m->_22 + m->_42;
}

void
D3DUtils_2DInverseTransformXY(D3DMATRIX *m, float *px, float *py)
{
    float x = *px, y = *py;

    x -= m->_41;
    y -= m->_42;

    float det = m->_11 * m->_22 - m->_21 * m->_12;
    if (fabs(det) < 0.0000000001f) {
        *px = 0.0f;
        *py = 0.0f;
    } else {
        *px = (x * m->_22 - y * m->_21) / det;
        *py = (y * m->_11 - x * m->_12) / det;
    }
}

#endif // UPDATE_TX

static void
D3DContext_DisposeShader(jlong programID)
{
    IDirect3DPixelShader9 *shader =
        (IDirect3DPixelShader9 *)jlong_to_ptr(programID);

    J2dTraceLn(J2D_TRACE_INFO, "D3DContext_DisposeShader");

    SAFE_RELEASE(shader);
}

// static
HRESULT
D3DContext::CreateInstance(IDirect3D9 *pd3d9, UINT adapter, D3DContext **ppCtx)
{
    HRESULT res;
    *ppCtx = new D3DContext(pd3d9, adapter);
    if (FAILED(res = (*ppCtx)->InitContext())) {
        delete *ppCtx;
        *ppCtx = NULL;
    }
    return res;
}

D3DContext::D3DContext(IDirect3D9 *pd3d, UINT adapter)
{
    J2dTraceLn(J2D_TRACE_INFO, "D3DContext::D3DContext");
    J2dTraceLn1(J2D_TRACE_VERBOSE, "  pd3d=0x%x", pd3d);
    pd3dObject = pd3d;
    pd3dDevice = NULL;
    adapterOrdinal = adapter;

    pResourceMgr = NULL;
    pMaskCache = NULL;
    pVCacher = NULL;

    pSyncQuery = NULL;
    pSyncRTRes = NULL;
    pStateBlock = NULL;

    D3DC_INIT_SHADER_LIST(convolvePrograms,   MAX_CONVOLVE);
    D3DC_INIT_SHADER_LIST(rescalePrograms,    MAX_RESCALE);
    D3DC_INIT_SHADER_LIST(lookupPrograms,     MAX_LOOKUP);
    D3DC_INIT_SHADER_LIST(basicGradPrograms,  4);
    D3DC_INIT_SHADER_LIST(linearGradPrograms, 8);
    D3DC_INIT_SHADER_LIST(radialGradPrograms, 8);

    pLCDGlyphCache= NULL;
    pGrayscaleGlyphCache= NULL;
    lcdTextProgram = NULL;
    aaPgramProgram = NULL;

    contextCaps = CAPS_EMPTY;
    bBeginScenePending = FALSE;

    ZeroMemory(&devCaps, sizeof(D3DCAPS9));
    ZeroMemory(&curParams, sizeof(curParams));

    extraAlpha = 1.0f;
}

void D3DContext::ReleaseDefPoolResources()
{
    J2dTraceLn(J2D_TRACE_INFO, "D3DContext::ReleaseDefPoolResources");

    EndScene();

    D3DPipelineManager::NotifyAdapterEventListeners(devCaps.AdapterOrdinal,
                                                    DEVICE_RESET);

    contextCaps = CAPS_EMPTY;

    SAFE_RELEASE(pSyncQuery);
    SAFE_RELEASE(pStateBlock);

    if (pVCacher != NULL) {
        pVCacher->ReleaseDefPoolResources();
    }
    if (pMaskCache != NULL) {
        pMaskCache->ReleaseDefPoolResources();
    }
    if (pLCDGlyphCache != NULL) {
        pLCDGlyphCache->ReleaseDefPoolResources();
    }
    if (pGrayscaleGlyphCache != NULL) {
        pGrayscaleGlyphCache->ReleaseDefPoolResources();
    }
    if (pResourceMgr != NULL) {
        if (pSyncRTRes != NULL) {
            pResourceMgr->ReleaseResource(pSyncRTRes);
            pSyncRTRes = NULL;
        }
        pResourceMgr->ReleaseDefPoolResources();
    }
    ZeroMemory(lastTexture, sizeof(lastTexture));
    ZeroMemory(lastTextureColorState, sizeof(lastTextureColorState));
}

void D3DContext::ReleaseContextResources()
{
    J2dTraceLn1(J2D_TRACE_INFO,
                "D3DContext::ReleaseContextResources: pd3dDevice = 0x%x",
                pd3dDevice);

    ReleaseDefPoolResources();

    D3DPipelineManager::NotifyAdapterEventListeners(devCaps.AdapterOrdinal,
                                                    DEVICE_DISPOSED);

    // dispose shader lists
    ShaderList_Dispose(&convolvePrograms);
    ShaderList_Dispose(&rescalePrograms);
    ShaderList_Dispose(&lookupPrograms);
    ShaderList_Dispose(&basicGradPrograms);
    ShaderList_Dispose(&linearGradPrograms);
    ShaderList_Dispose(&radialGradPrograms);

    SAFE_DELETE(pLCDGlyphCache);
    SAFE_DELETE(pGrayscaleGlyphCache);

    SAFE_RELEASE(lcdTextProgram);
    SAFE_RELEASE(aaPgramProgram);

    SAFE_DELETE(pVCacher);
    SAFE_DELETE(pMaskCache);
    SAFE_DELETE(pResourceMgr);
}

D3DContext::~D3DContext() {
    J2dTraceLn2(J2D_TRACE_INFO,
                "~D3DContext: pd3dDevice=0x%x, pd3dObject =0x%x",
                pd3dDevice, pd3dObject);
    ReleaseContextResources();
    SAFE_RELEASE(pd3dDevice);
}

HRESULT
D3DContext::InitDevice(IDirect3DDevice9 *pd3dDevice)
{
    HRESULT res = S_OK;

    pd3dDevice->GetDeviceCaps(&devCaps);

    J2dRlsTraceLn1(J2D_TRACE_INFO,
                   "D3DContext::InitDevice: device %d", adapterOrdinal);

    // disable some of the unneeded and costly d3d functionality
    pd3dDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
    pd3dDevice->SetRenderState(D3DRS_SPECULARENABLE, FALSE);
    pd3dDevice->SetRenderState(D3DRS_LIGHTING,  FALSE);
    pd3dDevice->SetRenderState(D3DRS_CLIPPING,  FALSE);
    pd3dDevice->SetRenderState(D3DRS_ZENABLE, D3DZB_FALSE);
    pd3dDevice->SetRenderState(D3DRS_ZWRITEENABLE, D3DZB_FALSE);
    pd3dDevice->SetRenderState(D3DRS_COLORVERTEX, FALSE);
    pd3dDevice->SetRenderState(D3DRS_STENCILENABLE, FALSE);

    // set the default texture addressing mode
    pd3dDevice->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP);
    pd3dDevice->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP);

    // REMIND: check supported filters with
    // IDirect3D9::CheckDeviceFormat with D3DUSAGE_QUERY_FILTER
    pd3dDevice->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_POINT);
    pd3dDevice->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_POINT);

    // these states never change
    pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_MODULATE);
    pd3dDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE);
    pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE);
    pd3dDevice->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE);
    pd3dDevice->SetTextureStageState(1, D3DTSS_ALPHAOP, D3DTOP_MODULATE);
    pd3dDevice->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_MODULATE);
    pd3dDevice->SetTextureStageState(1, D3DTSS_ALPHAARG2, D3DTA_CURRENT);
    pd3dDevice->SetTextureStageState(1, D3DTSS_COLORARG2, D3DTA_CURRENT);

    // init the array of latest textures
    ZeroMemory(lastTexture, sizeof(lastTexture));
    ZeroMemory(lastTextureColorState, sizeof(lastTextureColorState));

    opState = STATE_CHANGE;

    if (pResourceMgr == NULL) {
        res = D3DResourceManager::CreateInstance(this, &pResourceMgr);
    } else {
        res = pResourceMgr->Init(this);
    }
    RETURN_STATUS_IF_FAILED(res);

    if (pVCacher == NULL) {
        res = D3DVertexCacher::CreateInstance(this, &pVCacher);
    } else {
        res = pVCacher->Init(this);
    }
    RETURN_STATUS_IF_FAILED(res);

    if (pMaskCache == NULL) {
        res = D3DMaskCache::CreateInstance(this, &pMaskCache);
    } else{
        res = pMaskCache->Init(this);
    }
    RETURN_STATUS_IF_FAILED(res);

    if (pLCDGlyphCache != NULL) {
        if (FAILED(res = pLCDGlyphCache->Init(this))) {
            // we can live without the cache
            SAFE_DELETE(pLCDGlyphCache);
            res = S_OK;
        }
    }

    if (pGrayscaleGlyphCache != NULL) {
        if (FAILED(res = pGrayscaleGlyphCache->Init(this))) {
            // we can live without the cache
            SAFE_DELETE(pGrayscaleGlyphCache);
            res = S_OK;
        }
    }

    D3DMATRIX tx;
    D3DUtils_SetIdentityMatrix(&tx);
    pd3dDevice->SetTransform(D3DTS_WORLD, &tx);
    bIsIdentityTx = TRUE;

    if (pSyncQuery == NULL) {
        // this is allowed to fail, do not propagate the error
        if (FAILED(pd3dDevice->CreateQuery(D3DQUERYTYPE_EVENT, &pSyncQuery))) {
            J2dRlsTraceLn(J2D_TRACE_WARNING,
                          "D3DContext::InitDevice: sync query not available");
            pSyncQuery = NULL;
        }
    }
    if (pSyncRTRes == NULL) {
        D3DFORMAT format;
        if (FAILED(GetResourceManager()->
                   CreateRTSurface(32, 32, TRUE, TRUE, &format, &pSyncRTRes))) {
            J2dRlsTraceLn(J2D_TRACE_WARNING,
                          "D3DContext::InitDevice: "
                          "error creating sync surface");
        }
    }

    bBeginScenePending = FALSE;

    J2dRlsTraceLn1(J2D_TRACE_INFO,
                   "D3DContext::InitDefice: successfully initialized device %d",
                   adapterOrdinal);

    return res;
}

HRESULT
D3DContext::CheckAndResetDevice()
{
    HRESULT res = E_FAIL;

    J2dTraceLn(J2D_TRACE_INFO, "D3DContext::CheckAndResetDevice");

    if (pd3dDevice != NULL) {
        if (FAILED(res = pd3dDevice->TestCooperativeLevel())) {
            if (res == D3DERR_DEVICELOST) {
                J2dTraceLn1(J2D_TRACE_VERBOSE, "  device %d is still lost",
                            adapterOrdinal);
                // nothing to be done here, wait for D3DERR_DEVICENOTRESET
                return res;
            } else if (res == D3DERR_DEVICENOTRESET) {
                J2dTraceLn1(J2D_TRACE_VERBOSE, "  device %d needs to be reset",
                            adapterOrdinal);
                res = ResetContext();
            } else {
                // some unexpected error
                DebugPrintD3DError(res, "D3DContext::CheckAndResetDevice: "\
                                   "unknown error %x from TestCooperativeLevel");
            }
        } else {
            J2dTraceLn1(J2D_TRACE_VERBOSE, "  device %d is not lost",
                        adapterOrdinal);
        }
    } else {
        J2dTraceLn(J2D_TRACE_VERBOSE, "  null device");
    }
    return res;
}

HRESULT
D3DContext::ResetContext()
{
    HRESULT res = E_FAIL;

    J2dRlsTraceLn(J2D_TRACE_INFO, "D3DContext::ResetContext");
    if (pd3dDevice != NULL) {
        D3DPRESENT_PARAMETERS newParams;

        newParams = curParams;

        if (newParams.Windowed) {
            // reset to the current display mode if we're windowed,
            // otherwise to the display mode we were in when the device
            // was lost
            newParams.BackBufferFormat = D3DFMT_UNKNOWN;
            newParams.FullScreen_RefreshRateInHz = 0;
            newParams.BackBufferWidth = 0;
            newParams.BackBufferHeight = 0;
        }
        res = ConfigureContext(&newParams);
    }
    return res;
}

HRESULT
D3DContext::ConfigureContext(D3DPRESENT_PARAMETERS *pNewParams)
{
    J2dRlsTraceLn1(J2D_TRACE_INFO, "D3DContext::ConfigureContext device %d",
                   adapterOrdinal);
    HRESULT res = S_OK;
    D3DFORMAT stencilFormat;
    HWND focusHWND = D3DPipelineManager::GetInstance()->GetCurrentFocusWindow();
    D3DDEVTYPE devType = D3DPipelineManager::GetInstance()->GetDeviceType();
    // this is needed so that we can find the stencil buffer format
    if (pNewParams->BackBufferFormat == D3DFMT_UNKNOWN) {
        D3DDISPLAYMODE dm;

        pd3dObject->GetAdapterDisplayMode(adapterOrdinal, &dm);
        pNewParams->BackBufferFormat = dm.Format;
    }

    stencilFormat =
        D3DPipelineManager::GetInstance()->GetMatchingDepthStencilFormat(
            adapterOrdinal,
            pNewParams->BackBufferFormat, pNewParams->BackBufferFormat);

    pNewParams->EnableAutoDepthStencil = TRUE;
    pNewParams->AutoDepthStencilFormat = stencilFormat;

    // do not set device window in the windowed mode, we use additional
    // swap chains for rendering, the default chain is not used. otherwise
    // our scratch focus window will be made visible
    J2dTraceLn1(J2D_TRACE_VERBOSE, "  windowed=%d",pNewParams->Windowed);
    if (pNewParams->Windowed) {
        pNewParams->hDeviceWindow = (HWND)0;
    }

    // The focus window may change when we're entering/exiting the full-screen
    // mode. It may either be set to the default focus window (when there are
    // no more devices in fs mode), or to fs window for another device
    // in fs mode. See D3DPipelineManager::GetCurrentFocusWindow.
    if (pd3dDevice != NULL) {
        D3DDEVICE_CREATION_PARAMETERS cParams;
        pd3dDevice->GetCreationParameters(&cParams);
        if (cParams.hFocusWindow != focusHWND) {
            J2dTraceLn(J2D_TRACE_VERBOSE,
                       "  focus window changed, need to recreate the device");

            // if fs -> windowed, first exit fs, then recreate, otherwise
            // the screen might be left in a different display mode
            if (pNewParams->Windowed && !curParams.Windowed) {
                J2dTraceLn(J2D_TRACE_VERBOSE,
                            "  exiting full-screen mode, reset the device");
                curParams.Windowed = FALSE;
                ReleaseDefPoolResources();
                res = pd3dDevice->Reset(&curParams);

                if (FAILED(res)) {
                    DebugPrintD3DError(res, "D3DContext::ConfigureContext: "\
                                       "cound not reset the device");
                }
            }

            // note that here we should release all device resources, not only
            // thos in the default pool since the device is released
            ReleaseContextResources();
            SAFE_RELEASE(pd3dDevice);
        }
    }

    if (pd3dDevice != NULL) {
        J2dTraceLn(J2D_TRACE_VERBOSE, "  resetting the device");

        ReleaseDefPoolResources();

        if (pNewParams->PresentationInterval == D3DPRESENT_INTERVAL_IMMEDIATE &&
            !IsImmediateIntervalSupported())
        {
            pNewParams->PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT;
        }

        res = pd3dDevice->Reset(pNewParams);
        if (FAILED(res)) {
            DebugPrintD3DError(res,
                "D3DContext::ConfigureContext: cound not reset the device");
            return res;
        }
        J2dRlsTraceLn1(J2D_TRACE_INFO,
            "D3DContext::ConfigureContext: successfully reset device: %d",
            adapterOrdinal);
    } else {
        D3DCAPS9 d3dCaps;
        DWORD dwBehaviorFlags;

        J2dTraceLn(J2D_TRACE_VERBOSE, "  creating a new device");

        if (FAILED(res = pd3dObject->GetDeviceCaps(adapterOrdinal,
                                                   devType, &d3dCaps)))
        {
            DebugPrintD3DError(res,
                "D3DContext::ConfigureContext: failed to get caps");
            return res;
        }

        if (pNewParams->PresentationInterval == D3DPRESENT_INTERVAL_IMMEDIATE &&
            !(d3dCaps.PresentationIntervals & D3DPRESENT_INTERVAL_IMMEDIATE))
        {
            pNewParams->PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT;
        }

        // not preserving fpu control word could cause issues (4860749)
        dwBehaviorFlags = D3DCREATE_FPU_PRESERVE;

        J2dRlsTrace(J2D_TRACE_VERBOSE,
                    "[V] dwBehaviorFlags=D3DCREATE_FPU_PRESERVE|");
        if (d3dCaps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT) {
            J2dRlsTrace(J2D_TRACE_VERBOSE,
                        "D3DCREATE_HARDWARE_VERTEXPROCESSING");
            dwBehaviorFlags |= D3DCREATE_HARDWARE_VERTEXPROCESSING;
        } else {
            J2dRlsTrace(J2D_TRACE_VERBOSE,
                        "D3DCREATE_SOFTWARE_VERTEXPROCESSING");
            dwBehaviorFlags |= D3DCREATE_SOFTWARE_VERTEXPROCESSING;
        }
        // Handling focus changes by ourselves proved to be problematic,
        // so we're reverting back to D3D handling
        // dwBehaviorFlags |= D3DCREATE_NOWINDOWCHANGES;
        J2dRlsTrace(J2D_TRACE_VERBOSE,"\n");

        if (FAILED(res = pd3dObject->CreateDevice(adapterOrdinal, devType,
                                                  focusHWND,
                                                  dwBehaviorFlags,
                                                  pNewParams, &pd3dDevice)))
        {
            DebugPrintD3DError(res,
                "D3DContext::ConfigureContext: error creating d3d device");
            return res;
        }
        J2dRlsTraceLn1(J2D_TRACE_INFO,
            "D3DContext::ConfigureContext: successfully created device: %d",
            adapterOrdinal);
        bIsHWRasterizer = (devType == D3DDEVTYPE_HAL);
    }

    curParams = *pNewParams;
    // during the creation of the device d3d modifies this field, we reset
    // it back to 0
    curParams.Flags = 0;

    if (FAILED(res = InitDevice(pd3dDevice))) {
        ReleaseContextResources();
        return res;
    }

    res = InitContextCaps();

    return res;
}

HRESULT
D3DContext::InitContext()
{
    J2dRlsTraceLn1(J2D_TRACE_INFO, "D3DContext::InitContext device %d",
                   adapterOrdinal);

    D3DPRESENT_PARAMETERS params;
    ZeroMemory(śms, sizeof(D3DPRESENT_PARAMETERS));

    params.hDeviceWindow = 0;
    params.Windowed = TRUE;
    params.BackBufferCount = 1;
    params.BackBufferFormat = D3DFMT_UNKNOWN;
    params.SwapEffect = D3DSWAPEFFECT_DISCARD;
    params.PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT;

    return ConfigureContext(śms);
}

HRESULT
D3DContext::Sync()
{
    HRESULT res = S_OK;

    J2dTraceLn(J2D_TRACE_INFO, "D3DContext::Sync");

    if (pSyncQuery != NULL) {
        J2dTrace(J2D_TRACE_VERBOSE, "  flushing the device queue..");
        while (S_FALSE ==
               (res = pSyncQuery->GetData(NULL, 0, D3DGETDATA_FLUSH))) ;
        J2dTrace(J2D_TRACE_VERBOSE, ".. done\n");
    }
    if (pSyncRTRes != NULL) {
        D3DLOCKED_RECT lr;
        IDirect3DSurface9 *pSurface = pSyncRTRes->GetSurface();
        if (SUCCEEDED(pSurface->LockRect(&lr, NULL, D3DLOCK_NOSYSLOCK))) {
            pSurface->UnlockRect();
        }
    }
    return res;
}

HRESULT
D3DContext::SaveState()
{
    HRESULT res;

    RETURN_STATUS_IF_NULL(pd3dDevice, S_OK);

    J2dTraceLn(J2D_TRACE_INFO, "D3DContext::SaveState");

    FlushVertexQueue();
    UpdateState(STATE_CHANGE);

    if (pStateBlock != NULL) {
        J2dTraceLn(J2D_TRACE_WARNING,
                   "D3DContext::SaveState: existing state block!");
        SAFE_RELEASE(pStateBlock);
    }

    if (SUCCEEDED(res =
            pd3dDevice->CreateStateBlock(D3DSBT_ALL, &pStateBlock)))
    {
        J2dTraceLn(J2D_TRACE_VERBOSE, "  created state block");
    } else {
        J2dTraceLn(J2D_TRACE_WARNING,
                   "D3DContext::SaveState: failed to create state block");
    }
    ZeroMemory(lastTexture, sizeof(lastTexture));

    return res;
}

HRESULT
D3DContext::RestoreState()
{
    HRESULT res = S_OK;

    J2dTraceLn(J2D_TRACE_INFO, "D3DContext::RestoreState");

    FlushVertexQueue();
    UpdateState(STATE_CHANGE);

    if (pStateBlock != NULL) {
        if (SUCCEEDED(res = pStateBlock->Apply())) {
            J2dTraceLn(J2D_TRACE_VERBOSE, "  restored device state");
        } else {
            J2dTraceLn(J2D_TRACE_WARNING,
                       "D3DContext::RestoreState: failed to restore state");
        }
        SAFE_RELEASE(pStateBlock);
    } else {
        J2dTraceLn(J2D_TRACE_WARNING,
                   "D3DContext::RestoreState: empty state block!");
    }
    ZeroMemory(lastTexture, sizeof(lastTexture));

    return res;
}

#define POINT_FILTER_CAP (D3DPTFILTERCAPS_MAGFPOINT|D3DPTFILTERCAPS_MINFPOINT)
#define LINEAR_FILTER_CAP (D3DPTFILTERCAPS_MAGFLINEAR|D3DPTFILTERCAPS_MINFLINEAR)

BOOL
D3DContext::IsStretchRectFilteringSupported(D3DTEXTUREFILTERTYPE fType)
{
    if (fType == D3DTEXF_POINT) {
        return ((devCaps.StretchRectFilterCaps & POINT_FILTER_CAP) != 0);
    }
    if (fType == D3DTEXF_LINEAR) {
        return ((devCaps.StretchRectFilterCaps & LINEAR_FILTER_CAP) != 0);
    }
    return FALSE;
}

BOOL
D3DContext::IsTextureFilteringSupported(D3DTEXTUREFILTERTYPE fType)
{
    if (fType == D3DTEXF_POINT) {
        return ((devCaps.TextureFilterCaps & POINT_FILTER_CAP) != 0);
    }
    if (fType == D3DTEXF_LINEAR) {
        return ((devCaps.TextureFilterCaps & LINEAR_FILTER_CAP) != 0);
    }
    return FALSE;
}

BOOL
D3DContext::IsTextureFormatSupported(D3DFORMAT format, DWORD usage)
{
    HRESULT hr = pd3dObject->CheckDeviceFormat(adapterOrdinal,
                                               devCaps.DeviceType,
                                               curParams.BackBufferFormat,
                                               usage,
                                               D3DRTYPE_TEXTURE,
                                               format);
    return SUCCEEDED( hr );
}

BOOL
D3DContext::IsDepthStencilBufferOk(D3DSURFACE_DESC *pTargetDesc)
{
    IDirect3DSurface9 *pStencil;
    J2dTraceLn(J2D_TRACE_INFO, "D3DContext::IsDepthStencilBufferOk");

    if (SUCCEEDED(pd3dDevice->GetDepthStencilSurface(&pStencil))) {
        D3DSURFACE_DESC descStencil;
        pStencil->GetDesc(&descStencil);
        pStencil->Release();

        D3DDISPLAYMODE dm;
        return
            (SUCCEEDED(pd3dDevice->GetDisplayMode(0, &dm)) &&
             pTargetDesc->Width <= descStencil.Width &&
             pTargetDesc->Height <= descStencil.Height &&
             SUCCEEDED(pd3dObject->CheckDepthStencilMatch(
                   adapterOrdinal,
                   devCaps.DeviceType,
                   dm.Format, pTargetDesc->Format,
                   descStencil.Format)));
    }
    J2dTraceLn(J2D_TRACE_VERBOSE,
        "  current stencil buffer is not compatible with new Render Target");

    return false;
}



HRESULT
D3DContext::InitDepthStencilBuffer(D3DSURFACE_DESC *pTargetDesc)
{
    HRESULT res;
    IDirect3DSurface9 *pBB;
    D3DDISPLAYMODE dm;

    J2dTraceLn(J2D_TRACE_INFO, "D3DContext::InitDepthStencilBuffer");

    if (FAILED(res = pd3dDevice->GetDisplayMode(0, &dm))) {
        return res;
    }

    D3DFORMAT newFormat =
        D3DPipelineManager::GetInstance()->GetMatchingDepthStencilFormat(
            adapterOrdinal, dm.Format, pTargetDesc->Format);

    res = pd3dDevice->CreateDepthStencilSurface(
        pTargetDesc->Width, pTargetDesc->Height,
        newFormat, D3DMULTISAMPLE_NONE, 0, false, &pBB, 0);
    if (SUCCEEDED(res)) {
        res = pd3dDevice->SetDepthStencilSurface(pBB);
        pBB->Release();
    }

    return res;
}


HRESULT
D3DContext::SetRenderTarget(IDirect3DSurface9 *pSurface)
{
    static D3DMATRIX tx;
    HRESULT res;
    D3DSURFACE_DESC descNew;
    IDirect3DSurface9 *pCurrentTarget;

    J2dTraceLn1(J2D_TRACE_INFO,
                "D3DContext::SetRenderTarget: pSurface=0x%x",
                pSurface);

    RETURN_STATUS_IF_NULL(pd3dDevice, E_FAIL);
    RETURN_STATUS_IF_NULL(pSurface, E_FAIL);

    pSurface->GetDesc(&descNew);

    if (SUCCEEDED(res = pd3dDevice->GetRenderTarget(0, &pCurrentTarget))) {
        if (pCurrentTarget != pSurface) {
            FlushVertexQueue();
            if (FAILED(res = pd3dDevice->SetRenderTarget(0, pSurface))) {
                DebugPrintD3DError(res, "D3DContext::SetRenderTarget: "\
                                        "error setting render target");
                SAFE_RELEASE(pCurrentTarget);
                return res;
            }

            if (!IsDepthStencilBufferOk(&descNew)) {
                if (FAILED(res = InitDepthStencilBuffer(&descNew))) {
                    SAFE_RELEASE(pCurrentTarget);
                    return res;
                }
            }
        }
        SAFE_RELEASE(pCurrentTarget);
    }
    // we set the transform even if the render target didn't change;
    // this is because in some cases (fs mode) we use the default SwapChain of
    // the device, and its render target will be the same as the device's, and
    // we have to set the matrix correctly. This shouldn't be a performance
    // issue as render target changes are relatively rare
    D3DUtils_SetOrthoMatrixOffCenterLH(&tx,
                       (float)descNew.Width,
                       (float)descNew.Height);
    pd3dDevice->SetTransform(D3DTS_PROJECTION, &tx);

    J2dTraceLn1(J2D_TRACE_VERBOSE, "  current render target=0x%x", pSurface);
    return res;
}

HRESULT
D3DContext::ResetTransform()
{
    HRESULT res = S_OK;
    D3DMATRIX tx;

    J2dTraceLn(J2D_TRACE_INFO, "D3DContext::ResetTransform");
    if (pd3dDevice == NULL) {
        return E_FAIL;
    }

    // no need for state change, just flush the queue
    FlushVertexQueue();

    D3DUtils_SetIdentityMatrix(&tx);
    if (FAILED(res = pd3dDevice->SetTransform(D3DTS_WORLD, &tx))) {
        DebugPrintD3DError(res, "D3DContext::SetTransform failed");
    }
    bIsIdentityTx = TRUE;
    return res;
}

HRESULT
D3DContext::SetTransform(jdouble m00, jdouble m10,
                         jdouble m01, jdouble m11,
                         jdouble m02, jdouble m12)
{
    HRESULT res = S_OK;
    D3DMATRIX tx, tx1;

    J2dTraceLn(J2D_TRACE_INFO, "D3DContext::SetTransform");
    if (pd3dDevice == NULL) {
        return E_FAIL;
    }

    // no need for state change, just flush the queue
    FlushVertexQueue();

    // In order to correctly map texels to pixels we need to
    // adjust geometry by -0.5f in the transformed space.
    // In order to do that we first create a translated matrix
    // and then concatenate it with the world transform.
    //
    // Note that we only use non-id transform with DrawTexture,
    // the rest is rendered pre-transformed.
    //
    // The identity transform for textures is handled in
    // D3DVertexCacher::DrawTexture() because shifting by -0.5 for id
    // transform breaks lines rendering.

    ZeroMemory(&tx1, sizeof(D3DMATRIX));

    tx1._11 = (float)m00;
    tx1._12 = (float)m10;
    tx1._21 = (float)m01;
    tx1._22 = (float)m11;
    tx1._41 = (float)m02;
    tx1._42 = (float)m12;

    tx1._33 = 1.0f;
    tx1._44 = 1.0f;

    D3DUtils_SetIdentityMatrix(&tx);
    tx._41 = -0.5f;
    tx._42 = -0.5f;
    D3DUtils_2DConcatenateM(&tx, &tx1);

    J2dTraceLn4(J2D_TRACE_VERBOSE,
                "  %5f %5f %5f %5f", tx._11, tx._12, tx._13, tx._14);
    J2dTraceLn4(J2D_TRACE_VERBOSE,
                "  %5f %5f %5f %5f", tx._21, tx._22, tx._23, tx._24);
    J2dTraceLn4(J2D_TRACE_VERBOSE,
                "  %5f %5f %5f %5f", tx._31, tx._32, tx._33, tx._34);
    J2dTraceLn4(J2D_TRACE_VERBOSE,
                "  %5f %5f %5f %5f", tx._41, tx._42, tx._43, tx._44);
    if (FAILED(res = pd3dDevice->SetTransform(D3DTS_WORLD, &tx))) {
        DebugPrintD3DError(res, "D3DContext::SetTransform failed");
    }
    bIsIdentityTx = FALSE;

    return res;
}

HRESULT
D3DContext::SetRectClip(int x1, int y1, int x2, int y2)
{
    HRESULT res = S_OK;
    D3DSURFACE_DESC desc;
    IDirect3DSurface9 *pCurrentTarget;

    J2dTraceLn(J2D_TRACE_INFO, "D3DContext::SetRectClip");
    J2dTraceLn4(J2D_TRACE_VERBOSE,
                "  x1=%-4d y1=%-4d x2=%-4d y2=%-4d",
                x1, y1, x2, y2);

    RETURN_STATUS_IF_NULL(pd3dDevice, E_FAIL);

    // no need for state change, just flush the queue
    FlushVertexQueue();

    pd3dDevice->SetRenderState(D3DRS_ZENABLE, D3DZB_FALSE);

    res = pd3dDevice->GetRenderTarget(0, &pCurrentTarget);
    RETURN_STATUS_IF_FAILED(res);

    pCurrentTarget->GetDesc(&desc);
    SAFE_RELEASE(pCurrentTarget);

    if (x1 <= 0 && y1 <= 0 &&
        (UINT)x2 >= desc.Width && (UINT)y2 >= desc.Height)
    {
        J2dTraceLn(J2D_TRACE_VERBOSE,
                   "  disabling clip (== render target dimensions)");
        return pd3dDevice->SetRenderState(D3DRS_SCISSORTESTENABLE, FALSE);
    }

    // clip to the dimensions of the target surface, otherwise
    // SetScissorRect will fail
    if (x1 < 0)                 x1 = 0;
    if (y1 < 0)                 y1 = 0;
    if ((UINT)x2 > desc.Width)  x2 = desc.Width;
    if ((UINT)y2 > desc.Height) y2 = desc.Height;
    if (x1 > x2)                x2 = x1 = 0;
    if (y1 > y2)                y2 = y1 = 0;
    RECT newRect = { x1, y1, x2, y2 };
    if (SUCCEEDED(res = pd3dDevice->SetScissorRect(&newRect))) {
        res = pd3dDevice->SetRenderState(D3DRS_SCISSORTESTENABLE, TRUE);
    } else {
        DebugPrintD3DError(res, "Error setting scissor rect");
        J2dRlsTraceLn4(J2D_TRACE_ERROR,
                       "  x1=%-4d y1=%-4d x2=%-4d y2=%-4d",
                       x1, y1, x2, y2);
    }

    return res;
}

HRESULT
D3DContext::ResetClip()
{
    J2dTraceLn(J2D_TRACE_INFO, "D3DContext::ResetClip");
    // no need for state change, just flush the queue
    FlushVertexQueue();
    pd3dDevice->SetRenderState(D3DRS_SCISSORTESTENABLE, FALSE);
    return pd3dDevice->SetRenderState(D3DRS_ZENABLE, D3DZB_FALSE);
}

ClipType
D3DContext::GetClipType()
{
    // REMIND: this method could be optimized: we could keep the
    // clip state around when re/setting the clip instead of asking
    // every time.
    DWORD zEnabled = 0;
    DWORD stEnabled = 0;

    J2dTraceLn(J2D_TRACE_INFO, "D3DContext::GetClipType");
    pd3dDevice->GetRenderState(D3DRS_SCISSORTESTENABLE, &stEnabled);
    if (stEnabled) {
        return CLIP_RECT;
    }
    pd3dDevice->GetRenderState(D3DRS_ZENABLE, &zEnabled);
    if (zEnabled) {
        return CLIP_SHAPE;
    }
    return CLIP_NONE;
}


/**
 * This method assumes that ::SetRenderTarget has already
 * been called. SetRenderTarget creates and attaches a
 * depth buffer to the target surface prior to setting it
 * as target surface to the device.
 */
DWORD dwAlphaSt, dwSrcBlendSt, dwDestBlendSt;
D3DMATRIX tx, idTx;

HRESULT
D3DContext::BeginShapeClip()
{
    HRESULT res = S_OK;
    J2dTraceLn(J2D_TRACE_INFO, "D3DContext::BeginShapeClip");

    UpdateState(STATE_CHANGE);

    pd3dDevice->SetRenderState(D3DRS_SCISSORTESTENABLE, FALSE);

    // save alpha blending state
    pd3dDevice->GetRenderState(D3DRS_ALPHABLENDENABLE, &dwAlphaSt);
    pd3dDevice->GetRenderState(D3DRS_SRCBLEND, &dwSrcBlendSt);
    pd3dDevice->GetRenderState(D3DRS_DESTBLEND, &dwDestBlendSt);

    pd3dDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
    pd3dDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ZERO);
    pd3dDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_ONE);

    pd3dDevice->GetTransform(D3DTS_WORLD, &tx);
    D3DUtils_SetIdentityMatrix(&idTx);
    // translate the clip spans by 1.0f in z direction so that the
    // clip spans are rendered to the z buffer
    idTx._43 = 1.0f;
    pd3dDevice->SetTransform(D3DTS_WORLD, &idTx);

    // The depth buffer is first cleared with zeroes, which is the farthest
    // plane from the viewer (our projection matrix is an inversed orthogonal
    // transform).
    // To set the clip we'll render the clip spans with Z coordinates of 1.0f
    // (the closest to the viewer). Since all rendering primitives
    // have their vertices' Z coordinate set to 0.0, they will effectively be
    // clipped because the Z depth test for them will fail (vertex with 1.0
    // depth is closer than the one with 0.0f)
    pd3dDevice->SetRenderState(D3DRS_ZENABLE, D3DZB_TRUE);
    pd3dDevice->SetRenderState(D3DRS_ZWRITEENABLE, TRUE);
    pd3dDevice->SetRenderState(D3DRS_ZFUNC, D3DCMP_ALWAYS);
    pd3dDevice->Clear(0, NULL, D3DCLEAR_ZBUFFER, 0L, 0.0f, 0x0L);

    //res = BeginScene(STATE_SHAPE_CLIPOP);

    return res;
}

HRESULT
D3DContext::EndShapeClip()
{
    HRESULT res;

    // no need for state change, just flush the queue
    res = FlushVertexQueue();

    // restore alpha blending state
    pd3dDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, dwAlphaSt);
    pd3dDevice->SetRenderState(D3DRS_SRCBLEND, dwSrcBlendSt);
    pd3dDevice->SetRenderState(D3DRS_DESTBLEND, dwDestBlendSt);

    // resore the transform
    pd3dDevice->SetTransform(D3DTS_WORLD, &tx);

    // Enable the depth buffer.
    // We disable further updates to the depth buffer: it should only
    // be updated in SetClip method.
    pd3dDevice->SetRenderState(D3DRS_ZWRITEENABLE, FALSE);
    pd3dDevice->SetRenderState(D3DRS_ZFUNC, D3DCMP_LESS);

    return res;
}

HRESULT
D3DContext::UploadTileToTexture(D3DResource *pTextureRes, void *pixels,
                                jint dstx, jint dsty,
                                jint srcx, jint srcy,
                                jint srcWidth, jint srcHeight,
                                jint srcStride,
                                TileFormat srcFormat,
                                jint *pPixelsTouchedL,
                                jint* pPixelsTouchedR)
{
#ifndef PtrAddBytes
#define PtrAddBytes(p, b)               ((void *) (((intptr_t) (p)) + (b)))
#define PtrCoord(p, x, xinc, y, yinc)   PtrAddBytes(p, (y)*(yinc) + (x)*(xinc))
#endif // PtrAddBytes

    HRESULT res = S_OK;
    IDirect3DTexture9 *pTexture = pTextureRes->GetTexture();
    D3DSURFACE_DESC *pDesc = pTextureRes->GetDesc();
    RECT r = { dstx, dsty, dstx+srcWidth, dsty+srcHeight };
    RECT *pR = &r;
    D3DLOCKED_RECT lockedRect;
    DWORD dwLockFlags = D3DLOCK_NOSYSLOCK;
    // these are only counted for LCD glyph uploads
    jint pixelsTouchedL = 0, pixelsTouchedR = 0;

    J2dTraceLn(J2D_TRACE_INFO, "D3DContext::UploadTileToTexture");
    J2dTraceLn4(J2D_TRACE_VERBOSE,
        " rect={%-4d, %-4d, %-4d, %-4d}",
        r.left, r.top, r.right, r.bottom);

    if (pDesc->Usage == D3DUSAGE_DYNAMIC) {
        // it is safe to lock with discard because we don't care about the
        // contents of dynamic textures and dstx,dsty for this case is
        // always 0,0 because we are uploading into a tile texture
        dwLockFlags |= D3DLOCK_DISCARD;
        pR = NULL;
    }

    if (FAILED(res = pTexture->LockRect(0, &lockedRect, pR, dwLockFlags))) {
        DebugPrintD3DError(res,
            "D3DContext::UploadImageToTexture: could "\
            "not lock texture");
        return res;
    }

    if (srcFormat == TILEFMT_1BYTE_ALPHA) {
        // either a MaskFill tile, or a grayscale glyph
        if (pDesc->Format == D3DFMT_A8) {
            void *pSrcPixels = PtrCoord(pixels, srcx, 1, srcy, srcStride);
            void *pDstPixels = lockedRect.pBits;
            do {
                memcpy(pDstPixels, pSrcPixels, srcWidth);
                pSrcPixels = PtrAddBytes(pSrcPixels, srcStride);
                pDstPixels = PtrAddBytes(pDstPixels, lockedRect.Pitch);
            } while (--srcHeight > 0);
        }
        else if (pDesc->Format == D3DFMT_A8R8G8B8) {
            jubyte *pSrcPixels = (jubyte*)
                PtrCoord(pixels, srcx, 1, srcy, srcStride);
            jint *pDstPixels = (jint*)lockedRect.pBits;
            for (int yy = 0; yy < srcHeight; yy++) {
                for (int xx = 0; xx < srcWidth; xx++) {
                    // only need to set the alpha channel (the D3D texture
                    // state will be setup in this case to replicate the
                    // alpha channel as needed)
                    pDstPixels[xx] = pSrcPixels[xx] << 24;
                }
                pSrcPixels = (jubyte*)PtrAddBytes(pSrcPixels, srcStride);
                pDstPixels = (jint*)PtrAddBytes(pDstPixels, lockedRect.Pitch);
            }
        }
    } else if (srcFormat == TILEFMT_3BYTE_RGB) {
        // LCD glyph with RGB order
        if (pDesc->Format == D3DFMT_R8G8B8) {
            jubyte *pSrcPixels = (jubyte*)
                PtrCoord(pixels, srcx, 3, srcy, srcStride);
            jubyte *pDstPixels = (jubyte*)lockedRect.pBits;
            for (int yy = 0; yy < srcHeight; yy++) {
                for (int xx = 0; xx < srcWidth*3; xx+=3) {
                    // alpha channel is ignored in this case
                    // (note that this is backwards from what one might
                    // expect; it appears that D3DFMT_R8G8B8 is actually
                    // laid out in BGR order in memory)
                    pDstPixels[xx+0] = pSrcPixels[xx+2];
                    pDstPixels[xx+1] = pSrcPixels[xx+1];
                    pDstPixels[xx+2] = pSrcPixels[xx+0];
                }
                pixelsTouchedL +=
                    (pDstPixels[0+0]|pDstPixels[0+1]|pDstPixels[0+2]) ? 1 : 0;
                jint i = 3*(srcWidth-1);
                pixelsTouchedR +=
                    (pDstPixels[i+0]|pDstPixels[i+1]|pDstPixels[i+2]) ? 1 : 0;

                pSrcPixels = (jubyte*)PtrAddBytes(pSrcPixels, srcStride);
                pDstPixels = (jubyte*)PtrAddBytes(pDstPixels, lockedRect.Pitch);
            }
        }
        else if (pDesc->Format == D3DFMT_A8R8G8B8) {
            jubyte *pSrcPixels = (jubyte*)
                PtrCoord(pixels, srcx, 3, srcy, srcStride);
            jint *pDstPixels = (jint*)lockedRect.pBits;
            for (int yy = 0; yy < srcHeight; yy++) {
                for (int dx = 0, sx = 0; dx < srcWidth; dx++, sx+=3) {
                    // alpha channel is ignored in this case
                    jubyte r = pSrcPixels[sx+0];
                    jubyte g = pSrcPixels[sx+1];
                    jubyte b = pSrcPixels[sx+2];
                    pDstPixels[dx] = (r << 16) | (g << 8) | (b);
                }
                pixelsTouchedL += (pDstPixels[0]          ? 1 : 0);
                pixelsTouchedR += (pDstPixels[srcWidth-1] ? 1 : 0);

                pSrcPixels = (jubyte*)PtrAddBytes(pSrcPixels, srcStride);
                pDstPixels = (jint*)PtrAddBytes(pDstPixels, lockedRect.Pitch);
            }
        }
    } else if (srcFormat == TILEFMT_3BYTE_BGR) {
        // LCD glyph with BGR order
        if (pDesc->Format == D3DFMT_R8G8B8) {
            void *pSrcPixels = PtrCoord(pixels, srcx, 3, srcy, srcStride);
            void *pDstPixels = lockedRect.pBits;
            jubyte *pbDst;
            do {
                // alpha channel is ignored in this case
                // (note that this is backwards from what one might
                // expect; it appears that D3DFMT_R8G8B8 is actually
                // laid out in BGR order in memory)
                memcpy(pDstPixels, pSrcPixels, srcWidth * 3);

                pbDst = (jubyte*)pDstPixels;
                pixelsTouchedL +=(pbDst[0+0]|pbDst[0+1]|pbDst[0+2]) ? 1 : 0;
                jint i = 3*(srcWidth-1);
                pixelsTouchedR +=(pbDst[i+0]|pbDst[i+1]|pbDst[i+2]) ? 1 : 0;

                pSrcPixels = PtrAddBytes(pSrcPixels, srcStride);
                pDstPixels = PtrAddBytes(pDstPixels, lockedRect.Pitch);
            } while (--srcHeight > 0);
        }
        else if (pDesc->Format == D3DFMT_A8R8G8B8) {
            jubyte *pSrcPixels = (jubyte*)
                PtrCoord(pixels, srcx, 3, srcy, srcStride);
            jint *pDstPixels = (jint*)lockedRect.pBits;
            for (int yy = 0; yy < srcHeight; yy++) {
                for (int dx = 0, sx = 0; dx < srcWidth; dx++, sx+=3) {
                    // alpha channel is ignored in this case
                    jubyte b = pSrcPixels[sx+0];
                    jubyte g = pSrcPixels[sx+1];
                    jubyte r = pSrcPixels[sx+2];
                    pDstPixels[dx] = (r << 16) | (g << 8) | (b);
                }
                pixelsTouchedL += (pDstPixels[0]          ? 1 : 0);
                pixelsTouchedR += (pDstPixels[srcWidth-1] ? 1 : 0);

                pSrcPixels = (jubyte*)PtrAddBytes(pSrcPixels, srcStride);
                pDstPixels = (jint*)PtrAddBytes(pDstPixels, lockedRect.Pitch);
            }
        }
    } else if (srcFormat == TILEFMT_4BYTE_ARGB_PRE) {
        // MaskBlit tile
        if (pDesc->Format == D3DFMT_A8R8G8B8) {
            void *pSrcPixels = PtrCoord(pixels, srcx, 4, srcy, srcStride);
            void *pDstPixels = lockedRect.pBits;
            do {
                memcpy(pDstPixels, pSrcPixels, srcWidth * 4);
                pSrcPixels = PtrAddBytes(pSrcPixels, srcStride);
                pDstPixels = PtrAddBytes(pDstPixels, lockedRect.Pitch);
            } while (--srcHeight > 0);
        }
    } else {
        // should not happen, no-op just in case...
    }

    if (pPixelsTouchedL) {
        *pPixelsTouchedL  = pixelsTouchedL;
    }
    if (pPixelsTouchedR) {
        *pPixelsTouchedR = pixelsTouchedR;
    }

    return pTexture->UnlockRect(0);
}

HRESULT
D3DContext::InitLCDGlyphCache()
{
    if (pLCDGlyphCache == NULL) {
        return D3DGlyphCache::CreateInstance(this, CACHE_LCD, &pLCDGlyphCache);
    }
    return S_OK;
}

HRESULT
D3DContext::InitGrayscaleGlyphCache()
{
    if (pGrayscaleGlyphCache == NULL) {
        return D3DGlyphCache::CreateInstance(this, CACHE_GRAY,
                                             &pGrayscaleGlyphCache);
    }
    return S_OK;
}

HRESULT
D3DContext::ResetComposite()
{
    J2dTraceLn(J2D_TRACE_INFO, "D3DContext::ResetComposite");

    RETURN_STATUS_IF_NULL(pd3dDevice, E_FAIL);

    HRESULT res = UpdateState(STATE_CHANGE);
    pd3dDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE);
    extraAlpha = 1.0f;
    return res;
}

HRESULT
D3DContext::SetAlphaComposite(jint rule, jfloat ea, jint flags)
{
    HRESULT res;
    J2dTraceLn3(J2D_TRACE_INFO,
                "D3DContext::SetAlphaComposite: rule=%-1d ea=%f flags=%d",
                rule, ea, flags);

    RETURN_STATUS_IF_NULL(pd3dDevice, E_FAIL);

    res = UpdateState(STATE_CHANGE);

    // we can safely disable blending when:
    //   - comp is SrcNoEa or SrcOverNoEa, and
    //   - the source is opaque
    // (turning off blending can have a large positive impact on performance)
    if ((rule == RULE_Src || rule == RULE_SrcOver) &&
        (ea == 1.0f) &&
        (flags & D3DC_SRC_IS_OPAQUE))
    {
        J2dTraceLn1(J2D_TRACE_VERBOSE,
                    "  disabling alpha comp rule=%-1d ea=1.0 src=opq)", rule);
        pd3dDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE);
    } else {
        J2dTraceLn2(J2D_TRACE_VERBOSE,
                    "  enabling alpha comp (rule=%-1d ea=%f)", rule, ea);
        pd3dDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);

        pd3dDevice->SetRenderState(D3DRS_SRCBLEND,
                                   StdBlendRules[rule].src);
        pd3dDevice->SetRenderState(D3DRS_DESTBLEND,
                                   StdBlendRules[rule].dst);
    }

    extraAlpha = ea;
    return res;
}

#ifdef UPDATE_TX

// Note: this method of adjusting pixel to texel mapping proved to be
// difficult to perfect. The current variation works great for id,
// scale (including all kinds of flips) transforms, but not still not
// for generic transforms.
//
// Since we currently only do DrawTexture with non-id transform we instead
// adjust the geometry (see D3DVertexCacher::DrawTexture(), SetTransform())
//
// In order to enable this code path UpdateTextureTransforms needs to
// be called in SetTexture(), SetTransform() and ResetTranform().
HRESULT
D3DContext::UpdateTextureTransforms(DWORD dwSamplerToUpdate)
{
    HRESULT res = S_OK;
    DWORD dwSampler, dwMaxSampler;

    if (dwSamplerToUpdate == -1) {
        // update all used samplers, dwMaxSampler will be set to max
        dwSampler = 0;
        dwSampler = MAX_USED_TEXTURE_SAMPLER;
        J2dTraceLn(J2D_TRACE_INFO, "D3DContext::UpdateTextureTransforms: "\
                                   "updating all samplers");
    } else {
        // update only given sampler, dwMaxSampler will be set to it as well
        dwSampler = dwSamplerToUpdate;
        dwMaxSampler = dwSamplerToUpdate;
        J2dTraceLn1(J2D_TRACE_INFO, "D3DContext::UpdateTextureTransforms: "\
                                    "updating sampler %d", dwSampler);
    }

    do {
        D3DTRANSFORMSTATETYPE state =
            (D3DTRANSFORMSTATETYPE)(D3DTS_TEXTURE0 + dwSampler);
        IDirect3DTexture9 *pTexture = lastTexture[dwSampler];

        if (pTexture != NULL) {
            D3DMATRIX mt, tx;
            D3DSURFACE_DESC texDesc;

            pd3dDevice->GetTransform(D3DTS_WORLD, &tx);
            J2dTraceLn4(10,
                        "  %5f %5f %5f %5f", tx._11, tx._12, tx._13, tx._14);
            J2dTraceLn4(10,
                        "  %5f %5f %5f %5f", tx._21, tx._22, tx._23, tx._24);
            J2dTraceLn4(10,
                        "  %5f %5f %5f %5f", tx._31, tx._32, tx._33, tx._34);
            J2dTraceLn4(10,
                        "  %5f %5f %5f %5f", tx._41, tx._42, tx._43, tx._44);

            // this formula works for scales and flips
            if (tx._11 == 0.0f) {
                tx._11 = tx._12;
            }
            if (tx._22 == 0.0f) {
                tx._22 = tx._21;
            }

            pTexture->GetLevelDesc(0, &texDesc);

            // shift by .5 texel, but take into account
            // the scale factor of the device transform

            // REMIND: this approach is not entirely correct,
            // as it only takes into account the scale of the device
            // transform.
            mt._31 = (1.0f / (2.0f * texDesc.Width  * tx._11));
            mt._32 = (1.0f / (2.0f * texDesc.Height * tx._22));
            J2dTraceLn2(J2D_TRACE_VERBOSE, "  offsets: tx=%f ty=%f",
                        mt._31, mt._32);

            pd3dDevice->SetTextureStageState(dwSampler,
                                             D3DTSS_TEXTURETRANSFORMFLAGS,
                                             D3DTTFF_COUNT2);
            res = pd3dDevice->SetTransform(state, &mt);
        } else {
            res = pd3dDevice->SetTextureStageState(dwSampler,
                                                   D3DTSS_TEXTURETRANSFORMFLAGS,
                                                   D3DTTFF_DISABLE);
        }
        dwSampler++;
    } while (dwSampler <= dwMaxSampler);

    return res;
}
#endif // UPDATE_TX

/**
 * We go into the pains of maintaining the list of set textures
 * instead of just calling GetTexture() and comparing the old one
 * with the new one because it's actually noticeably slower to call
 * GetTexture() (note that we'd have to then call Release() on the
 * texture since GetTexture() increases texture's ref. count).
 */
HRESULT
D3DContext::SetTexture(IDirect3DTexture9 *pTexture, DWORD dwSampler)
{
    HRESULT res = S_OK;
    J2dTraceLn(J2D_TRACE_INFO, "D3DContext::SetTexture");

    if (dwSampler < 0 || dwSampler > MAX_USED_TEXTURE_SAMPLER) {
        J2dTraceLn1(J2D_TRACE_ERROR,
                    "D3DContext::SetTexture: incorrect sampler: %d", dwSampler);
        return E_FAIL;
    }
    if (lastTexture[dwSampler] != pTexture) {
        if (FAILED(res = FlushVertexQueue())) {
            return res;
        }
        J2dTraceLn2(J2D_TRACE_VERBOSE,
                    "  new texture=0x%x on sampler %d", pTexture, dwSampler);
        res = pd3dDevice->SetTexture(dwSampler, pTexture);
        if (SUCCEEDED(res)) {
            lastTexture[dwSampler] = pTexture;
            // REMIND: see comment at UpdateTextureTransforms
#ifdef UPDATE_TX
            res = UpdateTextureTransforms(dwSampler);
#endif
        }  else {
            lastTexture[dwSampler] = NULL;
        }
    }
    return res;
}

HRESULT
D3DContext::UpdateTextureColorState(DWORD dwState, DWORD dwSampler)
{
    HRESULT res = S_OK;

    if (dwState != lastTextureColorState[dwSampler]) {
        res = pd3dDevice->SetTextureStageState(dwSampler,
                                               D3DTSS_ALPHAARG1, dwState);
        res = pd3dDevice->SetTextureStageState(dwSampler,
                                               D3DTSS_COLORARG1, dwState);
        lastTextureColorState[dwSampler] = dwState;
    }

    return res;
}

HRESULT /*NOLOCK*/
D3DContext::UpdateState(jbyte newState)
{
    HRESULT res = S_OK;

    if (opState == newState) {
        // The op is the same as last time, so we can return immediately.
        return res;
    } else if (opState != STATE_CHANGE) {
        res = FlushVertexQueue();
    }

    switch (opState) {
    case STATE_MASKOP:
        pMaskCache->Disable();
        break;
    case STATE_GLYPHOP:
        D3DTR_DisableGlyphVertexCache(this);
        break;
    case STATE_TEXTUREOP:
        // optimization: certain state changes (those marked STATE_CHANGE)
        // are allowed while texturing is enabled.
        // In this case, we can allow previousOp to remain as it is and
        // then return early.
        if (newState == STATE_CHANGE) {
            return res;
        }
        // REMIND: not necessary if we are switching to MASKOP or GLYPHOP
        // (or a complex paint, for that matter), but would that be a
        // worthwhile optimization?
        SetTexture(NULL);
        break;
    case STATE_AAPGRAMOP:
        res = DisableAAParallelogramProgram();
        break;
    default:
        break;
    }

    switch (newState) {
    case STATE_MASKOP:
        pMaskCache->Enable();
        UpdateTextureColorState(D3DTA_TEXTURE | D3DTA_ALPHAREPLICATE);
        break;
    case STATE_GLYPHOP:
        D3DTR_EnableGlyphVertexCache(this);
        UpdateTextureColorState(D3DTA_TEXTURE | D3DTA_ALPHAREPLICATE);
        break;
    case STATE_TEXTUREOP:
        UpdateTextureColorState(D3DTA_TEXTURE);
        break;
    case STATE_AAPGRAMOP:
        res = EnableAAParallelogramProgram();
        break;
    default:
        break;
    }

    opState = newState;

    return res;
}

HRESULT D3DContext::FlushVertexQueue()
{
    if (pVCacher != NULL) {
        return pVCacher->Render();
    }
    return E_FAIL;
}

HRESULT D3DContext::BeginScene(jbyte newState)
{
    if (!pd3dDevice) {
        return E_FAIL;
    } else {
        UpdateState(newState);
        if (!bBeginScenePending) {
            bBeginScenePending = TRUE;
            HRESULT res = pd3dDevice->BeginScene();
            J2dTraceLn(J2D_TRACE_INFO, "D3DContext::BeginScene");
            if (FAILED(res)) {
                // this will cause context reinitialization
                opState = STATE_CHANGE;
            }
            return res;
        }
        return S_OK;
    }
}

HRESULT D3DContext::EndScene() {
    if (bBeginScenePending) {
        FlushVertexQueue();
        bBeginScenePending = FALSE;
        J2dTraceLn(J2D_TRACE_INFO, "D3DContext::EndScene");
        return pd3dDevice->EndScene();
    }
    return S_OK;
}

/**
 * Compiles and links the given fragment shader program.  If
 * successful, this function returns a handle to the newly created shader
 * program; otherwise returns 0.
 */
IDirect3DPixelShader9 *D3DContext::CreateFragmentProgram(DWORD **shaders,
                                                       ShaderList *programs,
                                                       jint flags)
{
    DWORD *sourceCode;
    IDirect3DPixelShader9 *pProgram;

    J2dTraceLn1(J2D_TRACE_INFO,
                "D3DContext::CreateFragmentProgram: flags=%d",
                flags);

    sourceCode = shaders[flags];
    if (FAILED(pd3dDevice->CreatePixelShader(sourceCode, &pProgram))) {
        J2dRlsTraceLn(J2D_TRACE_ERROR,
            "D3DContext::CreateFragmentProgram: error creating program");
        return NULL;
    }

    // add it to the cache
    ShaderList_AddProgram(programs, ptr_to_jlong(pProgram),
                          0 /*unused*/, 0 /*unused*/, flags);

    return pProgram;
}

/**
 * Locates and enables a fragment program given a list of shader programs
 * (ShaderInfos), using this context's state and flags as search
 * parameters.  The "flags" parameter is a bitwise-or'd value that helps
 * differentiate one program for another; the interpretation of this value
 * varies depending on the type of shader (BufImgOp, Paint, etc) but here
 * it is only used to find another ShaderInfo with that same "flags" value.
 */
HRESULT D3DContext::EnableFragmentProgram(DWORD **shaders,
                                          ShaderList *programList,
                                          jint flags)
{
    HRESULT res;
    jlong programID;
    IDirect3DPixelShader9 *pProgram;

    J2dTraceLn(J2D_TRACE_INFO, "D3DContext::EnableFragmentProgram");

    programID =
        ShaderList_FindProgram(programList,
                               0 /*unused*/, 0 /*unused*/, flags);

    pProgram = (IDirect3DPixelShader9 *)jlong_to_ptr(programID);
    if (pProgram == NULL) {
        pProgram = CreateFragmentProgram(shaders, programList, flags);
        if (pProgram == NULL) {
            return E_FAIL;
        }
    }

    if (FAILED(res = pd3dDevice->SetPixelShader(pProgram))) {
        J2dRlsTraceLn(J2D_TRACE_ERROR,
            "D3DContext::EnableFragmentProgram: error setting pixel shader");
        return res;
    }

    return S_OK;
}

HRESULT D3DContext::EnableBasicGradientProgram(jint flags)
{
    return EnableFragmentProgram((DWORD **)gradShaders,
                                 &basicGradPrograms, flags);
}

HRESULT D3DContext::EnableLinearGradientProgram(jint flags)
{
    return EnableFragmentProgram((DWORD **)linearShaders,
                                 &linearGradPrograms, flags);
}

HRESULT D3DContext::EnableRadialGradientProgram(jint flags)
{
    return EnableFragmentProgram((DWORD **)radialShaders,
                                 &radialGradPrograms, flags);
}

HRESULT D3DContext::EnableConvolveProgram(jint flags)
{
    return EnableFragmentProgram((DWORD **)convolveShaders,
                                 &convolvePrograms, flags);
}

HRESULT D3DContext::EnableRescaleProgram(jint flags)
{
    return EnableFragmentProgram((DWORD **)rescaleShaders,
                                 &rescalePrograms, flags);
}

HRESULT D3DContext::EnableLookupProgram(jint flags)
{
    return EnableFragmentProgram((DWORD **)lookupShaders,
                                 &lookupPrograms, flags);
}

HRESULT D3DContext::EnableLCDTextProgram()
{
    HRESULT res;

    J2dTraceLn(J2D_TRACE_INFO, "D3DContext::EnableLCDTextProgram");

    if (lcdTextProgram == NULL) {
        if (FAILED(res = pd3dDevice->CreatePixelShader(lcdtext0,
                                                       &lcdTextProgram)))
        {
            return res;
        }
    }

    if (FAILED(res = pd3dDevice->SetPixelShader(lcdTextProgram))) {
        J2dRlsTraceLn(J2D_TRACE_ERROR,
            "D3DContext::EnableLCDTextProgram: error setting pixel shader");
        return res;
    }

    return S_OK;
}

HRESULT D3DContext::EnableAAParallelogramProgram()
{
    HRESULT res;

    J2dTraceLn(J2D_TRACE_INFO, "D3DContext::EnableAAParallelogramProgram");

    if (aaPgramProgram == NULL) {
        if (FAILED(res = pd3dDevice->CreatePixelShader(aapgram0,
                                                       &aaPgramProgram))) {
            DebugPrintD3DError(res, "D3DContext::EnableAAParallelogramProgram: "
                               "error creating pixel shader");
            return res;
        }
    }

    if (FAILED(res = pd3dDevice->SetPixelShader(aaPgramProgram))) {
        DebugPrintD3DError(res, "D3DContext::EnableAAParallelogramProgram: "
                           "error setting pixel shader");
        return res;
    }

    return S_OK;
}

HRESULT D3DContext::DisableAAParallelogramProgram()
{
    HRESULT res;

    J2dTraceLn(J2D_TRACE_INFO, "D3DContext::DisableAAParallelogramProgram");

    if (aaPgramProgram != NULL) {
        if (FAILED(res = pd3dDevice->SetPixelShader(NULL))) {
            DebugPrintD3DError(res,
                               "D3DContext::DisableAAParallelogramProgram: "
                               "error clearing pixel shader");
            return res;
        }
    }

    return S_OK;
}

BOOL D3DContext::IsAlphaRTSurfaceSupported()
{
    HRESULT res = pd3dObject->CheckDeviceFormat(adapterOrdinal,
            devCaps.DeviceType,
            curParams.BackBufferFormat,
            D3DUSAGE_RENDERTARGET,
            D3DRTYPE_SURFACE,
            D3DFMT_A8R8G8B8);
    return SUCCEEDED(res);
}

BOOL D3DContext::IsAlphaRTTSupported()
{
    HRESULT res = pd3dObject->CheckDeviceFormat(adapterOrdinal,
            devCaps.DeviceType,
            curParams.BackBufferFormat,
            D3DUSAGE_RENDERTARGET,
            D3DRTYPE_TEXTURE,
            D3DFMT_A8R8G8B8);
    return SUCCEEDED(res);
}

BOOL D3DContext::IsOpaqueRTTSupported()
{
    HRESULT res = pd3dObject->CheckDeviceFormat(adapterOrdinal,
            devCaps.DeviceType,
            curParams.BackBufferFormat,
            D3DUSAGE_RENDERTARGET,
            D3DRTYPE_TEXTURE,
            curParams.BackBufferFormat);
    return SUCCEEDED(res);
}

HRESULT D3DContext::InitContextCaps() {
    J2dTraceLn(J2D_TRACE_INFO, "D3DContext::InitContextCaps");
    J2dTraceLn1(J2D_TRACE_VERBOSE, "  caps for adapter %d :", adapterOrdinal);

    if (pd3dDevice == NULL || pd3dObject == NULL) {
        contextCaps = CAPS_EMPTY;
        J2dRlsTraceLn(J2D_TRACE_VERBOSE, "  | CAPS_EMPTY");
        return E_FAIL;
    }

    contextCaps = CAPS_DEVICE_OK;
    J2dRlsTraceLn(J2D_TRACE_VERBOSE, "  | CAPS_DEVICE_OK");

    if (IsAlphaRTSurfaceSupported()) {
        contextCaps |= CAPS_RT_PLAIN_ALPHA;
        J2dRlsTraceLn(J2D_TRACE_VERBOSE, "  | CAPS_RT_PLAIN_ALPHA");
    }
    if (IsAlphaRTTSupported()) {
        contextCaps |= CAPS_RT_TEXTURE_ALPHA;
        J2dRlsTraceLn(J2D_TRACE_VERBOSE, "  | CAPS_RT_TEXTURE_ALPHA");
    }
    if (IsOpaqueRTTSupported()) {
        contextCaps |= CAPS_RT_TEXTURE_OPAQUE;
        J2dRlsTraceLn(J2D_TRACE_VERBOSE, "  | CAPS_RT_TEXTURE_OPAQUE");
    }
    if (IsPixelShader20Supported()) {
        contextCaps |= CAPS_LCD_SHADER | CAPS_BIOP_SHADER | CAPS_PS20;
        J2dRlsTraceLn(J2D_TRACE_VERBOSE,
                      "  | CAPS_LCD_SHADER | CAPS_BIOP_SHADER | CAPS_PS20");
        // Pre-PS3.0 video boards are very slow with the AA shader, so
        // we will require PS30 hw even though the shader is compiled for 2.0a
//        if (IsGradientInstructionExtensionSupported()) {
//            contextCaps |= CAPS_AA_SHADER;
//            J2dRlsTraceLn(J2D_TRACE_VERBOSE, "  | CAPS_AA_SHADER");
//        }
    }
    if (IsPixelShader30Supported()) {
        if ((contextCaps & CAPS_AA_SHADER) == 0) {
            // This flag was not already mentioned above...
            J2dRlsTraceLn(J2D_TRACE_VERBOSE, "  | CAPS_AA_SHADER");
        }
        contextCaps |= CAPS_PS30 | CAPS_AA_SHADER;
        J2dRlsTraceLn(J2D_TRACE_VERBOSE, "  | CAPS_PS30");
    }
    if (IsMultiTexturingSupported()) {
        contextCaps |= CAPS_MULTITEXTURE;
        J2dRlsTraceLn(J2D_TRACE_VERBOSE, "  | CAPS_MULTITEXTURE");
    }
    if (!IsPow2TexturesOnly()) {
        contextCaps |= CAPS_TEXNONPOW2;
        J2dRlsTraceLn(J2D_TRACE_VERBOSE, "  | CAPS_TEXNONPOW2");
    }
    if (!IsSquareTexturesOnly()) {
        contextCaps |= CAPS_TEXNONSQUARE;
        J2dRlsTraceLn(J2D_TRACE_VERBOSE, "  | CAPS_TEXNONSQUARE");
    }
    return S_OK;
}

Other Java examples (source code examples)

Here is a short list of links related to this Java D3DContext.cpp source code file:

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.