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