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 "pipeline/skia/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 "pipeline/skia/ShaderCache.h"
32 #include "pipeline/skia/SkiaGpuPipeline.h"
33 #include "pipeline/skia/SkiaProfileRenderer.h"
34 #include "pipeline/skia/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)
46         : SkiaGpuPipeline(thread) {
47     thread.renderState().registerContextCallback(this);
48 }
49 
~SkiaVulkanPipeline()50 SkiaVulkanPipeline::~SkiaVulkanPipeline() {
51     mRenderThread.renderState().removeContextCallback(this);
52 }
53 
vulkanManager()54 VulkanManager& SkiaVulkanPipeline::vulkanManager() {
55     return mRenderThread.vulkanManager();
56 }
57 
makeCurrent()58 MakeCurrentResult SkiaVulkanPipeline::makeCurrent() {
59     // In case the surface was destroyed (e.g. a previous trimMemory call) we
60     // need to recreate it here.
61     if (mHardwareBuffer) {
62         mRenderThread.requireVkContext();
63     } else if (!isSurfaceReady() && mNativeWindow) {
64         setSurface(mNativeWindow.get(), SwapBehavior::kSwap_default);
65     }
66     return isContextReady() ? MakeCurrentResult::AlreadyCurrent : MakeCurrentResult::Failed;
67 }
68 
getFrame()69 Frame SkiaVulkanPipeline::getFrame() {
70     LOG_ALWAYS_FATAL_IF(mVkSurface == nullptr, "getFrame() called on a context with no surface!");
71     return vulkanManager().dequeueNextBuffer(mVkSurface);
72 }
73 
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,const HardwareBufferRenderParams & bufferParams,std::mutex & profilerLock)74 IRenderPipeline::DrawResult SkiaVulkanPipeline::draw(
75         const Frame& frame, const SkRect& screenDirty, const SkRect& dirty,
76         const LightGeometry& lightGeometry, LayerUpdateQueue* layerUpdateQueue,
77         const Rect& contentDrawBounds, bool opaque, const LightInfo& lightInfo,
78         const std::vector<sp<RenderNode>>& renderNodes, FrameInfoVisualizer* profiler,
79         const HardwareBufferRenderParams& bufferParams, std::mutex& profilerLock) {
80     sk_sp<SkSurface> backBuffer;
81     SkMatrix preTransform;
82     if (mHardwareBuffer) {
83         backBuffer = getBufferSkSurface(bufferParams);
84         preTransform = bufferParams.getTransform();
85     } else {
86         backBuffer = mVkSurface->getCurrentSkSurface();
87         preTransform = mVkSurface->getCurrentPreTransform();
88     }
89 
90     if (backBuffer.get() == nullptr) {
91         return {false, -1, android::base::unique_fd{}};
92     }
93 
94     // update the coordinates of the global light position based on surface rotation
95     SkPoint lightCenter = preTransform.mapXY(lightGeometry.center.x, lightGeometry.center.y);
96     LightGeometry localGeometry = lightGeometry;
97     localGeometry.center.x = lightCenter.fX;
98     localGeometry.center.y = lightCenter.fY;
99 
100     LightingInfo::updateLighting(localGeometry, lightInfo);
101     renderFrame(*layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds, backBuffer,
102                 preTransform);
103 
104     // Draw visual debugging features
105     if (CC_UNLIKELY(Properties::showDirtyRegions ||
106                     ProfileType::None != Properties::getProfileType())) {
107         std::scoped_lock lock(profilerLock);
108         SkCanvas* profileCanvas = backBuffer->getCanvas();
109         SkAutoCanvasRestore saver(profileCanvas, true);
110         profileCanvas->concat(preTransform);
111         SkiaProfileRenderer profileRenderer(profileCanvas, frame.width(), frame.height());
112         profiler->draw(profileRenderer);
113     }
114 
115     VulkanManager::VkDrawResult drawResult;
116     {
117         ATRACE_NAME("flush commands");
118         drawResult = vulkanManager().finishFrame(backBuffer.get());
119     }
120     layerUpdateQueue->clear();
121 
122     // Log memory statistics
123     if (CC_UNLIKELY(Properties::debugLevel != kDebugDisabled)) {
124         dumpResourceCacheUsage();
125     }
126 
127     return {true, drawResult.submissionTime, std::move(drawResult.presentFence)};
128 }
129 
swapBuffers(const Frame & frame,IRenderPipeline::DrawResult & drawResult,const SkRect & screenDirty,FrameInfo * currentFrameInfo,bool * requireSwap)130 bool SkiaVulkanPipeline::swapBuffers(const Frame& frame, IRenderPipeline::DrawResult& drawResult,
131                                      const SkRect& screenDirty, FrameInfo* currentFrameInfo,
132                                      bool* requireSwap) {
133     // Even if we decided to cancel the frame, from the perspective of jank
134     // metrics the frame was swapped at this point
135     currentFrameInfo->markSwapBuffers();
136 
137     if (mHardwareBuffer) {
138         return false;
139     }
140 
141     *requireSwap = drawResult.success;
142 
143     if (*requireSwap) {
144         vulkanManager().swapBuffers(mVkSurface, screenDirty, std::move(drawResult.presentFence));
145     }
146 
147     return *requireSwap;
148 }
149 
createTextureLayer()150 DeferredLayerUpdater* SkiaVulkanPipeline::createTextureLayer() {
151     mRenderThread.requireVkContext();
152 
153     return new DeferredLayerUpdater(mRenderThread.renderState());
154 }
155 
onStop()156 void SkiaVulkanPipeline::onStop() {}
157 
flush()158 [[nodiscard]] android::base::unique_fd SkiaVulkanPipeline::flush() {
159     int fence = -1;
160     vulkanManager().createReleaseFence(&fence, mRenderThread.getGrContext());
161     return android::base::unique_fd(fence);
162 }
163 
164 // We can safely ignore the swap behavior because VkManager will always operate
165 // in a mode equivalent to EGLManager::SwapBehavior::kBufferAge
setSurface(ANativeWindow * surface,SwapBehavior)166 bool SkiaVulkanPipeline::setSurface(ANativeWindow* surface, SwapBehavior /*swapBehavior*/) {
167     mNativeWindow = surface;
168 
169     if (mVkSurface) {
170         vulkanManager().destroySurface(mVkSurface);
171         mVkSurface = nullptr;
172     }
173 
174     if (surface) {
175         mRenderThread.requireVkContext();
176         mVkSurface =
177                 vulkanManager().createSurface(surface, mColorMode, mSurfaceColorSpace,
178                                               mSurfaceColorType, mRenderThread.getGrContext(), 0);
179     }
180 
181     return mVkSurface != nullptr;
182 }
183 
setTargetSdrHdrRatio(float ratio)184 void SkiaVulkanPipeline::setTargetSdrHdrRatio(float ratio) {
185     SkiaPipeline::setTargetSdrHdrRatio(ratio);
186     if (mVkSurface) {
187         mVkSurface->setColorSpace(mSurfaceColorSpace);
188     }
189 }
190 
isSurfaceReady()191 bool SkiaVulkanPipeline::isSurfaceReady() {
192     return CC_UNLIKELY(mVkSurface != nullptr);
193 }
194 
isContextReady()195 bool SkiaVulkanPipeline::isContextReady() {
196     return CC_LIKELY(vulkanManager().hasVkContext());
197 }
198 
invokeFunctor(const RenderThread & thread,Functor * functor)199 void SkiaVulkanPipeline::invokeFunctor(const RenderThread& thread, Functor* functor) {
200     VkInteropFunctorDrawable::vkInvokeFunctor(functor);
201 }
202 
allocateHardwareBitmap(renderthread::RenderThread & renderThread,SkBitmap & skBitmap)203 sk_sp<Bitmap> SkiaVulkanPipeline::allocateHardwareBitmap(renderthread::RenderThread& renderThread,
204                                                          SkBitmap& skBitmap) {
205     LOG_ALWAYS_FATAL("Unimplemented");
206     return nullptr;
207 }
208 
onContextDestroyed()209 void SkiaVulkanPipeline::onContextDestroyed() {
210     if (mVkSurface) {
211         vulkanManager().destroySurface(mVkSurface);
212         mVkSurface = nullptr;
213     }
214 }
215 
getPixelSnapMatrix() const216 const SkM44& SkiaVulkanPipeline::getPixelSnapMatrix() const {
217     return mVkSurface->getPixelSnapMatrix();
218 }
219 
220 } /* namespace skiapipeline */
221 } /* namespace uirenderer */
222 } /* namespace android */
223