RecordedOp.h revision 98787e6c9b2c10b1ab7820bdac168686025b924a
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 "Matrix.h"
21#include "Rect.h"
22#include "RenderNode.h"
23#include "utils/LinearAllocator.h"
24#include "Vector.h"
25
26#include "SkXfermode.h"
27
28class SkBitmap;
29class SkPaint;
30
31namespace android {
32namespace uirenderer {
33
34class OffscreenBuffer;
35class RenderNode;
36struct Vertex;
37
38/**
39 * The provided macro is executed for each op type in order, with the results separated by commas.
40 *
41 * This serves as the authoritative list of ops, used for generating ID enum, and ID based LUTs.
42 */
43#define MAP_OPS(OP_FN) \
44        OP_FN(BitmapOp) \
45        OP_FN(RectOp) \
46        OP_FN(RenderNodeOp) \
47        OP_FN(ShadowOp) \
48        OP_FN(SimpleRectsOp) \
49        OP_FN(BeginLayerOp) \
50        OP_FN(EndLayerOp) \
51        OP_FN(LayerOp)
52
53// Generate OpId enum
54#define IDENTITY_FN(Type) Type,
55namespace RecordedOpId {
56    enum {
57        MAP_OPS(IDENTITY_FN)
58        Count,
59    };
60}
61static_assert(RecordedOpId::BitmapOp == 0,
62        "First index must be zero for LUTs to work");
63
64#define BASE_PARAMS const Rect& unmappedBounds, const Matrix4& localMatrix, const Rect& localClipRect, const SkPaint* paint
65#define BASE_PARAMS_PAINTLESS const Rect& unmappedBounds, const Matrix4& localMatrix, const Rect& localClipRect
66#define SUPER(Type) RecordedOp(RecordedOpId::Type, unmappedBounds, localMatrix, localClipRect, paint)
67#define SUPER_PAINTLESS(Type) RecordedOp(RecordedOpId::Type, unmappedBounds, localMatrix, localClipRect, nullptr)
68
69struct RecordedOp {
70    /* ID from RecordedOpId - generally used for jumping into function tables */
71    const int opId;
72
73    /* bounds in *local* space, without accounting for DisplayList transformation */
74    const Rect unmappedBounds;
75
76    /* transform in recording space (vs DisplayList origin) */
77    const Matrix4 localMatrix;
78
79    /* clip in recording space */
80    const Rect localClipRect;
81
82    /* optional paint, stored in base object to simplify merging logic */
83    const SkPaint* paint;
84protected:
85    RecordedOp(unsigned int opId, BASE_PARAMS)
86            : opId(opId)
87            , unmappedBounds(unmappedBounds)
88            , localMatrix(localMatrix)
89            , localClipRect(localClipRect)
90            , paint(paint) {}
91};
92
93struct RenderNodeOp : RecordedOp {
94    RenderNodeOp(BASE_PARAMS_PAINTLESS, RenderNode* renderNode)
95            : SUPER_PAINTLESS(RenderNodeOp)
96            , renderNode(renderNode) {}
97    RenderNode * renderNode; // not const, since drawing modifies it (somehow...)
98    bool skipInOrderDraw = false;
99};
100
101struct BitmapOp : RecordedOp {
102    BitmapOp(BASE_PARAMS, const SkBitmap* bitmap)
103            : SUPER(BitmapOp)
104            , bitmap(bitmap) {}
105    const SkBitmap* bitmap;
106    // TODO: asset atlas/texture id lookup?
107};
108
109struct RectOp : RecordedOp {
110    RectOp(BASE_PARAMS)
111            : SUPER(RectOp) {}
112};
113
114/**
115 * Real-time, dynamic-lit shadow.
116 *
117 * Uses invalid/empty bounds and matrix since ShadowOp bounds aren't known at defer time,
118 * and are resolved dynamically, and transform isn't needed.
119 *
120 * State construction handles these properties specially, ignoring matrix/bounds.
121 */
122struct ShadowOp : RecordedOp {
123    ShadowOp(const RenderNodeOp& casterOp, float casterAlpha, const SkPath* casterPath,
124            const Rect& clipRect, const Vector3& lightCenter)
125            : RecordedOp(RecordedOpId::ShadowOp, Rect(), Matrix4::identity(), clipRect, nullptr)
126            , shadowMatrixXY(casterOp.localMatrix)
127            , shadowMatrixZ(casterOp.localMatrix)
128            , casterAlpha(casterAlpha)
129            , casterPath(casterPath)
130            , lightCenter(lightCenter) {
131        const RenderNode& node = *casterOp.renderNode;
132        node.applyViewPropertyTransforms(shadowMatrixXY, false);
133        node.applyViewPropertyTransforms(shadowMatrixZ, true);
134    };
135    Matrix4 shadowMatrixXY;
136    Matrix4 shadowMatrixZ;
137    const float casterAlpha;
138    const SkPath* casterPath;
139    const Vector3 lightCenter;
140};
141
142struct SimpleRectsOp : RecordedOp { // Filled, no AA (TODO: better name?)
143    SimpleRectsOp(BASE_PARAMS, Vertex* vertices, size_t vertexCount)
144            : SUPER(SimpleRectsOp)
145            , vertices(vertices)
146            , vertexCount(vertexCount) {}
147    Vertex* vertices;
148    const size_t vertexCount;
149};
150
151/**
152 * Stateful operation! denotes the creation of an off-screen layer,
153 * and that commands following will render into it.
154 */
155struct BeginLayerOp : RecordedOp {
156    BeginLayerOp(BASE_PARAMS)
157            : SUPER(BeginLayerOp) {}
158};
159
160/**
161 * Stateful operation! Denotes end of off-screen layer, and that
162 * commands since last BeginLayerOp should be drawn into parent FBO.
163 *
164 * State in this op is empty, it just serves to signal that a layer has been finished.
165 */
166struct EndLayerOp : RecordedOp {
167    EndLayerOp()
168            : RecordedOp(RecordedOpId::EndLayerOp, Rect(0, 0), Matrix4::identity(), Rect(0, 0), nullptr) {}
169};
170
171/**
172 * Draws an OffscreenBuffer.
173 *
174 * Alpha, mode, and colorfilter are embedded, since LayerOps are always dynamically generated,
175 * when creating/tracking a SkPaint* during defer isn't worth the bother.
176 */
177struct LayerOp : RecordedOp {
178    // Records a one-use (saveLayer) layer for drawing. Once drawn, the layer will be destroyed.
179    LayerOp(BASE_PARAMS, OffscreenBuffer** layerHandle)
180            : SUPER_PAINTLESS(LayerOp)
181            , layerHandle(layerHandle)
182            , alpha(paint->getAlpha() / 255.0f)
183            , mode(PaintUtils::getXfermodeDirect(paint))
184            , colorFilter(paint->getColorFilter())
185            , destroy(true) {}
186
187    LayerOp(RenderNode& node)
188        : RecordedOp(RecordedOpId::LayerOp, Rect(node.getWidth(), node.getHeight()), Matrix4::identity(), Rect(node.getWidth(), node.getHeight()), nullptr)
189        , layerHandle(node.getLayerHandle())
190        , alpha(node.properties().layerProperties().alpha() / 255.0f)
191        , mode(node.properties().layerProperties().xferMode())
192        , colorFilter(node.properties().layerProperties().colorFilter())
193        , destroy(false) {}
194
195    // Records a handle to the Layer object, since the Layer itself won't be
196    // constructed until after this operation is constructed.
197    OffscreenBuffer** layerHandle;
198    const float alpha;
199    const SkXfermode::Mode mode;
200
201    // pointer to object owned by either LayerProperties, or a recorded Paint object in a
202    // BeginLayerOp. Lives longer than LayerOp in either case, so no skia ref counting is used.
203    SkColorFilter* colorFilter;
204
205    // whether to destroy the layer, once rendered
206    const bool destroy;
207};
208
209}; // namespace uirenderer
210}; // namespace android
211
212#endif // ANDROID_HWUI_RECORDED_OP_H
213