/* * Class: sun_java2d_d3d_D3DSurfaceData * Method: dbGetPixelNative * Signature: (JII)I */ JNIEXPORT jint JNICALL Java_sun_java2d_d3d_D3DSurfaceData_dbGetPixelNative (JNIEnv *env, jclass clazz, jlong pData, jint x, jint y) { HRESULT res; D3DSDOps *d3dsdo; D3DContext *pCtx; D3DPipelineManager *pMgr; D3DResource *pLockableRes; jint pixel = 0; J2dTraceLn(J2D_TRACE_INFO, "D3DSurfaceData_dbGetPixelNative"); RETURN_STATUS_IF_NULL(d3dsdo = (D3DSDOps *)jlong_to_ptr(pData), pixel); RETURN_STATUS_IF_NULL(d3dsdo->pResource, pixel); RETURN_STATUS_IF_NULL(pMgr = D3DPipelineManager::GetInstance(), pixel); if (FAILED(res = pMgr->GetD3DContext(d3dsdo->adapter, &pCtx))) { D3DRQ_MarkLostIfNeeded(res, d3dsdo); return pixel; } RETURN_STATUS_IF_NULL(pCtx->GetResourceManager(), 0); IDirect3DDevice9 *pd3dDevice = pCtx->Get3DDevice(); IDirect3DSurface9 *pSrc = d3dsdo->pResource->GetSurface(); D3DFORMAT srcFmt = d3dsdo->pResource->GetDesc()->Format; pCtx->UpdateState(STATE_OTHEROP); res = pCtx->GetResourceManager()-> GetLockableRTSurface(1, 1, srcFmt, &pLockableRes); if (SUCCEEDED(res)) { IDirect3DSurface9 *pTmpSurface; RECT srcRect = { x, y, x+1, y+1}; RECT dstRect = { 0l, 0l, 1, 1 }; pTmpSurface = pLockableRes->GetSurface(); res = pd3dDevice->StretchRect(pSrc, &srcRect, pTmpSurface, &dstRect, D3DTEXF_NONE); if (SUCCEEDED(res)) { D3DLOCKED_RECT lRect; res = pTmpSurface->LockRect(&lRect, &dstRect, D3DLOCK_NOSYSLOCK); if (SUCCEEDED(res)) { if (srcFmt == D3DFMT_X8R8G8B8) { pixel = *(jint*)lRect.pBits; } else { pixel = *(unsigned short*)lRect.pBits; } pTmpSurface->UnlockRect(); } } } D3DRQ_MarkLostIfNeeded(res, d3dsdo); return pixel; }
HRESULT D3DTR_EnableGlyphVertexCache(D3DContext *d3dc) { J2dTraceLn(J2D_TRACE_INFO, "D3DTR_EnableGlyphVertexCache"); IDirect3DDevice9 *pd3dDevice = d3dc->Get3DDevice(); D3DTEXTUREFILTERTYPE fhint = d3dc->IsTextureFilteringSupported(D3DTEXF_NONE) ? D3DTEXF_NONE : D3DTEXF_POINT; pd3dDevice->SetSamplerState(0, D3DSAMP_MAGFILTER, fhint); pd3dDevice->SetSamplerState(0, D3DSAMP_MINFILTER, fhint); // glyph cache had been successfully initialized if we got here D3DResource *pGlyphCacheTexRes = d3dc->GetGrayscaleGlyphCache()->GetGlyphCacheTexture(); return d3dc->SetTexture(pGlyphCacheTexRes->GetTexture(), 0); }
HRESULT D3DResourceManager::GetStockTextureResource(UINT width, UINT height, BOOL isRTT, BOOL isOpaque, D3DFORMAT *pFormat/*in/out*/, DWORD dwUsage, D3DResource **ppTextureResource) { D3DResource *pResource = *ppTextureResource; if (pResource != NULL) { if (pResource->GetTexture() != NULL) { return S_OK; } ReleaseResource(pResource); *ppTextureResource = NULL; } return CreateTexture(width, height, isRTT, isOpaque, pFormat, dwUsage, ppTextureResource); }
HRESULT D3DMaskCache::Enable() { HRESULT res; J2dTraceLn(J2D_TRACE_INFO, "D3DMaskCache::Enable"); D3DResource *pMaskTexRes; res = pCtx->GetResourceManager()->GetMaskTexture(&pMaskTexRes); RETURN_STATUS_IF_FAILED(res); res = pCtx->SetTexture(pMaskTexRes->GetTexture(), 0); IDirect3DDevice9 *pd3dDevice = pCtx->Get3DDevice(); D3DTEXTUREFILTERTYPE fhint = pCtx->IsTextureFilteringSupported(D3DTEXF_NONE) ? D3DTEXF_NONE : D3DTEXF_POINT; pd3dDevice->SetSamplerState(0, D3DSAMP_MAGFILTER, fhint); pd3dDevice->SetSamplerState(0, D3DSAMP_MINFILTER, fhint); return res; }
/** * This method checks to see if the given LCD glyph bounds fall within the * cached destination texture bounds. If so, this method can return * immediately. If not, this method will copy a chunk of framebuffer data * into the cached destination texture and then update the current cached * destination bounds before returning. * * The agx1, agx2 are "adjusted" glyph bounds, which are only used when checking * against the previous glyph bounds. */ static HRESULT D3DTR_UpdateCachedDestination(D3DContext *d3dc, D3DSDOps *dstOps, GlyphInfo *ginfo, jint gx1, jint gy1, jint gx2, jint gy2, jint agx1, jint agx2, jint glyphIndex, jint totalGlyphs) { jint dx1, dy1, dx2, dy2; D3DResource *pCachedDestTexRes; IDirect3DSurface9 *pCachedDestSurface, *pDst; HRESULT res; if (isCachedDestValid && INSIDE(gx1, gy1, gx2, gy2, cachedDestBounds)) { // glyph is already within the cached destination bounds; no need // to read back the entire destination region again, but we do // need to see if the current glyph overlaps the previous glyph... // only use the "adjusted" glyph bounds when checking against // previous glyph's bounds gx1 = agx1; gx2 = agx2; if (INTERSECTS(gx1, gy1, gx2, gy2, previousGlyphBounds)) { // the current glyph overlaps the destination region touched // by the previous glyph, so now we need to read back the part // of the destination corresponding to the previous glyph dx1 = previousGlyphBounds.x1; dy1 = previousGlyphBounds.y1; dx2 = previousGlyphBounds.x2; dy2 = previousGlyphBounds.y2; // REMIND: make sure we flush any pending primitives that are // dependent on the current contents of the cached dest d3dc->FlushVertexQueue(); RETURN_STATUS_IF_NULL(dstOps->pResource, E_FAIL); RETURN_STATUS_IF_NULL(pDst = dstOps->pResource->GetSurface(), E_FAIL); res = d3dc->GetResourceManager()-> GetCachedDestTexture(dstOps->pResource->GetDesc()->Format, &pCachedDestTexRes); RETURN_STATUS_IF_FAILED(res); pCachedDestSurface = pCachedDestTexRes->GetSurface(); // now dxy12 represent the "desired" destination bounds, but the // StretchRect() call may fail if these fall outside the actual // surface bounds; therefore, we use cxy12 to represent the // clamped bounds, and dxy12 are saved for later jint cx1 = (dx1 < 0) ? 0 : dx1; jint cy1 = (dy1 < 0) ? 0 : dy1; jint cx2 = (dx2 > dstOps->width) ? dstOps->width : dx2; jint cy2 = (dy2 > dstOps->height) ? dstOps->height : dy2; if (cx2 > cx1 && cy2 > cy1) { // copy destination into subregion of cached texture tile // cx1-cachedDestBounds.x1 == +xoffset from left of texture // cy1-cachedDestBounds.y1 == +yoffset from top of texture // cx2-cachedDestBounds.x1 == +xoffset from left of texture // cy2-cachedDestBounds.y1 == +yoffset from top of texture jint cdx1 = cx1-cachedDestBounds.x1; jint cdy1 = cy1-cachedDestBounds.y1; jint cdx2 = cx2-cachedDestBounds.x1; jint cdy2 = cy2-cachedDestBounds.y1; RECT srcRect = { cx1, cy1, cx2, cy2 }; RECT dstRect = { cdx1, cdy1, cdx2, cdy2 }; IDirect3DDevice9 *pd3dDevice = d3dc->Get3DDevice(); res = pd3dDevice->StretchRect(pDst, &srcRect, pCachedDestSurface, &dstRect, D3DTEXF_NONE); } } } else { // destination region is not valid, so we need to read back a // chunk of the destination into our cached texture // position the upper-left corner of the destination region on the // "top" line of glyph list // REMIND: this isn't ideal; it would be better if we had some idea // of the bounding box of the whole glyph list (this is // do-able, but would require iterating through the whole // list up front, which may present its own problems) dx1 = gx1; dy1 = gy1; jint remainingWidth; if (ginfo->advanceX > 0) { // estimate the width based on our current position in the glyph // list and using the x advance of the current glyph (this is just // a quick and dirty heuristic; if this is a "thin" glyph image, // then we're likely to underestimate, and if it's "thick" then we // may end up reading back more than we need to) remainingWidth = (jint)(ginfo->advanceX * (totalGlyphs - glyphIndex)); if (remainingWidth > D3DTR_CACHED_DEST_WIDTH) { remainingWidth = D3DTR_CACHED_DEST_WIDTH; } else if (remainingWidth < ginfo->width) { // in some cases, the x-advance may be slightly smaller // than the actual width of the glyph; if so, adjust our // estimate so that we can accomodate the entire glyph remainingWidth = ginfo->width; } } else { // a negative advance is possible when rendering rotated text, // in which case it is difficult to estimate an appropriate // region for readback, so we will pick a region that // encompasses just the current glyph remainingWidth = ginfo->width; } dx2 = dx1 + remainingWidth; // estimate the height (this is another sloppy heuristic; we'll // make the cached destination region tall enough to encompass most // glyphs that are small enough to fit in the glyph cache, and then // we add a little something extra to account for descenders dy2 = dy1 + D3DTR_CACHE_CELL_HEIGHT + 2; // REMIND: make sure we flush any pending primitives that are // dependent on the current contents of the cached dest d3dc->FlushVertexQueue(); RETURN_STATUS_IF_NULL(dstOps->pResource, E_FAIL); RETURN_STATUS_IF_NULL(pDst = dstOps->pResource->GetSurface(), E_FAIL); res = d3dc->GetResourceManager()-> GetCachedDestTexture(dstOps->pResource->GetDesc()->Format, &pCachedDestTexRes); RETURN_STATUS_IF_FAILED(res); pCachedDestSurface = pCachedDestTexRes->GetSurface(); // now dxy12 represent the "desired" destination bounds, but the // StretchRect() call may fail if these fall outside the actual // surface bounds; therefore, we use cxy12 to represent the // clamped bounds, and dxy12 are saved for later jint cx1 = (dx1 < 0) ? 0 : dx1; jint cy1 = (dy1 < 0) ? 0 : dy1; jint cx2 = (dx2 > dstOps->width) ? dstOps->width : dx2; jint cy2 = (dy2 > dstOps->height) ? dstOps->height : dy2; if (cx2 > cx1 && cy2 > cy1) { // copy destination into cached texture tile (the upper-left // corner of the destination region will be positioned at the // upper-left corner (0,0) of the texture) RECT srcRect = { cx1, cy1, cx2, cy2 }; RECT dstRect = { cx1-dx1, cy1-dy1, cx2-dx1, cy2-dy1 }; IDirect3DDevice9 *pd3dDevice = d3dc->Get3DDevice(); res = pd3dDevice->StretchRect(pDst, &srcRect, pCachedDestSurface, &dstRect, D3DTEXF_NONE); } // update the cached bounds and mark it valid cachedDestBounds.x1 = dx1; cachedDestBounds.y1 = dy1; cachedDestBounds.x2 = dx2; cachedDestBounds.y2 = dy2; isCachedDestValid = JNI_TRUE; } // always update the previous glyph bounds previousGlyphBounds.x1 = gx1; previousGlyphBounds.y1 = gy1; previousGlyphBounds.x2 = gx2; previousGlyphBounds.y2 = gy2; return res; }
/* * Class: sun_java2d_d3d_D3DSurfaceData * Method: updateWindowAccelImpl * Signature: (JJII)Z */ JNIEXPORT jboolean JNICALL Java_sun_java2d_d3d_D3DSurfaceData_updateWindowAccelImpl (JNIEnv *env, jclass clazz, jlong pd3dsd, jlong pData, jint w, jint h) { HRESULT res; AwtWindow *window; HBITMAP hBitmap = NULL; D3DSDOps *d3dsdo; D3DResource *pSrcRes; D3DContext *pCtx; D3DPipelineManager *pMgr; D3DResource *pLockableRes = NULL; IDirect3DSurface9 *pTmpSurface = NULL; IDirect3DDevice9 *pd3dDevice = NULL; D3DLOCKED_RECT lockedRect; J2dTraceLn(J2D_TRACE_ERROR, "D3DSurfaceData_updateWindowAccelImpl"); if (w <= 0 || h <= 0) { return JNI_TRUE; } RETURN_STATUS_IF_NULL(window = (AwtWindow *)jlong_to_ptr(pData), JNI_FALSE); RETURN_STATUS_IF_NULL(d3dsdo = (D3DSDOps *)jlong_to_ptr(pd3dsd), JNI_FALSE); RETURN_STATUS_IF_NULL(pMgr = D3DPipelineManager::GetInstance(), JNI_FALSE); RETURN_STATUS_IF_NULL(pSrcRes = d3dsdo->pResource, JNI_FALSE); if (FAILED(res = pMgr->GetD3DContext(d3dsdo->adapter, &pCtx))) { D3DRQ_MarkLostIfNeeded(res, d3dsdo); return JNI_FALSE; } RETURN_STATUS_IF_NULL(pd3dDevice = pCtx->Get3DDevice(), JNI_FALSE); pCtx->UpdateState(STATE_OTHEROP); res = pCtx->GetResourceManager()-> GetBlitOSPSurface(pSrcRes->GetDesc()->Width, pSrcRes->GetDesc()->Height, pSrcRes->GetDesc()->Format, &pLockableRes); if (FAILED(res)) { D3DRQ_MarkLostIfNeeded(res, d3dsdo); return JNI_FALSE; } pTmpSurface = pLockableRes->GetSurface(); res = pd3dDevice->GetRenderTargetData(pSrcRes->GetSurface(), pTmpSurface); if (FAILED(res)) { D3DRQ_MarkLostIfNeeded(res, d3dsdo); return JNI_FALSE; } res = pTmpSurface->LockRect(&lockedRect, NULL, D3DLOCK_NOSYSLOCK); if (SUCCEEDED(res)) { hBitmap = BitmapUtil::CreateBitmapFromARGBPre(w, h, lockedRect.Pitch, (int*)lockedRect.pBits); pTmpSurface->UnlockRect(); } RETURN_STATUS_IF_NULL(hBitmap, JNI_FALSE); window->UpdateWindow(env, NULL, w, h, hBitmap); // hBitmap is released in UpdateWindow return JNI_TRUE; }
HRESULT D3DBufImgOps_EnableLookupOp(D3DContext *d3dc, jboolean nonPremult, jboolean shortData, jint numBands, jint bandLength, jint offset, void *tableValues) { HRESULT res; IDirect3DDevice9 *pd3dDevice; D3DResource *pLutTexRes; IDirect3DTexture9 *pLutTex; int bytesPerElem = (shortData ? 2 : 1); jfloat foffsets[4]; void *bands[4]; int i; jint flags = 0; J2dTraceLn4(J2D_TRACE_INFO, "D3DBufImgOps_EnableLookupOp: short=%d num=%d len=%d off=%d", shortData, numBands, bandLength, offset); RETURN_STATUS_IF_NULL(d3dc, E_FAIL); d3dc->UpdateState(STATE_CHANGE); // choose the appropriate shader, depending on the source image // and the number of bands involved if (numBands != 4) { flags |= LOOKUP_USE_SRC_ALPHA; } if (nonPremult) { flags |= LOOKUP_NON_PREMULT; } // locate/enable the shader program for the given flags res = d3dc->EnableLookupProgram(flags); RETURN_STATUS_IF_FAILED(res); // update the "uniform" offset value for (i = 0; i < 4; i++) { foffsets[i] = offset / 255.0f; } pd3dDevice = d3dc->Get3DDevice(); pd3dDevice->SetPixelShaderConstantF(0, foffsets, 1); res = d3dc->GetResourceManager()->GetLookupOpLutTexture(&pLutTexRes); RETURN_STATUS_IF_FAILED(res); pLutTex = pLutTexRes->GetTexture(); // update the lookup table with the user-provided values if (numBands == 1) { // replicate the single band for R/G/B; alpha band is unused for (i = 0; i < 3; i++) { bands[i] = tableValues; } bands[3] = NULL; } else if (numBands == 3) { // user supplied band for each of R/G/B; alpha band is unused for (i = 0; i < 3; i++) { bands[i] = PtrAddBytes(tableValues, i*bandLength*bytesPerElem); } bands[3] = NULL; } else if (numBands == 4) { // user supplied band for each of R/G/B/A for (i = 0; i < 4; i++) { bands[i] = PtrAddBytes(tableValues, i*bandLength*bytesPerElem); } } // upload the bands one row at a time into our lookup table texture D3DLOCKED_RECT lockedRect; res = pLutTex->LockRect(0, &lockedRect, NULL, D3DLOCK_NOSYSLOCK); RETURN_STATUS_IF_FAILED(res); jushort *pBase = (jushort*)lockedRect.pBits; for (i = 0; i < 4; i++) { jushort *pDst; if (bands[i] == NULL) { continue; } pDst = pBase + (i * 256); if (shortData) { memcpy(pDst, bands[i], bandLength*sizeof(jushort)); } else { int j; jubyte *pSrc = (jubyte *)bands[i]; for (j = 0; j < bandLength; j++) { pDst[j] = (jushort)(pSrc[j] << 8); } } } pLutTex->UnlockRect(0); // bind the lookup table to texture unit 1 and enable texturing res = d3dc->SetTexture(pLutTex, 1); pd3dDevice->SetSamplerState(1, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP); pd3dDevice->SetSamplerState(1, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP); pd3dDevice->SetSamplerState(1, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); pd3dDevice->SetSamplerState(1, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); return res; }
/** * REMIND: This method assumes that the dimensions of the incoming pixel * array are less than or equal to the cached blit texture tile; * these are rather fragile assumptions, and should be cleaned up... */ HRESULT D3DMaskBlit_MaskBlit(JNIEnv *env, D3DContext *d3dc, jint dstx, jint dsty, jint width, jint height, void *pPixels) { HRESULT res = S_OK; jfloat dx1, dy1, dx2, dy2; jfloat tx1, ty1, tx2, ty2; J2dTraceLn(J2D_TRACE_INFO, "D3DMaskBlit_MaskBlit"); if (width <= 0 || height <= 0) { J2dTraceLn(J2D_TRACE_WARNING, "D3DMaskBlit_MaskBlit: invalid dimensions"); return res; } RETURN_STATUS_IF_NULL(pPixels, E_FAIL); RETURN_STATUS_IF_NULL(d3dc, E_FAIL); if (FAILED(res = d3dc->BeginScene(STATE_TEXTUREOP))) { return res; } D3DResource *pBlitTexRes; if (FAILED(res = d3dc->GetResourceManager()->GetBlitTexture(&pBlitTexRes))) { return res; } IDirect3DTexture9 *pBlitTex = pBlitTexRes->GetTexture(); if (FAILED(res = d3dc->SetTexture(pBlitTex, 0))) { return res; } IDirect3DDevice9 *pd3dDevice = d3dc->Get3DDevice(); D3DTEXTUREFILTERTYPE fhint = d3dc->IsTextureFilteringSupported(D3DTEXF_NONE) ? D3DTEXF_NONE : D3DTEXF_POINT; pd3dDevice->SetSamplerState(0, D3DSAMP_MAGFILTER, fhint); pd3dDevice->SetSamplerState(0, D3DSAMP_MINFILTER, fhint); // copy system memory IntArgbPre surface into cached texture if (FAILED(res = d3dc->UploadTileToTexture(pBlitTexRes, pPixels, 0, 0, 0, 0, width, height, width*4, TILEFMT_4BYTE_ARGB_PRE))) { return res; } dx1 = (jfloat)dstx; dy1 = (jfloat)dsty; dx2 = dx1 + width; dy2 = dy1 + height; tx1 = 0.0f; ty1 = 0.0f; tx2 = ((jfloat)width) / D3DC_BLIT_TILE_SIZE; ty2 = ((jfloat)height) / D3DC_BLIT_TILE_SIZE; // render cached texture to the destination surface res = d3dc->pVCacher->DrawTexture(dx1, dy1, dx2, dy2, tx1, ty1, tx2, ty2); res = d3dc->pVCacher->Render(); return res; }