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