Add std430 offset support

Change-Id: I37b7688b660ff4840cfb2bb5ddd348c1ba684fe6
Bug: skia:5039
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/365488
Reviewed-by: Greg Daniel <egdaniel@google.com>
Commit-Queue: Jim Van Verth <jvanverth@google.com>
This commit is contained in:
Jim Van Verth 2021-02-03 15:50:20 -05:00 committed by Skia Commit-Bot
parent efae4d56e1
commit 2af58b0377
6 changed files with 83 additions and 34 deletions

View File

@ -43,7 +43,8 @@ GrVkPipelineState::GrVkPipelineState(
, fGeometryProcessor(std::move(geometryProcessor)) , fGeometryProcessor(std::move(geometryProcessor))
, fXferProcessor(std::move(xferProcessor)) , fXferProcessor(std::move(xferProcessor))
, fFragmentProcessors(std::move(fragmentProcessors)) , fFragmentProcessors(std::move(fragmentProcessors))
, fDataManager(uniforms, uniformSize) { // TODO: add std430 usage
, fDataManager(uniforms, uniformSize, GrVkUniformHandler::kStd140Layout) {
fUniformBuffer.reset(GrVkUniformBuffer::Create(gpu, uniformSize)); fUniformBuffer.reset(GrVkUniformBuffer::Create(gpu, uniformSize));
fNumSamplers = samplers.count(); fNumSamplers = samplers.count();

View File

@ -360,7 +360,8 @@ GrVkPipelineState* GrVkPipelineStateBuilder::finalize(const GrProgramDesc& desc,
samplerDSHandle, samplerDSHandle,
fUniformHandles, fUniformHandles,
fUniformHandler.fUniforms, fUniformHandler.fUniforms,
fUniformHandler.fCurrentUBOOffset, // TODO: add std430 support
fUniformHandler.fCurrentOffsets[GrVkUniformHandler::kStd140Layout],
fUniformHandler.fSamplers, fUniformHandler.fSamplers,
std::move(fGeometryProcessor), std::move(fGeometryProcessor),
std::move(fXferProcessor), std::move(fXferProcessor),

View File

@ -12,8 +12,10 @@
#include "src/gpu/vk/GrVkUniformBuffer.h" #include "src/gpu/vk/GrVkUniformBuffer.h"
GrVkPipelineStateDataManager::GrVkPipelineStateDataManager(const UniformInfoArray& uniforms, GrVkPipelineStateDataManager::GrVkPipelineStateDataManager(const UniformInfoArray& uniforms,
uint32_t uniformSize) uint32_t uniformSize,
: INHERITED(uniforms.count(), uniformSize) { GrVkUniformHandler::Layout memLayout)
: INHERITED(uniforms.count(), uniformSize)
, fMemLayout(memLayout) {
// We must add uniforms in same order as the UniformInfoArray so that UniformHandles already // We must add uniforms in same order as the UniformInfoArray so that UniformHandles already
// owned by other objects will still match up here. // owned by other objects will still match up here.
int i = 0; int i = 0;
@ -24,9 +26,9 @@ GrVkPipelineStateDataManager::GrVkPipelineStateDataManager(const UniformInfoArra
SkDEBUGCODE( SkDEBUGCODE(
uniform.fArrayCount = uniformInfo.fVariable.getArrayCount(); uniform.fArrayCount = uniformInfo.fVariable.getArrayCount();
uniform.fType = uniformInfo.fVariable.getType(); uniform.fType = uniformInfo.fVariable.getType();
) )
uniform.fOffset = uniformInfo.fUBOffset; uniform.fOffset = uniformInfo.fOffsets[memLayout];
++i; ++i;
} }
} }
@ -50,3 +52,24 @@ void GrVkPipelineStateDataManager::uploadPushConstants(const GrVkGpu* gpu,
gpu->vkCaps().getPushConstantStageFlags(), gpu->vkCaps().getPushConstantStageFlags(),
0, fUniformSize, fUniformData.get()); 0, fUniformSize, fUniformData.get());
} }
void GrVkPipelineStateDataManager::setMatrix2fv(UniformHandle u,
int arrayCount,
const float m[]) const {
if (fMemLayout == GrVkUniformHandler::kStd430Layout) {
const Uniform& uni = fUniforms[u.toIndex()];
SkASSERT(uni.fType == kFloat2x2_GrSLType || uni.fType == kHalf2x2_GrSLType);
SkASSERT(arrayCount > 0);
SkASSERT(arrayCount <= uni.fArrayCount ||
(1 == arrayCount && GrShaderVar::kNonArray == uni.fArrayCount));
void* buffer = fUniformData.get();
fUniformsDirty = true;
static_assert(sizeof(float) == 4);
buffer = static_cast<char*>(buffer) + uni.fOffset;
memcpy(buffer, m, arrayCount * 2 * 2 * sizeof(float));
} else {
this->INHERITED::setMatrix2fv(u, arrayCount, m);
}
}

