xref: /aosp_15_r20/external/skia/src/gpu/graphite/task/CopyTask.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
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/CopyTask.h"
9 
10 #include "src/gpu/graphite/Buffer.h"
11 #include "src/gpu/graphite/CommandBuffer.h"
12 #include "src/gpu/graphite/Log.h"
13 #include "src/gpu/graphite/Texture.h"
14 #include "src/gpu/graphite/TextureProxy.h"
15 
16 namespace skgpu::graphite {
17 
Make(const Buffer * srcBuffer,size_t srcOffset,sk_sp<Buffer> dstBuffer,size_t dstOffset,size_t size)18 sk_sp<CopyBufferToBufferTask> CopyBufferToBufferTask::Make(const Buffer* srcBuffer,
19                                                            size_t srcOffset,
20                                                            sk_sp<Buffer> dstBuffer,
21                                                            size_t dstOffset,
22                                                            size_t size) {
23     SkASSERT(srcBuffer);
24     SkASSERT(size <= srcBuffer->size() - srcOffset);
25     SkASSERT(dstBuffer);
26     SkASSERT(size <= dstBuffer->size() - dstOffset);
27     return sk_sp<CopyBufferToBufferTask>(new CopyBufferToBufferTask(srcBuffer,
28                                                                     srcOffset,
29                                                                     std::move(dstBuffer),
30                                                                     dstOffset,
31                                                                     size));
32 }
33 
CopyBufferToBufferTask(const Buffer * srcBuffer,size_t srcOffset,sk_sp<Buffer> dstBuffer,size_t dstOffset,size_t size)34 CopyBufferToBufferTask::CopyBufferToBufferTask(const Buffer* srcBuffer,
35                                                size_t srcOffset,
36                                                sk_sp<Buffer> dstBuffer,
37                                                size_t dstOffset,
38                                                size_t size)
39         : fSrcBuffer(srcBuffer)
40         , fSrcOffset(srcOffset)
41         , fDstBuffer(std::move(dstBuffer))
42         , fDstOffset(dstOffset)
43         , fSize(size) {}
44 
45 CopyBufferToBufferTask::~CopyBufferToBufferTask() = default;
46 
prepareResources(ResourceProvider *,ScratchResourceManager *,const RuntimeEffectDictionary *)47 Task::Status CopyBufferToBufferTask::prepareResources(ResourceProvider*,
48                                                       ScratchResourceManager*,
49                                                       const RuntimeEffectDictionary*) {
50     return Status::kSuccess;
51 }
52 
addCommands(Context *,CommandBuffer * commandBuffer,ReplayTargetData)53 Task::Status CopyBufferToBufferTask::addCommands(Context*,
54                                                  CommandBuffer* commandBuffer,
55                                                  ReplayTargetData) {
56     if (commandBuffer->copyBufferToBuffer(fSrcBuffer, fSrcOffset, fDstBuffer, fDstOffset, fSize)) {
57         return Status::kSuccess;
58     } else {
59         return Status::kFail;
60     }
61 }
62 
Make(sk_sp<TextureProxy> textureProxy,SkIRect srcRect,sk_sp<Buffer> buffer,size_t bufferOffset,size_t bufferRowBytes)63 sk_sp<CopyTextureToBufferTask> CopyTextureToBufferTask::Make(sk_sp<TextureProxy> textureProxy,
64                                                              SkIRect srcRect,
65                                                              sk_sp<Buffer> buffer,
66                                                              size_t bufferOffset,
67                                                              size_t bufferRowBytes) {
68     if (!textureProxy) {
69         return nullptr;
70     }
71     return sk_sp<CopyTextureToBufferTask>(new CopyTextureToBufferTask(std::move(textureProxy),
72                                                                       srcRect,
73                                                                       std::move(buffer),
74                                                                       bufferOffset,
75                                                                       bufferRowBytes));
76 }
77 
CopyTextureToBufferTask(sk_sp<TextureProxy> textureProxy,SkIRect srcRect,sk_sp<Buffer> buffer,size_t bufferOffset,size_t bufferRowBytes)78 CopyTextureToBufferTask::CopyTextureToBufferTask(sk_sp<TextureProxy> textureProxy,
79                                                  SkIRect srcRect,
80                                                  sk_sp<Buffer> buffer,
81                                                  size_t bufferOffset,
82                                                  size_t bufferRowBytes)
83         : fTextureProxy(std::move(textureProxy))
84         , fSrcRect(srcRect)
85         , fBuffer(std::move(buffer))
86         , fBufferOffset(bufferOffset)
87         , fBufferRowBytes(bufferRowBytes) {
88 }
89 
~CopyTextureToBufferTask()90 CopyTextureToBufferTask::~CopyTextureToBufferTask() {}
91 
prepareResources(ResourceProvider * resourceProvider,ScratchResourceManager *,const RuntimeEffectDictionary *)92 Task::Status CopyTextureToBufferTask::prepareResources(ResourceProvider* resourceProvider,
93                                                        ScratchResourceManager*,
94                                                        const RuntimeEffectDictionary*) {
95     // If the source texture hasn't been instantiated yet, it means there was no prior task that
96     // could have initialized its contents so a readback to a buffer does not make sense.
97     SkASSERT(fTextureProxy->isInstantiated() || fTextureProxy->isLazy());
98     // TODO: The copy is also a consumer of the source, so it should participate in returning
99     // scratch resources like RenderPassTask does. For now, though, all copy tasks side step reuse
100     // entirely and they cannot participate until they've been moved into scoping tasks like
101     // DrawTask first.
102     return Status::kSuccess;
103 }
104 
addCommands(Context *,CommandBuffer * commandBuffer,ReplayTargetData)105 Task::Status CopyTextureToBufferTask::addCommands(Context*,
106                                                   CommandBuffer* commandBuffer,
107                                                   ReplayTargetData) {
108     if (commandBuffer->copyTextureToBuffer(fTextureProxy->refTexture(),
109                                            fSrcRect,
110                                            std::move(fBuffer),
111                                            fBufferOffset,
112                                            fBufferRowBytes)) {
113         // TODO(b/332681367): CopyTextureToBuffer is currently only used for readback operations,
114         // which are a one-time event. Should this just default to returning kDiscard?
115         return Status::kSuccess;
116     } else {
117         return Status::kFail;
118     }
119 }
120 
121 //--------------------------------------------------------------------------------------------------
122 
Make(sk_sp<TextureProxy> srcProxy,SkIRect srcRect,sk_sp<TextureProxy> dstProxy,SkIPoint dstPoint,int dstLevel)123 sk_sp<CopyTextureToTextureTask> CopyTextureToTextureTask::Make(sk_sp<TextureProxy> srcProxy,
124                                                                SkIRect srcRect,
125                                                                sk_sp<TextureProxy> dstProxy,
126                                                                SkIPoint dstPoint,
127                                                                int dstLevel) {
128     if (!srcProxy || !dstProxy) {
129         return nullptr;
130     }
131     return sk_sp<CopyTextureToTextureTask>(new CopyTextureToTextureTask(std::move(srcProxy),
132                                                                         srcRect,
133                                                                         std::move(dstProxy),
134                                                                         dstPoint,
135                                                                         dstLevel));
136 }
137 
CopyTextureToTextureTask(sk_sp<TextureProxy> srcProxy,SkIRect srcRect,sk_sp<TextureProxy> dstProxy,SkIPoint dstPoint,int dstLevel)138 CopyTextureToTextureTask::CopyTextureToTextureTask(sk_sp<TextureProxy> srcProxy,
139                                                    SkIRect srcRect,
140                                                    sk_sp<TextureProxy> dstProxy,
141                                                    SkIPoint dstPoint,
142                                                    int dstLevel)
143         : fSrcProxy(std::move(srcProxy))
144         , fSrcRect(srcRect)
145         , fDstProxy(std::move(dstProxy))
146         , fDstPoint(dstPoint)
147         , fDstLevel(dstLevel) {}
148 
~CopyTextureToTextureTask()149 CopyTextureToTextureTask::~CopyTextureToTextureTask() {}
150 
prepareResources(ResourceProvider * resourceProvider,ScratchResourceManager *,const RuntimeEffectDictionary *)151 Task::Status CopyTextureToTextureTask::prepareResources(ResourceProvider* resourceProvider,
152                                                         ScratchResourceManager*,
153                                                         const RuntimeEffectDictionary*) {
154     // Do not instantiate the src proxy. If the source texture hasn't been instantiated yet, it
155     // means there was no prior task that could have initialized its contents so propagating the
156     // undefined contents to the dst does not make sense.
157     // TODO(b/333729316): Assert that fSrcProxy is instantiated or lazy; right now it may not be
158     // instantatiated if this is a dst readback copy for a scratch Device. In that case, a
159     // RenderPassTask will immediately follow this copy task and instantiate the source proxy so
160     // that addCommands() has a texture to operate on. That said, the texture's contents will be
161     // undefined when the copy is executed ideally it just shouldn't happen.
162 
163     // TODO: The copy is also a consumer of the source, so it should participate in returning
164     // scratch resources like RenderPassTask does. For now, though, all copy tasks side step reuse
165     // entirely and they cannot participate until they've been moved into scoping tasks like
166     // DrawTask first. In particular, for texture-to-texture copies, they should be scoped to not
167     // invoke pending listeners for a subsequent RenderPassTask.
168 
169     // TODO: Use the scratch resource manager to instantiate fDstProxy, although the details of when
170     // that texture can be returned need to be worked out. While brittle, all current use cases
171     // of scratch texture-to-texture copies have the dst used immediately by the next task, so it
172     // could just add a pending listener that returns the texture w/o any read counting.
173     if (!TextureProxy::InstantiateIfNotLazy(resourceProvider, fDstProxy.get())) {
174         SKGPU_LOG_E("Could not instantiate dst texture proxy for CopyTextureToTextureTask!");
175         return Status::kFail;
176     }
177     return Status::kSuccess;
178 }
179 
addCommands(Context *,CommandBuffer * commandBuffer,ReplayTargetData)180 Task::Status CopyTextureToTextureTask::addCommands(Context*,
181                                                    CommandBuffer* commandBuffer,
182                                                    ReplayTargetData) {
183     // prepareResources() doesn't instantiate the source assuming that a prior task will have do so
184     // as part of initializing the texture contents.
185     SkASSERT(fSrcProxy->isInstantiated());
186     if (commandBuffer->copyTextureToTexture(fSrcProxy->refTexture(),
187                                             fSrcRect,
188                                             fDstProxy->refTexture(),
189                                             fDstPoint,
190                                             fDstLevel)) {
191         // TODO(b/332681367): The calling context should be able to specify whether or not this copy
192         // is a repeatable operation (e.g. dst readback copy for blending) or one time (e.g. client
193         // asked for a copy of an image or surface).
194         return Status::kSuccess;
195     } else {
196         return Status::kFail;
197     }
198 }
199 
200 } // namespace skgpu::graphite
201