aboutsummaryrefslogtreecommitdiff
path: root/src/windows/native/sun/java2d/d3d/D3DBlitLoops.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/windows/native/sun/java2d/d3d/D3DBlitLoops.cpp')
-rw-r--r--src/windows/native/sun/java2d/d3d/D3DBlitLoops.cpp1140
1 files changed, 1058 insertions, 82 deletions
diff --git a/src/windows/native/sun/java2d/d3d/D3DBlitLoops.cpp b/src/windows/native/sun/java2d/d3d/D3DBlitLoops.cpp
index e3e208a77..6792a444a 100644
--- a/src/windows/native/sun/java2d/d3d/D3DBlitLoops.cpp
+++ b/src/windows/native/sun/java2d/d3d/D3DBlitLoops.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright 2005-2006 Sun Microsystems, Inc. All Rights Reserved.
+ * Copyright 2007-2008 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
@@ -23,116 +23,1092 @@
* have any questions.
*/
-#include <stdlib.h>
#include <jni.h>
#include "jlong.h"
-#include <sun_java2d_d3d_D3DBlitLoops.h>
-#include "ddrawUtils.h"
-#include "GraphicsPrimitiveMgr.h"
-#include "Region.h"
-#include "D3DUtils.h"
-#include "D3DContext.h"
+#include "D3DPipeline.h"
+
+#include "SurfaceData.h"
+#include "D3DBlitLoops.h"
+#include "D3DRenderQueue.h"
#include "D3DSurfaceData.h"
+#include "GraphicsPrimitiveMgr.h"
+
+#include "IntArgb.h"
+#include "IntArgbPre.h"
+#include "IntRgb.h"
+#include "IntBgr.h"
+#include "Ushort555Rgb.h"
+#include "Ushort565Rgb.h"
+#include "ByteIndexed.h"
+
+
+extern "C" BlitFunc IntArgbToIntArgbPreConvert;
+extern "C" BlitFunc IntArgbPreToIntArgbConvert;
+extern "C" BlitFunc IntArgbBmToIntArgbConvert;
+extern "C" BlitFunc IntRgbToIntArgbConvert;
+extern "C" BlitFunc Ushort565RgbToIntArgbConvert;
+extern "C" BlitFunc Ushort555RgbToIntArgbConvert;
+extern "C" BlitFunc IntBgrToIntArgbConvert;
+extern "C" BlitFunc AnyIntIsomorphicCopy;
+extern "C" BlitFunc ByteIndexedToIntArgbConvert;
+extern "C" BlitFunc ByteIndexedToIntArgbPreConvert;
+
+#define GETMIN(v1, v2) (((v1) > (t=(v2))) && ((v1) = t))
+#define GETMAX(v1, v2) (((v1) < (t=(v2))) && ((v1) = t))
+
+#ifdef D3D_PPL_DLL
+
+JNIEXPORT void JNICALL
+SurfaceData_IntersectBounds(SurfaceDataBounds *dst, SurfaceDataBounds *src)
+{
+ int t;
+ GETMAX(dst->x1, src->x1);
+ GETMAX(dst->y1, src->y1);
+ GETMIN(dst->x2, src->x2);
+ GETMIN(dst->y2, src->y2);
+}
-extern CriticalSection windowMoveLock;
+JNIEXPORT void JNICALL
+SurfaceData_IntersectBoundsXYXY(SurfaceDataBounds *bounds,
+ jint x1, jint y1, jint x2, jint y2)
+{
+ int t;
+ GETMAX(bounds->x1, x1);
+ GETMAX(bounds->y1, y1);
+ GETMIN(bounds->x2, x2);
+ GETMIN(bounds->y2, y2);
+}
-extern "C" {
+JNIEXPORT void JNICALL
+SurfaceData_IntersectBoundsXYWH(SurfaceDataBounds *bounds,
+ jint x, jint y, jint w, jint h)
+{
+ w = (w <= 0) ? x : x+w;
+ if (w < x) {
+ w = 0x7fffffff;
+ }
+ if (bounds->x1 < x) {
+ bounds->x1 = x;
+ }
+ if (bounds->x2 > w) {
+ bounds->x2 = w;
+ }
+ h = (h <= 0) ? y : y+h;
+ if (h < y) {
+ h = 0x7fffffff;
+ }
+ if (bounds->y1 < y) {
+ bounds->y1 = y;
+ }
+ if (bounds->y2 > h) {
+ bounds->y2 = h;
+ }
+}
JNIEXPORT void JNICALL
-Java_sun_java2d_d3d_D3DBlitLoops_doTransform
- (JNIEnv *env, jclass d3dbl,
- jlong pSrcData, jlong pDstData,
- jlong pCtx,
- jint hint,
- jint sx1, jint sy1, jint sx2, jint sy2,
- jfloat dx1, jfloat dy1, jfloat dx2, jfloat dy2)
+SurfaceData_IntersectBlitBounds(SurfaceDataBounds *src,
+ SurfaceDataBounds *dst,
+ jint dx, jint dy)
{
- static J2DLVERTEX quadVerts[4] = {
- { 0.0f, 0.0f, 0.0f, 0x0, 0.0f, 0.0f },
- { 0.0f, 0.0f, 0.0f, 0x0, 0.0f, 0.0f },
- { 0.0f, 0.0f, 0.0f, 0x0, 0.0f, 0.0f },
- { 0.0f, 0.0f, 0.0f, 0x0, 0.0f, 0.0f }
- };
-
- J2dTraceLn(J2D_TRACE_INFO, "D3DBlitLoops_doTransform");
- J2dTraceLn4(J2D_TRACE_VERBOSE, " sx1=%-4d sy1=%-4d sx2=%-4d sy2=%-4d ",
- sx1, sy1, sx2, sy2);
+ int t;
+ GETMAX(dst->x1, src->x1 + dx);
+ GETMAX(dst->y1, src->y1 + dy);
+ GETMIN(dst->x2, src->x2 + dx);
+ GETMIN(dst->y2, src->y2 + dy);
+ GETMAX(src->x1, dst->x1 - dx);
+ GETMAX(src->y1, dst->y1 - dy);
+ GETMIN(src->x2, dst->x2 - dx);
+ GETMIN(src->y2, dst->y2 - dy);
+}
+
+#endif /* D3D_PPL_DLL */
+
+D3DPIPELINE_API HRESULT
+D3DBL_CopySurfaceToIntArgbImage(IDirect3DSurface9 *pSurface,
+ SurfaceDataRasInfo *pDstInfo,
+ jint srcx, jint srcy,
+ jint srcWidth, jint srcHeight,
+ jint dstx, jint dsty)
+{
+ HRESULT res = S_OK;
+ D3DLOCKED_RECT lockedRect;
+ RECT r = { srcx, srcy, srcx+srcWidth, srcy+srcHeight };
+ D3DSURFACE_DESC desc;
+ SurfaceDataRasInfo srcInfo;
+
+ J2dTraceLn(J2D_TRACE_INFO, "D3DBL_CopySurfaceToIntArgbImage");
J2dTraceLn4(J2D_TRACE_VERBOSE,
- " dx1=%4f dy1=%4f dx2=%4f dy2=%4f", dx1, dy1, dx2, dy2);
+ " rect={%-4d, %-4d, %-4d, %-4d}",
+ r.left, r.top, r.right, r.bottom);
- if (sx2 <= sx1 || sy2 <= sy1 || dx2 <= dx1 || dy2 <= dy1) {
- J2dTraceLn(J2D_TRACE_WARNING,
- "D3DBlitLoops_doTransform: invalid dimensions");
- return;
+ res = pSurface->LockRect(&lockedRect, &r, D3DLOCK_NOSYSLOCK);
+ RETURN_STATUS_IF_FAILED(res);
+ pSurface->GetDesc(&desc);
+
+ ZeroMemory(&srcInfo, sizeof(SurfaceDataRasInfo));
+ // srcInfo.bounds.x1 = 0;
+ // srcInfo.bounds.y1 = 0;
+ srcInfo.bounds.x2 = srcWidth;
+ srcInfo.bounds.y2 = srcHeight;
+ srcInfo.scanStride = lockedRect.Pitch;
+
+ void *pSrcBase = lockedRect.pBits;
+ void *pDstBase = PtrCoord(pDstInfo->rasBase,
+ dstx, pDstInfo->pixelStride,
+ dsty, pDstInfo->scanStride);
+
+ switch (desc.Format) {
+ case D3DFMT_A8R8G8B8:
+ srcInfo.pixelStride = 4;
+ IntArgbPreToIntArgbConvert(pSrcBase, pDstBase,
+ srcWidth, srcHeight,
+ &srcInfo, pDstInfo, NULL, NULL);
+ break;
+ case D3DFMT_X8R8G8B8:
+ srcInfo.pixelStride = 4;
+ IntRgbToIntArgbConvert(pSrcBase, pDstBase,
+ srcWidth, srcHeight,
+ &srcInfo, pDstInfo, NULL, NULL);
+ break;
+ case D3DFMT_X8B8G8R8:
+ srcInfo.pixelStride = 4;
+ IntBgrToIntArgbConvert(pSrcBase, pDstBase,
+ srcWidth, srcHeight,
+ &srcInfo, pDstInfo, NULL, NULL);
+ break;
+ case D3DFMT_X1R5G5B5:
+ srcInfo.pixelStride = 2;
+ Ushort555RgbToIntArgbConvert(pSrcBase, pDstBase,
+ srcWidth, srcHeight,
+ &srcInfo, pDstInfo, NULL, NULL);
+ break;
+ case D3DFMT_R5G6B5:
+ srcInfo.pixelStride = 2;
+ Ushort565RgbToIntArgbConvert(pSrcBase, pDstBase,
+ srcWidth, srcHeight,
+ &srcInfo, pDstInfo, NULL, NULL);
+ break;
+ default:
+ J2dRlsTraceLn1(J2D_TRACE_ERROR,
+ "D3DBL_CopySurfaceToIntArgbImage: unknown format %d",
+ desc.Format);
}
- D3DContext *d3dc = (D3DContext *)jlong_to_ptr(pCtx);
- if (d3dc == NULL) {
- J2dTraceLn(J2D_TRACE_WARNING,
- "D3DBlitLoops_doTransform: null device context");
- return;
+ return pSurface->UnlockRect();
+}
+
+D3DPIPELINE_API HRESULT
+D3DBL_CopyImageToIntXrgbSurface(SurfaceDataRasInfo *pSrcInfo,
+ int srctype,
+ D3DResource *pDstSurfaceRes,
+ jint srcx, jint srcy,
+ jint srcWidth, jint srcHeight,
+ jint dstx, jint dsty)
+{
+ HRESULT res = S_OK;
+ D3DLOCKED_RECT lockedRect;
+ RECT r = { dstx, dsty, dstx+srcWidth, dsty+srcHeight };
+ RECT *pR = &r;
+ SurfaceDataRasInfo dstInfo;
+ IDirect3DSurface9 *pDstSurface = pDstSurfaceRes->GetSurface();
+ D3DSURFACE_DESC *pDesc = pDstSurfaceRes->GetDesc();
+ DWORD dwLockFlags = D3DLOCK_NOSYSLOCK;
+
+ J2dTraceLn(J2D_TRACE_INFO, "D3DBL_CopyImageToIntXrgbSurface");
+ J2dTraceLn5(J2D_TRACE_VERBOSE,
+ " srctype=%d rect={%-4d, %-4d, %-4d, %-4d}",
+ srctype, r.left, r.top, r.right, r.bottom);
+
+ if (pDesc->Usage == D3DUSAGE_DYNAMIC &&
+ dstx == 0 && dstx == 0 &&
+ srcWidth == pDesc->Width && srcHeight == pDesc->Height)
+ {
+ dwLockFlags |= D3DLOCK_DISCARD;
+ pR = NULL;
}
- Win32SDOps *srcOps = (Win32SDOps *)jlong_to_ptr(pSrcData);
- Win32SDOps *dstOps = (Win32SDOps *)jlong_to_ptr(pDstData);
- if (!srcOps->ddInstance || !dstOps->ddInstance) {
- // Some situations can cause us to fail on primary
- // creation, resulting in null lpSurface and null ddInstance
- // for a Win32Surface object.. Just noop this call in that case.
- return;
+ res = pDstSurface->LockRect(&lockedRect, pR, dwLockFlags);
+ RETURN_STATUS_IF_FAILED(res);
+
+ ZeroMemory(&dstInfo, sizeof(SurfaceDataRasInfo));
+ // dstInfo.bounds.x1 = 0;
+ // dstInfo.bounds.y1 = 0;
+ dstInfo.bounds.x2 = srcWidth;
+ dstInfo.bounds.y2 = srcHeight;
+ dstInfo.scanStride = lockedRect.Pitch;
+ dstInfo.pixelStride = 4;
+
+ void *pSrcBase = PtrCoord(pSrcInfo->rasBase,
+ srcx, pSrcInfo->pixelStride,
+ srcy, pSrcInfo->scanStride);
+ void *pDstBase = lockedRect.pBits;
+
+ switch (srctype) {
+ case ST_INT_ARGB:
+ IntArgbToIntArgbPreConvert(pSrcBase, pDstBase,
+ srcWidth, srcHeight,
+ pSrcInfo, &dstInfo, NULL, NULL);
+ break;
+ case ST_INT_ARGB_PRE:
+ case ST_INT_RGB:
+ AnyIntIsomorphicCopy(pSrcBase, pDstBase,
+ srcWidth, srcHeight,
+ pSrcInfo, &dstInfo, NULL, NULL);
+ break;
+ case ST_INT_ARGB_BM:
+ // REMIND: we don't have such sw loop
+ // so this path is disabled for now on java level
+// IntArgbBmToIntArgbPreConvert(pSrcBase, pDstBase,
+// srcWidth, srcHeight,
+// pSrcInfo, &dstInfo, NULL, NULL);
+ break;
+ case ST_INT_BGR:
+ IntBgrToIntArgbConvert(pSrcBase, pDstBase,
+ srcWidth, srcHeight,
+ pSrcInfo, &dstInfo, NULL, NULL);
+ break;
+ case ST_USHORT_555_RGB:
+ Ushort555RgbToIntArgbConvert(pSrcBase, pDstBase,
+ srcWidth, srcHeight,
+ pSrcInfo, &dstInfo, NULL, NULL);
+ break;
+ case ST_USHORT_565_RGB:
+ Ushort565RgbToIntArgbConvert(pSrcBase, pDstBase,
+ srcWidth, srcHeight,
+ pSrcInfo, &dstInfo, NULL, NULL);
+ break;
+ case ST_BYTE_INDEXED:
+ ByteIndexedToIntArgbPreConvert(pSrcBase, pDstBase,
+ srcWidth, srcHeight,
+ pSrcInfo, &dstInfo, NULL, NULL);
+ break;
+ case ST_BYTE_INDEXED_BM:
+ // REMIND: we don't have such sw loop
+ // so this path is disabled for now on java level
+// ByteIndexedBmToIntArgbPreConvert(pSrcBase, pDstBase,
+// srcWidth, srcHeight,
+// pSrcInfo, &dstInfo, NULL, NULL);
+ break;
+ default:
+ J2dRlsTraceLn1(J2D_TRACE_ERROR,
+ "D3DBL_CopyImageToIntXrgbSurface: unknown type %d",
+ srctype);
}
- DDrawSurface *ddTargetSurface = d3dc->GetTargetSurface();
- DDrawSurface *ddSrcSurface = srcOps->lpSurface;
- if (ddTargetSurface == NULL || ddSrcSurface == NULL) {
- return;
+ return pDstSurface->UnlockRect();
+}
+
+/**
+ * Inner loop used for copying a source "render-to" D3D "Surface" to a
+ * destination D3D "Surface". Note that the same surface can
+ * not be used as both the source and destination, as is the case in a copyArea()
+ * operation. This method is invoked from D3DBlitLoops_IsoBlit().
+ *
+ * The standard StretchRect() mechanism is used to copy the source region
+ * into the destination region. If the regions have different dimensions,
+ * the source will be scaled into the destination as appropriate (only
+ * nearest neighbor filtering will be applied for simple scale operations).
+ */
+HRESULT
+D3DBlitSurfaceToSurface(D3DContext *d3dc, D3DSDOps *srcOps, D3DSDOps *dstOps,
+ D3DTEXTUREFILTERTYPE hint,
+ jint sx1, jint sy1, jint sx2, jint sy2,
+ jint dx1, jint dy1, jint dx2, jint dy2)
+{
+ IDirect3DSurface9 *pSrc, *pDst;
+
+ J2dTraceLn(J2D_TRACE_INFO, "D3DBlitSurfaceToSurface");
+
+ RETURN_STATUS_IF_NULL(srcOps->pResource, E_FAIL);
+ RETURN_STATUS_IF_NULL(dstOps->pResource, E_FAIL);
+ RETURN_STATUS_IF_NULL(pSrc = srcOps->pResource->GetSurface(), E_FAIL);
+ RETURN_STATUS_IF_NULL(pDst = dstOps->pResource->GetSurface(), E_FAIL);
+
+ d3dc->UpdateState(STATE_OTHEROP);
+ IDirect3DDevice9 *pd3dDevice = d3dc->Get3DDevice();
+
+ // need to clip the destination bounds,
+ // otherwise StretchRect could fail
+ jint sw = sx2 - sx1;
+ jint sh = sy2 - sy1;
+ jdouble dw = dx2 - dx1;
+ jdouble dh = dy2 - dy1;
+
+ SurfaceDataBounds dstBounds;
+ dstBounds.x1 = dx1;
+ dstBounds.y1 = dy1;
+ dstBounds.x2 = dx2;
+ dstBounds.y2 = dy2;
+ SurfaceData_IntersectBoundsXYXY(&dstBounds, 0, 0,
+ dstOps->width, dstOps->height);
+ if (d3dc->GetClipType() == CLIP_RECT) {
+ J2dTraceLn(J2D_TRACE_VERBOSE, " rect clip, clip dest manually");
+ RECT clipRect;
+ pd3dDevice->GetScissorRect(&clipRect);
+ SurfaceData_IntersectBoundsXYXY(&dstBounds,
+ clipRect.left, clipRect.top,
+ clipRect.right, clipRect.bottom);
+ }
+
+ if (dstBounds.x1 != dx1) {
+ sx1 += (int)((dstBounds.x1 - dx1) * (sw / dw));
+ }
+ if (dstBounds.y1 != dy1) {
+ sy1 += (int)((dstBounds.y1 - dy1) * (sh / dh));
+ }
+ if (dstBounds.x2 != dx2) {
+ sx2 += (int)((dstBounds.x2 - dx2) * (sw / dw));
+ }
+ if (dstBounds.y2 != dy2) {
+ sy2 += (int)((dstBounds.y2 - dy2) * (sh / dh));
}
- ddTargetSurface->GetExclusiveAccess();
- d3dc->GetExclusiveAccess();
- IDirect3DDevice7 *d3dDevice = d3dc->Get3DDevice();
- if (d3dDevice == NULL) {
- d3dc->ReleaseExclusiveAccess();
- ddTargetSurface->ReleaseExclusiveAccess();
- return;
+ // check if the rects are empty (StretchRect will fail if so)
+ if (dstBounds.x1 >= dstBounds.x2 || dstBounds.y1 >= dstBounds.y2 ||
+ sx1 >= sx2 || sy1 >= sy2)
+ {
+ return S_OK;
}
- float tw = (float)ddSrcSurface->GetDXSurface()->GetWidth();
- float th = (float)ddSrcSurface->GetDXSurface()->GetHeight();
- float tx1 = ((float)sx1) / tw;
- float ty1 = ((float)sy1) / th;
- float tx2 = ((float)sx2) / tw;
- float ty2 = ((float)sy2) / th;
+ RECT srcRect = { sx1, sy1, sx2, sy2 };
+ RECT dstRect = { dstBounds.x1, dstBounds.y1, dstBounds.x2, dstBounds.y2 };
+
+ return pd3dDevice->StretchRect(pSrc, &srcRect, pDst, &dstRect, hint);
+}
+
+/**
+ * A convenience method for issuing DrawTexture calls depending on the
+ * hint. See detailed explanation below.
+ */
+static inline HRESULT
+D3DDrawTextureWithHint(D3DContext *d3dc, D3DTEXTUREFILTERTYPE hint,
+ jint srcWidth, jint srcHeight,
+ float tw, float th,
+ jint sx1, jint sy1, jint sx2, jint sy2,
+ float dx1, float dy1, float dx2, float dy2,
+ float tx1, float ty1, float tx2, float ty2)
+{
+ HRESULT res;
+
+ if (hint == D3DTEXF_LINEAR &&
+ (srcWidth != tw || srcHeight != th ||
+ srcWidth != sx2 || srcHeight != sy2 ))
+ {
+ /*
+ * When the image bounds are smaller than the bounds of the
+ * texture that the image resides in, D3DTEXF_LINEAR will use pixels
+ * from outside the valid image bounds, which could result in garbage
+ * pixels showing up at the edges of the transformed result. We set
+ * the texture wrap mode to D3DTADDRESS_CLAMP, which solves the problem
+ * for the top and left edges. But when the source bounds do not
+ * match the texture bounds, we need to perform this as a four-part
+ * operation in order to prevent the filter used by D3D from using
+ * invalid pixels at the bottom and right edges.
+ *
+ * Note that we only need to apply this technique when the source
+ * bounds are equal to the actual image bounds. If the source bounds
+ * fall within the image bounds there is no need to apply this hack
+ * because the filter used by D3D will access valid pixels.
+ * Likewise, if the image bounds are equal to the texture bounds,
+ * then the edge conditions are handled properly by D3DTADDRESS_CLAMP.
+ */
+
+ // These values represent the bottom-right corner of source texture
+ // region pulled in by 1/2 of a source texel.
+ float tx2adj = tx2 - (1.0f / (2.0f * tw));
+ float ty2adj = ty2 - (1.0f / (2.0f * th));
+
+ // These values represent the above coordinates pulled in by a
+ // tiny fraction. As an example, if we sample the tiny area from
+ // tx2adj2 to tx2adj, the result should be the solid color at the
+ // texel center corresponding to tx2adj.
+ float tx2adj2 = tx2adj - 0.0001f;
+ float ty2adj2 = ty2adj - 0.0001f;
- D3DU_INIT_VERTEX_QUAD(quadVerts, dx1, dy1, dx2, dy2,
- d3dc->blitPolygonPixel,
- tx1, ty1, tx2, ty2);
+ // These values represent the bottom-right corner of the destination
+ // region pulled in by 1/2 of a destination pixel.
+ float dx2adj = dx2 - 0.5f;
+ float dy2adj = dy2 - 0.5f;
- if (hint == D3DSD_XFORM_BILINEAR) {
- d3dDevice->SetTextureStageState(0, D3DTSS_MAGFILTER, D3DTFG_LINEAR);
- d3dDevice->SetTextureStageState(0, D3DTSS_MINFILTER, D3DTFG_LINEAR);
- } else if (hint == D3DSD_XFORM_NEAREST_NEIGHBOR) {
- d3dDevice->SetTextureStageState(0, D3DTSS_MAGFILTER, D3DTFG_POINT);
- d3dDevice->SetTextureStageState(0, D3DTSS_MINFILTER, D3DTFG_POINT);
+ // First, render a majority of the source texture, from the top-left
+ // corner to the bottom-right, but not including the right or bottom
+ // edges.
+ d3dc->pVCacher->DrawTexture(dx1, dy1, dx2adj, dy2adj,
+ tx1, ty1, tx2adj, ty2adj);
+
+ // Second, render the remaining sliver on the right edge.
+ d3dc->pVCacher->DrawTexture(dx2adj, dy1, dx2, dy2adj,
+ tx2adj2, ty1, tx2adj, ty2adj);
+
+ // Third, render the remaining sliver on the bottom edge.
+ d3dc->pVCacher->DrawTexture(dx1, dy2adj, dx2adj, dy2,
+ tx1, ty2adj2, tx2adj, ty2adj);
+
+ // Finally, render the remaining speck at the bottom-right corner.
+ res = d3dc->pVCacher->DrawTexture(dx2adj, dy2adj, dx2, dy2,
+ tx2adj2, ty2adj2, tx2adj, ty2adj);
+ } else {
+ /*
+ * As mentioned above, we can issue a simple textured quad if:
+ * - the hint is D3DTEXF_POINT or
+ * - the source bounds are sufficiently inside the texture bounds or
+ * - the image bounds are equal to the texture bounds (as is the
+ * case when the image has power-of-two dimensions, or when the
+ * device supports non-pow2 textures)
+ */
+ res = d3dc->pVCacher->DrawTexture(dx1, dy1, dx2, dy2,
+ tx1, ty1, tx2, ty2);
}
+ return res;
+}
+/**
+ * Inner loop used for copying a source D3D "Texture" to a destination
+ * D3D "Surface". This method is invoked from D3DBlitLoops_IsoBlit().
+ *
+ * This method will copy, scale, or transform the source texture into the
+ * destination depending on the transform state, as established in
+ * and D3DContext::SetTransform(). If the source texture is
+ * transformed in any way when rendered into the destination, the filtering
+ * method applied is determined by the hint parameter.
+ */
+static HRESULT
+D3DBlitTextureToSurface(D3DContext *d3dc,
+ D3DSDOps *srcOps, D3DSDOps *dstOps,
+ jboolean rtt, D3DTEXTUREFILTERTYPE hint,
+ jint sx1, jint sy1, jint sx2, jint sy2,
+ float dx1, float dy1, float dx2, float dy2)
+{
HRESULT res;
- D3DU_PRIM2_LOOP_BEGIN(res, srcOps, dstOps);
- if (SUCCEEDED(res = d3dc->BeginScene(STATE_BLITOP))) {
- DXSurface *dxSurface = ddSrcSurface->GetDXSurface();
- if (SUCCEEDED(res = d3dc->SetTexture(dxSurface)))
- {
- res = d3dDevice->DrawPrimitive(D3DPT_TRIANGLEFAN, D3DFVF_J2DLVERTEX,
- quadVerts, 4, 0);
+ IDirect3DTexture9 *pSrc;
+ IDirect3DDevice9 *pd3dDevice;
+ float tx1, ty1, tx2, ty2;
+ float tw, th;
+
+ J2dTraceLn(J2D_TRACE_INFO, "D3DBlitTextureToSurface");
+
+ RETURN_STATUS_IF_NULL(srcOps->pResource, E_FAIL);
+ RETURN_STATUS_IF_NULL(dstOps->pResource, E_FAIL);
+
+ if ((pSrc = srcOps->pResource->GetTexture()) == NULL ||
+ FAILED(res = d3dc->BeginScene(STATE_TEXTUREOP) ||
+ FAILED(res = d3dc->SetTexture(pSrc))))
+ {
+ J2dRlsTraceLn(J2D_TRACE_ERROR,
+ "D3DBlitTextureToSurface: BeginScene or SetTexture failed");
+ return res;
+ }
+
+ pd3dDevice = d3dc->Get3DDevice();
+ pd3dDevice->SetSamplerState(0, D3DSAMP_MAGFILTER, hint);
+ pd3dDevice->SetSamplerState(0, D3DSAMP_MINFILTER, hint);
+ pd3dDevice->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP);
+ pd3dDevice->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP);
+
+ tw = (float)srcOps->pResource->GetDesc()->Width;
+ th = (float)srcOps->pResource->GetDesc()->Height;
+
+ // convert the source bounds into the range [0,1]
+ tx1 = ((float)sx1) / tw;
+ ty1 = ((float)sy1) / th;
+ tx2 = ((float)sx2) / tw;
+ ty2 = ((float)sy2) / th;
+
+ return D3DDrawTextureWithHint(d3dc, hint,
+ srcOps->width, srcOps->height,
+ tw, th,
+ sx1, sy1, sx2, sy2,
+ dx1, dy1, dx2, dy2,
+ tx1, ty1, tx2, ty2);
+}
+
+/**
+ * Inner loop used for copying a source system memory ("Sw") surface or
+ * D3D "Surface" to a destination D3D "Surface", using an D3D texture
+ * tile as an intermediate surface. This method is invoked from
+ * D3DBlitLoops_Blit() for "Sw" surfaces and D3DBlitLoops_IsoBlit() for
+ * "Surface" surfaces.
+ *
+ * This method is used to transform the source surface into the destination.
+ * Pixel rectangles cannot be arbitrarily transformed. However, texture
+ * mapped quads do respect the modelview transform matrix, so we use
+ * textures here to perform the transform operation. This method uses a
+ * tile-based approach in which a small subregion of the source surface is
+ * copied into a cached texture tile. The texture tile is then mapped
+ * into the appropriate location in the destination surface.
+ *
+ */
+D3DPIPELINE_API HRESULT
+D3DBlitToSurfaceViaTexture(D3DContext *d3dc, SurfaceDataRasInfo *srcInfo,
+ int srctype, D3DSDOps *srcOps,
+ jboolean swsurface, jint hint,
+ jint sx1, jint sy1, jint sx2, jint sy2,
+ jdouble dx1, jdouble dy1, jdouble dx2, jdouble dy2)
+{
+ double tx1, ty1, tx2, ty2;
+ double dx, dy, dw, dh, cdw, cdh;
+ jint tw, th;
+ jint sx, sy, sw, sh;
+ HRESULT res = S_OK;
+ D3DResource *pBlitTextureRes = NULL;
+ IDirect3DTexture9 *pBlitTexture = NULL;
+ IDirect3DSurface9 *pBlitSurface = NULL, *pSrc = NULL;
+ D3DTEXTUREFILTERTYPE fhint =
+ (hint == D3DSD_XFORM_BILINEAR) ? D3DTEXF_LINEAR : D3DTEXF_POINT;
+ fhint = d3dc->IsTextureFilteringSupported(fhint) ? fhint : D3DTEXF_NONE;
+
+ if (swsurface) {
+ res = d3dc->GetResourceManager()->GetBlitTexture(&pBlitTextureRes);
+ } else {
+ RETURN_STATUS_IF_NULL(srcOps->pResource, E_FAIL);
+ RETURN_STATUS_IF_NULL(pSrc = srcOps->pResource->GetSurface(), E_FAIL);
+
+ res = d3dc->GetResourceManager()->
+ GetBlitRTTexture(D3DC_BLIT_TILE_SIZE, D3DC_BLIT_TILE_SIZE,
+ srcOps->pResource->GetDesc()->Format,
+ &pBlitTextureRes);
+ }
+ if (FAILED(res)) {
+ J2dRlsTraceLn(J2D_TRACE_ERROR,
+ "D3DBlitToSurfaceViaTexture: could not init blit tile");
+ return res;
+ }
+ pBlitSurface = pBlitTextureRes->GetSurface();
+ pBlitTexture = pBlitTextureRes->GetTexture();
+
+ D3DSURFACE_DESC *pDesc = pBlitTextureRes->GetDesc();
+
+ tx1 = 0.0f;
+ ty1 = 0.0f;
+ tw = pDesc->Width;
+ th = pDesc->Height;
+ cdw = (dx2-dx1) / (((double)(sx2-sx1)) / tw);
+ cdh = (dy2-dy1) / (((double)(sy2-sy1)) / th);
+
+ res = d3dc->BeginScene(STATE_TEXTUREOP);
+ RETURN_STATUS_IF_FAILED(res);
+ res = d3dc->SetTexture(pBlitTexture);
+ RETURN_STATUS_IF_FAILED(res);
+
+ IDirect3DDevice9 *pd3dDevice = d3dc->Get3DDevice();
+ pd3dDevice->SetSamplerState(0, D3DSAMP_MAGFILTER, fhint);
+ pd3dDevice->SetSamplerState(0, D3DSAMP_MINFILTER, fhint);
+ pd3dDevice->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP);
+ pd3dDevice->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP);
+
+ for (sy = sy1, dy = dy1; sy < sy2; sy += th, dy += cdh) {
+ sh = ((sy + th) > sy2) ? (sy2 - sy) : th;
+ dh = ((dy + cdh) > dy2) ? (dy2 - dy) : cdh;
+
+ for (sx = sx1, dx = dx1; sx < sx2; sx += tw, dx += cdw) {
+ sw = ((sx + tw) > sx2) ? (sx2 - sx) : tw;
+ dw = ((dx + cdw) > dx2) ? (dx2 - dx) : cdw;
+
+ tx2 = ((double)sw) / tw;
+ ty2 = ((double)sh) / th;
+
+ if (swsurface) {
+ D3DBL_CopyImageToIntXrgbSurface(srcInfo,
+ srctype, pBlitTextureRes,
+ sx, sy, sw, sh,
+ 0, 0);
+ } else {
+ RECT srcRect = { (LONG)sx, (LONG)sy,
+ (LONG)(sx+dw), (LONG)(sy+dh) };
+ RECT dstRect = { 0l, 0l, (LONG)dw, (LONG)dh };
+ pd3dDevice->StretchRect(pSrc,
+ &srcRect, pBlitSurface, &dstRect,
+ D3DTEXF_NONE);
+ }
+ D3DDrawTextureWithHint(d3dc, fhint,
+ tw, th,
+ (float)tw, (float)th,
+ sx, sy, sw, sh,
+ (float)dx, (float)dy, (float)(dx+dw), (float)(dy+dh),
+ (float)tx1, (float)ty1, (float)tx2, (float)ty2);
+ res = d3dc->pVCacher->Render();
}
- d3dc->EndScene(res);
}
- D3DU_PRIM2_LOOP_END(env, res, srcOps, dstOps,
- "DrawPrimitive(D3DPT_TRIANGLEFAN)");
+ return res;
+}
+
+/**
+ * Inner loop used for copying a source system memory ("Sw") surface to a
+ * destination D3D "Texture". This method is invoked from
+ * D3DBlitLoops_Blit().
+ *
+ * The source surface is effectively loaded into the D3D texture object,
+ * which must have already been initialized by D3DSD_initTexture(). Note
+ * that this method is only capable of copying the source surface into the
+ * destination surface (i.e. no scaling or general transform is allowed).
+ * This restriction should not be an issue as this method is only used
+ * currently to cache a static system memory image into an D3D texture in
+ * a hidden-acceleration situation.
+ */
+static HRESULT
+D3DBlitSwToTexture(D3DContext *d3dc,
+ SurfaceDataRasInfo *srcInfo, int srctype,
+ D3DSDOps *dstOps,
+ jint sx1, jint sy1, jint sx2, jint sy2)
+{
+ RETURN_STATUS_IF_NULL(dstOps->pResource, E_FAIL);
+ RETURN_STATUS_IF_NULL(dstOps->pResource->GetSurface(), E_FAIL);
+
+ return D3DBL_CopyImageToIntXrgbSurface(srcInfo, srctype,
+ dstOps->pResource,
+ sx1, sy1, sx2-sx1, sy2-sy1,
+ 0, 0);
+}
+
+/**
+ * General blit method for copying a native D3D surface (of type "Surface"
+ * or "Texture") to another D3D "Surface". If texture is JNI_TRUE, this
+ * method will invoke the Texture->Surface inner loop; otherwise, one of the
+ * Surface->Surface inner loops will be invoked, depending on the transform
+ * state.
+ */
+D3DPIPELINE_API HRESULT
+D3DBlitLoops_IsoBlit(JNIEnv *env,
+ D3DContext *d3dc, jlong pSrcOps, jlong pDstOps,
+ jboolean xform, jint hint,
+ jboolean texture, jboolean rtt,
+ jint sx1, jint sy1, jint sx2, jint sy2,
+ jdouble dx1, jdouble dy1, jdouble dx2, jdouble dy2)
+{
+ D3DSDOps *srcOps = (D3DSDOps *)jlong_to_ptr(pSrcOps);
+ D3DSDOps *dstOps = (D3DSDOps *)jlong_to_ptr(pDstOps);
+ SurfaceDataRasInfo srcInfo;
+ jint sw = sx2 - sx1;
+ jint sh = sy2 - sy1;
+ jdouble dw = dx2 - dx1;
+ jdouble dh = dy2 - dy1;
+
+ J2dTraceLn(J2D_TRACE_INFO, "D3DBlitLoops_IsoBlit");
+
+ if (sw <= 0 || sh <= 0 || dw <= 0 || dh <= 0) {
+ J2dTraceLn(J2D_TRACE_WARNING,
+ "D3DBlitLoops_IsoBlit: invalid dimensions");
+ return E_FAIL;
+ }
+
+ RETURN_STATUS_IF_NULL(srcOps, E_FAIL);
+ RETURN_STATUS_IF_NULL(dstOps, E_FAIL);
+ RETURN_STATUS_IF_NULL(d3dc, E_FAIL);
+ RETURN_STATUS_IF_NULL(d3dc->Get3DDevice(), E_FAIL);
+
+ srcInfo.bounds.x1 = sx1;
+ srcInfo.bounds.y1 = sy1;
+ srcInfo.bounds.x2 = sx2;
+ srcInfo.bounds.y2 = sy2;
+
+ SurfaceData_IntersectBoundsXYXY(&srcInfo.bounds,
+ 0, 0, srcOps->width, srcOps->height);
+
+
+ HRESULT res = S_OK;
+ if (srcInfo.bounds.x2 > srcInfo.bounds.x1 &&
+ srcInfo.bounds.y2 > srcInfo.bounds.y1)
+ {
+ if (srcInfo.bounds.x1 != sx1) {
+ dx1 += (srcInfo.bounds.x1 - sx1) * (dw / sw);
+ sx1 = srcInfo.bounds.x1;
+ }
+ if (srcInfo.bounds.y1 != sy1) {
+ dy1 += (srcInfo.bounds.y1 - sy1) * (dh / sh);
+ sy1 = srcInfo.bounds.y1;
+ }
+ if (srcInfo.bounds.x2 != sx2) {
+ dx2 += (srcInfo.bounds.x2 - sx2) * (dw / sw);
+ sx2 = srcInfo.bounds.x2;
+ }
+ if (srcInfo.bounds.y2 != sy2) {
+ dy2 += (srcInfo.bounds.y2 - sy2) * (dh / sh);
+ sy2 = srcInfo.bounds.y2;
+ }
+
+ J2dTraceLn2(J2D_TRACE_VERBOSE, " texture=%d hint=%d", texture, hint);
+ J2dTraceLn4(J2D_TRACE_VERBOSE, " sx1=%d sy1=%d sx2=%d sy2=%d",
+ sx1, sy1, sx2, sy2);
+ J2dTraceLn4(J2D_TRACE_VERBOSE, " dx1=%f dy1=%f dx2=%f dy2=%f",
+ dx1, dy1, dx2, dy2);
+
+ D3DTEXTUREFILTERTYPE fhint =
+ (hint == D3DSD_XFORM_BILINEAR) ? D3DTEXF_LINEAR : D3DTEXF_POINT;
+ if (texture) {
+ fhint = d3dc->IsTextureFilteringSupported(fhint) ?
+ fhint : D3DTEXF_NONE;
+ res = D3DBlitTextureToSurface(d3dc, srcOps, dstOps, rtt, fhint,
+ sx1, sy1, sx2, sy2,
+ (float)dx1, (float)dy1,
+ (float)dx2, (float)dy2);
+ } else {
+ // StretchRect does not do compositing or clipping
+ IDirect3DDevice9 *pd3dDevice = d3dc->Get3DDevice();
+ DWORD abEnabled = 0;
+
+ pd3dDevice->GetRenderState(D3DRS_ALPHABLENDENABLE, &abEnabled);
+ J2dTraceLn3(J2D_TRACE_VERBOSE, " xform=%d clip=%d abEnabled=%d",
+ xform, d3dc->GetClipType(), abEnabled);
+ if (!xform && d3dc->GetClipType() != CLIP_SHAPE && !abEnabled) {
+ fhint = d3dc->IsStretchRectFilteringSupported(fhint) ?
+ fhint : D3DTEXF_NONE;
- d3dc->ReleaseExclusiveAccess();
- ddTargetSurface->ReleaseExclusiveAccess();
+ res = D3DBlitSurfaceToSurface(d3dc, srcOps, dstOps, fhint,
+ sx1, sy1, sx2, sy2,
+ (int)dx1, (int)dy1,
+ (int)dx2, (int)dy2);
+ } else {
+ res = D3DBlitToSurfaceViaTexture(d3dc, &srcInfo,
+ // surface type is unused here
+ ST_INT_ARGB_PRE,
+ srcOps,
+ JNI_FALSE, hint,
+ sx1, sy1, sx2, sy2,
+ dx1, dy1, dx2, dy2);
+ }
+ }
+ }
+ return res;
}
+/**
+ * General blit method for copying a system memory ("Sw") surface to a native
+ * D3D surface (of type "Surface" or "Texture"). If texture is JNI_TRUE,
+ * this method will invoke the Sw->Texture inner loop; otherwise, one of the
+ * Sw->Surface inner loops will be invoked, depending on the transform state.
+ */
+HRESULT
+D3DBlitLoops_Blit(JNIEnv *env,
+ D3DContext *d3dc, jlong pSrcOps, jlong pDstOps,
+ jboolean xform, jint hint,
+ jint srctype, jboolean texture,
+ jint sx1, jint sy1, jint sx2, jint sy2,
+ jdouble dx1, jdouble dy1, jdouble dx2, jdouble dy2)
+{
+ SurfaceDataOps *srcOps = (SurfaceDataOps *)jlong_to_ptr(pSrcOps);
+ D3DSDOps *dstOps = (D3DSDOps *)jlong_to_ptr(pDstOps);
+ SurfaceDataRasInfo srcInfo;
+ HRESULT res = S_OK;
+ jint sw = sx2 - sx1;
+ jint sh = sy2 - sy1;
+ jdouble dw = dx2 - dx1;
+ jdouble dh = dy2 - dy1;
+ jint lockFlags = SD_LOCK_READ;
+
+ J2dTraceLn(J2D_TRACE_INFO, "D3DBlitLoops_Blit");
+
+ if (sw <= 0 || sh <= 0 || dw <= 0 || dh <= 0 || srctype < 0) {
+ J2dTraceLn(J2D_TRACE_WARNING,
+ "D3DBlitLoops_Blit: invalid dimensions or srctype");
+ return E_FAIL;
+ }
+
+ RETURN_STATUS_IF_NULL(srcOps, E_FAIL);
+ RETURN_STATUS_IF_NULL(dstOps, E_FAIL);
+ RETURN_STATUS_IF_NULL(d3dc, E_FAIL);
+ RETURN_STATUS_IF_NULL(d3dc->Get3DDevice(), E_FAIL);
+
+ srcInfo.bounds.x1 = sx1;
+ srcInfo.bounds.y1 = sy1;
+ srcInfo.bounds.x2 = sx2;
+ srcInfo.bounds.y2 = sy2;
+
+ if (srctype == ST_BYTE_INDEXED || srctype == ST_BYTE_INDEXED_BM) {
+ lockFlags |= SD_LOCK_LUT;
+ }
+ if (srcOps->Lock(env, srcOps, &srcInfo, lockFlags) != SD_SUCCESS) {
+ J2dTraceLn(J2D_TRACE_WARNING,
+ "D3DBlitLoops_Blit: could not acquire lock");
+ return E_FAIL;
+ }
+
+ if (srcInfo.bounds.x2 > srcInfo.bounds.x1 &&
+ srcInfo.bounds.y2 > srcInfo.bounds.y1)
+ {
+ srcOps->GetRasInfo(env, srcOps, &srcInfo);
+ if (srcInfo.rasBase) {
+ if (srcInfo.bounds.x1 != sx1) {
+ dx1 += (srcInfo.bounds.x1 - sx1) * (dw / sw);
+ sx1 = srcInfo.bounds.x1;
+ }
+ if (srcInfo.bounds.y1 != sy1) {
+ dy1 += (srcInfo.bounds.y1 - sy1) * (dh / sh);
+ sy1 = srcInfo.bounds.y1;
+ }
+ if (srcInfo.bounds.x2 != sx2) {
+ dx2 += (srcInfo.bounds.x2 - sx2) * (dw / sw);
+ sx2 = srcInfo.bounds.x2;
+ }
+ if (srcInfo.bounds.y2 != sy2) {
+ dy2 += (srcInfo.bounds.y2 - sy2) * (dh / sh);
+ sy2 = srcInfo.bounds.y2;
+ }
+
+ J2dTraceLn3(J2D_TRACE_VERBOSE, " texture=%d srctype=%d hint=%d",
+ texture, srctype, hint);
+ J2dTraceLn4(J2D_TRACE_VERBOSE, " sx1=%d sy1=%d sx2=%d sy2=%d",
+ sx1, sy1, sx2, sy2);
+ J2dTraceLn4(J2D_TRACE_VERBOSE, " dx1=%f dy1=%f dx2=%f dy2=%f",
+ dx1, dy1, dx2, dy2);
+
+ if (texture) {
+ // These coordinates will always be integers since we
+ // only ever do a straight copy from sw to texture.
+ // Thus these casts are "safe" - no loss of precision.
+ res = D3DBlitSwToTexture(d3dc, &srcInfo, srctype, dstOps,
+ (jint)dx1, (jint)dy1,
+ (jint)dx2, (jint)dy2);
+ } else {
+ res = D3DBlitToSurfaceViaTexture(d3dc, &srcInfo, srctype, NULL,
+ JNI_TRUE, hint,
+ sx1, sy1, sx2, sy2,
+ dx1, dy1, dx2, dy2);
+ }
+ }
+ SurfaceData_InvokeRelease(env, srcOps, &srcInfo);
+ }
+ SurfaceData_InvokeUnlock(env, srcOps, &srcInfo);
+ return res;
+}
+
+/**
+ * Specialized blit method for copying a native D3D "Surface" (pbuffer,
+ * window, etc.) to a system memory ("Sw") surface.
+ */
+HRESULT
+D3DBlitLoops_SurfaceToSwBlit(JNIEnv *env, D3DContext *d3dc,
+ jlong pSrcOps, jlong pDstOps, jint dsttype,
+ jint srcx, jint srcy, jint dstx, jint dsty,
+ jint width, jint height)
+{
+ D3DSDOps *srcOps = (D3DSDOps *)jlong_to_ptr(pSrcOps);
+ SurfaceDataOps *dstOps = (SurfaceDataOps *)jlong_to_ptr(pDstOps);
+ SurfaceDataRasInfo srcInfo, dstInfo;
+ HRESULT res = S_OK;
+
+ J2dTraceLn(J2D_TRACE_INFO, "D3DBlitLoops_SurfaceToSwBlit");
+
+ if (width <= 0 || height <= 0) {
+ J2dTraceLn(J2D_TRACE_WARNING,
+ "D3DBlitLoops_SurfaceToSwBlit: dimensions are non-positive");
+ return S_OK;
+ }
+
+ RETURN_STATUS_IF_NULL(srcOps, E_FAIL);
+ RETURN_STATUS_IF_NULL(srcOps->pResource, E_FAIL);
+ RETURN_STATUS_IF_NULL(dstOps, E_FAIL);
+ RETURN_STATUS_IF_NULL(d3dc, E_FAIL);
+ RETURN_STATUS_IF_NULL(d3dc->Get3DDevice(), E_FAIL);
+
+ srcInfo.bounds.x1 = srcx;
+ srcInfo.bounds.y1 = srcy;
+ srcInfo.bounds.x2 = srcx + width;
+ srcInfo.bounds.y2 = srcy + height;
+ dstInfo.bounds.x1 = dstx;
+ dstInfo.bounds.y1 = dsty;
+ dstInfo.bounds.x2 = dstx + width;
+ dstInfo.bounds.y2 = dsty + height;
+
+ if (dstOps->Lock(env, dstOps, &dstInfo, SD_LOCK_WRITE) != SD_SUCCESS) {
+ J2dTraceLn(J2D_TRACE_WARNING,
+ "D3DBlitLoops_SurfaceToSwBlit: could not acquire dst lock");
+ return S_OK;
+ }
+
+ SurfaceData_IntersectBoundsXYXY(&srcInfo.bounds,
+ 0, 0, srcOps->width, srcOps->height);
+ SurfaceData_IntersectBlitBounds(&dstInfo.bounds, &srcInfo.bounds,
+ srcx - dstx, srcy - dsty);
+
+ if (srcInfo.bounds.x2 > srcInfo.bounds.x1 &&
+ srcInfo.bounds.y2 > srcInfo.bounds.y1)
+ {
+ dstOps->GetRasInfo(env, dstOps, &dstInfo);
+ if (dstInfo.rasBase) {
+ IDirect3DDevice9 *pd3dDevice = d3dc->Get3DDevice();
+ IDirect3DSurface9 *pSrc = srcOps->pResource->GetSurface();
+ D3DFORMAT srcFmt = srcOps->pResource->GetDesc()->Format;
+ UINT srcw = srcOps->pResource->GetDesc()->Width;
+ UINT srch = srcOps->pResource->GetDesc()->Height;
+ D3DResource *pLockableRes;
+
+ srcx = srcInfo.bounds.x1;
+ srcy = srcInfo.bounds.y1;
+ dstx = dstInfo.bounds.x1;
+ dsty = dstInfo.bounds.y1;
+ width = srcInfo.bounds.x2 - srcInfo.bounds.x1;
+ height = srcInfo.bounds.y2 - srcInfo.bounds.y1;
+
+ J2dTraceLn4(J2D_TRACE_VERBOSE, " sx=%d sy=%d w=%d h=%d",
+ srcx, srcy, width, height);
+ J2dTraceLn2(J2D_TRACE_VERBOSE, " dx=%d dy=%d",
+ dstx, dsty);
+
+ d3dc->UpdateState(STATE_OTHEROP);
+
+ // if we read more than 50% of the image it is faster
+ // to get the whole thing (50% is pulled out of a hat)
+ BOOL fullRead = ((width * height) >= (srcw * srch * 0.5f));
+ UINT lockSrcX = 0, lockSrcY = 0;
+
+ if (fullRead) {
+ // read whole surface into a sysmem surface
+ lockSrcX = srcx;
+ lockSrcY = srcy;
+ // the dest surface must have the same dimensions and format as
+ // the source, GetBlitOSPSurface ensures that
+ res = d3dc->GetResourceManager()->
+ GetBlitOSPSurface(srcw, srch, srcFmt, &pLockableRes);
+ } else {
+ // we first copy the source region to a temp
+ // render target surface of the same format as the
+ // source, then copy the pixels to the
+ // target buffered image surface
+ res = d3dc->GetResourceManager()->
+ GetLockableRTSurface(width, height, srcFmt, &pLockableRes);
+ }
+ if (SUCCEEDED(res)) {
+ IDirect3DSurface9 *pTmpSurface = pLockableRes->GetSurface();
+
+ if (fullRead) {
+ res = pd3dDevice->GetRenderTargetData(pSrc, pTmpSurface);
+ } else {
+ RECT srcRect = { srcx, srcy, srcx+width, srcy+height};
+ RECT dstRect = { 0l, 0l, width, height };
+
+ res = pd3dDevice->StretchRect(pSrc,
+ &srcRect, pTmpSurface,
+ &dstRect, D3DTEXF_NONE);
+ }
+
+ if (SUCCEEDED(res)) {
+ res = D3DBL_CopySurfaceToIntArgbImage(
+ pTmpSurface, /* src surface */
+ &dstInfo, /* dst info */
+ lockSrcX, lockSrcY, width, height, /* src rect */
+ dstx, dsty); /* dst coords */
+ }
+ }
+ }
+ SurfaceData_InvokeRelease(env, dstOps, &dstInfo);
+ }
+ SurfaceData_InvokeUnlock(env, dstOps, &dstInfo);
+ return res;
+}
+
+HRESULT
+D3DBlitLoops_CopyArea(JNIEnv *env,
+ D3DContext *d3dc, D3DSDOps *dstOps,
+ jint x, jint y, jint width, jint height,
+ jint dx, jint dy)
+{
+ SurfaceDataBounds srcBounds, dstBounds;
+ HRESULT res = S_OK;
+
+ J2dTraceLn(J2D_TRACE_INFO, "D3DBlitLoops_CopyArea");
+
+ RETURN_STATUS_IF_NULL(d3dc, E_FAIL);
+ RETURN_STATUS_IF_NULL(dstOps, E_FAIL);
+ RETURN_STATUS_IF_NULL(dstOps->pResource, E_FAIL);
+
+ J2dTraceLn4(J2D_TRACE_VERBOSE, " x=%d y=%d w=%d h=%d",
+ x, y, width, height);
+ J2dTraceLn2(J2D_TRACE_VERBOSE, " dx=%d dy=%d",
+ dx, dy);
+
+ IDirect3DDevice9 *pd3dDevice = d3dc->Get3DDevice();
+ RETURN_STATUS_IF_NULL(pd3dDevice, E_FAIL);
+ ClipType clipType = d3dc->GetClipType();
+
+ srcBounds.x1 = x;
+ srcBounds.y1 = y;
+ srcBounds.x2 = srcBounds.x1 + width;
+ srcBounds.y2 = srcBounds.y1 + height;
+ dstBounds.x1 = x + dx;
+ dstBounds.y1 = y + dy;
+ dstBounds.x2 = dstBounds.x1 + width;
+ dstBounds.y2 = dstBounds.y1 + height;
+
+ SurfaceData_IntersectBoundsXYXY(&srcBounds,
+ 0, 0, dstOps->width, dstOps->height);
+ if (clipType == CLIP_RECT) {
+ J2dTraceLn(J2D_TRACE_VERBOSE, " rect clip, clip dest manually");
+ RECT clipRect;
+ pd3dDevice->GetScissorRect(&clipRect);
+ SurfaceData_IntersectBoundsXYXY(&dstBounds,
+ clipRect.left, clipRect.top,
+ clipRect.right, clipRect.bottom);
+ }
+ SurfaceData_IntersectBoundsXYXY(&dstBounds,
+ 0, 0, dstOps->width, dstOps->height);
+ SurfaceData_IntersectBlitBounds(&dstBounds, &srcBounds, -dx, -dy);
+
+ if (dstBounds.x1 < dstBounds.x2 && dstBounds.y1 < dstBounds.y2) {
+ jint sx1 = srcBounds.x1, sy1 = srcBounds.y1,
+ sx2 = srcBounds.x2, sy2 = srcBounds.y2;
+ jint dx1 = dstBounds.x1, dy1 = dstBounds.y1,
+ dx2 = dstBounds.x2, dy2 = dstBounds.y2;
+ jint dw = dx2 - dx1, dh = dy2 - dy1;
+
+ IDirect3DTexture9 *pBlitTexture = NULL;
+ IDirect3DSurface9 *pBlitSurface = NULL;
+ D3DResource *pBlitTextureRes;
+
+ res = d3dc->GetResourceManager()->
+ GetBlitRTTexture(dw, dh,
+ dstOps->pResource->GetDesc()->Format,
+ &pBlitTextureRes);
+ if (SUCCEEDED(res)) {
+ pBlitSurface = pBlitTextureRes->GetSurface();
+ pBlitTexture = pBlitTextureRes->GetTexture();
+ }
+ if (!pBlitTexture || !pBlitSurface) {
+ J2dRlsTraceLn(J2D_TRACE_ERROR,
+ "D3DBlitLoops_CopyArea: could not init blit tile");
+ return E_FAIL;
+ }
+
+ // flush the rendering first
+ d3dc->UpdateState(STATE_OTHEROP);
+
+ // REMIND: see if we could always use texture mapping;
+ // the assumption here is that StretchRect is faster,
+ // if it's not, then we should always use texture mapping
+
+ // from src surface to the temp texture
+ RECT srcRect = { sx1, sy1, sx2, sy2 };
+ RECT tmpDstRect = { 0l, 0l, 0+dw, 0+dh };
+ res = pd3dDevice->StretchRect(dstOps->pResource->GetSurface(), &srcRect,
+ pBlitSurface, &tmpDstRect,
+ D3DTEXF_NONE);
+ if (clipType != CLIP_SHAPE) {
+ J2dTraceLn(J2D_TRACE_VERBOSE, " rect or no clip, use StretchRect");
+ // just do stretch rect to the destination
+ RECT dstRect = { dx1, dy1, dx2, dy2 };
+ // from temp surface to the destination
+ res = pd3dDevice->StretchRect(pBlitSurface, &tmpDstRect,
+ dstOps->pResource->GetSurface(),
+ &dstRect,
+ D3DTEXF_NONE);
+ } else {
+ J2dTraceLn(J2D_TRACE_VERBOSE, " shape clip, use texture mapping");
+ // shape clip - have to use texture mapping
+ D3DTEXTUREFILTERTYPE fhint =
+ d3dc->IsTextureFilteringSupported(D3DTEXF_NONE) ?
+ D3DTEXF_NONE: D3DTEXF_POINT;
+ pd3dDevice->SetSamplerState(0, D3DSAMP_MAGFILTER, fhint);
+ pd3dDevice->SetSamplerState(0, D3DSAMP_MINFILTER, fhint);
+ res = d3dc->BeginScene(STATE_TEXTUREOP);
+ RETURN_STATUS_IF_FAILED(res);
+ res = d3dc->SetTexture(pBlitTexture);
+
+ float tx2 = (float)dw/(float)pBlitTextureRes->GetDesc()->Width;
+ float ty2 = (float)dh/(float)pBlitTextureRes->GetDesc()->Height;
+ res = d3dc->pVCacher->DrawTexture(
+ (float)dx1, (float)dy1, (float)dx2, (float)dy2,
+ 0.0f, 0.0f, tx2, ty2);
+ }
+ }
+ return res;
}