1 /*
2  * Copyright 2024 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 "GraphiteGpuContext.h"
18 
19 #include <include/core/SkImageInfo.h>
20 #include <include/core/SkSurface.h>
21 #include <include/core/SkTraceMemoryDump.h>
22 #include <include/gpu/graphite/GraphiteTypes.h>
23 #include <include/gpu/graphite/Surface.h>
24 #include <include/gpu/graphite/vk/VulkanGraphiteUtils.h>
25 
26 #include "GpuTypes.h"
27 #include "skia/compat/GraphiteBackendTexture.h"
28 
29 #include <android-base/macros.h>
30 #include <log/log_main.h>
31 #include <memory>
32 
33 namespace android::renderengine::skia {
34 
35 namespace {
graphiteOptions()36 static skgpu::graphite::ContextOptions graphiteOptions() {
37     skgpu::graphite::ContextOptions options;
38     options.fDisableDriverCorrectnessWorkarounds = true;
39     return options;
40 }
41 } // namespace
42 
MakeVulkan_Graphite(const skgpu::VulkanBackendContext & vulkanBackendContext)43 std::unique_ptr<SkiaGpuContext> SkiaGpuContext::MakeVulkan_Graphite(
44         const skgpu::VulkanBackendContext& vulkanBackendContext) {
45     return std::make_unique<GraphiteGpuContext>(
46             skgpu::graphite::ContextFactory::MakeVulkan(vulkanBackendContext, graphiteOptions()));
47 }
48 
GraphiteGpuContext(std::unique_ptr<skgpu::graphite::Context> context)49 GraphiteGpuContext::GraphiteGpuContext(std::unique_ptr<skgpu::graphite::Context> context)
50       : mContext(std::move(context)) {
51     LOG_ALWAYS_FATAL_IF(mContext.get() == nullptr, "graphite::Context creation failed");
52     LOG_ALWAYS_FATAL_IF(mContext->backend() != skgpu::BackendApi::kVulkan,
53                         "graphite::Context::backend() == %d, but GraphiteBackendContext makes "
54                         "assumptions that are only valid for Vulkan (%d)",
55                         static_cast<int>(mContext->backend()),
56                         static_cast<int>(skgpu::BackendApi::kVulkan));
57 
58     // TODO: b/293371537 - Iterate on default cache limits (the Recorder should have the majority of
59     // the budget, and the Context should be given a smaller fraction.)
60     skgpu::graphite::RecorderOptions recorderOptions = skgpu::graphite::RecorderOptions();
61     this->mRecorder = mContext->makeRecorder(recorderOptions);
62     LOG_ALWAYS_FATAL_IF(mRecorder.get() == nullptr, "graphite::Recorder creation failed");
63 }
64 
~GraphiteGpuContext()65 GraphiteGpuContext::~GraphiteGpuContext() {
66     // The equivalent operation would occur when destroying the graphite::Context, but calling this
67     // explicitly allows any outstanding GraphiteBackendTextures to be released, thus allowing us to
68     // assert that this GraphiteGpuContext holds the last ref to the underlying graphite::Recorder.
69     mContext->submit(skgpu::graphite::SyncToCpu::kYes);
70     // We must call the Context's and Recorder's dtors before exiting this function, so all other
71     // refs must be released by now. Note: these assertions may be unreliable in a hypothetical
72     // future world where we take advantage of Graphite's multi-threading capabilities!
73     LOG_ALWAYS_FATAL_IF(mRecorder.use_count() > 1,
74                         "Something other than GraphiteGpuContext holds a ref to the underlying "
75                         "graphite::Recorder");
76     LOG_ALWAYS_FATAL_IF(mContext.use_count() > 1,
77                         "Something other than GraphiteGpuContext holds a ref to the underlying "
78                         "graphite::Context");
79 };
80 
graphiteContext()81 std::shared_ptr<skgpu::graphite::Context> GraphiteGpuContext::graphiteContext() {
82     return mContext;
83 }
84 
graphiteRecorder()85 std::shared_ptr<skgpu::graphite::Recorder> GraphiteGpuContext::graphiteRecorder() {
86     return mRecorder;
87 }
88 
makeBackendTexture(AHardwareBuffer * buffer,bool isOutputBuffer)89 std::unique_ptr<SkiaBackendTexture> GraphiteGpuContext::makeBackendTexture(AHardwareBuffer* buffer,
90                                                                            bool isOutputBuffer) {
91     return std::make_unique<GraphiteBackendTexture>(graphiteRecorder(), buffer, isOutputBuffer);
92 }
93 
createRenderTarget(SkImageInfo imageInfo)94 sk_sp<SkSurface> GraphiteGpuContext::createRenderTarget(SkImageInfo imageInfo) {
95     constexpr SkSurfaceProps* kProps = nullptr;
96     return SkSurfaces::RenderTarget(mRecorder.get(), imageInfo, skgpu::Mipmapped::kNo, kProps);
97 }
98 
getMaxRenderTargetSize() const99 size_t GraphiteGpuContext::getMaxRenderTargetSize() const {
100     // maxRenderTargetSize only differs from maxTextureSize on GL, so as long as Graphite implies
101     // Vk, then the distinction is irrelevant.
102     return getMaxTextureSize();
103 };
104 
getMaxTextureSize() const105 size_t GraphiteGpuContext::getMaxTextureSize() const {
106     return mContext->maxTextureSize();
107 };
108 
isAbandonedOrDeviceLost()109 bool GraphiteGpuContext::isAbandonedOrDeviceLost() {
110     return mContext->isDeviceLost();
111 }
112 
dumpMemoryStatistics(SkTraceMemoryDump * traceMemoryDump) const113 void GraphiteGpuContext::dumpMemoryStatistics(SkTraceMemoryDump* traceMemoryDump) const {
114     mContext->dumpMemoryStatistics(traceMemoryDump);
115 }
116 
117 } // namespace android::renderengine::skia
118