View File

@ -21,7 +21,8 @@ class GrVkPipelineStateDataManager : public GrUniformDataManager {
public: public:
typedef GrVkUniformHandler::UniformInfoArray UniformInfoArray; typedef GrVkUniformHandler::UniformInfoArray UniformInfoArray;
GrVkPipelineStateDataManager(const UniformInfoArray&, uint32_t uniformSize); GrVkPipelineStateDataManager(const UniformInfoArray&, uint32_t uniformSize,
GrVkUniformHandler::Layout memLayout);
// Returns true if either the geometry or fragment buffers needed to generate a new underlying // Returns true if either the geometry or fragment buffers needed to generate a new underlying
// VkBuffer object in order upload data. If true is returned, this is a signal to the caller // VkBuffer object in order upload data. If true is returned, this is a signal to the caller
@ -30,7 +31,12 @@ public:
void uploadPushConstants(const GrVkGpu*, VkPipelineLayout, GrVkCommandBuffer*) const; void uploadPushConstants(const GrVkGpu*, VkPipelineLayout, GrVkCommandBuffer*) const;
// TODO: we might need more of these once std430 size/alignment issues are worked out
void setMatrix2fv(UniformHandle, int arrayCount, const float matrices[]) const override;
private: private:
GrVkUniformHandler::Layout fMemLayout;
using INHERITED = GrUniformDataManager; using INHERITED = GrUniformDataManager;
}; };

View File

