1/*
2 * Copyright (c) 2005, 2012, 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 <stdlib.h>
29
30#include "sun_java2d_pipe_BufferedOpCodes.h"
31
32#include "jlong.h"
33#include "OGLBlitLoops.h"
34#include "OGLBufImgOps.h"
35#include "OGLContext.h"
36#include "OGLMaskBlit.h"
37#include "OGLMaskFill.h"
38#include "OGLPaints.h"
39#include "OGLRenderQueue.h"
40#include "OGLRenderer.h"
41#include "OGLSurfaceData.h"
42#include "OGLTextRenderer.h"
43#include "OGLVertexCache.h"
44
45/**
46 * Used to track whether we are in a series of a simple primitive operations
47 * or texturing operations.  This variable should be controlled only via
48 * the INIT/CHECK/RESET_PREVIOUS_OP() macros.  See the
49 * OGLRenderQueue_CheckPreviousOp() method below for more information.
50 */
51jint previousOp;
52
53/**
54 * References to the "current" context and destination surface.
55 */
56static OGLContext *oglc = NULL;
57static OGLSDOps *dstOps = NULL;
58
59/**
60 * The following methods are implemented in the windowing system (i.e. GLX
61 * and WGL) source files.
62 */
63extern OGLContext *OGLSD_SetScratchSurface(JNIEnv *env, jlong pConfigInfo);
64extern void OGLGC_DestroyOGLGraphicsConfig(jlong pConfigInfo);
65extern void OGLSD_SwapBuffers(JNIEnv *env, jlong window);
66extern void OGLSD_Flush(JNIEnv *env);
67
68JNIEXPORT void JNICALL
69Java_sun_java2d_opengl_OGLRenderQueue_flushBuffer
70    (JNIEnv *env, jobject oglrq,
71     jlong buf, jint limit)
72{
73    jboolean sync = JNI_FALSE;
74    unsigned char *b, *end;
75
76    J2dTraceLn1(J2D_TRACE_INFO,
77                "OGLRenderQueue_flushBuffer: limit=%d", limit);
78
79    b = (unsigned char *)jlong_to_ptr(buf);
80    if (b == NULL) {
81        J2dRlsTraceLn(J2D_TRACE_ERROR,
82            "OGLRenderQueue_flushBuffer: cannot get direct buffer address");
83        return;
84    }
85
86    INIT_PREVIOUS_OP();
87    end = b + limit;
88
89    while (b < end) {
90        jint opcode = NEXT_INT(b);
91
92        J2dTraceLn2(J2D_TRACE_VERBOSE,
93                    "OGLRenderQueue_flushBuffer: opcode=%d, rem=%d",
94                    opcode, (end-b));
95
96        switch (opcode) {
97
98        // draw ops
99        case sun_java2d_pipe_BufferedOpCodes_DRAW_LINE:
100            {
101                jint x1 = NEXT_INT(b);
102                jint y1 = NEXT_INT(b);
103                jint x2 = NEXT_INT(b);
104                jint y2 = NEXT_INT(b);
105                OGLRenderer_DrawLine(oglc, x1, y1, x2, y2);
106            }
107            break;
108        case sun_java2d_pipe_BufferedOpCodes_DRAW_RECT:
109            {
110                jint x = NEXT_INT(b);
111                jint y = NEXT_INT(b);
112                jint w = NEXT_INT(b);
113                jint h = NEXT_INT(b);
114                OGLRenderer_DrawRect(oglc, x, y, w, h);
115            }
116            break;
117        case sun_java2d_pipe_BufferedOpCodes_DRAW_POLY:
118            {
119                jint nPoints      = NEXT_INT(b);
120                jboolean isClosed = NEXT_BOOLEAN(b);
121                jint transX       = NEXT_INT(b);
122                jint transY       = NEXT_INT(b);
123                jint *xPoints = (jint *)b;
124                jint *yPoints = ((jint *)b) + nPoints;
125                OGLRenderer_DrawPoly(oglc, nPoints, isClosed,
126                                     transX, transY,
127                                     xPoints, yPoints);
128                SKIP_BYTES(b, nPoints * BYTES_PER_POLY_POINT);
129            }
130            break;
131        case sun_java2d_pipe_BufferedOpCodes_DRAW_PIXEL:
132            {
133                jint x = NEXT_INT(b);
134                jint y = NEXT_INT(b);
135                // Note that we could use GL_POINTS here, but the common
136                // use case for DRAW_PIXEL is when rendering a Path2D,
137                // which will consist of a mix of DRAW_PIXEL and DRAW_LINE
138                // calls.  So to improve batching we use GL_LINES here,
139                // even though it requires an extra vertex per pixel.
140                CONTINUE_IF_NULL(oglc);
141                CHECK_PREVIOUS_OP(GL_LINES);
142                j2d_glVertex2i(x, y);
143                j2d_glVertex2i(x+1, y+1);
144            }
145            break;
146        case sun_java2d_pipe_BufferedOpCodes_DRAW_SCANLINES:
147            {
148                jint count = NEXT_INT(b);
149                OGLRenderer_DrawScanlines(oglc, count, (jint *)b);
150                SKIP_BYTES(b, count * BYTES_PER_SCANLINE);
151            }
152            break;
153        case sun_java2d_pipe_BufferedOpCodes_DRAW_PARALLELOGRAM:
154            {
155                jfloat x11 = NEXT_FLOAT(b);
156                jfloat y11 = NEXT_FLOAT(b);
157                jfloat dx21 = NEXT_FLOAT(b);
158                jfloat dy21 = NEXT_FLOAT(b);
159                jfloat dx12 = NEXT_FLOAT(b);
160                jfloat dy12 = NEXT_FLOAT(b);
161                jfloat lwr21 = NEXT_FLOAT(b);
162                jfloat lwr12 = NEXT_FLOAT(b);
163                OGLRenderer_DrawParallelogram(oglc,
164                                              x11, y11,
165                                              dx21, dy21,
166                                              dx12, dy12,
167                                              lwr21, lwr12);
168            }
169            break;
170        case sun_java2d_pipe_BufferedOpCodes_DRAW_AAPARALLELOGRAM:
171            {
172                jfloat x11 = NEXT_FLOAT(b);
173                jfloat y11 = NEXT_FLOAT(b);
174                jfloat dx21 = NEXT_FLOAT(b);
175                jfloat dy21 = NEXT_FLOAT(b);
176                jfloat dx12 = NEXT_FLOAT(b);
177                jfloat dy12 = NEXT_FLOAT(b);
178                jfloat lwr21 = NEXT_FLOAT(b);
179                jfloat lwr12 = NEXT_FLOAT(b);
180                OGLRenderer_DrawAAParallelogram(oglc, dstOps,
181                                                x11, y11,
182                                                dx21, dy21,
183                                                dx12, dy12,
184                                                lwr21, lwr12);
185            }
186            break;
187
188        // fill ops
189        case sun_java2d_pipe_BufferedOpCodes_FILL_RECT:
190            {
191                jint x = NEXT_INT(b);
192                jint y = NEXT_INT(b);
193                jint w = NEXT_INT(b);
194                jint h = NEXT_INT(b);
195                OGLRenderer_FillRect(oglc, x, y, w, h);
196            }
197            break;
198        case sun_java2d_pipe_BufferedOpCodes_FILL_SPANS:
199            {
200                jint count = NEXT_INT(b);
201                OGLRenderer_FillSpans(oglc, count, (jint *)b);
202                SKIP_BYTES(b, count * BYTES_PER_SPAN);
203            }
204            break;
205        case sun_java2d_pipe_BufferedOpCodes_FILL_PARALLELOGRAM:
206            {
207                jfloat x11 = NEXT_FLOAT(b);
208                jfloat y11 = NEXT_FLOAT(b);
209                jfloat dx21 = NEXT_FLOAT(b);
210                jfloat dy21 = NEXT_FLOAT(b);
211                jfloat dx12 = NEXT_FLOAT(b);
212                jfloat dy12 = NEXT_FLOAT(b);
213                OGLRenderer_FillParallelogram(oglc,
214                                              x11, y11,
215                                              dx21, dy21,
216                                              dx12, dy12);
217            }
218            break;
219        case sun_java2d_pipe_BufferedOpCodes_FILL_AAPARALLELOGRAM:
220            {
221                jfloat x11 = NEXT_FLOAT(b);
222                jfloat y11 = NEXT_FLOAT(b);
223                jfloat dx21 = NEXT_FLOAT(b);
224                jfloat dy21 = NEXT_FLOAT(b);
225                jfloat dx12 = NEXT_FLOAT(b);
226                jfloat dy12 = NEXT_FLOAT(b);
227                OGLRenderer_FillAAParallelogram(oglc, dstOps,
228                                                x11, y11,
229                                                dx21, dy21,
230                                                dx12, dy12);
231            }
232            break;
233
234        // text-related ops
235        case sun_java2d_pipe_BufferedOpCodes_DRAW_GLYPH_LIST:
236            {
237                jint numGlyphs        = NEXT_INT(b);
238                jint packedParams     = NEXT_INT(b);
239                jfloat glyphListOrigX = NEXT_FLOAT(b);
240                jfloat glyphListOrigY = NEXT_FLOAT(b);
241                jboolean usePositions = EXTRACT_BOOLEAN(packedParams,
242                                                        OFFSET_POSITIONS);
243                jboolean subPixPos    = EXTRACT_BOOLEAN(packedParams,
244                                                        OFFSET_SUBPIXPOS);
245                jboolean rgbOrder     = EXTRACT_BOOLEAN(packedParams,
246                                                        OFFSET_RGBORDER);
247                jint lcdContrast      = EXTRACT_BYTE(packedParams,
248                                                     OFFSET_CONTRAST);
249                unsigned char *images = b;
250                unsigned char *positions;
251                jint bytesPerGlyph;
252                if (usePositions) {
253                    positions = (b + numGlyphs * BYTES_PER_GLYPH_IMAGE);
254                    bytesPerGlyph = BYTES_PER_POSITIONED_GLYPH;
255                } else {
256                    positions = NULL;
257                    bytesPerGlyph = BYTES_PER_GLYPH_IMAGE;
258                }
259                OGLTR_DrawGlyphList(env, oglc, dstOps,
260                                    numGlyphs, usePositions,
261                                    subPixPos, rgbOrder, lcdContrast,
262                                    glyphListOrigX, glyphListOrigY,
263                                    images, positions);
264                SKIP_BYTES(b, numGlyphs * bytesPerGlyph);
265            }
266            break;
267
268        // copy-related ops
269        case sun_java2d_pipe_BufferedOpCodes_COPY_AREA:
270            {
271                jint x  = NEXT_INT(b);
272                jint y  = NEXT_INT(b);
273                jint w  = NEXT_INT(b);
274                jint h  = NEXT_INT(b);
275                jint dx = NEXT_INT(b);
276                jint dy = NEXT_INT(b);
277                OGLBlitLoops_CopyArea(env, oglc, dstOps,
278                                      x, y, w, h, dx, dy);
279            }
280            break;
281        case sun_java2d_pipe_BufferedOpCodes_BLIT:
282            {
283                jint packedParams = NEXT_INT(b);
284                jint sx1          = NEXT_INT(b);
285                jint sy1          = NEXT_INT(b);
286                jint sx2          = NEXT_INT(b);
287                jint sy2          = NEXT_INT(b);
288                jdouble dx1       = NEXT_DOUBLE(b);
289                jdouble dy1       = NEXT_DOUBLE(b);
290                jdouble dx2       = NEXT_DOUBLE(b);
291                jdouble dy2       = NEXT_DOUBLE(b);
292                jlong pSrc        = NEXT_LONG(b);
293                jlong pDst        = NEXT_LONG(b);
294                jint hint         = EXTRACT_BYTE(packedParams, OFFSET_HINT);
295                jboolean texture  = EXTRACT_BOOLEAN(packedParams,
296                                                    OFFSET_TEXTURE);
297                jboolean rtt      = EXTRACT_BOOLEAN(packedParams,
298                                                    OFFSET_RTT);
299                jboolean xform    = EXTRACT_BOOLEAN(packedParams,
300                                                    OFFSET_XFORM);
301                jboolean isoblit  = EXTRACT_BOOLEAN(packedParams,
302                                                    OFFSET_ISOBLIT);
303                if (isoblit) {
304                    OGLBlitLoops_IsoBlit(env, oglc, pSrc, pDst,
305                                         xform, hint, texture, rtt,
306                                         sx1, sy1, sx2, sy2,
307                                         dx1, dy1, dx2, dy2);
308                } else {
309                    jint srctype = EXTRACT_BYTE(packedParams, OFFSET_SRCTYPE);
310                    OGLBlitLoops_Blit(env, oglc, pSrc, pDst,
311                                      xform, hint, srctype, texture,
312                                      sx1, sy1, sx2, sy2,
313                                      dx1, dy1, dx2, dy2);
314                }
315            }
316            break;
317        case sun_java2d_pipe_BufferedOpCodes_SURFACE_TO_SW_BLIT:
318            {
319                jint sx      = NEXT_INT(b);
320                jint sy      = NEXT_INT(b);
321                jint dx      = NEXT_INT(b);
322                jint dy      = NEXT_INT(b);
323                jint w       = NEXT_INT(b);
324                jint h       = NEXT_INT(b);
325                jint dsttype = NEXT_INT(b);
326                jlong pSrc   = NEXT_LONG(b);
327                jlong pDst   = NEXT_LONG(b);
328                OGLBlitLoops_SurfaceToSwBlit(env, oglc,
329                                             pSrc, pDst, dsttype,
330                                             sx, sy, dx, dy, w, h);
331            }
332            break;
333        case sun_java2d_pipe_BufferedOpCodes_MASK_FILL:
334            {
335                jint x        = NEXT_INT(b);
336                jint y        = NEXT_INT(b);
337                jint w        = NEXT_INT(b);
338                jint h        = NEXT_INT(b);
339                jint maskoff  = NEXT_INT(b);
340                jint maskscan = NEXT_INT(b);
341                jint masklen  = NEXT_INT(b);
342                unsigned char *pMask = (masklen > 0) ? b : NULL;
343                OGLMaskFill_MaskFill(oglc, x, y, w, h,
344                                     maskoff, maskscan, masklen, pMask);
345                SKIP_BYTES(b, masklen);
346            }
347            break;
348        case sun_java2d_pipe_BufferedOpCodes_MASK_BLIT:
349            {
350                jint dstx     = NEXT_INT(b);
351                jint dsty     = NEXT_INT(b);
352                jint width    = NEXT_INT(b);
353                jint height   = NEXT_INT(b);
354                jint masklen  = width * height * sizeof(jint);
355                OGLMaskBlit_MaskBlit(env, oglc,
356                                     dstx, dsty, width, height, b);
357                SKIP_BYTES(b, masklen);
358            }
359            break;
360
361        // state-related ops
362        case sun_java2d_pipe_BufferedOpCodes_SET_RECT_CLIP:
363            {
364                jint x1 = NEXT_INT(b);
365                jint y1 = NEXT_INT(b);
366                jint x2 = NEXT_INT(b);
367                jint y2 = NEXT_INT(b);
368                OGLContext_SetRectClip(oglc, dstOps, x1, y1, x2, y2);
369            }
370            break;
371        case sun_java2d_pipe_BufferedOpCodes_BEGIN_SHAPE_CLIP:
372            {
373                OGLContext_BeginShapeClip(oglc);
374            }
375            break;
376        case sun_java2d_pipe_BufferedOpCodes_SET_SHAPE_CLIP_SPANS:
377            {
378                jint count = NEXT_INT(b);
379                OGLRenderer_FillSpans(oglc, count, (jint *)b);
380                SKIP_BYTES(b, count * BYTES_PER_SPAN);
381            }
382            break;
383        case sun_java2d_pipe_BufferedOpCodes_END_SHAPE_CLIP:
384            {
385                OGLContext_EndShapeClip(oglc, dstOps);
386            }
387            break;
388        case sun_java2d_pipe_BufferedOpCodes_RESET_CLIP:
389            {
390                OGLContext_ResetClip(oglc);
391            }
392            break;
393        case sun_java2d_pipe_BufferedOpCodes_SET_ALPHA_COMPOSITE:
394            {
395                jint rule         = NEXT_INT(b);
396                jfloat extraAlpha = NEXT_FLOAT(b);
397                jint flags        = NEXT_INT(b);
398                OGLContext_SetAlphaComposite(oglc, rule, extraAlpha, flags);
399            }
400            break;
401        case sun_java2d_pipe_BufferedOpCodes_SET_XOR_COMPOSITE:
402            {
403                jint xorPixel = NEXT_INT(b);
404                OGLContext_SetXorComposite(oglc, xorPixel);
405            }
406            break;
407        case sun_java2d_pipe_BufferedOpCodes_RESET_COMPOSITE:
408            {
409                OGLContext_ResetComposite(oglc);
410            }
411            break;
412        case sun_java2d_pipe_BufferedOpCodes_SET_TRANSFORM:
413            {
414                jdouble m00 = NEXT_DOUBLE(b);
415                jdouble m10 = NEXT_DOUBLE(b);
416                jdouble m01 = NEXT_DOUBLE(b);
417                jdouble m11 = NEXT_DOUBLE(b);
418                jdouble m02 = NEXT_DOUBLE(b);
419                jdouble m12 = NEXT_DOUBLE(b);
420                OGLContext_SetTransform(oglc, m00, m10, m01, m11, m02, m12);
421            }
422            break;
423        case sun_java2d_pipe_BufferedOpCodes_RESET_TRANSFORM:
424            {
425                OGLContext_ResetTransform(oglc);
426            }
427            break;
428
429        // context-related ops
430        case sun_java2d_pipe_BufferedOpCodes_SET_SURFACES:
431            {
432                jlong pSrc = NEXT_LONG(b);
433                jlong pDst = NEXT_LONG(b);
434                if (oglc != NULL) {
435                    RESET_PREVIOUS_OP();
436                }
437                oglc = OGLContext_SetSurfaces(env, pSrc, pDst);
438                dstOps = (OGLSDOps *)jlong_to_ptr(pDst);
439            }
440            break;
441        case sun_java2d_pipe_BufferedOpCodes_SET_SCRATCH_SURFACE:
442            {
443                jlong pConfigInfo = NEXT_LONG(b);
444                if (oglc != NULL) {
445                    RESET_PREVIOUS_OP();
446                }
447                oglc = OGLSD_SetScratchSurface(env, pConfigInfo);
448                dstOps = NULL;
449            }
450            break;
451        case sun_java2d_pipe_BufferedOpCodes_FLUSH_SURFACE:
452            {
453                jlong pData = NEXT_LONG(b);
454                OGLSDOps *oglsdo = (OGLSDOps *)jlong_to_ptr(pData);
455                if (oglsdo != NULL) {
456                    CONTINUE_IF_NULL(oglc);
457                    RESET_PREVIOUS_OP();
458                    OGLSD_Delete(env, oglsdo);
459                }
460            }
461            break;
462        case sun_java2d_pipe_BufferedOpCodes_DISPOSE_SURFACE:
463            {
464                jlong pData = NEXT_LONG(b);
465                OGLSDOps *oglsdo = (OGLSDOps *)jlong_to_ptr(pData);
466                if (oglsdo != NULL) {
467                    CONTINUE_IF_NULL(oglc);
468                    RESET_PREVIOUS_OP();
469                    OGLSD_Delete(env, oglsdo);
470                    if (oglsdo->privOps != NULL) {
471                        free(oglsdo->privOps);
472                    }
473                }
474            }
475            break;
476        case sun_java2d_pipe_BufferedOpCodes_DISPOSE_CONFIG:
477            {
478                jlong pConfigInfo = NEXT_LONG(b);
479                CONTINUE_IF_NULL(oglc);
480                RESET_PREVIOUS_OP();
481                OGLGC_DestroyOGLGraphicsConfig(pConfigInfo);
482
483                // the previous method will call glX/wglMakeCurrent(None),
484                // so we should nullify the current oglc and dstOps to avoid
485                // calling glFlush() (or similar) while no context is current
486                oglc = NULL;
487                dstOps = NULL;
488            }
489            break;
490        case sun_java2d_pipe_BufferedOpCodes_INVALIDATE_CONTEXT:
491            {
492                // flush just in case there are any pending operations in
493                // the hardware pipe
494                if (oglc != NULL) {
495                    RESET_PREVIOUS_OP();
496                    j2d_glFlush();
497                }
498
499                // invalidate the references to the current context and
500                // destination surface that are maintained at the native level
501                oglc = NULL;
502                dstOps = NULL;
503            }
504            break;
505        case sun_java2d_pipe_BufferedOpCodes_SAVE_STATE:
506            {
507                j2d_glPushAttrib(GL_ALL_ATTRIB_BITS);
508                j2d_glPushClientAttrib(GL_CLIENT_ALL_ATTRIB_BITS);
509                j2d_glMatrixMode(GL_MODELVIEW);
510                j2d_glPushMatrix();
511                j2d_glMatrixMode(GL_PROJECTION);
512                j2d_glPushMatrix();
513                j2d_glMatrixMode(GL_TEXTURE);
514                j2d_glPushMatrix();
515            }
516            break;
517
518        case sun_java2d_pipe_BufferedOpCodes_RESTORE_STATE:
519            {
520                j2d_glPopAttrib();
521                j2d_glPopClientAttrib();
522                j2d_glMatrixMode(GL_MODELVIEW);
523                j2d_glPopMatrix();
524                j2d_glMatrixMode(GL_PROJECTION);
525                j2d_glPopMatrix();
526                j2d_glMatrixMode(GL_TEXTURE);
527                j2d_glPopMatrix();
528            }
529            break;
530        case sun_java2d_pipe_BufferedOpCodes_SYNC:
531            {
532                sync = JNI_TRUE;
533            }
534            break;
535
536        // multibuffering ops
537        case sun_java2d_pipe_BufferedOpCodes_SWAP_BUFFERS:
538            {
539                jlong window = NEXT_LONG(b);
540                if (oglc != NULL) {
541                    RESET_PREVIOUS_OP();
542                }
543                OGLSD_SwapBuffers(env, window);
544            }
545            break;
546
547        // special no-op (mainly used for achieving 8-byte alignment)
548        case sun_java2d_pipe_BufferedOpCodes_NOOP:
549            break;
550
551        // paint-related ops
552        case sun_java2d_pipe_BufferedOpCodes_RESET_PAINT:
553            {
554                OGLPaints_ResetPaint(oglc);
555            }
556            break;
557        case sun_java2d_pipe_BufferedOpCodes_SET_COLOR:
558            {
559                jint pixel = NEXT_INT(b);
560                OGLPaints_SetColor(oglc, pixel);
561            }
562            break;
563        case sun_java2d_pipe_BufferedOpCodes_SET_GRADIENT_PAINT:
564            {
565                jboolean useMask= NEXT_BOOLEAN(b);
566                jboolean cyclic = NEXT_BOOLEAN(b);
567                jdouble p0      = NEXT_DOUBLE(b);
568                jdouble p1      = NEXT_DOUBLE(b);
569                jdouble p3      = NEXT_DOUBLE(b);
570                jint pixel1     = NEXT_INT(b);
571                jint pixel2     = NEXT_INT(b);
572                OGLPaints_SetGradientPaint(oglc, useMask, cyclic,
573                                           p0, p1, p3,
574                                           pixel1, pixel2);
575            }
576            break;
577        case sun_java2d_pipe_BufferedOpCodes_SET_LINEAR_GRADIENT_PAINT:
578            {
579                jboolean useMask = NEXT_BOOLEAN(b);
580                jboolean linear  = NEXT_BOOLEAN(b);
581                jint cycleMethod = NEXT_INT(b);
582                jint numStops    = NEXT_INT(b);
583                jfloat p0        = NEXT_FLOAT(b);
584                jfloat p1        = NEXT_FLOAT(b);
585                jfloat p3        = NEXT_FLOAT(b);
586                void *fractions, *pixels;
587                fractions = b; SKIP_BYTES(b, numStops * sizeof(jfloat));
588                pixels    = b; SKIP_BYTES(b, numStops * sizeof(jint));
589                OGLPaints_SetLinearGradientPaint(oglc, dstOps,
590                                                 useMask, linear,
591                                                 cycleMethod, numStops,
592                                                 p0, p1, p3,
593                                                 fractions, pixels);
594            }
595            break;
596        case sun_java2d_pipe_BufferedOpCodes_SET_RADIAL_GRADIENT_PAINT:
597            {
598                jboolean useMask = NEXT_BOOLEAN(b);
599                jboolean linear  = NEXT_BOOLEAN(b);
600                jint numStops    = NEXT_INT(b);
601                jint cycleMethod = NEXT_INT(b);
602                jfloat m00       = NEXT_FLOAT(b);
603                jfloat m01       = NEXT_FLOAT(b);
604                jfloat m02       = NEXT_FLOAT(b);
605                jfloat m10       = NEXT_FLOAT(b);
606                jfloat m11       = NEXT_FLOAT(b);
607                jfloat m12       = NEXT_FLOAT(b);
608                jfloat focusX    = NEXT_FLOAT(b);
609                void *fractions, *pixels;
610                fractions = b; SKIP_BYTES(b, numStops * sizeof(jfloat));
611                pixels    = b; SKIP_BYTES(b, numStops * sizeof(jint));
612                OGLPaints_SetRadialGradientPaint(oglc, dstOps,
613                                                 useMask, linear,
614                                                 cycleMethod, numStops,
615                                                 m00, m01, m02,
616                                                 m10, m11, m12,
617                                                 focusX,
618                                                 fractions, pixels);
619            }
620            break;
621        case sun_java2d_pipe_BufferedOpCodes_SET_TEXTURE_PAINT:
622            {
623                jboolean useMask= NEXT_BOOLEAN(b);
624                jboolean filter = NEXT_BOOLEAN(b);
625                jlong pSrc      = NEXT_LONG(b);
626                jdouble xp0     = NEXT_DOUBLE(b);
627                jdouble xp1     = NEXT_DOUBLE(b);
628                jdouble xp3     = NEXT_DOUBLE(b);
629                jdouble yp0     = NEXT_DOUBLE(b);
630                jdouble yp1     = NEXT_DOUBLE(b);
631                jdouble yp3     = NEXT_DOUBLE(b);
632                OGLPaints_SetTexturePaint(oglc, useMask, pSrc, filter,
633                                          xp0, xp1, xp3,
634                                          yp0, yp1, yp3);
635            }
636            break;
637
638        // BufferedImageOp-related ops
639        case sun_java2d_pipe_BufferedOpCodes_ENABLE_CONVOLVE_OP:
640            {
641                jlong pSrc        = NEXT_LONG(b);
642                jboolean edgeZero = NEXT_BOOLEAN(b);
643                jint kernelWidth  = NEXT_INT(b);
644                jint kernelHeight = NEXT_INT(b);
645                OGLBufImgOps_EnableConvolveOp(oglc, pSrc, edgeZero,
646                                              kernelWidth, kernelHeight, b);
647                SKIP_BYTES(b, kernelWidth * kernelHeight * sizeof(jfloat));
648            }
649            break;
650        case sun_java2d_pipe_BufferedOpCodes_DISABLE_CONVOLVE_OP:
651            {
652                OGLBufImgOps_DisableConvolveOp(oglc);
653            }
654            break;
655        case sun_java2d_pipe_BufferedOpCodes_ENABLE_RESCALE_OP:
656            {
657                jlong pSrc          = NEXT_LONG(b);
658                jboolean nonPremult = NEXT_BOOLEAN(b);
659                jint numFactors     = 4;
660                unsigned char *scaleFactors = b;
661                unsigned char *offsets = (b + numFactors * sizeof(jfloat));
662                OGLBufImgOps_EnableRescaleOp(oglc, pSrc, nonPremult,
663                                             scaleFactors, offsets);
664                SKIP_BYTES(b, numFactors * sizeof(jfloat) * 2);
665            }
666            break;
667        case sun_java2d_pipe_BufferedOpCodes_DISABLE_RESCALE_OP:
668            {
669                OGLBufImgOps_DisableRescaleOp(oglc);
670            }
671            break;
672        case sun_java2d_pipe_BufferedOpCodes_ENABLE_LOOKUP_OP:
673            {
674                jlong pSrc          = NEXT_LONG(b);
675                jboolean nonPremult = NEXT_BOOLEAN(b);
676                jboolean shortData  = NEXT_BOOLEAN(b);
677                jint numBands       = NEXT_INT(b);
678                jint bandLength     = NEXT_INT(b);
679                jint offset         = NEXT_INT(b);
680                jint bytesPerElem = shortData ? sizeof(jshort):sizeof(jbyte);
681                void *tableValues = b;
682                OGLBufImgOps_EnableLookupOp(oglc, pSrc, nonPremult, shortData,
683                                            numBands, bandLength, offset,
684                                            tableValues);
685                SKIP_BYTES(b, numBands * bandLength * bytesPerElem);
686            }
687            break;
688        case sun_java2d_pipe_BufferedOpCodes_DISABLE_LOOKUP_OP:
689            {
690                OGLBufImgOps_DisableLookupOp(oglc);
691            }
692            break;
693
694        default:
695            J2dRlsTraceLn1(J2D_TRACE_ERROR,
696                "OGLRenderQueue_flushBuffer: invalid opcode=%d", opcode);
697            if (oglc != NULL) {
698                RESET_PREVIOUS_OP();
699            }
700            return;
701        }
702    }
703
704    if (oglc != NULL) {
705        RESET_PREVIOUS_OP();
706        if (sync) {
707            j2d_glFinish();
708        } else {
709            j2d_glFlush();
710        }
711        OGLSD_Flush(env);
712    }
713}
714
715/**
716 * Returns a pointer to the "current" context, as set by the last SET_SURFACES
717 * or SET_SCRATCH_SURFACE operation.
718 */
719OGLContext *
720OGLRenderQueue_GetCurrentContext()
721{
722    return oglc;
723}
724
725/**
726 * Returns a pointer to the "current" destination surface, as set by the last
727 * SET_SURFACES operation.
728 */
729OGLSDOps *
730OGLRenderQueue_GetCurrentDestination()
731{
732    return dstOps;
733}
734
735/**
736 * Used to track whether we are within a series of simple primitive operations
737 * or texturing operations.  The op parameter determines the nature of the
738 * operation that is to follow.  Valid values for this op parameter are:
739 *
740 *     GL_QUADS
741 *     GL_LINES
742 *     GL_LINE_LOOP
743 *     GL_LINE_STRIP
744 *     (basically any of the valid parameters for glBegin())
745 *
746 *     GL_TEXTURE_2D
747 *     GL_TEXTURE_RECTANGLE_ARB
748 *
749 *     OGL_STATE_RESET
750 *     OGL_STATE_CHANGE
751 *     OGL_STATE_MASK_OP
752 *     OGL_STATE_GLYPH_OP
753 *
754 * Note that the above constants are guaranteed to be unique values.  The
755 * last few are defined to be negative values to differentiate them from
756 * the core GL* constants, which are defined to be non-negative.
757 *
758 * For simple primitives, this method allows us to batch similar primitives
759 * within the same glBegin()/glEnd() pair.  For example, if we have 100
760 * consecutive FILL_RECT operations, we only have to call glBegin(GL_QUADS)
761 * for the first op, and then subsequent operations will consist only of
762 * glVertex*() calls, which helps improve performance.  The glEnd() call
763 * only needs to be issued before an operation that cannot happen within a
764 * glBegin()/glEnd() pair (e.g. updating the clip), or one that requires a
765 * different primitive mode (e.g. GL_LINES).
766 *
767 * For operations that involve texturing, this method helps us to avoid
768 * calling glEnable(GL_TEXTURE_2D) and glDisable(GL_TEXTURE_2D) around each
769 * operation.  For example, if we have an alternating series of ISO_BLIT
770 * and MASK_BLIT operations (both of which involve texturing), we need
771 * only to call glEnable(GL_TEXTURE_2D) before the first ISO_BLIT operation.
772 * The glDisable(GL_TEXTURE_2D) call only needs to be issued before an
773 * operation that cannot (or should not) happen while texturing is enabled
774 * (e.g. a context change, or a simple primitive operation like GL_QUADS).
775 */
776void
777OGLRenderQueue_CheckPreviousOp(jint op)
778{
779    if (previousOp == op) {
780        // The op is the same as last time, so we can return immediately.
781        return;
782    }
783
784    J2dTraceLn1(J2D_TRACE_VERBOSE,
785                "OGLRenderQueue_CheckPreviousOp: new op=%d", op);
786
787    switch (previousOp) {
788    case GL_TEXTURE_2D:
789    case GL_TEXTURE_RECTANGLE_ARB:
790        if (op == OGL_STATE_CHANGE) {
791            // Optimization: Certain state changes (those marked as
792            // OGL_STATE_CHANGE) are allowed while texturing is enabled.
793            // In this case, we can allow previousOp to remain as it is and
794            // then return early.
795            return;
796        } else {
797            // Otherwise, op must be a primitive operation, or a reset, so
798            // we will disable texturing.
799            j2d_glDisable(previousOp);
800            // This next step of binding to zero should not be strictly
801            // necessary, but on some older Nvidia boards (e.g. GeForce 2)
802            // problems will arise if GL_TEXTURE_2D and
803            // GL_TEXTURE_RECTANGLE_ARB are bound at the same time, so we
804            // will do this just to be safe.
805            j2d_glBindTexture(previousOp, 0);
806        }
807        break;
808    case OGL_STATE_MASK_OP:
809        OGLVertexCache_DisableMaskCache(oglc);
810        break;
811    case OGL_STATE_GLYPH_OP:
812        OGLTR_DisableGlyphVertexCache(oglc);
813        break;
814    case OGL_STATE_PGRAM_OP:
815        OGLRenderer_DisableAAParallelogramProgram();
816        break;
817    case OGL_STATE_RESET:
818    case OGL_STATE_CHANGE:
819        // No-op
820        break;
821    default:
822        // In this case, op must be one of:
823        //     - the start of a different primitive type (glBegin())
824        //     - a texturing operation
825        //     - a state change (not allowed within glBegin()/glEnd() pairs)
826        //     - a reset
827        // so we must first complete the previous primitive operation.
828        j2d_glEnd();
829        break;
830    }
831
832    switch (op) {
833    case GL_TEXTURE_2D:
834    case GL_TEXTURE_RECTANGLE_ARB:
835        // We are starting a texturing operation, so enable texturing.
836        j2d_glEnable(op);
837        break;
838    case OGL_STATE_MASK_OP:
839        OGLVertexCache_EnableMaskCache(oglc);
840        break;
841    case OGL_STATE_GLYPH_OP:
842        OGLTR_EnableGlyphVertexCache(oglc);
843        break;
844    case OGL_STATE_PGRAM_OP:
845        OGLRenderer_EnableAAParallelogramProgram();
846        break;
847    case OGL_STATE_RESET:
848    case OGL_STATE_CHANGE:
849        // No-op
850        break;
851    default:
852        // We are starting a primitive operation, so call glBegin() with
853        // the given primitive type.
854        j2d_glBegin(op);
855        break;
856    }
857
858    previousOp = op;
859}
860
861#endif /* !HEADLESS */
862