// Copyright 2021 Google LLC. // Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. #ifndef SortKey_DEFINED #define SortKey_DEFINED #include "include/core/SkTypes.h" // These are the material IDs that are stored in the sort key for each class of material constexpr int kInvalidMat = 0; constexpr int kSolidMat = 1; constexpr int kLinearMat = 2; constexpr int kRadialMat = 3; class SortKey { public: // field: | transparent | clipID | depth | material | // bits: | 1 | 8 | 4 | 4 | // Note: the depth and material fields are swapped when the key is opaque and the depth's // order is reversed. This forces all opaque draws with the be sorted by material first // and then front to back. Transparent draws will continue to be sorted back to front. static const uint32_t kMaterialShift = 0; static const uint32_t kNumMaterialBits = 4; static const uint32_t kMaterialMask = (0x1 << kNumMaterialBits) - 1; // The pseudo-Z generated by the draw calls is just a proxy for painter's order. // The "depth" value stored here is a munged version of the pseudo-Z to get the sorting // correct. // For opaque objects the pseudo-Z is reversed so opaque objects are drawn front to back (i.e., // reverse painter's order). // For transparent objects the pseudo-Z is untouched but the transparent bit is set on the // key so transparent object will always be drawn after the opaque objects and in painter's // order. static const uint32_t kDepthShift = kNumMaterialBits; static const uint32_t kNumDepthBits = 4; static const uint32_t kDepthMask = (0x1 << kNumDepthBits) - 1; static const uint32_t kMaxDepth = kDepthMask; static const uint32_t kTransparentShift = kNumMaterialBits + kNumDepthBits; static const uint32_t kNumTransparentBits = 1; static const uint32_t kTransparentMask = (0x1 << kNumTransparentBits) - 1; // TODO: make it clearer that we're initializing the default depth to be 0 here (since the // default key is opaque, its sense is flipped) SortKey() : fKey((kMaxDepth - 1) << kMaterialShift) {} explicit SortKey(bool transparent, uint32_t depth, uint32_t material) { SkASSERT(depth != 0 /* && material != 0*/); SkASSERT(!(depth & ~kDepthMask)); SkASSERT(!(material & ~kMaterialMask)); // TODO: better encapsulate the reversal of the depth & material when the key is opaque if (transparent) { fKey = (0x1 << kTransparentShift) | (depth & kDepthMask) << kDepthShift | (material & kMaterialMask) << kMaterialShift; } else { SkASSERT(kNumDepthBits == kNumMaterialBits); uint32_t munged; // We want the opaque draws to be sorted front to back munged = kMaxDepth - depth - 1; SkASSERT(!(munged & ~kDepthMask)); fKey = (munged & kDepthMask) << kMaterialShift | (material & kMaterialMask) << kDepthShift; } } bool transparent() const { return (fKey >> kTransparentShift) & kTransparentMask; } uint32_t depth() const { if (this->transparent()) { return (fKey >> kDepthShift) & kDepthMask; } // TODO: better encapsulate the reversal of the depth & material when the key is opaque uint32_t tmp = (fKey >> kMaterialShift) & kDepthMask; return (kMaxDepth - tmp) - 1; } uint32_t material() const { // TODO: better encapsulate the reversal of the depth & material when the key is opaque if (this->transparent()) { return (fKey >> kMaterialShift) & kMaterialMask; } else { return (fKey >> kDepthShift) & kMaterialMask; } } void dump() const { SkDebugf("transparent: %d depth: %d mat: %d\n", this->transparent(), this->depth(), this->material()); } bool operator>(const SortKey& other) const { return fKey > other.fKey; } bool operator<(const SortKey& other) const { return fKey < other.fKey; } private: uint64_t fKey; }; #endif // Key_DEFINED