Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/windows/native/sun/java2d/d3d/D3DBlitLoops.cpp
32288 views
/*1* Copyright (c) 2007, 2016, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425#include <jni.h>26#include "jlong.h"2728#include "D3DPipeline.h"2930#include "SurfaceData.h"31#include "D3DBlitLoops.h"32#include "D3DRenderQueue.h"33#include "D3DSurfaceData.h"34#include "GraphicsPrimitiveMgr.h"3536#include "IntArgb.h"37#include "IntArgbPre.h"38#include "IntRgb.h"39#include "IntBgr.h"40#include "Ushort555Rgb.h"41#include "Ushort565Rgb.h"42#include "ByteIndexed.h"434445extern "C" BlitFunc IntArgbToIntArgbPreConvert;46extern "C" BlitFunc IntArgbPreToIntArgbConvert;47extern "C" BlitFunc IntArgbBmToIntArgbConvert;48extern "C" BlitFunc IntRgbToIntArgbConvert;49extern "C" BlitFunc ThreeByteBgrToIntArgbConvert;50extern "C" BlitFunc Ushort565RgbToIntArgbConvert;51extern "C" BlitFunc Ushort555RgbToIntArgbConvert;52extern "C" BlitFunc IntBgrToIntArgbConvert;53extern "C" BlitFunc AnyIntIsomorphicCopy;54extern "C" BlitFunc ByteIndexedToIntArgbConvert;55extern "C" BlitFunc ByteIndexedToIntArgbPreConvert;5657#define GETMIN(v1, v2) (((v1) > (t=(v2))) && ((v1) = t))58#define GETMAX(v1, v2) (((v1) < (t=(v2))) && ((v1) = t))5960#ifdef D3D_PPL_DLL6162JNIEXPORT void JNICALL63SurfaceData_IntersectBounds(SurfaceDataBounds *dst, SurfaceDataBounds *src)64{65int t;66GETMAX(dst->x1, src->x1);67GETMAX(dst->y1, src->y1);68GETMIN(dst->x2, src->x2);69GETMIN(dst->y2, src->y2);70}7172JNIEXPORT void JNICALL73SurfaceData_IntersectBoundsXYXY(SurfaceDataBounds *bounds,74jint x1, jint y1, jint x2, jint y2)75{76int t;77GETMAX(bounds->x1, x1);78GETMAX(bounds->y1, y1);79GETMIN(bounds->x2, x2);80GETMIN(bounds->y2, y2);81}8283JNIEXPORT void JNICALL84SurfaceData_IntersectBoundsXYWH(SurfaceDataBounds *bounds,85jint x, jint y, jint w, jint h)86{87w = (w <= 0) ? x : x+w;88if (w < x) {89w = 0x7fffffff;90}91if (bounds->x1 < x) {92bounds->x1 = x;93}94if (bounds->x2 > w) {95bounds->x2 = w;96}97h = (h <= 0) ? y : y+h;98if (h < y) {99h = 0x7fffffff;100}101if (bounds->y1 < y) {102bounds->y1 = y;103}104if (bounds->y2 > h) {105bounds->y2 = h;106}107}108109JNIEXPORT void JNICALL110SurfaceData_IntersectBlitBounds(SurfaceDataBounds *src,111SurfaceDataBounds *dst,112jint dx, jint dy)113{114int t;115GETMAX(dst->x1, src->x1 + dx);116GETMAX(dst->y1, src->y1 + dy);117GETMIN(dst->x2, src->x2 + dx);118GETMIN(dst->y2, src->y2 + dy);119GETMAX(src->x1, dst->x1 - dx);120GETMAX(src->y1, dst->y1 - dy);121GETMIN(src->x2, dst->x2 - dx);122GETMIN(src->y2, dst->y2 - dy);123}124125#endif /* D3D_PPL_DLL */126127D3DPIPELINE_API HRESULT128D3DBL_CopySurfaceToIntArgbImage(IDirect3DSurface9 *pSurface,129SurfaceDataRasInfo *pDstInfo,130jint srcx, jint srcy,131jint srcWidth, jint srcHeight,132jint dstx, jint dsty)133{134HRESULT res = S_OK;135D3DLOCKED_RECT lockedRect;136RECT r = { srcx, srcy, srcx+srcWidth, srcy+srcHeight };137D3DSURFACE_DESC desc;138SurfaceDataRasInfo srcInfo;139140J2dTraceLn(J2D_TRACE_INFO, "D3DBL_CopySurfaceToIntArgbImage");141J2dTraceLn4(J2D_TRACE_VERBOSE,142" rect={%-4d, %-4d, %-4d, %-4d}",143r.left, r.top, r.right, r.bottom);144145res = pSurface->LockRect(&lockedRect, &r, D3DLOCK_NOSYSLOCK);146RETURN_STATUS_IF_FAILED(res);147pSurface->GetDesc(&desc);148149ZeroMemory(&srcInfo, sizeof(SurfaceDataRasInfo));150// srcInfo.bounds.x1 = 0;151// srcInfo.bounds.y1 = 0;152srcInfo.bounds.x2 = srcWidth;153srcInfo.bounds.y2 = srcHeight;154srcInfo.scanStride = lockedRect.Pitch;155156void *pSrcBase = lockedRect.pBits;157void *pDstBase = PtrCoord(pDstInfo->rasBase,158dstx, pDstInfo->pixelStride,159dsty, pDstInfo->scanStride);160161switch (desc.Format) {162case D3DFMT_A8R8G8B8:163srcInfo.pixelStride = 4;164IntArgbPreToIntArgbConvert(pSrcBase, pDstBase,165srcWidth, srcHeight,166&srcInfo, pDstInfo, NULL, NULL);167break;168case D3DFMT_X8R8G8B8:169srcInfo.pixelStride = 4;170IntRgbToIntArgbConvert(pSrcBase, pDstBase,171srcWidth, srcHeight,172&srcInfo, pDstInfo, NULL, NULL);173break;174case D3DFMT_X8B8G8R8:175srcInfo.pixelStride = 4;176IntBgrToIntArgbConvert(pSrcBase, pDstBase,177srcWidth, srcHeight,178&srcInfo, pDstInfo, NULL, NULL);179break;180case D3DFMT_X1R5G5B5:181srcInfo.pixelStride = 2;182Ushort555RgbToIntArgbConvert(pSrcBase, pDstBase,183srcWidth, srcHeight,184&srcInfo, pDstInfo, NULL, NULL);185break;186case D3DFMT_R5G6B5:187srcInfo.pixelStride = 2;188Ushort565RgbToIntArgbConvert(pSrcBase, pDstBase,189srcWidth, srcHeight,190&srcInfo, pDstInfo, NULL, NULL);191break;192default:193J2dRlsTraceLn1(J2D_TRACE_ERROR,194"D3DBL_CopySurfaceToIntArgbImage: unknown format %d",195desc.Format);196}197198return pSurface->UnlockRect();199}200201D3DPIPELINE_API HRESULT202D3DBL_CopyImageToIntXrgbSurface(SurfaceDataRasInfo *pSrcInfo,203int srctype,204D3DResource *pDstSurfaceRes,205jint srcx, jint srcy,206jint srcWidth, jint srcHeight,207jint dstx, jint dsty)208{209HRESULT res = S_OK;210D3DLOCKED_RECT lockedRect;211RECT r = { dstx, dsty, dstx+srcWidth, dsty+srcHeight };212RECT *pR = &r;213SurfaceDataRasInfo dstInfo;214IDirect3DSurface9 *pDstSurface = pDstSurfaceRes->GetSurface();215D3DSURFACE_DESC *pDesc = pDstSurfaceRes->GetDesc();216DWORD dwLockFlags = D3DLOCK_NOSYSLOCK;217218J2dTraceLn(J2D_TRACE_INFO, "D3DBL_CopyImageToIntXrgbSurface");219J2dTraceLn5(J2D_TRACE_VERBOSE,220" srctype=%d rect={%-4d, %-4d, %-4d, %-4d}",221srctype, r.left, r.top, r.right, r.bottom);222223if (pDesc->Usage == D3DUSAGE_DYNAMIC) {224// it is safe to lock with discard because we don't care about the225// contents of dynamic textures, and some drivers are happier if226// dynamic textures are always locked with DISCARD227dwLockFlags |= D3DLOCK_DISCARD;228pR = NULL;229} else {230// in non-DYNAMIC case we lock the exact rect so there's no need to231// offset the destination pointer232dstx = 0;233dsty = 0;234}235236res = pDstSurface->LockRect(&lockedRect, pR, dwLockFlags);237RETURN_STATUS_IF_FAILED(res);238239ZeroMemory(&dstInfo, sizeof(SurfaceDataRasInfo));240// dstInfo.bounds.x1 = 0;241// dstInfo.bounds.y1 = 0;242dstInfo.bounds.x2 = srcWidth;243dstInfo.bounds.y2 = srcHeight;244dstInfo.scanStride = lockedRect.Pitch;245dstInfo.pixelStride = 4;246247void *pSrcBase = PtrCoord(pSrcInfo->rasBase,248srcx, pSrcInfo->pixelStride,249srcy, pSrcInfo->scanStride);250void *pDstBase = PtrCoord(lockedRect.pBits,251dstx, dstInfo.pixelStride,252dsty, dstInfo.scanStride);253254switch (srctype) {255case ST_INT_ARGB:256IntArgbToIntArgbPreConvert(pSrcBase, pDstBase,257srcWidth, srcHeight,258pSrcInfo, &dstInfo, NULL, NULL);259break;260case ST_INT_ARGB_PRE:261AnyIntIsomorphicCopy(pSrcBase, pDstBase,262srcWidth, srcHeight,263pSrcInfo, &dstInfo, NULL, NULL);264break;265case ST_INT_RGB:266IntRgbToIntArgbConvert(pSrcBase, pDstBase,267srcWidth, srcHeight,268pSrcInfo, &dstInfo, NULL, NULL);269break;270case ST_INT_ARGB_BM:271// REMIND: we don't have such sw loop272// so this path is disabled for now on java level273// IntArgbBmToIntArgbPreConvert(pSrcBase, pDstBase,274// srcWidth, srcHeight,275// pSrcInfo, &dstInfo, NULL, NULL);276break;277case ST_INT_BGR:278IntBgrToIntArgbConvert(pSrcBase, pDstBase,279srcWidth, srcHeight,280pSrcInfo, &dstInfo, NULL, NULL);281break;282case ST_3BYTE_BGR:283ThreeByteBgrToIntArgbConvert(pSrcBase, pDstBase,284srcWidth, srcHeight,285pSrcInfo, &dstInfo, NULL, NULL);286break;287case ST_USHORT_555_RGB:288Ushort555RgbToIntArgbConvert(pSrcBase, pDstBase,289srcWidth, srcHeight,290pSrcInfo, &dstInfo, NULL, NULL);291break;292case ST_USHORT_565_RGB:293Ushort565RgbToIntArgbConvert(pSrcBase, pDstBase,294srcWidth, srcHeight,295pSrcInfo, &dstInfo, NULL, NULL);296break;297case ST_BYTE_INDEXED:298ByteIndexedToIntArgbPreConvert(pSrcBase, pDstBase,299srcWidth, srcHeight,300pSrcInfo, &dstInfo, NULL, NULL);301break;302case ST_BYTE_INDEXED_BM:303// REMIND: we don't have such sw loop304// so this path is disabled for now on java level305// ByteIndexedBmToIntArgbPreConvert(pSrcBase, pDstBase,306// srcWidth, srcHeight,307// pSrcInfo, &dstInfo, NULL, NULL);308break;309default:310J2dRlsTraceLn1(J2D_TRACE_ERROR,311"D3DBL_CopyImageToIntXrgbSurface: unknown type %d",312srctype);313}314315return pDstSurface->UnlockRect();316}317318/**319* Inner loop used for copying a source "render-to" D3D "Surface" to a320* destination D3D "Surface". Note that the same surface can321* not be used as both the source and destination, as is the case in a copyArea()322* operation. This method is invoked from D3DBlitLoops_IsoBlit().323*324* The standard StretchRect() mechanism is used to copy the source region325* into the destination region. If the regions have different dimensions,326* the source will be scaled into the destination as appropriate (only327* nearest neighbor filtering will be applied for simple scale operations).328*/329HRESULT330D3DBlitSurfaceToSurface(D3DContext *d3dc, D3DSDOps *srcOps, D3DSDOps *dstOps,331D3DTEXTUREFILTERTYPE hint,332jint sx1, jint sy1, jint sx2, jint sy2,333jint dx1, jint dy1, jint dx2, jint dy2)334{335IDirect3DSurface9 *pSrc, *pDst;336337J2dTraceLn(J2D_TRACE_INFO, "D3DBlitSurfaceToSurface");338339RETURN_STATUS_IF_NULL(srcOps->pResource, E_FAIL);340RETURN_STATUS_IF_NULL(dstOps->pResource, E_FAIL);341RETURN_STATUS_IF_NULL(pSrc = srcOps->pResource->GetSurface(), E_FAIL);342RETURN_STATUS_IF_NULL(pDst = dstOps->pResource->GetSurface(), E_FAIL);343344d3dc->UpdateState(STATE_OTHEROP);345IDirect3DDevice9 *pd3dDevice = d3dc->Get3DDevice();346347// need to clip the destination bounds,348// otherwise StretchRect could fail349jint sw = sx2 - sx1;350jint sh = sy2 - sy1;351jdouble dw = dx2 - dx1;352jdouble dh = dy2 - dy1;353354SurfaceDataBounds dstBounds;355dstBounds.x1 = dx1;356dstBounds.y1 = dy1;357dstBounds.x2 = dx2;358dstBounds.y2 = dy2;359SurfaceData_IntersectBoundsXYXY(&dstBounds, 0, 0,360dstOps->width, dstOps->height);361if (d3dc->GetClipType() == CLIP_RECT) {362J2dTraceLn(J2D_TRACE_VERBOSE, " rect clip, clip dest manually");363RECT clipRect;364pd3dDevice->GetScissorRect(&clipRect);365SurfaceData_IntersectBoundsXYXY(&dstBounds,366clipRect.left, clipRect.top,367clipRect.right, clipRect.bottom);368}369370if (dstBounds.x1 != dx1) {371sx1 += (int)((dstBounds.x1 - dx1) * (sw / dw));372}373if (dstBounds.y1 != dy1) {374sy1 += (int)((dstBounds.y1 - dy1) * (sh / dh));375}376if (dstBounds.x2 != dx2) {377sx2 += (int)((dstBounds.x2 - dx2) * (sw / dw));378}379if (dstBounds.y2 != dy2) {380sy2 += (int)((dstBounds.y2 - dy2) * (sh / dh));381}382383// check if the rects are empty (StretchRect will fail if so)384if (dstBounds.x1 >= dstBounds.x2 || dstBounds.y1 >= dstBounds.y2 ||385sx1 >= sx2 || sy1 >= sy2)386{387return S_OK;388}389390RECT srcRect = { sx1, sy1, sx2, sy2 };391RECT dstRect = { dstBounds.x1, dstBounds.y1, dstBounds.x2, dstBounds.y2 };392393return pd3dDevice->StretchRect(pSrc, &srcRect, pDst, &dstRect, hint);394}395396/**397* A convenience method for issuing DrawTexture calls depending on the398* hint. See detailed explanation below.399*/400static inline HRESULT401D3DDrawTextureWithHint(D3DContext *d3dc, D3DTEXTUREFILTERTYPE hint,402jint srcWidth, jint srcHeight,403float tw, float th,404jint sx1, jint sy1, jint sx2, jint sy2,405float dx1, float dy1, float dx2, float dy2,406float tx1, float ty1, float tx2, float ty2)407{408HRESULT res;409410if (hint == D3DTEXF_LINEAR &&411(srcWidth != tw || srcHeight != th ||412srcWidth != sx2 || srcHeight != sy2 ))413{414/*415* When the image bounds are smaller than the bounds of the416* texture that the image resides in, D3DTEXF_LINEAR will use pixels417* from outside the valid image bounds, which could result in garbage418* pixels showing up at the edges of the transformed result. We set419* the texture wrap mode to D3DTADDRESS_CLAMP, which solves the problem420* for the top and left edges. But when the source bounds do not421* match the texture bounds, we need to perform this as a four-part422* operation in order to prevent the filter used by D3D from using423* invalid pixels at the bottom and right edges.424*425* Note that we only need to apply this technique when the source426* bounds are equal to the actual image bounds. If the source bounds427* fall within the image bounds there is no need to apply this hack428* because the filter used by D3D will access valid pixels.429* Likewise, if the image bounds are equal to the texture bounds,430* then the edge conditions are handled properly by D3DTADDRESS_CLAMP.431*/432433// These values represent the bottom-right corner of source texture434// region pulled in by 1/2 of a source texel.435float tx2adj = tx2 - (1.0f / (2.0f * tw));436float ty2adj = ty2 - (1.0f / (2.0f * th));437438// These values represent the above coordinates pulled in by a439// tiny fraction. As an example, if we sample the tiny area from440// tx2adj2 to tx2adj, the result should be the solid color at the441// texel center corresponding to tx2adj.442float tx2adj2 = tx2adj - 0.0001f;443float ty2adj2 = ty2adj - 0.0001f;444445// These values represent the bottom-right corner of the destination446// region pulled in by 1/2 of a destination pixel.447float dx2adj = dx2 - 0.5f;448float dy2adj = dy2 - 0.5f;449450// First, render a majority of the source texture, from the top-left451// corner to the bottom-right, but not including the right or bottom452// edges.453d3dc->pVCacher->DrawTexture(dx1, dy1, dx2adj, dy2adj,454tx1, ty1, tx2adj, ty2adj);455456// Second, render the remaining sliver on the right edge.457d3dc->pVCacher->DrawTexture(dx2adj, dy1, dx2, dy2adj,458tx2adj2, ty1, tx2adj, ty2adj);459460// Third, render the remaining sliver on the bottom edge.461d3dc->pVCacher->DrawTexture(dx1, dy2adj, dx2adj, dy2,462tx1, ty2adj2, tx2adj, ty2adj);463464// Finally, render the remaining speck at the bottom-right corner.465res = d3dc->pVCacher->DrawTexture(dx2adj, dy2adj, dx2, dy2,466tx2adj2, ty2adj2, tx2adj, ty2adj);467} else {468/*469* As mentioned above, we can issue a simple textured quad if:470* - the hint is D3DTEXF_POINT or471* - the source bounds are sufficiently inside the texture bounds or472* - the image bounds are equal to the texture bounds (as is the473* case when the image has power-of-two dimensions, or when the474* device supports non-pow2 textures)475*/476res = d3dc->pVCacher->DrawTexture(dx1, dy1, dx2, dy2,477tx1, ty1, tx2, ty2);478}479return res;480}481482/**483* Inner loop used for copying a source D3D "Texture" to a destination484* D3D "Surface". This method is invoked from D3DBlitLoops_IsoBlit().485*486* This method will copy, scale, or transform the source texture into the487* destination depending on the transform state, as established in488* and D3DContext::SetTransform(). If the source texture is489* transformed in any way when rendered into the destination, the filtering490* method applied is determined by the hint parameter.491*/492static HRESULT493D3DBlitTextureToSurface(D3DContext *d3dc,494D3DSDOps *srcOps, D3DSDOps *dstOps,495jboolean rtt, D3DTEXTUREFILTERTYPE hint,496jint sx1, jint sy1, jint sx2, jint sy2,497float dx1, float dy1, float dx2, float dy2)498{499HRESULT res;500IDirect3DTexture9 *pSrc;501IDirect3DDevice9 *pd3dDevice;502float tx1, ty1, tx2, ty2;503float tw, th;504505J2dTraceLn(J2D_TRACE_INFO, "D3DBlitTextureToSurface");506507RETURN_STATUS_IF_NULL(srcOps->pResource, E_FAIL);508RETURN_STATUS_IF_NULL(dstOps->pResource, E_FAIL);509510pSrc = srcOps->pResource->GetTexture();511RETURN_STATUS_IF_NULL(pSrc, E_FAIL);512513if (FAILED(res = d3dc->BeginScene(STATE_TEXTUREOP) ||514FAILED(res = d3dc->SetTexture(pSrc))))515{516J2dRlsTraceLn(J2D_TRACE_ERROR,517"D3DBlitTextureToSurface: BeginScene or SetTexture failed");518return res;519}520521pd3dDevice = d3dc->Get3DDevice();522pd3dDevice->SetSamplerState(0, D3DSAMP_MAGFILTER, hint);523pd3dDevice->SetSamplerState(0, D3DSAMP_MINFILTER, hint);524pd3dDevice->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP);525pd3dDevice->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP);526527tw = (float)srcOps->pResource->GetDesc()->Width;528th = (float)srcOps->pResource->GetDesc()->Height;529530// convert the source bounds into the range [0,1]531tx1 = ((float)sx1) / tw;532ty1 = ((float)sy1) / th;533tx2 = ((float)sx2) / tw;534ty2 = ((float)sy2) / th;535536return D3DDrawTextureWithHint(d3dc, hint,537srcOps->width, srcOps->height,538tw, th,539sx1, sy1, sx2, sy2,540dx1, dy1, dx2, dy2,541tx1, ty1, tx2, ty2);542}543544/**545* Inner loop used for copying a source system memory ("Sw") surface or546* D3D "Surface" to a destination D3D "Surface", using an D3D texture547* tile as an intermediate surface. This method is invoked from548* D3DBlitLoops_Blit() for "Sw" surfaces and D3DBlitLoops_IsoBlit() for549* "Surface" surfaces.550*551* This method is used to transform the source surface into the destination.552* Pixel rectangles cannot be arbitrarily transformed. However, texture553* mapped quads do respect the modelview transform matrix, so we use554* textures here to perform the transform operation. This method uses a555* tile-based approach in which a small subregion of the source surface is556* copied into a cached texture tile. The texture tile is then mapped557* into the appropriate location in the destination surface.558*559*/560D3DPIPELINE_API HRESULT561D3DBlitToSurfaceViaTexture(D3DContext *d3dc, SurfaceDataRasInfo *srcInfo,562int srctype, D3DSDOps *srcOps,563jboolean swsurface, jint hint,564jint sx1, jint sy1, jint sx2, jint sy2,565jdouble dx1, jdouble dy1, jdouble dx2, jdouble dy2)566{567double tx1, ty1, tx2, ty2;568double dx, dy, dw, dh, cdw, cdh;569jint tw, th;570jint sx, sy, sw, sh;571HRESULT res = S_OK;572D3DResource *pBlitTextureRes = NULL;573IDirect3DTexture9 *pBlitTexture = NULL;574IDirect3DSurface9 *pBlitSurface = NULL, *pSrc = NULL;575D3DTEXTUREFILTERTYPE fhint =576(hint == D3DSD_XFORM_BILINEAR) ? D3DTEXF_LINEAR : D3DTEXF_POINT;577fhint = d3dc->IsTextureFilteringSupported(fhint) ? fhint : D3DTEXF_NONE;578579if (swsurface) {580res = d3dc->GetResourceManager()->GetBlitTexture(&pBlitTextureRes);581} else {582RETURN_STATUS_IF_NULL(srcOps->pResource, E_FAIL);583RETURN_STATUS_IF_NULL(pSrc = srcOps->pResource->GetSurface(), E_FAIL);584585res = d3dc->GetResourceManager()->586GetBlitRTTexture(D3DC_BLIT_TILE_SIZE, D3DC_BLIT_TILE_SIZE,587srcOps->pResource->GetDesc()->Format,588&pBlitTextureRes);589}590if (FAILED(res)) {591J2dRlsTraceLn(J2D_TRACE_ERROR,592"D3DBlitToSurfaceViaTexture: could not init blit tile");593return res;594}595pBlitSurface = pBlitTextureRes->GetSurface();596pBlitTexture = pBlitTextureRes->GetTexture();597598D3DSURFACE_DESC *pDesc = pBlitTextureRes->GetDesc();599600tx1 = 0.0f;601ty1 = 0.0f;602tw = pDesc->Width;603th = pDesc->Height;604cdw = (dx2-dx1) / (((double)(sx2-sx1)) / tw);605cdh = (dy2-dy1) / (((double)(sy2-sy1)) / th);606607res = d3dc->BeginScene(STATE_TEXTUREOP);608RETURN_STATUS_IF_FAILED(res);609res = d3dc->SetTexture(pBlitTexture);610RETURN_STATUS_IF_FAILED(res);611612IDirect3DDevice9 *pd3dDevice = d3dc->Get3DDevice();613pd3dDevice->SetSamplerState(0, D3DSAMP_MAGFILTER, fhint);614pd3dDevice->SetSamplerState(0, D3DSAMP_MINFILTER, fhint);615pd3dDevice->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP);616pd3dDevice->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP);617618for (sy = sy1, dy = dy1; sy < sy2; sy += th, dy += cdh) {619sh = ((sy + th) > sy2) ? (sy2 - sy) : th;620dh = ((dy + cdh) > dy2) ? (dy2 - dy) : cdh;621622for (sx = sx1, dx = dx1; sx < sx2; sx += tw, dx += cdw) {623sw = ((sx + tw) > sx2) ? (sx2 - sx) : tw;624dw = ((dx + cdw) > dx2) ? (dx2 - dx) : cdw;625626tx2 = ((double)sw) / tw;627ty2 = ((double)sh) / th;628629if (swsurface) {630D3DBL_CopyImageToIntXrgbSurface(srcInfo,631srctype, pBlitTextureRes,632sx, sy, sw, sh,6330, 0);634} else {635RECT srcRect = { (LONG)sx, (LONG)sy,636(LONG)(sx+dw), (LONG)(sy+dh) };637RECT dstRect = { 0l, 0l, (LONG)dw, (LONG)dh };638pd3dDevice->StretchRect(pSrc,639&srcRect, pBlitSurface, &dstRect,640D3DTEXF_NONE);641}642D3DDrawTextureWithHint(d3dc, fhint,643tw, th,644(float)tw, (float)th,645sx, sy, sw, sh,646(float)dx, (float)dy, (float)(dx+dw), (float)(dy+dh),647(float)tx1, (float)ty1, (float)tx2, (float)ty2);648res = d3dc->pVCacher->Render();649}650}651return res;652}653654/**655* Inner loop used for copying a source system memory ("Sw") surface to a656* destination D3D "Texture". This method is invoked from657* D3DBlitLoops_Blit().658*659* The source surface is effectively loaded into the D3D texture object,660* which must have already been initialized by D3DSD_initTexture(). Note661* that this method is only capable of copying the source surface into the662* destination surface (i.e. no scaling or general transform is allowed).663* This restriction should not be an issue as this method is only used664* currently to cache a static system memory image into an D3D texture in665* a hidden-acceleration situation.666*/667static HRESULT668D3DBlitSwToTexture(D3DContext *d3dc,669SurfaceDataRasInfo *srcInfo, int srctype,670D3DSDOps *dstOps,671jint sx1, jint sy1, jint sx2, jint sy2)672{673RETURN_STATUS_IF_NULL(dstOps->pResource, E_FAIL);674RETURN_STATUS_IF_NULL(dstOps->pResource->GetSurface(), E_FAIL);675676return D3DBL_CopyImageToIntXrgbSurface(srcInfo, srctype,677dstOps->pResource,678sx1, sy1, sx2-sx1, sy2-sy1,6790, 0);680}681682/**683* General blit method for copying a native D3D surface (of type "Surface"684* or "Texture") to another D3D "Surface". If texture is JNI_TRUE, this685* method will invoke the Texture->Surface inner loop; otherwise, one of the686* Surface->Surface inner loops will be invoked, depending on the transform687* state.688*/689D3DPIPELINE_API HRESULT690D3DBlitLoops_IsoBlit(JNIEnv *env,691D3DContext *d3dc, jlong pSrcOps, jlong pDstOps,692jboolean xform, jint hint,693jboolean texture, jboolean rtt,694jint sx1, jint sy1, jint sx2, jint sy2,695jdouble dx1, jdouble dy1, jdouble dx2, jdouble dy2)696{697D3DSDOps *srcOps = (D3DSDOps *)jlong_to_ptr(pSrcOps);698D3DSDOps *dstOps = (D3DSDOps *)jlong_to_ptr(pDstOps);699SurfaceDataRasInfo srcInfo;700jint sw = sx2 - sx1;701jint sh = sy2 - sy1;702jdouble dw = dx2 - dx1;703jdouble dh = dy2 - dy1;704705J2dTraceLn(J2D_TRACE_INFO, "D3DBlitLoops_IsoBlit");706707if (sw <= 0 || sh <= 0 || dw <= 0 || dh <= 0) {708J2dTraceLn(J2D_TRACE_WARNING,709"D3DBlitLoops_IsoBlit: invalid dimensions");710return E_FAIL;711}712713RETURN_STATUS_IF_NULL(srcOps, E_FAIL);714RETURN_STATUS_IF_NULL(dstOps, E_FAIL);715RETURN_STATUS_IF_NULL(d3dc, E_FAIL);716RETURN_STATUS_IF_NULL(d3dc->Get3DDevice(), E_FAIL);717718srcInfo.bounds.x1 = sx1;719srcInfo.bounds.y1 = sy1;720srcInfo.bounds.x2 = sx2;721srcInfo.bounds.y2 = sy2;722723SurfaceData_IntersectBoundsXYXY(&srcInfo.bounds,7240, 0, srcOps->width, srcOps->height);725726727HRESULT res = S_OK;728if (srcInfo.bounds.x2 > srcInfo.bounds.x1 &&729srcInfo.bounds.y2 > srcInfo.bounds.y1)730{731if (srcInfo.bounds.x1 != sx1) {732dx1 += (srcInfo.bounds.x1 - sx1) * (dw / sw);733sx1 = srcInfo.bounds.x1;734}735if (srcInfo.bounds.y1 != sy1) {736dy1 += (srcInfo.bounds.y1 - sy1) * (dh / sh);737sy1 = srcInfo.bounds.y1;738}739if (srcInfo.bounds.x2 != sx2) {740dx2 += (srcInfo.bounds.x2 - sx2) * (dw / sw);741sx2 = srcInfo.bounds.x2;742}743if (srcInfo.bounds.y2 != sy2) {744dy2 += (srcInfo.bounds.y2 - sy2) * (dh / sh);745sy2 = srcInfo.bounds.y2;746}747748J2dTraceLn2(J2D_TRACE_VERBOSE, " texture=%d hint=%d", texture, hint);749J2dTraceLn4(J2D_TRACE_VERBOSE, " sx1=%d sy1=%d sx2=%d sy2=%d",750sx1, sy1, sx2, sy2);751J2dTraceLn4(J2D_TRACE_VERBOSE, " dx1=%f dy1=%f dx2=%f dy2=%f",752dx1, dy1, dx2, dy2);753754D3DTEXTUREFILTERTYPE fhint =755(hint == D3DSD_XFORM_BILINEAR) ? D3DTEXF_LINEAR : D3DTEXF_POINT;756if (texture) {757fhint = d3dc->IsTextureFilteringSupported(fhint) ?758fhint : D3DTEXF_NONE;759res = D3DBlitTextureToSurface(d3dc, srcOps, dstOps, rtt, fhint,760sx1, sy1, sx2, sy2,761(float)dx1, (float)dy1,762(float)dx2, (float)dy2);763} else {764// StretchRect does not do compositing or clipping765IDirect3DDevice9 *pd3dDevice = d3dc->Get3DDevice();766DWORD abEnabled = 0;767768pd3dDevice->GetRenderState(D3DRS_ALPHABLENDENABLE, &abEnabled);769J2dTraceLn3(J2D_TRACE_VERBOSE, " xform=%d clip=%d abEnabled=%d",770xform, d3dc->GetClipType(), abEnabled);771if (!xform && d3dc->GetClipType() != CLIP_SHAPE && !abEnabled) {772fhint = d3dc->IsStretchRectFilteringSupported(fhint) ?773fhint : D3DTEXF_NONE;774775res = D3DBlitSurfaceToSurface(d3dc, srcOps, dstOps, fhint,776sx1, sy1, sx2, sy2,777(int)dx1, (int)dy1,778(int)dx2, (int)dy2);779} else {780res = D3DBlitToSurfaceViaTexture(d3dc, &srcInfo,781// surface type is unused here782ST_INT_ARGB_PRE,783srcOps,784JNI_FALSE, hint,785sx1, sy1, sx2, sy2,786dx1, dy1, dx2, dy2);787}788}789}790return res;791}792793/**794* General blit method for copying a system memory ("Sw") surface to a native795* D3D surface (of type "Surface" or "Texture"). If texture is JNI_TRUE,796* this method will invoke the Sw->Texture inner loop; otherwise, one of the797* Sw->Surface inner loops will be invoked, depending on the transform state.798*/799HRESULT800D3DBlitLoops_Blit(JNIEnv *env,801D3DContext *d3dc, jlong pSrcOps, jlong pDstOps,802jboolean xform, jint hint,803jint srctype, jboolean texture,804jint sx1, jint sy1, jint sx2, jint sy2,805jdouble dx1, jdouble dy1, jdouble dx2, jdouble dy2)806{807SurfaceDataOps *srcOps = (SurfaceDataOps *)jlong_to_ptr(pSrcOps);808D3DSDOps *dstOps = (D3DSDOps *)jlong_to_ptr(pDstOps);809SurfaceDataRasInfo srcInfo;810HRESULT res = S_OK;811jint sw = sx2 - sx1;812jint sh = sy2 - sy1;813jdouble dw = dx2 - dx1;814jdouble dh = dy2 - dy1;815jint lockFlags = SD_LOCK_READ;816817J2dTraceLn(J2D_TRACE_INFO, "D3DBlitLoops_Blit");818819if (sw <= 0 || sh <= 0 || dw <= 0 || dh <= 0 || srctype < 0) {820J2dTraceLn(J2D_TRACE_WARNING,821"D3DBlitLoops_Blit: invalid dimensions or srctype");822return E_FAIL;823}824825RETURN_STATUS_IF_NULL(srcOps, E_FAIL);826RETURN_STATUS_IF_NULL(dstOps, E_FAIL);827RETURN_STATUS_IF_NULL(d3dc, E_FAIL);828RETURN_STATUS_IF_NULL(d3dc->Get3DDevice(), E_FAIL);829830srcInfo.bounds.x1 = sx1;831srcInfo.bounds.y1 = sy1;832srcInfo.bounds.x2 = sx2;833srcInfo.bounds.y2 = sy2;834835if (srctype == ST_BYTE_INDEXED || srctype == ST_BYTE_INDEXED_BM) {836lockFlags |= SD_LOCK_LUT;837}838if (srcOps->Lock(env, srcOps, &srcInfo, lockFlags) != SD_SUCCESS) {839J2dTraceLn(J2D_TRACE_WARNING,840"D3DBlitLoops_Blit: could not acquire lock");841return E_FAIL;842}843844if (srcInfo.bounds.x2 > srcInfo.bounds.x1 &&845srcInfo.bounds.y2 > srcInfo.bounds.y1)846{847srcOps->GetRasInfo(env, srcOps, &srcInfo);848if (srcInfo.rasBase) {849if (srcInfo.bounds.x1 != sx1) {850dx1 += (srcInfo.bounds.x1 - sx1) * (dw / sw);851sx1 = srcInfo.bounds.x1;852}853if (srcInfo.bounds.y1 != sy1) {854dy1 += (srcInfo.bounds.y1 - sy1) * (dh / sh);855sy1 = srcInfo.bounds.y1;856}857if (srcInfo.bounds.x2 != sx2) {858dx2 += (srcInfo.bounds.x2 - sx2) * (dw / sw);859sx2 = srcInfo.bounds.x2;860}861if (srcInfo.bounds.y2 != sy2) {862dy2 += (srcInfo.bounds.y2 - sy2) * (dh / sh);863sy2 = srcInfo.bounds.y2;864}865866J2dTraceLn3(J2D_TRACE_VERBOSE, " texture=%d srctype=%d hint=%d",867texture, srctype, hint);868J2dTraceLn4(J2D_TRACE_VERBOSE, " sx1=%d sy1=%d sx2=%d sy2=%d",869sx1, sy1, sx2, sy2);870J2dTraceLn4(J2D_TRACE_VERBOSE, " dx1=%f dy1=%f dx2=%f dy2=%f",871dx1, dy1, dx2, dy2);872873if (texture) {874// These coordinates will always be integers since we875// only ever do a straight copy from sw to texture.876// Thus these casts are "safe" - no loss of precision.877res = D3DBlitSwToTexture(d3dc, &srcInfo, srctype, dstOps,878(jint)dx1, (jint)dy1,879(jint)dx2, (jint)dy2);880} else {881res = D3DBlitToSurfaceViaTexture(d3dc, &srcInfo, srctype, NULL,882JNI_TRUE, hint,883sx1, sy1, sx2, sy2,884dx1, dy1, dx2, dy2);885}886}887SurfaceData_InvokeRelease(env, srcOps, &srcInfo);888}889SurfaceData_InvokeUnlock(env, srcOps, &srcInfo);890return res;891}892893/**894* Specialized blit method for copying a native D3D "Surface" (pbuffer,895* window, etc.) to a system memory ("Sw") surface.896*/897HRESULT898D3DBlitLoops_SurfaceToSwBlit(JNIEnv *env, D3DContext *d3dc,899jlong pSrcOps, jlong pDstOps, jint dsttype,900jint srcx, jint srcy, jint dstx, jint dsty,901jint width, jint height)902{903D3DSDOps *srcOps = (D3DSDOps *)jlong_to_ptr(pSrcOps);904SurfaceDataOps *dstOps = (SurfaceDataOps *)jlong_to_ptr(pDstOps);905SurfaceDataRasInfo srcInfo, dstInfo;906HRESULT res = S_OK;907908J2dTraceLn(J2D_TRACE_INFO, "D3DBlitLoops_SurfaceToSwBlit");909910if (width <= 0 || height <= 0) {911J2dTraceLn(J2D_TRACE_WARNING,912"D3DBlitLoops_SurfaceToSwBlit: dimensions are non-positive");913return S_OK;914}915916RETURN_STATUS_IF_NULL(srcOps, E_FAIL);917RETURN_STATUS_IF_NULL(srcOps->pResource, E_FAIL);918RETURN_STATUS_IF_NULL(dstOps, E_FAIL);919RETURN_STATUS_IF_NULL(d3dc, E_FAIL);920RETURN_STATUS_IF_NULL(d3dc->Get3DDevice(), E_FAIL);921922srcInfo.bounds.x1 = srcx;923srcInfo.bounds.y1 = srcy;924srcInfo.bounds.x2 = srcx + width;925srcInfo.bounds.y2 = srcy + height;926dstInfo.bounds.x1 = dstx;927dstInfo.bounds.y1 = dsty;928dstInfo.bounds.x2 = dstx + width;929dstInfo.bounds.y2 = dsty + height;930931if (dstOps->Lock(env, dstOps, &dstInfo, SD_LOCK_WRITE) != SD_SUCCESS) {932J2dTraceLn(J2D_TRACE_WARNING,933"D3DBlitLoops_SurfaceToSwBlit: could not acquire dst lock");934return S_OK;935}936937SurfaceData_IntersectBoundsXYXY(&srcInfo.bounds,9380, 0, srcOps->width, srcOps->height);939SurfaceData_IntersectBlitBounds(&dstInfo.bounds, &srcInfo.bounds,940srcx - dstx, srcy - dsty);941942if (srcInfo.bounds.x2 > srcInfo.bounds.x1 &&943srcInfo.bounds.y2 > srcInfo.bounds.y1)944{945dstOps->GetRasInfo(env, dstOps, &dstInfo);946if (dstInfo.rasBase) {947IDirect3DDevice9 *pd3dDevice = d3dc->Get3DDevice();948IDirect3DSurface9 *pSrc = srcOps->pResource->GetSurface();949D3DFORMAT srcFmt = srcOps->pResource->GetDesc()->Format;950UINT srcw = srcOps->pResource->GetDesc()->Width;951UINT srch = srcOps->pResource->GetDesc()->Height;952D3DResource *pLockableRes;953954srcx = srcInfo.bounds.x1;955srcy = srcInfo.bounds.y1;956dstx = dstInfo.bounds.x1;957dsty = dstInfo.bounds.y1;958width = srcInfo.bounds.x2 - srcInfo.bounds.x1;959height = srcInfo.bounds.y2 - srcInfo.bounds.y1;960961J2dTraceLn4(J2D_TRACE_VERBOSE, " sx=%d sy=%d w=%d h=%d",962srcx, srcy, width, height);963J2dTraceLn2(J2D_TRACE_VERBOSE, " dx=%d dy=%d",964dstx, dsty);965966d3dc->UpdateState(STATE_OTHEROP);967968// if we read more than 50% of the image it is faster969// to get the whole thing (50% is pulled out of a hat)970BOOL fullRead = ((width * height) >= (srcw * srch * 0.5f));971UINT lockSrcX = 0, lockSrcY = 0;972973if (fullRead) {974// read whole surface into a sysmem surface975lockSrcX = srcx;976lockSrcY = srcy;977// the dest surface must have the same dimensions and format as978// the source, GetBlitOSPSurface ensures that979res = d3dc->GetResourceManager()->980GetBlitOSPSurface(srcw, srch, srcFmt, &pLockableRes);981} else {982// we first copy the source region to a temp983// render target surface of the same format as the984// source, then copy the pixels to the985// target buffered image surface986res = d3dc->GetResourceManager()->987GetLockableRTSurface(width, height, srcFmt, &pLockableRes);988}989if (SUCCEEDED(res)) {990IDirect3DSurface9 *pTmpSurface = pLockableRes->GetSurface();991992if (fullRead) {993res = pd3dDevice->GetRenderTargetData(pSrc, pTmpSurface);994} else {995RECT srcRect = { srcx, srcy, srcx+width, srcy+height};996RECT dstRect = { 0l, 0l, width, height };997998res = pd3dDevice->StretchRect(pSrc,999&srcRect, pTmpSurface,1000&dstRect, D3DTEXF_NONE);1001}10021003if (SUCCEEDED(res)) {1004res = D3DBL_CopySurfaceToIntArgbImage(1005pTmpSurface, /* src surface */1006&dstInfo, /* dst info */1007lockSrcX, lockSrcY, width, height, /* src rect */1008dstx, dsty); /* dst coords */1009}1010}1011}1012SurfaceData_InvokeRelease(env, dstOps, &dstInfo);1013}1014SurfaceData_InvokeUnlock(env, dstOps, &dstInfo);1015return res;1016}10171018HRESULT1019D3DBlitLoops_CopyArea(JNIEnv *env,1020D3DContext *d3dc, D3DSDOps *dstOps,1021jint x, jint y, jint width, jint height,1022jint dx, jint dy)1023{1024SurfaceDataBounds srcBounds, dstBounds;1025HRESULT res = S_OK;10261027J2dTraceLn(J2D_TRACE_INFO, "D3DBlitLoops_CopyArea");10281029RETURN_STATUS_IF_NULL(d3dc, E_FAIL);1030RETURN_STATUS_IF_NULL(dstOps, E_FAIL);1031RETURN_STATUS_IF_NULL(dstOps->pResource, E_FAIL);10321033J2dTraceLn4(J2D_TRACE_VERBOSE, " x=%d y=%d w=%d h=%d",1034x, y, width, height);1035J2dTraceLn2(J2D_TRACE_VERBOSE, " dx=%d dy=%d",1036dx, dy);10371038IDirect3DDevice9 *pd3dDevice = d3dc->Get3DDevice();1039RETURN_STATUS_IF_NULL(pd3dDevice, E_FAIL);1040ClipType clipType = d3dc->GetClipType();10411042srcBounds.x1 = x;1043srcBounds.y1 = y;1044srcBounds.x2 = srcBounds.x1 + width;1045srcBounds.y2 = srcBounds.y1 + height;1046dstBounds.x1 = x + dx;1047dstBounds.y1 = y + dy;1048dstBounds.x2 = dstBounds.x1 + width;1049dstBounds.y2 = dstBounds.y1 + height;10501051SurfaceData_IntersectBoundsXYXY(&srcBounds,10520, 0, dstOps->width, dstOps->height);1053if (clipType == CLIP_RECT) {1054J2dTraceLn(J2D_TRACE_VERBOSE, " rect clip, clip dest manually");1055RECT clipRect;1056pd3dDevice->GetScissorRect(&clipRect);1057SurfaceData_IntersectBoundsXYXY(&dstBounds,1058clipRect.left, clipRect.top,1059clipRect.right, clipRect.bottom);1060}1061SurfaceData_IntersectBoundsXYXY(&dstBounds,10620, 0, dstOps->width, dstOps->height);1063SurfaceData_IntersectBlitBounds(&dstBounds, &srcBounds, -dx, -dy);10641065if (dstBounds.x1 < dstBounds.x2 && dstBounds.y1 < dstBounds.y2) {1066jint sx1 = srcBounds.x1, sy1 = srcBounds.y1,1067sx2 = srcBounds.x2, sy2 = srcBounds.y2;1068jint dx1 = dstBounds.x1, dy1 = dstBounds.y1,1069dx2 = dstBounds.x2, dy2 = dstBounds.y2;1070jint dw = dx2 - dx1, dh = dy2 - dy1;10711072IDirect3DTexture9 *pBlitTexture = NULL;1073IDirect3DSurface9 *pBlitSurface = NULL;1074D3DResource *pBlitTextureRes;10751076res = d3dc->GetResourceManager()->1077GetBlitRTTexture(dw, dh,1078dstOps->pResource->GetDesc()->Format,1079&pBlitTextureRes);1080if (SUCCEEDED(res)) {1081pBlitSurface = pBlitTextureRes->GetSurface();1082pBlitTexture = pBlitTextureRes->GetTexture();1083}1084if (!pBlitTexture || !pBlitSurface) {1085J2dRlsTraceLn(J2D_TRACE_ERROR,1086"D3DBlitLoops_CopyArea: could not init blit tile");1087return E_FAIL;1088}10891090// flush the rendering first1091d3dc->UpdateState(STATE_OTHEROP);10921093// REMIND: see if we could always use texture mapping;1094// the assumption here is that StretchRect is faster,1095// if it's not, then we should always use texture mapping10961097// from src surface to the temp texture1098RECT srcRect = { sx1, sy1, sx2, sy2 };1099RECT tmpDstRect = { 0l, 0l, 0+dw, 0+dh };1100res = pd3dDevice->StretchRect(dstOps->pResource->GetSurface(), &srcRect,1101pBlitSurface, &tmpDstRect,1102D3DTEXF_NONE);1103if (clipType != CLIP_SHAPE) {1104J2dTraceLn(J2D_TRACE_VERBOSE, " rect or no clip, use StretchRect");1105// just do stretch rect to the destination1106RECT dstRect = { dx1, dy1, dx2, dy2 };1107// from temp surface to the destination1108res = pd3dDevice->StretchRect(pBlitSurface, &tmpDstRect,1109dstOps->pResource->GetSurface(),1110&dstRect,1111D3DTEXF_NONE);1112} else {1113J2dTraceLn(J2D_TRACE_VERBOSE, " shape clip, use texture mapping");1114// shape clip - have to use texture mapping1115D3DTEXTUREFILTERTYPE fhint =1116d3dc->IsTextureFilteringSupported(D3DTEXF_NONE) ?1117D3DTEXF_NONE: D3DTEXF_POINT;1118pd3dDevice->SetSamplerState(0, D3DSAMP_MAGFILTER, fhint);1119pd3dDevice->SetSamplerState(0, D3DSAMP_MINFILTER, fhint);1120res = d3dc->BeginScene(STATE_TEXTUREOP);1121RETURN_STATUS_IF_FAILED(res);1122res = d3dc->SetTexture(pBlitTexture);11231124float tx2 = (float)dw/(float)pBlitTextureRes->GetDesc()->Width;1125float ty2 = (float)dh/(float)pBlitTextureRes->GetDesc()->Height;1126res = d3dc->pVCacher->DrawTexture(1127(float)dx1, (float)dy1, (float)dx2, (float)dy2,11280.0f, 0.0f, tx2, ty2);1129}1130}1131return res;1132}113311341135