• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2016 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "SkiaVulkanPipeline.h"
18 
19 #include <GrDirectContext.h>
20 #include <GrTypes.h>
21 #include <SkSurface.h>
22 #include <SkTypes.h>
23 #include <cutils/properties.h>
24 #include <gui/TraceUtils.h>
25 #include <strings.h>
26 #include <vk/GrVkTypes.h>
27 
28 #include "DeferredLayerUpdater.h"
29 #include "LightingInfo.h"
30 #include "Readback.h"
31 #include "ShaderCache.h"
32 #include "SkiaPipeline.h"
33 #include "SkiaProfileRenderer.h"
34 #include "VkInteropFunctorDrawable.h"
35 #include "renderstate/RenderState.h"
36 #include "renderthread/Frame.h"
37 #include "renderthread/IRenderPipeline.h"
38 
39 using namespace android::uirenderer::renderthread;
40 
41 namespace android {
42 namespace uirenderer {
43 namespace skiapipeline {
44 
SkiaVulkanPipeline(renderthread::RenderThread & thread)45 SkiaVulkanPipeline::SkiaVulkanPipeline(renderthread::RenderThread& thread) : SkiaPipeline(thread) {
46     thread.renderState().registerContextCallback(this);
47 }
48 
~SkiaVulkanPipeline()49 SkiaVulkanPipeline::~SkiaVulkanPipeline() {
50     mRenderThread.renderState().removeContextCallback(this);
51 }
52 
vulkanManager()53 VulkanManager& SkiaVulkanPipeline::vulkanManager() {
54     return mRenderThread.vulkanManager();
55 }
56 
makeCurrent()57 MakeCurrentResult SkiaVulkanPipeline::makeCurrent() {
58     // In case the surface was destroyed (e.g. a previous trimMemory call) we
59     // need to recreate it here.
60     if (!isSurfaceReady() && mNativeWindow) {
61         setSurface(mNativeWindow.get(), SwapBehavior::kSwap_default);
62     }
63     return isContextReady() ? MakeCurrentResult::AlreadyCurrent : MakeCurrentResult::Failed;
64 }
65 
getFrame()66 Frame SkiaVulkanPipeline::getFrame() {
67     LOG_ALWAYS_FATAL_IF(mVkSurface == nullptr, "getFrame() called on a context with no surface!");
68     return vulkanManager().dequeueNextBuffer(mVkSurface);
69 }
70 
draw(const Frame & frame,const SkRect & screenDirty,const SkRect & dirty,const LightGeometry & lightGeometry,LayerUpdateQueue * layerUpdateQueue,const Rect & contentDrawBounds,bool opaque,const LightInfo & lightInfo,const std::vector<sp<RenderNode>> & renderNodes,FrameInfoVisualizer * profiler)71 IRenderPipeline::DrawResult SkiaVulkanPipeline::draw(
72         const Frame& frame, const SkRect& screenDirty, const SkRect& dirty,
73         const LightGeometry& lightGeometry, LayerUpdateQueue* layerUpdateQueue,
74         const Rect& contentDrawBounds, bool opaque, const LightInfo& lightInfo,
75         const std::vector<sp<RenderNode>>& renderNodes, FrameInfoVisualizer* profiler) {
76     sk_sp<SkSurface> backBuffer = mVkSurface->getCurrentSkSurface();
77     if (backBuffer.get() == nullptr) {
78         return {false, -1};
79     }
80 
81     // update the coordinates of the global light position based on surface rotation
82     SkPoint lightCenter = mVkSurface->getCurrentPreTransform().mapXY(lightGeometry.center.x,
83                                                                      lightGeometry.center.y);
84     LightGeometry localGeometry = lightGeometry;
85     localGeometry.center.x = lightCenter.fX;
86     localGeometry.center.y = lightCenter.fY;
87 
88     LightingInfo::updateLighting(localGeometry, lightInfo);
89     renderFrame(*layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds, backBuffer,
90                 mVkSurface->getCurrentPreTransform());
91 
92     // Draw visual debugging features
93     if (CC_UNLIKELY(Properties::showDirtyRegions ||
94                     ProfileType::None != Properties::getProfileType())) {
95         SkCanvas* profileCanvas = backBuffer->getCanvas();
96         SkiaProfileRenderer profileRenderer(profileCanvas);
97         profiler->draw(profileRenderer);
98     }
99 
100     nsecs_t submissionTime = IRenderPipeline::DrawResult::kUnknownTime;
101     {
102         ATRACE_NAME("flush commands");
103         submissionTime = vulkanManager().finishFrame(backBuffer.get());
104     }
105     layerUpdateQueue->clear();
106 
107     // Log memory statistics
108     if (CC_UNLIKELY(Properties::debugLevel != kDebugDisabled)) {
109         dumpResourceCacheUsage();
110     }
111 
112     return {true, submissionTime};
113 }
114 
swapBuffers(const Frame & frame,bool drew,const SkRect & screenDirty,FrameInfo * currentFrameInfo,bool * requireSwap)115 bool SkiaVulkanPipeline::swapBuffers(const Frame& frame, bool drew, const SkRect& screenDirty,
116                                      FrameInfo* currentFrameInfo, bool* requireSwap) {
117     *requireSwap = drew;
118 
119     // Even if we decided to cancel the frame, from the perspective of jank
120     // metrics the frame was swapped at this point
121     currentFrameInfo->markSwapBuffers();
122 
123     if (*requireSwap) {
124         vulkanManager().swapBuffers(mVkSurface, screenDirty);
125     }
126 
127     return *requireSwap;
128 }
129 
createTextureLayer()130 DeferredLayerUpdater* SkiaVulkanPipeline::createTextureLayer() {
131     mRenderThread.requireVkContext();
132 
133     return new DeferredLayerUpdater(mRenderThread.renderState());
134 }
135 
onStop()136 void SkiaVulkanPipeline::onStop() {}
137 
138 // We can safely ignore the swap behavior because VkManager will always operate
139 // in a mode equivalent to EGLManager::SwapBehavior::kBufferAge
setSurface(ANativeWindow * surface,SwapBehavior)140 bool SkiaVulkanPipeline::setSurface(ANativeWindow* surface, SwapBehavior /*swapBehavior*/) {
141     mNativeWindow = surface;
142 
143     if (mVkSurface) {
144         vulkanManager().destroySurface(mVkSurface);
145         mVkSurface = nullptr;
146     }
147 
148     if (surface) {
149         mRenderThread.requireVkContext();
150         mVkSurface =
151                 vulkanManager().createSurface(surface, mColorMode, mSurfaceColorSpace,
152                                               mSurfaceColorType, mRenderThread.getGrContext(), 0);
153     }
154 
155     return mVkSurface != nullptr;
156 }
157 
isSurfaceReady()158 bool SkiaVulkanPipeline::isSurfaceReady() {
159     return CC_UNLIKELY(mVkSurface != nullptr);
160 }
161 
isContextReady()162 bool SkiaVulkanPipeline::isContextReady() {
163     return CC_LIKELY(vulkanManager().hasVkContext());
164 }
165 
invokeFunctor(const RenderThread & thread,Functor * functor)166 void SkiaVulkanPipeline::invokeFunctor(const RenderThread& thread, Functor* functor) {
167     VkInteropFunctorDrawable::vkInvokeFunctor(functor);
168 }
169 
allocateHardwareBitmap(renderthread::RenderThread & renderThread,SkBitmap & skBitmap)170 sk_sp<Bitmap> SkiaVulkanPipeline::allocateHardwareBitmap(renderthread::RenderThread& renderThread,
171                                                          SkBitmap& skBitmap) {
172     LOG_ALWAYS_FATAL("Unimplemented");
173     return nullptr;
174 }
175 
onContextDestroyed()176 void SkiaVulkanPipeline::onContextDestroyed() {
177     if (mVkSurface) {
178         vulkanManager().destroySurface(mVkSurface);
179         mVkSurface = nullptr;
180     }
181 }
182 
getPixelSnapMatrix() const183 const SkM44& SkiaVulkanPipeline::getPixelSnapMatrix() const {
184     return mVkSurface->getPixelSnapMatrix();
185 }
186 
187 } /* namespace skiapipeline */
188 } /* namespace uirenderer */
189 } /* namespace android */
190