| /* | |
| * 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<TextureProxy> target, | |
| std::pair<LoadOp, StoreOp> ops, | |
| std::array<float, 4> clearColor) | |
| : fTarget(std::move(target)) | |
| , fBounds(SkIRect::MakeEmpty()) | |
| , fOps(ops) | |
| , fClearColor(clearColor) {} | |
| DrawPass::~DrawPass() = default; | |
| bool DrawPass::prepareResources(ResourceProvider* resourceProvider, | |
| sk_sp<const RuntimeEffectDictionary> 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<GraphicsPipeline> 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<BindBufferInfo>(result)) { | |
| fStorageBufferInfo = std::get<BindBufferInfo>(result); | |
| SkASSERT(fStorageBufferInfo); | |
| } else { | |
| fStorageFallbackTexture = std::move(std::get<sk_sp<TextureProxy>>(result)); | |
| SkASSERT(fStorageFallbackTexture); | |
| } | |
| } | |
| } // namespace skgpu::graphite |