/* * 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 "ddrawUtils.h" #include "D3DUtils.h" #include "D3DSurfaceData.h" #ifdef DEBUG // These strings must be in the same order as pixel // formats in D3DSurfaceData.java char * TR_NAMES[] = { "TR_OPAQUE", "TR_BITMASK", "TR_TRANSLUCENT" }; char * PF_NAMES[] = { "PF_INVALID" , "PF_INT_ARGB" , "PF_INT_RGB" , "PF_INT_RGBX", "PF_INT_BGR" , "PF_USHORT_565_RGB" , "PF_USHORT_555_RGB" , "PF_USHORT_555_RGBX" , "PF_INT_ARGB_PRE" , "PF_USHORT_4444_ARGB" }; #endif // DEBUG /** * This structure could be used when searching for a pixel * format with preferred bit depth. */ typedef struct { // Pointer to a DDPIXELFORMAT structure where the found pixel // format will be copied to DDPIXELFORMAT *pddpf; // If TRUE, the search was successful, FALSE otherwise BOOL bFoundFormat; // Preferred bit depth int preferredDepth; } PixelFormatSearchStruct; jint D3DUtils_GetPixelFormatType(DDPIXELFORMAT*lpddpf); HRESULT WINAPI EnumAlphaTextureFormatsCallback(DDPIXELFORMAT* pddpf, VOID* pContext ) { J2dTraceLn(J2D_TRACE_VERBOSE, "EnumAlphaTextureFormatsCallback"); DDPIXELFORMAT* pddpfOut = (DDPIXELFORMAT*)pContext; // Looking for a 8-bit luminance texture (and probably not alpha-luminance) if((pddpf->dwFlags & DDPF_ALPHA) && (pddpf->dwAlphaBitDepth == 8)) { memcpy(pddpfOut, pddpf, sizeof(DDPIXELFORMAT)); return D3DENUMRET_CANCEL; } return D3DENUMRET_OK; } HRESULT CALLBACK D3DUtils_TextureSearchCallback(DDPIXELFORMAT *lpddpf, void *param) { J2dTraceLn(J2D_TRACE_VERBOSE, "D3DUtils_TextureSearchCallback"); jint pfType = D3DUtils_GetPixelFormatType(lpddpf); if (pfType == PF_INVALID) { return DDENUMRET_OK; } DWORD dwAlphaBitCount = 0; if (lpddpf->dwFlags & DDPF_ALPHAPIXELS) { DWORD dwMask = lpddpf->dwRGBAlphaBitMask; while( dwMask ) { dwMask = dwMask & ( dwMask - 1 ); dwAlphaBitCount++; } } DWORD dwRGBBitCount = lpddpf->dwRGBBitCount; WORD wDepthIndex = D3D_DEPTH_IDX(dwRGBBitCount); WORD wTransparencyIndex = dwAlphaBitCount > 0 ? TR_TRANSLUCENT_IDX : TR_OPAQUE_IDX; D3DTextureTable *table = (D3DTextureTable*)param; D3DTextureTableCell *cell = &(*table)[wTransparencyIndex][wDepthIndex]; if (cell->pfType == PF_INVALID || pfType < cell->pfType) { // set only if it wasn't set or if current pfType is better than // the one found previously: it's better to use 565 than 555 memcpy(&cell->pddpf, lpddpf, sizeof(DDPIXELFORMAT)); cell->pfType = pfType; } // continue for all pixel formats return DDENUMRET_OK; } HRESULT WINAPI EnumZBufferFormatsCallback(DDPIXELFORMAT* pddpf, VOID* pContext ) { J2dTraceLn(J2D_TRACE_VERBOSE, "EnumZBufferFormatsCallback"); PixelFormatSearchStruct *ppfss = (PixelFormatSearchStruct*)pContext; DDPIXELFORMAT* pddpfOut = ppfss->pddpf; // if found a format with the exact depth, return it if (pddpf->dwZBufferBitDepth == (DWORD)ppfss->preferredDepth) { ppfss->bFoundFormat = TRUE; memcpy(pddpfOut, pddpf, sizeof(DDPIXELFORMAT)); return D3DENUMRET_CANCEL; } // If a format with exact depth can't be found, look for the best // available, preferring those with the lowest bit depth to save // video memory. Also, prefer formats with no stencil bits. if (!ppfss->bFoundFormat || (pddpfOut->dwZBufferBitDepth > pddpf->dwZBufferBitDepth && !(pddpf->dwFlags & DDPF_STENCILBUFFER))) { ppfss->bFoundFormat = TRUE; memcpy(pddpfOut, pddpf, sizeof(DDPIXELFORMAT)); } return D3DENUMRET_OK; } HRESULT WINAPI DeviceEnumCallback(LPSTR strDesc, LPSTR strName, LPD3DDEVICEDESC7 pDesc, LPVOID pParentInfo) { J2dTraceLn(J2D_TRACE_VERBOSE, "DeviceEnumCallback"); DEVICES_INFO *devinfo = (DEVICES_INFO*)pParentInfo; if (pDesc->deviceGUID == IID_IDirect3DHALDevice) { devinfo->pGUIDs[HAL_IDX] = &IID_IDirect3DHALDevice; } else if (pDesc->deviceGUID == IID_IDirect3DTnLHalDevice) { devinfo->pGUIDs[TNL_IDX] = &IID_IDirect3DTnLHalDevice; } else if (pDesc->deviceGUID == IID_IDirect3DRGBDevice) { devinfo->pGUIDs[RGB_IDX] = &IID_IDirect3DRGBDevice; } else if (pDesc->deviceGUID == IID_IDirect3DRefDevice) { devinfo->pGUIDs[REF_IDX] = &IID_IDirect3DRefDevice; } return D3DENUMRET_OK; } HRESULT D3DUtils_FindMaskTileTextureFormat(IDirect3DDevice7 *d3dDevice, DDPIXELFORMAT* pddpf) { J2dTraceLn(J2D_TRACE_INFO, "D3DUtils_FindMaskTileTextureFormat"); d3dDevice->EnumTextureFormats(EnumAlphaTextureFormatsCallback, (void*)pddpf); if (pddpf->dwAlphaBitDepth == 8) { return D3D_OK; } return DDERR_GENERIC; } HRESULT D3DUtils_FindDepthBufferFormat(IDirect3D7 *d3dObject, int preferredDepth, DDPIXELFORMAT* pddpf, const GUID *pDeviceGUID) { J2dTraceLn(J2D_TRACE_INFO, "D3DUtils_FindDepthBufferFormat"); PixelFormatSearchStruct pfss; pfss.pddpf = pddpf; pfss.bFoundFormat = FALSE; pfss.preferredDepth = preferredDepth; d3dObject->EnumZBufferFormats(*pDeviceGUID, EnumZBufferFormatsCallback, (void*)&pfss); return pfss.bFoundFormat ? D3D_OK : DDERR_GENERIC; } jint D3DUtils_GetPixelFormatType(DDPIXELFORMAT*lpddpf) { J2dTraceLn(J2D_TRACE_VERBOSE, "D3DUtils_GetPixelFormatType"); if (lpddpf == NULL) return PF_INVALID; DWORD dwFlags = lpddpf->dwFlags; // skip weird formats if (lpddpf->dwRGBBitCount < 16 || dwFlags & DDPF_ALPHA || dwFlags & DDPF_ZBUFFER || dwFlags & DDPF_ZPIXELS || dwFlags & DDPF_LUMINANCE || dwFlags & DDPF_FOURCC || dwFlags & DDPF_STENCILBUFFER || dwFlags & DDPF_BUMPLUMINANCE || dwFlags & DDPF_BUMPDUDV) { return PF_INVALID; } jint pfType = PF_INVALID; DWORD aMask = lpddpf->dwRGBAlphaBitMask; DWORD rMask = lpddpf->dwRBitMask; DWORD gMask = lpddpf->dwGBitMask; DWORD bMask = lpddpf->dwBBitMask; if (rMask == 0x0000f800 && gMask == 0x000007e0 && bMask == 0x0000001f && aMask == 0x00000000) { pfType = PF_USHORT_565_RGB; } else if (rMask == 0x00007C00 && gMask == 0x000003E0 && bMask == 0x0000001f && aMask == 0x00000000) { pfType = PF_USHORT_555_RGB; } else if (rMask == 0x00000f00 && gMask == 0x000000f0 && bMask == 0x0000000f && aMask == 0x0000f000) { // REMIND: we currently don't support this // pixel format, since we don't have the loops for a // premultiplied version of it. So we'll just use INT_ARGB // for now pfType = PF_INVALID; // pfType = PF_USHORT_4444_ARGB; } else if (rMask == 0x00ff0000 && gMask == 0x0000ff00 && bMask == 0x000000ff) { if (lpddpf->dwRGBBitCount == 32) { pfType = (dwFlags & DDPF_ALPHAPIXELS) ? PF_INT_ARGB : PF_INT_RGB; } else { // We currently don't support this format. // pfType = PF_3BYTE_BGR; pfType = PF_INVALID; } } return pfType; } void D3DUtils_SetupTextureFormats(IDirect3DDevice7 *d3dDevice, D3DTextureTable &table) { J2dTraceLn(J2D_TRACE_INFO, "D3DUtils_SetupTextureFormats"); if (d3dDevice == NULL || table == NULL) { return; } ZeroMemory(table, sizeof(D3DTextureTable)); int t; for (t = TR_OPAQUE_IDX; t < TR_MAX_IDX; t++) { for (int d = DEPTH16_IDX; d < DEPTH_MAX_IDX; d++) { table[t][d].pfType = PF_INVALID; } } d3dDevice->EnumTextureFormats(D3DUtils_TextureSearchCallback, table); // We've retrieved the pixel formats for this device. The matrix may // look something like this, depending on the formats the device supports: // Transparency/Depth Depth 16 Depth 24 Depth 32 // ------------------------------------------------------------------------ // TR_OPAQUE PF_USHORT_565_RGB PF_INVALID PF_INT_RGB // TR_BITMASK PF_INVALID PF_INVALID PF_INVALID // TR_TRANSLUCENT PF_INVALID PF_INVALID PF_INT_ARGB // we'll be using translucent pixel formats for bitmask images // for now, this may change later memcpy(&table[TR_BITMASK_IDX], &table[TR_TRANSLUCENT_IDX], sizeof(D3DTextureTableCell[DEPTH_MAX_IDX])); // Transparency/Depth Depth 16 Depth 24 Depth 32 // ------------------------------------------------------------------------ // TR_OPAQUE PF_USHORT_565_RGB PF_INVALID PF_INT_RGB // TR_BITMASK PF_INVALID PF_INVALID PF_INT_ARGB // TR_TRANSLUCENT PF_INVALID PF_INVALID PF_INT_ARGB // REMIND: crude force // Find substitutes for pixel formats which we didn't find. // For example, if we didn't find a 24-bit format, 32-bit will be // a first choice for substitution. But if it wasn't found either, // then use 16-bit format D3DTextureTableCell *cell16, *cell24, *cell32; for (t = TR_OPAQUE_IDX; t < TR_MAX_IDX; t++) { cell16 = &table[t][DEPTH16_IDX]; cell24 = &table[t][DEPTH24_IDX]; cell32 = &table[t][DEPTH32_IDX]; if (cell32->pfType == PF_INVALID) { if (cell24->pfType != PF_INVALID) { memcpy(cell32, cell24, sizeof(D3DTextureTableCell)); } else if (cell16->pfType != PF_INVALID) { memcpy(cell32, cell16, sizeof(D3DTextureTableCell)); } else { // no valid pixel formats for this transparency // type were found continue; } } // now we know that 32-bit is valid if (cell24->pfType == PF_INVALID) { // use 32-bit format as a substitution for 24-bit memcpy(cell24, cell32, sizeof(D3DTextureTableCell)); } // now we know that 32- and 24-bit are valid if (cell16->pfType == PF_INVALID) { // use 24-bit format as a substitution for 16-bit memcpy(cell16, cell24, sizeof(D3DTextureTableCell)); } } // After this loop the matrix may look something like this: // Transparency/Depth Depth 16 Depth 24 Depth 32 // ------------------------------------------------------------------------ // TR_OPAQUE PF_USHORT_565_RGB PF_INT_RGB PF_INT_RGB // TR_BITMASK PF_INT_ARGB PF_INT_ARGB PF_INT_ARGB // TR_TRANSLUCENT PF_INT_ARGB PF_INT_ARGB PF_INT_ARGB #ifdef DEBUG // Print out the matrix (should look something like the comment above) J2dTraceLn1(J2D_TRACE_INFO, "Texutre formats table for device %x", d3dDevice); J2dTraceLn(J2D_TRACE_INFO, "Transparency/Depth Depth 16 "\ "Depth 24 Depth 32"); J2dTraceLn(J2D_TRACE_INFO, "-------------------------------------------"\ "----------------------------"); for (t = TR_OPAQUE_IDX; t < TR_MAX_IDX; t++) { J2dTrace1(J2D_TRACE_INFO, "%15s", TR_NAMES[t]); for (int d = DEPTH16_IDX; d < DEPTH_MAX_IDX; d++) { J2dTrace1(J2D_TRACE_INFO, "%20s", PF_NAMES[table[t][d].pfType]); } J2dTrace(J2D_TRACE_INFO, "\n"); } #endif // DEBUG } const GUID * D3DUtils_SelectDeviceGUID(IDirect3D7 *d3dObject) { static char * RASTERIZER_NAMES[] = { "TNL", "HAL", "REFERENCE", "RGB" }; // try to use TnL rasterizer by default int defIndex = TNL_IDX; J2dTraceLn(J2D_TRACE_INFO, "D3DUtils_SelectDeviceGUID"); // unless a different one was requested char *pRasterizer = getenv("J2D_D3D_RASTERIZER"); if (pRasterizer != NULL) { if (strncmp(pRasterizer, "ref", 3) == 0) { defIndex = REF_IDX; } else if (strncmp(pRasterizer, "rgb", 3) == 0) { defIndex = RGB_IDX; } else if (strncmp(pRasterizer, "hal", 3) == 0) { defIndex = HAL_IDX; } else if (strncmp(pRasterizer, "tnl", 3) == 0) { defIndex = TNL_IDX; } J2dTraceLn1(J2D_TRACE_VERBOSE, " rasterizer requested: %s", RASTERIZER_NAMES[defIndex]); } DEVICES_INFO devInfo; memset(&devInfo, 0, sizeof(devInfo)); HRESULT res; if (FAILED(res = d3dObject->EnumDevices(DeviceEnumCallback, (VOID*)&devInfo))) { DebugPrintDirectDrawError(res, "D3DUtils_SelectDeviceGUID: "\ "EnumDevices failed"); return NULL; } // return requested rasterizer's guid if it's present if (devInfo.pGUIDs[defIndex] != NULL) { J2dRlsTraceLn1(J2D_TRACE_VERBOSE, "D3DUtils_SelectDeviceGUID: using %s rasterizer", RASTERIZER_NAMES[defIndex]); return devInfo.pGUIDs[defIndex]; } // if not, try to find one, starting with the best available defIndex = TNL_IDX; do { if (devInfo.pGUIDs[defIndex] != NULL) { J2dRlsTraceLn1(J2D_TRACE_VERBOSE, "D3DUtils_SelectDeviceGUID: using %s rasterizer", RASTERIZER_NAMES[defIndex]); return devInfo.pGUIDs[defIndex]; } // While we could use the rgb and ref rasterizers if tnl and // hal aren't present, it's not practical for performance purposes. // so we just leave an opportunity to force them. } while (++defIndex < REF_IDX /*DEV_IDX_MAX*/); J2dRlsTraceLn(J2D_TRACE_ERROR, "D3DUtils_SelectDeviceGUID: "\ "No Accelerated Rasterizers Found"); return NULL; } /* * This function sets passed matrix to be a custom left-hand off-center * orthogonal matrix. The output is identical to D3DX's function call * D3DXMatrixOrthoOffCenterLH((D3DXMATRIX*)&tx, * 0.0, width, height, 0.0, -1.0, 1.0); */ void D3DUtils_SetOrthoMatrixOffCenterLH(D3DMATRIX *m, float width, float height) { DASSERT((m != NULL) && (width > 0.0f) && (height > 0.0f)); memset(m, 0, 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, BOOL adjust) { DASSERT(m != NULL); m->_12 = m->_13 = m->_14 = m->_21 = m->_23 = m->_24 = 0.0f; m->_31 = m->_32 = m->_34 = m->_43 = 0.0f; m->_11 = m->_22 = m->_33 = m->_44 = 1.0f; if (adjust) { // This is required for proper texel alignment m->_41 = m->_42 = -0.5f; } else { m->_41 = m->_42 = 0.0f; } } DDrawSurface * D3DUtils_CreatePlainSurface(JNIEnv *env, DDraw *ddObject, D3DContext *d3dContext, int w, int h) { DXSurface *dxSurface; jint pType; J2dTraceLn(J2D_TRACE_INFO, "D3DUtils_CreatePlainSurface"); if (FAILED(d3dContext->CreateSurface(env, w, h, 32, TR_OPAQUE, D3D_PLAIN_SURFACE, &dxSurface, &pType))) { return NULL; } return new DDrawSurface(ddObject, dxSurface); } DDrawSurface * D3DUtils_CreateTexture(JNIEnv *env, DDraw *ddObject, D3DContext *d3dContext, int transparency, int w, int h) { J2dTraceLn(J2D_TRACE_INFO, "D3DUtils_CreateTexture"); DXSurface *dxSurface; jint pType; if (FAILED(d3dContext->CreateSurface(env, w, h, 32, transparency, D3D_TEXTURE_SURFACE, &dxSurface, &pType))) { return NULL; } return new DDrawSurface(ddObject, dxSurface); } HRESULT D3DUtils_UploadIntImageToXRGBTexture(DDrawSurface *lpTexture, int *pSrc, int width, int height) { HRESULT res; int texW = lpTexture->GetDXSurface()->GetWidth(); int texH = lpTexture->GetDXSurface()->GetHeight(); int srcStride = width * 4; J2dTraceLn(J2D_TRACE_INFO, "D3DUtils_UploadIntImageToXRGBTexture"); if (width > texW) { width = texW; } if (height > texH) { height = texH; } SurfaceDataRasInfo rasInfo; if (SUCCEEDED(res = lpTexture->Lock(NULL, &rasInfo, DDLOCK_WAIT|DDLOCK_NOSYSLOCK, NULL))) { void *pDstPixels = rasInfo.rasBase; void *pSrcPixels = (void*)pSrc; // REMIND: clear the dest first memset(pDstPixels, 0, texH * rasInfo.scanStride); do { memcpy(pDstPixels, pSrcPixels, width * 4); pSrcPixels = PtrAddBytes(pSrcPixels, srcStride); pDstPixels = PtrAddBytes(pDstPixels, rasInfo.scanStride); } while (--height > 0); res = lpTexture->Unlock(NULL); } return res; } HRESULT D3DUtils_CheckD3DCaps(LPD3DDEVICEDESC7 lpDesc7) { // The device must support fast rasterization static DWORD dwDevCaps = (D3DDEVCAPS_DRAWPRIMTLVERTEX | D3DDEVCAPS_HWRASTERIZATION); BOOL vt = lpDesc7->dwDevCaps & D3DDEVCAPS_DRAWPRIMTLVERTEX; BOOL rz = lpDesc7->dwDevCaps & D3DDEVCAPS_HWRASTERIZATION; J2dTraceLn(J2D_TRACE_INFO, "D3DUtils_CheckD3DCaps"); return (lpDesc7->dwDevCaps & dwDevCaps) ? D3D_OK : DDERR_GENERIC; } HRESULT D3DUtils_CheckTextureCaps(LPD3DDEVICEDESC7 lpDesc7) { J2dTraceLn(J2D_TRACE_INFO, "D3DUtils_CheckTextureCaps"); // REMIND: we should really check both Tri and Lin caps, // but hopefully we won't be using line strips soon LPD3DPRIMCAPS lpDpcTriCaps = &lpDesc7->dpcTriCaps; // Filtering requirements static DWORD dwFilterCaps = (D3DPTFILTERCAPS_LINEAR | D3DPTFILTERCAPS_NEAREST); // Check for caps used for alpha compositing (implementation of // Porter-Duff rules) static DWORD dwBlendCaps = (D3DPBLENDCAPS_ZERO | D3DPBLENDCAPS_ONE | D3DPBLENDCAPS_SRCALPHA | D3DPBLENDCAPS_INVSRCALPHA | D3DPBLENDCAPS_DESTALPHA | D3DPBLENDCAPS_INVDESTALPHA); if ((lpDesc7->dwTextureOpCaps & D3DTEXOPCAPS_MODULATE) && (lpDpcTriCaps->dwTextureFilterCaps & dwFilterCaps) && (lpDpcTriCaps->dwSrcBlendCaps & dwBlendCaps) && (lpDpcTriCaps->dwDestBlendCaps & dwBlendCaps)) { return D3D_OK; } return DDERR_GENERIC; } HRESULT D3DUtils_CheckDeviceCaps(LPD3DDEVICEDESC7 lpDesc7) { J2dTraceLn(J2D_TRACE_INFO, "D3DUtils_CheckDeviceCaps"); if (SUCCEEDED(D3DUtils_CheckD3DCaps(lpDesc7)) && SUCCEEDED(D3DUtils_CheckTextureCaps(lpDesc7)) && SUCCEEDED(D3DUtils_CheckDepthCaps(lpDesc7))) { return D3D_OK; } return DDERR_GENERIC; } HRESULT D3DUtils_CheckDepthCaps(LPD3DDEVICEDESC7 lpDesc7) { J2dTraceLn(J2D_TRACE_INFO, "D3DUtils_CheckDepthCaps"); // Check for required depth-buffer operations // (see D3DContext::SetClip() for more info). static DWORD dwZCmpCaps = (D3DPCMPCAPS_ALWAYS | D3DPCMPCAPS_LESS); // D3DPMISCCAPS_MASKZ capability allows enabling/disabling // depth buffer updates. if ((lpDesc7->dpcTriCaps.dwMiscCaps & D3DPMISCCAPS_MASKZ) && (lpDesc7->dpcTriCaps.dwZCmpCaps & dwZCmpCaps)) { return D3D_OK; } return DDERR_GENERIC; }