1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
|
/*
* Copyright (C) 2011 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.view;
import android.graphics.Bitmap;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.SurfaceTexture;
/**
* A hardware layer can be used to render graphics operations into a hardware
* friendly buffer. For instance, with an OpenGL backend a hardware layer
* would use a Frame Buffer Object (FBO.) The hardware layer can be used as
* a drawing cache when a complex set of graphics operations needs to be
* drawn several times.
*
* @hide
*/
final class HardwareLayer {
private static final int LAYER_TYPE_TEXTURE = 1;
private static final int LAYER_TYPE_DISPLAY_LIST = 2;
private HardwareRenderer mRenderer;
private Finalizer mFinalizer;
private DisplayList mDisplayList;
private final int mLayerType;
private HardwareLayer(HardwareRenderer renderer, long deferredUpdater, int type) {
if (renderer == null || deferredUpdater == 0) {
throw new IllegalArgumentException("Either hardware renderer: " + renderer
+ " or deferredUpdater: " + deferredUpdater + " is invalid");
}
mRenderer = renderer;
mLayerType = type;
mFinalizer = new Finalizer(deferredUpdater);
// Layer is considered initialized at this point, notify the HardwareRenderer
mRenderer.onLayerCreated(this);
}
private void assertType(int type) {
if (mLayerType != type) {
throw new IllegalAccessError("Method not appropriate for this layer type! " + mLayerType);
}
}
/**
* Update the paint used when drawing this layer.
*
* @param paint The paint used when the layer is drawn into the destination canvas.
* @see View#setLayerPaint(android.graphics.Paint)
*/
public void setLayerPaint(Paint paint) {
nSetLayerPaint(mFinalizer.mDeferredUpdater, paint.mNativePaint,
paint.getColorFilter() != null ? paint.getColorFilter().native_instance : 0);
}
/**
* Indicates whether this layer can be rendered.
*
* @return True if the layer can be rendered into, false otherwise
*/
public boolean isValid() {
return mFinalizer != null && mFinalizer.mDeferredUpdater != 0;
}
/**
* Destroys resources without waiting for a GC.
*/
public void destroy() {
if (!isValid()) {
// Already destroyed
return;
}
if (mDisplayList != null) {
mDisplayList.reset();
mDisplayList = null;
}
if (mRenderer != null) {
mRenderer.onLayerDestroyed(this);
mRenderer = null;
}
doDestroyLayerUpdater();
}
public long getDeferredLayerUpdater() {
return mFinalizer.mDeferredUpdater;
}
/**
* Destroys the deferred layer updater but not the backing layer. The
* backing layer is instead returned and is the caller's responsibility
* to destroy/recycle as appropriate.
*
* It is safe to call this in onLayerDestroyed only
*/
public long detachBackingLayer() {
long backingLayer = nDetachBackingLayer(mFinalizer.mDeferredUpdater);
doDestroyLayerUpdater();
return backingLayer;
}
private void doDestroyLayerUpdater() {
if (mFinalizer != null) {
mFinalizer.destroy();
mFinalizer = null;
}
}
public DisplayList startRecording() {
assertType(LAYER_TYPE_DISPLAY_LIST);
if (mDisplayList == null) {
mDisplayList = DisplayList.create("HardwareLayer");
}
return mDisplayList;
}
public void endRecording(Rect dirtyRect) {
nUpdateRenderLayer(mFinalizer.mDeferredUpdater, mDisplayList.getNativeDisplayList(),
dirtyRect.left, dirtyRect.top, dirtyRect.right, dirtyRect.bottom);
mRenderer.pushLayerUpdate(this);
}
/**
* Copies this layer into the specified bitmap.
*
* @param bitmap The bitmap to copy they layer into
*
* @return True if the copy was successful, false otherwise
*/
public boolean copyInto(Bitmap bitmap) {
return mRenderer.copyLayerInto(this, bitmap);
}
/**
* Update the layer's properties. Note that after calling this isValid() may
* return false if the requested width/height cannot be satisfied
*
* @param width The new width of this layer
* @param height The new height of this layer
* @param isOpaque Whether this layer is opaque
*
* @return true if the layer's properties will change, false if they already
* match the desired values.
*/
public boolean prepare(int width, int height, boolean isOpaque) {
return nPrepare(mFinalizer.mDeferredUpdater, width, height, isOpaque);
}
/**
* Sets an optional transform on this layer.
*
* @param matrix The transform to apply to the layer.
*/
public void setTransform(Matrix matrix) {
nSetTransform(mFinalizer.mDeferredUpdater, matrix.native_instance);
}
/**
* Indicates that this layer has lost its texture.
*/
public void detachSurfaceTexture(final SurfaceTexture surface) {
assertType(LAYER_TYPE_TEXTURE);
mRenderer.safelyRun(new Runnable() {
@Override
public void run() {
surface.detachFromGLContext();
// SurfaceTexture owns the texture name and detachFromGLContext
// should have deleted it
nOnTextureDestroyed(mFinalizer.mDeferredUpdater);
}
});
}
/**
* This exists to minimize impact into the current HardwareLayer paths as
* some of the specifics of how to handle error cases in the fully
* deferred model will work
*/
@Deprecated
public void flushChanges() {
if (HardwareRenderer.sUseRenderThread) {
// Not supported, don't try.
return;
}
boolean success = nFlushChanges(mFinalizer.mDeferredUpdater);
if (!success) {
destroy();
}
}
public long getLayer() {
return nGetLayer(mFinalizer.mDeferredUpdater);
}
public void setSurfaceTexture(SurfaceTexture surface) {
assertType(LAYER_TYPE_TEXTURE);
nSetSurfaceTexture(mFinalizer.mDeferredUpdater, surface, false);
}
public void updateSurfaceTexture() {
assertType(LAYER_TYPE_TEXTURE);
nUpdateSurfaceTexture(mFinalizer.mDeferredUpdater);
}
/**
* This should only be used by HardwareRenderer! Do not call directly
*/
SurfaceTexture createSurfaceTexture() {
assertType(LAYER_TYPE_TEXTURE);
SurfaceTexture st = new SurfaceTexture(nGetTexName(mFinalizer.mDeferredUpdater));
nSetSurfaceTexture(mFinalizer.mDeferredUpdater, st, true);
return st;
}
/**
* This should only be used by HardwareRenderer! Do not call directly
*/
static HardwareLayer createTextureLayer(HardwareRenderer renderer) {
return new HardwareLayer(renderer, nCreateTextureLayer(), LAYER_TYPE_TEXTURE);
}
static HardwareLayer adoptTextureLayer(HardwareRenderer renderer, long layer) {
return new HardwareLayer(renderer, layer, LAYER_TYPE_TEXTURE);
}
/**
* This should only be used by HardwareRenderer! Do not call directly
*/
static HardwareLayer createDisplayListLayer(HardwareRenderer renderer,
int width, int height) {
return new HardwareLayer(renderer, nCreateRenderLayer(width, height), LAYER_TYPE_DISPLAY_LIST);
}
static HardwareLayer adoptDisplayListLayer(HardwareRenderer renderer, long layer) {
return new HardwareLayer(renderer, layer, LAYER_TYPE_DISPLAY_LIST);
}
/** This also creates the underlying layer */
private static native long nCreateTextureLayer();
private static native long nCreateRenderLayer(int width, int height);
private static native void nOnTextureDestroyed(long layerUpdater);
private static native long nDetachBackingLayer(long layerUpdater);
/** This also destroys the underlying layer if it is still attached.
* Note it does not recycle the underlying layer, but instead queues it
* for deferred deletion.
* The HardwareRenderer should use detachBackingLayer() in the
* onLayerDestroyed() callback to do recycling if desired.
*/
private static native void nDestroyLayerUpdater(long layerUpdater);
private static native boolean nPrepare(long layerUpdater, int width, int height, boolean isOpaque);
private static native void nSetLayerPaint(long layerUpdater, long paint, long colorFilter);
private static native void nSetTransform(long layerUpdater, long matrix);
private static native void nSetSurfaceTexture(long layerUpdater,
SurfaceTexture surface, boolean isAlreadyAttached);
private static native void nUpdateSurfaceTexture(long layerUpdater);
private static native void nUpdateRenderLayer(long layerUpdater, long displayList,
int left, int top, int right, int bottom);
private static native boolean nFlushChanges(long layerUpdater);
private static native long nGetLayer(long layerUpdater);
private static native int nGetTexName(long layerUpdater);
private static class Finalizer {
private long mDeferredUpdater;
public Finalizer(long deferredUpdater) {
mDeferredUpdater = deferredUpdater;
}
@Override
protected void finalize() throws Throwable {
try {
destroy();
} finally {
super.finalize();
}
}
void destroy() {
if (mDeferredUpdater != 0) {
nDestroyLayerUpdater(mDeferredUpdater);
mDeferredUpdater = 0;
}
}
}
}
|