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