Path: blob/master/src/java.desktop/share/classes/sun/java2d/opengl/OGLSurfaceData.java
41159 views
/*1* Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package sun.java2d.opengl;2627import java.awt.AlphaComposite;28import java.awt.Composite;29import java.awt.GraphicsConfiguration;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.*;5152/**53* This class describes an OpenGL "surface", that is, a region of pixels54* managed via OpenGL. An OGLSurfaceData can be tagged with one of three55* different SurfaceType objects for the purpose of registering loops, etc.56* This diagram shows the hierarchy of OGL SurfaceTypes:57*58* Any59* / \60* OpenGLSurface OpenGLTexture61* |62* OpenGLSurfaceRTT63*64* OpenGLSurface65* This kind of surface can be rendered to using OpenGL APIs. It is also66* 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 to69* achieve the same goal).70*71* OpenGLTexture72* This kind of surface cannot be rendered to using OpenGL (in the same sense73* as in OpenGLSurface). However, it is possible to upload a region of pixels74* to an OpenGLTexture object via glTexSubImage2D(). One can also copy a75* surface of type OpenGLTexture to an OpenGLSurface by binding the texture76* to a quad and then rendering it to the destination surface (this process77* is known as "texture mapping").78*79* OpenGLSurfaceRTT80* This kind of surface can be thought of as a sort of hybrid between81* OpenGLSurface and OpenGLTexture, in that one can render to this kind of82* surface as if it were of type OpenGLSurface, but the process of copying83* this kind of surface to another is more like an OpenGLTexture. (Note that84* "RTT" stands for "render-to-texture".)85*86* In addition to these SurfaceType variants, we have also defined some87* constants that describe in more detail the type of underlying OpenGL88* surface. This table helps explain the relationships between those89* "type" constants and their corresponding SurfaceType:90*91* OGL Type Corresponding SurfaceType92* -------- -------------------------93* WINDOW OpenGLSurface94* TEXTURE OpenGLTexture95* FLIP_BACKBUFFER OpenGLSurface96* FBOBJECT OpenGLSurfaceRTT97*/98public abstract class OGLSurfaceData extends SurfaceData99implements AccelSurface {100101/**102* OGL-specific surface types103*104* @see sun.java2d.pipe.hw.AccelSurface105*/106public static final int FBOBJECT = RT_TEXTURE;107108/**109* Pixel formats110*/111public static final int PF_INT_ARGB = 0;112public static final int PF_INT_ARGB_PRE = 1;113public static final int PF_INT_RGB = 2;114public static final int PF_INT_RGBX = 3;115public static final int PF_INT_BGR = 4;116public static final int PF_INT_BGRX = 5;117public static final int PF_USHORT_565_RGB = 6;118public static final int PF_USHORT_555_RGB = 7;119public static final int PF_USHORT_555_RGBX = 8;120public static final int PF_BYTE_GRAY = 9;121public static final int PF_USHORT_GRAY = 10;122public static final int PF_3BYTE_BGR = 11;123124/**125* SurfaceTypes126*/127private static final String DESC_OPENGL_SURFACE = "OpenGL Surface";128private static final String DESC_OPENGL_SURFACE_RTT =129"OpenGL Surface (render-to-texture)";130private static final String DESC_OPENGL_TEXTURE = "OpenGL Texture";131132static final SurfaceType OpenGLSurface =133SurfaceType.Any.deriveSubType(DESC_OPENGL_SURFACE,134PixelConverter.ArgbPre.instance);135static final SurfaceType OpenGLSurfaceRTT =136OpenGLSurface.deriveSubType(DESC_OPENGL_SURFACE_RTT);137static final SurfaceType OpenGLTexture =138SurfaceType.Any.deriveSubType(DESC_OPENGL_TEXTURE);139140/** This will be true if the fbobject system property has been enabled. */141private static boolean isFBObjectEnabled;142143/** This will be true if the lcdshader system property has been enabled.*/144private static boolean isLCDShaderEnabled;145146/** This will be true if the biopshader system property has been enabled.*/147private static boolean isBIOpShaderEnabled;148149/** This will be true if the gradshader system property has been enabled.*/150private static boolean isGradShaderEnabled;151152private OGLGraphicsConfig graphicsConfig;153protected int type;154// these fields are set from the native code when the surface is155// initialized156private int nativeWidth, nativeHeight;157158protected static OGLRenderer oglRenderPipe;159protected static PixelToParallelogramConverter oglTxRenderPipe;160protected static ParallelogramPipe oglAAPgramPipe;161protected static OGLTextRenderer oglTextPipe;162protected static OGLDrawImage oglImagePipe;163164protected native boolean initTexture(long pData,165boolean isOpaque, boolean texNonPow2,166boolean texRect,167int width, int height);168protected native boolean initFBObject(long pData,169boolean isOpaque, boolean texNonPow2,170boolean texRect,171int width, int height);172protected native boolean initFlipBackbuffer(long pData);173174private native int getTextureTarget(long pData);175private native int getTextureID(long pData);176177static {178if (!GraphicsEnvironment.isHeadless()) {179// fbobject currently enabled by default; use "false" to disable180@SuppressWarnings("removal")181String fbo = java.security.AccessController.doPrivileged(182new sun.security.action.GetPropertyAction(183"sun.java2d.opengl.fbobject"));184isFBObjectEnabled = !"false".equals(fbo);185186// lcdshader currently enabled by default; use "false" to disable187@SuppressWarnings("removal")188String lcd = java.security.AccessController.doPrivileged(189new sun.security.action.GetPropertyAction(190"sun.java2d.opengl.lcdshader"));191isLCDShaderEnabled = !"false".equals(lcd);192193// biopshader currently enabled by default; use "false" to disable194@SuppressWarnings("removal")195String biop = java.security.AccessController.doPrivileged(196new sun.security.action.GetPropertyAction(197"sun.java2d.opengl.biopshader"));198isBIOpShaderEnabled = !"false".equals(biop);199200// gradshader currently enabled by default; use "false" to disable201@SuppressWarnings("removal")202String grad = java.security.AccessController.doPrivileged(203new sun.security.action.GetPropertyAction(204"sun.java2d.opengl.gradshader"));205isGradShaderEnabled = !"false".equals(grad);206207OGLRenderQueue rq = OGLRenderQueue.getInstance();208oglImagePipe = new OGLDrawImage();209oglTextPipe = new OGLTextRenderer(rq);210oglRenderPipe = new OGLRenderer(rq);211if (GraphicsPrimitive.tracingEnabled()) {212oglTextPipe = oglTextPipe.traceWrap();213//The wrapped oglRenderPipe will wrap the AA pipe as well...214//oglAAPgramPipe = oglRenderPipe.traceWrap();215}216oglAAPgramPipe = oglRenderPipe.getAAParallelogramPipe();217oglTxRenderPipe =218new PixelToParallelogramConverter(oglRenderPipe,219oglRenderPipe,2201.0, 0.25, true);221222OGLBlitLoops.register();223OGLMaskFill.register();224OGLMaskBlit.register();225}226}227228protected OGLSurfaceData(OGLGraphicsConfig gc,229ColorModel cm, int type)230{231super(getCustomSurfaceType(type), cm);232this.graphicsConfig = gc;233this.type = type;234setBlitProxyKey(gc.getProxyKey());235}236237@Override238public SurfaceDataProxy makeProxyFor(SurfaceData srcData) {239return OGLSurfaceDataProxy.createProxy(srcData, graphicsConfig);240}241242/**243* Returns the appropriate SurfaceType corresponding to the given OpenGL244* surface type constant (e.g. TEXTURE -> OpenGLTexture).245*/246private static SurfaceType getCustomSurfaceType(int oglType) {247switch (oglType) {248case TEXTURE:249return OpenGLTexture;250case FBOBJECT:251return OpenGLSurfaceRTT;252default:253return OpenGLSurface;254}255}256257/**258* Note: This should only be called from the QFT under the AWT lock.259* This method is kept separate from the initSurface() method below just260* to keep the code a bit cleaner.261*/262private void initSurfaceNow(int width, int height) {263boolean isOpaque = (getTransparency() == Transparency.OPAQUE);264boolean success = false;265266switch (type) {267case TEXTURE:268success = initTexture(getNativeOps(),269isOpaque, isTexNonPow2Available(),270isTexRectAvailable(),271width, height);272break;273274case FBOBJECT:275success = initFBObject(getNativeOps(),276isOpaque, isTexNonPow2Available(),277isTexRectAvailable(),278width, height);279break;280281case FLIP_BACKBUFFER:282success = initFlipBackbuffer(getNativeOps());283break;284285default:286break;287}288289if (!success) {290throw new OutOfMemoryError("can't create offscreen surface");291}292}293294/**295* Initializes the appropriate OpenGL offscreen surface based on the value296* of the type parameter. If the surface creation fails for any reason,297* an OutOfMemoryError will be thrown.298*/299protected void initSurface(final int width, final int height) {300OGLRenderQueue rq = OGLRenderQueue.getInstance();301rq.lock();302try {303switch (type) {304case TEXTURE:305case FBOBJECT:306// need to make sure the context is current before307// creating the texture or fbobject308OGLContext.setScratchSurface(graphicsConfig);309break;310default:311break;312}313rq.flushAndInvokeNow(new Runnable() {314public void run() {315initSurfaceNow(width, height);316}317});318} finally {319rq.unlock();320}321}322323/**324* Returns the OGLContext for the GraphicsConfig associated with this325* surface.326*/327public final OGLContext getContext() {328return graphicsConfig.getContext();329}330331/**332* Returns the OGLGraphicsConfig associated with this surface.333*/334final OGLGraphicsConfig getOGLGraphicsConfig() {335return graphicsConfig;336}337338/**339* Returns one of the surface type constants defined above.340*/341public final int getType() {342return type;343}344345/**346* If this surface is backed by a texture object, returns the target347* for that texture (either GL_TEXTURE_2D or GL_TEXTURE_RECTANGLE_ARB).348* Otherwise, this method will return zero.349*/350public final int getTextureTarget() {351return getTextureTarget(getNativeOps());352}353354/**355* If this surface is backed by a texture object, returns the texture ID356* for that texture.357* Otherwise, this method will return zero.358*/359public final int getTextureID() {360return getTextureID(getNativeOps());361}362363/**364* Returns native resource of specified {@code resType} associated with365* this surface.366*367* Specifically, for {@code OGLSurfaceData} this method returns the368* the following:369* <pre>370* TEXTURE - texture id371* </pre>372*373* Note: the resource returned by this method is only valid on the rendering374* thread.375*376* @return native resource of specified type or 0L if377* such resource doesn't exist or can not be retrieved.378* @see sun.java2d.pipe.hw.AccelSurface#getNativeResource379*/380public long getNativeResource(int resType) {381if (resType == TEXTURE) {382return getTextureID();383}384return 0L;385}386387public Raster getRaster(int x, int y, int w, int h) {388throw new InternalError("not implemented yet");389}390391/**392* For now, we can only render LCD text if:393* - the fragment shader extension is available, and394* - the source color is opaque, and395* - blending is SrcOverNoEa or disabled396* - and the destination is opaque397*398* Eventually, we could enhance the native OGL text rendering code399* and remove the above restrictions, but that would require significantly400* more code just to support a few uncommon cases.401*/402public boolean canRenderLCDText(SunGraphics2D sg2d) {403return404graphicsConfig.isCapPresent(CAPS_EXT_LCD_SHADER) &&405sg2d.surfaceData.getTransparency() == Transparency.OPAQUE &&406sg2d.paintState <= SunGraphics2D.PAINT_OPAQUECOLOR &&407(sg2d.compositeState <= SunGraphics2D.COMP_ISCOPY ||408(sg2d.compositeState <= SunGraphics2D.COMP_ALPHA && canHandleComposite(sg2d.composite)));409}410411private boolean canHandleComposite(Composite c) {412if (c instanceof AlphaComposite) {413AlphaComposite ac = (AlphaComposite)c;414415return ac.getRule() == AlphaComposite.SRC_OVER && ac.getAlpha() >= 1f;416}417return false;418}419420public void validatePipe(SunGraphics2D sg2d) {421TextPipe textpipe;422boolean validated = false;423424// OGLTextRenderer handles both AA and non-AA text, but425// only works with the following modes:426// (Note: For LCD text we only enter this code path if427// canRenderLCDText() has already validated that the mode is428// CompositeType.SrcNoEa (opaque color), which will be subsumed429// by the CompositeType.SrcNoEa (any color) test below.)430431if (/* CompositeType.SrcNoEa (any color) */432(sg2d.compositeState <= SunGraphics2D.COMP_ISCOPY &&433sg2d.paintState <= SunGraphics2D.PAINT_ALPHACOLOR) ||434435/* CompositeType.SrcOver (any color) */436(sg2d.compositeState == SunGraphics2D.COMP_ALPHA &&437sg2d.paintState <= SunGraphics2D.PAINT_ALPHACOLOR &&438(((AlphaComposite)sg2d.composite).getRule() ==439AlphaComposite.SRC_OVER)) ||440441/* CompositeType.Xor (any color) */442(sg2d.compositeState == SunGraphics2D.COMP_XOR &&443sg2d.paintState <= SunGraphics2D.PAINT_ALPHACOLOR))444{445textpipe = oglTextPipe;446} else {447// do this to initialize textpipe correctly; we will attempt448// to override the non-text pipes below449super.validatePipe(sg2d);450textpipe = sg2d.textpipe;451validated = true;452}453454PixelToParallelogramConverter txPipe = null;455OGLRenderer nonTxPipe = null;456457if (sg2d.antialiasHint != SunHints.INTVAL_ANTIALIAS_ON) {458if (sg2d.paintState <= SunGraphics2D.PAINT_ALPHACOLOR) {459if (sg2d.compositeState <= SunGraphics2D.COMP_XOR) {460txPipe = oglTxRenderPipe;461nonTxPipe = oglRenderPipe;462}463} else if (sg2d.compositeState <= SunGraphics2D.COMP_ALPHA) {464if (OGLPaints.isValid(sg2d)) {465txPipe = oglTxRenderPipe;466nonTxPipe = oglRenderPipe;467}468// custom paints handled by super.validatePipe() below469}470} else {471if (sg2d.paintState <= SunGraphics2D.PAINT_ALPHACOLOR) {472if (graphicsConfig.isCapPresent(CAPS_PS30) &&473(sg2d.imageComp == CompositeType.SrcOverNoEa ||474sg2d.imageComp == CompositeType.SrcOver))475{476if (!validated) {477super.validatePipe(sg2d);478validated = true;479}480PixelToParallelogramConverter aaConverter =481new PixelToParallelogramConverter(sg2d.shapepipe,482oglAAPgramPipe,4831.0/8.0, 0.499,484false);485sg2d.drawpipe = aaConverter;486sg2d.fillpipe = aaConverter;487sg2d.shapepipe = aaConverter;488} else if (sg2d.compositeState == SunGraphics2D.COMP_XOR) {489// install the solid pipes when AA and XOR are both enabled490txPipe = oglTxRenderPipe;491nonTxPipe = oglRenderPipe;492}493}494// other cases handled by super.validatePipe() below495}496497if (txPipe != null) {498if (sg2d.transformState >= SunGraphics2D.TRANSFORM_TRANSLATESCALE) {499sg2d.drawpipe = txPipe;500sg2d.fillpipe = txPipe;501} else if (sg2d.strokeState != SunGraphics2D.STROKE_THIN) {502sg2d.drawpipe = txPipe;503sg2d.fillpipe = nonTxPipe;504} else {505sg2d.drawpipe = nonTxPipe;506sg2d.fillpipe = nonTxPipe;507}508// Note that we use the transforming pipe here because it509// will examine the shape and possibly perform an optimized510// operation if it can be simplified. The simplifications511// will be valid for all STROKE and TRANSFORM types.512sg2d.shapepipe = txPipe;513} else {514if (!validated) {515super.validatePipe(sg2d);516}517}518519// install the text pipe based on our earlier decision520sg2d.textpipe = textpipe;521522// always override the image pipe with the specialized OGL pipe523sg2d.imagepipe = oglImagePipe;524}525526@Override527protected MaskFill getMaskFill(SunGraphics2D sg2d) {528if (sg2d.paintState > SunGraphics2D.PAINT_ALPHACOLOR) {529/*530* We can only accelerate non-Color MaskFill operations if531* all of the following conditions hold true:532* - there is an implementation for the given paintState533* - the current Paint can be accelerated for this destination534* - multitexturing is available (since we need to modulate535* the alpha mask texture with the paint texture)536*537* In all other cases, we return null, in which case the538* validation code will choose a more general software-based loop.539*/540if (!OGLPaints.isValid(sg2d) ||541!graphicsConfig.isCapPresent(CAPS_MULTITEXTURE))542{543return null;544}545}546return super.getMaskFill(sg2d);547}548549@Override550public boolean copyArea(SunGraphics2D sg2d, int x, int y, int w, int h,551int dx, int dy) {552if (sg2d.compositeState >= SunGraphics2D.COMP_XOR) {553return false;554}555oglRenderPipe.copyArea(sg2d, x, y, w, h, dx, dy);556return true;557}558559public void flush() {560invalidate();561OGLRenderQueue rq = OGLRenderQueue.getInstance();562rq.lock();563try {564// make sure we have a current context before565// disposing the native resources (e.g. texture object)566OGLContext.setScratchSurface(graphicsConfig);567568RenderBuffer buf = rq.getBuffer();569rq.ensureCapacityAndAlignment(12, 4);570buf.putInt(FLUSH_SURFACE);571buf.putLong(getNativeOps());572573// this call is expected to complete synchronously, so flush now574rq.flushNow();575} finally {576rq.unlock();577}578}579580/**581* Disposes the native resources associated with the given OGLSurfaceData582* (referenced by the pData parameter). This method is invoked from583* the native Dispose() method from the Disposer thread when the584* Java-level OGLSurfaceData object is about to go away. Note that we585* also pass a reference to the OGLGraphicsConfig586* for the purposes of making a context current.587*/588static void dispose(long pData, OGLGraphicsConfig gc) {589OGLRenderQueue rq = OGLRenderQueue.getInstance();590rq.lock();591try {592// make sure we have a current context before593// disposing the native resources (e.g. texture object)594OGLContext.setScratchSurface(gc);595596RenderBuffer buf = rq.getBuffer();597rq.ensureCapacityAndAlignment(12, 4);598buf.putInt(DISPOSE_SURFACE);599buf.putLong(pData);600601// this call is expected to complete synchronously, so flush now602rq.flushNow();603} finally {604rq.unlock();605}606}607608static void swapBuffers(long window) {609OGLRenderQueue rq = OGLRenderQueue.getInstance();610rq.lock();611try {612RenderBuffer buf = rq.getBuffer();613rq.ensureCapacityAndAlignment(12, 4);614buf.putInt(SWAP_BUFFERS);615buf.putLong(window);616rq.flushNow();617} finally {618rq.unlock();619}620}621622/**623* Returns true if OpenGL textures can have non-power-of-two dimensions624* when using the basic GL_TEXTURE_2D target.625*/626boolean isTexNonPow2Available() {627return graphicsConfig.isCapPresent(CAPS_TEXNONPOW2);628}629630/**631* Returns true if OpenGL textures can have non-power-of-two dimensions632* when using the GL_TEXTURE_RECTANGLE_ARB target (only available when the633* GL_ARB_texture_rectangle extension is present).634*/635boolean isTexRectAvailable() {636return graphicsConfig.isCapPresent(CAPS_EXT_TEXRECT);637}638639public Rectangle getNativeBounds() {640OGLRenderQueue rq = OGLRenderQueue.getInstance();641rq.lock();642try {643return new Rectangle(nativeWidth, nativeHeight);644} finally {645rq.unlock();646}647}648649/**650* Returns true if the surface is an on-screen window surface or651* a FBO texture attached to an on-screen CALayer.652*653* Needed by Mac OS X port.654*/655boolean isOnScreen() {656return getType() == WINDOW;657}658}659660661