Reland "Remove GrProgramDesc::KeyHeader structure"

This is a reland of 4bcd58afbf

Original change's description:
> Remove GrProgramDesc::KeyHeader structure
>
> Instead, just fold all of this information into the key, like everything
> else. The only value that was accessed elsewhere is the initial key
> length. That doesn't need to be part of the key, so store it separately
> in the GrProgramDesc.
>
> Removing this special case logic is just the first step in revising how
> we assemble keys.
>
> Bug: skia:11372
> Change-Id: I52eb76812045e1906797cb37e809cfd0b3332ef0
> Reviewed-on: https://skia-review.googlesource.com/c/skia/+/376797
> Reviewed-by: Brian Salomon <bsalomon@google.com>
> Commit-Queue: Brian Osman <brianosman@google.com>

Bug: skia:11372
Change-Id: I2cdb49aee3537e54dad9af1f9b47cf1aed1aca21
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/376849
Reviewed-by: Brian Salomon <bsalomon@google.com>
Commit-Queue: Brian Osman <brianosman@google.com>
This commit is contained in:
Brian Osman 2021-02-26 14:29:39 -05:00 committed by Skia Commit-Bot
parent 4a4fbe8140
commit 202420e014
2 changed files with 24 additions and 70 deletions

View File

@ -175,11 +175,7 @@ bool GrProgramDesc::Build(GrProgramDesc* desc,
// bindings in use or other descriptor field settings) it should be set // bindings in use or other descriptor field settings) it should be set
// to a canonical value to avoid duplicate programs with different keys. // to a canonical value to avoid duplicate programs with different keys.
static_assert(0 == kProcessorKeysOffset % sizeof(uint32_t));
// Make room for everything up to the effect keys.
desc->key().reset(); desc->key().reset();
desc->key().push_back_n(kProcessorKeysOffset);
GrProcessorKeyBuilder b(&desc->key()); GrProcessorKeyBuilder b(&desc->key());
const GrPrimitiveProcessor& primitiveProcessor = programInfo.primProc(); const GrPrimitiveProcessor& primitiveProcessor = programInfo.primProc();
@ -223,36 +219,29 @@ bool GrProgramDesc::Build(GrProgramDesc* desc,
b.add32(renderTarget->getSamplePatternKey()); b.add32(renderTarget->getSamplePatternKey());
} }
// --------DO NOT MOVE HEADER ABOVE THIS LINE-------------------------------------------------- // Add "header" metadata
// Because header is a pointer into the dynamic array, we can't push any new data into the key uint32_t header = 0;
// below here. SkDEBUGCODE(uint32_t header_bits = 0);
KeyHeader* header = desc->atOffset<KeyHeader, kHeaderOffset>(); auto add_bits = [&](uint32_t nbits, uint32_t val) {
SkASSERT(val < (1 << nbits));
// make sure any padding in the header is zeroed. SkASSERT((header_bits += nbits) <= 32);
memset(header, 0, kHeaderSize); header = (header << nbits) | val;
header->fWriteSwizzle = pipeline.writeSwizzle().asKey(); };
header->fColorFragmentProcessorCnt = numColorFPs; add_bits(16, pipeline.writeSwizzle().asKey());
header->fCoverageFragmentProcessorCnt = numCoverageFPs; add_bits( 1, numColorFPs);
SkASSERT(header->fColorFragmentProcessorCnt == numColorFPs); add_bits( 2, numCoverageFPs);
SkASSERT(header->fCoverageFragmentProcessorCnt == numCoverageFPs);
// If we knew the shader won't depend on origin, we could skip this (and use the same program // If we knew the shader won't depend on origin, we could skip this (and use the same program
// for both origins). Instrumenting all fragment processors would be difficult and error prone. // for both origins). Instrumenting all fragment processors would be difficult and error prone.
header->fSurfaceOriginKey = add_bits( 2, GrGLSLFragmentShaderBuilder::KeyForSurfaceOrigin(programInfo.origin()));
GrGLSLFragmentShaderBuilder::KeyForSurfaceOrigin(programInfo.origin()); add_bits( 1, static_cast<uint32_t>(programInfo.requestedFeatures()));
header->fProcessorFeatures = (uint8_t)programInfo.requestedFeatures(); add_bits( 1, pipeline.snapVerticesToPixelCenters());
// Ensure enough bits.
SkASSERT(header->fProcessorFeatures == (int) programInfo.requestedFeatures());
header->fSnapVerticesToPixelCenters = pipeline.snapVerticesToPixelCenters();
// The base descriptor only stores whether or not the primitiveType is kPoints. Backend- // The base descriptor only stores whether or not the primitiveType is kPoints. Backend-
// specific versions (e.g., Vulkan) require more detail // specific versions (e.g., Vulkan) require more detail
header->fHasPointSize = (programInfo.primitiveType() == GrPrimitiveType::kPoints); add_bits( 1, (programInfo.primitiveType() == GrPrimitiveType::kPoints));
header->fInitialKeyLength = desc->keyLength(); b.add32(header);
// Fail if the initial key length won't fit in 27 bits.
if (header->fInitialKeyLength != desc->keyLength()) { desc->fInitialKeyLength = desc->keyLength();
desc->key().reset();
return false;
}
return true; return true;
} }

