• 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/CommandBuffer.h"
9 
10 #include "src/core/SkTraceEvent.h"
11 #include "src/gpu/RefCntedCallback.h"
12 #include "src/gpu/graphite/Buffer.h"
13 #include "src/gpu/graphite/ComputePipeline.h"
14 #include "src/gpu/graphite/DrawPass.h"
15 #include "src/gpu/graphite/GraphicsPipeline.h"
16 #include "src/gpu/graphite/Log.h"
17 #include "src/gpu/graphite/RenderPassDesc.h"
18 #include "src/gpu/graphite/ResourceProvider.h"
19 #include "src/gpu/graphite/Sampler.h"
20 #include "src/gpu/graphite/Texture.h"
21 #include "src/gpu/graphite/TextureProxy.h"
22 
23 namespace skgpu::graphite {
24 
CommandBuffer(Protected isProtected)25 CommandBuffer::CommandBuffer(Protected isProtected) : fIsProtected(isProtected) {}
26 
~CommandBuffer()27 CommandBuffer::~CommandBuffer() {
28     this->releaseResources();
29 }
30 
releaseResources()31 void CommandBuffer::releaseResources() {
32     TRACE_EVENT0("skia.gpu", TRACE_FUNC);
33 
34     fTrackedUsageResources.clear();
35     fCommandBufferResources.clear();
36 }
37 
resetCommandBuffer()38 void CommandBuffer::resetCommandBuffer() {
39     TRACE_EVENT0("skia.gpu", TRACE_FUNC);
40 
41     // The dst copy texture and sampler are kept alive by the tracked resources, so reset these
42     // before we release their refs. Assuming we don't go idle and free lots of resources, we'll
43     // get the same cached sampler the next time we need a dst copy.
44     fDstCopy = {nullptr, nullptr};
45     this->releaseResources();
46     this->onResetCommandBuffer();
47     fBuffersToAsyncMap.clear();
48 }
49 
trackResource(sk_sp<Resource> resource)50 void CommandBuffer::trackResource(sk_sp<Resource> resource) {
51     fTrackedUsageResources.push_back(std::move(resource));
52 }
53 
trackCommandBufferResource(sk_sp<Resource> resource)54 void CommandBuffer::trackCommandBufferResource(sk_sp<Resource> resource) {
55     fCommandBufferResources.push_back(std::move(resource));
56 }
57 
addFinishedProc(sk_sp<RefCntedCallback> finishedProc)58 void CommandBuffer::addFinishedProc(sk_sp<RefCntedCallback> finishedProc) {
59     fFinishedProcs.push_back(std::move(finishedProc));
60 }
61 
callFinishedProcs(bool success)62 void CommandBuffer::callFinishedProcs(bool success) {
63     if (!success) {
64         for (int i = 0; i < fFinishedProcs.size(); ++i) {
65             fFinishedProcs[i]->setFailureResult();
66         }
67     } else {
68         if (auto stats = this->gpuStats()) {
69             for (int i = 0; i < fFinishedProcs.size(); ++i) {
70                 if (fFinishedProcs[i]->receivesGpuStats()) {
71                     fFinishedProcs[i]->setStats(*stats);
72                 }
73             }
74         }
75     }
76     fFinishedProcs.clear();
77 }
78 
addBuffersToAsyncMapOnSubmit(SkSpan<const sk_sp<Buffer>> buffers)79 void CommandBuffer::addBuffersToAsyncMapOnSubmit(SkSpan<const sk_sp<Buffer>> buffers) {
80     for (size_t i = 0; i < buffers.size(); ++i) {
81         SkASSERT(buffers[i]);
82         fBuffersToAsyncMap.push_back(buffers[i]);
83     }
84 }
85 
buffersToAsyncMapOnSubmit() const86 SkSpan<const sk_sp<Buffer>> CommandBuffer::buffersToAsyncMapOnSubmit() const {
87     return fBuffersToAsyncMap;
88 }
89 
addRenderPass(const RenderPassDesc & renderPassDesc,sk_sp<Texture> colorTexture,sk_sp<Texture> resolveTexture,sk_sp<Texture> depthStencilTexture,const Texture * dstCopy,SkIRect dstReadBounds,SkISize viewportDims,const DrawPassList & drawPasses)90 bool CommandBuffer::addRenderPass(const RenderPassDesc& renderPassDesc,
91                                   sk_sp<Texture> colorTexture,
92                                   sk_sp<Texture> resolveTexture,
93                                   sk_sp<Texture> depthStencilTexture,
94                                   const Texture* dstCopy,
95                                   SkIRect dstReadBounds,
96                                   SkISize viewportDims,
97                                   const DrawPassList& drawPasses) {
98     TRACE_EVENT0("skia.gpu", TRACE_FUNC);
99 
100     SkIRect renderPassBounds;
101     for (const auto& drawPass : drawPasses) {
102         renderPassBounds.join(drawPass->bounds());
103     }
104     if (renderPassDesc.fColorAttachment.fLoadOp == LoadOp::kClear) {
105         renderPassBounds.join(fRenderPassBounds);
106     }
107     renderPassBounds.offset(fReplayTranslation.x(), fReplayTranslation.y());
108     if (!renderPassBounds.intersect(fRenderPassBounds)) {
109         // The entire RenderPass is offscreen given the replay translation so skip adding the pass
110         // at all
111         return true;
112     }
113 
114     dstReadBounds.offset(fReplayTranslation.x(), fReplayTranslation.y());
115     if (!dstReadBounds.intersect(fRenderPassBounds)) {
116         // The draws within the RenderPass that would sample from the dstCopy have been translated
117         // off screen. Set the bounds to empty and let the GPU clipping do its job.
118         dstReadBounds = SkIRect::MakeEmpty();
119     }
120     // Save the dstCopy texture so that it can be embedded into texture bind commands later on.
121     // Stash the texture's full dimensions on the rect so we can calculate normalized coords later.
122     fDstCopy.first = dstCopy;
123     fDstReadBounds = dstCopy ? SkIRect::MakePtSize(dstReadBounds.topLeft(), dstCopy->dimensions())
124                              : SkIRect::MakeEmpty();
125     if (dstCopy && !fDstCopy.second) {
126         // Only lookup the sampler the first time we require a dstCopy. The texture can change
127         // on subsequent passes but it will always use the same nearest neighbor sampling.
128         sk_sp<Sampler> nearestNeighbor = this->resourceProvider()->findOrCreateCompatibleSampler(
129                 {SkFilterMode::kNearest, SkTileMode::kClamp});
130         fDstCopy.second = nearestNeighbor.get();
131         this->trackResource(std::move(nearestNeighbor));
132     }
133 
134     // We don't intersect the viewport with the render pass bounds or target size because it just
135     // defines a linear transform, which we don't want to change just because a portion of it maps
136     // to a region that gets clipped.
137     SkIRect viewport = SkIRect::MakePtSize(fReplayTranslation, viewportDims);
138     if (!this->onAddRenderPass(renderPassDesc,
139                                renderPassBounds,
140                                colorTexture.get(),
141                                resolveTexture.get(),
142                                depthStencilTexture.get(),
143                                viewport,
144                                drawPasses)) {
145         return false;
146     }
147 
148     if (colorTexture) {
149         this->trackCommandBufferResource(std::move(colorTexture));
150     }
151     if (resolveTexture) {
152         this->trackCommandBufferResource(std::move(resolveTexture));
153     }
154     if (depthStencilTexture) {
155         this->trackCommandBufferResource(std::move(depthStencilTexture));
156     }
157     // We just assume if you are adding a render pass that the render pass will actually do work. In
158     // theory we could have a discard load that doesn't submit any draws, clears, etc. But hopefully
159     // something so trivial would be caught before getting here.
160     SkDEBUGCODE(fHasWork = true;)
161 
162     return true;
163 }
164 
addComputePass(DispatchGroupSpan dispatchGroups)165 bool CommandBuffer::addComputePass(DispatchGroupSpan dispatchGroups) {
166     TRACE_EVENT0("skia.gpu", TRACE_FUNC);
167 
168     if (!this->onAddComputePass(dispatchGroups)) {
169         return false;
170     }
171 
172     SkDEBUGCODE(fHasWork = true;)
173 
174     return true;
175 }
176 
copyBufferToBuffer(const Buffer * srcBuffer,size_t srcOffset,sk_sp<Buffer> dstBuffer,size_t dstOffset,size_t size)177 bool CommandBuffer::copyBufferToBuffer(const Buffer* srcBuffer,
178                                        size_t srcOffset,
179                                        sk_sp<Buffer> dstBuffer,
180                                        size_t dstOffset,
181                                        size_t size) {
182     SkASSERT(srcBuffer);
183     SkASSERT(dstBuffer);
184 
185     if (!this->onCopyBufferToBuffer(srcBuffer, srcOffset, dstBuffer.get(), dstOffset, size)) {
186         return false;
187     }
188 
189     this->trackResource(std::move(dstBuffer));
190 
191     SkDEBUGCODE(fHasWork = true;)
192 
193     return true;
194 }
195 
copyTextureToBuffer(sk_sp<Texture> texture,SkIRect srcRect,sk_sp<Buffer> buffer,size_t bufferOffset,size_t bufferRowBytes)196 bool CommandBuffer::copyTextureToBuffer(sk_sp<Texture> texture,
197                                         SkIRect srcRect,
198                                         sk_sp<Buffer> buffer,
199                                         size_t bufferOffset,
200                                         size_t bufferRowBytes) {
201     SkASSERT(texture);
202     SkASSERT(buffer);
203 
204     if (!this->onCopyTextureToBuffer(texture.get(), srcRect, buffer.get(), bufferOffset,
205                                      bufferRowBytes)) {
206         return false;
207     }
208 
209     this->trackCommandBufferResource(std::move(texture));
210     this->trackResource(std::move(buffer));
211 
212     SkDEBUGCODE(fHasWork = true;)
213 
214     return true;
215 }
216 
copyBufferToTexture(const Buffer * buffer,sk_sp<Texture> texture,const BufferTextureCopyData * copyData,int count)217 bool CommandBuffer::copyBufferToTexture(const Buffer* buffer,
218                                         sk_sp<Texture> texture,
219                                         const BufferTextureCopyData* copyData,
220                                         int count) {
221     SkASSERT(buffer);
222     SkASSERT(texture);
223     SkASSERT(count > 0 && copyData);
224 
225     if (!this->onCopyBufferToTexture(buffer, texture.get(), copyData, count)) {
226         return false;
227     }
228 
229     this->trackCommandBufferResource(std::move(texture));
230 
231     SkDEBUGCODE(fHasWork = true;)
232 
233     return true;
234 }
235 
copyTextureToTexture(sk_sp<Texture> src,SkIRect srcRect,sk_sp<Texture> dst,SkIPoint dstPoint,int mipLevel)236 bool CommandBuffer::copyTextureToTexture(sk_sp<Texture> src,
237                                          SkIRect srcRect,
238                                          sk_sp<Texture> dst,
239                                          SkIPoint dstPoint,
240                                          int mipLevel) {
241     SkASSERT(src);
242     SkASSERT(dst);
243     if (src->textureInfo().isProtected() == Protected::kYes &&
244         dst->textureInfo().isProtected() != Protected::kYes) {
245         SKGPU_LOG_E("Can't copy from protected memory to non-protected");
246         return false;
247     }
248 
249     if (!this->onCopyTextureToTexture(src.get(), srcRect, dst.get(), dstPoint, mipLevel)) {
250         return false;
251     }
252 
253     this->trackCommandBufferResource(std::move(src));
254     this->trackCommandBufferResource(std::move(dst));
255 
256     SkDEBUGCODE(fHasWork = true;)
257 
258     return true;
259 }
260 
synchronizeBufferToCpu(sk_sp<Buffer> buffer)261 bool CommandBuffer::synchronizeBufferToCpu(sk_sp<Buffer> buffer) {
262     SkASSERT(buffer);
263 
264     bool didResultInWork = false;
265     if (!this->onSynchronizeBufferToCpu(buffer.get(), &didResultInWork)) {
266         return false;
267     }
268 
269     if (didResultInWork) {
270         this->trackResource(std::move(buffer));
271         SkDEBUGCODE(fHasWork = true;)
272     }
273 
274     return true;
275 }
276 
clearBuffer(const Buffer * buffer,size_t offset,size_t size)277 bool CommandBuffer::clearBuffer(const Buffer* buffer, size_t offset, size_t size) {
278     SkASSERT(buffer);
279 
280     if (!this->onClearBuffer(buffer, offset, size)) {
281         return false;
282     }
283 
284     SkDEBUGCODE(fHasWork = true;)
285 
286     return true;
287 }
288 
setReplayTranslationAndClip(const SkIVector & translation,const SkIRect & clip,const SkIRect & renderTargetBounds)289 bool CommandBuffer::setReplayTranslationAndClip(const SkIVector& translation,
290                                                 const SkIRect& clip,
291                                                 const SkIRect& renderTargetBounds) {
292     fReplayTranslation = translation;
293     fRenderPassBounds = renderTargetBounds;
294 
295     // If a replay clip is defined, we intersect it with the render target bounds.
296     if (!clip.isEmpty()) {
297         if (!fRenderPassBounds.intersect(clip.makeOffset(translation))) {
298             return false;
299         }
300     }
301 
302     return true;
303 }
304 
305 } // namespace skgpu::graphite
306