FrameBuilder.h revision 8d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7
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_OP_REORDERER_H 18#define ANDROID_HWUI_OP_REORDERER_H 19 20#include "BakedOpState.h" 21#include "CanvasState.h" 22#include "DisplayList.h" 23#include "RecordedOp.h" 24 25#include <vector> 26#include <unordered_map> 27 28struct SkRect; 29 30namespace android { 31namespace uirenderer { 32 33class BakedOpState; 34class BatchBase; 35class LayerUpdateQueue; 36class MergingOpBatch; 37class OffscreenBuffer; 38class OpBatch; 39class Rect; 40 41typedef int batchid_t; 42typedef const void* mergeid_t; 43 44namespace OpBatchType { 45 enum { 46 None = 0, // Don't batch 47 Bitmap, 48 Patch, 49 AlphaVertices, 50 Vertices, 51 AlphaMaskTexture, 52 Text, 53 ColorText, 54 Shadow, 55 56 Count // must be last 57 }; 58} 59 60class OpReorderer : public CanvasStateClient { 61 typedef std::function<void(void*, const RecordedOp&, const BakedOpState&)> BakedOpDispatcher; 62 63 /** 64 * Stores the deferred render operations and state used to compute ordering 65 * for a single FBO/layer. 66 */ 67 class LayerReorderer { 68 public: 69 // Create LayerReorderer for Fbo0 70 LayerReorderer(uint32_t width, uint32_t height, const Rect& repaintRect) 71 : LayerReorderer(width, height, repaintRect, nullptr, nullptr) {}; 72 73 // Create LayerReorderer for an offscreen layer, where beginLayerOp is present for a 74 // saveLayer, renderNode is present for a HW layer. 75 LayerReorderer(uint32_t width, uint32_t height, 76 const Rect& repaintRect, const BeginLayerOp* beginLayerOp, RenderNode* renderNode); 77 78 // iterate back toward target to see if anything drawn since should overlap the new op 79 // if no target, merging ops still iterate to find similar batch to insert after 80 void locateInsertIndex(int batchId, const Rect& clippedBounds, 81 BatchBase** targetBatch, size_t* insertBatchIndex) const; 82 83 void deferUnmergeableOp(LinearAllocator& allocator, BakedOpState* op, batchid_t batchId); 84 85 // insertion point of a new batch, will hopefully be immediately after similar batch 86 // (generally, should be similar shader) 87 void deferMergeableOp(LinearAllocator& allocator, 88 BakedOpState* op, batchid_t batchId, mergeid_t mergeId); 89 90 void replayBakedOpsImpl(void* arg, BakedOpDispatcher* receivers) const; 91 92 bool empty() const { 93 return mBatches.empty(); 94 } 95 96 void clear() { 97 mBatches.clear(); 98 } 99 100 void dump() const; 101 102 const uint32_t width; 103 const uint32_t height; 104 const Rect repaintRect; 105 OffscreenBuffer* offscreenBuffer; 106 const BeginLayerOp* beginLayerOp; 107 const RenderNode* renderNode; 108 private: 109 std::vector<BatchBase*> mBatches; 110 111 /** 112 * Maps the mergeid_t returned by an op's getMergeId() to the most recently seen 113 * MergingDrawBatch of that id. These ids are unique per draw type and guaranteed to not 114 * collide, which avoids the need to resolve mergeid collisions. 115 */ 116 std::unordered_map<mergeid_t, MergingOpBatch*> mMergingBatchLookup[OpBatchType::Count]; 117 118 // Maps batch ids to the most recent *non-merging* batch of that id 119 OpBatch* mBatchLookup[OpBatchType::Count] = { nullptr }; 120 }; 121 122public: 123 OpReorderer(const LayerUpdateQueue& layers, const SkRect& clip, 124 uint32_t viewportWidth, uint32_t viewportHeight, 125 const std::vector< sp<RenderNode> >& nodes, const Vector3& lightCenter); 126 127 virtual ~OpReorderer() {} 128 129 /** 130 * replayBakedOps() is templated based on what class will receive ops being replayed. 131 * 132 * It constructs a lookup array of lambdas, which allows a recorded BakeOpState to use 133 * state->op->opId to lookup a receiver that will be called when the op is replayed. 134 * 135 * For example a BitmapOp would resolve, via the lambda lookup, to calling: 136 * 137 * StaticDispatcher::onBitmapOp(Renderer& renderer, const BitmapOp& op, const BakedOpState& state); 138 */ 139#define BAKED_OP_RECEIVER(Type) \ 140 [](void* internalRenderer, const RecordedOp& op, const BakedOpState& state) { \ 141 StaticDispatcher::on##Type(*(static_cast<Renderer*>(internalRenderer)), static_cast<const Type&>(op), state); \ 142 }, 143 template <typename StaticDispatcher, typename Renderer> 144 void replayBakedOps(Renderer& renderer) { 145 static BakedOpDispatcher receivers[] = { 146 MAP_OPS(BAKED_OP_RECEIVER) 147 }; 148 149 // Relay through layers in reverse order, since layers 150 // later in the list will be drawn by earlier ones 151 for (int i = mLayerReorderers.size() - 1; i >= 1; i--) { 152 LayerReorderer& layer = mLayerReorderers[i]; 153 if (layer.renderNode) { 154 // cached HW layer - can't skip layer if empty 155 renderer.startRepaintLayer(layer.offscreenBuffer, layer.repaintRect); 156 layer.replayBakedOpsImpl((void*)&renderer, receivers); 157 renderer.endLayer(); 158 } else if (!layer.empty()) { // save layer - skip entire layer if empty 159 layer.offscreenBuffer = renderer.startTemporaryLayer(layer.width, layer.height); 160 layer.replayBakedOpsImpl((void*)&renderer, receivers); 161 renderer.endLayer(); 162 } 163 } 164 165 const LayerReorderer& fbo0 = mLayerReorderers[0]; 166 renderer.startFrame(fbo0.width, fbo0.height, fbo0.repaintRect); 167 fbo0.replayBakedOpsImpl((void*)&renderer, receivers); 168 renderer.endFrame(); 169 } 170 171 void dump() const { 172 for (auto&& layer : mLayerReorderers) { 173 layer.dump(); 174 } 175 } 176 177 /////////////////////////////////////////////////////////////////// 178 /// CanvasStateClient interface 179 /////////////////////////////////////////////////////////////////// 180 virtual void onViewportInitialized() override; 181 virtual void onSnapshotRestored(const Snapshot& removed, const Snapshot& restored) override; 182 virtual GLuint getTargetFbo() const override { return 0; } 183 184private: 185 enum class ChildrenSelectMode { 186 Negative, 187 Positive 188 }; 189 void saveForLayer(uint32_t layerWidth, uint32_t layerHeight, 190 float contentTranslateX, float contentTranslateY, 191 const Rect& repaintRect, 192 const Vector3& lightCenter, 193 const BeginLayerOp* beginLayerOp, RenderNode* renderNode); 194 void restoreForLayer(); 195 196 LayerReorderer& currentLayer() { return mLayerReorderers[mLayerStack.back()]; } 197 198 BakedOpState* tryBakeOpState(const RecordedOp& recordedOp) { 199 return BakedOpState::tryConstruct(mAllocator, *mCanvasState.currentSnapshot(), recordedOp); 200 } 201 202 // should always be surrounded by a save/restore pair, and not called if DisplayList is null 203 void deferNodePropsAndOps(RenderNode& node); 204 205 template <typename V> 206 void defer3dChildren(ChildrenSelectMode mode, const V& zTranslatedNodes); 207 208 void deferShadow(const RenderNodeOp& casterOp); 209 210 void deferProjectedChildren(const RenderNode& renderNode); 211 212 void deferNodeOps(const RenderNode& renderNode); 213 214 void deferRenderNodeOp(const RenderNodeOp& op); 215 216 void replayBakedOpsImpl(void* arg, BakedOpDispatcher* receivers); 217 218 SkPath* createFrameAllocatedPath() { 219 mFrameAllocatedPaths.emplace_back(new SkPath); 220 return mFrameAllocatedPaths.back().get(); 221 } 222 /** 223 * Declares all OpReorderer::onXXXXOp() methods for every RecordedOp type. 224 * 225 * These private methods are called from within deferImpl to defer each individual op 226 * type differently. 227 */ 228#define INTERNAL_OP_HANDLER(Type) \ 229 void on##Type(const Type& op); 230 MAP_OPS(INTERNAL_OP_HANDLER) 231 232 std::vector<std::unique_ptr<SkPath> > mFrameAllocatedPaths; 233 234 // List of every deferred layer's render state. Replayed in reverse order to render a frame. 235 std::vector<LayerReorderer> mLayerReorderers; 236 237 /* 238 * Stack of indices within mLayerReorderers representing currently active layers. If drawing 239 * layerA within a layerB, will contain, in order: 240 * - 0 (representing FBO 0, always present) 241 * - layerB's index 242 * - layerA's index 243 * 244 * Note that this doesn't vector doesn't always map onto all values of mLayerReorderers. When a 245 * layer is finished deferring, it will still be represented in mLayerReorderers, but it's index 246 * won't be in mLayerStack. This is because it can be replayed, but can't have any more drawing 247 * ops added to it. 248 */ 249 std::vector<size_t> mLayerStack; 250 251 CanvasState mCanvasState; 252 253 // contains ResolvedOps and Batches 254 LinearAllocator mAllocator; 255}; 256 257}; // namespace uirenderer 258}; // namespace android 259 260#endif // ANDROID_HWUI_OP_REORDERER_H 261