• 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/DrawContext.h"
9 
10 #include "include/core/SkColorSpace.h"
11 #include "include/core/SkPixmap.h"
12 #include "include/private/SkColorData.h"
13 
14 #include "include/gpu/graphite/Context.h"
15 #include "include/gpu/graphite/Recorder.h"
16 #include "src/gpu/graphite/Buffer.h"
17 #include "src/gpu/graphite/Caps.h"
18 #include "src/gpu/graphite/CommandBuffer.h"
19 #include "src/gpu/graphite/ContextPriv.h"
20 #include "src/gpu/graphite/DrawList.h"
21 #include "src/gpu/graphite/DrawPass.h"
22 #include "src/gpu/graphite/RecorderPriv.h"
23 #include "src/gpu/graphite/RenderPassTask.h"
24 #include "src/gpu/graphite/ResourceTypes.h"
25 #include "src/gpu/graphite/SharedContext.h"
26 #include "src/gpu/graphite/TextureProxy.h"
27 #include "src/gpu/graphite/TextureProxyView.h"
28 #include "src/gpu/graphite/UploadTask.h"
29 #include "src/gpu/graphite/geom/BoundsManager.h"
30 #include "src/gpu/graphite/geom/Geometry.h"
31 #include "src/gpu/graphite/text/AtlasManager.h"
32 
33 #ifdef SK_ENABLE_PIET_GPU
34 #include "src/gpu/graphite/PietRenderTask.h"
35 #endif
36 
37 namespace skgpu::graphite {
38 
Make(sk_sp<TextureProxy> target,SkISize deviceSize,const SkColorInfo & colorInfo,const SkSurfaceProps & props)39 sk_sp<DrawContext> DrawContext::Make(sk_sp<TextureProxy> target,
40                                      SkISize deviceSize,
41                                      const SkColorInfo& colorInfo,
42                                      const SkSurfaceProps& props) {
43     if (!target) {
44         return nullptr;
45     }
46 
47     // TODO: validate that the color type and alpha type are compatible with the target's info
48     SkASSERT(!target->isInstantiated() || target->dimensions() == deviceSize);
49     SkImageInfo imageInfo = SkImageInfo::Make(deviceSize, colorInfo);
50     return sk_sp<DrawContext>(new DrawContext(std::move(target), imageInfo, props));
51 }
52 
DrawContext(sk_sp<TextureProxy> target,const SkImageInfo & ii,const SkSurfaceProps & props)53 DrawContext::DrawContext(sk_sp<TextureProxy> target,
54                          const SkImageInfo& ii,
55                          const SkSurfaceProps& props)
56         : fTarget(std::move(target))
57         , fImageInfo(ii)
58         , fSurfaceProps(props)
59         , fPendingDraws(std::make_unique<DrawList>())
60         , fPendingUploads(std::make_unique<UploadList>()) {
61     // TBD - Will probably want DrawLists (and its internal commands) to come from an arena
62     // that the DC manages.
63 }
64 
~DrawContext()65 DrawContext::~DrawContext() {
66     // If the DC is destroyed and there are pending commands, they won't be drawn.
67     fPendingDraws.reset();
68     fDrawPasses.clear();
69 }
70 
readSurfaceView(const Caps * caps)71 TextureProxyView DrawContext::readSurfaceView(const Caps* caps) {
72     TextureProxy* proxy = this->target();
73 
74     if (!caps->isTexturable(proxy->textureInfo())) {
75         return {};
76     }
77 
78     Swizzle swizzle = caps->getReadSwizzle(this->imageInfo().colorType(),
79                                            proxy->textureInfo());
80 
81     return TextureProxyView(sk_ref_sp(proxy), swizzle);
82 }
83 
clear(const SkColor4f & clearColor)84 void DrawContext::clear(const SkColor4f& clearColor) {
85     fPendingLoadOp = LoadOp::kClear;
86     SkPMColor4f pmColor = clearColor.premul();
87     fPendingClearColor = pmColor.array();
88 
89     // a fullscreen clear will overwrite anything that came before, so start a new DrawList
90     // and clear any drawpasses that haven't been snapped yet
91     fPendingDraws = std::make_unique<DrawList>();
92     fDrawPasses.clear();
93 }
94 
recordDraw(const Renderer * renderer,const Transform & localToDevice,const Geometry & geometry,const Clip & clip,DrawOrder ordering,const PaintParams * paint,const StrokeStyle * stroke)95 void DrawContext::recordDraw(const Renderer* renderer,
96                              const Transform& localToDevice,
97                              const Geometry& geometry,
98                              const Clip& clip,
99                              DrawOrder ordering,
100                              const PaintParams* paint,
101                              const StrokeStyle* stroke) {
102     SkASSERT(SkIRect::MakeSize(this->imageInfo().dimensions()).contains(clip.scissor()));
103     fPendingDraws->recordDraw(renderer, localToDevice, geometry, clip, ordering, paint, stroke);
104 }
105 
recordTextUploads(AtlasManager * am)106 bool DrawContext::recordTextUploads(AtlasManager* am) {
107     return am->recordUploads(fPendingUploads.get(), /*useCachedUploads=*/false);
108 }
109 
recordUpload(Recorder * recorder,sk_sp<TextureProxy> targetProxy,const SkColorInfo & srcColorInfo,const SkColorInfo & dstColorInfo,const std::vector<MipLevel> & levels,const SkIRect & dstRect,std::unique_ptr<ConditionalUploadContext> condContext)110 bool DrawContext::recordUpload(Recorder* recorder,
111                                sk_sp<TextureProxy> targetProxy,
112                                const SkColorInfo& srcColorInfo,
113                                const SkColorInfo& dstColorInfo,
114                                const std::vector<MipLevel>& levels,
115                                const SkIRect& dstRect,
116                                std::unique_ptr<ConditionalUploadContext> condContext) {
117     // Our caller should have clipped to the bounds of the surface already.
118     SkASSERT(targetProxy->isFullyLazy() ||
119              SkIRect::MakeSize(targetProxy->dimensions()).contains(dstRect));
120     return fPendingUploads->recordUpload(recorder,
121                                          std::move(targetProxy),
122                                          srcColorInfo,
123                                          dstColorInfo,
124                                          levels,
125                                          dstRect,
126                                          std::move(condContext));
127 }
128 
129 #ifdef SK_ENABLE_PIET_GPU
recordPietSceneRender(Recorder *,sk_sp<TextureProxy> targetProxy,sk_sp<const skgpu::piet::Scene> scene)130 bool DrawContext::recordPietSceneRender(Recorder*,
131                                         sk_sp<TextureProxy> targetProxy,
132                                         sk_sp<const skgpu::piet::Scene> scene) {
133     fPendingPietRenders.push_back(PietRenderInstance(std::move(scene), std::move(targetProxy)));
134     return true;
135 }
136 #endif
137 
snapDrawPass(Recorder * recorder)138 void DrawContext::snapDrawPass(Recorder* recorder) {
139     if (fPendingDraws->drawCount() == 0 && fPendingLoadOp != LoadOp::kClear) {
140         return;
141     }
142 
143     auto pass = DrawPass::Make(recorder,
144                                std::move(fPendingDraws),
145                                fTarget,
146                                this->imageInfo(),
147                                std::make_pair(fPendingLoadOp, fPendingStoreOp),
148                                fPendingClearColor);
149     fDrawPasses.push_back(std::move(pass));
150     fPendingDraws = std::make_unique<DrawList>();
151     fPendingLoadOp = LoadOp::kLoad;
152     fPendingStoreOp = StoreOp::kStore;
153 }
154 
Make(const Caps * caps,const TextureInfo & targetInfo,LoadOp loadOp,StoreOp storeOp,SkEnumBitMask<DepthStencilFlags> depthStencilFlags,const std::array<float,4> & clearColor,bool requiresMSAA)155 RenderPassDesc RenderPassDesc::Make(const Caps* caps,
156                                     const TextureInfo& targetInfo,
157                                     LoadOp loadOp,
158                                     StoreOp storeOp,
159                                     SkEnumBitMask<DepthStencilFlags> depthStencilFlags,
160                                     const std::array<float, 4>& clearColor,
161                                     bool requiresMSAA) {
162     RenderPassDesc desc;
163 
164     // It doesn't make sense to have a storeOp for our main target not be store. Why are we doing
165     // this DrawPass then
166     SkASSERT(storeOp == StoreOp::kStore);
167     if (requiresMSAA) {
168         // TODO: If the resolve texture isn't readable, the MSAA color attachment will need to be
169         // persistently associated with the framebuffer, in which case it's not discardable.
170         desc.fColorAttachment.fTextureInfo = caps->getDefaultMSAATextureInfo(targetInfo,
171                                                                              Discardable::kYes);
172         if (loadOp != LoadOp::kClear) {
173             desc.fColorAttachment.fLoadOp = LoadOp::kDiscard;
174         } else {
175             desc.fColorAttachment.fLoadOp = LoadOp::kClear;
176         }
177         desc.fColorAttachment.fStoreOp = StoreOp::kDiscard;
178 
179         desc.fColorResolveAttachment.fTextureInfo = targetInfo;
180         if (loadOp != LoadOp::kLoad) {
181             desc.fColorResolveAttachment.fLoadOp = LoadOp::kDiscard;
182         } else {
183             desc.fColorResolveAttachment.fLoadOp = LoadOp::kLoad;
184         }
185         desc.fColorResolveAttachment.fStoreOp = storeOp;
186     } else {
187         desc.fColorAttachment.fTextureInfo = targetInfo;
188         desc.fColorAttachment.fLoadOp = loadOp;
189         desc.fColorAttachment.fStoreOp = storeOp;
190     }
191     desc.fClearColor = clearColor;
192 
193     if (depthStencilFlags != DepthStencilFlags::kNone) {
194         desc.fDepthStencilAttachment.fTextureInfo = caps->getDefaultDepthStencilTextureInfo(
195                 depthStencilFlags,
196                 desc.fColorAttachment.fTextureInfo.numSamples(),
197                 Protected::kNo);
198         // Always clear the depth and stencil to 0 at the start of a DrawPass, but discard at the
199         // end since their contents do not affect the next frame.
200         desc.fDepthStencilAttachment.fLoadOp = LoadOp::kClear;
201         desc.fClearDepth = 0.f;
202         desc.fClearStencil = 0;
203         desc.fDepthStencilAttachment.fStoreOp = StoreOp::kDiscard;
204     }
205 
206     return desc;
207 }
208 
snapRenderPassTask(Recorder * recorder)209 sk_sp<Task> DrawContext::snapRenderPassTask(Recorder* recorder) {
210     this->snapDrawPass(recorder);
211     if (fDrawPasses.empty()) {
212         return nullptr;
213     }
214 
215     const Caps* caps = recorder->priv().caps();
216 
217     // TODO: At this point we would determine all the targets used by the drawPasses,
218     // build up the union of them and store them in the RenderPassDesc. However, for
219     // the moment we should have only one drawPass.
220     SkASSERT(fDrawPasses.size() == 1);
221     auto& drawPass = fDrawPasses[0];
222     const TextureInfo& targetInfo = drawPass->target()->textureInfo();
223     auto [loadOp, storeOp] = drawPass->ops();
224 
225     RenderPassDesc desc = RenderPassDesc::Make(caps, targetInfo, loadOp, storeOp,
226                                                drawPass->depthStencilFlags(),
227                                                drawPass->clearColor(),
228                                                drawPass->requiresMSAA());
229 
230     sk_sp<TextureProxy> targetProxy = sk_ref_sp(fDrawPasses[0]->target());
231     return RenderPassTask::Make(std::move(fDrawPasses), desc, std::move(targetProxy));
232 }
233 
snapUploadTask(Recorder * recorder)234 sk_sp<Task> DrawContext::snapUploadTask(Recorder* recorder) {
235     if (!fPendingUploads || fPendingUploads->size() == 0) {
236         return nullptr;
237     }
238 
239     sk_sp<Task> uploadTask = UploadTask::Make(fPendingUploads.get());
240 
241     fPendingUploads = std::make_unique<UploadList>();
242 
243     return uploadTask;
244 }
245 
246 #ifdef SK_ENABLE_PIET_GPU
snapPietRenderTask(Recorder * recorder)247 sk_sp<Task> DrawContext::snapPietRenderTask(Recorder* recorder) {
248     if (fPendingPietRenders.empty()) {
249         return nullptr;
250     }
251     return sk_sp<Task>(new PietRenderTask(std::move(fPendingPietRenders)));
252 }
253 #endif
254 
255 } // namespace skgpu::graphite
256