• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2021 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/graphite/task/RenderPassTask.h"
9 
10 #include "src/gpu/SkBackingFit.h"
11 #include "src/gpu/graphite/Caps.h"
12 #include "src/gpu/graphite/CommandBuffer.h"
13 #include "src/gpu/graphite/ContextPriv.h"
14 #include "src/gpu/graphite/DrawPass.h"
15 #include "src/gpu/graphite/Log.h"
16 #include "src/gpu/graphite/ResourceProvider.h"
17 #include "src/gpu/graphite/ScratchResourceManager.h"
18 #include "src/gpu/graphite/Texture.h"
19 #include "src/gpu/graphite/TextureProxy.h"
20 
21 namespace skgpu::graphite {
22 
23 namespace {
24 
get_msaa_size(const SkISize & targetSize,const Caps & caps)25 SkISize get_msaa_size(const SkISize& targetSize, const Caps& caps) {
26     if (caps.differentResolveAttachmentSizeSupport()) {
27         // Use approx size for better reuse.
28         return GetApproxSize(targetSize);
29     }
30 
31     return targetSize;
32 }
33 
34 }  // anonymous namespace
35 
Make(DrawPassList passes,const RenderPassDesc & desc,sk_sp<TextureProxy> target,sk_sp<TextureProxy> dstCopy,SkIRect dstReadBounds)36 sk_sp<RenderPassTask> RenderPassTask::Make(DrawPassList passes,
37                                            const RenderPassDesc& desc,
38                                            sk_sp<TextureProxy> target,
39                                            sk_sp<TextureProxy> dstCopy,
40                                            SkIRect dstReadBounds) {
41     // For now we have one DrawPass per RenderPassTask
42     SkASSERT(passes.size() == 1);
43     // If we have a dst copy texture, ensure it is big enough to cover the copy bounds that
44     // will be sampled.
45     SkASSERT(!dstCopy || (dstCopy->dimensions().width() >= dstReadBounds.width() &&
46                           dstCopy->dimensions().height() >= dstReadBounds.height()));
47     if (!target) {
48         return nullptr;
49     }
50 
51     if (desc.fColorAttachment.fTextureInfo.isValid()) {
52         // The color attachment's samples count must ether match the render pass's samples count
53         // or be 1 (when multisampled render to single sampled is used).
54         SkASSERT(desc.fSampleCount == desc.fColorAttachment.fTextureInfo.numSamples() ||
55                  1 == desc.fColorAttachment.fTextureInfo.numSamples());
56     }
57 
58     if (desc.fDepthStencilAttachment.fTextureInfo.isValid()) {
59         SkASSERT(desc.fSampleCount == desc.fDepthStencilAttachment.fTextureInfo.numSamples());
60     }
61 
62     return sk_sp<RenderPassTask>(new RenderPassTask(std::move(passes),
63                                                     desc,
64                                                     std::move(target),
65                                                     std::move(dstCopy),
66                                                     dstReadBounds));
67 }
68 
RenderPassTask(DrawPassList passes,const RenderPassDesc & desc,sk_sp<TextureProxy> target,sk_sp<TextureProxy> dstCopy,SkIRect dstReadBounds)69 RenderPassTask::RenderPassTask(DrawPassList passes,
70                                const RenderPassDesc& desc,
71                                sk_sp<TextureProxy> target,
72                                sk_sp<TextureProxy> dstCopy,
73                                SkIRect dstReadBounds)
74         : fDrawPasses(std::move(passes))
75         , fRenderPassDesc(desc)
76         , fTarget(std::move(target))
77         , fDstCopy(std::move(dstCopy))
78         , fDstReadBounds(dstReadBounds) {}
79 
80 RenderPassTask::~RenderPassTask() = default;
81 
prepareResources(ResourceProvider * resourceProvider,ScratchResourceManager * scratchManager,const RuntimeEffectDictionary * runtimeDict)82 Task::Status RenderPassTask::prepareResources(ResourceProvider* resourceProvider,
83                                               ScratchResourceManager* scratchManager,
84                                               const RuntimeEffectDictionary* runtimeDict) {
85     SkASSERT(fTarget);
86 
87     bool instantiated;
88     if (scratchManager->pendingReadCount(fTarget.get()) == 0) {
89         // TODO(b/389908339, b/338976898): If there are no pending reads on a scratch texture
90         // instantiation request, it means that the scratch Device was caught by a
91         // Recorder::flushTrackedDevices() event but hasn't actually been restored to its parent. In
92         // this case, the eventual read of the surface will be in another Recording and it can't be
93         // allocated as a true scratch resource.
94         //
95         // Without pending reads, DrawTask does not track its lifecycle to return the scratch
96         // resource, so we need to match that and instantiate with a regular non-shareable resource.
97         instantiated = TextureProxy::InstantiateIfNotLazy(resourceProvider, fTarget.get());
98     } else {
99         instantiated = TextureProxy::InstantiateIfNotLazy(scratchManager, fTarget.get());
100     }
101     if (!instantiated) {
102         SKGPU_LOG_W("Failed to instantiate RenderPassTask target. Will not create renderpass!");
103         SKGPU_LOG_W("Dimensions are (%d, %d).",
104                     fTarget->dimensions().width(), fTarget->dimensions().height());
105         return Status::kFail;
106     }
107 
108     // Assuming one draw pass per renderpasstask for now
109     SkASSERT(fDrawPasses.size() == 1);
110     for (const auto& drawPass: fDrawPasses) {
111         if (!drawPass->prepareResources(resourceProvider, runtimeDict, fRenderPassDesc)) {
112             return Status::kFail;
113         }
114     }
115 
116     // Once all internal resources have been prepared and instantiated, reclaim any pending returns
117     // from the scratch manager, since at the equivalent point in the task graph's addCommands()
118     // phase, the renderpass will have sampled from any scratch textures and their contents no
119     // longer have to be preserved.
120     scratchManager->notifyResourcesConsumed();
121     return Status::kSuccess;
122 }
123 
addCommands(Context * context,CommandBuffer * commandBuffer,ReplayTargetData replayData)124 Task::Status RenderPassTask::addCommands(Context* context,
125                                          CommandBuffer* commandBuffer,
126                                          ReplayTargetData replayData) {
127     // TBD: Expose the surfaces that will need to be attached within the renderpass?
128 
129     // Instantiate the target
130     SkASSERT(fTarget && fTarget->isInstantiated());
131     SkASSERT(!fDstCopy || fDstCopy->isInstantiated());
132 
133     // Only apply the replay translation and clip if we're drawing to the final replay target.
134     const SkIRect renderTargetBounds = SkIRect::MakeSize(fTarget->dimensions());
135     if (fTarget->texture() == replayData.fTarget) {
136         // The clip set here will intersect with the render target bounds, and then any scissor set
137         // during this render pass. If there is no intersection between the clip and the render
138         // target bounds, we can skip this entire render pass.
139         if (!commandBuffer->setReplayTranslationAndClip(
140                     replayData.fTranslation, replayData.fClip, renderTargetBounds)) {
141             return Status::kSuccess;
142         }
143 
144     } else {
145         // An empty clip is ignored, and will default to the render target bounds.
146         constexpr SkIVector kNoReplayTranslation = {0, 0};
147         constexpr SkIRect kNoReplayClip = SkIRect::MakeEmpty();
148         commandBuffer->setReplayTranslationAndClip(
149                 kNoReplayTranslation, kNoReplayClip, renderTargetBounds);
150     }
151 
152     // We don't instantiate the MSAA or DS attachments in prepareResources because we want to use
153     // the discardable attachments from the Context.
154     ResourceProvider* resourceProvider = context->priv().resourceProvider();
155     sk_sp<Texture> colorAttachment;
156     sk_sp<Texture> resolveAttachment;
157     if (fRenderPassDesc.fColorResolveAttachment.fTextureInfo.isValid()) {
158         SkASSERT(fTarget->numSamples() == 1 &&
159                  fRenderPassDesc.fColorAttachment.fTextureInfo.numSamples() > 1);
160         colorAttachment = resourceProvider->findOrCreateDiscardableMSAAAttachment(
161                 get_msaa_size(fTarget->dimensions(), *context->priv().caps()),
162                 fRenderPassDesc.fColorAttachment.fTextureInfo);
163         if (!colorAttachment) {
164             SKGPU_LOG_W("Could not get Color attachment for RenderPassTask");
165             return Status::kFail;
166         }
167         resolveAttachment = fTarget->refTexture();
168     } else {
169         colorAttachment = fTarget->refTexture();
170     }
171 
172     sk_sp<Texture> depthStencilAttachment;
173     if (fRenderPassDesc.fDepthStencilAttachment.fTextureInfo.isValid()) {
174         // TODO: ensure this is a scratch/recycled texture
175         SkASSERT(fTarget->isInstantiated());
176         SkISize dimensions = context->priv().caps()->getDepthAttachmentDimensions(
177                 colorAttachment->textureInfo(), colorAttachment->dimensions());
178 
179         depthStencilAttachment = resourceProvider->findOrCreateDepthStencilAttachment(
180                 dimensions, fRenderPassDesc.fDepthStencilAttachment.fTextureInfo);
181         if (!depthStencilAttachment) {
182             SKGPU_LOG_W("Could not get DepthStencil attachment for RenderPassTask");
183             return Status::kFail;
184         }
185     }
186 
187     // TODO(b/313629288) we always pass in the render target's dimensions as the viewport here.
188     // Using the dimensions of the logical device that we're drawing to could reduce flakiness in
189     // rendering.
190     if (commandBuffer->addRenderPass(fRenderPassDesc,
191                                      std::move(colorAttachment),
192                                      std::move(resolveAttachment),
193                                      std::move(depthStencilAttachment),
194                                      fDstCopy ? fDstCopy->texture() : nullptr,
195                                      fDstReadBounds,
196                                      fTarget->dimensions(),
197                                      fDrawPasses)) {
198         return Status::kSuccess;
199     } else {
200         return Status::kFail;
201     }
202 }
203 
204 } // namespace skgpu::graphite
205