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