View File

@ -22,7 +22,7 @@ class GrShaderCaps;
*/ */
class GrProgramDesc { class GrProgramDesc {
public: public:
GrProgramDesc(const GrProgramDesc& other) : fKey(other.fKey) {} // for SkLRUCache GrProgramDesc(const GrProgramDesc& other) = default;
bool isValid() const { return !fKey.empty(); } bool isValid() const { return !fKey.empty(); }
@ -41,6 +41,7 @@ public:
uint32_t keyLength = other.keyLength(); uint32_t keyLength = other.keyLength();
fKey.reset(SkToInt(keyLength)); fKey.reset(SkToInt(keyLength));
memcpy(fKey.begin(), other.fKey.begin(), keyLength); memcpy(fKey.begin(), other.fKey.begin(), keyLength);
fInitialKeyLength = other.fInitialKeyLength;
return *this; return *this;
} }
@ -65,7 +66,7 @@ public:
return !(*this == other); return !(*this == other);
} }
uint32_t initialKeyLength() const { return this->header().fInitialKeyLength; } uint32_t initialKeyLength() const { return fInitialKeyLength; }
protected: protected:
friend class GrDawnCaps; friend class GrDawnCaps;
@ -100,48 +101,11 @@ protected:
return true; return true;
} }
// TODO: this should be removed and converted to just data added to the key
struct KeyHeader {
// Set to uniquely identify any swizzling of the shader's output color(s).
uint16_t fWriteSwizzle;
uint8_t fColorFragmentProcessorCnt; // Can be packed into 4 bits if required.
uint8_t fCoverageFragmentProcessorCnt;
// Set to uniquely identify the rt's origin, or 0 if the shader does not require this info.
uint32_t fSurfaceOriginKey : 2;
uint32_t fProcessorFeatures : 1;
uint32_t fSnapVerticesToPixelCenters : 1;
uint32_t fHasPointSize : 1;
// This is the key size (in bytes) after core key construction. It doesn't include any
// portions added by the platform-specific backends.
uint32_t fInitialKeyLength : 27;
};
static_assert(sizeof(KeyHeader) == 8);
const KeyHeader& header() const { return *this->atOffset<KeyHeader, kHeaderOffset>(); }
template<typename T, size_t OFFSET> T* atOffset() {
return reinterpret_cast<T*>(reinterpret_cast<intptr_t>(fKey.begin()) + OFFSET);
}
template<typename T, size_t OFFSET> const T* atOffset() const {
return reinterpret_cast<const T*>(reinterpret_cast<intptr_t>(fKey.begin()) + OFFSET);
}
// The key, stored in fKey, is composed of two parts:
// 1. Header struct defined above.
// 2. A Backend specific payload which includes the per-processor keys.
enum KeyOffsets {
kHeaderOffset = 0,
kHeaderSize = SkAlign4(sizeof(KeyHeader)),
// This is the offset into the backend-specific part of the key, which includes
// per-processor keys.
kProcessorKeysOffset = kHeaderOffset + kHeaderSize,
};
enum { enum {
kHeaderSize = 4, // "header" in ::Build
kMaxPreallocProcessors = 8, kMaxPreallocProcessors = 8,
kIntsPerProcessor = 4, // This is an overestimate of the average effect key size. kIntsPerProcessor = 4, // This is an overestimate of the average effect key size.
kPreAllocSize = kHeaderOffset + kHeaderSize + kPreAllocSize = kHeaderSize +
kMaxPreallocProcessors * sizeof(uint32_t) * kIntsPerProcessor, kMaxPreallocProcessors * sizeof(uint32_t) * kIntsPerProcessor,
}; };
@ -149,6 +113,7 @@ protected:
private: private:
SkSTArray<kPreAllocSize, uint8_t, true> fKey; SkSTArray<kPreAllocSize, uint8_t, true> fKey;
uint32_t fInitialKeyLength = 0;
}; };
#endif #endif