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))
|
, 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();
|
||||||
|
@ -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),
|
||||||
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -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(¤tOffset, kFloat_GrSLType, 0);
|
uint32_t currentOffset = fCurrentOffsets[kStd140Layout];
|
||||||
|
return get_aligned_offset(¤tOffset, kFloat_GrSLType, 0, kStd140Layout);
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
Loading…
Reference in New Issue
Block a user