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:
parent
efae4d56e1
commit
2af58b0377
@ -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();
|
||||
|
@ -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),
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
|
@ -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(¤tOffset, kFloat_GrSLType, 0);
|
||||
// TODO: make use of std430 offset
|
||||
uint32_t currentOffset = fCurrentOffsets[kStd140Layout];
|
||||
return get_aligned_offset(¤tOffset, kFloat_GrSLType, 0, kStd140Layout);
|
||||
}
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user