1 /*
2  * Copyright (c) 2007, 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.d3d;
27 
28 import java.awt.Component;
29 import java.awt.GraphicsConfiguration;
30 import java.awt.Image;
31 import java.awt.Transparency;
32 import java.awt.image.ColorModel;
33 
34 import sun.awt.AWTAccessor;
35 import sun.awt.AWTAccessor.ComponentAccessor;
36 import sun.awt.Win32GraphicsConfig;
37 import sun.awt.image.SunVolatileImage;
38 import sun.awt.image.SurfaceManager;
39 import sun.awt.image.VolatileSurfaceManager;
40 import sun.awt.windows.WComponentPeer;
41 import sun.java2d.InvalidPipeException;
42 import sun.java2d.SurfaceData;
43 import static sun.java2d.pipe.hw.AccelSurface.*;
44 import static sun.java2d.d3d.D3DContext.D3DContextCaps.*;
45 import sun.java2d.windows.GDIWindowSurfaceData;
46 
47 public class D3DVolatileSurfaceManager
48     extends VolatileSurfaceManager
49 {
50     private boolean accelerationEnabled;
51     private int restoreCountdown;
52 
D3DVolatileSurfaceManager(SunVolatileImage vImg, Object context)53     public D3DVolatileSurfaceManager(SunVolatileImage vImg, Object context) {
54         super(vImg, context);
55 
56         /*
57          * We will attempt to accelerate this image only under the
58          * following conditions:
59          *   - the image is opaque OR
60          *   - the image is translucent AND
61          *       - the GraphicsConfig supports the FBO extension OR
62          *       - the GraphicsConfig has a stored alpha channel
63          */
64         int transparency = vImg.getTransparency();
65         D3DGraphicsDevice gd = (D3DGraphicsDevice)
66             vImg.getGraphicsConfig().getDevice();
67         accelerationEnabled =
68             (transparency == Transparency.OPAQUE) ||
69             (transparency == Transparency.TRANSLUCENT &&
70              (gd.isCapPresent(CAPS_RT_PLAIN_ALPHA) ||
71               gd.isCapPresent(CAPS_RT_TEXTURE_ALPHA)));
72     }
73 
isAccelerationEnabled()74     protected boolean isAccelerationEnabled() {
75         return accelerationEnabled;
76     }
setAccelerationEnabled(boolean accelerationEnabled)77     public void setAccelerationEnabled(boolean accelerationEnabled) {
78         this.accelerationEnabled = accelerationEnabled;
79     }
80 
81     /**
82      * Create a pbuffer-based SurfaceData object (or init the backbuffer
83      * of an existing window if this is a double buffered GraphicsConfig).
84      */
initAcceleratedSurface()85     protected SurfaceData initAcceleratedSurface() {
86         SurfaceData sData;
87         Component comp = vImg.getComponent();
88         final ComponentAccessor acc = AWTAccessor.getComponentAccessor();
89         WComponentPeer peer = (comp != null) ? acc.getPeer(comp) : null;
90 
91         try {
92             boolean forceback = false;
93             if (context instanceof Boolean) {
94                 forceback = ((Boolean)context).booleanValue();
95             }
96 
97             if (forceback) {
98                 // peer must be non-null in this case
99                 sData = D3DSurfaceData.createData(peer, vImg);
100             } else {
101                 D3DGraphicsConfig gc =
102                     (D3DGraphicsConfig)vImg.getGraphicsConfig();
103                 ColorModel cm = gc.getColorModel(vImg.getTransparency());
104                 int type = vImg.getForcedAccelSurfaceType();
105                 // if acceleration type is forced (type != UNDEFINED) then
106                 // use the forced type, otherwise use RT_TEXTURE
107                 if (type == UNDEFINED) {
108                     type = RT_TEXTURE;
109                 }
110                 sData = D3DSurfaceData.createData(gc,
111                                                   vImg.getWidth(),
112                                                   vImg.getHeight(),
113                                                   cm, vImg,
114                                                   type);
115             }
116         } catch (NullPointerException ex) {
117             sData = null;
118         } catch (OutOfMemoryError er) {
119             sData = null;
120         } catch (InvalidPipeException ipe) {
121             sData = null;
122         }
123 
124         return sData;
125     }
126 
isConfigValid(GraphicsConfiguration gc)127     protected boolean isConfigValid(GraphicsConfiguration gc) {
128         return ((gc == null) || (gc == vImg.getGraphicsConfig()));
129     }
130 
131     /**
132      * Set the number of iterations for restoreAcceleratedSurface to fail
133      * before attempting to restore the accelerated surface.
134      *
135      * @see #restoreAcceleratedSurface
136      * @see #handleVItoScreenOp
137      */
setRestoreCountdown(int count)138     private synchronized void setRestoreCountdown(int count) {
139         restoreCountdown = count;
140     }
141 
142     /**
143      * Note that we create a new surface instead of restoring
144      * an old one. This will help with D3DContext revalidation.
145      */
146     @Override
restoreAcceleratedSurface()147     protected void restoreAcceleratedSurface() {
148         synchronized (this) {
149             if (restoreCountdown > 0) {
150                 restoreCountdown--;
151                 throw new
152                     InvalidPipeException("Will attempt to restore surface " +
153                                           " in " + restoreCountdown);
154             }
155         }
156 
157         SurfaceData sData = initAcceleratedSurface();
158         if (sData != null) {
159             sdAccel = sData;
160         } else {
161             throw new InvalidPipeException("could not restore surface");
162             // REMIND: alternatively, we could try this:
163 //            ((D3DSurfaceData)sdAccel).restoreSurface();
164         }
165     }
166 
167     /**
168      * We're asked to restore contents by the accelerated surface, which means
169      * that it had been lost.
170      */
171     @Override
restoreContents()172     public SurfaceData restoreContents() {
173         acceleratedSurfaceLost();
174         return super.restoreContents();
175     }
176 
177     /**
178      * If the destination surface's peer can potentially handle accelerated
179      * on-screen rendering then it is likely that the condition which resulted
180      * in VI to Screen operation is temporary, so this method sets the
181      * restore countdown in hope that the on-screen accelerated rendering will
182      * resume. In the meantime the backup surface of the VISM will be used.
183      *
184      * The countdown is needed because otherwise we may never break out
185      * of "do { vi.validate()..} while(vi.lost)" loop since validate() could
186      * restore the source surface every time and it will get lost again on the
187      * next copy attempt, and we would never get a chance to use the backup
188      * surface. By using the countdown we allow the backup surface to be used
189      * while the screen surface gets sorted out, or if it for some reason can
190      * never be restored.
191      *
192      * If the destination surface's peer could never do accelerated onscreen
193      * rendering then the acceleration for the SurfaceManager associated with
194      * the source surface is disabled forever.
195      */
handleVItoScreenOp(SurfaceData src, SurfaceData dst)196     static void handleVItoScreenOp(SurfaceData src, SurfaceData dst) {
197         if (src instanceof D3DSurfaceData &&
198             dst instanceof GDIWindowSurfaceData)
199         {
200             D3DSurfaceData d3dsd = (D3DSurfaceData)src;
201             SurfaceManager mgr =
202                 SurfaceManager.getManager((Image)d3dsd.getDestination());
203             if (mgr instanceof D3DVolatileSurfaceManager) {
204                 D3DVolatileSurfaceManager vsm = (D3DVolatileSurfaceManager)mgr;
205                 if (vsm != null) {
206                     d3dsd.setSurfaceLost(true);
207 
208                     GDIWindowSurfaceData wsd = (GDIWindowSurfaceData)dst;
209                     WComponentPeer p = wsd.getPeer();
210                     if (D3DScreenUpdateManager.canUseD3DOnScreen(p,
211                             (Win32GraphicsConfig)p.getGraphicsConfiguration(),
212                             p.getBackBuffersNum()))
213                     {
214                         // 10 is only chosen to be greater than the number of
215                         // times a sane person would call validate() inside
216                         // a validation loop, and to reduce thrashing between
217                         // accelerated and backup surfaces
218                         vsm.setRestoreCountdown(10);
219                     } else {
220                         vsm.setAccelerationEnabled(false);
221                     }
222                 }
223             }
224         }
225     }
226 
227     @Override
initContents()228     public void initContents() {
229         if (vImg.getForcedAccelSurfaceType() != TEXTURE) {
230             super.initContents();
231         }
232     }
233 }
234