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