/* * Copyright 2019 Google LLC * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ #include "src/gpu/ganesh/GrTextureResolveRenderTask.h" #include "include/gpu/GpuTypes.h" #include "include/private/base/SkAssert.h" #include "include/private/base/SkMacros.h" #include "src/gpu/ganesh/GrDrawingManager.h" #include "src/gpu/ganesh/GrGpu.h" #include "src/gpu/ganesh/GrOpFlushState.h" #include "src/gpu/ganesh/GrRenderTargetProxy.h" #include "src/gpu/ganesh/GrResourceAllocator.h" #include "src/gpu/ganesh/GrSurfaceProxyView.h" #include "src/gpu/ganesh/GrTexture.h" #include "src/gpu/ganesh/GrTextureProxy.h" #include "src/gpu/ganesh/GrTextureResolveManager.h" #include #include #include class GrRenderTarget; void GrTextureResolveRenderTask::addProxy(GrDrawingManager* drawingMgr, sk_sp proxyRef, GrSurfaceProxy::ResolveFlags flags, const GrCaps& caps) { GrSurfaceProxy::ResolveFlags newFlags = flags; GrSurfaceProxy* proxy = proxyRef.get(); Resolve* resolve; bool newProxy = false; // We might just need to update the flags for an existing dependency. if (auto found = std::find(fTargets.begin(), fTargets.end(), proxyRef); found != fTargets.end()) { size_t index = found - fTargets.begin(); resolve = &fResolves[index]; newFlags = ~resolve->fFlags & flags; resolve->fFlags |= flags; } else { // Ensure the last render task that operated on the proxy is closed. That's where msaa and // mipmaps should have been marked dirty. SkASSERT(!drawingMgr->getLastRenderTask(proxy) || drawingMgr->getLastRenderTask(proxy)->isClosed()); SkASSERT(GrSurfaceProxy::ResolveFlags::kNone != flags); resolve = &fResolves.emplace_back(flags); newProxy = true; } if (GrSurfaceProxy::ResolveFlags::kMSAA & newFlags) { GrRenderTargetProxy* renderTargetProxy = proxy->asRenderTargetProxy(); SkASSERT(renderTargetProxy); SkASSERT(renderTargetProxy->isMSAADirty()); resolve->fMSAAResolveRect = renderTargetProxy->msaaDirtyRect(); renderTargetProxy->markMSAAResolved(); } if (GrSurfaceProxy::ResolveFlags::kMipMaps & newFlags) { GrTextureProxy* textureProxy = proxy->asTextureProxy(); SkASSERT(skgpu::Mipmapped::kYes == textureProxy->mipmapped()); SkASSERT(textureProxy->mipmapsAreDirty()); textureProxy->markMipmapsClean(); } // We must do this after updating the proxy state because of assertions that the proxy isn't // dirty. if (newProxy) { // Add the proxy as a dependency: We will read the existing contents of this texture while // generating mipmap levels and/or resolving MSAA. this->addDependency( drawingMgr, proxy, skgpu::Mipmapped::kNo, GrTextureResolveManager(nullptr), caps); this->addTarget(drawingMgr, GrSurfaceProxyView(std::move(proxyRef))); } } void GrTextureResolveRenderTask::gatherProxyIntervals(GrResourceAllocator* alloc) const { // This renderTask doesn't have "normal" ops, however we still need to add intervals so // fEndOfOpsTaskOpIndices will remain in sync. We create fake op#'s to capture the fact that we // manipulate the resolve proxies. auto fakeOp = alloc->curOp(); SkASSERT(fResolves.size() == this->numTargets()); for (const sk_sp& target : fTargets) { alloc->addInterval(target.get(), fakeOp, fakeOp, GrResourceAllocator::ActualUse::kYes, GrResourceAllocator::AllowRecycling::kYes); } alloc->incOps(); } bool GrTextureResolveRenderTask::onExecute(GrOpFlushState* flushState) { // Resolve all msaa back-to-back, before regenerating mipmaps. SkASSERT(fResolves.size() == this->numTargets()); for (int i = 0; i < fResolves.size(); ++i) { const Resolve& resolve = fResolves[i]; if (GrSurfaceProxy::ResolveFlags::kMSAA & resolve.fFlags) { GrSurfaceProxy* proxy = this->target(i); // peekRenderTarget might be null if there was an instantiation error. if (GrRenderTarget* renderTarget = proxy->peekRenderTarget()) { flushState->gpu()->resolveRenderTarget(renderTarget, resolve.fMSAAResolveRect); } } } // Regenerate all mipmaps back-to-back. for (int i = 0; i < fResolves.size(); ++i) { const Resolve& resolve = fResolves[i]; if (GrSurfaceProxy::ResolveFlags::kMipMaps & resolve.fFlags) { // peekTexture might be null if there was an instantiation error. GrTexture* texture = this->target(i)->peekTexture(); if (texture && texture->mipmapsAreDirty()) { flushState->gpu()->regenerateMipMapLevels(texture); SkASSERT(!texture->mipmapsAreDirty()); } } } return true; } #ifdef SK_DEBUG void GrTextureResolveRenderTask::visitProxies_debugOnly(const GrVisitProxyFunc&) const {} #endif #if defined(GPU_TEST_UTILS) GrSurfaceProxy::ResolveFlags GrTextureResolveRenderTask::flagsForProxy(sk_sp proxy) const { if (auto found = std::find(fTargets.begin(), fTargets.end(), proxy); found != fTargets.end()) { return fResolves[found - fTargets.begin()].fFlags; } return GrSurfaceProxy::ResolveFlags::kNone; } #endif