1 /*
   2  * Copyright (c) 2007, 2008, 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 <jni.h>
  27 #include <jlong.h>
  28 #include <jni_util.h>
  29 #include "sun_java2d_pipe_BufferedMaskBlit.h"
  30 #include "sun_java2d_pipe_BufferedOpCodes.h"
  31 #include "Trace.h"
  32 #include "GraphicsPrimitiveMgr.h"
  33 #include "IntArgb.h"
  34 #include "IntRgb.h"
  35 #include "IntBgr.h"
  36 
  37 #define MAX_MASK_LENGTH (32 * 32)
  38 extern unsigned char mul8table[256][256];
  39 
  40 /**
  41  * This implementation of MaskBlit first combines the source system memory
  42  * tile with the corresponding alpha mask and stores the resulting
  43  * IntArgbPre pixels directly into the RenderBuffer.  Those pixels are
  44  * then eventually pulled off the RenderBuffer and copied to the destination
  45  * surface in OGL/D3DMaskBlit.
  46  *
  47  * Note that currently there are only inner loops defined for IntArgb,
  48  * IntArgbPre, IntRgb, and IntBgr, as those are the most commonly used
  49  * formats for this operation.
  50  */
  51 JNIEXPORT jint JNICALL
  52 Java_sun_java2d_pipe_BufferedMaskBlit_enqueueTile
  53     (JNIEnv *env, jobject mb,
  54      jlong buf, jint bpos,
  55      jobject srcData, jlong pSrcOps, jint srcType,
  56      jbyteArray maskArray, jint masklen, jint maskoff, jint maskscan,
  57      jint srcx, jint srcy, jint dstx, jint dsty,
  58      jint width, jint height)
  59 {
  60     SurfaceDataOps *srcOps = (SurfaceDataOps *)jlong_to_ptr(pSrcOps);
  61     SurfaceDataRasInfo srcInfo;
  62     unsigned char *bbuf;
  63     jint *pBuf;
  64 
  65     J2dTraceLn1(J2D_TRACE_INFO,
  66                 "BufferedMaskBlit_enqueueTile: bpos=%d",
  67                 bpos);
  68 
  69     if (srcOps == NULL) {
  70         J2dRlsTraceLn(J2D_TRACE_ERROR,
  71             "BufferedMaskBlit_enqueueTile: srcOps is null");
  72         return bpos;
  73     }
  74 
  75     bbuf = (unsigned char *)jlong_to_ptr(buf);
  76     if (bbuf == NULL) {
  77         J2dRlsTraceLn(J2D_TRACE_ERROR,
  78             "BufferedMaskBlit_enqueueTile: cannot get direct buffer address");
  79         return bpos;
  80     }
  81     pBuf = (jint *)(bbuf + bpos);
  82 
  83     if (JNU_IsNull(env, maskArray)) {
  84         J2dRlsTraceLn(J2D_TRACE_ERROR,
  85             "BufferedMaskBlit_enqueueTile: mask array is null");
  86         return bpos;
  87     }
  88 
  89     if (masklen > MAX_MASK_LENGTH) {
  90         // REMIND: this approach is seriously flawed if the mask
  91         //         length is ever greater than MAX_MASK_LENGTH (won't fit
  92         //         into the cached mask tile); so far this hasn't
  93         //         been a problem though...
  94         J2dRlsTraceLn(J2D_TRACE_ERROR,
  95             "BufferedMaskBlit_enqueueTile: mask array too large");
  96         return bpos;
  97     }
  98 
  99     srcInfo.bounds.x1 = srcx;
 100     srcInfo.bounds.y1 = srcy;
 101     srcInfo.bounds.x2 = srcx + width;
 102     srcInfo.bounds.y2 = srcy + height;
 103 
 104     if (srcOps->Lock(env, srcOps, &srcInfo, SD_LOCK_READ) != SD_SUCCESS) {
 105         J2dRlsTraceLn(J2D_TRACE_WARNING,
 106                       "BufferedMaskBlit_enqueueTile: could not acquire lock");
 107         return bpos;
 108     }
 109 
 110     if (srcInfo.bounds.x2 > srcInfo.bounds.x1 &&
 111         srcInfo.bounds.y2 > srcInfo.bounds.y1)
 112     {
 113         srcOps->GetRasInfo(env, srcOps, &srcInfo);
 114         if (srcInfo.rasBase) {
 115             jint h;
 116             jint srcScanStride = srcInfo.scanStride;
 117             jint srcPixelStride = srcInfo.pixelStride;
 118             jint *pSrc = (jint *)
 119                 PtrCoord(srcInfo.rasBase,
 120                          srcInfo.bounds.x1, srcInfo.pixelStride,
 121                          srcInfo.bounds.y1, srcInfo.scanStride);
 122             unsigned char *pMask, *pMaskAlloc;
 123             pMask = pMaskAlloc =
 124                 (*env)->GetPrimitiveArrayCritical(env, maskArray, 0);
 125             if (pMask == NULL) {
 126                 J2dRlsTraceLn(J2D_TRACE_ERROR,
 127                     "BufferedMaskBlit_enqueueTile: cannot lock mask array");
 128                 SurfaceData_InvokeRelease(env, srcOps, &srcInfo);
 129                 SurfaceData_InvokeUnlock(env, srcOps, &srcInfo);
 130                 return bpos;
 131             }
 132 
 133             width = srcInfo.bounds.x2 - srcInfo.bounds.x1;
 134             height = srcInfo.bounds.y2 - srcInfo.bounds.y1;
 135             maskoff += ((srcInfo.bounds.y1 - srcy) * maskscan +
 136                         (srcInfo.bounds.x1 - srcx));
 137             maskscan -= width;
 138             pMask += maskoff;
 139             srcScanStride -= width * srcPixelStride;
 140             h = height;
 141 
 142             J2dTraceLn4(J2D_TRACE_VERBOSE,
 143                         "  sx=%d sy=%d w=%d h=%d",
 144                         srcInfo.bounds.x1, srcInfo.bounds.y1, width, height);
 145             J2dTraceLn2(J2D_TRACE_VERBOSE,
 146                         "  maskoff=%d maskscan=%d",
 147                         maskoff, maskscan);
 148             J2dTraceLn2(J2D_TRACE_VERBOSE,
 149                         "  pixstride=%d scanstride=%d",
 150                         srcPixelStride, srcScanStride);
 151 
 152             // enqueue parameters
 153             pBuf[0] = sun_java2d_pipe_BufferedOpCodes_MASK_BLIT;
 154             pBuf[1] = dstx;
 155             pBuf[2] = dsty;
 156             pBuf[3] = width;
 157             pBuf[4] = height;
 158             pBuf += 5;
 159             bpos += 5 * sizeof(jint);
 160 
 161             // apply alpha values from mask to the source tile, and store
 162             // resulting IntArgbPre pixels into RenderBuffer (there are
 163             // separate inner loops for the most common source formats)
 164             switch (srcType) {
 165             case sun_java2d_pipe_BufferedMaskBlit_ST_INT_ARGB:
 166                 do {
 167                     jint w = width;
 168                     do {
 169                         jint pathA = *pMask++;
 170                         if (!pathA) {
 171                             pBuf[0] = 0;
 172                         } else {
 173                             jint pixel = pSrc[0];
 174                             if (pathA == 0xff && (pixel >> 24) + 1 == 0) {
 175                                 pBuf[0] = pixel;
 176                             } else {
 177                                 jint r, g, b, a;
 178                                 ExtractIntDcmComponents1234(pixel, a, r, g, b);
 179                                 a = MUL8(pathA, a);
 180                                 r = MUL8(a, r);
 181                                 g = MUL8(a, g);
 182                                 b = MUL8(a, b);
 183                                 pBuf[0] = (a << 24) | (r << 16) | (g << 8) | b;
 184                             }
 185                         }
 186                         pSrc = PtrAddBytes(pSrc, srcPixelStride);
 187                         pBuf++;
 188                     } while (--w > 0);
 189                     pSrc = PtrAddBytes(pSrc, srcScanStride);
 190                     pMask = PtrAddBytes(pMask, maskscan);
 191                 } while (--h > 0);
 192                 break;
 193 
 194             case sun_java2d_pipe_BufferedMaskBlit_ST_INT_ARGB_PRE:
 195                 do {
 196                     jint w = width;
 197                     do {
 198                         jint pathA = *pMask++;
 199                         if (!pathA) {
 200                             pBuf[0] = 0;
 201                         } else if (pathA == 0xff) {
 202                             pBuf[0] = pSrc[0];
 203                         } else {
 204                             jint r, g, b, a;
 205                             a = MUL8(pathA, (pSrc[0] >> 24) & 0xff);
 206                             r = MUL8(pathA, (pSrc[0] >> 16) & 0xff);
 207                             g = MUL8(pathA, (pSrc[0] >>  8) & 0xff);
 208                             b = MUL8(pathA, (pSrc[0] >>  0) & 0xff);
 209                             pBuf[0] = (a << 24) | (r << 16) | (g << 8) | b;
 210                         }
 211                         pSrc = PtrAddBytes(pSrc, srcPixelStride);
 212                         pBuf++;
 213                     } while (--w > 0);
 214                     pSrc = PtrAddBytes(pSrc, srcScanStride);
 215                     pMask = PtrAddBytes(pMask, maskscan);
 216                 } while (--h > 0);
 217                 break;
 218 
 219             case sun_java2d_pipe_BufferedMaskBlit_ST_INT_RGB:
 220                 do {
 221                     jint w = width;
 222                     do {
 223                         jint pathA = *pMask++;
 224                         if (!pathA) {
 225                             pBuf[0] = 0;
 226                         } else if (pathA == 0xff) {
 227                             pBuf[0] = pSrc[0] | 0xff000000;
 228                         } else {
 229                             jint r, g, b, a;
 230                             LoadIntRgbTo3ByteRgb(pSrc, c, 0, r, g, b);
 231                             a = pathA;
 232                             r = MUL8(a, r);
 233                             g = MUL8(a, g);
 234                             b = MUL8(a, b);
 235                             pBuf[0] = (a << 24) | (r << 16) | (g << 8) | b;
 236                         }
 237                         pSrc = PtrAddBytes(pSrc, srcPixelStride);
 238                         pBuf++;
 239                     } while (--w > 0);
 240                     pSrc = PtrAddBytes(pSrc, srcScanStride);
 241                     pMask = PtrAddBytes(pMask, maskscan);
 242                 } while (--h > 0);
 243                 break;
 244 
 245             case sun_java2d_pipe_BufferedMaskBlit_ST_INT_BGR:
 246                 do {
 247                     jint w = width;
 248                     do {
 249                         jint pathA = *pMask++;
 250                         if (!pathA) {
 251                             pBuf[0] = 0;
 252                         } else {
 253                             jint r, g, b, a;
 254                             LoadIntBgrTo3ByteRgb(pSrc, c, 0, r, g, b);
 255                             a = pathA;
 256                             r = MUL8(a, r);
 257                             g = MUL8(a, g);
 258                             b = MUL8(a, b);
 259                             pBuf[0] = (a << 24) | (r << 16) | (g << 8) | b;
 260                         }
 261                         pSrc = PtrAddBytes(pSrc, srcPixelStride);
 262                         pBuf++;
 263                     } while (--w > 0);
 264                     pSrc = PtrAddBytes(pSrc, srcScanStride);
 265                     pMask = PtrAddBytes(pMask, maskscan);
 266                 } while (--h > 0);
 267                 break;
 268 
 269             default:
 270                 // should not get here, just no-op...
 271                 break;
 272             }
 273 
 274             // increment current byte position
 275             bpos += width * height * sizeof(jint);
 276 
 277             (*env)->ReleasePrimitiveArrayCritical(env, maskArray,
 278                                                   pMaskAlloc, JNI_ABORT);
 279         }
 280         SurfaceData_InvokeRelease(env, srcOps, &srcInfo);
 281     }
 282     SurfaceData_InvokeUnlock(env, srcOps, &srcInfo);
 283 
 284     // return the current byte position
 285     return bpos;
 286 }