blob: 983c27b4a5114dc27f675d408462f031fafba6a7 [file] [log] [blame]
Chris Craikb565df12015-10-05 13:00:52 -07001/*
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_BAKED_OP_STATE_H
18#define ANDROID_HWUI_BAKED_OP_STATE_H
19
20#include "Matrix.h"
21#include "RecordedOp.h"
22#include "Rect.h"
23#include "Snapshot.h"
24
25namespace android {
26namespace uirenderer {
27
28namespace OpClipSideFlags {
29 enum {
30 None = 0x0,
31 Left = 0x1,
32 Top = 0x2,
33 Right = 0x4,
34 Bottom = 0x8,
35 Full = 0xF,
36 // ConservativeFull = 0x1F needed?
37 };
38}
39
40/**
Chris Craik15c3f192015-12-03 12:16:56 -080041 * Holds a list of BakedOpStates of ops that can be drawn together
42 */
43struct MergedBakedOpList {
44 const BakedOpState*const* states;
45 size_t count;
46 int clipSideFlags;
47 Rect clip;
48};
49
50/**
Chris Craikb565df12015-10-05 13:00:52 -070051 * Holds the resolved clip, transform, and bounds of a recordedOp, when replayed with a snapshot
52 */
53class ResolvedRenderState {
54public:
55 // TODO: remove the mapRects/matrix multiply when snapshot & recorded transforms are translates
56 ResolvedRenderState(const Snapshot& snapshot, const RecordedOp& recordedOp) {
57 /* TODO: benchmark a fast path for translate-only matrices, such as:
58 if (CC_LIKELY(snapshot.transform->getType() == Matrix4::kTypeTranslate
59 && recordedOp.localMatrix.getType() == Matrix4::kTypeTranslate)) {
60 float translateX = snapshot.transform->getTranslateX() + recordedOp.localMatrix.getTranslateX();
61 float translateY = snapshot.transform->getTranslateY() + recordedOp.localMatrix.getTranslateY();
62 transform.loadTranslate(translateX, translateY, 0);
63
64 // resolvedClipRect = intersect(parentMatrix * localClip, parentClip)
65 clipRect = recordedOp.localClipRect;
66 clipRect.translate(translateX, translateY);
67 clipRect.doIntersect(snapshot.getClipRect());
68 clipRect.snapToPixelBoundaries();
69
70 // resolvedClippedBounds = intersect(resolvedMatrix * opBounds, resolvedClipRect)
71 clippedBounds = recordedOp.unmappedBounds;
72 clippedBounds.translate(translateX, translateY);
73 } ... */
74
75 // resolvedMatrix = parentMatrix * localMatrix
76 transform.loadMultiply(*snapshot.transform, recordedOp.localMatrix);
77
78 // resolvedClipRect = intersect(parentMatrix * localClip, parentClip)
79 clipRect = recordedOp.localClipRect;
80 snapshot.transform->mapRect(clipRect);
Chris Craik6fe991e52015-10-20 09:39:42 -070081 clipRect.doIntersect(snapshot.getRenderTargetClip());
Chris Craikb565df12015-10-05 13:00:52 -070082 clipRect.snapToPixelBoundaries();
83
84 // resolvedClippedBounds = intersect(resolvedMatrix * opBounds, resolvedClipRect)
85 clippedBounds = recordedOp.unmappedBounds;
86 transform.mapRect(clippedBounds);
87
88 if (clipRect.left > clippedBounds.left) clipSideFlags |= OpClipSideFlags::Left;
89 if (clipRect.top > clippedBounds.top) clipSideFlags |= OpClipSideFlags::Top;
90 if (clipRect.right < clippedBounds.right) clipSideFlags |= OpClipSideFlags::Right;
91 if (clipRect.bottom < clippedBounds.bottom) clipSideFlags |= OpClipSideFlags::Bottom;
92 clippedBounds.doIntersect(clipRect);
93
94 /**
95 * TODO: once we support complex clips, we may want to reject to avoid that work where
96 * possible. Should we:
97 * 1 - quickreject based on clippedBounds, quick early (duplicating logic in resolvedOp)
98 * 2 - merge stuff into tryConstruct factory method, so it can handle quickRejection
99 * and early return null in one place.
100 */
101 }
Chris Craikd3daa312015-11-06 10:59:56 -0800102
103 /**
104 * Constructor for unbounded ops without transform/clip (namely shadows)
105 *
106 * Since the op doesn't have known bounds, we conservatively set the mapped bounds
107 * to the current clipRect, and clipSideFlags to Full.
108 */
109 ResolvedRenderState(const Snapshot& snapshot) {
110 transform = *snapshot.transform;
111 clipRect = snapshot.getRenderTargetClip();
112 clippedBounds = clipRect;
113 transform.mapRect(clippedBounds);
114 clipSideFlags = OpClipSideFlags::Full;
115 }
116
Chris Craikb565df12015-10-05 13:00:52 -0700117 Matrix4 transform;
118 Rect clipRect;
119 int clipSideFlags = 0;
120 Rect clippedBounds;
121};
122
123/**
124 * Self-contained op wrapper, containing all resolved state required to draw the op.
125 *
126 * Stashed pointers within all point to longer lived objects, with no ownership implied.
127 */
128class BakedOpState {
129public:
130 static BakedOpState* tryConstruct(LinearAllocator& allocator,
131 const Snapshot& snapshot, const RecordedOp& recordedOp) {
Chris Craikd3daa312015-11-06 10:59:56 -0800132 BakedOpState* bakedOp = new (allocator) BakedOpState(snapshot, recordedOp);
Chris Craikb565df12015-10-05 13:00:52 -0700133 if (bakedOp->computedState.clippedBounds.isEmpty()) {
134 // bounds are empty, so op is rejected
135 allocator.rewindIfLastAlloc(bakedOp);
136 return nullptr;
137 }
138 return bakedOp;
139 }
140
Chris Craikd3daa312015-11-06 10:59:56 -0800141 static BakedOpState* tryShadowOpConstruct(LinearAllocator& allocator,
142 const Snapshot& snapshot, const ShadowOp* shadowOpPtr) {
143 if (snapshot.getRenderTargetClip().isEmpty()) return nullptr;
144
145 // clip isn't empty, so construct the op
146 return new (allocator) BakedOpState(snapshot, shadowOpPtr);
147 }
148
Chris Craikb565df12015-10-05 13:00:52 -0700149 static void* operator new(size_t size, LinearAllocator& allocator) {
150 return allocator.alloc(size);
151 }
152
153 // computed state:
154 const ResolvedRenderState computedState;
155
156 // simple state (straight pointer/value storage):
157 const float alpha;
158 const RoundRectClipState* roundRectClipState;
159 const ProjectionPathMask* projectionPathMask;
160 const RecordedOp* op;
161
162private:
163 BakedOpState(const Snapshot& snapshot, const RecordedOp& recordedOp)
164 : computedState(snapshot, recordedOp)
165 , alpha(snapshot.alpha)
166 , roundRectClipState(snapshot.roundRectClipState)
167 , projectionPathMask(snapshot.projectionPathMask)
168 , op(&recordedOp) {}
Chris Craikd3daa312015-11-06 10:59:56 -0800169
170 BakedOpState(const Snapshot& snapshot, const ShadowOp* shadowOpPtr)
171 : computedState(snapshot)
172 , alpha(snapshot.alpha)
173 , roundRectClipState(snapshot.roundRectClipState)
174 , projectionPathMask(snapshot.projectionPathMask)
175 , op(shadowOpPtr) {}
Chris Craikb565df12015-10-05 13:00:52 -0700176};
177
178}; // namespace uirenderer
179}; // namespace android
180
181#endif // ANDROID_HWUI_BAKED_OP_STATE_H