/* * Copyright 2021 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/graphite/DrawPass.h" #include "include/private/SkLog.h" #include "src/core/SkTraceEvent.h" #include "src/gpu/graphite/CommandBuffer.h" #include "src/gpu/graphite/PaintParams.h" #include "src/gpu/graphite/PaintParamsKey.h" #include "src/gpu/graphite/PipelineCreationTask.h" #include "src/gpu/graphite/PipelineData.h" #include "src/gpu/graphite/PipelineManager.h" #include "src/gpu/graphite/RenderPassDesc.h" #include "src/gpu/graphite/Resource.h" // IWYU pragma: keep #include "src/gpu/graphite/ResourceProvider.h" #include "src/gpu/graphite/ResourceTypes.h" #include "src/gpu/graphite/RuntimeEffectDictionary.h" #include "src/gpu/graphite/SharedContext.h" #include "src/gpu/graphite/Texture.h" // IWYU pragma: keep #include "src/gpu/graphite/TextureProxy.h" using namespace skia_private; namespace skgpu::graphite { DrawPass::DrawPass(sk_sp target, std::pair ops, std::array clearColor) : fTarget(std::move(target)) , fBounds(SkIRect::MakeEmpty()) , fOps(ops) , fClearColor(clearColor) {} DrawPass::~DrawPass() = default; bool DrawPass::prepareResources(ResourceProvider* resourceProvider, sk_sp runtimeDict, const RenderPassDesc& renderPassDesc) { TRACE_EVENT0("skia.gpu", TRACE_FUNC); SharedContext* sharedContext = resourceProvider->sharedContext(); PipelineManager* pipelineManager = sharedContext->pipelineManager(); fPipelineHandles.reserve(fPipelineDescs.size()); for (const GraphicsPipelineDesc& pipelineDesc : fPipelineDescs) { fPipelineHandles.push_back( pipelineManager->createHandle(sharedContext, runtimeDict, pipelineDesc, renderPassDesc, PipelineCreationFlags::kNone)); } // The DrawPass may be long-lived on a Recording and we no longer need the GraphicPipelineDescs // once we've created pipeline handles, so we drop the storage for them here. fPipelineDescs.clear(); for (int i = 0; i < fSampledTextures.size(); ++i) { // It should not have been possible to draw an Image that has an invalid texture info SkASSERT(fSampledTextures[i]->textureInfo().isValid()); // Tasks should have been ordered to instantiate any scratch textures already, or any // client-owned image will have been instantiated at creation. However, if a TextureProxy // was cached for reuse across Recordings, it's possible that the initializing Recording // failed, leaving the TextureProxy in a bad state (and currently with no way to reconstruct // the tasks required to initialize it). // TODO(b/409888039): Once TextureProxies track their dependendent tasks to include in all // Recordings, this "should" be able to changed to asserts. if (!fSampledTextures[i]->isInstantiated() && !fSampledTextures[i]->isLazy()) { SKIA_LOG_W("Cannot sample from an uninstantiated TextureProxy, label %s", fSampledTextures[i]->label()); return false; } } if (fStorageFallbackTexture) { SkASSERT(fStorageFallbackTexture->textureInfo().isValid()); if (!fStorageFallbackTexture->isInstantiated() && !fStorageFallbackTexture->isLazy()) { SKIA_LOG_W("Cannot sample from an uninstantiated TextureProxy, label %s", fStorageFallbackTexture->label()); return false; } } return true; } bool DrawPass::addResourceRefs(ResourceProvider* resourceProvider, CommandBuffer* commandBuffer) { TRACE_EVENT0_ALWAYS("skia.shaders", "GraphitePipelineUse"); SharedContext* sharedContext = resourceProvider->sharedContext(); PipelineManager* pipelineManager = sharedContext->pipelineManager(); SkASSERT(fPipelineHandles.size() == fPipelineDrawAreas.size()); for (int i = 0; i < fPipelineHandles.size(); ++i) { sk_sp pipeline = pipelineManager->resolveHandle(fPipelineHandles[i]); if (!pipeline) { SKIA_LOG_W("Failed to create Pipeline for draw in RenderPass. Dropping draw!"); return false; } fStorageBufferStages |= pipeline->storageBufferStages(); TRACE_EVENT_INSTANT1_ALWAYS( "skia.shaders", TRACE_STR_COPY(pipeline->getLabel()), TRACE_EVENT_SCOPE_THREAD, "area", sk_float_saturate2int(fPipelineDrawAreas[i])); commandBuffer->trackResource(std::move(pipeline)); } SkDEBUGCODE(fPipelinesHaveBeenResolved = true;) for (int i = 0; i < fSampledTextures.size(); ++i) { commandBuffer->trackResource(fSampledTextures[i]->refTexture()); } if (fStorageFallbackTexture) { // When the StorageContext finalizes the fallback texture, it creates an UploadTask that is // a recordDependency of the drawContext, so assert that the texture should be tracked and // instantiated by this point. // // Note, this is a violation of separate of concerns---ideally the drawPass should be solely // responsible for resourceTracking, but to avoid duplicated work, we assert here. SkASSERT(fStorageFallbackTexture->isInstantiated()); SkASSERT(commandBuffer->isResourceTracked(fStorageFallbackTexture->texture())); } return true; } void DrawPass::setStorageResult(StorageContextResult result) { if (std::holds_alternative(result)) { fStorageBufferInfo = std::get(result); SkASSERT(fStorageBufferInfo); } else { fStorageFallbackTexture = std::move(std::get>(result)); SkASSERT(fStorageFallbackTexture); } } } // namespace skgpu::graphite