From 617673f83f30a36eecd429df586e5ef6598116e1 Mon Sep 17 00:00:00 2001 From: John Reck Date: Mon, 9 Apr 2018 09:41:29 -0700 Subject: Remove dead code Remove an old protobuf serialization experiement, skp capture does this better Test: builds Change-Id: Icd875eabee6b517729f901841e48e579d0e8de4d --- libs/hwui/RenderNode.cpp | 74 ------------------------------------------------ 1 file changed, 74 deletions(-) (limited to 'libs/hwui/RenderNode.cpp') diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp index d93a7578cfd7..5ac330bcadb8 100644 --- a/libs/hwui/RenderNode.cpp +++ b/libs/hwui/RenderNode.cpp @@ -29,9 +29,6 @@ #include "utils/StringUtils.h" #include "utils/TraceUtils.h" -#include "protos/ProtoHelpers.h" -#include "protos/hwui.pb.h" - #include #include #include @@ -101,77 +98,6 @@ void RenderNode::output(std::ostream& output, uint32_t level) { output << std::endl; } -void RenderNode::copyTo(proto::RenderNode* pnode) { - pnode->set_id(static_cast(reinterpret_cast(this))); - pnode->set_name(mName.string(), mName.length()); - - proto::RenderProperties* pprops = pnode->mutable_properties(); - pprops->set_left(properties().getLeft()); - pprops->set_top(properties().getTop()); - pprops->set_right(properties().getRight()); - pprops->set_bottom(properties().getBottom()); - pprops->set_clip_flags(properties().getClippingFlags()); - pprops->set_alpha(properties().getAlpha()); - pprops->set_translation_x(properties().getTranslationX()); - pprops->set_translation_y(properties().getTranslationY()); - pprops->set_translation_z(properties().getTranslationZ()); - pprops->set_elevation(properties().getElevation()); - pprops->set_rotation(properties().getRotation()); - pprops->set_rotation_x(properties().getRotationX()); - pprops->set_rotation_y(properties().getRotationY()); - pprops->set_scale_x(properties().getScaleX()); - pprops->set_scale_y(properties().getScaleY()); - pprops->set_pivot_x(properties().getPivotX()); - pprops->set_pivot_y(properties().getPivotY()); - pprops->set_has_overlapping_rendering(properties().getHasOverlappingRendering()); - pprops->set_pivot_explicitly_set(properties().isPivotExplicitlySet()); - pprops->set_project_backwards(properties().getProjectBackwards()); - pprops->set_projection_receiver(properties().isProjectionReceiver()); - set(pprops->mutable_clip_bounds(), properties().getClipBounds()); - - const Outline& outline = properties().getOutline(); - if (outline.getType() != Outline::Type::None) { - proto::Outline* poutline = pprops->mutable_outline(); - poutline->clear_path(); - if (outline.getType() == Outline::Type::Empty) { - poutline->set_type(proto::Outline_Type_Empty); - } else if (outline.getType() == Outline::Type::ConvexPath) { - poutline->set_type(proto::Outline_Type_ConvexPath); - if (const SkPath* path = outline.getPath()) { - set(poutline->mutable_path(), *path); - } - } else if (outline.getType() == Outline::Type::RoundRect) { - poutline->set_type(proto::Outline_Type_RoundRect); - } else { - ALOGW("Uknown outline type! %d", static_cast(outline.getType())); - poutline->set_type(proto::Outline_Type_None); - } - poutline->set_should_clip(outline.getShouldClip()); - poutline->set_alpha(outline.getAlpha()); - poutline->set_radius(outline.getRadius()); - set(poutline->mutable_bounds(), outline.getBounds()); - } else { - pprops->clear_outline(); - } - - const RevealClip& revealClip = properties().getRevealClip(); - if (revealClip.willClip()) { - proto::RevealClip* prevealClip = pprops->mutable_reveal_clip(); - prevealClip->set_x(revealClip.getX()); - prevealClip->set_y(revealClip.getY()); - prevealClip->set_radius(revealClip.getRadius()); - } else { - pprops->clear_reveal_clip(); - } - - pnode->clear_children(); - if (mDisplayList) { - for (auto&& child : mDisplayList->getChildren()) { - child->renderNode->copyTo(pnode->add_children()); - } - } -} - int RenderNode::getDebugSize() { int size = sizeof(RenderNode); if (mStagingDisplayList) { -- cgit v1.2.3-59-g8ed1b From 1072fffddbd004f8ff0d089716d52add2960969e Mon Sep 17 00:00:00 2001 From: John Reck Date: Thu, 12 Apr 2018 15:20:09 -0700 Subject: Remove Properties::isSkiaPipeline (3/!?) Test: hwuiunit & CtsUiRenderingTestCases pass Change-Id: Ie7b336eacdd1b8660e09653c64eb6ea0a7b4a258 --- libs/hwui/Android.bp | 1 - libs/hwui/Extensions.cpp | 83 --------------------------------- libs/hwui/Extensions.h | 42 ++++++----------- libs/hwui/Properties.cpp | 5 -- libs/hwui/Properties.h | 1 - libs/hwui/RenderNode.cpp | 6 +-- libs/hwui/SkiaCanvas.cpp | 10 +--- libs/hwui/hwui/Bitmap.cpp | 15 ++---- libs/hwui/hwui/Canvas.cpp | 5 +- libs/hwui/renderthread/CacheManager.cpp | 4 +- libs/hwui/renderthread/RenderProxy.cpp | 2 +- 11 files changed, 24 insertions(+), 150 deletions(-) delete mode 100644 libs/hwui/Extensions.cpp (limited to 'libs/hwui/RenderNode.cpp') diff --git a/libs/hwui/Android.bp b/libs/hwui/Android.bp index 7319354c7c5f..381d07ac0c66 100644 --- a/libs/hwui/Android.bp +++ b/libs/hwui/Android.bp @@ -217,7 +217,6 @@ cc_defaults { "DeferredLayerUpdater.cpp", "DeviceInfo.cpp", "DisplayList.cpp", - "Extensions.cpp", "FboCache.cpp", "FontRenderer.cpp", "FrameBuilder.cpp", diff --git a/libs/hwui/Extensions.cpp b/libs/hwui/Extensions.cpp deleted file mode 100644 index 530e82e65a28..000000000000 --- a/libs/hwui/Extensions.cpp +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright (C) 2013 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "Extensions.h" - -#include "Debug.h" -#include "Properties.h" -#include "utils/StringUtils.h" - -#include - -#include -#include - -#include - -namespace android { -namespace uirenderer { - -Extensions::Extensions() { - if (Properties::isSkiaEnabled()) { - return; - } - const char* version = (const char*)glGetString(GL_VERSION); - - // Section 6.1.5 of the OpenGL ES specification indicates the GL version - // string strictly follows this format: - // - // OpenGLES - // - // In addition section 6.1.5 describes the version number thusly: - // - // "The version number is either of the form major number.minor number or - // major number.minor number.release number, where the numbers all have one - // or more digits. The release number and vendor specific information are - // optional." - - if (sscanf(version, "OpenGL ES %d.%d", &mVersionMajor, &mVersionMinor) != 2) { - // If we cannot parse the version number, assume OpenGL ES 2.0 - mVersionMajor = 2; - mVersionMinor = 0; - } - - auto extensions = StringUtils::split((const char*)glGetString(GL_EXTENSIONS)); - mHasNPot = extensions.has("GL_OES_texture_npot"); - mHasFramebufferFetch = extensions.has("GL_NV_shader_framebuffer_fetch"); - mHasDiscardFramebuffer = extensions.has("GL_EXT_discard_framebuffer"); - mHasDebugMarker = extensions.has("GL_EXT_debug_marker"); - mHas1BitStencil = extensions.has("GL_OES_stencil1"); - mHas4BitStencil = extensions.has("GL_OES_stencil4"); - mHasUnpackSubImage = extensions.has("GL_EXT_unpack_subimage"); - mHasRenderableFloatTexture = extensions.has("GL_OES_texture_half_float"); - - mHasSRGB = mVersionMajor >= 3 || extensions.has("GL_EXT_sRGB"); - mHasSRGBWriteControl = extensions.has("GL_EXT_sRGB_write_control"); - -#ifdef ANDROID_ENABLE_LINEAR_BLENDING - // If linear blending is enabled, the device must have (ES3.0 or EXT_sRGB) - // and EXT_sRGB_write_control - LOG_ALWAYS_FATAL_IF(!mHasSRGB, "Linear blending requires ES 3.0 or EXT_sRGB"); - LOG_ALWAYS_FATAL_IF(!mHasSRGBWriteControl, "Linear blending requires EXT_sRGB_write_control"); - - mHasLinearBlending = true; -#else - mHasLinearBlending = false; -#endif -} - -}; // namespace uirenderer -}; // namespace android diff --git a/libs/hwui/Extensions.h b/libs/hwui/Extensions.h index 214ee0bbeefd..e90f40c1c979 100644 --- a/libs/hwui/Extensions.h +++ b/libs/hwui/Extensions.h @@ -26,43 +26,31 @@ namespace uirenderer { class Extensions { public: - Extensions(); - - inline bool hasNPot() const { return mHasNPot; } - inline bool hasFramebufferFetch() const { return mHasFramebufferFetch; } - inline bool hasDiscardFramebuffer() const { return mHasDiscardFramebuffer; } - inline bool hasDebugMarker() const { return mHasDebugMarker; } - inline bool has1BitStencil() const { return mHas1BitStencil; } - inline bool has4BitStencil() const { return mHas4BitStencil; } - inline bool hasUnpackRowLength() const { return mVersionMajor >= 3 || mHasUnpackSubImage; } + Extensions() {} + + inline bool hasNPot() const { return false; } + inline bool hasFramebufferFetch() const { return false; } + inline bool hasDiscardFramebuffer() const { return false; } + inline bool hasDebugMarker() const { return false; } + inline bool has1BitStencil() const { return false; } + inline bool has4BitStencil() const { return false; } + inline bool hasUnpackRowLength() const { return mVersionMajor >= 3; } inline bool hasPixelBufferObjects() const { return mVersionMajor >= 3; } inline bool hasOcclusionQueries() const { return mVersionMajor >= 3; } inline bool hasFloatTextures() const { return mVersionMajor >= 3; } inline bool hasRenderableFloatTextures() const { - return (mVersionMajor >= 3 && mVersionMinor >= 2) || mHasRenderableFloatTexture; + return (mVersionMajor >= 3 && mVersionMinor >= 2); } - inline bool hasSRGB() const { return mHasSRGB; } - inline bool hasSRGBWriteControl() const { return hasSRGB() && mHasSRGBWriteControl; } - inline bool hasLinearBlending() const { return hasSRGB() && mHasLinearBlending; } + inline bool hasSRGB() const { return false; } + inline bool hasSRGBWriteControl() const { return hasSRGB() && false; } + inline bool hasLinearBlending() const { return hasSRGB() && false; } inline int getMajorGlVersion() const { return mVersionMajor; } inline int getMinorGlVersion() const { return mVersionMinor; } private: - bool mHasNPot; - bool mHasFramebufferFetch; - bool mHasDiscardFramebuffer; - bool mHasDebugMarker; - bool mHas1BitStencil; - bool mHas4BitStencil; - bool mHasUnpackSubImage; - bool mHasSRGB; - bool mHasSRGBWriteControl; - bool mHasLinearBlending; - bool mHasRenderableFloatTexture; - - int mVersionMajor; - int mVersionMinor; + int mVersionMajor = 2; + int mVersionMinor = 0; }; // class Extensions }; // namespace uirenderer diff --git a/libs/hwui/Properties.cpp b/libs/hwui/Properties.cpp index 0d1257fc7b12..064763f65e09 100644 --- a/libs/hwui/Properties.cpp +++ b/libs/hwui/Properties.cpp @@ -215,10 +215,5 @@ void Properties::overrideRenderPipelineType(RenderPipelineType type) { sRenderPipelineType = type; } -bool Properties::isSkiaEnabled() { - auto renderType = getRenderPipelineType(); - return RenderPipelineType::SkiaGL == renderType || RenderPipelineType::SkiaVulkan == renderType; -} - }; // namespace uirenderer }; // namespace android diff --git a/libs/hwui/Properties.h b/libs/hwui/Properties.h index 03a3e36c4495..5376bab50b58 100644 --- a/libs/hwui/Properties.h +++ b/libs/hwui/Properties.h @@ -247,7 +247,6 @@ public: static ProfileType getProfileType(); ANDROID_API static RenderPipelineType getRenderPipelineType(); - static bool isSkiaEnabled(); ANDROID_API static bool enableHighContrastText; diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp index 5ac330bcadb8..62b80c43ebb7 100644 --- a/libs/hwui/RenderNode.cpp +++ b/libs/hwui/RenderNode.cpp @@ -114,11 +114,7 @@ void RenderNode::prepareTree(TreeInfo& info) { LOG_ALWAYS_FATAL_IF(!info.damageAccumulator, "DamageAccumulator missing"); MarkAndSweepRemoved observer(&info); - // The OpenGL renderer reserves the stencil buffer for overdraw debugging. Functors - // will need to be drawn in a layer. - bool functorsNeedLayer = Properties::debugOverdraw && !Properties::isSkiaEnabled(); - - prepareTreeImpl(observer, info, functorsNeedLayer); + prepareTreeImpl(observer, info, false); } void RenderNode::addAnimator(const sp& animator) { diff --git a/libs/hwui/SkiaCanvas.cpp b/libs/hwui/SkiaCanvas.cpp index 40b811d813fd..6bd12f4c7ff3 100644 --- a/libs/hwui/SkiaCanvas.cpp +++ b/libs/hwui/SkiaCanvas.cpp @@ -62,13 +62,7 @@ SkiaCanvas::SkiaCanvas(const SkBitmap& bitmap) { mCanvasOwned = std::unique_ptr(new SkCanvas(bitmap, SkCanvas::ColorBehavior::kLegacy)); if (cs.get() == nullptr || cs->isSRGB()) { - if (!uirenderer::Properties::isSkiaEnabled()) { - mCanvasWrapper = - SkCreateColorSpaceXformCanvas(mCanvasOwned.get(), SkColorSpace::MakeSRGB()); - mCanvas = mCanvasWrapper.get(); - } else { - mCanvas = mCanvasOwned.get(); - } + mCanvas = mCanvasOwned.get(); } else { /** The wrapper is needed if we are drawing into a non-sRGB destination, since * we need to transform all colors (not just bitmaps via filters) into the @@ -101,8 +95,6 @@ void SkiaCanvas::setBitmap(const SkBitmap& bitmap) { std::unique_ptr newCanvasWrapper; if (cs.get() != nullptr && !cs->isSRGB()) { newCanvasWrapper = SkCreateColorSpaceXformCanvas(newCanvas.get(), std::move(cs)); - } else if (!uirenderer::Properties::isSkiaEnabled()) { - newCanvasWrapper = SkCreateColorSpaceXformCanvas(newCanvas.get(), SkColorSpace::MakeSRGB()); } // deletes the previously owned canvas (if any) diff --git a/libs/hwui/hwui/Bitmap.cpp b/libs/hwui/hwui/Bitmap.cpp index 795ec5bd4f76..beb4a9e185a3 100644 --- a/libs/hwui/hwui/Bitmap.cpp +++ b/libs/hwui/hwui/Bitmap.cpp @@ -205,10 +205,8 @@ Bitmap::Bitmap(GraphicBuffer* buffer, const SkImageInfo& info) mPixelStorage.hardware.buffer = buffer; buffer->incStrong(buffer); setImmutable(); // HW bitmaps are always immutable - if (uirenderer::Properties::isSkiaEnabled()) { - mImage = SkImage::MakeFromAHardwareBuffer(reinterpret_cast(buffer), - mInfo.alphaType(), mInfo.refColorSpace()); - } + mImage = SkImage::MakeFromAHardwareBuffer(reinterpret_cast(buffer), + mInfo.alphaType(), mInfo.refColorSpace()); } Bitmap::~Bitmap() { @@ -288,13 +286,9 @@ void Bitmap::setAlphaType(SkAlphaType alphaType) { void Bitmap::getSkBitmap(SkBitmap* outBitmap) { outBitmap->setHasHardwareMipMap(mHasHardwareMipMap); if (isHardware()) { - if (uirenderer::Properties::isSkiaEnabled()) { outBitmap->allocPixels(SkImageInfo::Make(info().width(), info().height(), info().colorType(), info().alphaType(), nullptr)); - } else { - outBitmap->allocPixels(info()); - } uirenderer::renderthread::RenderProxy::copyGraphicBufferInto(graphicBuffer(), outBitmap); return; } @@ -317,7 +311,7 @@ GraphicBuffer* Bitmap::graphicBuffer() { sk_sp Bitmap::makeImage(sk_sp* outputColorFilter) { sk_sp image = mImage; if (!image) { - SkASSERT(!(isHardware() && uirenderer::Properties::isSkiaEnabled())); + SkASSERT(!isHardware()); SkBitmap skiaBitmap; skiaBitmap.setInfo(info(), rowBytes()); skiaBitmap.setPixelRef(sk_ref_sp(this), 0, 0); @@ -327,8 +321,7 @@ sk_sp Bitmap::makeImage(sk_sp* outputColorFilter) { // TODO: refactor Bitmap to not derive from SkPixelRef, which would allow caching here. image = SkMakeImageFromRasterBitmap(skiaBitmap, kNever_SkCopyPixelsMode); } - if (uirenderer::Properties::isSkiaEnabled() && image->colorSpace() != nullptr && - !image->colorSpace()->isSRGB()) { + if (image->colorSpace() != nullptr && !image->colorSpace()->isSRGB()) { *outputColorFilter = SkToSRGBColorFilter::Make(image->refColorSpace()); } return image; diff --git a/libs/hwui/hwui/Canvas.cpp b/libs/hwui/hwui/Canvas.cpp index 20543df85068..b453227ba770 100644 --- a/libs/hwui/hwui/Canvas.cpp +++ b/libs/hwui/hwui/Canvas.cpp @@ -29,10 +29,7 @@ namespace android { Canvas* Canvas::create_recording_canvas(int width, int height, uirenderer::RenderNode* renderNode) { - if (uirenderer::Properties::isSkiaEnabled()) { - return new uirenderer::skiapipeline::SkiaRecordingCanvas(renderNode, width, height); - } - return new uirenderer::RecordingCanvas(width, height); + return new uirenderer::skiapipeline::SkiaRecordingCanvas(renderNode, width, height); } static inline void drawStroke(SkScalar left, SkScalar right, SkScalar top, SkScalar thickness, diff --git a/libs/hwui/renderthread/CacheManager.cpp b/libs/hwui/renderthread/CacheManager.cpp index 3ca92953e5f7..00298414a9a3 100644 --- a/libs/hwui/renderthread/CacheManager.cpp +++ b/libs/hwui/renderthread/CacheManager.cpp @@ -50,9 +50,7 @@ CacheManager::CacheManager(const DisplayInfo& display) : mMaxSurfaceArea(display mVectorDrawableAtlas = new skiapipeline::VectorDrawableAtlas( mMaxSurfaceArea / 2, skiapipeline::VectorDrawableAtlas::StorageMode::disallowSharedSurface); - if (Properties::isSkiaEnabled()) { - skiapipeline::ShaderCache::get().initShaderDiskCache(); - } + skiapipeline::ShaderCache::get().initShaderDiskCache(); } void CacheManager::reset(sk_sp context) { diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp index a1a2bad41bf7..653ea2808ae7 100644 --- a/libs/hwui/renderthread/RenderProxy.cpp +++ b/libs/hwui/renderthread/RenderProxy.cpp @@ -334,7 +334,7 @@ sk_sp RenderProxy::allocateHardwareBitmap(SkBitmap& bitmap) { int RenderProxy::copyGraphicBufferInto(GraphicBuffer* buffer, SkBitmap* bitmap) { RenderThread& thread = RenderThread::getInstance(); - if (Properties::isSkiaEnabled() && gettid() == thread.getTid()) { + if (gettid() == thread.getTid()) { // TODO: fix everything that hits this. We should never be triggering a readback ourselves. return (int)thread.readback().copyGraphicBufferInto(buffer, bitmap); } else { -- cgit v1.2.3-59-g8ed1b From d9d7f127b5f07df9434aff67374a0012b1750cd4 Mon Sep 17 00:00:00 2001 From: John Reck Date: Thu, 3 May 2018 14:40:56 -0700 Subject: Delete a bunch of code This removes the duality of DisplayList, removing a small amount of overhead Test: buids & hwuiunit passes Change-Id: I8bb3a20e9ead1caec4b4a8a3e9f2c08f717a7096 --- libs/hwui/Android.bp | 4 - libs/hwui/Animator.h | 4 +- libs/hwui/BakedOpRenderer.h | 11 +- libs/hwui/DisplayList.cpp | 142 ---- libs/hwui/DisplayList.h | 133 +--- libs/hwui/FrameBuilder.cpp | 867 --------------------- libs/hwui/FrameBuilder.h | 251 ------ libs/hwui/Lighting.h | 38 + libs/hwui/RecordingCanvas.cpp | 631 --------------- libs/hwui/RecordingCanvas.h | 320 -------- libs/hwui/RenderNode.cpp | 72 -- libs/hwui/RenderNode.h | 5 - libs/hwui/VectorDrawable.h | 2 + libs/hwui/hwui/Canvas.cpp | 1 - libs/hwui/hwui/Canvas.h | 10 +- libs/hwui/pipeline/skia/GLFunctorDrawable.h | 4 +- libs/hwui/pipeline/skia/RenderNodeDrawable.cpp | 14 +- libs/hwui/pipeline/skia/RenderNodeDrawable.h | 8 +- libs/hwui/pipeline/skia/SkiaDisplayList.h | 42 +- libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp | 5 +- libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h | 4 +- libs/hwui/pipeline/skia/SkiaPipeline.cpp | 5 +- libs/hwui/pipeline/skia/SkiaPipeline.h | 10 +- libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp | 4 +- libs/hwui/pipeline/skia/SkiaVulkanPipeline.h | 4 +- libs/hwui/renderstate/RenderState.cpp | 1 + libs/hwui/renderthread/CanvasContext.h | 8 +- libs/hwui/renderthread/DrawFrameTask.h | 1 - libs/hwui/renderthread/IRenderPipeline.h | 11 +- libs/hwui/renderthread/RenderProxy.cpp | 5 +- libs/hwui/tests/common/TestUtils.h | 15 +- libs/hwui/tests/common/scenes/TestSceneBase.h | 2 +- .../tests/microbench/DisplayListCanvasBench.cpp | 8 +- libs/hwui/tests/microbench/FrameBuilderBench.cpp | 149 ---- libs/hwui/tests/unit/SkiaCanvasTests.cpp | 1 - libs/hwui/tests/unit/SkiaPipelineTests.cpp | 4 +- libs/hwui/utils/TestWindowContext.cpp | 6 +- 37 files changed, 143 insertions(+), 2659 deletions(-) delete mode 100644 libs/hwui/DisplayList.cpp delete mode 100644 libs/hwui/FrameBuilder.cpp delete mode 100644 libs/hwui/FrameBuilder.h create mode 100644 libs/hwui/Lighting.h delete mode 100644 libs/hwui/RecordingCanvas.cpp delete mode 100644 libs/hwui/RecordingCanvas.h delete mode 100644 libs/hwui/tests/microbench/FrameBuilderBench.cpp (limited to 'libs/hwui/RenderNode.cpp') diff --git a/libs/hwui/Android.bp b/libs/hwui/Android.bp index d716844b11c3..1ad40ec68622 100644 --- a/libs/hwui/Android.bp +++ b/libs/hwui/Android.bp @@ -210,8 +210,6 @@ cc_defaults { "DamageAccumulator.cpp", "DeferredLayerUpdater.cpp", "DeviceInfo.cpp", - "DisplayList.cpp", - "FrameBuilder.cpp", "FrameInfo.cpp", "FrameInfoVisualizer.cpp", "GlLayer.cpp", @@ -237,7 +235,6 @@ cc_defaults { "Properties.cpp", "PropertyValuesAnimatorSet.cpp", "PropertyValuesHolder.cpp", - "RecordingCanvas.cpp", "RenderNode.cpp", "RenderProperties.cpp", "ResourceCache.cpp", @@ -399,7 +396,6 @@ cc_benchmark { srcs: [ "tests/microbench/main.cpp", "tests/microbench/DisplayListCanvasBench.cpp", - "tests/microbench/FrameBuilderBench.cpp", "tests/microbench/LinearAllocatorBench.cpp", "tests/microbench/PathParserBench.cpp", "tests/microbench/RenderNodeBench.cpp", diff --git a/libs/hwui/Animator.h b/libs/hwui/Animator.h index 42f4cf8828bd..ed7b6eb1cf4a 100644 --- a/libs/hwui/Animator.h +++ b/libs/hwui/Animator.h @@ -16,6 +16,8 @@ #ifndef ANIMATOR_H #define ANIMATOR_H +#include "CanvasProperty.h" + #include #include #include @@ -31,8 +33,6 @@ namespace uirenderer { class AnimationContext; class BaseRenderNodeAnimator; -class CanvasPropertyPrimitive; -class CanvasPropertyPaint; class Interpolator; class RenderNode; class RenderProperties; diff --git a/libs/hwui/BakedOpRenderer.h b/libs/hwui/BakedOpRenderer.h index ae8928ea8461..72c93650a83b 100644 --- a/libs/hwui/BakedOpRenderer.h +++ b/libs/hwui/BakedOpRenderer.h @@ -17,6 +17,7 @@ #pragma once #include "BakedOpState.h" +#include "Lighting.h" #include "Matrix.h" #include "utils/Macros.h" @@ -42,16 +43,6 @@ struct ClipBase; class BakedOpRenderer { public: typedef void (*GlopReceiver)(BakedOpRenderer&, const Rect*, const ClipBase*, const Glop&); - /** - * Position agnostic shadow lighting info. Used with all shadow ops in scene. - */ - struct LightInfo { - LightInfo() : LightInfo(0, 0) {} - LightInfo(uint8_t ambientShadowAlpha, uint8_t spotShadowAlpha) - : ambientShadowAlpha(ambientShadowAlpha), spotShadowAlpha(spotShadowAlpha) {} - uint8_t ambientShadowAlpha; - uint8_t spotShadowAlpha; - }; BakedOpRenderer(Caches& caches, RenderState& renderState, bool opaque, bool wideColorGamut, const LightInfo& lightInfo) diff --git a/libs/hwui/DisplayList.cpp b/libs/hwui/DisplayList.cpp deleted file mode 100644 index f1f0d2ddfcff..000000000000 --- a/libs/hwui/DisplayList.cpp +++ /dev/null @@ -1,142 +0,0 @@ -/* - * Copyright (C) 2013 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include - -#include - -#include "DamageAccumulator.h" -#include "Debug.h" -#include "DisplayList.h" -#include "OpDumper.h" -#include "RecordedOp.h" -#include "RenderNode.h" -#include "VectorDrawable.h" -#include "renderthread/CanvasContext.h" - -namespace android { -namespace uirenderer { - -DisplayList::DisplayList() - : projectionReceiveIndex(-1) - , stdAllocator(allocator) - , chunks(stdAllocator) - , ops(stdAllocator) - , children(stdAllocator) - , bitmapResources(stdAllocator) - , pathResources(stdAllocator) - , patchResources(stdAllocator) - , paints(stdAllocator) - , regions(stdAllocator) - , referenceHolders(stdAllocator) - , functors(stdAllocator) - , vectorDrawables(stdAllocator) {} - -DisplayList::~DisplayList() { - cleanupResources(); -} - -void DisplayList::cleanupResources() { - if (CC_UNLIKELY(patchResources.size())) { - ResourceCache& resourceCache = ResourceCache::getInstance(); - resourceCache.lock(); - - for (size_t i = 0; i < patchResources.size(); i++) { - resourceCache.decrementRefcountLocked(patchResources[i]); - } - - resourceCache.unlock(); - } - - for (size_t i = 0; i < pathResources.size(); i++) { - const SkPath* path = pathResources[i]; - delete path; - } - - for (auto& iter : functors) { - if (iter.listener) { - iter.listener->onGlFunctorReleased(iter.functor); - } - } - - patchResources.clear(); - pathResources.clear(); - paints.clear(); - regions.clear(); -} - -size_t DisplayList::addChild(NodeOpType* op) { - referenceHolders.push_back(op->renderNode); - size_t index = children.size(); - children.push_back(op); - return index; -} - -void DisplayList::syncContents() { - for (auto& iter : functors) { - (*iter.functor)(DrawGlInfo::kModeSync, nullptr); - } - for (auto& vectorDrawable : vectorDrawables) { - vectorDrawable->syncProperties(); - } -} - -void DisplayList::updateChildren(std::function updateFn) { - for (auto&& child : children) { - updateFn(child->renderNode); - } -} - -bool DisplayList::prepareListAndChildren( - TreeObserver& observer, TreeInfo& info, bool functorsNeedLayer, - std::function childFn) { - info.prepareTextures = info.canvasContext.pinImages(bitmapResources); - - for (auto&& op : children) { - RenderNode* childNode = op->renderNode; - info.damageAccumulator->pushTransform(&op->localMatrix); - bool childFunctorsNeedLayer = - functorsNeedLayer; // TODO! || op->mRecordedWithPotentialStencilClip; - childFn(childNode, observer, info, childFunctorsNeedLayer); - info.damageAccumulator->popTransform(); - } - - bool isDirty = false; - for (auto& vectorDrawable : vectorDrawables) { - // If any vector drawable in the display list needs update, damage the node. - if (vectorDrawable->isDirty()) { - isDirty = true; - } - vectorDrawable->setPropertyChangeWillBeConsumed(true); - } - return isDirty; -} - -void DisplayList::output(std::ostream& output, uint32_t level) { - for (auto&& op : getOps()) { - OpDumper::dump(*op, output, level + 1); - if (op->opId == RecordedOpId::RenderNodeOp) { - auto rnOp = reinterpret_cast(op); - rnOp->renderNode->output(output, level + 1); - } else { - output << std::endl; - } - } -} - -}; // namespace uirenderer -}; // namespace android diff --git a/libs/hwui/DisplayList.h b/libs/hwui/DisplayList.h index 7a9c65dd365b..a952cc23e1ef 100644 --- a/libs/hwui/DisplayList.h +++ b/libs/hwui/DisplayList.h @@ -16,149 +16,20 @@ #pragma once -#include -#include -#include - -#include - -#include -#include -#include -#include -#include - -#include - -#include - -#include "CanvasProperty.h" -#include "Debug.h" -#include "GlFunctorLifecycleListener.h" -#include "Matrix.h" -#include "RenderProperties.h" -#include "TreeInfo.h" -#include "hwui/Bitmap.h" - -#include - -class SkBitmap; -class SkPaint; -class SkPath; -class SkRegion; +#include "pipeline/skia/SkiaDisplayList.h" namespace android { namespace uirenderer { -struct ClipBase; -class Rect; -class Layer; - -struct RecordedOp; -struct RenderNodeOp; - -typedef RecordedOp BaseOpType; -typedef RenderNodeOp NodeOpType; - namespace VectorDrawable { class Tree; }; typedef uirenderer::VectorDrawable::Tree VectorDrawableRoot; -struct FunctorContainer { - Functor* functor; - GlFunctorLifecycleListener* listener; -}; - /** * Data structure that holds the list of commands used in display list stream */ -class DisplayList { - friend class RecordingCanvas; - -public: - struct Chunk { - // range of included ops in DisplayList::ops() - size_t beginOpIndex; - size_t endOpIndex; - - // range of included children in DisplayList::children() - size_t beginChildIndex; - size_t endChildIndex; - - // whether children with non-zero Z in the chunk should be reordered - bool reorderChildren; - - // clip at the beginning of a reorder section, applied to reordered children - const ClipBase* reorderClip; - }; - - DisplayList(); - virtual ~DisplayList(); - - // index of DisplayListOp restore, after which projected descendants should be drawn - int projectionReceiveIndex; - - const LsaVector& getChunks() const { return chunks; } - const LsaVector& getOps() const { return ops; } - - const LsaVector& getChildren() const { return children; } - - const LsaVector>& getBitmapResources() const { return bitmapResources; } - - size_t addChild(NodeOpType* childOp); - - void ref(VirtualLightRefBase* prop) { referenceHolders.push_back(prop); } - - size_t getUsedSize() { return allocator.usedSize(); } - - virtual bool isEmpty() const { return ops.empty(); } - virtual bool hasFunctor() const { return !functors.empty(); } - virtual bool hasVectorDrawables() const { return !vectorDrawables.empty(); } - virtual bool isSkiaDL() const { return false; } - virtual bool reuseDisplayList(RenderNode* node, renderthread::CanvasContext* context) { - return false; - } - - virtual void syncContents(); - virtual void updateChildren(std::function updateFn); - virtual bool prepareListAndChildren( - TreeObserver& observer, TreeInfo& info, bool functorsNeedLayer, - std::function childFn); - - virtual void output(std::ostream& output, uint32_t level); - -protected: - // allocator into which all ops and LsaVector arrays allocated - LinearAllocator allocator; - LinearStdAllocator stdAllocator; - -private: - LsaVector chunks; - LsaVector ops; - - // list of Ops referring to RenderNode children for quick, non-drawing traversal - LsaVector children; - - // Resources - Skia objects + 9 patches referred to by this DisplayList - LsaVector> bitmapResources; - LsaVector pathResources; - LsaVector patchResources; - LsaVector> paints; - LsaVector> regions; - LsaVector> referenceHolders; - - // List of functors - LsaVector functors; - - // List of VectorDrawables that need to be notified of pushStaging. Note that this list gets - // nothing - // but a callback during sync DisplayList, unlike the list of functors defined above, which - // gets special treatment exclusive for webview. - LsaVector vectorDrawables; - - void cleanupResources(); -}; +using DisplayList = skiapipeline::SkiaDisplayList; }; // namespace uirenderer }; // namespace android diff --git a/libs/hwui/FrameBuilder.cpp b/libs/hwui/FrameBuilder.cpp deleted file mode 100644 index 575aea524133..000000000000 --- a/libs/hwui/FrameBuilder.cpp +++ /dev/null @@ -1,867 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "FrameBuilder.h" - -#include "DeferredLayerUpdater.h" -#include "LayerUpdateQueue.h" -#include "RenderNode.h" -#include "VectorDrawable.h" -#include "hwui/Canvas.h" -#include "renderstate/OffscreenBufferPool.h" -#include "utils/FatVector.h" -#include "utils/PaintUtils.h" -#include "utils/TraceUtils.h" - -#include -#include - -namespace android { -namespace uirenderer { - -FrameBuilder::FrameBuilder(const SkRect& clip, uint32_t viewportWidth, uint32_t viewportHeight, - const LightGeometry& lightGeometry, Caches& caches) - : mStdAllocator(mAllocator) - , mLayerBuilders(mStdAllocator) - , mLayerStack(mStdAllocator) - , mCanvasState(*this) - , mCaches(caches) - , mLightRadius(lightGeometry.radius) - , mDrawFbo0(true) { - // Prepare to defer Fbo0 - auto fbo0 = mAllocator.create(viewportWidth, viewportHeight, Rect(clip)); - mLayerBuilders.push_back(fbo0); - mLayerStack.push_back(0); - mCanvasState.initializeSaveStack(viewportWidth, viewportHeight, clip.fLeft, clip.fTop, - clip.fRight, clip.fBottom, lightGeometry.center); -} - -FrameBuilder::FrameBuilder(const LayerUpdateQueue& layers, const LightGeometry& lightGeometry, - Caches& caches) - : mStdAllocator(mAllocator) - , mLayerBuilders(mStdAllocator) - , mLayerStack(mStdAllocator) - , mCanvasState(*this) - , mCaches(caches) - , mLightRadius(lightGeometry.radius) - , mDrawFbo0(false) { - // TODO: remove, with each layer on its own save stack - - // Prepare to defer Fbo0 (which will be empty) - auto fbo0 = mAllocator.create(1, 1, Rect(1, 1)); - mLayerBuilders.push_back(fbo0); - mLayerStack.push_back(0); - mCanvasState.initializeSaveStack(1, 1, 0, 0, 1, 1, lightGeometry.center); - - deferLayers(layers); -} - -void FrameBuilder::deferLayers(const LayerUpdateQueue& layers) { - // Render all layers to be updated, in order. Defer in reverse order, so that they'll be - // updated in the order they're passed in (mLayerBuilders are issued to Renderer in reverse) - for (int i = layers.entries().size() - 1; i >= 0; i--) { - RenderNode* layerNode = layers.entries()[i].renderNode.get(); - // only schedule repaint if node still on layer - possible it may have been - // removed during a dropped frame, but layers may still remain scheduled so - // as not to lose info on what portion is damaged - OffscreenBuffer* layer = layerNode->getLayer(); - if (CC_LIKELY(layer)) { - ATRACE_FORMAT("Optimize HW Layer DisplayList %s %ux%u", layerNode->getName(), - layerNode->getWidth(), layerNode->getHeight()); - - Rect layerDamage = layers.entries()[i].damage; - // TODO: ensure layer damage can't be larger than layer - layerDamage.doIntersect(0, 0, layer->viewportWidth, layer->viewportHeight); - layerNode->computeOrdering(); - - // map current light center into RenderNode's coordinate space - Vector3 lightCenter = mCanvasState.currentSnapshot()->getRelativeLightCenter(); - layer->inverseTransformInWindow.mapPoint3d(lightCenter); - - saveForLayer(layerNode->getWidth(), layerNode->getHeight(), 0, 0, layerDamage, - lightCenter, nullptr, layerNode); - - if (layerNode->getDisplayList()) { - deferNodeOps(*layerNode); - } - restoreForLayer(); - } - } -} - -void FrameBuilder::deferRenderNode(RenderNode& renderNode) { - renderNode.computeOrdering(); - - mCanvasState.save(SaveFlags::MatrixClip); - deferNodePropsAndOps(renderNode); - mCanvasState.restore(); -} - -void FrameBuilder::deferRenderNode(float tx, float ty, Rect clipRect, RenderNode& renderNode) { - renderNode.computeOrdering(); - - mCanvasState.save(SaveFlags::MatrixClip); - mCanvasState.translate(tx, ty); - mCanvasState.clipRect(clipRect.left, clipRect.top, clipRect.right, clipRect.bottom, - SkClipOp::kIntersect); - deferNodePropsAndOps(renderNode); - mCanvasState.restore(); -} - -static Rect nodeBounds(RenderNode& node) { - auto& props = node.properties(); - return Rect(props.getLeft(), props.getTop(), props.getRight(), props.getBottom()); -} - -void FrameBuilder::deferRenderNodeScene(const std::vector >& nodes, - const Rect& contentDrawBounds) { - if (nodes.size() < 1) return; - if (nodes.size() == 1) { - if (!nodes[0]->nothingToDraw()) { - deferRenderNode(*nodes[0]); - } - return; - } - // It there are multiple render nodes, they are laid out as follows: - // #0 - backdrop (content + caption) - // #1 - content (local bounds are at (0,0), will be translated and clipped to backdrop) - // #2 - additional overlay nodes - // Usually the backdrop cannot be seen since it will be entirely covered by the content. While - // resizing however it might become partially visible. The following render loop will crop the - // backdrop against the content and draw the remaining part of it. It will then draw the content - // cropped to the backdrop (since that indicates a shrinking of the window). - // - // Additional nodes will be drawn on top with no particular clipping semantics. - - // Usually the contents bounds should be mContentDrawBounds - however - we will - // move it towards the fixed edge to give it a more stable appearance (for the moment). - // If there is no content bounds we ignore the layering as stated above and start with 2. - - // Backdrop bounds in render target space - const Rect backdrop = nodeBounds(*nodes[0]); - - // Bounds that content will fill in render target space (note content node bounds may be bigger) - Rect content(contentDrawBounds.getWidth(), contentDrawBounds.getHeight()); - content.translate(backdrop.left, backdrop.top); - if (!content.contains(backdrop) && !nodes[0]->nothingToDraw()) { - // Content doesn't entirely overlap backdrop, so fill around content (right/bottom) - - // Note: in the future, if content doesn't snap to backdrop's left/top, this may need to - // also fill left/top. Currently, both 2up and freeform position content at the top/left of - // the backdrop, so this isn't necessary. - if (content.right < backdrop.right) { - // draw backdrop to right side of content - deferRenderNode(0, 0, - Rect(content.right, backdrop.top, backdrop.right, backdrop.bottom), - *nodes[0]); - } - if (content.bottom < backdrop.bottom) { - // draw backdrop to bottom of content - // Note: bottom fill uses content left/right, to avoid overdrawing left/right fill - deferRenderNode(0, 0, - Rect(content.left, content.bottom, content.right, backdrop.bottom), - *nodes[0]); - } - } - - if (!nodes[1]->nothingToDraw()) { - if (!backdrop.isEmpty()) { - // content node translation to catch up with backdrop - float dx = contentDrawBounds.left - backdrop.left; - float dy = contentDrawBounds.top - backdrop.top; - - Rect contentLocalClip = backdrop; - contentLocalClip.translate(dx, dy); - deferRenderNode(-dx, -dy, contentLocalClip, *nodes[1]); - } else { - deferRenderNode(*nodes[1]); - } - } - - // remaining overlay nodes, simply defer - for (size_t index = 2; index < nodes.size(); index++) { - if (!nodes[index]->nothingToDraw()) { - deferRenderNode(*nodes[index]); - } - } -} - -void FrameBuilder::onViewportInitialized() {} - -void FrameBuilder::onSnapshotRestored(const Snapshot& removed, const Snapshot& restored) {} - -void FrameBuilder::deferNodePropsAndOps(RenderNode& node) { - const RenderProperties& properties = node.properties(); - const Outline& outline = properties.getOutline(); - if (properties.getAlpha() <= 0 || (outline.getShouldClip() && outline.isEmpty()) || - properties.getScaleX() == 0 || properties.getScaleY() == 0) { - return; // rejected - } - - if (properties.getLeft() != 0 || properties.getTop() != 0) { - mCanvasState.translate(properties.getLeft(), properties.getTop()); - } - if (properties.getStaticMatrix()) { - mCanvasState.concatMatrix(*properties.getStaticMatrix()); - } else if (properties.getAnimationMatrix()) { - mCanvasState.concatMatrix(*properties.getAnimationMatrix()); - } - if (properties.hasTransformMatrix()) { - if (properties.isTransformTranslateOnly()) { - mCanvasState.translate(properties.getTranslationX(), properties.getTranslationY()); - } else { - mCanvasState.concatMatrix(*properties.getTransformMatrix()); - } - } - - const int width = properties.getWidth(); - const int height = properties.getHeight(); - - Rect saveLayerBounds; // will be set to non-empty if saveLayer needed - const bool isLayer = properties.effectiveLayerType() != LayerType::None; - int clipFlags = properties.getClippingFlags(); - if (properties.getAlpha() < 1) { - if (isLayer) { - clipFlags &= ~CLIP_TO_BOUNDS; // bounds clipping done by layer - } - if (CC_LIKELY(isLayer || !properties.getHasOverlappingRendering())) { - // simply scale rendering content's alpha - mCanvasState.scaleAlpha(properties.getAlpha()); - } else { - // schedule saveLayer by initializing saveLayerBounds - saveLayerBounds.set(0, 0, width, height); - if (clipFlags) { - properties.getClippingRectForFlags(clipFlags, &saveLayerBounds); - clipFlags = 0; // all clipping done by savelayer - } - } - - if (CC_UNLIKELY(ATRACE_ENABLED() && properties.promotedToLayer())) { - // pretend alpha always causes savelayer to warn about - // performance problem affecting old versions - ATRACE_FORMAT("%s alpha caused saveLayer %dx%d", node.getName(), width, height); - } - } - if (clipFlags) { - Rect clipRect; - properties.getClippingRectForFlags(clipFlags, &clipRect); - mCanvasState.clipRect(clipRect.left, clipRect.top, clipRect.right, clipRect.bottom, - SkClipOp::kIntersect); - } - - if (properties.getRevealClip().willClip()) { - Rect bounds; - properties.getRevealClip().getBounds(&bounds); - mCanvasState.setClippingRoundRect(mAllocator, bounds, - properties.getRevealClip().getRadius()); - } else if (properties.getOutline().willClip()) { - mCanvasState.setClippingOutline(mAllocator, &(properties.getOutline())); - } - - bool quickRejected = mCanvasState.currentSnapshot()->getRenderTargetClip().isEmpty() || - (properties.getClipToBounds() && - mCanvasState.quickRejectConservative(0, 0, width, height)); - if (!quickRejected) { - // not rejected, so defer render as either Layer, or direct (possibly wrapped in saveLayer) - if (node.getLayer()) { - // HW layer - LayerOp* drawLayerOp = mAllocator.create_trivial(node); - BakedOpState* bakedOpState = tryBakeOpState(*drawLayerOp); - if (bakedOpState) { - // Node's layer already deferred, schedule it to render into parent layer - currentLayer().deferUnmergeableOp(mAllocator, bakedOpState, OpBatchType::Bitmap); - } - } else if (CC_UNLIKELY(!saveLayerBounds.isEmpty())) { - // draw DisplayList contents within temporary, since persisted layer could not be used. - // (temp layers are clipped to viewport, since they don't persist offscreen content) - SkPaint saveLayerPaint; - saveLayerPaint.setAlpha(properties.getAlpha()); - deferBeginLayerOp(*mAllocator.create_trivial( - saveLayerBounds, Matrix4::identity(), - nullptr, // no record-time clip - need only respect defer-time one - &saveLayerPaint)); - deferNodeOps(node); - deferEndLayerOp(*mAllocator.create_trivial()); - } else { - deferNodeOps(node); - } - } -} - -typedef key_value_pair_t ZRenderNodeOpPair; - -template -static void buildZSortedChildList(V* zTranslatedNodes, const DisplayList& displayList, - const DisplayList::Chunk& chunk) { - if (chunk.beginChildIndex == chunk.endChildIndex) return; - - for (size_t i = chunk.beginChildIndex; i < chunk.endChildIndex; i++) { - RenderNodeOp* childOp = displayList.getChildren()[i]; - RenderNode* child = childOp->renderNode; - float childZ = child->properties().getZ(); - - if (!MathUtils::isZero(childZ) && chunk.reorderChildren) { - zTranslatedNodes->push_back(ZRenderNodeOpPair(childZ, childOp)); - childOp->skipInOrderDraw = true; - } else if (!child->properties().getProjectBackwards()) { - // regular, in order drawing DisplayList - childOp->skipInOrderDraw = false; - } - } - - // Z sort any 3d children (stable-ness makes z compare fall back to standard drawing order) - std::stable_sort(zTranslatedNodes->begin(), zTranslatedNodes->end()); -} - -template -static size_t findNonNegativeIndex(const V& zTranslatedNodes) { - for (size_t i = 0; i < zTranslatedNodes.size(); i++) { - if (zTranslatedNodes[i].key >= 0.0f) return i; - } - return zTranslatedNodes.size(); -} - -template -void FrameBuilder::defer3dChildren(const ClipBase* reorderClip, ChildrenSelectMode mode, - const V& zTranslatedNodes) { - const int size = zTranslatedNodes.size(); - if (size == 0 || (mode == ChildrenSelectMode::Negative && zTranslatedNodes[0].key > 0.0f) || - (mode == ChildrenSelectMode::Positive && zTranslatedNodes[size - 1].key < 0.0f)) { - // no 3d children to draw - return; - } - - /** - * Draw shadows and (potential) casters mostly in order, but allow the shadows of casters - * with very similar Z heights to draw together. - * - * This way, if Views A & B have the same Z height and are both casting shadows, the shadows are - * underneath both, and neither's shadow is drawn on top of the other. - */ - const size_t nonNegativeIndex = findNonNegativeIndex(zTranslatedNodes); - size_t drawIndex, shadowIndex, endIndex; - if (mode == ChildrenSelectMode::Negative) { - drawIndex = 0; - endIndex = nonNegativeIndex; - shadowIndex = endIndex; // draw no shadows - } else { - drawIndex = nonNegativeIndex; - endIndex = size; - shadowIndex = drawIndex; // potentially draw shadow for each pos Z child - } - - float lastCasterZ = 0.0f; - while (shadowIndex < endIndex || drawIndex < endIndex) { - if (shadowIndex < endIndex) { - const RenderNodeOp* casterNodeOp = zTranslatedNodes[shadowIndex].value; - const float casterZ = zTranslatedNodes[shadowIndex].key; - // attempt to render the shadow if the caster about to be drawn is its caster, - // OR if its caster's Z value is similar to the previous potential caster - if (shadowIndex == drawIndex || casterZ - lastCasterZ < 0.1f) { - deferShadow(reorderClip, *casterNodeOp); - - lastCasterZ = casterZ; // must do this even if current caster not casting a shadow - shadowIndex++; - continue; - } - } - - const RenderNodeOp* childOp = zTranslatedNodes[drawIndex].value; - deferRenderNodeOpImpl(*childOp); - drawIndex++; - } -} - -void FrameBuilder::deferShadow(const ClipBase* reorderClip, const RenderNodeOp& casterNodeOp) { - // DEAD CODE -} - -void FrameBuilder::deferProjectedChildren(const RenderNode& renderNode) { - int count = mCanvasState.save(SaveFlags::MatrixClip); - const SkPath* projectionReceiverOutline = renderNode.properties().getOutline().getPath(); - - SkPath transformedMaskPath; // on stack, since BakedOpState makes a deep copy - if (projectionReceiverOutline) { - // transform the mask for this projector into render target space - // TODO: consider combining both transforms by stashing transform instead of applying - SkMatrix skCurrentTransform; - mCanvasState.currentTransform()->copyTo(skCurrentTransform); - projectionReceiverOutline->transform(skCurrentTransform, &transformedMaskPath); - mCanvasState.setProjectionPathMask(&transformedMaskPath); - } - - for (size_t i = 0; i < renderNode.mProjectedNodes.size(); i++) { - RenderNodeOp* childOp = renderNode.mProjectedNodes[i]; - RenderNode& childNode = *childOp->renderNode; - - // Draw child if it has content, but ignore state in childOp - matrix already applied to - // transformFromCompositingAncestor, and record-time clip is ignored when projecting - if (!childNode.nothingToDraw()) { - int restoreTo = mCanvasState.save(SaveFlags::MatrixClip); - - // Apply transform between ancestor and projected descendant - mCanvasState.concatMatrix(childOp->transformFromCompositingAncestor); - - deferNodePropsAndOps(childNode); - - mCanvasState.restoreToCount(restoreTo); - } - } - mCanvasState.restoreToCount(count); -} - -/** - * Used to define a list of lambdas referencing private FrameBuilder::onXX::defer() methods. - * - * This allows opIds embedded in the RecordedOps to be used for dispatching to these lambdas. - * E.g. a BitmapOp op then would be dispatched to FrameBuilder::onBitmapOp(const BitmapOp&) - */ -#define OP_RECEIVER(Type) \ - [](FrameBuilder& frameBuilder, const RecordedOp& op) { \ - frameBuilder.defer##Type(static_cast(op)); \ - }, -void FrameBuilder::deferNodeOps(const RenderNode& renderNode) { - typedef void (*OpDispatcher)(FrameBuilder & frameBuilder, const RecordedOp& op); - static OpDispatcher receivers[] = BUILD_DEFERRABLE_OP_LUT(OP_RECEIVER); - - // can't be null, since DL=null node rejection happens before deferNodePropsAndOps - const DisplayList& displayList = *(renderNode.getDisplayList()); - for (auto& chunk : displayList.getChunks()) { - FatVector zTranslatedNodes; - buildZSortedChildList(&zTranslatedNodes, displayList, chunk); - - defer3dChildren(chunk.reorderClip, ChildrenSelectMode::Negative, zTranslatedNodes); - for (size_t opIndex = chunk.beginOpIndex; opIndex < chunk.endOpIndex; opIndex++) { - const RecordedOp* op = displayList.getOps()[opIndex]; - receivers[op->opId](*this, *op); - - if (CC_UNLIKELY(!renderNode.mProjectedNodes.empty() && - displayList.projectionReceiveIndex >= 0 && - static_cast(opIndex) == displayList.projectionReceiveIndex)) { - deferProjectedChildren(renderNode); - } - } - defer3dChildren(chunk.reorderClip, ChildrenSelectMode::Positive, zTranslatedNodes); - } -} - -void FrameBuilder::deferRenderNodeOpImpl(const RenderNodeOp& op) { - if (op.renderNode->nothingToDraw()) return; - int count = mCanvasState.save(SaveFlags::MatrixClip); - - // apply state from RecordedOp (clip first, since op's clip is transformed by current matrix) - mCanvasState.writableSnapshot()->applyClip(op.localClip, - *mCanvasState.currentSnapshot()->transform); - mCanvasState.concatMatrix(op.localMatrix); - - // then apply state from node properties, and defer ops - deferNodePropsAndOps(*op.renderNode); - - mCanvasState.restoreToCount(count); -} - -void FrameBuilder::deferRenderNodeOp(const RenderNodeOp& op) { - if (!op.skipInOrderDraw) { - deferRenderNodeOpImpl(op); - } -} - -/** - * Defers an unmergeable, strokeable op, accounting correctly - * for paint's style on the bounds being computed. - */ -BakedOpState* FrameBuilder::deferStrokeableOp(const RecordedOp& op, batchid_t batchId, - BakedOpState::StrokeBehavior strokeBehavior, - bool expandForPathTexture) { - // Note: here we account for stroke when baking the op - BakedOpState* bakedState = BakedOpState::tryStrokeableOpConstruct( - mAllocator, *mCanvasState.writableSnapshot(), op, strokeBehavior, expandForPathTexture); - if (!bakedState) return nullptr; // quick rejected - - if (op.opId == RecordedOpId::RectOp && op.paint->getStyle() != SkPaint::kStroke_Style) { - bakedState->setupOpacity(op.paint); - } - - currentLayer().deferUnmergeableOp(mAllocator, bakedState, batchId); - return bakedState; -} - -/** - * Returns batch id for tessellatable shapes, based on paint. Checks to see if path effect/AA will - * be used, since they trigger significantly different rendering paths. - * - * Note: not used for lines/points, since they don't currently support path effects. - */ -static batchid_t tessBatchId(const RecordedOp& op) { - const SkPaint& paint = *(op.paint); - return paint.getPathEffect() - ? OpBatchType::AlphaMaskTexture - : (paint.isAntiAlias() ? OpBatchType::AlphaVertices : OpBatchType::Vertices); -} - -void FrameBuilder::deferArcOp(const ArcOp& op) { - // Pass true below since arcs have a tendency to draw outside their expected bounds within - // their path textures. Passing true makes it more likely that we'll scissor, instead of - // corrupting the frame by drawing outside of clip bounds. - deferStrokeableOp(op, tessBatchId(op), BakedOpState::StrokeBehavior::StyleDefined, true); -} - -static bool hasMergeableClip(const BakedOpState& state) { - return !state.computedState.clipState || - state.computedState.clipState->mode == ClipMode::Rectangle; -} - -void FrameBuilder::deferBitmapOp(const BitmapOp& op) { - BakedOpState* bakedState = tryBakeOpState(op); - if (!bakedState) return; // quick rejected - - if (op.bitmap->isOpaque()) { - bakedState->setupOpacity(op.paint); - } - - // Don't merge non-simply transformed or neg scale ops, SET_TEXTURE doesn't handle rotation - // Don't merge A8 bitmaps - the paint's color isn't compared by mergeId, or in - // MergingDrawBatch::canMergeWith() - if (bakedState->computedState.transform.isSimple() && - bakedState->computedState.transform.positiveScale() && - PaintUtils::getBlendModeDirect(op.paint) == SkBlendMode::kSrcOver && - op.bitmap->colorType() != kAlpha_8_SkColorType && hasMergeableClip(*bakedState)) { - mergeid_t mergeId = reinterpret_cast(op.bitmap->getGenerationID()); - currentLayer().deferMergeableOp(mAllocator, bakedState, OpBatchType::Bitmap, mergeId); - } else { - currentLayer().deferUnmergeableOp(mAllocator, bakedState, OpBatchType::Bitmap); - } -} - -void FrameBuilder::deferBitmapMeshOp(const BitmapMeshOp& op) { - BakedOpState* bakedState = tryBakeOpState(op); - if (!bakedState) return; // quick rejected - currentLayer().deferUnmergeableOp(mAllocator, bakedState, OpBatchType::Bitmap); -} - -void FrameBuilder::deferBitmapRectOp(const BitmapRectOp& op) { - BakedOpState* bakedState = tryBakeOpState(op); - if (!bakedState) return; // quick rejected - currentLayer().deferUnmergeableOp(mAllocator, bakedState, OpBatchType::Bitmap); -} - -void FrameBuilder::deferVectorDrawableOp(const VectorDrawableOp& op) { - Bitmap& bitmap = op.vectorDrawable->getBitmapUpdateIfDirty(); - SkPaint* paint = op.vectorDrawable->getPaint(); - const BitmapRectOp* resolvedOp = mAllocator.create_trivial( - op.unmappedBounds, op.localMatrix, op.localClip, paint, &bitmap, - Rect(bitmap.width(), bitmap.height())); - deferBitmapRectOp(*resolvedOp); -} - -void FrameBuilder::deferCirclePropsOp(const CirclePropsOp& op) { - // allocate a temporary oval op (with mAllocator, so it persists until render), so the - // renderer doesn't have to handle the RoundRectPropsOp type, and so state baking is simple. - float x = *(op.x); - float y = *(op.y); - float radius = *(op.radius); - Rect unmappedBounds(x - radius, y - radius, x + radius, y + radius); - const OvalOp* resolvedOp = mAllocator.create_trivial(unmappedBounds, op.localMatrix, - op.localClip, op.paint); - deferOvalOp(*resolvedOp); -} - -void FrameBuilder::deferColorOp(const ColorOp& op) { - BakedOpState* bakedState = tryBakeUnboundedOpState(op); - if (!bakedState) return; // quick rejected - currentLayer().deferUnmergeableOp(mAllocator, bakedState, OpBatchType::Vertices); -} - -void FrameBuilder::deferFunctorOp(const FunctorOp& op) { - BakedOpState* bakedState = tryBakeUnboundedOpState(op); - if (!bakedState) return; // quick rejected - currentLayer().deferUnmergeableOp(mAllocator, bakedState, OpBatchType::Functor); -} - -void FrameBuilder::deferLinesOp(const LinesOp& op) { - batchid_t batch = op.paint->isAntiAlias() ? OpBatchType::AlphaVertices : OpBatchType::Vertices; - deferStrokeableOp(op, batch, BakedOpState::StrokeBehavior::Forced); -} - -void FrameBuilder::deferOvalOp(const OvalOp& op) { - deferStrokeableOp(op, tessBatchId(op)); -} - -void FrameBuilder::deferPatchOp(const PatchOp& op) { - BakedOpState* bakedState = tryBakeOpState(op); - if (!bakedState) return; // quick rejected - - if (bakedState->computedState.transform.isPureTranslate() && - PaintUtils::getBlendModeDirect(op.paint) == SkBlendMode::kSrcOver && - hasMergeableClip(*bakedState)) { - mergeid_t mergeId = reinterpret_cast(op.bitmap->getGenerationID()); - - // Only use the MergedPatch batchId when merged, so Bitmap+Patch don't try to merge together - currentLayer().deferMergeableOp(mAllocator, bakedState, OpBatchType::MergedPatch, mergeId); - } else { - // Use Bitmap batchId since Bitmap+Patch use same shader - currentLayer().deferUnmergeableOp(mAllocator, bakedState, OpBatchType::Bitmap); - } -} - -void FrameBuilder::deferPathOp(const PathOp& op) { - /*auto state = */deferStrokeableOp(op, OpBatchType::AlphaMaskTexture); -} - -void FrameBuilder::deferPointsOp(const PointsOp& op) { - batchid_t batch = op.paint->isAntiAlias() ? OpBatchType::AlphaVertices : OpBatchType::Vertices; - deferStrokeableOp(op, batch, BakedOpState::StrokeBehavior::Forced); -} - -void FrameBuilder::deferRectOp(const RectOp& op) { - deferStrokeableOp(op, tessBatchId(op)); -} - -void FrameBuilder::deferRoundRectOp(const RoundRectOp& op) { - // DEAD CODE -} - -void FrameBuilder::deferRoundRectPropsOp(const RoundRectPropsOp& op) { - // allocate a temporary round rect op (with mAllocator, so it persists until render), so the - // renderer doesn't have to handle the RoundRectPropsOp type, and so state baking is simple. - const RoundRectOp* resolvedOp = mAllocator.create_trivial( - Rect(*(op.left), *(op.top), *(op.right), *(op.bottom)), op.localMatrix, op.localClip, - op.paint, *op.rx, *op.ry); - deferRoundRectOp(*resolvedOp); -} - -void FrameBuilder::deferSimpleRectsOp(const SimpleRectsOp& op) { - BakedOpState* bakedState = tryBakeOpState(op); - if (!bakedState) return; // quick rejected - currentLayer().deferUnmergeableOp(mAllocator, bakedState, OpBatchType::Vertices); -} - -void FrameBuilder::deferTextOp(const TextOp& op) { - // DEAD CODE -} - -void FrameBuilder::deferTextOnPathOp(const TextOnPathOp& op) { - // DEAD CODE -} - -void FrameBuilder::deferTextureLayerOp(const TextureLayerOp& op) { - GlLayer* layer = static_cast(op.layerHandle->backingLayer()); - if (CC_UNLIKELY(!layer || !layer->isRenderable())) return; - - const TextureLayerOp* textureLayerOp = &op; - // Now safe to access transform (which was potentially unready at record time) - if (!layer->getTransform().isIdentity()) { - // non-identity transform present, so 'inject it' into op by copying + replacing matrix - Matrix4 combinedMatrix(op.localMatrix); - combinedMatrix.multiply(layer->getTransform()); - textureLayerOp = mAllocator.create(op, combinedMatrix); - } - BakedOpState* bakedState = tryBakeOpState(*textureLayerOp); - - if (!bakedState) return; // quick rejected - currentLayer().deferUnmergeableOp(mAllocator, bakedState, OpBatchType::TextureLayer); -} - -void FrameBuilder::saveForLayer(uint32_t layerWidth, uint32_t layerHeight, float contentTranslateX, - float contentTranslateY, const Rect& repaintRect, - const Vector3& lightCenter, const BeginLayerOp* beginLayerOp, - RenderNode* renderNode) { - mCanvasState.save(SaveFlags::MatrixClip); - mCanvasState.writableSnapshot()->initializeViewport(layerWidth, layerHeight); - mCanvasState.writableSnapshot()->roundRectClipState = nullptr; - mCanvasState.writableSnapshot()->setRelativeLightCenter(lightCenter); - mCanvasState.writableSnapshot()->transform->loadTranslate(contentTranslateX, contentTranslateY, - 0); - mCanvasState.writableSnapshot()->setClip(repaintRect.left, repaintRect.top, repaintRect.right, - repaintRect.bottom); - - // create a new layer repaint, and push its index on the stack - mLayerStack.push_back(mLayerBuilders.size()); - auto newFbo = mAllocator.create(layerWidth, layerHeight, repaintRect, - beginLayerOp, renderNode); - mLayerBuilders.push_back(newFbo); -} - -void FrameBuilder::restoreForLayer() { - // restore canvas, and pop finished layer off of the stack - mCanvasState.restore(); - mLayerStack.pop_back(); -} - -// TODO: defer time rejection (when bounds become empty) + tests -// Option - just skip layers with no bounds at playback + defer? -void FrameBuilder::deferBeginLayerOp(const BeginLayerOp& op) { - uint32_t layerWidth = (uint32_t)op.unmappedBounds.getWidth(); - uint32_t layerHeight = (uint32_t)op.unmappedBounds.getHeight(); - - auto previous = mCanvasState.currentSnapshot(); - Vector3 lightCenter = previous->getRelativeLightCenter(); - - // Combine all transforms used to present saveLayer content: - // parent content transform * canvas transform * bounds offset - Matrix4 contentTransform(*(previous->transform)); - contentTransform.multiply(op.localMatrix); - contentTransform.translate(op.unmappedBounds.left, op.unmappedBounds.top); - - Matrix4 inverseContentTransform; - inverseContentTransform.loadInverse(contentTransform); - - // map the light center into layer-relative space - inverseContentTransform.mapPoint3d(lightCenter); - - // Clip bounds of temporary layer to parent's clip rect, so: - Rect saveLayerBounds(layerWidth, layerHeight); - // 1) transform Rect(width, height) into parent's space - // note: left/top offsets put in contentTransform above - contentTransform.mapRect(saveLayerBounds); - // 2) intersect with parent's clip - saveLayerBounds.doIntersect(previous->getRenderTargetClip()); - // 3) and transform back - inverseContentTransform.mapRect(saveLayerBounds); - saveLayerBounds.doIntersect(Rect(layerWidth, layerHeight)); - saveLayerBounds.roundOut(); - - // if bounds are reduced, will clip the layer's area by reducing required bounds... - layerWidth = saveLayerBounds.getWidth(); - layerHeight = saveLayerBounds.getHeight(); - // ...and shifting drawing content to account for left/top side clipping - float contentTranslateX = -saveLayerBounds.left; - float contentTranslateY = -saveLayerBounds.top; - - saveForLayer(layerWidth, layerHeight, contentTranslateX, contentTranslateY, - Rect(layerWidth, layerHeight), lightCenter, &op, nullptr); -} - -void FrameBuilder::deferEndLayerOp(const EndLayerOp& /* ignored */) { - const BeginLayerOp& beginLayerOp = *currentLayer().beginLayerOp; - int finishedLayerIndex = mLayerStack.back(); - - restoreForLayer(); - - // saveLayer will clip & translate the draw contents, so we need - // to translate the drawLayer by how much the contents was translated - // TODO: Unify this with beginLayerOp so we don't have to calculate this - // twice - uint32_t layerWidth = (uint32_t)beginLayerOp.unmappedBounds.getWidth(); - uint32_t layerHeight = (uint32_t)beginLayerOp.unmappedBounds.getHeight(); - - auto previous = mCanvasState.currentSnapshot(); - Vector3 lightCenter = previous->getRelativeLightCenter(); - - // Combine all transforms used to present saveLayer content: - // parent content transform * canvas transform * bounds offset - Matrix4 contentTransform(*(previous->transform)); - contentTransform.multiply(beginLayerOp.localMatrix); - contentTransform.translate(beginLayerOp.unmappedBounds.left, beginLayerOp.unmappedBounds.top); - - Matrix4 inverseContentTransform; - inverseContentTransform.loadInverse(contentTransform); - - // map the light center into layer-relative space - inverseContentTransform.mapPoint3d(lightCenter); - - // Clip bounds of temporary layer to parent's clip rect, so: - Rect saveLayerBounds(layerWidth, layerHeight); - // 1) transform Rect(width, height) into parent's space - // note: left/top offsets put in contentTransform above - contentTransform.mapRect(saveLayerBounds); - // 2) intersect with parent's clip - saveLayerBounds.doIntersect(previous->getRenderTargetClip()); - // 3) and transform back - inverseContentTransform.mapRect(saveLayerBounds); - saveLayerBounds.doIntersect(Rect(layerWidth, layerHeight)); - saveLayerBounds.roundOut(); - - Matrix4 localMatrix(beginLayerOp.localMatrix); - localMatrix.translate(saveLayerBounds.left, saveLayerBounds.top); - - // record the draw operation into the previous layer's list of draw commands - // uses state from the associated beginLayerOp, since it has all the state needed for drawing - LayerOp* drawLayerOp = mAllocator.create_trivial( - beginLayerOp.unmappedBounds, localMatrix, beginLayerOp.localClip, beginLayerOp.paint, - &(mLayerBuilders[finishedLayerIndex]->offscreenBuffer)); - BakedOpState* bakedOpState = tryBakeOpState(*drawLayerOp); - - if (bakedOpState) { - // Layer will be drawn into parent layer (which is now current, since we popped mLayerStack) - currentLayer().deferUnmergeableOp(mAllocator, bakedOpState, OpBatchType::Bitmap); - } else { - // Layer won't be drawn - delete its drawing batches to prevent it from doing any work - // TODO: need to prevent any render work from being done - // - create layerop earlier for reject purposes? - mLayerBuilders[finishedLayerIndex]->clear(); - return; - } -} - -void FrameBuilder::deferBeginUnclippedLayerOp(const BeginUnclippedLayerOp& op) { - Matrix4 boundsTransform(*(mCanvasState.currentSnapshot()->transform)); - boundsTransform.multiply(op.localMatrix); - - Rect dstRect(op.unmappedBounds); - boundsTransform.mapRect(dstRect); - dstRect.roundOut(); - dstRect.doIntersect(mCanvasState.currentSnapshot()->getRenderTargetClip()); - - if (dstRect.isEmpty()) { - // Unclipped layer rejected - push a null op, so next EndUnclippedLayerOp is ignored - currentLayer().activeUnclippedSaveLayers.push_back(nullptr); - } else { - // Allocate a holding position for the layer object (copyTo will produce, copyFrom will - // consume) - OffscreenBuffer** layerHandle = mAllocator.create(nullptr); - - /** - * First, defer an operation to copy out the content from the rendertarget into a layer. - */ - auto copyToOp = mAllocator.create_trivial(op, layerHandle); - BakedOpState* bakedState = BakedOpState::directConstruct( - mAllocator, &(currentLayer().repaintClip), dstRect, *copyToOp); - currentLayer().deferUnmergeableOp(mAllocator, bakedState, OpBatchType::CopyToLayer); - - /** - * Defer a clear rect, so that clears from multiple unclipped layers can be drawn - * both 1) simultaneously, and 2) as long after the copyToLayer executes as possible - */ - currentLayer().deferLayerClear(dstRect); - - /** - * And stash an operation to copy that layer back under the rendertarget until - * a balanced EndUnclippedLayerOp is seen - */ - auto copyFromOp = mAllocator.create_trivial(op, layerHandle); - bakedState = BakedOpState::directConstruct(mAllocator, &(currentLayer().repaintClip), - dstRect, *copyFromOp); - currentLayer().activeUnclippedSaveLayers.push_back(bakedState); - } -} - -void FrameBuilder::deferEndUnclippedLayerOp(const EndUnclippedLayerOp& /* ignored */) { - LOG_ALWAYS_FATAL_IF(currentLayer().activeUnclippedSaveLayers.empty(), "no layer to end!"); - - BakedOpState* copyFromLayerOp = currentLayer().activeUnclippedSaveLayers.back(); - currentLayer().activeUnclippedSaveLayers.pop_back(); - if (copyFromLayerOp) { - currentLayer().deferUnmergeableOp(mAllocator, copyFromLayerOp, OpBatchType::CopyFromLayer); - } -} - -void FrameBuilder::finishDefer() { - // DEAD CODE -} - -} // namespace uirenderer -} // namespace android diff --git a/libs/hwui/FrameBuilder.h b/libs/hwui/FrameBuilder.h deleted file mode 100644 index 974daf8a17bb..000000000000 --- a/libs/hwui/FrameBuilder.h +++ /dev/null @@ -1,251 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include "BakedOpState.h" -#include "CanvasState.h" -#include "DisplayList.h" -#include "LayerBuilder.h" -#include "RecordedOp.h" -#include "utils/GLUtils.h" - -#include -#include - -struct SkRect; - -namespace android { -namespace uirenderer { - -class BakedOpState; -class LayerUpdateQueue; -class OffscreenBuffer; -class Rect; - -/** - * Processes, optimizes, and stores rendering commands from RenderNodes and - * LayerUpdateQueue, building content needed to render a frame. - * - * Resolves final drawing state for each operation (including clip, alpha and matrix), and then - * reorder and merge each op as it is resolved for drawing efficiency. Each layer of content (either - * from the LayerUpdateQueue, or temporary layers created by saveLayer operations in the - * draw stream) will create different reorder contexts, each in its own LayerBuilder. - * - * Then the prepared or 'baked' drawing commands can be issued by calling the templated - * replayBakedOps() function, which will dispatch them (including any created merged op collections) - * to a Dispatcher and Renderer. See BakedOpDispatcher for how these baked drawing operations are - * resolved into Glops and rendered via BakedOpRenderer. - * - * This class is also the authoritative source for traversing RenderNodes, both for standard op - * traversal within a DisplayList, and for out of order RenderNode traversal for Z and projection. - */ -class FrameBuilder : public CanvasStateClient { -public: - struct LightGeometry { - Vector3 center; - float radius; - }; - - FrameBuilder(const SkRect& clip, uint32_t viewportWidth, uint32_t viewportHeight, - const LightGeometry& lightGeometry, Caches& caches); - - FrameBuilder(const LayerUpdateQueue& layerUpdateQueue, const LightGeometry& lightGeometry, - Caches& caches); - - void deferLayers(const LayerUpdateQueue& layers); - - void deferRenderNode(RenderNode& renderNode); - - void deferRenderNode(float tx, float ty, Rect clipRect, RenderNode& renderNode); - - void deferRenderNodeScene(const std::vector >& nodes, - const Rect& contentDrawBounds); - - virtual ~FrameBuilder() {} - - /** - * replayBakedOps() is templated based on what class will receive ops being replayed. - * - * It constructs a lookup array of lambdas, which allows a recorded BakeOpState to use - * state->op->opId to lookup a receiver that will be called when the op is replayed. - */ - template - void replayBakedOps(Renderer& renderer) { - std::vector temporaryLayers; - finishDefer(); -/** - * Defines a LUT of lambdas which allow a recorded BakedOpState to use state->op->opId to - * dispatch the op via a method on a static dispatcher when the op is replayed. - * - * For example a BitmapOp would resolve, via the lambda lookup, to calling: - * - * StaticDispatcher::onBitmapOp(Renderer& renderer, const BitmapOp& op, const BakedOpState& state); - */ -#define X(Type) \ - [](void* renderer, const BakedOpState& state) { \ - StaticDispatcher::on##Type(*(static_cast(renderer)), \ - static_cast(*(state.op)), state); \ - }, - static BakedOpReceiver unmergedReceivers[] = BUILD_RENDERABLE_OP_LUT(X); -#undef X - -/** - * Defines a LUT of lambdas which allow merged arrays of BakedOpState* to be passed to a - * static dispatcher when the group of merged ops is replayed. - */ -#define X(Type) \ - [](void* renderer, const MergedBakedOpList& opList) { \ - StaticDispatcher::onMerged##Type##s(*(static_cast(renderer)), opList); \ - }, - static MergedOpReceiver mergedReceivers[] = BUILD_MERGEABLE_OP_LUT(X); -#undef X - - // Relay through layers in reverse order, since layers - // later in the list will be drawn by earlier ones - for (int i = mLayerBuilders.size() - 1; i >= 1; i--) { - GL_CHECKPOINT(MODERATE); - LayerBuilder& layer = *(mLayerBuilders[i]); - if (layer.renderNode) { - // cached HW layer - can't skip layer if empty - renderer.startRepaintLayer(layer.offscreenBuffer, layer.repaintRect); - GL_CHECKPOINT(MODERATE); - layer.replayBakedOpsImpl((void*)&renderer, unmergedReceivers, mergedReceivers); - GL_CHECKPOINT(MODERATE); - renderer.endLayer(); - } else if (!layer.empty()) { - // save layer - skip entire layer if empty (in which case, LayerOp has null layer). - layer.offscreenBuffer = renderer.startTemporaryLayer(layer.width, layer.height); - temporaryLayers.push_back(layer.offscreenBuffer); - GL_CHECKPOINT(MODERATE); - layer.replayBakedOpsImpl((void*)&renderer, unmergedReceivers, mergedReceivers); - GL_CHECKPOINT(MODERATE); - renderer.endLayer(); - } - } - - GL_CHECKPOINT(MODERATE); - if (CC_LIKELY(mDrawFbo0)) { - const LayerBuilder& fbo0 = *(mLayerBuilders[0]); - renderer.startFrame(fbo0.width, fbo0.height, fbo0.repaintRect); - GL_CHECKPOINT(MODERATE); - fbo0.replayBakedOpsImpl((void*)&renderer, unmergedReceivers, mergedReceivers); - GL_CHECKPOINT(MODERATE); - renderer.endFrame(fbo0.repaintRect); - } - - for (auto& temporaryLayer : temporaryLayers) { - renderer.recycleTemporaryLayer(temporaryLayer); - } - } - - void dump() const { - for (auto&& layer : mLayerBuilders) { - layer->dump(); - } - } - - /////////////////////////////////////////////////////////////////// - /// CanvasStateClient interface - /////////////////////////////////////////////////////////////////// - virtual void onViewportInitialized() override; - virtual void onSnapshotRestored(const Snapshot& removed, const Snapshot& restored) override; - virtual GLuint getTargetFbo() const override { return 0; } - -private: - void finishDefer(); - enum class ChildrenSelectMode { Negative, Positive }; - void saveForLayer(uint32_t layerWidth, uint32_t layerHeight, float contentTranslateX, - float contentTranslateY, const Rect& repaintRect, const Vector3& lightCenter, - const BeginLayerOp* beginLayerOp, RenderNode* renderNode); - void restoreForLayer(); - - LayerBuilder& currentLayer() { return *(mLayerBuilders[mLayerStack.back()]); } - - BakedOpState* tryBakeOpState(const RecordedOp& recordedOp) { - return BakedOpState::tryConstruct(mAllocator, *mCanvasState.writableSnapshot(), recordedOp); - } - BakedOpState* tryBakeUnboundedOpState(const RecordedOp& recordedOp) { - return BakedOpState::tryConstructUnbounded(mAllocator, *mCanvasState.writableSnapshot(), - recordedOp); - } - - // should always be surrounded by a save/restore pair, and not called if DisplayList is null - void deferNodePropsAndOps(RenderNode& node); - - template - void defer3dChildren(const ClipBase* reorderClip, ChildrenSelectMode mode, - const V& zTranslatedNodes); - - void deferShadow(const ClipBase* reorderClip, const RenderNodeOp& casterOp); - - void deferProjectedChildren(const RenderNode& renderNode); - - void deferNodeOps(const RenderNode& renderNode); - - void deferRenderNodeOpImpl(const RenderNodeOp& op); - - void replayBakedOpsImpl(void* arg, BakedOpReceiver* receivers); - - SkPath* createFrameAllocatedPath() { return mAllocator.create(); } - - BakedOpState* deferStrokeableOp(const RecordedOp& op, batchid_t batchId, - BakedOpState::StrokeBehavior strokeBehavior = - BakedOpState::StrokeBehavior::StyleDefined, - bool expandForPathTexture = false); - -/** - * Declares all FrameBuilder::deferXXXXOp() methods for every RecordedOp type. - * - * These private methods are called from within deferImpl to defer each individual op - * type differently. - */ -#define X(Type) void defer##Type(const Type& op); - MAP_DEFERRABLE_OPS(X) -#undef X - - // contains single-frame objects, such as BakedOpStates, LayerBuilders, Batches - LinearAllocator mAllocator; - LinearStdAllocator mStdAllocator; - - // List of every deferred layer's render state. Replayed in reverse order to render a frame. - LsaVector mLayerBuilders; - - /* - * Stack of indices within mLayerBuilders representing currently active layers. If drawing - * layerA within a layerB, will contain, in order: - * - 0 (representing FBO 0, always present) - * - layerB's index - * - layerA's index - * - * Note that this doesn't vector doesn't always map onto all values of mLayerBuilders. When a - * layer is finished deferring, it will still be represented in mLayerBuilders, but it's index - * won't be in mLayerStack. This is because it can be replayed, but can't have any more drawing - * ops added to it. - */ - LsaVector mLayerStack; - - CanvasState mCanvasState; - - Caches& mCaches; - - float mLightRadius; - - const bool mDrawFbo0; -}; - -}; // namespace uirenderer -}; // namespace android diff --git a/libs/hwui/Lighting.h b/libs/hwui/Lighting.h new file mode 100644 index 000000000000..d972c2181aea --- /dev/null +++ b/libs/hwui/Lighting.h @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "Vector.h" + +namespace android { +namespace uirenderer { + +struct LightGeometry { + Vector3 center; + float radius; +}; + +struct LightInfo { + LightInfo() : LightInfo(0, 0) {} + LightInfo(uint8_t ambientShadowAlpha, uint8_t spotShadowAlpha) + : ambientShadowAlpha(ambientShadowAlpha), spotShadowAlpha(spotShadowAlpha) {} + uint8_t ambientShadowAlpha; + uint8_t spotShadowAlpha; +}; + +}; // namespace uirenderer +}; // namespace android diff --git a/libs/hwui/RecordingCanvas.cpp b/libs/hwui/RecordingCanvas.cpp deleted file mode 100644 index e1df1e7725b5..000000000000 --- a/libs/hwui/RecordingCanvas.cpp +++ /dev/null @@ -1,631 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "RecordingCanvas.h" - -#include "DeferredLayerUpdater.h" -#include "RecordedOp.h" -#include "RenderNode.h" -#include "VectorDrawable.h" -#include "hwui/MinikinUtils.h" - -namespace android { -namespace uirenderer { - -RecordingCanvas::RecordingCanvas(size_t width, size_t height) - : mState(*this), mResourceCache(ResourceCache::getInstance()) { - resetRecording(width, height); -} - -RecordingCanvas::~RecordingCanvas() { - LOG_ALWAYS_FATAL_IF(mDisplayList, "Destroyed a RecordingCanvas during a record!"); -} - -void RecordingCanvas::resetRecording(int width, int height, RenderNode* node) { - LOG_ALWAYS_FATAL_IF(mDisplayList, "prepareDirty called a second time during a recording!"); - mDisplayList = new DisplayList(); - - mState.initializeRecordingSaveStack(width, height); - - mDeferredBarrierType = DeferredBarrierType::InOrder; -} - -DisplayList* RecordingCanvas::finishRecording() { - restoreToCount(1); - mPaintMap.clear(); - mRegionMap.clear(); - mPathMap.clear(); - DisplayList* displayList = mDisplayList; - mDisplayList = nullptr; - mSkiaCanvasProxy.reset(nullptr); - return displayList; -} - -void RecordingCanvas::insertReorderBarrier(bool enableReorder) { - if (enableReorder) { - mDeferredBarrierType = DeferredBarrierType::OutOfOrder; - mDeferredBarrierClip = getRecordedClip(); - } else { - mDeferredBarrierType = DeferredBarrierType::InOrder; - mDeferredBarrierClip = nullptr; - } -} - -SkCanvas* RecordingCanvas::asSkCanvas() { - LOG_ALWAYS_FATAL_IF(!mDisplayList, "attempting to get an SkCanvas when we are not recording!"); - if (!mSkiaCanvasProxy) { - mSkiaCanvasProxy.reset(new SkiaCanvasProxy(this)); - } - - // SkCanvas instances default to identity transform, but should inherit - // the state of this Canvas; if this code was in the SkiaCanvasProxy - // constructor, we couldn't cache mSkiaCanvasProxy. - SkMatrix parentTransform; - getMatrix(&parentTransform); - mSkiaCanvasProxy.get()->setMatrix(parentTransform); - - return mSkiaCanvasProxy.get(); -} - -// ---------------------------------------------------------------------------- -// CanvasStateClient implementation -// ---------------------------------------------------------------------------- - -void RecordingCanvas::onViewportInitialized() {} - -void RecordingCanvas::onSnapshotRestored(const Snapshot& removed, const Snapshot& restored) { - if (removed.flags & Snapshot::kFlagIsFboLayer) { - addOp(alloc().create_trivial()); - } else if (removed.flags & Snapshot::kFlagIsLayer) { - addOp(alloc().create_trivial()); - } -} - -// ---------------------------------------------------------------------------- -// android/graphics/Canvas state operations -// ---------------------------------------------------------------------------- -// Save (layer) -int RecordingCanvas::save(SaveFlags::Flags flags) { - return mState.save((int)flags); -} - -void RecordingCanvas::RecordingCanvas::restore() { - mState.restore(); -} - -void RecordingCanvas::restoreToCount(int saveCount) { - mState.restoreToCount(saveCount); -} - -int RecordingCanvas::saveLayer(float left, float top, float right, float bottom, - const SkPaint* paint, SaveFlags::Flags flags) { - // force matrix/clip isolation for layer - flags |= SaveFlags::MatrixClip; - bool clippedLayer = flags & SaveFlags::ClipToLayer; - - const Snapshot& previous = *mState.currentSnapshot(); - - // initialize the snapshot as though it almost represents an FBO layer so deferred draw - // operations will be able to store and restore the current clip and transform info, and - // quick rejection will be correct (for display lists) - - Rect unmappedBounds(left, top, right, bottom); - unmappedBounds.roundOut(); - - // determine clipped bounds relative to previous viewport. - Rect visibleBounds = unmappedBounds; - previous.transform->mapRect(visibleBounds); - - if (CC_UNLIKELY(!clippedLayer && previous.transform->rectToRect() && - visibleBounds.contains(previous.getRenderTargetClip()))) { - // unlikely case where an unclipped savelayer is recorded with a clip it can use, - // as none of its unaffected/unclipped area is visible - clippedLayer = true; - flags |= SaveFlags::ClipToLayer; - } - - visibleBounds.doIntersect(previous.getRenderTargetClip()); - visibleBounds.snapToPixelBoundaries(); - visibleBounds.doIntersect(Rect(previous.getViewportWidth(), previous.getViewportHeight())); - - // Map visible bounds back to layer space, and intersect with parameter bounds - Rect layerBounds = visibleBounds; - if (CC_LIKELY(!layerBounds.isEmpty())) { - // if non-empty, can safely map by the inverse transform - Matrix4 inverse; - inverse.loadInverse(*previous.transform); - inverse.mapRect(layerBounds); - layerBounds.doIntersect(unmappedBounds); - } - - int saveValue = mState.save((int)flags); - Snapshot& snapshot = *mState.writableSnapshot(); - - // layerBounds is in original bounds space, but clipped by current recording clip - if (!layerBounds.isEmpty() && !unmappedBounds.isEmpty()) { - if (CC_LIKELY(clippedLayer)) { - auto previousClip = getRecordedClip(); // capture before new snapshot clip has changed - if (addOp(alloc().create_trivial( - unmappedBounds, - *previous.transform, // transform to *draw* with - previousClip, // clip to *draw* with - refPaint(paint))) >= 0) { - snapshot.flags |= Snapshot::kFlagIsLayer | Snapshot::kFlagIsFboLayer; - snapshot.initializeViewport(unmappedBounds.getWidth(), unmappedBounds.getHeight()); - snapshot.transform->loadTranslate(-unmappedBounds.left, -unmappedBounds.top, 0.0f); - - Rect clip = layerBounds; - clip.translate(-unmappedBounds.left, -unmappedBounds.top); - snapshot.resetClip(clip.left, clip.top, clip.right, clip.bottom); - snapshot.roundRectClipState = nullptr; - return saveValue; - } - } else { - if (addOp(alloc().create_trivial( - unmappedBounds, *mState.currentSnapshot()->transform, getRecordedClip(), - refPaint(paint))) >= 0) { - snapshot.flags |= Snapshot::kFlagIsLayer; - return saveValue; - } - } - } - - // Layer not needed, so skip recording it... - if (CC_LIKELY(clippedLayer)) { - // ... and set empty clip to reject inner content, if possible - snapshot.resetClip(0, 0, 0, 0); - } - return saveValue; -} - -// Matrix -void RecordingCanvas::rotate(float degrees) { - if (degrees == 0) return; - - mState.rotate(degrees); -} - -void RecordingCanvas::scale(float sx, float sy) { - if (sx == 1 && sy == 1) return; - - mState.scale(sx, sy); -} - -void RecordingCanvas::skew(float sx, float sy) { - mState.skew(sx, sy); -} - -void RecordingCanvas::translate(float dx, float dy) { - if (dx == 0 && dy == 0) return; - - mState.translate(dx, dy, 0); -} - -// Clip -bool RecordingCanvas::getClipBounds(SkRect* outRect) const { - *outRect = mState.getLocalClipBounds().toSkRect(); - return !(outRect->isEmpty()); -} -bool RecordingCanvas::quickRejectRect(float left, float top, float right, float bottom) const { - return mState.quickRejectConservative(left, top, right, bottom); -} -bool RecordingCanvas::quickRejectPath(const SkPath& path) const { - SkRect bounds = path.getBounds(); - return mState.quickRejectConservative(bounds.fLeft, bounds.fTop, bounds.fRight, bounds.fBottom); -} -bool RecordingCanvas::clipRect(float left, float top, float right, float bottom, SkClipOp op) { - return mState.clipRect(left, top, right, bottom, op); -} -bool RecordingCanvas::clipPath(const SkPath* path, SkClipOp op) { - return mState.clipPath(path, op); -} - -// ---------------------------------------------------------------------------- -// android/graphics/Canvas draw operations -// ---------------------------------------------------------------------------- -void RecordingCanvas::drawColor(int color, SkBlendMode mode) { - addOp(alloc().create_trivial(getRecordedClip(), color, mode)); -} - -void RecordingCanvas::drawPaint(const SkPaint& paint) { - SkRect bounds; - if (getClipBounds(&bounds)) { - drawRect(bounds.fLeft, bounds.fTop, bounds.fRight, bounds.fBottom, paint); - } -} - -static Rect calcBoundsOfPoints(const float* points, int floatCount) { - Rect unmappedBounds(points[0], points[1], points[0], points[1]); - for (int i = 2; i < floatCount; i += 2) { - unmappedBounds.expandToCover(points[i], points[i + 1]); - } - return unmappedBounds; -} - -// Geometry -void RecordingCanvas::drawPoints(const float* points, int floatCount, const SkPaint& paint) { - if (CC_UNLIKELY(floatCount < 2 || paint.nothingToDraw())) return; - floatCount &= ~0x1; // round down to nearest two - - addOp(alloc().create_trivial( - calcBoundsOfPoints(points, floatCount), *mState.currentSnapshot()->transform, - getRecordedClip(), refPaint(&paint), refBuffer(points, floatCount), floatCount)); -} - -void RecordingCanvas::drawLines(const float* points, int floatCount, const SkPaint& paint) { - if (CC_UNLIKELY(floatCount < 4 || paint.nothingToDraw())) return; - floatCount &= ~0x3; // round down to nearest four - - addOp(alloc().create_trivial( - calcBoundsOfPoints(points, floatCount), *mState.currentSnapshot()->transform, - getRecordedClip(), refPaint(&paint), refBuffer(points, floatCount), floatCount)); -} - -void RecordingCanvas::drawRect(float left, float top, float right, float bottom, - const SkPaint& paint) { - if (CC_UNLIKELY(paint.nothingToDraw())) return; - - addOp(alloc().create_trivial(Rect(left, top, right, bottom), - *(mState.currentSnapshot()->transform), getRecordedClip(), - refPaint(&paint))); -} - -void RecordingCanvas::drawSimpleRects(const float* rects, int vertexCount, const SkPaint* paint) { - if (rects == nullptr) return; - - Vertex* rectData = (Vertex*)mDisplayList->allocator.create_trivial_array(vertexCount); - Vertex* vertex = rectData; - - float left = FLT_MAX; - float top = FLT_MAX; - float right = FLT_MIN; - float bottom = FLT_MIN; - for (int index = 0; index < vertexCount; index += 4) { - float l = rects[index + 0]; - float t = rects[index + 1]; - float r = rects[index + 2]; - float b = rects[index + 3]; - - Vertex::set(vertex++, l, t); - Vertex::set(vertex++, r, t); - Vertex::set(vertex++, l, b); - Vertex::set(vertex++, r, b); - - left = std::min(left, l); - top = std::min(top, t); - right = std::max(right, r); - bottom = std::max(bottom, b); - } - addOp(alloc().create_trivial( - Rect(left, top, right, bottom), *(mState.currentSnapshot()->transform), - getRecordedClip(), refPaint(paint), rectData, vertexCount)); -} - -void RecordingCanvas::drawRegion(const SkRegion& region, const SkPaint& paint) { - if (CC_UNLIKELY(paint.nothingToDraw())) return; - - if (paint.getStyle() == SkPaint::kFill_Style && - (!paint.isAntiAlias() || mState.currentTransform()->isSimple())) { - int count = 0; - Vector rects; - SkRegion::Iterator it(region); - while (!it.done()) { - const SkIRect& r = it.rect(); - rects.push(r.fLeft); - rects.push(r.fTop); - rects.push(r.fRight); - rects.push(r.fBottom); - count += 4; - it.next(); - } - drawSimpleRects(rects.array(), count, &paint); - } else { - SkRegion::Iterator it(region); - while (!it.done()) { - const SkIRect& r = it.rect(); - drawRect(r.fLeft, r.fTop, r.fRight, r.fBottom, paint); - it.next(); - } - } -} - -void RecordingCanvas::drawRoundRect(float left, float top, float right, float bottom, float rx, - float ry, const SkPaint& paint) { - if (CC_UNLIKELY(paint.nothingToDraw())) return; - - if (CC_LIKELY(MathUtils::isPositive(rx) || MathUtils::isPositive(ry))) { - addOp(alloc().create_trivial(Rect(left, top, right, bottom), - *(mState.currentSnapshot()->transform), - getRecordedClip(), refPaint(&paint), rx, ry)); - } else { - drawRect(left, top, right, bottom, paint); - } -} - -void RecordingCanvas::drawRoundRect(CanvasPropertyPrimitive* left, CanvasPropertyPrimitive* top, - CanvasPropertyPrimitive* right, CanvasPropertyPrimitive* bottom, - CanvasPropertyPrimitive* rx, CanvasPropertyPrimitive* ry, - CanvasPropertyPaint* paint) { - mDisplayList->ref(left); - mDisplayList->ref(top); - mDisplayList->ref(right); - mDisplayList->ref(bottom); - mDisplayList->ref(rx); - mDisplayList->ref(ry); - mDisplayList->ref(paint); - refBitmapsInShader(paint->value.getShader()); - addOp(alloc().create_trivial( - *(mState.currentSnapshot()->transform), getRecordedClip(), &paint->value, &left->value, - &top->value, &right->value, &bottom->value, &rx->value, &ry->value)); -} - -void RecordingCanvas::drawCircle(float x, float y, float radius, const SkPaint& paint) { - // TODO: move to Canvas.h - if (CC_UNLIKELY(radius <= 0 || paint.nothingToDraw())) return; - - drawOval(x - radius, y - radius, x + radius, y + radius, paint); -} - -void RecordingCanvas::drawCircle(CanvasPropertyPrimitive* x, CanvasPropertyPrimitive* y, - CanvasPropertyPrimitive* radius, CanvasPropertyPaint* paint) { - mDisplayList->ref(x); - mDisplayList->ref(y); - mDisplayList->ref(radius); - mDisplayList->ref(paint); - refBitmapsInShader(paint->value.getShader()); - addOp(alloc().create_trivial(*(mState.currentSnapshot()->transform), - getRecordedClip(), &paint->value, &x->value, - &y->value, &radius->value)); -} - -void RecordingCanvas::drawOval(float left, float top, float right, float bottom, - const SkPaint& paint) { - if (CC_UNLIKELY(paint.nothingToDraw())) return; - - addOp(alloc().create_trivial(Rect(left, top, right, bottom), - *(mState.currentSnapshot()->transform), getRecordedClip(), - refPaint(&paint))); -} - -void RecordingCanvas::drawArc(float left, float top, float right, float bottom, float startAngle, - float sweepAngle, bool useCenter, const SkPaint& paint) { - if (CC_UNLIKELY(paint.nothingToDraw())) return; - - if (fabs(sweepAngle) >= 360.0f) { - drawOval(left, top, right, bottom, paint); - } else { - addOp(alloc().create_trivial( - Rect(left, top, right, bottom), *(mState.currentSnapshot()->transform), - getRecordedClip(), refPaint(&paint), startAngle, sweepAngle, useCenter)); - } -} - -void RecordingCanvas::drawPath(const SkPath& path, const SkPaint& paint) { - if (CC_UNLIKELY(paint.nothingToDraw())) return; - - addOp(alloc().create_trivial(Rect(path.getBounds()), - *(mState.currentSnapshot()->transform), getRecordedClip(), - refPaint(&paint), refPath(&path))); -} - -void RecordingCanvas::drawVectorDrawable(VectorDrawableRoot* tree) { - mDisplayList->ref(tree); - mDisplayList->vectorDrawables.push_back(tree); - addOp(alloc().create_trivial( - tree, Rect(tree->stagingProperties()->getBounds()), - *(mState.currentSnapshot()->transform), getRecordedClip())); -} - -// Bitmap-based -void RecordingCanvas::drawBitmap(Bitmap& bitmap, float left, float top, const SkPaint* paint) { - save(SaveFlags::Matrix); - translate(left, top); - drawBitmap(bitmap, paint); - restore(); -} - -void RecordingCanvas::drawBitmap(Bitmap& bitmap, const SkMatrix& matrix, const SkPaint* paint) { - if (matrix.isIdentity()) { - drawBitmap(bitmap, paint); - } else if (!(matrix.getType() & ~(SkMatrix::kScale_Mask | SkMatrix::kTranslate_Mask)) && - MathUtils::isPositive(matrix.getScaleX()) && - MathUtils::isPositive(matrix.getScaleY())) { - // SkMatrix::isScaleTranslate() not available in L - SkRect src; - SkRect dst; - bitmap.getBounds(&src); - matrix.mapRect(&dst, src); - drawBitmap(bitmap, src.fLeft, src.fTop, src.fRight, src.fBottom, dst.fLeft, dst.fTop, - dst.fRight, dst.fBottom, paint); - } else { - save(SaveFlags::Matrix); - concat(matrix); - drawBitmap(bitmap, paint); - restore(); - } -} - -void RecordingCanvas::drawBitmap(Bitmap& bitmap, float srcLeft, float srcTop, float srcRight, - float srcBottom, float dstLeft, float dstTop, float dstRight, - float dstBottom, const SkPaint* paint) { - if (srcLeft == 0 && srcTop == 0 && srcRight == bitmap.width() && srcBottom == bitmap.height() && - (srcBottom - srcTop == dstBottom - dstTop) && (srcRight - srcLeft == dstRight - dstLeft)) { - // transform simple rect to rect drawing case into position bitmap ops, since they merge - save(SaveFlags::Matrix); - translate(dstLeft, dstTop); - drawBitmap(bitmap, paint); - restore(); - } else { - addOp(alloc().create_trivial( - Rect(dstLeft, dstTop, dstRight, dstBottom), *(mState.currentSnapshot()->transform), - getRecordedClip(), refPaint(paint), refBitmap(bitmap), - Rect(srcLeft, srcTop, srcRight, srcBottom))); - } -} - -void RecordingCanvas::drawBitmapMesh(Bitmap& bitmap, int meshWidth, int meshHeight, - const float* vertices, const int* colors, - const SkPaint* paint) { - int vertexCount = (meshWidth + 1) * (meshHeight + 1); - addOp(alloc().create_trivial( - calcBoundsOfPoints(vertices, vertexCount * 2), *(mState.currentSnapshot()->transform), - getRecordedClip(), refPaint(paint), refBitmap(bitmap), meshWidth, meshHeight, - refBuffer(vertices, vertexCount * 2), // 2 floats per vertex - refBuffer(colors, vertexCount))); // 1 color per vertex -} - -void RecordingCanvas::drawNinePatch(Bitmap& bitmap, const android::Res_png_9patch& patch, - float dstLeft, float dstTop, float dstRight, float dstBottom, - const SkPaint* paint) { - addOp(alloc().create_trivial(Rect(dstLeft, dstTop, dstRight, dstBottom), - *(mState.currentSnapshot()->transform), getRecordedClip(), - refPaint(paint), refBitmap(bitmap), refPatch(&patch))); -} - -double RecordingCanvas::drawAnimatedImage(AnimatedImageDrawable*) { - // Unimplemented - return 0; -} - -// Text -void RecordingCanvas::drawGlyphs(ReadGlyphFunc glyphFunc, int glyphCount, const SkPaint& paint, - float x, float y, float boundsLeft, float boundsTop, - float boundsRight, float boundsBottom, float totalAdvance) { - if (glyphCount <= 0 || paint.nothingToDraw()) return; - uint16_t* glyphs = (glyph_t*)alloc().alloc(glyphCount * sizeof(glyph_t)); - float* positions = (float*)alloc().alloc(2 * glyphCount * sizeof(float)); - glyphFunc(glyphs, positions); - - // TODO: either must account for text shadow in bounds, or record separate ops for text shadows - addOp(alloc().create_trivial(Rect(boundsLeft, boundsTop, boundsRight, boundsBottom), - *(mState.currentSnapshot()->transform), getRecordedClip(), - refPaint(&paint), glyphs, positions, glyphCount, x, y)); - drawTextDecorations(x, y, totalAdvance, paint); -} - -void RecordingCanvas::drawLayoutOnPath(const minikin::Layout& layout, float hOffset, float vOffset, - const SkPaint& paint, const SkPath& path, size_t start, - size_t end) { - uint16_t glyphs[1]; - for (size_t i = start; i < end; i++) { - glyphs[0] = layout.getGlyphId(i); - float x = hOffset + layout.getX(i); - float y = vOffset + layout.getY(i); - if (paint.nothingToDraw()) return; - const uint16_t* tempGlyphs = refBuffer(glyphs, 1); - addOp(alloc().create_trivial(*(mState.currentSnapshot()->transform), - getRecordedClip(), refPaint(&paint), tempGlyphs, - 1, refPath(&path), x, y)); - } -} - -void RecordingCanvas::drawBitmap(Bitmap& bitmap, const SkPaint* paint) { - addOp(alloc().create_trivial(Rect(bitmap.width(), bitmap.height()), - *(mState.currentSnapshot()->transform), - getRecordedClip(), refPaint(paint), refBitmap(bitmap))); -} - -void RecordingCanvas::drawRenderNode(RenderNode* renderNode) { - auto&& stagingProps = renderNode->stagingProperties(); - RenderNodeOp* op = alloc().create_trivial( - Rect(stagingProps.getWidth(), stagingProps.getHeight()), - *(mState.currentSnapshot()->transform), getRecordedClip(), renderNode); - int opIndex = addOp(op); - if (CC_LIKELY(opIndex >= 0)) { - int childIndex = mDisplayList->addChild(op); - - // update the chunk's child indices - DisplayList::Chunk& chunk = mDisplayList->chunks.back(); - chunk.endChildIndex = childIndex + 1; - - if (renderNode->stagingProperties().isProjectionReceiver()) { - // use staging property, since recording on UI thread - mDisplayList->projectionReceiveIndex = opIndex; - } - } -} - -void RecordingCanvas::drawLayer(DeferredLayerUpdater* layerHandle) { - // We ref the DeferredLayerUpdater due to its thread-safe ref-counting semantics. - mDisplayList->ref(layerHandle); - - LOG_ALWAYS_FATAL_IF(layerHandle->getBackingLayerApi() != Layer::Api::OpenGL); - // Note that the backing layer has *not* yet been updated, so don't trust - // its width, height, transform, etc...! - addOp(alloc().create_trivial( - Rect(layerHandle->getWidth(), layerHandle->getHeight()), - *(mState.currentSnapshot()->transform), getRecordedClip(), layerHandle)); -} - -void RecordingCanvas::callDrawGLFunction(Functor* functor, GlFunctorLifecycleListener* listener) { - mDisplayList->functors.push_back({functor, listener}); - mDisplayList->ref(listener); - addOp(alloc().create_trivial(*(mState.currentSnapshot()->transform), - getRecordedClip(), functor)); -} - -int RecordingCanvas::addOp(RecordedOp* op) { - // skip op with empty clip - if (op->localClip && op->localClip->rect.isEmpty()) { - // NOTE: this rejection happens after op construction/content ref-ing, so content ref'd - // and held by renderthread isn't affected by clip rejection. - // Could rewind alloc here if desired, but callers would have to not touch op afterwards. - return -1; - } - - int insertIndex = mDisplayList->ops.size(); - mDisplayList->ops.push_back(op); - if (mDeferredBarrierType != DeferredBarrierType::None) { - // op is first in new chunk - mDisplayList->chunks.emplace_back(); - DisplayList::Chunk& newChunk = mDisplayList->chunks.back(); - newChunk.beginOpIndex = insertIndex; - newChunk.endOpIndex = insertIndex + 1; - newChunk.reorderChildren = (mDeferredBarrierType == DeferredBarrierType::OutOfOrder); - newChunk.reorderClip = mDeferredBarrierClip; - - int nextChildIndex = mDisplayList->children.size(); - newChunk.beginChildIndex = newChunk.endChildIndex = nextChildIndex; - mDeferredBarrierType = DeferredBarrierType::None; - } else { - // standard case - append to existing chunk - mDisplayList->chunks.back().endOpIndex = insertIndex + 1; - } - return insertIndex; -} - -void RecordingCanvas::refBitmapsInShader(const SkShader* shader) { - if (!shader) return; - - // If this paint has an SkShader that has an SkBitmap add - // it to the bitmap pile - SkBitmap bitmap; - SkShader::TileMode xy[2]; - if (shader->isABitmap(&bitmap, nullptr, xy)) { - Bitmap* hwuiBitmap = static_cast(bitmap.pixelRef()); - refBitmap(*hwuiBitmap); - return; - } - SkShader::ComposeRec rec; - if (shader->asACompose(&rec)) { - refBitmapsInShader(rec.fShaderA); - refBitmapsInShader(rec.fShaderB); - return; - } -} - -}; // namespace uirenderer -}; // namespace android diff --git a/libs/hwui/RecordingCanvas.h b/libs/hwui/RecordingCanvas.h deleted file mode 100644 index e663402a80f3..000000000000 --- a/libs/hwui/RecordingCanvas.h +++ /dev/null @@ -1,320 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef ANDROID_HWUI_RECORDING_CANVAS_H -#define ANDROID_HWUI_RECORDING_CANVAS_H - -#include "CanvasState.h" -#include "DisplayList.h" -#include "ResourceCache.h" -#include "SkiaCanvasProxy.h" -#include "Snapshot.h" -#include "hwui/Bitmap.h" -#include "hwui/Canvas.h" -#include "utils/LinearAllocator.h" -#include "utils/Macros.h" - -#include -#include -#include - -#include - -namespace android { -namespace uirenderer { - -struct ClipBase; -class DeferredLayerUpdater; -struct RecordedOp; - -class ANDROID_API RecordingCanvas : public Canvas, public CanvasStateClient { - enum class DeferredBarrierType { - None, - InOrder, - OutOfOrder, - }; - -public: - RecordingCanvas(size_t width, size_t height); - virtual ~RecordingCanvas(); - - virtual void resetRecording(int width, int height, RenderNode* node = nullptr) override; - virtual WARN_UNUSED_RESULT DisplayList* finishRecording() override; - // ---------------------------------------------------------------------------- - // MISC HWUI OPERATIONS - TODO: CATEGORIZE - // ---------------------------------------------------------------------------- - virtual void insertReorderBarrier(bool enableReorder) override; - - virtual void drawLayer(DeferredLayerUpdater* layerHandle) override; - virtual void drawRenderNode(RenderNode* renderNode) override; - virtual void callDrawGLFunction(Functor* functor, - GlFunctorLifecycleListener* listener) override; - - // ---------------------------------------------------------------------------- - // CanvasStateClient interface - // ---------------------------------------------------------------------------- - virtual void onViewportInitialized() override; - virtual void onSnapshotRestored(const Snapshot& removed, const Snapshot& restored) override; - virtual GLuint getTargetFbo() const override { return -1; } - - // ---------------------------------------------------------------------------- - // HWUI Canvas draw operations - // ---------------------------------------------------------------------------- - - virtual void drawRoundRect(CanvasPropertyPrimitive* left, CanvasPropertyPrimitive* top, - CanvasPropertyPrimitive* right, CanvasPropertyPrimitive* bottom, - CanvasPropertyPrimitive* rx, CanvasPropertyPrimitive* ry, - CanvasPropertyPaint* paint) override; - virtual void drawCircle(CanvasPropertyPrimitive* x, CanvasPropertyPrimitive* y, - CanvasPropertyPrimitive* radius, CanvasPropertyPaint* paint) override; - - // ---------------------------------------------------------------------------- - // android/graphics/Canvas interface - // ---------------------------------------------------------------------------- - virtual SkCanvas* asSkCanvas() override; - - virtual void setBitmap(const SkBitmap& bitmap) override { - LOG_ALWAYS_FATAL("RecordingCanvas is not backed by a bitmap."); - } - - virtual bool isOpaque() override { return false; } - virtual int width() override { return mState.getWidth(); } - virtual int height() override { return mState.getHeight(); } - - // ---------------------------------------------------------------------------- - // android/graphics/Canvas state operations - // ---------------------------------------------------------------------------- - // Save (layer) - virtual int getSaveCount() const override { return mState.getSaveCount(); } - virtual int save(SaveFlags::Flags flags) override; - virtual void restore() override; - virtual void restoreToCount(int saveCount) override; - - virtual int saveLayer(float left, float top, float right, float bottom, const SkPaint* paint, - SaveFlags::Flags flags) override; - virtual int saveLayerAlpha(float left, float top, float right, float bottom, int alpha, - SaveFlags::Flags flags) override { - SkPaint paint; - paint.setAlpha(alpha); - return saveLayer(left, top, right, bottom, &paint, flags); - } - - // Matrix - virtual void getMatrix(SkMatrix* outMatrix) const override { mState.getMatrix(outMatrix); } - virtual void setMatrix(const SkMatrix& matrix) override { mState.setMatrix(matrix); } - - virtual void concat(const SkMatrix& matrix) override { mState.concatMatrix(matrix); } - virtual void rotate(float degrees) override; - virtual void scale(float sx, float sy) override; - virtual void skew(float sx, float sy) override; - virtual void translate(float dx, float dy) override; - - // Clip - virtual bool getClipBounds(SkRect* outRect) const override; - virtual bool quickRejectRect(float left, float top, float right, float bottom) const override; - virtual bool quickRejectPath(const SkPath& path) const override; - - virtual bool clipRect(float left, float top, float right, float bottom, SkClipOp op) override; - virtual bool clipPath(const SkPath* path, SkClipOp op) override; - - // Misc - virtual SkDrawFilter* getDrawFilter() override { return mDrawFilter.get(); } - virtual void setDrawFilter(SkDrawFilter* filter) override { - mDrawFilter.reset(SkSafeRef(filter)); - } - - // ---------------------------------------------------------------------------- - // android/graphics/Canvas draw operations - // ---------------------------------------------------------------------------- - virtual void drawColor(int color, SkBlendMode mode) override; - virtual void drawPaint(const SkPaint& paint) override; - - // Geometry - virtual void drawPoint(float x, float y, const SkPaint& paint) override { - float points[2] = {x, y}; - drawPoints(points, 2, paint); - } - virtual void drawPoints(const float* points, int floatCount, const SkPaint& paint) override; - virtual void drawLine(float startX, float startY, float stopX, float stopY, - const SkPaint& paint) override { - float points[4] = {startX, startY, stopX, stopY}; - drawLines(points, 4, paint); - } - virtual void drawLines(const float* points, int floatCount, const SkPaint& paint) override; - virtual void drawRect(float left, float top, float right, float bottom, - const SkPaint& paint) override; - virtual void drawRegion(const SkRegion& region, const SkPaint& paint) override; - virtual void drawRoundRect(float left, float top, float right, float bottom, float rx, float ry, - const SkPaint& paint) override; - virtual void drawCircle(float x, float y, float radius, const SkPaint& paint) override; - virtual void drawOval(float left, float top, float right, float bottom, - const SkPaint& paint) override; - virtual void drawArc(float left, float top, float right, float bottom, float startAngle, - float sweepAngle, bool useCenter, const SkPaint& paint) override; - virtual void drawPath(const SkPath& path, const SkPaint& paint) override; - virtual void drawVertices(const SkVertices*, SkBlendMode, const SkPaint& paint) - override { /* RecordingCanvas does not support drawVertices(); ignore */ - } - - virtual void drawVectorDrawable(VectorDrawableRoot* tree) override; - - // Bitmap-based - virtual void drawBitmap(Bitmap& bitmap, float left, float top, const SkPaint* paint) override; - virtual void drawBitmap(Bitmap& bitmap, const SkMatrix& matrix, const SkPaint* paint) override; - virtual void drawBitmap(Bitmap& bitmap, float srcLeft, float srcTop, float srcRight, - float srcBottom, float dstLeft, float dstTop, float dstRight, - float dstBottom, const SkPaint* paint) override; - virtual void drawBitmapMesh(Bitmap& bitmap, int meshWidth, int meshHeight, - const float* vertices, const int* colors, - const SkPaint* paint) override; - virtual void drawNinePatch(Bitmap& bitmap, const android::Res_png_9patch& chunk, float dstLeft, - float dstTop, float dstRight, float dstBottom, - const SkPaint* paint) override; - virtual double drawAnimatedImage(AnimatedImageDrawable*) override; - - // Text - virtual bool drawTextAbsolutePos() const override { return false; } - -protected: - virtual void drawGlyphs(ReadGlyphFunc glyphFunc, int count, const SkPaint& paint, float x, - float y, float boundsLeft, float boundsTop, float boundsRight, - float boundsBottom, float totalAdvance) override; - virtual void drawLayoutOnPath(const minikin::Layout& layout, float hOffset, float vOffset, - const SkPaint& paint, const SkPath& path, size_t start, - size_t end) override; - -private: - const ClipBase* getRecordedClip() { - return mState.writableSnapshot()->mutateClipArea().serializeClip(alloc()); - } - - void drawBitmap(Bitmap& bitmap, const SkPaint* paint); - void drawSimpleRects(const float* rects, int vertexCount, const SkPaint* paint); - - int addOp(RecordedOp* op); - // ---------------------------------------------------------------------------- - // lazy object copy - // ---------------------------------------------------------------------------- - LinearAllocator& alloc() { return mDisplayList->allocator; } - - void refBitmapsInShader(const SkShader* shader); - - template - inline const T* refBuffer(const T* srcBuffer, int32_t count) { - if (!srcBuffer) return nullptr; - - T* dstBuffer = (T*)mDisplayList->allocator.alloc(count * sizeof(T)); - memcpy(dstBuffer, srcBuffer, count * sizeof(T)); - return dstBuffer; - } - - inline const SkPath* refPath(const SkPath* path) { - if (!path) return nullptr; - - // The points/verbs within the path are refcounted so this copy operation - // is inexpensive and maintains the generationID of the original path. - const SkPath* cachedPath = new SkPath(*path); - mDisplayList->pathResources.push_back(cachedPath); - return cachedPath; - } - - /** - * Returns a RenderThread-safe, const copy of the SkPaint parameter passed in - * (with deduping based on paint hash / equality check) - */ - inline const SkPaint* refPaint(const SkPaint* paint) { - if (!paint) return nullptr; - - // If there is a draw filter apply it here and store the modified paint - // so that we don't need to modify the paint every time we access it. - SkTLazy filteredPaint; - if (mDrawFilter.get()) { - filteredPaint.set(*paint); - mDrawFilter->filter(filteredPaint.get(), SkDrawFilter::kPaint_Type); - paint = filteredPaint.get(); - } - - // compute the hash key for the paint and check the cache. - const uint32_t key = paint->getHash(); - const SkPaint* cachedPaint = mPaintMap.valueFor(key); - // In the unlikely event that 2 unique paints have the same hash we do a - // object equality check to ensure we don't erroneously dedup them. - if (cachedPaint == nullptr || *cachedPaint != *paint) { - cachedPaint = new SkPaint(*paint); - mDisplayList->paints.emplace_back(cachedPaint); - // replaceValueFor() performs an add if the entry doesn't exist - mPaintMap.replaceValueFor(key, cachedPaint); - refBitmapsInShader(cachedPaint->getShader()); - } - - return cachedPaint; - } - - inline const SkRegion* refRegion(const SkRegion* region) { - if (!region) { - return region; - } - - const SkRegion* cachedRegion = mRegionMap.valueFor(region); - // TODO: Add generation ID to SkRegion - if (cachedRegion == nullptr) { - std::unique_ptr copy(new SkRegion(*region)); - cachedRegion = copy.get(); - mDisplayList->regions.push_back(std::move(copy)); - - // replaceValueFor() performs an add if the entry doesn't exist - mRegionMap.replaceValueFor(region, cachedRegion); - } - - return cachedRegion; - } - - inline Bitmap* refBitmap(Bitmap& bitmap) { - // Note that this assumes the bitmap is immutable. There are cases this won't handle - // correctly, such as creating the bitmap from scratch, drawing with it, changing its - // contents, and drawing again. The only fix would be to always copy it the first time, - // which doesn't seem worth the extra cycles for this unlikely case. - - // this is required because sk_sp's ctor adopts the pointer, - // but does not increment the refcount, - bitmap.ref(); - mDisplayList->bitmapResources.emplace_back(&bitmap); - return &bitmap; - } - - inline const Res_png_9patch* refPatch(const Res_png_9patch* patch) { - mDisplayList->patchResources.push_back(patch); - mResourceCache.incrementRefcount(patch); - return patch; - } - - DefaultKeyedVector mPaintMap; - DefaultKeyedVector mPathMap; - DefaultKeyedVector mRegionMap; - - CanvasState mState; - std::unique_ptr mSkiaCanvasProxy; - ResourceCache& mResourceCache; - DeferredBarrierType mDeferredBarrierType = DeferredBarrierType::None; - const ClipBase* mDeferredBarrierClip = nullptr; - DisplayList* mDisplayList = nullptr; - sk_sp mDrawFilter; -}; // class RecordingCanvas - -}; // namespace uirenderer -}; // namespace android - -#endif // ANDROID_HWUI_RECORDING_CANVAS_H diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp index 62b80c43ebb7..e9039001bd53 100644 --- a/libs/hwui/RenderNode.cpp +++ b/libs/hwui/RenderNode.cpp @@ -381,78 +381,6 @@ void RenderNode::applyViewPropertyTransforms(mat4& matrix, bool true3dTransform) } } -/** - * Organizes the DisplayList hierarchy to prepare for background projection reordering. - * - * This should be called before a call to defer() or drawDisplayList() - * - * Each DisplayList that serves as a 3d root builds its list of composited children, - * which are flagged to not draw in the standard draw loop. - */ -void RenderNode::computeOrdering() { - ATRACE_CALL(); - mProjectedNodes.clear(); - - // TODO: create temporary DDLOp and call computeOrderingImpl on top DisplayList so that - // transform properties are applied correctly to top level children - if (mDisplayList == nullptr) return; - for (unsigned int i = 0; i < mDisplayList->getChildren().size(); i++) { - RenderNodeOp* childOp = mDisplayList->getChildren()[i]; - childOp->renderNode->computeOrderingImpl(childOp, &mProjectedNodes, &mat4::identity()); - } -} - -void RenderNode::computeOrderingImpl( - RenderNodeOp* opState, std::vector* compositedChildrenOfProjectionSurface, - const mat4* transformFromProjectionSurface) { - mProjectedNodes.clear(); - if (mDisplayList == nullptr || mDisplayList->isEmpty()) return; - - // TODO: should avoid this calculation in most cases - // TODO: just calculate single matrix, down to all leaf composited elements - Matrix4 localTransformFromProjectionSurface(*transformFromProjectionSurface); - localTransformFromProjectionSurface.multiply(opState->localMatrix); - - if (properties().getProjectBackwards()) { - // composited projectee, flag for out of order draw, save matrix, and store in proj surface - opState->skipInOrderDraw = true; - opState->transformFromCompositingAncestor = localTransformFromProjectionSurface; - compositedChildrenOfProjectionSurface->push_back(opState); - } else { - // standard in order draw - opState->skipInOrderDraw = false; - } - - if (mDisplayList->getChildren().size() > 0) { - const bool isProjectionReceiver = mDisplayList->projectionReceiveIndex >= 0; - bool haveAppliedPropertiesToProjection = false; - for (unsigned int i = 0; i < mDisplayList->getChildren().size(); i++) { - RenderNodeOp* childOp = mDisplayList->getChildren()[i]; - RenderNode* child = childOp->renderNode; - - std::vector* projectionChildren = nullptr; - const mat4* projectionTransform = nullptr; - if (isProjectionReceiver && !child->properties().getProjectBackwards()) { - // if receiving projections, collect projecting descendant - - // Note that if a direct descendant is projecting backwards, we pass its - // grandparent projection collection, since it shouldn't project onto its - // parent, where it will already be drawing. - projectionChildren = &mProjectedNodes; - projectionTransform = &mat4::identity(); - } else { - if (!haveAppliedPropertiesToProjection) { - applyViewPropertyTransforms(localTransformFromProjectionSurface); - haveAppliedPropertiesToProjection = true; - } - projectionChildren = compositedChildrenOfProjectionSurface; - projectionTransform = &localTransformFromProjectionSurface; - } - child->computeOrderingImpl(childOp, projectionChildren, projectionTransform); - } - } -} - const SkPath* RenderNode::getClippedOutline(const SkRect& clipRect) const { const SkPath* outlinePath = properties().getOutline().getPath(); const uint32_t outlineID = outlinePath->getGenerationID(); diff --git a/libs/hwui/RenderNode.h b/libs/hwui/RenderNode.h index 1e0d4e2c2254..45a53f9a37df 100644 --- a/libs/hwui/RenderNode.h +++ b/libs/hwui/RenderNode.h @@ -48,8 +48,6 @@ namespace android { namespace uirenderer { class CanvasState; -class DisplayListOp; -class FrameBuilder; class OffscreenBuffer; class Rect; class SkiaShader; @@ -76,7 +74,6 @@ class RenderNode; */ class RenderNode : public VirtualLightRefBase { friend class TestUtils; // allow TestUtils to access syncDisplayList / syncProperties - friend class FrameBuilder; public: enum DirtyPropertyMask { @@ -104,8 +101,6 @@ public: ANDROID_API void setStagingDisplayList(DisplayList* newData); - void computeOrdering(); - ANDROID_API void output(); ANDROID_API int getDebugSize(); diff --git a/libs/hwui/VectorDrawable.h b/libs/hwui/VectorDrawable.h index da52a9503377..e84b9acffca7 100644 --- a/libs/hwui/VectorDrawable.h +++ b/libs/hwui/VectorDrawable.h @@ -718,6 +718,8 @@ private: } // namespace VectorDrawable typedef VectorDrawable::Path::Data PathData; +typedef uirenderer::VectorDrawable::Tree VectorDrawableRoot; + } // namespace uirenderer } // namespace android diff --git a/libs/hwui/hwui/Canvas.cpp b/libs/hwui/hwui/Canvas.cpp index b453227ba770..30f6f12b424e 100644 --- a/libs/hwui/hwui/Canvas.cpp +++ b/libs/hwui/hwui/Canvas.cpp @@ -19,7 +19,6 @@ #include "MinikinUtils.h" #include "Paint.h" #include "Properties.h" -#include "RecordingCanvas.h" #include "RenderNode.h" #include "Typeface.h" #include "pipeline/skia/SkiaRecordingCanvas.h" diff --git a/libs/hwui/hwui/Canvas.h b/libs/hwui/hwui/Canvas.h index f341cf96120d..341b0c56a50c 100644 --- a/libs/hwui/hwui/Canvas.h +++ b/libs/hwui/hwui/Canvas.h @@ -44,8 +44,16 @@ namespace uirenderer { class CanvasPropertyPaint; class CanvasPropertyPrimitive; class DeferredLayerUpdater; -class DisplayList; class RenderNode; + +namespace skiapipeline { +class SkiaDisplayList; +} + +/** + * Data structure that holds the list of commands used in display list stream + */ +using DisplayList = skiapipeline::SkiaDisplayList; } namespace SaveFlags { diff --git a/libs/hwui/pipeline/skia/GLFunctorDrawable.h b/libs/hwui/pipeline/skia/GLFunctorDrawable.h index af57d7d33c2c..d9e65c95444e 100644 --- a/libs/hwui/pipeline/skia/GLFunctorDrawable.h +++ b/libs/hwui/pipeline/skia/GLFunctorDrawable.h @@ -16,6 +16,8 @@ #pragma once +#include "GlFunctorLifecycleListener.h" + #include #include @@ -25,8 +27,6 @@ namespace android { namespace uirenderer { -class GlFunctorLifecycleListener; - namespace skiapipeline { /** diff --git a/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp b/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp index 6c04d7862979..1b816febf846 100644 --- a/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp +++ b/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp @@ -25,6 +25,19 @@ namespace android { namespace uirenderer { namespace skiapipeline { +RenderNodeDrawable::RenderNodeDrawable(RenderNode* node, SkCanvas* canvas, bool composeLayer, + bool inReorderingSection) + : mRenderNode(node) + , mRecordedTransform(canvas->getTotalMatrix()) + , mComposeLayer(composeLayer) + , mInReorderingSection(inReorderingSection) {} + +RenderNodeDrawable::~RenderNodeDrawable() { + // Just here to move the destructor into the cpp file where we can access RenderNode. + + // TODO: Detangle the header nightmare. +} + void RenderNodeDrawable::drawBackwardsProjectedNodes(SkCanvas* canvas, const SkiaDisplayList& displayList, int nestLevel) { @@ -115,7 +128,6 @@ void RenderNodeDrawable::forceDraw(SkCanvas* canvas) { return; } - SkASSERT(renderNode->getDisplayList()->isSkiaDL()); SkiaDisplayList* displayList = (SkiaDisplayList*)renderNode->getDisplayList(); SkAutoCanvasRestore acr(canvas, true); diff --git a/libs/hwui/pipeline/skia/RenderNodeDrawable.h b/libs/hwui/pipeline/skia/RenderNodeDrawable.h index ef21cd8a29b5..6594bd22c0b1 100644 --- a/libs/hwui/pipeline/skia/RenderNodeDrawable.h +++ b/libs/hwui/pipeline/skia/RenderNodeDrawable.h @@ -47,11 +47,9 @@ public: * layer into the canvas. */ explicit RenderNodeDrawable(RenderNode* node, SkCanvas* canvas, bool composeLayer = true, - bool inReorderingSection = false) - : mRenderNode(node) - , mRecordedTransform(canvas->getTotalMatrix()) - , mComposeLayer(composeLayer) - , mInReorderingSection(inReorderingSection) {} + bool inReorderingSection = false); + + ~RenderNodeDrawable(); /** * Draws into the canvas this render node and its children. If the node is marked as a diff --git a/libs/hwui/pipeline/skia/SkiaDisplayList.h b/libs/hwui/pipeline/skia/SkiaDisplayList.h index 818ec114a5b3..58b9242e087f 100644 --- a/libs/hwui/pipeline/skia/SkiaDisplayList.h +++ b/libs/hwui/pipeline/skia/SkiaDisplayList.h @@ -16,10 +16,11 @@ #pragma once -#include "DisplayList.h" #include "hwui/AnimatedImageDrawable.h" #include "GLFunctorDrawable.h" #include "RenderNodeDrawable.h" +#include "TreeInfo.h" +#include "utils/LinearAllocator.h" #include #include @@ -28,8 +29,17 @@ namespace android { namespace uirenderer { +namespace renderthread { +class CanvasContext; +} + class Outline; +namespace VectorDrawable { +class Tree; +}; +typedef uirenderer::VectorDrawable::Tree VectorDrawableRoot; + namespace skiapipeline { /** @@ -38,10 +48,14 @@ namespace skiapipeline { * runtime. The downside of this inheritance is that we pay for the overhead * of the parent class construction/destruction without any real benefit. */ -class SkiaDisplayList : public DisplayList { +class SkiaDisplayList { public: - SkiaDisplayList() { SkASSERT(projectionReceiveIndex == -1); } - virtual ~SkiaDisplayList() { + // index of DisplayListOp restore, after which projected descendants should be drawn + int projectionReceiveIndex = -1; + + size_t getUsedSize() { return allocator.usedSize(); } + + ~SkiaDisplayList() { /* Given that we are using a LinearStdAllocator to store some of the * SkDrawable contents we must ensure that any other object that is * holding a reference to those drawables is destroyed prior to their @@ -68,29 +82,27 @@ public: return allocator.create(std::forward(params)...); } - bool isSkiaDL() const override { return true; } - /** * Returns true if the DisplayList does not have any recorded content */ - bool isEmpty() const override { return mDisplayList.empty(); } + bool isEmpty() const { return mDisplayList.empty(); } /** * Returns true if this list directly contains a GLFunctor drawing command. */ - bool hasFunctor() const override { return !mChildFunctors.empty(); } + bool hasFunctor() const { return !mChildFunctors.empty(); } /** * Returns true if this list directly contains a VectorDrawable drawing command. */ - bool hasVectorDrawables() const override { return !mVectorDrawables.empty(); } + bool hasVectorDrawables() const { return !mVectorDrawables.empty(); } /** * Attempts to reset and reuse this DisplayList. * * @return true if the displayList will be reused and therefore should not be deleted */ - bool reuseDisplayList(RenderNode* node, renderthread::CanvasContext* context) override; + bool reuseDisplayList(RenderNode* node, renderthread::CanvasContext* context); /** * ONLY to be called by RenderNode::syncDisplayList so that we can notify any @@ -99,7 +111,7 @@ public: * NOTE: This function can be folded into RenderNode when we no longer need * to subclass from DisplayList */ - void syncContents() override; + void syncContents(); /** * ONLY to be called by RenderNode::prepareTree in order to prepare this @@ -116,12 +128,12 @@ public: bool prepareListAndChildren( TreeObserver& observer, TreeInfo& info, bool functorsNeedLayer, - std::function childFn) override; + std::function childFn); /** * Calls the provided function once for each child of this DisplayList */ - void updateChildren(std::function updateFn) override; + void updateChildren(std::function updateFn); /** * Returns true if there is a child render node that is a projection receiver. @@ -134,7 +146,9 @@ public: void draw(SkCanvas* canvas) { mDisplayList.draw(canvas); } - void output(std::ostream& output, uint32_t level) override; + void output(std::ostream& output, uint32_t level); + + LinearAllocator allocator; /** * We use std::deque here because (1) we need to iterate through these diff --git a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp index cfcfd2b74a5a..15277f175350 100644 --- a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp +++ b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp @@ -25,6 +25,7 @@ #include "renderstate/RenderState.h" #include "renderthread/EglManager.h" #include "renderthread/Frame.h" +#include "utils/GLUtils.h" #include "utils/TraceUtils.h" #include @@ -58,10 +59,10 @@ Frame SkiaOpenGLPipeline::getFrame() { } bool SkiaOpenGLPipeline::draw(const Frame& frame, const SkRect& screenDirty, const SkRect& dirty, - const FrameBuilder::LightGeometry& lightGeometry, + const LightGeometry& lightGeometry, LayerUpdateQueue* layerUpdateQueue, const Rect& contentDrawBounds, bool opaque, bool wideColorGamut, - const BakedOpRenderer::LightInfo& lightInfo, + const LightInfo& lightInfo, const std::vector>& renderNodes, FrameInfoVisualizer* profiler) { mEglManager.damageFrame(frame, dirty); diff --git a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h index ef5d9347a3ea..04b68f5e3278 100644 --- a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h +++ b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h @@ -33,9 +33,9 @@ public: renderthread::MakeCurrentResult makeCurrent() override; renderthread::Frame getFrame() override; bool draw(const renderthread::Frame& frame, const SkRect& screenDirty, const SkRect& dirty, - const FrameBuilder::LightGeometry& lightGeometry, LayerUpdateQueue* layerUpdateQueue, + const LightGeometry& lightGeometry, LayerUpdateQueue* layerUpdateQueue, const Rect& contentDrawBounds, bool opaque, bool wideColorGamut, - const BakedOpRenderer::LightInfo& lightInfo, + const LightInfo& lightInfo, const std::vector >& renderNodes, FrameInfoVisualizer* profiler) override; bool swapBuffers(const renderthread::Frame& frame, bool drew, const SkRect& screenDirty, diff --git a/libs/hwui/pipeline/skia/SkiaPipeline.cpp b/libs/hwui/pipeline/skia/SkiaPipeline.cpp index d66cba12ad99..988981d65775 100644 --- a/libs/hwui/pipeline/skia/SkiaPipeline.cpp +++ b/libs/hwui/pipeline/skia/SkiaPipeline.cpp @@ -81,9 +81,9 @@ void SkiaPipeline::onPrepareTree() { mVectorDrawables.clear(); } -void SkiaPipeline::renderLayers(const FrameBuilder::LightGeometry& lightGeometry, +void SkiaPipeline::renderLayers(const LightGeometry& lightGeometry, LayerUpdateQueue* layerUpdateQueue, bool opaque, - bool wideColorGamut, const BakedOpRenderer::LightInfo& lightInfo) { + bool wideColorGamut, const LightInfo& lightInfo) { updateLighting(lightGeometry, lightInfo); ATRACE_NAME("draw layers"); renderVectorDrawableCache(); @@ -103,7 +103,6 @@ void SkiaPipeline::renderLayersImpl(const LayerUpdateQueue& layers, bool opaque, // as not to lose info on what portion is damaged if (CC_LIKELY(layerNode->getLayerSurface() != nullptr)) { SkASSERT(layerNode->getLayerSurface()); - SkASSERT(layerNode->getDisplayList()->isSkiaDL()); SkiaDisplayList* displayList = (SkiaDisplayList*)layerNode->getDisplayList(); if (!displayList || displayList->isEmpty()) { SkDEBUGF(("%p drawLayers(%s) : missing drawable", layerNode, layerNode->getName())); diff --git a/libs/hwui/pipeline/skia/SkiaPipeline.h b/libs/hwui/pipeline/skia/SkiaPipeline.h index 38ad9c09a8aa..8c9c80381b84 100644 --- a/libs/hwui/pipeline/skia/SkiaPipeline.h +++ b/libs/hwui/pipeline/skia/SkiaPipeline.h @@ -17,7 +17,7 @@ #pragma once #include -#include "FrameBuilder.h" +#include "Lighting.h" #include "hwui/AnimatedImageDrawable.h" #include "renderthread/CanvasContext.h" #include "renderthread/IRenderPipeline.h" @@ -42,9 +42,9 @@ public: void unpinImages() override; void onPrepareTree() override; - void renderLayers(const FrameBuilder::LightGeometry& lightGeometry, + void renderLayers(const LightGeometry& lightGeometry, LayerUpdateQueue* layerUpdateQueue, bool opaque, bool wideColorGamut, - const BakedOpRenderer::LightInfo& lightInfo) override; + const LightInfo& lightInfo) override; bool createOrUpdateLayer(RenderNode* node, const DamageAccumulator& damageAccumulator, bool wideColorGamut, ErrorHandler* errorHandler) override; @@ -97,8 +97,8 @@ public: return mLightCenter; } - static void updateLighting(const FrameBuilder::LightGeometry& lightGeometry, - const BakedOpRenderer::LightInfo& lightInfo) { + static void updateLighting(const LightGeometry& lightGeometry, + const LightInfo& lightInfo) { mLightRadius = lightGeometry.radius; mAmbientShadowAlpha = lightInfo.ambientShadowAlpha; mSpotShadowAlpha = lightInfo.spotShadowAlpha; diff --git a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp index 5825060f902a..b2519fe59891 100644 --- a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp +++ b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp @@ -62,10 +62,10 @@ Frame SkiaVulkanPipeline::getFrame() { } bool SkiaVulkanPipeline::draw(const Frame& frame, const SkRect& screenDirty, const SkRect& dirty, - const FrameBuilder::LightGeometry& lightGeometry, + const LightGeometry& lightGeometry, LayerUpdateQueue* layerUpdateQueue, const Rect& contentDrawBounds, bool opaque, bool wideColorGamut, - const BakedOpRenderer::LightInfo& lightInfo, + const LightInfo& lightInfo, const std::vector>& renderNodes, FrameInfoVisualizer* profiler) { sk_sp backBuffer = mVkSurface->getBackBufferSurface(); diff --git a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h index 03b4c79f2beb..7806b42e03dc 100644 --- a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h +++ b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h @@ -31,9 +31,9 @@ public: renderthread::MakeCurrentResult makeCurrent() override; renderthread::Frame getFrame() override; bool draw(const renderthread::Frame& frame, const SkRect& screenDirty, const SkRect& dirty, - const FrameBuilder::LightGeometry& lightGeometry, LayerUpdateQueue* layerUpdateQueue, + const LightGeometry& lightGeometry, LayerUpdateQueue* layerUpdateQueue, const Rect& contentDrawBounds, bool opaque, bool wideColorGamut, - const BakedOpRenderer::LightInfo& lightInfo, + const LightInfo& lightInfo, const std::vector >& renderNodes, FrameInfoVisualizer* profiler) override; bool swapBuffers(const renderthread::Frame& frame, bool drew, const SkRect& screenDirty, diff --git a/libs/hwui/renderstate/RenderState.cpp b/libs/hwui/renderstate/RenderState.cpp index f173136d6f8d..a60e2b5c815e 100644 --- a/libs/hwui/renderstate/RenderState.cpp +++ b/libs/hwui/renderstate/RenderState.cpp @@ -18,6 +18,7 @@ #include "DeferredLayerUpdater.h" #include "GlLayer.h" #include "VkLayer.h" +#include "Snapshot.h" #include "renderthread/CanvasContext.h" #include "renderthread/EglManager.h" diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h index aaef85a5b1bc..358b842cee20 100644 --- a/libs/hwui/renderthread/CanvasContext.h +++ b/libs/hwui/renderthread/CanvasContext.h @@ -16,10 +16,8 @@ #pragma once -#include "BakedOpDispatcher.h" -#include "BakedOpRenderer.h" #include "DamageAccumulator.h" -#include "FrameBuilder.h" +#include "Lighting.h" #include "FrameInfo.h" #include "FrameInfoVisualizer.h" #include "FrameMetricsReporter.h" @@ -231,8 +229,8 @@ private: bool mOpaque; bool mWideColorGamut = false; - BakedOpRenderer::LightInfo mLightInfo; - FrameBuilder::LightGeometry mLightGeometry = {{0, 0, 0}, 0}; + LightInfo mLightInfo; + LightGeometry mLightGeometry = {{0, 0, 0}, 0}; bool mHaveNewSurface = false; DamageAccumulator mDamageAccumulator; diff --git a/libs/hwui/renderthread/DrawFrameTask.h b/libs/hwui/renderthread/DrawFrameTask.h index d8c43e0d8ca8..0037a0f4306d 100644 --- a/libs/hwui/renderthread/DrawFrameTask.h +++ b/libs/hwui/renderthread/DrawFrameTask.h @@ -32,7 +32,6 @@ namespace android { namespace uirenderer { class DeferredLayerUpdater; -class DisplayList; class RenderNode; namespace renderthread { diff --git a/libs/hwui/renderthread/IRenderPipeline.h b/libs/hwui/renderthread/IRenderPipeline.h index b1de49733c09..b94a7588a507 100644 --- a/libs/hwui/renderthread/IRenderPipeline.h +++ b/libs/hwui/renderthread/IRenderPipeline.h @@ -17,7 +17,10 @@ #pragma once #include "FrameInfoVisualizer.h" +#include "LayerUpdateQueue.h" #include "SwapBehavior.h" +#include "hwui/Bitmap.h" +#include "thread/TaskManager.h" #include #include @@ -50,9 +53,9 @@ public: virtual MakeCurrentResult makeCurrent() = 0; virtual Frame getFrame() = 0; virtual bool draw(const Frame& frame, const SkRect& screenDirty, const SkRect& dirty, - const FrameBuilder::LightGeometry& lightGeometry, + const LightGeometry& lightGeometry, LayerUpdateQueue* layerUpdateQueue, const Rect& contentDrawBounds, - bool opaque, bool wideColorGamut, const BakedOpRenderer::LightInfo& lightInfo, + bool opaque, bool wideColorGamut, const LightInfo& lightInfo, const std::vector>& renderNodes, FrameInfoVisualizer* profiler) = 0; virtual bool swapBuffers(const Frame& frame, bool drew, const SkRect& screenDirty, @@ -64,9 +67,9 @@ public: virtual bool isSurfaceReady() = 0; virtual bool isContextReady() = 0; virtual void onDestroyHardwareResources() = 0; - virtual void renderLayers(const FrameBuilder::LightGeometry& lightGeometry, + virtual void renderLayers(const LightGeometry& lightGeometry, LayerUpdateQueue* layerUpdateQueue, bool opaque, bool wideColorGamut, - const BakedOpRenderer::LightInfo& lightInfo) = 0; + const LightInfo& lightInfo) = 0; virtual TaskManager* getTaskManager() = 0; virtual bool createOrUpdateLayer(RenderNode* node, const DamageAccumulator& damageAccumulator, bool wideColorGamut, ErrorHandler* errorHandler) = 0; diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp index 0caf59b42202..4d1e1e8fb04b 100644 --- a/libs/hwui/renderthread/RenderProxy.cpp +++ b/libs/hwui/renderthread/RenderProxy.cpp @@ -66,10 +66,7 @@ void RenderProxy::setSwapBehavior(SwapBehavior swapBehavior) { bool RenderProxy::loadSystemProperties() { return mRenderThread.queue().runSync([this]() -> bool { - bool needsRedraw = false; - if (Caches::hasInstance()) { - needsRedraw = Properties::load(); - } + bool needsRedraw = Properties::load(); if (mContext->profiler().consumeProperties()) { needsRedraw = true; } diff --git a/libs/hwui/tests/common/TestUtils.h b/libs/hwui/tests/common/TestUtils.h index ca5a88bc5904..13fb5285bc31 100644 --- a/libs/hwui/tests/common/TestUtils.h +++ b/libs/hwui/tests/common/TestUtils.h @@ -29,7 +29,6 @@ #include #include -#include #include @@ -335,16 +334,10 @@ private: } auto displayList = node->getDisplayList(); if (displayList) { - if (displayList->isSkiaDL()) { - for (auto&& childDr : static_cast( - const_cast(displayList)) - ->mChildNodes) { - syncHierarchyPropertiesAndDisplayListImpl(childDr.getRenderNode()); - } - } else { - for (auto&& childOp : displayList->getChildren()) { - syncHierarchyPropertiesAndDisplayListImpl(childOp->renderNode); - } + for (auto&& childDr : static_cast( + const_cast(displayList)) + ->mChildNodes) { + syncHierarchyPropertiesAndDisplayListImpl(childDr.getRenderNode()); } } } diff --git a/libs/hwui/tests/common/scenes/TestSceneBase.h b/libs/hwui/tests/common/scenes/TestSceneBase.h index 792312a6a7a4..6f76a502ae3e 100644 --- a/libs/hwui/tests/common/scenes/TestSceneBase.h +++ b/libs/hwui/tests/common/scenes/TestSceneBase.h @@ -16,7 +16,7 @@ #pragma once -#include "RecordingCanvas.h" +#include "hwui/Canvas.h" #include "RenderNode.h" #include "tests/common/TestContext.h" #include "tests/common/TestScene.h" diff --git a/libs/hwui/tests/microbench/DisplayListCanvasBench.cpp b/libs/hwui/tests/microbench/DisplayListCanvasBench.cpp index 0aaf7731c927..9388c2062736 100644 --- a/libs/hwui/tests/microbench/DisplayListCanvasBench.cpp +++ b/libs/hwui/tests/microbench/DisplayListCanvasBench.cpp @@ -16,8 +16,10 @@ #include +#include "CanvasState.h" #include "DisplayList.h" -#include "RecordingCanvas.h" +#include "hwui/Canvas.h" +#include "pipeline/skia/SkiaDisplayList.h" #include "tests/common/TestUtils.h" using namespace android; @@ -25,7 +27,7 @@ using namespace android::uirenderer; void BM_DisplayList_alloc(benchmark::State& benchState) { while (benchState.KeepRunning()) { - auto displayList = new DisplayList(); + auto displayList = new skiapipeline::SkiaDisplayList(); benchmark::DoNotOptimize(displayList); delete displayList; } @@ -34,7 +36,7 @@ BENCHMARK(BM_DisplayList_alloc); void BM_DisplayList_alloc_theoretical(benchmark::State& benchState) { while (benchState.KeepRunning()) { - auto displayList = new char[sizeof(DisplayList)]; + auto displayList = new char[sizeof(skiapipeline::SkiaDisplayList)]; benchmark::DoNotOptimize(displayList); delete[] displayList; } diff --git a/libs/hwui/tests/microbench/FrameBuilderBench.cpp b/libs/hwui/tests/microbench/FrameBuilderBench.cpp deleted file mode 100644 index b6217665d743..000000000000 --- a/libs/hwui/tests/microbench/FrameBuilderBench.cpp +++ /dev/null @@ -1,149 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include - -#include "BakedOpDispatcher.h" -#include "BakedOpRenderer.h" -#include "BakedOpState.h" -#include "FrameBuilder.h" -#include "LayerUpdateQueue.h" -#include "RecordedOp.h" -#include "RecordingCanvas.h" -#include "Vector.h" -#include "tests/common/TestContext.h" -#include "tests/common/TestScene.h" -#include "tests/common/TestUtils.h" - -#include - -using namespace android; -using namespace android::uirenderer; -using namespace android::uirenderer::renderthread; -using namespace android::uirenderer::test; - -const FrameBuilder::LightGeometry sLightGeometry = {{100, 100, 100}, 50}; -const BakedOpRenderer::LightInfo sLightInfo = {128, 128}; - -static sp createTestNode() { - auto node = TestUtils::createNode( - 0, 0, 200, 200, [](RenderProperties& props, RecordingCanvas& canvas) { - sk_sp bitmap(TestUtils::createBitmap(10, 10)); - SkPaint paint; - - // Alternate between drawing rects and bitmaps, with bitmaps overlapping rects. - // Rects don't overlap bitmaps, so bitmaps should be brought to front as a group. - canvas.save(SaveFlags::MatrixClip); - for (int i = 0; i < 30; i++) { - canvas.translate(0, 10); - canvas.drawRect(0, 0, 10, 10, paint); - canvas.drawBitmap(*bitmap, 5, 0, nullptr); - } - canvas.restore(); - }); - TestUtils::syncHierarchyPropertiesAndDisplayList(node); - return node; -} - -void BM_FrameBuilder_defer(benchmark::State& state) { - TestUtils::runOnRenderThread([&state](RenderThread& thread) { - auto node = createTestNode(); - while (state.KeepRunning()) { - FrameBuilder frameBuilder(SkRect::MakeWH(100, 200), 100, 200, sLightGeometry, - Caches::getInstance()); - frameBuilder.deferRenderNode(*node); - benchmark::DoNotOptimize(&frameBuilder); - } - }); -} -BENCHMARK(BM_FrameBuilder_defer); - -void BM_FrameBuilder_deferAndRender(benchmark::State& state) { - TestUtils::runOnRenderThread([&state](RenderThread& thread) { - auto node = createTestNode(); - - RenderState& renderState = thread.renderState(); - Caches& caches = Caches::getInstance(); - - while (state.KeepRunning()) { - FrameBuilder frameBuilder(SkRect::MakeWH(100, 200), 100, 200, sLightGeometry, caches); - frameBuilder.deferRenderNode(*node); - - BakedOpRenderer renderer(caches, renderState, true, false, sLightInfo); - frameBuilder.replayBakedOps(renderer); - benchmark::DoNotOptimize(&renderer); - } - }); -} -BENCHMARK(BM_FrameBuilder_deferAndRender); - -static sp getSyncedSceneNode(const char* sceneName) { - gDisplay = getBuiltInDisplay(); // switch to real display if present - - TestContext testContext; - TestScene::Options opts; - std::unique_ptr scene(TestScene::testMap()[sceneName].createScene(opts)); - - sp rootNode = TestUtils::createNode( - 0, 0, gDisplay.w, gDisplay.h, - [&scene](RenderProperties& props, RecordingCanvas& canvas) { - scene->createContent(gDisplay.w, gDisplay.h, canvas); - }); - - TestUtils::syncHierarchyPropertiesAndDisplayList(rootNode); - return rootNode; -} - -static auto SCENES = { - "listview", -}; - -void BM_FrameBuilder_defer_scene(benchmark::State& state) { - TestUtils::runOnRenderThread([&state](RenderThread& thread) { - const char* sceneName = *(SCENES.begin() + state.range(0)); - state.SetLabel(sceneName); - auto node = getSyncedSceneNode(sceneName); - while (state.KeepRunning()) { - FrameBuilder frameBuilder(SkRect::MakeWH(gDisplay.w, gDisplay.h), gDisplay.w, - gDisplay.h, sLightGeometry, Caches::getInstance()); - frameBuilder.deferRenderNode(*node); - benchmark::DoNotOptimize(&frameBuilder); - } - }); -} -BENCHMARK(BM_FrameBuilder_defer_scene)->DenseRange(0, SCENES.size() - 1); - -void BM_FrameBuilder_deferAndRender_scene(benchmark::State& state) { - TestUtils::runOnRenderThread([&state](RenderThread& thread) { - const char* sceneName = *(SCENES.begin() + state.range(0)); - state.SetLabel(sceneName); - auto node = getSyncedSceneNode(sceneName); - - RenderState& renderState = thread.renderState(); - Caches& caches = Caches::getInstance(); - - while (state.KeepRunning()) { - FrameBuilder frameBuilder(SkRect::MakeWH(gDisplay.w, gDisplay.h), gDisplay.w, - gDisplay.h, sLightGeometry, Caches::getInstance()); - frameBuilder.deferRenderNode(*node); - - BakedOpRenderer renderer(caches, renderState, true, false, sLightInfo); - frameBuilder.replayBakedOps(renderer); - benchmark::DoNotOptimize(&renderer); - } - }); -} -BENCHMARK(BM_FrameBuilder_deferAndRender_scene)->DenseRange(0, SCENES.size() - 1); diff --git a/libs/hwui/tests/unit/SkiaCanvasTests.cpp b/libs/hwui/tests/unit/SkiaCanvasTests.cpp index 2e4de0bac755..634ceffe0741 100644 --- a/libs/hwui/tests/unit/SkiaCanvasTests.cpp +++ b/libs/hwui/tests/unit/SkiaCanvasTests.cpp @@ -16,7 +16,6 @@ #include "tests/common/TestUtils.h" -#include #include #include #include diff --git a/libs/hwui/tests/unit/SkiaPipelineTests.cpp b/libs/hwui/tests/unit/SkiaPipelineTests.cpp index 42a92fcc7d89..26b6000a91e6 100644 --- a/libs/hwui/tests/unit/SkiaPipelineTests.cpp +++ b/libs/hwui/tests/unit/SkiaPipelineTests.cpp @@ -167,10 +167,10 @@ RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaPipeline, renderLayer) { ASSERT_EQ(layerUpdateQueue.entries().size(), 2UL); bool opaque = true; - FrameBuilder::LightGeometry lightGeometry; + LightGeometry lightGeometry; lightGeometry.radius = 1.0f; lightGeometry.center = {0.0f, 0.0f, 0.0f}; - BakedOpRenderer::LightInfo lightInfo; + LightInfo lightInfo; auto pipeline = std::make_unique(renderThread); pipeline->renderLayers(lightGeometry, &layerUpdateQueue, opaque, false, lightInfo); ASSERT_EQ(TestUtils::getColor(surfaceLayer1, 0, 0), SK_ColorRED); diff --git a/libs/hwui/utils/TestWindowContext.cpp b/libs/hwui/utils/TestWindowContext.cpp index 700d3b3cf000..8ac6e1f2d39a 100644 --- a/libs/hwui/utils/TestWindowContext.cpp +++ b/libs/hwui/utils/TestWindowContext.cpp @@ -17,7 +17,6 @@ #include "AnimationContext.h" #include "IContextFactory.h" -#include "RecordingCanvas.h" #include "RenderNode.h" #include "SkTypes.h" #include "gui/BufferQueue.h" @@ -25,6 +24,7 @@ #include "gui/IGraphicBufferConsumer.h" #include "gui/IGraphicBufferProducer.h" #include "gui/Surface.h" +#include "hwui/Canvas.h" #include "renderthread/RenderProxy.h" #include @@ -81,7 +81,7 @@ public: android::uirenderer::Vector3 lightVector{lightX, -200.0f, 800.0f}; mProxy->setup(800.0f, 255 * 0.075f, 255 * 0.15f); mProxy->setLightCenter(lightVector); - mCanvas.reset(new android::uirenderer::RecordingCanvas(mSize.width(), mSize.height())); + mCanvas.reset(Canvas::create_recording_canvas(mSize.width(), mSize.height(), mRootNode.get())); } SkCanvas* prepareToDraw() { @@ -155,7 +155,7 @@ public: private: std::unique_ptr mRootNode; std::unique_ptr mProxy; - std::unique_ptr mCanvas; + std::unique_ptr mCanvas; android::sp mProducer; android::sp mConsumer; android::sp mCpuConsumer; -- cgit v1.2.3-59-g8ed1b From e7f688bd01b9c4a76ed0363dfc5e502e62be6a7f Mon Sep 17 00:00:00 2001 From: Mike Reed Date: Fri, 4 May 2018 15:21:43 -0400 Subject: remove BakedOps and much of renderstate Test: make Change-Id: If070b7436b848c6840abfac5f051b0f5b6cb17ce --- libs/hwui/Android.bp | 10 - libs/hwui/BakedOpDispatcher.cpp | 367 --------------- libs/hwui/BakedOpDispatcher.h | 54 --- libs/hwui/BakedOpRenderer.cpp | 374 --------------- libs/hwui/BakedOpRenderer.h | 141 ------ libs/hwui/BakedOpState.cpp | 165 ------- libs/hwui/BakedOpState.h | 164 ------- libs/hwui/Caches.cpp | 7 +- libs/hwui/FrameInfoVisualizer.cpp | 1 - libs/hwui/GlopBuilder.cpp | 650 -------------------------- libs/hwui/GlopBuilder.h | 142 ------ libs/hwui/LayerBuilder.cpp | 378 --------------- libs/hwui/LayerBuilder.h | 137 ------ libs/hwui/ProfileRenderer.cpp | 40 -- libs/hwui/ProfileRenderer.h | 40 -- libs/hwui/RenderNode.cpp | 1 - libs/hwui/pipeline/skia/SkiaProfileRenderer.h | 2 +- libs/hwui/renderstate/Blend.cpp | 138 ------ libs/hwui/renderstate/Blend.h | 63 --- libs/hwui/renderstate/MeshState.cpp | 179 ------- libs/hwui/renderstate/MeshState.h | 133 ------ libs/hwui/renderstate/OffscreenBufferPool.cpp | 38 +- libs/hwui/renderstate/RenderState.cpp | 142 +----- libs/hwui/renderstate/RenderState.h | 14 - libs/hwui/renderstate/Scissor.cpp | 103 ---- libs/hwui/renderstate/Scissor.h | 51 -- libs/hwui/renderstate/Stencil.cpp | 140 ------ libs/hwui/renderstate/Stencil.h | 103 ---- libs/hwui/renderthread/CanvasContext.cpp | 1 - 29 files changed, 6 insertions(+), 3772 deletions(-) delete mode 100644 libs/hwui/BakedOpDispatcher.cpp delete mode 100644 libs/hwui/BakedOpDispatcher.h delete mode 100644 libs/hwui/BakedOpRenderer.cpp delete mode 100644 libs/hwui/BakedOpRenderer.h delete mode 100644 libs/hwui/BakedOpState.cpp delete mode 100644 libs/hwui/BakedOpState.h delete mode 100644 libs/hwui/GlopBuilder.cpp delete mode 100644 libs/hwui/GlopBuilder.h delete mode 100644 libs/hwui/LayerBuilder.cpp delete mode 100644 libs/hwui/LayerBuilder.h delete mode 100644 libs/hwui/ProfileRenderer.cpp delete mode 100644 libs/hwui/ProfileRenderer.h delete mode 100644 libs/hwui/renderstate/Blend.cpp delete mode 100644 libs/hwui/renderstate/Blend.h delete mode 100644 libs/hwui/renderstate/MeshState.cpp delete mode 100644 libs/hwui/renderstate/MeshState.h delete mode 100644 libs/hwui/renderstate/Scissor.cpp delete mode 100644 libs/hwui/renderstate/Scissor.h delete mode 100644 libs/hwui/renderstate/Stencil.cpp delete mode 100644 libs/hwui/renderstate/Stencil.h (limited to 'libs/hwui/RenderNode.cpp') diff --git a/libs/hwui/Android.bp b/libs/hwui/Android.bp index 6de3a384945e..f3cd3de2c9b6 100644 --- a/libs/hwui/Android.bp +++ b/libs/hwui/Android.bp @@ -170,13 +170,9 @@ cc_defaults { "pipeline/skia/SkiaRecordingCanvas.cpp", "pipeline/skia/SkiaVulkanPipeline.cpp", "pipeline/skia/VectorDrawableAtlas.cpp", - "renderstate/Blend.cpp", - "renderstate/MeshState.cpp", "renderstate/OffscreenBufferPool.cpp", "renderstate/PixelBufferState.cpp", "renderstate/RenderState.cpp", - "renderstate/Scissor.cpp", - "renderstate/Stencil.cpp", "renderstate/TextureState.cpp", "renderthread/CacheManager.cpp", "renderthread/CanvasContext.cpp", @@ -200,9 +196,6 @@ cc_defaults { "AnimationContext.cpp", "Animator.cpp", "AnimatorManager.cpp", - "BakedOpDispatcher.cpp", - "BakedOpRenderer.cpp", - "BakedOpState.cpp", "Caches.cpp", "CanvasState.cpp", "ClipArea.cpp", @@ -212,13 +205,11 @@ cc_defaults { "FrameInfo.cpp", "FrameInfoVisualizer.cpp", "GlLayer.cpp", - "GlopBuilder.cpp", "GpuMemoryTracker.cpp", "Image.cpp", "Interpolator.cpp", "JankTracker.cpp", "Layer.cpp", - "LayerBuilder.cpp", "LayerUpdateQueue.cpp", "Matrix.cpp", "OpDumper.cpp", @@ -229,7 +220,6 @@ cc_defaults { "PixelBuffer.cpp", "ProfileData.cpp", "ProfileDataContainer.cpp", - "ProfileRenderer.cpp", "Program.cpp", "Properties.cpp", "PropertyValuesAnimatorSet.cpp", diff --git a/libs/hwui/BakedOpDispatcher.cpp b/libs/hwui/BakedOpDispatcher.cpp deleted file mode 100644 index 1f931ed08c0d..000000000000 --- a/libs/hwui/BakedOpDispatcher.cpp +++ /dev/null @@ -1,367 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "BakedOpDispatcher.h" - -#include "BakedOpRenderer.h" -#include "Caches.h" -#include "DeferredLayerUpdater.h" -#include "Glop.h" -#include "GlopBuilder.h" -#include "Patch.h" -#include "PathTessellator.h" -#include "VertexBuffer.h" -#include "renderstate/OffscreenBufferPool.h" -#include "renderstate/RenderState.h" -#include "utils/GLUtils.h" - -#include -#include -#include -#include - -namespace android { -namespace uirenderer { - -void BakedOpDispatcher::onMergedBitmapOps(BakedOpRenderer& renderer, - const MergedBakedOpList& opList) { - // DEAD CODE -} - -void BakedOpDispatcher::onMergedPatchOps(BakedOpRenderer& renderer, - const MergedBakedOpList& opList) { - // DEAD CODE -} - -static void renderTextShadow(BakedOpRenderer& renderer, const TextOp& op, - const BakedOpState& textOpState) { - // DEAD CODE -} - -enum class TextRenderType { Defer, Flush }; - -static void renderText(BakedOpRenderer& renderer, const TextOp& op, const BakedOpState& state, - const ClipBase* renderClip, TextRenderType renderType) { - // DEAD CODE -} - -void BakedOpDispatcher::onMergedTextOps(BakedOpRenderer& renderer, - const MergedBakedOpList& opList) { - for (size_t i = 0; i < opList.count; i++) { - const BakedOpState& state = *(opList.states[i]); - const TextOp& op = *(static_cast(state.op)); - renderTextShadow(renderer, op, state); - } - - ClipRect renderTargetClip(opList.clip); - const ClipBase* clip = opList.clipSideFlags ? &renderTargetClip : nullptr; - for (size_t i = 0; i < opList.count; i++) { - const BakedOpState& state = *(opList.states[i]); - const TextOp& op = *(static_cast(state.op)); - TextRenderType renderType = - (i + 1 == opList.count) ? TextRenderType::Flush : TextRenderType::Defer; - renderText(renderer, op, state, clip, renderType); - } -} - -namespace VertexBufferRenderFlags { -enum { - Offset = 0x1, - ShadowInterp = 0x2, -}; -} - -static void renderVertexBuffer(BakedOpRenderer& renderer, const BakedOpState& state, - const VertexBuffer& vertexBuffer, float translateX, float translateY, - const SkPaint& paint, int vertexBufferRenderFlags) { - if (CC_LIKELY(vertexBuffer.getVertexCount())) { - bool shadowInterp = vertexBufferRenderFlags & VertexBufferRenderFlags::ShadowInterp; - const int transformFlags = vertexBufferRenderFlags & VertexBufferRenderFlags::Offset - ? TransformFlags::OffsetByFudgeFactor - : 0; - - Glop glop; - GlopBuilder(renderer.renderState(), renderer.caches(), &glop) - .setRoundRectClipState(state.roundRectClipState) - .setMeshVertexBuffer(vertexBuffer) - .setFillPaint(paint, state.alpha, shadowInterp) - .setTransform(state.computedState.transform, transformFlags) - .setModelViewOffsetRect(translateX, translateY, vertexBuffer.getBounds()) - .build(); - renderer.renderGlop(state, glop); - } -} - -SkRect getBoundsOfFill(const RecordedOp& op) { - SkRect bounds = op.unmappedBounds.toSkRect(); - if (op.paint->getStyle() == SkPaint::kStrokeAndFill_Style) { - float outsetDistance = op.paint->getStrokeWidth() / 2; - bounds.outset(outsetDistance, outsetDistance); - } - return bounds; -} - -void BakedOpDispatcher::onArcOp(BakedOpRenderer& renderer, const ArcOp& op, - const BakedOpState& state) { - // DEAD CODE -} - -void BakedOpDispatcher::onBitmapOp(BakedOpRenderer& renderer, const BitmapOp& op, - const BakedOpState& state) { - Texture* texture = renderer.getTexture(op.bitmap); - if (!texture) return; - const AutoTexture autoCleanup(texture); - - const int textureFillFlags = (op.bitmap->colorType() == kAlpha_8_SkColorType) - ? TextureFillFlags::IsAlphaMaskTexture - : TextureFillFlags::None; - Glop glop; - GlopBuilder(renderer.renderState(), renderer.caches(), &glop) - .setRoundRectClipState(state.roundRectClipState) - .setMeshTexturedUnitQuad(texture->uvMapper) - .setFillTexturePaint(*texture, textureFillFlags, op.paint, state.alpha) - .setTransform(state.computedState.transform, TransformFlags::None) - .setModelViewMapUnitToRectSnap(Rect(texture->width(), texture->height())) - .build(); - renderer.renderGlop(state, glop); -} - -void BakedOpDispatcher::onBitmapMeshOp(BakedOpRenderer& renderer, const BitmapMeshOp& op, - const BakedOpState& state) { - // DEAD CODE -} - -void BakedOpDispatcher::onBitmapRectOp(BakedOpRenderer& renderer, const BitmapRectOp& op, - const BakedOpState& state) { - Texture* texture = renderer.getTexture(op.bitmap); - if (!texture) return; - const AutoTexture autoCleanup(texture); - - Rect uv(std::max(0.0f, op.src.left / texture->width()), - std::max(0.0f, op.src.top / texture->height()), - std::min(1.0f, op.src.right / texture->width()), - std::min(1.0f, op.src.bottom / texture->height())); - - const int textureFillFlags = (op.bitmap->colorType() == kAlpha_8_SkColorType) - ? TextureFillFlags::IsAlphaMaskTexture - : TextureFillFlags::None; - const bool tryToSnap = MathUtils::areEqual(op.src.getWidth(), op.unmappedBounds.getWidth()) && - MathUtils::areEqual(op.src.getHeight(), op.unmappedBounds.getHeight()); - Glop glop; - GlopBuilder(renderer.renderState(), renderer.caches(), &glop) - .setRoundRectClipState(state.roundRectClipState) - .setMeshTexturedUvQuad(texture->uvMapper, uv) - .setFillTexturePaint(*texture, textureFillFlags, op.paint, state.alpha) - .setTransform(state.computedState.transform, TransformFlags::None) - .setModelViewMapUnitToRectOptionalSnap(tryToSnap, op.unmappedBounds) - .build(); - renderer.renderGlop(state, glop); -} - -void BakedOpDispatcher::onColorOp(BakedOpRenderer& renderer, const ColorOp& op, - const BakedOpState& state) { - SkPaint paint; - paint.setColor(op.color); - paint.setBlendMode(op.mode); - - Glop glop; - GlopBuilder(renderer.renderState(), renderer.caches(), &glop) - .setRoundRectClipState(state.roundRectClipState) - .setMeshUnitQuad() - .setFillPaint(paint, state.alpha) - .setTransform(Matrix4::identity(), TransformFlags::None) - .setModelViewMapUnitToRect(state.computedState.clipState->rect) - .build(); - renderer.renderGlop(state, glop); -} - -void BakedOpDispatcher::onFunctorOp(BakedOpRenderer& renderer, const FunctorOp& op, - const BakedOpState& state) { - renderer.renderFunctor(op, state); -} - -void BakedOpDispatcher::onLinesOp(BakedOpRenderer& renderer, const LinesOp& op, - const BakedOpState& state) { - VertexBuffer buffer; - PathTessellator::tessellateLines(op.points, op.floatCount, op.paint, - state.computedState.transform, buffer); - int displayFlags = op.paint->isAntiAlias() ? 0 : VertexBufferRenderFlags::Offset; - renderVertexBuffer(renderer, state, buffer, 0, 0, *(op.paint), displayFlags); -} - -void BakedOpDispatcher::onOvalOp(BakedOpRenderer& renderer, const OvalOp& op, - const BakedOpState& state) { - // DEAD CODE -} - -void BakedOpDispatcher::onPatchOp(BakedOpRenderer& renderer, const PatchOp& op, - const BakedOpState& state) { - // DEAD CODE -} - -void BakedOpDispatcher::onPathOp(BakedOpRenderer& renderer, const PathOp& op, - const BakedOpState& state) { - // DEAD CODE -} - -void BakedOpDispatcher::onPointsOp(BakedOpRenderer& renderer, const PointsOp& op, - const BakedOpState& state) { - VertexBuffer buffer; - PathTessellator::tessellatePoints(op.points, op.floatCount, op.paint, - state.computedState.transform, buffer); - int displayFlags = op.paint->isAntiAlias() ? 0 : VertexBufferRenderFlags::Offset; - renderVertexBuffer(renderer, state, buffer, 0, 0, *(op.paint), displayFlags); -} - -// See SkPaintDefaults.h -#define SkPaintDefaults_MiterLimit SkIntToScalar(4) - -void BakedOpDispatcher::onRectOp(BakedOpRenderer& renderer, const RectOp& op, - const BakedOpState& state) { - // DEAD CODE -} - -void BakedOpDispatcher::onRoundRectOp(BakedOpRenderer& renderer, const RoundRectOp& op, - const BakedOpState& state) { - // DEAD CODE -} - -void BakedOpDispatcher::onSimpleRectsOp(BakedOpRenderer& renderer, const SimpleRectsOp& op, - const BakedOpState& state) { - Glop glop; - GlopBuilder(renderer.renderState(), renderer.caches(), &glop) - .setRoundRectClipState(state.roundRectClipState) - .setMeshIndexedQuads(&op.vertices[0], op.vertexCount / 4) - .setFillPaint(*op.paint, state.alpha) - .setTransform(state.computedState.transform, TransformFlags::None) - .setModelViewOffsetRect(0, 0, op.unmappedBounds) - .build(); - renderer.renderGlop(state, glop); -} - -void BakedOpDispatcher::onTextOp(BakedOpRenderer& renderer, const TextOp& op, - const BakedOpState& state) { - renderTextShadow(renderer, op, state); - renderText(renderer, op, state, state.computedState.getClipIfNeeded(), TextRenderType::Flush); -} - -void BakedOpDispatcher::onTextOnPathOp(BakedOpRenderer& renderer, const TextOnPathOp& op, - const BakedOpState& state) { - // DEAD CODE -} - -void BakedOpDispatcher::onTextureLayerOp(BakedOpRenderer& renderer, const TextureLayerOp& op, - const BakedOpState& state) { - GlLayer* layer = static_cast(op.layerHandle->backingLayer()); - if (!layer) { - return; - } - const bool tryToSnap = layer->getForceFilter(); - float alpha = (layer->getAlpha() / 255.0f) * state.alpha; - Glop glop; - GlopBuilder(renderer.renderState(), renderer.caches(), &glop) - .setRoundRectClipState(state.roundRectClipState) - .setMeshTexturedUvQuad(nullptr, Rect(0, 1, 1, 0)) // TODO: simplify with VBO - .setFillTextureLayer(*(layer), alpha) - .setTransform(state.computedState.transform, TransformFlags::None) - .setModelViewMapUnitToRectOptionalSnap(tryToSnap, - Rect(layer->getWidth(), layer->getHeight())) - .build(); - renderer.renderGlop(state, glop); -} - -void renderRectForLayer(BakedOpRenderer& renderer, const LayerOp& op, const BakedOpState& state, - int color, SkBlendMode mode, SkColorFilter* colorFilter) { - SkPaint paint; - paint.setColor(color); - paint.setBlendMode(mode); - paint.setColorFilter(sk_ref_sp(colorFilter)); - RectOp rectOp(op.unmappedBounds, op.localMatrix, op.localClip, &paint); - BakedOpDispatcher::onRectOp(renderer, rectOp, state); -} - -void BakedOpDispatcher::onLayerOp(BakedOpRenderer& renderer, const LayerOp& op, - const BakedOpState& state) { - // Note that we don't use op->paint in this function - it's never set on a LayerOp - OffscreenBuffer* buffer = *op.layerHandle; - - if (CC_UNLIKELY(!buffer)) return; - - float layerAlpha = op.alpha * state.alpha; - Glop glop; - GlopBuilder(renderer.renderState(), renderer.caches(), &glop) - .setRoundRectClipState(state.roundRectClipState) - .setMeshTexturedIndexedVbo(buffer->vbo, buffer->elementCount) - .setFillLayer(buffer->texture, op.colorFilter, layerAlpha, op.mode, - Blend::ModeOrderSwap::NoSwap) - .setTransform(state.computedState.transform, TransformFlags::None) - .setModelViewOffsetRectSnap( - op.unmappedBounds.left, op.unmappedBounds.top, - Rect(op.unmappedBounds.getWidth(), op.unmappedBounds.getHeight())) - .build(); - renderer.renderGlop(state, glop); - - if (!buffer->hasRenderedSinceRepaint) { - buffer->hasRenderedSinceRepaint = true; - if (CC_UNLIKELY(Properties::debugLayersUpdates)) { - // render debug layer highlight - renderRectForLayer(renderer, op, state, 0x7f00ff00, SkBlendMode::kSrcOver, nullptr); - } else if (CC_UNLIKELY(Properties::debugOverdraw)) { - // render transparent to increment overdraw for repaint area - renderRectForLayer(renderer, op, state, SK_ColorTRANSPARENT, SkBlendMode::kSrcOver, - nullptr); - } - } -} - -void BakedOpDispatcher::onCopyToLayerOp(BakedOpRenderer& renderer, const CopyToLayerOp& op, - const BakedOpState& state) { - LOG_ALWAYS_FATAL_IF(*(op.layerHandle) != nullptr, "layer already exists!"); - *(op.layerHandle) = renderer.copyToLayer(state.computedState.clippedBounds); - LOG_ALWAYS_FATAL_IF(*op.layerHandle == nullptr, "layer copy failed"); -} - -void BakedOpDispatcher::onCopyFromLayerOp(BakedOpRenderer& renderer, const CopyFromLayerOp& op, - const BakedOpState& state) { - LOG_ALWAYS_FATAL_IF(*op.layerHandle == nullptr, "no layer to draw underneath!"); - if (!state.computedState.clippedBounds.isEmpty()) { - if (op.paint && op.paint->getAlpha() < 255) { - SkPaint layerPaint; - layerPaint.setAlpha(op.paint->getAlpha()); - layerPaint.setBlendMode(SkBlendMode::kDstIn); - layerPaint.setColorFilter(sk_ref_sp(op.paint->getColorFilter())); - RectOp rectOp(state.computedState.clippedBounds, Matrix4::identity(), nullptr, - &layerPaint); - BakedOpDispatcher::onRectOp(renderer, rectOp, state); - } - - OffscreenBuffer& layer = **(op.layerHandle); - auto mode = PaintUtils::getBlendModeDirect(op.paint); - Glop glop; - GlopBuilder(renderer.renderState(), renderer.caches(), &glop) - .setRoundRectClipState(state.roundRectClipState) - .setMeshTexturedUvQuad(nullptr, layer.getTextureCoordinates()) - .setFillLayer(layer.texture, nullptr, 1.0f, mode, Blend::ModeOrderSwap::Swap) - .setTransform(state.computedState.transform, TransformFlags::None) - .setModelViewMapUnitToRect(state.computedState.clippedBounds) - .build(); - renderer.renderGlop(state, glop); - } - renderer.renderState().layerPool().putOrDelete(*op.layerHandle); -} - -} // namespace uirenderer -} // namespace android diff --git a/libs/hwui/BakedOpDispatcher.h b/libs/hwui/BakedOpDispatcher.h deleted file mode 100644 index cc3287075ef8..000000000000 --- a/libs/hwui/BakedOpDispatcher.h +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef ANDROID_HWUI_BAKED_OP_DISPATCHER_H -#define ANDROID_HWUI_BAKED_OP_DISPATCHER_H - -#include "BakedOpState.h" -#include "RecordedOp.h" - -namespace android { -namespace uirenderer { - -class BakedOpRenderer; - -/** - * Provides all "onBitmapOp(...)" style static methods for every op type, which convert the - * RecordedOps and their state to Glops, and renders them with the provided BakedOpRenderer. - * - * onXXXOp methods must either render directly with the renderer, or call a static renderYYY - * method to render content. There should never be draw content rejection in BakedOpDispatcher - - * it must happen at a higher level (except in error-ish cases, like texture-too-big). - */ -class BakedOpDispatcher { -public: -// Declares all "onMergedBitmapOps(...)" style methods for mergeable op types -#define X(Type) \ - static void onMerged##Type##s(BakedOpRenderer& renderer, const MergedBakedOpList& opList); - MAP_MERGEABLE_OPS(X) -#undef X - -// Declares all "onBitmapOp(...)" style methods for every op type -#define X(Type) \ - static void on##Type(BakedOpRenderer& renderer, const Type& op, const BakedOpState& state); - MAP_RENDERABLE_OPS(X) -#undef X -}; - -}; // namespace uirenderer -}; // namespace android - -#endif // ANDROID_HWUI_BAKED_OP_DISPATCHER_H diff --git a/libs/hwui/BakedOpRenderer.cpp b/libs/hwui/BakedOpRenderer.cpp deleted file mode 100644 index 0a3e3e470053..000000000000 --- a/libs/hwui/BakedOpRenderer.cpp +++ /dev/null @@ -1,374 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "BakedOpRenderer.h" - -#include "Caches.h" -#include "Glop.h" -#include "GlopBuilder.h" -#include "VertexBuffer.h" -#include "renderstate/OffscreenBufferPool.h" -#include "renderstate/RenderState.h" -#include "utils/GLUtils.h" - -#include - -namespace android { -namespace uirenderer { - -OffscreenBuffer* BakedOpRenderer::startTemporaryLayer(uint32_t width, uint32_t height) { - LOG_ALWAYS_FATAL_IF(mRenderTarget.offscreenBuffer, "already has layer..."); - - OffscreenBuffer* buffer = - mRenderState.layerPool().get(mRenderState, width, height, mWideColorGamut); - startRepaintLayer(buffer, Rect(width, height)); - return buffer; -} - -void BakedOpRenderer::recycleTemporaryLayer(OffscreenBuffer* offscreenBuffer) { - mRenderState.layerPool().putOrDelete(offscreenBuffer); -} - -void BakedOpRenderer::startRepaintLayer(OffscreenBuffer* offscreenBuffer, const Rect& repaintRect) { - LOG_ALWAYS_FATAL_IF(mRenderTarget.offscreenBuffer, "already has layer..."); - - // subtract repaintRect from region, since it will be regenerated - if (repaintRect.contains(0, 0, offscreenBuffer->viewportWidth, - offscreenBuffer->viewportHeight)) { - // repaint full layer, so throw away entire region - offscreenBuffer->region.clear(); - } else { - offscreenBuffer->region.subtractSelf(android::Rect(repaintRect.left, repaintRect.top, - repaintRect.right, repaintRect.bottom)); - } - - mRenderTarget.offscreenBuffer = offscreenBuffer; - mRenderTarget.offscreenBuffer->hasRenderedSinceRepaint = false; - - // create and bind framebuffer - mRenderTarget.frameBufferId = mRenderState.createFramebuffer(); - mRenderState.bindFramebuffer(mRenderTarget.frameBufferId); - - // attach the texture to the FBO - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, - offscreenBuffer->texture.id(), 0); - GL_CHECKPOINT(LOW); - - int status = glCheckFramebufferStatus(GL_FRAMEBUFFER); - LOG_ALWAYS_FATAL_IF(status != GL_FRAMEBUFFER_COMPLETE, - "framebuffer incomplete, status %d, textureId %d, size %dx%d", status, - offscreenBuffer->texture.id(), offscreenBuffer->texture.width(), - offscreenBuffer->texture.height()); - - // Change the viewport & ortho projection - setViewport(offscreenBuffer->viewportWidth, offscreenBuffer->viewportHeight); - - clearColorBuffer(repaintRect); -} - -void BakedOpRenderer::endLayer() { - if (mRenderTarget.stencil) { - // if stencil was used for clipping, detach it and return it to pool - glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, 0); - GL_CHECKPOINT(MODERATE); - mRenderTarget.stencil = nullptr; - } - mRenderTarget.lastStencilClip = nullptr; - - mRenderTarget.offscreenBuffer->updateMeshFromRegion(); - mRenderTarget.offscreenBuffer = nullptr; // It's in drawLayerOp's hands now. - - // Detach the texture from the FBO - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0); - GL_CHECKPOINT(LOW); - mRenderState.deleteFramebuffer(mRenderTarget.frameBufferId); - mRenderTarget.frameBufferId = 0; -} - -OffscreenBuffer* BakedOpRenderer::copyToLayer(const Rect& area) { - const uint32_t width = area.getWidth(); - const uint32_t height = area.getHeight(); - OffscreenBuffer* buffer = - mRenderState.layerPool().get(mRenderState, width, height, mWideColorGamut); - if (!area.isEmpty() && width != 0 && height != 0) { - mCaches.textureState().activateTexture(0); - mCaches.textureState().bindTexture(buffer->texture.id()); - - glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, area.left, - mRenderTarget.viewportHeight - area.bottom, width, height); - } - return buffer; -} - -void BakedOpRenderer::startFrame(uint32_t width, uint32_t height, const Rect& repaintRect) { - LOG_ALWAYS_FATAL_IF(mRenderTarget.frameBufferId != 0, "primary framebufferId must be 0"); - mRenderState.bindFramebuffer(0); - setViewport(width, height); - - if (!mOpaque) { - clearColorBuffer(repaintRect); - } - - mRenderState.debugOverdraw(true, true); -} - -void BakedOpRenderer::endFrame(const Rect& repaintRect) { - if (CC_UNLIKELY(Properties::debugOverdraw)) { - ClipRect overdrawClip(repaintRect); - Rect viewportRect(mRenderTarget.viewportWidth, mRenderTarget.viewportHeight); - // overdraw visualization - for (int i = 1; i <= 4; i++) { - if (i < 4) { - // nth level of overdraw tests for n+1 draws per pixel - mRenderState.stencil().enableDebugTest(i + 1, false); - } else { - // 4th level tests for 4 or higher draws per pixel - mRenderState.stencil().enableDebugTest(4, true); - } - - SkPaint paint; - paint.setColor(mCaches.getOverdrawColor(i)); - Glop glop; - GlopBuilder(mRenderState, mCaches, &glop) - .setRoundRectClipState(nullptr) - .setMeshUnitQuad() - .setFillPaint(paint, 1.0f) - .setTransform(Matrix4::identity(), TransformFlags::None) - .setModelViewMapUnitToRect(viewportRect) - .build(); - renderGlop(nullptr, &overdrawClip, glop); - } - mRenderState.stencil().disable(); - } - - // Note: we leave FBO 0 renderable here, for post-frame-content decoration -} - -void BakedOpRenderer::setViewport(uint32_t width, uint32_t height) { - mRenderTarget.viewportWidth = width; - mRenderTarget.viewportHeight = height; - mRenderTarget.orthoMatrix.loadOrtho(width, height); - - mRenderState.setViewport(width, height); - mRenderState.blend().syncEnabled(); -} - -void BakedOpRenderer::clearColorBuffer(const Rect& rect) { - if (rect.contains(Rect(mRenderTarget.viewportWidth, mRenderTarget.viewportHeight))) { - // Full viewport is being cleared - disable scissor - mRenderState.scissor().setEnabled(false); - } else { - // Requested rect is subset of viewport - scissor to it to avoid over-clearing - mRenderState.scissor().setEnabled(true); - mRenderState.scissor().set(rect.left, mRenderTarget.viewportHeight - rect.bottom, - rect.getWidth(), rect.getHeight()); - } - glClear(GL_COLOR_BUFFER_BIT); - if (!mRenderTarget.frameBufferId) mHasDrawn = true; -} - -Texture* BakedOpRenderer::getTexture(Bitmap* bitmap) { - return nullptr; -} - -void BakedOpRenderer::drawRects(const float* rects, int count, const SkPaint* paint) { - std::vector vertices; - vertices.reserve(count); - Vertex* vertex = vertices.data(); - - for (int index = 0; index < count; index += 4) { - float l = rects[index + 0]; - float t = rects[index + 1]; - float r = rects[index + 2]; - float b = rects[index + 3]; - - Vertex::set(vertex++, l, t); - Vertex::set(vertex++, r, t); - Vertex::set(vertex++, l, b); - Vertex::set(vertex++, r, b); - } - - LOG_ALWAYS_FATAL_IF(mRenderTarget.frameBufferId != 0, "decoration only supported for FBO 0"); - // TODO: Currently assume full FBO damage, due to FrameInfoVisualizer::unionDirty. - // Should should scissor/set mHasDrawn safely. - mRenderState.scissor().setEnabled(false); - Glop glop; - GlopBuilder(mRenderState, mCaches, &glop) - .setRoundRectClipState(nullptr) - .setMeshIndexedQuads(vertices.data(), count / 4) - .setFillPaint(*paint, 1.0f) - .setTransform(Matrix4::identity(), TransformFlags::None) - .setModelViewIdentityEmptyBounds() - .build(); - mRenderState.render(glop, mRenderTarget.orthoMatrix, false); - mHasDrawn = true; -} - -// clears and re-fills stencil with provided rendertarget space quads, -// and then put stencil into test mode -void BakedOpRenderer::setupStencilQuads(std::vector& quadVertices, int incrementThreshold) { - mRenderState.stencil().enableWrite(incrementThreshold); - mRenderState.stencil().clear(); - Glop glop; - GlopBuilder(mRenderState, mCaches, &glop) - .setRoundRectClipState(nullptr) - .setMeshIndexedQuads(quadVertices.data(), quadVertices.size() / 4) - .setFillBlack() - .setTransform(Matrix4::identity(), TransformFlags::None) - .setModelViewIdentityEmptyBounds() - .build(); - mRenderState.render(glop, mRenderTarget.orthoMatrix, false); - mRenderState.stencil().enableTest(incrementThreshold); -} - -void BakedOpRenderer::setupStencilRectList(const ClipBase* clip) { - LOG_ALWAYS_FATAL_IF(clip->mode != ClipMode::RectangleList, - "can't rectlist clip without rectlist"); - auto&& rectList = reinterpret_cast(clip)->rectList; - int quadCount = rectList.getTransformedRectanglesCount(); - std::vector rectangleVertices; - rectangleVertices.reserve(quadCount * 4); - for (int i = 0; i < quadCount; i++) { - const TransformedRectangle& tr(rectList.getTransformedRectangle(i)); - const Matrix4& transform = tr.getTransform(); - Rect bounds = tr.getBounds(); - if (transform.rectToRect()) { - // If rectToRect, can simply map bounds before storing verts - transform.mapRect(bounds); - bounds.doIntersect(clip->rect); - if (bounds.isEmpty()) { - continue; // will be outside of scissor, skip - } - } - - rectangleVertices.push_back(Vertex{bounds.left, bounds.top}); - rectangleVertices.push_back(Vertex{bounds.right, bounds.top}); - rectangleVertices.push_back(Vertex{bounds.left, bounds.bottom}); - rectangleVertices.push_back(Vertex{bounds.right, bounds.bottom}); - - if (!transform.rectToRect()) { - // If not rectToRect, must map each point individually - for (auto cur = rectangleVertices.end() - 4; cur < rectangleVertices.end(); cur++) { - transform.mapPoint(cur->x, cur->y); - } - } - } - setupStencilQuads(rectangleVertices, rectList.getTransformedRectanglesCount()); -} - -void BakedOpRenderer::setupStencilRegion(const ClipBase* clip) { - LOG_ALWAYS_FATAL_IF(clip->mode != ClipMode::Region, "can't region clip without region"); - auto&& region = reinterpret_cast(clip)->region; - - std::vector regionVertices; - SkRegion::Cliperator it(region, clip->rect.toSkIRect()); - while (!it.done()) { - const SkIRect& r = it.rect(); - regionVertices.push_back(Vertex{(float)r.fLeft, (float)r.fTop}); - regionVertices.push_back(Vertex{(float)r.fRight, (float)r.fTop}); - regionVertices.push_back(Vertex{(float)r.fLeft, (float)r.fBottom}); - regionVertices.push_back(Vertex{(float)r.fRight, (float)r.fBottom}); - it.next(); - } - setupStencilQuads(regionVertices, 0); -} - -void BakedOpRenderer::prepareRender(const Rect* dirtyBounds, const ClipBase* clip) { - // Prepare scissor (done before stencil, to simplify filling stencil) - mRenderState.scissor().setEnabled(clip != nullptr); - if (clip) { - mRenderState.scissor().set(mRenderTarget.viewportHeight, clip->rect); - } - - // If stencil may be used for clipping, enable it, fill it, or disable it as appropriate - if (CC_LIKELY(!Properties::debugOverdraw)) { - // only modify stencil mode and content when it's not used for overdraw visualization - if (CC_UNLIKELY(clip && clip->mode != ClipMode::Rectangle)) { - // NOTE: this pointer check is only safe for non-rect clips, - // since rect clips may be created on the stack - if (mRenderTarget.lastStencilClip != clip) { - // Stencil needed, but current stencil isn't up to date - mRenderTarget.lastStencilClip = clip; - - // DEAD CODE - - if (clip->mode == ClipMode::RectangleList) { - setupStencilRectList(clip); - } else { - setupStencilRegion(clip); - } - } else { - // stencil is up to date - just need to ensure it's enabled (since an unclipped - // or scissor-only clipped op may have been drawn, disabling the stencil) - int incrementThreshold = 0; - if (CC_LIKELY(clip->mode == ClipMode::RectangleList)) { - auto&& rectList = reinterpret_cast(clip)->rectList; - incrementThreshold = rectList.getTransformedRectanglesCount(); - } - mRenderState.stencil().enableTest(incrementThreshold); - } - } else { - // either scissor or no clip, so disable stencil test - mRenderState.stencil().disable(); - } - } - - if (dirtyBounds) { - // dirty offscreenbuffer if present - dirtyRenderTarget(*dirtyBounds); - } -} - -void BakedOpRenderer::renderGlopImpl(const Rect* dirtyBounds, const ClipBase* clip, - const Glop& glop) { - prepareRender(dirtyBounds, clip); - // Disable blending if this is the first draw to the main framebuffer, in case app has defined - // transparency where it doesn't make sense - as first draw in opaque window. Note that we only - // apply this improvement when the blend mode is SRC_OVER - other modes (e.g. CLEAR) can be - // valid draws that affect other content (e.g. draw CLEAR, then draw DST_OVER) - bool overrideDisableBlending = !mHasDrawn && mOpaque && !mRenderTarget.frameBufferId && - glop.blend.src == GL_ONE && - glop.blend.dst == GL_ONE_MINUS_SRC_ALPHA; - mRenderState.render(glop, mRenderTarget.orthoMatrix, overrideDisableBlending); - if (!mRenderTarget.frameBufferId) mHasDrawn = true; -} - -void BakedOpRenderer::renderFunctor(const FunctorOp& op, const BakedOpState& state) { - prepareRender(&state.computedState.clippedBounds, state.computedState.getClipIfNeeded()); - - DrawGlInfo info; - auto&& clip = state.computedState.clipRect(); - info.clipLeft = clip.left; - info.clipTop = clip.top; - info.clipRight = clip.right; - info.clipBottom = clip.bottom; - info.isLayer = offscreenRenderTarget(); - info.width = mRenderTarget.viewportWidth; - info.height = mRenderTarget.viewportHeight; - state.computedState.transform.copyTo(&info.transform[0]); - - mRenderState.invokeFunctor(op.functor, DrawGlInfo::kModeDraw, &info); - if (!mRenderTarget.frameBufferId) mHasDrawn = true; -} - -void BakedOpRenderer::dirtyRenderTarget(const Rect& uiDirty) { - if (mRenderTarget.offscreenBuffer) { - mRenderTarget.offscreenBuffer->dirty(uiDirty); - } -} - -} // namespace uirenderer -} // namespace android diff --git a/libs/hwui/BakedOpRenderer.h b/libs/hwui/BakedOpRenderer.h deleted file mode 100644 index 72c93650a83b..000000000000 --- a/libs/hwui/BakedOpRenderer.h +++ /dev/null @@ -1,141 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include "BakedOpState.h" -#include "Lighting.h" -#include "Matrix.h" -#include "utils/Macros.h" - -namespace android { -namespace uirenderer { - -class Caches; -struct Glop; -class Layer; -struct RenderBuffer; -class RenderState; -struct ClipBase; - -/** - * Main rendering manager for a collection of work - one frame + any contained FBOs. - * - * Manages frame and FBO lifecycle, binding the GL framebuffer as appropriate. This is the only - * place where FBOs are bound, created, and destroyed. - * - * All rendering operations will be sent by the Dispatcher, a collection of static methods, - * which has intentionally limited access to the renderer functionality. - */ -class BakedOpRenderer { -public: - typedef void (*GlopReceiver)(BakedOpRenderer&, const Rect*, const ClipBase*, const Glop&); - - BakedOpRenderer(Caches& caches, RenderState& renderState, bool opaque, bool wideColorGamut, - const LightInfo& lightInfo) - : mGlopReceiver(DefaultGlopReceiver) - , mRenderState(renderState) - , mCaches(caches) - , mOpaque(opaque) - , mWideColorGamut(wideColorGamut) - , mLightInfo(lightInfo) {} - - RenderState& renderState() { return mRenderState; } - Caches& caches() { return mCaches; } - - void startFrame(uint32_t width, uint32_t height, const Rect& repaintRect); - void endFrame(const Rect& repaintRect); - WARN_UNUSED_RESULT OffscreenBuffer* startTemporaryLayer(uint32_t width, uint32_t height); - void recycleTemporaryLayer(OffscreenBuffer* offscreenBuffer); - void startRepaintLayer(OffscreenBuffer* offscreenBuffer, const Rect& repaintRect); - void endLayer(); - WARN_UNUSED_RESULT OffscreenBuffer* copyToLayer(const Rect& area); - - Texture* getTexture(Bitmap* bitmap); - const LightInfo& getLightInfo() const { return mLightInfo; } - - void renderGlop(const BakedOpState& state, const Glop& glop) { - renderGlop(&state.computedState.clippedBounds, state.computedState.getClipIfNeeded(), glop); - } - void renderFunctor(const FunctorOp& op, const BakedOpState& state); - - void renderGlop(const Rect* dirtyBounds, const ClipBase* clip, const Glop& glop) { - mGlopReceiver(*this, dirtyBounds, clip, glop); - } - bool offscreenRenderTarget() { return mRenderTarget.offscreenBuffer != nullptr; } - void dirtyRenderTarget(const Rect& dirtyRect); - bool didDraw() const { return mHasDrawn; } - - uint32_t getViewportWidth() const { return mRenderTarget.viewportWidth; } - uint32_t getViewportHeight() const { return mRenderTarget.viewportHeight; } - - // simple draw methods, to be used for end frame decoration - void drawRect(float left, float top, float right, float bottom, const SkPaint* paint) { - float ltrb[4] = {left, top, right, bottom}; - drawRects(ltrb, 4, paint); - } - void drawRects(const float* rects, int count, const SkPaint* paint); - -protected: - GlopReceiver mGlopReceiver; - -private: - static void DefaultGlopReceiver(BakedOpRenderer& renderer, const Rect* dirtyBounds, - const ClipBase* clip, const Glop& glop) { - renderer.renderGlopImpl(dirtyBounds, clip, glop); - } - void renderGlopImpl(const Rect* dirtyBounds, const ClipBase* clip, const Glop& glop); - void setViewport(uint32_t width, uint32_t height); - void clearColorBuffer(const Rect& clearRect); - void prepareRender(const Rect* dirtyBounds, const ClipBase* clip); - void setupStencilRectList(const ClipBase* clip); - void setupStencilRegion(const ClipBase* clip); - void setupStencilQuads(std::vector& quadVertices, int incrementThreshold); - - RenderState& mRenderState; - Caches& mCaches; - bool mOpaque; - bool mWideColorGamut; - bool mHasDrawn = false; - - // render target state - setup by start/end layer/frame - // only valid to use in between start/end pairs. - struct { - // If not drawing to a layer: fbo = 0, offscreenBuffer = null, - // Otherwise these refer to currently painting layer's state - GLuint frameBufferId = 0; - OffscreenBuffer* offscreenBuffer = nullptr; - - // Used when drawing to a layer and using stencil clipping. otherwise null. - RenderBuffer* stencil = nullptr; - - // value representing the ClipRectList* or ClipRegion* currently stored in - // the stencil of the current render target - const ClipBase* lastStencilClip = nullptr; - - // Size of renderable region in current render target - for layers, may not match actual - // bounds of FBO texture. offscreenBuffer->texture has this information. - uint32_t viewportWidth = 0; - uint32_t viewportHeight = 0; - - Matrix4 orthoMatrix; - } mRenderTarget; - - const LightInfo mLightInfo; -}; - -}; // namespace uirenderer -}; // namespace android diff --git a/libs/hwui/BakedOpState.cpp b/libs/hwui/BakedOpState.cpp deleted file mode 100644 index 0c673f315ded..000000000000 --- a/libs/hwui/BakedOpState.cpp +++ /dev/null @@ -1,165 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "BakedOpState.h" - -#include "ClipArea.h" - -namespace android { -namespace uirenderer { - -static int computeClipSideFlags(const Rect& clip, const Rect& bounds) { - int clipSideFlags = 0; - if (clip.left > bounds.left) clipSideFlags |= OpClipSideFlags::Left; - if (clip.top > bounds.top) clipSideFlags |= OpClipSideFlags::Top; - if (clip.right < bounds.right) clipSideFlags |= OpClipSideFlags::Right; - if (clip.bottom < bounds.bottom) clipSideFlags |= OpClipSideFlags::Bottom; - return clipSideFlags; -} - -ResolvedRenderState::ResolvedRenderState(LinearAllocator& allocator, Snapshot& snapshot, - const RecordedOp& recordedOp, bool expandForStroke, - bool expandForPathTexture) { - // resolvedMatrix = parentMatrix * localMatrix - transform.loadMultiply(*snapshot.transform, recordedOp.localMatrix); - - // resolvedClippedBounds = intersect(resolvedMatrix * opBounds, resolvedClipRect) - clippedBounds = recordedOp.unmappedBounds; - if (CC_UNLIKELY(expandForStroke)) { - // account for non-hairline stroke - clippedBounds.outset(recordedOp.paint->getStrokeWidth() * 0.5f); - } else if (CC_UNLIKELY(expandForPathTexture)) { - clippedBounds.outset(1); - } - transform.mapRect(clippedBounds); - if (CC_UNLIKELY(expandForStroke && - (!transform.isPureTranslate() || recordedOp.paint->getStrokeWidth() < 1.0f))) { - // account for hairline stroke when stroke may be < 1 scaled pixel - // Non translate || strokeWidth < 1 is conservative, but will cover all cases - clippedBounds.outset(0.5f); - } - - // resolvedClipRect = intersect(parentMatrix * localClip, parentClip) - clipState = snapshot.serializeIntersectedClip(allocator, recordedOp.localClip, - *(snapshot.transform)); - LOG_ALWAYS_FATAL_IF(!clipState, "must clip!"); - - const Rect& clipRect = clipState->rect; - if (CC_UNLIKELY(clipRect.isEmpty() || !clippedBounds.intersects(clipRect))) { - // Rejected based on either empty clip, or bounds not intersecting with clip - - // Note: we could rewind the clipState object in situations where the clipRect is empty, - // but *only* if the caching logic within ClipArea was aware of the rewind. - clipState = nullptr; - clippedBounds.setEmpty(); - } else { - // Not rejected! compute true clippedBounds, clipSideFlags, and path mask - clipSideFlags = computeClipSideFlags(clipRect, clippedBounds); - clippedBounds.doIntersect(clipRect); - - if (CC_UNLIKELY(snapshot.projectionPathMask)) { - // map projection path mask from render target space into op space, - // so intersection with op geometry is possible - Matrix4 inverseTransform; - inverseTransform.loadInverse(transform); - SkMatrix skInverseTransform; - inverseTransform.copyTo(skInverseTransform); - - auto localMask = allocator.create(); - snapshot.projectionPathMask->transform(skInverseTransform, localMask); - localProjectionPathMask = localMask; - } - } -} - -ResolvedRenderState::ResolvedRenderState(LinearAllocator& allocator, Snapshot& snapshot, - const Matrix4& localTransform, const ClipBase* localClip) { - transform.loadMultiply(*snapshot.transform, localTransform); - clipState = snapshot.serializeIntersectedClip(allocator, localClip, *(snapshot.transform)); - clippedBounds = clipState->rect; - clipSideFlags = OpClipSideFlags::Full; - localProjectionPathMask = nullptr; -} - -ResolvedRenderState::ResolvedRenderState(LinearAllocator& allocator, Snapshot& snapshot) - : transform(*snapshot.transform) - , clipState(snapshot.mutateClipArea().serializeClip(allocator)) - , clippedBounds(clipState->rect) - , clipSideFlags(OpClipSideFlags::Full) - , localProjectionPathMask(nullptr) {} - -ResolvedRenderState::ResolvedRenderState(const ClipRect* clipRect, const Rect& dstRect) - : transform(Matrix4::identity()) - , clipState(clipRect) - , clippedBounds(dstRect) - , clipSideFlags(computeClipSideFlags(clipRect->rect, dstRect)) - , localProjectionPathMask(nullptr) { - clippedBounds.doIntersect(clipRect->rect); -} - -BakedOpState* BakedOpState::tryConstruct(LinearAllocator& allocator, Snapshot& snapshot, - const RecordedOp& recordedOp) { - if (CC_UNLIKELY(snapshot.getRenderTargetClip().isEmpty())) return nullptr; - BakedOpState* bakedState = - allocator.create_trivial(allocator, snapshot, recordedOp, false, false); - if (bakedState->computedState.clippedBounds.isEmpty()) { - // bounds are empty, so op is rejected - allocator.rewindIfLastAlloc(bakedState); - return nullptr; - } - return bakedState; -} - -BakedOpState* BakedOpState::tryConstructUnbounded(LinearAllocator& allocator, Snapshot& snapshot, - const RecordedOp& recordedOp) { - if (CC_UNLIKELY(snapshot.getRenderTargetClip().isEmpty())) return nullptr; - return allocator.create_trivial(allocator, snapshot, recordedOp); -} - -BakedOpState* BakedOpState::tryStrokeableOpConstruct(LinearAllocator& allocator, Snapshot& snapshot, - const RecordedOp& recordedOp, - StrokeBehavior strokeBehavior, - bool expandForPathTexture) { - if (CC_UNLIKELY(snapshot.getRenderTargetClip().isEmpty())) return nullptr; - bool expandForStroke = - (strokeBehavior == StrokeBehavior::Forced || - (recordedOp.paint && recordedOp.paint->getStyle() != SkPaint::kFill_Style)); - - BakedOpState* bakedState = allocator.create_trivial( - allocator, snapshot, recordedOp, expandForStroke, expandForPathTexture); - if (bakedState->computedState.clippedBounds.isEmpty()) { - // bounds are empty, so op is rejected - // NOTE: this won't succeed if a clip was allocated - allocator.rewindIfLastAlloc(bakedState); - return nullptr; - } - return bakedState; -} - -BakedOpState* BakedOpState::directConstruct(LinearAllocator& allocator, const ClipRect* clip, - const Rect& dstRect, const RecordedOp& recordedOp) { - return allocator.create_trivial(clip, dstRect, recordedOp); -} - -void BakedOpState::setupOpacity(const SkPaint* paint) { - computedState.opaqueOverClippedBounds = computedState.transform.isSimple() && - computedState.clipState->mode == ClipMode::Rectangle && - MathUtils::areEqual(alpha, 1.0f) && - !roundRectClipState && PaintUtils::isOpaquePaint(paint); -} - -} // namespace uirenderer -} // namespace android diff --git a/libs/hwui/BakedOpState.h b/libs/hwui/BakedOpState.h deleted file mode 100644 index a50feff44fc0..000000000000 --- a/libs/hwui/BakedOpState.h +++ /dev/null @@ -1,164 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef ANDROID_HWUI_BAKED_OP_STATE_H -#define ANDROID_HWUI_BAKED_OP_STATE_H - -#include "Matrix.h" -#include "RecordedOp.h" -#include "Rect.h" -#include "Snapshot.h" - -namespace android { -namespace uirenderer { - -class BakedOpState; - -namespace OpClipSideFlags { -enum { - None = 0x0, - Left = 0x1, - Top = 0x2, - Right = 0x4, - Bottom = 0x8, - Full = 0xF, - // ConservativeFull = 0x1F needed? -}; -} - -/** - * Holds a list of BakedOpStates of ops that can be drawn together - */ -struct MergedBakedOpList { - const BakedOpState* const* states; - size_t count; - int clipSideFlags; - Rect clip; -}; - -/** - * Holds the resolved clip, transform, and bounds of a recordedOp, when replayed with a snapshot - */ -class ResolvedRenderState { -public: - ResolvedRenderState(LinearAllocator& allocator, Snapshot& snapshot, - const RecordedOp& recordedOp, bool expandForStroke, - bool expandForPathTexture); - - // Constructor for unbounded ops *with* transform/clip - ResolvedRenderState(LinearAllocator& allocator, Snapshot& snapshot, - const Matrix4& localTransform, const ClipBase* localClip); - - // Constructor for unbounded ops without transform/clip (namely shadows) - ResolvedRenderState(LinearAllocator& allocator, Snapshot& snapshot); - - // Constructor for primitive ops provided clip, and no transform - ResolvedRenderState(const ClipRect* viewportRect, const Rect& dstRect); - - Rect computeLocalSpaceClip() const { - Matrix4 inverse; - inverse.loadInverse(transform); - - Rect outClip(clipRect()); - inverse.mapRect(outClip); - return outClip; - } - - const Rect& clipRect() const { return clipState->rect; } - - bool requiresClip() const { - return clipSideFlags != OpClipSideFlags::None || - CC_UNLIKELY(clipState->mode != ClipMode::Rectangle); - } - - // returns the clip if it's needed to draw the operation, otherwise nullptr - const ClipBase* getClipIfNeeded() const { return requiresClip() ? clipState : nullptr; } - - Matrix4 transform; - const ClipBase* clipState = nullptr; - Rect clippedBounds; - int clipSideFlags = 0; - const SkPath* localProjectionPathMask = nullptr; - bool opaqueOverClippedBounds = false; -}; - -/** - * Self-contained op wrapper, containing all resolved state required to draw the op. - * - * Stashed pointers within all point to longer lived objects, with no ownership implied. - */ -class BakedOpState { -public: - static BakedOpState* tryConstruct(LinearAllocator& allocator, Snapshot& snapshot, - const RecordedOp& recordedOp); - - static BakedOpState* tryConstructUnbounded(LinearAllocator& allocator, Snapshot& snapshot, - const RecordedOp& recordedOp); - - enum class StrokeBehavior { - // stroking is forced, regardless of style on paint (such as for lines) - Forced, - // stroking is defined by style on paint - StyleDefined, - }; - - static BakedOpState* tryStrokeableOpConstruct(LinearAllocator& allocator, Snapshot& snapshot, - const RecordedOp& recordedOp, - StrokeBehavior strokeBehavior, - bool expandForPathTexture); - - static BakedOpState* directConstruct(LinearAllocator& allocator, const ClipRect* clip, - const Rect& dstRect, const RecordedOp& recordedOp); - - // Set opaqueOverClippedBounds. If this method isn't called, the op is assumed translucent. - void setupOpacity(const SkPaint* paint); - - // computed state: - ResolvedRenderState computedState; - - // simple state (straight pointer/value storage): - const float alpha; - const RoundRectClipState* roundRectClipState; - const RecordedOp* op; - -private: - friend class LinearAllocator; - - BakedOpState(LinearAllocator& allocator, Snapshot& snapshot, const RecordedOp& recordedOp, - bool expandForStroke, bool expandForPathTexture) - : computedState(allocator, snapshot, recordedOp, expandForStroke, expandForPathTexture) - , alpha(snapshot.alpha) - , roundRectClipState(snapshot.roundRectClipState) - , op(&recordedOp) {} - - // TODO: fix this brittleness - BakedOpState(LinearAllocator& allocator, Snapshot& snapshot, const RecordedOp& recordedOp) - : computedState(allocator, snapshot, recordedOp.localMatrix, recordedOp.localClip) - , alpha(snapshot.alpha) - , roundRectClipState(snapshot.roundRectClipState) - , op(&recordedOp) {} - - BakedOpState(const ClipRect* clipRect, const Rect& dstRect, const RecordedOp& recordedOp) - : computedState(clipRect, dstRect) - , alpha(1.0f) - , roundRectClipState(nullptr) - , op(&recordedOp) {} -}; - -}; // namespace uirenderer -}; // namespace android - -#endif // ANDROID_HWUI_BAKED_OP_STATE_H diff --git a/libs/hwui/Caches.cpp b/libs/hwui/Caches.cpp index 74e099719090..891de5e9d279 100644 --- a/libs/hwui/Caches.cpp +++ b/libs/hwui/Caches.cpp @@ -188,12 +188,7 @@ void Caches::flush(FlushMode mode) { /////////////////////////////////////////////////////////////////////////////// TextureVertex* Caches::getRegionMesh() { - // Create the mesh, 2 triangles and 4 vertices per rectangle in the region - if (!mRegionMesh) { - mRegionMesh.reset(new TextureVertex[kMaxNumberOfQuads * 4]); - } - - return mRegionMesh.get(); + return nullptr; } /////////////////////////////////////////////////////////////////////////////// diff --git a/libs/hwui/FrameInfoVisualizer.cpp b/libs/hwui/FrameInfoVisualizer.cpp index 5aea04d94cbe..236a6b667f3b 100644 --- a/libs/hwui/FrameInfoVisualizer.cpp +++ b/libs/hwui/FrameInfoVisualizer.cpp @@ -15,7 +15,6 @@ */ #include "FrameInfoVisualizer.h" -#include "BakedOpRenderer.h" #include "IProfileRenderer.h" #include "utils/Color.h" diff --git a/libs/hwui/GlopBuilder.cpp b/libs/hwui/GlopBuilder.cpp deleted file mode 100644 index 13a41123bc2f..000000000000 --- a/libs/hwui/GlopBuilder.cpp +++ /dev/null @@ -1,650 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#include "GlopBuilder.h" - -#include "Caches.h" -#include "GlLayer.h" -#include "Glop.h" -#include "Layer.h" -#include "Matrix.h" -#include "Patch.h" -#include "SkiaShader.h" -#include "Texture.h" -#include "VertexBuffer.h" -#include "renderstate/MeshState.h" -#include "renderstate/RenderState.h" -#include "utils/PaintUtils.h" - -#include -#include - -#define DEBUG_GLOP_BUILDER 0 - -#if DEBUG_GLOP_BUILDER - -#define TRIGGER_STAGE(stageFlag) \ - LOG_ALWAYS_FATAL_IF((stageFlag)&mStageFlags, "Stage %d cannot be run twice", (stageFlag)); \ - mStageFlags = static_cast(mStageFlags | (stageFlag)) - -#define REQUIRE_STAGES(requiredFlags) \ - LOG_ALWAYS_FATAL_IF((mStageFlags & (requiredFlags)) != (requiredFlags), \ - "not prepared for current stage") - -#else - -#define TRIGGER_STAGE(stageFlag) ((void)0) -#define REQUIRE_STAGES(requiredFlags) ((void)0) - -#endif - -namespace android { -namespace uirenderer { - -static void setUnitQuadTextureCoords(Rect uvs, TextureVertex* quadVertex) { - quadVertex[0] = {0, 0, uvs.left, uvs.top}; - quadVertex[1] = {1, 0, uvs.right, uvs.top}; - quadVertex[2] = {0, 1, uvs.left, uvs.bottom}; - quadVertex[3] = {1, 1, uvs.right, uvs.bottom}; -} - -GlopBuilder::GlopBuilder(RenderState& renderState, Caches& caches, Glop* outGlop) - : mRenderState(renderState), mCaches(caches), mShader(nullptr), mOutGlop(outGlop) { - mStageFlags = kInitialStage; -} - -//////////////////////////////////////////////////////////////////////////////// -// Mesh -//////////////////////////////////////////////////////////////////////////////// - -GlopBuilder& GlopBuilder::setMeshTexturedIndexedVbo(GLuint vbo, GLsizei elementCount) { - TRIGGER_STAGE(kMeshStage); - - mOutGlop->mesh.primitiveMode = GL_TRIANGLES; - mOutGlop->mesh.indices = {mRenderState.meshState().getQuadListIBO(), nullptr}; - mOutGlop->mesh.vertices = {vbo, VertexAttribFlags::TextureCoord, - nullptr, (const void*)kMeshTextureOffset, - nullptr, kTextureVertexStride}; - mOutGlop->mesh.elementCount = elementCount; - return *this; -} - -GlopBuilder& GlopBuilder::setMeshUnitQuad() { - TRIGGER_STAGE(kMeshStage); - - mOutGlop->mesh.primitiveMode = GL_TRIANGLE_STRIP; - mOutGlop->mesh.indices = {0, nullptr}; - mOutGlop->mesh.vertices = {mRenderState.meshState().getUnitQuadVBO(), - VertexAttribFlags::None, - nullptr, - nullptr, - nullptr, - kTextureVertexStride}; - mOutGlop->mesh.elementCount = 4; - return *this; -} - -GlopBuilder& GlopBuilder::setMeshTexturedUnitQuad(const UvMapper* uvMapper) { - if (uvMapper) { - // can't use unit quad VBO, so build UV vertices manually - return setMeshTexturedUvQuad(uvMapper, Rect(1, 1)); - } - - TRIGGER_STAGE(kMeshStage); - - mOutGlop->mesh.primitiveMode = GL_TRIANGLE_STRIP; - mOutGlop->mesh.indices = {0, nullptr}; - mOutGlop->mesh.vertices = {mRenderState.meshState().getUnitQuadVBO(), - VertexAttribFlags::TextureCoord, - nullptr, - (const void*)kMeshTextureOffset, - nullptr, - kTextureVertexStride}; - mOutGlop->mesh.elementCount = 4; - return *this; -} - -GlopBuilder& GlopBuilder::setMeshTexturedUvQuad(const UvMapper* uvMapper, Rect uvs) { - TRIGGER_STAGE(kMeshStage); - - if (CC_UNLIKELY(uvMapper)) { - uvMapper->map(uvs); - } - setUnitQuadTextureCoords(uvs, &mOutGlop->mesh.mappedVertices[0]); - - const TextureVertex* textureVertex = mOutGlop->mesh.mappedVertices; - mOutGlop->mesh.primitiveMode = GL_TRIANGLE_STRIP; - mOutGlop->mesh.indices = {0, nullptr}; - mOutGlop->mesh.vertices = {0, - VertexAttribFlags::TextureCoord, - &textureVertex[0].x, - &textureVertex[0].u, - nullptr, - kTextureVertexStride}; - mOutGlop->mesh.elementCount = 4; - return *this; -} - -GlopBuilder& GlopBuilder::setMeshIndexedQuads(Vertex* vertexData, int quadCount) { - TRIGGER_STAGE(kMeshStage); - - mOutGlop->mesh.primitiveMode = GL_TRIANGLES; - mOutGlop->mesh.indices = {mRenderState.meshState().getQuadListIBO(), nullptr}; - mOutGlop->mesh.vertices = { - 0, VertexAttribFlags::None, vertexData, nullptr, nullptr, kVertexStride}; - mOutGlop->mesh.elementCount = 6 * quadCount; - return *this; -} - -GlopBuilder& GlopBuilder::setMeshTexturedIndexedQuads(TextureVertex* vertexData, int elementCount) { - TRIGGER_STAGE(kMeshStage); - - mOutGlop->mesh.primitiveMode = GL_TRIANGLES; - mOutGlop->mesh.indices = {mRenderState.meshState().getQuadListIBO(), nullptr}; - mOutGlop->mesh.vertices = {0, - VertexAttribFlags::TextureCoord, - &vertexData[0].x, - &vertexData[0].u, - nullptr, - kTextureVertexStride}; - mOutGlop->mesh.elementCount = elementCount; - return *this; -} - -GlopBuilder& GlopBuilder::setMeshColoredTexturedMesh(ColorTextureVertex* vertexData, - int elementCount) { - TRIGGER_STAGE(kMeshStage); - - mOutGlop->mesh.primitiveMode = GL_TRIANGLES; - mOutGlop->mesh.indices = {0, nullptr}; - mOutGlop->mesh.vertices = {0, - VertexAttribFlags::TextureCoord | VertexAttribFlags::Color, - &vertexData[0].x, - &vertexData[0].u, - &vertexData[0].r, - kColorTextureVertexStride}; - mOutGlop->mesh.elementCount = elementCount; - return *this; -} - -GlopBuilder& GlopBuilder::setMeshVertexBuffer(const VertexBuffer& vertexBuffer) { - TRIGGER_STAGE(kMeshStage); - - const VertexBuffer::MeshFeatureFlags flags = vertexBuffer.getMeshFeatureFlags(); - - bool alphaVertex = flags & VertexBuffer::kAlpha; - bool indices = flags & VertexBuffer::kIndices; - - mOutGlop->mesh.primitiveMode = GL_TRIANGLE_STRIP; - mOutGlop->mesh.indices = {0, vertexBuffer.getIndices()}; - mOutGlop->mesh.vertices = {0, - alphaVertex ? VertexAttribFlags::Alpha : VertexAttribFlags::None, - vertexBuffer.getBuffer(), - nullptr, - nullptr, - alphaVertex ? kAlphaVertexStride : kVertexStride}; - mOutGlop->mesh.elementCount = - indices ? vertexBuffer.getIndexCount() : vertexBuffer.getVertexCount(); - mOutGlop->mesh.vertexCount = vertexBuffer.getVertexCount(); // used for glDrawRangeElements() - return *this; -} - -GlopBuilder& GlopBuilder::setMeshPatchQuads(const Patch& patch) { - // DEAD CODE - return *this; -} - -//////////////////////////////////////////////////////////////////////////////// -// Fill -//////////////////////////////////////////////////////////////////////////////// - -void GlopBuilder::setFill(int color, float alphaScale, SkBlendMode mode, - Blend::ModeOrderSwap modeUsage, const SkShader* shader, - const SkColorFilter* colorFilter) { - if (mode != SkBlendMode::kClear) { - if (!shader) { - FloatColor c; - c.set(color); - c.r *= alphaScale; - c.g *= alphaScale; - c.b *= alphaScale; - c.a *= alphaScale; - mOutGlop->fill.color = c; - } else { - float alpha = (SkColorGetA(color) / 255.0f) * alphaScale; - mOutGlop->fill.color = {1, 1, 1, alpha}; - } - } else { - mOutGlop->fill.color = {0, 0, 0, 1}; - } - - mOutGlop->blend = {GL_ZERO, GL_ZERO}; - if (mOutGlop->fill.color.a < 1.0f || - (mOutGlop->mesh.vertices.attribFlags & VertexAttribFlags::Alpha) || - (mOutGlop->fill.texture.texture && mOutGlop->fill.texture.texture->blend) || - mOutGlop->roundRectClipState || PaintUtils::isBlendedShader(shader) || - PaintUtils::isBlendedColorFilter(colorFilter) || mode != SkBlendMode::kSrcOver) { - if (CC_LIKELY(mode <= SkBlendMode::kScreen)) { - Blend::getFactors(mode, modeUsage, &mOutGlop->blend.src, &mOutGlop->blend.dst); - } else { - // These blend modes are not supported by OpenGL directly and have - // to be implemented using shaders. Since the shader will perform - // the blending, don't enable GL blending off here - // If the blend mode cannot be implemented using shaders, fall - // back to the default SrcOver blend mode instead - if (CC_UNLIKELY(mCaches.extensions().hasFramebufferFetch())) { - mDescription.framebufferMode = mode; - mDescription.swapSrcDst = (modeUsage == Blend::ModeOrderSwap::Swap); - // blending in shader, don't enable - } else { - // unsupported - Blend::getFactors(SkBlendMode::kSrcOver, modeUsage, &mOutGlop->blend.src, - &mOutGlop->blend.dst); - } - } - } - mShader = shader; // shader resolved in ::build() - - if (colorFilter) { - SkColor color; - SkBlendMode bmode; - SkScalar srcColorMatrix[20]; - if (colorFilter->asColorMode(&color, &bmode)) { - mOutGlop->fill.filterMode = mDescription.colorOp = - ProgramDescription::ColorFilterMode::Blend; - mDescription.colorMode = bmode; - mOutGlop->fill.filter.color.set(color); - } else if (colorFilter->asColorMatrix(srcColorMatrix)) { - mOutGlop->fill.filterMode = mDescription.colorOp = - ProgramDescription::ColorFilterMode::Matrix; - - float* colorMatrix = mOutGlop->fill.filter.matrix.matrix; - memcpy(colorMatrix, srcColorMatrix, 4 * sizeof(float)); - memcpy(&colorMatrix[4], &srcColorMatrix[5], 4 * sizeof(float)); - memcpy(&colorMatrix[8], &srcColorMatrix[10], 4 * sizeof(float)); - memcpy(&colorMatrix[12], &srcColorMatrix[15], 4 * sizeof(float)); - - // Skia uses the range [0..255] for the addition vector, but we need - // the [0..1] range to apply the vector in GLSL - float* colorVector = mOutGlop->fill.filter.matrix.vector; - colorVector[0] = EOCF(srcColorMatrix[4] / 255.0f); - colorVector[1] = EOCF(srcColorMatrix[9] / 255.0f); - colorVector[2] = EOCF(srcColorMatrix[14] / 255.0f); - colorVector[3] = srcColorMatrix[19] / 255.0f; // alpha is linear - } else { - ALOGE("unsupported ColorFilter type: %s", colorFilter->getTypeName()); - LOG_ALWAYS_FATAL("unsupported ColorFilter"); - } - } else { - mOutGlop->fill.filterMode = ProgramDescription::ColorFilterMode::None; - } -} - -GlopBuilder& GlopBuilder::setFillTexturePaint(Texture& texture, const int textureFillFlags, - const SkPaint* paint, float alphaScale) { - TRIGGER_STAGE(kFillStage); - REQUIRE_STAGES(kMeshStage | kRoundRectClipStage); - - GLenum filter = (textureFillFlags & TextureFillFlags::ForceFilter) - ? GL_LINEAR - : PaintUtils::getFilter(paint); - mOutGlop->fill.texture = {&texture, filter, GL_CLAMP_TO_EDGE, nullptr}; - - if (paint) { - int color = paint->getColor(); - SkShader* shader = paint->getShader(); - - if (!(textureFillFlags & TextureFillFlags::IsAlphaMaskTexture)) { - // Texture defines color, so disable shaders, and reset all non-alpha color channels - color |= 0x00FFFFFF; - shader = nullptr; - } - setFill(color, alphaScale, paint->getBlendMode(), Blend::ModeOrderSwap::NoSwap, shader, - paint->getColorFilter()); - } else { - mOutGlop->fill.color = {alphaScale, alphaScale, alphaScale, alphaScale}; - - if (alphaScale < 1.0f || (mOutGlop->mesh.vertices.attribFlags & VertexAttribFlags::Alpha) || - texture.blend || mOutGlop->roundRectClipState) { - Blend::getFactors(SkBlendMode::kSrcOver, Blend::ModeOrderSwap::NoSwap, - &mOutGlop->blend.src, &mOutGlop->blend.dst); - } else { - mOutGlop->blend = {GL_ZERO, GL_ZERO}; - } - } - - if (textureFillFlags & TextureFillFlags::IsAlphaMaskTexture) { - mDescription.modulate = mOutGlop->fill.color.isNotBlack(); - mDescription.hasAlpha8Texture = true; - } else { - mDescription.modulate = mOutGlop->fill.color.a < 1.0f; - } - return *this; -} - -GlopBuilder& GlopBuilder::setFillPaint(const SkPaint& paint, float alphaScale, bool shadowInterp) { - TRIGGER_STAGE(kFillStage); - REQUIRE_STAGES(kMeshStage | kRoundRectClipStage); - - if (CC_LIKELY(!shadowInterp)) { - mOutGlop->fill.texture = {nullptr, GL_INVALID_ENUM, GL_INVALID_ENUM, nullptr}; - } else { - mOutGlop->fill.texture = {mCaches.textureState().getShadowLutTexture(), GL_INVALID_ENUM, - GL_INVALID_ENUM, nullptr}; - } - - setFill(paint.getColor(), alphaScale, paint.getBlendMode(), Blend::ModeOrderSwap::NoSwap, - paint.getShader(), paint.getColorFilter()); - mDescription.useShadowAlphaInterp = shadowInterp; - mDescription.modulate = mOutGlop->fill.color.a < 1.0f; - return *this; -} - -GlopBuilder& GlopBuilder::setFillPathTexturePaint(PathTexture& texture, const SkPaint& paint, - float alphaScale) { - // DEAD CODE - return *this; -} - -GlopBuilder& GlopBuilder::setFillShadowTexturePaint(ShadowTexture& texture, int shadowColor, - const SkPaint& paint, float alphaScale) { - // DEAD CODE - return *this; -} - -GlopBuilder& GlopBuilder::setFillBlack() { - TRIGGER_STAGE(kFillStage); - REQUIRE_STAGES(kMeshStage | kRoundRectClipStage); - - mOutGlop->fill.texture = {nullptr, GL_INVALID_ENUM, GL_INVALID_ENUM, nullptr}; - setFill(SK_ColorBLACK, 1.0f, SkBlendMode::kSrcOver, Blend::ModeOrderSwap::NoSwap, nullptr, - nullptr); - return *this; -} - -GlopBuilder& GlopBuilder::setFillClear() { - TRIGGER_STAGE(kFillStage); - REQUIRE_STAGES(kMeshStage | kRoundRectClipStage); - - mOutGlop->fill.texture = {nullptr, GL_INVALID_ENUM, GL_INVALID_ENUM, nullptr}; - setFill(SK_ColorBLACK, 1.0f, SkBlendMode::kClear, Blend::ModeOrderSwap::NoSwap, nullptr, - nullptr); - return *this; -} - -GlopBuilder& GlopBuilder::setFillLayer(Texture& texture, const SkColorFilter* colorFilter, - float alpha, SkBlendMode mode, - Blend::ModeOrderSwap modeUsage) { - TRIGGER_STAGE(kFillStage); - REQUIRE_STAGES(kMeshStage | kRoundRectClipStage); - - mOutGlop->fill.texture = {&texture, GL_LINEAR, GL_CLAMP_TO_EDGE, nullptr}; - - setFill(SK_ColorWHITE, alpha, mode, modeUsage, nullptr, colorFilter); - - mDescription.modulate = mOutGlop->fill.color.a < 1.0f; - return *this; -} - -GlopBuilder& GlopBuilder::setFillTextureLayer(GlLayer& layer, float alpha) { - TRIGGER_STAGE(kFillStage); - REQUIRE_STAGES(kMeshStage | kRoundRectClipStage); - - mOutGlop->fill.texture = {&(layer.getTexture()), GL_LINEAR, GL_CLAMP_TO_EDGE, - &layer.getTexTransform()}; - - setFill(SK_ColorWHITE, alpha, layer.getMode(), Blend::ModeOrderSwap::NoSwap, nullptr, - layer.getColorFilter()); - - mDescription.modulate = mOutGlop->fill.color.a < 1.0f; - mDescription.hasTextureTransform = true; - return *this; -} - -GlopBuilder& GlopBuilder::setFillExternalTexture(Texture& texture, Matrix4& textureTransform, - bool requiresFilter) { - TRIGGER_STAGE(kFillStage); - REQUIRE_STAGES(kMeshStage | kRoundRectClipStage); - - GLenum filter = requiresFilter ? GL_LINEAR : GL_NEAREST; - mOutGlop->fill.texture = {&texture, filter, GL_CLAMP_TO_EDGE, &textureTransform}; - - setFill(SK_ColorWHITE, 1.0f, SkBlendMode::kSrc, Blend::ModeOrderSwap::NoSwap, nullptr, nullptr); - - mDescription.modulate = mOutGlop->fill.color.a < 1.0f; - mDescription.hasTextureTransform = true; - return *this; -} - -GlopBuilder& GlopBuilder::setGammaCorrection(bool enabled) { - REQUIRE_STAGES(kFillStage); - - mDescription.hasGammaCorrection = enabled; - return *this; -} - -//////////////////////////////////////////////////////////////////////////////// -// Transform -//////////////////////////////////////////////////////////////////////////////// - -GlopBuilder& GlopBuilder::setTransform(const Matrix4& canvas, const int transformFlags) { - TRIGGER_STAGE(kTransformStage); - - mOutGlop->transform.canvas = canvas; - mOutGlop->transform.transformFlags = transformFlags; - return *this; -} - -//////////////////////////////////////////////////////////////////////////////// -// ModelView -//////////////////////////////////////////////////////////////////////////////// - -GlopBuilder& GlopBuilder::setModelViewMapUnitToRect(const Rect destination) { - TRIGGER_STAGE(kModelViewStage); - - mOutGlop->transform.modelView.loadTranslate(destination.left, destination.top, 0.0f); - mOutGlop->transform.modelView.scale(destination.getWidth(), destination.getHeight(), 1.0f); - return *this; -} - -GlopBuilder& GlopBuilder::setModelViewMapUnitToRectSnap(const Rect destination) { - TRIGGER_STAGE(kModelViewStage); - REQUIRE_STAGES(kTransformStage | kFillStage); - - float left = destination.left; - float top = destination.top; - - const Matrix4& meshTransform = mOutGlop->transform.meshTransform(); - if (CC_LIKELY(meshTransform.isPureTranslate())) { - // snap by adjusting the model view matrix - const float translateX = meshTransform.getTranslateX(); - const float translateY = meshTransform.getTranslateY(); - - left = (int)floorf(left + translateX + 0.5f) - translateX; - top = (int)floorf(top + translateY + 0.5f) - translateY; - mOutGlop->fill.texture.filter = GL_NEAREST; - } - - mOutGlop->transform.modelView.loadTranslate(left, top, 0.0f); - mOutGlop->transform.modelView.scale(destination.getWidth(), destination.getHeight(), 1.0f); - return *this; -} - -GlopBuilder& GlopBuilder::setModelViewOffsetRect(float offsetX, float offsetY, const Rect source) { - TRIGGER_STAGE(kModelViewStage); - - mOutGlop->transform.modelView.loadTranslate(offsetX, offsetY, 0.0f); - return *this; -} - -GlopBuilder& GlopBuilder::setModelViewOffsetRectSnap(float offsetX, float offsetY, - const Rect source) { - TRIGGER_STAGE(kModelViewStage); - REQUIRE_STAGES(kTransformStage | kFillStage); - - const Matrix4& meshTransform = mOutGlop->transform.meshTransform(); - if (CC_LIKELY(meshTransform.isPureTranslate())) { - // snap by adjusting the model view matrix - const float translateX = meshTransform.getTranslateX(); - const float translateY = meshTransform.getTranslateY(); - - offsetX = (int)floorf(offsetX + translateX + source.left + 0.5f) - translateX - source.left; - offsetY = (int)floorf(offsetY + translateY + source.top + 0.5f) - translateY - source.top; - mOutGlop->fill.texture.filter = GL_NEAREST; - } - - mOutGlop->transform.modelView.loadTranslate(offsetX, offsetY, 0.0f); - return *this; -} - -//////////////////////////////////////////////////////////////////////////////// -// RoundRectClip -//////////////////////////////////////////////////////////////////////////////// - -GlopBuilder& GlopBuilder::setRoundRectClipState(const RoundRectClipState* roundRectClipState) { - TRIGGER_STAGE(kRoundRectClipStage); - - mOutGlop->roundRectClipState = roundRectClipState; - mDescription.hasRoundRectClip = roundRectClipState != nullptr; - return *this; -} - -//////////////////////////////////////////////////////////////////////////////// -// Build -//////////////////////////////////////////////////////////////////////////////// - -void verify(const ProgramDescription& description, const Glop& glop) { - if (glop.fill.texture.texture != nullptr) { - LOG_ALWAYS_FATAL_IF( - ((description.hasTexture && description.hasExternalTexture) || - (!description.hasTexture && !description.hasExternalTexture && - !description.useShadowAlphaInterp) || - ((glop.mesh.vertices.attribFlags & VertexAttribFlags::TextureCoord) == 0 && - !description.useShadowAlphaInterp)), - "Texture %p, hT%d, hET %d, attribFlags %x", glop.fill.texture.texture, - description.hasTexture, description.hasExternalTexture, - glop.mesh.vertices.attribFlags); - } else { - LOG_ALWAYS_FATAL_IF( - (description.hasTexture || description.hasExternalTexture || - ((glop.mesh.vertices.attribFlags & VertexAttribFlags::TextureCoord) != 0)), - "No texture, hT%d, hET %d, attribFlags %x", description.hasTexture, - description.hasExternalTexture, glop.mesh.vertices.attribFlags); - } - - if ((glop.mesh.vertices.attribFlags & VertexAttribFlags::Alpha) && - glop.mesh.vertices.bufferObject) { - LOG_ALWAYS_FATAL("VBO and alpha attributes are not currently compatible"); - } - - if (description.hasTextureTransform != (glop.fill.texture.textureTransform != nullptr)) { - LOG_ALWAYS_FATAL("Texture transform incorrectly specified"); - } -} - -void GlopBuilder::build() { - REQUIRE_STAGES(kAllStages); - if (mOutGlop->mesh.vertices.attribFlags & VertexAttribFlags::TextureCoord) { - Texture* texture = mOutGlop->fill.texture.texture; - if (texture->target() == GL_TEXTURE_2D) { - mDescription.hasTexture = true; - } else { - mDescription.hasExternalTexture = true; - } - mDescription.hasLinearTexture = texture->isLinear(); - mDescription.hasColorSpaceConversion = texture->hasColorSpaceConversion(); - mDescription.transferFunction = texture->getTransferFunctionType(); - mDescription.hasTranslucentConversion = texture->blend; - } - - mDescription.hasColors = mOutGlop->mesh.vertices.attribFlags & VertexAttribFlags::Color; - mDescription.hasVertexAlpha = mOutGlop->mesh.vertices.attribFlags & VertexAttribFlags::Alpha; - - // Enable debug highlight when what we're about to draw is tested against - // the stencil buffer and if stencil highlight debugging is on - mDescription.hasDebugHighlight = - !Properties::debugOverdraw && - Properties::debugStencilClip == StencilClipDebug::ShowHighlight && - mRenderState.stencil().isTestEnabled(); - - // serialize shader info into ShaderData - GLuint textureUnit = mOutGlop->fill.texture.texture ? 1 : 0; - - if (CC_LIKELY(!mShader)) { - mOutGlop->fill.skiaShaderData.skiaShaderType = kNone_SkiaShaderType; - } else { - Matrix4 shaderMatrix; - if (mOutGlop->transform.transformFlags & TransformFlags::MeshIgnoresCanvasTransform) { - // canvas level transform was built into the modelView and geometry, - // so the shader matrix must reverse this - shaderMatrix.loadInverse(mOutGlop->transform.canvas); - shaderMatrix.multiply(mOutGlop->transform.modelView); - } else { - shaderMatrix = mOutGlop->transform.modelView; - } - SkiaShader::store(mCaches, *mShader, shaderMatrix, &textureUnit, &mDescription, - &(mOutGlop->fill.skiaShaderData)); - } - - // duplicates ProgramCache's definition of color uniform presence - const bool singleColor = !mDescription.hasTexture && !mDescription.hasExternalTexture && - !mDescription.hasGradient && !mDescription.hasBitmap; - mOutGlop->fill.colorEnabled = mDescription.modulate || singleColor; - - verify(mDescription, *mOutGlop); -} - -void GlopBuilder::dump(const Glop& glop) { - ALOGD("Glop Mesh"); - const Glop::Mesh& mesh = glop.mesh; - ALOGD(" primitive mode: %d", mesh.primitiveMode); - ALOGD(" indices: buffer obj %x, indices %p", mesh.indices.bufferObject, - mesh.indices.indices); - - const Glop::Mesh::Vertices& vertices = glop.mesh.vertices; - ALOGD(" vertices: buffer obj %x, flags %x, pos %p, tex %p, clr %p, stride %d", - vertices.bufferObject, vertices.attribFlags, vertices.position, vertices.texCoord, - vertices.color, vertices.stride); - ALOGD(" element count: %d", mesh.elementCount); - - ALOGD("Glop Fill"); - const Glop::Fill& fill = glop.fill; - ALOGD(" program %p", fill.program); - if (fill.texture.texture) { - ALOGD(" texture %p, target %d, filter %d, clamp %d", fill.texture.texture, - fill.texture.texture->target(), fill.texture.filter, fill.texture.clamp); - if (fill.texture.textureTransform) { - fill.texture.textureTransform->dump("texture transform"); - } - } - ALOGD_IF(fill.colorEnabled, " color (argb) %.2f %.2f %.2f %.2f", fill.color.a, fill.color.r, - fill.color.g, fill.color.b); - ALOGD_IF(fill.filterMode != ProgramDescription::ColorFilterMode::None, " filterMode %d", - (int)fill.filterMode); - ALOGD_IF(fill.skiaShaderData.skiaShaderType, " shader type %d", - fill.skiaShaderData.skiaShaderType); - - ALOGD("Glop transform"); - glop.transform.modelView.dump(" model view"); - glop.transform.canvas.dump(" canvas"); - ALOGD_IF(glop.transform.transformFlags, " transformFlags 0x%x", glop.transform.transformFlags); - - ALOGD_IF(glop.roundRectClipState, "Glop RRCS %p", glop.roundRectClipState); - - ALOGD("Glop blend %d %d", glop.blend.src, glop.blend.dst); -} - -} /* namespace uirenderer */ -} /* namespace android */ diff --git a/libs/hwui/GlopBuilder.h b/libs/hwui/GlopBuilder.h deleted file mode 100644 index dac38223b877..000000000000 --- a/libs/hwui/GlopBuilder.h +++ /dev/null @@ -1,142 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include "Glop.h" -#include "Program.h" -#include "renderstate/Blend.h" -#include "utils/Macros.h" - -class SkPaint; -class SkShader; - -namespace android { -namespace uirenderer { - -class Caches; -class GlLayer; -class Matrix4; -class Patch; -class RenderState; -class Texture; -class UvMapper; -class VertexBuffer; -struct PathTexture; -struct ShadowTexture; - -namespace TextureFillFlags { -enum { - None = 0, - IsAlphaMaskTexture = 1 << 0, - ForceFilter = 1 << 1, -}; -} - -class GlopBuilder { - PREVENT_COPY_AND_ASSIGN(GlopBuilder); - -public: - GlopBuilder(RenderState& renderState, Caches& caches, Glop* outGlop); - - GlopBuilder& setMeshTexturedIndexedVbo(GLuint vbo, GLsizei elementCount); - GlopBuilder& setMeshUnitQuad(); - GlopBuilder& setMeshTexturedUnitQuad(const UvMapper* uvMapper); - GlopBuilder& setMeshTexturedUvQuad(const UvMapper* uvMapper, const Rect uvs); - GlopBuilder& setMeshVertexBuffer(const VertexBuffer& vertexBuffer); - GlopBuilder& setMeshIndexedQuads(Vertex* vertexData, int quadCount); - GlopBuilder& setMeshColoredTexturedMesh(ColorTextureVertex* vertexData, - int elementCount); // TODO: use indexed quads - GlopBuilder& setMeshTexturedIndexedQuads(TextureVertex* vertexData, - int elementCount); // TODO: take quadCount - GlopBuilder& setMeshPatchQuads(const Patch& patch); - - GlopBuilder& setFillPaint(const SkPaint& paint, float alphaScale, - bool shadowInterp = false); // TODO: avoid boolean with default - GlopBuilder& setFillTexturePaint(Texture& texture, const int textureFillFlags, - const SkPaint* paint, float alphaScale); - GlopBuilder& setFillPathTexturePaint(PathTexture& texture, const SkPaint& paint, - float alphaScale); - GlopBuilder& setFillShadowTexturePaint(ShadowTexture& texture, int shadowColor, - const SkPaint& paint, float alphaScale); - GlopBuilder& setFillBlack(); - GlopBuilder& setFillClear(); - GlopBuilder& setFillLayer(Texture& texture, const SkColorFilter* colorFilter, float alpha, - SkBlendMode mode, Blend::ModeOrderSwap modeUsage); - GlopBuilder& setFillTextureLayer(GlLayer& layer, float alpha); - // TODO: setFillLayer normally forces its own wrap & filter mode, - // which isn't always correct. - GlopBuilder& setFillExternalTexture(Texture& texture, Matrix4& textureTransform, - bool requiresFilter); - - GlopBuilder& setTransform(const Matrix4& canvas, const int transformFlags); - - GlopBuilder& setModelViewMapUnitToRect(const Rect destination); - GlopBuilder& setModelViewMapUnitToRectSnap(const Rect destination); - GlopBuilder& setModelViewMapUnitToRectOptionalSnap(bool snap, const Rect& destination) { - if (snap) { - return setModelViewMapUnitToRectSnap(destination); - } else { - return setModelViewMapUnitToRect(destination); - } - } - GlopBuilder& setModelViewOffsetRect(float offsetX, float offsetY, const Rect source); - GlopBuilder& setModelViewOffsetRectSnap(float offsetX, float offsetY, const Rect source); - GlopBuilder& setModelViewOffsetRectOptionalSnap(bool snap, float offsetX, float offsetY, - const Rect& source) { - if (snap) { - return setModelViewOffsetRectSnap(offsetX, offsetY, source); - } else { - return setModelViewOffsetRect(offsetX, offsetY, source); - } - } - GlopBuilder& setModelViewIdentityEmptyBounds() { - // pass empty rect since not needed for damage / snap - return setModelViewOffsetRect(0, 0, Rect()); - } - - GlopBuilder& setRoundRectClipState(const RoundRectClipState* roundRectClipState); - - GlopBuilder& setGammaCorrection(bool enabled); - - void build(); - - static void dump(const Glop& glop); - -private: - void setFill(int color, float alphaScale, SkBlendMode mode, Blend::ModeOrderSwap modeUsage, - const SkShader* shader, const SkColorFilter* colorFilter); - - enum StageFlags { - kInitialStage = 0, - kMeshStage = 1 << 0, - kTransformStage = 1 << 1, - kModelViewStage = 1 << 2, - kFillStage = 1 << 3, - kRoundRectClipStage = 1 << 4, - kAllStages = - kMeshStage | kFillStage | kTransformStage | kModelViewStage | kRoundRectClipStage, - } mStageFlags; - - ProgramDescription mDescription; - RenderState& mRenderState; - Caches& mCaches; - const SkShader* mShader; - Glop* mOutGlop; -}; - -} /* namespace uirenderer */ -} /* namespace android */ diff --git a/libs/hwui/LayerBuilder.cpp b/libs/hwui/LayerBuilder.cpp deleted file mode 100644 index 15ede4ca148a..000000000000 --- a/libs/hwui/LayerBuilder.cpp +++ /dev/null @@ -1,378 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "LayerBuilder.h" - -#include "BakedOpState.h" -#include "RenderNode.h" -#include "utils/PaintUtils.h" -#include "utils/TraceUtils.h" - -#include - -namespace android { -namespace uirenderer { - -class BatchBase { -public: - BatchBase(batchid_t batchId, BakedOpState* op, bool merging) - : mBatchId(batchId), mMerging(merging) { - mBounds = op->computedState.clippedBounds; - mOps.push_back(op); - } - - bool intersects(const Rect& rect) const { - if (!rect.intersects(mBounds)) return false; - - for (const BakedOpState* op : mOps) { - if (rect.intersects(op->computedState.clippedBounds)) { - return true; - } - } - return false; - } - - batchid_t getBatchId() const { return mBatchId; } - bool isMerging() const { return mMerging; } - - const std::vector& getOps() const { return mOps; } - - void dump() const { - ALOGD(" Batch %p, id %d, merging %d, count %d, bounds " RECT_STRING, this, mBatchId, - mMerging, (int)mOps.size(), RECT_ARGS(mBounds)); - } - -protected: - batchid_t mBatchId; - Rect mBounds; - std::vector mOps; - bool mMerging; -}; - -class OpBatch : public BatchBase { -public: - OpBatch(batchid_t batchId, BakedOpState* op) : BatchBase(batchId, op, false) {} - - void batchOp(BakedOpState* op) { - mBounds.unionWith(op->computedState.clippedBounds); - mOps.push_back(op); - } -}; - -class MergingOpBatch : public BatchBase { -public: - MergingOpBatch(batchid_t batchId, BakedOpState* op) - : BatchBase(batchId, op, true), mClipSideFlags(op->computedState.clipSideFlags) {} - - /* - * Helper for determining if a new op can merge with a MergingDrawBatch based on their bounds - * and clip side flags. Positive bounds delta means new bounds fit in old. - */ - static inline bool checkSide(const int currentFlags, const int newFlags, const int side, - float boundsDelta) { - bool currentClipExists = currentFlags & side; - bool newClipExists = newFlags & side; - - // if current is clipped, we must be able to fit new bounds in current - if (boundsDelta > 0 && currentClipExists) return false; - - // if new is clipped, we must be able to fit current bounds in new - if (boundsDelta < 0 && newClipExists) return false; - - return true; - } - - static bool paintIsDefault(const SkPaint& paint) { - return paint.getAlpha() == 255 && paint.getColorFilter() == nullptr && - paint.getShader() == nullptr; - } - - static bool paintsAreEquivalent(const SkPaint& a, const SkPaint& b) { - // Note: don't check color, since all currently mergeable ops can merge across colors - return a.getAlpha() == b.getAlpha() && a.getColorFilter() == b.getColorFilter() && - a.getShader() == b.getShader(); - } - - /* - * Checks if a (mergeable) op can be merged into this batch - * - * If true, the op's multiDraw must be guaranteed to handle both ops simultaneously, so it is - * important to consider all paint attributes used in the draw calls in deciding both a) if an - * op tries to merge at all, and b) if the op can merge with another set of ops - * - * False positives can lead to information from the paints of subsequent merged operations being - * dropped, so we make simplifying qualifications on the ops that can merge, per op type. - */ - bool canMergeWith(BakedOpState* op) const { - bool isTextBatch = - getBatchId() == OpBatchType::Text || getBatchId() == OpBatchType::ColorText; - - // Overlapping other operations is only allowed for text without shadow. For other ops, - // multiDraw isn't guaranteed to overdraw correctly - if (!isTextBatch || PaintUtils::hasTextShadow(op->op->paint)) { - if (intersects(op->computedState.clippedBounds)) return false; - } - - const BakedOpState* lhs = op; - const BakedOpState* rhs = mOps[0]; - - if (!MathUtils::areEqual(lhs->alpha, rhs->alpha)) return false; - - // Identical round rect clip state means both ops will clip in the same way, or not at all. - // As the state objects are const, we can compare their pointers to determine mergeability - if (lhs->roundRectClipState != rhs->roundRectClipState) return false; - - // Local masks prevent merge, since they're potentially in different coordinate spaces - if (lhs->computedState.localProjectionPathMask || - rhs->computedState.localProjectionPathMask) - return false; - - /* Clipping compatibility check - * - * Exploits the fact that if a op or batch is clipped on a side, its bounds will equal its - * clip for that side. - */ - const int currentFlags = mClipSideFlags; - const int newFlags = op->computedState.clipSideFlags; - if (currentFlags != OpClipSideFlags::None || newFlags != OpClipSideFlags::None) { - const Rect& opBounds = op->computedState.clippedBounds; - float boundsDelta = mBounds.left - opBounds.left; - if (!checkSide(currentFlags, newFlags, OpClipSideFlags::Left, boundsDelta)) - return false; - boundsDelta = mBounds.top - opBounds.top; - if (!checkSide(currentFlags, newFlags, OpClipSideFlags::Top, boundsDelta)) return false; - - // right and bottom delta calculation reversed to account for direction - boundsDelta = opBounds.right - mBounds.right; - if (!checkSide(currentFlags, newFlags, OpClipSideFlags::Right, boundsDelta)) - return false; - boundsDelta = opBounds.bottom - mBounds.bottom; - if (!checkSide(currentFlags, newFlags, OpClipSideFlags::Bottom, boundsDelta)) - return false; - } - - const SkPaint* newPaint = op->op->paint; - const SkPaint* oldPaint = mOps[0]->op->paint; - - if (newPaint == oldPaint) { - // if paints are equal, then modifiers + paint attribs don't need to be compared - return true; - } else if (newPaint && !oldPaint) { - return paintIsDefault(*newPaint); - } else if (!newPaint && oldPaint) { - return paintIsDefault(*oldPaint); - } - return paintsAreEquivalent(*newPaint, *oldPaint); - } - - void mergeOp(BakedOpState* op) { - mBounds.unionWith(op->computedState.clippedBounds); - mOps.push_back(op); - - // Because a new op must have passed canMergeWith(), we know it's passed the clipping compat - // check, and doesn't extend past a side of the clip that's in use by the merged batch. - // Therefore it's safe to simply always merge flags, and use the bounds as the clip rect. - mClipSideFlags |= op->computedState.clipSideFlags; - } - - int getClipSideFlags() const { return mClipSideFlags; } - const Rect& getClipRect() const { return mBounds; } - -private: - int mClipSideFlags; -}; - -LayerBuilder::LayerBuilder(uint32_t width, uint32_t height, const Rect& repaintRect, - const BeginLayerOp* beginLayerOp, RenderNode* renderNode) - : width(width) - , height(height) - , repaintRect(repaintRect) - , repaintClip(repaintRect) - , offscreenBuffer(renderNode ? renderNode->getLayer() : nullptr) - , beginLayerOp(beginLayerOp) - , renderNode(renderNode) {} - -// iterate back toward target to see if anything drawn since should overlap the new op -// if no target, merging ops still iterate to find similar batch to insert after -void LayerBuilder::locateInsertIndex(int batchId, const Rect& clippedBounds, - BatchBase** targetBatch, size_t* insertBatchIndex) const { - for (int i = mBatches.size() - 1; i >= 0; i--) { - BatchBase* overBatch = mBatches[i]; - - if (overBatch == *targetBatch) break; - - // TODO: also consider shader shared between batch types - if (batchId == overBatch->getBatchId()) { - *insertBatchIndex = i + 1; - if (!*targetBatch) break; // found insert position, quit - } - - if (overBatch->intersects(clippedBounds)) { - // NOTE: it may be possible to optimize for special cases where two operations - // of the same batch/paint could swap order, such as with a non-mergeable - // (clipped) and a mergeable text operation - *targetBatch = nullptr; - break; - } - } -} - -void LayerBuilder::deferLayerClear(const Rect& rect) { - mClearRects.push_back(rect); -} - -void LayerBuilder::onDeferOp(LinearAllocator& allocator, const BakedOpState* bakedState) { - if (bakedState->op->opId != RecordedOpId::CopyToLayerOp) { - // First non-CopyToLayer, so stop stashing up layer clears for unclipped save layers, - // and issue them together in one draw. - flushLayerClears(allocator); - - if (CC_UNLIKELY(activeUnclippedSaveLayers.empty() && - bakedState->computedState.opaqueOverClippedBounds && - bakedState->computedState.clippedBounds.contains(repaintRect) && - !Properties::debugOverdraw)) { - // discard all deferred drawing ops, since new one will occlude them - clear(); - } - } -} - -void LayerBuilder::flushLayerClears(LinearAllocator& allocator) { - if (CC_UNLIKELY(!mClearRects.empty())) { - const int vertCount = mClearRects.size() * 4; - // put the verts in the frame allocator, since - // 1) SimpleRectsOps needs verts, not rects - // 2) even if mClearRects stored verts, std::vectors will move their contents - Vertex* const verts = (Vertex*)allocator.create_trivial_array(vertCount); - - Vertex* currentVert = verts; - Rect bounds = mClearRects[0]; - for (auto&& rect : mClearRects) { - bounds.unionWith(rect); - Vertex::set(currentVert++, rect.left, rect.top); - Vertex::set(currentVert++, rect.right, rect.top); - Vertex::set(currentVert++, rect.left, rect.bottom); - Vertex::set(currentVert++, rect.right, rect.bottom); - } - mClearRects.clear(); // discard rects before drawing so this method isn't reentrant - - // One or more unclipped saveLayers have been enqueued, with deferred clears. - // Flush all of these clears with a single draw - SkPaint* paint = allocator.create(); - paint->setBlendMode(SkBlendMode::kClear); - SimpleRectsOp* op = allocator.create_trivial( - bounds, Matrix4::identity(), nullptr, paint, verts, vertCount); - BakedOpState* bakedState = - BakedOpState::directConstruct(allocator, &repaintClip, bounds, *op); - deferUnmergeableOp(allocator, bakedState, OpBatchType::Vertices); - } -} - -void LayerBuilder::deferUnmergeableOp(LinearAllocator& allocator, BakedOpState* op, - batchid_t batchId) { - onDeferOp(allocator, op); - OpBatch* targetBatch = mBatchLookup[batchId]; - - size_t insertBatchIndex = mBatches.size(); - if (targetBatch) { - locateInsertIndex(batchId, op->computedState.clippedBounds, (BatchBase**)(&targetBatch), - &insertBatchIndex); - } - - if (targetBatch) { - targetBatch->batchOp(op); - } else { - // new non-merging batch - targetBatch = allocator.create(batchId, op); - mBatchLookup[batchId] = targetBatch; - mBatches.insert(mBatches.begin() + insertBatchIndex, targetBatch); - } -} - -void LayerBuilder::deferMergeableOp(LinearAllocator& allocator, BakedOpState* op, batchid_t batchId, - mergeid_t mergeId) { - onDeferOp(allocator, op); - MergingOpBatch* targetBatch = nullptr; - - // Try to merge with any existing batch with same mergeId - auto getResult = mMergingBatchLookup[batchId].find(mergeId); - if (getResult != mMergingBatchLookup[batchId].end()) { - targetBatch = getResult->second; - if (!targetBatch->canMergeWith(op)) { - targetBatch = nullptr; - } - } - - size_t insertBatchIndex = mBatches.size(); - locateInsertIndex(batchId, op->computedState.clippedBounds, (BatchBase**)(&targetBatch), - &insertBatchIndex); - - if (targetBatch) { - targetBatch->mergeOp(op); - } else { - // new merging batch - targetBatch = allocator.create(batchId, op); - mMergingBatchLookup[batchId].insert(std::make_pair(mergeId, targetBatch)); - - mBatches.insert(mBatches.begin() + insertBatchIndex, targetBatch); - } -} - -void LayerBuilder::replayBakedOpsImpl(void* arg, BakedOpReceiver* unmergedReceivers, - MergedOpReceiver* mergedReceivers) const { - if (renderNode) { - ATRACE_FORMAT_BEGIN("Issue HW Layer DisplayList %s %ux%u", renderNode->getName(), width, - height); - } else { - ATRACE_BEGIN("flush drawing commands"); - } - - for (const BatchBase* batch : mBatches) { - size_t size = batch->getOps().size(); - if (size > 1 && batch->isMerging()) { - int opId = batch->getOps()[0]->op->opId; - const MergingOpBatch* mergingBatch = static_cast(batch); - MergedBakedOpList data = {batch->getOps().data(), size, - mergingBatch->getClipSideFlags(), - mergingBatch->getClipRect()}; - mergedReceivers[opId](arg, data); - } else { - for (const BakedOpState* op : batch->getOps()) { - unmergedReceivers[op->op->opId](arg, *op); - } - } - } - ATRACE_END(); -} - -void LayerBuilder::clear() { - mBatches.clear(); - for (int i = 0; i < OpBatchType::Count; i++) { - mBatchLookup[i] = nullptr; - mMergingBatchLookup[i].clear(); - } -} - -void LayerBuilder::dump() const { - ALOGD("LayerBuilder %p, %ux%u buffer %p, blo %p, rn %p (%s)", this, width, height, - offscreenBuffer, beginLayerOp, renderNode, renderNode ? renderNode->getName() : "-"); - for (const BatchBase* batch : mBatches) { - batch->dump(); - } -} - -} // namespace uirenderer -} // namespace android diff --git a/libs/hwui/LayerBuilder.h b/libs/hwui/LayerBuilder.h deleted file mode 100644 index c799d48f7821..000000000000 --- a/libs/hwui/LayerBuilder.h +++ /dev/null @@ -1,137 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include "ClipArea.h" -#include "Rect.h" -#include "utils/Macros.h" - -#include -#include - -struct SkRect; - -namespace android { -namespace uirenderer { - -class BakedOpState; -struct BeginLayerOp; -class BatchBase; -class LinearAllocator; -struct MergedBakedOpList; -class MergingOpBatch; -class OffscreenBuffer; -class OpBatch; -class RenderNode; - -typedef int batchid_t; -typedef const void* mergeid_t; - -namespace OpBatchType { -enum { - Bitmap, - MergedPatch, - AlphaVertices, - Vertices, - AlphaMaskTexture, - Text, - ColorText, - Shadow, - TextureLayer, - Functor, - CopyToLayer, - CopyFromLayer, - - Count // must be last -}; -} - -typedef void (*BakedOpReceiver)(void*, const BakedOpState&); -typedef void (*MergedOpReceiver)(void*, const MergedBakedOpList& opList); - -/** - * Stores the deferred render operations and state used to compute ordering - * for a single FBO/layer. - */ -class LayerBuilder { - // Prevent copy/assign because users may stash pointer to offscreenBuffer and viewportClip - PREVENT_COPY_AND_ASSIGN(LayerBuilder); - -public: - // Create LayerBuilder for Fbo0 - LayerBuilder(uint32_t width, uint32_t height, const Rect& repaintRect) - : LayerBuilder(width, height, repaintRect, nullptr, nullptr){}; - - // Create LayerBuilder for an offscreen layer, where beginLayerOp is present for a - // saveLayer, renderNode is present for a HW layer. - LayerBuilder(uint32_t width, uint32_t height, const Rect& repaintRect, - const BeginLayerOp* beginLayerOp, RenderNode* renderNode); - - // iterate back toward target to see if anything drawn since should overlap the new op - // if no target, merging ops still iterate to find similar batch to insert after - void locateInsertIndex(int batchId, const Rect& clippedBounds, BatchBase** targetBatch, - size_t* insertBatchIndex) const; - - void deferUnmergeableOp(LinearAllocator& allocator, BakedOpState* op, batchid_t batchId); - - // insertion point of a new batch, will hopefully be immediately after similar batch - // (generally, should be similar shader) - void deferMergeableOp(LinearAllocator& allocator, BakedOpState* op, batchid_t batchId, - mergeid_t mergeId); - - void replayBakedOpsImpl(void* arg, BakedOpReceiver* receivers, MergedOpReceiver*) const; - - void deferLayerClear(const Rect& dstRect); - - bool empty() const { return mBatches.empty(); } - - void clear(); - - void dump() const; - - const uint32_t width; - const uint32_t height; - const Rect repaintRect; - const ClipRect repaintClip; - OffscreenBuffer* offscreenBuffer; - const BeginLayerOp* beginLayerOp; - const RenderNode* renderNode; - - // list of deferred CopyFromLayer ops, to be deferred upon encountering EndUnclippedLayerOps - std::vector activeUnclippedSaveLayers; - -private: - void onDeferOp(LinearAllocator& allocator, const BakedOpState* bakedState); - void flushLayerClears(LinearAllocator& allocator); - - std::vector mBatches; - - /** - * Maps the mergeid_t returned by an op's getMergeId() to the most recently seen - * MergingDrawBatch of that id. These ids are unique per draw type and guaranteed to not - * collide, which avoids the need to resolve mergeid collisions. - */ - std::unordered_map mMergingBatchLookup[OpBatchType::Count]; - - // Maps batch ids to the most recent *non-merging* batch of that id - OpBatch* mBatchLookup[OpBatchType::Count] = {nullptr}; - - std::vector mClearRects; -}; - -}; // namespace uirenderer -}; // namespace android diff --git a/libs/hwui/ProfileRenderer.cpp b/libs/hwui/ProfileRenderer.cpp deleted file mode 100644 index 8a00ffa54c58..000000000000 --- a/libs/hwui/ProfileRenderer.cpp +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "ProfileRenderer.h" - -namespace android { -namespace uirenderer { - -void ProfileRenderer::drawRect(float left, float top, float right, float bottom, - const SkPaint& paint) { - mRenderer.drawRect(left, top, right, bottom, &paint); -} - -void ProfileRenderer::drawRects(const float* rects, int count, const SkPaint& paint) { - mRenderer.drawRects(rects, count, &paint); -} - -uint32_t ProfileRenderer::getViewportWidth() { - return mRenderer.getViewportWidth(); -} - -uint32_t ProfileRenderer::getViewportHeight() { - return mRenderer.getViewportHeight(); -} - -} /* namespace uirenderer */ -} /* namespace android */ diff --git a/libs/hwui/ProfileRenderer.h b/libs/hwui/ProfileRenderer.h deleted file mode 100644 index 5c8bb2529fb4..000000000000 --- a/libs/hwui/ProfileRenderer.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "IProfileRenderer.h" - -#include "BakedOpRenderer.h" - -namespace android { -namespace uirenderer { - -class ProfileRenderer : public IProfileRenderer { -public: - ProfileRenderer(BakedOpRenderer& renderer) : mRenderer(renderer) {} - - void drawRect(float left, float top, float right, float bottom, const SkPaint& paint) override; - void drawRects(const float* rects, int count, const SkPaint& paint) override; - uint32_t getViewportWidth() override; - uint32_t getViewportHeight() override; - - virtual ~ProfileRenderer() {} - -private: - BakedOpRenderer& mRenderer; -}; - -} /* namespace uirenderer */ -} /* namespace android */ diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp index e9039001bd53..83fa84eb131e 100644 --- a/libs/hwui/RenderNode.cpp +++ b/libs/hwui/RenderNode.cpp @@ -16,7 +16,6 @@ #include "RenderNode.h" -#include "BakedOpRenderer.h" #include "DamageAccumulator.h" #include "Debug.h" #include "RecordedOp.h" diff --git a/libs/hwui/pipeline/skia/SkiaProfileRenderer.h b/libs/hwui/pipeline/skia/SkiaProfileRenderer.h index 5ae7d6b0b607..daa4c1839693 100644 --- a/libs/hwui/pipeline/skia/SkiaProfileRenderer.h +++ b/libs/hwui/pipeline/skia/SkiaProfileRenderer.h @@ -16,7 +16,7 @@ #include "IProfileRenderer.h" -#include "BakedOpRenderer.h" +#include "SkCanvas.h" namespace android { namespace uirenderer { diff --git a/libs/hwui/renderstate/Blend.cpp b/libs/hwui/renderstate/Blend.cpp deleted file mode 100644 index 08e18e0f0d0c..000000000000 --- a/libs/hwui/renderstate/Blend.cpp +++ /dev/null @@ -1,138 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#include -#include "Program.h" - -namespace android { -namespace uirenderer { - -/** - * Structure mapping Skia xfermodes to OpenGL blending factors. - */ -struct Blender { - SkBlendMode mode; - GLenum src; - GLenum dst; -}; - -// assumptions made by lookup tables in either this file or ProgramCache -static_assert(0 == static_cast(SkBlendMode::kClear), "SkBlendMode enums have changed"); -static_assert(1 == static_cast(SkBlendMode::kSrc), "SkBlendMode enums have changed"); -static_assert(2 == static_cast(SkBlendMode::kDst), "SkBlendMode enums have changed"); -static_assert(3 == static_cast(SkBlendMode::kSrcOver), "SkBlendMode enums have changed"); -static_assert(4 == static_cast(SkBlendMode::kDstOver), "SkBlendMode enums have changed"); -static_assert(5 == static_cast(SkBlendMode::kSrcIn), "SkBlendMode enums have changed"); -static_assert(6 == static_cast(SkBlendMode::kDstIn), "SkBlendMode enums have changed"); -static_assert(7 == static_cast(SkBlendMode::kSrcOut), "SkBlendMode enums have changed"); -static_assert(8 == static_cast(SkBlendMode::kDstOut), "SkBlendMode enums have changed"); -static_assert(9 == static_cast(SkBlendMode::kSrcATop), "SkBlendMode enums have changed"); -static_assert(10 == static_cast(SkBlendMode::kDstATop), "SkBlendMode enums have changed"); -static_assert(11 == static_cast(SkBlendMode::kXor), "SkBlendMode enums have changed"); -static_assert(12 == static_cast(SkBlendMode::kPlus), "SkBlendMode enums have changed"); -static_assert(13 == static_cast(SkBlendMode::kModulate), "SkBlendMode enums have changed"); -static_assert(14 == static_cast(SkBlendMode::kScreen), "SkBlendMode enums have changed"); -static_assert(15 == static_cast(SkBlendMode::kOverlay), "SkBlendMode enums have changed"); -static_assert(16 == static_cast(SkBlendMode::kDarken), "SkBlendMode enums have changed"); -static_assert(17 == static_cast(SkBlendMode::kLighten), "SkBlendMode enums have changed"); - -// In this array, the index of each Blender equals the value of the first -// entry. For instance, gBlends[1] == gBlends[SkBlendMode::kSrc] -const Blender kBlends[] = {{SkBlendMode::kClear, GL_ZERO, GL_ONE_MINUS_SRC_ALPHA}, - {SkBlendMode::kSrc, GL_ONE, GL_ZERO}, - {SkBlendMode::kDst, GL_ZERO, GL_ONE}, - {SkBlendMode::kSrcOver, GL_ONE, GL_ONE_MINUS_SRC_ALPHA}, - {SkBlendMode::kDstOver, GL_ONE_MINUS_DST_ALPHA, GL_ONE}, - {SkBlendMode::kSrcIn, GL_DST_ALPHA, GL_ZERO}, - {SkBlendMode::kDstIn, GL_ZERO, GL_SRC_ALPHA}, - {SkBlendMode::kSrcOut, GL_ONE_MINUS_DST_ALPHA, GL_ZERO}, - {SkBlendMode::kDstOut, GL_ZERO, GL_ONE_MINUS_SRC_ALPHA}, - {SkBlendMode::kSrcATop, GL_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA}, - {SkBlendMode::kDstATop, GL_ONE_MINUS_DST_ALPHA, GL_SRC_ALPHA}, - {SkBlendMode::kXor, GL_ONE_MINUS_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA}, - {SkBlendMode::kPlus, GL_ONE, GL_ONE}, - {SkBlendMode::kModulate, GL_ZERO, GL_SRC_COLOR}, - {SkBlendMode::kScreen, GL_ONE, GL_ONE_MINUS_SRC_COLOR}}; - -// This array contains the swapped version of each SkBlendMode. For instance -// this array's SrcOver blending mode is actually DstOver. You can refer to -// createLayer() for more information on the purpose of this array. -const Blender kBlendsSwap[] = {{SkBlendMode::kClear, GL_ONE_MINUS_DST_ALPHA, GL_ZERO}, - {SkBlendMode::kSrc, GL_ZERO, GL_ONE}, - {SkBlendMode::kDst, GL_ONE, GL_ZERO}, - {SkBlendMode::kSrcOver, GL_ONE_MINUS_DST_ALPHA, GL_ONE}, - {SkBlendMode::kDstOver, GL_ONE, GL_ONE_MINUS_SRC_ALPHA}, - {SkBlendMode::kSrcIn, GL_ZERO, GL_SRC_ALPHA}, - {SkBlendMode::kDstIn, GL_DST_ALPHA, GL_ZERO}, - {SkBlendMode::kSrcOut, GL_ZERO, GL_ONE_MINUS_SRC_ALPHA}, - {SkBlendMode::kDstOut, GL_ONE_MINUS_DST_ALPHA, GL_ZERO}, - {SkBlendMode::kSrcATop, GL_ONE_MINUS_DST_ALPHA, GL_SRC_ALPHA}, - {SkBlendMode::kDstATop, GL_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA}, - {SkBlendMode::kXor, GL_ONE_MINUS_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA}, - {SkBlendMode::kPlus, GL_ONE, GL_ONE}, - {SkBlendMode::kModulate, GL_DST_COLOR, GL_ZERO}, - {SkBlendMode::kScreen, GL_ONE_MINUS_DST_COLOR, GL_ONE}}; - -Blend::Blend() : mEnabled(false), mSrcMode(GL_ZERO), mDstMode(GL_ZERO) { - // gl blending off by default -} - -void Blend::invalidate() { - syncEnabled(); - mSrcMode = mDstMode = GL_ZERO; -} - -void Blend::syncEnabled() { - if (mEnabled) { - glEnable(GL_BLEND); - } else { - glDisable(GL_BLEND); - } -} - -void Blend::getFactors(SkBlendMode mode, ModeOrderSwap modeUsage, GLenum* outSrc, GLenum* outDst) { - int index = static_cast(mode); - *outSrc = (modeUsage == ModeOrderSwap::Swap) ? kBlendsSwap[index].src : kBlends[index].src; - *outDst = (modeUsage == ModeOrderSwap::Swap) ? kBlendsSwap[index].dst : kBlends[index].dst; -} - -void Blend::setFactors(GLenum srcMode, GLenum dstMode) { - if ((srcMode == GL_ZERO || srcMode == GL_ONE) && dstMode == GL_ZERO) { - // disable blending - if (mEnabled) { - glDisable(GL_BLEND); - mEnabled = false; - } - } else { - // enable blending - if (!mEnabled) { - glEnable(GL_BLEND); - mEnabled = true; - } - - if (srcMode != mSrcMode || dstMode != mDstMode) { - glBlendFunc(srcMode, dstMode); - mSrcMode = srcMode; - mDstMode = dstMode; - } - } -} - -void Blend::dump() { - ALOGD("Blend: enabled %d, func src %d, dst %d", mEnabled, mSrcMode, mDstMode); -} - -} /* namespace uirenderer */ -} /* namespace android */ diff --git a/libs/hwui/renderstate/Blend.h b/libs/hwui/renderstate/Blend.h deleted file mode 100644 index 7e559bace3f2..000000000000 --- a/libs/hwui/renderstate/Blend.h +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#ifndef RENDERSTATE_BLEND_H -#define RENDERSTATE_BLEND_H - -#include "Vertex.h" - -#include -#include -#include -#include - -namespace android { -namespace uirenderer { - -class Blend { - friend class RenderState; - -public: - // dictates whether to swap src/dst - enum class ModeOrderSwap { - NoSwap, - Swap, - }; - void syncEnabled(); - - static void getFactors(SkBlendMode mode, ModeOrderSwap modeUsage, GLenum* outSrc, - GLenum* outDst); - void setFactors(GLenum src, GLenum dst); - - bool getEnabled() { return mEnabled; } - void getFactors(GLenum* src, GLenum* dst) { - *src = mSrcMode; - *dst = mDstMode; - } - - void dump(); - -private: - Blend(); - void invalidate(); - bool mEnabled; - GLenum mSrcMode; - GLenum mDstMode; -}; - -} /* namespace uirenderer */ -} /* namespace android */ - -#endif // RENDERSTATE_BLEND_H diff --git a/libs/hwui/renderstate/MeshState.cpp b/libs/hwui/renderstate/MeshState.cpp deleted file mode 100644 index 4f6c49e67b99..000000000000 --- a/libs/hwui/renderstate/MeshState.cpp +++ /dev/null @@ -1,179 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#include "renderstate/MeshState.h" - -#include "Program.h" - -namespace android { -namespace uirenderer { - -MeshState::MeshState() - : mCurrentIndicesBuffer(0) - , mCurrentPixelBuffer(0) - , mCurrentPositionPointer(this) - , mCurrentPositionStride(0) - , mCurrentTexCoordsPointer(this) - , mCurrentTexCoordsStride(0) - , mTexCoordsArrayEnabled(false) - , mQuadListIndices(0) { - glGenBuffers(1, &mUnitQuadBuffer); - glBindBuffer(GL_ARRAY_BUFFER, mUnitQuadBuffer); - glBufferData(GL_ARRAY_BUFFER, sizeof(kUnitQuadVertices), kUnitQuadVertices, GL_STATIC_DRAW); - mCurrentBuffer = mUnitQuadBuffer; - - uint16_t regionIndices[kMaxNumberOfQuads * 6]; - for (uint32_t i = 0; i < kMaxNumberOfQuads; i++) { - uint16_t quad = i * 4; - int index = i * 6; - regionIndices[index] = quad; // top-left - regionIndices[index + 1] = quad + 1; // top-right - regionIndices[index + 2] = quad + 2; // bottom-left - regionIndices[index + 3] = quad + 2; // bottom-left - regionIndices[index + 4] = quad + 1; // top-right - regionIndices[index + 5] = quad + 3; // bottom-right - } - glGenBuffers(1, &mQuadListIndices); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mQuadListIndices); - glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(regionIndices), regionIndices, GL_STATIC_DRAW); - mCurrentIndicesBuffer = mQuadListIndices; - - // position attribute always enabled - glEnableVertexAttribArray(Program::kBindingPosition); -} - -MeshState::~MeshState() { - glDeleteBuffers(1, &mUnitQuadBuffer); - mCurrentBuffer = 0; - - glDeleteBuffers(1, &mQuadListIndices); - mQuadListIndices = 0; -} - -void MeshState::dump() { - ALOGD("MeshState VBOs: unitQuad %d, current %d", mUnitQuadBuffer, mCurrentBuffer); - ALOGD("MeshState IBOs: quadList %d, current %d", mQuadListIndices, mCurrentIndicesBuffer); - ALOGD("MeshState vertices: vertex data %p, stride %d", mCurrentPositionPointer, - mCurrentPositionStride); - ALOGD("MeshState texCoord: data %p, stride %d", mCurrentTexCoordsPointer, - mCurrentTexCoordsStride); -} - -/////////////////////////////////////////////////////////////////////////////// -// Buffer Objects -/////////////////////////////////////////////////////////////////////////////// - -void MeshState::bindMeshBuffer(GLuint buffer) { - if (mCurrentBuffer != buffer) { - glBindBuffer(GL_ARRAY_BUFFER, buffer); - mCurrentBuffer = buffer; - - // buffer has changed, so invalidate cached vertex pos/texcoord pointers - resetVertexPointers(); - } -} - -void MeshState::unbindMeshBuffer() { - return bindMeshBuffer(0); -} - -void MeshState::genOrUpdateMeshBuffer(GLuint* buffer, GLsizeiptr size, const void* data, - GLenum usage) { - if (!*buffer) { - glGenBuffers(1, buffer); - } - bindMeshBuffer(*buffer); - glBufferData(GL_ARRAY_BUFFER, size, data, usage); -} - -void MeshState::updateMeshBufferSubData(GLuint buffer, GLintptr offset, GLsizeiptr size, - const void* data) { - bindMeshBuffer(buffer); - glBufferSubData(GL_ARRAY_BUFFER, offset, size, data); -} - -void MeshState::deleteMeshBuffer(GLuint buffer) { - if (buffer == mCurrentBuffer) { - // GL defines that deleting the currently bound VBO rebinds to 0 (no VBO). - // Reflect this in our cached value. - mCurrentBuffer = 0; - } - glDeleteBuffers(1, &buffer); -} - -/////////////////////////////////////////////////////////////////////////////// -// Vertices -/////////////////////////////////////////////////////////////////////////////// - -void MeshState::bindPositionVertexPointer(const GLvoid* vertices, GLsizei stride) { - // update pos coords if !current vbo, since vertices may point into mutable memory (e.g. stack) - if (mCurrentBuffer == 0 || vertices != mCurrentPositionPointer || - stride != mCurrentPositionStride) { - glVertexAttribPointer(Program::kBindingPosition, 2, GL_FLOAT, GL_FALSE, stride, vertices); - mCurrentPositionPointer = vertices; - mCurrentPositionStride = stride; - } -} - -void MeshState::bindTexCoordsVertexPointer(const GLvoid* vertices, GLsizei stride) { - // update tex coords if !current vbo, since vertices may point into mutable memory (e.g. stack) - if (mCurrentBuffer == 0 || vertices != mCurrentTexCoordsPointer || - stride != mCurrentTexCoordsStride) { - glVertexAttribPointer(Program::kBindingTexCoords, 2, GL_FLOAT, GL_FALSE, stride, vertices); - mCurrentTexCoordsPointer = vertices; - mCurrentTexCoordsStride = stride; - } -} - -void MeshState::resetVertexPointers() { - mCurrentPositionPointer = this; - mCurrentTexCoordsPointer = this; -} - -void MeshState::enableTexCoordsVertexArray() { - if (!mTexCoordsArrayEnabled) { - glEnableVertexAttribArray(Program::kBindingTexCoords); - mCurrentTexCoordsPointer = this; - mTexCoordsArrayEnabled = true; - } -} - -void MeshState::disableTexCoordsVertexArray() { - if (mTexCoordsArrayEnabled) { - glDisableVertexAttribArray(Program::kBindingTexCoords); - mTexCoordsArrayEnabled = false; - } -} - -/////////////////////////////////////////////////////////////////////////////// -// Indices -/////////////////////////////////////////////////////////////////////////////// - -void MeshState::bindIndicesBuffer(const GLuint buffer) { - if (mCurrentIndicesBuffer != buffer) { - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer); - mCurrentIndicesBuffer = buffer; - } -} - -void MeshState::unbindIndicesBuffer() { - if (mCurrentIndicesBuffer) { - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); - mCurrentIndicesBuffer = 0; - } -} - -} /* namespace uirenderer */ -} /* namespace android */ diff --git a/libs/hwui/renderstate/MeshState.h b/libs/hwui/renderstate/MeshState.h deleted file mode 100644 index 95faf1ebfb02..000000000000 --- a/libs/hwui/renderstate/MeshState.h +++ /dev/null @@ -1,133 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#ifndef RENDERSTATE_MESHSTATE_H -#define RENDERSTATE_MESHSTATE_H - -#include "Vertex.h" - -#include -#include -#include - -namespace android { -namespace uirenderer { - -class Program; - -// Maximum number of quads that pre-allocated meshes can draw -const uint32_t kMaxNumberOfQuads = 2048; - -// This array is never used directly but used as a memcpy source in the -// OpenGLRenderer constructor -const TextureVertex kUnitQuadVertices[] = { - {0, 0, 0, 0}, {1, 0, 1, 0}, {0, 1, 0, 1}, {1, 1, 1, 1}, -}; - -const GLsizei kVertexStride = sizeof(Vertex); -const GLsizei kAlphaVertexStride = sizeof(AlphaVertex); -const GLsizei kTextureVertexStride = sizeof(TextureVertex); -const GLsizei kColorTextureVertexStride = sizeof(ColorTextureVertex); - -const GLsizei kMeshTextureOffset = 2 * sizeof(float); -const GLsizei kVertexAlphaOffset = 2 * sizeof(float); -const GLsizei kVertexAAWidthOffset = 2 * sizeof(float); -const GLsizei kVertexAALengthOffset = 3 * sizeof(float); -const GLsizei kUnitQuadCount = 4; - -class MeshState { -private: - friend class RenderState; - -public: - ~MeshState(); - void dump(); - /////////////////////////////////////////////////////////////////////////////// - // Buffer objects - /////////////////////////////////////////////////////////////////////////////// - - /** - * Binds the specified VBO if needed. If buffer == 0, binds default simple textured quad. - */ - void bindMeshBuffer(GLuint buffer); - - /** - * Unbinds the current VBO if active. - */ - void unbindMeshBuffer(); - - void genOrUpdateMeshBuffer(GLuint* buffer, GLsizeiptr size, const void* data, GLenum usage); - void updateMeshBufferSubData(GLuint buffer, GLintptr offset, GLsizeiptr size, const void* data); - void deleteMeshBuffer(GLuint); - - /////////////////////////////////////////////////////////////////////////////// - // Vertices - /////////////////////////////////////////////////////////////////////////////// - /** - * Binds an attrib to the specified float vertex pointer. - * Assumes a stride of gTextureVertexStride and a size of 2. - */ - void bindPositionVertexPointer(const GLvoid* vertices, GLsizei stride = kTextureVertexStride); - - /** - * Binds an attrib to the specified float vertex pointer. - * Assumes a stride of gTextureVertexStride and a size of 2. - */ - void bindTexCoordsVertexPointer(const GLvoid* vertices, GLsizei stride = kTextureVertexStride); - - /** - * Resets the vertex pointers. - */ - void resetVertexPointers(); - - void enableTexCoordsVertexArray(); - void disableTexCoordsVertexArray(); - - /////////////////////////////////////////////////////////////////////////////// - // Indices - /////////////////////////////////////////////////////////////////////////////// - void bindIndicesBuffer(const GLuint buffer); - void unbindIndicesBuffer(); - - /////////////////////////////////////////////////////////////////////////////// - // Getters - for use in Glop building - /////////////////////////////////////////////////////////////////////////////// - GLuint getUnitQuadVBO() { return mUnitQuadBuffer; } - GLuint getQuadListIBO() { return mQuadListIndices; } - -private: - MeshState(); - - GLuint mUnitQuadBuffer; - - GLuint mCurrentBuffer; - GLuint mCurrentIndicesBuffer; - GLuint mCurrentPixelBuffer; - - const void* mCurrentPositionPointer; - GLsizei mCurrentPositionStride; - const void* mCurrentTexCoordsPointer; - GLsizei mCurrentTexCoordsStride; - - bool mTexCoordsArrayEnabled; - - // Global index buffer - GLuint mQuadListIndices; -}; - -} /* namespace uirenderer */ -} /* namespace android */ - -#endif // RENDERSTATE_MESHSTATE_H diff --git a/libs/hwui/renderstate/OffscreenBufferPool.cpp b/libs/hwui/renderstate/OffscreenBufferPool.cpp index a0f5cb9d4e09..e148ebdf1dd7 100644 --- a/libs/hwui/renderstate/OffscreenBufferPool.cpp +++ b/libs/hwui/renderstate/OffscreenBufferPool.cpp @@ -67,37 +67,7 @@ void OffscreenBuffer::dirty(Rect dirtyArea) { } void OffscreenBuffer::updateMeshFromRegion() { - // avoid T-junctions as they cause artifacts in between the resultant - // geometry when complex transforms occur. - // TODO: generate the safeRegion only if necessary based on drawing transform - Region safeRegion = Region::createTJunctionFreeRegion(region); - - size_t count; - const android::Rect* rects = safeRegion.getArray(&count); - - const float texX = 1.0f / float(texture.width()); - const float texY = 1.0f / float(texture.height()); - - FatVector meshVector(count * - 4); // uses heap if more than 64 vertices needed - TextureVertex* mesh = &meshVector[0]; - for (size_t i = 0; i < count; i++) { - const android::Rect* r = &rects[i]; - - const float u1 = r->left * texX; - const float v1 = (viewportHeight - r->top) * texY; - const float u2 = r->right * texX; - const float v2 = (viewportHeight - r->bottom) * texY; - - TextureVertex::set(mesh++, r->left, r->top, u1, v1); - TextureVertex::set(mesh++, r->right, r->top, u2, v1); - TextureVertex::set(mesh++, r->left, r->bottom, u1, v2); - TextureVertex::set(mesh++, r->right, r->bottom, u2, v2); - } - elementCount = count * 6; - renderState.meshState().genOrUpdateMeshBuffer( - &vbo, sizeof(TextureVertex) * count * 4, &meshVector[0], - GL_DYNAMIC_DRAW); // TODO: GL_STATIC_DRAW if savelayer + // DEAD CODE } uint32_t OffscreenBuffer::computeIdealDimension(uint32_t dimension) { @@ -105,11 +75,7 @@ uint32_t OffscreenBuffer::computeIdealDimension(uint32_t dimension) { } OffscreenBuffer::~OffscreenBuffer() { - ATRACE_FORMAT("Destroy %ux%u HW Layer", texture.width(), texture.height()); - texture.deleteTexture(); - renderState.meshState().deleteMeshBuffer(vbo); - elementCount = 0; - vbo = 0; + // DEAD CODE } /////////////////////////////////////////////////////////////////////////////// diff --git a/libs/hwui/renderstate/RenderState.cpp b/libs/hwui/renderstate/RenderState.cpp index a60e2b5c815e..a1c8dca35bfb 100644 --- a/libs/hwui/renderstate/RenderState.cpp +++ b/libs/hwui/renderstate/RenderState.cpp @@ -37,20 +37,11 @@ RenderState::RenderState(renderthread::RenderThread& thread) } RenderState::~RenderState() { - LOG_ALWAYS_FATAL_IF(mBlend || mMeshState || mScissor || mStencil, - "State object lifecycle not managed correctly"); } void RenderState::onGLContextCreated() { - LOG_ALWAYS_FATAL_IF(mBlend || mMeshState || mScissor || mStencil, - "State object lifecycle not managed correctly"); GpuMemoryTracker::onGpuContextCreated(); - mBlend = new Blend(); - mMeshState = new MeshState(); - mScissor = new Scissor(); - mStencil = new Stencil(); - // Deferred because creation needs GL context for texture limits if (!mLayerPool) { mLayerPool = new OffscreenBufferPool(); @@ -77,22 +68,11 @@ void RenderState::onGLContextDestroyed() { mCaches->terminate(); - delete mBlend; - mBlend = nullptr; - delete mMeshState; - mMeshState = nullptr; - delete mScissor; - mScissor = nullptr; - delete mStencil; - mStencil = nullptr; - destroyLayersInUpdater(); GpuMemoryTracker::onGpuContextDestroyed(); } void RenderState::onVkContextCreated() { - LOG_ALWAYS_FATAL_IF(mBlend || mMeshState || mScissor || mStencil, - "State object lifecycle not managed correctly"); GpuMemoryTracker::onGpuContextCreated(); } @@ -177,10 +157,6 @@ void RenderState::invokeFunctor(Functor* functor, DrawGlInfo::Mode mode, DrawGlI void RenderState::interruptForFunctorInvoke() { mCaches->setProgram(nullptr); mCaches->textureState().resetActiveTexture(); - meshState().unbindMeshBuffer(); - meshState().unbindIndicesBuffer(); - meshState().resetVertexPointers(); - meshState().disableTexCoordsVertexArray(); debugOverdraw(false, false); // TODO: We need a way to know whether the functor is sRGB aware (b/32072673) if (mCaches->extensions().hasLinearBlending() && mCaches->extensions().hasSRGBWriteControl()) { @@ -199,25 +175,12 @@ void RenderState::resumeFromFunctorInvoke() { glClearColor(0.0f, 0.0f, 0.0f, 0.0f); - scissor().invalidate(); - blend().invalidate(); - mCaches->textureState().activateTexture(0); mCaches->textureState().resetBoundTextures(); } void RenderState::debugOverdraw(bool enable, bool clear) { - if (Properties::debugOverdraw && mFramebuffer == 0) { - if (clear) { - scissor().setEnabled(false); - stencil().clear(); - } - if (enable) { - stencil().enableDebugWrite(); - } else { - stencil().disable(); - } - } + // DEAD CODE } static void destroyLayerInUpdater(DeferredLayerUpdater* layerUpdater) { @@ -242,9 +205,6 @@ void RenderState::postDecStrong(VirtualLightRefBase* object) { void RenderState::render(const Glop& glop, const Matrix4& orthoMatrix, bool overrideDisableBlending) { - const Glop::Mesh& mesh = glop.mesh; - const Glop::Mesh::Vertices& vertices = mesh.vertices; - const Glop::Mesh::Indices& indices = mesh.indices; const Glop::Fill& fill = glop.fill; GL_CHECKPOINT(MODERATE); @@ -297,16 +257,6 @@ void RenderState::render(const Glop& glop, const Matrix4& orthoMatrix, GL_CHECKPOINT(MODERATE); - // -------------------------------- - // ---------- Mesh setup ---------- - // -------------------------------- - // vertices - meshState().bindMeshBuffer(vertices.bufferObject); - meshState().bindPositionVertexPointer(vertices.position, vertices.stride); - - // indices - meshState().bindIndicesBuffer(indices.bufferObject); - // texture if (fill.texture.texture != nullptr) { const Glop::Fill::TextureData& texture = fill.texture; @@ -327,28 +277,6 @@ void RenderState::render(const Glop& glop, const Matrix4& orthoMatrix, } } - // vertex attributes (tex coord, color, alpha) - if (vertices.attribFlags & VertexAttribFlags::TextureCoord) { - meshState().enableTexCoordsVertexArray(); - meshState().bindTexCoordsVertexPointer(vertices.texCoord, vertices.stride); - } else { - meshState().disableTexCoordsVertexArray(); - } - int colorLocation = -1; - if (vertices.attribFlags & VertexAttribFlags::Color) { - colorLocation = fill.program->getAttrib("colors"); - glEnableVertexAttribArray(colorLocation); - glVertexAttribPointer(colorLocation, 4, GL_FLOAT, GL_FALSE, vertices.stride, - vertices.color); - } - int alphaLocation = -1; - if (vertices.attribFlags & VertexAttribFlags::Alpha) { - // NOTE: alpha vertex position is computed assuming no VBO - const void* alphaCoords = ((const GLbyte*)vertices.position) + kVertexAlphaOffset; - alphaLocation = fill.program->getAttrib("vtxAlpha"); - glEnableVertexAttribArray(alphaLocation); - glVertexAttribPointer(alphaLocation, 1, GL_FLOAT, GL_FALSE, vertices.stride, alphaCoords); - } // Shader uniforms SkiaShader::apply(*mCaches, fill.skiaShaderData, mViewportWidth, mViewportHeight); @@ -392,77 +320,11 @@ void RenderState::render(const Glop& glop, const Matrix4& orthoMatrix, } } - // ------------------------------------ - // ---------- GL state setup ---------- - // ------------------------------------ - if (CC_UNLIKELY(overrideDisableBlending)) { - blend().setFactors(GL_ZERO, GL_ZERO); - } else { - blend().setFactors(glop.blend.src, glop.blend.dst); - } - - GL_CHECKPOINT(MODERATE); - - // ------------------------------------ - // ---------- Actual drawing ---------- - // ------------------------------------ - if (indices.bufferObject == meshState().getQuadListIBO()) { - // Since the indexed quad list is of limited length, we loop over - // the glDrawXXX method while updating the vertex pointer - GLsizei elementsCount = mesh.elementCount; - const GLbyte* vertexData = static_cast(vertices.position); - while (elementsCount > 0) { - GLsizei drawCount = std::min(elementsCount, (GLsizei)kMaxNumberOfQuads * 6); - GLsizei vertexCount = (drawCount / 6) * 4; - meshState().bindPositionVertexPointer(vertexData, vertices.stride); - if (vertices.attribFlags & VertexAttribFlags::TextureCoord) { - meshState().bindTexCoordsVertexPointer(vertexData + kMeshTextureOffset, - vertices.stride); - } - - if (mCaches->extensions().getMajorGlVersion() >= 3) { - glDrawRangeElements(mesh.primitiveMode, 0, vertexCount - 1, drawCount, - GL_UNSIGNED_SHORT, nullptr); - } else { - glDrawElements(mesh.primitiveMode, drawCount, GL_UNSIGNED_SHORT, nullptr); - } - elementsCount -= drawCount; - vertexData += vertexCount * vertices.stride; - } - } else if (indices.bufferObject || indices.indices) { - if (mCaches->extensions().getMajorGlVersion() >= 3) { - // use glDrawRangeElements to reduce CPU overhead (otherwise the driver has to determine - // the min/max index values) - glDrawRangeElements(mesh.primitiveMode, 0, mesh.vertexCount - 1, mesh.elementCount, - GL_UNSIGNED_SHORT, indices.indices); - } else { - glDrawElements(mesh.primitiveMode, mesh.elementCount, GL_UNSIGNED_SHORT, - indices.indices); - } - } else { - glDrawArrays(mesh.primitiveMode, 0, mesh.elementCount); - } - - GL_CHECKPOINT(MODERATE); - - // ----------------------------------- - // ---------- Mesh teardown ---------- - // ----------------------------------- - if (vertices.attribFlags & VertexAttribFlags::Alpha) { - glDisableVertexAttribArray(alphaLocation); - } - if (vertices.attribFlags & VertexAttribFlags::Color) { - glDisableVertexAttribArray(colorLocation); - } - GL_CHECKPOINT(MODERATE); } void RenderState::dump() { - blend().dump(); - meshState().dump(); - scissor().dump(); - stencil().dump(); + // DEAD CODE } } /* namespace uirenderer */ diff --git a/libs/hwui/renderstate/RenderState.h b/libs/hwui/renderstate/RenderState.h index e033cf2c5046..189ddc174902 100644 --- a/libs/hwui/renderstate/RenderState.h +++ b/libs/hwui/renderstate/RenderState.h @@ -18,12 +18,8 @@ #include "Caches.h" #include "Glop.h" -#include "renderstate/Blend.h" -#include "renderstate/MeshState.h" #include "renderstate/OffscreenBufferPool.h" #include "renderstate/PixelBufferState.h" -#include "renderstate/Scissor.h" -#include "renderstate/Stencil.h" #include "utils/Macros.h" #include @@ -105,11 +101,6 @@ public: void render(const Glop& glop, const Matrix4& orthoMatrix, bool overrideDisableBlending); - Blend& blend() { return *mBlend; } - MeshState& meshState() { return *mMeshState; } - Scissor& scissor() { return *mScissor; } - Stencil& stencil() { return *mStencil; } - OffscreenBufferPool& layerPool() { return *mLayerPool; } GrContext* getGrContext() const; @@ -127,11 +118,6 @@ private: renderthread::RenderThread& mRenderThread; Caches* mCaches = nullptr; - Blend* mBlend = nullptr; - MeshState* mMeshState = nullptr; - Scissor* mScissor = nullptr; - Stencil* mStencil = nullptr; - OffscreenBufferPool* mLayerPool = nullptr; std::set mActiveLayers; diff --git a/libs/hwui/renderstate/Scissor.cpp b/libs/hwui/renderstate/Scissor.cpp deleted file mode 100644 index e37ed029542b..000000000000 --- a/libs/hwui/renderstate/Scissor.cpp +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#include "renderstate/Scissor.h" - -#include "Rect.h" - -#include - -namespace android { -namespace uirenderer { - -Scissor::Scissor() - : mEnabled(false), mScissorX(0), mScissorY(0), mScissorWidth(0), mScissorHeight(0) {} - -bool Scissor::setEnabled(bool enabled) { - if (mEnabled != enabled) { - if (enabled) { - glEnable(GL_SCISSOR_TEST); - } else { - glDisable(GL_SCISSOR_TEST); - } - mEnabled = enabled; - return true; - } - return false; -} - -bool Scissor::set(GLint x, GLint y, GLint width, GLint height) { - if (mEnabled && - (x != mScissorX || y != mScissorY || width != mScissorWidth || height != mScissorHeight)) { - if (x < 0) { - width += x; - x = 0; - } - if (y < 0) { - height += y; - y = 0; - } - if (width < 0) { - width = 0; - } - if (height < 0) { - height = 0; - } - glScissor(x, y, width, height); - - mScissorX = x; - mScissorY = y; - mScissorWidth = width; - mScissorHeight = height; - - return true; - } - return false; -} - -void Scissor::set(int viewportHeight, const Rect& clip) { - // transform to Y-flipped GL space, and prevent negatives - GLint x = std::max(0, (int)clip.left); - GLint y = std::max(0, viewportHeight - (int)clip.bottom); - GLint width = std::max(0, ((int)clip.right) - x); - GLint height = std::max(0, (viewportHeight - (int)clip.top) - y); - - if (x != mScissorX || y != mScissorY || width != mScissorWidth || height != mScissorHeight) { - glScissor(x, y, width, height); - - mScissorX = x; - mScissorY = y; - mScissorWidth = width; - mScissorHeight = height; - } -} - -void Scissor::reset() { - mScissorX = mScissorY = mScissorWidth = mScissorHeight = 0; -} - -void Scissor::invalidate() { - mEnabled = glIsEnabled(GL_SCISSOR_TEST); - setEnabled(true); - reset(); -} - -void Scissor::dump() { - ALOGD("Scissor: enabled %d, %d %d %d %d", mEnabled, mScissorX, mScissorY, mScissorWidth, - mScissorHeight); -} - -} /* namespace uirenderer */ -} /* namespace android */ diff --git a/libs/hwui/renderstate/Scissor.h b/libs/hwui/renderstate/Scissor.h deleted file mode 100644 index 2b04f4e1384a..000000000000 --- a/libs/hwui/renderstate/Scissor.h +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#ifndef RENDERSTATE_SCISSOR_H -#define RENDERSTATE_SCISSOR_H - -#include -#include - -namespace android { -namespace uirenderer { - -class Rect; - -class Scissor { - friend class RenderState; - -public: - bool setEnabled(bool enabled); - bool set(GLint x, GLint y, GLint width, GLint height); - void set(int viewportHeight, const Rect& clip); - void reset(); - bool isEnabled() { return mEnabled; } - void dump(); - -private: - Scissor(); - void invalidate(); - bool mEnabled; - GLint mScissorX; - GLint mScissorY; - GLint mScissorWidth; - GLint mScissorHeight; -}; - -} /* namespace uirenderer */ -} /* namespace android */ - -#endif // RENDERSTATE_SCISSOR_H diff --git a/libs/hwui/renderstate/Stencil.cpp b/libs/hwui/renderstate/Stencil.cpp deleted file mode 100644 index dc465fc7a6f8..000000000000 --- a/libs/hwui/renderstate/Stencil.cpp +++ /dev/null @@ -1,140 +0,0 @@ -/* - * Copyright (C) 2012 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "renderstate/Stencil.h" - -#include "Caches.h" -#include "Debug.h" -#include "Extensions.h" -#include "Properties.h" - -#include - -namespace android { -namespace uirenderer { - -#if DEBUG_STENCIL -#define STENCIL_WRITE_VALUE 0xff -#define STENCIL_MASK_VALUE 0xff -#else -#define STENCIL_WRITE_VALUE 0x1 -#define STENCIL_MASK_VALUE 0x1 -#endif - -uint8_t Stencil::getStencilSize() { - return STENCIL_BUFFER_SIZE; -} - -/** - * This method will return either GL_STENCIL_INDEX4_OES if supported, - * GL_STENCIL_INDEX8 if not. - * - * Layers can't use a single bit stencil because multi-rect ClipArea needs a high enough - * stencil resolution to represent the summation of multiple intersecting rect geometries. - */ -GLenum Stencil::getLayerStencilFormat() { -#if !DEBUG_STENCIL - const Extensions& extensions = DeviceInfo::get()->extensions(); - if (extensions.has4BitStencil()) { - return GL_STENCIL_INDEX4_OES; - } -#endif - return GL_STENCIL_INDEX8; -} - -void Stencil::clear() { - glStencilMask(0xff); - glClearStencil(0); - glClear(GL_STENCIL_BUFFER_BIT); - - if (mState == StencilState::Test) { - // reset to test state, with immutable stencil - glStencilMask(0); - } -} - -void Stencil::enableTest(int incrementThreshold) { - if (mState != StencilState::Test) { - enable(); - if (incrementThreshold > 0) { - glStencilFunc(GL_EQUAL, incrementThreshold, 0xff); - } else { - glStencilFunc(GL_EQUAL, STENCIL_WRITE_VALUE, STENCIL_MASK_VALUE); - } - // We only want to test, let's keep everything - glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); - glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); - glStencilMask(0); - mState = StencilState::Test; - } -} - -void Stencil::enableWrite(int incrementThreshold) { - if (mState != StencilState::Write) { - enable(); - if (incrementThreshold > 0) { - glStencilFunc(GL_ALWAYS, 1, 0xff); - // The test always passes so the first two values are meaningless - glStencilOp(GL_INCR, GL_INCR, GL_INCR); - } else { - glStencilFunc(GL_ALWAYS, STENCIL_WRITE_VALUE, STENCIL_MASK_VALUE); - // The test always passes so the first two values are meaningless - glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); - } - glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); - glStencilMask(0xff); - mState = StencilState::Write; - } -} - -void Stencil::enableDebugTest(GLint value, bool greater) { - enable(); - glStencilFunc(greater ? GL_LESS : GL_EQUAL, value, 0xffffffff); - // We only want to test, let's keep everything - glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); - mState = StencilState::Test; - glStencilMask(0); -} - -void Stencil::enableDebugWrite() { - enable(); - glStencilFunc(GL_ALWAYS, 0x1, 0xffffffff); - // The test always passes so the first two values are meaningless - glStencilOp(GL_KEEP, GL_KEEP, GL_INCR); - glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); - mState = StencilState::Write; - glStencilMask(0xff); -} - -void Stencil::enable() { - if (mState == StencilState::Disabled) { - glEnable(GL_STENCIL_TEST); - } -} - -void Stencil::disable() { - if (mState != StencilState::Disabled) { - glDisable(GL_STENCIL_TEST); - mState = StencilState::Disabled; - } -} - -void Stencil::dump() { - ALOGD("Stencil: state %d", mState); -} - -}; // namespace uirenderer -}; // namespace android diff --git a/libs/hwui/renderstate/Stencil.h b/libs/hwui/renderstate/Stencil.h deleted file mode 100644 index 95f372344ee4..000000000000 --- a/libs/hwui/renderstate/Stencil.h +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Copyright (C) 2012 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef ANDROID_HWUI_STENCIL_H -#define ANDROID_HWUI_STENCIL_H - -#include - -#include - -namespace android { -namespace uirenderer { - -/////////////////////////////////////////////////////////////////////////////// -// Stencil buffer management -/////////////////////////////////////////////////////////////////////////////// - -class ANDROID_API Stencil { -public: - /** - * Returns the desired size for the stencil buffer. If the returned value - * is 0, then no stencil buffer is required. - */ - ANDROID_API static uint8_t getStencilSize(); - - static GLenum getLayerStencilFormat(); - - /** - * Clears the stencil buffer. - */ - void clear(); - - /** - * Enables stencil test. When the stencil test is enabled the stencil buffer is not written - * into. An increment threshold of zero causes the stencil to use a constant reference value - * and GL_EQUAL for the test. A non-zero increment threshold causes the stencil to use that - * value as the reference value and GL_EQUAL for the test. - */ - void enableTest(int incrementThreshold); - - /** - * Enables stencil write. When stencil write is enabled, the stencil - * test always succeeds and the value 0x1 is written in the stencil - * buffer for each fragment. An increment threshold of zero causes the stencil to use a constant - * reference value and GL_EQUAL for the test. A non-zero increment threshold causes the stencil - * to use that value as the reference value and GL_EQUAL for the test. - */ - void enableWrite(int incrementThreshold); - - /** - * The test passes only when equal to the specified value. - */ - void enableDebugTest(GLint value, bool greater = false); - - /** - * Used for debugging. The stencil test always passes and increments. - */ - void enableDebugWrite(); - - /** - * Disables stencil test and write. - */ - void disable(); - - /** - * Indicates whether either test or write is enabled. - */ - bool isEnabled() { return mState != StencilState::Disabled; } - - /** - * Indicates whether testing only is enabled. - */ - bool isTestEnabled() { return mState == StencilState::Test; } - - bool isWriteEnabled() { return mState == StencilState::Write; } - - void dump(); - -private: - enum class StencilState { Disabled, Test, Write }; - - void enable(); - StencilState mState = StencilState::Disabled; - -}; // class Stencil - -}; // namespace uirenderer -}; // namespace android - -#endif // ANDROID_HWUI_STENCIL_H diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp index a36dae44ede9..96920dddf5a9 100644 --- a/libs/hwui/renderthread/CanvasContext.cpp +++ b/libs/hwui/renderthread/CanvasContext.cpp @@ -29,7 +29,6 @@ #include "pipeline/skia/SkiaPipeline.h" #include "pipeline/skia/SkiaVulkanPipeline.h" #include "renderstate/RenderState.h" -#include "renderstate/Stencil.h" #include "utils/GLUtils.h" #include "utils/TimeUtils.h" #include "../Properties.h" -- cgit v1.2.3-59-g8ed1b From faaf6872b1092f98820289e89015ba8dbef62784 Mon Sep 17 00:00:00 2001 From: Mike Reed Date: Wed, 9 May 2018 09:16:40 -0400 Subject: remove unneeded RecordedOps Test: make Change-Id: Ifcb0df64ad649623ae875462f55d9009a4e1ac03 --- libs/hwui/Android.bp | 4 - libs/hwui/Image.cpp | 61 ----- libs/hwui/Image.h | 63 ----- libs/hwui/OpDumper.cpp | 53 ---- libs/hwui/OpDumper.h | 33 --- libs/hwui/Patch.cpp | 229 ---------------- libs/hwui/Patch.h | 73 ----- libs/hwui/RecordedOp.h | 481 --------------------------------- libs/hwui/RenderNode.cpp | 1 - libs/hwui/Vertex.h | 40 --- libs/hwui/tests/common/TestUtils.h | 3 +- libs/hwui/tests/unit/OpDumperTests.cpp | 43 --- 12 files changed, 1 insertion(+), 1083 deletions(-) delete mode 100644 libs/hwui/Image.cpp delete mode 100644 libs/hwui/Image.h delete mode 100644 libs/hwui/OpDumper.cpp delete mode 100644 libs/hwui/OpDumper.h delete mode 100644 libs/hwui/Patch.cpp delete mode 100644 libs/hwui/Patch.h delete mode 100644 libs/hwui/RecordedOp.h delete mode 100644 libs/hwui/tests/unit/OpDumperTests.cpp (limited to 'libs/hwui/RenderNode.cpp') diff --git a/libs/hwui/Android.bp b/libs/hwui/Android.bp index 01138c30b8c2..4c2a021836f0 100644 --- a/libs/hwui/Android.bp +++ b/libs/hwui/Android.bp @@ -206,15 +206,12 @@ cc_defaults { "FrameInfoVisualizer.cpp", "GlLayer.cpp", "GpuMemoryTracker.cpp", - "Image.cpp", "Interpolator.cpp", "JankTracker.cpp", "Layer.cpp", "LayerUpdateQueue.cpp", "Matrix.cpp", - "OpDumper.cpp", "EglReadback.cpp", - "Patch.cpp", "PathParser.cpp", "PixelBuffer.cpp", "ProfileData.cpp", @@ -318,7 +315,6 @@ cc_test { "tests/unit/LayerUpdateQueueTests.cpp", "tests/unit/LinearAllocatorTests.cpp", "tests/unit/MatrixTests.cpp", - "tests/unit/OpDumperTests.cpp", "tests/unit/PathInterpolatorTests.cpp", "tests/unit/RenderNodeDrawableTests.cpp", "tests/unit/RenderNodeTests.cpp", diff --git a/libs/hwui/Image.cpp b/libs/hwui/Image.cpp deleted file mode 100644 index d30796d01479..000000000000 --- a/libs/hwui/Image.cpp +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (C) 2013 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include - -#include "Caches.h" -#include "Image.h" - -namespace android { -namespace uirenderer { - -Image::Image(sp buffer) { - // Create the EGLImage object that maps the GraphicBuffer - EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY); - EGLClientBuffer clientBuffer = (EGLClientBuffer)buffer->getNativeBuffer(); - EGLint attrs[] = {EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_NONE}; - - mImage = eglCreateImageKHR(display, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID, clientBuffer, - attrs); - - if (mImage == EGL_NO_IMAGE_KHR) { - ALOGW("Error creating image (%#x)", eglGetError()); - mTexture = 0; - } else { - // Create a 2D texture to sample from the EGLImage - glGenTextures(1, &mTexture); - Caches::getInstance().textureState().bindTexture(mTexture); - glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, mImage); - - GLenum status = GL_NO_ERROR; - while ((status = glGetError()) != GL_NO_ERROR) { - ALOGW("Error creating image (%#x)", status); - } - } -} - -Image::~Image() { - if (mImage != EGL_NO_IMAGE_KHR) { - eglDestroyImageKHR(eglGetDisplay(EGL_DEFAULT_DISPLAY), mImage); - mImage = EGL_NO_IMAGE_KHR; - - Caches::getInstance().textureState().deleteTexture(mTexture); - mTexture = 0; - } -} - -}; // namespace uirenderer -}; // namespace android diff --git a/libs/hwui/Image.h b/libs/hwui/Image.h deleted file mode 100644 index 989b6ff3648d..000000000000 --- a/libs/hwui/Image.h +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright (C) 2013 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef ANDROID_HWUI_IMAGE_H -#define ANDROID_HWUI_IMAGE_H - -#include -#include - -#include -#include - -#include - -namespace android { -namespace uirenderer { - -/** - * A simple wrapper that creates an EGLImage and a texture for a GraphicBuffer. - */ -class Image { -public: - /** - * Creates a new image from the specified graphic buffer. If the image - * cannot be created, getTexture() will return 0 and getImage() will - * return EGL_NO_IMAGE_KHR. - */ - explicit Image(sp buffer); - ~Image(); - - /** - * Returns the name of the GL texture that can be used to sample - * from this image. - */ - GLuint getTexture() const { return mTexture; } - - /** - * Returns the name of the EGL image represented by this object. - */ - EGLImageKHR getImage() const { return mImage; } - -private: - GLuint mTexture; - EGLImageKHR mImage; -}; // class Image - -}; // namespace uirenderer -}; // namespace android - -#endif // ANDROID_HWUI_IMAGE_H diff --git a/libs/hwui/OpDumper.cpp b/libs/hwui/OpDumper.cpp deleted file mode 100644 index 5d2ccc77e82f..000000000000 --- a/libs/hwui/OpDumper.cpp +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "OpDumper.h" - -#include "ClipArea.h" -#include "RecordedOp.h" - -namespace android { -namespace uirenderer { - -#define STRINGIFY(n) #n, -static const char* sOpNameLut[] = BUILD_FULL_OP_LUT(STRINGIFY); - -void OpDumper::dump(const RecordedOp& op, std::ostream& output, int level) { - for (int i = 0; i < level; i++) { - output << " "; - } - - Rect localBounds(op.unmappedBounds); - op.localMatrix.mapRect(localBounds); - output << sOpNameLut[op.opId] << " " << localBounds; - - if (op.localClip && - (!op.localClip->rect.contains(localBounds) || op.localClip->intersectWithRoot)) { - output << std::fixed << std::setprecision(0) << " clip=" << op.localClip->rect - << " mode=" << (int)op.localClip->mode; - - if (op.localClip->intersectWithRoot) { - output << " iwr"; - } - } -} - -const char* OpDumper::opName(const RecordedOp& op) { - return sOpNameLut[op.opId]; -} - -} // namespace uirenderer -} // namespace android diff --git a/libs/hwui/OpDumper.h b/libs/hwui/OpDumper.h deleted file mode 100644 index edbe381fcc72..000000000000 --- a/libs/hwui/OpDumper.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include - -namespace android { -namespace uirenderer { - -struct RecordedOp; - -class OpDumper { -public: - static void dump(const RecordedOp& op, std::ostream& output, int level = 0); - static const char* opName(const RecordedOp& op); -}; - -}; // namespace uirenderer -}; // namespace android diff --git a/libs/hwui/Patch.cpp b/libs/hwui/Patch.cpp deleted file mode 100644 index c243dad01f04..000000000000 --- a/libs/hwui/Patch.cpp +++ /dev/null @@ -1,229 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "Patch.h" - -#include "Caches.h" -#include "Properties.h" -#include "UvMapper.h" -#include "utils/MathUtils.h" - -#include -#include - -namespace android { -namespace uirenderer { - -/////////////////////////////////////////////////////////////////////////////// -// Vertices management -/////////////////////////////////////////////////////////////////////////////// - -uint32_t Patch::getSize() const { - return verticesCount * sizeof(TextureVertex); -} - -Patch::Patch(const float bitmapWidth, const float bitmapHeight, float width, float height, - const UvMapper& mapper, const Res_png_9patch* patch) - : mColors(patch->getColors()) { - int8_t emptyQuads = 0; - const int8_t numColors = patch->numColors; - if (uint8_t(numColors) < sizeof(uint32_t) * 4) { - for (int8_t i = 0; i < numColors; i++) { - if (mColors[i] == 0x0) { - emptyQuads++; - } - } - } - - hasEmptyQuads = emptyQuads > 0; - - uint32_t xCount = patch->numXDivs; - uint32_t yCount = patch->numYDivs; - - uint32_t maxVertices = ((xCount + 1) * (yCount + 1) - emptyQuads) * 4; - if (maxVertices == 0) return; - - vertices.reset(new TextureVertex[maxVertices]); - TextureVertex* vertex = vertices.get(); - - const int32_t* xDivs = patch->getXDivs(); - const int32_t* yDivs = patch->getYDivs(); - - const uint32_t xStretchCount = (xCount + 1) >> 1; - const uint32_t yStretchCount = (yCount + 1) >> 1; - - float stretchX = 0.0f; - float stretchY = 0.0f; - - float rescaleX = 1.0f; - float rescaleY = 1.0f; - - if (xStretchCount > 0) { - uint32_t stretchSize = 0; - for (uint32_t i = 1; i < xCount; i += 2) { - stretchSize += xDivs[i] - xDivs[i - 1]; - } - const float xStretchTex = stretchSize; - const float fixed = bitmapWidth - stretchSize; - const float xStretch = std::max(width - fixed, 0.0f); - stretchX = xStretch / xStretchTex; - rescaleX = fixed == 0.0f ? 0.0f : std::min(std::max(width, 0.0f) / fixed, 1.0f); - } - - if (yStretchCount > 0) { - uint32_t stretchSize = 0; - for (uint32_t i = 1; i < yCount; i += 2) { - stretchSize += yDivs[i] - yDivs[i - 1]; - } - const float yStretchTex = stretchSize; - const float fixed = bitmapHeight - stretchSize; - const float yStretch = std::max(height - fixed, 0.0f); - stretchY = yStretch / yStretchTex; - rescaleY = fixed == 0.0f ? 0.0f : std::min(std::max(height, 0.0f) / fixed, 1.0f); - } - - uint32_t quadCount = 0; - - float previousStepY = 0.0f; - - float y1 = 0.0f; - float y2 = 0.0f; - float v1 = 0.0f; - - mUvMapper = mapper; - - for (uint32_t i = 0; i < yCount; i++) { - float stepY = yDivs[i]; - const float segment = stepY - previousStepY; - - if (i & 1) { - y2 = y1 + floorf(segment * stretchY + 0.5f); - } else { - y2 = y1 + segment * rescaleY; - } - - float vOffset = y1 == y2 ? 0.0f : 0.5 - (0.5 * segment / (y2 - y1)); - float v2 = std::max(0.0f, stepY - vOffset) / bitmapHeight; - v1 += vOffset / bitmapHeight; - - if (stepY > 0.0f) { - generateRow(xDivs, xCount, vertex, y1, y2, v1, v2, stretchX, rescaleX, width, - bitmapWidth, quadCount); - } - - y1 = y2; - v1 = stepY / bitmapHeight; - - previousStepY = stepY; - } - - if (previousStepY != bitmapHeight) { - y2 = height; - generateRow(xDivs, xCount, vertex, y1, y2, v1, 1.0f, stretchX, rescaleX, width, bitmapWidth, - quadCount); - } - - if (verticesCount != maxVertices) { - std::unique_ptr reducedVertices(new TextureVertex[verticesCount]); - memcpy(reducedVertices.get(), vertices.get(), verticesCount * sizeof(TextureVertex)); - vertices = std::move(reducedVertices); - } -} - -void Patch::generateRow(const int32_t* xDivs, uint32_t xCount, TextureVertex*& vertex, float y1, - float y2, float v1, float v2, float stretchX, float rescaleX, float width, - float bitmapWidth, uint32_t& quadCount) { - float previousStepX = 0.0f; - - float x1 = 0.0f; - float x2 = 0.0f; - float u1 = 0.0f; - - // Generate the row quad by quad - for (uint32_t i = 0; i < xCount; i++) { - float stepX = xDivs[i]; - const float segment = stepX - previousStepX; - - if (i & 1) { - x2 = x1 + floorf(segment * stretchX + 0.5f); - } else { - x2 = x1 + segment * rescaleX; - } - - float uOffset = x1 == x2 ? 0.0f : 0.5 - (0.5 * segment / (x2 - x1)); - float u2 = std::max(0.0f, stepX - uOffset) / bitmapWidth; - u1 += uOffset / bitmapWidth; - - if (stepX > 0.0f) { - generateQuad(vertex, x1, y1, x2, y2, u1, v1, u2, v2, quadCount); - } - - x1 = x2; - u1 = stepX / bitmapWidth; - - previousStepX = stepX; - } - - if (previousStepX != bitmapWidth) { - x2 = width; - generateQuad(vertex, x1, y1, x2, y2, u1, v1, 1.0f, v2, quadCount); - } -} - -void Patch::generateQuad(TextureVertex*& vertex, float x1, float y1, float x2, float y2, float u1, - float v1, float u2, float v2, uint32_t& quadCount) { - const uint32_t oldQuadCount = quadCount; - quadCount++; - - x1 = std::max(x1, 0.0f); - x2 = std::max(x2, 0.0f); - y1 = std::max(y1, 0.0f); - y2 = std::max(y2, 0.0f); - - // Skip degenerate and transparent (empty) quads - if ((mColors[oldQuadCount] == 0) || x1 >= x2 || y1 >= y2) { -#if DEBUG_PATCHES_EMPTY_VERTICES - PATCH_LOGD(" quad %d (empty)", oldQuadCount); - PATCH_LOGD(" left, top = %.2f, %.2f\t\tu1, v1 = %.8f, %.8f", x1, y1, u1, v1); - PATCH_LOGD(" right, bottom = %.2f, %.2f\t\tu2, v2 = %.8f, %.8f", x2, y2, u2, v2); -#endif - return; - } - - // Record all non empty quads - if (hasEmptyQuads) { - quads.emplace_back(x1, y1, x2, y2); - } - - mUvMapper.map(u1, v1, u2, v2); - - TextureVertex::set(vertex++, x1, y1, u1, v1); - TextureVertex::set(vertex++, x2, y1, u2, v1); - TextureVertex::set(vertex++, x1, y2, u1, v2); - TextureVertex::set(vertex++, x2, y2, u2, v2); - - verticesCount += 4; - indexCount += 6; - -#if DEBUG_PATCHES_VERTICES - PATCH_LOGD(" quad %d", oldQuadCount); - PATCH_LOGD(" left, top = %.2f, %.2f\t\tu1, v1 = %.8f, %.8f", x1, y1, u1, v1); - PATCH_LOGD(" right, bottom = %.2f, %.2f\t\tu2, v2 = %.8f, %.8f", x2, y2, u2, v2); -#endif -} - -}; // namespace uirenderer -}; // namespace android diff --git a/libs/hwui/Patch.h b/libs/hwui/Patch.h deleted file mode 100644 index a659ed227bec..000000000000 --- a/libs/hwui/Patch.h +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef ANDROID_HWUI_PATCH_H -#define ANDROID_HWUI_PATCH_H - -#include - -#include - -#include - -#include "Rect.h" -#include "UvMapper.h" - -#include - -namespace android { -namespace uirenderer { - -struct TextureVertex; - -/////////////////////////////////////////////////////////////////////////////// -// 9-patch structures -/////////////////////////////////////////////////////////////////////////////// - -class Patch { -public: - Patch(const float bitmapWidth, const float bitmapHeight, float width, float height, - const UvMapper& mapper, const Res_png_9patch* patch); - - /** - * Returns the size of this patch's mesh in bytes. - */ - uint32_t getSize() const; - - std::unique_ptr vertices; - uint32_t verticesCount = 0; - uint32_t indexCount = 0; - bool hasEmptyQuads = false; - std::vector quads; - - GLintptr positionOffset = 0; - GLintptr textureOffset = 0; - -private: - void generateRow(const int32_t* xDivs, uint32_t xCount, TextureVertex*& vertex, float y1, - float y2, float v1, float v2, float stretchX, float rescaleX, float width, - float bitmapWidth, uint32_t& quadCount); - void generateQuad(TextureVertex*& vertex, float x1, float y1, float x2, float y2, float u1, - float v1, float u2, float v2, uint32_t& quadCount); - - const uint32_t* mColors; - UvMapper mUvMapper; -}; // struct Patch - -}; // namespace uirenderer -}; // namespace android - -#endif // ANDROID_HWUI_PATCH_H diff --git a/libs/hwui/RecordedOp.h b/libs/hwui/RecordedOp.h deleted file mode 100644 index a8f105d0e2db..000000000000 --- a/libs/hwui/RecordedOp.h +++ /dev/null @@ -1,481 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include "GlLayer.h" -#include "Matrix.h" -#include "Rect.h" -#include "RenderNode.h" -#include "Vector.h" -#include "utils/LinearAllocator.h" -#include "utils/PaintUtils.h" - -#include - -class SkBitmap; -class SkPaint; - -namespace android { -namespace uirenderer { - -struct ClipBase; -class OffscreenBuffer; -class RenderNode; -class DeferredLayerUpdater; -typedef uint16_t glyph_t; - -struct Vertex; - -namespace VectorDrawable { -class Tree; -} - -/** - * Authoritative op list, used for generating the op ID enum, ID based LUTS, and - * the functions to which they dispatch. Parameter macros are executed for each op, - * in order, based on the op's type. - * - * There are 4 types of op, which defines dispatch/LUT capability: - * - * | DisplayList | Render | Merge | - * -------------|-------------|-------------|-------------| - * PRE RENDER | Yes | | | - * RENDER ONLY | | Yes | | - * UNMERGEABLE | Yes | Yes | | - * MERGEABLE | Yes | Yes | Yes | - * - * PRE RENDER - These ops are recorded into DisplayLists, but can't be directly rendered. This - * may be because they need to be transformed into other op types (e.g. CirclePropsOp), - * be traversed to access multiple renderable ops within (e.g. RenderNodeOp), or because they - * modify renderbuffer lifecycle, instead of directly rendering content (the various LayerOps). - * - * RENDER ONLY - These ops cannot be recorded into DisplayLists, and are instead implicitly - * constructed from other commands/RenderNode properties. They cannot be merged. - * - * UNMERGEABLE - These ops can be recorded into DisplayLists and rendered directly, but do not - * support merged rendering. - * - * MERGEABLE - These ops can be recorded into DisplayLists and rendered individually, or merged - * under certain circumstances. - */ -#define MAP_OPS_BASED_ON_TYPE(PRE_RENDER_OP_FN, RENDER_ONLY_OP_FN, UNMERGEABLE_OP_FN, \ - MERGEABLE_OP_FN) \ - PRE_RENDER_OP_FN(RenderNodeOp) \ - PRE_RENDER_OP_FN(CirclePropsOp) \ - PRE_RENDER_OP_FN(RoundRectPropsOp) \ - PRE_RENDER_OP_FN(BeginLayerOp) \ - PRE_RENDER_OP_FN(EndLayerOp) \ - PRE_RENDER_OP_FN(BeginUnclippedLayerOp) \ - PRE_RENDER_OP_FN(EndUnclippedLayerOp) \ - PRE_RENDER_OP_FN(VectorDrawableOp) \ - \ - RENDER_ONLY_OP_FN(LayerOp) \ - RENDER_ONLY_OP_FN(CopyToLayerOp) \ - RENDER_ONLY_OP_FN(CopyFromLayerOp) \ - \ - UNMERGEABLE_OP_FN(ArcOp) \ - UNMERGEABLE_OP_FN(BitmapMeshOp) \ - UNMERGEABLE_OP_FN(BitmapRectOp) \ - UNMERGEABLE_OP_FN(ColorOp) \ - UNMERGEABLE_OP_FN(FunctorOp) \ - UNMERGEABLE_OP_FN(LinesOp) \ - UNMERGEABLE_OP_FN(OvalOp) \ - UNMERGEABLE_OP_FN(PathOp) \ - UNMERGEABLE_OP_FN(PointsOp) \ - UNMERGEABLE_OP_FN(RectOp) \ - UNMERGEABLE_OP_FN(RoundRectOp) \ - UNMERGEABLE_OP_FN(SimpleRectsOp) \ - UNMERGEABLE_OP_FN(TextOnPathOp) \ - UNMERGEABLE_OP_FN(TextureLayerOp) \ - \ - MERGEABLE_OP_FN(BitmapOp) \ - MERGEABLE_OP_FN(PatchOp) \ - MERGEABLE_OP_FN(TextOp) - -/** - * LUT generators, which will insert nullptr for unsupported ops - */ -#define NULLPTR_OP_FN(Type) nullptr, - -#define BUILD_DEFERRABLE_OP_LUT(OP_FN) \ - { MAP_OPS_BASED_ON_TYPE(OP_FN, NULLPTR_OP_FN, OP_FN, OP_FN) } - -#define BUILD_MERGEABLE_OP_LUT(OP_FN) \ - { MAP_OPS_BASED_ON_TYPE(NULLPTR_OP_FN, NULLPTR_OP_FN, NULLPTR_OP_FN, OP_FN) } - -#define BUILD_RENDERABLE_OP_LUT(OP_FN) \ - { MAP_OPS_BASED_ON_TYPE(NULLPTR_OP_FN, OP_FN, OP_FN, OP_FN) } - -#define BUILD_FULL_OP_LUT(OP_FN) \ - { MAP_OPS_BASED_ON_TYPE(OP_FN, OP_FN, OP_FN, OP_FN) } - -/** - * Op mapping functions, which skip unsupported ops. - * - * Note: Do not use for LUTS, since these do not preserve ID order. - */ -#define NULL_OP_FN(Type) - -#define MAP_DEFERRABLE_OPS(OP_FN) MAP_OPS_BASED_ON_TYPE(OP_FN, NULL_OP_FN, OP_FN, OP_FN) - -#define MAP_MERGEABLE_OPS(OP_FN) MAP_OPS_BASED_ON_TYPE(NULL_OP_FN, NULL_OP_FN, NULL_OP_FN, OP_FN) - -#define MAP_RENDERABLE_OPS(OP_FN) MAP_OPS_BASED_ON_TYPE(NULL_OP_FN, OP_FN, OP_FN, OP_FN) - -// Generate OpId enum -#define IDENTITY_FN(Type) Type, -namespace RecordedOpId { -enum { - MAP_OPS_BASED_ON_TYPE(IDENTITY_FN, IDENTITY_FN, IDENTITY_FN, IDENTITY_FN) Count, -}; -} -static_assert(RecordedOpId::RenderNodeOp == 0, "First index must be zero for LUTs to work"); - -#define BASE_PARAMS \ - const Rect &unmappedBounds, const Matrix4 &localMatrix, const ClipBase *localClip, \ - const SkPaint *paint -#define BASE_PARAMS_PAINTLESS \ - const Rect &unmappedBounds, const Matrix4 &localMatrix, const ClipBase *localClip -#define SUPER(Type) RecordedOp(RecordedOpId::Type, unmappedBounds, localMatrix, localClip, paint) -#define SUPER_PAINTLESS(Type) \ - RecordedOp(RecordedOpId::Type, unmappedBounds, localMatrix, localClip, nullptr) - -struct RecordedOp { - /* ID from RecordedOpId - generally used for jumping into function tables */ - const int opId; - - /* bounds in *local* space, without accounting for DisplayList transformation, or stroke */ - const Rect unmappedBounds; - - /* transform in recording space (vs DisplayList origin) */ - const Matrix4 localMatrix; - - /* clip in recording space - nullptr if not clipped */ - const ClipBase* localClip; - - /* optional paint, stored in base object to simplify merging logic */ - const SkPaint* paint; - -protected: - RecordedOp(unsigned int opId, BASE_PARAMS) - : opId(opId) - , unmappedBounds(unmappedBounds) - , localMatrix(localMatrix) - , localClip(localClip) - , paint(paint) {} -}; - -struct RenderNodeOp : RecordedOp { - RenderNodeOp(BASE_PARAMS_PAINTLESS, RenderNode* renderNode) - : SUPER_PAINTLESS(RenderNodeOp), renderNode(renderNode) {} - RenderNode* renderNode; // not const, since drawing modifies it - - /** - * Holds the transformation between the projection surface ViewGroup and this RenderNode - * drawing instance. Represents any translations / transformations done within the drawing of - * the compositing ancestor ViewGroup's draw, before the draw of the View represented by this - * DisplayList draw instance. - * - * Note: doesn't include transformation within the RenderNode, or its properties. - */ - Matrix4 transformFromCompositingAncestor; - bool skipInOrderDraw = false; -}; - -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Standard Ops -//////////////////////////////////////////////////////////////////////////////////////////////////// - -struct ArcOp : RecordedOp { - ArcOp(BASE_PARAMS, float startAngle, float sweepAngle, bool useCenter) - : SUPER(ArcOp), startAngle(startAngle), sweepAngle(sweepAngle), useCenter(useCenter) {} - const float startAngle; - const float sweepAngle; - const bool useCenter; -}; - -struct BitmapOp : RecordedOp { - BitmapOp(BASE_PARAMS, Bitmap* bitmap) : SUPER(BitmapOp), bitmap(bitmap) {} - Bitmap* bitmap; -}; - -struct BitmapMeshOp : RecordedOp { - BitmapMeshOp(BASE_PARAMS, Bitmap* bitmap, int meshWidth, int meshHeight, const float* vertices, - const int* colors) - : SUPER(BitmapMeshOp) - , bitmap(bitmap) - , meshWidth(meshWidth) - , meshHeight(meshHeight) - , vertices(vertices) - , colors(colors) {} - Bitmap* bitmap; - const int meshWidth; - const int meshHeight; - const float* vertices; - const int* colors; -}; - -struct BitmapRectOp : RecordedOp { - BitmapRectOp(BASE_PARAMS, Bitmap* bitmap, const Rect& src) - : SUPER(BitmapRectOp), bitmap(bitmap), src(src) {} - Bitmap* bitmap; - const Rect src; -}; - -struct CirclePropsOp : RecordedOp { - CirclePropsOp(const Matrix4& localMatrix, const ClipBase* localClip, const SkPaint* paint, - float* x, float* y, float* radius) - : RecordedOp(RecordedOpId::CirclePropsOp, Rect(), localMatrix, localClip, paint) - , x(x) - , y(y) - , radius(radius) {} - const float* x; - const float* y; - const float* radius; -}; - -struct ColorOp : RecordedOp { - // Note: unbounded op that will fillclip, so no bounds/matrix needed - ColorOp(const ClipBase* localClip, int color, SkBlendMode mode) - : RecordedOp(RecordedOpId::ColorOp, Rect(), Matrix4::identity(), localClip, nullptr) - , color(color) - , mode(mode) {} - const int color; - const SkBlendMode mode; -}; - -struct FunctorOp : RecordedOp { - // Note: undefined record-time bounds, since this op fills the clip - // TODO: explicitly define bounds - FunctorOp(const Matrix4& localMatrix, const ClipBase* localClip, Functor* functor) - : RecordedOp(RecordedOpId::FunctorOp, Rect(), localMatrix, localClip, nullptr) - , functor(functor) {} - Functor* functor; -}; - -struct LinesOp : RecordedOp { - LinesOp(BASE_PARAMS, const float* points, const int floatCount) - : SUPER(LinesOp), points(points), floatCount(floatCount) {} - const float* points; - const int floatCount; -}; - -struct OvalOp : RecordedOp { - OvalOp(BASE_PARAMS) : SUPER(OvalOp) {} -}; - -struct PatchOp : RecordedOp { - PatchOp(BASE_PARAMS, Bitmap* bitmap, const Res_png_9patch* patch) - : SUPER(PatchOp), bitmap(bitmap), patch(patch) {} - Bitmap* bitmap; - const Res_png_9patch* patch; -}; - -struct PathOp : RecordedOp { - PathOp(BASE_PARAMS, const SkPath* path) : SUPER(PathOp), path(path) {} - const SkPath* path; -}; - -struct PointsOp : RecordedOp { - PointsOp(BASE_PARAMS, const float* points, const int floatCount) - : SUPER(PointsOp), points(points), floatCount(floatCount) {} - const float* points; - const int floatCount; -}; - -struct RectOp : RecordedOp { - RectOp(BASE_PARAMS) : SUPER(RectOp) {} -}; - -struct RoundRectOp : RecordedOp { - RoundRectOp(BASE_PARAMS, float rx, float ry) : SUPER(RoundRectOp), rx(rx), ry(ry) {} - const float rx; - const float ry; -}; - -struct RoundRectPropsOp : RecordedOp { - RoundRectPropsOp(const Matrix4& localMatrix, const ClipBase* localClip, const SkPaint* paint, - float* left, float* top, float* right, float* bottom, float* rx, float* ry) - : RecordedOp(RecordedOpId::RoundRectPropsOp, Rect(), localMatrix, localClip, paint) - , left(left) - , top(top) - , right(right) - , bottom(bottom) - , rx(rx) - , ry(ry) {} - const float* left; - const float* top; - const float* right; - const float* bottom; - const float* rx; - const float* ry; -}; - -struct VectorDrawableOp : RecordedOp { - VectorDrawableOp(VectorDrawable::Tree* tree, BASE_PARAMS_PAINTLESS) - : SUPER_PAINTLESS(VectorDrawableOp), vectorDrawable(tree) {} - VectorDrawable::Tree* vectorDrawable; -}; - -struct SimpleRectsOp : RecordedOp { // Filled, no AA (TODO: better name?) - SimpleRectsOp(BASE_PARAMS, Vertex* vertices, size_t vertexCount) - : SUPER(SimpleRectsOp), vertices(vertices), vertexCount(vertexCount) {} - Vertex* vertices; - const size_t vertexCount; -}; - -struct TextOp : RecordedOp { - TextOp(BASE_PARAMS, const glyph_t* glyphs, const float* positions, int glyphCount, float x, - float y) - : SUPER(TextOp) - , glyphs(glyphs) - , positions(positions) - , glyphCount(glyphCount) - , x(x) - , y(y) {} - const glyph_t* glyphs; - const float* positions; - const int glyphCount; - const float x; - const float y; -}; - -struct TextOnPathOp : RecordedOp { - // TODO: explicitly define bounds - TextOnPathOp(const Matrix4& localMatrix, const ClipBase* localClip, const SkPaint* paint, - const glyph_t* glyphs, int glyphCount, const SkPath* path, float hOffset, - float vOffset) - : RecordedOp(RecordedOpId::TextOnPathOp, Rect(), localMatrix, localClip, paint) - , glyphs(glyphs) - , glyphCount(glyphCount) - , path(path) - , hOffset(hOffset) - , vOffset(vOffset) {} - const glyph_t* glyphs; - const int glyphCount; - - const SkPath* path; - const float hOffset; - const float vOffset; -}; - -struct TextureLayerOp : RecordedOp { - TextureLayerOp(BASE_PARAMS_PAINTLESS, DeferredLayerUpdater* layer) - : SUPER_PAINTLESS(TextureLayerOp), layerHandle(layer) {} - - // Copy an existing TextureLayerOp, replacing the underlying matrix - TextureLayerOp(const TextureLayerOp& op, const Matrix4& replacementMatrix) - : RecordedOp(RecordedOpId::TextureLayerOp, op.unmappedBounds, replacementMatrix, - op.localClip, op.paint) - , layerHandle(op.layerHandle) {} - DeferredLayerUpdater* layerHandle; -}; - -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Layers -//////////////////////////////////////////////////////////////////////////////////////////////////// - -/** - * Stateful operation! denotes the creation of an off-screen layer, - * and that commands following will render into it. - */ -struct BeginLayerOp : RecordedOp { - BeginLayerOp(BASE_PARAMS) : SUPER(BeginLayerOp) {} -}; - -/** - * Stateful operation! Denotes end of off-screen layer, and that - * commands since last BeginLayerOp should be drawn into parent FBO. - * - * State in this op is empty, it just serves to signal that a layer has been finished. - */ -struct EndLayerOp : RecordedOp { - EndLayerOp() - : RecordedOp(RecordedOpId::EndLayerOp, Rect(), Matrix4::identity(), nullptr, nullptr) {} -}; - -struct BeginUnclippedLayerOp : RecordedOp { - BeginUnclippedLayerOp(BASE_PARAMS) : SUPER(BeginUnclippedLayerOp) {} -}; - -struct EndUnclippedLayerOp : RecordedOp { - EndUnclippedLayerOp() - : RecordedOp(RecordedOpId::EndUnclippedLayerOp, Rect(), Matrix4::identity(), nullptr, - nullptr) {} -}; - -struct CopyToLayerOp : RecordedOp { - CopyToLayerOp(const RecordedOp& op, OffscreenBuffer** layerHandle) - : RecordedOp(RecordedOpId::CopyToLayerOp, op.unmappedBounds, op.localMatrix, - nullptr, // clip intentionally ignored - op.paint) - , layerHandle(layerHandle) {} - - // Records a handle to the Layer object, since the Layer itself won't be - // constructed until after this operation is constructed. - OffscreenBuffer** layerHandle; -}; - -// draw the parameter layer underneath -struct CopyFromLayerOp : RecordedOp { - CopyFromLayerOp(const RecordedOp& op, OffscreenBuffer** layerHandle) - : RecordedOp(RecordedOpId::CopyFromLayerOp, op.unmappedBounds, op.localMatrix, - nullptr, // clip intentionally ignored - op.paint) - , layerHandle(layerHandle) {} - - // Records a handle to the Layer object, since the Layer itself won't be - // constructed until after this operation is constructed. - OffscreenBuffer** layerHandle; -}; - -/** - * Draws an OffscreenBuffer. - * - * Alpha, mode, and colorfilter are embedded, since LayerOps are always dynamically generated, - * when creating/tracking a SkPaint* during defer isn't worth the bother. - */ -struct LayerOp : RecordedOp { - // Records a one-use (saveLayer) layer for drawing. - LayerOp(BASE_PARAMS, OffscreenBuffer** layerHandle) - : SUPER_PAINTLESS(LayerOp) - , layerHandle(layerHandle) - , alpha(paint ? paint->getAlpha() / 255.0f : 1.0f) - , mode(PaintUtils::getBlendModeDirect(paint)) - , colorFilter(paint ? paint->getColorFilter() : nullptr) {} - - explicit LayerOp(RenderNode& node) - : RecordedOp(RecordedOpId::LayerOp, Rect(node.getWidth(), node.getHeight()), - Matrix4::identity(), nullptr, nullptr) - , layerHandle(node.getLayerHandle()) - , alpha(node.properties().layerProperties().alpha() / 255.0f) - , mode(node.properties().layerProperties().xferMode()) - , colorFilter(node.properties().layerProperties().colorFilter()) {} - - // Records a handle to the Layer object, since the Layer itself won't be - // constructed until after this operation is constructed. - OffscreenBuffer** layerHandle; - const float alpha; - const SkBlendMode mode; - - // pointer to object owned by either LayerProperties, or a recorded Paint object in a - // BeginLayerOp. Lives longer than LayerOp in either case, so no skia ref counting is used. - SkColorFilter* colorFilter; -}; - -}; // namespace uirenderer -}; // namespace android diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp index 83fa84eb131e..a2e1f6041b62 100644 --- a/libs/hwui/RenderNode.cpp +++ b/libs/hwui/RenderNode.cpp @@ -18,7 +18,6 @@ #include "DamageAccumulator.h" #include "Debug.h" -#include "RecordedOp.h" #include "TreeInfo.h" #include "VectorDrawable.h" #include "renderstate/RenderState.h" diff --git a/libs/hwui/Vertex.h b/libs/hwui/Vertex.h index 186d0a88a33e..a6aae55b2ee8 100644 --- a/libs/hwui/Vertex.h +++ b/libs/hwui/Vertex.h @@ -74,46 +74,6 @@ struct TextureVertex { REQUIRE_COMPATIBLE_LAYOUT(TextureVertex); -/** - * Simple structure to describe a vertex with a position, texture UV and an - * sRGB color with alpha. The color is stored pre-multiplied in linear space. - */ -struct ColorTextureVertex { - float x, y; - float u, v; - float r, g, b, a; // pre-multiplied linear - - static inline void set(ColorTextureVertex* vertex, float x, float y, float u, float v, - uint32_t color) { - FloatColor c; - c.set(color); - *vertex = {x, y, u, v, c.r, c.g, c.b, c.a}; - } -}; // struct ColorTextureVertex - -REQUIRE_COMPATIBLE_LAYOUT(ColorTextureVertex); - -/** - * Simple structure to describe a vertex with a position and an alpha value. - */ -struct AlphaVertex { - float x, y; - float alpha; - - static inline void set(AlphaVertex* vertex, float x, float y, float alpha) { - *vertex = {x, y, alpha}; - } - - static inline void copyWithOffset(AlphaVertex* vertex, const AlphaVertex& src, float x, - float y) { - AlphaVertex::set(vertex, src.x + x, src.y + y, src.alpha); - } - - static inline void setColor(AlphaVertex* vertex, float alpha) { vertex[0].alpha = alpha; } -}; // struct AlphaVertex - -REQUIRE_COMPATIBLE_LAYOUT(AlphaVertex); - }; // namespace uirenderer }; // namespace android diff --git a/libs/hwui/tests/common/TestUtils.h b/libs/hwui/tests/common/TestUtils.h index 13fb5285bc31..743f8093bfa8 100644 --- a/libs/hwui/tests/common/TestUtils.h +++ b/libs/hwui/tests/common/TestUtils.h @@ -18,6 +18,7 @@ #include #include +#include #include #include #include @@ -28,8 +29,6 @@ #include #include -#include - #include namespace android { diff --git a/libs/hwui/tests/unit/OpDumperTests.cpp b/libs/hwui/tests/unit/OpDumperTests.cpp deleted file mode 100644 index ef30e872a7bd..000000000000 --- a/libs/hwui/tests/unit/OpDumperTests.cpp +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include - -#include "OpDumper.h" -#include "tests/common/TestUtils.h" - -using namespace android; -using namespace android::uirenderer; - -TEST(OpDumper, dump) { - SkPaint paint; - RectOp op(uirenderer::Rect(100, 100), Matrix4::identity(), nullptr, &paint); - - std::stringstream stream; - OpDumper::dump(op, stream); - EXPECT_STREQ("RectOp [100 x 100]", stream.str().c_str()); - - stream.str(""); - OpDumper::dump(op, stream, 2); - EXPECT_STREQ(" RectOp [100 x 100]", stream.str().c_str()); - - ClipRect clipRect(uirenderer::Rect(50, 50)); - op.localClip = &clipRect; - - stream.str(""); - OpDumper::dump(op, stream, 2); - EXPECT_STREQ(" RectOp [100 x 100] clip=[50 x 50] mode=0", stream.str().c_str()); -} -- cgit v1.2.3-59-g8ed1b From 8f45d4afd95e73fab931722038fb411ab3f1603d Mon Sep 17 00:00:00 2001 From: John Reck Date: Wed, 15 Aug 2018 10:17:12 -0700 Subject: New DisplayList v2 First step of many * Pulls SkLiteDL and SkLiteRecorder into HWUI * forceDark shifted to be a sync-time transformation instead of record time. No meaningful behavior change, but much more flexible heuristics are possible this way. Test: build, poked around with forceDark on Change-Id: I7b7cec5b7fd7c2b18823b4d92d821cf5898f9b88 --- libs/hwui/Android.bp | 1 + libs/hwui/CanvasTransform.cpp | 75 +- libs/hwui/CanvasTransform.h | 4 +- libs/hwui/DisplayListOps.in | 52 ++ libs/hwui/RecordingCanvas.cpp | 934 +++++++++++++++++++++ libs/hwui/RecordingCanvas.h | 203 +++++ libs/hwui/RenderNode.cpp | 14 + libs/hwui/RenderNode.h | 8 +- libs/hwui/hwui/Bitmap.cpp | 41 +- libs/hwui/hwui/Bitmap.h | 3 +- libs/hwui/pipeline/skia/SkiaDisplayList.h | 7 +- libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp | 10 +- libs/hwui/pipeline/skia/SkiaRecordingCanvas.h | 5 +- libs/hwui/tests/unit/RenderNodeDrawableTests.cpp | 6 +- libs/hwui/tests/unit/SkiaDisplayListTests.cpp | 50 +- libs/hwui/tests/unit/SkiaPipelineTests.cpp | 1 - libs/hwui/tests/unit/SkiaRenderPropertiesTests.cpp | 1 - libs/hwui/utils/LinearAllocator.cpp | 10 +- libs/hwui/utils/Macros.h | 9 + libs/hwui/utils/TypeLogic.h | 40 + 20 files changed, 1349 insertions(+), 125 deletions(-) create mode 100644 libs/hwui/DisplayListOps.in create mode 100644 libs/hwui/RecordingCanvas.cpp create mode 100644 libs/hwui/RecordingCanvas.h create mode 100644 libs/hwui/utils/TypeLogic.h (limited to 'libs/hwui/RenderNode.cpp') diff --git a/libs/hwui/Android.bp b/libs/hwui/Android.bp index 62ab7900737e..b7ffb5d9dc2e 100644 --- a/libs/hwui/Android.bp +++ b/libs/hwui/Android.bp @@ -223,6 +223,7 @@ cc_defaults { "Properties.cpp", "PropertyValuesAnimatorSet.cpp", "PropertyValuesHolder.cpp", + "RecordingCanvas.cpp", "RenderNode.cpp", "RenderProperties.cpp", "ResourceCache.cpp", diff --git a/libs/hwui/CanvasTransform.cpp b/libs/hwui/CanvasTransform.cpp index 1b15dbd526cc..adcdc18ab418 100644 --- a/libs/hwui/CanvasTransform.cpp +++ b/libs/hwui/CanvasTransform.cpp @@ -15,16 +15,20 @@ */ #include "CanvasTransform.h" -#include "utils/Color.h" #include "Properties.h" +#include "utils/Color.h" -#include #include +#include #include +#include +#include #include #include +#include + namespace android::uirenderer { static SkColor makeLight(SkColor color) { @@ -66,6 +70,32 @@ static void applyColorTransform(ColorTransform transform, SkPaint& paint) { SkColor newColor = transformColor(transform, paint.getColor()); paint.setColor(newColor); + if (paint.getShader()) { + SkShader::GradientInfo info; + std::array _colorStorage; + std::array _offsetStorage; + info.fColorCount = _colorStorage.size(); + info.fColors = _colorStorage.data(); + info.fColorOffsets = _offsetStorage.data(); + SkShader::GradientType type = paint.getShader()->asAGradient(&info); + ALOGW_IF(type, "Found gradient of type = %d", type); + + if (info.fColorCount <= 10) { + switch (type) { + case SkShader::kLinear_GradientType: + for (int i = 0; i < info.fColorCount; i++) { + info.fColors[i] = transformColor(transform, info.fColors[i]); + } + paint.setShader(SkGradientShader::MakeLinear(info.fPoint, info.fColors, + info.fColorOffsets, info.fColorCount, + info.fTileMode, info.fGradientFlags, nullptr)); + break; + default:break; + } + + } + } + if (paint.getColorFilter()) { SkBlendMode mode; SkColor color; @@ -77,43 +107,10 @@ static void applyColorTransform(ColorTransform transform, SkPaint& paint) { } } -class ColorFilterCanvas : public SkPaintFilterCanvas { -public: - ColorFilterCanvas(ColorTransform transform, SkCanvas* canvas) - : SkPaintFilterCanvas(canvas), mTransform(transform) {} - - bool onFilter(SkTCopyOnFirstWrite* paint, Type type) const override { - if (*paint) { - applyColorTransform(mTransform, *(paint->writable())); - } - return true; - } - -private: - ColorTransform mTransform; -}; - -std::unique_ptr makeTransformCanvas(SkCanvas* inCanvas, ColorTransform transform) { - switch (transform) { - case ColorTransform::Light: - return std::make_unique(ColorTransform::Light, inCanvas); - case ColorTransform::Dark: - return std::make_unique(ColorTransform::Dark, inCanvas); - default: - return nullptr; - } -} - -std::unique_ptr makeTransformCanvas(SkCanvas* inCanvas, UsageHint usageHint) { - if (Properties::forceDarkMode) { - switch (usageHint) { - case UsageHint::Unknown: - return makeTransformCanvas(inCanvas, ColorTransform::Light); - case UsageHint::Background: - return makeTransformCanvas(inCanvas, ColorTransform::Dark); - } - } - return nullptr; +bool transformPaint(ColorTransform transform, SkPaint* paint) { + // TODO + applyColorTransform(transform, *paint); + return true; } }; // namespace android::uirenderer \ No newline at end of file diff --git a/libs/hwui/CanvasTransform.h b/libs/hwui/CanvasTransform.h index f71fdfaf3fba..32d9a0594879 100644 --- a/libs/hwui/CanvasTransform.h +++ b/libs/hwui/CanvasTransform.h @@ -34,7 +34,7 @@ enum class ColorTransform { Dark, }; -std::unique_ptr makeTransformCanvas(SkCanvas* inCanvas, ColorTransform transform); -std::unique_ptr makeTransformCanvas(SkCanvas* inCanvas, UsageHint usageHint); +// True if the paint was modified, false otherwise +bool transformPaint(ColorTransform transform, SkPaint* paint); } // namespace android::uirenderer; \ No newline at end of file diff --git a/libs/hwui/DisplayListOps.in b/libs/hwui/DisplayListOps.in new file mode 100644 index 000000000000..f61c1562c6a7 --- /dev/null +++ b/libs/hwui/DisplayListOps.in @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +X(Flush) +X(Save) +X(Restore) +X(SaveLayer) +X(Concat) +X(SetMatrix) +X(Translate) +X(ClipPath) +X(ClipRect) +X(ClipRRect) +X(ClipRegion) +X(DrawPaint) +X(DrawPath) +X(DrawRect) +X(DrawRegion) +X(DrawOval) +X(DrawArc) +X(DrawRRect) +X(DrawDRRect) +X(DrawAnnotation) +X(DrawDrawable) +X(DrawPicture) +X(DrawImage) +X(DrawImageNine) +X(DrawImageRect) +X(DrawImageLattice) +X(DrawText) +X(DrawPosText) +X(DrawPosTextH) +X(DrawTextRSXform) +X(DrawTextBlob) +X(DrawPatch) +X(DrawPoints) +X(DrawVertices) +X(DrawAtlas) +X(DrawShadowRec) \ No newline at end of file diff --git a/libs/hwui/RecordingCanvas.cpp b/libs/hwui/RecordingCanvas.cpp new file mode 100644 index 000000000000..57befc6fa9d7 --- /dev/null +++ b/libs/hwui/RecordingCanvas.cpp @@ -0,0 +1,934 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "RecordingCanvas.h" + +#include "SkCanvas.h" +#include "SkData.h" +#include "SkDrawShadowInfo.h" +#include "SkImage.h" +#include "SkImageFilter.h" +#include "SkMath.h" +#include "SkPicture.h" +#include "SkRSXform.h" +#include "SkRegion.h" +#include "SkTextBlob.h" +#include "SkVertices.h" + +#include + +namespace android { +namespace uirenderer { + +#ifndef SKLITEDL_PAGE +#define SKLITEDL_PAGE 4096 +#endif + +// A stand-in for an optional SkRect which was not set, e.g. bounds for a saveLayer(). +static const SkRect kUnset = {SK_ScalarInfinity, 0, 0, 0}; +static const SkRect* maybe_unset(const SkRect& r) { + return r.left() == SK_ScalarInfinity ? nullptr : &r; +} + +// copy_v(dst, src,n, src,n, ...) copies an arbitrary number of typed srcs into dst. +static void copy_v(void* dst) {} + +template +static void copy_v(void* dst, const S* src, int n, Rest&&... rest) { + SkASSERTF(((uintptr_t)dst & (alignof(S) - 1)) == 0, + "Expected %p to be aligned for at least %zu bytes.", dst, alignof(S)); + sk_careful_memcpy(dst, src, n * sizeof(S)); + copy_v(SkTAddOffset(dst, n * sizeof(S)), std::forward(rest)...); +} + +// Helper for getting back at arrays which have been copy_v'd together after an Op. +template +static const D* pod(const T* op, size_t offset = 0) { + return SkTAddOffset(op + 1, offset); +} + +namespace { + +#define X(T) T, +enum class Type : uint8_t { +#include "DisplayListOps.in" +}; +#undef X + +struct Op { + uint32_t type : 8; + uint32_t skip : 24; +}; +static_assert(sizeof(Op) == 4, ""); + +struct Flush final : Op { + static const auto kType = Type::Flush; + void draw(SkCanvas* c, const SkMatrix&) const { c->flush(); } +}; + +struct Save final : Op { + static const auto kType = Type::Save; + void draw(SkCanvas* c, const SkMatrix&) const { c->save(); } +}; +struct Restore final : Op { + static const auto kType = Type::Restore; + void draw(SkCanvas* c, const SkMatrix&) const { c->restore(); } +}; +struct SaveLayer final : Op { + static const auto kType = Type::SaveLayer; + SaveLayer(const SkRect* bounds, const SkPaint* paint, const SkImageFilter* backdrop, + const SkImage* clipMask, const SkMatrix* clipMatrix, SkCanvas::SaveLayerFlags flags) { + if (bounds) { + this->bounds = *bounds; + } + if (paint) { + this->paint = *paint; + } + this->backdrop = sk_ref_sp(backdrop); + this->clipMask = sk_ref_sp(clipMask); + this->clipMatrix = clipMatrix ? *clipMatrix : SkMatrix::I(); + this->flags = flags; + } + SkRect bounds = kUnset; + SkPaint paint; + sk_sp backdrop; + sk_sp clipMask; + SkMatrix clipMatrix; + SkCanvas::SaveLayerFlags flags; + void draw(SkCanvas* c, const SkMatrix&) const { + c->saveLayer({maybe_unset(bounds), &paint, backdrop.get(), clipMask.get(), + clipMatrix.isIdentity() ? nullptr : &clipMatrix, flags}); + } +}; + +struct Concat final : Op { + static const auto kType = Type::Concat; + Concat(const SkMatrix& matrix) : matrix(matrix) {} + SkMatrix matrix; + void draw(SkCanvas* c, const SkMatrix&) const { c->concat(matrix); } +}; +struct SetMatrix final : Op { + static const auto kType = Type::SetMatrix; + SetMatrix(const SkMatrix& matrix) : matrix(matrix) {} + SkMatrix matrix; + void draw(SkCanvas* c, const SkMatrix& original) const { + c->setMatrix(SkMatrix::Concat(original, matrix)); + } +}; +struct Translate final : Op { + static const auto kType = Type::Translate; + Translate(SkScalar dx, SkScalar dy) : dx(dx), dy(dy) {} + SkScalar dx, dy; + void draw(SkCanvas* c, const SkMatrix&) const { c->translate(dx, dy); } +}; + +struct ClipPath final : Op { + static const auto kType = Type::ClipPath; + ClipPath(const SkPath& path, SkClipOp op, bool aa) : path(path), op(op), aa(aa) {} + SkPath path; + SkClipOp op; + bool aa; + void draw(SkCanvas* c, const SkMatrix&) const { c->clipPath(path, op, aa); } +}; +struct ClipRect final : Op { + static const auto kType = Type::ClipRect; + ClipRect(const SkRect& rect, SkClipOp op, bool aa) : rect(rect), op(op), aa(aa) {} + SkRect rect; + SkClipOp op; + bool aa; + void draw(SkCanvas* c, const SkMatrix&) const { c->clipRect(rect, op, aa); } +}; +struct ClipRRect final : Op { + static const auto kType = Type::ClipRRect; + ClipRRect(const SkRRect& rrect, SkClipOp op, bool aa) : rrect(rrect), op(op), aa(aa) {} + SkRRect rrect; + SkClipOp op; + bool aa; + void draw(SkCanvas* c, const SkMatrix&) const { c->clipRRect(rrect, op, aa); } +}; +struct ClipRegion final : Op { + static const auto kType = Type::ClipRegion; + ClipRegion(const SkRegion& region, SkClipOp op) : region(region), op(op) {} + SkRegion region; + SkClipOp op; + void draw(SkCanvas* c, const SkMatrix&) const { c->clipRegion(region, op); } +}; + +struct DrawPaint final : Op { + static const auto kType = Type::DrawPaint; + DrawPaint(const SkPaint& paint) : paint(paint) {} + SkPaint paint; + void draw(SkCanvas* c, const SkMatrix&) const { c->drawPaint(paint); } +}; +struct DrawPath final : Op { + static const auto kType = Type::DrawPath; + DrawPath(const SkPath& path, const SkPaint& paint) : path(path), paint(paint) {} + SkPath path; + SkPaint paint; + void draw(SkCanvas* c, const SkMatrix&) const { c->drawPath(path, paint); } +}; +struct DrawRect final : Op { + static const auto kType = Type::DrawRect; + DrawRect(const SkRect& rect, const SkPaint& paint) : rect(rect), paint(paint) {} + SkRect rect; + SkPaint paint; + void draw(SkCanvas* c, const SkMatrix&) const { c->drawRect(rect, paint); } +}; +struct DrawRegion final : Op { + static const auto kType = Type::DrawRegion; + DrawRegion(const SkRegion& region, const SkPaint& paint) : region(region), paint(paint) {} + SkRegion region; + SkPaint paint; + void draw(SkCanvas* c, const SkMatrix&) const { c->drawRegion(region, paint); } +}; +struct DrawOval final : Op { + static const auto kType = Type::DrawOval; + DrawOval(const SkRect& oval, const SkPaint& paint) : oval(oval), paint(paint) {} + SkRect oval; + SkPaint paint; + void draw(SkCanvas* c, const SkMatrix&) const { c->drawOval(oval, paint); } +}; +struct DrawArc final : Op { + static const auto kType = Type::DrawArc; + DrawArc(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle, bool useCenter, + const SkPaint& paint) + : oval(oval) + , startAngle(startAngle) + , sweepAngle(sweepAngle) + , useCenter(useCenter) + , paint(paint) {} + SkRect oval; + SkScalar startAngle; + SkScalar sweepAngle; + bool useCenter; + SkPaint paint; + void draw(SkCanvas* c, const SkMatrix&) const { + c->drawArc(oval, startAngle, sweepAngle, useCenter, paint); + } +}; +struct DrawRRect final : Op { + static const auto kType = Type::DrawRRect; + DrawRRect(const SkRRect& rrect, const SkPaint& paint) : rrect(rrect), paint(paint) {} + SkRRect rrect; + SkPaint paint; + void draw(SkCanvas* c, const SkMatrix&) const { c->drawRRect(rrect, paint); } +}; +struct DrawDRRect final : Op { + static const auto kType = Type::DrawDRRect; + DrawDRRect(const SkRRect& outer, const SkRRect& inner, const SkPaint& paint) + : outer(outer), inner(inner), paint(paint) {} + SkRRect outer, inner; + SkPaint paint; + void draw(SkCanvas* c, const SkMatrix&) const { c->drawDRRect(outer, inner, paint); } +}; + +struct DrawAnnotation final : Op { + static const auto kType = Type::DrawAnnotation; + DrawAnnotation(const SkRect& rect, SkData* value) : rect(rect), value(sk_ref_sp(value)) {} + SkRect rect; + sk_sp value; + void draw(SkCanvas* c, const SkMatrix&) const { + c->drawAnnotation(rect, pod(this), value.get()); + } +}; +struct DrawDrawable final : Op { + static const auto kType = Type::DrawDrawable; + DrawDrawable(SkDrawable* drawable, const SkMatrix* matrix) : drawable(sk_ref_sp(drawable)) { + if (matrix) { + this->matrix = *matrix; + } + } + sk_sp drawable; + SkMatrix matrix = SkMatrix::I(); + void draw(SkCanvas* c, const SkMatrix&) const { c->drawDrawable(drawable.get(), &matrix); } +}; +struct DrawPicture final : Op { + static const auto kType = Type::DrawPicture; + DrawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) + : picture(sk_ref_sp(picture)) { + if (matrix) { + this->matrix = *matrix; + } + if (paint) { + this->paint = *paint; + has_paint = true; + } + } + sk_sp picture; + SkMatrix matrix = SkMatrix::I(); + SkPaint paint; + bool has_paint = false; // TODO: why is a default paint not the same? + void draw(SkCanvas* c, const SkMatrix&) const { + c->drawPicture(picture.get(), &matrix, has_paint ? &paint : nullptr); + } +}; + +struct DrawImage final : Op { + static const auto kType = Type::DrawImage; + DrawImage(sk_sp&& image, SkScalar x, SkScalar y, const SkPaint* paint) + : image(std::move(image)), x(x), y(y) { + if (paint) { + this->paint = *paint; + } + } + sk_sp image; + SkScalar x, y; + SkPaint paint; + void draw(SkCanvas* c, const SkMatrix&) const { c->drawImage(image.get(), x, y, &paint); } +}; +struct DrawImageNine final : Op { + static const auto kType = Type::DrawImageNine; + DrawImageNine(sk_sp&& image, const SkIRect& center, const SkRect& dst, + const SkPaint* paint) + : image(std::move(image)), center(center), dst(dst) { + if (paint) { + this->paint = *paint; + } + } + sk_sp image; + SkIRect center; + SkRect dst; + SkPaint paint; + void draw(SkCanvas* c, const SkMatrix&) const { + c->drawImageNine(image.get(), center, dst, &paint); + } +}; +struct DrawImageRect final : Op { + static const auto kType = Type::DrawImageRect; + DrawImageRect(sk_sp&& image, const SkRect* src, const SkRect& dst, + const SkPaint* paint, SkCanvas::SrcRectConstraint constraint) + : image(std::move(image)), dst(dst), constraint(constraint) { + this->src = src ? *src : SkRect::MakeIWH(image->width(), image->height()); + if (paint) { + this->paint = *paint; + } + } + sk_sp image; + SkRect src, dst; + SkPaint paint; + SkCanvas::SrcRectConstraint constraint; + void draw(SkCanvas* c, const SkMatrix&) const { + c->drawImageRect(image.get(), src, dst, &paint, constraint); + } +}; +struct DrawImageLattice final : Op { + static const auto kType = Type::DrawImageLattice; + DrawImageLattice(sk_sp&& image, int xs, int ys, int fs, const SkIRect& src, + const SkRect& dst, const SkPaint* paint) + : image(std::move(image)), xs(xs), ys(ys), fs(fs), src(src), dst(dst) { + if (paint) { + this->paint = *paint; + } + } + sk_sp image; + int xs, ys, fs; + SkIRect src; + SkRect dst; + SkPaint paint; + void draw(SkCanvas* c, const SkMatrix&) const { + auto xdivs = pod(this, 0), ydivs = pod(this, xs * sizeof(int)); + auto colors = (0 == fs) ? nullptr : pod(this, (xs + ys) * sizeof(int)); + auto flags = + (0 == fs) ? nullptr : pod( + this, (xs + ys) * sizeof(int) + fs * sizeof(SkColor)); + c->drawImageLattice(image.get(), {xdivs, ydivs, flags, xs, ys, &src, colors}, dst, &paint); + } +}; + +struct DrawText final : Op { + static const auto kType = Type::DrawText; + DrawText(size_t bytes, SkScalar x, SkScalar y, const SkPaint& paint) + : bytes(bytes), x(x), y(y), paint(paint) {} + size_t bytes; + SkScalar x, y; + SkPaint paint; + void draw(SkCanvas* c, const SkMatrix&) const { + c->drawText(pod(this), bytes, x, y, paint); + } +}; +struct DrawPosText final : Op { + static const auto kType = Type::DrawPosText; + DrawPosText(size_t bytes, const SkPaint& paint, int n) : bytes(bytes), paint(paint), n(n) {} + size_t bytes; + SkPaint paint; + int n; + void draw(SkCanvas* c, const SkMatrix&) const { + auto points = pod(this); + auto text = pod(this, n * sizeof(SkPoint)); + c->drawPosText(text, bytes, points, paint); + } +}; +struct DrawPosTextH final : Op { + static const auto kType = Type::DrawPosTextH; + DrawPosTextH(size_t bytes, SkScalar y, const SkPaint& paint, int n) + : bytes(bytes), y(y), paint(paint), n(n) {} + size_t bytes; + SkScalar y; + SkPaint paint; + int n; + void draw(SkCanvas* c, const SkMatrix&) const { + auto xs = pod(this); + auto text = pod(this, n * sizeof(SkScalar)); + c->drawPosTextH(text, bytes, xs, y, paint); + } +}; +struct DrawTextRSXform final : Op { + static const auto kType = Type::DrawTextRSXform; + DrawTextRSXform(size_t bytes, int xforms, const SkRect* cull, const SkPaint& paint) + : bytes(bytes), xforms(xforms), paint(paint) { + if (cull) { + this->cull = *cull; + } + } + size_t bytes; + int xforms; + SkRect cull = kUnset; + SkPaint paint; + void draw(SkCanvas* c, const SkMatrix&) const { + // For alignment, the SkRSXforms are first in the pod section, followed by the text. + c->drawTextRSXform(pod(this, xforms * sizeof(SkRSXform)), bytes, pod(this), + maybe_unset(cull), paint); + } +}; +struct DrawTextBlob final : Op { + static const auto kType = Type::DrawTextBlob; + DrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y, const SkPaint& paint) + : blob(sk_ref_sp(blob)), x(x), y(y), paint(paint) {} + sk_sp blob; + SkScalar x, y; + SkPaint paint; + void draw(SkCanvas* c, const SkMatrix&) const { c->drawTextBlob(blob.get(), x, y, paint); } +}; + +struct DrawPatch final : Op { + static const auto kType = Type::DrawPatch; + DrawPatch(const SkPoint cubics[12], const SkColor colors[4], const SkPoint texs[4], + SkBlendMode bmode, const SkPaint& paint) + : xfermode(bmode), paint(paint) { + copy_v(this->cubics, cubics, 12); + if (colors) { + copy_v(this->colors, colors, 4); + has_colors = true; + } + if (texs) { + copy_v(this->texs, texs, 4); + has_texs = true; + } + } + SkPoint cubics[12]; + SkColor colors[4]; + SkPoint texs[4]; + SkBlendMode xfermode; + SkPaint paint; + bool has_colors = false; + bool has_texs = false; + void draw(SkCanvas* c, const SkMatrix&) const { + c->drawPatch(cubics, has_colors ? colors : nullptr, has_texs ? texs : nullptr, xfermode, + paint); + } +}; +struct DrawPoints final : Op { + static const auto kType = Type::DrawPoints; + DrawPoints(SkCanvas::PointMode mode, size_t count, const SkPaint& paint) + : mode(mode), count(count), paint(paint) {} + SkCanvas::PointMode mode; + size_t count; + SkPaint paint; + void draw(SkCanvas* c, const SkMatrix&) const { + c->drawPoints(mode, count, pod(this), paint); + } +}; +struct DrawVertices final : Op { + static const auto kType = Type::DrawVertices; + DrawVertices(const SkVertices* v, int bc, SkBlendMode m, const SkPaint& p) + : vertices(sk_ref_sp(const_cast(v))), boneCount(bc), mode(m), paint(p) {} + sk_sp vertices; + int boneCount; + SkBlendMode mode; + SkPaint paint; + void draw(SkCanvas* c, const SkMatrix&) const { + c->drawVertices(vertices, pod(this), boneCount, mode, paint); + } +}; +struct DrawAtlas final : Op { + static const auto kType = Type::DrawAtlas; + DrawAtlas(const SkImage* atlas, int count, SkBlendMode xfermode, const SkRect* cull, + const SkPaint* paint, bool has_colors) + : atlas(sk_ref_sp(atlas)), count(count), xfermode(xfermode), has_colors(has_colors) { + if (cull) { + this->cull = *cull; + } + if (paint) { + this->paint = *paint; + } + } + sk_sp atlas; + int count; + SkBlendMode xfermode; + SkRect cull = kUnset; + SkPaint paint; + bool has_colors; + void draw(SkCanvas* c, const SkMatrix&) const { + auto xforms = pod(this, 0); + auto texs = pod(this, count * sizeof(SkRSXform)); + auto colors = has_colors ? pod(this, count * (sizeof(SkRSXform) + sizeof(SkRect))) + : nullptr; + c->drawAtlas(atlas.get(), xforms, texs, colors, count, xfermode, maybe_unset(cull), &paint); + } +}; +struct DrawShadowRec final : Op { + static const auto kType = Type::DrawShadowRec; + DrawShadowRec(const SkPath& path, const SkDrawShadowRec& rec) : fPath(path), fRec(rec) {} + SkPath fPath; + SkDrawShadowRec fRec; + void draw(SkCanvas* c, const SkMatrix&) const { c->private_draw_shadow_rec(fPath, fRec); } +}; +} + +template +void* DisplayListData::push(size_t pod, Args&&... args) { + size_t skip = SkAlignPtr(sizeof(T) + pod); + SkASSERT(skip < (1 << 24)); + if (fUsed + skip > fReserved) { + static_assert(SkIsPow2(SKLITEDL_PAGE), "This math needs updating for non-pow2."); + // Next greater multiple of SKLITEDL_PAGE. + fReserved = (fUsed + skip + SKLITEDL_PAGE) & ~(SKLITEDL_PAGE - 1); + fBytes.realloc(fReserved); + } + SkASSERT(fUsed + skip <= fReserved); + auto op = (T*)(fBytes.get() + fUsed); + fUsed += skip; + new (op) T{std::forward(args)...}; + op->type = (uint32_t)T::kType; + op->skip = skip; + return op + 1; +} + +template +inline void DisplayListData::map(const Fn fns[], Args... args) const { + auto end = fBytes.get() + fUsed; + for (const uint8_t* ptr = fBytes.get(); ptr < end;) { + auto op = (const Op*)ptr; + auto type = op->type; + auto skip = op->skip; + if (auto fn = fns[type]) { // We replace no-op functions with nullptrs + fn(op, args...); // to avoid the overhead of a pointless call. + } + ptr += skip; + } +} + +void DisplayListData::flush() { + this->push(0); +} + +void DisplayListData::save() { + this->push(0); +} +void DisplayListData::restore() { + this->push(0); +} +void DisplayListData::saveLayer(const SkRect* bounds, const SkPaint* paint, + const SkImageFilter* backdrop, const SkImage* clipMask, + const SkMatrix* clipMatrix, SkCanvas::SaveLayerFlags flags) { + this->push(0, bounds, paint, backdrop, clipMask, clipMatrix, flags); +} + +void DisplayListData::concat(const SkMatrix& matrix) { + this->push(0, matrix); +} +void DisplayListData::setMatrix(const SkMatrix& matrix) { + this->push(0, matrix); +} +void DisplayListData::translate(SkScalar dx, SkScalar dy) { + this->push(0, dx, dy); +} + +void DisplayListData::clipPath(const SkPath& path, SkClipOp op, bool aa) { + this->push(0, path, op, aa); +} +void DisplayListData::clipRect(const SkRect& rect, SkClipOp op, bool aa) { + this->push(0, rect, op, aa); +} +void DisplayListData::clipRRect(const SkRRect& rrect, SkClipOp op, bool aa) { + this->push(0, rrect, op, aa); +} +void DisplayListData::clipRegion(const SkRegion& region, SkClipOp op) { + this->push(0, region, op); +} + +void DisplayListData::drawPaint(const SkPaint& paint) { + this->push(0, paint); +} +void DisplayListData::drawPath(const SkPath& path, const SkPaint& paint) { + this->push(0, path, paint); +} +void DisplayListData::drawRect(const SkRect& rect, const SkPaint& paint) { + this->push(0, rect, paint); +} +void DisplayListData::drawRegion(const SkRegion& region, const SkPaint& paint) { + this->push(0, region, paint); +} +void DisplayListData::drawOval(const SkRect& oval, const SkPaint& paint) { + this->push(0, oval, paint); +} +void DisplayListData::drawArc(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle, + bool useCenter, const SkPaint& paint) { + this->push(0, oval, startAngle, sweepAngle, useCenter, paint); +} +void DisplayListData::drawRRect(const SkRRect& rrect, const SkPaint& paint) { + this->push(0, rrect, paint); +} +void DisplayListData::drawDRRect(const SkRRect& outer, const SkRRect& inner, const SkPaint& paint) { + this->push(0, outer, inner, paint); +} + +void DisplayListData::drawAnnotation(const SkRect& rect, const char* key, SkData* value) { + size_t bytes = strlen(key) + 1; + void* pod = this->push(bytes, rect, value); + copy_v(pod, key, bytes); +} +void DisplayListData::drawDrawable(SkDrawable* drawable, const SkMatrix* matrix) { + this->push(0, drawable, matrix); +} +void DisplayListData::drawPicture(const SkPicture* picture, const SkMatrix* matrix, + const SkPaint* paint) { + this->push(0, picture, matrix, paint); +} +void DisplayListData::drawImage(sk_sp image, SkScalar x, SkScalar y, + const SkPaint* paint) { + this->push(0, std::move(image), x, y, paint); +} +void DisplayListData::drawImageNine(sk_sp image, const SkIRect& center, + const SkRect& dst, const SkPaint* paint) { + this->push(0, std::move(image), center, dst, paint); +} +void DisplayListData::drawImageRect(sk_sp image, const SkRect* src, + const SkRect& dst, const SkPaint* paint, + SkCanvas::SrcRectConstraint constraint) { + this->push(0, std::move(image), src, dst, paint, constraint); +} +void DisplayListData::drawImageLattice(sk_sp image, const SkCanvas::Lattice& lattice, + const SkRect& dst, const SkPaint* paint) { + int xs = lattice.fXCount, ys = lattice.fYCount; + int fs = lattice.fRectTypes ? (xs + 1) * (ys + 1) : 0; + size_t bytes = (xs + ys) * sizeof(int) + fs * sizeof(SkCanvas::Lattice::RectType) + + fs * sizeof(SkColor); + SkASSERT(lattice.fBounds); + void* pod = this->push(bytes, std::move(image), xs, ys, fs, *lattice.fBounds, + dst, paint); + copy_v(pod, lattice.fXDivs, xs, lattice.fYDivs, ys, lattice.fColors, fs, lattice.fRectTypes, + fs); +} + +void DisplayListData::drawText(const void* text, size_t bytes, SkScalar x, SkScalar y, + const SkPaint& paint) { + void* pod = this->push(bytes, bytes, x, y, paint); + copy_v(pod, (const char*)text, bytes); +} +void DisplayListData::drawPosText(const void* text, size_t bytes, const SkPoint pos[], + const SkPaint& paint) { + int n = paint.countText(text, bytes); + void* pod = this->push(n * sizeof(SkPoint) + bytes, bytes, paint, n); + copy_v(pod, pos, n, (const char*)text, bytes); +} +void DisplayListData::drawPosTextH(const void* text, size_t bytes, const SkScalar xs[], SkScalar y, + const SkPaint& paint) { + int n = paint.countText(text, bytes); + void* pod = this->push(n * sizeof(SkScalar) + bytes, bytes, y, paint, n); + copy_v(pod, xs, n, (const char*)text, bytes); +} +void DisplayListData::drawTextRSXform(const void* text, size_t bytes, const SkRSXform xforms[], + const SkRect* cull, const SkPaint& paint) { + int n = paint.countText(text, bytes); + void* pod = this->push(bytes + n * sizeof(SkRSXform), bytes, n, cull, paint); + copy_v(pod, xforms, n, (const char*)text, bytes); +} +void DisplayListData::drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y, + const SkPaint& paint) { + this->push(0, blob, x, y, paint); +} + +void DisplayListData::drawPatch(const SkPoint points[12], const SkColor colors[4], + const SkPoint texs[4], SkBlendMode bmode, const SkPaint& paint) { + this->push(0, points, colors, texs, bmode, paint); +} +void DisplayListData::drawPoints(SkCanvas::PointMode mode, size_t count, const SkPoint points[], + const SkPaint& paint) { + void* pod = this->push(count * sizeof(SkPoint), mode, count, paint); + copy_v(pod, points, count); +} +void DisplayListData::drawVertices(const SkVertices* vertices, const SkVertices::Bone bones[], + int boneCount, SkBlendMode mode, const SkPaint& paint) { + void* pod = this->push(boneCount * sizeof(SkVertices::Bone), vertices, boneCount, + mode, paint); + copy_v(pod, bones, boneCount); +} +void DisplayListData::drawAtlas(const SkImage* atlas, const SkRSXform xforms[], const SkRect texs[], + const SkColor colors[], int count, SkBlendMode xfermode, + const SkRect* cull, const SkPaint* paint) { + size_t bytes = count * (sizeof(SkRSXform) + sizeof(SkRect)); + if (colors) { + bytes += count * sizeof(SkColor); + } + void* pod = + this->push(bytes, atlas, count, xfermode, cull, paint, colors != nullptr); + copy_v(pod, xforms, count, texs, count, colors, colors ? count : 0); +} +void DisplayListData::drawShadowRec(const SkPath& path, const SkDrawShadowRec& rec) { + this->push(0, path, rec); +} + +typedef void (*draw_fn)(const void*, SkCanvas*, const SkMatrix&); +typedef void (*void_fn)(const void*); +typedef void (*color_transform_fn)(const void*, ColorTransform); + +// All ops implement draw(). +#define X(T) \ + [](const void* op, SkCanvas* c, const SkMatrix& original) { \ + ((const T*)op)->draw(c, original); \ + }, +static const draw_fn draw_fns[] = { +#include "DisplayListOps.in" +}; +#undef X + +// Most state ops (matrix, clip, save, restore) have a trivial destructor. +#define X(T) \ + !std::is_trivially_destructible::value ? [](const void* op) { ((const T*)op)->~T(); } \ + : (void_fn) nullptr, + +static const void_fn dtor_fns[] = { +#include "DisplayListOps.in" +}; +#undef X + +void DisplayListData::draw(SkCanvas* canvas) const { + SkAutoCanvasRestore acr(canvas, false); + this->map(draw_fns, canvas, canvas->getTotalMatrix()); +} + +DisplayListData::~DisplayListData() { + this->reset(); +} + +void DisplayListData::reset() { + this->map(dtor_fns); + + // Leave fBytes and fReserved alone. + fUsed = 0; +} + +template +using has_paint_t = decltype(std::declval().paint); + +template +constexpr color_transform_fn colorTransformForOp() { + if + constexpr(std::experimental::is_detected_v) { + return [](const void* op, ColorTransform transform) { + // TODO: We should be const. Or not. Or just use a different map + // Unclear, but this is the quick fix + transformPaint(transform, + const_cast(&(reinterpret_cast(op)->paint))); + }; + } + else { + return nullptr; + } +} + +#define X(T) colorTransformForOp(), +static const color_transform_fn color_transform_fns[] = { +#include "DisplayListOps.in" +}; +#undef X + +void DisplayListData::applyColorTransform(ColorTransform transform) { + this->map(color_transform_fns, transform); +} + +RecordingCanvas::RecordingCanvas() : INHERITED(1, 1), fDL(nullptr) {} + +void RecordingCanvas::reset(DisplayListData* dl, const SkIRect& bounds) { + this->resetCanvas(bounds.right(), bounds.bottom()); + fDL = dl; +} + +sk_sp RecordingCanvas::onNewSurface(const SkImageInfo&, const SkSurfaceProps&) { + return nullptr; +} + +void RecordingCanvas::onFlush() { + fDL->flush(); +} + +void RecordingCanvas::willSave() { + fDL->save(); +} +SkCanvas::SaveLayerStrategy RecordingCanvas::getSaveLayerStrategy(const SaveLayerRec& rec) { + fDL->saveLayer(rec.fBounds, rec.fPaint, rec.fBackdrop, rec.fClipMask, rec.fClipMatrix, + rec.fSaveLayerFlags); + return SkCanvas::kNoLayer_SaveLayerStrategy; +} +void RecordingCanvas::willRestore() { + fDL->restore(); +} + +void RecordingCanvas::didConcat(const SkMatrix& matrix) { + fDL->concat(matrix); +} +void RecordingCanvas::didSetMatrix(const SkMatrix& matrix) { + fDL->setMatrix(matrix); +} +void RecordingCanvas::didTranslate(SkScalar dx, SkScalar dy) { + fDL->translate(dx, dy); +} + +void RecordingCanvas::onClipRect(const SkRect& rect, SkClipOp op, ClipEdgeStyle style) { + fDL->clipRect(rect, op, style == kSoft_ClipEdgeStyle); + this->INHERITED::onClipRect(rect, op, style); +} +void RecordingCanvas::onClipRRect(const SkRRect& rrect, SkClipOp op, ClipEdgeStyle style) { + fDL->clipRRect(rrect, op, style == kSoft_ClipEdgeStyle); + this->INHERITED::onClipRRect(rrect, op, style); +} +void RecordingCanvas::onClipPath(const SkPath& path, SkClipOp op, ClipEdgeStyle style) { + fDL->clipPath(path, op, style == kSoft_ClipEdgeStyle); + this->INHERITED::onClipPath(path, op, style); +} +void RecordingCanvas::onClipRegion(const SkRegion& region, SkClipOp op) { + fDL->clipRegion(region, op); + this->INHERITED::onClipRegion(region, op); +} + +void RecordingCanvas::onDrawPaint(const SkPaint& paint) { + fDL->drawPaint(paint); +} +void RecordingCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) { + fDL->drawPath(path, paint); +} +void RecordingCanvas::onDrawRect(const SkRect& rect, const SkPaint& paint) { + fDL->drawRect(rect, paint); +} +void RecordingCanvas::onDrawRegion(const SkRegion& region, const SkPaint& paint) { + fDL->drawRegion(region, paint); +} +void RecordingCanvas::onDrawOval(const SkRect& oval, const SkPaint& paint) { + fDL->drawOval(oval, paint); +} +void RecordingCanvas::onDrawArc(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle, + bool useCenter, const SkPaint& paint) { + fDL->drawArc(oval, startAngle, sweepAngle, useCenter, paint); +} +void RecordingCanvas::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) { + fDL->drawRRect(rrect, paint); +} +void RecordingCanvas::onDrawDRRect(const SkRRect& out, const SkRRect& in, const SkPaint& paint) { + fDL->drawDRRect(out, in, paint); +} + +void RecordingCanvas::onDrawDrawable(SkDrawable* drawable, const SkMatrix* matrix) { + fDL->drawDrawable(drawable, matrix); +} +void RecordingCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix, + const SkPaint* paint) { + fDL->drawPicture(picture, matrix, paint); +} +void RecordingCanvas::onDrawAnnotation(const SkRect& rect, const char key[], SkData* val) { + fDL->drawAnnotation(rect, key, val); +} + +void RecordingCanvas::onDrawText(const void* text, size_t bytes, SkScalar x, SkScalar y, + const SkPaint& paint) { + fDL->drawText(text, bytes, x, y, paint); +} +void RecordingCanvas::onDrawPosText(const void* text, size_t bytes, const SkPoint pos[], + const SkPaint& paint) { + fDL->drawPosText(text, bytes, pos, paint); +} +void RecordingCanvas::onDrawPosTextH(const void* text, size_t bytes, const SkScalar xs[], + SkScalar y, const SkPaint& paint) { + fDL->drawPosTextH(text, bytes, xs, y, paint); +} +void RecordingCanvas::onDrawTextRSXform(const void* text, size_t bytes, const SkRSXform xform[], + const SkRect* cull, const SkPaint& paint) { + fDL->drawTextRSXform(text, bytes, xform, cull, paint); +} +void RecordingCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y, + const SkPaint& paint) { + fDL->drawTextBlob(blob, x, y, paint); +} + +void RecordingCanvas::onDrawBitmap(const SkBitmap& bm, SkScalar x, SkScalar y, + const SkPaint* paint) { + fDL->drawImage(SkImage::MakeFromBitmap(bm), x, y, paint); +} +void RecordingCanvas::onDrawBitmapNine(const SkBitmap& bm, const SkIRect& center, const SkRect& dst, + const SkPaint* paint) { + fDL->drawImageNine(SkImage::MakeFromBitmap(bm), center, dst, paint); +} +void RecordingCanvas::onDrawBitmapRect(const SkBitmap& bm, const SkRect* src, const SkRect& dst, + const SkPaint* paint, SrcRectConstraint constraint) { + fDL->drawImageRect(SkImage::MakeFromBitmap(bm), src, dst, paint, constraint); +} +void RecordingCanvas::onDrawBitmapLattice(const SkBitmap& bm, const SkCanvas::Lattice& lattice, + const SkRect& dst, const SkPaint* paint) { + fDL->drawImageLattice(SkImage::MakeFromBitmap(bm), lattice, dst, paint); +} + +void RecordingCanvas::onDrawImage(const SkImage* img, SkScalar x, SkScalar y, + const SkPaint* paint) { + fDL->drawImage(sk_ref_sp(img), x, y, paint); +} +void RecordingCanvas::onDrawImageNine(const SkImage* img, const SkIRect& center, const SkRect& dst, + const SkPaint* paint) { + fDL->drawImageNine(sk_ref_sp(img), center, dst, paint); +} +void RecordingCanvas::onDrawImageRect(const SkImage* img, const SkRect* src, const SkRect& dst, + const SkPaint* paint, SrcRectConstraint constraint) { + fDL->drawImageRect(sk_ref_sp(img), src, dst, paint, constraint); +} +void RecordingCanvas::onDrawImageLattice(const SkImage* img, const SkCanvas::Lattice& lattice, + const SkRect& dst, const SkPaint* paint) { + fDL->drawImageLattice(sk_ref_sp(img), lattice, dst, paint); +} + +void RecordingCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4], + const SkPoint texCoords[4], SkBlendMode bmode, + const SkPaint& paint) { + fDL->drawPatch(cubics, colors, texCoords, bmode, paint); +} +void RecordingCanvas::onDrawPoints(SkCanvas::PointMode mode, size_t count, const SkPoint pts[], + const SkPaint& paint) { + fDL->drawPoints(mode, count, pts, paint); +} +void RecordingCanvas::onDrawVerticesObject(const SkVertices* vertices, + const SkVertices::Bone bones[], int boneCount, + SkBlendMode mode, const SkPaint& paint) { + fDL->drawVertices(vertices, bones, boneCount, mode, paint); +} +void RecordingCanvas::onDrawAtlas(const SkImage* atlas, const SkRSXform xforms[], + const SkRect texs[], const SkColor colors[], int count, + SkBlendMode bmode, const SkRect* cull, const SkPaint* paint) { + fDL->drawAtlas(atlas, xforms, texs, colors, count, bmode, cull, paint); +} +void RecordingCanvas::onDrawShadowRec(const SkPath& path, const SkDrawShadowRec& rec) { + fDL->drawShadowRec(path, rec); +} + +}; // namespace uirenderer +}; // namespace android diff --git a/libs/hwui/RecordingCanvas.h b/libs/hwui/RecordingCanvas.h new file mode 100644 index 000000000000..32ce1d333448 --- /dev/null +++ b/libs/hwui/RecordingCanvas.h @@ -0,0 +1,203 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "CanvasTransform.h" +#include "hwui/Canvas.h" +#include "utils/Macros.h" +#include "utils/TypeLogic.h" + +#include "SkCanvas.h" +#include "SkCanvasVirtualEnforcer.h" +#include "SkDrawable.h" +#include "SkNoDrawCanvas.h" +#include "SkPaint.h" +#include "SkPath.h" +#include "SkRect.h" +#include "SkTDArray.h" +#include "SkTemplates.h" + +#include + +namespace android { +namespace uirenderer { + +enum class DisplayListOpType : uint8_t { +#define X(T) T, +#include "DisplayListOps.in" +#undef X +}; + +struct DisplayListOp { + const uint8_t type : 8; + const uint32_t skip : 24; +}; + +static_assert(sizeof(DisplayListOp) == 4); + +class RecordingCanvas; + +class DisplayListData final { +public: + ~DisplayListData(); + + void draw(SkCanvas* canvas) const; + + void reset(); + bool empty() const { return fUsed == 0; } + + void applyColorTransform(ColorTransform transform); + +private: + friend class RecordingCanvas; + + void flush(); + + void save(); + void saveLayer(const SkRect*, const SkPaint*, const SkImageFilter*, const SkImage*, + const SkMatrix*, SkCanvas::SaveLayerFlags); + void restore(); + + void concat(const SkMatrix&); + void setMatrix(const SkMatrix&); + void translate(SkScalar, SkScalar); + void translateZ(SkScalar); + + void clipPath(const SkPath&, SkClipOp, bool aa); + void clipRect(const SkRect&, SkClipOp, bool aa); + void clipRRect(const SkRRect&, SkClipOp, bool aa); + void clipRegion(const SkRegion&, SkClipOp); + + void drawPaint(const SkPaint&); + void drawPath(const SkPath&, const SkPaint&); + void drawRect(const SkRect&, const SkPaint&); + void drawRegion(const SkRegion&, const SkPaint&); + void drawOval(const SkRect&, const SkPaint&); + void drawArc(const SkRect&, SkScalar, SkScalar, bool, const SkPaint&); + void drawRRect(const SkRRect&, const SkPaint&); + void drawDRRect(const SkRRect&, const SkRRect&, const SkPaint&); + + void drawAnnotation(const SkRect&, const char*, SkData*); + void drawDrawable(SkDrawable*, const SkMatrix*); + void drawPicture(const SkPicture*, const SkMatrix*, const SkPaint*); + + void drawText(const void*, size_t, SkScalar, SkScalar, const SkPaint&); + void drawPosText(const void*, size_t, const SkPoint[], const SkPaint&); + void drawPosTextH(const void*, size_t, const SkScalar[], SkScalar, const SkPaint&); + void drawTextRSXform(const void*, size_t, const SkRSXform[], const SkRect*, const SkPaint&); + void drawTextBlob(const SkTextBlob*, SkScalar, SkScalar, const SkPaint&); + + void drawImage(sk_sp, SkScalar, SkScalar, const SkPaint*); + void drawImageNine(sk_sp, const SkIRect&, const SkRect&, const SkPaint*); + void drawImageRect(sk_sp, const SkRect*, const SkRect&, const SkPaint*, + SkCanvas::SrcRectConstraint); + void drawImageLattice(sk_sp, const SkCanvas::Lattice&, const SkRect&, + const SkPaint*); + + void drawPatch(const SkPoint[12], const SkColor[4], const SkPoint[4], SkBlendMode, + const SkPaint&); + void drawPoints(SkCanvas::PointMode, size_t, const SkPoint[], const SkPaint&); + void drawVertices(const SkVertices*, const SkVertices::Bone bones[], int boneCount, SkBlendMode, + const SkPaint&); + void drawAtlas(const SkImage*, const SkRSXform[], const SkRect[], const SkColor[], int, + SkBlendMode, const SkRect*, const SkPaint*); + void drawShadowRec(const SkPath&, const SkDrawShadowRec&); + + template + void* push(size_t, Args&&...); + + template + void map(const Fn[], Args...) const; + + SkAutoTMalloc fBytes; + size_t fUsed = 0; + size_t fReserved = 0; +}; + +class RecordingCanvas final : public SkCanvasVirtualEnforcer { +public: + RecordingCanvas(); + void reset(DisplayListData*, const SkIRect& bounds); + + sk_sp onNewSurface(const SkImageInfo&, const SkSurfaceProps&) override; + + void willSave() override; + SaveLayerStrategy getSaveLayerStrategy(const SaveLayerRec&) override; + void willRestore() override; + + void onFlush() override; + + void didConcat(const SkMatrix&) override; + void didSetMatrix(const SkMatrix&) override; + void didTranslate(SkScalar, SkScalar) override; + + void onClipRect(const SkRect&, SkClipOp, ClipEdgeStyle) override; + void onClipRRect(const SkRRect&, SkClipOp, ClipEdgeStyle) override; + void onClipPath(const SkPath&, SkClipOp, ClipEdgeStyle) override; + void onClipRegion(const SkRegion&, SkClipOp) override; + + void onDrawPaint(const SkPaint&) override; + void onDrawPath(const SkPath&, const SkPaint&) override; + void onDrawRect(const SkRect&, const SkPaint&) override; + void onDrawRegion(const SkRegion&, const SkPaint&) override; + void onDrawOval(const SkRect&, const SkPaint&) override; + void onDrawArc(const SkRect&, SkScalar, SkScalar, bool, const SkPaint&) override; + void onDrawRRect(const SkRRect&, const SkPaint&) override; + void onDrawDRRect(const SkRRect&, const SkRRect&, const SkPaint&) override; + + void onDrawDrawable(SkDrawable*, const SkMatrix*) override; + void onDrawPicture(const SkPicture*, const SkMatrix*, const SkPaint*) override; + void onDrawAnnotation(const SkRect&, const char[], SkData*) override; + + void onDrawText(const void*, size_t, SkScalar x, SkScalar y, const SkPaint&) override; + void onDrawPosText(const void*, size_t, const SkPoint[], const SkPaint&) override; + void onDrawPosTextH(const void*, size_t, const SkScalar[], SkScalar, const SkPaint&) override; + + void onDrawTextRSXform(const void*, size_t, const SkRSXform[], const SkRect*, + const SkPaint&) override; + void onDrawTextBlob(const SkTextBlob*, SkScalar, SkScalar, const SkPaint&) override; + + void onDrawBitmap(const SkBitmap&, SkScalar, SkScalar, const SkPaint*) override; + void onDrawBitmapLattice(const SkBitmap&, const Lattice&, const SkRect&, + const SkPaint*) override; + void onDrawBitmapNine(const SkBitmap&, const SkIRect&, const SkRect&, const SkPaint*) override; + void onDrawBitmapRect(const SkBitmap&, const SkRect*, const SkRect&, const SkPaint*, + SrcRectConstraint) override; + + void onDrawImage(const SkImage*, SkScalar, SkScalar, const SkPaint*) override; + void onDrawImageLattice(const SkImage*, const Lattice&, const SkRect&, const SkPaint*) override; + void onDrawImageNine(const SkImage*, const SkIRect&, const SkRect&, const SkPaint*) override; + void onDrawImageRect(const SkImage*, const SkRect*, const SkRect&, const SkPaint*, + SrcRectConstraint) override; + + void onDrawPatch(const SkPoint[12], const SkColor[4], const SkPoint[4], SkBlendMode, + const SkPaint&) override; + void onDrawPoints(PointMode, size_t count, const SkPoint pts[], const SkPaint&) override; + void onDrawVerticesObject(const SkVertices*, const SkVertices::Bone bones[], int boneCount, + SkBlendMode, const SkPaint&) override; + void onDrawAtlas(const SkImage*, const SkRSXform[], const SkRect[], const SkColor[], int, + SkBlendMode, const SkRect*, const SkPaint*) override; + void onDrawShadowRec(const SkPath&, const SkDrawShadowRec&) override; + +private: + typedef SkCanvasVirtualEnforcer INHERITED; + + DisplayListData* fDL; +}; + +}; // namespace uirenderer +}; // namespace android \ No newline at end of file diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp index a2e1f6041b62..d5afb2011429 100644 --- a/libs/hwui/RenderNode.cpp +++ b/libs/hwui/RenderNode.cpp @@ -272,6 +272,20 @@ void RenderNode::syncDisplayList(TreeObserver& observer, TreeInfo* info) { mStagingDisplayList = nullptr; if (mDisplayList) { mDisplayList->syncContents(); + if (CC_UNLIKELY(Properties::forceDarkMode)) { + auto usage = usageHint(); + if (usage == UsageHint::Unknown) { + if (mDisplayList->mChildNodes.size() > 1) { + usage = UsageHint::Background; + } else if (mDisplayList->mChildNodes.size() == 1 && + mDisplayList->mChildNodes.front().getRenderNode()->usageHint() != + UsageHint::Background) { + usage = UsageHint::Background; + } + } + mDisplayList->mDisplayList.applyColorTransform( + usage == UsageHint::Background ? ColorTransform::Dark : ColorTransform::Light); + } } } diff --git a/libs/hwui/RenderNode.h b/libs/hwui/RenderNode.h index 8393288d2ffd..83b0c2278151 100644 --- a/libs/hwui/RenderNode.h +++ b/libs/hwui/RenderNode.h @@ -209,13 +209,9 @@ public: void output(std::ostream& output, uint32_t level); - void setUsageHint(UsageHint usageHint) { - mUsageHint = usageHint; - } + void setUsageHint(UsageHint usageHint) { mUsageHint = usageHint; } - UsageHint usageHint() const { - return mUsageHint; - } + UsageHint usageHint() const { return mUsageHint; } private: void computeOrderingImpl(RenderNodeOp* opState, diff --git a/libs/hwui/hwui/Bitmap.cpp b/libs/hwui/hwui/Bitmap.cpp index e7d12de44c0c..3939696692d2 100644 --- a/libs/hwui/hwui/Bitmap.cpp +++ b/libs/hwui/hwui/Bitmap.cpp @@ -34,8 +34,8 @@ #include #include -#include #include +#include namespace android { @@ -333,17 +333,17 @@ sk_sp Bitmap::makeImage(sk_sp* outputColorFilter) { // TODO: Move this to the canvas (or other?) layer where we have the target lightness // mode and can selectively do the right thing. - if (palette() != BitmapPalette::Unknown && uirenderer::Properties::forceDarkMode) { - SkHighContrastConfig config; - config.fInvertStyle = SkHighContrastConfig::InvertStyle::kInvertLightness; - *outputColorFilter = SkHighContrastFilter::Make(config)->makeComposed(*outputColorFilter); - } + // if (palette() != BitmapPalette::Unknown && uirenderer::Properties::forceDarkMode) { + // SkHighContrastConfig config; + // config.fInvertStyle = SkHighContrastConfig::InvertStyle::kInvertLightness; + // *outputColorFilter = + // SkHighContrastFilter::Make(config)->makeComposed(*outputColorFilter); + // } return image; } class MinMaxAverage { public: - void add(float sample) { if (mCount == 0) { mMin = sample; @@ -356,21 +356,13 @@ public: mCount++; } - float average() { - return mTotal / mCount; - } + float average() { return mTotal / mCount; } - float min() { - return mMin; - } + float min() { return mMin; } - float max() { - return mMax; - } + float max() { return mMax; } - float delta() { - return mMax - mMin; - } + float delta() { return mMax - mMin; } private: float mMin = 0.0f; @@ -413,14 +405,15 @@ BitmapPalette Bitmap::computePalette(const SkImageInfo& info, const void* addr, // TODO: Tune the coverage threshold if (sampledCount < 5) { ALOGV("Not enough samples, only found %d for image sized %dx%d, format = %d, alpha = %d", - sampledCount, info.width(), info.height(), (int) info.colorType(), (int) info.alphaType()); + sampledCount, info.width(), info.height(), (int)info.colorType(), + (int)info.alphaType()); return BitmapPalette::Unknown; } - ALOGV("samples = %d, hue [min = %f, max = %f, avg = %f]; saturation [min = %f, max = %f, avg = %f]", - sampledCount, - hue.min(), hue.max(), hue.average(), - saturation.min(), saturation.max(), saturation.average()); + ALOGV("samples = %d, hue [min = %f, max = %f, avg = %f]; saturation [min = %f, max = %f, avg = " + "%f]", + sampledCount, hue.min(), hue.max(), hue.average(), saturation.min(), saturation.max(), + saturation.average()); if (hue.delta() <= 20 && saturation.delta() <= .1f) { if (value.average() >= .5f) { diff --git a/libs/hwui/hwui/Bitmap.h b/libs/hwui/hwui/Bitmap.h index d2680429a1e9..170335da7d7c 100644 --- a/libs/hwui/hwui/Bitmap.h +++ b/libs/hwui/hwui/Bitmap.h @@ -69,7 +69,8 @@ public: Bitmap(void* address, void* context, FreeFunc freeFunc, const SkImageInfo& info, size_t rowBytes); Bitmap(void* address, int fd, size_t mappedSize, const SkImageInfo& info, size_t rowBytes); - Bitmap(GraphicBuffer* buffer, const SkImageInfo& info, BitmapPalette palette = BitmapPalette::Unknown); + Bitmap(GraphicBuffer* buffer, const SkImageInfo& info, + BitmapPalette palette = BitmapPalette::Unknown); int rowBytesAsPixels() const { return rowBytes() >> mInfo.shiftPerPixel(); } diff --git a/libs/hwui/pipeline/skia/SkiaDisplayList.h b/libs/hwui/pipeline/skia/SkiaDisplayList.h index 6eff5895a620..4f30f98e147d 100644 --- a/libs/hwui/pipeline/skia/SkiaDisplayList.h +++ b/libs/hwui/pipeline/skia/SkiaDisplayList.h @@ -18,12 +18,11 @@ #include "hwui/AnimatedImageDrawable.h" #include "GLFunctorDrawable.h" +#include "RecordingCanvas.h" #include "RenderNodeDrawable.h" #include "TreeInfo.h" #include "utils/LinearAllocator.h" -#include -#include #include namespace android { @@ -140,7 +139,7 @@ public: */ inline bool containsProjectionReceiver() const { return mProjectionReceiver; } - void attachRecorder(SkLiteRecorder* recorder, const SkIRect& bounds) { + void attachRecorder(RecordingCanvas* recorder, const SkIRect& bounds) { recorder->reset(&mDisplayList, bounds); } @@ -160,7 +159,7 @@ public: std::vector mMutableImages; std::vector mVectorDrawables; std::vector mAnimatedImages; - SkLiteDL mDisplayList; + DisplayListData mDisplayList; // mProjectionReceiver points to a child node (stored in mChildNodes) that is as a projection // receiver. It is set at record time and used at both prepare and draw tree traversals to diff --git a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp index b9748afc6cb4..83d7e6a361bc 100644 --- a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp +++ b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp @@ -45,21 +45,13 @@ void SkiaRecordingCanvas::initDisplayList(uirenderer::RenderNode* renderNode, in } mDisplayList->attachRecorder(&mRecorder, SkIRect::MakeWH(width, height)); - SkCanvas* canvas = &mRecorder; - if (renderNode) { - mWrappedCanvas = makeTransformCanvas(&mRecorder, renderNode->usageHint()); - if (mWrappedCanvas) { - canvas = mWrappedCanvas.get(); - } - } - SkiaCanvas::reset(canvas); + SkiaCanvas::reset(&mRecorder); } uirenderer::DisplayList* SkiaRecordingCanvas::finishRecording() { // close any existing chunks if necessary insertReorderBarrier(false); mRecorder.restoreToCount(1); - mWrappedCanvas = nullptr; return mDisplayList.release(); } diff --git a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.h b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.h index 50d84d6cf101..988728dfe23e 100644 --- a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.h +++ b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.h @@ -15,7 +15,7 @@ */ #pragma once -#include +#include "RecordingCanvas.h" #include "ReorderBarrierDrawables.h" #include "SkiaCanvas.h" #include "SkiaDisplayList.h" @@ -76,9 +76,8 @@ public: uirenderer::GlFunctorLifecycleListener* listener) override; private: - SkLiteRecorder mRecorder; + RecordingCanvas mRecorder; std::unique_ptr mDisplayList; - std::unique_ptr mWrappedCanvas; StartReorderBarrierDrawable* mCurrentBarrier; /** diff --git a/libs/hwui/tests/unit/RenderNodeDrawableTests.cpp b/libs/hwui/tests/unit/RenderNodeDrawableTests.cpp index eb67e6cf33b6..48bc8e4df155 100644 --- a/libs/hwui/tests/unit/RenderNodeDrawableTests.cpp +++ b/libs/hwui/tests/unit/RenderNodeDrawableTests.cpp @@ -18,13 +18,13 @@ #include #include -#include #include #include #include "AnimationContext.h" #include "DamageAccumulator.h" #include "FatalTestCanvas.h" #include "IContextFactory.h" +#include "RecordingCanvas.h" #include "SkiaCanvas.h" #include "pipeline/skia/SkiaDisplayList.h" #include "pipeline/skia/SkiaOpenGLPipeline.h" @@ -44,8 +44,8 @@ TEST(RenderNodeDrawable, create) { canvas.drawColor(Color::Red_500, SkBlendMode::kSrcOver); }); - SkLiteDL skLiteDL; - SkLiteRecorder canvas; + DisplayListData skLiteDL; + RecordingCanvas canvas; canvas.reset(&skLiteDL, SkIRect::MakeWH(1, 1)); canvas.translate(100, 100); RenderNodeDrawable drawable(rootNode.get(), &canvas); diff --git a/libs/hwui/tests/unit/SkiaDisplayListTests.cpp b/libs/hwui/tests/unit/SkiaDisplayListTests.cpp index 88d6dcf990a5..6c398eea895f 100644 --- a/libs/hwui/tests/unit/SkiaDisplayListTests.cpp +++ b/libs/hwui/tests/unit/SkiaDisplayListTests.cpp @@ -36,32 +36,36 @@ TEST(SkiaDisplayList, create) { } TEST(SkiaDisplayList, reset) { - SkiaDisplayList skiaDL; + std::unique_ptr skiaDL; + { + SkiaRecordingCanvas canvas{nullptr, 1, 1}; + canvas.drawColor(0, SkBlendMode::kSrc); + skiaDL.reset(canvas.finishRecording()); + } SkCanvas dummyCanvas; RenderNodeDrawable drawable(nullptr, &dummyCanvas); - skiaDL.mChildNodes.emplace_back(nullptr, &dummyCanvas); - skiaDL.mChildFunctors.emplace_back(nullptr, nullptr, &dummyCanvas); - skiaDL.mMutableImages.push_back(nullptr); - skiaDL.mVectorDrawables.push_back(nullptr); - skiaDL.mDisplayList.drawAnnotation(SkRect::MakeWH(200, 200), "testAnnotation", nullptr); - skiaDL.mProjectionReceiver = &drawable; - - ASSERT_FALSE(skiaDL.mChildNodes.empty()); - ASSERT_FALSE(skiaDL.mChildFunctors.empty()); - ASSERT_FALSE(skiaDL.mMutableImages.empty()); - ASSERT_FALSE(skiaDL.mVectorDrawables.empty()); - ASSERT_FALSE(skiaDL.isEmpty()); - ASSERT_TRUE(skiaDL.mProjectionReceiver); - - skiaDL.reset(); - - ASSERT_TRUE(skiaDL.mChildNodes.empty()); - ASSERT_TRUE(skiaDL.mChildFunctors.empty()); - ASSERT_TRUE(skiaDL.mMutableImages.empty()); - ASSERT_TRUE(skiaDL.mVectorDrawables.empty()); - ASSERT_TRUE(skiaDL.isEmpty()); - ASSERT_FALSE(skiaDL.mProjectionReceiver); + skiaDL->mChildNodes.emplace_back(nullptr, &dummyCanvas); + skiaDL->mChildFunctors.emplace_back(nullptr, nullptr, &dummyCanvas); + skiaDL->mMutableImages.push_back(nullptr); + skiaDL->mVectorDrawables.push_back(nullptr); + skiaDL->mProjectionReceiver = &drawable; + + ASSERT_FALSE(skiaDL->mChildNodes.empty()); + ASSERT_FALSE(skiaDL->mChildFunctors.empty()); + ASSERT_FALSE(skiaDL->mMutableImages.empty()); + ASSERT_FALSE(skiaDL->mVectorDrawables.empty()); + ASSERT_FALSE(skiaDL->isEmpty()); + ASSERT_TRUE(skiaDL->mProjectionReceiver); + + skiaDL->reset(); + + ASSERT_TRUE(skiaDL->mChildNodes.empty()); + ASSERT_TRUE(skiaDL->mChildFunctors.empty()); + ASSERT_TRUE(skiaDL->mMutableImages.empty()); + ASSERT_TRUE(skiaDL->mVectorDrawables.empty()); + ASSERT_TRUE(skiaDL->isEmpty()); + ASSERT_FALSE(skiaDL->mProjectionReceiver); } TEST(SkiaDisplayList, reuseDisplayList) { diff --git a/libs/hwui/tests/unit/SkiaPipelineTests.cpp b/libs/hwui/tests/unit/SkiaPipelineTests.cpp index 26b6000a91e6..a9124d90f9a5 100644 --- a/libs/hwui/tests/unit/SkiaPipelineTests.cpp +++ b/libs/hwui/tests/unit/SkiaPipelineTests.cpp @@ -18,7 +18,6 @@ #include #include -#include #include #include #include "AnimationContext.h" diff --git a/libs/hwui/tests/unit/SkiaRenderPropertiesTests.cpp b/libs/hwui/tests/unit/SkiaRenderPropertiesTests.cpp index ad5fdacc8594..479c462bd1a6 100644 --- a/libs/hwui/tests/unit/SkiaRenderPropertiesTests.cpp +++ b/libs/hwui/tests/unit/SkiaRenderPropertiesTests.cpp @@ -18,7 +18,6 @@ #include #include -#include #include #include #include "AnimationContext.h" diff --git a/libs/hwui/utils/LinearAllocator.cpp b/libs/hwui/utils/LinearAllocator.cpp index 5a59de8b922a..3e5021cd45d4 100644 --- a/libs/hwui/utils/LinearAllocator.cpp +++ b/libs/hwui/utils/LinearAllocator.cpp @@ -29,6 +29,7 @@ #include #include +#include // The ideal size of a page allocation (these need to be multiples of 8) #define INITIAL_PAGE_SIZE ((size_t)512) // 512b @@ -41,15 +42,6 @@ // Must be smaller than INITIAL_PAGE_SIZE #define MAX_WASTE_RATIO (0.5f) -#if ALIGN_DOUBLE -#define ALIGN_SZ (sizeof(double)) -#else -#define ALIGN_SZ (sizeof(int)) -#endif - -#define ALIGN(x) (((x) + ALIGN_SZ - 1) & ~(ALIGN_SZ - 1)) -#define ALIGN_PTR(p) ((void*)(ALIGN((size_t)(p)))) - #if LOG_NDEBUG #define ADD_ALLOCATION() #define RM_ALLOCATION() diff --git a/libs/hwui/utils/Macros.h b/libs/hwui/utils/Macros.h index d758f29d6dcb..eee6785afd53 100644 --- a/libs/hwui/utils/Macros.h +++ b/libs/hwui/utils/Macros.h @@ -34,4 +34,13 @@ private: \ #define WARN_UNUSED_RESULT __attribute__((warn_unused_result)) +#if ALIGN_DOUBLE +#define ALIGN_SZ (sizeof(double)) +#else +#define ALIGN_SZ (sizeof(int)) +#endif + +#define ALIGN(x) (((x) + ALIGN_SZ - 1) & ~(ALIGN_SZ - 1)) +#define ALIGN_PTR(p) ((void*)(ALIGN((size_t)(p)))) + #endif /* MACROS_H */ diff --git a/libs/hwui/utils/TypeLogic.h b/libs/hwui/utils/TypeLogic.h new file mode 100644 index 000000000000..dbdad33d8335 --- /dev/null +++ b/libs/hwui/utils/TypeLogic.h @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include + +namespace android::uirenderer { + +template struct copy_const { + using type = std::conditional_t::value, std::add_const_t, D>; +}; +template using copy_const_t = typename copy_const::type; + +template struct copy_volatile { + using type = std::conditional_t::value, std::add_volatile_t, D>; +}; +template using copy_volatile_t = typename copy_volatile::type; + +template struct copy_cv { + using type = copy_volatile_t, S>; +}; + +template using same_cv = copy_cv, S>; +template using same_cv_t = typename same_cv::type; + +}; // namespace android::uirenderer \ No newline at end of file -- cgit v1.2.3-59-g8ed1b From 28a4d9935c214374cbd487d3419abb80f57d6f80 Mon Sep 17 00:00:00 2001 From: Derek Sollenberger Date: Thu, 20 Sep 2018 13:37:24 -0400 Subject: Refactor RenderState and remove unused functionality. Test: hwui_unit_tests still pass Change-Id: Ie943671535ab8c5da1bac05985e815e0cb842dc1 --- libs/hwui/DeferredLayerUpdater.cpp | 8 ++- libs/hwui/DeferredLayerUpdater.h | 6 +- libs/hwui/RenderNode.cpp | 6 +- libs/hwui/hwui/Bitmap.cpp | 2 - libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp | 1 + libs/hwui/pipeline/skia/SkiaPipeline.cpp | 4 -- libs/hwui/pipeline/skia/SkiaPipeline.h | 2 - libs/hwui/renderstate/RenderState.cpp | 76 +------------------------- libs/hwui/renderstate/RenderState.h | 55 +------------------ libs/hwui/renderthread/CanvasContext.cpp | 7 --- libs/hwui/renderthread/CanvasContext.h | 6 -- libs/hwui/renderthread/RenderProxy.cpp | 7 --- libs/hwui/renderthread/RenderProxy.h | 2 - libs/hwui/tests/common/TestUtils.h | 1 + 14 files changed, 22 insertions(+), 161 deletions(-) (limited to 'libs/hwui/RenderNode.cpp') diff --git a/libs/hwui/DeferredLayerUpdater.cpp b/libs/hwui/DeferredLayerUpdater.cpp index 837d5461d2a8..b772e5b87f2a 100644 --- a/libs/hwui/DeferredLayerUpdater.cpp +++ b/libs/hwui/DeferredLayerUpdater.cpp @@ -29,12 +29,16 @@ DeferredLayerUpdater::DeferredLayerUpdater(RenderState& renderState) , mGLContextAttached(false) , mUpdateTexImage(false) , mLayer(nullptr) { - renderState.registerDeferredLayerUpdater(this); + renderState.registerContextCallback(this); } DeferredLayerUpdater::~DeferredLayerUpdater() { setTransform(nullptr); - mRenderState.unregisterDeferredLayerUpdater(this); + mRenderState.removeContextCallback(this); + destroyLayer(); +} + +void DeferredLayerUpdater::onContextDestroyed() { destroyLayer(); } diff --git a/libs/hwui/DeferredLayerUpdater.h b/libs/hwui/DeferredLayerUpdater.h index 4c323b861002..b2c5131dd613 100644 --- a/libs/hwui/DeferredLayerUpdater.h +++ b/libs/hwui/DeferredLayerUpdater.h @@ -27,6 +27,7 @@ #include #include +#include "renderstate/RenderState.h" #include "surfacetexture/SurfaceTexture.h" #include "Layer.h" #include "Rect.h" @@ -38,7 +39,7 @@ class RenderState; // Container to hold the properties a layer should be set to at the start // of a render pass -class DeferredLayerUpdater : public VirtualLightRefBase { +class DeferredLayerUpdater : public VirtualLightRefBase, public IGpuContextCallback { public: // Note that DeferredLayerUpdater assumes it is taking ownership of the layer // and will not call incrementRef on it as a result. @@ -98,6 +99,9 @@ public: void destroyLayer(); +protected: + void onContextDestroyed() override; + private: RenderState& mRenderState; diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp index d5afb2011429..896b4340f1b8 100644 --- a/libs/hwui/RenderNode.cpp +++ b/libs/hwui/RenderNode.cpp @@ -158,7 +158,7 @@ void RenderNode::pushLayerUpdate(TreeInfo& info) { CC_UNLIKELY(properties().getWidth() == 0) || CC_UNLIKELY(properties().getHeight() == 0) || CC_UNLIKELY(!properties().fitsOnLayer())) { if (CC_UNLIKELY(hasLayer())) { - renderthread::CanvasContext::destroyLayer(this); + this->setLayerSurface(nullptr); } return; } @@ -313,7 +313,7 @@ void RenderNode::deleteDisplayList(TreeObserver& observer, TreeInfo* info) { void RenderNode::destroyHardwareResources(TreeInfo* info) { if (hasLayer()) { - renderthread::CanvasContext::destroyLayer(this); + this->setLayerSurface(nullptr); } setStagingDisplayList(nullptr); @@ -323,7 +323,7 @@ void RenderNode::destroyHardwareResources(TreeInfo* info) { void RenderNode::destroyLayers() { if (hasLayer()) { - renderthread::CanvasContext::destroyLayer(this); + this->setLayerSurface(nullptr); } if (mDisplayList) { mDisplayList->updateChildren([](RenderNode* child) { child->destroyLayers(); }); diff --git a/libs/hwui/hwui/Bitmap.cpp b/libs/hwui/hwui/Bitmap.cpp index 440620a6a417..f1c10d1570a4 100644 --- a/libs/hwui/hwui/Bitmap.cpp +++ b/libs/hwui/hwui/Bitmap.cpp @@ -230,8 +230,6 @@ Bitmap::~Bitmap() { mPixelStorage.hardware.buffer = nullptr; break; } - - android::uirenderer::renderthread::RenderProxy::onBitmapDestroyed(getStableID()); } bool Bitmap::hasHardwareMipMap() const { diff --git a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp index e586be1d0708..e8bf4922cd46 100644 --- a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp +++ b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp @@ -21,6 +21,7 @@ #include "SkiaPipeline.h" #include "SkiaProfileRenderer.h" #include "hwui/Bitmap.h" +#include "private/hwui/DrawGlInfo.h" #include "renderstate/RenderState.h" #include "renderthread/EglManager.h" #include "renderthread/Frame.h" diff --git a/libs/hwui/pipeline/skia/SkiaPipeline.cpp b/libs/hwui/pipeline/skia/SkiaPipeline.cpp index 7f8abb8afa97..2dfe7c71ca1b 100644 --- a/libs/hwui/pipeline/skia/SkiaPipeline.cpp +++ b/libs/hwui/pipeline/skia/SkiaPipeline.cpp @@ -200,10 +200,6 @@ bool SkiaPipeline::createOrUpdateLayer(RenderNode* node, const DamageAccumulator return false; } -void SkiaPipeline::destroyLayer(RenderNode* node) { - node->setLayerSurface(nullptr); -} - void SkiaPipeline::prepareToDraw(const RenderThread& thread, Bitmap* bitmap) { GrContext* context = thread.getGrContext(); if (context) { diff --git a/libs/hwui/pipeline/skia/SkiaPipeline.h b/libs/hwui/pipeline/skia/SkiaPipeline.h index b78dea1a5c87..ee9158c5ffc1 100644 --- a/libs/hwui/pipeline/skia/SkiaPipeline.h +++ b/libs/hwui/pipeline/skia/SkiaPipeline.h @@ -54,8 +54,6 @@ public: std::vector* getVectorDrawables() { return &mVectorDrawables; } - static void destroyLayer(RenderNode* node); - static void prepareToDraw(const renderthread::RenderThread& thread, Bitmap* bitmap); void renderLayersImpl(const LayerUpdateQueue& layers, bool opaque); diff --git a/libs/hwui/renderstate/RenderState.cpp b/libs/hwui/renderstate/RenderState.cpp index b595ab859a61..fad9440be73f 100644 --- a/libs/hwui/renderstate/RenderState.cpp +++ b/libs/hwui/renderstate/RenderState.cpp @@ -14,90 +14,28 @@ * limitations under the License. */ #include "renderstate/RenderState.h" -#include -#include "DeferredLayerUpdater.h" -#include "Snapshot.h" -#include "renderthread/CanvasContext.h" -#include "renderthread/EglManager.h" -#include "utils/GLUtils.h" - -#include - -#include +#include "renderthread/RenderThread.h" +#include "GpuMemoryTracker.h" namespace android { namespace uirenderer { -RenderState::RenderState(renderthread::RenderThread& thread) - : mRenderThread(thread), mViewportWidth(0), mViewportHeight(0), mFramebuffer(0) { +RenderState::RenderState(renderthread::RenderThread& thread) : mRenderThread(thread) { mThreadId = pthread_self(); } -RenderState::~RenderState() { -} - void RenderState::onContextCreated() { GpuMemoryTracker::onGpuContextCreated(); } -static void destroyLayerInUpdater(DeferredLayerUpdater* layerUpdater) { - layerUpdater->destroyLayer(); -} - void RenderState::onContextDestroyed() { - std::for_each(mActiveLayerUpdaters.begin(), mActiveLayerUpdaters.end(), destroyLayerInUpdater); for(auto callback : mContextCallbacks) { callback->onContextDestroyed(); } GpuMemoryTracker::onGpuContextDestroyed(); } -GrContext* RenderState::getGrContext() const { - return mRenderThread.getGrContext(); -} - -void RenderState::onBitmapDestroyed(uint32_t pixelRefId) { - // DEAD CODE -} - -void RenderState::setViewport(GLsizei width, GLsizei height) { - mViewportWidth = width; - mViewportHeight = height; - glViewport(0, 0, mViewportWidth, mViewportHeight); -} - -void RenderState::getViewport(GLsizei* outWidth, GLsizei* outHeight) { - *outWidth = mViewportWidth; - *outHeight = mViewportHeight; -} - -void RenderState::bindFramebuffer(GLuint fbo) { - if (mFramebuffer != fbo) { - mFramebuffer = fbo; - glBindFramebuffer(GL_FRAMEBUFFER, mFramebuffer); - } -} - -GLuint RenderState::createFramebuffer() { - GLuint ret; - glGenFramebuffers(1, &ret); - return ret; -} - -void RenderState::deleteFramebuffer(GLuint fbo) { - if (mFramebuffer == fbo) { - // GL defines that deleting the currently bound FBO rebinds FBO 0. - // Reflect this in our cached value. - mFramebuffer = 0; - } - glDeleteFramebuffers(1, &fbo); -} - -void RenderState::debugOverdraw(bool enable, bool clear) { - // DEAD CODE -} - void RenderState::postDecStrong(VirtualLightRefBase* object) { if (pthread_equal(mThreadId, pthread_self())) { object->decStrong(nullptr); @@ -110,13 +48,5 @@ void RenderState::postDecStrong(VirtualLightRefBase* object) { // Render /////////////////////////////////////////////////////////////////////////////// -void RenderState::dump() { - // DEAD CODE -} - -renderthread::RenderThread& RenderState::getRenderThread() { - return mRenderThread; -} - } /* namespace uirenderer */ } /* namespace android */ diff --git a/libs/hwui/renderstate/RenderState.h b/libs/hwui/renderstate/RenderState.h index dee02e9873d8..ff5d02fe359a 100644 --- a/libs/hwui/renderstate/RenderState.h +++ b/libs/hwui/renderstate/RenderState.h @@ -18,26 +18,16 @@ #include "utils/Macros.h" -#include -#include -#include -#include -#include -#include #include #include -class GrContext; - namespace android { namespace uirenderer { class Layer; -class DeferredLayerUpdater; namespace renderthread { class CacheManager; -class CanvasContext; class RenderThread; } @@ -55,69 +45,30 @@ class RenderState { friend class renderthread::CacheManager; public: - void onBitmapDestroyed(uint32_t pixelRefId); - - void setViewport(GLsizei width, GLsizei height); - void getViewport(GLsizei* outWidth, GLsizei* outHeight); - - void bindFramebuffer(GLuint fbo); - GLuint getFramebuffer() { return mFramebuffer; } - GLuint createFramebuffer(); - void deleteFramebuffer(GLuint fbo); - - void debugOverdraw(bool enable, bool clear); - void registerContextCallback(IGpuContextCallback* cb) { mContextCallbacks.insert(cb); } void removeContextCallback(IGpuContextCallback* cb) { mContextCallbacks.erase(cb); } void registerLayer(Layer* layer) { mActiveLayers.insert(layer); } void unregisterLayer(Layer* layer) { mActiveLayers.erase(layer); } - void registerCanvasContext(renderthread::CanvasContext* context) { - mRegisteredContexts.insert(context); - } - - void unregisterCanvasContext(renderthread::CanvasContext* context) { - mRegisteredContexts.erase(context); - } - - void registerDeferredLayerUpdater(DeferredLayerUpdater* layerUpdater) { - mActiveLayerUpdaters.insert(layerUpdater); - } - - void unregisterDeferredLayerUpdater(DeferredLayerUpdater* layerUpdater) { - mActiveLayerUpdaters.erase(layerUpdater); - } - // TODO: This system is a little clunky feeling, this could use some // more thinking... void postDecStrong(VirtualLightRefBase* object); - GrContext* getGrContext() const; - - void dump(); - - renderthread::RenderThread& getRenderThread(); + renderthread::RenderThread& getRenderThread() const { return mRenderThread; } private: explicit RenderState(renderthread::RenderThread& thread); - ~RenderState(); + ~RenderState() {} // Context notifications are only to be triggered by renderthread::RenderThread void onContextCreated(); void onContextDestroyed(); - renderthread::RenderThread& mRenderThread; - std::set mContextCallbacks; std::set mActiveLayers; - std::set mActiveLayerUpdaters; - std::set mRegisteredContexts; - - GLsizei mViewportWidth; - GLsizei mViewportHeight; - GLuint mFramebuffer; + renderthread::RenderThread& mRenderThread; pthread_t mThreadId; }; diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp index ea6a851419c0..c8c394a72541 100644 --- a/libs/hwui/renderthread/CanvasContext.cpp +++ b/libs/hwui/renderthread/CanvasContext.cpp @@ -27,7 +27,6 @@ #include "pipeline/skia/SkiaOpenGLPipeline.h" #include "pipeline/skia/SkiaPipeline.h" #include "pipeline/skia/SkiaVulkanPipeline.h" -#include "renderstate/RenderState.h" #include "utils/GLUtils.h" #include "utils/TimeUtils.h" #include "../Properties.h" @@ -76,10 +75,6 @@ CanvasContext* CanvasContext::create(RenderThread& thread, bool translucent, return nullptr; } -void CanvasContext::destroyLayer(RenderNode* node) { - skiapipeline::SkiaPipeline::destroyLayer(node); -} - void CanvasContext::invokeFunctor(const RenderThread& thread, Functor* functor) { ATRACE_CALL(); auto renderType = Properties::getRenderPipelineType(); @@ -113,13 +108,11 @@ CanvasContext::CanvasContext(RenderThread& thread, bool translucent, RenderNode* , mRenderPipeline(std::move(renderPipeline)) { rootRenderNode->makeRoot(); mRenderNodes.emplace_back(rootRenderNode); - mRenderThread.renderState().registerCanvasContext(this); mProfiler.setDensity(mRenderThread.mainDisplayInfo().density); } CanvasContext::~CanvasContext() { destroy(); - mRenderThread.renderState().unregisterCanvasContext(this); for (auto& node : mRenderNodes) { node->clearRoot(); } diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h index 8448788eb9a6..2315cb9c73f9 100644 --- a/libs/hwui/renderthread/CanvasContext.h +++ b/libs/hwui/renderthread/CanvasContext.h @@ -96,12 +96,6 @@ public: */ void unpinImages() { mRenderPipeline->unpinImages(); } - /** - * Destroy any layers that have been attached to the provided RenderNode removing - * any state that may have been set during createOrUpdateLayer(). - */ - static void destroyLayer(RenderNode* node); - static void invokeFunctor(const RenderThread& thread, Functor* functor); static void prepareToDraw(const RenderThread& thread, Bitmap* bitmap); diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp index 7a5348ac85d9..6106e24c093b 100644 --- a/libs/hwui/renderthread/RenderProxy.cpp +++ b/libs/hwui/renderthread/RenderProxy.cpp @@ -345,13 +345,6 @@ int RenderProxy::copyHWBitmapInto(Bitmap* hwBitmap, SkBitmap* bitmap) { } } -void RenderProxy::onBitmapDestroyed(uint32_t pixelRefId) { - if (!RenderThread::hasInstance()) return; - RenderThread& thread = RenderThread::getInstance(); - thread.queue().post( - [&thread, pixelRefId]() { thread.renderState().onBitmapDestroyed(pixelRefId); }); -} - void RenderProxy::disableVsync() { Properties::disableVsync = true; } diff --git a/libs/hwui/renderthread/RenderProxy.h b/libs/hwui/renderthread/RenderProxy.h index 969ad00d7443..d22f56ef38fd 100644 --- a/libs/hwui/renderthread/RenderProxy.h +++ b/libs/hwui/renderthread/RenderProxy.h @@ -127,8 +127,6 @@ public: static int copyHWBitmapInto(Bitmap* hwBitmap, SkBitmap* bitmap); - static void onBitmapDestroyed(uint32_t pixelRefId); - ANDROID_API static void disableVsync(); static void repackVectorDrawableAtlas(); diff --git a/libs/hwui/tests/common/TestUtils.h b/libs/hwui/tests/common/TestUtils.h index c35f512553d8..a00b8db3c617 100644 --- a/libs/hwui/tests/common/TestUtils.h +++ b/libs/hwui/tests/common/TestUtils.h @@ -24,6 +24,7 @@ #include #include #include +#include #include #include -- cgit v1.2.3-59-g8ed1b From f3c724fd7c18e78b8d981b0ff35477ecbf383298 Mon Sep 17 00:00:00 2001 From: John Reck Date: Thu, 20 Sep 2018 13:00:04 -0700 Subject: Make auto-dark a bit better Handles transform of basic bitmaps Tweak to always treat text as foreground Test: builds, poked around with force_dark Change-Id: I733d39e05067438335da5a7eac06111f66f1228d --- libs/hwui/CanvasTransform.cpp | 17 ++++++ libs/hwui/CanvasTransform.h | 5 ++ libs/hwui/RecordingCanvas.cpp | 78 +++++++++++++++++-------- libs/hwui/RecordingCanvas.h | 16 ++++- libs/hwui/RenderNode.cpp | 4 ++ libs/hwui/RenderNode.h | 2 +- libs/hwui/hwui/Bitmap.cpp | 9 --- libs/hwui/pipeline/skia/SkiaDisplayList.cpp | 1 - libs/hwui/pipeline/skia/SkiaDisplayList.h | 5 +- libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp | 8 +-- 10 files changed, 101 insertions(+), 44 deletions(-) (limited to 'libs/hwui/RenderNode.cpp') diff --git a/libs/hwui/CanvasTransform.cpp b/libs/hwui/CanvasTransform.cpp index adcdc18ab418..a03b31723808 100644 --- a/libs/hwui/CanvasTransform.cpp +++ b/libs/hwui/CanvasTransform.cpp @@ -28,6 +28,7 @@ #include #include +#include namespace android::uirenderer { @@ -113,4 +114,20 @@ bool transformPaint(ColorTransform transform, SkPaint* paint) { return true; } +bool transformPaint(ColorTransform transform, SkPaint* paint, BitmapPalette palette) { + bool shouldInvert = false; + if (palette == BitmapPalette::Light && transform == ColorTransform::Dark) { + shouldInvert = true; + } + if (palette == BitmapPalette::Dark && transform == ColorTransform::Light) { + shouldInvert = true; + } + if (shouldInvert) { + SkHighContrastConfig config; + config.fInvertStyle = SkHighContrastConfig::InvertStyle::kInvertLightness; + paint->setColorFilter(SkHighContrastFilter::Make(config)->makeComposed(paint->refColorFilter())); + } + return shouldInvert; +} + }; // namespace android::uirenderer \ No newline at end of file diff --git a/libs/hwui/CanvasTransform.h b/libs/hwui/CanvasTransform.h index 32d9a0594879..e723d645e05e 100644 --- a/libs/hwui/CanvasTransform.h +++ b/libs/hwui/CanvasTransform.h @@ -16,6 +16,8 @@ #pragma once +#include "hwui/Bitmap.h" + #include #include @@ -26,6 +28,7 @@ namespace android::uirenderer { enum class UsageHint { Unknown = 0, Background = 1, + Foreground = 2, }; enum class ColorTransform { @@ -37,4 +40,6 @@ enum class ColorTransform { // True if the paint was modified, false otherwise bool transformPaint(ColorTransform transform, SkPaint* paint); +bool transformPaint(ColorTransform transform, SkPaint* paint, BitmapPalette palette); + } // namespace android::uirenderer; \ No newline at end of file diff --git a/libs/hwui/RecordingCanvas.cpp b/libs/hwui/RecordingCanvas.cpp index 3eaff03db369..5f54c025c819 100644 --- a/libs/hwui/RecordingCanvas.cpp +++ b/libs/hwui/RecordingCanvas.cpp @@ -278,8 +278,8 @@ struct DrawPicture final : Op { struct DrawImage final : Op { static const auto kType = Type::DrawImage; - DrawImage(sk_sp&& image, SkScalar x, SkScalar y, const SkPaint* paint) - : image(std::move(image)), x(x), y(y) { + DrawImage(sk_sp&& image, SkScalar x, SkScalar y, const SkPaint* paint, BitmapPalette palette) + : image(std::move(image)), x(x), y(y), palette(palette) { if (paint) { this->paint = *paint; } @@ -287,6 +287,7 @@ struct DrawImage final : Op { sk_sp image; SkScalar x, y; SkPaint paint; + BitmapPalette palette; void draw(SkCanvas* c, const SkMatrix&) const { c->drawImage(image.get(), x, y, &paint); } }; struct DrawImageNine final : Op { @@ -309,8 +310,8 @@ struct DrawImageNine final : Op { struct DrawImageRect final : Op { static const auto kType = Type::DrawImageRect; DrawImageRect(sk_sp&& image, const SkRect* src, const SkRect& dst, - const SkPaint* paint, SkCanvas::SrcRectConstraint constraint) - : image(std::move(image)), dst(dst), constraint(constraint) { + const SkPaint* paint, SkCanvas::SrcRectConstraint constraint, BitmapPalette palette) + : image(std::move(image)), dst(dst), constraint(constraint), palette(palette) { this->src = src ? *src : SkRect::MakeIWH(this->image->width(), this->image->height()); if (paint) { this->paint = *paint; @@ -320,6 +321,7 @@ struct DrawImageRect final : Op { SkRect src, dst; SkPaint paint; SkCanvas::SrcRectConstraint constraint; + BitmapPalette palette; void draw(SkCanvas* c, const SkMatrix&) const { c->drawImageRect(image.get(), src, dst, &paint, constraint); } @@ -609,8 +611,8 @@ void DisplayListData::drawPicture(const SkPicture* picture, const SkMatrix* matr this->push(0, picture, matrix, paint); } void DisplayListData::drawImage(sk_sp image, SkScalar x, SkScalar y, - const SkPaint* paint) { - this->push(0, std::move(image), x, y, paint); + const SkPaint* paint, BitmapPalette palette) { + this->push(0, std::move(image), x, y, paint, palette); } void DisplayListData::drawImageNine(sk_sp image, const SkIRect& center, const SkRect& dst, const SkPaint* paint) { @@ -618,8 +620,8 @@ void DisplayListData::drawImageNine(sk_sp image, const SkIRect& c } void DisplayListData::drawImageRect(sk_sp image, const SkRect* src, const SkRect& dst, const SkPaint* paint, - SkCanvas::SrcRectConstraint constraint) { - this->push(0, std::move(image), src, dst, paint, constraint); + SkCanvas::SrcRectConstraint constraint, BitmapPalette palette) { + this->push(0, std::move(image), src, dst, paint, constraint, palette); } void DisplayListData::drawImageLattice(sk_sp image, const SkCanvas::Lattice& lattice, const SkRect& dst, const SkPaint* paint) { @@ -638,28 +640,33 @@ void DisplayListData::drawText(const void* text, size_t bytes, SkScalar x, SkSca const SkPaint& paint) { void* pod = this->push(bytes, bytes, x, y, paint); copy_v(pod, (const char*)text, bytes); + mHasText = true; } void DisplayListData::drawPosText(const void* text, size_t bytes, const SkPoint pos[], const SkPaint& paint) { int n = paint.countText(text, bytes); void* pod = this->push(n * sizeof(SkPoint) + bytes, bytes, paint, n); copy_v(pod, pos, n, (const char*)text, bytes); + mHasText = true; } void DisplayListData::drawPosTextH(const void* text, size_t bytes, const SkScalar xs[], SkScalar y, const SkPaint& paint) { int n = paint.countText(text, bytes); void* pod = this->push(n * sizeof(SkScalar) + bytes, bytes, y, paint, n); copy_v(pod, xs, n, (const char*)text, bytes); + mHasText = true; } void DisplayListData::drawTextRSXform(const void* text, size_t bytes, const SkRSXform xforms[], const SkRect* cull, const SkPaint& paint) { int n = paint.countText(text, bytes); void* pod = this->push(bytes + n * sizeof(SkRSXform), bytes, n, cull, paint); copy_v(pod, xforms, n, (const char*)text, bytes); + mHasText = true; } void DisplayListData::drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y, const SkPaint& paint) { this->push(0, blob, x, y, paint); + mHasText = true; } void DisplayListData::drawPatch(const SkPoint points[12], const SkColor colors[4], @@ -733,20 +740,35 @@ void DisplayListData::reset() { } template -using has_paint_t = decltype(std::declval().paint); +using has_paint_helper = decltype(std::declval().paint); + +template +constexpr bool has_paint = std::experimental::is_detected_v; + +template +using has_palette_helper = decltype(std::declval().palette); + +template +constexpr bool has_palette = std::experimental::is_detected_v; template constexpr color_transform_fn colorTransformForOp() { - if - constexpr(std::experimental::is_detected_v) { - return [](const void* op, ColorTransform transform) { - // TODO: We should be const. Or not. Or just use a different map - // Unclear, but this is the quick fix - transformPaint(transform, - const_cast(&(reinterpret_cast(op)->paint))); - }; - } - else { + if constexpr(has_paint && has_palette) { + // It's a bitmap + return [](const void* opRaw, ColorTransform transform) { + // TODO: We should be const. Or not. Or just use a different map + // Unclear, but this is the quick fix + const T* op = reinterpret_cast(opRaw); + transformPaint(transform, const_cast(&(op->paint)), op->palette); + }; + } else if constexpr(has_paint) { + return [](const void* opRaw, ColorTransform transform) { + // TODO: We should be const. Or not. Or just use a different map + // Unclear, but this is the quick fix + const T* op = reinterpret_cast(opRaw); + transformPaint(transform, const_cast(&(op->paint))); + }; + } else { return nullptr; } } @@ -875,7 +897,7 @@ void RecordingCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScala void RecordingCanvas::onDrawBitmap(const SkBitmap& bm, SkScalar x, SkScalar y, const SkPaint* paint) { - fDL->drawImage(SkImage::MakeFromBitmap(bm), x, y, paint); + fDL->drawImage(SkImage::MakeFromBitmap(bm), x, y, paint, BitmapPalette::Unknown); } void RecordingCanvas::onDrawBitmapNine(const SkBitmap& bm, const SkIRect& center, const SkRect& dst, const SkPaint* paint) { @@ -883,16 +905,26 @@ void RecordingCanvas::onDrawBitmapNine(const SkBitmap& bm, const SkIRect& center } void RecordingCanvas::onDrawBitmapRect(const SkBitmap& bm, const SkRect* src, const SkRect& dst, const SkPaint* paint, SrcRectConstraint constraint) { - fDL->drawImageRect(SkImage::MakeFromBitmap(bm), src, dst, paint, constraint); + fDL->drawImageRect(SkImage::MakeFromBitmap(bm), src, dst, paint, constraint, BitmapPalette::Unknown); } void RecordingCanvas::onDrawBitmapLattice(const SkBitmap& bm, const SkCanvas::Lattice& lattice, const SkRect& dst, const SkPaint* paint) { fDL->drawImageLattice(SkImage::MakeFromBitmap(bm), lattice, dst, paint); } +void RecordingCanvas::drawImage(const sk_sp& image, SkScalar x, SkScalar y, + const SkPaint* paint, BitmapPalette palette) { + fDL->drawImage(image, x, y, paint, palette); +} + +void RecordingCanvas::drawImageRect(const sk_sp& image, const SkRect& src, const SkRect& dst, + const SkPaint* paint, SrcRectConstraint constraint, BitmapPalette palette) { + fDL->drawImageRect(image, &src, dst, paint, constraint, palette); +} + void RecordingCanvas::onDrawImage(const SkImage* img, SkScalar x, SkScalar y, const SkPaint* paint) { - fDL->drawImage(sk_ref_sp(img), x, y, paint); + fDL->drawImage(sk_ref_sp(img), x, y, paint, BitmapPalette::Unknown); } void RecordingCanvas::onDrawImageNine(const SkImage* img, const SkIRect& center, const SkRect& dst, const SkPaint* paint) { @@ -900,7 +932,7 @@ void RecordingCanvas::onDrawImageNine(const SkImage* img, const SkIRect& center, } void RecordingCanvas::onDrawImageRect(const SkImage* img, const SkRect* src, const SkRect& dst, const SkPaint* paint, SrcRectConstraint constraint) { - fDL->drawImageRect(sk_ref_sp(img), src, dst, paint, constraint); + fDL->drawImageRect(sk_ref_sp(img), src, dst, paint, constraint, BitmapPalette::Unknown); } void RecordingCanvas::onDrawImageLattice(const SkImage* img, const SkCanvas::Lattice& lattice, const SkRect& dst, const SkPaint* paint) { diff --git a/libs/hwui/RecordingCanvas.h b/libs/hwui/RecordingCanvas.h index 32ce1d333448..eecf51ce0996 100644 --- a/libs/hwui/RecordingCanvas.h +++ b/libs/hwui/RecordingCanvas.h @@ -17,6 +17,7 @@ #pragma once #include "CanvasTransform.h" +#include "hwui/Bitmap.h" #include "hwui/Canvas.h" #include "utils/Macros.h" #include "utils/TypeLogic.h" @@ -53,6 +54,7 @@ class RecordingCanvas; class DisplayListData final { public: + DisplayListData() : mHasText(false) {} ~DisplayListData(); void draw(SkCanvas* canvas) const; @@ -62,6 +64,8 @@ public: void applyColorTransform(ColorTransform transform); + bool hasText() const { return mHasText; } + private: friend class RecordingCanvas; @@ -101,10 +105,10 @@ private: void drawTextRSXform(const void*, size_t, const SkRSXform[], const SkRect*, const SkPaint&); void drawTextBlob(const SkTextBlob*, SkScalar, SkScalar, const SkPaint&); - void drawImage(sk_sp, SkScalar, SkScalar, const SkPaint*); + void drawImage(sk_sp, SkScalar, SkScalar, const SkPaint*, BitmapPalette palette); void drawImageNine(sk_sp, const SkIRect&, const SkRect&, const SkPaint*); void drawImageRect(sk_sp, const SkRect*, const SkRect&, const SkPaint*, - SkCanvas::SrcRectConstraint); + SkCanvas::SrcRectConstraint, BitmapPalette palette); void drawImageLattice(sk_sp, const SkCanvas::Lattice&, const SkRect&, const SkPaint*); @@ -126,6 +130,8 @@ private: SkAutoTMalloc fBytes; size_t fUsed = 0; size_t fReserved = 0; + + bool mHasText : 1; }; class RecordingCanvas final : public SkCanvasVirtualEnforcer { @@ -178,6 +184,12 @@ public: void onDrawBitmapRect(const SkBitmap&, const SkRect*, const SkRect&, const SkPaint*, SrcRectConstraint) override; + void drawImage(const sk_sp& image, SkScalar left, SkScalar top, + const SkPaint* paint, BitmapPalette pallete); + + void drawImageRect(const sk_sp& image, const SkRect& src, const SkRect& dst, + const SkPaint* paint, SrcRectConstraint constraint, BitmapPalette palette); + void onDrawImage(const SkImage*, SkScalar, SkScalar, const SkPaint*) override; void onDrawImageLattice(const SkImage*, const Lattice&, const SkRect&, const SkPaint*) override; void onDrawImageNine(const SkImage*, const SkIRect&, const SkRect&, const SkPaint*) override; diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp index d5afb2011429..26e5cea2452a 100644 --- a/libs/hwui/RenderNode.cpp +++ b/libs/hwui/RenderNode.cpp @@ -272,8 +272,12 @@ void RenderNode::syncDisplayList(TreeObserver& observer, TreeInfo* info) { mStagingDisplayList = nullptr; if (mDisplayList) { mDisplayList->syncContents(); + if (CC_UNLIKELY(Properties::forceDarkMode)) { auto usage = usageHint(); + if (mDisplayList->hasText()) { + usage = UsageHint::Foreground; + } if (usage == UsageHint::Unknown) { if (mDisplayList->mChildNodes.size() > 1) { usage = UsageHint::Background; diff --git a/libs/hwui/RenderNode.h b/libs/hwui/RenderNode.h index 83b0c2278151..211dd2db5cf8 100644 --- a/libs/hwui/RenderNode.h +++ b/libs/hwui/RenderNode.h @@ -107,7 +107,7 @@ public: bool isRenderable() const { return mDisplayList && !mDisplayList->isEmpty(); } bool hasProjectionReceiver() const { - return mDisplayList && mDisplayList->projectionReceiveIndex >= 0; + return mDisplayList && mDisplayList->containsProjectionReceiver(); } const char* getName() const { return mName.string(); } diff --git a/libs/hwui/hwui/Bitmap.cpp b/libs/hwui/hwui/Bitmap.cpp index 440620a6a417..6556a6413ef5 100644 --- a/libs/hwui/hwui/Bitmap.cpp +++ b/libs/hwui/hwui/Bitmap.cpp @@ -330,15 +330,6 @@ sk_sp Bitmap::makeImage(sk_sp* outputColorFilter) { if (image->colorSpace() != nullptr && !image->colorSpace()->isSRGB()) { *outputColorFilter = SkToSRGBColorFilter::Make(image->refColorSpace()); } - - // TODO: Move this to the canvas (or other?) layer where we have the target lightness - // mode and can selectively do the right thing. - // if (palette() != BitmapPalette::Unknown && uirenderer::Properties::forceDarkMode) { - // SkHighContrastConfig config; - // config.fInvertStyle = SkHighContrastConfig::InvertStyle::kInvertLightness; - // *outputColorFilter = - // SkHighContrastFilter::Make(config)->makeComposed(*outputColorFilter); - // } return image; } diff --git a/libs/hwui/pipeline/skia/SkiaDisplayList.cpp b/libs/hwui/pipeline/skia/SkiaDisplayList.cpp index 78b64b2f01eb..38905138e332 100644 --- a/libs/hwui/pipeline/skia/SkiaDisplayList.cpp +++ b/libs/hwui/pipeline/skia/SkiaDisplayList.cpp @@ -132,7 +132,6 @@ void SkiaDisplayList::reset() { mChildFunctors.clear(); mChildNodes.clear(); - projectionReceiveIndex = -1; allocator.~LinearAllocator(); new (&allocator) LinearAllocator(); } diff --git a/libs/hwui/pipeline/skia/SkiaDisplayList.h b/libs/hwui/pipeline/skia/SkiaDisplayList.h index 4c7853931029..ac7bb7b0950c 100644 --- a/libs/hwui/pipeline/skia/SkiaDisplayList.h +++ b/libs/hwui/pipeline/skia/SkiaDisplayList.h @@ -49,9 +49,6 @@ namespace skiapipeline { */ class SkiaDisplayList { public: - // index of DisplayListOp restore, after which projected descendants should be drawn - int projectionReceiveIndex = -1; - size_t getUsedSize() { return allocator.usedSize(); } ~SkiaDisplayList() { @@ -96,6 +93,8 @@ public: */ bool hasVectorDrawables() const { return !mVectorDrawables.empty(); } + bool hasText() const { return mDisplayList.hasText(); } + /** * Attempts to reset and reuse this DisplayList. * diff --git a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp index 3c281e78ddd5..3042006e5684 100644 --- a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp +++ b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp @@ -113,8 +113,6 @@ void SkiaRecordingCanvas::drawRenderNode(uirenderer::RenderNode* renderNode) { // use staging property, since recording on UI thread if (renderNode->stagingProperties().isProjectionReceiver()) { mDisplayList->mProjectionReceiver = &renderNodeDrawable; - // set projectionReceiveIndex so that RenderNode.hasProjectionReceiver returns true - mDisplayList->projectionReceiveIndex = mDisplayList->mChildNodes.size() - 1; } } @@ -196,7 +194,7 @@ SkiaCanvas::PaintCoW&& SkiaRecordingCanvas::filterBitmap(PaintCoW&& paint, void SkiaRecordingCanvas::drawBitmap(Bitmap& bitmap, float left, float top, const SkPaint* paint) { sk_sp colorFilter; sk_sp image = bitmap.makeImage(&colorFilter); - mRecorder.drawImage(image, left, top, filterBitmap(paint, std::move(colorFilter))); + mRecorder.drawImage(image, left, top, filterBitmap(paint, std::move(colorFilter)), bitmap.palette()); // if image->unique() is true, then mRecorder.drawImage failed for some reason. It also means // it is not safe to store a raw SkImage pointer, because the image object will be destroyed // when this function ends. @@ -211,7 +209,7 @@ void SkiaRecordingCanvas::drawBitmap(Bitmap& bitmap, const SkMatrix& matrix, con sk_sp colorFilter; sk_sp image = bitmap.makeImage(&colorFilter); - mRecorder.drawImage(image, 0, 0, filterBitmap(paint, std::move(colorFilter))); + mRecorder.drawImage(image, 0, 0, filterBitmap(paint, std::move(colorFilter)), bitmap.palette()); if (!bitmap.isImmutable() && image.get() && !image->unique()) { mDisplayList->mMutableImages.push_back(image.get()); } @@ -226,7 +224,7 @@ void SkiaRecordingCanvas::drawBitmap(Bitmap& bitmap, float srcLeft, float srcTop sk_sp colorFilter; sk_sp image = bitmap.makeImage(&colorFilter); mRecorder.drawImageRect(image, srcRect, dstRect, filterBitmap(paint, std::move(colorFilter)), - SkCanvas::kFast_SrcRectConstraint); + SkCanvas::kFast_SrcRectConstraint, bitmap.palette()); if (!bitmap.isImmutable() && image.get() && !image->unique() && !srcRect.isEmpty() && !dstRect.isEmpty()) { mDisplayList->mMutableImages.push_back(image.get()); -- cgit v1.2.3-59-g8ed1b From 1423e1331fa8b97d36950d143560a332b6c6bed7 Mon Sep 17 00:00:00 2001 From: John Reck Date: Fri, 21 Sep 2018 14:30:19 -0700 Subject: Create plumbing for disabling force-dark Test: sysui's rounded corners are no longer white Bug: 102591313 Change-Id: Id99ae38c354cef06b94a5fb79b5b1a9a216a514c --- core/java/android/view/RenderNode.java | 30 +++++++++++++++++++ core/java/android/view/Surface.java | 1 + core/java/android/view/View.java | 34 ++++++++++++++++++++++ core/jni/android_view_RenderNode.cpp | 10 +++++++ graphics/java/android/graphics/Bitmap.java | 1 + libs/hwui/RenderNode.cpp | 12 +++++++- libs/hwui/RenderProperties.h | 9 ++++++ libs/hwui/TreeInfo.h | 3 ++ .../com/android/systemui/ScreenDecorations.java | 2 ++ 9 files changed, 101 insertions(+), 1 deletion(-) (limited to 'libs/hwui/RenderNode.cpp') diff --git a/core/java/android/view/RenderNode.java b/core/java/android/view/RenderNode.java index fcea0c3f890a..982e5c2a6924 100644 --- a/core/java/android/view/RenderNode.java +++ b/core/java/android/view/RenderNode.java @@ -843,6 +843,32 @@ public class RenderNode { return nGetDebugSize(mNativeRenderNode); } + /** + * Sets whether or not to allow force dark to apply to this RenderNode. + * + * Setting this to false will disable the auto-dark feature on everything this RenderNode + * draws, including any descendants. + * + * Setting this to true will allow this RenderNode to be automatically made dark, however + * a value of 'true' will not override any 'false' value in its parent chain nor will + * it prevent any 'false' in any of its children. + * + * @param allow Whether or not to allow force dark. + * @return true If the value has changed, false otherwise. + */ + public boolean setAllowForceDark(boolean allow) { + return nSetAllowForceDark(mNativeRenderNode, allow); + } + + /** + * See {@link #setAllowForceDark(boolean)} + * + * @return true if force dark is allowed (default), false if it is disabled + */ + public boolean getAllowForceDark() { + return nGetAllowForceDark(mNativeRenderNode); + } + /////////////////////////////////////////////////////////////////////////// // Animations /////////////////////////////////////////////////////////////////////////// @@ -1043,4 +1069,8 @@ public class RenderNode { private static native int nGetWidth(long renderNode); @CriticalNative private static native int nGetHeight(long renderNode); + @CriticalNative + private static native boolean nSetAllowForceDark(long renderNode, boolean allowForceDark); + @CriticalNative + private static native boolean nGetAllowForceDark(long renderNode); } diff --git a/core/java/android/view/Surface.java b/core/java/android/view/Surface.java index 427f570b1294..6fb1bbabddc2 100644 --- a/core/java/android/view/Surface.java +++ b/core/java/android/view/Surface.java @@ -895,6 +895,7 @@ public class Surface implements Parcelable { HwuiContext(boolean isWideColorGamut) { mRenderNode = RenderNode.create("HwuiCanvas", null); mRenderNode.setClipToBounds(false); + mRenderNode.setAllowForceDark(false); mIsWideColorGamut = isWideColorGamut; mHwuiRenderer = nHwuiCreate(mRenderNode.mNativeRenderNode, mNativeObject, isWideColorGamut); diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index 19e3f7f623cb..f4be9f2d7949 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -15245,6 +15245,40 @@ public class View implements Drawable.Callback, KeyEvent.Callback, return mTransformationInfo != null ? mTransformationInfo.mTransitionAlpha : 1; } + /** + * Sets whether or not to allow force dark to apply to this view. + * + * Setting this to false will disable the auto-dark feature on everything this view + * draws, including any descendants. + * + * Setting this to true will allow this view to be automatically made dark, however + * a value of 'true' will not override any 'false' value in its parent chain nor will + * it prevent any 'false' in any of its children. + * + * @param allow Whether or not to allow force dark. + * + * @hide + */ + public void setAllowForceDark(boolean allow) { + if (mRenderNode.setAllowForceDark(allow)) { + // Currently toggling force-dark requires a new display list push to apply + // TODO: Make it not clobber the display list so this is just a damageSelf() instead + invalidate(); + } + } + + /** + * See {@link #setAllowForceDark(boolean)} + * + * @return true if force dark is allowed (default), false if it is disabled + * + * @hide + */ + @ViewDebug.ExportedProperty(category = "drawing") + public boolean getAllowForceDark() { + return mRenderNode.getAllowForceDark(); + } + /** * Top position of this view relative to its parent. * diff --git a/core/jni/android_view_RenderNode.cpp b/core/jni/android_view_RenderNode.cpp index 46b19bdf660f..0701f3e0d2ed 100644 --- a/core/jni/android_view_RenderNode.cpp +++ b/core/jni/android_view_RenderNode.cpp @@ -444,6 +444,14 @@ static jint android_view_RenderNode_getHeight(jlong renderNodePtr) { return reinterpret_cast(renderNodePtr)->stagingProperties().getHeight(); } +static jboolean android_view_RenderNode_setAllowForceDark(jlong renderNodePtr, jboolean allow) { + return SET_AND_DIRTY(setAllowForceDark, allow, RenderNode::GENERIC); +} + +static jboolean android_view_RenderNode_getAllowForceDark(jlong renderNodePtr) { + return reinterpret_cast(renderNodePtr)->stagingProperties().getAllowForceDark(); +} + // ---------------------------------------------------------------------------- // RenderProperties - Animations // ---------------------------------------------------------------------------- @@ -664,6 +672,8 @@ static const JNINativeMethod gMethods[] = { { "nGetPivotY", "(J)F", (void*) android_view_RenderNode_getPivotY }, { "nGetWidth", "(J)I", (void*) android_view_RenderNode_getWidth }, { "nGetHeight", "(J)I", (void*) android_view_RenderNode_getHeight }, + { "nSetAllowForceDark", "(JZ)Z", (void*) android_view_RenderNode_setAllowForceDark }, + { "nGetAllowForceDark", "(J)Z", (void*) android_view_RenderNode_getAllowForceDark }, }; int register_android_view_RenderNode(JNIEnv* env) { diff --git a/graphics/java/android/graphics/Bitmap.java b/graphics/java/android/graphics/Bitmap.java index cea6c1c5d125..9cbbf4ef366f 100644 --- a/graphics/java/android/graphics/Bitmap.java +++ b/graphics/java/android/graphics/Bitmap.java @@ -1253,6 +1253,7 @@ public final class Bitmap implements Parcelable { final RenderNode node = RenderNode.create("BitmapTemporary", null); node.setLeftTopRightBottom(0, 0, width, height); node.setClipToBounds(false); + node.setAllowForceDark(false); final DisplayListCanvas canvas = node.start(width, height); if (source.getWidth() != width || source.getHeight() != height) { canvas.scale(width / (float) source.getWidth(), diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp index 26e5cea2452a..9cfaa6a881ae 100644 --- a/libs/hwui/RenderNode.cpp +++ b/libs/hwui/RenderNode.cpp @@ -112,7 +112,9 @@ void RenderNode::prepareTree(TreeInfo& info) { LOG_ALWAYS_FATAL_IF(!info.damageAccumulator, "DamageAccumulator missing"); MarkAndSweepRemoved observer(&info); + const int before = info.disableForceDark; prepareTreeImpl(observer, info, false); + LOG_ALWAYS_FATAL_IF(before != info.disableForceDark, "Mis-matched force dark"); } void RenderNode::addAnimator(const sp& animator) { @@ -195,6 +197,11 @@ void RenderNode::prepareTreeImpl(TreeObserver& observer, TreeInfo& info, bool fu if (info.mode == TreeInfo::MODE_FULL) { pushStagingPropertiesChanges(info); } + + if (!mProperties.getAllowForceDark()) { + info.disableForceDark++; + } + uint32_t animatorDirtyMask = 0; if (CC_LIKELY(info.runAnimations)) { animatorDirtyMask = mAnimatorManager.animate(info); @@ -232,6 +239,9 @@ void RenderNode::prepareTreeImpl(TreeObserver& observer, TreeInfo& info, bool fu } pushLayerUpdate(info); + if (!mProperties.getAllowForceDark()) { + info.disableForceDark--; + } info.damageAccumulator->popTransform(); } @@ -273,7 +283,7 @@ void RenderNode::syncDisplayList(TreeObserver& observer, TreeInfo* info) { if (mDisplayList) { mDisplayList->syncContents(); - if (CC_UNLIKELY(Properties::forceDarkMode)) { + if (CC_UNLIKELY(info && !info->disableForceDark)) { auto usage = usageHint(); if (mDisplayList->hasText()) { usage = UsageHint::Foreground; diff --git a/libs/hwui/RenderProperties.h b/libs/hwui/RenderProperties.h index 7966845ff814..04379ae68a0d 100644 --- a/libs/hwui/RenderProperties.h +++ b/libs/hwui/RenderProperties.h @@ -535,6 +535,14 @@ public: return CC_UNLIKELY(promotedToLayer()) ? LayerType::RenderLayer : mLayerProperties.mType; } + bool setAllowForceDark(bool allow) { + return RP_SET(mPrimitiveFields.mAllowForceDark, allow); + } + + bool getAllowForceDark() const { + return mPrimitiveFields.mAllowForceDark; + } + private: // Rendering properties struct PrimitiveFields { @@ -554,6 +562,7 @@ private: bool mMatrixOrPivotDirty = false; bool mProjectBackwards = false; bool mProjectionReceiver = false; + bool mAllowForceDark = true; Rect mClipBounds; Outline mOutline; RevealClip mRevealClip; diff --git a/libs/hwui/TreeInfo.h b/libs/hwui/TreeInfo.h index f2766d6a5b6e..caa5762d174a 100644 --- a/libs/hwui/TreeInfo.h +++ b/libs/hwui/TreeInfo.h @@ -17,6 +17,7 @@ #pragma once #include "utils/Macros.h" +#include "Properties.h" #include @@ -93,6 +94,8 @@ public: bool updateWindowPositions = false; + int disableForceDark = Properties::forceDarkMode ? 0 : 1; + struct Out { bool hasFunctors = false; // This is only updated if evaluateAnimations is true diff --git a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java index 044cc5cab20c..48181bc629a8 100644 --- a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java +++ b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java @@ -187,9 +187,11 @@ public class ScreenDecorations extends SystemUI implements Tunable { mOverlay.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE); mOverlay.setAlpha(0); + mOverlay.setAllowForceDark(false); mBottomOverlay.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE); mBottomOverlay.setAlpha(0); + mBottomOverlay.setAllowForceDark(false); updateViews(); -- cgit v1.2.3-59-g8ed1b From 3b4510cd774d1a9e48b4758e95b02e7b32853607 Mon Sep 17 00:00:00 2001 From: John Reck Date: Thu, 27 Sep 2018 17:39:45 -0700 Subject: Auto-dark NinePatches & launcher Support palette for ninepatches (fixes popupwindow) Crude heuristic tweak to treat any RenderNode that fully contains other nodes as background nodes. Test: all apps is now readable, and so is chrome's menu Change-Id: I9926973c0be1dbf0088fa2d61e4ee2a414b19a97 --- libs/hwui/RecordingCanvas.cpp | 102 ++++++++++++++++-------- libs/hwui/RecordingCanvas.h | 8 +- libs/hwui/RenderNode.cpp | 50 ++++++++---- libs/hwui/RenderNode.h | 1 + libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp | 5 +- 5 files changed, 113 insertions(+), 53 deletions(-) (limited to 'libs/hwui/RenderNode.cpp') diff --git a/libs/hwui/RecordingCanvas.cpp b/libs/hwui/RecordingCanvas.cpp index c30af842ebbb..f928de9b92a6 100644 --- a/libs/hwui/RecordingCanvas.cpp +++ b/libs/hwui/RecordingCanvas.cpp @@ -23,6 +23,7 @@ #include "SkDrawShadowInfo.h" #include "SkImage.h" #include "SkImageFilter.h" +#include "SkLatticeIter.h" #include "SkMath.h" #include "SkPicture.h" #include "SkRSXform.h" @@ -280,7 +281,8 @@ struct DrawPicture final : Op { struct DrawImage final : Op { static const auto kType = Type::DrawImage; - DrawImage(sk_sp&& image, SkScalar x, SkScalar y, const SkPaint* paint, BitmapPalette palette) + DrawImage(sk_sp&& image, SkScalar x, SkScalar y, const SkPaint* paint, + BitmapPalette palette) : image(std::move(image)), x(x), y(y), palette(palette) { if (paint) { this->paint = *paint; @@ -312,7 +314,8 @@ struct DrawImageNine final : Op { struct DrawImageRect final : Op { static const auto kType = Type::DrawImageRect; DrawImageRect(sk_sp&& image, const SkRect* src, const SkRect& dst, - const SkPaint* paint, SkCanvas::SrcRectConstraint constraint, BitmapPalette palette) + const SkPaint* paint, SkCanvas::SrcRectConstraint constraint, + BitmapPalette palette) : image(std::move(image)), dst(dst), constraint(constraint), palette(palette) { this->src = src ? *src : SkRect::MakeIWH(this->image->width(), this->image->height()); if (paint) { @@ -331,8 +334,14 @@ struct DrawImageRect final : Op { struct DrawImageLattice final : Op { static const auto kType = Type::DrawImageLattice; DrawImageLattice(sk_sp&& image, int xs, int ys, int fs, const SkIRect& src, - const SkRect& dst, const SkPaint* paint) - : image(std::move(image)), xs(xs), ys(ys), fs(fs), src(src), dst(dst) { + const SkRect& dst, const SkPaint* paint, BitmapPalette palette) + : image(std::move(image)) + , xs(xs) + , ys(ys) + , fs(fs) + , src(src) + , dst(dst) + , palette(palette) { if (paint) { this->paint = *paint; } @@ -342,6 +351,7 @@ struct DrawImageLattice final : Op { SkIRect src; SkRect dst; SkPaint paint; + BitmapPalette palette; void draw(SkCanvas* c, const SkMatrix&) const { auto xdivs = pod(this, 0), ydivs = pod(this, xs * sizeof(int)); auto colors = (0 == fs) ? nullptr : pod(this, (xs + ys) * sizeof(int)); @@ -511,16 +521,13 @@ struct DrawVectorDrawable final : Op { tree->getPaintFor(&paint, tree->stagingProperties()); } - void draw(SkCanvas* canvas, const SkMatrix&) const { - mRoot->draw(canvas, mBounds, paint); - } + void draw(SkCanvas* canvas, const SkMatrix&) const { mRoot->draw(canvas, mBounds, paint); } sp mRoot; SkRect mBounds; SkPaint paint; BitmapPalette palette; }; - } template @@ -647,14 +654,15 @@ void DisplayListData::drawImageRect(sk_sp image, const SkRect* sr this->push(0, std::move(image), src, dst, paint, constraint, palette); } void DisplayListData::drawImageLattice(sk_sp image, const SkCanvas::Lattice& lattice, - const SkRect& dst, const SkPaint* paint) { + const SkRect& dst, const SkPaint* paint, + BitmapPalette palette) { int xs = lattice.fXCount, ys = lattice.fYCount; int fs = lattice.fRectTypes ? (xs + 1) * (ys + 1) : 0; size_t bytes = (xs + ys) * sizeof(int) + fs * sizeof(SkCanvas::Lattice::RectType) + fs * sizeof(SkColor); SkASSERT(lattice.fBounds); void* pod = this->push(bytes, std::move(image), xs, ys, fs, *lattice.fBounds, - dst, paint); + dst, paint, palette); copy_v(pod, lattice.fXDivs, xs, lattice.fYDivs, ys, lattice.fColors, fs, lattice.fRectTypes, fs); } @@ -779,22 +787,26 @@ constexpr bool has_palette = std::experimental::is_detected_v constexpr color_transform_fn colorTransformForOp() { - if constexpr(has_paint && has_palette) { - // It's a bitmap - return [](const void* opRaw, ColorTransform transform) { - // TODO: We should be const. Or not. Or just use a different map - // Unclear, but this is the quick fix - const T* op = reinterpret_cast(opRaw); - transformPaint(transform, const_cast(&(op->paint)), op->palette); - }; - } else if constexpr(has_paint) { - return [](const void* opRaw, ColorTransform transform) { - // TODO: We should be const. Or not. Or just use a different map - // Unclear, but this is the quick fix - const T* op = reinterpret_cast(opRaw); - transformPaint(transform, const_cast(&(op->paint))); - }; - } else { + if + constexpr(has_paint && has_palette) { + // It's a bitmap + return [](const void* opRaw, ColorTransform transform) { + // TODO: We should be const. Or not. Or just use a different map + // Unclear, but this is the quick fix + const T* op = reinterpret_cast(opRaw); + transformPaint(transform, const_cast(&(op->paint)), op->palette); + }; + } + else if + constexpr(has_paint) { + return [](const void* opRaw, ColorTransform transform) { + // TODO: We should be const. Or not. Or just use a different map + // Unclear, but this is the quick fix + const T* op = reinterpret_cast(opRaw); + transformPaint(transform, const_cast(&(op->paint))); + }; + } + else { return nullptr; } } @@ -931,11 +943,12 @@ void RecordingCanvas::onDrawBitmapNine(const SkBitmap& bm, const SkIRect& center } void RecordingCanvas::onDrawBitmapRect(const SkBitmap& bm, const SkRect* src, const SkRect& dst, const SkPaint* paint, SrcRectConstraint constraint) { - fDL->drawImageRect(SkImage::MakeFromBitmap(bm), src, dst, paint, constraint, BitmapPalette::Unknown); + fDL->drawImageRect(SkImage::MakeFromBitmap(bm), src, dst, paint, constraint, + BitmapPalette::Unknown); } void RecordingCanvas::onDrawBitmapLattice(const SkBitmap& bm, const SkCanvas::Lattice& lattice, const SkRect& dst, const SkPaint* paint) { - fDL->drawImageLattice(SkImage::MakeFromBitmap(bm), lattice, dst, paint); + fDL->drawImageLattice(SkImage::MakeFromBitmap(bm), lattice, dst, paint, BitmapPalette::Unknown); } void RecordingCanvas::drawImage(const sk_sp& image, SkScalar x, SkScalar y, @@ -943,11 +956,34 @@ void RecordingCanvas::drawImage(const sk_sp& image, SkScalar x, SkScala fDL->drawImage(image, x, y, paint, palette); } -void RecordingCanvas::drawImageRect(const sk_sp& image, const SkRect& src, const SkRect& dst, - const SkPaint* paint, SrcRectConstraint constraint, BitmapPalette palette) { +void RecordingCanvas::drawImageRect(const sk_sp& image, const SkRect& src, + const SkRect& dst, const SkPaint* paint, + SrcRectConstraint constraint, BitmapPalette palette) { fDL->drawImageRect(image, &src, dst, paint, constraint, palette); } +void RecordingCanvas::drawImageLattice(const sk_sp& image, const Lattice& lattice, + const SkRect& dst, const SkPaint* paint, + BitmapPalette palette) { + if (!image || dst.isEmpty()) { + return; + } + + SkIRect bounds; + Lattice latticePlusBounds = lattice; + if (!latticePlusBounds.fBounds) { + bounds = SkIRect::MakeWH(image->width(), image->height()); + latticePlusBounds.fBounds = &bounds; + } + + if (SkLatticeIter::Valid(image->width(), image->height(), latticePlusBounds)) { + fDL->drawImageLattice(image, latticePlusBounds, dst, paint, palette); + } else { + fDL->drawImageRect(image, nullptr, dst, paint, SrcRectConstraint::kFast_SrcRectConstraint, + palette); + } +} + void RecordingCanvas::onDrawImage(const SkImage* img, SkScalar x, SkScalar y, const SkPaint* paint) { fDL->drawImage(sk_ref_sp(img), x, y, paint, BitmapPalette::Unknown); @@ -962,7 +998,7 @@ void RecordingCanvas::onDrawImageRect(const SkImage* img, const SkRect* src, con } void RecordingCanvas::onDrawImageLattice(const SkImage* img, const SkCanvas::Lattice& lattice, const SkRect& dst, const SkPaint* paint) { - fDL->drawImageLattice(sk_ref_sp(img), lattice, dst, paint); + fDL->drawImageLattice(sk_ref_sp(img), lattice, dst, paint, BitmapPalette::Unknown); } void RecordingCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4], @@ -975,8 +1011,8 @@ void RecordingCanvas::onDrawPoints(SkCanvas::PointMode mode, size_t count, const fDL->drawPoints(mode, count, pts, paint); } void RecordingCanvas::onDrawVerticesObject(const SkVertices* vertices, - const SkVertices::Bone bones[], int boneCount, - SkBlendMode mode, const SkPaint& paint) { + const SkVertices::Bone bones[], int boneCount, + SkBlendMode mode, const SkPaint& paint) { fDL->drawVertices(vertices, bones, boneCount, mode, paint); } void RecordingCanvas::onDrawAtlas(const SkImage* atlas, const SkRSXform xforms[], diff --git a/libs/hwui/RecordingCanvas.h b/libs/hwui/RecordingCanvas.h index 80c80ca46515..099e0be433ea 100644 --- a/libs/hwui/RecordingCanvas.h +++ b/libs/hwui/RecordingCanvas.h @@ -110,7 +110,7 @@ private: void drawImageRect(sk_sp, const SkRect*, const SkRect&, const SkPaint*, SkCanvas::SrcRectConstraint, BitmapPalette palette); void drawImageLattice(sk_sp, const SkCanvas::Lattice&, const SkRect&, - const SkPaint*); + const SkPaint*, BitmapPalette); void drawPatch(const SkPoint[12], const SkColor[4], const SkPoint[4], SkBlendMode, const SkPaint&); @@ -185,11 +185,13 @@ public: void onDrawBitmapRect(const SkBitmap&, const SkRect*, const SkRect&, const SkPaint*, SrcRectConstraint) override; - void drawImage(const sk_sp& image, SkScalar left, SkScalar top, - const SkPaint* paint, BitmapPalette pallete); + void drawImage(const sk_sp& image, SkScalar left, SkScalar top, const SkPaint* paint, + BitmapPalette pallete); void drawImageRect(const sk_sp& image, const SkRect& src, const SkRect& dst, const SkPaint* paint, SrcRectConstraint constraint, BitmapPalette palette); + void drawImageLattice(const sk_sp& image, const Lattice& lattice, const SkRect& dst, + const SkPaint* paint, BitmapPalette palette); void onDrawImage(const SkImage*, SkScalar, SkScalar, const SkPaint*) override; void onDrawImageLattice(const SkImage*, const Lattice&, const SkRect&, const SkPaint*) override; diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp index d9a7cc3a575f..d2a8f02cc6a7 100644 --- a/libs/hwui/RenderNode.cpp +++ b/libs/hwui/RenderNode.cpp @@ -282,25 +282,45 @@ void RenderNode::syncDisplayList(TreeObserver& observer, TreeInfo* info) { mStagingDisplayList = nullptr; if (mDisplayList) { mDisplayList->syncContents(); + handleForceDark(info); + } +} - if (CC_UNLIKELY(info && !info->disableForceDark)) { - auto usage = usageHint(); - if (mDisplayList->hasText()) { - usage = UsageHint::Foreground; - } - if (usage == UsageHint::Unknown) { - if (mDisplayList->mChildNodes.size() > 1) { - usage = UsageHint::Background; - } else if (mDisplayList->mChildNodes.size() == 1 && - mDisplayList->mChildNodes.front().getRenderNode()->usageHint() != - UsageHint::Background) { - usage = UsageHint::Background; - } +void RenderNode::handleForceDark(android::uirenderer::TreeInfo *info) { + if (CC_LIKELY(!info || info->disableForceDark)) { + return; + } + auto usage = usageHint(); + const auto& children = mDisplayList->mChildNodes; + if (mDisplayList->hasText()) { + usage = UsageHint::Foreground; + } + if (usage == UsageHint::Unknown) { + if (children.size() > 1) { + usage = UsageHint::Background; + } else if (children.size() == 1 && + children.front().getRenderNode()->usageHint() != + UsageHint::Background) { + usage = UsageHint::Background; + } + } + if (children.size() > 1) { + // Crude overlap check + SkRect drawn = SkRect::MakeEmpty(); + for (auto iter = children.rbegin(); iter != children.rend(); ++iter) { + const auto& child = iter->getRenderNode(); + // We use stagingProperties here because we haven't yet sync'd the children + SkRect bounds = SkRect::MakeXYWH(child->stagingProperties().getX(), child->stagingProperties().getY(), + child->stagingProperties().getWidth(), child->stagingProperties().getHeight()); + if (bounds.contains(drawn)) { + // This contains everything drawn after it, so make it a background + child->setUsageHint(UsageHint::Background); } - mDisplayList->mDisplayList.applyColorTransform( - usage == UsageHint::Background ? ColorTransform::Dark : ColorTransform::Light); + drawn.join(bounds); } } + mDisplayList->mDisplayList.applyColorTransform( + usage == UsageHint::Background ? ColorTransform::Dark : ColorTransform::Light); } void RenderNode::pushStagingDisplayListChanges(TreeObserver& observer, TreeInfo& info) { diff --git a/libs/hwui/RenderNode.h b/libs/hwui/RenderNode.h index 211dd2db5cf8..be0b46b1c45f 100644 --- a/libs/hwui/RenderNode.h +++ b/libs/hwui/RenderNode.h @@ -220,6 +220,7 @@ private: void syncProperties(); void syncDisplayList(TreeObserver& observer, TreeInfo* info); + void handleForceDark(TreeInfo* info); void prepareTreeImpl(TreeObserver& observer, TreeInfo& info, bool functorsNeedLayer); void pushStagingPropertiesChanges(TreeInfo& info); diff --git a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp index fac07d74dad4..3fa73a4dadda 100644 --- a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp +++ b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp @@ -245,8 +245,9 @@ void SkiaRecordingCanvas::drawNinePatch(Bitmap& bitmap, const Res_png_9patch& ch } sk_sp colorFilter; sk_sp image = bitmap.makeImage(&colorFilter); - mRecorder.drawImageLattice(image.get(), lattice, dst, - filterBitmap(std::move(filteredPaint), std::move(colorFilter))); + mRecorder.drawImageLattice(image, lattice, dst, + filterBitmap(std::move(filteredPaint), std::move(colorFilter)), + bitmap.palette()); if (!bitmap.isImmutable() && image.get() && !image->unique() && !dst.isEmpty()) { mDisplayList->mMutableImages.push_back(image.get()); } -- cgit v1.2.3-59-g8ed1b From f96b284dec00580c6a586cf6787b98eeb2cd73f5 Mon Sep 17 00:00:00 2001 From: John Reck Date: Thu, 29 Nov 2018 09:44:10 -0800 Subject: Add a unique ID to rendernode Bug: 120089776 Test: dump'd skp, verified ID present Change-Id: I97a03804ebc53925e1b79db3dd616a728eff0bfa --- api/current.txt | 1 + core/jni/android_view_RenderNode.cpp | 5 +++ graphics/java/android/graphics/RenderNode.java | 19 ++++++++++++ libs/hwui/RenderNode.cpp | 42 +++++++++++++++++++++++++- libs/hwui/RenderNode.h | 6 ++++ libs/hwui/pipeline/skia/RenderNodeDrawable.cpp | 22 +++++++++++--- 6 files changed, 90 insertions(+), 5 deletions(-) (limited to 'libs/hwui/RenderNode.cpp') diff --git a/api/current.txt b/api/current.txt index 5bd9d2b59608..3d7680444d0b 100644 --- a/api/current.txt +++ b/api/current.txt @@ -14687,6 +14687,7 @@ package android.graphics { method public float getTranslationX(); method public float getTranslationY(); method public float getTranslationZ(); + method public long getUniqueId(); method public int getWidth(); method public boolean hasDisplayList(); method public boolean hasIdentityMatrix(); diff --git a/core/jni/android_view_RenderNode.cpp b/core/jni/android_view_RenderNode.cpp index e89b5933fdc8..752624b0a0be 100644 --- a/core/jni/android_view_RenderNode.cpp +++ b/core/jni/android_view_RenderNode.cpp @@ -468,6 +468,10 @@ static jboolean android_view_RenderNode_getAllowForceDark(jlong renderNodePtr) { return reinterpret_cast(renderNodePtr)->stagingProperties().getAllowForceDark(); } +static jlong android_view_RenderNode_getUniqueId(jlong renderNodePtr) { + return reinterpret_cast(renderNodePtr)->uniqueId(); +} + // ---------------------------------------------------------------------------- // RenderProperties - Animations // ---------------------------------------------------------------------------- @@ -694,6 +698,7 @@ static const JNINativeMethod gMethods[] = { { "nGetHeight", "(J)I", (void*) android_view_RenderNode_getHeight }, { "nSetAllowForceDark", "(JZ)Z", (void*) android_view_RenderNode_setAllowForceDark }, { "nGetAllowForceDark", "(J)Z", (void*) android_view_RenderNode_getAllowForceDark }, + { "nGetUniqueId", "(J)J", (void*) android_view_RenderNode_getUniqueId }, }; int register_android_view_RenderNode(JNIEnv* env) { diff --git a/graphics/java/android/graphics/RenderNode.java b/graphics/java/android/graphics/RenderNode.java index 45d7a2178b84..d6f08b92a648 100644 --- a/graphics/java/android/graphics/RenderNode.java +++ b/graphics/java/android/graphics/RenderNode.java @@ -1173,6 +1173,22 @@ public final class RenderNode { return nGetAllowForceDark(mNativeRenderNode); } + /** + * Returns the unique ID that identifies this RenderNode. This ID is unique for the + * lifetime of the process. IDs are reset on process death, and are unique only within + * the process. + * + * This ID is intended to be used with debugging tools to associate a particular + * RenderNode across different debug dumping & inspection tools. For example + * a View layout inspector should include the unique ID for any RenderNodes that it owns + * to associate the drawing content with the layout content. + * + * @return the unique ID for this RenderNode + */ + public long getUniqueId() { + return nGetUniqueId(mNativeRenderNode); + } + /////////////////////////////////////////////////////////////////////////// // Animations /////////////////////////////////////////////////////////////////////////// @@ -1479,4 +1495,7 @@ public final class RenderNode { @CriticalNative private static native boolean nGetAllowForceDark(long renderNode); + + @CriticalNative + private static native long nGetUniqueId(long renderNode); } diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp index d2a8f02cc6a7..4a639102192f 100644 --- a/libs/hwui/RenderNode.cpp +++ b/libs/hwui/RenderNode.cpp @@ -29,6 +29,7 @@ #include #include +#include #include #include @@ -47,8 +48,14 @@ private: TreeInfo* mTreeInfo; }; +static int64_t generateId() { + static std::atomic sNextId{1}; + return sNextId++; +} + RenderNode::RenderNode() - : mDirtyPropertyFields(0) + : mUniqueId(generateId()) + , mDirtyPropertyFields(0) , mNeedsDisplayListSync(false) , mDisplayList(nullptr) , mStagingDisplayList(nullptr) @@ -444,5 +451,38 @@ const SkPath* RenderNode::getClippedOutline(const SkRect& clipRect) const { return &mClippedOutlineCache.clippedOutline; } +using StringBuffer = FatVector; + +template +static void format(StringBuffer& buffer, const std::string_view& format, T... args) { + buffer.resize(buffer.capacity()); + while (1) { + int needed = snprintf(buffer.data(), buffer.size(), + format.data(), std::forward(args)...); + if (needed < 0) { + buffer[0] = '\0'; + buffer.resize(1); + return; + } + if (needed < buffer.size()) { + buffer.resize(needed + 1); + return; + } + buffer.resize(buffer.size() * 2); + } +} + +void RenderNode::markDrawStart(SkCanvas& canvas) { + StringBuffer buffer; + format(buffer, "RenderNode(id=%d, name='%s')", uniqueId(), getName()); + canvas.drawAnnotation(SkRect::MakeWH(getWidth(), getHeight()), buffer.data(), nullptr); +} + +void RenderNode::markDrawEnd(SkCanvas& canvas) { + StringBuffer buffer; + format(buffer, "/RenderNode(id=%d, name='%s')", uniqueId(), getName()); + canvas.drawAnnotation(SkRect::MakeWH(getWidth(), getHeight()), buffer.data(), nullptr); +} + } /* namespace uirenderer */ } /* namespace android */ diff --git a/libs/hwui/RenderNode.h b/libs/hwui/RenderNode.h index be0b46b1c45f..6060123ed759 100644 --- a/libs/hwui/RenderNode.h +++ b/libs/hwui/RenderNode.h @@ -213,6 +213,11 @@ public: UsageHint usageHint() const { return mUsageHint; } + int64_t uniqueId() const { return mUniqueId; } + + void markDrawStart(SkCanvas& canvas); + void markDrawEnd(SkCanvas& canvas); + private: void computeOrderingImpl(RenderNodeOp* opState, std::vector* compositedChildrenOfProjectionSurface, @@ -233,6 +238,7 @@ private: void incParentRefCount() { mParentCount++; } void decParentRefCount(TreeObserver& observer, TreeInfo* info = nullptr); + const int64_t mUniqueId; String8 mName; sp mUserContext; diff --git a/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp b/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp index ea14d11b7b3e..d80cb6d1ab70 100644 --- a/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp +++ b/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp @@ -115,12 +115,26 @@ void RenderNodeDrawable::onDraw(SkCanvas* canvas) { } } +class MarkDraw { +public: + explicit MarkDraw(SkCanvas& canvas, RenderNode& node) : mCanvas(canvas), mNode(node) { + if (CC_UNLIKELY(Properties::skpCaptureEnabled)) { + mNode.markDrawStart(mCanvas); + } + } + ~MarkDraw() { + if (CC_UNLIKELY(Properties::skpCaptureEnabled)) { + mNode.markDrawEnd(mCanvas); + } + } +private: + SkCanvas& mCanvas; + RenderNode& mNode; +}; + void RenderNodeDrawable::forceDraw(SkCanvas* canvas) { RenderNode* renderNode = mRenderNode.get(); - if (CC_UNLIKELY(Properties::skpCaptureEnabled)) { - SkRect dimensions = SkRect::MakeWH(renderNode->getWidth(), renderNode->getHeight()); - canvas->drawAnnotation(dimensions, renderNode->getName(), nullptr); - } + MarkDraw _marker{*canvas, *renderNode}; // We only respect the nothingToDraw check when we are composing a layer. This // ensures that we paint the layer even if it is not currently visible in the -- cgit v1.2.3-59-g8ed1b From 7af5b2c65387c08b59cdcff700a7321f85912d0e Mon Sep 17 00:00:00 2001 From: John Reck Date: Wed, 5 Dec 2018 13:36:20 -0800 Subject: Fix skp on 32-bit %d strikes again... Test: dumped skp on 32bit app Change-Id: Ica4d9e3939d0e726beb80fbf45a938b004b5eb5d --- libs/hwui/RenderNode.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'libs/hwui/RenderNode.cpp') diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp index 4a639102192f..00ce28ad196f 100644 --- a/libs/hwui/RenderNode.cpp +++ b/libs/hwui/RenderNode.cpp @@ -454,6 +454,9 @@ const SkPath* RenderNode::getClippedOutline(const SkRect& clipRect) const { using StringBuffer = FatVector; template +// TODO:__printflike(2, 3) +// Doesn't work because the warning doesn't understand string_view and doesn't like that +// it's not a C-style variadic function. static void format(StringBuffer& buffer, const std::string_view& format, T... args) { buffer.resize(buffer.capacity()); while (1) { @@ -468,19 +471,20 @@ static void format(StringBuffer& buffer, const std::string_view& format, T... ar buffer.resize(needed + 1); return; } - buffer.resize(buffer.size() * 2); + // If we're doing a heap alloc anyway might as well give it some slop + buffer.resize(needed + 100); } } void RenderNode::markDrawStart(SkCanvas& canvas) { StringBuffer buffer; - format(buffer, "RenderNode(id=%d, name='%s')", uniqueId(), getName()); + format(buffer, "RenderNode(id=%" PRId64 ", name='%s')", uniqueId(), getName()); canvas.drawAnnotation(SkRect::MakeWH(getWidth(), getHeight()), buffer.data(), nullptr); } void RenderNode::markDrawEnd(SkCanvas& canvas) { StringBuffer buffer; - format(buffer, "/RenderNode(id=%d, name='%s')", uniqueId(), getName()); + format(buffer, "/RenderNode(id=%" PRId64 ", name='%s')", uniqueId(), getName()); canvas.drawAnnotation(SkRect::MakeWH(getWidth(), getHeight()), buffer.data(), nullptr); } -- cgit v1.2.3-59-g8ed1b From 283bb46846ad161045efc4650d3cbc40abf5f24b Mon Sep 17 00:00:00 2001 From: John Reck Date: Thu, 13 Dec 2018 16:40:14 -0800 Subject: New WebViewFunctor API Should function alongside existing functor API. Bug: 120997728 Test: hwuiunit passes Change-Id: I8f6143d0be1111431b55016f34de319f6b8c8910 --- core/jni/android_view_DisplayListCanvas.cpp | 6 + .../java/android/graphics/RecordingCanvas.java | 10 ++ libs/hwui/Android.bp | 4 + libs/hwui/RenderNode.cpp | 5 +- libs/hwui/WebViewFunctorManager.cpp | 167 +++++++++++++++++++++ libs/hwui/WebViewFunctorManager.h | 92 ++++++++++++ libs/hwui/hwui/Canvas.h | 3 + libs/hwui/pipeline/skia/FunctorDrawable.h | 36 ++++- libs/hwui/pipeline/skia/GLFunctorDrawable.cpp | 41 ++--- libs/hwui/pipeline/skia/GLFunctorDrawable.h | 6 +- libs/hwui/pipeline/skia/LayerDrawable.cpp | 20 +-- libs/hwui/pipeline/skia/LayerDrawable.h | 4 +- libs/hwui/pipeline/skia/RenderNodeDrawable.cpp | 7 +- libs/hwui/pipeline/skia/ShaderCache.cpp | 16 +- libs/hwui/pipeline/skia/ShaderCache.h | 8 +- libs/hwui/pipeline/skia/SkiaDisplayList.cpp | 4 +- libs/hwui/pipeline/skia/SkiaDisplayList.h | 4 +- libs/hwui/pipeline/skia/SkiaMemoryTracer.cpp | 22 +-- libs/hwui/pipeline/skia/SkiaMemoryTracer.h | 4 +- libs/hwui/pipeline/skia/SkiaPipeline.cpp | 9 +- libs/hwui/pipeline/skia/SkiaPipeline.h | 3 +- libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp | 33 ++-- libs/hwui/pipeline/skia/SkiaRecordingCanvas.h | 1 + libs/hwui/pipeline/skia/SkiaUtils.h | 2 +- libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp | 2 +- libs/hwui/pipeline/skia/VkFunctorDrawable.cpp | 37 ++--- libs/hwui/pipeline/skia/VkFunctorDrawable.h | 15 +- .../pipeline/skia/VkInteropFunctorDrawable.cpp | 78 +++++----- libs/hwui/pipeline/skia/VkInteropFunctorDrawable.h | 12 +- libs/hwui/private/hwui/WebViewFunctor.h | 82 ++++++++++ libs/hwui/renderthread/CanvasContext.cpp | 3 +- libs/hwui/renderthread/RenderProxy.cpp | 9 ++ libs/hwui/renderthread/RenderProxy.h | 1 + libs/hwui/renderthread/RenderThread.cpp | 5 +- libs/hwui/renderthread/RenderThread.h | 4 +- libs/hwui/tests/common/TestUtils.cpp | 20 +-- libs/hwui/tests/common/TestUtils.h | 62 +++++++- libs/hwui/tests/unit/DeferredLayerUpdaterTests.cpp | 2 +- libs/hwui/tests/unit/GpuMemoryTrackerTests.cpp | 2 +- libs/hwui/tests/unit/RenderNodeDrawableTests.cpp | 58 ++++--- libs/hwui/tests/unit/RenderNodeTests.cpp | 3 +- libs/hwui/tests/unit/ShaderCacheTests.cpp | 99 ++++++------ libs/hwui/tests/unit/SkiaDisplayListTests.cpp | 27 +++- libs/hwui/tests/unit/SkiaPipelineTests.cpp | 38 ++--- libs/hwui/tests/unit/TypefaceTests.cpp | 6 +- libs/hwui/tests/unit/VectorDrawableTests.cpp | 25 +-- .../hwui/tests/unit/WebViewFunctorManagerTests.cpp | 154 +++++++++++++++++++ libs/hwui/tests/unit/main.cpp | 4 +- 48 files changed, 940 insertions(+), 315 deletions(-) create mode 100644 libs/hwui/WebViewFunctorManager.cpp create mode 100644 libs/hwui/WebViewFunctorManager.h create mode 100644 libs/hwui/private/hwui/WebViewFunctor.h create mode 100644 libs/hwui/tests/unit/WebViewFunctorManagerTests.cpp (limited to 'libs/hwui/RenderNode.cpp') diff --git a/core/jni/android_view_DisplayListCanvas.cpp b/core/jni/android_view_DisplayListCanvas.cpp index e0fd1a634557..40a133b9383b 100644 --- a/core/jni/android_view_DisplayListCanvas.cpp +++ b/core/jni/android_view_DisplayListCanvas.cpp @@ -168,6 +168,11 @@ static void android_view_DisplayListCanvas_drawCircleProps(jlong canvasPtr, canvas->drawCircle(xProp, yProp, radiusProp, paintProp); } +static void android_view_DisplayListCanvas_drawWebViewFunctor(jlong canvasPtr, jint functor) { + Canvas* canvas = reinterpret_cast(canvasPtr); + canvas->drawWebViewFunctor(functor); +} + // ---------------------------------------------------------------------------- // JNI Glue // ---------------------------------------------------------------------------- @@ -192,6 +197,7 @@ static JNINativeMethod gMethods[] = { { "nDrawTextureLayer", "(JJ)V", (void*) android_view_DisplayListCanvas_drawTextureLayer }, { "nDrawCircle", "(JJJJJ)V", (void*) android_view_DisplayListCanvas_drawCircleProps }, { "nDrawRoundRect", "(JJJJJJJJ)V",(void*) android_view_DisplayListCanvas_drawRoundRectProps }, + { "nDrawWebViewFunctor", "(JI)V", (void*) android_view_DisplayListCanvas_drawWebViewFunctor }, }; int register_android_view_DisplayListCanvas(JNIEnv* env) { diff --git a/graphics/java/android/graphics/RecordingCanvas.java b/graphics/java/android/graphics/RecordingCanvas.java index 67ad4045868e..515532ffda52 100644 --- a/graphics/java/android/graphics/RecordingCanvas.java +++ b/graphics/java/android/graphics/RecordingCanvas.java @@ -189,6 +189,14 @@ public final class RecordingCanvas extends DisplayListCanvas { nCallDrawGLFunction(mNativeCanvasWrapper, drawGLFunctor, releasedCallback); } + /** + * Calls the provided functor that was created via WebViewFunctor_create() + * @hide + */ + public void drawWebViewFunctor(int functor) { + nDrawWebViewFunctor(mNativeCanvasWrapper, functor); + } + /////////////////////////////////////////////////////////////////////////// // Display list /////////////////////////////////////////////////////////////////////////// @@ -303,4 +311,6 @@ public final class RecordingCanvas extends DisplayListCanvas { @CriticalNative private static native void nDrawRoundRect(long renderer, long propLeft, long propTop, long propRight, long propBottom, long propRx, long propRy, long propPaint); + @CriticalNative + private static native void nDrawWebViewFunctor(long canvas, int functor); } diff --git a/libs/hwui/Android.bp b/libs/hwui/Android.bp index d22eaf38cef6..b631b120f468 100644 --- a/libs/hwui/Android.bp +++ b/libs/hwui/Android.bp @@ -9,6 +9,8 @@ cc_defaults { "hwui_lto", ], + cpp_std: "experimental", + cflags: [ "-DEGL_EGLEXT_PROTOTYPES", "-DGL_GLEXT_PROTOTYPES", @@ -224,6 +226,7 @@ cc_defaults { "RenderProperties.cpp", "SkiaCanvas.cpp", "TreeInfo.cpp", + "WebViewFunctorManager.cpp", "VectorDrawable.cpp", "protos/graphicsstats.proto", ], @@ -328,6 +331,7 @@ cc_test { "tests/unit/TypefaceTests.cpp", "tests/unit/VectorDrawableTests.cpp", "tests/unit/VectorDrawableAtlasTests.cpp", + "tests/unit/WebViewFunctorManagerTests.cpp", ], } diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp index 00ce28ad196f..1ff7ffe6bf87 100644 --- a/libs/hwui/RenderNode.cpp +++ b/libs/hwui/RenderNode.cpp @@ -288,7 +288,10 @@ void RenderNode::syncDisplayList(TreeObserver& observer, TreeInfo* info) { mDisplayList = mStagingDisplayList; mStagingDisplayList = nullptr; if (mDisplayList) { - mDisplayList->syncContents(); + WebViewSyncData syncData { + .applyForceDark = info && !info->disableForceDark + }; + mDisplayList->syncContents(syncData); handleForceDark(info); } } diff --git a/libs/hwui/WebViewFunctorManager.cpp b/libs/hwui/WebViewFunctorManager.cpp new file mode 100644 index 000000000000..20e77b453706 --- /dev/null +++ b/libs/hwui/WebViewFunctorManager.cpp @@ -0,0 +1,167 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "WebViewFunctorManager.h" + +#include +#include "Properties.h" + +#include +#include +#include + +namespace android::uirenderer { + +RenderMode WebViewFunctor_queryPlatformRenderMode() { + auto pipelineType = Properties::getRenderPipelineType(); + switch (pipelineType) { + case RenderPipelineType::SkiaGL: + return RenderMode::OpenGL_ES; + case RenderPipelineType::SkiaVulkan: + return RenderMode::Vulkan; + default: + LOG_ALWAYS_FATAL("Unknown render pipeline type: %d", (int)pipelineType); + } +} + +int WebViewFunctor_create(const WebViewFunctorCallbacks& prototype, RenderMode functorMode) { + if (functorMode != RenderMode::OpenGL_ES && functorMode != RenderMode::Vulkan) { + ALOGW("Unknown rendermode %d", (int)functorMode); + return -1; + } + if (functorMode == RenderMode::Vulkan && + WebViewFunctor_queryPlatformRenderMode() != RenderMode::Vulkan) { + ALOGW("Unable to map from GLES platform to a vulkan functor"); + return -1; + } + return WebViewFunctorManager::instance().createFunctor(prototype, functorMode); +} + +void WebViewFunctor_release(int functor) { + WebViewFunctorManager::instance().releaseFunctor(functor); +} + +static std::atomic_int sNextId{1}; + +WebViewFunctor::WebViewFunctor(const WebViewFunctorCallbacks& callbacks, RenderMode functorMode) { + mFunctor = sNextId++; + mCallbacks = callbacks; + mMode = functorMode; +} + +WebViewFunctor::~WebViewFunctor() { + destroyContext(); + + ATRACE_NAME("WebViewFunctor::onDestroy"); + mCallbacks.onDestroyed(mFunctor); +} + +void WebViewFunctor::sync(const WebViewSyncData& syncData) const { + ATRACE_NAME("WebViewFunctor::sync"); + mCallbacks.onSync(mFunctor, syncData); +} + +void WebViewFunctor::drawGl(const DrawGlInfo& drawInfo) { + ATRACE_NAME("WebViewFunctor::drawGl"); + if (!mHasContext) { + mHasContext = true; + } + mCallbacks.gles.draw(mFunctor, drawInfo); +} + +void WebViewFunctor::destroyContext() { + if (mHasContext) { + mHasContext = false; + ATRACE_NAME("WebViewFunctor::onContextDestroyed"); + mCallbacks.onContextDestroyed(mFunctor); + } +} + +WebViewFunctorManager& WebViewFunctorManager::instance() { + static WebViewFunctorManager sInstance; + return sInstance; +} + +int WebViewFunctorManager::createFunctor(const WebViewFunctorCallbacks& callbacks, + RenderMode functorMode) { + auto object = std::make_unique(callbacks, functorMode); + int id = object->id(); + auto handle = object->createHandle(); + { + std::lock_guard _lock{mLock}; + mActiveFunctors.push_back(std::move(handle)); + mFunctors.push_back(std::move(object)); + } + return id; +} + +void WebViewFunctorManager::releaseFunctor(int functor) { + sp toRelease; + { + std::lock_guard _lock{mLock}; + for (auto iter = mActiveFunctors.begin(); iter != mActiveFunctors.end(); iter++) { + if ((*iter)->id() == functor) { + toRelease = std::move(*iter); + mActiveFunctors.erase(iter); + break; + } + } + } +} + +void WebViewFunctorManager::onContextDestroyed() { + // WARNING: SKETCHY + // Because we know that we always remove from mFunctors on RenderThread, the same + // thread that always invokes onContextDestroyed, we know that the functor pointers + // will remain valid without the lock held. + // However, we won't block new functors from being added in the meantime. + mLock.lock(); + const size_t size = mFunctors.size(); + WebViewFunctor* toDestroyContext[size]; + for (size_t i = 0; i < size; i++) { + toDestroyContext[i] = mFunctors[i].get(); + } + mLock.unlock(); + for (size_t i = 0; i < size; i++) { + toDestroyContext[i]->destroyContext(); + } +} + +void WebViewFunctorManager::destroyFunctor(int functor) { + std::unique_ptr toRelease; + { + std::lock_guard _lock{mLock}; + for (auto iter = mFunctors.begin(); iter != mFunctors.end(); iter++) { + if ((*iter)->id() == functor) { + toRelease = std::move(*iter); + mFunctors.erase(iter); + break; + } + } + } +} + +sp WebViewFunctorManager::handleFor(int functor) { + std::lock_guard _lock{mLock}; + for (auto& iter : mActiveFunctors) { + if (iter->id() == functor) { + return iter; + } + } + return nullptr; +} + +} // namespace android::uirenderer \ No newline at end of file diff --git a/libs/hwui/WebViewFunctorManager.h b/libs/hwui/WebViewFunctorManager.h new file mode 100644 index 000000000000..2a621dd411e3 --- /dev/null +++ b/libs/hwui/WebViewFunctorManager.h @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include + +#include +#include +#include + +namespace android::uirenderer { + +class WebViewFunctorManager; + +class WebViewFunctor { +public: + WebViewFunctor(const WebViewFunctorCallbacks& callbacks, RenderMode functorMode); + ~WebViewFunctor(); + + class Handle : public LightRefBase { + public: + ~Handle() { renderthread::RenderProxy::destroyFunctor(id()); } + + int id() const { return mReference.id(); } + + void sync(const WebViewSyncData& syncData) const { mReference.sync(syncData); } + + void drawGl(const DrawGlInfo& drawInfo) const { mReference.drawGl(drawInfo); } + + private: + friend class WebViewFunctor; + + Handle(WebViewFunctor& ref) : mReference(ref) {} + + WebViewFunctor& mReference; + }; + + int id() const { return mFunctor; } + void sync(const WebViewSyncData& syncData) const; + void drawGl(const DrawGlInfo& drawInfo); + void destroyContext(); + + sp createHandle() { + LOG_ALWAYS_FATAL_IF(mCreatedHandle); + mCreatedHandle = true; + return sp{new Handle(*this)}; + } + +private: + WebViewFunctorCallbacks mCallbacks; + int mFunctor; + RenderMode mMode; + bool mHasContext = false; + bool mCreatedHandle = false; +}; + +class WebViewFunctorManager { +public: + static WebViewFunctorManager& instance(); + + int createFunctor(const WebViewFunctorCallbacks& callbacks, RenderMode functorMode); + void releaseFunctor(int functor); + void onContextDestroyed(); + void destroyFunctor(int functor); + + sp handleFor(int functor); + +private: + WebViewFunctorManager() = default; + ~WebViewFunctorManager() = default; + + std::mutex mLock; + std::vector> mFunctors; + std::vector> mActiveFunctors; +}; + +} // namespace android::uirenderer diff --git a/libs/hwui/hwui/Canvas.h b/libs/hwui/hwui/Canvas.h index a5f21d8e6d73..71814c365c31 100644 --- a/libs/hwui/hwui/Canvas.h +++ b/libs/hwui/hwui/Canvas.h @@ -178,6 +178,9 @@ public: virtual void drawRenderNode(uirenderer::RenderNode* renderNode) = 0; virtual void callDrawGLFunction(Functor* functor, uirenderer::GlFunctorLifecycleListener* listener) = 0; + virtual void drawWebViewFunctor(int /*functor*/) { + LOG_ALWAYS_FATAL("Not supported"); + } // ---------------------------------------------------------------------------- // Canvas state operations diff --git a/libs/hwui/pipeline/skia/FunctorDrawable.h b/libs/hwui/pipeline/skia/FunctorDrawable.h index af3a056864a7..cf2f93b95e71 100644 --- a/libs/hwui/pipeline/skia/FunctorDrawable.h +++ b/libs/hwui/pipeline/skia/FunctorDrawable.h @@ -21,7 +21,9 @@ #include #include +#include #include +#include namespace android { namespace uirenderer { @@ -35,17 +37,43 @@ namespace skiapipeline { class FunctorDrawable : public SkDrawable { public: FunctorDrawable(Functor* functor, GlFunctorLifecycleListener* listener, SkCanvas* canvas) - : mFunctor(functor), mListener(listener), mBounds(canvas->getLocalClipBounds()) {} + : mBounds(canvas->getLocalClipBounds()) + , mAnyFunctor(std::in_place_type, functor, listener) {} + + FunctorDrawable(int functor, SkCanvas* canvas) + : mBounds(canvas->getLocalClipBounds()) + , mAnyFunctor(std::in_place_type, functor) {} + virtual ~FunctorDrawable() {} - virtual void syncFunctor() const = 0; + virtual void syncFunctor(const WebViewSyncData& data) const { + if (mAnyFunctor.index() == 0) { + std::get<0>(mAnyFunctor).handle->sync(data); + } else { + (*(std::get<1>(mAnyFunctor).functor))(DrawGlInfo::kModeSync, nullptr); + } + } protected: virtual SkRect onGetBounds() override { return mBounds; } - Functor* mFunctor; - sp mListener; const SkRect mBounds; + + struct LegacyFunctor { + explicit LegacyFunctor(Functor* functor, GlFunctorLifecycleListener* listener) + : functor(functor), listener(listener) {} + Functor* functor; + sp listener; + }; + + struct NewFunctor { + explicit NewFunctor(int functor) { + handle = WebViewFunctorManager::instance().handleFor(functor); + } + sp handle; + }; + + std::variant mAnyFunctor; }; } // namespace skiapipeline diff --git a/libs/hwui/pipeline/skia/GLFunctorDrawable.cpp b/libs/hwui/pipeline/skia/GLFunctorDrawable.cpp index 4a87e7502c6f..240efb41285c 100644 --- a/libs/hwui/pipeline/skia/GLFunctorDrawable.cpp +++ b/libs/hwui/pipeline/skia/GLFunctorDrawable.cpp @@ -17,29 +17,28 @@ #include "GLFunctorDrawable.h" #include #include +#include "FunctorDrawable.h" #include "GlFunctorLifecycleListener.h" +#include "GrBackendSurface.h" +#include "GrRenderTarget.h" +#include "GrRenderTargetContext.h" #include "RenderNode.h" #include "SkAndroidFrameworkUtils.h" #include "SkClipStack.h" #include "SkRect.h" -#include "GrBackendSurface.h" -#include "GrRenderTarget.h" -#include "GrRenderTargetContext.h" namespace android { namespace uirenderer { namespace skiapipeline { GLFunctorDrawable::~GLFunctorDrawable() { - if (mListener.get() != nullptr) { - mListener->onGlFunctorReleased(mFunctor); + if (auto lp = std::get_if(&mAnyFunctor)) { + if (lp->listener) { + lp->listener->onGlFunctorReleased(lp->functor); + } } } -void GLFunctorDrawable::syncFunctor() const { - (*mFunctor)(DrawGlInfo::kModeSync, nullptr); -} - static void setScissor(int viewportHeight, const SkIRect& clip) { SkASSERT(!clip.isEmpty()); // transform to Y-flipped GL space, and prevent negatives @@ -49,14 +48,14 @@ static void setScissor(int viewportHeight, const SkIRect& clip) { } static bool GetFboDetails(SkCanvas* canvas, GLuint* outFboID, SkISize* outFboSize) { - GrRenderTargetContext *renderTargetContext = + GrRenderTargetContext* renderTargetContext = canvas->internal_private_accessTopLayerRenderTargetContext(); if (!renderTargetContext) { ALOGW("Unable to extract renderTarget info from canvas; aborting GLFunctor draw"); return false; } - GrRenderTarget *renderTarget = renderTargetContext->accessRenderTarget(); + GrRenderTarget* renderTarget = renderTargetContext->accessRenderTarget(); if (!renderTarget) { ALOGW("Unable to extract renderTarget info from canvas; aborting GLFunctor draw"); return false; @@ -94,16 +93,16 @@ void GLFunctorDrawable::onDraw(SkCanvas* canvas) { sk_sp tmpSurface; // we are in a state where there is an unclipped saveLayer if (fboID != 0 && !surfaceBounds.contains(clipBounds)) { - // create an offscreen layer and clear it - SkImageInfo surfaceInfo = canvas->imageInfo().makeWH(clipBounds.width(), clipBounds.height()); - tmpSurface = SkSurface::MakeRenderTarget(canvas->getGrContext(), SkBudgeted::kYes, - surfaceInfo); + SkImageInfo surfaceInfo = + canvas->imageInfo().makeWH(clipBounds.width(), clipBounds.height()); + tmpSurface = + SkSurface::MakeRenderTarget(canvas->getGrContext(), SkBudgeted::kYes, surfaceInfo); tmpSurface->getCanvas()->clear(SK_ColorTRANSPARENT); GrGLFramebufferInfo fboInfo; if (!tmpSurface->getBackendRenderTarget(SkSurface::kFlushWrite_BackendHandleAccess) - .getGLFramebufferInfo(&fboInfo)) { + .getGLFramebufferInfo(&fboInfo)) { ALOGW("Unable to extract renderTarget info from offscreen canvas; aborting GLFunctor"); return; } @@ -144,7 +143,7 @@ void GLFunctorDrawable::onDraw(SkCanvas* canvas) { bool clearStencilAfterFunctor = false; if (CC_UNLIKELY(clipRegion.isComplex())) { // clear the stencil - //TODO: move stencil clear and canvas flush to SkAndroidFrameworkUtils::clipWithStencil + // TODO: move stencil clear and canvas flush to SkAndroidFrameworkUtils::clipWithStencil glDisable(GL_SCISSOR_TEST); glStencilMask(0x1); glClearStencil(0); @@ -163,7 +162,7 @@ void GLFunctorDrawable::onDraw(SkCanvas* canvas) { // GL ops get inserted here if previous flush is missing, which could dirty the stencil bool stencilWritten = SkAndroidFrameworkUtils::clipWithStencil(tmpCanvas); - tmpCanvas->flush(); //need this flush for the single op that draws into the stencil + tmpCanvas->flush(); // need this flush for the single op that draws into the stencil // ensure that the framebuffer that the webview will render into is bound before after we // draw into the stencil @@ -188,7 +187,11 @@ void GLFunctorDrawable::onDraw(SkCanvas* canvas) { setScissor(info.height, clipRegion.getBounds()); } - (*mFunctor)(DrawGlInfo::kModeDraw, &info); + if (mAnyFunctor.index() == 0) { + std::get<0>(mAnyFunctor).handle->drawGl(info); + } else { + (*(std::get<1>(mAnyFunctor).functor))(DrawGlInfo::kModeDraw, &info); + } if (clearStencilAfterFunctor) { // clear stencil buffer as it may be used by Skia diff --git a/libs/hwui/pipeline/skia/GLFunctorDrawable.h b/libs/hwui/pipeline/skia/GLFunctorDrawable.h index 215979cba2e3..2ea4f67428bc 100644 --- a/libs/hwui/pipeline/skia/GLFunctorDrawable.h +++ b/libs/hwui/pipeline/skia/GLFunctorDrawable.h @@ -31,11 +31,9 @@ namespace skiapipeline { */ class GLFunctorDrawable : public FunctorDrawable { public: - GLFunctorDrawable(Functor* functor, GlFunctorLifecycleListener* listener, SkCanvas* canvas) - : FunctorDrawable(functor, listener, canvas) {} - virtual ~GLFunctorDrawable(); + using FunctorDrawable::FunctorDrawable; - void syncFunctor() const override; + virtual ~GLFunctorDrawable(); protected: void onDraw(SkCanvas* canvas) override; diff --git a/libs/hwui/pipeline/skia/LayerDrawable.cpp b/libs/hwui/pipeline/skia/LayerDrawable.cpp index f08ac17e4082..eed19420a78a 100644 --- a/libs/hwui/pipeline/skia/LayerDrawable.cpp +++ b/libs/hwui/pipeline/skia/LayerDrawable.cpp @@ -14,8 +14,8 @@ * limitations under the License. */ -#include #include "LayerDrawable.h" +#include #include "GrBackendSurface.h" #include "SkColorFilter.h" @@ -44,10 +44,9 @@ static bool shouldFilter(const SkMatrix& matrix) { if (!matrix.isScaleTranslate()) return true; // We only care about meaningful scale here - bool noScale = MathUtils::isOne(matrix.getScaleX()) - && MathUtils::isOne(matrix.getScaleY()); - bool pixelAligned = SkScalarIsInt(matrix.getTranslateX()) - && SkScalarIsInt(matrix.getTranslateY()); + bool noScale = MathUtils::isOne(matrix.getScaleX()) && MathUtils::isOne(matrix.getScaleY()); + bool pixelAligned = + SkScalarIsInt(matrix.getTranslateX()) && SkScalarIsInt(matrix.getTranslateY()); return !(noScale && pixelAligned); } @@ -120,11 +119,12 @@ bool LayerDrawable::DrawLayer(GrContext* context, SkCanvas* canvas, Layer* layer // Integer translation is defined as when src rect and dst rect align fractionally. // Skia TextureOp has the above logic build-in, but not NonAAFillRectOp. TextureOp works // only for SrcOver blending and without color filter (readback uses Src blending). - bool isIntegerTranslate = isBasicallyTranslate(totalMatrix) - && SkScalarFraction(skiaDestRect.fLeft + totalMatrix[SkMatrix::kMTransX]) - == SkScalarFraction(skiaSrcRect.fLeft) - && SkScalarFraction(skiaDestRect.fTop + totalMatrix[SkMatrix::kMTransY]) - == SkScalarFraction(skiaSrcRect.fTop); + bool isIntegerTranslate = + isBasicallyTranslate(totalMatrix) && + SkScalarFraction(skiaDestRect.fLeft + totalMatrix[SkMatrix::kMTransX]) == + SkScalarFraction(skiaSrcRect.fLeft) && + SkScalarFraction(skiaDestRect.fTop + totalMatrix[SkMatrix::kMTransY]) == + SkScalarFraction(skiaSrcRect.fTop); if (layer->getForceFilter() || !isIntegerTranslate) { paint.setFilterQuality(kLow_SkFilterQuality); } diff --git a/libs/hwui/pipeline/skia/LayerDrawable.h b/libs/hwui/pipeline/skia/LayerDrawable.h index 95dc6d0cf096..7cd515ae9fcb 100644 --- a/libs/hwui/pipeline/skia/LayerDrawable.h +++ b/libs/hwui/pipeline/skia/LayerDrawable.h @@ -32,8 +32,8 @@ class LayerDrawable : public SkDrawable { public: explicit LayerDrawable(DeferredLayerUpdater* layerUpdater) : mLayerUpdater(layerUpdater) {} - static bool DrawLayer(GrContext* context, SkCanvas* canvas, Layer* layer, - const SkRect* srcRect, const SkRect* dstRect, bool useLayerTransform); + static bool DrawLayer(GrContext* context, SkCanvas* canvas, Layer* layer, const SkRect* srcRect, + const SkRect* dstRect, bool useLayerTransform); protected: virtual SkRect onGetBounds() override { diff --git a/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp b/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp index 4494cb05df10..df1537e2d824 100644 --- a/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp +++ b/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp @@ -127,6 +127,7 @@ public: mNode.markDrawEnd(mCanvas); } } + private: SkCanvas& mCanvas; RenderNode& mNode; @@ -140,7 +141,7 @@ void RenderNodeDrawable::forceDraw(SkCanvas* canvas) { // ensures that we paint the layer even if it is not currently visible in the // event that the properties change and it becomes visible. if ((mProjectedDisplayList == nullptr && !renderNode->isRenderable()) || - (renderNode->nothingToDraw() && mComposeLayer)) { + (renderNode->nothingToDraw() && mComposeLayer)) { return; } @@ -234,8 +235,8 @@ void RenderNodeDrawable::drawContent(SkCanvas* canvas) const { // we need to restrict the portion of the surface drawn to the size of the renderNode. SkASSERT(renderNode->getLayerSurface()->width() >= bounds.width()); SkASSERT(renderNode->getLayerSurface()->height() >= bounds.height()); - canvas->drawImageRect(renderNode->getLayerSurface()->makeImageSnapshot().get(), - bounds, bounds, &paint); + canvas->drawImageRect(renderNode->getLayerSurface()->makeImageSnapshot().get(), bounds, + bounds, &paint); if (!renderNode->getSkiaLayer()->hasRenderedSinceRepaint) { renderNode->getSkiaLayer()->hasRenderedSinceRepaint = true; diff --git a/libs/hwui/pipeline/skia/ShaderCache.cpp b/libs/hwui/pipeline/skia/ShaderCache.cpp index 073b4814305e..562a3b225e36 100644 --- a/libs/hwui/pipeline/skia/ShaderCache.cpp +++ b/libs/hwui/pipeline/skia/ShaderCache.cpp @@ -15,11 +15,11 @@ */ #include "ShaderCache.h" -#include #include -#include -#include #include +#include +#include +#include #include "FileBlobCache.h" #include "Properties.h" #include "utils/TraceUtils.h" @@ -44,8 +44,7 @@ ShaderCache& ShaderCache::get() { } bool ShaderCache::validateCache(const void* identity, ssize_t size) { - if (nullptr == identity && size == 0) - return true; + if (nullptr == identity && size == 0) return true; if (nullptr == identity || size < 0) { if (CC_UNLIKELY(Properties::debugLevel & kDebugCaches)) { @@ -66,8 +65,7 @@ bool ShaderCache::validateCache(const void* identity, ssize_t size) { auto key = sIDKey; auto loaded = mBlobCache->get(&key, sizeof(key), hash.data(), hash.size()); - if (loaded && std::equal(hash.begin(), hash.end(), mIDHash.begin())) - return true; + if (loaded && std::equal(hash.begin(), hash.end(), mIDHash.begin())) return true; if (CC_UNLIKELY(Properties::debugLevel & kDebugCaches)) { ALOGW("ShaderCache::validateCache cache validation fails"); @@ -119,7 +117,7 @@ sk_sp ShaderCache::load(const SkData& key) { int maxTries = 3; while (valueSize > mObservedBlobValueSize && maxTries > 0) { mObservedBlobValueSize = std::min(valueSize, maxValueSize); - void *newValueBuffer = realloc(valueBuffer, mObservedBlobValueSize); + void* newValueBuffer = realloc(valueBuffer, mObservedBlobValueSize); if (!newValueBuffer) { free(valueBuffer); return nullptr; @@ -133,7 +131,7 @@ sk_sp ShaderCache::load(const SkData& key) { return nullptr; } if (valueSize > mObservedBlobValueSize) { - ALOGE("ShaderCache::load value size is too big %d", (int) valueSize); + ALOGE("ShaderCache::load value size is too big %d", (int)valueSize); free(valueBuffer); return nullptr; } diff --git a/libs/hwui/pipeline/skia/ShaderCache.h b/libs/hwui/pipeline/skia/ShaderCache.h index 82804cf93785..d41aadb269dd 100644 --- a/libs/hwui/pipeline/skia/ShaderCache.h +++ b/libs/hwui/pipeline/skia/ShaderCache.h @@ -16,12 +16,12 @@ #pragma once +#include #include #include #include #include #include -#include namespace android { @@ -52,7 +52,7 @@ public: * the initialized state the load and store methods will return without * performing any cache operations. */ - virtual void initShaderDiskCache(const void *identity, ssize_t size); + virtual void initShaderDiskCache(const void* identity, ssize_t size); virtual void initShaderDiskCache() { initShaderDiskCache(nullptr, 0); } @@ -153,7 +153,7 @@ private: /** * "mObservedBlobValueSize" is the maximum value size observed by the cache reading function. */ - size_t mObservedBlobValueSize = 20*1024; + size_t mObservedBlobValueSize = 20 * 1024; /** * The time in seconds to wait before saving newly inserted cache entries. @@ -176,7 +176,7 @@ private: */ static constexpr uint8_t sIDKey = 0; - friend class ShaderCacheTestUtils; //used for unit testing + friend class ShaderCacheTestUtils; // used for unit testing }; } /* namespace skiapipeline */ diff --git a/libs/hwui/pipeline/skia/SkiaDisplayList.cpp b/libs/hwui/pipeline/skia/SkiaDisplayList.cpp index ac6f6a3f776d..230065c222a9 100644 --- a/libs/hwui/pipeline/skia/SkiaDisplayList.cpp +++ b/libs/hwui/pipeline/skia/SkiaDisplayList.cpp @@ -27,9 +27,9 @@ namespace android { namespace uirenderer { namespace skiapipeline { -void SkiaDisplayList::syncContents() { +void SkiaDisplayList::syncContents(const WebViewSyncData& data) { for (auto& functor : mChildFunctors) { - functor->syncFunctor(); + functor->syncFunctor(data); } for (auto& animatedImage : mAnimatedImages) { animatedImage->syncProperties(); diff --git a/libs/hwui/pipeline/skia/SkiaDisplayList.h b/libs/hwui/pipeline/skia/SkiaDisplayList.h index d7879e722a29..309ec02a9435 100644 --- a/libs/hwui/pipeline/skia/SkiaDisplayList.h +++ b/libs/hwui/pipeline/skia/SkiaDisplayList.h @@ -16,11 +16,11 @@ #pragma once -#include "hwui/AnimatedImageDrawable.h" #include "FunctorDrawable.h" #include "RecordingCanvas.h" #include "RenderNodeDrawable.h" #include "TreeInfo.h" +#include "hwui/AnimatedImageDrawable.h" #include "utils/LinearAllocator.h" #include @@ -109,7 +109,7 @@ public: * NOTE: This function can be folded into RenderNode when we no longer need * to subclass from DisplayList */ - void syncContents(); + void syncContents(const WebViewSyncData& data); /** * ONLY to be called by RenderNode::prepareTree in order to prepare this diff --git a/libs/hwui/pipeline/skia/SkiaMemoryTracer.cpp b/libs/hwui/pipeline/skia/SkiaMemoryTracer.cpp index ea578cb3ec05..e48ecf490c56 100644 --- a/libs/hwui/pipeline/skia/SkiaMemoryTracer.cpp +++ b/libs/hwui/pipeline/skia/SkiaMemoryTracer.cpp @@ -21,16 +21,16 @@ namespace uirenderer { namespace skiapipeline { SkiaMemoryTracer::SkiaMemoryTracer(std::vector resourceMap, bool itemizeType) - : mResourceMap(resourceMap) - , mItemizeType(itemizeType) - , mTotalSize("bytes", 0) - , mPurgeableSize("bytes", 0) {} + : mResourceMap(resourceMap) + , mItemizeType(itemizeType) + , mTotalSize("bytes", 0) + , mPurgeableSize("bytes", 0) {} SkiaMemoryTracer::SkiaMemoryTracer(const char* categoryKey, bool itemizeType) - : mCategoryKey(categoryKey) - , mItemizeType(itemizeType) - , mTotalSize("bytes", 0) - , mPurgeableSize("bytes", 0) {} + : mCategoryKey(categoryKey) + , mItemizeType(itemizeType) + , mTotalSize("bytes", 0) + , mPurgeableSize("bytes", 0) {} const char* SkiaMemoryTracer::mapName(const char* resourceName) { for (auto& resource : mResourceMap) { @@ -42,7 +42,7 @@ const char* SkiaMemoryTracer::mapName(const char* resourceName) { } void SkiaMemoryTracer::processElement() { - if(!mCurrentElement.empty()) { + if (!mCurrentElement.empty()) { // Only count elements that contain "size", other values just provide metadata. auto sizeResult = mCurrentValues.find("size"); if (sizeResult != mCurrentValues.end()) { @@ -136,8 +136,8 @@ void SkiaMemoryTracer::logOutput(String8& log) { for (const auto& typedValue : namedItem.second) { TraceValue traceValue = convertUnits(typedValue.second); const char* entry = (traceValue.count > 1) ? "entries" : "entry"; - log.appendFormat(" %s: %.2f %s (%d %s)\n", typedValue.first, - traceValue.value, traceValue.units, traceValue.count, entry); + log.appendFormat(" %s: %.2f %s (%d %s)\n", typedValue.first, traceValue.value, + traceValue.units, traceValue.count, entry); } } else { auto result = namedItem.second.find("size"); diff --git a/libs/hwui/pipeline/skia/SkiaMemoryTracer.h b/libs/hwui/pipeline/skia/SkiaMemoryTracer.h index abf1f4b052ce..e9a7981ef028 100644 --- a/libs/hwui/pipeline/skia/SkiaMemoryTracer.h +++ b/libs/hwui/pipeline/skia/SkiaMemoryTracer.h @@ -50,8 +50,8 @@ public: } bool shouldDumpWrappedObjects() const override { return true; } - void setMemoryBacking(const char*, const char*, const char*) override { } - void setDiscardableMemoryBacking(const char*, const SkDiscardableMemory&) override { } + void setMemoryBacking(const char*, const char*, const char*) override {} + void setDiscardableMemoryBacking(const char*, const SkDiscardableMemory&) override {} private: struct TraceValue { diff --git a/libs/hwui/pipeline/skia/SkiaPipeline.cpp b/libs/hwui/pipeline/skia/SkiaPipeline.cpp index 7a255c15bf5f..bbc827d58dfe 100644 --- a/libs/hwui/pipeline/skia/SkiaPipeline.cpp +++ b/libs/hwui/pipeline/skia/SkiaPipeline.cpp @@ -183,15 +183,15 @@ bool SkiaPipeline::createOrUpdateLayer(RenderNode* node, const DamageAccumulator } else { String8 cachesOutput; mRenderThread.cacheManager().dumpMemoryUsage(cachesOutput, - &mRenderThread.renderState()); + &mRenderThread.renderState()); ALOGE("%s", cachesOutput.string()); if (errorHandler) { std::ostringstream err; err << "Unable to create layer for " << node->getName(); const int maxTextureSize = DeviceInfo::get()->maxTextureSize(); err << ", size " << info.width() << "x" << info.height() << " max size " - << maxTextureSize << " color type " << (int)info.colorType() - << " has context " << (int)(mRenderThread.getGrContext() != nullptr); + << maxTextureSize << " color type " << (int)info.colorType() << " has context " + << (int)(mRenderThread.getGrContext() != nullptr); errorHandler->onError(err.str()); } } @@ -300,8 +300,7 @@ void SkiaPipeline::endCapture(SkSurface* surface) { mSavePictureProcessor->savePicture(data, mCapturedFile); } else { mSavePictureProcessor->savePicture( - data, - mCapturedFile + "_" + std::to_string(mCaptureSequence)); + data, mCapturedFile + "_" + std::to_string(mCaptureSequence)); } mCaptureSequence--; } diff --git a/libs/hwui/pipeline/skia/SkiaPipeline.h b/libs/hwui/pipeline/skia/SkiaPipeline.h index 42a411a6808c..c94b24a2cde7 100644 --- a/libs/hwui/pipeline/skia/SkiaPipeline.h +++ b/libs/hwui/pipeline/skia/SkiaPipeline.h @@ -97,8 +97,7 @@ public: return mLightCenter; } - static void updateLighting(const LightGeometry& lightGeometry, - const LightInfo& lightInfo) { + static void updateLighting(const LightGeometry& lightGeometry, const LightInfo& lightInfo) { mLightRadius = lightGeometry.radius; mAmbientShadowAlpha = lightInfo.ambientShadowAlpha; mSpotShadowAlpha = lightInfo.spotShadowAlpha; diff --git a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp index b56c3ef94791..6eefed959913 100644 --- a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp +++ b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp @@ -24,8 +24,8 @@ #include "RenderNode.h" #include "pipeline/skia/AnimatedDrawables.h" #include "pipeline/skia/GLFunctorDrawable.h" -#include "pipeline/skia/VkInteropFunctorDrawable.h" #include "pipeline/skia/VkFunctorDrawable.h" +#include "pipeline/skia/VkInteropFunctorDrawable.h" namespace android { namespace uirenderer { @@ -95,8 +95,8 @@ void SkiaRecordingCanvas::insertReorderBarrier(bool enableReorder) { drawDrawable(drawable); } if (enableReorder) { - mCurrentBarrier = mDisplayList->allocateDrawable( - mDisplayList.get()); + mCurrentBarrier = + mDisplayList->allocateDrawable(mDisplayList.get()); drawDrawable(mCurrentBarrier); } } @@ -127,11 +127,25 @@ void SkiaRecordingCanvas::callDrawGLFunction(Functor* functor, if (Properties::getRenderPipelineType() == RenderPipelineType::SkiaVulkan) { // TODO(cblume) use VkFunctorDrawable instead of VkInteropFunctorDrawable here when the // interop is disabled/moved. - functorDrawable = mDisplayList->allocateDrawable(functor, - listener, asSkCanvas()); + functorDrawable = mDisplayList->allocateDrawable( + functor, listener, asSkCanvas()); + } else { + functorDrawable = + mDisplayList->allocateDrawable(functor, listener, asSkCanvas()); + } + mDisplayList->mChildFunctors.push_back(functorDrawable); + drawDrawable(functorDrawable); +} + +void SkiaRecordingCanvas::drawWebViewFunctor(int functor) { + FunctorDrawable* functorDrawable; + if (Properties::getRenderPipelineType() == RenderPipelineType::SkiaVulkan) { + // TODO(cblume) use VkFunctorDrawable instead of VkInteropFunctorDrawable here when the + // interop is disabled. + functorDrawable = + mDisplayList->allocateDrawable(functor, asSkCanvas()); } else { - functorDrawable = mDisplayList->allocateDrawable(functor, listener, - asSkCanvas()); + functorDrawable = mDisplayList->allocateDrawable(functor, asSkCanvas()); } mDisplayList->mChildFunctors.push_back(functorDrawable); drawDrawable(functorDrawable); @@ -167,7 +181,7 @@ SkiaCanvas::PaintCoW&& SkiaRecordingCanvas::filterBitmap(PaintCoW&& paint, if (colorSpaceFilter) { if (tmpPaint.getColorFilter()) { tmpPaint.setColorFilter(SkColorFilter::MakeComposeFilter( - tmpPaint.refColorFilter(), std::move(colorSpaceFilter))); + tmpPaint.refColorFilter(), std::move(colorSpaceFilter))); } else { tmpPaint.setColorFilter(std::move(colorSpaceFilter)); } @@ -248,8 +262,7 @@ void SkiaRecordingCanvas::drawNinePatch(Bitmap& bitmap, const Res_png_9patch& ch filteredPaint.writeable().setFilterQuality(kLow_SkFilterQuality); } sk_sp image = bitmap.makeImage(); - mRecorder.drawImageLattice(image, lattice, dst, - filterPaint(std::move(filteredPaint)), + mRecorder.drawImageLattice(image, lattice, dst, filterPaint(std::move(filteredPaint)), bitmap.palette()); if (!bitmap.isImmutable() && image.get() && !image->unique() && !dst.isEmpty()) { mDisplayList->mMutableImages.push_back(image.get()); diff --git a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.h b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.h index d6107a9d9969..afeccea3fb70 100644 --- a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.h +++ b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.h @@ -74,6 +74,7 @@ public: virtual void drawRenderNode(uirenderer::RenderNode* renderNode) override; virtual void callDrawGLFunction(Functor* functor, uirenderer::GlFunctorLifecycleListener* listener) override; + void drawWebViewFunctor(int functor) override; private: RecordingCanvas mRecorder; diff --git a/libs/hwui/pipeline/skia/SkiaUtils.h b/libs/hwui/pipeline/skia/SkiaUtils.h index 834446905216..fa7f1fe2f746 100644 --- a/libs/hwui/pipeline/skia/SkiaUtils.h +++ b/libs/hwui/pipeline/skia/SkiaUtils.h @@ -22,7 +22,7 @@ namespace android { static inline SkRect SkRectMakeLargest() { const SkScalar v = SK_ScalarMax; - return { -v, -v, v, v }; + return {-v, -v, v, v}; }; } /* namespace android */ diff --git a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp index 437b5dc83f58..b64eb2426231 100644 --- a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp +++ b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp @@ -20,9 +20,9 @@ #include "Readback.h" #include "SkiaPipeline.h" #include "SkiaProfileRenderer.h" +#include "VkInteropFunctorDrawable.h" #include "renderstate/RenderState.h" #include "renderthread/Frame.h" -#include "VkInteropFunctorDrawable.h" #include #include diff --git a/libs/hwui/pipeline/skia/VkFunctorDrawable.cpp b/libs/hwui/pipeline/skia/VkFunctorDrawable.cpp index 71ad5e17301a..156f74a611a7 100644 --- a/libs/hwui/pipeline/skia/VkFunctorDrawable.cpp +++ b/libs/hwui/pipeline/skia/VkFunctorDrawable.cpp @@ -17,23 +17,21 @@ #include "VkFunctorDrawable.h" #include -#include "thread/ThreadBase.h" -#include "utils/TimeUtils.h" #include -#include +#include #include #include #include -#include #include +#include +#include "thread/ThreadBase.h" +#include "utils/TimeUtils.h" namespace android { namespace uirenderer { namespace skiapipeline { -VkFunctorDrawHandler::VkFunctorDrawHandler(Functor *functor) - : INHERITED() - , mFunctor(functor) {} +VkFunctorDrawHandler::VkFunctorDrawHandler(Functor* functor) : INHERITED(), mFunctor(functor) {} VkFunctorDrawHandler::~VkFunctorDrawHandler() { // TODO(cblume) Fill in the DrawVkInfo parameters. @@ -55,14 +53,12 @@ void VkFunctorDrawHandler::draw(const GrBackendDrawableInfo& info) { (*mFunctor)(DrawVkInfo::kModeComposite, &draw_vk_info); } -VkFunctorDrawable::VkFunctorDrawable(Functor* functor, GlFunctorLifecycleListener* listener, - SkCanvas* canvas) - : FunctorDrawable(functor, listener, canvas) {} - -VkFunctorDrawable::~VkFunctorDrawable() = default; - -void VkFunctorDrawable::syncFunctor() const { - (*mFunctor)(DrawVkInfo::kModeSync, nullptr); +VkFunctorDrawable::~VkFunctorDrawable() { + if (auto lp = std::get_if(&mAnyFunctor)) { + if (lp->listener) { + lp->listener->onGlFunctorReleased(lp->functor); + } + } } void VkFunctorDrawable::onDraw(SkCanvas* /*canvas*/) { @@ -71,12 +67,17 @@ void VkFunctorDrawable::onDraw(SkCanvas* /*canvas*/) { } std::unique_ptr VkFunctorDrawable::onSnapGpuDrawHandler( - GrBackendApi backendApi, const SkMatrix& matrix) { + GrBackendApi backendApi, const SkMatrix& matrix) { if (backendApi != GrBackendApi::kVulkan) { return nullptr; } - std::unique_ptr draw(new VkFunctorDrawHandler(mFunctor)); - return std::move(draw); + std::unique_ptr draw; + if (mAnyFunctor.index() == 0) { + LOG_ALWAYS_FATAL("Not implemented"); + return nullptr; + } else { + return std::make_unique(std::get<1>(mAnyFunctor).functor); + } } } // namespace skiapipeline diff --git a/libs/hwui/pipeline/skia/VkFunctorDrawable.h b/libs/hwui/pipeline/skia/VkFunctorDrawable.h index 5cd131405d15..d6fefc1fca06 100644 --- a/libs/hwui/pipeline/skia/VkFunctorDrawable.h +++ b/libs/hwui/pipeline/skia/VkFunctorDrawable.h @@ -18,9 +18,9 @@ #include "FunctorDrawable.h" -#include -#include #include +#include +#include namespace android { namespace uirenderer { @@ -36,6 +36,7 @@ public: ~VkFunctorDrawHandler() override; void draw(const GrBackendDrawableInfo& info) override; + private: typedef GpuDrawHandler INHERITED; @@ -48,17 +49,15 @@ private: */ class VkFunctorDrawable : public FunctorDrawable { public: - VkFunctorDrawable(Functor* functor, GlFunctorLifecycleListener* listener, - SkCanvas* canvas); - ~VkFunctorDrawable() override; + using FunctorDrawable::FunctorDrawable; - void syncFunctor() const override; + ~VkFunctorDrawable() override; protected: // SkDrawable functions: void onDraw(SkCanvas* canvas) override; - std::unique_ptr onSnapGpuDrawHandler(GrBackendApi backendApi, - const SkMatrix& matrix) override; + std::unique_ptr onSnapGpuDrawHandler( + GrBackendApi backendApi, const SkMatrix& matrix) override; }; } // namespace skiapipeline diff --git a/libs/hwui/pipeline/skia/VkInteropFunctorDrawable.cpp b/libs/hwui/pipeline/skia/VkInteropFunctorDrawable.cpp index 82285501cb63..a5faae7d5068 100644 --- a/libs/hwui/pipeline/skia/VkInteropFunctorDrawable.cpp +++ b/libs/hwui/pipeline/skia/VkInteropFunctorDrawable.cpp @@ -17,13 +17,13 @@ #include "VkInteropFunctorDrawable.h" #include -#include "renderthread/EglManager.h" -#include "thread/ThreadBase.h" -#include "utils/TimeUtils.h" -#include #include #include #include +#include +#include "renderthread/EglManager.h" +#include "thread/ThreadBase.h" +#include "utils/TimeUtils.h" #include #include @@ -44,6 +44,7 @@ static renderthread::EglManager sEglManager; class ScopedDrawRequest { public: ScopedDrawRequest() { beginDraw(); } + private: void beginDraw() { std::lock_guard _lock{sLock}; @@ -57,9 +58,7 @@ private: } if (!sEglManager.hasEglContext()) { - sGLDrawThread->queue().runSync([]() { - sEglManager.initialize(); - }); + sGLDrawThread->queue().runSync([]() { sEglManager.initialize(); }); } } }; @@ -93,14 +92,14 @@ void VkInteropFunctorDrawable::onDraw(SkCanvas* canvas) { if (!mFrameBuffer.get() || mFBInfo != surfaceInfo) { // Buffer will be used as an OpenGL ES render target. mFrameBuffer = new GraphicBuffer( - //TODO: try to reduce the size of the buffer: possibly by using clip bounds. - static_cast(surfaceInfo.width()), - static_cast(surfaceInfo.height()), - ColorTypeToPixelFormat(surfaceInfo.colorType()), - GraphicBuffer::USAGE_HW_TEXTURE | GraphicBuffer::USAGE_SW_WRITE_NEVER | - GraphicBuffer::USAGE_SW_READ_NEVER | GraphicBuffer::USAGE_HW_RENDER, - std::string("VkInteropFunctorDrawable::onDraw pid [") + std::to_string(getpid()) + - "]"); + // TODO: try to reduce the size of the buffer: possibly by using clip bounds. + static_cast(surfaceInfo.width()), + static_cast(surfaceInfo.height()), + ColorTypeToPixelFormat(surfaceInfo.colorType()), + GraphicBuffer::USAGE_HW_TEXTURE | GraphicBuffer::USAGE_SW_WRITE_NEVER | + GraphicBuffer::USAGE_SW_READ_NEVER | GraphicBuffer::USAGE_HW_RENDER, + std::string("VkInteropFunctorDrawable::onDraw pid [") + std::to_string(getpid()) + + "]"); status_t error = mFrameBuffer->initCheck(); if (error < 0) { ALOGW("VkInteropFunctorDrawable::onDraw() failed in GraphicBuffer.create()"); @@ -110,16 +109,15 @@ void VkInteropFunctorDrawable::onDraw(SkCanvas* canvas) { mFBInfo = surfaceInfo; } - //TODO: Synchronization is needed on mFrameBuffer to guarantee that the previous Vulkan - //TODO: draw command has completed. - //TODO: A simple but inefficient way is to flush and issue a QueueWaitIdle call. See - //TODO: GrVkGpu::destroyResources() for example. + // TODO: Synchronization is needed on mFrameBuffer to guarantee that the previous Vulkan + // TODO: draw command has completed. + // TODO: A simple but inefficient way is to flush and issue a QueueWaitIdle call. See + // TODO: GrVkGpu::destroyResources() for example. bool success = sGLDrawThread->queue().runSync([&]() -> bool { ATRACE_FORMAT("WebViewDraw_%dx%d", mFBInfo.width(), mFBInfo.height()); EGLDisplay display = sEglManager.eglDisplay(); - LOG_ALWAYS_FATAL_IF(display == EGL_NO_DISPLAY, - "Failed to get EGL_DEFAULT_DISPLAY! err=%s", - uirenderer::renderthread::EglManager::eglErrorString()); + LOG_ALWAYS_FATAL_IF(display == EGL_NO_DISPLAY, "Failed to get EGL_DEFAULT_DISPLAY! err=%s", + uirenderer::renderthread::EglManager::eglErrorString()); // We use an EGLImage to access the content of the GraphicBuffer // The EGL image is later bound to a 2D texture EGLClientBuffer clientBuffer = (EGLClientBuffer)mFrameBuffer->getNativeBuffer(); @@ -154,10 +152,10 @@ void VkInteropFunctorDrawable::onDraw(SkCanvas* canvas) { AutoGLFramebuffer glFb; // Bind texture to the frame buffer. glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, - glTexture.mTexture, 0); + glTexture.mTexture, 0); if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { ALOGE("Failed framebuffer check for created target buffer: %s", - GLUtils::getGLFramebufferError()); + GLUtils::getGLFramebufferError()); return false; } @@ -166,19 +164,22 @@ void VkInteropFunctorDrawable::onDraw(SkCanvas* canvas) { glClearColor(0.0f, 0.0f, 0.0f, 0.0f); glClear(GL_COLOR_BUFFER_BIT); - (*mFunctor)(DrawGlInfo::kModeDraw, &info); + if (mAnyFunctor.index() == 0) { + std::get<0>(mAnyFunctor).handle->drawGl(info); + } else { + (*(std::get<1>(mAnyFunctor).functor))(DrawGlInfo::kModeDraw, &info); + } EGLSyncKHR glDrawFinishedFence = eglCreateSyncKHR(eglGetCurrentDisplay(), EGL_SYNC_FENCE_KHR, NULL); LOG_ALWAYS_FATAL_IF(glDrawFinishedFence == EGL_NO_SYNC_KHR, - "Could not create sync fence %#x", eglGetError()); + "Could not create sync fence %#x", eglGetError()); glFlush(); // TODO: export EGLSyncKHR in file descr // TODO: import file desc in Vulkan Semaphore // TODO: instead block the GPU: probably by using external Vulkan semaphore. // Block the CPU until the glFlush finish. - EGLint waitStatus = eglClientWaitSyncKHR(display, glDrawFinishedFence, 0, - FENCE_TIMEOUT); + EGLint waitStatus = eglClientWaitSyncKHR(display, glDrawFinishedFence, 0, FENCE_TIMEOUT); LOG_ALWAYS_FATAL_IF(waitStatus != EGL_CONDITION_SATISFIED_KHR, "Failed to wait for the fence %#x", eglGetError()); eglDestroySyncKHR(display, glDrawFinishedFence); @@ -197,26 +198,25 @@ void VkInteropFunctorDrawable::onDraw(SkCanvas* canvas) { canvas->resetMatrix(); auto functorImage = SkImage::MakeFromAHardwareBuffer( - reinterpret_cast(mFrameBuffer.get()), kPremul_SkAlphaType, - nullptr, kBottomLeft_GrSurfaceOrigin); + reinterpret_cast(mFrameBuffer.get()), kPremul_SkAlphaType, nullptr, + kBottomLeft_GrSurfaceOrigin); canvas->drawImage(functorImage, 0, 0, &paint); canvas->restore(); } VkInteropFunctorDrawable::~VkInteropFunctorDrawable() { - if (mListener.get() != nullptr) { - ScopedDrawRequest _drawRequest{}; - sGLDrawThread->queue().runSync([&]() { - mListener->onGlFunctorReleased(mFunctor); - }); + if (auto lp = std::get_if(&mAnyFunctor)) { + if (lp->listener) { + ScopedDrawRequest _drawRequest{}; + sGLDrawThread->queue().runSync( + [&]() { lp->listener->onGlFunctorReleased(lp->functor); }); + } } } -void VkInteropFunctorDrawable::syncFunctor() const { +void VkInteropFunctorDrawable::syncFunctor(const WebViewSyncData& data) const { ScopedDrawRequest _drawRequest{}; - sGLDrawThread->queue().runSync([&]() { - (*mFunctor)(DrawGlInfo::kModeSync, nullptr); - }); + sGLDrawThread->queue().runSync([&]() { FunctorDrawable::syncFunctor(data); }); } } // namespace skiapipeline diff --git a/libs/hwui/pipeline/skia/VkInteropFunctorDrawable.h b/libs/hwui/pipeline/skia/VkInteropFunctorDrawable.h index 8fe52c5ef700..c47ee114263f 100644 --- a/libs/hwui/pipeline/skia/VkInteropFunctorDrawable.h +++ b/libs/hwui/pipeline/skia/VkInteropFunctorDrawable.h @@ -18,8 +18,8 @@ #include "FunctorDrawable.h" -#include #include +#include namespace android { namespace uirenderer { @@ -32,20 +32,18 @@ namespace skiapipeline { */ class VkInteropFunctorDrawable : public FunctorDrawable { public: - VkInteropFunctorDrawable(Functor* functor, GlFunctorLifecycleListener* listener, - SkCanvas* canvas) - : FunctorDrawable(functor, listener, canvas) {} - virtual ~VkInteropFunctorDrawable(); + using FunctorDrawable::FunctorDrawable; - void syncFunctor() const override; + virtual ~VkInteropFunctorDrawable(); static void vkInvokeFunctor(Functor* functor); + void syncFunctor(const WebViewSyncData& data) const override; + protected: virtual void onDraw(SkCanvas* canvas) override; private: - // Variables below describe/store temporary offscreen buffer used for Vulkan pipeline. sp mFrameBuffer; SkImageInfo mFBInfo; diff --git a/libs/hwui/private/hwui/WebViewFunctor.h b/libs/hwui/private/hwui/WebViewFunctor.h new file mode 100644 index 000000000000..e5346aabaee3 --- /dev/null +++ b/libs/hwui/private/hwui/WebViewFunctor.h @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef FRAMEWORKS_BASE_WEBVIEWFUNCTOR_H +#define FRAMEWORKS_BASE_WEBVIEWFUNCTOR_H + +#include + +namespace android::uirenderer { + +enum class RenderMode { + OpenGL_ES, + Vulkan, +}; + +// Static for the lifetime of the process +RenderMode WebViewFunctor_queryPlatformRenderMode(); + +struct WebViewSyncData { + bool applyForceDark; +}; + +struct WebViewFunctorCallbacks { + // kModeSync, called on RenderThread + void (*onSync)(int functor, const WebViewSyncData& syncData); + + // Called when either the context is destroyed _or_ when the functor's last reference goes + // away. Will always be called with an active context and always on renderthread. + void (*onContextDestroyed)(int functor); + + // Called when the last reference to the handle goes away and the handle is considered + // irrevocably destroyed. Will always be proceeded by a call to onContextDestroyed if + // this functor had ever been drawn. + void (*onDestroyed)(int functor); + + union { + struct { + // Called on RenderThread. initialize is guaranteed to happen before this call + void (*draw)(int functor, const DrawGlInfo& params); + } gles; + // TODO: VK support. The current DrawVkInfo is monolithic and needs to be split up for + // what params are valid on what callbacks + struct { + // Called either the first time the functor is used or the first time it's used after + // a call to onContextDestroyed. + // void (*initialize)(int functor, const InitParams& params); + // void (*frameStart)(int functor, /* todo: what params are actually needed for this to + // be useful? Is this useful? */) + // void (*draw)(int functor, const CompositeParams& params /* todo: rename - composite + // almost always means something else, and we aren't compositing */); + // void (*frameEnd)(int functor, const PostCompositeParams& params /* todo: same as + // CompositeParams - rename */); + } vk; + }; +}; + +// Creates a new WebViewFunctor from the given prototype. The prototype is copied after +// this function returns. Caller retains full ownership of it. +// Returns -1 if the creation fails (such as an unsupported functorMode + platform mode combination) +int WebViewFunctor_create(const WebViewFunctorCallbacks& prototype, RenderMode functorMode); + +// May be called on any thread to signal that the functor should be destroyed. +// The functor will receive an onDestroyed when the last usage of it is released, +// and it should be considered alive & active until that point. +void WebViewFunctor_release(int functor); + +} // namespace android::uirenderer + +#endif // FRAMEWORKS_BASE_WEBVIEWFUNCTOR_H diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp index 4e4262c5c0a7..8e57a3a119e3 100644 --- a/libs/hwui/renderthread/CanvasContext.cpp +++ b/libs/hwui/renderthread/CanvasContext.cpp @@ -576,8 +576,7 @@ void CanvasContext::trimMemory(RenderThread& thread, int level) { ATRACE_CALL(); if (level >= TRIM_MEMORY_COMPLETE) { thread.cacheManager().trimMemory(CacheManager::TrimMemoryMode::Complete); - thread.destroyGlContext(); - thread.vulkanManager().destroy(); + thread.destroyRenderingContext(); } else if (level >= TRIM_MEMORY_UI_HIDDEN) { thread.cacheManager().trimMemory(CacheManager::TrimMemoryMode::UiHidden); } diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp index 085812a00f71..aa6af23d8ed3 100644 --- a/libs/hwui/renderthread/RenderProxy.cpp +++ b/libs/hwui/renderthread/RenderProxy.cpp @@ -30,6 +30,7 @@ #include "renderthread/RenderThread.h" #include "utils/Macros.h" #include "utils/TimeUtils.h" +#include "WebViewFunctorManager.h" #include @@ -143,6 +144,14 @@ void RenderProxy::invokeFunctor(Functor* functor, bool waitForCompletion) { } } +void RenderProxy::destroyFunctor(int functor) { + ATRACE_CALL(); + RenderThread& thread = RenderThread::getInstance(); + thread.queue().post([=]() { + WebViewFunctorManager::instance().destroyFunctor(functor); + }); +} + DeferredLayerUpdater* RenderProxy::createTextureLayer() { return mRenderThread.queue().runSync([this]() -> auto { return mContext->createTextureLayer(); diff --git a/libs/hwui/renderthread/RenderProxy.h b/libs/hwui/renderthread/RenderProxy.h index d9b789f28f8d..9dc918121be6 100644 --- a/libs/hwui/renderthread/RenderProxy.h +++ b/libs/hwui/renderthread/RenderProxy.h @@ -82,6 +82,7 @@ public: ANDROID_API void destroy(); ANDROID_API static void invokeFunctor(Functor* functor, bool waitForCompletion); + static void destroyFunctor(int functor); ANDROID_API DeferredLayerUpdater* createTextureLayer(); ANDROID_API void buildLayer(RenderNode* node); diff --git a/libs/hwui/renderthread/RenderThread.cpp b/libs/hwui/renderthread/RenderThread.cpp index 207673c1c8dd..c06faddf7fa6 100644 --- a/libs/hwui/renderthread/RenderThread.cpp +++ b/libs/hwui/renderthread/RenderThread.cpp @@ -132,6 +132,7 @@ RenderThread::RenderThread() , mFrameCallbackTaskPending(false) , mRenderState(nullptr) , mEglManager(nullptr) + , mFunctorManager(WebViewFunctorManager::instance()) , mVkManager(nullptr) { Properties::load(); start("RenderThread"); @@ -197,11 +198,13 @@ void RenderThread::requireGlContext() { setGrContext(grContext); } -void RenderThread::destroyGlContext() { +void RenderThread::destroyRenderingContext() { + mFunctorManager.onContextDestroyed(); if (mEglManager->hasEglContext()) { setGrContext(nullptr); mEglManager->destroy(); } + vulkanManager().destroy(); } void RenderThread::dumpGraphicsMemory(int fd) { diff --git a/libs/hwui/renderthread/RenderThread.h b/libs/hwui/renderthread/RenderThread.h index 2384f9541ec0..12666b323d11 100644 --- a/libs/hwui/renderthread/RenderThread.h +++ b/libs/hwui/renderthread/RenderThread.h @@ -23,6 +23,7 @@ #include "CacheManager.h" #include "TimeLord.h" #include "thread/ThreadBase.h" +#include "WebViewFunctorManager.h" #include #include @@ -104,7 +105,7 @@ public: void dumpGraphicsMemory(int fd); void requireGlContext(); - void destroyGlContext(); + void destroyRenderingContext(); /** * isCurrent provides a way to query, if the caller is running on @@ -151,6 +152,7 @@ private: TimeLord mTimeLord; RenderState* mRenderState; EglManager* mEglManager; + WebViewFunctorManager& mFunctorManager; ProfileDataContainer mGlobalProfileData; Readback* mReadback = nullptr; diff --git a/libs/hwui/tests/common/TestUtils.cpp b/libs/hwui/tests/common/TestUtils.cpp index f81202292a49..7aa9b82e3583 100644 --- a/libs/hwui/tests/common/TestUtils.cpp +++ b/libs/hwui/tests/common/TestUtils.cpp @@ -32,6 +32,8 @@ namespace android { namespace uirenderer { +std::unordered_map TestUtils::sMockFunctorCounts{}; + SkColor TestUtils::interpolateColor(float fraction, SkColor start, SkColor end) { int startA = (start >> 24) & 0xff; int startR = (start >> 16) & 0xff; @@ -82,12 +84,10 @@ void TestUtils::drawUtf8ToCanvas(Canvas* canvas, const char* text, const SkPaint uint32_t length = strlen(text); SkPaint glyphPaint(paint); glyphPaint.setTextEncoding(kGlyphID_SkTextEncoding); - canvas->drawText( - utf16.get(), length, // text buffer - 0, length, // draw range - 0, length, // context range - x, y, minikin::Bidi::LTR, - glyphPaint, nullptr, nullptr /* measured text */); + canvas->drawText(utf16.get(), length, // text buffer + 0, length, // draw range + 0, length, // context range + x, y, minikin::Bidi::LTR, glyphPaint, nullptr, nullptr /* measured text */); } void TestUtils::drawUtf8ToCanvas(Canvas* canvas, const char* text, const SkPaint& paint, @@ -96,7 +96,7 @@ void TestUtils::drawUtf8ToCanvas(Canvas* canvas, const char* text, const SkPaint SkPaint glyphPaint(paint); glyphPaint.setTextEncoding(kGlyphID_SkTextEncoding); canvas->drawTextOnPath(utf16.get(), strlen(text), minikin::Bidi::LTR, path, 0, 0, glyphPaint, - nullptr); + nullptr); } void TestUtils::TestTask::run() { @@ -110,11 +110,7 @@ void TestUtils::TestTask::run() { rtCallback(renderThread); - if (Properties::getRenderPipelineType() == RenderPipelineType::SkiaVulkan) { - renderThread.vulkanManager().destroy(); - } else { - renderThread.destroyGlContext(); - } + renderThread.destroyRenderingContext(); } std::unique_ptr TestUtils::asciiToUtf16(const char* str) { diff --git a/libs/hwui/tests/common/TestUtils.h b/libs/hwui/tests/common/TestUtils.h index c5db861d4f48..5ff8993e6779 100644 --- a/libs/hwui/tests/common/TestUtils.h +++ b/libs/hwui/tests/common/TestUtils.h @@ -27,6 +27,7 @@ #include #include +#include #include namespace android { @@ -201,8 +202,7 @@ public: static void recordNode(RenderNode& node, std::function contentCallback) { std::unique_ptr canvas(Canvas::create_recording_canvas( - node.stagingProperties().getWidth(), node.stagingProperties().getHeight(), - &node)); + node.stagingProperties().getWidth(), node.stagingProperties().getHeight(), &node)); contentCallback(*canvas.get()); node.setStagingDisplayList(canvas->finishRecording()); } @@ -267,7 +267,14 @@ public: renderthread::RenderThread::getInstance().queue().runSync([&]() { task.run(); }); } + static void runOnRenderThreadUnmanaged(RtCallback rtCallback) { + auto& rt = renderthread::RenderThread::getInstance(); + rt.queue().runSync([&]() { rtCallback(rt); }); + } + + static bool isRenderThreadRunning() { return renderthread::RenderThread::hasInstance(); } + static pid_t getRenderThreadTid() { return renderthread::RenderThread::getInstance().getTid(); } static SkColor interpolateColor(float fraction, SkColor start, SkColor end); @@ -296,7 +303,52 @@ public: static SkRect getClipBounds(const SkCanvas* canvas); static SkRect getLocalClipBounds(const SkCanvas* canvas); + struct CallCounts { + int sync = 0; + int contextDestroyed = 0; + int destroyed = 0; + int glesDraw = 0; + }; + + static void expectOnRenderThread() { EXPECT_EQ(gettid(), TestUtils::getRenderThreadTid()); } + + static WebViewFunctorCallbacks createMockFunctor(RenderMode mode) { + auto callbacks = WebViewFunctorCallbacks{ + .onSync = + [](int functor, const WebViewSyncData& data) { + expectOnRenderThread(); + sMockFunctorCounts[functor].sync++; + }, + .onContextDestroyed = + [](int functor) { + expectOnRenderThread(); + sMockFunctorCounts[functor].contextDestroyed++; + }, + .onDestroyed = + [](int functor) { + expectOnRenderThread(); + sMockFunctorCounts[functor].destroyed++; + }, + }; + switch (mode) { + case RenderMode::OpenGL_ES: + callbacks.gles.draw = [](int functor, const DrawGlInfo& params) { + expectOnRenderThread(); + sMockFunctorCounts[functor].glesDraw++; + }; + break; + default: + ADD_FAILURE(); + return WebViewFunctorCallbacks{}; + } + return callbacks; + } + + static CallCounts& countsForFunctor(int functor) { return sMockFunctorCounts[functor]; } + private: + static std::unordered_map sMockFunctorCounts; + static void syncHierarchyPropertiesAndDisplayListImpl(RenderNode* node) { MarkAndSweepRemoved observer(nullptr); node->syncProperties(); @@ -306,9 +358,9 @@ private: } auto displayList = node->getDisplayList(); if (displayList) { - for (auto&& childDr : static_cast( - const_cast(displayList)) - ->mChildNodes) { + for (auto&& childDr : + static_cast(const_cast(displayList)) + ->mChildNodes) { syncHierarchyPropertiesAndDisplayListImpl(childDr.getRenderNode()); } } diff --git a/libs/hwui/tests/unit/DeferredLayerUpdaterTests.cpp b/libs/hwui/tests/unit/DeferredLayerUpdaterTests.cpp index a6869791a915..f4c3e13b0ea6 100644 --- a/libs/hwui/tests/unit/DeferredLayerUpdaterTests.cpp +++ b/libs/hwui/tests/unit/DeferredLayerUpdaterTests.cpp @@ -19,9 +19,9 @@ #include "tests/common/TestUtils.h" -#include #include #include +#include using namespace android; using namespace android::uirenderer; diff --git a/libs/hwui/tests/unit/GpuMemoryTrackerTests.cpp b/libs/hwui/tests/unit/GpuMemoryTrackerTests.cpp index 08b967964c59..dac888cd79ca 100644 --- a/libs/hwui/tests/unit/GpuMemoryTrackerTests.cpp +++ b/libs/hwui/tests/unit/GpuMemoryTrackerTests.cpp @@ -39,7 +39,7 @@ public: // current thread can spoof being a GPU thread static void destroyEglContext() { if (TestUtils::isRenderThreadRunning()) { - TestUtils::runOnRenderThread([](RenderThread& thread) { thread.destroyGlContext(); }); + TestUtils::runOnRenderThread([](RenderThread& thread) { thread.destroyRenderingContext(); }); } } diff --git a/libs/hwui/tests/unit/RenderNodeDrawableTests.cpp b/libs/hwui/tests/unit/RenderNodeDrawableTests.cpp index 0331581799b7..c813cd945905 100644 --- a/libs/hwui/tests/unit/RenderNodeDrawableTests.cpp +++ b/libs/hwui/tests/unit/RenderNodeDrawableTests.cpp @@ -355,9 +355,7 @@ RENDERTHREAD_SKIA_PIPELINE_TEST(RenderNodeDrawable, emptyReceiver) { class ProjectionTestCanvas : public SkCanvas { public: ProjectionTestCanvas(int width, int height) : SkCanvas(width, height) {} - void onDrawRect(const SkRect& rect, const SkPaint& paint) override { - mDrawCounter++; - } + void onDrawRect(const SkRect& rect, const SkPaint& paint) override { mDrawCounter++; } int getDrawCounter() { return mDrawCounter; } @@ -370,7 +368,7 @@ RENDERTHREAD_SKIA_PIPELINE_TEST(RenderNodeDrawable, emptyReceiver) { [](RenderProperties& properties, SkiaRecordingCanvas& canvas) { properties.setProjectionReceiver(true); }, - "B"); // a receiver with an empty display list + "B"); // a receiver with an empty display list auto projectingRipple = TestUtils::createSkiaNode( 0, 0, 100, 100, @@ -389,14 +387,14 @@ RENDERTHREAD_SKIA_PIPELINE_TEST(RenderNodeDrawable, emptyReceiver) { canvas.drawRenderNode(projectingRipple.get()); }, "C"); - auto parent = TestUtils::createSkiaNode( - 0, 0, 100, 100, - [&receiverBackground, &child](RenderProperties& properties, - SkiaRecordingCanvas& canvas) { - canvas.drawRenderNode(receiverBackground.get()); - canvas.drawRenderNode(child.get()); - }, - "A"); + auto parent = + TestUtils::createSkiaNode(0, 0, 100, 100, + [&receiverBackground, &child](RenderProperties& properties, + SkiaRecordingCanvas& canvas) { + canvas.drawRenderNode(receiverBackground.get()); + canvas.drawRenderNode(child.get()); + }, + "A"); ContextFactory contextFactory; std::unique_ptr canvasContext( CanvasContext::create(renderThread, false, parent.get(), &contextFactory)); @@ -1058,7 +1056,7 @@ RENDERTHREAD_SKIA_PIPELINE_TEST(RenderNodeDrawable, layerComposeQuality) { public: FrameTestCanvas() : TestCanvasBase(CANVAS_WIDTH, CANVAS_HEIGHT) {} void onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst, - const SkPaint* paint, SrcRectConstraint constraint) override { + const SkPaint* paint, SrcRectConstraint constraint) override { mDrawCounter++; EXPECT_EQ(kLow_SkFilterQuality, paint->getFilterQuality()); } @@ -1076,7 +1074,7 @@ RENDERTHREAD_SKIA_PIPELINE_TEST(RenderNodeDrawable, layerComposeQuality) { FrameTestCanvas canvas; RenderNodeDrawable drawable(layerNode.get(), &canvas, true); canvas.drawDrawable(&drawable); - EXPECT_EQ(1, canvas.mDrawCounter); //make sure the layer was composed + EXPECT_EQ(1, canvas.mDrawCounter); // make sure the layer was composed // clean up layer pointer, so we can safely destruct RenderNode layerNode->setLayerSurface(nullptr); @@ -1129,15 +1127,14 @@ TEST(ReorderBarrierDrawable, testShadowMatrix) { getTotalMatrix()); } else { // Second invocation is preparing the matrix for an elevated RenderNodeDrawable. - EXPECT_EQ(SkMatrix::MakeTrans(TRANSLATE_X, TRANSLATE_Y), - matrix); - EXPECT_EQ(SkMatrix::MakeTrans(TRANSLATE_X, TRANSLATE_Y), - getTotalMatrix()); + EXPECT_EQ(SkMatrix::MakeTrans(TRANSLATE_X, TRANSLATE_Y), matrix); + EXPECT_EQ(SkMatrix::MakeTrans(TRANSLATE_X, TRANSLATE_Y), getTotalMatrix()); } } protected: int mDrawCounter = 0; + private: bool mFirstDidConcat = true; }; @@ -1174,14 +1171,14 @@ RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaRecordingCanvas, drawVectorDrawable) { public: VectorDrawableTestCanvas() : TestCanvasBase(CANVAS_WIDTH, CANVAS_HEIGHT) {} void onDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst, - const SkPaint* paint, SrcRectConstraint constraint) override { + const SkPaint* paint, SrcRectConstraint constraint) override { const int index = mDrawCounter++; switch (index) { case 0: EXPECT_EQ(dst, SkRect::MakeWH(CANVAS_WIDTH, CANVAS_HEIGHT)); break; case 1: - EXPECT_EQ(dst, SkRect::MakeWH(CANVAS_WIDTH/2, CANVAS_HEIGHT)); + EXPECT_EQ(dst, SkRect::MakeWH(CANVAS_WIDTH / 2, CANVAS_HEIGHT)); break; default: ADD_FAILURE(); @@ -1191,17 +1188,18 @@ RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaRecordingCanvas, drawVectorDrawable) { VectorDrawable::Group* group = new VectorDrawable::Group(); sp vectorDrawable(new VectorDrawableRoot(group)); - vectorDrawable->mutateStagingProperties()->setScaledSize(CANVAS_WIDTH/10, CANVAS_HEIGHT/10); + vectorDrawable->mutateStagingProperties()->setScaledSize(CANVAS_WIDTH / 10, CANVAS_HEIGHT / 10); - auto node = TestUtils::createSkiaNode(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT, - [&](RenderProperties& props, SkiaRecordingCanvas& canvas) { - vectorDrawable->mutateStagingProperties()->setBounds(SkRect::MakeWH(CANVAS_WIDTH, - CANVAS_HEIGHT)); - canvas.drawVectorDrawable(vectorDrawable.get()); - vectorDrawable->mutateStagingProperties()->setBounds(SkRect::MakeWH(CANVAS_WIDTH/2, - CANVAS_HEIGHT)); - canvas.drawVectorDrawable(vectorDrawable.get()); - }); + auto node = + TestUtils::createSkiaNode(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT, + [&](RenderProperties& props, SkiaRecordingCanvas& canvas) { + vectorDrawable->mutateStagingProperties()->setBounds( + SkRect::MakeWH(CANVAS_WIDTH, CANVAS_HEIGHT)); + canvas.drawVectorDrawable(vectorDrawable.get()); + vectorDrawable->mutateStagingProperties()->setBounds( + SkRect::MakeWH(CANVAS_WIDTH / 2, CANVAS_HEIGHT)); + canvas.drawVectorDrawable(vectorDrawable.get()); + }); VectorDrawableTestCanvas canvas; RenderNodeDrawable drawable(node.get(), &canvas, true); diff --git a/libs/hwui/tests/unit/RenderNodeTests.cpp b/libs/hwui/tests/unit/RenderNodeTests.cpp index a6073ebb5c74..3ebd0538ce87 100644 --- a/libs/hwui/tests/unit/RenderNodeTests.cpp +++ b/libs/hwui/tests/unit/RenderNodeTests.cpp @@ -295,7 +295,8 @@ RENDERTHREAD_TEST(RenderNode, prepareTree_nullableDisplayList) { canvasContext->destroy(); } -RENDERTHREAD_TEST(RenderNode, prepareTree_HwLayer_AVD_enqueueDamage) { +// TODO: Is this supposed to work in SkiaGL/SkiaVK? +RENDERTHREAD_TEST(DISABLED_RenderNode, prepareTree_HwLayer_AVD_enqueueDamage) { VectorDrawable::Group* group = new VectorDrawable::Group(); sp vectorDrawable(new VectorDrawableRoot(group)); diff --git a/libs/hwui/tests/unit/ShaderCacheTests.cpp b/libs/hwui/tests/unit/ShaderCacheTests.cpp index 1433aa0349f4..87981f115763 100644 --- a/libs/hwui/tests/unit/ShaderCacheTests.cpp +++ b/libs/hwui/tests/unit/ShaderCacheTests.cpp @@ -14,17 +14,17 @@ * limitations under the License. */ -#include -#include #include -#include +#include #include +#include #include #include #include #include -#include "pipeline/skia/ShaderCache.h" +#include #include "FileBlobCache.h" +#include "pipeline/skia/ShaderCache.h" using namespace android::uirenderer::skiapipeline; @@ -66,7 +66,6 @@ public: } /* namespace uirenderer */ } /* namespace android */ - namespace { std::string getExternalStorageFolder() { @@ -82,14 +81,12 @@ bool folderExist(const std::string& folderName) { return false; } -inline bool -checkShader(const sk_sp& shader1, const sk_sp& shader2) { - return nullptr != shader1 && nullptr != shader2 && shader1->size() == shader2->size() - && 0 == memcmp(shader1->data(), shader2->data(), shader1->size()); +inline bool checkShader(const sk_sp& shader1, const sk_sp& shader2) { + return nullptr != shader1 && nullptr != shader2 && shader1->size() == shader2->size() && + 0 == memcmp(shader1->data(), shader2->data(), shader1->size()); } -inline bool -checkShader(const sk_sp& shader, const char* program) { +inline bool checkShader(const sk_sp& shader, const char* program) { sk_sp shader2 = SkData::MakeWithCString(program); return checkShader(shader, shader2); } @@ -116,32 +113,31 @@ void genRandomData(std::vector& buffer) { } } - #define GrProgramDescTest(a) (*SkData::MakeWithCString(#a).get()) TEST(ShaderCacheTest, testWriteAndRead) { if (!folderExist(getExternalStorageFolder())) { - //don't run the test if external storage folder is not available + // don't run the test if external storage folder is not available return; } - std::string cacheFile1 = getExternalStorageFolder() + "/shaderCacheTest1"; - std::string cacheFile2 = getExternalStorageFolder() + "/shaderCacheTest2"; + std::string cacheFile1 = getExternalStorageFolder() + "/shaderCacheTest1"; + std::string cacheFile2 = getExternalStorageFolder() + "/shaderCacheTest2"; - //remove any test files from previous test run + // remove any test files from previous test run int deleteFile = remove(cacheFile1.c_str()); ASSERT_TRUE(0 == deleteFile || ENOENT == errno); std::srand(0); - //read the cache from a file that does not exist + // read the cache from a file that does not exist ShaderCache::get().setFilename(cacheFile1.c_str()); - ShaderCacheTestUtils::setSaveDelay(ShaderCache::get(), 0); //disable deferred save + ShaderCacheTestUtils::setSaveDelay(ShaderCache::get(), 0); // disable deferred save ShaderCache::get().initShaderDiskCache(); - //read a key - should not be found since the cache is empty + // read a key - should not be found since the cache is empty sk_sp outVS; ASSERT_EQ(ShaderCache::get().load(GrProgramDescTest(432)), sk_sp()); - //write to the in-memory cache without storing on disk and verify we read the same values + // write to the in-memory cache without storing on disk and verify we read the same values sk_sp inVS; setShader(inVS, "sassas"); ShaderCache::get().store(GrProgramDescTest(100), *inVS.get()); @@ -152,23 +148,23 @@ TEST(ShaderCacheTest, testWriteAndRead) { ASSERT_NE((outVS = ShaderCache::get().load(GrProgramDescTest(432))), sk_sp()); ASSERT_TRUE(checkShader(outVS, "someVS")); - //store content to disk and release in-memory cache + // store content to disk and release in-memory cache ShaderCacheTestUtils::terminate(ShaderCache::get(), true); - //change to a file that does not exist and verify load fails + // change to a file that does not exist and verify load fails ShaderCache::get().setFilename(cacheFile2.c_str()); ShaderCache::get().initShaderDiskCache(); ASSERT_EQ(ShaderCache::get().load(GrProgramDescTest(432)), sk_sp()); ShaderCacheTestUtils::terminate(ShaderCache::get(), false); - //load again content from disk from an existing file and check the data is read correctly + // load again content from disk from an existing file and check the data is read correctly ShaderCache::get().setFilename(cacheFile1.c_str()); ShaderCache::get().initShaderDiskCache(); sk_sp outVS2; ASSERT_NE((outVS2 = ShaderCache::get().load(GrProgramDescTest(432))), sk_sp()); ASSERT_TRUE(checkShader(outVS2, "someVS")); - //change data, store to disk, read back again and verify data has been changed + // change data, store to disk, read back again and verify data has been changed setShader(inVS, "ewData1"); ShaderCache::get().store(GrProgramDescTest(432), *inVS.get()); ShaderCacheTestUtils::terminate(ShaderCache::get(), true); @@ -176,9 +172,8 @@ TEST(ShaderCacheTest, testWriteAndRead) { ASSERT_NE((outVS2 = ShaderCache::get().load(GrProgramDescTest(432))), sk_sp()); ASSERT_TRUE(checkShader(outVS2, "ewData1")); - - //write and read big data chunk (50K) - size_t dataSize = 50*1024; + // write and read big data chunk (50K) + size_t dataSize = 50 * 1024; std::vector dataBuffer(dataSize); genRandomData(dataBuffer); setShader(inVS, dataBuffer); @@ -194,31 +189,31 @@ TEST(ShaderCacheTest, testWriteAndRead) { TEST(ShaderCacheTest, testCacheValidation) { if (!folderExist(getExternalStorageFolder())) { - //don't run the test if external storage folder is not available + // don't run the test if external storage folder is not available return; } - std::string cacheFile1 = getExternalStorageFolder() + "/shaderCacheTest1"; - std::string cacheFile2 = getExternalStorageFolder() + "/shaderCacheTest2"; + std::string cacheFile1 = getExternalStorageFolder() + "/shaderCacheTest1"; + std::string cacheFile2 = getExternalStorageFolder() + "/shaderCacheTest2"; - //remove any test files from previous test run + // remove any test files from previous test run int deleteFile = remove(cacheFile1.c_str()); ASSERT_TRUE(0 == deleteFile || ENOENT == errno); std::srand(0); - //generate identity and read the cache from a file that does not exist + // generate identity and read the cache from a file that does not exist ShaderCache::get().setFilename(cacheFile1.c_str()); - ShaderCacheTestUtils::setSaveDelay(ShaderCache::get(), 0); //disable deferred save + ShaderCacheTestUtils::setSaveDelay(ShaderCache::get(), 0); // disable deferred save std::vector identity(1024); genRandomData(identity); - ShaderCache::get().initShaderDiskCache(identity.data(), identity.size() * - sizeof(decltype(identity)::value_type)); + ShaderCache::get().initShaderDiskCache( + identity.data(), identity.size() * sizeof(decltype(identity)::value_type)); // generate random content in cache and store to disk constexpr size_t numBlob(10); constexpr size_t keySize(1024); constexpr size_t dataSize(50 * 1024); - std::vector< std::pair, sk_sp> > blobVec(numBlob); + std::vector, sk_sp>> blobVec(numBlob); for (auto& blob : blobVec) { std::vector keyBuffer(keySize); std::vector dataBuffer(dataSize); @@ -237,47 +232,47 @@ TEST(ShaderCacheTest, testCacheValidation) { // change to a file that does not exist and verify validation fails ShaderCache::get().setFilename(cacheFile2.c_str()); ShaderCache::get().initShaderDiskCache(); - ASSERT_FALSE( ShaderCacheTestUtils::validateCache(ShaderCache::get(), identity) ); + ASSERT_FALSE(ShaderCacheTestUtils::validateCache(ShaderCache::get(), identity)); ShaderCacheTestUtils::terminate(ShaderCache::get(), false); // restore the original file and verify validation succeeds ShaderCache::get().setFilename(cacheFile1.c_str()); - ShaderCache::get().initShaderDiskCache(identity.data(), identity.size() * - sizeof(decltype(identity)::value_type)); - ASSERT_TRUE( ShaderCacheTestUtils::validateCache(ShaderCache::get(), identity) ); + ShaderCache::get().initShaderDiskCache( + identity.data(), identity.size() * sizeof(decltype(identity)::value_type)); + ASSERT_TRUE(ShaderCacheTestUtils::validateCache(ShaderCache::get(), identity)); for (const auto& blob : blobVec) { auto outVS = ShaderCache::get().load(*blob.first.get()); - ASSERT_TRUE( checkShader(outVS, blob.second) ); + ASSERT_TRUE(checkShader(outVS, blob.second)); } // generate error identity and verify load fails ShaderCache::get().initShaderDiskCache(identity.data(), -1); for (const auto& blob : blobVec) { - ASSERT_EQ( ShaderCache::get().load(*blob.first.get()), sk_sp() ); + ASSERT_EQ(ShaderCache::get().load(*blob.first.get()), sk_sp()); } - ShaderCache::get().initShaderDiskCache(nullptr, identity.size() * - sizeof(decltype(identity)::value_type)); + ShaderCache::get().initShaderDiskCache( + nullptr, identity.size() * sizeof(decltype(identity)::value_type)); for (const auto& blob : blobVec) { - ASSERT_EQ( ShaderCache::get().load(*blob.first.get()), sk_sp() ); + ASSERT_EQ(ShaderCache::get().load(*blob.first.get()), sk_sp()); } // verify the cache validation again after load fails - ShaderCache::get().initShaderDiskCache(identity.data(), identity.size() * - sizeof(decltype(identity)::value_type)); - ASSERT_TRUE( ShaderCacheTestUtils::validateCache(ShaderCache::get(), identity) ); + ShaderCache::get().initShaderDiskCache( + identity.data(), identity.size() * sizeof(decltype(identity)::value_type)); + ASSERT_TRUE(ShaderCacheTestUtils::validateCache(ShaderCache::get(), identity)); for (const auto& blob : blobVec) { auto outVS = ShaderCache::get().load(*blob.first.get()); - ASSERT_TRUE( checkShader(outVS, blob.second) ); + ASSERT_TRUE(checkShader(outVS, blob.second)); } // generate another identity and verify load fails for (auto& data : identity) { data += std::rand(); } - ShaderCache::get().initShaderDiskCache(identity.data(), identity.size() * - sizeof(decltype(identity)::value_type)); + ShaderCache::get().initShaderDiskCache( + identity.data(), identity.size() * sizeof(decltype(identity)::value_type)); for (const auto& blob : blobVec) { - ASSERT_EQ( ShaderCache::get().load(*blob.first.get()), sk_sp() ); + ASSERT_EQ(ShaderCache::get().load(*blob.first.get()), sk_sp()); } ShaderCacheTestUtils::terminate(ShaderCache::get(), false); diff --git a/libs/hwui/tests/unit/SkiaDisplayListTests.cpp b/libs/hwui/tests/unit/SkiaDisplayListTests.cpp index 415f9e8517ff..53bf84f13fd6 100644 --- a/libs/hwui/tests/unit/SkiaDisplayListTests.cpp +++ b/libs/hwui/tests/unit/SkiaDisplayListTests.cpp @@ -100,16 +100,35 @@ TEST(SkiaDisplayList, syncContexts) { GLFunctorDrawable functorDrawable(&functor, nullptr, &dummyCanvas); skiaDL.mChildFunctors.push_back(&functorDrawable); + int functor2 = WebViewFunctor_create(TestUtils::createMockFunctor(RenderMode::OpenGL_ES), + RenderMode::OpenGL_ES); + auto& counts = TestUtils::countsForFunctor(functor2); + skiaDL.mChildFunctors.push_back( + skiaDL.allocateDrawable(functor2, &dummyCanvas)); + WebViewFunctor_release(functor2); + SkRect bounds = SkRect::MakeWH(200, 200); VectorDrawableRoot vectorDrawable(new VectorDrawable::Group()); vectorDrawable.mutateStagingProperties()->setBounds(bounds); skiaDL.mVectorDrawables.push_back(&vectorDrawable); // ensure that the functor and vectorDrawable are properly synced - skiaDL.syncContents(); - - ASSERT_EQ(functor.getLastMode(), DrawGlInfo::kModeSync); - ASSERT_EQ(vectorDrawable.mutateProperties()->getBounds(), bounds); + TestUtils::runOnRenderThread([&](auto&) { + skiaDL.syncContents(WebViewSyncData{ + .applyForceDark = false, + }); + }); + + EXPECT_EQ(functor.getLastMode(), DrawGlInfo::kModeSync); + EXPECT_EQ(counts.sync, 1); + EXPECT_EQ(counts.destroyed, 0); + EXPECT_EQ(vectorDrawable.mutateProperties()->getBounds(), bounds); + + skiaDL.reset(); + TestUtils::runOnRenderThread([](auto&) { + // Fence + }); + EXPECT_EQ(counts.destroyed, 1); } class ContextFactory : public IContextFactory { diff --git a/libs/hwui/tests/unit/SkiaPipelineTests.cpp b/libs/hwui/tests/unit/SkiaPipelineTests.cpp index d16b8be89e20..3c06dab36fe4 100644 --- a/libs/hwui/tests/unit/SkiaPipelineTests.cpp +++ b/libs/hwui/tests/unit/SkiaPipelineTests.cpp @@ -24,10 +24,10 @@ #include "DamageAccumulator.h" #include "IContextFactory.h" #include "SkiaCanvas.h" -#include "pipeline/skia/SkiaUtils.h" #include "pipeline/skia/SkiaDisplayList.h" #include "pipeline/skia/SkiaOpenGLPipeline.h" #include "pipeline/skia/SkiaRecordingCanvas.h" +#include "pipeline/skia/SkiaUtils.h" #include "renderthread/CanvasContext.h" #include "tests/common/TestUtils.h" @@ -51,8 +51,7 @@ RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaPipeline, renderFrame) { auto surface = SkSurface::MakeRasterN32Premul(1, 1); surface->getCanvas()->drawColor(SK_ColorBLUE, SkBlendMode::kSrcOver); ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorBLUE); - pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds, - surface); + pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds, surface); ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorRED); } @@ -84,8 +83,7 @@ RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaPipeline, testOnPrepareTree) { ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorBLUE); // drawFrame will crash if "SkiaPipeline::onPrepareTree" did not clean invalid VD pointer - pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds, - surface); + pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds, surface); ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorRED); } @@ -106,12 +104,10 @@ RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaPipeline, renderFrameCheckOpaque) { auto surface = SkSurface::MakeRasterN32Premul(2, 2); surface->getCanvas()->drawColor(SK_ColorBLUE, SkBlendMode::kSrcOver); ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorBLUE); - pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, true, contentDrawBounds, - surface); + pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, true, contentDrawBounds, surface); ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorBLUE); ASSERT_EQ(TestUtils::getColor(surface, 0, 1), SK_ColorGREEN); - pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, false, contentDrawBounds, - surface); + pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, false, contentDrawBounds, surface); ASSERT_EQ(TestUtils::getColor(surface, 0, 0), (unsigned int)SK_ColorTRANSPARENT); ASSERT_EQ(TestUtils::getColor(surface, 0, 1), SK_ColorGREEN); } @@ -130,8 +126,7 @@ RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaPipeline, renderFrameCheckDirtyRect) { auto surface = SkSurface::MakeRasterN32Premul(2, 2); surface->getCanvas()->drawColor(SK_ColorBLUE, SkBlendMode::kSrcOver); ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorBLUE); - pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, true, contentDrawBounds, - surface); + pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, true, contentDrawBounds, surface); ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorBLUE); ASSERT_EQ(TestUtils::getColor(surface, 1, 0), SK_ColorBLUE); ASSERT_EQ(TestUtils::getColor(surface, 0, 1), SK_ColorRED); @@ -203,38 +198,32 @@ RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaPipeline, renderOverdraw) { ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorBLUE); // Single draw, should be white. - pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds, - surface); + pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds, surface); ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorWHITE); // 1 Overdraw, should be blue blended onto white. renderNodes.push_back(whiteNode); - pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds, - surface); + pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds, surface); ASSERT_EQ(TestUtils::getColor(surface, 0, 0), (unsigned)0xffd0d0ff); // 2 Overdraw, should be green blended onto white renderNodes.push_back(whiteNode); - pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds, - surface); + pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds, surface); ASSERT_EQ(TestUtils::getColor(surface, 0, 0), (unsigned)0xffd0ffd0); // 3 Overdraw, should be pink blended onto white. renderNodes.push_back(whiteNode); - pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds, - surface); + pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds, surface); ASSERT_EQ(TestUtils::getColor(surface, 0, 0), (unsigned)0xffffc0c0); // 4 Overdraw, should be red blended onto white. renderNodes.push_back(whiteNode); - pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds, - surface); + pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds, surface); ASSERT_EQ(TestUtils::getColor(surface, 0, 0), (unsigned)0xffff8080); // 5 Overdraw, should be red blended onto white. renderNodes.push_back(whiteNode); - pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds, - surface); + pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds, surface); ASSERT_EQ(TestUtils::getColor(surface, 0, 0), (unsigned)0xffff8080); } @@ -389,7 +378,6 @@ RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaPipeline, context_lost) { EXPECT_FALSE(pipeline->isSurfaceReady()); EXPECT_TRUE(pipeline->setSurface((Surface*)0x01, SwapBehavior::kSwap_default, ColorMode::SRGB)); EXPECT_TRUE(pipeline->isSurfaceReady()); - renderThread.destroyGlContext(); + renderThread.destroyRenderingContext(); EXPECT_FALSE(pipeline->isSurfaceReady()); } - diff --git a/libs/hwui/tests/unit/TypefaceTests.cpp b/libs/hwui/tests/unit/TypefaceTests.cpp index b645aeb55074..1a09b1c52d8a 100644 --- a/libs/hwui/tests/unit/TypefaceTests.cpp +++ b/libs/hwui/tests/unit/TypefaceTests.cpp @@ -54,9 +54,9 @@ std::shared_ptr buildFamily(const char* fileName) { sk_sp fm(SkFontMgr::RefDefault()); sk_sp typeface(fm->makeFromStream(std::move(fontData))); LOG_ALWAYS_FATAL_IF(typeface == nullptr, "Failed to make typeface from %s", fileName); - std::shared_ptr font = std::make_shared( - std::move(typeface), data, st.st_size, fileName, 0, - std::vector()); + std::shared_ptr font = + std::make_shared(std::move(typeface), data, st.st_size, fileName, 0, + std::vector()); std::vector fonts; fonts.push_back(minikin::Font::Builder(font).build()); return std::make_shared(std::move(fonts)); diff --git a/libs/hwui/tests/unit/VectorDrawableTests.cpp b/libs/hwui/tests/unit/VectorDrawableTests.cpp index ee6beba847a0..9e7f0964b2d2 100644 --- a/libs/hwui/tests/unit/VectorDrawableTests.cpp +++ b/libs/hwui/tests/unit/VectorDrawableTests.cpp @@ -85,8 +85,10 @@ const static TestData sTestDataSet[] = { outPath->rCubicTo(8.0, 8.0, 8.0, 8.0, 8.0, 8.0); outPath->cubicTo(16.0, 16.0, 9.0, 9.0, 9.0, 9.0); outPath->rCubicTo(0.0, 0.0, 9.0, 9.0, 9.0, 9.0); - outPath->arcTo(10.0, 10.0, 0.0, SkPath::kLarge_ArcSize, SkPath::kCW_Direction, 10.0, 10.0); - outPath->arcTo(10.0, 10.0, 0.0, SkPath::kLarge_ArcSize, SkPath::kCW_Direction, 20.0, 20.0); + outPath->arcTo(10.0, 10.0, 0.0, SkPath::kLarge_ArcSize, SkPath::kCW_Direction, 10.0, + 10.0); + outPath->arcTo(10.0, 10.0, 0.0, SkPath::kLarge_ArcSize, SkPath::kCW_Direction, 20.0, + 20.0); }}, // Check box VectorDrawable path data @@ -157,7 +159,8 @@ const static TestData sTestDataSet[] = { }, [](SkPath* outPath) { outPath->moveTo(300.0, 70.0); - outPath->arcTo(230.0, 230.0, 0.0, SkPath::kLarge_ArcSize, SkPath::kCCW_Direction, 301.0, 70.0); + outPath->arcTo(230.0, 230.0, 0.0, SkPath::kLarge_ArcSize, SkPath::kCCW_Direction, + 301.0, 70.0); outPath->close(); outPath->moveTo(300.0, 70.0); }}, @@ -236,14 +239,14 @@ struct StringPath { }; const StringPath sStringPaths[] = { - {"3e...3", false}, // Not starting with a verb and ill-formatted float - {"L.M.F.A.O", false}, // No floats following verbs - {"m 1 1", true}, // Valid path data - {"\n \t z", true}, // Valid path data with leading spaces - {"1-2e34567", false}, // Not starting with a verb and ill-formatted float - {"f 4 5", false}, // Invalid verb - {"\r ", false}, // Empty string - {"L1,0 L1,1 L0,1 z M1000", false} // Not enough floats following verb M. + {"3e...3", false}, // Not starting with a verb and ill-formatted float + {"L.M.F.A.O", false}, // No floats following verbs + {"m 1 1", true}, // Valid path data + {"\n \t z", true}, // Valid path data with leading spaces + {"1-2e34567", false}, // Not starting with a verb and ill-formatted float + {"f 4 5", false}, // Invalid verb + {"\r ", false}, // Empty string + {"L1,0 L1,1 L0,1 z M1000", false} // Not enough floats following verb M. }; static bool hasSameVerbs(const PathData& from, const PathData& to) { diff --git a/libs/hwui/tests/unit/WebViewFunctorManagerTests.cpp b/libs/hwui/tests/unit/WebViewFunctorManagerTests.cpp new file mode 100644 index 000000000000..c8169aff1c5e --- /dev/null +++ b/libs/hwui/tests/unit/WebViewFunctorManagerTests.cpp @@ -0,0 +1,154 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include "WebViewFunctorManager.h" +#include "private/hwui/WebViewFunctor.h" +#include "renderthread/RenderProxy.h" +#include "tests/common/TestUtils.h" + +#include + +using namespace android; +using namespace android::uirenderer; + +TEST(WebViewFunctor, createDestroyGLES) { + int functor = WebViewFunctor_create(TestUtils::createMockFunctor(RenderMode::OpenGL_ES), + RenderMode::OpenGL_ES); + ASSERT_NE(-1, functor); + WebViewFunctor_release(functor); + TestUtils::runOnRenderThreadUnmanaged([](renderthread::RenderThread&) { + // Empty, don't care + }); + auto& counts = TestUtils::countsForFunctor(functor); + // We never initialized, so contextDestroyed == 0 + EXPECT_EQ(0, counts.contextDestroyed); + EXPECT_EQ(1, counts.destroyed); +} + +TEST(WebViewFunctor, createSyncHandleGLES) { + int functor = WebViewFunctor_create(TestUtils::createMockFunctor(RenderMode::OpenGL_ES), + RenderMode::OpenGL_ES); + ASSERT_NE(-1, functor); + auto handle = WebViewFunctorManager::instance().handleFor(functor); + ASSERT_TRUE(handle); + WebViewFunctor_release(functor); + EXPECT_FALSE(WebViewFunctorManager::instance().handleFor(functor)); + TestUtils::runOnRenderThreadUnmanaged([](renderthread::RenderThread&) { + // fence + }); + auto& counts = TestUtils::countsForFunctor(functor); + EXPECT_EQ(0, counts.sync); + EXPECT_EQ(0, counts.contextDestroyed); + EXPECT_EQ(0, counts.destroyed); + + TestUtils::runOnRenderThreadUnmanaged([&](auto&) { + WebViewSyncData syncData; + handle->sync(syncData); + }); + + EXPECT_EQ(1, counts.sync); + + TestUtils::runOnRenderThreadUnmanaged([&](auto&) { + WebViewSyncData syncData; + handle->sync(syncData); + }); + + EXPECT_EQ(2, counts.sync); + + handle.clear(); + + TestUtils::runOnRenderThreadUnmanaged([](renderthread::RenderThread&) { + // fence + }); + + EXPECT_EQ(2, counts.sync); + EXPECT_EQ(0, counts.contextDestroyed); + EXPECT_EQ(1, counts.destroyed); +} + +TEST(WebViewFunctor, createSyncDrawGLES) { + int functor = WebViewFunctor_create(TestUtils::createMockFunctor(RenderMode::OpenGL_ES), + RenderMode::OpenGL_ES); + ASSERT_NE(-1, functor); + auto handle = WebViewFunctorManager::instance().handleFor(functor); + ASSERT_TRUE(handle); + WebViewFunctor_release(functor); + auto& counts = TestUtils::countsForFunctor(functor); + for (int i = 0; i < 5; i++) { + TestUtils::runOnRenderThreadUnmanaged([&](auto&) { + WebViewSyncData syncData; + handle->sync(syncData); + DrawGlInfo drawInfo; + handle->drawGl(drawInfo); + handle->drawGl(drawInfo); + }); + } + handle.clear(); + TestUtils::runOnRenderThreadUnmanaged([](renderthread::RenderThread&) { + // fence + }); + EXPECT_EQ(5, counts.sync); + EXPECT_EQ(10, counts.glesDraw); + EXPECT_EQ(1, counts.contextDestroyed); + EXPECT_EQ(1, counts.destroyed); +} + +TEST(WebViewFunctor, contextDestroyed) { + int functor = WebViewFunctor_create(TestUtils::createMockFunctor(RenderMode::OpenGL_ES), + RenderMode::OpenGL_ES); + ASSERT_NE(-1, functor); + auto handle = WebViewFunctorManager::instance().handleFor(functor); + ASSERT_TRUE(handle); + WebViewFunctor_release(functor); + auto& counts = TestUtils::countsForFunctor(functor); + TestUtils::runOnRenderThreadUnmanaged([&](auto&) { + WebViewSyncData syncData; + handle->sync(syncData); + DrawGlInfo drawInfo; + handle->drawGl(drawInfo); + }); + EXPECT_EQ(1, counts.sync); + EXPECT_EQ(1, counts.glesDraw); + EXPECT_EQ(0, counts.contextDestroyed); + EXPECT_EQ(0, counts.destroyed); + TestUtils::runOnRenderThreadUnmanaged([](auto& rt) { + rt.destroyRenderingContext(); + }); + EXPECT_EQ(1, counts.sync); + EXPECT_EQ(1, counts.glesDraw); + EXPECT_EQ(1, counts.contextDestroyed); + EXPECT_EQ(0, counts.destroyed); + TestUtils::runOnRenderThreadUnmanaged([&](auto&) { + WebViewSyncData syncData; + handle->sync(syncData); + DrawGlInfo drawInfo; + handle->drawGl(drawInfo); + }); + EXPECT_EQ(2, counts.sync); + EXPECT_EQ(2, counts.glesDraw); + EXPECT_EQ(1, counts.contextDestroyed); + EXPECT_EQ(0, counts.destroyed); + handle.clear(); + TestUtils::runOnRenderThreadUnmanaged([](renderthread::RenderThread&) { + // fence + }); + EXPECT_EQ(2, counts.sync); + EXPECT_EQ(2, counts.glesDraw); + EXPECT_EQ(2, counts.contextDestroyed); + EXPECT_EQ(1, counts.destroyed); +} \ No newline at end of file diff --git a/libs/hwui/tests/unit/main.cpp b/libs/hwui/tests/unit/main.cpp index aecceb3609f5..63d15403b607 100644 --- a/libs/hwui/tests/unit/main.cpp +++ b/libs/hwui/tests/unit/main.cpp @@ -17,14 +17,14 @@ #include "gmock/gmock.h" #include "gtest/gtest.h" +#include "Properties.h" #include "debug/GlesDriver.h" #include "debug/NullGlesDriver.h" #include "hwui/Typeface.h" -#include "Properties.h" #include "tests/common/LeakChecker.h" -#include "thread/TaskProcessor.h" #include "thread/Task.h" #include "thread/TaskManager.h" +#include "thread/TaskProcessor.h" #include -- cgit v1.2.3-59-g8ed1b From f1aa7909e6496da4a1ae9ccfcbab5db843d329c3 Mon Sep 17 00:00:00 2001 From: John Reck Date: Thu, 7 Mar 2019 17:01:08 -0800 Subject: Fix damage tracking for RenderNode drawn twice Bug: 127866048 Test: CustomRenderer demo Change-Id: I431a7284b1d0a026e06500a78f41830a268235a5 --- libs/hwui/RenderNode.cpp | 7 ++ libs/hwui/RenderNode.h | 2 + libs/hwui/TreeInfo.cpp | 1 + libs/hwui/TreeInfo.h | 1 + .../src/com/android/test/hwui/CustomRenderer.java | 90 +++++++++++++++++----- 5 files changed, 82 insertions(+), 19 deletions(-) (limited to 'libs/hwui/RenderNode.cpp') diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp index 1ff7ffe6bf87..e0ed3e4940a8 100644 --- a/libs/hwui/RenderNode.cpp +++ b/libs/hwui/RenderNode.cpp @@ -134,6 +134,7 @@ void RenderNode::removeAnimator(const sp& animator) { void RenderNode::damageSelf(TreeInfo& info) { if (isRenderable()) { + mDamageGenerationId = info.damageGenerationId; if (properties().getClipDamageToBounds()) { info.damageAccumulator->dirty(0, 0, properties().getWidth(), properties().getHeight()); } else { @@ -199,6 +200,12 @@ void RenderNode::pushLayerUpdate(TreeInfo& info) { * stencil buffer may be needed. Views that use a functor to draw will be forced onto a layer. */ void RenderNode::prepareTreeImpl(TreeObserver& observer, TreeInfo& info, bool functorsNeedLayer) { + if (mDamageGenerationId == info.damageGenerationId) { + // We hit the same node a second time in the same tree. We don't know the minimal + // damage rect anymore, so just push the biggest we can onto our parent's transform + // We push directly onto parent in case we are clipped to bounds but have moved position. + info.damageAccumulator->dirty(DIRTY_MIN, DIRTY_MIN, DIRTY_MAX, DIRTY_MAX); + } info.damageAccumulator->pushTransform(this); if (info.mode == TreeInfo::MODE_FULL) { diff --git a/libs/hwui/RenderNode.h b/libs/hwui/RenderNode.h index 6060123ed759..23e7a0e60554 100644 --- a/libs/hwui/RenderNode.h +++ b/libs/hwui/RenderNode.h @@ -255,6 +255,8 @@ private: DisplayList* mDisplayList; DisplayList* mStagingDisplayList; + int64_t mDamageGenerationId; + friend class AnimatorManager; AnimatorManager mAnimatorManager; diff --git a/libs/hwui/TreeInfo.cpp b/libs/hwui/TreeInfo.cpp index 808a12a311e2..cdad20ec6caa 100644 --- a/libs/hwui/TreeInfo.cpp +++ b/libs/hwui/TreeInfo.cpp @@ -24,6 +24,7 @@ TreeInfo::TreeInfo(TraversalMode mode, renderthread::CanvasContext& canvasContex : mode(mode) , prepareTextures(mode == MODE_FULL) , canvasContext(canvasContext) + , damageGenerationId(canvasContext.getFrameNumber()) , disableForceDark(canvasContext.useForceDark() ? 0 : 1) {} } // namespace android::uirenderer diff --git a/libs/hwui/TreeInfo.h b/libs/hwui/TreeInfo.h index a0d960527ca6..04eabac395f0 100644 --- a/libs/hwui/TreeInfo.h +++ b/libs/hwui/TreeInfo.h @@ -87,6 +87,7 @@ public: // Must not be null during actual usage DamageAccumulator* damageAccumulator = nullptr; + int64_t damageGenerationId = 0; LayerUpdateQueue* layerUpdateQueue = nullptr; ErrorHandler* errorHandler = nullptr; diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/CustomRenderer.java b/tests/HwAccelerationTest/src/com/android/test/hwui/CustomRenderer.java index fece8babb400..5ad7fb9027a2 100644 --- a/tests/HwAccelerationTest/src/com/android/test/hwui/CustomRenderer.java +++ b/tests/HwAccelerationTest/src/com/android/test/hwui/CustomRenderer.java @@ -16,6 +16,7 @@ package com.android.test.hwui; +import android.animation.ObjectAnimator; import android.app.Activity; import android.graphics.Color; import android.graphics.HardwareRenderer; @@ -23,12 +24,15 @@ import android.graphics.Paint; import android.graphics.RecordingCanvas; import android.graphics.RenderNode; import android.os.Bundle; -import android.util.Log; +import android.os.Handler; import android.view.SurfaceHolder; public class CustomRenderer extends Activity { - private RenderNode mContent = new RenderNode("CustomRenderer"); + private RenderNode mRootNode = new RenderNode("CustomRenderer"); + private RenderNode mChildNode = new RenderNode("RedBox"); private HardwareRenderer mRenderer = new HardwareRenderer(); + private ObjectAnimator mAnimator; + private Handler mRedrawHandler = new Handler(true); @Override protected void onCreate(Bundle savedInstanceState) { @@ -36,6 +40,64 @@ public class CustomRenderer extends Activity { getWindow().takeSurface(mSurfaceCallbacks); } + @Override + protected void onStart() { + super.onStart(); + mAnimator = ObjectAnimator.ofFloat(mChildNode, "translationY", 0, 300); + mAnimator.setRepeatMode(ObjectAnimator.REVERSE); + mAnimator.setRepeatCount(ObjectAnimator.INFINITE); + final Runnable redraw = this::draw; + mAnimator.addUpdateListener(animation -> { + mRedrawHandler.post(redraw); + }); + } + + @Override + protected void onStop() { + super.onStop(); + mAnimator.end(); + mAnimator = null; + } + + private void setupRoot(int width, int height) { + mRootNode.setPosition(0, 0, width, height); + + RecordingCanvas canvas = mRootNode.beginRecording(); + canvas.drawColor(Color.WHITE); + Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG); + paint.setColor(Color.BLACK); + paint.setTextAlign(Paint.Align.CENTER); + float textSize = Math.min(width, height) * .05f; + paint.setTextSize(textSize); + canvas.drawText("Hello custom renderer!", width / 2, textSize * 2, paint); + + canvas.translate(0, height / 4); + canvas.drawRenderNode(mChildNode); + canvas.translate(width / 2, 0); + canvas.drawRenderNode(mChildNode); + mRootNode.endRecording(); + + setupChild(width / 2, height / 2); + } + + private void setupChild(int width, int height) { + mChildNode.setPosition(0, 0, width, height); + mChildNode.setScaleX(.5f); + mChildNode.setScaleY(.5f); + + RecordingCanvas canvas = mChildNode.beginRecording(); + canvas.drawColor(Color.RED); + mChildNode.endRecording(); + } + + private void draw() { + // Since we are constantly pumping frames between onStart & onStop we don't really + // care about any errors that may happen. They will self-correct. + mRenderer.createRenderRequest() + .setVsyncTime(System.nanoTime()) + .syncAndDraw(); + } + private SurfaceHolder.Callback2 mSurfaceCallbacks = new SurfaceHolder.Callback2() { @Override @@ -48,24 +110,14 @@ public class CustomRenderer extends Activity { @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { - mContent.setLeftTopRightBottom(0, 0, width, height); - RecordingCanvas canvas = mContent.beginRecording(); - canvas.drawColor(Color.WHITE); - Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG); - paint.setColor(Color.BLACK); - paint.setTextAlign(Paint.Align.CENTER); - paint.setTextSize(Math.min(width, height) * .05f); - canvas.drawText("Hello custom renderer!", width / 2, height / 2, paint); - mContent.endRecording(); - - mRenderer.setContentRoot(mContent); + setupRoot(width, height); + + mRenderer.setContentRoot(mRootNode); mRenderer.setSurface(holder.getSurface()); - mRenderer.createRenderRequest() - .setVsyncTime(System.nanoTime()) - .setFrameCommitCallback(Runnable::run, () -> { - Log.d("CustomRenderer", "Frame committed!"); - }) - .syncAndDraw(); + draw(); + if (!mAnimator.isStarted()) { + mAnimator.start(); + } } @Override -- cgit v1.2.3-59-g8ed1b From 097e1d333088cb01dddacd235a6e654d4002a2b3 Mon Sep 17 00:00:00 2001 From: John Reck Date: Wed, 12 Jun 2019 15:01:51 -0700 Subject: Fix setPositionListener race condition Fixes: 131625115 Test: atest android.view.cts.SystemGestureExclusionRectsTest android.view.cts.SurfaceViewSyncTest android.uirendering.cts.testclasses.SurfaceViewTests Change-Id: Ia357ff6fa5d5fe1e152abc23bbd6d8051cfd7aa7 --- libs/hwui/RenderNode.cpp | 6 ++++++ libs/hwui/RenderNode.h | 8 ++++---- 2 files changed, 10 insertions(+), 4 deletions(-) (limited to 'libs/hwui/RenderNode.cpp') diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp index e0ed3e4940a8..b73347b233d7 100644 --- a/libs/hwui/RenderNode.cpp +++ b/libs/hwui/RenderNode.cpp @@ -264,6 +264,12 @@ void RenderNode::syncProperties() { } void RenderNode::pushStagingPropertiesChanges(TreeInfo& info) { + if (mPositionListenerDirty) { + mPositionListener = std::move(mStagingPositionListener); + mStagingPositionListener = nullptr; + mPositionListenerDirty = false; + } + // Push the animators first so that setupStartValueIfNecessary() is called // before properties() is trampled by stagingProperties(), as they are // required by some animators. diff --git a/libs/hwui/RenderNode.h b/libs/hwui/RenderNode.h index 23e7a0e60554..c6db7f1ba60d 100644 --- a/libs/hwui/RenderNode.h +++ b/libs/hwui/RenderNode.h @@ -188,11 +188,9 @@ public: virtual void onPositionLost(RenderNode& node, const TreeInfo* info) = 0; }; - // Note this is not thread safe, this needs to be called - // before the RenderNode is used for drawing. - // RenderNode takes ownership of the pointer ANDROID_API void setPositionListener(PositionListener* listener) { - mPositionListener = listener; + mStagingPositionListener = listener; + mPositionListenerDirty = true; } // This is only modified in MODE_FULL, so it can be safely accessed @@ -275,6 +273,8 @@ private: // mDisplayList, not mStagingDisplayList. uint32_t mParentCount; + bool mPositionListenerDirty = false; + sp mStagingPositionListener; sp mPositionListener; UsageHint mUsageHint = UsageHint::Unknown; -- cgit v1.2.3-59-g8ed1b