|
1 /* |
|
2 * Copyright (c) 2019, 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 #ifndef HEADLESS |
|
27 |
|
28 #include <jlong.h> |
|
29 |
|
30 #include "MTLBufImgOps.h" |
|
31 #include "MTLContext.h" |
|
32 #include "MTLRenderQueue.h" |
|
33 #include "MTLSurfaceDataBase.h" |
|
34 #include "GraphicsPrimitiveMgr.h" |
|
35 |
|
36 /** Evaluates to true if the given bit is set on the local flags variable. */ |
|
37 #define IS_SET(flagbit) \ |
|
38 (((flags) & (flagbit)) != 0) |
|
39 |
|
40 /**************************** ConvolveOp support ****************************/ |
|
41 |
|
42 /** |
|
43 * The ConvolveOp shader is fairly straightforward. For each texel in |
|
44 * the source texture, the shader samples the MxN texels in the surrounding |
|
45 * area, multiplies each by its corresponding kernel value, and then sums |
|
46 * them all together to produce a single color result. Finally, the |
|
47 * resulting value is multiplied by the current OpenGL color, which contains |
|
48 * the extra alpha value. |
|
49 * |
|
50 * Note that this shader source code includes some "holes" marked by "%s". |
|
51 * This allows us to build different shader programs (e.g. one for |
|
52 * 3x3, one for 5x5, and so on) simply by filling in these "holes" with |
|
53 * a call to sprintf(). See the MTLBufImgOps_CreateConvolveProgram() method |
|
54 * for more details. |
|
55 * |
|
56 * REMIND: Currently this shader (and the supporting code in the |
|
57 * EnableConvolveOp() method) only supports 3x3 and 5x5 filters. |
|
58 * Early shader-level hardware did not support non-constant sized |
|
59 * arrays but modern hardware should support them (although I |
|
60 * don't know of any simple way to find out, other than to compile |
|
61 * the shader at runtime and see if the drivers complain). |
|
62 */ |
|
63 static const char *convolveShaderSource = |
|
64 // maximum size supported by this shader |
|
65 "const int MAX_KERNEL_SIZE = %s;" |
|
66 // image to be convolved |
|
67 "uniform sampler%s baseImage;" |
|
68 // image edge limits: |
|
69 // imgEdge.xy = imgMin.xy (anything < will be treated as edge case) |
|
70 // imgEdge.zw = imgMax.xy (anything > will be treated as edge case) |
|
71 "uniform vec4 imgEdge;" |
|
72 // value for each location in the convolution kernel: |
|
73 // kernelVals[i].x = offsetX[i] |
|
74 // kernelVals[i].y = offsetY[i] |
|
75 // kernelVals[i].z = kernel[i] |
|
76 "uniform vec3 kernelVals[MAX_KERNEL_SIZE];" |
|
77 "" |
|
78 "void main(void)" |
|
79 "{" |
|
80 " int i;" |
|
81 " vec4 sum;" |
|
82 "" |
|
83 " if (any(lessThan(gl_TexCoord[0].st, imgEdge.xy)) ||" |
|
84 " any(greaterThan(gl_TexCoord[0].st, imgEdge.zw)))" |
|
85 " {" |
|
86 // (placeholder for edge condition code) |
|
87 " %s" |
|
88 " } else {" |
|
89 " sum = vec4(0.0);" |
|
90 " for (i = 0; i < MAX_KERNEL_SIZE; i++) {" |
|
91 " sum +=" |
|
92 " kernelVals[i].z *" |
|
93 " texture%s(baseImage," |
|
94 " gl_TexCoord[0].st + kernelVals[i].xy);" |
|
95 " }" |
|
96 " }" |
|
97 "" |
|
98 // modulate with gl_Color in order to apply extra alpha |
|
99 " gl_FragColor = sum * gl_Color;" |
|
100 "}"; |
|
101 |
|
102 /** |
|
103 * Flags that can be bitwise-or'ed together to control how the shader |
|
104 * source code is generated. |
|
105 */ |
|
106 #define CONVOLVE_RECT (1 << 0) |
|
107 #define CONVOLVE_EDGE_ZERO_FILL (1 << 1) |
|
108 #define CONVOLVE_5X5 (1 << 2) |
|
109 |
|
110 /** |
|
111 * The handles to the ConvolveOp fragment program objects. The index to |
|
112 * the array should be a bitwise-or'ing of the CONVOLVE_* flags defined |
|
113 * above. Note that most applications will likely need to initialize one |
|
114 * or two of these elements, so the array is usually sparsely populated. |
|
115 */ |
|
116 static GLhandleARB convolvePrograms[8]; |
|
117 |
|
118 /** |
|
119 * The maximum kernel size supported by the ConvolveOp shader. |
|
120 */ |
|
121 #define MAX_KERNEL_SIZE 25 |
|
122 |
|
123 /** |
|
124 * Compiles and links the ConvolveOp shader program. If successful, this |
|
125 * function returns a handle to the newly created shader program; otherwise |
|
126 * returns 0. |
|
127 */ |
|
128 static GLhandleARB |
|
129 MTLBufImgOps_CreateConvolveProgram(jint flags) |
|
130 { |
|
131 //TODO |
|
132 return NULL; |
|
133 } |
|
134 |
|
135 void |
|
136 MTLBufImgOps_EnableConvolveOp(MTLContext *mtlc, jlong pSrcOps, |
|
137 jboolean edgeZeroFill, |
|
138 jint kernelWidth, jint kernelHeight, |
|
139 unsigned char *kernel) |
|
140 { |
|
141 //TODO |
|
142 } |
|
143 |
|
144 void |
|
145 MTLBufImgOps_DisableConvolveOp(MTLContext *mtlc) |
|
146 { |
|
147 //TODO |
|
148 J2dTraceLn(J2D_TRACE_INFO, "MTLBufImgOps_DisableConvolveOp"); |
|
149 } |
|
150 |
|
151 /**************************** RescaleOp support *****************************/ |
|
152 |
|
153 /** |
|
154 * The RescaleOp shader is one of the simplest possible. Each fragment |
|
155 * from the source image is multiplied by the user's scale factor and added |
|
156 * to the user's offset value (these are component-wise operations). |
|
157 * Finally, the resulting value is multiplied by the current OpenGL color, |
|
158 * which contains the extra alpha value. |
|
159 * |
|
160 * The RescaleOp spec says that the operation is performed regardless of |
|
161 * whether the source data is premultiplied or non-premultiplied. This is |
|
162 * a problem for the OpenGL pipeline in that a non-premultiplied |
|
163 * BufferedImage will have already been converted into premultiplied |
|
164 * when uploaded to an OpenGL texture. Therefore, we have a special mode |
|
165 * called RESCALE_NON_PREMULT (used only for source images that were |
|
166 * originally non-premultiplied) that un-premultiplies the source color |
|
167 * prior to the rescale operation, then re-premultiplies the resulting |
|
168 * color before returning from the fragment shader. |
|
169 * |
|
170 * Note that this shader source code includes some "holes" marked by "%s". |
|
171 * This allows us to build different shader programs (e.g. one for |
|
172 * GL_TEXTURE_2D targets, one for GL_TEXTURE_RECTANGLE_ARB targets, and so on) |
|
173 * simply by filling in these "holes" with a call to sprintf(). See the |
|
174 * MTLBufImgOps_CreateRescaleProgram() method for more details. |
|
175 */ |
|
176 static const char *rescaleShaderSource = |
|
177 // image to be rescaled |
|
178 "uniform sampler%s baseImage;" |
|
179 // vector containing scale factors |
|
180 "uniform vec4 scaleFactors;" |
|
181 // vector containing offsets |
|
182 "uniform vec4 offsets;" |
|
183 "" |
|
184 "void main(void)" |
|
185 "{" |
|
186 " vec4 srcColor = texture%s(baseImage, gl_TexCoord[0].st);" |
|
187 // (placeholder for un-premult code) |
|
188 " %s" |
|
189 // rescale source value |
|
190 " vec4 result = (srcColor * scaleFactors) + offsets;" |
|
191 // (placeholder for re-premult code) |
|
192 " %s" |
|
193 // modulate with gl_Color in order to apply extra alpha |
|
194 " gl_FragColor = result * gl_Color;" |
|
195 "}"; |
|
196 |
|
197 /** |
|
198 * Flags that can be bitwise-or'ed together to control how the shader |
|
199 * source code is generated. |
|
200 */ |
|
201 #define RESCALE_RECT (1 << 0) |
|
202 #define RESCALE_NON_PREMULT (1 << 1) |
|
203 |
|
204 /** |
|
205 * The handles to the RescaleOp fragment program objects. The index to |
|
206 * the array should be a bitwise-or'ing of the RESCALE_* flags defined |
|
207 * above. Note that most applications will likely need to initialize one |
|
208 * or two of these elements, so the array is usually sparsely populated. |
|
209 */ |
|
210 static GLhandleARB rescalePrograms[4]; |
|
211 |
|
212 /** |
|
213 * Compiles and links the RescaleOp shader program. If successful, this |
|
214 * function returns a handle to the newly created shader program; otherwise |
|
215 * returns 0. |
|
216 */ |
|
217 static GLhandleARB |
|
218 MTLBufImgOps_CreateRescaleProgram(jint flags) |
|
219 { |
|
220 //TODO |
|
221 return NULL; |
|
222 } |
|
223 |
|
224 void |
|
225 MTLBufImgOps_EnableRescaleOp(MTLContext *mtlc, jlong pSrcOps, |
|
226 jboolean nonPremult, |
|
227 unsigned char *scaleFactors, |
|
228 unsigned char *offsets) |
|
229 { |
|
230 //TODO |
|
231 } |
|
232 |
|
233 void |
|
234 MTLBufImgOps_DisableRescaleOp(MTLContext *mtlc) |
|
235 { |
|
236 //TODO |
|
237 J2dTraceLn(J2D_TRACE_INFO, "MTLBufImgOps_DisableRescaleOp"); |
|
238 RETURN_IF_NULL(mtlc); |
|
239 } |
|
240 |
|
241 /**************************** LookupOp support ******************************/ |
|
242 |
|
243 /** |
|
244 * The LookupOp shader takes a fragment color (from the source texture) as |
|
245 * input, subtracts the optional user offset value, and then uses the |
|
246 * resulting value to index into the lookup table texture to provide |
|
247 * a new color result. Finally, the resulting value is multiplied by |
|
248 * the current OpenGL color, which contains the extra alpha value. |
|
249 * |
|
250 * The lookup step requires 3 texture accesses (or 4, when alpha is included), |
|
251 * which is somewhat unfortunate because it's not ideal from a performance |
|
252 * standpoint, but that sort of thing is getting faster with newer hardware. |
|
253 * In the 3-band case, we could consider using a three-dimensional texture |
|
254 * and performing the lookup with a single texture access step. We already |
|
255 * use this approach in the LCD text shader, and it works well, but for the |
|
256 * purposes of this LookupOp shader, it's probably overkill. Also, there's |
|
257 * a difference in that the LCD text shader only needs to populate the 3D LUT |
|
258 * once, but here we would need to populate it on every invocation, which |
|
259 * would likely be a waste of VRAM and CPU/GPU cycles. |
|
260 * |
|
261 * The LUT texture is currently hardcoded as 4 rows/bands, each containing |
|
262 * 256 elements. This means that we currently only support user-provided |
|
263 * tables with no more than 256 elements in each band (this is checked at |
|
264 * at the Java level). If the user provides a table with less than 256 |
|
265 * elements per band, our shader will still work fine, but if elements are |
|
266 * accessed with an index >= the size of the LUT, then the shader will simply |
|
267 * produce undefined values. Typically the user would provide an offset |
|
268 * value that would prevent this from happening, but it's worth pointing out |
|
269 * this fact because the software LookupOp implementation would usually |
|
270 * throw an ArrayIndexOutOfBoundsException in this scenario (although it is |
|
271 * not something demanded by the spec). |
|
272 * |
|
273 * The LookupOp spec says that the operation is performed regardless of |
|
274 * whether the source data is premultiplied or non-premultiplied. This is |
|
275 * a problem for the OpenGL pipeline in that a non-premultiplied |
|
276 * BufferedImage will have already been converted into premultiplied |
|
277 * when uploaded to an OpenGL texture. Therefore, we have a special mode |
|
278 * called LOOKUP_NON_PREMULT (used only for source images that were |
|
279 * originally non-premultiplied) that un-premultiplies the source color |
|
280 * prior to the lookup operation, then re-premultiplies the resulting |
|
281 * color before returning from the fragment shader. |
|
282 * |
|
283 * Note that this shader source code includes some "holes" marked by "%s". |
|
284 * This allows us to build different shader programs (e.g. one for |
|
285 * GL_TEXTURE_2D targets, one for GL_TEXTURE_RECTANGLE_ARB targets, and so on) |
|
286 * simply by filling in these "holes" with a call to sprintf(). See the |
|
287 * MTLBufImgOps_CreateLookupProgram() method for more details. |
|
288 */ |
|
289 static const char *lookupShaderSource = |
|
290 // source image (bound to texture unit 0) |
|
291 "uniform sampler%s baseImage;" |
|
292 // lookup table (bound to texture unit 1) |
|
293 "uniform sampler2D lookupTable;" |
|
294 // offset subtracted from source index prior to lookup step |
|
295 "uniform vec4 offset;" |
|
296 "" |
|
297 "void main(void)" |
|
298 "{" |
|
299 " vec4 srcColor = texture%s(baseImage, gl_TexCoord[0].st);" |
|
300 // (placeholder for un-premult code) |
|
301 " %s" |
|
302 // subtract offset from original index |
|
303 " vec4 srcIndex = srcColor - offset;" |
|
304 // use source value as input to lookup table (note that |
|
305 // "v" texcoords are hardcoded to hit texel centers of |
|
306 // each row/band in texture) |
|
307 " vec4 result;" |
|
308 " result.r = texture2D(lookupTable, vec2(srcIndex.r, 0.125)).r;" |
|
309 " result.g = texture2D(lookupTable, vec2(srcIndex.g, 0.375)).r;" |
|
310 " result.b = texture2D(lookupTable, vec2(srcIndex.b, 0.625)).r;" |
|
311 // (placeholder for alpha store code) |
|
312 " %s" |
|
313 // (placeholder for re-premult code) |
|
314 " %s" |
|
315 // modulate with gl_Color in order to apply extra alpha |
|
316 " gl_FragColor = result * gl_Color;" |
|
317 "}"; |
|
318 |
|
319 /** |
|
320 * Flags that can be bitwise-or'ed together to control how the shader |
|
321 * source code is generated. |
|
322 */ |
|
323 #define LOOKUP_RECT (1 << 0) |
|
324 #define LOOKUP_USE_SRC_ALPHA (1 << 1) |
|
325 #define LOOKUP_NON_PREMULT (1 << 2) |
|
326 |
|
327 /** |
|
328 * The handles to the LookupOp fragment program objects. The index to |
|
329 * the array should be a bitwise-or'ing of the LOOKUP_* flags defined |
|
330 * above. Note that most applications will likely need to initialize one |
|
331 * or two of these elements, so the array is usually sparsely populated. |
|
332 */ |
|
333 static GLhandleARB lookupPrograms[8]; |
|
334 |
|
335 /** |
|
336 * The handle to the lookup table texture object used by the shader. |
|
337 */ |
|
338 static GLuint lutTextureID = 0; |
|
339 |
|
340 /** |
|
341 * Compiles and links the LookupOp shader program. If successful, this |
|
342 * function returns a handle to the newly created shader program; otherwise |
|
343 * returns 0. |
|
344 */ |
|
345 static GLhandleARB |
|
346 MTLBufImgOps_CreateLookupProgram(jint flags) |
|
347 { |
|
348 //TODO |
|
349 |
|
350 return NULL; |
|
351 } |
|
352 |
|
353 void |
|
354 MTLBufImgOps_EnableLookupOp(MTLContext *mtlc, jlong pSrcOps, |
|
355 jboolean nonPremult, jboolean shortData, |
|
356 jint numBands, jint bandLength, jint offset, |
|
357 void *tableValues) |
|
358 { |
|
359 //TODO |
|
360 } |
|
361 |
|
362 void |
|
363 MTLBufImgOps_DisableLookupOp(MTLContext *mtlc) |
|
364 { |
|
365 //TODO |
|
366 J2dTraceLn(J2D_TRACE_INFO, "MTLBufImgOps_DisableLookupOp"); |
|
367 } |
|
368 |
|
369 #endif /* !HEADLESS */ |