/* * Copyright (c) 2007, 2008, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ #include "D3DPipeline.h" #include #include "sun_java2d_pipe_BufferedOpCodes.h" #include "jlong.h" #include "D3DBlitLoops.h" #include "D3DBufImgOps.h" #include "D3DPipelineManager.h" #include "D3DContext.h" #include "D3DMaskBlit.h" #include "D3DMaskFill.h" #include "D3DPaints.h" #include "D3DRenderQueue.h" #include "D3DRenderer.h" #include "D3DSurfaceData.h" #include "D3DTextRenderer.h" #include "Trace.h" #include "awt_Toolkit.h" BOOL DWMIsCompositionEnabled(); /** * References to the "current" context and destination surface. */ static D3DContext *d3dc = NULL; static D3DSDOps *dstOps = NULL; static BOOL bLostDevices = FALSE; typedef struct { byte *buffer; int limit; jobject runnable; } FlushBufferStruct; HRESULT D3DRQ_SwapBuffers(D3DPipelineManager *pMgr, D3DSDOps *d3dsdo, int x1, int y1, int x2, int y2) { HRESULT res; D3DContext *pCtx; IDirect3DSwapChain9 *pSwapChain; RECT srcRect, dstRect, *pSrcRect, *pDstRect; J2dTraceLn(J2D_TRACE_INFO, "D3DRQ_SwapBuffers"); J2dTraceLn4(J2D_TRACE_VERBOSE, " x1=%d y1=%d x2=%d y2=%d", x1, y1, x2, y2); RETURN_STATUS_IF_NULL(d3dsdo, E_FAIL); RETURN_STATUS_IF_NULL(d3dsdo->pResource, E_FAIL); RETURN_STATUS_IF_NULL(pSwapChain=d3dsdo->pResource->GetSwapChain(), E_FAIL); pCtx = D3DRQ_GetCurrentContext(); if (pCtx != NULL) { // flush the current vertex queue here, just in case res = d3dc->FlushVertexQueue(); D3DRQ_MarkLostIfNeeded(res, dstOps); pCtx = NULL; } // end scene for this destination res = pMgr->GetD3DContext(d3dsdo->adapter, &pCtx); RETURN_STATUS_IF_FAILED(res); pCtx->EndScene(); // This is a workaround for what apparently is a DWM bug. // If the dimensions of the back-buffer don't match the dimensions of // the window, Present() will flash the whole window with black. // The workaround is to detect this situation and not do a present. // It is ok to do so since a repaint event is coming due to the resize that // just happened. // // REMIND: this will need to be updated if we switch to creating // back-buffers of the size of the client area instead of the whole window // (use GetClientRect() instead of GetWindowRect()). if (DWMIsCompositionEnabled()) { RECT r; D3DPRESENT_PARAMETERS params; pSwapChain->GetPresentParameters(¶ms); GetWindowRect(params.hDeviceWindow, &r); int ww = r.right - r.left; int wh = r.bottom - r.top; if (ww != params.BackBufferWidth || wh != params.BackBufferHeight) { J2dTraceLn4(J2D_TRACE_WARNING, "D3DRQ_SwapBuffers: surface/window dimensions mismatch: "\ "win: w=%d h=%d, bb: w=%d h=%d", ww, wh, params.BackBufferWidth, params.BackBufferHeight); return S_OK; } } if (d3dsdo->swapEffect == D3DSWAPEFFECT_COPY) { J2dTraceLn(J2D_TRACE_VERBOSE, " D3DSWAPEFFECT_COPY"); if (x1 < 0) x1 = 0; if (y1 < 0) y1 = 0; if (x2 > d3dsdo->width) x2 = d3dsdo->width; if (y2 > d3dsdo->height) y2 = d3dsdo->height; if (x2 <= x1 || y2 <= y1) { // nothing to present return S_OK; } srcRect.left = x1; srcRect.top = y1; srcRect.right = x2; srcRect.bottom = y2; dstRect = srcRect; pSrcRect = &srcRect; pDstRect = &dstRect; // only offset in windowed mode if (pCtx!= NULL && pCtx->GetPresentationParams()->Windowed) { OffsetRect(pDstRect, d3dsdo->xoff, d3dsdo->yoff); } else { // some boards (Nvidia) have problems with copy strategy and // non-null src/dest rectangles in fs mode; unfortunately this // means that we'll paint over fs window decorations pSrcRect = NULL; pDstRect = NULL; } } else { if (d3dsdo->swapEffect == D3DSWAPEFFECT_FLIP) { J2dTraceLn(J2D_TRACE_VERBOSE, " D3DSWAPEFFECT_FLIP"); } else { J2dTraceLn(J2D_TRACE_VERBOSE, " D3DSWAPEFFECT_DISCARD"); } // src and dest rectangles must be NULL for FLIP/DISCARD pSrcRect = NULL; pDstRect = NULL; } res = pSwapChain->Present(pSrcRect, pDstRect, 0, NULL, 0); res = D3DRQ_MarkLostIfNeeded(res, d3dsdo); return res; } HRESULT D3DRQ_MarkLostIfNeeded(HRESULT res, D3DSDOps *d3dops) { if (res == D3DERR_DEVICELOST || res == D3DERR_DEVICENOTRESET) { D3DContext *pCtx; J2dTraceLn(J2D_TRACE_WARNING, "D3DRQ_MarkLostIfNeeded: device lost"); bLostDevices = TRUE; // only mark surfaces belonging to the lost device if (d3dops != NULL && SUCCEEDED(res = D3DPipelineManager::GetInstance()-> GetD3DContext(d3dops->adapter, &pCtx))) { IDirect3DDevice9 *pd3dDevice = pCtx->Get3DDevice(); if (pd3dDevice) { HRESULT res1 = pd3dDevice->TestCooperativeLevel(); if (res1 != D3DERR_DEVICELOST && res1 != D3DERR_DEVICENOTRESET){ // this surface's device is not lost, do not mark it return res; } } } D3DSD_MarkLost(d3dops); } return res; } void D3DRQ_FlushBuffer(void *pParam) { FlushBufferStruct *pFlush = (FlushBufferStruct*)pParam; JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); unsigned char *b, *end; int limit; HRESULT res = S_OK; BOOL bSync = FALSE; b = pFlush->buffer; limit = pFlush->limit; J2dTraceLn1(J2D_TRACE_INFO, "D3DRQ_flushBuffer: limit=%d", limit); end = b + limit; D3DPipelineManager *pMgr = D3DPipelineManager::GetInstance(); if (pMgr == NULL) { J2dRlsTraceLn(J2D_TRACE_WARNING, "D3DRQ_flushBuffer: null manager"); return; } if (bLostDevices) { if (SUCCEEDED(res = pMgr->HandleLostDevices())) { bLostDevices = FALSE; } } while (b < end) { jint opcode = NEXT_INT(b); J2dTraceLn1(J2D_TRACE_VERBOSE, "D3DRQ_flushBuffer: opcode=%d", opcode); switch (opcode) { // draw ops case sun_java2d_pipe_BufferedOpCodes_DRAW_LINE: { jint x1 = NEXT_INT(b); jint y1 = NEXT_INT(b); jint x2 = NEXT_INT(b); jint y2 = NEXT_INT(b); CONTINUE_IF_NULL(d3dc); res = D3DRenderer_DrawLine(d3dc, x1, y1, x2, y2); } break; case sun_java2d_pipe_BufferedOpCodes_DRAW_RECT: { jint x = NEXT_INT(b); jint y = NEXT_INT(b); jint w = NEXT_INT(b); jint h = NEXT_INT(b); CONTINUE_IF_NULL(d3dc); res = D3DRenderer_DrawRect(d3dc, x, y, w, h); } break; case sun_java2d_pipe_BufferedOpCodes_DRAW_POLY: { jint nPoints = NEXT_INT(b); jboolean isClosed = NEXT_BOOLEAN(b); jint transX = NEXT_INT(b); jint transY = NEXT_INT(b); jint *xPoints = (jint *)b; jint *yPoints = ((jint *)b) + nPoints; CONTINUE_IF_NULL(d3dc); res = D3DRenderer_DrawPoly(d3dc, nPoints, isClosed, transX, transY, xPoints, yPoints); SKIP_BYTES(b, nPoints * BYTES_PER_POLY_POINT); } break; case sun_java2d_pipe_BufferedOpCodes_DRAW_PIXEL: { jint x = NEXT_INT(b); jint y = NEXT_INT(b); CONTINUE_IF_NULL(d3dc); res = D3DRenderer_DrawLine(d3dc, x, y, x, y); } break; case sun_java2d_pipe_BufferedOpCodes_DRAW_SCANLINES: { jint count = NEXT_INT(b); res = D3DRenderer_DrawScanlines(d3dc, count, (jint *)b); SKIP_BYTES(b, count * BYTES_PER_SCANLINE); } break; case sun_java2d_pipe_BufferedOpCodes_DRAW_PARALLELOGRAM: { jfloat x11 = NEXT_FLOAT(b); jfloat y11 = NEXT_FLOAT(b); jfloat dx21 = NEXT_FLOAT(b); jfloat dy21 = NEXT_FLOAT(b); jfloat dx12 = NEXT_FLOAT(b); jfloat dy12 = NEXT_FLOAT(b); jfloat lwr21 = NEXT_FLOAT(b); jfloat lwr12 = NEXT_FLOAT(b); CONTINUE_IF_NULL(d3dc); res = D3DRenderer_DrawParallelogram(d3dc, x11, y11, dx21, dy21, dx12, dy12, lwr21, lwr12); } break; case sun_java2d_pipe_BufferedOpCodes_DRAW_AAPARALLELOGRAM: { jfloat x11 = NEXT_FLOAT(b); jfloat y11 = NEXT_FLOAT(b); jfloat dx21 = NEXT_FLOAT(b); jfloat dy21 = NEXT_FLOAT(b); jfloat dx12 = NEXT_FLOAT(b); jfloat dy12 = NEXT_FLOAT(b); jfloat lwr21 = NEXT_FLOAT(b); jfloat lwr12 = NEXT_FLOAT(b); CONTINUE_IF_NULL(d3dc); res = D3DRenderer_DrawAAParallelogram(d3dc, x11, y11, dx21, dy21, dx12, dy12, lwr21, lwr12); } break; // fill ops case sun_java2d_pipe_BufferedOpCodes_FILL_RECT: { jint x = NEXT_INT(b); jint y = NEXT_INT(b); jint w = NEXT_INT(b); jint h = NEXT_INT(b); CONTINUE_IF_NULL(d3dc); res = D3DRenderer_FillRect(d3dc, x, y, w, h); } break; case sun_java2d_pipe_BufferedOpCodes_FILL_PARALLELOGRAM: { jfloat x11 = NEXT_FLOAT(b); jfloat y11 = NEXT_FLOAT(b); jfloat dx21 = NEXT_FLOAT(b); jfloat dy21 = NEXT_FLOAT(b); jfloat dx12 = NEXT_FLOAT(b); jfloat dy12 = NEXT_FLOAT(b); CONTINUE_IF_NULL(d3dc); res = D3DRenderer_FillParallelogram(d3dc, x11, y11, dx21, dy21, dx12, dy12); } break; case sun_java2d_pipe_BufferedOpCodes_FILL_AAPARALLELOGRAM: { jfloat x11 = NEXT_FLOAT(b); jfloat y11 = NEXT_FLOAT(b); jfloat dx21 = NEXT_FLOAT(b); jfloat dy21 = NEXT_FLOAT(b); jfloat dx12 = NEXT_FLOAT(b); jfloat dy12 = NEXT_FLOAT(b); CONTINUE_IF_NULL(d3dc); res = D3DRenderer_FillAAParallelogram(d3dc, x11, y11, dx21, dy21, dx12, dy12); } break; case sun_java2d_pipe_BufferedOpCodes_FILL_SPANS: { jint count = NEXT_INT(b); res = D3DRenderer_FillSpans(d3dc, count, (jint *)b); SKIP_BYTES(b, count * BYTES_PER_SPAN); } break; // text-related ops case sun_java2d_pipe_BufferedOpCodes_DRAW_GLYPH_LIST: { jint numGlyphs = NEXT_INT(b); jint packedParams = NEXT_INT(b); jfloat glyphListOrigX = NEXT_FLOAT(b); jfloat glyphListOrigY = NEXT_FLOAT(b); jboolean usePositions = EXTRACT_BOOLEAN(packedParams, OFFSET_POSITIONS); jboolean subPixPos = EXTRACT_BOOLEAN(packedParams, OFFSET_SUBPIXPOS); jboolean rgbOrder = EXTRACT_BOOLEAN(packedParams, OFFSET_RGBORDER); jint lcdContrast = EXTRACT_BYTE(packedParams, OFFSET_CONTRAST); unsigned char *images = b; unsigned char *positions; jint bytesPerGlyph; if (usePositions) { positions = (b + numGlyphs * BYTES_PER_GLYPH_IMAGE); bytesPerGlyph = BYTES_PER_POSITIONED_GLYPH; } else { positions = NULL; bytesPerGlyph = BYTES_PER_GLYPH_IMAGE; } res = D3DTR_DrawGlyphList(d3dc, dstOps, numGlyphs, usePositions, subPixPos, rgbOrder, lcdContrast, glyphListOrigX, glyphListOrigY, images, positions); SKIP_BYTES(b, numGlyphs * bytesPerGlyph); } break; // copy-related ops case sun_java2d_pipe_BufferedOpCodes_COPY_AREA: { jint x = NEXT_INT(b); jint y = NEXT_INT(b); jint w = NEXT_INT(b); jint h = NEXT_INT(b); jint dx = NEXT_INT(b); jint dy = NEXT_INT(b); res = D3DBlitLoops_CopyArea(env, d3dc, dstOps, x, y, w, h, dx, dy); } break; case sun_java2d_pipe_BufferedOpCodes_BLIT: { jint packedParams = NEXT_INT(b); jint sx1 = NEXT_INT(b); jint sy1 = NEXT_INT(b); jint sx2 = NEXT_INT(b); jint sy2 = NEXT_INT(b); jdouble dx1 = NEXT_DOUBLE(b); jdouble dy1 = NEXT_DOUBLE(b); jdouble dx2 = NEXT_DOUBLE(b); jdouble dy2 = NEXT_DOUBLE(b); jlong pSrc = NEXT_LONG(b); jlong pDst = NEXT_LONG(b); jint hint = EXTRACT_BYTE(packedParams, OFFSET_HINT); jboolean texture = EXTRACT_BOOLEAN(packedParams, OFFSET_TEXTURE); jboolean rtt = EXTRACT_BOOLEAN(packedParams, OFFSET_RTT); jboolean xform = EXTRACT_BOOLEAN(packedParams, OFFSET_XFORM); jboolean isoblit = EXTRACT_BOOLEAN(packedParams, OFFSET_ISOBLIT); if (isoblit) { res = D3DBlitLoops_IsoBlit(env, d3dc, pSrc, pDst, xform, hint, texture, rtt, sx1, sy1, sx2, sy2, dx1, dy1, dx2, dy2); D3DRQ_MarkLostIfNeeded(res, (D3DSDOps*)pSrc); } else { jint srctype = EXTRACT_BYTE(packedParams, OFFSET_SRCTYPE); res = D3DBlitLoops_Blit(env, d3dc, pSrc, pDst, xform, hint, srctype, texture, sx1, sy1, sx2, sy2, dx1, dy1, dx2, dy2); } } break; case sun_java2d_pipe_BufferedOpCodes_SURFACE_TO_SW_BLIT: { jint sx = NEXT_INT(b); jint sy = NEXT_INT(b); jint dx = NEXT_INT(b); jint dy = NEXT_INT(b); jint w = NEXT_INT(b); jint h = NEXT_INT(b); jint dsttype = NEXT_INT(b); jlong pSrc = NEXT_LONG(b); jlong pDst = NEXT_LONG(b); res = D3DBlitLoops_SurfaceToSwBlit(env, d3dc, pSrc, pDst, dsttype, sx, sy, dx, dy, w, h); D3DRQ_MarkLostIfNeeded(res, (D3DSDOps*)pSrc); } break; case sun_java2d_pipe_BufferedOpCodes_MASK_FILL: { jint x = NEXT_INT(b); jint y = NEXT_INT(b); jint w = NEXT_INT(b); jint h = NEXT_INT(b); jint maskoff = NEXT_INT(b); jint maskscan = NEXT_INT(b); jint masklen = NEXT_INT(b); unsigned char *pMask = (masklen > 0) ? b : NULL; res = D3DMaskFill_MaskFill(d3dc, x, y, w, h, maskoff, maskscan, masklen, pMask); SKIP_BYTES(b, masklen); } break; case sun_java2d_pipe_BufferedOpCodes_MASK_BLIT: { jint dstx = NEXT_INT(b); jint dsty = NEXT_INT(b); jint width = NEXT_INT(b); jint height = NEXT_INT(b); jint masklen = width * height * sizeof(jint); res = D3DMaskBlit_MaskBlit(env, d3dc, dstx, dsty, width, height, b); SKIP_BYTES(b, masklen); } break; // state-related ops case sun_java2d_pipe_BufferedOpCodes_SET_RECT_CLIP: { jint x1 = NEXT_INT(b); jint y1 = NEXT_INT(b); jint x2 = NEXT_INT(b); jint y2 = NEXT_INT(b); CONTINUE_IF_NULL(d3dc); res = d3dc->SetRectClip(x1, y1, x2, y2); } break; case sun_java2d_pipe_BufferedOpCodes_BEGIN_SHAPE_CLIP: { CONTINUE_IF_NULL(d3dc); res = d3dc->BeginShapeClip(); } break; case sun_java2d_pipe_BufferedOpCodes_SET_SHAPE_CLIP_SPANS: { jint count = NEXT_INT(b); res = D3DRenderer_FillSpans(d3dc, count, (jint *)b); SKIP_BYTES(b, count * BYTES_PER_SPAN); } break; case sun_java2d_pipe_BufferedOpCodes_END_SHAPE_CLIP: { CONTINUE_IF_NULL(d3dc); res = d3dc->EndShapeClip(); } break; case sun_java2d_pipe_BufferedOpCodes_RESET_CLIP: { CONTINUE_IF_NULL(d3dc); res = d3dc->ResetClip(); } break; case sun_java2d_pipe_BufferedOpCodes_SET_ALPHA_COMPOSITE: { jint rule = NEXT_INT(b); jfloat extraAlpha = NEXT_FLOAT(b); jint flags = NEXT_INT(b); CONTINUE_IF_NULL(d3dc); res = d3dc->SetAlphaComposite(rule, extraAlpha, flags); } break; case sun_java2d_pipe_BufferedOpCodes_SET_XOR_COMPOSITE: { jint xorPixel = NEXT_INT(b); // res = d3dc->SetXorComposite(d3dc, xorPixel); } break; case sun_java2d_pipe_BufferedOpCodes_RESET_COMPOSITE: { CONTINUE_IF_NULL(d3dc); res = d3dc->ResetComposite(); } break; case sun_java2d_pipe_BufferedOpCodes_SET_TRANSFORM: { jdouble m00 = NEXT_DOUBLE(b); jdouble m10 = NEXT_DOUBLE(b); jdouble m01 = NEXT_DOUBLE(b); jdouble m11 = NEXT_DOUBLE(b); jdouble m02 = NEXT_DOUBLE(b); jdouble m12 = NEXT_DOUBLE(b); res = d3dc->SetTransform(m00, m10, m01, m11, m02, m12); } break; case sun_java2d_pipe_BufferedOpCodes_RESET_TRANSFORM: { CONTINUE_IF_NULL(d3dc); res = d3dc->ResetTransform(); } break; // context-related ops case sun_java2d_pipe_BufferedOpCodes_SET_SURFACES: { jlong pSrc = NEXT_LONG(b); jlong pDst = NEXT_LONG(b); D3DContext *oldd3dc = NULL; if (d3dc != NULL) { oldd3dc = d3dc; d3dc = NULL; oldd3dc->UpdateState(STATE_CHANGE); } dstOps = (D3DSDOps *)jlong_to_ptr(pDst); res = pMgr->GetD3DContext(dstOps->adapter, &d3dc); if (FAILED(res)) { J2dRlsTraceLn(J2D_TRACE_ERROR, "D3DRQ_FlushBuffer: failed to get context"); D3DRQ_ResetCurrentContextAndDestination(); break; } // REMIND: we may also want to do EndScene on each // render target change so that the GPU can go work on // whatever is already in the queue if (oldd3dc != d3dc && oldd3dc != NULL) { res = oldd3dc->EndScene(); } CONTINUE_IF_NULL(dstOps->pResource); res = d3dc->SetRenderTarget(dstOps->pResource->GetSurface()); } break; case sun_java2d_pipe_BufferedOpCodes_SET_SCRATCH_SURFACE: { jint screen = NEXT_INT(b); jint adapter = pMgr->GetAdapterOrdinalForScreen(screen); D3DContext *oldd3dc = NULL; if (d3dc != NULL) { oldd3dc = d3dc; d3dc = NULL; } res = pMgr->GetD3DContext(adapter, &d3dc); if (FAILED(res)) { J2dRlsTraceLn(J2D_TRACE_ERROR, "D3DRQ_FlushBuffer: failed to get context"); D3DRQ_ResetCurrentContextAndDestination(); } else if (oldd3dc != d3dc && oldd3dc != NULL) { res = oldd3dc->EndScene(); } } break; case sun_java2d_pipe_BufferedOpCodes_FLUSH_SURFACE: { jlong pData = NEXT_LONG(b); D3DSDOps *d3dsdo = (D3DSDOps *)jlong_to_ptr(pData); D3DSD_Flush(d3dsdo); if (dstOps == d3dsdo) { dstOps = NULL; } } break; case sun_java2d_pipe_BufferedOpCodes_DISPOSE_SURFACE: { jlong pData = NEXT_LONG(b); D3DSDOps *d3dsdo = (D3DSDOps *)jlong_to_ptr(pData); D3DSD_Flush(d3dsdo); if (dstOps == d3dsdo) { dstOps = NULL; } } break; case sun_java2d_pipe_BufferedOpCodes_DISPOSE_CONFIG: { jlong pConfigInfo = NEXT_LONG(b); CONTINUE_IF_NULL(d3dc); // REMIND: does this need to be implemented for D3D? } break; case sun_java2d_pipe_BufferedOpCodes_INVALIDATE_CONTEXT: { // flush just in case there are any pending operations in // the hardware pipe if (d3dc != NULL) { res = d3dc->EndScene(); } // invalidate the references to the current context and // destination surface that are maintained at the native level D3DRQ_ResetCurrentContextAndDestination(); } break; case sun_java2d_pipe_BufferedOpCodes_SYNC: { bSync = TRUE; } break; case sun_java2d_pipe_BufferedOpCodes_RESTORE_DEVICES: { J2dTraceLn(J2D_TRACE_INFO, "D3DRQ_FlushBuffer: RESTORE_DEVICES"); if (SUCCEEDED(res = pMgr->HandleLostDevices())) { bLostDevices = FALSE; } else { bLostDevices = TRUE; } } break; case sun_java2d_pipe_BufferedOpCodes_SAVE_STATE: { CONTINUE_IF_NULL(d3dc); res = d3dc->SaveState(); } break; case sun_java2d_pipe_BufferedOpCodes_RESTORE_STATE: { CONTINUE_IF_NULL(d3dc); res = d3dc->RestoreState(); } break; // multibuffering ops case sun_java2d_pipe_BufferedOpCodes_SWAP_BUFFERS: { jlong sdo = NEXT_LONG(b); jint x1 = NEXT_INT(b); jint y1 = NEXT_INT(b); jint x2 = NEXT_INT(b); jint y2 = NEXT_INT(b); res = D3DRQ_SwapBuffers(pMgr, (D3DSDOps *)jlong_to_ptr(sdo), x1, y1, x2, y2); } break; // special no-op (mainly used for achieving 8-byte alignment) case sun_java2d_pipe_BufferedOpCodes_NOOP: break; // paint-related ops case sun_java2d_pipe_BufferedOpCodes_RESET_PAINT: { res = D3DPaints_ResetPaint(d3dc); } break; case sun_java2d_pipe_BufferedOpCodes_SET_COLOR: { jint pixel = NEXT_INT(b); res = D3DPaints_SetColor(d3dc, pixel); } break; case sun_java2d_pipe_BufferedOpCodes_SET_GRADIENT_PAINT: { jboolean useMask= NEXT_BOOLEAN(b); jboolean cyclic = NEXT_BOOLEAN(b); jdouble p0 = NEXT_DOUBLE(b); jdouble p1 = NEXT_DOUBLE(b); jdouble p3 = NEXT_DOUBLE(b); jint pixel1 = NEXT_INT(b); jint pixel2 = NEXT_INT(b); res = D3DPaints_SetGradientPaint(d3dc, useMask, cyclic, p0, p1, p3, pixel1, pixel2); } break; case sun_java2d_pipe_BufferedOpCodes_SET_LINEAR_GRADIENT_PAINT: { jboolean useMask = NEXT_BOOLEAN(b); jboolean linear = NEXT_BOOLEAN(b); jint cycleMethod = NEXT_INT(b); jint numStops = NEXT_INT(b); jfloat p0 = NEXT_FLOAT(b); jfloat p1 = NEXT_FLOAT(b); jfloat p3 = NEXT_FLOAT(b); void *fractions, *pixels; fractions = b; SKIP_BYTES(b, numStops * sizeof(jfloat)); pixels = b; SKIP_BYTES(b, numStops * sizeof(jint)); res = D3DPaints_SetLinearGradientPaint(d3dc, dstOps, useMask, linear, cycleMethod, numStops, p0, p1, p3, fractions, pixels); } break; case sun_java2d_pipe_BufferedOpCodes_SET_RADIAL_GRADIENT_PAINT: { jboolean useMask = NEXT_BOOLEAN(b); jboolean linear = NEXT_BOOLEAN(b); jint numStops = NEXT_INT(b); jint cycleMethod = NEXT_INT(b); jfloat m00 = NEXT_FLOAT(b); jfloat m01 = NEXT_FLOAT(b); jfloat m02 = NEXT_FLOAT(b); jfloat m10 = NEXT_FLOAT(b); jfloat m11 = NEXT_FLOAT(b); jfloat m12 = NEXT_FLOAT(b); jfloat focusX = NEXT_FLOAT(b); void *fractions, *pixels; fractions = b; SKIP_BYTES(b, numStops * sizeof(jfloat)); pixels = b; SKIP_BYTES(b, numStops * sizeof(jint)); res = D3DPaints_SetRadialGradientPaint(d3dc, dstOps, useMask, linear, cycleMethod, numStops, m00, m01, m02, m10, m11, m12, focusX, fractions, pixels); } break; case sun_java2d_pipe_BufferedOpCodes_SET_TEXTURE_PAINT: { jboolean useMask= NEXT_BOOLEAN(b); jboolean filter = NEXT_BOOLEAN(b); jlong pSrc = NEXT_LONG(b); jdouble xp0 = NEXT_DOUBLE(b); jdouble xp1 = NEXT_DOUBLE(b); jdouble xp3 = NEXT_DOUBLE(b); jdouble yp0 = NEXT_DOUBLE(b); jdouble yp1 = NEXT_DOUBLE(b); jdouble yp3 = NEXT_DOUBLE(b); res = D3DPaints_SetTexturePaint(d3dc, useMask, pSrc, filter, xp0, xp1, xp3, yp0, yp1, yp3); } break; // BufferedImageOp-related ops case sun_java2d_pipe_BufferedOpCodes_ENABLE_CONVOLVE_OP: { jlong pSrc = NEXT_LONG(b); jboolean edgeZero = NEXT_BOOLEAN(b); jint kernelWidth = NEXT_INT(b); jint kernelHeight = NEXT_INT(b); res = D3DBufImgOps_EnableConvolveOp(d3dc, pSrc, edgeZero, kernelWidth, kernelHeight, b); SKIP_BYTES(b, kernelWidth * kernelHeight * sizeof(jfloat)); } break; case sun_java2d_pipe_BufferedOpCodes_DISABLE_CONVOLVE_OP: { res = D3DBufImgOps_DisableConvolveOp(d3dc); } break; case sun_java2d_pipe_BufferedOpCodes_ENABLE_RESCALE_OP: { jlong pSrc = NEXT_LONG(b); // unused jboolean nonPremult = NEXT_BOOLEAN(b); jint numFactors = 4; unsigned char *scaleFactors = b; unsigned char *offsets = (b + numFactors * sizeof(jfloat)); res = D3DBufImgOps_EnableRescaleOp(d3dc, nonPremult, scaleFactors, offsets); SKIP_BYTES(b, numFactors * sizeof(jfloat) * 2); } break; case sun_java2d_pipe_BufferedOpCodes_DISABLE_RESCALE_OP: { D3DBufImgOps_DisableRescaleOp(d3dc); } break; case sun_java2d_pipe_BufferedOpCodes_ENABLE_LOOKUP_OP: { jlong pSrc = NEXT_LONG(b); // unused jboolean nonPremult = NEXT_BOOLEAN(b); jboolean shortData = NEXT_BOOLEAN(b); jint numBands = NEXT_INT(b); jint bandLength = NEXT_INT(b); jint offset = NEXT_INT(b); jint bytesPerElem = shortData ? sizeof(jshort):sizeof(jbyte); void *tableValues = b; res = D3DBufImgOps_EnableLookupOp(d3dc, nonPremult, shortData, numBands, bandLength, offset, tableValues); SKIP_BYTES(b, numBands * bandLength * bytesPerElem); } break; case sun_java2d_pipe_BufferedOpCodes_DISABLE_LOOKUP_OP: { res = D3DBufImgOps_DisableLookupOp(d3dc); } break; default: J2dRlsTraceLn1(J2D_TRACE_ERROR, "D3DRQ_flushBuffer: invalid opcode=%d", opcode); return; } // we may mark the surface lost repeatedly but that won't do much harm res = D3DRQ_MarkLostIfNeeded(res, dstOps); } if (d3dc != NULL) { res = d3dc->EndScene(); // REMIND: EndScene is not really enough to flush the // whole d3d pipeline // REMIND: there may be an issue with BeginScene/EndScene // for each flushQueue, because of the blits, which flush // the queue if (bSync) { res = d3dc->Sync(); } } // REMIND: we need to also handle hard errors here as well, and disable // particular context if needed D3DRQ_MarkLostIfNeeded(res, dstOps); if (!JNU_IsNull(env, pFlush->runnable)) { J2dTraceLn(J2D_TRACE_VERBOSE, " executing runnable"); JNU_CallMethodByName(env, NULL, pFlush->runnable, "run", "()V"); } } /** * Returns a pointer to the "current" context, as set by the last SET_SURFACES * or SET_SCRATCH_SURFACE operation. */ D3DContext * D3DRQ_GetCurrentContext() { return d3dc; } /** * Returns a pointer to the "current" destination surface, as set by the last * SET_SURFACES operation. */ D3DSDOps * D3DRQ_GetCurrentDestination() { return dstOps; } /** * Resets current context and destination surface. */ void D3DRQ_ResetCurrentContextAndDestination() { J2dTraceLn(J2D_TRACE_INFO, "D3DRQ_ResetCurrentContextAndDestination"); d3dc = NULL; dstOps = NULL; } extern "C" { /* * Class: sun_java2d_d3d_D3DRenderQueue * Method: flushBuffer * Signature: (JILjava/lang/Runnable;)V */ JNIEXPORT void JNICALL Java_sun_java2d_d3d_D3DRenderQueue_flushBuffer (JNIEnv *env, jobject d3drq, jlong buf, jint limit, jobject runnable) { FlushBufferStruct bufstr; // just in case we forget to init any new fields ZeroMemory(&bufstr, sizeof(FlushBufferStruct)); bufstr.buffer = (unsigned char *)jlong_to_ptr(buf); if (bufstr.buffer == NULL) { J2dRlsTraceLn(J2D_TRACE_ERROR, "D3DRenderQueue_flushBuffer: cannot get direct buffer address"); return; } bufstr.limit = limit; bufstr.runnable = JNU_IsNull(env, runnable) ? NULL : env->NewGlobalRef(runnable); AwtToolkit::GetInstance().InvokeFunction(D3DRQ_FlushBuffer, &bufstr); if (!JNU_IsNull(env, bufstr.runnable)) { env->DeleteGlobalRef(bufstr.runnable); } } }