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) |
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 | } |
287 | |