HardwareLayer.java revision e4267ea4f20740c37c01bfb6aefcf61fddc4566a
1/*
2 * Copyright (C) 2011 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.view;
18
19import android.graphics.Bitmap;
20import android.graphics.Matrix;
21import android.graphics.Paint;
22import android.graphics.Rect;
23import android.graphics.SurfaceTexture;
24
25import com.android.internal.util.VirtualRefBasePtr;
26
27/**
28 * A hardware layer can be used to render graphics operations into a hardware
29 * friendly buffer. For instance, with an OpenGL backend a hardware layer
30 * would use a Frame Buffer Object (FBO.) The hardware layer can be used as
31 * a drawing cache when a complex set of graphics operations needs to be
32 * drawn several times.
33 *
34 * @hide
35 */
36final class HardwareLayer {
37    private static final int LAYER_TYPE_TEXTURE = 1;
38    private static final int LAYER_TYPE_DISPLAY_LIST = 2;
39
40    private HardwareRenderer mRenderer;
41    private VirtualRefBasePtr mFinalizer;
42    private RenderNode mDisplayList;
43    private final int mLayerType;
44
45    private HardwareLayer(HardwareRenderer renderer, long deferredUpdater, int type) {
46        if (renderer == null || deferredUpdater == 0) {
47            throw new IllegalArgumentException("Either hardware renderer: " + renderer
48                    + " or deferredUpdater: " + deferredUpdater + " is invalid");
49        }
50        mRenderer = renderer;
51        mLayerType = type;
52        mFinalizer = new VirtualRefBasePtr(deferredUpdater);
53    }
54
55    private void assertType(int type) {
56        if (mLayerType != type) {
57            throw new IllegalAccessError("Method not appropriate for this layer type! " + mLayerType);
58        }
59    }
60
61    boolean hasDisplayList() {
62        return mDisplayList != null;
63    }
64
65    /**
66     * Update the paint used when drawing this layer.
67     *
68     * @param paint The paint used when the layer is drawn into the destination canvas.
69     * @see View#setLayerPaint(android.graphics.Paint)
70     */
71    public void setLayerPaint(Paint paint) {
72        nSetLayerPaint(mFinalizer.get(), paint.mNativePaint);
73        mRenderer.pushLayerUpdate(this);
74    }
75
76    /**
77     * Indicates whether this layer can be rendered.
78     *
79     * @return True if the layer can be rendered into, false otherwise
80     */
81    public boolean isValid() {
82        return mFinalizer != null && mFinalizer.get() != 0;
83    }
84
85    /**
86     * Destroys resources without waiting for a GC.
87     */
88    public void destroy() {
89        if (!isValid()) {
90            // Already destroyed
91            return;
92        }
93
94        if (mDisplayList != null) {
95            mDisplayList.destroyDisplayListData();
96            mDisplayList = null;
97        }
98        mRenderer.onLayerDestroyed(this);
99        mRenderer = null;
100        mFinalizer.release();
101        mFinalizer = null;
102    }
103
104    public long getDeferredLayerUpdater() {
105        return mFinalizer.get();
106    }
107
108    public RenderNode startRecording() {
109        assertType(LAYER_TYPE_DISPLAY_LIST);
110
111        if (mDisplayList == null) {
112            mDisplayList = RenderNode.create("HardwareLayer");
113        }
114        return mDisplayList;
115    }
116
117    public void endRecording(Rect dirtyRect) {
118        nUpdateRenderLayer(mFinalizer.get(), mDisplayList.getNativeDisplayList(),
119                dirtyRect.left, dirtyRect.top, dirtyRect.right, dirtyRect.bottom);
120        mRenderer.pushLayerUpdate(this);
121    }
122
123    /**
124     * Copies this layer into the specified bitmap.
125     *
126     * @param bitmap The bitmap to copy they layer into
127     *
128     * @return True if the copy was successful, false otherwise
129     */
130    public boolean copyInto(Bitmap bitmap) {
131        return mRenderer.copyLayerInto(this, bitmap);
132    }
133
134    /**
135     * Update the layer's properties. Note that after calling this isValid() may
136     * return false if the requested width/height cannot be satisfied
137     *
138     * @param width The new width of this layer
139     * @param height The new height of this layer
140     * @param isOpaque Whether this layer is opaque
141     *
142     * @return true if the layer's properties will change, false if they already
143     *         match the desired values.
144     */
145    public boolean prepare(int width, int height, boolean isOpaque) {
146        return nPrepare(mFinalizer.get(), width, height, isOpaque);
147    }
148
149    /**
150     * Sets an optional transform on this layer.
151     *
152     * @param matrix The transform to apply to the layer.
153     */
154    public void setTransform(Matrix matrix) {
155        nSetTransform(mFinalizer.get(), matrix.native_instance);
156        mRenderer.pushLayerUpdate(this);
157    }
158
159    /**
160     * Indicates that this layer has lost its texture.
161     */
162    public void detachSurfaceTexture(final SurfaceTexture surface) {
163        assertType(LAYER_TYPE_TEXTURE);
164        mRenderer.safelyRun(new Runnable() {
165            @Override
166            public void run() {
167                surface.detachFromGLContext();
168                // SurfaceTexture owns the texture name and detachFromGLContext
169                // should have deleted it
170                nOnTextureDestroyed(mFinalizer.get());
171            }
172        });
173    }
174
175    public long getLayer() {
176        return nGetLayer(mFinalizer.get());
177    }
178
179    public void setSurfaceTexture(SurfaceTexture surface) {
180        assertType(LAYER_TYPE_TEXTURE);
181        nSetSurfaceTexture(mFinalizer.get(), surface, false);
182        mRenderer.pushLayerUpdate(this);
183    }
184
185    public void updateSurfaceTexture() {
186        assertType(LAYER_TYPE_TEXTURE);
187        nUpdateSurfaceTexture(mFinalizer.get());
188        mRenderer.pushLayerUpdate(this);
189    }
190
191    /**
192     * This should only be used by HardwareRenderer! Do not call directly
193     */
194    SurfaceTexture createSurfaceTexture() {
195        assertType(LAYER_TYPE_TEXTURE);
196        SurfaceTexture st = new SurfaceTexture(nGetTexName(mFinalizer.get()));
197        nSetSurfaceTexture(mFinalizer.get(), st, true);
198        return st;
199    }
200
201    static HardwareLayer adoptTextureLayer(HardwareRenderer renderer, long layer) {
202        return new HardwareLayer(renderer, layer, LAYER_TYPE_TEXTURE);
203    }
204
205    static HardwareLayer adoptDisplayListLayer(HardwareRenderer renderer, long layer) {
206        return new HardwareLayer(renderer, layer, LAYER_TYPE_DISPLAY_LIST);
207    }
208
209    private static native void nOnTextureDestroyed(long layerUpdater);
210
211    private static native boolean nPrepare(long layerUpdater, int width, int height, boolean isOpaque);
212    private static native void nSetLayerPaint(long layerUpdater, long paint);
213    private static native void nSetTransform(long layerUpdater, long matrix);
214    private static native void nSetSurfaceTexture(long layerUpdater,
215            SurfaceTexture surface, boolean isAlreadyAttached);
216    private static native void nUpdateSurfaceTexture(long layerUpdater);
217    private static native void nUpdateRenderLayer(long layerUpdater, long displayList,
218            int left, int top, int right, int bottom);
219
220    private static native long nGetLayer(long layerUpdater);
221    private static native int nGetTexName(long layerUpdater);
222}
223