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