blob: 9a40c3b3d3b00e235b07deb6bee3c13a564223b1 [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/**
41 * Holds the resolved clip, transform, and bounds of a recordedOp, when replayed with a snapshot
42 */
43class ResolvedRenderState {
44public:
45 // TODO: remove the mapRects/matrix multiply when snapshot & recorded transforms are translates
46 ResolvedRenderState(const Snapshot& snapshot, const RecordedOp& recordedOp) {
47 /* TODO: benchmark a fast path for translate-only matrices, such as:
48 if (CC_LIKELY(snapshot.transform->getType() == Matrix4::kTypeTranslate
49 && recordedOp.localMatrix.getType() == Matrix4::kTypeTranslate)) {
50 float translateX = snapshot.transform->getTranslateX() + recordedOp.localMatrix.getTranslateX();
51 float translateY = snapshot.transform->getTranslateY() + recordedOp.localMatrix.getTranslateY();
52 transform.loadTranslate(translateX, translateY, 0);
53
54 // resolvedClipRect = intersect(parentMatrix * localClip, parentClip)
55 clipRect = recordedOp.localClipRect;
56 clipRect.translate(translateX, translateY);
57 clipRect.doIntersect(snapshot.getClipRect());
58 clipRect.snapToPixelBoundaries();
59
60 // resolvedClippedBounds = intersect(resolvedMatrix * opBounds, resolvedClipRect)
61 clippedBounds = recordedOp.unmappedBounds;
62 clippedBounds.translate(translateX, translateY);
63 } ... */
64
65 // resolvedMatrix = parentMatrix * localMatrix
66 transform.loadMultiply(*snapshot.transform, recordedOp.localMatrix);
67
68 // resolvedClipRect = intersect(parentMatrix * localClip, parentClip)
69 clipRect = recordedOp.localClipRect;
70 snapshot.transform->mapRect(clipRect);
Chris Craik6fe991e52015-10-20 09:39:42 -070071 clipRect.doIntersect(snapshot.getRenderTargetClip());
Chris Craikb565df12015-10-05 13:00:52 -070072 clipRect.snapToPixelBoundaries();
73
74 // resolvedClippedBounds = intersect(resolvedMatrix * opBounds, resolvedClipRect)
75 clippedBounds = recordedOp.unmappedBounds;
76 transform.mapRect(clippedBounds);
77
78 if (clipRect.left > clippedBounds.left) clipSideFlags |= OpClipSideFlags::Left;
79 if (clipRect.top > clippedBounds.top) clipSideFlags |= OpClipSideFlags::Top;
80 if (clipRect.right < clippedBounds.right) clipSideFlags |= OpClipSideFlags::Right;
81 if (clipRect.bottom < clippedBounds.bottom) clipSideFlags |= OpClipSideFlags::Bottom;
82 clippedBounds.doIntersect(clipRect);
83
84 /**
85 * TODO: once we support complex clips, we may want to reject to avoid that work where
86 * possible. Should we:
87 * 1 - quickreject based on clippedBounds, quick early (duplicating logic in resolvedOp)
88 * 2 - merge stuff into tryConstruct factory method, so it can handle quickRejection
89 * and early return null in one place.
90 */
91 }
Chris Craikd3daa312015-11-06 10:59:56 -080092
93 /**
94 * Constructor for unbounded ops without transform/clip (namely shadows)
95 *
96 * Since the op doesn't have known bounds, we conservatively set the mapped bounds
97 * to the current clipRect, and clipSideFlags to Full.
98 */
99 ResolvedRenderState(const Snapshot& snapshot) {
100 transform = *snapshot.transform;
101 clipRect = snapshot.getRenderTargetClip();
102 clippedBounds = clipRect;
103 transform.mapRect(clippedBounds);
104 clipSideFlags = OpClipSideFlags::Full;
105 }
106
Chris Craikb565df12015-10-05 13:00:52 -0700107 Matrix4 transform;
108 Rect clipRect;
109 int clipSideFlags = 0;
110 Rect clippedBounds;
111};
112
113/**
114 * Self-contained op wrapper, containing all resolved state required to draw the op.
115 *
116 * Stashed pointers within all point to longer lived objects, with no ownership implied.
117 */
118class BakedOpState {
119public:
120 static BakedOpState* tryConstruct(LinearAllocator& allocator,
121 const Snapshot& snapshot, const RecordedOp& recordedOp) {
Chris Craikd3daa312015-11-06 10:59:56 -0800122 BakedOpState* bakedOp = new (allocator) BakedOpState(snapshot, recordedOp);
Chris Craikb565df12015-10-05 13:00:52 -0700123 if (bakedOp->computedState.clippedBounds.isEmpty()) {
124 // bounds are empty, so op is rejected
125 allocator.rewindIfLastAlloc(bakedOp);
126 return nullptr;
127 }
128 return bakedOp;
129 }
130
Chris Craikd3daa312015-11-06 10:59:56 -0800131 static BakedOpState* tryShadowOpConstruct(LinearAllocator& allocator,
132 const Snapshot& snapshot, const ShadowOp* shadowOpPtr) {
133 if (snapshot.getRenderTargetClip().isEmpty()) return nullptr;
134
135 // clip isn't empty, so construct the op
136 return new (allocator) BakedOpState(snapshot, shadowOpPtr);
137 }
138
Chris Craikb565df12015-10-05 13:00:52 -0700139 static void* operator new(size_t size, LinearAllocator& allocator) {
140 return allocator.alloc(size);
141 }
142
143 // computed state:
144 const ResolvedRenderState computedState;
145
146 // simple state (straight pointer/value storage):
147 const float alpha;
148 const RoundRectClipState* roundRectClipState;
149 const ProjectionPathMask* projectionPathMask;
150 const RecordedOp* op;
151
152private:
153 BakedOpState(const Snapshot& snapshot, const RecordedOp& recordedOp)
154 : computedState(snapshot, recordedOp)
155 , alpha(snapshot.alpha)
156 , roundRectClipState(snapshot.roundRectClipState)
157 , projectionPathMask(snapshot.projectionPathMask)
158 , op(&recordedOp) {}
Chris Craikd3daa312015-11-06 10:59:56 -0800159
160 BakedOpState(const Snapshot& snapshot, const ShadowOp* shadowOpPtr)
161 : computedState(snapshot)
162 , alpha(snapshot.alpha)
163 , roundRectClipState(snapshot.roundRectClipState)
164 , projectionPathMask(snapshot.projectionPathMask)
165 , op(shadowOpPtr) {}
Chris Craikb565df12015-10-05 13:00:52 -0700166};
167
168}; // namespace uirenderer
169}; // namespace android
170
171#endif // ANDROID_HWUI_BAKED_OP_STATE_H