1/*
2 * Copyright 2017 Google Inc.
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 "SkDeferredDisplayListRecorder.h"
9
10#if SK_SUPPORT_GPU
11#include "GrContextPriv.h"
12#include "GrProxyProvider.h"
13#include "GrTexture.h"
14
15#include "SkGpuDevice.h"
16#include "SkGr.h"
17#include "SkSurface_Gpu.h"
18#endif
19
20#include "SkCanvas.h" // TODO: remove
21#include "SkDeferredDisplayList.h"
22#include "SkSurface.h"
23#include "SkSurfaceCharacterization.h"
24
25SkDeferredDisplayListRecorder::SkDeferredDisplayListRecorder(
26                    const SkSurfaceCharacterization& characterization)
27        : fCharacterization(characterization) {
28}
29
30SkDeferredDisplayListRecorder::~SkDeferredDisplayListRecorder() {
31#if SK_SUPPORT_GPU && !defined(SK_RASTER_RECORDER_IMPLEMENTATION)
32    auto proxyProvider = fContext->contextPriv().proxyProvider();
33
34    // DDL TODO: Remove this. DDL contexts should allow for deletion while still having live
35    // uniquely keyed proxies.
36    proxyProvider->removeAllUniqueKeys();
37#endif
38}
39
40
41bool SkDeferredDisplayListRecorder::init() {
42    SkASSERT(!fSurface);
43
44    if (!fCharacterization.isValid()) {
45        return false;
46    }
47
48#ifdef SK_RASTER_RECORDER_IMPLEMENTATION
49    // Use raster right now to allow threading
50    const SkImageInfo ii = SkImageInfo::Make(fCharacterization.width(), fCharacterization.height(),
51                                             kN32_SkColorType, kOpaque_SkAlphaType,
52                                             fCharacterization.refColorSpace());
53
54    fSurface = SkSurface::MakeRaster(ii, &fCharacterization.surfaceProps());
55    return SkToBool(fSurface.get());
56#else
57    SkASSERT(!fLazyProxyData);
58
59#if SK_SUPPORT_GPU
60    if (!fContext) {
61        fContext = GrContextPriv::MakeDDL(fCharacterization.refContextInfo());
62        if (!fContext) {
63            return false;
64        }
65    }
66
67    fLazyProxyData = sk_sp<SkDeferredDisplayList::LazyProxyData>(
68                                                    new SkDeferredDisplayList::LazyProxyData);
69
70    auto proxyProvider = fContext->contextPriv().proxyProvider();
71
72    GrSurfaceDesc desc;
73    desc.fFlags = kRenderTarget_GrSurfaceFlag;
74    desc.fOrigin = fCharacterization.origin();
75    desc.fWidth = fCharacterization.width();
76    desc.fHeight = fCharacterization.height();
77    desc.fConfig = fCharacterization.config();
78    desc.fSampleCnt = fCharacterization.stencilCount();
79
80    sk_sp<SkDeferredDisplayList::LazyProxyData> lazyProxyData = fLazyProxyData;
81
82    // What we're doing here is we're creating a lazy proxy to back the SkSurface. The lazy
83    // proxy, when instantiated, will use the GrRenderTarget that backs the SkSurface that the
84    // DDL is being replayed into.
85
86    sk_sp<GrRenderTargetProxy> proxy = proxyProvider->createLazyRenderTargetProxy(
87            [ lazyProxyData ] (GrResourceProvider* resourceProvider) {
88                if (!resourceProvider) {
89                    return sk_sp<GrSurface>();
90                }
91
92                // The proxy backing the destination surface had better have been instantiated
93                // prior to the proxy backing the DLL's surface. Steal its GrRenderTarget.
94                SkASSERT(lazyProxyData->fReplayDest->priv().peekSurface());
95                return sk_ref_sp<GrSurface>(lazyProxyData->fReplayDest->priv().peekSurface());
96            },
97            desc,
98            GrRenderTargetFlags::kNone,
99            GrProxyProvider::Textureable(fCharacterization.isTextureable()),
100            GrMipMapped::kNo,
101            SkBackingFit::kExact,
102            SkBudgeted::kYes);
103
104    sk_sp<GrSurfaceContext> c = fContext->contextPriv().makeWrappedSurfaceContext(
105                                                                 std::move(proxy),
106                                                                 fCharacterization.refColorSpace(),
107                                                                 &fCharacterization.surfaceProps());
108    fSurface = SkSurface_Gpu::MakeWrappedRenderTarget(fContext.get(),
109                                                      sk_ref_sp(c->asRenderTargetContext()));
110    return SkToBool(fSurface.get());
111#else
112    return false;
113#endif
114
115#endif
116}
117
118SkCanvas* SkDeferredDisplayListRecorder::getCanvas() {
119    if (!fSurface) {
120        if (!this->init()) {
121            return nullptr;
122        }
123    }
124
125    return fSurface->getCanvas();
126}
127
128std::unique_ptr<SkDeferredDisplayList> SkDeferredDisplayListRecorder::detach() {
129#ifdef SK_RASTER_RECORDER_IMPLEMENTATION
130    sk_sp<SkImage> img = fSurface->makeImageSnapshot();
131    fSurface.reset();
132
133    // TODO: need to wrap the opLists associated with the deferred draws
134    // in the SkDeferredDisplayList.
135    return std::unique_ptr<SkDeferredDisplayList>(
136                            new SkDeferredDisplayList(fCharacterization, std::move(img)));
137#else
138
139#if SK_SUPPORT_GPU
140    auto ddl = std::unique_ptr<SkDeferredDisplayList>(
141                           new SkDeferredDisplayList(fCharacterization, std::move(fLazyProxyData)));
142
143    fContext->contextPriv().moveOpListsToDDL(ddl.get());
144    return ddl;
145#else
146    return nullptr;
147#endif
148
149#endif // SK_RASTER_RECORDER_IMPLEMENTATION
150
151}
152
153