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#ifdef SK_RASTER_RECORDER_IMPLEMENTATION
45    // Use raster right now to allow threading
46    const SkImageInfo ii = SkImageInfo::Make(fCharacterization.width(), fCharacterization.height(),
47                                             kN32_SkColorType, kOpaque_SkAlphaType,
48                                             fCharacterization.refColorSpace());
49
50    fSurface = SkSurface::MakeRaster(ii, &fCharacterization.surfaceProps());
51    return SkToBool(fSurface.get());
52#else
53    SkASSERT(!fLazyProxyData);
54
55#if SK_SUPPORT_GPU
56    if (!fContext) {
57        fContext = GrContextPriv::MakeDDL(fCharacterization.contextInfo());
58        if (!fContext) {
59            return false;
60        }
61    }
62
63    fLazyProxyData = sk_sp<SkDeferredDisplayList::LazyProxyData>(
64                                                    new SkDeferredDisplayList::LazyProxyData);
65
66    auto proxyProvider = fContext->contextPriv().proxyProvider();
67
68    GrSurfaceDesc desc;
69    desc.fFlags = kRenderTarget_GrSurfaceFlag;
70    desc.fOrigin = fCharacterization.origin();
71    desc.fWidth = fCharacterization.width();
72    desc.fHeight = fCharacterization.height();
73    desc.fConfig = fCharacterization.config();
74    desc.fSampleCnt = fCharacterization.stencilCount();
75
76    sk_sp<SkDeferredDisplayList::LazyProxyData> lazyProxyData = fLazyProxyData;
77
78    // What we're doing here is we're creating a lazy proxy to back the SkSurface. The lazy
79    // proxy, when instantiated, will use the GrTexture that backs the SkSurface that the
80    // DDL is being replayed into.
81
82    sk_sp<GrSurfaceProxy> proxy = proxyProvider->createLazyProxy(
83        [ lazyProxyData ] (GrResourceProvider* resourceProvider, GrSurfaceOrigin* /* outOrigin */) {
84            if (!resourceProvider) {
85                return sk_sp<GrTexture>();
86            }
87
88            // The proxy backing the destination surface had better have been instantiated
89            // prior to the proxy backing the DLL's surface. Steal its GrTexture.
90            // DDL TODO: What do we do in the case where the Surface we're replaying into
91            // isn't texturable?
92            SkASSERT(lazyProxyData->fReplayDest->priv().peekTexture());
93            return sk_ref_sp<GrTexture>(lazyProxyData->fReplayDest->priv().peekTexture());
94        }, desc, GrMipMapped::kNo, SkBackingFit::kExact, SkBudgeted::kYes);
95
96    sk_sp<GrSurfaceContext> c = fContext->contextPriv().makeWrappedSurfaceContext(
97                                                                 std::move(proxy),
98                                                                 fCharacterization.refColorSpace(),
99                                                                 &fCharacterization.surfaceProps());
100    fSurface = SkSurface_Gpu::MakeWrappedRenderTarget(fContext.get(),
101                                                      sk_ref_sp(c->asRenderTargetContext()));
102    return SkToBool(fSurface.get());
103#else
104    return false;
105#endif
106
107#endif
108}
109
110SkCanvas* SkDeferredDisplayListRecorder::getCanvas() {
111    if (!fSurface) {
112        if (!this->init()) {
113            return nullptr;
114        }
115    }
116
117    return fSurface->getCanvas();
118}
119
120std::unique_ptr<SkDeferredDisplayList> SkDeferredDisplayListRecorder::detach() {
121#ifdef SK_RASTER_RECORDER_IMPLEMENTATION
122    sk_sp<SkImage> img = fSurface->makeImageSnapshot();
123    fSurface.reset();
124
125    // TODO: need to wrap the opLists associated with the deferred draws
126    // in the SkDeferredDisplayList.
127    return std::unique_ptr<SkDeferredDisplayList>(
128                            new SkDeferredDisplayList(fCharacterization, std::move(img)));
129#else
130
131#if SK_SUPPORT_GPU
132    auto ddl = std::unique_ptr<SkDeferredDisplayList>(
133                           new SkDeferredDisplayList(fCharacterization, std::move(fLazyProxyData)));
134
135    fContext->contextPriv().moveOpListsToDDL(ddl.get());
136    return ddl;
137#else
138    return nullptr;
139#endif
140
141#endif // SK_RASTER_RECORDER_IMPLEMENTATION
142
143}
144
145