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 #include "SkMessageBus.h" 10 #include "SkDeferredDisplayList.h" 11 #include "SkSurface.h" 12 #include "SkSurfaceCharacterization.h" 13 14 #if !SK_SUPPORT_GPU 15 SkDeferredDisplayListRecorder::SkDeferredDisplayListRecorder(const SkSurfaceCharacterization&) {} 16 17 SkDeferredDisplayListRecorder::~SkDeferredDisplayListRecorder() {} 18 19 bool SkDeferredDisplayListRecorder::init() { return false; } 20 21 SkCanvas* SkDeferredDisplayListRecorder::getCanvas() { return nullptr; } 22 23 std::unique_ptr<SkDeferredDisplayList> SkDeferredDisplayListRecorder::detach() { return nullptr; } 24 25 sk_sp<SkImage> SkDeferredDisplayListRecorder::makePromiseTexture( 26 const GrBackendFormat& backendFormat, 27 int width, 28 int height, 29 GrMipMapped mipMapped, 30 GrSurfaceOrigin origin, 31 SkColorType colorType, 32 SkAlphaType alphaType, 33 sk_sp<SkColorSpace> colorSpace, 34 PromiseImageTextureFulfillProc textureFulfillProc, 35 PromiseImageTextureReleaseProc textureReleaseProc, 36 PromiseImageTextureDoneProc textureDoneProc, 37 PromiseImageTextureContext textureContext) { 38 return nullptr; 39 } 40 41 sk_sp<SkImage> SkDeferredDisplayListRecorder::makeYUVAPromiseTexture( 42 SkYUVColorSpace yuvColorSpace, 43 const GrBackendFormat yuvaFormats[], 44 const SkISize yuvaSizes[], 45 const SkYUVAIndex yuvaIndices[4], 46 int imageWidth, 47 int imageHeight, 48 GrSurfaceOrigin imageOrigin, 49 sk_sp<SkColorSpace> imageColorSpace, 50 PromiseImageTextureFulfillProc textureFulfillProc, 51 PromiseImageTextureReleaseProc textureReleaseProc, 52 PromiseImageTextureDoneProc textureDoneProc, 53 PromiseImageTextureContext textureContexts[]) { 54 return nullptr; 55 } 56 57 #else 58 59 #include "GrContextPriv.h" 60 #include "GrProxyProvider.h" 61 #include "GrRenderTargetContext.h" 62 #include "GrTexture.h" 63 #include "SkGr.h" 64 #include "SkImage_Gpu.h" 65 #include "SkImage_GpuYUVA.h" 66 #include "SkMakeUnique.h" 67 #include "SkPromiseImageTexture.h" 68 #include "SkSurface_Gpu.h" 69 #include "SkYUVASizeInfo.h" 70 71 SkDeferredDisplayListRecorder::SkDeferredDisplayListRecorder(const SkSurfaceCharacterization& c) 72 : fCharacterization(c) { 73 if (fCharacterization.isValid()) { 74 fContext = GrContextPriv::MakeDDL(fCharacterization.refContextInfo()); 75 } 76 } 77 78 SkDeferredDisplayListRecorder::~SkDeferredDisplayListRecorder() { 79 if (fContext) { 80 auto proxyProvider = fContext->priv().proxyProvider(); 81 82 // This allows the uniquely keyed proxies to keep their keys but removes their back 83 // pointer to the about-to-be-deleted proxy provider. The proxies will use their 84 // unique key to reattach to cached versions of themselves or to appropriately tag new 85 // resources (if a cached version was not found). This system operates independent of 86 // the replaying context's proxy provider (i.e., these uniquely keyed proxies will not 87 // appear in the replaying proxy providers uniquely keyed proxy map). This should be fine 88 // since no one else should be trying to reconnect to the orphaned proxies and orphaned 89 // proxies from different DDLs that share the same key should simply reconnect to the 90 // same cached resource. 91 proxyProvider->orphanAllUniqueKeys(); 92 } 93 } 94 95 96 bool SkDeferredDisplayListRecorder::init() { 97 SkASSERT(fContext); 98 SkASSERT(!fLazyProxyData); 99 SkASSERT(!fSurface); 100 101 if (!fCharacterization.isValid()) { 102 return false; 103 } 104 105 fLazyProxyData = sk_sp<SkDeferredDisplayList::LazyProxyData>( 106 new SkDeferredDisplayList::LazyProxyData); 107 108 auto proxyProvider = fContext->priv().proxyProvider(); 109 110 bool usesGLFBO0 = fCharacterization.usesGLFBO0(); 111 if (usesGLFBO0) { 112 if (GrBackendApi::kOpenGL != fContext->backend() || 113 fCharacterization.isTextureable()) { 114 return false; 115 } 116 } 117 118 if (fCharacterization.vulkanSecondaryCBCompatible()) { 119 // Because of the restrictive API allowed for a GrVkSecondaryCBDrawContext, we know ahead 120 // of time that we don't be able to support certain parameter combinations. Specifially we 121 // fail on usesGLFBO0 since we can't mix GL and Vulkan. We can't have a texturable object. 122 // And finally the GrVkSecondaryCBDrawContext always assumes a top left origin. 123 if (usesGLFBO0 || 124 fCharacterization.isTextureable() || 125 fCharacterization.origin() == kBottomLeft_GrSurfaceOrigin) { 126 return false; 127 } 128 } 129 130 GrSurfaceDesc desc; 131 desc.fFlags = kRenderTarget_GrSurfaceFlag; 132 desc.fWidth = fCharacterization.width(); 133 desc.fHeight = fCharacterization.height(); 134 desc.fConfig = fCharacterization.config(); 135 desc.fSampleCnt = fCharacterization.stencilCount(); 136 137 sk_sp<SkDeferredDisplayList::LazyProxyData> lazyProxyData = fLazyProxyData; 138 139 // What we're doing here is we're creating a lazy proxy to back the SkSurface. The lazy 140 // proxy, when instantiated, will use the GrRenderTarget that backs the SkSurface that the 141 // DDL is being replayed into. 142 143 GrInternalSurfaceFlags surfaceFlags = GrInternalSurfaceFlags::kNone; 144 if (fContext->priv().caps()->usesMixedSamples() && desc.fSampleCnt > 1 && !usesGLFBO0) { 145 // In GL, FBO 0 never supports mixed samples 146 surfaceFlags |= GrInternalSurfaceFlags::kMixedSampled; 147 } 148 if (usesGLFBO0) { 149 surfaceFlags |= GrInternalSurfaceFlags::kGLRTFBOIDIs0; 150 } 151 static constexpr GrProxyProvider::TextureInfo kTextureInfo{GrMipMapped::kNo, 152 GrTextureType::k2D}; 153 const GrProxyProvider::TextureInfo* optionalTextureInfo = nullptr; 154 if (fCharacterization.isTextureable()) { 155 optionalTextureInfo = &kTextureInfo; 156 } 157 158 const GrBackendFormat format = fContext->priv().caps()->getBackendFormatFromColorType( 159 fCharacterization.colorType()); 160 161 sk_sp<GrRenderTargetProxy> proxy = proxyProvider->createLazyRenderTargetProxy( 162 [lazyProxyData](GrResourceProvider* resourceProvider) { 163 if (!resourceProvider) { 164 return sk_sp<GrSurface>(); 165 } 166 167 // The proxy backing the destination surface had better have been instantiated 168 // prior to the proxy backing the DLL's surface. Steal its GrRenderTarget. 169 SkASSERT(lazyProxyData->fReplayDest->peekSurface()); 170 return sk_ref_sp<GrSurface>(lazyProxyData->fReplayDest->peekSurface()); 171 }, 172 format, 173 desc, 174 fCharacterization.origin(), 175 surfaceFlags, 176 optionalTextureInfo, 177 SkBackingFit::kExact, 178 SkBudgeted::kYes, 179 fCharacterization.vulkanSecondaryCBCompatible()); 180 181 sk_sp<GrSurfaceContext> c = fContext->priv().makeWrappedSurfaceContext( 182 std::move(proxy), 183 fCharacterization.refColorSpace(), 184 &fCharacterization.surfaceProps()); 185 fSurface = SkSurface_Gpu::MakeWrappedRenderTarget(fContext.get(), 186 sk_ref_sp(c->asRenderTargetContext())); 187 return SkToBool(fSurface.get()); 188 } 189 190 SkCanvas* SkDeferredDisplayListRecorder::getCanvas() { 191 if (!fContext) { 192 return nullptr; 193 } 194 195 if (!fSurface && !this->init()) { 196 return nullptr; 197 } 198 199 return fSurface->getCanvas(); 200 } 201 202 std::unique_ptr<SkDeferredDisplayList> SkDeferredDisplayListRecorder::detach() { 203 if (!fContext) { 204 return nullptr; 205 } 206 207 if (fSurface) { 208 SkCanvas* canvas = fSurface->getCanvas(); 209 210 canvas->restoreToCount(0); 211 } 212 213 auto ddl = std::unique_ptr<SkDeferredDisplayList>( 214 new SkDeferredDisplayList(fCharacterization, std::move(fLazyProxyData))); 215 216 fContext->priv().moveOpListsToDDL(ddl.get()); 217 218 // We want a new lazy proxy target for each recorded DDL so force the (lazy proxy-backed) 219 // SkSurface to be regenerated for each DDL. 220 fSurface = nullptr; 221 return ddl; 222 } 223 224 sk_sp<SkImage> SkDeferredDisplayListRecorder::makePromiseTexture( 225 const GrBackendFormat& backendFormat, 226 int width, 227 int height, 228 GrMipMapped mipMapped, 229 GrSurfaceOrigin origin, 230 SkColorType colorType, 231 SkAlphaType alphaType, 232 sk_sp<SkColorSpace> colorSpace, 233 PromiseImageTextureFulfillProc textureFulfillProc, 234 PromiseImageTextureReleaseProc textureReleaseProc, 235 PromiseImageTextureDoneProc textureDoneProc, 236 PromiseImageTextureContext textureContext) { 237 if (!fContext) { 238 return nullptr; 239 } 240 241 return SkImage_Gpu::MakePromiseTexture(fContext.get(), 242 backendFormat, 243 width, 244 height, 245 mipMapped, 246 origin, 247 colorType, 248 alphaType, 249 std::move(colorSpace), 250 textureFulfillProc, 251 textureReleaseProc, 252 textureDoneProc, 253 textureContext); 254 } 255 256 sk_sp<SkImage> SkDeferredDisplayListRecorder::makeYUVAPromiseTexture( 257 SkYUVColorSpace yuvColorSpace, 258 const GrBackendFormat yuvaFormats[], 259 const SkISize yuvaSizes[], 260 const SkYUVAIndex yuvaIndices[4], 261 int imageWidth, 262 int imageHeight, 263 GrSurfaceOrigin imageOrigin, 264 sk_sp<SkColorSpace> imageColorSpace, 265 PromiseImageTextureFulfillProc textureFulfillProc, 266 PromiseImageTextureReleaseProc textureReleaseProc, 267 PromiseImageTextureDoneProc textureDoneProc, 268 PromiseImageTextureContext textureContexts[]) { 269 if (!fContext) { 270 return nullptr; 271 } 272 273 return SkImage_GpuYUVA::MakePromiseYUVATexture(fContext.get(), 274 yuvColorSpace, 275 yuvaFormats, 276 yuvaSizes, 277 yuvaIndices, 278 imageWidth, 279 imageHeight, 280 imageOrigin, 281 std::move(imageColorSpace), 282 textureFulfillProc, 283 textureReleaseProc, 284 textureDoneProc, 285 textureContexts); 286 } 287 288 #endif 289