summaryrefslogtreecommitdiffstats
path: root/gfx/skia/skia/src/core/SkDeferredDisplayListRecorder.cpp
blob: 91080bd1a3f92dc99260a4c53e55708a37265906 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
/*
 * Copyright 2017 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "include/core/SkDeferredDisplayListRecorder.h"

#include "include/core/SkDeferredDisplayList.h"
#include "include/core/SkSurface.h"
#include "include/core/SkSurfaceCharacterization.h"
#include "src/core/SkMessageBus.h"

#if !defined(SK_GANESH)
SkDeferredDisplayListRecorder::SkDeferredDisplayListRecorder(const SkSurfaceCharacterization&) {}

SkDeferredDisplayListRecorder::~SkDeferredDisplayListRecorder() {}

bool SkDeferredDisplayListRecorder::init() { return false; }

SkCanvas* SkDeferredDisplayListRecorder::getCanvas() { return nullptr; }

sk_sp<SkDeferredDisplayList> SkDeferredDisplayListRecorder::detach() { return nullptr; }

#else

#include "include/core/SkPromiseImageTexture.h"
#include "include/gpu/GrRecordingContext.h"
#include "include/gpu/GrYUVABackendTextures.h"
#include "src/gpu/SkBackingFit.h"
#include "src/gpu/ganesh/GrCaps.h"
#include "src/gpu/ganesh/GrProxyProvider.h"
#include "src/gpu/ganesh/GrRecordingContextPriv.h"
#include "src/gpu/ganesh/GrRenderTargetProxy.h"
#include "src/gpu/ganesh/GrTexture.h"
#include "src/gpu/ganesh/SkGr.h"
#include "src/image/SkImage_Gpu.h"
#include "src/image/SkImage_GpuYUVA.h"
#include "src/image/SkSurface_Gpu.h"

SkDeferredDisplayListRecorder::SkDeferredDisplayListRecorder(const SkSurfaceCharacterization& c)
        : fCharacterization(c) {
    if (fCharacterization.isValid()) {
        fContext = GrRecordingContextPriv::MakeDDL(fCharacterization.refContextInfo());
    }
}

SkDeferredDisplayListRecorder::~SkDeferredDisplayListRecorder() {
    if (fContext) {
        auto proxyProvider = fContext->priv().proxyProvider();

        // This allows the uniquely keyed proxies to keep their keys but removes their back
        // pointer to the about-to-be-deleted proxy provider. The proxies will use their
        // unique key to reattach to cached versions of themselves or to appropriately tag new
        // resources (if a cached version was not found). This system operates independent of
        // the replaying context's proxy provider (i.e., these uniquely keyed proxies will not
        // appear in the replaying proxy providers uniquely keyed proxy map). This should be fine
        // since no one else should be trying to reconnect to the orphaned proxies and orphaned
        // proxies from different DDLs that share the same key should simply reconnect to the
        // same cached resource.
        proxyProvider->orphanAllUniqueKeys();
    }
}

bool SkDeferredDisplayListRecorder::init() {
    SkASSERT(fContext);
    SkASSERT(!fTargetProxy);
    SkASSERT(!fLazyProxyData);
    SkASSERT(!fSurface);

    if (!fCharacterization.isValid()) {
        return false;
    }

    fLazyProxyData = sk_sp<SkDeferredDisplayList::LazyProxyData>(
                                                    new SkDeferredDisplayList::LazyProxyData);

    auto proxyProvider = fContext->priv().proxyProvider();
    const GrCaps* caps = fContext->priv().caps();

    bool usesGLFBO0 = fCharacterization.usesGLFBO0();
    if (usesGLFBO0) {
        if (GrBackendApi::kOpenGL != fContext->backend() ||
            fCharacterization.isTextureable()) {
            return false;
        }
    }

    bool vkRTSupportsInputAttachment = fCharacterization.vkRTSupportsInputAttachment();
    if (vkRTSupportsInputAttachment && GrBackendApi::kVulkan != fContext->backend()) {
        return false;
    }

    if (fCharacterization.vulkanSecondaryCBCompatible()) {
        // Because of the restrictive API allowed for a GrVkSecondaryCBDrawContext, we know ahead
        // of time that we don't be able to support certain parameter combinations. Specifically we
        // fail on usesGLFBO0 since we can't mix GL and Vulkan. We can't have a texturable object.
        // We can't use it as in input attachment since we don't control the render pass this will
        // be played into and thus can't force it to have an input attachment and the correct
        // dependencies. And finally the GrVkSecondaryCBDrawContext always assumes a top left
        // origin.
        if (usesGLFBO0 ||
            vkRTSupportsInputAttachment ||
            fCharacterization.isTextureable() ||
            fCharacterization.origin() == kBottomLeft_GrSurfaceOrigin) {
            return false;
        }
    }

    GrColorType grColorType = SkColorTypeToGrColorType(fCharacterization.colorType());

    // What we're doing here is we're creating a lazy proxy to back the SkSurface. The lazy
    // proxy, when instantiated, will use the GrRenderTarget that backs the SkSurface that the
    // DDL is being replayed into.

    GrInternalSurfaceFlags surfaceFlags = GrInternalSurfaceFlags::kNone;
    if (usesGLFBO0) {
        surfaceFlags |= GrInternalSurfaceFlags::kGLRTFBOIDIs0;
    } else if (fCharacterization.sampleCount() > 1 && !caps->msaaResolvesAutomatically() &&
               fCharacterization.isTextureable()) {
        surfaceFlags |= GrInternalSurfaceFlags::kRequiresManualMSAAResolve;
    }

    if (vkRTSupportsInputAttachment) {
        surfaceFlags |= GrInternalSurfaceFlags::kVkRTSupportsInputAttachment;
    }

    // FIXME: Why do we use GrMipmapped::kNo instead of SkSurfaceCharacterization::fIsMipMapped?
    static constexpr GrProxyProvider::TextureInfo kTextureInfo{GrMipmapped::kNo,
                                                               GrTextureType::k2D};
    const GrProxyProvider::TextureInfo* optionalTextureInfo = nullptr;
    if (fCharacterization.isTextureable()) {
        optionalTextureInfo = &kTextureInfo;
    }

    fTargetProxy = proxyProvider->createLazyRenderTargetProxy(
            [lazyProxyData = fLazyProxyData](GrResourceProvider* resourceProvider,
                                             const GrSurfaceProxy::LazySurfaceDesc&) {
                // The proxy backing the destination surface had better have been instantiated
                // prior to this one (i.e., the proxy backing the DDL's surface).
                // Fulfill this lazy proxy with the destination surface's GrRenderTarget.
                SkASSERT(lazyProxyData->fReplayDest->peekSurface());
                auto surface = sk_ref_sp<GrSurface>(lazyProxyData->fReplayDest->peekSurface());
                return GrSurfaceProxy::LazyCallbackResult(std::move(surface));
            },
            fCharacterization.backendFormat(),
            fCharacterization.dimensions(),
            fCharacterization.sampleCount(),
            surfaceFlags,
            optionalTextureInfo,
            GrMipmapStatus::kNotAllocated,
            SkBackingFit::kExact,
            skgpu::Budgeted::kYes,
            fCharacterization.isProtected(),
            fCharacterization.vulkanSecondaryCBCompatible(),
            GrSurfaceProxy::UseAllocator::kYes);

    if (!fTargetProxy) {
        return false;
    }
    fTargetProxy->priv().setIsDDLTarget();

    auto device = fContext->priv().createDevice(grColorType,
                                                fTargetProxy,
                                                fCharacterization.refColorSpace(),
                                                fCharacterization.origin(),
                                                fCharacterization.surfaceProps(),
                                                skgpu::ganesh::Device::InitContents::kUninit);
    if (!device) {
        return false;
    }

    fSurface = sk_make_sp<SkSurface_Gpu>(std::move(device));
    return SkToBool(fSurface.get());
}

SkCanvas* SkDeferredDisplayListRecorder::getCanvas() {
    if (!fContext) {
        return nullptr;
    }

    if (!fSurface && !this->init()) {
        return nullptr;
    }

    return fSurface->getCanvas();
}

sk_sp<SkDeferredDisplayList> SkDeferredDisplayListRecorder::detach() {
    if (!fContext || !fTargetProxy) {
        return nullptr;
    }

    if (fSurface) {
        SkCanvas* canvas = fSurface->getCanvas();

        canvas->restoreToCount(0);
    }

    auto ddl = sk_sp<SkDeferredDisplayList>(new SkDeferredDisplayList(fCharacterization,
                                                                      std::move(fTargetProxy),
                                                                      std::move(fLazyProxyData)));

    fContext->priv().moveRenderTasksToDDL(ddl.get());

    // We want a new lazy proxy target for each recorded DDL so force the (lazy proxy-backed)
    // SkSurface to be regenerated for each DDL.
    fSurface = nullptr;
    return ddl;
}

#ifndef SK_MAKE_PROMISE_TEXTURE_DISABLE_LEGACY_API
sk_sp<SkImage> SkDeferredDisplayListRecorder::makePromiseTexture(
        const GrBackendFormat& backendFormat,
        int width,
        int height,
        GrMipmapped mipmapped,
        GrSurfaceOrigin origin,
        SkColorType colorType,
        SkAlphaType alphaType,
        sk_sp<SkColorSpace> colorSpace,
        PromiseImageTextureFulfillProc textureFulfillProc,
        PromiseImageTextureReleaseProc textureReleaseProc,
        PromiseImageTextureContext textureContext) {
    if (!fContext) {
        return nullptr;
    }
    return SkImage::MakePromiseTexture(fContext->threadSafeProxy(),
                                       backendFormat,
                                       {width, height},
                                       mipmapped,
                                       origin,
                                       colorType,
                                       alphaType,
                                       std::move(colorSpace),
                                       textureFulfillProc,
                                       textureReleaseProc,
                                       textureContext);
}

sk_sp<SkImage> SkDeferredDisplayListRecorder::makeYUVAPromiseTexture(
        const GrYUVABackendTextureInfo& backendTextureInfo,
        sk_sp<SkColorSpace> imageColorSpace,
        PromiseImageTextureFulfillProc textureFulfillProc,
        PromiseImageTextureReleaseProc textureReleaseProc,
        PromiseImageTextureContext textureContexts[]) {
    if (!fContext) {
        return nullptr;
    }
    return SkImage::MakePromiseYUVATexture(fContext->threadSafeProxy(),
                                           backendTextureInfo,
                                           std::move(imageColorSpace),
                                           textureFulfillProc,
                                           textureReleaseProc,
                                           textureContexts);
}
#endif // !SK_MAKE_PROMISE_TEXTURE_DISABLE_LEGACY_API

#endif