@ -96,7 +96,7 @@ static uint32_t grsltype_to_alignment_mask(GrSLType type) {
} }
/** Returns the size in bytes taken up in vulkanbuffers for GrSLTypes. */ /** Returns the size in bytes taken up in vulkanbuffers for GrSLTypes. */
static inline uint32_t grsltype_to_vk_size(GrSLType type) { static inline uint32_t grsltype_to_vk_size(GrSLType type, int layout) {
switch(type) { switch(type) {
case kByte_GrSLType: case kByte_GrSLType:
return sizeof(int8_t); return sizeof(int8_t);
@ -156,8 +156,11 @@ static inline uint32_t grsltype_to_vk_size(GrSLType type) {
return 4 * sizeof(int32_t); return 4 * sizeof(int32_t);
case kHalf2x2_GrSLType: // fall through case kHalf2x2_GrSLType: // fall through
case kFloat2x2_GrSLType: case kFloat2x2_GrSLType:
//TODO: this will be 4 * szof(float) on std430. if (layout == GrVkUniformHandler::kStd430Layout) {
return 8 * sizeof(float); return 4 * sizeof(float);
} else {
return 8 * sizeof(float);
}
case kHalf3x3_GrSLType: // fall through case kHalf3x3_GrSLType: // fall through
case kFloat3x3_GrSLType: case kFloat3x3_GrSLType:
return 12 * sizeof(float); return 12 * sizeof(float);
@ -182,16 +185,16 @@ static inline uint32_t grsltype_to_vk_size(GrSLType type) {
SK_ABORT("Unexpected type"); SK_ABORT("Unexpected type");
} }
// Given the current offset into the ubo data, calculate the offset for the uniform we're trying to
// Given the current offset into the ubo, calculate the offset for the uniform we're trying to add // add taking into consideration all alignment requirements. The uniformOffset is set to the offset
// taking into consideration all alignment requirements. The uniformOffset is set to the offset for // for the new uniform, and currentOffset is updated to be the offset to the end of the new uniform.
// the new uniform, and currentOffset is updated to be the offset to the end of the new uniform. static uint32_t get_aligned_offset(uint32_t* currentOffset,
static uint32_t get_ubo_aligned_offset(uint32_t* currentOffset,
GrSLType type, GrSLType type,
int arrayCount) { int arrayCount,
int layout) {
uint32_t alignmentMask = grsltype_to_alignment_mask(type); uint32_t alignmentMask = grsltype_to_alignment_mask(type);
// We want to use the std140 layout here, so we must make arrays align to 16 bytes. // For std140 layout we must make arrays align to 16 bytes.
if (arrayCount || type == kFloat2x2_GrSLType) { if (layout == GrVkUniformHandler::kStd140Layout && (arrayCount || type == kFloat2x2_GrSLType)) {
alignmentMask = 0xF; alignmentMask = 0xF;
} }
uint32_t offsetDiff = *currentOffset & alignmentMask; uint32_t offsetDiff = *currentOffset & alignmentMask;
@ -201,11 +204,12 @@ static uint32_t get_ubo_aligned_offset(uint32_t* currentOffset,
int32_t uniformOffset = *currentOffset + offsetDiff; int32_t uniformOffset = *currentOffset + offsetDiff;
SkASSERT(sizeof(float) == 4); SkASSERT(sizeof(float) == 4);
if (arrayCount) { if (arrayCount) {
uint32_t elementSize = std::max<uint32_t>(16, grsltype_to_vk_size(type)); // TODO: this shouldn't be necessary for std430
uint32_t elementSize = std::max<uint32_t>(16, grsltype_to_vk_size(type, layout));
SkASSERT(0 == (elementSize & 0xF)); SkASSERT(0 == (elementSize & 0xF));
*currentOffset = uniformOffset + elementSize * arrayCount; *currentOffset = uniformOffset + elementSize * arrayCount;
} else { } else {
*currentOffset = uniformOffset + grsltype_to_vk_size(type); *currentOffset = uniformOffset + grsltype_to_vk_size(type, layout);
} }
return uniformOffset; return uniformOffset;
} }
@ -242,17 +246,17 @@ GrGLSLUniformHandler::UniformHandle GrVkUniformHandler::internalAddUniformArray(
} }
SkString resolvedName = fProgramBuilder->nameVariable(prefix, name, mangleName); SkString resolvedName = fProgramBuilder->nameVariable(prefix, name, mangleName);
uint32_t offset = get_ubo_aligned_offset(&fCurrentUBOOffset, type, arrayCount); uint32_t offsets[kLayoutCount];
SkString layoutQualifier; for (int layout = 0; layout < kLayoutCount; ++layout) {
layoutQualifier.appendf("offset=%d", offset); offsets[layout] = get_aligned_offset(&fCurrentOffsets[layout], type, arrayCount, layout);
}
VkUniformInfo& uni = fUniforms.push_back(VkUniformInfo{ VkUniformInfo& uni = fUniforms.push_back(VkUniformInfo{
{ {
GrShaderVar{std::move(resolvedName), type, GrShaderVar::TypeModifier::None, arrayCount, GrShaderVar{std::move(resolvedName), type, GrShaderVar::TypeModifier::None, arrayCount},
std::move(layoutQualifier), SkString()},
visibility, owner, SkString(name) visibility, owner, SkString(name)
}, },
offset, nullptr {offsets[0], offsets[1]}, nullptr
}); });
if (outName) { if (outName) {
@ -281,7 +285,7 @@ GrGLSLUniformHandler::SamplerHandle GrVkUniformHandler::addSampler(
std::move(layoutQualifier), SkString()}, std::move(layoutQualifier), SkString()},
kFragment_GrShaderFlag, nullptr, SkString(name) kFragment_GrShaderFlag, nullptr, SkString(name)
}, },
0, nullptr {0, 0}, nullptr
}); });
// Check if we are dealing with an external texture and store the needed information if so. // Check if we are dealing with an external texture and store the needed information if so.
@ -341,7 +345,8 @@ void GrVkUniformHandler::appendUniformDecls(GrShaderFlags visibility, SkString*
if (!firstOffsetCheck) { if (!firstOffsetCheck) {
// Check to make sure we are starting our offset at 0 so the offset qualifier we // Check to make sure we are starting our offset at 0 so the offset qualifier we
// set on each variable in the uniform block is valid. // set on each variable in the uniform block is valid.
SkASSERT(0 == localUniform.fUBOffset); SkASSERT(0 == localUniform.fOffsets[kStd140Layout] &&
0 == localUniform.fOffsets[kStd430Layout]);
firstOffsetCheck = true; firstOffsetCheck = true;
} }
} }
@ -351,6 +356,9 @@ void GrVkUniformHandler::appendUniformDecls(GrShaderFlags visibility, SkString*
for (const VkUniformInfo& localUniform : fUniforms.items()) { for (const VkUniformInfo& localUniform : fUniforms.items()) {
if (visibility & localUniform.fVisibility) { if (visibility & localUniform.fVisibility) {
if (GrSLTypeIsFloatType(localUniform.fVariable.getType())) { if (GrSLTypeIsFloatType(localUniform.fVariable.getType())) {
// TODO: add use of std430 layout
uniformsString.appendf("layout(offset=%d) ",
localUniform.fOffsets[kStd140Layout]);
localUniform.fVariable.appendDecl(fProgramBuilder->shaderCaps(), &uniformsString); localUniform.fVariable.appendDecl(fProgramBuilder->shaderCaps(), &uniformsString);
uniformsString.append(";\n"); uniformsString.append(";\n");
} }
@ -365,6 +373,7 @@ void GrVkUniformHandler::appendUniformDecls(GrShaderFlags visibility, SkString*
} }
uint32_t GrVkUniformHandler::getRTHeightOffset() const { uint32_t GrVkUniformHandler::getRTHeightOffset() const {
uint32_t currentOffset = fCurrentUBOOffset; // TODO: make use of std430 offset
return get_ubo_aligned_offset(&currentOffset, kFloat_GrSLType, 0); uint32_t currentOffset = fCurrentOffsets[kStd140Layout];
return get_aligned_offset(&currentOffset, kFloat_GrSLType, 0, kStd140Layout);
} }

View File

@ -44,9 +44,18 @@ public:
kDstInputAttachmentIndex = 0 kDstInputAttachmentIndex = 0
}; };
// The two types of memory layout we're concerned with
enum Layout {
kStd140Layout = 0,
kStd430Layout = 1,
kLastLayout = kStd430Layout
};
static constexpr int kLayoutCount = kLastLayout + 1;
struct VkUniformInfo : public UniformInfo { struct VkUniformInfo : public UniformInfo {
// fUBOffset is only valid if the GrSLType of the fVariable is not a sampler // offsets are only valid if the GrSLType of the fVariable is not a sampler.
uint32_t fUBOffset; uint32_t fOffsets[kLayoutCount];
// fImmutableSampler is used for sampling an image with a ycbcr conversion. // fImmutableSampler is used for sampling an image with a ycbcr conversion.
const GrVkSampler* fImmutableSampler = nullptr; const GrVkSampler* fImmutableSampler = nullptr;
}; };
@ -83,7 +92,7 @@ private:
: INHERITED(program) : INHERITED(program)
, fUniforms(kUniformsPerBlock) , fUniforms(kUniformsPerBlock)
, fSamplers(kUniformsPerBlock) , fSamplers(kUniformsPerBlock)
, fCurrentUBOOffset(0) { , fCurrentOffsets{ 0, 0 } {
} }
UniformHandle internalAddUniformArray(const GrFragmentProcessor* owner, UniformHandle internalAddUniformArray(const GrFragmentProcessor* owner,
@ -141,7 +150,7 @@ private:
UniformInfo fInputUniform; UniformInfo fInputUniform;
GrSwizzle fInputSwizzle; GrSwizzle fInputSwizzle;
uint32_t fCurrentUBOOffset; uint32_t fCurrentOffsets[kLayoutCount];
friend class GrVkPipelineStateBuilder; friend class GrVkPipelineStateBuilder;
friend class GrVkDescriptorSetManager; friend class GrVkDescriptorSetManager;