1/*
2 * Copyright (c) 2003, 2015, 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
26package sun.java2d.opengl;
27
28import java.awt.AlphaComposite;
29import java.awt.Composite;
30import java.awt.Transparency;
31import java.awt.geom.AffineTransform;
32import java.awt.image.AffineTransformOp;
33import java.awt.image.BufferedImage;
34import java.awt.image.BufferedImageOp;
35import java.lang.ref.WeakReference;
36import sun.java2d.SurfaceData;
37import sun.java2d.loops.Blit;
38import sun.java2d.loops.CompositeType;
39import sun.java2d.loops.GraphicsPrimitive;
40import sun.java2d.loops.GraphicsPrimitiveMgr;
41import sun.java2d.loops.ScaledBlit;
42import sun.java2d.loops.SurfaceType;
43import sun.java2d.loops.TransformBlit;
44import sun.java2d.pipe.Region;
45import sun.java2d.pipe.RenderBuffer;
46import sun.java2d.pipe.RenderQueue;
47import static sun.java2d.pipe.BufferedOpCodes.*;
48import java.lang.annotation.Native;
49
50final class OGLBlitLoops {
51
52    static void register() {
53        Blit blitIntArgbPreToSurface =
54            new OGLSwToSurfaceBlit(SurfaceType.IntArgbPre,
55                                   OGLSurfaceData.PF_INT_ARGB_PRE);
56        Blit blitIntArgbPreToTexture =
57            new OGLSwToTextureBlit(SurfaceType.IntArgbPre,
58                                   OGLSurfaceData.PF_INT_ARGB_PRE);
59        TransformBlit transformBlitIntArgbPreToSurface =
60            new OGLSwToSurfaceTransform(SurfaceType.IntArgbPre,
61                                        OGLSurfaceData.PF_INT_ARGB_PRE);
62        OGLSurfaceToSwBlit blitSurfaceToIntArgbPre =
63            new OGLSurfaceToSwBlit(SurfaceType.IntArgbPre,
64                                   OGLSurfaceData.PF_INT_ARGB_PRE);
65
66        GraphicsPrimitive[] primitives = {
67            // surface->surface ops
68            new OGLSurfaceToSurfaceBlit(),
69            new OGLSurfaceToSurfaceScale(),
70            new OGLSurfaceToSurfaceTransform(),
71
72            // render-to-texture surface->surface ops
73            new OGLRTTSurfaceToSurfaceBlit(),
74            new OGLRTTSurfaceToSurfaceScale(),
75            new OGLRTTSurfaceToSurfaceTransform(),
76
77            // surface->sw ops
78            new OGLSurfaceToSwBlit(SurfaceType.IntArgb,
79                                   OGLSurfaceData.PF_INT_ARGB),
80            blitSurfaceToIntArgbPre,
81
82            // sw->surface ops
83            blitIntArgbPreToSurface,
84            new OGLSwToSurfaceBlit(SurfaceType.IntRgb,
85                                   OGLSurfaceData.PF_INT_RGB),
86            new OGLSwToSurfaceBlit(SurfaceType.IntRgbx,
87                                   OGLSurfaceData.PF_INT_RGBX),
88            new OGLSwToSurfaceBlit(SurfaceType.IntBgr,
89                                   OGLSurfaceData.PF_INT_BGR),
90            new OGLSwToSurfaceBlit(SurfaceType.IntBgrx,
91                                   OGLSurfaceData.PF_INT_BGRX),
92            new OGLSwToSurfaceBlit(SurfaceType.ThreeByteBgr,
93                                   OGLSurfaceData.PF_3BYTE_BGR),
94            new OGLSwToSurfaceBlit(SurfaceType.Ushort565Rgb,
95                                   OGLSurfaceData.PF_USHORT_565_RGB),
96            new OGLSwToSurfaceBlit(SurfaceType.Ushort555Rgb,
97                                   OGLSurfaceData.PF_USHORT_555_RGB),
98            new OGLSwToSurfaceBlit(SurfaceType.Ushort555Rgbx,
99                                   OGLSurfaceData.PF_USHORT_555_RGBX),
100            new OGLSwToSurfaceBlit(SurfaceType.ByteGray,
101                                   OGLSurfaceData.PF_BYTE_GRAY),
102            new OGLSwToSurfaceBlit(SurfaceType.UshortGray,
103                                   OGLSurfaceData.PF_USHORT_GRAY),
104            new OGLGeneralBlit(OGLSurfaceData.OpenGLSurface,
105                               CompositeType.AnyAlpha,
106                               blitIntArgbPreToSurface),
107
108            new OGLAnyCompositeBlit(OGLSurfaceData.OpenGLSurface,
109                                    blitSurfaceToIntArgbPre,
110                                    blitSurfaceToIntArgbPre,
111                                    blitIntArgbPreToSurface),
112            new OGLAnyCompositeBlit(SurfaceType.Any,
113                                    null,
114                                    blitSurfaceToIntArgbPre,
115                                    blitIntArgbPreToSurface),
116
117            new OGLSwToSurfaceScale(SurfaceType.IntRgb,
118                                    OGLSurfaceData.PF_INT_RGB),
119            new OGLSwToSurfaceScale(SurfaceType.IntRgbx,
120                                    OGLSurfaceData.PF_INT_RGBX),
121            new OGLSwToSurfaceScale(SurfaceType.IntBgr,
122                                    OGLSurfaceData.PF_INT_BGR),
123            new OGLSwToSurfaceScale(SurfaceType.IntBgrx,
124                                    OGLSurfaceData.PF_INT_BGRX),
125            new OGLSwToSurfaceScale(SurfaceType.ThreeByteBgr,
126                                    OGLSurfaceData.PF_3BYTE_BGR),
127            new OGLSwToSurfaceScale(SurfaceType.Ushort565Rgb,
128                                    OGLSurfaceData.PF_USHORT_565_RGB),
129            new OGLSwToSurfaceScale(SurfaceType.Ushort555Rgb,
130                                    OGLSurfaceData.PF_USHORT_555_RGB),
131            new OGLSwToSurfaceScale(SurfaceType.Ushort555Rgbx,
132                                    OGLSurfaceData.PF_USHORT_555_RGBX),
133            new OGLSwToSurfaceScale(SurfaceType.ByteGray,
134                                    OGLSurfaceData.PF_BYTE_GRAY),
135            new OGLSwToSurfaceScale(SurfaceType.UshortGray,
136                                    OGLSurfaceData.PF_USHORT_GRAY),
137            new OGLSwToSurfaceScale(SurfaceType.IntArgbPre,
138                                    OGLSurfaceData.PF_INT_ARGB_PRE),
139
140            new OGLSwToSurfaceTransform(SurfaceType.IntRgb,
141                                        OGLSurfaceData.PF_INT_RGB),
142            new OGLSwToSurfaceTransform(SurfaceType.IntRgbx,
143                                        OGLSurfaceData.PF_INT_RGBX),
144            new OGLSwToSurfaceTransform(SurfaceType.IntBgr,
145                                        OGLSurfaceData.PF_INT_BGR),
146            new OGLSwToSurfaceTransform(SurfaceType.IntBgrx,
147                                        OGLSurfaceData.PF_INT_BGRX),
148            new OGLSwToSurfaceTransform(SurfaceType.ThreeByteBgr,
149                                        OGLSurfaceData.PF_3BYTE_BGR),
150            new OGLSwToSurfaceTransform(SurfaceType.Ushort565Rgb,
151                                        OGLSurfaceData.PF_USHORT_565_RGB),
152            new OGLSwToSurfaceTransform(SurfaceType.Ushort555Rgb,
153                                        OGLSurfaceData.PF_USHORT_555_RGB),
154            new OGLSwToSurfaceTransform(SurfaceType.Ushort555Rgbx,
155                                        OGLSurfaceData.PF_USHORT_555_RGBX),
156            new OGLSwToSurfaceTransform(SurfaceType.ByteGray,
157                                        OGLSurfaceData.PF_BYTE_GRAY),
158            new OGLSwToSurfaceTransform(SurfaceType.UshortGray,
159                                        OGLSurfaceData.PF_USHORT_GRAY),
160            transformBlitIntArgbPreToSurface,
161
162            new OGLGeneralTransformedBlit(transformBlitIntArgbPreToSurface),
163
164            // texture->surface ops
165            new OGLTextureToSurfaceBlit(),
166            new OGLTextureToSurfaceScale(),
167            new OGLTextureToSurfaceTransform(),
168
169            // sw->texture ops
170            blitIntArgbPreToTexture,
171            new OGLSwToTextureBlit(SurfaceType.IntRgb,
172                                   OGLSurfaceData.PF_INT_RGB),
173            new OGLSwToTextureBlit(SurfaceType.IntRgbx,
174                                   OGLSurfaceData.PF_INT_RGBX),
175            new OGLSwToTextureBlit(SurfaceType.IntBgr,
176                                   OGLSurfaceData.PF_INT_BGR),
177            new OGLSwToTextureBlit(SurfaceType.IntBgrx,
178                                   OGLSurfaceData.PF_INT_BGRX),
179            new OGLSwToTextureBlit(SurfaceType.ThreeByteBgr,
180                                   OGLSurfaceData.PF_3BYTE_BGR),
181            new OGLSwToTextureBlit(SurfaceType.Ushort565Rgb,
182                                   OGLSurfaceData.PF_USHORT_565_RGB),
183            new OGLSwToTextureBlit(SurfaceType.Ushort555Rgb,
184                                   OGLSurfaceData.PF_USHORT_555_RGB),
185            new OGLSwToTextureBlit(SurfaceType.Ushort555Rgbx,
186                                   OGLSurfaceData.PF_USHORT_555_RGBX),
187            new OGLSwToTextureBlit(SurfaceType.ByteGray,
188                                   OGLSurfaceData.PF_BYTE_GRAY),
189            new OGLSwToTextureBlit(SurfaceType.UshortGray,
190                                   OGLSurfaceData.PF_USHORT_GRAY),
191            new OGLGeneralBlit(OGLSurfaceData.OpenGLTexture,
192                               CompositeType.SrcNoEa,
193                               blitIntArgbPreToTexture),
194        };
195        GraphicsPrimitiveMgr.register(primitives);
196    }
197
198    /**
199     * The following offsets are used to pack the parameters in
200     * createPackedParams().  (They are also used at the native level when
201     * unpacking the params.)
202     */
203    @Native private static final int OFFSET_SRCTYPE = 16;
204    @Native private static final int OFFSET_HINT    =  8;
205    @Native private static final int OFFSET_TEXTURE =  3;
206    @Native private static final int OFFSET_RTT     =  2;
207    @Native private static final int OFFSET_XFORM   =  1;
208    @Native private static final int OFFSET_ISOBLIT =  0;
209
210    /**
211     * Packs the given parameters into a single int value in order to save
212     * space on the rendering queue.
213     */
214    private static int createPackedParams(boolean isoblit, boolean texture,
215                                          boolean rtt, boolean xform,
216                                          int hint, int srctype)
217    {
218        return
219            ((srctype           << OFFSET_SRCTYPE) |
220             (hint              << OFFSET_HINT   ) |
221             ((texture ? 1 : 0) << OFFSET_TEXTURE) |
222             ((rtt     ? 1 : 0) << OFFSET_RTT    ) |
223             ((xform   ? 1 : 0) << OFFSET_XFORM  ) |
224             ((isoblit ? 1 : 0) << OFFSET_ISOBLIT));
225    }
226
227    /**
228     * Enqueues a BLIT operation with the given parameters.  Note that the
229     * RenderQueue lock must be held before calling this method.
230     */
231    private static void enqueueBlit(RenderQueue rq,
232                                    SurfaceData src, SurfaceData dst,
233                                    int packedParams,
234                                    int sx1, int sy1,
235                                    int sx2, int sy2,
236                                    double dx1, double dy1,
237                                    double dx2, double dy2)
238    {
239        // assert rq.lock.isHeldByCurrentThread();
240        RenderBuffer buf = rq.getBuffer();
241        rq.ensureCapacityAndAlignment(72, 24);
242        buf.putInt(BLIT);
243        buf.putInt(packedParams);
244        buf.putInt(sx1).putInt(sy1);
245        buf.putInt(sx2).putInt(sy2);
246        buf.putDouble(dx1).putDouble(dy1);
247        buf.putDouble(dx2).putDouble(dy2);
248        buf.putLong(src.getNativeOps());
249        buf.putLong(dst.getNativeOps());
250    }
251
252    static void Blit(SurfaceData srcData, SurfaceData dstData,
253                     Composite comp, Region clip,
254                     AffineTransform xform, int hint,
255                     int sx1, int sy1,
256                     int sx2, int sy2,
257                     double dx1, double dy1,
258                     double dx2, double dy2,
259                     int srctype, boolean texture)
260    {
261        int ctxflags = 0;
262        if (srcData.getTransparency() == Transparency.OPAQUE) {
263            ctxflags |= OGLContext.SRC_IS_OPAQUE;
264        }
265
266        OGLRenderQueue rq = OGLRenderQueue.getInstance();
267        rq.lock();
268        try {
269            // make sure the RenderQueue keeps a hard reference to the
270            // source (sysmem) SurfaceData to prevent it from being
271            // disposed while the operation is processed on the QFT
272            rq.addReference(srcData);
273
274            OGLSurfaceData oglDst = (OGLSurfaceData)dstData;
275            if (texture) {
276                // make sure we have a current context before uploading
277                // the sysmem data to the texture object
278                OGLGraphicsConfig gc = oglDst.getOGLGraphicsConfig();
279                OGLContext.setScratchSurface(gc);
280            } else {
281                OGLContext.validateContext(oglDst, oglDst,
282                                           clip, comp, xform, null, null,
283                                           ctxflags);
284            }
285
286            int packedParams = createPackedParams(false, texture,
287                                                  false, xform != null,
288                                                  hint, srctype);
289            enqueueBlit(rq, srcData, dstData,
290                        packedParams,
291                        sx1, sy1, sx2, sy2,
292                        dx1, dy1, dx2, dy2);
293
294            // always flush immediately, since we (currently) have no means
295            // of tracking changes to the system memory surface
296            rq.flushNow();
297        } finally {
298            rq.unlock();
299        }
300    }
301
302    /**
303     * Note: The srcImg and biop parameters are only used when invoked
304     * from the OGLBufImgOps.renderImageWithOp() method; in all other cases,
305     * this method can be called with null values for those two parameters,
306     * and they will be effectively ignored.
307     */
308    static void IsoBlit(SurfaceData srcData, SurfaceData dstData,
309                        BufferedImage srcImg, BufferedImageOp biop,
310                        Composite comp, Region clip,
311                        AffineTransform xform, int hint,
312                        int sx1, int sy1,
313                        int sx2, int sy2,
314                        double dx1, double dy1,
315                        double dx2, double dy2,
316                        boolean texture)
317    {
318        int ctxflags = 0;
319        if (srcData.getTransparency() == Transparency.OPAQUE) {
320            ctxflags |= OGLContext.SRC_IS_OPAQUE;
321        }
322
323        OGLRenderQueue rq = OGLRenderQueue.getInstance();
324        rq.lock();
325        try {
326            OGLSurfaceData oglSrc = (OGLSurfaceData)srcData;
327            OGLSurfaceData oglDst = (OGLSurfaceData)dstData;
328            int srctype = oglSrc.getType();
329            boolean rtt;
330            OGLSurfaceData srcCtxData;
331            if (srctype == OGLSurfaceData.TEXTURE) {
332                // the source is a regular texture object; we substitute
333                // the destination surface for the purposes of making a
334                // context current
335                rtt = false;
336                srcCtxData = oglDst;
337            } else {
338                // the source is a pbuffer, backbuffer, or render-to-texture
339                // surface; we set rtt to true to differentiate this kind
340                // of surface from a regular texture object
341                rtt = true;
342                if (srctype == OGLSurfaceData.FBOBJECT) {
343                    srcCtxData = oglDst;
344                } else {
345                    srcCtxData = oglSrc;
346                }
347            }
348
349            OGLContext.validateContext(srcCtxData, oglDst,
350                                       clip, comp, xform, null, null,
351                                       ctxflags);
352
353            if (biop != null) {
354                OGLBufImgOps.enableBufImgOp(rq, oglSrc, srcImg, biop);
355            }
356
357            int packedParams = createPackedParams(true, texture,
358                                                  rtt, xform != null,
359                                                  hint, 0 /*unused*/);
360            enqueueBlit(rq, srcData, dstData,
361                        packedParams,
362                        sx1, sy1, sx2, sy2,
363                        dx1, dy1, dx2, dy2);
364
365            if (biop != null) {
366                OGLBufImgOps.disableBufImgOp(rq, biop);
367            }
368
369            if (rtt && oglDst.isOnScreen()) {
370                // we only have to flush immediately when copying from a
371                // (non-texture) surface to the screen; otherwise Swing apps
372                // might appear unresponsive until the auto-flush completes
373                rq.flushNow();
374            }
375        } finally {
376            rq.unlock();
377        }
378    }
379}
380
381class OGLSurfaceToSurfaceBlit extends Blit {
382
383    OGLSurfaceToSurfaceBlit() {
384        super(OGLSurfaceData.OpenGLSurface,
385              CompositeType.AnyAlpha,
386              OGLSurfaceData.OpenGLSurface);
387    }
388
389    public void Blit(SurfaceData src, SurfaceData dst,
390                     Composite comp, Region clip,
391                     int sx, int sy, int dx, int dy, int w, int h)
392    {
393        OGLBlitLoops.IsoBlit(src, dst,
394                             null, null,
395                             comp, clip, null,
396                             AffineTransformOp.TYPE_NEAREST_NEIGHBOR,
397                             sx, sy, sx+w, sy+h,
398                             dx, dy, dx+w, dy+h,
399                             false);
400    }
401}
402
403class OGLSurfaceToSurfaceScale extends ScaledBlit {
404
405    OGLSurfaceToSurfaceScale() {
406        super(OGLSurfaceData.OpenGLSurface,
407              CompositeType.AnyAlpha,
408              OGLSurfaceData.OpenGLSurface);
409    }
410
411    public void Scale(SurfaceData src, SurfaceData dst,
412                      Composite comp, Region clip,
413                      int sx1, int sy1,
414                      int sx2, int sy2,
415                      double dx1, double dy1,
416                      double dx2, double dy2)
417    {
418        OGLBlitLoops.IsoBlit(src, dst,
419                             null, null,
420                             comp, clip, null,
421                             AffineTransformOp.TYPE_NEAREST_NEIGHBOR,
422                             sx1, sy1, sx2, sy2,
423                             dx1, dy1, dx2, dy2,
424                             false);
425    }
426}
427
428class OGLSurfaceToSurfaceTransform extends TransformBlit {
429
430    OGLSurfaceToSurfaceTransform() {
431        super(OGLSurfaceData.OpenGLSurface,
432              CompositeType.AnyAlpha,
433              OGLSurfaceData.OpenGLSurface);
434    }
435
436    public void Transform(SurfaceData src, SurfaceData dst,
437                          Composite comp, Region clip,
438                          AffineTransform at, int hint,
439                          int sx, int sy, int dx, int dy,
440                          int w, int h)
441    {
442        OGLBlitLoops.IsoBlit(src, dst,
443                             null, null,
444                             comp, clip, at, hint,
445                             sx, sy, sx+w, sy+h,
446                             dx, dy, dx+w, dy+h,
447                             false);
448    }
449}
450
451class OGLRTTSurfaceToSurfaceBlit extends Blit {
452
453    OGLRTTSurfaceToSurfaceBlit() {
454        super(OGLSurfaceData.OpenGLSurfaceRTT,
455              CompositeType.AnyAlpha,
456              OGLSurfaceData.OpenGLSurface);
457    }
458
459    public void Blit(SurfaceData src, SurfaceData dst,
460                     Composite comp, Region clip,
461                     int sx, int sy, int dx, int dy, int w, int h)
462    {
463        OGLBlitLoops.IsoBlit(src, dst,
464                             null, null,
465                             comp, clip, null,
466                             AffineTransformOp.TYPE_NEAREST_NEIGHBOR,
467                             sx, sy, sx+w, sy+h,
468                             dx, dy, dx+w, dy+h,
469                             true);
470    }
471}
472
473class OGLRTTSurfaceToSurfaceScale extends ScaledBlit {
474
475    OGLRTTSurfaceToSurfaceScale() {
476        super(OGLSurfaceData.OpenGLSurfaceRTT,
477              CompositeType.AnyAlpha,
478              OGLSurfaceData.OpenGLSurface);
479    }
480
481    public void Scale(SurfaceData src, SurfaceData dst,
482                      Composite comp, Region clip,
483                      int sx1, int sy1,
484                      int sx2, int sy2,
485                      double dx1, double dy1,
486                      double dx2, double dy2)
487    {
488        OGLBlitLoops.IsoBlit(src, dst,
489                             null, null,
490                             comp, clip, null,
491                             AffineTransformOp.TYPE_NEAREST_NEIGHBOR,
492                             sx1, sy1, sx2, sy2,
493                             dx1, dy1, dx2, dy2,
494                             true);
495    }
496}
497
498class OGLRTTSurfaceToSurfaceTransform extends TransformBlit {
499
500    OGLRTTSurfaceToSurfaceTransform() {
501        super(OGLSurfaceData.OpenGLSurfaceRTT,
502              CompositeType.AnyAlpha,
503              OGLSurfaceData.OpenGLSurface);
504    }
505
506    public void Transform(SurfaceData src, SurfaceData dst,
507                          Composite comp, Region clip,
508                          AffineTransform at, int hint,
509                          int sx, int sy, int dx, int dy, int w, int h)
510    {
511        OGLBlitLoops.IsoBlit(src, dst,
512                             null, null,
513                             comp, clip, at, hint,
514                             sx, sy, sx+w, sy+h,
515                             dx, dy, dx+w, dy+h,
516                             true);
517    }
518}
519
520final class OGLSurfaceToSwBlit extends Blit {
521
522    private final int typeval;
523    private WeakReference<SurfaceData> srcTmp;
524
525    // destination will actually be ArgbPre or Argb
526    OGLSurfaceToSwBlit(final SurfaceType dstType,final int typeval) {
527        super(OGLSurfaceData.OpenGLSurface,
528              CompositeType.SrcNoEa,
529              dstType);
530        this.typeval = typeval;
531    }
532
533    private synchronized void complexClipBlit(SurfaceData src, SurfaceData dst,
534                                              Composite comp, Region clip,
535                                              int sx, int sy, int dx, int dy,
536                                              int w, int h) {
537        SurfaceData cachedSrc = null;
538        if (srcTmp != null) {
539            // use cached intermediate surface, if available
540            cachedSrc = srcTmp.get();
541        }
542
543        // We can convert argb_pre data from OpenGL surface in two places:
544        // - During OpenGL surface -> SW blit
545        // - During SW -> SW blit
546        // The first one is faster when we use opaque OGL surface, because in
547        // this case we simply skip conversion and use color components as is.
548        // Because of this we align intermediate buffer type with type of
549        // destination not source.
550        final int type = typeval == OGLSurfaceData.PF_INT_ARGB_PRE ?
551                         BufferedImage.TYPE_INT_ARGB_PRE :
552                         BufferedImage.TYPE_INT_ARGB;
553
554        src = convertFrom(this, src, sx, sy, w, h, cachedSrc, type);
555
556        // copy intermediate SW to destination SW using complex clip
557        final Blit performop = Blit.getFromCache(src.getSurfaceType(),
558                                                 CompositeType.SrcNoEa,
559                                                 dst.getSurfaceType());
560        performop.Blit(src, dst, comp, clip, 0, 0, dx, dy, w, h);
561
562        if (src != cachedSrc) {
563            // cache the intermediate surface
564            srcTmp = new WeakReference<>(src);
565        }
566    }
567
568    public void Blit(SurfaceData src, SurfaceData dst,
569                     Composite comp, Region clip,
570                     int sx, int sy, int dx, int dy,
571                     int w, int h)
572    {
573        if (clip != null) {
574            clip = clip.getIntersectionXYWH(dx, dy, w, h);
575            // At the end this method will flush the RenderQueue, we should exit
576            // from it as soon as possible.
577            if (clip.isEmpty()) {
578                return;
579            }
580            sx += clip.getLoX() - dx;
581            sy += clip.getLoY() - dy;
582            dx = clip.getLoX();
583            dy = clip.getLoY();
584            w = clip.getWidth();
585            h = clip.getHeight();
586
587            if (!clip.isRectangular()) {
588                complexClipBlit(src, dst, comp, clip, sx, sy, dx, dy, w, h);
589                return;
590            }
591        }
592
593        OGLRenderQueue rq = OGLRenderQueue.getInstance();
594        rq.lock();
595        try {
596            // make sure the RenderQueue keeps a hard reference to the
597            // destination (sysmem) SurfaceData to prevent it from being
598            // disposed while the operation is processed on the QFT
599            rq.addReference(dst);
600
601            RenderBuffer buf = rq.getBuffer();
602            OGLContext.validateContext((OGLSurfaceData)src);
603
604            rq.ensureCapacityAndAlignment(48, 32);
605            buf.putInt(SURFACE_TO_SW_BLIT);
606            buf.putInt(sx).putInt(sy);
607            buf.putInt(dx).putInt(dy);
608            buf.putInt(w).putInt(h);
609            buf.putInt(typeval);
610            buf.putLong(src.getNativeOps());
611            buf.putLong(dst.getNativeOps());
612
613            // always flush immediately
614            rq.flushNow();
615        } finally {
616            rq.unlock();
617        }
618    }
619}
620
621class OGLSwToSurfaceBlit extends Blit {
622
623    private int typeval;
624
625    OGLSwToSurfaceBlit(SurfaceType srcType, int typeval) {
626        super(srcType,
627              CompositeType.AnyAlpha,
628              OGLSurfaceData.OpenGLSurface);
629        this.typeval = typeval;
630    }
631
632    public void Blit(SurfaceData src, SurfaceData dst,
633                     Composite comp, Region clip,
634                     int sx, int sy, int dx, int dy, int w, int h)
635    {
636        OGLBlitLoops.Blit(src, dst,
637                          comp, clip, null,
638                          AffineTransformOp.TYPE_NEAREST_NEIGHBOR,
639                          sx, sy, sx+w, sy+h,
640                          dx, dy, dx+w, dy+h,
641                          typeval, false);
642    }
643}
644
645class OGLSwToSurfaceScale extends ScaledBlit {
646
647    private int typeval;
648
649    OGLSwToSurfaceScale(SurfaceType srcType, int typeval) {
650        super(srcType,
651              CompositeType.AnyAlpha,
652              OGLSurfaceData.OpenGLSurface);
653        this.typeval = typeval;
654    }
655
656    public void Scale(SurfaceData src, SurfaceData dst,
657                      Composite comp, Region clip,
658                      int sx1, int sy1,
659                      int sx2, int sy2,
660                      double dx1, double dy1,
661                      double dx2, double dy2)
662    {
663        OGLBlitLoops.Blit(src, dst,
664                          comp, clip, null,
665                          AffineTransformOp.TYPE_NEAREST_NEIGHBOR,
666                          sx1, sy1, sx2, sy2,
667                          dx1, dy1, dx2, dy2,
668                          typeval, false);
669    }
670}
671
672class OGLSwToSurfaceTransform extends TransformBlit {
673
674    private int typeval;
675
676    OGLSwToSurfaceTransform(SurfaceType srcType, int typeval) {
677        super(srcType,
678              CompositeType.AnyAlpha,
679              OGLSurfaceData.OpenGLSurface);
680        this.typeval = typeval;
681    }
682
683    public void Transform(SurfaceData src, SurfaceData dst,
684                          Composite comp, Region clip,
685                          AffineTransform at, int hint,
686                          int sx, int sy, int dx, int dy, int w, int h)
687    {
688        OGLBlitLoops.Blit(src, dst,
689                          comp, clip, at, hint,
690                          sx, sy, sx+w, sy+h,
691                          dx, dy, dx+w, dy+h,
692                          typeval, false);
693    }
694}
695
696class OGLSwToTextureBlit extends Blit {
697
698    private int typeval;
699
700    OGLSwToTextureBlit(SurfaceType srcType, int typeval) {
701        super(srcType,
702              CompositeType.SrcNoEa,
703              OGLSurfaceData.OpenGLTexture);
704        this.typeval = typeval;
705    }
706
707    public void Blit(SurfaceData src, SurfaceData dst,
708                     Composite comp, Region clip,
709                     int sx, int sy, int dx, int dy, int w, int h)
710    {
711        OGLBlitLoops.Blit(src, dst,
712                          comp, clip, null,
713                          AffineTransformOp.TYPE_NEAREST_NEIGHBOR,
714                          sx, sy, sx+w, sy+h,
715                          dx, dy, dx+w, dy+h,
716                          typeval, true);
717    }
718}
719
720class OGLTextureToSurfaceBlit extends Blit {
721
722    OGLTextureToSurfaceBlit() {
723        super(OGLSurfaceData.OpenGLTexture,
724              CompositeType.AnyAlpha,
725              OGLSurfaceData.OpenGLSurface);
726    }
727
728    public void Blit(SurfaceData src, SurfaceData dst,
729                     Composite comp, Region clip,
730                     int sx, int sy, int dx, int dy, int w, int h)
731    {
732        OGLBlitLoops.IsoBlit(src, dst,
733                             null, null,
734                             comp, clip, null,
735                             AffineTransformOp.TYPE_NEAREST_NEIGHBOR,
736                             sx, sy, sx+w, sy+h,
737                             dx, dy, dx+w, dy+h,
738                             true);
739    }
740}
741
742class OGLTextureToSurfaceScale extends ScaledBlit {
743
744    OGLTextureToSurfaceScale() {
745        super(OGLSurfaceData.OpenGLTexture,
746              CompositeType.AnyAlpha,
747              OGLSurfaceData.OpenGLSurface);
748    }
749
750    public void Scale(SurfaceData src, SurfaceData dst,
751                      Composite comp, Region clip,
752                      int sx1, int sy1,
753                      int sx2, int sy2,
754                      double dx1, double dy1,
755                      double dx2, double dy2)
756    {
757        OGLBlitLoops.IsoBlit(src, dst,
758                             null, null,
759                             comp, clip, null,
760                             AffineTransformOp.TYPE_NEAREST_NEIGHBOR,
761                             sx1, sy1, sx2, sy2,
762                             dx1, dy1, dx2, dy2,
763                             true);
764    }
765}
766
767class OGLTextureToSurfaceTransform extends TransformBlit {
768
769    OGLTextureToSurfaceTransform() {
770        super(OGLSurfaceData.OpenGLTexture,
771              CompositeType.AnyAlpha,
772              OGLSurfaceData.OpenGLSurface);
773    }
774
775    public void Transform(SurfaceData src, SurfaceData dst,
776                          Composite comp, Region clip,
777                          AffineTransform at, int hint,
778                          int sx, int sy, int dx, int dy,
779                          int w, int h)
780    {
781        OGLBlitLoops.IsoBlit(src, dst,
782                             null, null,
783                             comp, clip, at, hint,
784                             sx, sy, sx+w, sy+h,
785                             dx, dy, dx+w, dy+h,
786                             true);
787    }
788}
789
790/**
791 * This general Blit implementation converts any source surface to an
792 * intermediate IntArgbPre surface, and then uses the more specific
793 * IntArgbPre->OpenGLSurface/Texture loop to get the intermediate
794 * (premultiplied) surface down to OpenGL using simple blit.
795 */
796class OGLGeneralBlit extends Blit {
797
798    private final Blit performop;
799    private WeakReference<SurfaceData> srcTmp;
800
801    OGLGeneralBlit(SurfaceType dstType,
802                   CompositeType compType,
803                   Blit performop)
804    {
805        super(SurfaceType.Any, compType, dstType);
806        this.performop = performop;
807    }
808
809    public synchronized void Blit(SurfaceData src, SurfaceData dst,
810                                  Composite comp, Region clip,
811                                  int sx, int sy, int dx, int dy,
812                                  int w, int h)
813    {
814        Blit convertsrc = Blit.getFromCache(src.getSurfaceType(),
815                                            CompositeType.SrcNoEa,
816                                            SurfaceType.IntArgbPre);
817
818        SurfaceData cachedSrc = null;
819        if (srcTmp != null) {
820            // use cached intermediate surface, if available
821            cachedSrc = srcTmp.get();
822        }
823
824        // convert source to IntArgbPre
825        src = convertFrom(convertsrc, src, sx, sy, w, h,
826                          cachedSrc, BufferedImage.TYPE_INT_ARGB_PRE);
827
828        // copy IntArgbPre intermediate surface to OpenGL surface
829        performop.Blit(src, dst, comp, clip,
830                       0, 0, dx, dy, w, h);
831
832        if (src != cachedSrc) {
833            // cache the intermediate surface
834            srcTmp = new WeakReference<>(src);
835        }
836    }
837}
838
839/**
840 * This general TransformedBlit implementation converts any source surface to an
841 * intermediate IntArgbPre surface, and then uses the more specific
842 * IntArgbPre->OpenGLSurface/Texture loop to get the intermediate
843 * (premultiplied) surface down to OpenGL using simple transformBlit.
844 */
845final class OGLGeneralTransformedBlit extends TransformBlit {
846
847    private final TransformBlit performop;
848    private WeakReference<SurfaceData> srcTmp;
849
850    OGLGeneralTransformedBlit(final TransformBlit performop) {
851        super(SurfaceType.Any, CompositeType.AnyAlpha,
852              OGLSurfaceData.OpenGLSurface);
853        this.performop = performop;
854    }
855
856    @Override
857    public synchronized void Transform(SurfaceData src, SurfaceData dst,
858                                       Composite comp, Region clip,
859                                       AffineTransform at, int hint, int srcx,
860                                       int srcy, int dstx, int dsty, int width,
861                                       int height){
862        Blit convertsrc = Blit.getFromCache(src.getSurfaceType(),
863                                            CompositeType.SrcNoEa,
864                                            SurfaceType.IntArgbPre);
865        // use cached intermediate surface, if available
866        final SurfaceData cachedSrc = srcTmp != null ? srcTmp.get() : null;
867        // convert source to IntArgbPre
868        src = convertFrom(convertsrc, src, srcx, srcy, width, height, cachedSrc,
869                          BufferedImage.TYPE_INT_ARGB_PRE);
870
871        // transform IntArgbPre intermediate surface to OpenGL surface
872        performop.Transform(src, dst, comp, clip, at, hint, 0, 0, dstx, dsty,
873                            width, height);
874
875        if (src != cachedSrc) {
876            // cache the intermediate surface
877            srcTmp = new WeakReference<>(src);
878        }
879    }
880}
881
882/**
883 * This general OGLAnyCompositeBlit implementation can convert any source/target
884 * surface to an intermediate surface using convertsrc/convertdst loops, applies
885 * necessary composite operation, and then uses convertresult loop to get the
886 * intermediate surface down to OpenGL.
887 */
888final class OGLAnyCompositeBlit extends Blit {
889
890    private WeakReference<SurfaceData> dstTmp;
891    private WeakReference<SurfaceData> srcTmp;
892    private final Blit convertsrc;
893    private final Blit convertdst;
894    private final Blit convertresult;
895
896    OGLAnyCompositeBlit(SurfaceType srctype, Blit convertsrc, Blit convertdst,
897                        Blit convertresult) {
898        super(srctype, CompositeType.Any, OGLSurfaceData.OpenGLSurface);
899        this.convertsrc = convertsrc;
900        this.convertdst = convertdst;
901        this.convertresult = convertresult;
902    }
903
904    public synchronized void Blit(SurfaceData src, SurfaceData dst,
905                                  Composite comp, Region clip,
906                                  int sx, int sy, int dx, int dy,
907                                  int w, int h)
908    {
909        if (convertsrc != null) {
910            SurfaceData cachedSrc = null;
911            if (srcTmp != null) {
912                // use cached intermediate surface, if available
913                cachedSrc = srcTmp.get();
914            }
915            // convert source to IntArgbPre
916            src = convertFrom(convertsrc, src, sx, sy, w, h, cachedSrc,
917                              BufferedImage.TYPE_INT_ARGB_PRE);
918            if (src != cachedSrc) {
919                // cache the intermediate surface
920                srcTmp = new WeakReference<>(src);
921            }
922        }
923
924        SurfaceData cachedDst = null;
925
926        if (dstTmp != null) {
927            // use cached intermediate surface, if available
928            cachedDst = dstTmp.get();
929        }
930
931        // convert destination to IntArgbPre
932        SurfaceData dstBuffer = convertFrom(convertdst, dst, dx, dy, w, h,
933                          cachedDst, BufferedImage.TYPE_INT_ARGB_PRE);
934        Region bufferClip =
935                clip == null ? null : clip.getTranslatedRegion(-dx, -dy);
936
937        Blit performop = Blit.getFromCache(src.getSurfaceType(),
938                CompositeType.Any, dstBuffer.getSurfaceType());
939        performop.Blit(src, dstBuffer, comp, bufferClip, sx, sy, 0, 0, w, h);
940
941        if (dstBuffer != cachedDst) {
942            // cache the intermediate surface
943            dstTmp = new WeakReference<>(dstBuffer);
944        }
945        // now blit the buffer back to the destination
946        convertresult.Blit(dstBuffer, dst, AlphaComposite.Src, clip, 0, 0, dx,
947                           dy, w, h);
948    }
949}
950