/*
* 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 <malloc.h>
#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(&params);
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);
}
}
}