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
17void 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
52void 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 GrSurfaceProxyView& target : fTargets) {
59 alloc->addInterval(target.proxy(), fakeOp, fakeOp,
60 GrResourceAllocator::ActualUse::kYes);
61 }
62 alloc->incOps();
63}
64
65bool GrTextureResolveRenderTask::onExecute(GrOpFlushState* flushState) {
66 // Resolve all msaa back-to-back, before regenerating mipmaps.
67 SkASSERT(fResolves.count() == this->numTargets());
68 for (int i = 0; i < fResolves.count(); ++i) {
69 const Resolve& resolve = fResolves[i];
70 if (GrSurfaceProxy::ResolveFlags::kMSAA & resolve.fFlags) {
71 GrSurfaceProxy* proxy = this->target(i).proxy();
72 // peekRenderTarget might be null if there was an instantiation error.
73 if (GrRenderTarget* renderTarget = proxy->peekRenderTarget()) {
74 flushState->gpu()->resolveRenderTarget(renderTarget, resolve.fMSAAResolveRect);
75 }
76 }
77 }
78 // Regenerate all mipmaps back-to-back.
79 for (int i = 0; i < fResolves.count(); ++i) {
80 const Resolve& resolve = fResolves[i];
81 if (GrSurfaceProxy::ResolveFlags::kMipMaps & resolve.fFlags) {
82 // peekTexture might be null if there was an instantiation error.
83 GrTexture* texture = this->target(i).proxy()->peekTexture();
84 if (texture && texture->mipmapsAreDirty()) {
85 flushState->gpu()->regenerateMipMapLevels(texture);
86 SkASSERT(!texture->mipmapsAreDirty());
87 }
88 }
89 }
90
91 return true;
92}
93
94#ifdef SK_DEBUG
95void GrTextureResolveRenderTask::visitProxies_debugOnly(const GrOp::VisitProxyFunc& fn) const {}
96#endif
97