/** * Enables the LCD text shader and updates any related state, such as the * gamma values. */ static HRESULT D3DTR_EnableLCDGlyphModeState(D3DContext *d3dc, D3DSDOps *dstOps, jboolean useCache, jint contrast) { D3DResource *pGlyphTexRes, *pCachedDestTexRes; IDirect3DTexture9 *pGlyphTex, *pCachedDestTex; RETURN_STATUS_IF_NULL(dstOps->pResource, E_FAIL); HRESULT res = S_OK; if (useCache) { // glyph cache had been already initialized pGlyphTexRes = d3dc->GetLCDGlyphCache()->GetGlyphCacheTexture(); } else { res = d3dc->GetResourceManager()->GetBlitTexture(&pGlyphTexRes); } RETURN_STATUS_IF_FAILED(res); pGlyphTex = pGlyphTexRes->GetTexture(); res = d3dc->GetResourceManager()-> GetCachedDestTexture(dstOps->pResource->GetDesc()->Format, &pCachedDestTexRes); RETURN_STATUS_IF_FAILED(res); pCachedDestTex = pCachedDestTexRes->GetTexture(); 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); pd3dDevice->SetSamplerState(1, D3DSAMP_MAGFILTER, fhint); pd3dDevice->SetSamplerState(1, D3DSAMP_MINFILTER, fhint); d3dc->UpdateTextureColorState(D3DTA_TEXTURE, 1); // bind the texture containing glyph data to texture unit 0 d3dc->SetTexture(pGlyphTex, 0); // bind the texture tile containing destination data to texture unit 1 d3dc->SetTexture(pCachedDestTex, 1); // create/enable the LCD text shader res = d3dc->EnableLCDTextProgram(); RETURN_STATUS_IF_FAILED(res); // update the current contrast settings (note: these change very rarely, // but it seems that D3D pixel shader registers aren't maintained as // part of the pixel shader instance, so we need to update these // everytime around in case another shader blew away the contents // of those registers) D3DTR_UpdateLCDTextContrast(d3dc, contrast); // update the current color settings return D3DTR_UpdateLCDTextColor(d3dc, contrast); }
HRESULT D3DPIPELINE_API D3DRenderer_FillAAParallelogram(D3DContext *d3dc, jfloat fx11, jfloat fy11, jfloat dx21, jfloat dy21, jfloat dx12, jfloat dy12) { IDirect3DDevice9 *pd3dDevice; HRESULT res; J2dTraceLn6(J2D_TRACE_INFO, "D3DRenderer_FillAAParallelogram " "x=%6.2f y=%6.2f " "dx1=%6.2f dy1=%6.2f " "dx2=%6.2f dy2=%6.2f ", fx11, fy11, dx21, dy21, dx12, dy12); res = d3dc->BeginScene(STATE_AAPGRAMOP); RETURN_STATUS_IF_FAILED(res); pd3dDevice = d3dc->Get3DDevice(); if (pd3dDevice == NULL) { return E_FAIL; } res = d3dc->pVCacher->FillParallelogramAA(fx11, fy11, dx21, dy21, dx12, dy12); return res; }
HRESULT D3DPipelineManager::InitAdapters() { HRESULT res = E_FAIL; J2dTraceLn(J2D_TRACE_INFO, "D3DPPLM::InitAdapters()"); if (pAdapters != NULL) { ReleaseAdapters(); } adapterCount = pd3d9->GetAdapterCount(); pAdapters = new D3DAdapter[adapterCount]; if (pAdapters == NULL) { J2dRlsTraceLn(J2D_TRACE_ERROR, "InitAdapters: out of memory"); adapterCount = 0; return E_FAIL; } ZeroMemory(pAdapters, adapterCount * sizeof(D3DAdapter)); res = CheckAdaptersInfo(); RETURN_STATUS_IF_FAILED(res); currentFSFocusAdapter = -1; if (CreateDefaultFocusWindow() == 0) { return E_FAIL; } return S_OK; }
static HRESULT D3DTR_DrawGrayscaleGlyphViaCache(D3DContext *d3dc, GlyphInfo *ginfo, jint x, jint y) { HRESULT res = S_OK; D3DGlyphCache *pGrayscaleGCache; CacheCellInfo *cell; GlyphCacheInfo *gcache; jfloat x1, y1, x2, y2; J2dTraceLn(J2D_TRACE_VERBOSE, "D3DTR_DrawGrayscaleGlyphViaCache"); if (glyphMode != MODE_USE_CACHE_GRAY) { D3DTR_DisableGlyphModeState(d3dc); res = d3dc->BeginScene(STATE_GLYPHOP); RETURN_STATUS_IF_FAILED(res); glyphMode = MODE_USE_CACHE_GRAY; } pGrayscaleGCache = d3dc->GetGrayscaleGlyphCache(); gcache = pGrayscaleGCache->GetGlyphCache(); cell = AccelGlyphCache_GetCellInfoForCache(ginfo, gcache); if (cell == NULL) { // attempt to add glyph to accelerated glyph cache res = pGrayscaleGCache->AddGlyph(ginfo); RETURN_STATUS_IF_FAILED(res); cell = AccelGlyphCache_GetCellInfoForCache(ginfo, gcache); RETURN_STATUS_IF_NULL(cell, E_FAIL); } cell->timesRendered++; x1 = (jfloat)x; y1 = (jfloat)y; x2 = x1 + ginfo->width; y2 = y1 + ginfo->height; return d3dc->pVCacher->DrawTexture(x1, y1, x2, y2, cell->tx1, cell->ty1, cell->tx2, cell->ty2); }
HRESULT D3DVertexCacher::Init(D3DContext *pCtx) { D3DCAPS9 caps; RETURN_STATUS_IF_NULL(pCtx, E_FAIL); ReleaseDefPoolResources(); this->pCtx = pCtx; firstPendingBatch = 0; firstPendingVertex = 0; firstUnusedVertex = 0; currentBatch = 0; ZeroMemory(vertices, sizeof(vertices)); ZeroMemory(batches, sizeof(batches)); lpD3DDevice = pCtx->Get3DDevice(); RETURN_STATUS_IF_NULL(lpD3DDevice, E_FAIL); ZeroMemory(&caps, sizeof(caps)); lpD3DDevice->GetDeviceCaps(&caps); D3DPOOL pool = (caps.DeviceType == D3DDEVTYPE_HAL) ? D3DPOOL_DEFAULT : D3DPOOL_SYSTEMMEM; // usage depends on whether we use hw or sw vertex processing HRESULT res = lpD3DDevice->CreateVertexBuffer(MAX_BATCH_SIZE*sizeof(J2DLVERTEX), D3DUSAGE_DYNAMIC|D3DUSAGE_WRITEONLY, D3DFVF_J2DLVERTEX, pool, &lpD3DVertexBuffer, NULL); RETURN_STATUS_IF_FAILED(res); res = lpD3DDevice->SetStreamSource(0, lpD3DVertexBuffer, 0, sizeof(J2DLVERTEX)); RETURN_STATUS_IF_FAILED(res); lpD3DDevice->SetFVF(D3DFVF_J2DLVERTEX); return res; }
HRESULT D3DPipelineManager::D3DEnabledOnAdapter(UINT adapter) { HRESULT res; D3DDISPLAYMODE dm; res = pd3d9->GetAdapterDisplayMode(adapter, &dm); RETURN_STATUS_IF_FAILED(res); res = pd3d9->CheckDeviceType(adapter, devType, dm.Format, dm.Format, TRUE); if (FAILED(res)) { J2dRlsTraceLn1(J2D_TRACE_ERROR, "D3DPPLM::D3DEnabledOnAdapter: no " \ "suitable d3d device on adapter %d", adapter); } return res; }
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; }
static HRESULT D3DTR_DrawGrayscaleGlyphNoCache(D3DContext *d3dc, GlyphInfo *ginfo, jint x, jint y) { jint tw, th; jint sx, sy, sw, sh; jint x0; jint w = ginfo->width; jint h = ginfo->height; HRESULT res = S_OK; J2dTraceLn(J2D_TRACE_VERBOSE, "D3DTR_DrawGrayscaleGlyphNoCache"); if (glyphMode != MODE_NO_CACHE_GRAY) { D3DTR_DisableGlyphModeState(d3dc); res = d3dc->BeginScene(STATE_MASKOP); RETURN_STATUS_IF_FAILED(res); glyphMode = MODE_NO_CACHE_GRAY; } x0 = x; tw = D3D_MASK_CACHE_TILE_WIDTH; th = D3D_MASK_CACHE_TILE_HEIGHT; for (sy = 0; sy < h; sy += th, y += th) { x = x0; sh = ((sy + th) > h) ? (h - sy) : th; for (sx = 0; sx < w; sx += tw, x += tw) { sw = ((sx + tw) > w) ? (w - sx) : tw; res = d3dc->GetMaskCache()->AddMaskQuad(sx, sy, x, y, sw, sh, w, ginfo->image); } } return res; }
HRESULT D3DBufImgOps_EnableRescaleOp(D3DContext *d3dc, jboolean nonPremult, unsigned char *scaleFactors, unsigned char *offsets) { HRESULT res; IDirect3DDevice9 *pd3dDevice; jint flags = 0; J2dTraceLn(J2D_TRACE_INFO, "D3DBufImgOps_EnableRescaleOp"); RETURN_STATUS_IF_NULL(d3dc, E_FAIL); d3dc->UpdateState(STATE_CHANGE); // choose the appropriate shader, depending on the source image if (nonPremult) { flags |= RESCALE_NON_PREMULT; } // locate/enable the shader program for the given flags res = d3dc->EnableRescaleProgram(flags); RETURN_STATUS_IF_FAILED(res); // update the "uniform" scale factor values (note that the Java-level // dispatching code always passes down 4 values here, regardless of // the original source image type) pd3dDevice = d3dc->Get3DDevice(); pd3dDevice->SetPixelShaderConstantF(0, (float *)scaleFactors, 1); // update the "uniform" offset values (note that the Java-level // dispatching code always passes down 4 values here, and that the // offsets will have already been normalized to the range [0,1]) return pd3dDevice->SetPixelShaderConstantF(1, (float *)offsets, 1); }
static HRESULT D3DTR_DrawLCDGlyphViaCache(D3DContext *d3dc, D3DSDOps *dstOps, GlyphInfo *ginfo, jint x, jint y, jint glyphIndex, jint totalGlyphs, jboolean rgbOrder, jint contrast) { HRESULT res; D3DGlyphCache *pLCDGCache; CacheCellInfo *cell; GlyphCacheInfo *gcache; jint dx1, dy1, dx2, dy2; jfloat dtx1, dty1, dtx2, dty2; J2dTraceLn(J2D_TRACE_VERBOSE, "D3DTR_DrawLCDGlyphViaCache"); // the glyph cache is initialized before this method is called pLCDGCache = d3dc->GetLCDGlyphCache(); if (glyphMode != MODE_USE_CACHE_LCD) { D3DTR_DisableGlyphModeState(d3dc); res = d3dc->BeginScene(STATE_TEXTUREOP); RETURN_STATUS_IF_FAILED(res); pLCDGCache->CheckGlyphCacheByteOrder(rgbOrder); res = D3DTR_EnableLCDGlyphModeState(d3dc, dstOps, JNI_TRUE, contrast); RETURN_STATUS_IF_FAILED(res); glyphMode = MODE_USE_CACHE_LCD; } gcache = pLCDGCache->GetGlyphCache(); cell = AccelGlyphCache_GetCellInfoForCache(ginfo, gcache); if (cell == NULL) { // attempt to add glyph to accelerated glyph cache res = pLCDGCache->AddGlyph(ginfo); RETURN_STATUS_IF_FAILED(res); // we'll just no-op in the rare case that the cell is NULL cell = AccelGlyphCache_GetCellInfoForCache(ginfo, gcache); RETURN_STATUS_IF_NULL(cell, E_FAIL); } cell->timesRendered++; // location of the glyph in the destination's coordinate space dx1 = x; dy1 = y; dx2 = dx1 + ginfo->width; dy2 = dy1 + ginfo->height; // copy destination into second cached texture, if necessary D3DTR_UpdateCachedDestination(d3dc, dstOps, ginfo, dx1, dy1, dx2, dy2, dx1 + cell->leftOff, // adjusted dx1 dx2 + cell->rightOff, // adjusted dx2 glyphIndex, totalGlyphs); // texture coordinates of the destination tile dtx1 = ((jfloat)(dx1 - cachedDestBounds.x1)) / D3DTR_CACHED_DEST_WIDTH; dty1 = ((jfloat)(dy1 - cachedDestBounds.y1)) / D3DTR_CACHED_DEST_HEIGHT; dtx2 = ((jfloat)(dx2 - cachedDestBounds.x1)) / D3DTR_CACHED_DEST_WIDTH; dty2 = ((jfloat)(dy2 - cachedDestBounds.y1)) / D3DTR_CACHED_DEST_HEIGHT; // render composed texture to the destination surface return d3dc->pVCacher->DrawTexture((jfloat)dx1, (jfloat)dy1, (jfloat)dx2, (jfloat)dy2, cell->tx1, cell->ty1, cell->tx2, cell->ty2, dtx1, dty1, dtx2, dty2); }
/** * 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; }
HRESULT D3DPIPELINE_API D3DRenderer_DrawAAParallelogram(D3DContext *d3dc, jfloat fx11, jfloat fy11, jfloat dx21, jfloat dy21, jfloat dx12, jfloat dy12, jfloat lwr21, jfloat lwr12) { IDirect3DDevice9 *pd3dDevice; // dx,dy for line width in the "21" and "12" directions. jfloat ldx21, ldy21, ldx12, ldy12; // parameters for "outer" parallelogram jfloat ofx11, ofy11, odx21, ody21, odx12, ody12; // parameters for "inner" parallelogram jfloat ifx11, ify11, idx21, idy21, idx12, idy12; HRESULT res; J2dTraceLn8(J2D_TRACE_INFO, "D3DRenderer_DrawAAParallelogram " "x=%6.2f y=%6.2f " "dx1=%6.2f dy1=%6.2f lwr1=%6.2f " "dx2=%6.2f dy2=%6.2f lwr2=%6.2f ", fx11, fy11, dx21, dy21, lwr21, dx12, dy12, lwr12); res = d3dc->BeginScene(STATE_AAPGRAMOP); RETURN_STATUS_IF_FAILED(res); pd3dDevice = d3dc->Get3DDevice(); if (pd3dDevice == NULL) { return E_FAIL; } // calculate true dx,dy for line widths from the "line width ratios" ldx21 = dx21 * lwr21; ldy21 = dy21 * lwr21; ldx12 = dx12 * lwr12; ldy12 = dy12 * lwr12; // calculate coordinates of the outer parallelogram ofx11 = fx11 - (ldx21 + ldx12) / 2.0f; ofy11 = fy11 - (ldy21 + ldy12) / 2.0f; odx21 = dx21 + ldx21; ody21 = dy21 + ldy21; odx12 = dx12 + ldx12; ody12 = dy12 + ldy12; // Only process the inner parallelogram if the line width ratio // did not consume the entire interior of the parallelogram // (i.e. if the width ratio was less than 1.0) if (lwr21 < 1.0f && lwr12 < 1.0f) { // calculate coordinates of the inner parallelogram ifx11 = fx11 + (ldx21 + ldx12) / 2.0f; ify11 = fy11 + (ldy21 + ldy12) / 2.0f; idx21 = dx21 - ldx21; idy21 = dy21 - ldy21; idx12 = dx12 - ldx12; idy12 = dy12 - ldy12; res = d3dc->pVCacher->DrawParallelogramAA(ofx11, ofy11, odx21, ody21, odx12, ody12, ifx11, ify11, idx21, idy21, idx12, idy12); } else { // Just invoke a regular fill on the outer parallelogram res = d3dc->pVCacher->FillParallelogramAA(ofx11, ofy11, odx21, ody21, odx12, ody12); } return res; }
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; }
HRESULT D3DResourceManager::CreateSwapChain(HWND hWnd, UINT numBuffers, UINT width, UINT height, D3DSWAPEFFECT swapEffect, UINT presentationInterval, D3DResource ** ppSwapChainResource) { HRESULT res; IDirect3DDevice9 *pd3dDevice; IDirect3DSwapChain9 *pSwapChain = NULL; D3DPRESENT_PARAMETERS newParams, *curParams; J2dTraceLn(J2D_TRACE_INFO, "D3DRM::CreateSwapChain"); J2dTraceLn4(J2D_TRACE_VERBOSE, " w=%d h=%d hwnd=%x numBuffers=%d", width, height, hWnd, numBuffers); if (pCtx == NULL || ppSwapChainResource == NULL || (pd3dDevice = pCtx->Get3DDevice()) == NULL) { return E_FAIL; } RETURN_STATUS_IF_FAILED(res = pd3dDevice->TestCooperativeLevel()); curParams = pCtx->GetPresentationParams(); if (curParams->Windowed == FALSE) { // there's a single swap chain in full-screen mode, use it if // it fits our parameters, reset the device otherwise if (curParams->BackBufferCount != numBuffers || curParams->SwapEffect != swapEffect || curParams->PresentationInterval != presentationInterval) { newParams = *curParams; newParams.BackBufferCount = numBuffers; newParams.SwapEffect = swapEffect; newParams.PresentationInterval = presentationInterval; res = pCtx->ConfigureContext(&newParams); RETURN_STATUS_IF_FAILED(res); // this reset will not have released the device, so our pd3dDevice // is still valid, but to be on a safe side, reset it pd3dDevice = pCtx->Get3DDevice(); } res = pd3dDevice->GetSwapChain(0, &pSwapChain); } else { ZeroMemory(&newParams, sizeof(D3DPRESENT_PARAMETERS)); newParams.BackBufferWidth = width; newParams.BackBufferHeight = height; newParams.hDeviceWindow = hWnd; newParams.Windowed = TRUE; newParams.BackBufferCount = numBuffers; newParams.SwapEffect = swapEffect; newParams.PresentationInterval = presentationInterval; res = pd3dDevice->CreateAdditionalSwapChain(&newParams, &pSwapChain); } if (SUCCEEDED(res)) { J2dTraceLn1(J2D_TRACE_VERBOSE," created swap chain: 0x%x ",pSwapChain); *ppSwapChainResource = new D3DResource(pSwapChain); res = AddResource(*ppSwapChainResource); } else { DebugPrintD3DError(res, "D3DRM::CreateSwapChain failed"); *ppSwapChainResource = NULL; } return res; }
HRESULT D3DMaskCache::AddMaskQuad(int srcx, int srcy, int dstx, int dsty, int width, int height, int maskscan, void *mask) { HRESULT res; float tx1, ty1, tx2, ty2; float dx1, dy1, dx2, dy2; J2dTraceLn1(J2D_TRACE_INFO, "D3DVertexCacher::AddMaskQuad: %d", maskCacheIndex); if (maskCacheIndex >= D3D_MASK_CACHE_MAX_INDEX || pCtx->pVCacher->GetFreeVertices() < 6) { res = pCtx->pVCacher->Render(); RETURN_STATUS_IF_FAILED(res); maskCacheIndex = 0; } if (mask != NULL) { int texx = D3D_MASK_CACHE_TILE_WIDTH * (maskCacheIndex % D3D_MASK_CACHE_WIDTH_IN_TILES); int texy = D3D_MASK_CACHE_TILE_HEIGHT * (maskCacheIndex / D3D_MASK_CACHE_WIDTH_IN_TILES); D3DResource *pMaskTexRes; res = pCtx->GetResourceManager()->GetMaskTexture(&pMaskTexRes); RETURN_STATUS_IF_FAILED(res); // copy alpha mask into texture tile pCtx->UploadTileToTexture(pMaskTexRes, mask, texx, texy, srcx, srcy, width, height, maskscan, TILEFMT_1BYTE_ALPHA); tx1 = ((float)texx) / D3D_MASK_CACHE_WIDTH_IN_TEXELS; ty1 = ((float)texy) / D3D_MASK_CACHE_HEIGHT_IN_TEXELS; maskCacheIndex++; } else { // use special fully opaque tile tx1 = ((float)D3D_MASK_CACHE_SPECIAL_TILE_X) / D3D_MASK_CACHE_WIDTH_IN_TEXELS; ty1 = ((float)D3D_MASK_CACHE_SPECIAL_TILE_Y) / D3D_MASK_CACHE_HEIGHT_IN_TEXELS; } tx2 = tx1 + (((float)width) / D3D_MASK_CACHE_WIDTH_IN_TEXELS); ty2 = ty1 + (((float)height) / D3D_MASK_CACHE_HEIGHT_IN_TEXELS); dx1 = (float)dstx; dy1 = (float)dsty; dx2 = dx1 + width; dy2 = dy1 + height; return pCtx->pVCacher->DrawTexture(dx1, dy1, dx2, dy2, tx1, ty1, tx2, ty2); }
HRESULT D3DBufImgOps_EnableConvolveOp(D3DContext *d3dc, jlong pSrcOps, jboolean edgeZeroFill, jint kernelWidth, jint kernelHeight, unsigned char *kernel) { HRESULT res; IDirect3DDevice9 *pd3dDevice; D3DSDOps *srcOps = (D3DSDOps *)jlong_to_ptr(pSrcOps); jint kernelSize = kernelWidth * kernelHeight; jint texW, texH; jfloat xoff, yoff; jfloat edgeX, edgeY; jfloat imgEdge[4]; jfloat kernelVals[MAX_KERNEL_SIZE*4]; jint i, j, kIndex; jint flags = 0; J2dTraceLn2(J2D_TRACE_INFO, "D3DBufImgOps_EnableConvolveOp: kernelW=%d kernelH=%d", kernelWidth, kernelHeight); RETURN_STATUS_IF_NULL(d3dc, E_FAIL); RETURN_STATUS_IF_NULL(srcOps, E_FAIL); d3dc->UpdateState(STATE_CHANGE); // texcoords are specified in the range [0,1], so to achieve an // x/y offset of approximately one pixel we have to normalize // to that range here texW = srcOps->pResource->GetDesc()->Width; texH = srcOps->pResource->GetDesc()->Height; xoff = 1.0f / texW; yoff = 1.0f / texH; if (edgeZeroFill) { flags |= CONVOLVE_EDGE_ZERO_FILL; } if (kernelWidth == 5 && kernelHeight == 5) { flags |= CONVOLVE_5X5; } // locate/enable the shader program for the given flags res = d3dc->EnableConvolveProgram(flags); RETURN_STATUS_IF_FAILED(res); // update the "uniform" image min/max values // (texcoords are in the range [0,1]) // imgEdge[0] = imgMin.x // imgEdge[1] = imgMin.y // imgEdge[2] = imgMax.x // imgEdge[3] = imgMax.y edgeX = (kernelWidth/2) * xoff; edgeY = (kernelHeight/2) * yoff; imgEdge[0] = edgeX; imgEdge[1] = edgeY; imgEdge[2] = (((jfloat)srcOps->width) / texW) - edgeX; imgEdge[3] = (((jfloat)srcOps->height) / texH) - edgeY; pd3dDevice = d3dc->Get3DDevice(); pd3dDevice->SetPixelShaderConstantF(0, imgEdge, 1); // update the "uniform" kernel offsets and values kIndex = 0; for (i = -kernelHeight/2; i < kernelHeight/2+1; i++) { for (j = -kernelWidth/2; j < kernelWidth/2+1; j++) { kernelVals[kIndex+0] = j*xoff; kernelVals[kIndex+1] = i*yoff; kernelVals[kIndex+2] = NEXT_FLOAT(kernel); kernelVals[kIndex+3] = 0.0f; // unused kIndex += 4; } } return pd3dDevice->SetPixelShaderConstantF(1, kernelVals, kernelSize); }
HRESULT D3DPipelineManager::CheckDeviceCaps(UINT adapter) { HRESULT res; D3DCAPS9 d3dCaps; J2dTraceLn(J2D_TRACE_INFO, "D3DPPLM::CheckDeviceCaps"); res = pd3d9->GetDeviceCaps(adapter, devType, &d3dCaps); RETURN_STATUS_IF_FAILED(res); CHECK_CAP(d3dCaps.DevCaps, D3DDEVCAPS_DRAWPRIMTLVERTEX); // by requiring hardware tnl we are hoping for better drivers quality if (!IsD3DForced()) { // fail if not hw tnl unless d3d was forced CHECK_CAP(d3dCaps.DevCaps, D3DDEVCAPS_HWTRANSFORMANDLIGHT); } if (d3dCaps.DeviceType == D3DDEVTYPE_HAL) { CHECK_CAP(d3dCaps.DevCaps, D3DDEVCAPS_HWRASTERIZATION); } CHECK_CAP(d3dCaps.RasterCaps, D3DPRASTERCAPS_SCISSORTEST); CHECK_CAP(d3dCaps.Caps3, D3DCAPS3_ALPHA_FULLSCREEN_FLIP_OR_DISCARD); CHECK_CAP(d3dCaps.PrimitiveMiscCaps, D3DPMISCCAPS_CULLNONE); CHECK_CAP(d3dCaps.PrimitiveMiscCaps, D3DPMISCCAPS_BLENDOP); CHECK_CAP(d3dCaps.PrimitiveMiscCaps, D3DPMISCCAPS_MASKZ); CHECK_CAP(d3dCaps.ZCmpCaps, D3DPCMPCAPS_ALWAYS); CHECK_CAP(d3dCaps.ZCmpCaps, D3DPCMPCAPS_LESS); CHECK_CAP(d3dCaps.SrcBlendCaps, D3DPBLENDCAPS_ZERO); CHECK_CAP(d3dCaps.SrcBlendCaps, D3DPBLENDCAPS_ONE); CHECK_CAP(d3dCaps.SrcBlendCaps, D3DPBLENDCAPS_SRCALPHA); CHECK_CAP(d3dCaps.SrcBlendCaps, D3DPBLENDCAPS_DESTALPHA); CHECK_CAP(d3dCaps.SrcBlendCaps, D3DPBLENDCAPS_INVSRCALPHA); CHECK_CAP(d3dCaps.SrcBlendCaps, D3DPBLENDCAPS_INVDESTALPHA); CHECK_CAP(d3dCaps.DestBlendCaps, D3DPBLENDCAPS_ZERO); CHECK_CAP(d3dCaps.DestBlendCaps, D3DPBLENDCAPS_ONE); CHECK_CAP(d3dCaps.DestBlendCaps, D3DPBLENDCAPS_SRCALPHA); CHECK_CAP(d3dCaps.DestBlendCaps, D3DPBLENDCAPS_DESTALPHA); CHECK_CAP(d3dCaps.DestBlendCaps, D3DPBLENDCAPS_INVSRCALPHA); CHECK_CAP(d3dCaps.DestBlendCaps, D3DPBLENDCAPS_INVDESTALPHA); CHECK_CAP(d3dCaps.TextureAddressCaps, D3DPTADDRESSCAPS_CLAMP); CHECK_CAP(d3dCaps.TextureAddressCaps, D3DPTADDRESSCAPS_WRAP); CHECK_CAP(d3dCaps.TextureOpCaps, D3DTEXOPCAPS_MODULATE); if (d3dCaps.PixelShaderVersion < D3DPS_VERSION(2,0) && !IsD3DForced()) { J2dRlsTraceLn1(J2D_TRACE_ERROR, "D3DPPLM::CheckDeviceCaps: adapter %d: Failed "\ "(pixel shaders 2.0 required)", adapter); return E_FAIL; } J2dRlsTraceLn1(J2D_TRACE_INFO, "D3DPPLM::CheckDeviceCaps: adapter %d: Passed", adapter); return S_OK; }
static HRESULT D3DTR_DrawLCDGlyphNoCache(D3DContext *d3dc, D3DSDOps *dstOps, GlyphInfo *ginfo, jint x, jint y, jint rowBytesOffset, jboolean rgbOrder, jint contrast) { jfloat tx1, ty1, tx2, ty2; jfloat dx1, dy1, dx2, dy2; jfloat dtx1, dty1, dtx2, dty2; jint tw, th; jint sx, sy, sw, sh; jint cx1, cy1, cx2, cy2; jint x0; jint w = ginfo->width; jint h = ginfo->height; TileFormat tileFormat = rgbOrder ? TILEFMT_3BYTE_RGB : TILEFMT_3BYTE_BGR; IDirect3DDevice9 *pd3dDevice = d3dc->Get3DDevice(); D3DResource *pBlitTextureRes, *pCachedDestTextureRes; IDirect3DTexture9 *pBlitTexture; IDirect3DSurface9 *pCachedDestSurface, *pDst; HRESULT res; J2dTraceLn(J2D_TRACE_VERBOSE, "D3DTR_DrawLCDGlyphNoCache"); RETURN_STATUS_IF_NULL(dstOps->pResource, E_FAIL); RETURN_STATUS_IF_NULL(pDst = dstOps->pResource->GetSurface(), E_FAIL); res = d3dc->GetResourceManager()->GetBlitTexture(&pBlitTextureRes); RETURN_STATUS_IF_FAILED(res); res = d3dc->GetResourceManager()-> GetCachedDestTexture(dstOps->pResource->GetDesc()->Format, &pCachedDestTextureRes); RETURN_STATUS_IF_FAILED(res); pBlitTexture = pBlitTextureRes->GetTexture(); pCachedDestSurface = pCachedDestTextureRes->GetSurface(); if (glyphMode != MODE_NO_CACHE_LCD) { D3DTR_DisableGlyphModeState(d3dc); res = d3dc->BeginScene(STATE_TEXTUREOP); RETURN_STATUS_IF_FAILED(res); res = D3DTR_EnableLCDGlyphModeState(d3dc,dstOps, JNI_FALSE, contrast); RETURN_STATUS_IF_FAILED(res); glyphMode = MODE_NO_CACHE_LCD; } x0 = x; tx1 = 0.0f; ty1 = 0.0f; dtx1 = 0.0f; dty1 = 0.0f; tw = D3DTR_NOCACHE_TILE_SIZE; th = D3DTR_NOCACHE_TILE_SIZE; for (sy = 0; sy < h; sy += th, y += th) { x = x0; sh = ((sy + th) > h) ? (h - sy) : th; for (sx = 0; sx < w; sx += tw, x += tw) { sw = ((sx + tw) > w) ? (w - sx) : tw; // calculate the bounds of the tile to be copied from the // destination into the cached tile cx1 = x; cy1 = y; cx2 = cx1 + sw; cy2 = cy1 + sh; // need to clamp to the destination bounds, otherwise the // StretchRect() call may fail if (cx1 < 0) cx1 = 0; if (cy1 < 0) cy1 = 0; if (cx2 > dstOps->width) cx2 = dstOps->width; if (cy2 > dstOps->height) cy2 = dstOps->height; if (cx2 > cx1 && cy2 > cy1) { // copy LCD mask into glyph texture tile d3dc->UploadTileToTexture(pBlitTextureRes, ginfo->image+rowBytesOffset, 0, 0, sx, sy, sw, sh, ginfo->rowBytes, tileFormat); // update the lower-right glyph texture coordinates tx2 = ((jfloat)sw) / D3DC_BLIT_TILE_SIZE; ty2 = ((jfloat)sh) / D3DC_BLIT_TILE_SIZE; // calculate the actual destination vertices dx1 = (jfloat)x; dy1 = (jfloat)y; dx2 = dx1 + sw; dy2 = dy1 + sh; // 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-x, cy1-y, cx2-x, cy2-y }; pd3dDevice->StretchRect(pDst, &srcRect, pCachedDestSurface, &dstRect, D3DTEXF_NONE); // update the remaining destination texture coordinates dtx2 = ((jfloat)sw) / D3DTR_CACHED_DEST_WIDTH; dty2 = ((jfloat)sh) / D3DTR_CACHED_DEST_HEIGHT; // render composed texture to the destination surface res = d3dc->pVCacher->DrawTexture( dx1, dy1, dx2, dy2, tx1, ty1, tx2, ty2, dtx1, dty1, dtx2, dty2); // unfortunately we need to flush after each tile d3dc->FlushVertexQueue(); } } } return res; }
HRESULT D3DPIPELINE_API D3DRenderer_DrawParallelogram(D3DContext *d3dc, jfloat fx11, jfloat fy11, jfloat dx21, jfloat dy21, jfloat dx12, jfloat dy12, jfloat lwr21, jfloat lwr12) { HRESULT res; J2dTraceLn8(J2D_TRACE_INFO, "D3DRenderer_DrawParallelogram " "x=%6.2f y=%6.2f " "dx1=%6.2f dy1=%6.2f lwr1=%6.2f " "dx2=%6.2f dy2=%6.2f lwr2=%6.2f ", fx11, fy11, dx21, dy21, lwr21, dx12, dy12, lwr12); // dx,dy for line width in the "21" and "12" directions. jfloat ldx21 = dx21 * lwr21; jfloat ldy21 = dy21 * lwr21; jfloat ldx12 = dx12 * lwr12; jfloat ldy12 = dy12 * lwr12; // calculate origin of the outer parallelogram jfloat ox11 = fx11 - (ldx21 + ldx12) / 2.0f; jfloat oy11 = fy11 - (ldy21 + ldy12) / 2.0f; res = d3dc->BeginScene(STATE_RENDEROP); RETURN_STATUS_IF_FAILED(res); // Only need to generate 4 quads if the interior still // has a hole in it (i.e. if the line width ratio was // less than 1.0) if (lwr21 < 1.0f && lwr12 < 1.0f) { // Note: "TOP", "BOTTOM", "LEFT" and "RIGHT" here are // relative to whether the dxNN variables are positive // and negative. The math works fine regardless of // their signs, but for conceptual simplicity the // comments will refer to the sides as if the dxNN // were all positive. "TOP" and "BOTTOM" segments // are defined by the dxy21 deltas. "LEFT" and "RIGHT" // segments are defined by the dxy12 deltas. // Each segment includes its starting corner and comes // to just short of the following corner. Thus, each // corner is included just once and the only lengths // needed are the original parallelogram delta lengths // and the "line width deltas". The sides will cover // the following relative territories: // // T T T T T R // L R // L R // L R // L R // L B B B B B // TOP segment, to left side of RIGHT edge // "width" of original pgram, "height" of hor. line size fx11 = ox11; fy11 = oy11; res = d3dc->pVCacher->FillParallelogram(fx11, fy11, dx21, dy21, ldx12, ldy12); // RIGHT segment, to top of BOTTOM edge // "width" of vert. line size , "height" of original pgram fx11 = ox11 + dx21; fy11 = oy11 + dy21; res = d3dc->pVCacher->FillParallelogram(fx11, fy11, ldx21, ldy21, dx12, dy12); // BOTTOM segment, from right side of LEFT edge // "width" of original pgram, "height" of hor. line size fx11 = ox11 + dx12 + ldx21; fy11 = oy11 + dy12 + ldy21; res = d3dc->pVCacher->FillParallelogram(fx11, fy11, dx21, dy21, ldx12, ldy12); // LEFT segment, from bottom of TOP edge // "width" of vert. line size , "height" of inner pgram fx11 = ox11 + ldx12; fy11 = oy11 + ldy12; res = d3dc->pVCacher->FillParallelogram(fx11, fy11, ldx21, ldy21, dx12, dy12); } else { // The line width ratios were large enough to consume // the entire hole in the middle of the parallelogram // so we can just issue one large quad for the outer // parallelogram. dx21 += ldx21; dy21 += ldy21; dx12 += ldx12; dy12 += ldy12; res = d3dc->pVCacher->FillParallelogram(ox11, oy11, dx21, dy21, dx12, dy12); } return res; }