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.GraphicsEnvironment;
31import java.awt.Rectangle;
32import java.awt.Transparency;
33import java.awt.image.ColorModel;
34import java.awt.image.Raster;
35import sun.awt.SunHints;
36import sun.awt.image.PixelConverter;
37import sun.java2d.pipe.hw.AccelSurface;
38import sun.java2d.SunGraphics2D;
39import sun.java2d.SurfaceData;
40import sun.java2d.SurfaceDataProxy;
41import sun.java2d.loops.CompositeType;
42import sun.java2d.loops.GraphicsPrimitive;
43import sun.java2d.loops.MaskFill;
44import sun.java2d.loops.SurfaceType;
45import sun.java2d.pipe.ParallelogramPipe;
46import sun.java2d.pipe.PixelToParallelogramConverter;
47import sun.java2d.pipe.RenderBuffer;
48import sun.java2d.pipe.TextPipe;
49import static sun.java2d.pipe.BufferedOpCodes.*;
50import static sun.java2d.opengl.OGLContext.OGLContextCaps.*;
51
52/**
53 * This class describes an OpenGL "surface", that is, a region of pixels
54 * managed via OpenGL.  An OGLSurfaceData can be tagged with one of three
55 * different SurfaceType objects for the purpose of registering loops, etc.
56 * This diagram shows the hierarchy of OGL SurfaceTypes:
57 *
58 *                               Any
59 *                             /     \
60 *                 OpenGLSurface     OpenGLTexture
61 *                      |
62 *               OpenGLSurfaceRTT
63 *
64 * OpenGLSurface
65 * This kind of surface can be rendered to using OpenGL APIs.  It is also
66 * possible to copy an OpenGLSurface to another OpenGLSurface (or to itself).
67 * This is typically accomplished by calling MakeContextCurrent(dstSD, srcSD)
68 * and then calling glCopyPixels() (although there are other techniques to
69 * achieve the same goal).
70 *
71 * OpenGLTexture
72 * This kind of surface cannot be rendered to using OpenGL (in the same sense
73 * as in OpenGLSurface).  However, it is possible to upload a region of pixels
74 * to an OpenGLTexture object via glTexSubImage2D().  One can also copy a
75 * surface of type OpenGLTexture to an OpenGLSurface by binding the texture
76 * to a quad and then rendering it to the destination surface (this process
77 * is known as "texture mapping").
78 *
79 * OpenGLSurfaceRTT
80 * This kind of surface can be thought of as a sort of hybrid between
81 * OpenGLSurface and OpenGLTexture, in that one can render to this kind of
82 * surface as if it were of type OpenGLSurface, but the process of copying
83 * this kind of surface to another is more like an OpenGLTexture.  (Note that
84 * "RTT" stands for "render-to-texture".)
85 *
86 * In addition to these SurfaceType variants, we have also defined some
87 * constants that describe in more detail the type of underlying OpenGL
88 * surface.  This table helps explain the relationships between those
89 * "type" constants and their corresponding SurfaceType:
90 *
91 * OGL Type          Corresponding SurfaceType
92 * --------          -------------------------
93 * WINDOW            OpenGLSurface
94 * TEXTURE           OpenGLTexture
95 * FLIP_BACKBUFFER   OpenGLSurface
96 * FBOBJECT          OpenGLSurfaceRTT
97 */
98public abstract class OGLSurfaceData extends SurfaceData
99    implements AccelSurface {
100
101    /**
102     * OGL-specific surface types
103     *
104     * @see sun.java2d.pipe.hw.AccelSurface
105     */
106    public static final int FBOBJECT        = RT_TEXTURE;
107
108    /**
109     * Pixel formats
110     */
111    public static final int PF_INT_ARGB        = 0;
112    public static final int PF_INT_ARGB_PRE    = 1;
113    public static final int PF_INT_RGB         = 2;
114    public static final int PF_INT_RGBX        = 3;
115    public static final int PF_INT_BGR         = 4;
116    public static final int PF_INT_BGRX        = 5;
117    public static final int PF_USHORT_565_RGB  = 6;
118    public static final int PF_USHORT_555_RGB  = 7;
119    public static final int PF_USHORT_555_RGBX = 8;
120    public static final int PF_BYTE_GRAY       = 9;
121    public static final int PF_USHORT_GRAY     = 10;
122    public static final int PF_3BYTE_BGR       = 11;
123
124    /**
125     * SurfaceTypes
126     */
127    private static final String DESC_OPENGL_SURFACE = "OpenGL Surface";
128    private static final String DESC_OPENGL_SURFACE_RTT =
129        "OpenGL Surface (render-to-texture)";
130    private static final String DESC_OPENGL_TEXTURE = "OpenGL Texture";
131
132    static final SurfaceType OpenGLSurface =
133        SurfaceType.Any.deriveSubType(DESC_OPENGL_SURFACE,
134                                      PixelConverter.ArgbPre.instance);
135    static final SurfaceType OpenGLSurfaceRTT =
136        OpenGLSurface.deriveSubType(DESC_OPENGL_SURFACE_RTT);
137    static final SurfaceType OpenGLTexture =
138        SurfaceType.Any.deriveSubType(DESC_OPENGL_TEXTURE);
139
140    /** This will be true if the fbobject system property has been enabled. */
141    private static boolean isFBObjectEnabled;
142
143    /** This will be true if the lcdshader system property has been enabled.*/
144    private static boolean isLCDShaderEnabled;
145
146    /** This will be true if the biopshader system property has been enabled.*/
147    private static boolean isBIOpShaderEnabled;
148
149    /** This will be true if the gradshader system property has been enabled.*/
150    private static boolean isGradShaderEnabled;
151
152    private OGLGraphicsConfig graphicsConfig;
153    protected int type;
154    // these fields are set from the native code when the surface is
155    // initialized
156    private int nativeWidth, nativeHeight;
157
158    protected static OGLRenderer oglRenderPipe;
159    protected static PixelToParallelogramConverter oglTxRenderPipe;
160    protected static ParallelogramPipe oglAAPgramPipe;
161    protected static OGLTextRenderer oglTextPipe;
162    protected static OGLDrawImage oglImagePipe;
163
164    protected native boolean initTexture(long pData,
165                                         boolean isOpaque, boolean texNonPow2,
166                                         boolean texRect,
167                                         int width, int height);
168    protected native boolean initFBObject(long pData,
169                                          boolean isOpaque, boolean texNonPow2,
170                                          boolean texRect,
171                                          int width, int height);
172    protected native boolean initFlipBackbuffer(long pData);
173
174    private native int getTextureTarget(long pData);
175    private native int getTextureID(long pData);
176
177    static {
178        if (!GraphicsEnvironment.isHeadless()) {
179            // fbobject currently enabled by default; use "false" to disable
180            String fbo = java.security.AccessController.doPrivileged(
181                new sun.security.action.GetPropertyAction(
182                    "sun.java2d.opengl.fbobject"));
183            isFBObjectEnabled = !"false".equals(fbo);
184
185            // lcdshader currently enabled by default; use "false" to disable
186            String lcd = java.security.AccessController.doPrivileged(
187                new sun.security.action.GetPropertyAction(
188                    "sun.java2d.opengl.lcdshader"));
189            isLCDShaderEnabled = !"false".equals(lcd);
190
191            // biopshader currently enabled by default; use "false" to disable
192            String biop = java.security.AccessController.doPrivileged(
193                new sun.security.action.GetPropertyAction(
194                    "sun.java2d.opengl.biopshader"));
195            isBIOpShaderEnabled = !"false".equals(biop);
196
197            // gradshader currently enabled by default; use "false" to disable
198            String grad = java.security.AccessController.doPrivileged(
199                new sun.security.action.GetPropertyAction(
200                    "sun.java2d.opengl.gradshader"));
201            isGradShaderEnabled = !"false".equals(grad);
202
203            OGLRenderQueue rq = OGLRenderQueue.getInstance();
204            oglImagePipe = new OGLDrawImage();
205            oglTextPipe = new OGLTextRenderer(rq);
206            oglRenderPipe = new OGLRenderer(rq);
207            if (GraphicsPrimitive.tracingEnabled()) {
208                oglTextPipe = oglTextPipe.traceWrap();
209                //The wrapped oglRenderPipe will wrap the AA pipe as well...
210                //oglAAPgramPipe = oglRenderPipe.traceWrap();
211            }
212            oglAAPgramPipe = oglRenderPipe.getAAParallelogramPipe();
213            oglTxRenderPipe =
214                new PixelToParallelogramConverter(oglRenderPipe,
215                                                  oglRenderPipe,
216                                                  1.0, 0.25, true);
217
218            OGLBlitLoops.register();
219            OGLMaskFill.register();
220            OGLMaskBlit.register();
221        }
222    }
223
224    protected OGLSurfaceData(OGLGraphicsConfig gc,
225                             ColorModel cm, int type)
226    {
227        super(getCustomSurfaceType(type), cm);
228        this.graphicsConfig = gc;
229        this.type = type;
230        setBlitProxyKey(gc.getProxyKey());
231    }
232
233    @Override
234    public SurfaceDataProxy makeProxyFor(SurfaceData srcData) {
235        return OGLSurfaceDataProxy.createProxy(srcData, graphicsConfig);
236    }
237
238    /**
239     * Returns the appropriate SurfaceType corresponding to the given OpenGL
240     * surface type constant (e.g. TEXTURE -> OpenGLTexture).
241     */
242    private static SurfaceType getCustomSurfaceType(int oglType) {
243        switch (oglType) {
244        case TEXTURE:
245            return OpenGLTexture;
246        case FBOBJECT:
247            return OpenGLSurfaceRTT;
248        default:
249            return OpenGLSurface;
250        }
251    }
252
253    /**
254     * Note: This should only be called from the QFT under the AWT lock.
255     * This method is kept separate from the initSurface() method below just
256     * to keep the code a bit cleaner.
257     */
258    private void initSurfaceNow(int width, int height) {
259        boolean isOpaque = (getTransparency() == Transparency.OPAQUE);
260        boolean success = false;
261
262        switch (type) {
263        case TEXTURE:
264            success = initTexture(getNativeOps(),
265                                  isOpaque, isTexNonPow2Available(),
266                                  isTexRectAvailable(),
267                                  width, height);
268            break;
269
270        case FBOBJECT:
271            success = initFBObject(getNativeOps(),
272                                   isOpaque, isTexNonPow2Available(),
273                                   isTexRectAvailable(),
274                                   width, height);
275            break;
276
277        case FLIP_BACKBUFFER:
278            success = initFlipBackbuffer(getNativeOps());
279            break;
280
281        default:
282            break;
283        }
284
285        if (!success) {
286            throw new OutOfMemoryError("can't create offscreen surface");
287        }
288    }
289
290    /**
291     * Initializes the appropriate OpenGL offscreen surface based on the value
292     * of the type parameter.  If the surface creation fails for any reason,
293     * an OutOfMemoryError will be thrown.
294     */
295    protected void initSurface(final int width, final int height) {
296        OGLRenderQueue rq = OGLRenderQueue.getInstance();
297        rq.lock();
298        try {
299            switch (type) {
300            case TEXTURE:
301            case FBOBJECT:
302                // need to make sure the context is current before
303                // creating the texture or fbobject
304                OGLContext.setScratchSurface(graphicsConfig);
305                break;
306            default:
307                break;
308            }
309            rq.flushAndInvokeNow(new Runnable() {
310                public void run() {
311                    initSurfaceNow(width, height);
312                }
313            });
314        } finally {
315            rq.unlock();
316        }
317    }
318
319    /**
320     * Returns the OGLContext for the GraphicsConfig associated with this
321     * surface.
322     */
323    public final OGLContext getContext() {
324        return graphicsConfig.getContext();
325    }
326
327    /**
328     * Returns the OGLGraphicsConfig associated with this surface.
329     */
330    final OGLGraphicsConfig getOGLGraphicsConfig() {
331        return graphicsConfig;
332    }
333
334    /**
335     * Returns one of the surface type constants defined above.
336     */
337    public final int getType() {
338        return type;
339    }
340
341    /**
342     * If this surface is backed by a texture object, returns the target
343     * for that texture (either GL_TEXTURE_2D or GL_TEXTURE_RECTANGLE_ARB).
344     * Otherwise, this method will return zero.
345     */
346    public final int getTextureTarget() {
347        return getTextureTarget(getNativeOps());
348    }
349
350    /**
351     * If this surface is backed by a texture object, returns the texture ID
352     * for that texture.
353     * Otherwise, this method will return zero.
354     */
355    public final int getTextureID() {
356        return getTextureID(getNativeOps());
357    }
358
359    /**
360     * Returns native resource of specified {@code resType} associated with
361     * this surface.
362     *
363     * Specifically, for {@code OGLSurfaceData} this method returns the
364     * the following:
365     * <pre>
366     * TEXTURE              - texture id
367     * </pre>
368     *
369     * Note: the resource returned by this method is only valid on the rendering
370     * thread.
371     *
372     * @return native resource of specified type or 0L if
373     * such resource doesn't exist or can not be retrieved.
374     * @see sun.java2d.pipe.hw.AccelSurface#getNativeResource
375     */
376    public long getNativeResource(int resType) {
377        if (resType == TEXTURE) {
378            return getTextureID();
379        }
380        return 0L;
381    }
382
383    public Raster getRaster(int x, int y, int w, int h) {
384        throw new InternalError("not implemented yet");
385    }
386
387    /**
388     * For now, we can only render LCD text if:
389     *   - the fragment shader extension is available, and
390     *   - the source color is opaque, and
391     *   - blending is SrcOverNoEa or disabled
392     *   - and the destination is opaque
393     *
394     * Eventually, we could enhance the native OGL text rendering code
395     * and remove the above restrictions, but that would require significantly
396     * more code just to support a few uncommon cases.
397     */
398    public boolean canRenderLCDText(SunGraphics2D sg2d) {
399        return
400            graphicsConfig.isCapPresent(CAPS_EXT_LCD_SHADER) &&
401            sg2d.surfaceData.getTransparency() == Transparency.OPAQUE &&
402            sg2d.paintState <= SunGraphics2D.PAINT_OPAQUECOLOR &&
403            (sg2d.compositeState <= SunGraphics2D.COMP_ISCOPY ||
404             (sg2d.compositeState <= SunGraphics2D.COMP_ALPHA && canHandleComposite(sg2d.composite)));
405    }
406
407    private boolean canHandleComposite(Composite c) {
408        if (c instanceof AlphaComposite) {
409            AlphaComposite ac = (AlphaComposite)c;
410
411            return ac.getRule() == AlphaComposite.SRC_OVER && ac.getAlpha() >= 1f;
412        }
413        return false;
414    }
415
416    public void validatePipe(SunGraphics2D sg2d) {
417        TextPipe textpipe;
418        boolean validated = false;
419
420        // OGLTextRenderer handles both AA and non-AA text, but
421        // only works with the following modes:
422        // (Note: For LCD text we only enter this code path if
423        // canRenderLCDText() has already validated that the mode is
424        // CompositeType.SrcNoEa (opaque color), which will be subsumed
425        // by the CompositeType.SrcNoEa (any color) test below.)
426
427        if (/* CompositeType.SrcNoEa (any color) */
428            (sg2d.compositeState <= SunGraphics2D.COMP_ISCOPY &&
429             sg2d.paintState <= SunGraphics2D.PAINT_ALPHACOLOR)         ||
430
431            /* CompositeType.SrcOver (any color) */
432            (sg2d.compositeState == SunGraphics2D.COMP_ALPHA   &&
433             sg2d.paintState <= SunGraphics2D.PAINT_ALPHACOLOR &&
434             (((AlphaComposite)sg2d.composite).getRule() ==
435              AlphaComposite.SRC_OVER))                                 ||
436
437            /* CompositeType.Xor (any color) */
438            (sg2d.compositeState == SunGraphics2D.COMP_XOR &&
439             sg2d.paintState <= SunGraphics2D.PAINT_ALPHACOLOR))
440        {
441            textpipe = oglTextPipe;
442        } else {
443            // do this to initialize textpipe correctly; we will attempt
444            // to override the non-text pipes below
445            super.validatePipe(sg2d);
446            textpipe = sg2d.textpipe;
447            validated = true;
448        }
449
450        PixelToParallelogramConverter txPipe = null;
451        OGLRenderer nonTxPipe = null;
452
453        if (sg2d.antialiasHint != SunHints.INTVAL_ANTIALIAS_ON) {
454            if (sg2d.paintState <= SunGraphics2D.PAINT_ALPHACOLOR) {
455                if (sg2d.compositeState <= SunGraphics2D.COMP_XOR) {
456                    txPipe = oglTxRenderPipe;
457                    nonTxPipe = oglRenderPipe;
458                }
459            } else if (sg2d.compositeState <= SunGraphics2D.COMP_ALPHA) {
460                if (OGLPaints.isValid(sg2d)) {
461                    txPipe = oglTxRenderPipe;
462                    nonTxPipe = oglRenderPipe;
463                }
464                // custom paints handled by super.validatePipe() below
465            }
466        } else {
467            if (sg2d.paintState <= SunGraphics2D.PAINT_ALPHACOLOR) {
468                if (graphicsConfig.isCapPresent(CAPS_PS30) &&
469                    (sg2d.imageComp == CompositeType.SrcOverNoEa ||
470                     sg2d.imageComp == CompositeType.SrcOver))
471                {
472                    if (!validated) {
473                        super.validatePipe(sg2d);
474                        validated = true;
475                    }
476                    PixelToParallelogramConverter aaConverter =
477                        new PixelToParallelogramConverter(sg2d.shapepipe,
478                                                          oglAAPgramPipe,
479                                                          1.0/8.0, 0.499,
480                                                          false);
481                    sg2d.drawpipe = aaConverter;
482                    sg2d.fillpipe = aaConverter;
483                    sg2d.shapepipe = aaConverter;
484                } else if (sg2d.compositeState == SunGraphics2D.COMP_XOR) {
485                    // install the solid pipes when AA and XOR are both enabled
486                    txPipe = oglTxRenderPipe;
487                    nonTxPipe = oglRenderPipe;
488                }
489            }
490            // other cases handled by super.validatePipe() below
491        }
492
493        if (txPipe != null) {
494            if (sg2d.transformState >= SunGraphics2D.TRANSFORM_TRANSLATESCALE) {
495                sg2d.drawpipe = txPipe;
496                sg2d.fillpipe = txPipe;
497            } else if (sg2d.strokeState != SunGraphics2D.STROKE_THIN) {
498                sg2d.drawpipe = txPipe;
499                sg2d.fillpipe = nonTxPipe;
500            } else {
501                sg2d.drawpipe = nonTxPipe;
502                sg2d.fillpipe = nonTxPipe;
503            }
504            // Note that we use the transforming pipe here because it
505            // will examine the shape and possibly perform an optimized
506            // operation if it can be simplified.  The simplifications
507            // will be valid for all STROKE and TRANSFORM types.
508            sg2d.shapepipe = txPipe;
509        } else {
510            if (!validated) {
511                super.validatePipe(sg2d);
512            }
513        }
514
515        // install the text pipe based on our earlier decision
516        sg2d.textpipe = textpipe;
517
518        // always override the image pipe with the specialized OGL pipe
519        sg2d.imagepipe = oglImagePipe;
520    }
521
522    @Override
523    protected MaskFill getMaskFill(SunGraphics2D sg2d) {
524        if (sg2d.paintState > SunGraphics2D.PAINT_ALPHACOLOR) {
525            /*
526             * We can only accelerate non-Color MaskFill operations if
527             * all of the following conditions hold true:
528             *   - there is an implementation for the given paintState
529             *   - the current Paint can be accelerated for this destination
530             *   - multitexturing is available (since we need to modulate
531             *     the alpha mask texture with the paint texture)
532             *
533             * In all other cases, we return null, in which case the
534             * validation code will choose a more general software-based loop.
535             */
536            if (!OGLPaints.isValid(sg2d) ||
537                !graphicsConfig.isCapPresent(CAPS_MULTITEXTURE))
538            {
539                return null;
540            }
541        }
542        return super.getMaskFill(sg2d);
543    }
544
545    @Override
546    public boolean copyArea(SunGraphics2D sg2d, int x, int y, int w, int h,
547                            int dx, int dy) {
548        if (sg2d.compositeState >= SunGraphics2D.COMP_XOR) {
549            return false;
550        }
551        oglRenderPipe.copyArea(sg2d, x, y, w, h, dx, dy);
552        return true;
553    }
554
555    public void flush() {
556        invalidate();
557        OGLRenderQueue rq = OGLRenderQueue.getInstance();
558        rq.lock();
559        try {
560            // make sure we have a current context before
561            // disposing the native resources (e.g. texture object)
562            OGLContext.setScratchSurface(graphicsConfig);
563
564            RenderBuffer buf = rq.getBuffer();
565            rq.ensureCapacityAndAlignment(12, 4);
566            buf.putInt(FLUSH_SURFACE);
567            buf.putLong(getNativeOps());
568
569            // this call is expected to complete synchronously, so flush now
570            rq.flushNow();
571        } finally {
572            rq.unlock();
573        }
574    }
575
576    /**
577     * Disposes the native resources associated with the given OGLSurfaceData
578     * (referenced by the pData parameter).  This method is invoked from
579     * the native Dispose() method from the Disposer thread when the
580     * Java-level OGLSurfaceData object is about to go away.  Note that we
581     * also pass a reference to the native GLX/WGLGraphicsConfigInfo
582     * (pConfigInfo) for the purposes of making a context current.
583     */
584    static void dispose(long pData, long pConfigInfo) {
585        OGLRenderQueue rq = OGLRenderQueue.getInstance();
586        rq.lock();
587        try {
588            // make sure we have a current context before
589            // disposing the native resources (e.g. texture object)
590            OGLContext.setScratchSurface(pConfigInfo);
591
592            RenderBuffer buf = rq.getBuffer();
593            rq.ensureCapacityAndAlignment(12, 4);
594            buf.putInt(DISPOSE_SURFACE);
595            buf.putLong(pData);
596
597            // this call is expected to complete synchronously, so flush now
598            rq.flushNow();
599        } finally {
600            rq.unlock();
601        }
602    }
603
604    static void swapBuffers(long window) {
605        OGLRenderQueue rq = OGLRenderQueue.getInstance();
606        rq.lock();
607        try {
608            RenderBuffer buf = rq.getBuffer();
609            rq.ensureCapacityAndAlignment(12, 4);
610            buf.putInt(SWAP_BUFFERS);
611            buf.putLong(window);
612            rq.flushNow();
613        } finally {
614            rq.unlock();
615        }
616    }
617
618    /**
619     * Returns true if OpenGL textures can have non-power-of-two dimensions
620     * when using the basic GL_TEXTURE_2D target.
621     */
622    boolean isTexNonPow2Available() {
623        return graphicsConfig.isCapPresent(CAPS_TEXNONPOW2);
624    }
625
626    /**
627     * Returns true if OpenGL textures can have non-power-of-two dimensions
628     * when using the GL_TEXTURE_RECTANGLE_ARB target (only available when the
629     * GL_ARB_texture_rectangle extension is present).
630     */
631    boolean isTexRectAvailable() {
632        return graphicsConfig.isCapPresent(CAPS_EXT_TEXRECT);
633    }
634
635    public Rectangle getNativeBounds() {
636        OGLRenderQueue rq = OGLRenderQueue.getInstance();
637        rq.lock();
638        try {
639            return new Rectangle(nativeWidth, nativeHeight);
640        } finally {
641            rq.unlock();
642        }
643    }
644
645    /**
646     * Returns true if the surface is an on-screen window surface or
647     * a FBO texture attached to an on-screen CALayer.
648     *
649     * Needed by Mac OS X port.
650     */
651    boolean isOnScreen() {
652        return getType() == WINDOW;
653    }
654}
655