xref: /aosp_15_r20/external/skia/src/gpu/ganesh/GrDeferredDisplayListRecorder.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1 /*
2  * Copyright 2023 Google LLC
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7 
8 #include "include/private/chromium/GrDeferredDisplayListRecorder.h"
9 
10 #include "include/core/SkCanvas.h"
11 #include "include/core/SkSurface.h"
12 #include "include/gpu/GpuTypes.h"
13 #include "include/gpu/ganesh/GrRecordingContext.h"
14 #include "include/gpu/ganesh/GrTypes.h"
15 #include "include/private/base/SkTo.h"
16 #include "include/private/chromium/GrDeferredDisplayList.h"
17 #include "include/private/chromium/GrSurfaceCharacterization.h"
18 #include "include/private/gpu/ganesh/GrTypesPriv.h"
19 #include "src/gpu/SkBackingFit.h"
20 #include "src/gpu/ganesh/Device.h"
21 #include "src/gpu/ganesh/GrCaps.h"
22 #include "src/gpu/ganesh/GrProxyProvider.h"
23 #include "src/gpu/ganesh/GrRecordingContextPriv.h"
24 #include "src/gpu/ganesh/GrRenderTargetProxy.h"
25 #include "src/gpu/ganesh/GrSurface.h"
26 #include "src/gpu/ganesh/GrSurfaceProxy.h"
27 #include "src/gpu/ganesh/GrSurfaceProxyPriv.h"
28 #include "src/gpu/ganesh/surface/SkSurface_Ganesh.h"
29 
30 #include <functional>
31 #include <utility>
32 
33 class GrResourceProvider;
34 
GrDeferredDisplayListRecorder(const GrSurfaceCharacterization & c)35 GrDeferredDisplayListRecorder::GrDeferredDisplayListRecorder(const GrSurfaceCharacterization& c)
36         : fCharacterization(c) {
37     if (fCharacterization.isValid()) {
38         fContext = GrRecordingContextPriv::MakeDDL(fCharacterization.refContextInfo());
39     }
40 }
41 
~GrDeferredDisplayListRecorder()42 GrDeferredDisplayListRecorder::~GrDeferredDisplayListRecorder() {
43     if (fContext) {
44         auto proxyProvider = fContext->priv().proxyProvider();
45 
46         // This allows the uniquely keyed proxies to keep their keys but removes their back
47         // pointer to the about-to-be-deleted proxy provider. The proxies will use their
48         // unique key to reattach to cached versions of themselves or to appropriately tag new
49         // resources (if a cached version was not found). This system operates independent of
50         // the replaying context's proxy provider (i.e., these uniquely keyed proxies will not
51         // appear in the replaying proxy providers uniquely keyed proxy map). This should be fine
52         // since no one else should be trying to reconnect to the orphaned proxies and orphaned
53         // proxies from different DDLs that share the same key should simply reconnect to the
54         // same cached resource.
55         proxyProvider->orphanAllUniqueKeys();
56     }
57 }
58 
init()59 bool GrDeferredDisplayListRecorder::init() {
60     SkASSERT(fContext);
61     SkASSERT(!fTargetProxy);
62     SkASSERT(!fLazyProxyData);
63     SkASSERT(!fSurface);
64 
65     if (!fCharacterization.isValid()) {
66         return false;
67     }
68 
69     fLazyProxyData = sk_sp<GrDeferredDisplayList::LazyProxyData>(
70                                                     new GrDeferredDisplayList::LazyProxyData);
71 
72     auto proxyProvider = fContext->priv().proxyProvider();
73     const GrCaps* caps = fContext->priv().caps();
74 
75     bool usesGLFBO0 = fCharacterization.usesGLFBO0();
76     if (usesGLFBO0) {
77         if (GrBackendApi::kOpenGL != fContext->backend() ||
78             fCharacterization.isTextureable()) {
79             return false;
80         }
81     }
82 
83     bool vkRTSupportsInputAttachment = fCharacterization.vkRTSupportsInputAttachment();
84     if (vkRTSupportsInputAttachment && GrBackendApi::kVulkan != fContext->backend()) {
85         return false;
86     }
87 
88     if (fCharacterization.vulkanSecondaryCBCompatible()) {
89         // Because of the restrictive API allowed for a GrVkSecondaryCBDrawContext, we know ahead
90         // of time that we don't be able to support certain parameter combinations. Specifically we
91         // fail on usesGLFBO0 since we can't mix GL and Vulkan. We can't have a texturable object.
92         // We can't use it as in input attachment since we don't control the render pass this will
93         // be played into and thus can't force it to have an input attachment and the correct
94         // dependencies. And finally the GrVkSecondaryCBDrawContext always assumes a top left
95         // origin.
96         if (usesGLFBO0 ||
97             vkRTSupportsInputAttachment ||
98             fCharacterization.isTextureable() ||
99             fCharacterization.origin() == kBottomLeft_GrSurfaceOrigin) {
100             return false;
101         }
102     }
103 
104     GrColorType grColorType = SkColorTypeToGrColorType(fCharacterization.colorType());
105 
106     // What we're doing here is we're creating a lazy proxy to back the SkSurface. The lazy
107     // proxy, when instantiated, will use the GrRenderTarget that backs the SkSurface that the
108     // DDL is being replayed into.
109 
110     GrInternalSurfaceFlags surfaceFlags = GrInternalSurfaceFlags::kNone;
111     if (usesGLFBO0) {
112         surfaceFlags |= GrInternalSurfaceFlags::kGLRTFBOIDIs0;
113     } else if (fCharacterization.sampleCount() > 1 && !caps->msaaResolvesAutomatically() &&
114                fCharacterization.isTextureable()) {
115         surfaceFlags |= GrInternalSurfaceFlags::kRequiresManualMSAAResolve;
116     }
117 
118     if (vkRTSupportsInputAttachment) {
119         surfaceFlags |= GrInternalSurfaceFlags::kVkRTSupportsInputAttachment;
120     }
121 
122     // FIXME: Why do we use skgpu::Mipmapped::kNo instead of
123     // GrSurfaceCharacterization::fIsMipMapped?
124     static constexpr GrProxyProvider::TextureInfo kTextureInfo{skgpu::Mipmapped::kNo,
125                                                                GrTextureType::k2D};
126     const GrProxyProvider::TextureInfo* optionalTextureInfo = nullptr;
127     if (fCharacterization.isTextureable()) {
128         optionalTextureInfo = &kTextureInfo;
129     }
130 
131     fTargetProxy = proxyProvider->createLazyRenderTargetProxy(
132             [lazyProxyData = fLazyProxyData](GrResourceProvider* resourceProvider,
133                                              const GrSurfaceProxy::LazySurfaceDesc&) {
134                 // The proxy backing the destination surface had better have been instantiated
135                 // prior to this one (i.e., the proxy backing the DDL's surface).
136                 // Fulfill this lazy proxy with the destination surface's GrRenderTarget.
137                 SkASSERT(lazyProxyData->fReplayDest->peekSurface());
138                 auto surface = sk_ref_sp<GrSurface>(lazyProxyData->fReplayDest->peekSurface());
139                 return GrSurfaceProxy::LazyCallbackResult(std::move(surface));
140             },
141             fCharacterization.backendFormat(),
142             fCharacterization.dimensions(),
143             fCharacterization.sampleCount(),
144             surfaceFlags,
145             optionalTextureInfo,
146             GrMipmapStatus::kNotAllocated,
147             SkBackingFit::kExact,
148             skgpu::Budgeted::kYes,
149             fCharacterization.isProtected(),
150             fCharacterization.vulkanSecondaryCBCompatible(),
151             GrSurfaceProxy::UseAllocator::kYes);
152 
153     if (!fTargetProxy) {
154         return false;
155     }
156     fTargetProxy->priv().setIsDDLTarget();
157 
158     auto device = fContext->priv().createDevice(grColorType,
159                                                 fTargetProxy,
160                                                 fCharacterization.refColorSpace(),
161                                                 fCharacterization.origin(),
162                                                 fCharacterization.surfaceProps(),
163                                                 skgpu::ganesh::Device::InitContents::kUninit);
164     if (!device) {
165         return false;
166     }
167 
168     fSurface = sk_make_sp<SkSurface_Ganesh>(std::move(device));
169     return SkToBool(fSurface.get());
170 }
171 
getCanvas()172 SkCanvas* GrDeferredDisplayListRecorder::getCanvas() {
173     if (!fContext) {
174         return nullptr;
175     }
176 
177     if (!fSurface && !this->init()) {
178         return nullptr;
179     }
180 
181     return fSurface->getCanvas();
182 }
183 
detach()184 sk_sp<GrDeferredDisplayList> GrDeferredDisplayListRecorder::detach() {
185     if (!fContext || !fTargetProxy) {
186         return nullptr;
187     }
188 
189     if (fSurface) {
190         SkCanvas* canvas = fSurface->getCanvas();
191 
192         canvas->restoreToCount(0);
193     }
194 
195     auto ddl = sk_sp<GrDeferredDisplayList>(new GrDeferredDisplayList(fCharacterization,
196                                                                       std::move(fTargetProxy),
197                                                                       std::move(fLazyProxyData)));
198 
199     fContext->priv().moveRenderTasksToDDL(ddl.get());
200 
201     // We want a new lazy proxy target for each recorded DDL so force the (lazy proxy-backed)
202     // SkSurface to be regenerated for each DDL.
203     fSurface = nullptr;
204     return ddl;
205 }
206