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