1/* 2 * Copyright 2015 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 "GrDrawingManager.h" 9 10#include "GrContext.h" 11#include "GrRenderTargetContext.h" 12#include "GrPathRenderingRenderTargetContext.h" 13#include "GrRenderTargetProxy.h" 14#include "GrResourceProvider.h" 15#include "GrSoftwarePathRenderer.h" 16#include "GrSurfacePriv.h" 17#include "GrTextureContext.h" 18#include "GrTextureOpList.h" 19#include "SkSurface_Gpu.h" 20#include "SkTTopoSort.h" 21 22#include "text/GrAtlasTextContext.h" 23#include "text/GrStencilAndCoverTextContext.h" 24 25void GrDrawingManager::cleanup() { 26 for (int i = 0; i < fOpLists.count(); ++i) { 27 fOpLists[i]->makeClosed(); // no opList should receive a new command after this 28 fOpLists[i]->clearTarget(); 29 30 // We shouldn't need to do this, but it turns out some clients still hold onto opLists 31 // after a cleanup 32 fOpLists[i]->reset(); 33 fOpLists[i]->unref(); 34 } 35 36 fOpLists.reset(); 37 38 delete fPathRendererChain; 39 fPathRendererChain = nullptr; 40 SkSafeSetNull(fSoftwarePathRenderer); 41} 42 43GrDrawingManager::~GrDrawingManager() { 44 this->cleanup(); 45} 46 47void GrDrawingManager::abandon() { 48 fAbandoned = true; 49 for (int i = 0; i < fOpLists.count(); ++i) { 50 fOpLists[i]->abandonGpuResources(); 51 } 52 this->cleanup(); 53} 54 55void GrDrawingManager::freeGpuResources() { 56 // a path renderer may be holding onto resources 57 delete fPathRendererChain; 58 fPathRendererChain = nullptr; 59 SkSafeSetNull(fSoftwarePathRenderer); 60 for (int i = 0; i < fOpLists.count(); ++i) { 61 fOpLists[i]->freeGpuResources(); 62 } 63} 64 65void GrDrawingManager::reset() { 66 for (int i = 0; i < fOpLists.count(); ++i) { 67 fOpLists[i]->reset(); 68 } 69 fFlushState.reset(); 70} 71 72void GrDrawingManager::internalFlush(GrResourceCache::FlushType type) { 73 if (fFlushing || this->wasAbandoned()) { 74 return; 75 } 76 fFlushing = true; 77 bool flushed = false; 78 79 for (int i = 0; i < fOpLists.count(); ++i) { 80 // Semi-usually the GrOpLists are already closed at this point, but sometimes Ganesh 81 // needs to flush mid-draw. In that case, the SkGpuDevice's GrOpLists won't be closed 82 // but need to be flushed anyway. Closing such GrOpLists here will mean new 83 // GrOpLists will be created to replace them if the SkGpuDevice(s) write to them again. 84 fOpLists[i]->makeClosed(); 85 } 86 87 SkDEBUGCODE(bool result =) 88 SkTTopoSort<GrOpList, GrOpList::TopoSortTraits>(&fOpLists); 89 SkASSERT(result); 90 91 GrPreFlushResourceProvider preFlushProvider(this); 92 93 if (fPreFlushCBObjects.count()) { 94 // MDB TODO: pre-MDB '1' is the correct pre-allocated size. Post-MDB it will need 95 // to be larger. 96 SkAutoSTArray<1, uint32_t> opListIds(fOpLists.count()); 97 for (int i = 0; i < fOpLists.count(); ++i) { 98 opListIds[i] = fOpLists[i]->uniqueID(); 99 } 100 101 SkSTArray<1, sk_sp<GrRenderTargetContext>> renderTargetContexts; 102 for (int i = 0; i < fPreFlushCBObjects.count(); ++i) { 103 fPreFlushCBObjects[i]->preFlush(&preFlushProvider, 104 opListIds.get(), opListIds.count(), 105 &renderTargetContexts); 106 if (!renderTargetContexts.count()) { 107 continue; // This is fine. No atlases of this type are required for this flush 108 } 109 110 for (int j = 0; j < renderTargetContexts.count(); ++j) { 111 GrRenderTargetOpList* opList = renderTargetContexts[j]->getOpList(); 112 if (!opList) { 113 continue; // Odd - but not a big deal 114 } 115 SkDEBUGCODE(opList->validateTargetsSingleRenderTarget()); 116 opList->prepareOps(&fFlushState); 117 if (!opList->executeOps(&fFlushState)) { 118 continue; // This is bad 119 } 120 } 121 renderTargetContexts.reset(); 122 } 123 } 124 125 for (int i = 0; i < fOpLists.count(); ++i) { 126 fOpLists[i]->prepareOps(&fFlushState); 127 } 128 129#if 0 130 // Enable this to print out verbose GrOp information 131 for (int i = 0; i < fOpLists.count(); ++i) { 132 SkDEBUGCODE(fOpLists[i]->dump();) 133 } 134#endif 135 136 // Upload all data to the GPU 137 fFlushState.preIssueDraws(); 138 139 for (int i = 0; i < fOpLists.count(); ++i) { 140 if (fOpLists[i]->executeOps(&fFlushState)) { 141 flushed = true; 142 } 143 } 144 145 SkASSERT(fFlushState.nextDrawToken() == fFlushState.nextTokenToFlush()); 146 147 for (int i = 0; i < fOpLists.count(); ++i) { 148 fOpLists[i]->reset(); 149#ifdef ENABLE_MDB 150 fOpLists[i]->unref(); 151#endif 152 } 153 154#ifndef ENABLE_MDB 155 // When MDB is disabled we keep reusing the same GrOpList 156 if (fOpLists.count()) { 157 SkASSERT(fOpLists.count() == 1); 158 // Clear out this flag so the topological sort's SkTTopoSort_CheckAllUnmarked check 159 // won't bark 160 fOpLists[0]->resetFlag(GrOpList::kWasOutput_Flag); 161 } 162#else 163 fOpLists.reset(); 164#endif 165 166 fFlushState.reset(); 167 // We always have to notify the cache when it requested a flush so it can reset its state. 168 if (flushed || type == GrResourceCache::FlushType::kCacheRequested) { 169 fContext->getResourceCache()->notifyFlushOccurred(type); 170 } 171 fFlushing = false; 172} 173 174void GrDrawingManager::prepareSurfaceForExternalIO(GrSurface* surface) { 175 if (this->wasAbandoned()) { 176 return; 177 } 178 SkASSERT(surface); 179 SkASSERT(surface->getContext() == fContext); 180 181 if (surface->surfacePriv().hasPendingIO()) { 182 this->flush(); 183 } 184 185 GrRenderTarget* rt = surface->asRenderTarget(); 186 if (fContext->getGpu() && rt) { 187 fContext->getGpu()->resolveRenderTarget(rt); 188 } 189} 190 191void GrDrawingManager::addPreFlushCallbackObject(sk_sp<GrPreFlushCallbackObject> preFlushCBObject) { 192 fPreFlushCBObjects.push_back(preFlushCBObject); 193} 194 195GrRenderTargetOpList* GrDrawingManager::newOpList(GrRenderTargetProxy* rtp) { 196 SkASSERT(fContext); 197 198#ifndef ENABLE_MDB 199 // When MDB is disabled we always just return the single GrOpList 200 if (fOpLists.count()) { 201 SkASSERT(fOpLists.count() == 1); 202 // In the non-MDB-world the same GrOpList gets reused for multiple render targets. 203 // Update this pointer so all the asserts are happy 204 rtp->setLastOpList(fOpLists[0]); 205 // DrawingManager gets the creation ref - this ref is for the caller 206 207 // TODO: although this is true right now it isn't cool 208 return SkRef((GrRenderTargetOpList*) fOpLists[0]); 209 } 210#endif 211 212 GrRenderTargetOpList* opList = new GrRenderTargetOpList(rtp, 213 fContext->getGpu(), 214 fContext->resourceProvider(), 215 fContext->getAuditTrail(), 216 fOptionsForOpLists); 217 218 *fOpLists.append() = opList; 219 220 // DrawingManager gets the creation ref - this ref is for the caller 221 return SkRef(opList); 222} 223 224GrTextureOpList* GrDrawingManager::newOpList(GrTextureProxy* textureProxy) { 225 SkASSERT(fContext); 226 227 GrTextureOpList* opList = new GrTextureOpList(textureProxy, fContext->getGpu(), 228 fContext->getAuditTrail()); 229 230#ifndef ENABLE_MDB 231 // When MDB is disabled we still create a new GrOpList, but don't store or ref it - we rely 232 // on the caller to immediately execute and free it. 233 return opList; 234#else 235 *fOpLists.append() = opList; 236 237 // Drawing manager gets the creation ref - this ref is for the caller 238 return SkRef(opList); 239#endif 240} 241 242GrAtlasTextContext* GrDrawingManager::getAtlasTextContext() { 243 if (!fAtlasTextContext) { 244 fAtlasTextContext.reset(GrAtlasTextContext::Create()); 245 } 246 247 return fAtlasTextContext.get(); 248} 249 250/* 251 * This method finds a path renderer that can draw the specified path on 252 * the provided target. 253 * Due to its expense, the software path renderer has split out so it can 254 * can be individually allowed/disallowed via the "allowSW" boolean. 255 */ 256GrPathRenderer* GrDrawingManager::getPathRenderer(const GrPathRenderer::CanDrawPathArgs& args, 257 bool allowSW, 258 GrPathRendererChain::DrawType drawType, 259 GrPathRenderer::StencilSupport* stencilSupport) { 260 261 if (!fPathRendererChain) { 262 fPathRendererChain = new GrPathRendererChain(fContext, fOptionsForPathRendererChain); 263 } 264 265 GrPathRenderer* pr = fPathRendererChain->getPathRenderer(args, drawType, stencilSupport); 266 if (!pr && allowSW) { 267 if (!fSoftwarePathRenderer) { 268 fSoftwarePathRenderer = 269 new GrSoftwarePathRenderer(fContext->resourceProvider(), 270 fOptionsForPathRendererChain.fAllowPathMaskCaching); 271 } 272 if (fSoftwarePathRenderer->canDrawPath(args)) { 273 pr = fSoftwarePathRenderer; 274 } 275 } 276 277 return pr; 278} 279 280sk_sp<GrRenderTargetContext> GrDrawingManager::makeRenderTargetContext( 281 sk_sp<GrSurfaceProxy> sProxy, 282 sk_sp<SkColorSpace> colorSpace, 283 const SkSurfaceProps* surfaceProps) { 284 if (this->wasAbandoned() || !sProxy->asRenderTargetProxy()) { 285 return nullptr; 286 } 287 288 // SkSurface catches bad color space usage at creation. This check handles anything that slips 289 // by, including internal usage. We allow a null color space here, for read/write pixels and 290 // other special code paths. If a color space is provided, though, enforce all other rules. 291 if (colorSpace && !SkSurface_Gpu::Valid(fContext, sProxy->config(), colorSpace.get())) { 292 SkDEBUGFAIL("Invalid config and colorspace combination"); 293 return nullptr; 294 } 295 296 sk_sp<GrRenderTargetProxy> rtp(sk_ref_sp(sProxy->asRenderTargetProxy())); 297 298 bool useDIF = false; 299 if (surfaceProps) { 300 useDIF = surfaceProps->isUseDeviceIndependentFonts(); 301 } 302 303 if (useDIF && fContext->caps()->shaderCaps()->pathRenderingSupport() && 304 rtp->isStencilBufferMultisampled()) { 305 // TODO: defer stencil buffer attachment for PathRenderingDrawContext 306 sk_sp<GrRenderTarget> rt(sk_ref_sp(rtp->instantiate(fContext->resourceProvider()))); 307 if (!rt) { 308 return nullptr; 309 } 310 GrStencilAttachment* sb = fContext->resourceProvider()->attachStencilAttachment(rt.get()); 311 if (sb) { 312 return sk_sp<GrRenderTargetContext>(new GrPathRenderingRenderTargetContext( 313 fContext, this, std::move(rtp), 314 std::move(colorSpace), surfaceProps, 315 fContext->getAuditTrail(), fSingleOwner)); 316 } 317 } 318 319 return sk_sp<GrRenderTargetContext>(new GrRenderTargetContext(fContext, this, std::move(rtp), 320 std::move(colorSpace), 321 surfaceProps, 322 fContext->getAuditTrail(), 323 fSingleOwner)); 324} 325 326sk_sp<GrTextureContext> GrDrawingManager::makeTextureContext(sk_sp<GrSurfaceProxy> sProxy, 327 sk_sp<SkColorSpace> colorSpace) { 328 if (this->wasAbandoned() || !sProxy->asTextureProxy()) { 329 return nullptr; 330 } 331 332 // SkSurface catches bad color space usage at creation. This check handles anything that slips 333 // by, including internal usage. We allow a null color space here, for read/write pixels and 334 // other special code paths. If a color space is provided, though, enforce all other rules. 335 if (colorSpace && !SkSurface_Gpu::Valid(fContext, sProxy->config(), colorSpace.get())) { 336 SkDEBUGFAIL("Invalid config and colorspace combination"); 337 return nullptr; 338 } 339 340 // GrTextureRenderTargets should always be using GrRenderTargetContext 341 SkASSERT(!sProxy->asRenderTargetProxy()); 342 343 sk_sp<GrTextureProxy> textureProxy(sk_ref_sp(sProxy->asTextureProxy())); 344 345 return sk_sp<GrTextureContext>(new GrTextureContext(fContext, this, std::move(textureProxy), 346 std::move(colorSpace), 347 fContext->getAuditTrail(), 348 fSingleOwner)); 349} 350