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