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
26package sun.java2d.d3d;
27
28import java.awt.Component;
29import java.awt.GraphicsConfiguration;
30import java.awt.Image;
31import java.awt.Transparency;
32import java.awt.image.ColorModel;
33
34import sun.awt.AWTAccessor;
35import sun.awt.AWTAccessor.ComponentAccessor;
36import sun.awt.Win32GraphicsConfig;
37import sun.awt.image.SunVolatileImage;
38import sun.awt.image.SurfaceManager;
39import sun.awt.image.VolatileSurfaceManager;
40import sun.awt.windows.WComponentPeer;
41import sun.java2d.InvalidPipeException;
42import sun.java2d.SurfaceData;
43import static sun.java2d.pipe.hw.AccelSurface.*;
44import static sun.java2d.d3d.D3DContext.D3DContextCaps.*;
45import sun.java2d.windows.GDIWindowSurfaceData;
46
47public class D3DVolatileSurfaceManager
48    extends VolatileSurfaceManager
49{
50    private boolean accelerationEnabled;
51    private int restoreCountdown;
52
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
74    protected boolean isAccelerationEnabled() {
75        return accelerationEnabled;
76    }
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     */
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
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     */
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
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
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     */
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
228    public void initContents() {
229        if (vImg.getForcedAccelSurfaceType() != TEXTURE) {
230            super.initContents();
231        }
232    }
233}
234