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