jdk/src/windows/native/sun/java2d/d3d/D3DSurfaceData.cpp
author duke
Sat, 01 Dec 2007 00:00:00 +0000
changeset 2 90ce3da70b43
child 887 0aab8d3fa11a
permissions -rw-r--r--
Initial load

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

#include "D3DSurfaceData.h"
#include "D3DContext.h"
#include "jlong.h"
#include "jni_util.h"
#include "Trace.h"
#include "ddrawUtils.h"
#include "Devices.h"

#include "Win32SurfaceData.h"
#include "sun_java2d_d3d_D3DBackBufferSurfaceData.h"

extern LockFunc Win32OSSD_Lock;
extern GetRasInfoFunc Win32OSSD_GetRasInfo;
extern UnlockFunc Win32OSSD_Unlock;
extern DisposeFunc Win32OSSD_Dispose;
extern GetDCFunc Win32OSSD_GetDC;
extern ReleaseDCFunc Win32OSSD_ReleaseDC;
extern InvalidateSDFunc Win32OSSD_InvalidateSD;
extern RestoreSurfaceFunc Win32OSSD_RestoreSurface;
extern DisposeFunc Win32BBSD_Dispose;

extern "C" {

RestoreSurfaceFunc D3DSD_RestoreSurface;

/*
 * D3D-surface specific restore function.
 * We need to make sure the D3DContext is notified if the
 * surface is lost (only if this surface is the current target,
 * otherwise it's possible that it'll get restored (along with its
 * depth buffer), and the context will still think that the clipping
 * that's set for this surface is valid.
 * Consider this scenario:
 * do {
 *     vi.validate(gc); // validated, vi's surface is restored, clipping is lost
 *     // render stuff using d3d, clipping is reset
 *     // -> surface loss event happens
 *     // do a DD blit of the VI to the screen
 *     // at this point the VI surface will be marked lost
 *     // and will be restored in validate() next time around,
 *     // losing the clipping w/o notifying the D3D context
 * } while (vi.surfaceLost());
 */
void D3DSD_RestoreSurface(JNIEnv *env, Win32SDOps *wsdo) {
    J2dTraceLn(J2D_TRACE_INFO, "D3DSD_RestoreSurface");
    D3DSDOps *d3dsdo = (D3DSDOps *)wsdo;
    // This is needed only for non-textures, since textures can't
    // lose their surfaces, as they're managed.
    if (!(d3dsdo->d3dType & D3D_TEXTURE_SURFACE) && wsdo->lpSurface != NULL)
    {
        if (wsdo->ddInstance != NULL && wsdo->ddInstance->ddObject != NULL) {
            D3DContext *d3dContext =
                wsdo->ddInstance->ddObject->GetD3dContext();
            if (d3dContext != NULL) {
                d3dContext->InvalidateIfTarget(env, wsdo->lpSurface);
            }
        }
    }
    Win32OSSD_RestoreSurface(env, wsdo);
}

/*
 * Class:     sun_java2d_d3d_D3DSurfaceData
 * Method:    initOps
 * Signature: (Ljava/lang/Object;)V
 */
JNIEXPORT void JNICALL
Java_sun_java2d_d3d_D3DSurfaceData_initOps(JNIEnv *env,
                                           jobject wsd,
                                           jint depth,
                                           jint transparency)
{
    J2dTraceLn(J2D_TRACE_INFO, "D3DSurfaceData_initOps");
    Win32SDOps *wsdo = (Win32SDOps *)SurfaceData_InitOps(env, wsd,
                                                         sizeof(D3DSDOps));
    wsdo->sdOps.Lock = Win32OSSD_Lock;
    wsdo->sdOps.GetRasInfo = Win32OSSD_GetRasInfo;
    wsdo->sdOps.Unlock = Win32OSSD_Unlock;
    wsdo->sdOps.Dispose = Win32OSSD_Dispose;
    wsdo->RestoreSurface = D3DSD_RestoreSurface;
    wsdo->GetDC = Win32OSSD_GetDC;
    wsdo->ReleaseDC = Win32OSSD_ReleaseDC;
    wsdo->InvalidateSD = Win32OSSD_InvalidateSD;
    wsdo->invalid = JNI_FALSE;
    wsdo->lockType = WIN32SD_LOCK_UNLOCKED;
    wsdo->window = NULL;
    wsdo->backBufferCount = 0;
    wsdo->depth = depth;
    switch (depth) {
        case 8:
            wsdo->pixelStride = 1;
            break;
        case 15: //555
            wsdo->pixelStride = 2;
            wsdo->pixelMasks[0] = 0x1f << 10;
            wsdo->pixelMasks[1] = 0x1f << 5;
            wsdo->pixelMasks[2] = 0x1f;
            break;
        case 16: //565
            wsdo->pixelStride = 2;
            wsdo->pixelMasks[0] = 0x1f << 11;
            wsdo->pixelMasks[1] = 0x3f << 5;
            wsdo->pixelMasks[2] = 0x1f;
            break;
        case 24:
            wsdo->pixelStride = 3;
            break;
        case 32: //x888
            wsdo->pixelStride = 4;
            wsdo->pixelMasks[0] = 0xff0000;
            wsdo->pixelMasks[1] = 0x00ff00;
            wsdo->pixelMasks[2] = 0x0000ff;
            break;
    }
    wsdo->surfaceLock = new CriticalSection();
    wsdo->surfaceLost = FALSE;
    wsdo->transparency = transparency;
    wsdo->surfacePuntData.usingDDSystem = FALSE;
    wsdo->surfacePuntData.lpSurfaceSystem = NULL;
    wsdo->surfacePuntData.lpSurfaceVram = NULL;
    wsdo->surfacePuntData.numBltsSinceRead = 0;
    wsdo->surfacePuntData.pixelsReadSinceBlt = 0;
    wsdo->surfacePuntData.numBltsThreshold = 2;
    wsdo->gdiOpPending = FALSE;
}

jboolean init_D3DSDO(JNIEnv* env, Win32SDOps* wsdo, jint width, jint height,
                     jint d3dSurfaceType, jint screen)
{
    // default in case of an error
    wsdo->lpSurface = NULL;
    wsdo->ddInstance = NULL;

    {
        Devices::InstanceAccess devices;
        wsdo->device = devices->GetDeviceReference(screen, FALSE);
    }
    if (wsdo->device == NULL) {
        J2dTraceLn1(J2D_TRACE_WARNING,
                    "init_D3DSDO: Incorrect "\
                    "screen number (screen=%d)", screen);
        wsdo->invalid = TRUE;
        return JNI_FALSE;
    }
    wsdo->w = width;
    wsdo->h = height;
    wsdo->surfacePuntData.disablePunts = TRUE;
    return JNI_TRUE;
}

/*
 * Class:     sun_java2d_d3d_D3DSurfaceData
 * Method:    initOffScreenSurface
 * Signature: (JJJIIII)I
 */
JNIEXPORT jint JNICALL
Java_sun_java2d_d3d_D3DSurfaceData_initOffScreenSurface
    (JNIEnv *env, jobject sData,
     jlong pCtx,
     jlong pData, jlong parentPdata,
     jint width, jint height,
     jint d3dSurfaceType, jint screen)
{
    Win32SDOps *wsdo = (Win32SDOps *)jlong_to_ptr(pData);
    D3DContext *pd3dc = (D3DContext *)jlong_to_ptr(pCtx);

    J2dTraceLn(J2D_TRACE_INFO, "D3DSurfaceData_initOffScreenSurface");
    J2dTraceLn4(J2D_TRACE_VERBOSE,
                "  width=%-4d height=%-4d type=%-3d scr=%-3d",
                width, height, d3dSurfaceType, screen);

    // REMIND: ideally this should be done in initOps
    if (d3dSurfaceType == D3D_ATTACHED_SURFACE) {
        wsdo->sdOps.Dispose = Win32BBSD_Dispose;
    }

    if (init_D3DSDO(env, wsdo, width, height,
                    d3dSurfaceType, screen) == JNI_FALSE)
    {
        SurfaceData_ThrowInvalidPipeException(env,
            "Can't create offscreen surface");
        return PF_INVALID;
    }

    HMONITOR hMon = (HMONITOR)wsdo->device->GetMonitor();
    DDrawObjectStruct *ddInstance = GetDDInstanceForDevice(hMon);
    if (!ddInstance || !ddInstance->valid || !pd3dc) {
        return PF_INVALID;
    }

    if (d3dSurfaceType == D3D_ATTACHED_SURFACE) {
        // REMIND: still using the old path. ideally the creation of attached
        // surface shoudld be done in the same way as other types of surfaces,
        // that is, in D3DContext::CreateSurface, but we really don't use
        // anything from D3DContext to get an attached surface, so this
        // was left here.

        Win32SDOps *wsdo_parent = (Win32SDOps *)jlong_to_ptr(parentPdata);
        // we're being explicit here: requesting backbuffer, and render target
        DDrawSurface* pNew = wsdo_parent->lpSurface == NULL ?
            NULL :
            wsdo_parent->lpSurface->
                GetDDAttachedSurface(DDSCAPS_BACKBUFFER|DDSCAPS_3DDEVICE);
        if (pNew == NULL ||
            FAILED(pd3dc->AttachDepthBuffer(pNew->GetDXSurface())))
        {
            J2dRlsTraceLn1(J2D_TRACE_ERROR,
                           "D3DSD_initSurface: GetAttachedSurface for parent"\
                           " wsdo_parent->lpSurface=0x%x failed",
                           wsdo_parent->lpSurface);
            if (pNew != NULL) {
                delete pNew;
            }
            SurfaceData_ThrowInvalidPipeException(env,
                "Can't create attached offscreen surface");
            return PF_INVALID;
        }

        wsdo->lpSurface = pNew;
        wsdo->ddInstance = ddInstance;
        J2dTraceLn2(J2D_TRACE_VERBOSE,
                    "D3DSD_initSurface: created attached surface: "\
                    "wsdo->lpSurface=0x%x for parent "\
                    "wsdo_parent->lpSurface=0x%x",
                    wsdo->lpSurface, wsdo_parent->lpSurface);
        // we don't care about pixel format for non-texture surfaces
        return PF_INVALID;
    }

    DXSurface *dxSurface = NULL;
    jint pf = PF_INVALID;
    HRESULT res;
    if (SUCCEEDED(res = pd3dc->CreateSurface(env, wsdo->w, wsdo->h,
                                             wsdo->depth, wsdo->transparency,
                                             d3dSurfaceType,
                                             &dxSurface, &pf)))
    {
        // REMIND: put all the error-handling stuff here from
        // DDCreateOffScreenSurface
        wsdo->lpSurface = new DDrawSurface(ddInstance->ddObject, dxSurface);
        wsdo->surfacePuntData.lpSurfaceVram = wsdo->lpSurface;
        wsdo->ddInstance = ddInstance;
        // the dimensions of the surface may be adjusted in case of
        // textures
        wsdo->w = dxSurface->GetWidth();
        wsdo->h = dxSurface->GetHeight();
        J2dTraceLn1(J2D_TRACE_VERBOSE,
                    "D3DSurfaceData_initSurface: created surface: "\
                    "wsdo->lpSurface=0x%x", wsdo->lpSurface);
    } else {
        DebugPrintDirectDrawError(res,
                                  "D3DSurfaceData_initSurface: "\
                                  "CreateSurface failed");
        // REMIND: should use some other way to signal that
        // surface creation was unsuccessful
        SurfaceData_ThrowInvalidPipeException(env,
                                              "Can't create offscreen surf");
    }
    return pf;
}

/*
 * Class:     sun_java2d_d3d_D3DBackBufferSurfaceData
 * Method:    restoreDepthBuffer
 * Signature: ()V
 */
JNIEXPORT void JNICALL
Java_sun_java2d_d3d_D3DBackBufferSurfaceData_restoreDepthBuffer(JNIEnv *env,
                                                                jobject sData)
{
    Win32SDOps *wsdo = Win32SurfaceData_GetOpsNoSetup(env, sData);
    J2dTraceLn1(J2D_TRACE_INFO,
                "D3DBBSD_restoreDepthBuffer: wsdo=0x%x", wsdo);

    if (wsdo != NULL) {
        if (!DDRestoreSurface(wsdo)) {
            // Failure - throw exception
            J2dRlsTraceLn(J2D_TRACE_ERROR,
                          "D3DBBSD_restoreDepthBuffer: failed to "\
                          "restore depth buffer");

            SurfaceData_ThrowInvalidPipeException(env,
                                                  "RestoreDepthBuffer failure");
        }
    }
}

}