1 /*
2 * Copyright 2019 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 "src/gpu/vk/GrVkSecondaryCBDrawContext.h"
9
10 #include "include/core/SkDeferredDisplayList.h"
11 #include "include/core/SkImageInfo.h"
12 #include "include/core/SkSurfaceCharacterization.h"
13 #include "include/gpu/GrDirectContext.h"
14 #include "include/gpu/GrRecordingContext.h"
15 #include "include/gpu/vk/GrVkTypes.h"
16 #include "src/core/SkSurfacePriv.h"
17 #include "src/gpu/GrContextThreadSafeProxyPriv.h"
18 #include "src/gpu/GrDirectContextPriv.h"
19 #include "src/gpu/GrProxyProvider.h"
20 #include "src/gpu/GrRecordingContextPriv.h"
21 #include "src/gpu/GrRenderTargetProxy.h"
22 #include "src/gpu/GrSurfaceProxyView.h"
23
Make(GrRecordingContext * rContext,const SkImageInfo & imageInfo,const GrVkDrawableInfo & vkInfo,const SkSurfaceProps * props)24 sk_sp<GrVkSecondaryCBDrawContext> GrVkSecondaryCBDrawContext::Make(GrRecordingContext* rContext,
25 const SkImageInfo& imageInfo,
26 const GrVkDrawableInfo& vkInfo,
27 const SkSurfaceProps* props) {
28 if (!rContext) {
29 return nullptr;
30 }
31
32 if (rContext->backend() != GrBackendApi::kVulkan) {
33 return nullptr;
34 }
35
36 sk_sp<GrSurfaceProxy> proxy(
37 rContext->priv().proxyProvider()->wrapVulkanSecondaryCBAsRenderTarget(imageInfo,
38 vkInfo));
39 if (!proxy) {
40 return nullptr;
41 }
42
43 SkASSERT(proxy->isInstantiated());
44
45 auto device = rContext->priv().createDevice(SkColorTypeToGrColorType(imageInfo.colorType()),
46 std::move(proxy),
47 imageInfo.refColorSpace(),
48 kTopLeft_GrSurfaceOrigin,
49 SkSurfacePropsCopyOrDefault(props),
50 skgpu::BaseDevice::InitContents::kUninit);
51 if (!device) {
52 return nullptr;
53 }
54
55 return sk_sp<GrVkSecondaryCBDrawContext>(new GrVkSecondaryCBDrawContext(std::move(device),
56 props));
57 }
58
GrVkSecondaryCBDrawContext(sk_sp<skgpu::BaseDevice> device,const SkSurfaceProps * props)59 GrVkSecondaryCBDrawContext::GrVkSecondaryCBDrawContext(sk_sp<skgpu::BaseDevice> device,
60 const SkSurfaceProps* props)
61 : fDevice(device)
62 , fProps(SkSurfacePropsCopyOrDefault(props)) {}
63
~GrVkSecondaryCBDrawContext()64 GrVkSecondaryCBDrawContext::~GrVkSecondaryCBDrawContext() {
65 SkASSERT(!fDevice);
66 SkASSERT(!fCachedCanvas.get());
67 }
68
getCanvas()69 SkCanvas* GrVkSecondaryCBDrawContext::getCanvas() {
70 if (!fCachedCanvas) {
71 fCachedCanvas = std::make_unique<SkCanvas>(fDevice);
72 }
73 return fCachedCanvas.get();
74 }
75
flush()76 void GrVkSecondaryCBDrawContext::flush() {
77 auto dContext = GrAsDirectContext(fDevice->recordingContext());
78
79 if (dContext) {
80 dContext->priv().flushSurface(fDevice->targetProxy());
81 dContext->submit();
82 }
83 }
84
wait(int numSemaphores,const GrBackendSemaphore waitSemaphores[],bool deleteSemaphoresAfterWait)85 bool GrVkSecondaryCBDrawContext::wait(int numSemaphores,
86 const GrBackendSemaphore waitSemaphores[],
87 bool deleteSemaphoresAfterWait) {
88 return fDevice->wait(numSemaphores, waitSemaphores, deleteSemaphoresAfterWait);
89 }
90
releaseResources()91 void GrVkSecondaryCBDrawContext::releaseResources() {
92 fCachedCanvas.reset();
93 fDevice.reset();
94 }
95
characterize(SkSurfaceCharacterization * characterization) const96 bool GrVkSecondaryCBDrawContext::characterize(SkSurfaceCharacterization* characterization) const {
97 auto direct = fDevice->recordingContext()->asDirectContext();
98 if (!direct) {
99 return false;
100 }
101
102 SkImageInfo ii = fDevice->imageInfo();
103 if (ii.colorType() == kUnknown_SkColorType) {
104 return false;
105 }
106
107 GrSurfaceProxyView readSurfaceView = fDevice->readSurfaceView();
108 size_t maxResourceBytes = direct->getResourceCacheLimit();
109
110 // We current don't support textured GrVkSecondaryCBDrawContexts.
111 SkASSERT(!readSurfaceView.asTextureProxy());
112
113 GrBackendFormat format = readSurfaceView.asRenderTargetProxy()->backendFormat();
114 int numSamples = readSurfaceView.asRenderTargetProxy()->numSamples();
115 GrProtected isProtected = readSurfaceView.asRenderTargetProxy()->isProtected();
116
117 characterization->set(direct->threadSafeProxy(),
118 maxResourceBytes,
119 ii,
120 format,
121 readSurfaceView.origin(),
122 numSamples,
123 SkSurfaceCharacterization::Textureable(false),
124 SkSurfaceCharacterization::MipMapped(false),
125 SkSurfaceCharacterization::UsesGLFBO0(false),
126 SkSurfaceCharacterization::VkRTSupportsInputAttachment(false),
127 SkSurfaceCharacterization::VulkanSecondaryCBCompatible(true),
128 isProtected,
129 this->props());
130
131 return true;
132 }
133
isCompatible(const SkSurfaceCharacterization & characterization) const134 bool GrVkSecondaryCBDrawContext::isCompatible(
135 const SkSurfaceCharacterization& characterization) const {
136
137 auto dContext = fDevice->recordingContext()->asDirectContext();
138 if (!dContext) {
139 return false;
140 }
141
142 if (!characterization.isValid()) {
143 return false;
144 }
145
146 if (!characterization.vulkanSecondaryCBCompatible()) {
147 return false;
148 }
149
150 if (characterization.isTextureable()) {
151 // We don't support textureable DDL when rendering to a GrVkSecondaryCBDrawContext.
152 return false;
153 }
154
155 if (characterization.usesGLFBO0()) {
156 return false;
157 }
158
159 SkImageInfo ii = fDevice->imageInfo();
160 if (ii.colorType() == kUnknown_SkColorType) {
161 return false;
162 }
163
164 GrSurfaceProxyView readSurfaceView = fDevice->readSurfaceView();
165 // As long as the current state in the context allows for greater or equal resources,
166 // we allow the DDL to be replayed.
167 // DDL TODO: should we just remove the resource check and ignore the cache limits on playback?
168 size_t maxResourceBytes = dContext->getResourceCacheLimit();
169
170 GrBackendFormat format = readSurfaceView.asRenderTargetProxy()->backendFormat();
171 int numSamples = readSurfaceView.asRenderTargetProxy()->numSamples();
172 GrProtected isProtected = readSurfaceView.asRenderTargetProxy()->isProtected();
173
174 return characterization.contextInfo() &&
175 characterization.contextInfo()->priv().matches(dContext) &&
176 characterization.cacheMaxResourceBytes() <= maxResourceBytes &&
177 characterization.origin() == readSurfaceView.origin() &&
178 characterization.backendFormat() == format &&
179 characterization.width() == ii.width() &&
180 characterization.height() == ii.height() &&
181 characterization.colorType() == ii.colorType() &&
182 characterization.sampleCount() == numSamples &&
183 SkColorSpace::Equals(characterization.colorSpace(), ii.colorInfo().colorSpace()) &&
184 characterization.isProtected() == isProtected &&
185 characterization.surfaceProps() == fDevice->surfaceProps();
186 }
187
188 #ifndef SK_DDL_IS_UNIQUE_POINTER
draw(sk_sp<const SkDeferredDisplayList> ddl)189 bool GrVkSecondaryCBDrawContext::draw(sk_sp<const SkDeferredDisplayList> ddl) {
190 #else
191 bool GrVkSecondaryCBDrawContext::draw(const SkDeferredDisplayList* ddl) {
192 #endif
193 if (!ddl || !this->isCompatible(ddl->characterization())) {
194 return false;
195 }
196
197 auto direct = fDevice->recordingContext()->asDirectContext();
198 if (!direct) {
199 return false;
200 }
201
202 GrSurfaceProxyView readSurfaceView = fDevice->readSurfaceView();
203
204 direct->priv().createDDLTask(std::move(ddl), readSurfaceView.asRenderTargetProxyRef(), {0, 0});
205 return true;
206 }
207