[graphite] Plumb through the BlendInfo

The general flow of the blendInfo is:

It is created/filled in during the PaintParamsKey creation
   - it is currently stored on the SkPipelineData to get it
     out of the creation phase

Ownership is "transferred" to the ShaderCodeDictionary::Entry
when the PaintParamsKey is converted to a uniqueKey
   - this makes sense bc the blendInfo depends pretty directly
     on the PaintParamsKey

When a FS is generated by a backend the BlendInfo is retrieved
(from the SCD::Entry) and placed in the SkShaderInfo
   - the backend can then use the BlendInfo to set up the
     fixed-function blending

Note:
   The duplication of the BlendInfo in the SkPipelineData and the
   SCD::Entry is unfortunate but may go away in the future. We
   are faced with the general problem of the pre-compilation pass
   needing to get both the structure of the uniforms a program
   requires and the BlendInfo but _not_ the uniforms. So, in the
   future, an SkPipelineData may always be passed in to collect
   data but then disassembled (e.g., the uniformBlock is cached,
   the blendInfo goes into the SCD::Entry, etc.)

Bug: skia:12701
Change-Id: I5571809981cefa6770f69a4c1b8361db14afc44b
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/517876
Reviewed-by: Jim Van Verth <jvanverth@google.com>
Commit-Queue: Robert Phillips <robertphillips@google.com>
This commit is contained in:
Robert Phillips 2022-03-09 09:37:44 -05:00 committed by SkCQ
parent 88f90513a9
commit 5891d67871
7 changed files with 132 additions and 29 deletions

View File

@ -29,7 +29,7 @@ std::tuple<SkUniquePaintParamsID, std::unique_ptr<SkPipelineData>> ExtractPaintD
SkPaintParamsKey key = builder->lockAsKey();
auto entry = dict->findOrCreate(key);
auto entry = dict->findOrCreate(key, pipelineData->blendInfo());
return { entry->uniqueID(), std::move(pipelineData) };
}

View File

