1 /*
   2  * Copyright (c) 2007, 2019, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 #include "D3DPipeline.h"
  27 #include <malloc.h>
  28 #include "sun_java2d_pipe_BufferedOpCodes.h"
  29 
  30 #include "jlong.h"
  31 #include "D3DBlitLoops.h"
  32 #include "D3DBufImgOps.h"
  33 #include "D3DPipelineManager.h"
  34 #include "D3DContext.h"
  35 #include "D3DMaskBlit.h"
  36 #include "D3DMaskFill.h"
  37 #include "D3DPaints.h"
  38 #include "D3DRenderQueue.h"
  39 #include "D3DRenderer.h"
  40 #include "D3DSurfaceData.h"
  41 #include "D3DTextRenderer.h"
  42 #include "Trace.h"
  43 #include "awt_Toolkit.h"
  44 
  45 BOOL DWMIsCompositionEnabled();
  46 
  47 /**
  48  * References to the "current" context and destination surface.
  49  */
  50 static D3DContext *d3dc = NULL;
  51 static D3DSDOps *dstOps = NULL;
  52 static BOOL bLostDevices = FALSE;
  53 
  54 typedef struct {
  55     byte *buffer;
  56     int limit;
  57     jobject runnable;
  58 } FlushBufferStruct;
  59 
  60 HRESULT
  61 D3DRQ_SwapBuffers(D3DPipelineManager *pMgr, D3DSDOps *d3dsdo,
  62                   int x1, int y1, int x2, int y2)
  63 {
  64     HRESULT res;
  65     D3DContext *pCtx;
  66     IDirect3DSwapChain9 *pSwapChain;
  67     RECT srcRect, dstRect, *pSrcRect, *pDstRect;
  68 
  69     J2dTraceLn(J2D_TRACE_INFO, "D3DRQ_SwapBuffers");
  70     J2dTraceLn4(J2D_TRACE_VERBOSE, "  x1=%d y1=%d x2=%d y2=%d",
  71                 x1, y1, x2, y2);
  72 
  73     RETURN_STATUS_IF_NULL(d3dsdo, E_FAIL);
  74     RETURN_STATUS_IF_NULL(d3dsdo->pResource, E_FAIL);
  75     RETURN_STATUS_IF_NULL(pSwapChain=d3dsdo->pResource->GetSwapChain(), E_FAIL);
  76 
  77     pCtx = D3DRQ_GetCurrentContext();
  78     if (pCtx != NULL) {
  79         // flush the current vertex queue here, just in case
  80         res = d3dc->FlushVertexQueue();
  81         D3DRQ_MarkLostIfNeeded(res, dstOps);
  82         pCtx = NULL;
  83     }
  84     // end scene for this destination
  85     res = pMgr->GetD3DContext(d3dsdo->adapter, &pCtx);
  86     RETURN_STATUS_IF_FAILED(res);
  87 
  88     pCtx->EndScene();
  89 
  90     // This is a workaround for what apparently is a DWM bug.
  91     // If the dimensions of the back-buffer don't match the dimensions of
  92     // the window, Present() will flash the whole window with black.
  93     // The workaround is to detect this situation and not do a present.
  94     // It is ok to do so since a repaint event is coming due to the resize that
  95     // just happened.
  96     //
  97     // REMIND: this will need to be updated if we switch to creating
  98     // back-buffers of the size of the client area instead of the whole window
  99     // (use GetClientRect() instead of GetWindowRect()).
 100     if (DWMIsCompositionEnabled()) {
 101         RECT r;
 102         D3DPRESENT_PARAMETERS params;
 103 
 104         pSwapChain->GetPresentParameters(&params);
 105         GetWindowRect(params.hDeviceWindow, &r);
 106         int ww = r.right - r.left;
 107         int wh = r.bottom - r.top;
 108         if (ww != params.BackBufferWidth || wh != params.BackBufferHeight) {
 109             J2dTraceLn4(J2D_TRACE_WARNING,
 110                 "D3DRQ_SwapBuffers: surface/window dimensions mismatch: "\
 111                 "win: w=%d h=%d, bb: w=%d h=%d",
 112                 ww, wh, params.BackBufferWidth, params.BackBufferHeight);
 113 
 114             return S_OK;
 115         }
 116     }
 117 
 118     if (d3dsdo->swapEffect == D3DSWAPEFFECT_COPY) {
 119         J2dTraceLn(J2D_TRACE_VERBOSE, "  D3DSWAPEFFECT_COPY");
 120         if (x1 < 0) x1 = 0;
 121         if (y1 < 0) y1 = 0;
 122         if (x2 > d3dsdo->width)  x2 = d3dsdo->width;
 123         if (y2 > d3dsdo->height) y2 = d3dsdo->height;
 124         if (x2 <= x1 || y2 <= y1) {
 125             // nothing to present
 126             return S_OK;
 127         }
 128         srcRect.left = x1;
 129         srcRect.top = y1;
 130         srcRect.right = x2;
 131         srcRect.bottom = y2;
 132 
 133         dstRect = srcRect;
 134 
 135         pSrcRect = &srcRect;
 136         pDstRect = &dstRect;
 137         // only offset in windowed mode
 138         if (pCtx!= NULL && pCtx->GetPresentationParams()->Windowed) {
 139             OffsetRect(pDstRect, d3dsdo->xoff, d3dsdo->yoff);
 140         } else {
 141             // some boards (Nvidia) have problems with copy strategy and
 142             // non-null src/dest rectangles in fs mode; unfortunately this
 143             // means that we'll paint over fs window decorations
 144             pSrcRect = NULL;
 145             pDstRect = NULL;
 146         }
 147     } else {
 148         if (d3dsdo->swapEffect == D3DSWAPEFFECT_FLIP) {
 149             J2dTraceLn(J2D_TRACE_VERBOSE, "  D3DSWAPEFFECT_FLIP");
 150         } else {
 151             J2dTraceLn(J2D_TRACE_VERBOSE, "  D3DSWAPEFFECT_DISCARD");
 152         }
 153         // src and dest rectangles must be NULL for FLIP/DISCARD
 154         pSrcRect = NULL;
 155         pDstRect = NULL;
 156     }
 157 
 158     res = pSwapChain->Present(pSrcRect, pDstRect, 0, NULL, 0);
 159     res = D3DRQ_MarkLostIfNeeded(res, d3dsdo);
 160 
 161     return res;
 162 }
 163 
 164 HRESULT
 165 D3DRQ_MarkLostIfNeeded(HRESULT res, D3DSDOps *d3dops)
 166 {
 167     if (res == D3DERR_DEVICELOST || res == D3DERR_DEVICENOTRESET) {
 168         D3DContext *pCtx;
 169 
 170         J2dTraceLn(J2D_TRACE_WARNING, "D3DRQ_MarkLostIfNeeded: device lost");
 171         bLostDevices = TRUE;
 172 
 173         // only mark surfaces belonging to the lost device
 174         if (d3dops != NULL &&
 175             SUCCEEDED(res = D3DPipelineManager::GetInstance()->
 176                 GetD3DContext(d3dops->adapter, &pCtx)))
 177         {
 178             IDirect3DDevice9 *pd3dDevice = pCtx->Get3DDevice();
 179             if (pd3dDevice) {
 180                 HRESULT res1 = pd3dDevice->TestCooperativeLevel();
 181                 if (res1 != D3DERR_DEVICELOST && res1 != D3DERR_DEVICENOTRESET){
 182                     // this surface's device is not lost, do not mark it
 183                     return res;
 184                 }
 185             }
 186         }
 187         D3DSD_MarkLost(d3dops);
 188     }
 189     return res;
 190 }
 191 
 192 void D3DRQ_FlushBuffer(void *pParam)
 193 {
 194     FlushBufferStruct *pFlush = (FlushBufferStruct*)pParam;
 195     JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
 196     unsigned char *b, *end;
 197     int limit;
 198     HRESULT res = S_OK;
 199     BOOL bSync = FALSE;
 200 
 201     b = pFlush->buffer;
 202     limit = pFlush->limit;
 203     J2dTraceLn1(J2D_TRACE_INFO, "D3DRQ_flushBuffer: limit=%d", limit);
 204 
 205     end = b + limit;
 206 
 207     D3DPipelineManager *pMgr = D3DPipelineManager::GetInstance();
 208     if (pMgr == NULL) {
 209         J2dRlsTraceLn(J2D_TRACE_WARNING, "D3DRQ_flushBuffer: null manager");
 210         return;
 211     }
 212 
 213     if (bLostDevices) {
 214         if (SUCCEEDED(res = pMgr->HandleLostDevices())) {
 215             bLostDevices = FALSE;
 216         }
 217     }
 218 
 219     while (b < end) {
 220         jint opcode = NEXT_INT(b);
 221 
 222         J2dTraceLn1(J2D_TRACE_VERBOSE, "D3DRQ_flushBuffer: opcode=%d", opcode);
 223 
 224         switch (opcode) {
 225 
 226         // draw ops
 227         case sun_java2d_pipe_BufferedOpCodes_DRAW_LINE:
 228             {
 229                 jint x1 = NEXT_INT(b);
 230                 jint y1 = NEXT_INT(b);
 231                 jint x2 = NEXT_INT(b);
 232                 jint y2 = NEXT_INT(b);
 233 
 234                 CONTINUE_IF_NULL(d3dc);
 235                 res = D3DRenderer_DrawLine(d3dc, x1, y1, x2, y2);
 236             }
 237             break;
 238         case sun_java2d_pipe_BufferedOpCodes_DRAW_RECT:
 239             {
 240                 jint x = NEXT_INT(b);
 241                 jint y = NEXT_INT(b);
 242                 jint w = NEXT_INT(b);
 243                 jint h = NEXT_INT(b);
 244                 CONTINUE_IF_NULL(d3dc);
 245                 res = D3DRenderer_DrawRect(d3dc, x, y, w, h);
 246             }
 247             break;
 248         case sun_java2d_pipe_BufferedOpCodes_DRAW_POLY:
 249             {
 250                 jint nPoints      = NEXT_INT(b);
 251                 jboolean isClosed = NEXT_BOOLEAN(b);
 252                 jint transX       = NEXT_INT(b);
 253                 jint transY       = NEXT_INT(b);
 254                 jint *xPoints = (jint *)b;
 255                 jint *yPoints = ((jint *)b) + nPoints;
 256                 CONTINUE_IF_NULL(d3dc);
 257                 res = D3DRenderer_DrawPoly(d3dc, nPoints, isClosed,
 258                                            transX, transY,
 259                                      xPoints, yPoints);
 260                 SKIP_BYTES(b, nPoints * BYTES_PER_POLY_POINT);
 261             }
 262             break;
 263         case sun_java2d_pipe_BufferedOpCodes_DRAW_PIXEL:
 264             {
 265                 jint x = NEXT_INT(b);
 266                 jint y = NEXT_INT(b);
 267 
 268                 CONTINUE_IF_NULL(d3dc);
 269                 res = D3DRenderer_DrawLine(d3dc, x, y, x, y);
 270             }
 271             break;
 272         case sun_java2d_pipe_BufferedOpCodes_DRAW_SCANLINES:
 273             {
 274                 jint count = NEXT_INT(b);
 275                 res = D3DRenderer_DrawScanlines(d3dc, count, (jint *)b);
 276                 SKIP_BYTES(b, count * BYTES_PER_SCANLINE);
 277             }
 278             break;
 279         case sun_java2d_pipe_BufferedOpCodes_DRAW_PARALLELOGRAM:
 280             {
 281                 jfloat x11 = NEXT_FLOAT(b);
 282                 jfloat y11 = NEXT_FLOAT(b);
 283                 jfloat dx21 = NEXT_FLOAT(b);
 284                 jfloat dy21 = NEXT_FLOAT(b);
 285                 jfloat dx12 = NEXT_FLOAT(b);
 286                 jfloat dy12 = NEXT_FLOAT(b);
 287                 jfloat lwr21 = NEXT_FLOAT(b);
 288                 jfloat lwr12 = NEXT_FLOAT(b);
 289 
 290                 CONTINUE_IF_NULL(d3dc);
 291                 res = D3DRenderer_DrawParallelogram(d3dc,
 292                                                     x11, y11,
 293                                                     dx21, dy21,
 294                                                     dx12, dy12,
 295                                                     lwr21, lwr12);
 296             }
 297             break;
 298         case sun_java2d_pipe_BufferedOpCodes_DRAW_AAPARALLELOGRAM:
 299             {
 300                 jfloat x11 = NEXT_FLOAT(b);
 301                 jfloat y11 = NEXT_FLOAT(b);
 302                 jfloat dx21 = NEXT_FLOAT(b);
 303                 jfloat dy21 = NEXT_FLOAT(b);
 304                 jfloat dx12 = NEXT_FLOAT(b);
 305                 jfloat dy12 = NEXT_FLOAT(b);
 306                 jfloat lwr21 = NEXT_FLOAT(b);
 307                 jfloat lwr12 = NEXT_FLOAT(b);
 308 
 309                 CONTINUE_IF_NULL(d3dc);
 310                 res = D3DRenderer_DrawAAParallelogram(d3dc,
 311                                                       x11, y11,
 312                                                       dx21, dy21,
 313                                                       dx12, dy12,
 314                                                       lwr21, lwr12);
 315             }
 316             break;
 317 
 318         // fill ops
 319         case sun_java2d_pipe_BufferedOpCodes_FILL_RECT:
 320             {
 321                 jint x = NEXT_INT(b);
 322                 jint y = NEXT_INT(b);
 323                 jint w = NEXT_INT(b);
 324                 jint h = NEXT_INT(b);
 325 
 326                 CONTINUE_IF_NULL(d3dc);
 327                 res = D3DRenderer_FillRect(d3dc, x, y, w, h);
 328             }
 329             break;
 330         case sun_java2d_pipe_BufferedOpCodes_FILL_PARALLELOGRAM:
 331             {
 332                 jfloat x11 = NEXT_FLOAT(b);
 333                 jfloat y11 = NEXT_FLOAT(b);
 334                 jfloat dx21 = NEXT_FLOAT(b);
 335                 jfloat dy21 = NEXT_FLOAT(b);
 336                 jfloat dx12 = NEXT_FLOAT(b);
 337                 jfloat dy12 = NEXT_FLOAT(b);
 338 
 339                 CONTINUE_IF_NULL(d3dc);
 340                 res = D3DRenderer_FillParallelogram(d3dc,
 341                                                     x11, y11,
 342                                                     dx21, dy21,
 343                                                     dx12, dy12);
 344             }
 345             break;
 346         case sun_java2d_pipe_BufferedOpCodes_FILL_AAPARALLELOGRAM:
 347             {
 348                 jfloat x11 = NEXT_FLOAT(b);
 349                 jfloat y11 = NEXT_FLOAT(b);
 350                 jfloat dx21 = NEXT_FLOAT(b);
 351                 jfloat dy21 = NEXT_FLOAT(b);
 352                 jfloat dx12 = NEXT_FLOAT(b);
 353                 jfloat dy12 = NEXT_FLOAT(b);
 354 
 355                 CONTINUE_IF_NULL(d3dc);
 356                 res = D3DRenderer_FillAAParallelogram(d3dc,
 357                                                       x11, y11,
 358                                                       dx21, dy21,
 359                                                       dx12, dy12);
 360             }
 361             break;
 362         case sun_java2d_pipe_BufferedOpCodes_FILL_SPANS:
 363             {
 364                 jint count = NEXT_INT(b);
 365                 res = D3DRenderer_FillSpans(d3dc, count, (jint *)b);
 366                 SKIP_BYTES(b, count * BYTES_PER_SPAN);
 367             }
 368             break;
 369 
 370         // text-related ops
 371         case sun_java2d_pipe_BufferedOpCodes_DRAW_GLYPH_LIST:
 372             {
 373                 jint numGlyphs        = NEXT_INT(b);
 374                 jint packedParams     = NEXT_INT(b);
 375                 jfloat glyphListOrigX = NEXT_FLOAT(b);
 376                 jfloat glyphListOrigY = NEXT_FLOAT(b);
 377                 jboolean usePositions = EXTRACT_BOOLEAN(packedParams,
 378                                                         OFFSET_POSITIONS);
 379                 jboolean subPixPos    = EXTRACT_BOOLEAN(packedParams,
 380                                                         OFFSET_SUBPIXPOS);
 381                 jboolean rgbOrder     = EXTRACT_BOOLEAN(packedParams,
 382                                                         OFFSET_RGBORDER);
 383                 jint lcdContrast      = EXTRACT_BYTE(packedParams,
 384                                                      OFFSET_CONTRAST);
 385                 unsigned char *images = b;
 386                 unsigned char *positions;
 387                 jint bytesPerGlyph;
 388                 if (usePositions) {
 389                     positions = (b + numGlyphs * BYTES_PER_GLYPH_IMAGE);
 390                     bytesPerGlyph = BYTES_PER_POSITIONED_GLYPH;
 391                 } else {
 392                     positions = NULL;
 393                     bytesPerGlyph = BYTES_PER_GLYPH_IMAGE;
 394                 }
 395                 res = D3DTR_DrawGlyphList(d3dc, dstOps,
 396                                           numGlyphs, usePositions,
 397                                           subPixPos, rgbOrder, lcdContrast,
 398                                           glyphListOrigX, glyphListOrigY,
 399                                           images, positions);
 400                 SKIP_BYTES(b, numGlyphs * bytesPerGlyph);
 401             }
 402             break;
 403 
 404         // copy-related ops
 405         case sun_java2d_pipe_BufferedOpCodes_COPY_AREA:
 406             {
 407                 jint x  = NEXT_INT(b);
 408                 jint y  = NEXT_INT(b);
 409                 jint w  = NEXT_INT(b);
 410                 jint h  = NEXT_INT(b);
 411                 jint dx = NEXT_INT(b);
 412                 jint dy = NEXT_INT(b);
 413                 res = D3DBlitLoops_CopyArea(env, d3dc, dstOps,
 414                                             x, y, w, h, dx, dy);
 415             }
 416             break;
 417         case sun_java2d_pipe_BufferedOpCodes_BLIT:
 418             {
 419                 jint packedParams = NEXT_INT(b);
 420                 jint sx1          = NEXT_INT(b);
 421                 jint sy1          = NEXT_INT(b);
 422                 jint sx2          = NEXT_INT(b);
 423                 jint sy2          = NEXT_INT(b);
 424                 jdouble dx1       = NEXT_DOUBLE(b);
 425                 jdouble dy1       = NEXT_DOUBLE(b);
 426                 jdouble dx2       = NEXT_DOUBLE(b);
 427                 jdouble dy2       = NEXT_DOUBLE(b);
 428                 jlong pSrc        = NEXT_LONG(b);
 429                 jlong pDst        = NEXT_LONG(b);
 430                 jint hint         = EXTRACT_BYTE(packedParams, OFFSET_HINT);
 431                 jboolean texture  = EXTRACT_BOOLEAN(packedParams,
 432                                                     OFFSET_TEXTURE);
 433                 jboolean rtt      = EXTRACT_BOOLEAN(packedParams,
 434                                                     OFFSET_RTT);
 435                 jboolean xform    = EXTRACT_BOOLEAN(packedParams,
 436                                                     OFFSET_XFORM);
 437                 jboolean isoblit  = EXTRACT_BOOLEAN(packedParams,
 438                                                     OFFSET_ISOBLIT);
 439                 if (isoblit) {
 440                     res = D3DBlitLoops_IsoBlit(env, d3dc, pSrc, pDst,
 441                                                xform, hint, texture, rtt,
 442                                                sx1, sy1, sx2, sy2,
 443                                                dx1, dy1, dx2, dy2);
 444                     D3DRQ_MarkLostIfNeeded(res, (D3DSDOps*)pSrc);
 445                 } else {
 446                     jint srctype = EXTRACT_BYTE(packedParams, OFFSET_SRCTYPE);
 447                     res = D3DBlitLoops_Blit(env, d3dc, pSrc, pDst,
 448                                             xform, hint, srctype, texture,
 449                                             sx1, sy1, sx2, sy2,
 450                                             dx1, dy1, dx2, dy2);
 451                 }
 452             }
 453             break;
 454         case sun_java2d_pipe_BufferedOpCodes_SURFACE_TO_SW_BLIT:
 455             {
 456                 jint sx      = NEXT_INT(b);
 457                 jint sy      = NEXT_INT(b);
 458                 jint dx      = NEXT_INT(b);
 459                 jint dy      = NEXT_INT(b);
 460                 jint w       = NEXT_INT(b);
 461                 jint h       = NEXT_INT(b);
 462                 jint dsttype = NEXT_INT(b);
 463                 jlong pSrc   = NEXT_LONG(b);
 464                 jlong pDst   = NEXT_LONG(b);
 465                 res = D3DBlitLoops_SurfaceToSwBlit(env, d3dc,
 466                                                    pSrc, pDst, dsttype,
 467                                                    sx, sy, dx, dy, w, h);
 468                 D3DRQ_MarkLostIfNeeded(res, (D3DSDOps*)pSrc);
 469             }
 470             break;
 471         case sun_java2d_pipe_BufferedOpCodes_MASK_FILL:
 472             {
 473                 jint x        = NEXT_INT(b);
 474                 jint y        = NEXT_INT(b);
 475                 jint w        = NEXT_INT(b);
 476                 jint h        = NEXT_INT(b);
 477                 jint maskoff  = NEXT_INT(b);
 478                 jint maskscan = NEXT_INT(b);
 479                 jint masklen  = NEXT_INT(b);
 480                 unsigned char *pMask = (masklen > 0) ? b : NULL;
 481                 res = D3DMaskFill_MaskFill(d3dc, x, y, w, h,
 482                                            maskoff, maskscan, masklen, pMask);
 483                 SKIP_BYTES(b, masklen);
 484             }
 485             break;
 486         case sun_java2d_pipe_BufferedOpCodes_MASK_BLIT:
 487             {
 488                 jint dstx     = NEXT_INT(b);
 489                 jint dsty     = NEXT_INT(b);
 490                 jint width    = NEXT_INT(b);
 491                 jint height   = NEXT_INT(b);
 492                 jint masklen  = width * height * sizeof(jint);
 493                 res = D3DMaskBlit_MaskBlit(env, d3dc,
 494                                            dstx, dsty, width, height, b);
 495                 SKIP_BYTES(b, masklen);
 496             }
 497             break;
 498 
 499         // state-related ops
 500         case sun_java2d_pipe_BufferedOpCodes_SET_RECT_CLIP:
 501             {
 502                 jint x1 = NEXT_INT(b);
 503                 jint y1 = NEXT_INT(b);
 504                 jint x2 = NEXT_INT(b);
 505                 jint y2 = NEXT_INT(b);
 506                 CONTINUE_IF_NULL(d3dc);
 507                 res = d3dc->SetRectClip(x1, y1, x2, y2);
 508             }
 509             break;
 510         case sun_java2d_pipe_BufferedOpCodes_BEGIN_SHAPE_CLIP:
 511             {
 512                 CONTINUE_IF_NULL(d3dc);
 513                 res = d3dc->BeginShapeClip();
 514             }
 515             break;
 516         case sun_java2d_pipe_BufferedOpCodes_SET_SHAPE_CLIP_SPANS:
 517             {
 518                 jint count = NEXT_INT(b);
 519                 res = D3DRenderer_FillSpans(d3dc, count, (jint *)b);
 520                 SKIP_BYTES(b, count * BYTES_PER_SPAN);
 521             }
 522             break;
 523         case sun_java2d_pipe_BufferedOpCodes_END_SHAPE_CLIP:
 524             {
 525                 CONTINUE_IF_NULL(d3dc);
 526                 res = d3dc->EndShapeClip();
 527             }
 528             break;
 529         case sun_java2d_pipe_BufferedOpCodes_RESET_CLIP:
 530             {
 531                 CONTINUE_IF_NULL(d3dc);
 532                 res = d3dc->ResetClip();
 533             }
 534             break;
 535         case sun_java2d_pipe_BufferedOpCodes_SET_ALPHA_COMPOSITE:
 536             {
 537                 jint rule         = NEXT_INT(b);
 538                 jfloat extraAlpha = NEXT_FLOAT(b);
 539                 jint flags        = NEXT_INT(b);
 540                 CONTINUE_IF_NULL(d3dc);
 541                 res = d3dc->SetAlphaComposite(rule, extraAlpha, flags);
 542             }
 543             break;
 544         case sun_java2d_pipe_BufferedOpCodes_SET_XOR_COMPOSITE:
 545             {
 546                 jint xorPixel = NEXT_INT(b);
 547 //                res = d3dc->SetXorComposite(d3dc, xorPixel);
 548             }
 549             break;
 550         case sun_java2d_pipe_BufferedOpCodes_RESET_COMPOSITE:
 551             {
 552                 CONTINUE_IF_NULL(d3dc);
 553                 res = d3dc->ResetComposite();
 554             }
 555             break;
 556         case sun_java2d_pipe_BufferedOpCodes_SET_TRANSFORM:
 557             {
 558                 jdouble m00 = NEXT_DOUBLE(b);
 559                 jdouble m10 = NEXT_DOUBLE(b);
 560                 jdouble m01 = NEXT_DOUBLE(b);
 561                 jdouble m11 = NEXT_DOUBLE(b);
 562                 jdouble m02 = NEXT_DOUBLE(b);
 563                 jdouble m12 = NEXT_DOUBLE(b);
 564                 res = d3dc->SetTransform(m00, m10, m01, m11, m02, m12);
 565             }
 566             break;
 567         case sun_java2d_pipe_BufferedOpCodes_RESET_TRANSFORM:
 568             {
 569                 CONTINUE_IF_NULL(d3dc);
 570                 res = d3dc->ResetTransform();
 571             }
 572             break;
 573 
 574         // context-related ops
 575         case sun_java2d_pipe_BufferedOpCodes_SET_SURFACES:
 576             {
 577                 jlong pSrc = NEXT_LONG(b);
 578                 jlong pDst = NEXT_LONG(b);
 579                 D3DContext *oldd3dc = NULL;
 580                 if (d3dc != NULL) {
 581                     oldd3dc = d3dc;
 582                     d3dc = NULL;
 583                     oldd3dc->UpdateState(STATE_CHANGE);
 584                 }
 585                 dstOps = (D3DSDOps *)jlong_to_ptr(pDst);
 586                 res = pMgr->GetD3DContext(dstOps->adapter, &d3dc);
 587                 if (FAILED(res)) {
 588                     J2dRlsTraceLn(J2D_TRACE_ERROR,
 589                         "D3DRQ_FlushBuffer: failed to get context");
 590                     D3DRQ_ResetCurrentContextAndDestination();
 591                     break;
 592                 }
 593                 // REMIND: we may also want to do EndScene on each
 594                 // render target change so that the GPU can go work on
 595                 // whatever is already in the queue
 596                 if (oldd3dc != d3dc && oldd3dc != NULL) {
 597                     res = oldd3dc->EndScene();
 598                 }
 599                 CONTINUE_IF_NULL(dstOps->pResource);
 600                 res = d3dc->SetRenderTarget(dstOps->pResource->GetSurface());
 601             }
 602             break;
 603         case sun_java2d_pipe_BufferedOpCodes_SET_SCRATCH_SURFACE:
 604             {
 605                 jint screen = NEXT_INT(b);
 606                 jint adapter = pMgr->GetAdapterOrdinalForScreen(screen);
 607                 D3DContext *oldd3dc = NULL;
 608 
 609                 if (d3dc != NULL) {
 610                     oldd3dc = d3dc;
 611                     d3dc = NULL;
 612                 }
 613                 res = pMgr->GetD3DContext(adapter, &d3dc);
 614                 if (FAILED(res)) {
 615                     J2dRlsTraceLn(J2D_TRACE_ERROR,
 616                         "D3DRQ_FlushBuffer: failed to get context");
 617                     D3DRQ_ResetCurrentContextAndDestination();
 618                 } else if (oldd3dc != d3dc && oldd3dc != NULL) {
 619                     res = oldd3dc->EndScene();
 620                 }
 621             }
 622             break;
 623         case sun_java2d_pipe_BufferedOpCodes_FLUSH_SURFACE:
 624             {
 625                 jlong pData = NEXT_LONG(b);
 626                 D3DSDOps *d3dsdo = (D3DSDOps *)jlong_to_ptr(pData);
 627                 D3DSD_Flush(d3dsdo);
 628                 if (dstOps == d3dsdo) {
 629                     dstOps = NULL;
 630                 }
 631             }
 632             break;
 633         case sun_java2d_pipe_BufferedOpCodes_DISPOSE_SURFACE:
 634             {
 635                 jlong pData = NEXT_LONG(b);
 636                 D3DSDOps *d3dsdo = (D3DSDOps *)jlong_to_ptr(pData);
 637                 D3DSD_Flush(d3dsdo);
 638                 if (dstOps == d3dsdo) {
 639                     dstOps = NULL;
 640                 }
 641             }
 642             break;
 643         case sun_java2d_pipe_BufferedOpCodes_DISPOSE_CONFIG:
 644             {
 645                 jlong pConfigInfo = NEXT_LONG(b);
 646                 CONTINUE_IF_NULL(d3dc);
 647                 // REMIND: does this need to be implemented for D3D?
 648             }
 649             break;
 650         case sun_java2d_pipe_BufferedOpCodes_INVALIDATE_CONTEXT:
 651             {
 652                 // flush just in case there are any pending operations in
 653                 // the hardware pipe
 654                 if (d3dc != NULL) {
 655                     res = d3dc->EndScene();
 656                 }
 657 
 658                 // invalidate the references to the current context and
 659                 // destination surface that are maintained at the native level
 660                 D3DRQ_ResetCurrentContextAndDestination();
 661             }
 662             break;
 663 
 664         case sun_java2d_pipe_BufferedOpCodes_SYNC:
 665             {
 666                 bSync = TRUE;
 667             }
 668             break;
 669 
 670         case sun_java2d_pipe_BufferedOpCodes_RESTORE_DEVICES:
 671             {
 672                 J2dTraceLn(J2D_TRACE_INFO, "D3DRQ_FlushBuffer:  RESTORE_DEVICES");
 673                 if (SUCCEEDED(res = pMgr->HandleLostDevices())) {
 674                     bLostDevices = FALSE;
 675                 } else {
 676                     bLostDevices = TRUE;
 677                 }
 678             }
 679             break;
 680         // multibuffering ops
 681         case sun_java2d_pipe_BufferedOpCodes_SWAP_BUFFERS:
 682             {
 683                 jlong sdo = NEXT_LONG(b);
 684                 jint x1 = NEXT_INT(b);
 685                 jint y1 = NEXT_INT(b);
 686                 jint x2 = NEXT_INT(b);
 687                 jint y2 = NEXT_INT(b);
 688 
 689                 res = D3DRQ_SwapBuffers(pMgr, (D3DSDOps *)jlong_to_ptr(sdo),
 690                                         x1, y1, x2, y2);
 691             }
 692             break;
 693 
 694         // special no-op (mainly used for achieving 8-byte alignment)
 695         case sun_java2d_pipe_BufferedOpCodes_NOOP:
 696             break;
 697 
 698         // paint-related ops
 699         case sun_java2d_pipe_BufferedOpCodes_RESET_PAINT:
 700             {
 701                 res = D3DPaints_ResetPaint(d3dc);
 702             }
 703             break;
 704         case sun_java2d_pipe_BufferedOpCodes_SET_COLOR:
 705             {
 706                 jint pixel = NEXT_INT(b);
 707                 res = D3DPaints_SetColor(d3dc, pixel);
 708             }
 709             break;
 710         case sun_java2d_pipe_BufferedOpCodes_SET_GRADIENT_PAINT:
 711             {
 712                 jboolean useMask= NEXT_BOOLEAN(b);
 713                 jboolean cyclic = NEXT_BOOLEAN(b);
 714                 jdouble p0      = NEXT_DOUBLE(b);
 715                 jdouble p1      = NEXT_DOUBLE(b);
 716                 jdouble p3      = NEXT_DOUBLE(b);
 717                 jint pixel1     = NEXT_INT(b);
 718                 jint pixel2     = NEXT_INT(b);
 719                 res = D3DPaints_SetGradientPaint(d3dc, useMask, cyclic,
 720                                                  p0, p1, p3,
 721                                                  pixel1, pixel2);
 722             }
 723             break;
 724         case sun_java2d_pipe_BufferedOpCodes_SET_LINEAR_GRADIENT_PAINT:
 725             {
 726                 jboolean useMask = NEXT_BOOLEAN(b);
 727                 jboolean linear  = NEXT_BOOLEAN(b);
 728                 jint cycleMethod = NEXT_INT(b);
 729                 jint numStops    = NEXT_INT(b);
 730                 jfloat p0        = NEXT_FLOAT(b);
 731                 jfloat p1        = NEXT_FLOAT(b);
 732                 jfloat p3        = NEXT_FLOAT(b);
 733                 void *fractions, *pixels;
 734                 fractions = b; SKIP_BYTES(b, numStops * sizeof(jfloat));
 735                 pixels    = b; SKIP_BYTES(b, numStops * sizeof(jint));
 736                 res = D3DPaints_SetLinearGradientPaint(d3dc, dstOps,
 737                                                         useMask, linear,
 738                                                         cycleMethod, numStops,
 739                                                         p0, p1, p3,
 740                                                         fractions, pixels);
 741             }
 742             break;
 743         case sun_java2d_pipe_BufferedOpCodes_SET_RADIAL_GRADIENT_PAINT:
 744             {
 745                 jboolean useMask = NEXT_BOOLEAN(b);
 746                 jboolean linear  = NEXT_BOOLEAN(b);
 747                 jint numStops    = NEXT_INT(b);
 748                 jint cycleMethod = NEXT_INT(b);
 749                 jfloat m00       = NEXT_FLOAT(b);
 750                 jfloat m01       = NEXT_FLOAT(b);
 751                 jfloat m02       = NEXT_FLOAT(b);
 752                 jfloat m10       = NEXT_FLOAT(b);
 753                 jfloat m11       = NEXT_FLOAT(b);
 754                 jfloat m12       = NEXT_FLOAT(b);
 755                 jfloat focusX    = NEXT_FLOAT(b);
 756                 void *fractions, *pixels;
 757                 fractions = b; SKIP_BYTES(b, numStops * sizeof(jfloat));
 758                 pixels    = b; SKIP_BYTES(b, numStops * sizeof(jint));
 759                 res = D3DPaints_SetRadialGradientPaint(d3dc, dstOps,
 760                                                        useMask, linear,
 761                                                        cycleMethod, numStops,
 762                                                        m00, m01, m02,
 763                                                        m10, m11, m12,
 764                                                        focusX,
 765                                                        fractions, pixels);
 766             }
 767             break;
 768         case sun_java2d_pipe_BufferedOpCodes_SET_TEXTURE_PAINT:
 769             {
 770                 jboolean useMask= NEXT_BOOLEAN(b);
 771                 jboolean filter = NEXT_BOOLEAN(b);
 772                 jlong pSrc      = NEXT_LONG(b);
 773                 jdouble xp0     = NEXT_DOUBLE(b);
 774                 jdouble xp1     = NEXT_DOUBLE(b);
 775                 jdouble xp3     = NEXT_DOUBLE(b);
 776                 jdouble yp0     = NEXT_DOUBLE(b);
 777                 jdouble yp1     = NEXT_DOUBLE(b);
 778                 jdouble yp3     = NEXT_DOUBLE(b);
 779                 res = D3DPaints_SetTexturePaint(d3dc, useMask, pSrc, filter,
 780                                                 xp0, xp1, xp3,
 781                                                 yp0, yp1, yp3);
 782             }
 783             break;
 784 
 785         // BufferedImageOp-related ops
 786         case sun_java2d_pipe_BufferedOpCodes_ENABLE_CONVOLVE_OP:
 787             {
 788                 jlong pSrc        = NEXT_LONG(b);
 789                 jboolean edgeZero = NEXT_BOOLEAN(b);
 790                 jint kernelWidth  = NEXT_INT(b);
 791                 jint kernelHeight = NEXT_INT(b);
 792                 res = D3DBufImgOps_EnableConvolveOp(d3dc, pSrc, edgeZero,
 793                                                     kernelWidth, kernelHeight, b);
 794                 SKIP_BYTES(b, kernelWidth * kernelHeight * sizeof(jfloat));
 795             }
 796             break;
 797         case sun_java2d_pipe_BufferedOpCodes_DISABLE_CONVOLVE_OP:
 798             {
 799                 res = D3DBufImgOps_DisableConvolveOp(d3dc);
 800             }
 801             break;
 802         case sun_java2d_pipe_BufferedOpCodes_ENABLE_RESCALE_OP:
 803             {
 804                 jlong pSrc          = NEXT_LONG(b); // unused
 805                 jboolean nonPremult = NEXT_BOOLEAN(b);
 806                 jint numFactors     = 4;
 807                 unsigned char *scaleFactors = b;
 808                 unsigned char *offsets = (b + numFactors * sizeof(jfloat));
 809                 res = D3DBufImgOps_EnableRescaleOp(d3dc, nonPremult,
 810                                                    scaleFactors, offsets);
 811                 SKIP_BYTES(b, numFactors * sizeof(jfloat) * 2);
 812             }
 813             break;
 814         case sun_java2d_pipe_BufferedOpCodes_DISABLE_RESCALE_OP:
 815             {
 816                 D3DBufImgOps_DisableRescaleOp(d3dc);
 817             }
 818             break;
 819         case sun_java2d_pipe_BufferedOpCodes_ENABLE_LOOKUP_OP:
 820             {
 821                 jlong pSrc          = NEXT_LONG(b); // unused
 822                 jboolean nonPremult = NEXT_BOOLEAN(b);
 823                 jboolean shortData  = NEXT_BOOLEAN(b);
 824                 jint numBands       = NEXT_INT(b);
 825                 jint bandLength     = NEXT_INT(b);
 826                 jint offset         = NEXT_INT(b);
 827                 jint bytesPerElem = shortData ? sizeof(jshort):sizeof(jbyte);
 828                 void *tableValues = b;
 829                 res = D3DBufImgOps_EnableLookupOp(d3dc, nonPremult, shortData,
 830                                                   numBands, bandLength, offset,
 831                                                   tableValues);
 832                 SKIP_BYTES(b, numBands * bandLength * bytesPerElem);
 833             }
 834             break;
 835         case sun_java2d_pipe_BufferedOpCodes_DISABLE_LOOKUP_OP:
 836             {
 837                 res = D3DBufImgOps_DisableLookupOp(d3dc);
 838             }
 839             break;
 840 
 841         default:
 842             J2dRlsTraceLn1(J2D_TRACE_ERROR,
 843                 "D3DRQ_flushBuffer: invalid opcode=%d", opcode);
 844             return;
 845         }
 846         // we may mark the surface lost repeatedly but that won't do much harm
 847         res = D3DRQ_MarkLostIfNeeded(res, dstOps);
 848     }
 849 
 850     if (d3dc != NULL) {
 851         res = d3dc->EndScene();
 852         // REMIND: EndScene is not really enough to flush the
 853         // whole d3d pipeline
 854 
 855         // REMIND: there may be an issue with BeginScene/EndScene
 856         // for each flushQueue, because of the blits, which flush
 857         // the queue
 858         if (bSync) {
 859             res = d3dc->Sync();
 860         }
 861     }
 862 
 863     // REMIND: we need to also handle hard errors here as well, and disable
 864     // particular context if needed
 865     D3DRQ_MarkLostIfNeeded(res, dstOps);
 866 
 867     if (!JNU_IsNull(env, pFlush->runnable)) {
 868         J2dTraceLn(J2D_TRACE_VERBOSE, "  executing runnable");
 869         JNU_CallMethodByName(env, NULL, pFlush->runnable, "run", "()V");
 870     }
 871 }
 872 
 873 /**
 874  * Returns a pointer to the "current" context, as set by the last SET_SURFACES
 875  * or SET_SCRATCH_SURFACE operation.
 876  */
 877 D3DContext *
 878 D3DRQ_GetCurrentContext()
 879 {
 880     return d3dc;
 881 }
 882 
 883 /**
 884  * Returns a pointer to the "current" destination surface, as set by the last
 885  * SET_SURFACES operation.
 886  */
 887 D3DSDOps *
 888 D3DRQ_GetCurrentDestination()
 889 {
 890     return dstOps;
 891 }
 892 
 893 /**
 894  * Resets current context and destination surface.
 895  */
 896 void
 897 D3DRQ_ResetCurrentContextAndDestination()
 898 {
 899     J2dTraceLn(J2D_TRACE_INFO, "D3DRQ_ResetCurrentContextAndDestination");
 900 
 901     d3dc = NULL;
 902     dstOps = NULL;
 903 }
 904 
 905 extern "C"
 906 {
 907 
 908 /*
 909  * Class:     sun_java2d_d3d_D3DRenderQueue
 910  * Method:    flushBuffer
 911  * Signature: (JILjava/lang/Runnable;)V
 912  */
 913 JNIEXPORT void JNICALL
 914 Java_sun_java2d_d3d_D3DRenderQueue_flushBuffer
 915   (JNIEnv *env, jobject d3drq, jlong buf, jint limit, jobject runnable)
 916 {
 917     FlushBufferStruct bufstr;
 918     // just in case we forget to init any new fields
 919     ZeroMemory(&bufstr, sizeof(FlushBufferStruct));
 920 
 921     bufstr.buffer = (unsigned char *)jlong_to_ptr(buf);
 922     if (bufstr.buffer == NULL) {
 923         J2dRlsTraceLn(J2D_TRACE_ERROR,
 924             "D3DRenderQueue_flushBuffer: cannot get direct buffer address");
 925         return;
 926     }
 927     bufstr.limit = limit;
 928 
 929     bufstr.runnable = JNU_IsNull(env, runnable) ?
 930         NULL : env->NewGlobalRef(runnable);
 931     AwtToolkit::GetInstance().InvokeFunction(D3DRQ_FlushBuffer, &bufstr);
 932     if (!JNU_IsNull(env, bufstr.runnable)) {
 933         env->DeleteGlobalRef(bufstr.runnable);
 934     }
 935 }
 936 
 937 }