1/*
2 * Copyright (c) 2007, 2010, 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)
38extern 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 */
51JNIEXPORT jint JNICALL
52Java_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}
287