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))
, fXferProcessor(std::move(xferProcessor))
, fFragmentProcessors(std::move(fragmentProcessors))
, fDataManager(uniforms, uniformSize) {
// TODO: add std430 usage
, fDataManager(uniforms, uniformSize, GrVkUniformHandler::kStd140Layout) {
fUniformBuffer.reset(GrVkUniformBuffer::Create(gpu, uniformSize));
fNumSamplers = samplers.count();

View File

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

View File

@ -12,8 +12,10 @@
#include "src/gpu/vk/GrVkUniformBuffer.h"
GrVkPipelineStateDataManager::GrVkPipelineStateDataManager(const UniformInfoArray& uniforms,
uint32_t uniformSize)
: INHERITED(uniforms.count(), uniformSize) {
uint32_t uniformSize,
GrVkUniformHandler::Layout memLayout)
: INHERITED(uniforms.count(), uniformSize)
, fMemLayout(memLayout) {
// We must add uniforms in same order as the UniformInfoArray so that UniformHandles already
// owned by other objects will still match up here.
int i = 0;
@ -24,9 +26,9 @@ GrVkPipelineStateDataManager::GrVkPipelineStateDataManager(const UniformInfoArra
SkDEBUGCODE(
uniform.fArrayCount = uniformInfo.fVariable.getArrayCount();
uniform.fType = uniformInfo.fVariable.getType();
)
)
uniform.fOffset = uniformInfo.fUBOffset;
uniform.fOffset = uniformInfo.fOffsets[memLayout];
++i;
}
}
@ -50,3 +52,24 @@ void GrVkPipelineStateDataManager::uploadPushConstants(const GrVkGpu* gpu,
gpu->vkCaps().getPushConstantStageFlags(),
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:
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
// 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;
// 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:
GrVkUniformHandler::Layout fMemLayout;
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. */
static inline uint32_t grsltype_to_vk_size(GrSLType type) {
static inline uint32_t grsltype_to_vk_size(GrSLType type, int layout) {
switch(type) {
case kByte_GrSLType:
return sizeof(int8_t);
@ -156,8 +156,11 @@ static inline uint32_t grsltype_to_vk_size(GrSLType type) {
return 4 * sizeof(int32_t);
case kHalf2x2_GrSLType: // fall through
case kFloat2x2_GrSLType:
//TODO: this will be 4 * szof(float) on std430.
return 8 * sizeof(float);
if (layout == GrVkUniformHandler::kStd430Layout) {
return 4 * sizeof(float);
} else {
return 8 * sizeof(float);
}
case kHalf3x3_GrSLType: // fall through
case kFloat3x3_GrSLType:
return 12 * sizeof(float);
@ -182,16 +185,16 @@ static inline uint32_t grsltype_to_vk_size(GrSLType type) {
SK_ABORT("Unexpected type");
}
// Given the current offset into the ubo, calculate the offset for the uniform we're trying to add
// taking into consideration all alignment requirements. The uniformOffset is set to the offset for
// the new uniform, and currentOffset is updated to be the offset to the end of the new uniform.
static uint32_t get_ubo_aligned_offset(uint32_t* currentOffset,
// Given the current offset into the ubo data, calculate the offset for the uniform we're trying to
// add taking into consideration all alignment requirements. The uniformOffset is set to the offset
// for 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,
GrSLType type,
int arrayCount) {
int arrayCount,
int layout) {
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.
if (arrayCount || type == kFloat2x2_GrSLType) {
// For std140 layout we must make arrays align to 16 bytes.
if (layout == GrVkUniformHandler::kStd140Layout && (arrayCount || type == kFloat2x2_GrSLType)) {
alignmentMask = 0xF;
}
uint32_t offsetDiff = *currentOffset & alignmentMask;
@ -201,11 +204,12 @@ static uint32_t get_ubo_aligned_offset(uint32_t* currentOffset,
int32_t uniformOffset = *currentOffset + offsetDiff;
SkASSERT(sizeof(float) == 4);
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));
*currentOffset = uniformOffset + elementSize * arrayCount;
} else {
*currentOffset = uniformOffset + grsltype_to_vk_size(type);
*currentOffset = uniformOffset + grsltype_to_vk_size(type, layout);
}
return uniformOffset;
}
@ -242,17 +246,17 @@ GrGLSLUniformHandler::UniformHandle GrVkUniformHandler::internalAddUniformArray(
}
SkString resolvedName = fProgramBuilder->nameVariable(prefix, name, mangleName);
uint32_t offset = get_ubo_aligned_offset(&fCurrentUBOOffset, type, arrayCount);
SkString layoutQualifier;
layoutQualifier.appendf("offset=%d", offset);
uint32_t offsets[kLayoutCount];
for (int layout = 0; layout < kLayoutCount; ++layout) {
offsets[layout] = get_aligned_offset(&fCurrentOffsets[layout], type, arrayCount, layout);
}
VkUniformInfo& uni = fUniforms.push_back(VkUniformInfo{
{
GrShaderVar{std::move(resolvedName), type, GrShaderVar::TypeModifier::None, arrayCount,
std::move(layoutQualifier), SkString()},
GrShaderVar{std::move(resolvedName), type, GrShaderVar::TypeModifier::None, arrayCount},
visibility, owner, SkString(name)
},
offset, nullptr
{offsets[0], offsets[1]}, nullptr
});
if (outName) {
@ -281,7 +285,7 @@ GrGLSLUniformHandler::SamplerHandle GrVkUniformHandler::addSampler(
std::move(layoutQualifier), SkString()},
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.
@ -341,7 +345,8 @@ void GrVkUniformHandler::appendUniformDecls(GrShaderFlags visibility, SkString*
if (!firstOffsetCheck) {
// 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.
SkASSERT(0 == localUniform.fUBOffset);
SkASSERT(0 == localUniform.fOffsets[kStd140Layout] &&
0 == localUniform.fOffsets[kStd430Layout]);
firstOffsetCheck = true;
}
}
@ -351,6 +356,9 @@ void GrVkUniformHandler::appendUniformDecls(GrShaderFlags visibility, SkString*
for (const VkUniformInfo& localUniform : fUniforms.items()) {
if (visibility & localUniform.fVisibility) {
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);
uniformsString.append(";\n");
}
@ -365,6 +373,7 @@ void GrVkUniformHandler::appendUniformDecls(GrShaderFlags visibility, SkString*
}
uint32_t GrVkUniformHandler::getRTHeightOffset() const {
uint32_t currentOffset = fCurrentUBOOffset;
return get_ubo_aligned_offset(&currentOffset, kFloat_GrSLType, 0);
// TODO: make use of std430 offset
uint32_t currentOffset = fCurrentOffsets[kStd140Layout];
return get_aligned_offset(&currentOffset, kFloat_GrSLType, 0, kStd140Layout);
}

View File

@ -44,9 +44,18 @@ public:
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 {
// fUBOffset is only valid if the GrSLType of the fVariable is not a sampler
uint32_t fUBOffset;
// offsets are only valid if the GrSLType of the fVariable is not a sampler.
uint32_t fOffsets[kLayoutCount];
// fImmutableSampler is used for sampling an image with a ycbcr conversion.
const GrVkSampler* fImmutableSampler = nullptr;
};
@ -83,7 +92,7 @@ private:
: INHERITED(program)
, fUniforms(kUniformsPerBlock)
, fSamplers(kUniformsPerBlock)
, fCurrentUBOOffset(0) {
, fCurrentOffsets{ 0, 0 } {
}
UniformHandle internalAddUniformArray(const GrFragmentProcessor* owner,
@ -141,7 +150,7 @@ private:
UniformInfo fInputUniform;
GrSwizzle fInputSwizzle;
uint32_t fCurrentUBOOffset;
uint32_t fCurrentOffsets[kLayoutCount];
friend class GrVkPipelineStateBuilder;
friend class GrVkDescriptorSetManager;