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 =
 123                 (*env)->GetPrimitiveArrayCritical(env, maskArray, 0);
 124             if (pMask == NULL) {
 125                 J2dRlsTraceLn(J2D_TRACE_ERROR,
 126                     "BufferedMaskBlit_enqueueTile: cannot lock mask array");
 127                 SurfaceData_InvokeRelease(env, srcOps, &srcInfo);
 128                 SurfaceData_InvokeUnlock(env, srcOps, &srcInfo);
 129                 return bpos;
 130             }
 131 
 132             width = srcInfo.bounds.x2 - srcInfo.bounds.x1;
 133             height = srcInfo.bounds.y2 - srcInfo.bounds.y1;
 134             maskoff += ((srcInfo.bounds.y1 - srcy) * maskscan +
 135                         (srcInfo.bounds.x1 - srcx));
 136             maskscan -= width;
 137             pMask += maskoff;
 138             srcScanStride -= width * srcPixelStride;
 139             h = height;
 140 
 141             J2dTraceLn4(J2D_TRACE_VERBOSE,
 142                         "  sx=%d sy=%d w=%d h=%d",
 143                         srcInfo.bounds.x1, srcInfo.bounds.y1, width, height);
 144             J2dTraceLn2(J2D_TRACE_VERBOSE,
 145                         "  maskoff=%d maskscan=%d",
 146                         maskoff, maskscan);
 147             J2dTraceLn2(J2D_TRACE_VERBOSE,
 148                         "  pixstride=%d scanstride=%d",
 149                         srcPixelStride, srcScanStride);
 150 
 151             // enqueue parameters
 152             pBuf[0] = sun_java2d_pipe_BufferedOpCodes_MASK_BLIT;
 153             pBuf[1] = dstx;
 154             pBuf[2] = dsty;
 155             pBuf[3] = width;
 156             pBuf[4] = height;
 157             pBuf += 5;
 158             bpos += 5 * sizeof(jint);
 159 
 160             // apply alpha values from mask to the source tile, and store
 161             // resulting IntArgbPre pixels into RenderBuffer (there are
 162             // separate inner loops for the most common source formats)
 163             switch (srcType) {
 164             case sun_java2d_pipe_BufferedMaskBlit_ST_INT_ARGB:
 165                 do {
 166                     jint w = width;
 167                     do {
 168                         jint pathA = *pMask++;
 169                         if (!pathA) {
 170                             pBuf[0] = 0;
 171                         } else {
 172                             jint pixel = pSrc[0];
 173                             if (pathA == 0xff && (pixel >> 24) + 1 == 0) {
 174                                 pBuf[0] = pixel;
 175                             } else {
 176                                 jint r, g, b, a;
 177                                 ExtractIntDcmComponents1234(pixel, a, r, g, b);
 178                                 a = MUL8(pathA, a);
 179                                 r = MUL8(a, r);
 180                                 g = MUL8(a, g);
 181                                 b = MUL8(a, b);
 182                                 pBuf[0] = (a << 24) | (r << 16) | (g << 8) | b;
 183                             }
 184                         }
 185                         pSrc = PtrAddBytes(pSrc, srcPixelStride);
 186                         pBuf++;
 187                     } while (--w > 0);
 188                     pSrc = PtrAddBytes(pSrc, srcScanStride);
 189                     pMask = PtrAddBytes(pMask, maskscan);
 190                 } while (--h > 0);
 191                 break;
 192 
 193             case sun_java2d_pipe_BufferedMaskBlit_ST_INT_ARGB_PRE:
 194                 do {
 195                     jint w = width;
 196                     do {
 197                         jint pathA = *pMask++;
 198                         if (!pathA) {
 199                             pBuf[0] = 0;
 200                         } else if (pathA == 0xff) {
 201                             pBuf[0] = pSrc[0];
 202                         } else {
 203                             jint r, g, b, a;
 204                             a = MUL8(pathA, (pSrc[0] >> 24) & 0xff);
 205                             r = MUL8(pathA, (pSrc[0] >> 16) & 0xff);
 206                             g = MUL8(pathA, (pSrc[0] >>  8) & 0xff);
 207                             b = MUL8(pathA, (pSrc[0] >>  0) & 0xff);
 208                             pBuf[0] = (a << 24) | (r << 16) | (g << 8) | b;
 209                         }
 210                         pSrc = PtrAddBytes(pSrc, srcPixelStride);
 211                         pBuf++;
 212                     } while (--w > 0);
 213                     pSrc = PtrAddBytes(pSrc, srcScanStride);
 214                     pMask = PtrAddBytes(pMask, maskscan);
 215                 } while (--h > 0);
 216                 break;
 217 
 218             case sun_java2d_pipe_BufferedMaskBlit_ST_INT_RGB:
 219                 do {
 220                     jint w = width;
 221                     do {
 222                         jint pathA = *pMask++;
 223                         if (!pathA) {
 224                             pBuf[0] = 0;
 225                         } else if (pathA == 0xff) {
 226                             pBuf[0] = pSrc[0] | 0xff000000;
 227                         } else {
 228                             jint r, g, b, a;
 229                             LoadIntRgbTo3ByteRgb(pSrc, c, 0, r, g, b);
 230                             a = pathA;
 231                             r = MUL8(a, r);
 232                             g = MUL8(a, g);
 233                             b = MUL8(a, b);
 234                             pBuf[0] = (a << 24) | (r << 16) | (g << 8) | b;
 235                         }
 236                         pSrc = PtrAddBytes(pSrc, srcPixelStride);
 237                         pBuf++;
 238                     } while (--w > 0);
 239                     pSrc = PtrAddBytes(pSrc, srcScanStride);
 240                     pMask = PtrAddBytes(pMask, maskscan);
 241                 } while (--h > 0);
 242                 break;
 243 
 244             case sun_java2d_pipe_BufferedMaskBlit_ST_INT_BGR:
 245                 do {
 246                     jint w = width;
 247                     do {
 248                         jint pathA = *pMask++;
 249                         if (!pathA) {
 250                             pBuf[0] = 0;
 251                         } else {
 252                             jint r, g, b, a;
 253                             LoadIntBgrTo3ByteRgb(pSrc, c, 0, r, g, b);
 254                             a = pathA;
 255                             r = MUL8(a, r);
 256                             g = MUL8(a, g);
 257                             b = MUL8(a, b);
 258                             pBuf[0] = (a << 24) | (r << 16) | (g << 8) | b;
 259                         }
 260                         pSrc = PtrAddBytes(pSrc, srcPixelStride);
 261                         pBuf++;
 262                     } while (--w > 0);
 263                     pSrc = PtrAddBytes(pSrc, srcScanStride);
 264                     pMask = PtrAddBytes(pMask, maskscan);
 265                 } while (--h > 0);
 266                 break;
 267 
 268             default:
 269                 // should not get here, just no-op...
 270                 break;
 271             }
 272 
 273             // increment current byte position
 274             bpos += width * height * sizeof(jint);
 275 
 276             (*env)->ReleasePrimitiveArrayCritical(env, maskArray,
 277                                                   pMask, JNI_ABORT);
 278         }
 279         SurfaceData_InvokeRelease(env, srcOps, &srcInfo);
 280     }
 281     SurfaceData_InvokeUnlock(env, srcOps, &srcInfo);
 282 
 283     // return the current byte position
 284     return bpos;
 285 }