• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2021 Google LLC.
2 // Use of this source code is governed by a BSD-style license that can be found in the LICENSE file.
3 
4 #include "experimental/sorttoy/Fake.h"
5 
6 #include "experimental/sorttoy/Cmds.h"
7 #include "experimental/sorttoy/SortKey.h"
8 
9 #include "include/core/SkBitmap.h"
10 #include "include/core/SkCanvas.h"
11 
12 //-------------------------------------------------------------------------------------------------
addClip(sk_sp<ClipCmd> clipCmd)13 void FakeMCBlob::MCState::addClip(sk_sp<ClipCmd> clipCmd) {
14     clipCmd->mutate(fTrans);
15     fCmds.push_back(std::move(clipCmd));
16     fCached = nullptr;
17 }
18 
operator ==(const MCState & other) const19 bool FakeMCBlob::MCState::operator==(const MCState& other) const {
20     if (fTrans != other.fTrans || fCmds.size() != other.fCmds.size()) {
21         return false;
22     }
23 
24     for (size_t i = 0; i < fCmds.size(); ++i) {
25         if (fCmds[i]->rect() != other.fCmds[i]->rect()) {
26             return false;
27         }
28     }
29 
30     return true;
31 }
32 
aboutToBePopped(PaintersOrder paintersOrderWhenPopped)33 void FakeMCBlob::MCState::aboutToBePopped(PaintersOrder paintersOrderWhenPopped) {
34     for (sk_sp<ClipCmd>& c : fCmds) {
35         c->onAboutToBePopped(paintersOrderWhenPopped);
36     }
37 }
38 
39 
FakeMCBlob(const std::vector<MCState> & stack)40 FakeMCBlob::FakeMCBlob(const std::vector<MCState>& stack) : fID(NextID()), fStack(stack) {
41     fScissor = SkIRect::MakeLTRB(-1000, -1000, 1000, 1000);
42 
43     for (MCState& s : fStack) {
44         // xform the clip rects into device space to compute the scissor
45         for (const sk_sp<ClipCmd>& c : s.fCmds) {
46             SkASSERT(c->hasBeenMutated());
47             SkIRect r = c->rect();
48             r.offset(fCTM);
49             if (!fScissor.intersect(r)) {
50                 fScissor.setEmpty();
51             }
52         }
53         fCTM += s.getTrans();
54     }
55 }
56 
57 //-------------------------------------------------------------------------------------------------
58 // Linearly blend between c0 & c1:
59 //      (t == 0) -> c0
60 //      (t == 1) -> c1
blend(float t,SkColor c0,SkColor c1)61 static SkColor blend(float t, SkColor c0, SkColor c1) {
62     SkASSERT(t >= 0.0f && t <= 1.0f);
63 
64     SkColor4f top = SkColor4f::FromColor(c0);
65     SkColor4f bot = SkColor4f::FromColor(c1);
66 
67     SkColor4f result = {
68         t * bot.fR + (1.0f - t) * top.fR,
69         t * bot.fG + (1.0f - t) * top.fG,
70         t * bot.fB + (1.0f - t) * top.fB,
71         t * bot.fA + (1.0f - t) * top.fA
72     };
73     return result.toSkColor();
74 }
75 
toID() const76 int FakePaint::toID() const {
77     switch (fType) {
78         case Type::kNormal: return kSolidMat;
79         case Type::kLinear: return kLinearMat;
80         case Type::kRadial: return kRadialMat;
81     }
82     SkUNREACHABLE;
83 }
84 
evalColor(int x,int y) const85 SkColor FakePaint::evalColor(int x, int y) const {
86     switch (fType) {
87         case Type::kNormal: return fColor0;
88         case Type::kLinear: {
89             float t = SK_ScalarRoot2Over2 * x + SK_ScalarRoot2Over2 * y;
90             t /= SK_ScalarSqrt2 * 256.0f;
91             return blend(t, fColor0, fColor1);
92         }
93         case Type::kRadial: {
94             x -= 128;
95             y -= 128;
96             float dist = sqrt(x*x + y*y) / 128.0f;
97             if (dist > 1.0f) {
98                 return fColor0;
99             } else {
100                 return blend(dist, fColor0, fColor1);
101             }
102         }
103     }
104     SkUNREACHABLE;
105 }
106 
107 //-------------------------------------------------------------------------------------------------
save()108 void FakeDevice::save() {
109     fTracker.push();
110 }
111 
drawShape(ID id,PaintersOrder paintersOrder,Shape shape,SkIRect r,FakePaint p)112 void FakeDevice::drawShape(ID id, PaintersOrder paintersOrder, Shape shape, SkIRect r, FakePaint p) {
113     sk_sp<FakeMCBlob> state = fTracker.snapState();
114     SkASSERT(state);
115 
116     sk_sp<Cmd> tmp = sk_make_sp<DrawCmd>(id, paintersOrder, shape, r, p, std::move(state));
117 
118     fSortedCmds.push_back(std::move(tmp));
119 }
120 
clipShape(ID id,PaintersOrder paintersOrder,Shape shape,SkIRect r)121 void FakeDevice::clipShape(ID id, PaintersOrder paintersOrder, Shape shape, SkIRect r) {
122     sk_sp<ClipCmd> tmp = sk_make_sp<ClipCmd>(id, paintersOrder, shape, r);
123 
124     fTracker.clip(std::move(tmp));
125 }
126 
restore(PaintersOrder paintersOrderWhenPopped)127 void FakeDevice::restore(PaintersOrder paintersOrderWhenPopped) {
128     fTracker.pop(paintersOrderWhenPopped);
129 }
130 
finalize()131 void FakeDevice::finalize() {
132     SkASSERT(!fFinalized);
133     fFinalized = true;
134 
135     this->sort();
136     for (const sk_sp<Cmd>& c : fSortedCmds) {
137         c->rasterize(fZBuffer, &fBM);
138     }
139 }
140 
getOrder(std::vector<ID> * ops) const141 void FakeDevice::getOrder(std::vector<ID>* ops) const {
142     SkASSERT(fFinalized);
143 
144     for (const sk_sp<Cmd>& c : fSortedCmds) {
145         ops->push_back(c->id());
146     }
147 }
148 
sort()149 void FakeDevice::sort() {
150     // In general we want:
151     //  opaque draws to occur front to back (i.e., in reverse painter's order) while minimizing
152     //        state changes due to materials
153     //  transparent draws to occur back to front (i.e., in painter's order)
154     //
155     // In both scenarios we would like to batch as much as possible.
156     std::sort(fSortedCmds.begin(), fSortedCmds.end(),
157               [](const sk_sp<Cmd>& a, const sk_sp<Cmd>& b) {
158                     return a->getKey() < b->getKey();
159                 });
160 }
161 
162 //-------------------------------------------------------------------------------------------------
drawShape(ID id,Shape shape,SkIRect r,FakePaint p)163 void FakeCanvas::drawShape(ID id, Shape shape, SkIRect r, FakePaint p) {
164     SkASSERT(!fFinalized);
165 
166     fDeviceStack.back()->drawShape(id, this->nextPaintersOrder(), shape, r, p);
167 }
168 
clipShape(ID id,Shape shape,SkIRect r)169 void FakeCanvas::clipShape(ID id, Shape shape, SkIRect r) {
170     SkASSERT(!fFinalized);
171 
172     fDeviceStack.back()->clipShape(id, this->nextPaintersOrder(), shape, r);
173 }
174 
finalize()175 void FakeCanvas::finalize() {
176     SkASSERT(!fFinalized);
177     fFinalized = true;
178 
179     for (auto& d : fDeviceStack) {
180         d->finalize();
181     }
182 }
183 
getOrder() const184 std::vector<ID> FakeCanvas::getOrder() const {
185     SkASSERT(fFinalized);
186 
187     std::vector<ID> ops;
188 
189     for (auto& d : fDeviceStack) {
190         d->getOrder(&ops);
191     }
192 
193     return ops;
194 }
195