@ -17,6 +17,7 @@
#include "include/core/SkSpan.h"
#include "include/gpu/ShaderErrorHandler.h"
#include "include/private/SkSLString.h"
#include "src/core/SkPipelineData.h"
#include "src/core/SkShaderCodeDictionary.h"
namespace skgpu::mtl {
@ -179,9 +180,9 @@ std::string get_sksl_vs(const GraphicsPipelineDesc& desc) {
std::string get_sksl_fs(SkShaderCodeDictionary* dict,
const GraphicsPipelineDesc& desc,
bool* writesColor) {
SkPipelineData::BlendInfo* blendInfo) {
if (!desc.paintParamsID().isValid()) {
*writesColor = false;
// TODO: we should return the error shader code here
return {};
}
@ -189,7 +190,7 @@ std::string get_sksl_fs(SkShaderCodeDictionary* dict,
dict->getShaderInfo(desc.paintParamsID(), &shaderInfo);
*writesColor = shaderInfo.writesColor();
*blendInfo = shaderInfo.blendInfo();
#if SK_SUPPORT_GPU
return shaderInfo.toSkSL();
#else
@ -327,6 +328,23 @@ MTLVertexDescriptor* create_vertex_descriptor(const RenderStep* step) {
return vertexDescriptor;
}
static MTLRenderPipelineColorAttachmentDescriptor* create_color_attachment(
MTLPixelFormat format,
const SkPipelineData::BlendInfo& blendInfo) {
// TODO: I *think* this gets cleaned up by the pipelineDescriptor?
auto mtlColorAttachment = [[MTLRenderPipelineColorAttachmentDescriptor alloc] init];
mtlColorAttachment.pixelFormat = format;
mtlColorAttachment.blendingEnabled = FALSE;
mtlColorAttachment.writeMask = blendInfo.fWritesColor ? MTLColorWriteMaskAll
: MTLColorWriteMaskNone;
return mtlColorAttachment;
}
} // anonymous namespace
std::string GetMtlUniforms(int bufferID,
@ -382,10 +400,10 @@ sk_sp<GraphicsPipeline> GraphicsPipeline::Make(ResourceProvider* resourceProvide
return nullptr;
}
bool writesColor;
SkPipelineData::BlendInfo blendInfo;
auto dict = resourceProvider->shaderCodeDictionary();
if (!SkSLToMSL(gpu,
get_sksl_fs(dict, pipelineDesc, &writesColor),
get_sksl_fs(dict, pipelineDesc, &blendInfo),
SkSL::ProgramKind::kFragment,
settings,
&msl[kFragment_ShaderType],
@ -416,17 +434,11 @@ sk_sp<GraphicsPipeline> GraphicsPipeline::Make(ResourceProvider* resourceProvide
// TODO: I *think* this gets cleaned up by the pipelineDescriptor?
(*psoDescriptor).vertexDescriptor = create_vertex_descriptor(pipelineDesc.renderStep());
// TODO: I *think* this gets cleaned up by the pipelineDescriptor as well?
auto mtlColorAttachment = [[MTLRenderPipelineColorAttachmentDescriptor alloc] init];
mtl::TextureInfo mtlTexInfo;
renderPassDesc.fColorAttachment.fTextureInfo.getMtlTextureInfo(&mtlTexInfo);
mtlColorAttachment.pixelFormat = (MTLPixelFormat)mtlTexInfo.fFormat;
mtlColorAttachment.blendingEnabled = FALSE;
mtlColorAttachment.writeMask = writesColor ? MTLColorWriteMaskAll : MTLColorWriteMaskNone;
auto mtlColorAttachment = create_color_attachment((MTLPixelFormat)mtlTexInfo.fFormat,
blendInfo);
(*psoDescriptor).colorAttachments[0] = mtlColorAttachment;

View File

@ -488,6 +488,11 @@ void AddToKey(SkShaderCodeDictionary* dict,
validate_block_header(builder,
SkBuiltInCodeSnippetID::kShaderBasedBlender,
kBlockDataSize);
if (pipelineData) {
// TODO: set up the correct blend info
pipelineData->setBlendInfo(SkPipelineData::BlendInfo());
}
return;
}
#endif// SK_GRAPHITE_ENABLED
@ -534,10 +539,12 @@ SkUniquePaintParamsID CreateKey(SkShaderCodeDictionary* dict,
break;
}
BlendModeBlock::AddToKey(dict, builder, nullptr, bm);
// TODO: the blendInfo should be filled in by BlendModeBlock::AddToKey
SkPipelineData::BlendInfo blendInfo;
BlendModeBlock::AddToKey(dict, builder, /* pipelineData*/ nullptr, bm);
SkPaintParamsKey key = builder->lockAsKey();
const SkShaderCodeDictionary::Entry* entry = dict->findOrCreate(key);
auto entry = dict->findOrCreate(key, blendInfo);
return entry->uniqueID();
}

View File

@ -230,10 +230,6 @@ void SkPaintParamsKey::AddBlockToShaderInfo(SkShaderCodeDictionary* dict,
AddBlockToShaderInfo(dict, childReader, result);
}
if (reader.codeSnippetId() != SkBuiltInCodeSnippetID::kDepthStencilOnlyDraw) {
result->setWritesColor();
}
}
void SkPaintParamsKey::toShaderInfo(SkShaderCodeDictionary* dict, SkShaderInfo* result) const {

View File

@ -10,9 +10,12 @@
#include <vector>
#include "include/core/SkRefCnt.h"
#include "include/private/SkColorData.h"
#include "src/core/SkUniformData.h"
class SkUniformData;
#ifdef SK_GRAPHITE_ENABLED
#include "src/gpu/Blend.h"
#endif
// TODO: The current plan for fixing uniform padding is for the SkPipelineData to hold a
// persistent uniformManager. A stretch goal for this system would be for this combination
@ -20,9 +23,34 @@ class SkUniformData;
// obviously, vastly complicate uniform accumulation.
class SkPipelineData {
public:
#ifdef SK_GRAPHITE_ENABLED
struct BlendInfo {
bool operator==(const BlendInfo& other) const {
return fEquation == other.fEquation &&
fSrcBlend == other.fSrcBlend &&
fDstBlend == other.fDstBlend &&
fBlendConstant == other.fBlendConstant &&
fWritesColor == other.fWritesColor;
}
skgpu::BlendEquation fEquation = skgpu::BlendEquation::kAdd;
skgpu::BlendCoeff fSrcBlend = skgpu::BlendCoeff::kOne;
skgpu::BlendCoeff fDstBlend = skgpu::BlendCoeff::kZero;
SkPMColor4f fBlendConstant = SK_PMColor4fTRANSPARENT;
bool fWritesColor = true;
};
#endif
SkPipelineData() = default;
SkPipelineData(sk_sp<SkUniformData> initial);
#ifdef SK_GRAPHITE_ENABLED
void setBlendInfo(const SkPipelineData::BlendInfo& blendInfo) {
fBlendInfo = blendInfo;
}
const BlendInfo& blendInfo() const { return fBlendInfo; }
#endif
void add(sk_sp<SkUniformData>);
bool empty() const { return fUniformData.empty(); }
@ -45,6 +73,10 @@ public:
private:
// TODO: SkUniformData should be held uniquely
std::vector<sk_sp<SkUniformData>> fUniformData;
#ifdef SK_GRAPHITE_ENABLED
BlendInfo fBlendInfo;
#endif
};
#endif // SkPipelineData_DEFINED

View File

@ -125,12 +125,21 @@ std::string SkShaderInfo::toSkSL() const {
}
#endif
SkShaderCodeDictionary::Entry* SkShaderCodeDictionary::makeEntry(const SkPaintParamsKey& key) {
SkShaderCodeDictionary::Entry* SkShaderCodeDictionary::makeEntry(
const SkPaintParamsKey& key
#ifdef SK_GRAPHITE_ENABLED
, const SkPipelineData::BlendInfo& blendInfo
#endif
) {
uint8_t* newKeyData = fArena.makeArray<uint8_t>(key.sizeInBytes());
memcpy(newKeyData, key.data(), key.sizeInBytes());
SkSpan<const uint8_t> newKeyAsSpan = SkMakeSpan(newKeyData, key.sizeInBytes());
#ifdef SK_GRAPHITE_ENABLED
return fArena.make([&](void *ptr) { return new(ptr) Entry(newKeyAsSpan, blendInfo); });
#else
return fArena.make([&](void *ptr) { return new(ptr) Entry(newKeyAsSpan); });
#endif
}
size_t SkShaderCodeDictionary::Hash::operator()(const SkPaintParamsKey* key) const {
@ -138,7 +147,11 @@ size_t SkShaderCodeDictionary::Hash::operator()(const SkPaintParamsKey* key) con
}
const SkShaderCodeDictionary::Entry* SkShaderCodeDictionary::findOrCreate(
const SkPaintParamsKey& key) {
const SkPaintParamsKey& key
#ifdef SK_GRAPHITE_ENABLED
, const SkPipelineData::BlendInfo& blendInfo
#endif
) {
SkAutoSpinlock lock{fSpinLock};
auto iter = fHash.find(&key);
@ -147,7 +160,11 @@ const SkShaderCodeDictionary::Entry* SkShaderCodeDictionary::findOrCreate(
return iter->second;
}
#ifdef SK_GRAPHITE_ENABLED
Entry* newEntry = this->makeEntry(key, blendInfo);
#else
Entry* newEntry = this->makeEntry(key);
#endif
newEntry->setUniqueID(fEntryVector.size());
fHash.insert(std::make_pair(&newEntry->paintParamsKey(), newEntry));
fEntryVector.push_back(newEntry);
@ -198,6 +215,10 @@ void SkShaderCodeDictionary::getShaderInfo(SkUniquePaintParamsID uniqueID, SkSha
auto entry = this->lookup(uniqueID);
entry->paintParamsKey().toShaderInfo(this, info);
#ifdef SK_GRAPHITE_ENABLED
info->setBlendInfo(entry->blendInfo());
#endif
}
//--------------------------------------------------------------------------------------------------

View File

@ -16,6 +16,7 @@
#include "include/private/SkUniquePaintParamsID.h"
#include "src/core/SkArenaAlloc.h"
#include "src/core/SkPaintParamsKey.h"
#include "src/core/SkPipelineData.h"
#include "src/core/SkUniform.h"
@ -53,16 +54,19 @@ struct SkShaderSnippet {
SkSpan<const SkPaintParamsKey::DataPayloadField> fDataPayloadExpectations;
};
// This is just a simple collection object that gathers together all the information needed
// for program creation and its invocation.
class SkShaderInfo {
public:
void add(const SkShaderSnippet& entry) {
fEntries.push_back(entry);
}
// TODO: writing to color should be a property of the SnippetEntries and accumulated as the
// entries are added. _Not_ set manually via 'setWritesColor'.
void setWritesColor() { fWritesColor = true; }
bool writesColor() const { return fWritesColor; }
#ifdef SK_GRAPHITE_ENABLED
void setBlendInfo(const SkPipelineData::BlendInfo& blendInfo) {
fBlendInfo = blendInfo;
}
const SkPipelineData::BlendInfo& blendInfo() const { return fBlendInfo; }
#endif
#if SK_SUPPORT_GPU && defined(SK_GRAPHITE_ENABLED) && defined(SK_METAL)
std::string toSkSL() const;
@ -75,7 +79,12 @@ private:
int indent) const;
std::vector<SkShaderSnippet> fEntries;
bool fWritesColor = false;
#ifdef SK_GRAPHITE_ENABLED
// The blendInfo doesn't actually contribute to the program's creation but, it contains the
// matching fixed-function settings that the program's caller needs to set up.
SkPipelineData::BlendInfo fBlendInfo;
#endif
};
class SkShaderCodeDictionary {
@ -89,11 +98,21 @@ public:
return fUniqueID;
}
const SkPaintParamsKey& paintParamsKey() const { return fKey; }
#ifdef SK_GRAPHITE_ENABLED
const SkPipelineData::BlendInfo& blendInfo() const { return fBlendInfo; }
#endif
private:
friend class SkShaderCodeDictionary;
#ifdef SK_GRAPHITE_ENABLED
Entry(const SkPaintParamsKey& key, const SkPipelineData::BlendInfo& blendInfo)
: fKey(key.asSpan())
, fBlendInfo(blendInfo) {
}
#else
Entry(const SkPaintParamsKey& key) : fKey(key.asSpan()) {}
#endif
void setUniqueID(uint32_t newID) {
SkASSERT(!fUniqueID.isValid());
@ -102,9 +121,21 @@ public:
SkUniquePaintParamsID fUniqueID; // fixed-size (uint32_t) unique ID assigned to a key
SkPaintParamsKey fKey; // variable-length paint key descriptor
#ifdef SK_GRAPHITE_ENABLED
// The BlendInfo isn't used in the hash (that is the key's job) but it does directly vary
// with the key. It could, theoretically, be recreated from the key but that would add
// extra complexity.
SkPipelineData::BlendInfo fBlendInfo;
#endif
};
#ifdef SK_GRAPHITE_ENABLED
const Entry* findOrCreate(const SkPaintParamsKey&,
const SkPipelineData::BlendInfo&) SK_EXCLUDES(fSpinLock);
#else
const Entry* findOrCreate(const SkPaintParamsKey&) SK_EXCLUDES(fSpinLock);
#endif
const Entry* lookup(SkUniquePaintParamsID) const SK_EXCLUDES(fSpinLock);
@ -131,7 +162,11 @@ public:
SkSpan<const SkPaintParamsKey::DataPayloadField> expectations);
private:
#ifdef SK_GRAPHITE_ENABLED
Entry* makeEntry(const SkPaintParamsKey&, const SkPipelineData::BlendInfo&);
#else
Entry* makeEntry(const SkPaintParamsKey&);
#endif
struct Hash {
size_t operator()(const SkPaintParamsKey*) const;