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 "experimental/graphite/src/DrawContext.h"
9
10#include "include/private/SkColorData.h"
11
12#include "experimental/graphite/src/CommandBuffer.h"
13#include "experimental/graphite/src/DrawList.h"
14#include "experimental/graphite/src/DrawPass.h"
15#include "experimental/graphite/src/RenderPassTask.h"
16#include "experimental/graphite/src/TextureProxy.h"
17#include "experimental/graphite/src/geom/BoundsManager.h"
18#include "experimental/graphite/src/geom/Shape.h"
19
20namespace skgpu {
21
22sk_sp<DrawContext> DrawContext::Make(sk_sp<TextureProxy> target,
23                                     sk_sp<SkColorSpace> colorSpace,
24                                     SkColorType colorType,
25                                     SkAlphaType alphaType) {
26    if (!target) {
27        return nullptr;
28    }
29
30    // TODO: validate that the color type and alpha type are compatible with the target's info
31    SkImageInfo imageInfo = SkImageInfo::Make(target->dimensions(),
32                                              colorType,
33                                              alphaType,
34                                              std::move(colorSpace));
35    return sk_sp<DrawContext>(new DrawContext(std::move(target), imageInfo));
36}
37
38DrawContext::DrawContext(sk_sp<TextureProxy> target, const SkImageInfo& ii)
39        : fTarget(std::move(target))
40        , fImageInfo(ii)
41        , fPendingDraws(std::make_unique<DrawList>()) {
42    // TBD - Will probably want DrawLists (and its internal commands) to come from an arena
43    // that the DC manages.
44}
45
46DrawContext::~DrawContext() {
47    // If the DC is destroyed and there are pending commands, they won't be drawn.
48    fPendingDraws.reset();
49    fDrawPasses.clear();
50}
51
52void DrawContext::stencilAndFillPath(const Transform& localToDevice,
53                                     const Shape& shape,
54                                     const Clip& clip,
55                                     DrawOrder order,
56                                     const PaintParams* paint)  {
57    SkASSERT(SkIRect::MakeSize(fTarget->dimensions()).contains(clip.scissor()));
58    fPendingDraws->stencilAndFillPath(localToDevice, shape, clip, order,paint);
59}
60
61void DrawContext::fillConvexPath(const Transform& localToDevice,
62                                 const Shape& shape,
63                                 const Clip& clip,
64                                 DrawOrder order,
65                                 const PaintParams* paint) {
66    SkASSERT(SkIRect::MakeSize(fTarget->dimensions()).contains(clip.scissor()));
67    fPendingDraws->fillConvexPath(localToDevice, shape, clip, order, paint);
68}
69
70void DrawContext::strokePath(const Transform& localToDevice,
71                             const Shape& shape,
72                             const StrokeParams& stroke,
73                             const Clip& clip,
74                             DrawOrder order,
75                             const PaintParams* paint) {
76    SkASSERT(SkIRect::MakeSize(fTarget->dimensions()).contains(clip.scissor()));
77    fPendingDraws->strokePath(localToDevice, shape, stroke, clip, order, paint);
78}
79
80void DrawContext::clear(const SkColor4f& clearColor) {
81    fPendingLoadOp = LoadOp::kClear;
82    SkPMColor4f pmColor = clearColor.premul();
83    fPendingClearColor = pmColor.array();
84
85    // a fullscreen clear will overwrite anything that came before, so start a new DrawList
86    // and clear any drawpasses that haven't been snapped yet
87    fPendingDraws = std::make_unique<DrawList>();
88    fDrawPasses.clear();
89}
90
91void DrawContext::snapDrawPass(Recorder* recorder, const BoundsManager* occlusionCuller) {
92    if (fPendingDraws->drawCount() == 0) {
93        return;
94    }
95
96    auto pass = DrawPass::Make(recorder, std::move(fPendingDraws), fTarget,
97                               std::make_pair(fPendingLoadOp, fPendingStoreOp), fPendingClearColor,
98                               occlusionCuller);
99    fDrawPasses.push_back(std::move(pass));
100    fPendingDraws = std::make_unique<DrawList>();
101    fPendingLoadOp = LoadOp::kLoad;
102    fPendingStoreOp = StoreOp::kStore;
103}
104
105sk_sp<Task> DrawContext::snapRenderPassTask(Recorder* recorder,
106                                            const BoundsManager* occlusionCuller) {
107    this->snapDrawPass(recorder, occlusionCuller);
108    if (fDrawPasses.empty()) {
109        return nullptr;
110    }
111
112    // TODO: At this point we would determine all the targets used by the drawPasses,
113    // build up the union of them and store them in the RenderPassDesc. However, for
114    // the moment we should have only one drawPass.
115    SkASSERT(fDrawPasses.size() == 1);
116    RenderPassDesc desc;
117    desc.fColorAttachment.fTextureProxy = sk_ref_sp(fDrawPasses[0]->target());
118    std::tie(desc.fColorAttachment.fLoadOp, desc.fColorAttachment.fStoreOp) = fDrawPasses[0]->ops();
119    desc.fClearColor = fDrawPasses[0]->clearColor();
120
121    return RenderPassTask::Make(std::move(fDrawPasses), desc);
122}
123
124} // namespace skgpu
125