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