Buffer fix for VkProgram caching

When caching VkPrograms, we can end up with situations where we
overwrite uniform buffers while they're in use (or being prepared for
use) in the command buffer. This fix will address that. This also
addresses the rare but similar case of overwriting vertex or index
buffers when they're in flight.

GOLD_TRYBOT_URL= https://gold.skia.org/search2?unt=true&query=source_type%3Dgm&master=false&issue=1774963003

Review URL: https://codereview.chromium.org/1774963003
This commit is contained in:
jvanverth 2016-03-08 12:09:27 -08:00 committed by Commit bot
parent 40736abf74
commit 910114a350
3 changed files with 47 additions and 69 deletions

View File

@ -125,6 +125,9 @@ void* GrVkBuffer::vkMap(const GrVkGpu* gpu) {
VALIDATE();
SkASSERT(!this->vkIsMapped());
// we should be the only owner
SkASSERT(fResource->unique());
VkResult err = VK_CALL(gpu, MapMemory(gpu->device(), alloc(), 0, VK_WHOLE_SIZE, 0, &fMapPtr));
if (err) {
fMapPtr = nullptr;
@ -155,6 +158,12 @@ bool GrVkBuffer::vkUpdateData(const GrVkGpu* gpu, const void* src, size_t srcSiz
return false;
}
if (!fResource->unique()) {
// in use by the command buffer, so we need to create a new one
fResource->unref(gpu);
fResource = Create(gpu, fDesc);
}
void* mapPtr;
VkResult err = VK_CALL(gpu, MapMemory(gpu->device(), alloc(), 0, srcSizeInBytes, 0, &mapPtr));

View File

@ -14,7 +14,9 @@ GrVkProgramDataManager::GrVkProgramDataManager(const UniformInfoArray& uniforms,
uint32_t vertexUniformSize,
uint32_t fragmentUniformSize)
: fVertexUniformSize(vertexUniformSize)
, fFragmentUniformSize(fragmentUniformSize) {
, fFragmentUniformSize(fragmentUniformSize)
, fVertexUniformsDirty(false)
, fFragmentUniformsDirty(false) {
fVertexUniformData.reset(vertexUniformSize);
fFragmentUniformData.reset(fragmentUniformSize);
int count = uniforms.count();
@ -38,19 +40,27 @@ GrVkProgramDataManager::GrVkProgramDataManager(const UniformInfoArray& uniforms,
}
}
void* GrVkProgramDataManager::getBufferPtrAndMarkDirty(const Uniform& uni) const {
void* buffer;
if (GrVkUniformHandler::kVertexBinding == uni.fBinding) {
buffer = fVertexUniformData.get();
fVertexUniformsDirty = true;
}
else {
SkASSERT(GrVkUniformHandler::kFragBinding == uni.fBinding);
buffer = fFragmentUniformData.get();
fFragmentUniformsDirty = true;
}
buffer = static_cast<char*>(buffer)+uni.fOffset;
return buffer;
}
void GrVkProgramDataManager::set1f(UniformHandle u, float v0) const {
const Uniform& uni = fUniforms[u.toIndex()];
SkASSERT(uni.fType == kFloat_GrSLType);
SkASSERT(GrGLSLShaderVar::kNonArray == uni.fArrayCount);
SkASSERT(GrVkUniformHandler::kUniformBufferDescSet == uni.fSetNumber);
void* buffer;
if (GrVkUniformHandler::kVertexBinding == uni.fBinding) {
buffer = fVertexUniformData.get();
} else {
SkASSERT(GrVkUniformHandler::kFragBinding == uni.fBinding);
buffer = fFragmentUniformData.get();
}
buffer = static_cast<char*>(buffer) + uni.fOffset;
void* buffer = this->getBufferPtrAndMarkDirty(uni);
SkASSERT(sizeof(float) == 4);
memcpy(buffer, &v0, sizeof(float));
}
@ -65,14 +75,7 @@ void GrVkProgramDataManager::set1fv(UniformHandle u,
(1 == arrayCount && GrGLSLShaderVar::kNonArray == uni.fArrayCount));
SkASSERT(GrVkUniformHandler::kUniformBufferDescSet == uni.fSetNumber);
void* buffer;
if (GrVkUniformHandler::kVertexBinding == uni.fBinding) {
buffer = fVertexUniformData.get();
} else {
SkASSERT(GrVkUniformHandler::kFragBinding == uni.fBinding);
buffer = fFragmentUniformData.get();
}
buffer = static_cast<char*>(buffer) + uni.fOffset;
void* buffer = this->getBufferPtrAndMarkDirty(uni);
SkASSERT(sizeof(float) == 4);
for (int i = 0; i < arrayCount; ++i) {
const float* curVec = &v[i];
@ -86,14 +89,7 @@ void GrVkProgramDataManager::set2f(UniformHandle u, float v0, float v1) const {
SkASSERT(uni.fType == kVec2f_GrSLType);
SkASSERT(GrGLSLShaderVar::kNonArray == uni.fArrayCount);
SkASSERT(GrVkUniformHandler::kUniformBufferDescSet == uni.fSetNumber);
void* buffer;
if (GrVkUniformHandler::kVertexBinding == uni.fBinding) {
buffer = fVertexUniformData.get();
} else {
SkASSERT(GrVkUniformHandler::kFragBinding == uni.fBinding);
buffer = fFragmentUniformData.get();
}
buffer = static_cast<char*>(buffer) + uni.fOffset;
void* buffer = this->getBufferPtrAndMarkDirty(uni);
SkASSERT(sizeof(float) == 4);
float v[2] = { v0, v1 };
memcpy(buffer, v, 2 * sizeof(float));
@ -109,14 +105,7 @@ void GrVkProgramDataManager::set2fv(UniformHandle u,
(1 == arrayCount && GrGLSLShaderVar::kNonArray == uni.fArrayCount));
SkASSERT(GrVkUniformHandler::kUniformBufferDescSet == uni.fSetNumber);
void* buffer;
if (GrVkUniformHandler::kVertexBinding == uni.fBinding) {
buffer = fVertexUniformData.get();
} else {
SkASSERT(GrVkUniformHandler::kFragBinding == uni.fBinding);
buffer = fFragmentUniformData.get();
}
buffer = static_cast<char*>(buffer) + uni.fOffset;
void* buffer = this->getBufferPtrAndMarkDirty(uni);
SkASSERT(sizeof(float) == 4);
for (int i = 0; i < arrayCount; ++i) {
const float* curVec = &v[2 * i];
@ -130,14 +119,7 @@ void GrVkProgramDataManager::set3f(UniformHandle u, float v0, float v1, float v2
SkASSERT(uni.fType == kVec3f_GrSLType);
SkASSERT(GrGLSLShaderVar::kNonArray == uni.fArrayCount);
SkASSERT(GrVkUniformHandler::kUniformBufferDescSet == uni.fSetNumber);
void* buffer;
if (GrVkUniformHandler::kVertexBinding == uni.fBinding) {
buffer = fVertexUniformData.get();
} else {
SkASSERT(GrVkUniformHandler::kFragBinding == uni.fBinding);
buffer = fFragmentUniformData.get();
}
buffer = static_cast<char*>(buffer) + uni.fOffset;
void* buffer = this->getBufferPtrAndMarkDirty(uni);
SkASSERT(sizeof(float) == 4);
float v[3] = { v0, v1, v2 };
memcpy(buffer, v, 3 * sizeof(float));
@ -153,14 +135,7 @@ void GrVkProgramDataManager::set3fv(UniformHandle u,
(1 == arrayCount && GrGLSLShaderVar::kNonArray == uni.fArrayCount));
SkASSERT(GrVkUniformHandler::kUniformBufferDescSet == uni.fSetNumber);
void* buffer;
if (GrVkUniformHandler::kVertexBinding == uni.fBinding) {
buffer = fVertexUniformData.get();
} else {
SkASSERT(GrVkUniformHandler::kFragBinding == uni.fBinding);
buffer = fFragmentUniformData.get();
}
buffer = static_cast<char*>(buffer) + uni.fOffset;
void* buffer = this->getBufferPtrAndMarkDirty(uni);
SkASSERT(sizeof(float) == 4);
for (int i = 0; i < arrayCount; ++i) {
const float* curVec = &v[3 * i];
@ -174,14 +149,7 @@ void GrVkProgramDataManager::set4f(UniformHandle u, float v0, float v1, float v2
SkASSERT(uni.fType == kVec4f_GrSLType);
SkASSERT(GrGLSLShaderVar::kNonArray == uni.fArrayCount);
SkASSERT(GrVkUniformHandler::kUniformBufferDescSet == uni.fSetNumber);
void* buffer;
if (GrVkUniformHandler::kVertexBinding == uni.fBinding) {
buffer = fVertexUniformData.get();
} else {
SkASSERT(GrVkUniformHandler::kFragBinding == uni.fBinding);
buffer = fFragmentUniformData.get();
}
buffer = static_cast<char*>(buffer) + uni.fOffset;
void* buffer = this->getBufferPtrAndMarkDirty(uni);
SkASSERT(sizeof(float) == 4);
float v[4] = { v0, v1, v2, v3 };
memcpy(buffer, v, 4 * sizeof(float));
@ -197,14 +165,7 @@ void GrVkProgramDataManager::set4fv(UniformHandle u,
(1 == arrayCount && GrGLSLShaderVar::kNonArray == uni.fArrayCount));
SkASSERT(GrVkUniformHandler::kUniformBufferDescSet == uni.fSetNumber);
void* buffer;
if (GrVkUniformHandler::kVertexBinding == uni.fBinding) {
buffer = fVertexUniformData.get();
} else {
SkASSERT(GrVkUniformHandler::kFragBinding == uni.fBinding);
buffer = fFragmentUniformData.get();
}
buffer = static_cast<char*>(buffer) + uni.fOffset;
void* buffer = this->getBufferPtrAndMarkDirty(uni);
SkASSERT(sizeof(float) == 4);
memcpy(buffer, v, arrayCount * 4 * sizeof(float));
}
@ -236,8 +197,8 @@ void GrVkProgramDataManager::setMatrix4fv(UniformHandle u, int arrayCount, const
template<int N> struct set_uniform_matrix;
template<int N> inline void GrVkProgramDataManager::setMatrices(UniformHandle u,
int arrayCount,
const float matrices[]) const {
int arrayCount,
const float matrices[]) const {
const Uniform& uni = fUniforms[u.toIndex()];
SkASSERT(uni.fType == kMat22f_GrSLType + (N - 2));
SkASSERT(arrayCount > 0);
@ -248,9 +209,11 @@ template<int N> inline void GrVkProgramDataManager::setMatrices(UniformHandle u,
void* buffer;
if (GrVkUniformHandler::kVertexBinding == uni.fBinding) {
buffer = fVertexUniformData.get();
fVertexUniformsDirty = true;
} else {
SkASSERT(GrVkUniformHandler::kFragBinding == uni.fBinding);
buffer = fFragmentUniformData.get();
fFragmentUniformsDirty = true;
}
set_uniform_matrix<N>::set(buffer, uni.fOffset, arrayCount, matrices);
@ -283,7 +246,7 @@ template<> struct set_uniform_matrix<4> {
void GrVkProgramDataManager::uploadUniformBuffers(const GrVkGpu* gpu,
GrVkUniformBuffer* vertexBuffer,
GrVkUniformBuffer* fragmentBuffer) const {
if (vertexBuffer) {
if (vertexBuffer && fVertexUniformsDirty) {
vertexBuffer->addMemoryBarrier(gpu,
VK_ACCESS_UNIFORM_READ_BIT,
VK_ACCESS_HOST_WRITE_BIT,
@ -291,9 +254,10 @@ void GrVkProgramDataManager::uploadUniformBuffers(const GrVkGpu* gpu,
VK_PIPELINE_STAGE_HOST_BIT,
false);
SkAssertResult(vertexBuffer->updateData(gpu, fVertexUniformData.get(), fVertexUniformSize));
fVertexUniformsDirty = false;
}
if (fragmentBuffer) {
if (fragmentBuffer && fFragmentUniformsDirty) {
fragmentBuffer->addMemoryBarrier(gpu,
VK_ACCESS_UNIFORM_READ_BIT,
VK_ACCESS_HOST_WRITE_BIT,
@ -302,6 +266,7 @@ void GrVkProgramDataManager::uploadUniformBuffers(const GrVkGpu* gpu,
false);
SkAssertResult(fragmentBuffer->updateData(gpu, fFragmentUniformData.get(),
fFragmentUniformSize));
fFragmentUniformsDirty = false;
}
}

View File

@ -63,6 +63,8 @@ private:
template<int N> inline void setMatrices(UniformHandle, int arrayCount,
const float matrices[]) const;
void* getBufferPtrAndMarkDirty(const Uniform& uni) const;
uint32_t fVertexUniformSize;
uint32_t fFragmentUniformSize;
@ -70,6 +72,8 @@ private:
mutable SkAutoMalloc fVertexUniformData;
mutable SkAutoMalloc fFragmentUniformData;
mutable bool fVertexUniformsDirty;
mutable bool fFragmentUniformsDirty;
};
#endif