| /* |
| * Copyright (c) 2007, 2010, 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 <jni.h> |
| #include <jlong.h> |
| #include <jni_util.h> |
| #include "sun_java2d_pipe_BufferedMaskBlit.h" |
| #include "sun_java2d_pipe_BufferedOpCodes.h" |
| #include "Trace.h" |
| #include "GraphicsPrimitiveMgr.h" |
| #include "IntArgb.h" |
| #include "IntRgb.h" |
| #include "IntBgr.h" |
| |
| #define MAX_MASK_LENGTH (32 * 32) |
| extern unsigned char mul8table[256][256]; |
| |
| /** |
| * This implementation of MaskBlit first combines the source system memory |
| * tile with the corresponding alpha mask and stores the resulting |
| * IntArgbPre pixels directly into the RenderBuffer. Those pixels are |
| * then eventually pulled off the RenderBuffer and copied to the destination |
| * surface in OGL/D3DMaskBlit. |
| * |
| * Note that currently there are only inner loops defined for IntArgb, |
| * IntArgbPre, IntRgb, and IntBgr, as those are the most commonly used |
| * formats for this operation. |
| */ |
| JNIEXPORT jint JNICALL |
| Java_sun_java2d_pipe_BufferedMaskBlit_enqueueTile |
| (JNIEnv *env, jobject mb, |
| jlong buf, jint bpos, |
| jobject srcData, jlong pSrcOps, jint srcType, |
| jbyteArray maskArray, jint masklen, jint maskoff, jint maskscan, |
| jint srcx, jint srcy, jint dstx, jint dsty, |
| jint width, jint height) |
| { |
| SurfaceDataOps *srcOps = (SurfaceDataOps *)jlong_to_ptr(pSrcOps); |
| SurfaceDataRasInfo srcInfo; |
| unsigned char *bbuf; |
| jint *pBuf; |
| |
| J2dTraceLn1(J2D_TRACE_INFO, |
| "BufferedMaskBlit_enqueueTile: bpos=%d", |
| bpos); |
| |
| if (srcOps == NULL) { |
| J2dRlsTraceLn(J2D_TRACE_ERROR, |
| "BufferedMaskBlit_enqueueTile: srcOps is null"); |
| return bpos; |
| } |
| |
| bbuf = (unsigned char *)jlong_to_ptr(buf); |
| if (bbuf == NULL) { |
| J2dRlsTraceLn(J2D_TRACE_ERROR, |
| "BufferedMaskBlit_enqueueTile: cannot get direct buffer address"); |
| return bpos; |
| } |
| pBuf = (jint *)(bbuf + bpos); |
| |
| if (JNU_IsNull(env, maskArray)) { |
| J2dRlsTraceLn(J2D_TRACE_ERROR, |
| "BufferedMaskBlit_enqueueTile: mask array is null"); |
| return bpos; |
| } |
| |
| if (masklen > MAX_MASK_LENGTH) { |
| // REMIND: this approach is seriously flawed if the mask |
| // length is ever greater than MAX_MASK_LENGTH (won't fit |
| // into the cached mask tile); so far this hasn't |
| // been a problem though... |
| J2dRlsTraceLn(J2D_TRACE_ERROR, |
| "BufferedMaskBlit_enqueueTile: mask array too large"); |
| return bpos; |
| } |
| |
| srcInfo.bounds.x1 = srcx; |
| srcInfo.bounds.y1 = srcy; |
| srcInfo.bounds.x2 = srcx + width; |
| srcInfo.bounds.y2 = srcy + height; |
| |
| if (srcOps->Lock(env, srcOps, &srcInfo, SD_LOCK_READ) != SD_SUCCESS) { |
| J2dRlsTraceLn(J2D_TRACE_WARNING, |
| "BufferedMaskBlit_enqueueTile: could not acquire lock"); |
| return bpos; |
| } |
| |
| if (srcInfo.bounds.x2 > srcInfo.bounds.x1 && |
| srcInfo.bounds.y2 > srcInfo.bounds.y1) |
| { |
| srcOps->GetRasInfo(env, srcOps, &srcInfo); |
| if (srcInfo.rasBase) { |
| jint h; |
| jint srcScanStride = srcInfo.scanStride; |
| jint srcPixelStride = srcInfo.pixelStride; |
| jint *pSrc = (jint *) |
| PtrCoord(srcInfo.rasBase, |
| srcInfo.bounds.x1, srcInfo.pixelStride, |
| srcInfo.bounds.y1, srcInfo.scanStride); |
| unsigned char *pMask, *pMaskAlloc; |
| pMask = pMaskAlloc = |
| (*env)->GetPrimitiveArrayCritical(env, maskArray, 0); |
| if (pMask == NULL) { |
| J2dRlsTraceLn(J2D_TRACE_ERROR, |
| "BufferedMaskBlit_enqueueTile: cannot lock mask array"); |
| SurfaceData_InvokeRelease(env, srcOps, &srcInfo); |
| SurfaceData_InvokeUnlock(env, srcOps, &srcInfo); |
| return bpos; |
| } |
| |
| width = srcInfo.bounds.x2 - srcInfo.bounds.x1; |
| height = srcInfo.bounds.y2 - srcInfo.bounds.y1; |
| maskoff += ((srcInfo.bounds.y1 - srcy) * maskscan + |
| (srcInfo.bounds.x1 - srcx)); |
| maskscan -= width; |
| pMask += maskoff; |
| srcScanStride -= width * srcPixelStride; |
| h = height; |
| |
| J2dTraceLn4(J2D_TRACE_VERBOSE, |
| " sx=%d sy=%d w=%d h=%d", |
| srcInfo.bounds.x1, srcInfo.bounds.y1, width, height); |
| J2dTraceLn2(J2D_TRACE_VERBOSE, |
| " maskoff=%d maskscan=%d", |
| maskoff, maskscan); |
| J2dTraceLn2(J2D_TRACE_VERBOSE, |
| " pixstride=%d scanstride=%d", |
| srcPixelStride, srcScanStride); |
| |
| // enqueue parameters |
| pBuf[0] = sun_java2d_pipe_BufferedOpCodes_MASK_BLIT; |
| pBuf[1] = dstx; |
| pBuf[2] = dsty; |
| pBuf[3] = width; |
| pBuf[4] = height; |
| pBuf += 5; |
| bpos += 5 * sizeof(jint); |
| |
| // apply alpha values from mask to the source tile, and store |
| // resulting IntArgbPre pixels into RenderBuffer (there are |
| // separate inner loops for the most common source formats) |
| switch (srcType) { |
| case sun_java2d_pipe_BufferedMaskBlit_ST_INT_ARGB: |
| do { |
| jint w = width; |
| do { |
| jint pathA = *pMask++; |
| if (!pathA) { |
| pBuf[0] = 0; |
| } else { |
| jint pixel = pSrc[0]; |
| if (pathA == 0xff && (pixel >> 24) + 1 == 0) { |
| pBuf[0] = pixel; |
| } else { |
| jint r, g, b, a; |
| ExtractIntDcmComponents1234(pixel, a, r, g, b); |
| a = MUL8(pathA, a); |
| r = MUL8(a, r); |
| g = MUL8(a, g); |
| b = MUL8(a, b); |
| pBuf[0] = (a << 24) | (r << 16) | (g << 8) | b; |
| } |
| } |
| pSrc = PtrAddBytes(pSrc, srcPixelStride); |
| pBuf++; |
| } while (--w > 0); |
| pSrc = PtrAddBytes(pSrc, srcScanStride); |
| pMask = PtrAddBytes(pMask, maskscan); |
| } while (--h > 0); |
| break; |
| |
| case sun_java2d_pipe_BufferedMaskBlit_ST_INT_ARGB_PRE: |
| do { |
| jint w = width; |
| do { |
| jint pathA = *pMask++; |
| if (!pathA) { |
| pBuf[0] = 0; |
| } else if (pathA == 0xff) { |
| pBuf[0] = pSrc[0]; |
| } else { |
| jint r, g, b, a; |
| a = MUL8(pathA, (pSrc[0] >> 24) & 0xff); |
| r = MUL8(pathA, (pSrc[0] >> 16) & 0xff); |
| g = MUL8(pathA, (pSrc[0] >> 8) & 0xff); |
| b = MUL8(pathA, (pSrc[0] >> 0) & 0xff); |
| pBuf[0] = (a << 24) | (r << 16) | (g << 8) | b; |
| } |
| pSrc = PtrAddBytes(pSrc, srcPixelStride); |
| pBuf++; |
| } while (--w > 0); |
| pSrc = PtrAddBytes(pSrc, srcScanStride); |
| pMask = PtrAddBytes(pMask, maskscan); |
| } while (--h > 0); |
| break; |
| |
| case sun_java2d_pipe_BufferedMaskBlit_ST_INT_RGB: |
| do { |
| jint w = width; |
| do { |
| jint pathA = *pMask++; |
| if (!pathA) { |
| pBuf[0] = 0; |
| } else if (pathA == 0xff) { |
| pBuf[0] = pSrc[0] | 0xff000000; |
| } else { |
| jint r, g, b, a; |
| LoadIntRgbTo3ByteRgb(pSrc, c, 0, r, g, b); |
| a = pathA; |
| r = MUL8(a, r); |
| g = MUL8(a, g); |
| b = MUL8(a, b); |
| pBuf[0] = (a << 24) | (r << 16) | (g << 8) | b; |
| } |
| pSrc = PtrAddBytes(pSrc, srcPixelStride); |
| pBuf++; |
| } while (--w > 0); |
| pSrc = PtrAddBytes(pSrc, srcScanStride); |
| pMask = PtrAddBytes(pMask, maskscan); |
| } while (--h > 0); |
| break; |
| |
| case sun_java2d_pipe_BufferedMaskBlit_ST_INT_BGR: |
| do { |
| jint w = width; |
| do { |
| jint pathA = *pMask++; |
| if (!pathA) { |
| pBuf[0] = 0; |
| } else { |
| jint r, g, b, a; |
| LoadIntBgrTo3ByteRgb(pSrc, c, 0, r, g, b); |
| a = pathA; |
| r = MUL8(a, r); |
| g = MUL8(a, g); |
| b = MUL8(a, b); |
| pBuf[0] = (a << 24) | (r << 16) | (g << 8) | b; |
| } |
| pSrc = PtrAddBytes(pSrc, srcPixelStride); |
| pBuf++; |
| } while (--w > 0); |
| pSrc = PtrAddBytes(pSrc, srcScanStride); |
| pMask = PtrAddBytes(pMask, maskscan); |
| } while (--h > 0); |
| break; |
| |
| default: |
| // should not get here, just no-op... |
| break; |
| } |
| |
| // increment current byte position |
| bpos += width * height * sizeof(jint); |
| |
| (*env)->ReleasePrimitiveArrayCritical(env, maskArray, |
| pMaskAlloc, JNI_ABORT); |
| } |
| SurfaceData_InvokeRelease(env, srcOps, &srcInfo); |
| } |
| SurfaceData_InvokeUnlock(env, srcOps, &srcInfo); |
| |
| // return the current byte position |
| return bpos; |
| } |