1 /*
2  * Copyright 2019 Google LLC
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/GrTextureResolveRenderTask.h"
9 
10 #include "src/gpu/GrGpu.h"
11 #include "src/gpu/GrMemoryPool.h"
12 #include "src/gpu/GrOpFlushState.h"
13 #include "src/gpu/GrRenderTarget.h"
14 #include "src/gpu/GrResourceAllocator.h"
15 #include "src/gpu/GrTexture.h"
16 
addProxy(GrDrawingManager * drawingMgr,sk_sp<GrSurfaceProxy> proxyRef,GrSurfaceProxy::ResolveFlags flags,const GrCaps & caps)17 void GrTextureResolveRenderTask::addProxy(GrDrawingManager* drawingMgr,
18                                           sk_sp<GrSurfaceProxy> proxyRef,
19                                           GrSurfaceProxy::ResolveFlags flags,
20                                           const GrCaps& caps) {
21     Resolve& resolve = fResolves.emplace_back(flags);
22     GrSurfaceProxy* proxy = proxyRef.get();
23 
24     // Ensure the last render task that operated on the proxy is closed. That's where msaa and
25     // mipmaps should have been marked dirty.
26     SkASSERT(!drawingMgr->getLastRenderTask(proxy)
27              || drawingMgr->getLastRenderTask(proxy)->isClosed());
28     SkASSERT(GrSurfaceProxy::ResolveFlags::kNone != flags);
29 
30     if (GrSurfaceProxy::ResolveFlags::kMSAA & flags) {
31         GrRenderTargetProxy* renderTargetProxy = proxy->asRenderTargetProxy();
32         SkASSERT(renderTargetProxy);
33         SkASSERT(renderTargetProxy->isMSAADirty());
34         resolve.fMSAAResolveRect = renderTargetProxy->msaaDirtyRect();
35         renderTargetProxy->markMSAAResolved();
36     }
37 
38     if (GrSurfaceProxy::ResolveFlags::kMipMaps & flags) {
39         GrTextureProxy* textureProxy = proxy->asTextureProxy();
40         SkASSERT(GrMipmapped::kYes == textureProxy->mipmapped());
41         SkASSERT(textureProxy->mipmapsAreDirty());
42         textureProxy->markMipmapsClean();
43     }
44 
45     // Add the proxy as a dependency: We will read the existing contents of this texture while
46     // generating mipmap levels and/or resolving MSAA.
47     this->addDependency(drawingMgr, proxy, GrMipmapped::kNo,
48                         GrTextureResolveManager(nullptr), caps);
49     this->addTarget(drawingMgr, GrSurfaceProxyView(std::move(proxyRef)));
50 }
51 
gatherProxyIntervals(GrResourceAllocator * alloc) const52 void GrTextureResolveRenderTask::gatherProxyIntervals(GrResourceAllocator* alloc) const {
53     // This renderTask doesn't have "normal" ops, however we still need to add intervals so
54     // fEndOfOpsTaskOpIndices will remain in sync. We create fake op#'s to capture the fact that we
55     // manipulate the resolve proxies.
56     auto fakeOp = alloc->curOp();
57     SkASSERT(fResolves.count() == this->numTargets());
58     for (const sk_sp<GrSurfaceProxy>& target : fTargets) {
59         alloc->addInterval(target.get(), fakeOp, fakeOp, GrResourceAllocator::ActualUse::kYes);
60     }
61     alloc->incOps();
62 }
63 
onExecute(GrOpFlushState * flushState)64 bool GrTextureResolveRenderTask::onExecute(GrOpFlushState* flushState) {
65     // Resolve all msaa back-to-back, before regenerating mipmaps.
66     SkASSERT(fResolves.count() == this->numTargets());
67     for (int i = 0; i < fResolves.count(); ++i) {
68         const Resolve& resolve = fResolves[i];
69         if (GrSurfaceProxy::ResolveFlags::kMSAA & resolve.fFlags) {
70             GrSurfaceProxy* proxy = this->target(i);
71             // peekRenderTarget might be null if there was an instantiation error.
72             if (GrRenderTarget* renderTarget = proxy->peekRenderTarget()) {
73                 flushState->gpu()->resolveRenderTarget(renderTarget, resolve.fMSAAResolveRect);
74             }
75         }
76     }
77     // Regenerate all mipmaps back-to-back.
78     for (int i = 0; i < fResolves.count(); ++i) {
79         const Resolve& resolve = fResolves[i];
80         if (GrSurfaceProxy::ResolveFlags::kMipMaps & resolve.fFlags) {
81             // peekTexture might be null if there was an instantiation error.
82             GrTexture* texture = this->target(i)->peekTexture();
83             if (texture && texture->mipmapsAreDirty()) {
84                 flushState->gpu()->regenerateMipMapLevels(texture);
85                 SkASSERT(!texture->mipmapsAreDirty());
86             }
87         }
88     }
89 
90     return true;
91 }
92 
93 #ifdef SK_DEBUG
visitProxies_debugOnly(const GrOp::VisitProxyFunc & fn) const94 void GrTextureResolveRenderTask::visitProxies_debugOnly(const GrOp::VisitProxyFunc& fn) const {}
95 #endif
96