RecordedOp.h revision b87eadda1818034ce03d85f30388384d1ac65916
1/*
2 * Copyright (C) 2015 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
17#ifndef ANDROID_HWUI_RECORDED_OP_H
18#define ANDROID_HWUI_RECORDED_OP_H
19
20#include "font/FontUtil.h"
21#include "Matrix.h"
22#include "Rect.h"
23#include "RenderNode.h"
24#include "utils/LinearAllocator.h"
25#include "Vector.h"
26
27#include <androidfw/ResourceTypes.h>
28#include <SkXfermode.h>
29
30class SkBitmap;
31class SkPaint;
32
33namespace android {
34namespace uirenderer {
35
36struct ClipBase;
37class OffscreenBuffer;
38class RenderNode;
39struct Vertex;
40
41/**
42 * Authoritative op list, used for generating the op ID enum, ID based LUTS, and
43 * the functions to which they dispatch. Parameter macros are executed for each op,
44 * in order, based on the op's type.
45 *
46 * There are 4 types of op, which defines dispatch/LUT capability:
47 *
48 *              | DisplayList |   Render    |    Merge    |
49 * -------------|-------------|-------------|-------------|
50 * PRE RENDER   |     Yes     |             |             |
51 * RENDER ONLY  |             |     Yes     |             |
52 * UNMERGEABLE  |     Yes     |     Yes     |             |
53 * MERGEABLE    |     Yes     |     Yes     |     Yes     |
54 *
55 * PRE RENDER - These ops are recorded into DisplayLists, but can't be directly rendered. This
56 *      may be because they need to be transformed into other op types (e.g. CirclePropsOp),
57 *      be traversed to access multiple renderable ops within (e.g. RenderNodeOp), or because they
58 *      modify renderbuffer lifecycle, instead of directly rendering content (the various LayerOps).
59 *
60 * RENDER ONLY - These ops cannot be recorded into DisplayLists, and are instead implicitly
61 *      constructed from other commands/RenderNode properties. They cannot be merged.
62 *
63 * UNMERGEABLE - These ops can be recorded into DisplayLists and rendered directly, but do not
64 *      support merged rendering.
65 *
66 * MERGEABLE - These ops can be recorded into DisplayLists and rendered individually, or merged
67 *      under certain circumstances.
68 */
69#define MAP_OPS_BASED_ON_TYPE(PRE_RENDER_OP_FN, RENDER_ONLY_OP_FN, UNMERGEABLE_OP_FN, MERGEABLE_OP_FN) \
70        PRE_RENDER_OP_FN(RenderNodeOp) \
71        PRE_RENDER_OP_FN(CirclePropsOp) \
72        PRE_RENDER_OP_FN(RoundRectPropsOp) \
73        PRE_RENDER_OP_FN(BeginLayerOp) \
74        PRE_RENDER_OP_FN(EndLayerOp) \
75        PRE_RENDER_OP_FN(BeginUnclippedLayerOp) \
76        PRE_RENDER_OP_FN(EndUnclippedLayerOp) \
77        \
78        RENDER_ONLY_OP_FN(ShadowOp) \
79        RENDER_ONLY_OP_FN(LayerOp) \
80        RENDER_ONLY_OP_FN(CopyToLayerOp) \
81        RENDER_ONLY_OP_FN(CopyFromLayerOp) \
82        \
83        UNMERGEABLE_OP_FN(ArcOp) \
84        UNMERGEABLE_OP_FN(BitmapMeshOp) \
85        UNMERGEABLE_OP_FN(BitmapRectOp) \
86        UNMERGEABLE_OP_FN(FunctorOp) \
87        UNMERGEABLE_OP_FN(LinesOp) \
88        UNMERGEABLE_OP_FN(OvalOp) \
89        UNMERGEABLE_OP_FN(PathOp) \
90        UNMERGEABLE_OP_FN(PointsOp) \
91        UNMERGEABLE_OP_FN(RectOp) \
92        UNMERGEABLE_OP_FN(RoundRectOp) \
93        UNMERGEABLE_OP_FN(SimpleRectsOp) \
94        UNMERGEABLE_OP_FN(TextOnPathOp) \
95        UNMERGEABLE_OP_FN(TextureLayerOp) \
96        \
97        MERGEABLE_OP_FN(BitmapOp) \
98        MERGEABLE_OP_FN(PatchOp) \
99        MERGEABLE_OP_FN(TextOp)
100
101/**
102 * LUT generators, which will insert nullptr for unsupported ops
103 */
104#define NULLPTR_OP_FN(Type) nullptr,
105
106#define BUILD_DEFERRABLE_OP_LUT(OP_FN) \
107        { MAP_OPS_BASED_ON_TYPE(OP_FN, NULLPTR_OP_FN, OP_FN, OP_FN) }
108
109#define BUILD_MERGEABLE_OP_LUT(OP_FN) \
110        { MAP_OPS_BASED_ON_TYPE(NULLPTR_OP_FN, NULLPTR_OP_FN, NULLPTR_OP_FN, OP_FN) }
111
112#define BUILD_RENDERABLE_OP_LUT(OP_FN) \
113        { MAP_OPS_BASED_ON_TYPE(NULLPTR_OP_FN, OP_FN, OP_FN, OP_FN) }
114
115/**
116 * Op mapping functions, which skip unsupported ops.
117 *
118 * Note: Do not use for LUTS, since these do not preserve ID order.
119 */
120#define NULL_OP_FN(Type)
121
122#define MAP_DEFERRABLE_OPS(OP_FN) \
123        MAP_OPS_BASED_ON_TYPE(OP_FN, NULL_OP_FN, OP_FN, OP_FN)
124
125#define MAP_MERGEABLE_OPS(OP_FN) \
126        MAP_OPS_BASED_ON_TYPE(NULL_OP_FN, NULL_OP_FN, NULL_OP_FN, OP_FN)
127
128#define MAP_RENDERABLE_OPS(OP_FN) \
129        MAP_OPS_BASED_ON_TYPE(NULL_OP_FN, OP_FN, OP_FN, OP_FN)
130
131// Generate OpId enum
132#define IDENTITY_FN(Type) Type,
133namespace RecordedOpId {
134    enum {
135        MAP_OPS_BASED_ON_TYPE(IDENTITY_FN, IDENTITY_FN, IDENTITY_FN, IDENTITY_FN)
136        Count,
137    };
138}
139static_assert(RecordedOpId::RenderNodeOp == 0,
140        "First index must be zero for LUTs to work");
141
142#define BASE_PARAMS const Rect& unmappedBounds, const Matrix4& localMatrix, const ClipBase* localClip, const SkPaint* paint
143#define BASE_PARAMS_PAINTLESS const Rect& unmappedBounds, const Matrix4& localMatrix, const ClipBase* localClip
144#define SUPER(Type) RecordedOp(RecordedOpId::Type, unmappedBounds, localMatrix, localClip, paint)
145#define SUPER_PAINTLESS(Type) RecordedOp(RecordedOpId::Type, unmappedBounds, localMatrix, localClip, nullptr)
146
147struct RecordedOp {
148    /* ID from RecordedOpId - generally used for jumping into function tables */
149    const int opId;
150
151    /* bounds in *local* space, without accounting for DisplayList transformation, or stroke */
152    const Rect unmappedBounds;
153
154    /* transform in recording space (vs DisplayList origin) */
155    const Matrix4 localMatrix;
156
157    /* clip in recording space - nullptr if not clipped */
158    const ClipBase* localClip;
159
160    /* optional paint, stored in base object to simplify merging logic */
161    const SkPaint* paint;
162protected:
163    RecordedOp(unsigned int opId, BASE_PARAMS)
164            : opId(opId)
165            , unmappedBounds(unmappedBounds)
166            , localMatrix(localMatrix)
167            , localClip(localClip)
168            , paint(paint) {}
169};
170
171struct RenderNodeOp : RecordedOp {
172    RenderNodeOp(BASE_PARAMS_PAINTLESS, RenderNode* renderNode)
173            : SUPER_PAINTLESS(RenderNodeOp)
174            , renderNode(renderNode) {}
175    RenderNode * renderNode; // not const, since drawing modifies it
176
177    /**
178     * Holds the transformation between the projection surface ViewGroup and this RenderNode
179     * drawing instance. Represents any translations / transformations done within the drawing of
180     * the compositing ancestor ViewGroup's draw, before the draw of the View represented by this
181     * DisplayList draw instance.
182     *
183     * Note: doesn't include transformation within the RenderNode, or its properties.
184     */
185    Matrix4 transformFromCompositingAncestor;
186    bool skipInOrderDraw = false;
187};
188
189////////////////////////////////////////////////////////////////////////////////////////////////////
190// Standard Ops
191////////////////////////////////////////////////////////////////////////////////////////////////////
192
193struct ArcOp : RecordedOp {
194    ArcOp(BASE_PARAMS, float startAngle, float sweepAngle, bool useCenter)
195            : SUPER(ArcOp)
196            , startAngle(startAngle)
197            , sweepAngle(sweepAngle)
198            , useCenter(useCenter) {}
199    const float startAngle;
200    const float sweepAngle;
201    const bool useCenter;
202};
203
204struct BitmapOp : RecordedOp {
205    BitmapOp(BASE_PARAMS, const SkBitmap* bitmap)
206            : SUPER(BitmapOp)
207            , bitmap(bitmap) {}
208    const SkBitmap* bitmap;
209    // TODO: asset atlas/texture id lookup?
210};
211
212struct BitmapMeshOp : RecordedOp {
213    BitmapMeshOp(BASE_PARAMS, const SkBitmap* bitmap, int meshWidth, int meshHeight,
214            const float* vertices, const int* colors)
215            : SUPER(BitmapMeshOp)
216            , bitmap(bitmap)
217            , meshWidth(meshWidth)
218            , meshHeight(meshHeight)
219            , vertices(vertices)
220            , colors(colors) {}
221    const SkBitmap* bitmap;
222    const int meshWidth;
223    const int meshHeight;
224    const float* vertices;
225    const int* colors;
226};
227
228struct BitmapRectOp : RecordedOp {
229    BitmapRectOp(BASE_PARAMS, const SkBitmap* bitmap, const Rect& src)
230            : SUPER(BitmapRectOp)
231            , bitmap(bitmap)
232            , src(src) {}
233    const SkBitmap* bitmap;
234    const Rect src;
235};
236
237struct CirclePropsOp : RecordedOp {
238    CirclePropsOp(const Matrix4& localMatrix, const ClipBase* localClip, const SkPaint* paint,
239            float* x, float* y, float* radius)
240            : RecordedOp(RecordedOpId::CirclePropsOp, Rect(), localMatrix, localClip, paint)
241            , x(x)
242            , y(y)
243            , radius(radius) {}
244    const float* x;
245    const float* y;
246    const float* radius;
247};
248
249struct FunctorOp : RecordedOp {
250    FunctorOp(BASE_PARAMS_PAINTLESS, Functor* functor)
251            : SUPER_PAINTLESS(FunctorOp)
252            , functor(functor) {}
253    Functor* functor;
254};
255
256struct LinesOp : RecordedOp {
257    LinesOp(BASE_PARAMS, const float* points, const int floatCount)
258            : SUPER(LinesOp)
259            , points(points)
260            , floatCount(floatCount) {}
261    const float* points;
262    const int floatCount;
263};
264
265struct OvalOp : RecordedOp {
266    OvalOp(BASE_PARAMS)
267            : SUPER(OvalOp) {}
268};
269
270struct PatchOp : RecordedOp {
271    PatchOp(BASE_PARAMS, const SkBitmap* bitmap, const Res_png_9patch* patch)
272            : SUPER(PatchOp)
273            , bitmap(bitmap)
274            , patch(patch) {}
275    const SkBitmap* bitmap;
276    const Res_png_9patch* patch;
277};
278
279struct PathOp : RecordedOp {
280    PathOp(BASE_PARAMS, const SkPath* path)
281            : SUPER(PathOp)
282            , path(path) {}
283    const SkPath* path;
284};
285
286struct PointsOp : RecordedOp {
287    PointsOp(BASE_PARAMS, const float* points, const int floatCount)
288            : SUPER(PointsOp)
289            , points(points)
290            , floatCount(floatCount) {}
291    const float* points;
292    const int floatCount;
293};
294
295struct RectOp : RecordedOp {
296    RectOp(BASE_PARAMS)
297            : SUPER(RectOp) {}
298};
299
300struct RoundRectOp : RecordedOp {
301    RoundRectOp(BASE_PARAMS, float rx, float ry)
302            : SUPER(RoundRectOp)
303            , rx(rx)
304            , ry(ry) {}
305    const float rx;
306    const float ry;
307};
308
309struct RoundRectPropsOp : RecordedOp {
310    RoundRectPropsOp(const Matrix4& localMatrix, const ClipBase* localClip, const SkPaint* paint,
311            float* left, float* top, float* right, float* bottom, float *rx, float *ry)
312            : RecordedOp(RecordedOpId::RoundRectPropsOp, Rect(), localMatrix, localClip, paint)
313            , left(left)
314            , top(top)
315            , right(right)
316            , bottom(bottom)
317            , rx(rx)
318            , ry(ry) {}
319    const float* left;
320    const float* top;
321    const float* right;
322    const float* bottom;
323    const float* rx;
324    const float* ry;
325};
326
327/**
328 * Real-time, dynamic-lit shadow.
329 *
330 * Uses invalid/empty bounds and matrix since ShadowOp bounds aren't known at defer time,
331 * and are resolved dynamically, and transform isn't needed.
332 *
333 * State construction handles these properties specially, ignoring matrix/bounds.
334 */
335struct ShadowOp : RecordedOp {
336    ShadowOp(const RenderNodeOp& casterOp, float casterAlpha, const SkPath* casterPath,
337            const Rect& localClipRect, const Vector3& lightCenter)
338            : RecordedOp(RecordedOpId::ShadowOp, Rect(), Matrix4::identity(), nullptr, nullptr)
339            , shadowMatrixXY(casterOp.localMatrix)
340            , shadowMatrixZ(casterOp.localMatrix)
341            , casterAlpha(casterAlpha)
342            , casterPath(casterPath)
343            , localClipRect(localClipRect)
344            , lightCenter(lightCenter) {
345        const RenderNode& node = *casterOp.renderNode;
346        node.applyViewPropertyTransforms(shadowMatrixXY, false);
347        node.applyViewPropertyTransforms(shadowMatrixZ, true);
348    };
349    Matrix4 shadowMatrixXY;
350    Matrix4 shadowMatrixZ;
351    const float casterAlpha;
352    const SkPath* casterPath;
353    const Rect localClipRect;
354    const Vector3 lightCenter;
355};
356
357struct SimpleRectsOp : RecordedOp { // Filled, no AA (TODO: better name?)
358    SimpleRectsOp(BASE_PARAMS, Vertex* vertices, size_t vertexCount)
359            : SUPER(SimpleRectsOp)
360            , vertices(vertices)
361            , vertexCount(vertexCount) {}
362    Vertex* vertices;
363    const size_t vertexCount;
364};
365
366struct TextOp : RecordedOp {
367    TextOp(BASE_PARAMS, const glyph_t* glyphs, const float* positions, int glyphCount,
368            float x, float y)
369            : SUPER(TextOp)
370            , glyphs(glyphs)
371            , positions(positions)
372            , glyphCount(glyphCount)
373            , x(x)
374            , y(y) {}
375    const glyph_t* glyphs;
376    const float* positions;
377    const int glyphCount;
378    const float x;
379    const float y;
380};
381
382struct TextOnPathOp : RecordedOp {
383    TextOnPathOp(BASE_PARAMS, const glyph_t* glyphs, int glyphCount,
384            const SkPath* path, float hOffset, float vOffset)
385            : SUPER(TextOnPathOp)
386            , glyphs(glyphs)
387            , glyphCount(glyphCount)
388            , path(path)
389            , hOffset(hOffset)
390            , vOffset(vOffset) {}
391    const glyph_t* glyphs;
392    const int glyphCount;
393
394    const SkPath* path;
395    const float hOffset;
396    const float vOffset;
397};
398
399struct TextureLayerOp : RecordedOp {
400    TextureLayerOp(BASE_PARAMS_PAINTLESS, Layer* layer)
401            : SUPER_PAINTLESS(TextureLayerOp)
402            , layer(layer) {}
403    Layer* layer;
404};
405
406////////////////////////////////////////////////////////////////////////////////////////////////////
407// Layers
408////////////////////////////////////////////////////////////////////////////////////////////////////
409
410/**
411 * Stateful operation! denotes the creation of an off-screen layer,
412 * and that commands following will render into it.
413 */
414struct BeginLayerOp : RecordedOp {
415    BeginLayerOp(BASE_PARAMS)
416            : SUPER(BeginLayerOp) {}
417};
418
419/**
420 * Stateful operation! Denotes end of off-screen layer, and that
421 * commands since last BeginLayerOp should be drawn into parent FBO.
422 *
423 * State in this op is empty, it just serves to signal that a layer has been finished.
424 */
425struct EndLayerOp : RecordedOp {
426    EndLayerOp()
427            : RecordedOp(RecordedOpId::EndLayerOp, Rect(), Matrix4::identity(), nullptr, nullptr) {}
428};
429
430struct BeginUnclippedLayerOp : RecordedOp {
431    BeginUnclippedLayerOp(BASE_PARAMS)
432            : SUPER(BeginUnclippedLayerOp) {}
433};
434
435struct EndUnclippedLayerOp : RecordedOp {
436    EndUnclippedLayerOp()
437            : RecordedOp(RecordedOpId::EndUnclippedLayerOp, Rect(), Matrix4::identity(), nullptr, nullptr) {}
438};
439
440struct CopyToLayerOp : RecordedOp {
441    CopyToLayerOp(const RecordedOp& op, OffscreenBuffer** layerHandle)
442            : RecordedOp(RecordedOpId::CopyToLayerOp,
443                    op.unmappedBounds,
444                    op.localMatrix,
445                    nullptr, // clip intentionally ignored
446                    op.paint)
447            , layerHandle(layerHandle) {}
448
449    // Records a handle to the Layer object, since the Layer itself won't be
450    // constructed until after this operation is constructed.
451    OffscreenBuffer** layerHandle;
452};
453
454
455// draw the parameter layer underneath
456struct CopyFromLayerOp : RecordedOp {
457    CopyFromLayerOp(const RecordedOp& op, OffscreenBuffer** layerHandle)
458            : RecordedOp(RecordedOpId::CopyFromLayerOp,
459                    op.unmappedBounds,
460                    op.localMatrix,
461                    nullptr, // clip intentionally ignored
462                    op.paint)
463            , layerHandle(layerHandle) {}
464
465    // Records a handle to the Layer object, since the Layer itself won't be
466    // constructed until after this operation is constructed.
467    OffscreenBuffer** layerHandle;
468};
469
470/**
471 * Draws an OffscreenBuffer.
472 *
473 * Alpha, mode, and colorfilter are embedded, since LayerOps are always dynamically generated,
474 * when creating/tracking a SkPaint* during defer isn't worth the bother.
475 */
476struct LayerOp : RecordedOp {
477    // Records a one-use (saveLayer) layer for drawing. Once drawn, the layer will be destroyed.
478    LayerOp(BASE_PARAMS, OffscreenBuffer** layerHandle)
479            : SUPER_PAINTLESS(LayerOp)
480            , layerHandle(layerHandle)
481            , alpha(paint ? paint->getAlpha() / 255.0f : 1.0f)
482            , mode(PaintUtils::getXfermodeDirect(paint))
483            , colorFilter(paint ? paint->getColorFilter() : nullptr)
484            , destroy(true) {}
485
486    LayerOp(RenderNode& node)
487            : RecordedOp(RecordedOpId::LayerOp, Rect(node.getWidth(), node.getHeight()), Matrix4::identity(), nullptr, nullptr)
488            , layerHandle(node.getLayerHandle())
489            , alpha(node.properties().layerProperties().alpha() / 255.0f)
490            , mode(node.properties().layerProperties().xferMode())
491            , colorFilter(node.properties().layerProperties().colorFilter())
492            , destroy(false) {}
493
494    // Records a handle to the Layer object, since the Layer itself won't be
495    // constructed until after this operation is constructed.
496    OffscreenBuffer** layerHandle;
497    const float alpha;
498    const SkXfermode::Mode mode;
499
500    // pointer to object owned by either LayerProperties, or a recorded Paint object in a
501    // BeginLayerOp. Lives longer than LayerOp in either case, so no skia ref counting is used.
502    SkColorFilter* colorFilter;
503
504    // whether to destroy the layer, once rendered
505    const bool destroy;
506};
507
508}; // namespace uirenderer
509}; // namespace android
510
511#endif // ANDROID_HWUI_RECORDED_OP_H
512