1cb93a386Sopenharmony_ci// Copyright 2021 Google LLC.
2cb93a386Sopenharmony_ci// Use of this source code is governed by a BSD-style license that can be found in the LICENSE file.
3cb93a386Sopenharmony_ci
4cb93a386Sopenharmony_ci#ifndef SortKey_DEFINED
5cb93a386Sopenharmony_ci#define SortKey_DEFINED
6cb93a386Sopenharmony_ci
7cb93a386Sopenharmony_ci#include "include/core/SkTypes.h"
8cb93a386Sopenharmony_ci
9cb93a386Sopenharmony_ci// These are the material IDs that are stored in the sort key for each class of material
10cb93a386Sopenharmony_ciconstexpr int kInvalidMat = 0;
11cb93a386Sopenharmony_ciconstexpr int kSolidMat   = 1;
12cb93a386Sopenharmony_ciconstexpr int kLinearMat  = 2;
13cb93a386Sopenharmony_ciconstexpr int kRadialMat  = 3;
14cb93a386Sopenharmony_ci
15cb93a386Sopenharmony_ciclass SortKey {
16cb93a386Sopenharmony_cipublic:
17cb93a386Sopenharmony_ci    // field:  |  transparent  | clipID  | depth   |  material  |
18cb93a386Sopenharmony_ci    // bits:   |      1        |   8     |  4      |     4      |
19cb93a386Sopenharmony_ci    // Note: the depth and material fields are swapped when the key is opaque and the depth's
20cb93a386Sopenharmony_ci    // order is reversed. This forces all opaque draws with the be sorted by material first
21cb93a386Sopenharmony_ci    // and then front to back. Transparent draws will continue to be sorted back to front.
22cb93a386Sopenharmony_ci    static const uint32_t kMaterialShift = 0;
23cb93a386Sopenharmony_ci    static const uint32_t kNumMaterialBits = 4;
24cb93a386Sopenharmony_ci    static const uint32_t kMaterialMask = (0x1 << kNumMaterialBits) - 1;
25cb93a386Sopenharmony_ci
26cb93a386Sopenharmony_ci    // The pseudo-Z generated by the draw calls is just a proxy for painter's order.
27cb93a386Sopenharmony_ci    // The "depth" value stored here is a munged version of the pseudo-Z to get the sorting
28cb93a386Sopenharmony_ci    // correct.
29cb93a386Sopenharmony_ci    // For opaque objects the pseudo-Z is reversed so opaque objects are drawn front to back (i.e.,
30cb93a386Sopenharmony_ci    // reverse painter's order).
31cb93a386Sopenharmony_ci    // For transparent objects the pseudo-Z is untouched but the transparent bit is set on the
32cb93a386Sopenharmony_ci    // key so transparent object will always be drawn after the opaque objects and in painter's
33cb93a386Sopenharmony_ci    // order.
34cb93a386Sopenharmony_ci    static const uint32_t kDepthShift = kNumMaterialBits;
35cb93a386Sopenharmony_ci    static const uint32_t kNumDepthBits = 4;
36cb93a386Sopenharmony_ci    static const uint32_t kDepthMask = (0x1 << kNumDepthBits) - 1;
37cb93a386Sopenharmony_ci    static const uint32_t kMaxDepth = kDepthMask;
38cb93a386Sopenharmony_ci
39cb93a386Sopenharmony_ci    static const uint32_t kTransparentShift = kNumMaterialBits + kNumDepthBits;
40cb93a386Sopenharmony_ci    static const uint32_t kNumTransparentBits = 1;
41cb93a386Sopenharmony_ci    static const uint32_t kTransparentMask = (0x1 << kNumTransparentBits) - 1;
42cb93a386Sopenharmony_ci
43cb93a386Sopenharmony_ci    // TODO: make it clearer that we're initializing the default depth to be 0 here (since the
44cb93a386Sopenharmony_ci    // default key is opaque, its sense is flipped)
45cb93a386Sopenharmony_ci    SortKey() : fKey((kMaxDepth - 1) << kMaterialShift) {}
46cb93a386Sopenharmony_ci    explicit SortKey(bool transparent, uint32_t depth, uint32_t material) {
47cb93a386Sopenharmony_ci        SkASSERT(depth != 0 /* && material != 0*/);
48cb93a386Sopenharmony_ci        SkASSERT(!(depth & ~kDepthMask));
49cb93a386Sopenharmony_ci        SkASSERT(!(material & ~kMaterialMask));
50cb93a386Sopenharmony_ci
51cb93a386Sopenharmony_ci        // TODO: better encapsulate the reversal of the depth & material when the key is opaque
52cb93a386Sopenharmony_ci        if (transparent) {
53cb93a386Sopenharmony_ci            fKey = (0x1 << kTransparentShift) |
54cb93a386Sopenharmony_ci                   (depth & kDepthMask) << kDepthShift |
55cb93a386Sopenharmony_ci                   (material & kMaterialMask) << kMaterialShift;
56cb93a386Sopenharmony_ci        } else {
57cb93a386Sopenharmony_ci            SkASSERT(kNumDepthBits == kNumMaterialBits);
58cb93a386Sopenharmony_ci
59cb93a386Sopenharmony_ci            uint32_t munged;
60cb93a386Sopenharmony_ci            // We want the opaque draws to be sorted front to back
61cb93a386Sopenharmony_ci            munged = kMaxDepth - depth - 1;
62cb93a386Sopenharmony_ci            SkASSERT(!(munged & ~kDepthMask));
63cb93a386Sopenharmony_ci
64cb93a386Sopenharmony_ci            fKey = (munged & kDepthMask) << kMaterialShift |
65cb93a386Sopenharmony_ci                   (material & kMaterialMask) << kDepthShift;
66cb93a386Sopenharmony_ci        }
67cb93a386Sopenharmony_ci    }
68cb93a386Sopenharmony_ci
69cb93a386Sopenharmony_ci    bool transparent() const {
70cb93a386Sopenharmony_ci        return (fKey >> kTransparentShift) & kTransparentMask;
71cb93a386Sopenharmony_ci    }
72cb93a386Sopenharmony_ci
73cb93a386Sopenharmony_ci    uint32_t depth() const {
74cb93a386Sopenharmony_ci        if (this->transparent()) {
75cb93a386Sopenharmony_ci            return (fKey >> kDepthShift) & kDepthMask;
76cb93a386Sopenharmony_ci        }
77cb93a386Sopenharmony_ci
78cb93a386Sopenharmony_ci        // TODO: better encapsulate the reversal of the depth & material when the key is opaque
79cb93a386Sopenharmony_ci        uint32_t tmp = (fKey >> kMaterialShift) & kDepthMask;
80cb93a386Sopenharmony_ci        return (kMaxDepth - tmp) - 1;
81cb93a386Sopenharmony_ci    }
82cb93a386Sopenharmony_ci
83cb93a386Sopenharmony_ci    uint32_t material() const {
84cb93a386Sopenharmony_ci        // TODO: better encapsulate the reversal of the depth & material when the key is opaque
85cb93a386Sopenharmony_ci        if (this->transparent()) {
86cb93a386Sopenharmony_ci            return (fKey >> kMaterialShift) & kMaterialMask;
87cb93a386Sopenharmony_ci        } else {
88cb93a386Sopenharmony_ci            return (fKey >> kDepthShift) & kMaterialMask;
89cb93a386Sopenharmony_ci        }
90cb93a386Sopenharmony_ci    }
91cb93a386Sopenharmony_ci
92cb93a386Sopenharmony_ci    void dump() const {
93cb93a386Sopenharmony_ci        SkDebugf("transparent: %d depth: %d mat: %d\n",
94cb93a386Sopenharmony_ci                 this->transparent(),
95cb93a386Sopenharmony_ci                 this->depth(),
96cb93a386Sopenharmony_ci                 this->material());
97cb93a386Sopenharmony_ci    }
98cb93a386Sopenharmony_ci
99cb93a386Sopenharmony_ci    bool operator>(const SortKey& other) const { return fKey > other.fKey; }
100cb93a386Sopenharmony_ci    bool operator<(const SortKey& other) const { return fKey < other.fKey; }
101cb93a386Sopenharmony_ci
102cb93a386Sopenharmony_ciprivate:
103cb93a386Sopenharmony_ci    uint64_t fKey;
104cb93a386Sopenharmony_ci};
105cb93a386Sopenharmony_ci
106cb93a386Sopenharmony_ci#endif // Key_DEFINED
107