Commit 2b858c2f by Jamie Madill Committed by Commit Bot

Vulkan: More micro-optimizations to setupDraw.

Still a hotspot but much improved. Bug: angleproject:2786 Change-Id: Ie68ff314e6c952f281b48f6d9af37b5dcd194d6a Reviewed-on: https://chromium-review.googlesource.com/1194882 Commit-Queue: Jamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarFrank Henigman <fjhenigman@chromium.org>
parent a153eddb
......@@ -138,6 +138,13 @@ ContextVk::ContextVk(const gl::ContextState &state, RendererVk *renderer)
mNewCommandBufferDirtyBits.set(DIRTY_BIT_VERTEX_BUFFERS);
mNewCommandBufferDirtyBits.set(DIRTY_BIT_INDEX_BUFFER);
mNewCommandBufferDirtyBits.set(DIRTY_BIT_DESCRIPTOR_SETS);
mDirtyBitHandlers[DIRTY_BIT_DEFAULT_ATTRIBS] = &ContextVk::handleDirtyDefaultAttribs;
mDirtyBitHandlers[DIRTY_BIT_PIPELINE] = &ContextVk::handleDirtyPipeline;
mDirtyBitHandlers[DIRTY_BIT_TEXTURES] = &ContextVk::handleDirtyTextures;
mDirtyBitHandlers[DIRTY_BIT_VERTEX_BUFFERS] = &ContextVk::handleDirtyVertexBuffers;
mDirtyBitHandlers[DIRTY_BIT_INDEX_BUFFER] = &ContextVk::handleDirtyIndexBuffer;
mDirtyBitHandlers[DIRTY_BIT_DESCRIPTOR_SETS] = &ContextVk::handleDirtyDescriptorSets;
}
ContextVk::~ContextVk() = default;
......@@ -254,13 +261,14 @@ angle::Result ContextVk::initPipeline(const gl::DrawCallParams &drawCallParams)
angle::Result ContextVk::setupDraw(const gl::Context *context,
const gl::DrawCallParams &drawCallParams,
const DirtyBits &dirtyBitsMask,
DirtyBits dirtyBitMask,
vk::CommandBuffer **commandBufferOut)
{
// Set any dirty bits that depend on draw call parameters or other objects.
if (drawCallParams.mode() != mCurrentDrawMode)
{
invalidateCurrentPipeline();
mCurrentPipeline = nullptr;
mDirtyBits.set(DIRTY_BIT_PIPELINE);
mCurrentDrawMode = drawCallParams.mode();
}
......@@ -282,102 +290,16 @@ angle::Result ContextVk::setupDraw(const gl::Context *context,
mDirtyBits.set(DIRTY_BIT_DESCRIPTOR_SETS);
}
DirtyBits dirtyBits = mDirtyBits & dirtyBitMask;
if (dirtyBits.none())
return angle::Result::Continue();
// Flush any relevant dirty bits.
for (size_t dirtyBit : mDirtyBits &dirtyBitsMask)
for (size_t dirtyBit : dirtyBits)
{
mDirtyBits.reset(dirtyBit);
switch (dirtyBit)
{
case DIRTY_BIT_DEFAULT_ATTRIBS:
ANGLE_TRY(updateDefaultAttributes());
break;
case DIRTY_BIT_PIPELINE:
{
if (!mCurrentPipeline)
{
ANGLE_TRY(initPipeline(drawCallParams));
}
(*commandBufferOut)
->bindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, mCurrentPipeline->get());
// Update the queue serial for the pipeline object.
ASSERT(mCurrentPipeline && mCurrentPipeline->valid());
mCurrentPipeline->updateSerial(mRenderer->getCurrentQueueSerial());
break;
}
case DIRTY_BIT_TEXTURES:
{
ANGLE_TRY(updateActiveTextures(context));
// TODO(jmadill): Should probably merge this for loop with programVk's descriptor
// update.
for (size_t textureIndex : mProgram->getState().getActiveSamplersMask())
{
// Ensure any writes to the textures are flushed before we read from them.
TextureVk *textureVk = mActiveTextures[textureIndex];
ANGLE_TRY(textureVk->ensureImageInitialized(this));
textureVk->addReadDependency(mDrawFramebuffer);
}
if (mProgram->hasTextures())
{
ANGLE_TRY(mProgram->updateTexturesDescriptorSet(this));
}
break;
}
case DIRTY_BIT_DESCRIPTOR_SETS:
{
ANGLE_TRY(mProgram->updateDescriptorSets(this, drawCallParams, *commandBufferOut));
// Bind the graphics descriptor sets.
(*commandBufferOut)
->bindDescriptorSets(VK_PIPELINE_BIND_POINT_GRAPHICS,
mProgram->getPipelineLayout(),
kDriverUniformsDescriptorSetIndex, 1,
&mDriverUniformsDescriptorSet, 0, nullptr);
break;
}
case DIRTY_BIT_VERTEX_BUFFERS:
{
BindNonNullVertexBufferRanges(*commandBufferOut,
mProgram->getState().getActiveAttribLocationsMask(),
mProgram->getState().getMaxActiveAttribLocation(),
mVertexArray->getCurrentArrayBufferHandles(),
mVertexArray->getCurrentArrayBufferOffsets());
const auto &arrayBufferResources = mVertexArray->getCurrentArrayBufferResources();
for (size_t attribIndex : context->getStateCache().getActiveBufferedAttribsMask())
{
if (arrayBufferResources[attribIndex])
arrayBufferResources[attribIndex]->addReadDependency(mDrawFramebuffer);
}
break;
}
case DIRTY_BIT_INDEX_BUFFER:
{
(*commandBufferOut)
->bindIndexBuffer(mVertexArray->getCurrentElementArrayBufferHandle(),
mVertexArray->getCurrentElementArrayBufferOffset(),
gl_vk::GetIndexType(mCurrentDrawElementsType));
vk::CommandGraphResource *elementArrayBufferResource =
mVertexArray->getCurrentElementArrayBufferResource();
if (elementArrayBufferResource)
{
elementArrayBufferResource->addReadDependency(mDrawFramebuffer);
}
break;
}
default:
UNREACHABLE();
break;
}
ANGLE_TRY((this->*mDirtyBitHandlers[dirtyBit])(context, drawCallParams, *commandBufferOut));
}
return angle::Result::Continue();
......@@ -428,6 +350,109 @@ angle::Result ContextVk::setupLineLoopDraw(const gl::Context *context,
return setupDraw(context, drawCallParams, mIndexedDirtyBitsMask, commandBufferOut);
}
angle::Result ContextVk::handleDirtyDefaultAttribs(const gl::Context *context,
const gl::DrawCallParams &drawCallParams,
vk::CommandBuffer *commandBuffer)
{
ASSERT(mDirtyDefaultAttribsMask.any());
for (size_t attribIndex : mDirtyDefaultAttribsMask)
{
ANGLE_TRY(updateDefaultAttribute(attribIndex))
}
mDirtyDefaultAttribsMask.reset();
return angle::Result::Continue();
}
angle::Result ContextVk::handleDirtyPipeline(const gl::Context *context,
const gl::DrawCallParams &drawCallParams,
vk::CommandBuffer *commandBuffer)
{
if (!mCurrentPipeline)
{
ANGLE_TRY(initPipeline(drawCallParams));
}
commandBuffer->bindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, mCurrentPipeline->get());
// Update the queue serial for the pipeline object.
ASSERT(mCurrentPipeline && mCurrentPipeline->valid());
mCurrentPipeline->updateSerial(mRenderer->getCurrentQueueSerial());
return angle::Result::Continue();
}
angle::Result ContextVk::handleDirtyTextures(const gl::Context *context,
const gl::DrawCallParams &drawCallParams,
vk::CommandBuffer *commandBuffer)
{
ANGLE_TRY(updateActiveTextures(context));
// TODO(jmadill): Should probably merge this for loop with programVk's descriptor update.
for (size_t textureIndex : mProgram->getState().getActiveSamplersMask())
{
// Ensure any writes to the textures are flushed before we read from them.
TextureVk *textureVk = mActiveTextures[textureIndex];
ANGLE_TRY(textureVk->ensureImageInitialized(this));
textureVk->addReadDependency(mDrawFramebuffer);
}
if (mProgram->hasTextures())
{
ANGLE_TRY(mProgram->updateTexturesDescriptorSet(this));
}
return angle::Result::Continue();
}
angle::Result ContextVk::handleDirtyVertexBuffers(const gl::Context *context,
const gl::DrawCallParams &drawCallParams,
vk::CommandBuffer *commandBuffer)
{
BindNonNullVertexBufferRanges(
commandBuffer, mProgram->getState().getActiveAttribLocationsMask(),
mProgram->getState().getMaxActiveAttribLocation(),
mVertexArray->getCurrentArrayBufferHandles(), mVertexArray->getCurrentArrayBufferOffsets());
const auto &arrayBufferResources = mVertexArray->getCurrentArrayBufferResources();
for (size_t attribIndex : context->getStateCache().getActiveBufferedAttribsMask())
{
if (arrayBufferResources[attribIndex])
arrayBufferResources[attribIndex]->addReadDependency(mDrawFramebuffer);
}
return angle::Result::Continue();
}
angle::Result ContextVk::handleDirtyIndexBuffer(const gl::Context *context,
const gl::DrawCallParams &drawCallParams,
vk::CommandBuffer *commandBuffer)
{
commandBuffer->bindIndexBuffer(mVertexArray->getCurrentElementArrayBufferHandle(),
mVertexArray->getCurrentElementArrayBufferOffset(),
gl_vk::GetIndexType(mCurrentDrawElementsType));
vk::CommandGraphResource *elementArrayBufferResource =
mVertexArray->getCurrentElementArrayBufferResource();
if (elementArrayBufferResource)
{
elementArrayBufferResource->addReadDependency(mDrawFramebuffer);
}
return angle::Result::Continue();
}
angle::Result ContextVk::handleDirtyDescriptorSets(const gl::Context *context,
const gl::DrawCallParams &drawCallParams,
vk::CommandBuffer *commandBuffer)
{
ANGLE_TRY(mProgram->updateDescriptorSets(this, drawCallParams, commandBuffer));
// Bind the graphics descriptor sets.
commandBuffer->bindDescriptorSets(
VK_PIPELINE_BIND_POINT_GRAPHICS, mProgram->getPipelineLayout(),
kDriverUniformsDescriptorSetIndex, 1, &mDriverUniformsDescriptorSet, 0, nullptr);
return angle::Result::Continue();
}
gl::Error ContextVk::drawArrays(const gl::Context *context,
gl::PrimitiveMode mode,
GLint first,
......@@ -1182,19 +1207,6 @@ void ContextVk::invalidateDefaultAttributes(const gl::AttributesMask &dirtyMask)
}
}
angle::Result ContextVk::updateDefaultAttributes()
{
ASSERT(mDirtyDefaultAttribsMask.any());
for (size_t attribIndex : mDirtyDefaultAttribsMask)
{
ANGLE_TRY(updateDefaultAttribute(attribIndex))
}
mDirtyDefaultAttribsMask.reset();
return angle::Result::Continue();
}
angle::Result ContextVk::updateDefaultAttribute(size_t attribIndex)
{
vk::DynamicBuffer &defaultBuffer = mDefaultAttribBuffers[attribIndex];
......
......@@ -191,10 +191,16 @@ class ContextVk : public ContextImpl, public vk::Context
using DirtyBits = angle::BitSet<DIRTY_BIT_MAX>;
using DirtyBitHandler = angle::Result (ContextVk::*)(const gl::Context *,
const gl::DrawCallParams &,
vk::CommandBuffer *commandBuffer);
std::array<DirtyBitHandler, DIRTY_BIT_MAX> mDirtyBitHandlers;
angle::Result initPipeline(const gl::DrawCallParams &drawCallParams);
angle::Result setupDraw(const gl::Context *context,
const gl::DrawCallParams &drawCallParams,
const DirtyBits &dirtyBitsMask,
DirtyBits dirtyBitMask,
vk::CommandBuffer **commandBufferOut);
angle::Result setupIndexedDraw(const gl::Context *context,
const gl::DrawCallParams &drawCallParams,
......@@ -209,11 +215,29 @@ class ContextVk : public ContextImpl, public vk::Context
angle::Result updateDriverUniforms(const gl::State &glState);
angle::Result updateActiveTextures(const gl::Context *context);
angle::Result updateDefaultAttributes();
angle::Result updateDefaultAttribute(size_t attribIndex);
void invalidateCurrentTextures();
angle::Result handleDirtyDefaultAttribs(const gl::Context *context,
const gl::DrawCallParams &drawCallParams,
vk::CommandBuffer *commandBuffer);
angle::Result handleDirtyPipeline(const gl::Context *context,
const gl::DrawCallParams &drawCallParams,
vk::CommandBuffer *commandBuffer);
angle::Result handleDirtyTextures(const gl::Context *context,
const gl::DrawCallParams &drawCallParams,
vk::CommandBuffer *commandBuffer);
angle::Result handleDirtyVertexBuffers(const gl::Context *context,
const gl::DrawCallParams &drawCallParams,
vk::CommandBuffer *commandBuffer);
angle::Result handleDirtyIndexBuffer(const gl::Context *context,
const gl::DrawCallParams &drawCallParams,
vk::CommandBuffer *commandBuffer);
angle::Result handleDirtyDescriptorSets(const gl::Context *context,
const gl::DrawCallParams &drawCallParams,
vk::CommandBuffer *commandBuffer);
vk::PipelineAndSerial *mCurrentPipeline;
gl::PrimitiveMode mCurrentDrawMode;
......
......@@ -176,8 +176,7 @@ bool ProgramVk::ShaderInfo::valid() const
// ProgramVk implementation.
ProgramVk::DefaultUniformBlock::DefaultUniformBlock()
: storage(VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
kUniformBlockDynamicBufferMinSize),
uniformsDirty(false)
kUniformBlockDynamicBufferMinSize)
{
}
......@@ -397,9 +396,6 @@ angle::Result ProgramVk::initDefaultUniformBlocks(const gl::Context *glContext)
}
}
bool anyDirty = false;
bool allDirty = true;
for (vk::ShaderType shaderType : vk::AllShaderTypes())
{
if (requiredBufferSize[shaderType] > 0)
......@@ -416,20 +412,14 @@ angle::Result ProgramVk::initDefaultUniformBlocks(const gl::Context *glContext)
// Initialize uniform buffer memory to zero by default.
mDefaultUniformBlocks[shaderType].uniformData.fill(0);
mDefaultUniformBlocks[shaderType].uniformsDirty = true;
anyDirty = true;
}
else
{
allDirty = false;
mDefaultUniformBlocksDirty.set(shaderType);
}
}
if (anyDirty)
if (mDefaultUniformBlocksDirty.any())
{
// Initialize the "empty" uniform block if necessary.
if (!allDirty)
if (!mDefaultUniformBlocksDirty.all())
{
VkBufferCreateInfo uniformBufferInfo;
uniformBufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
......@@ -475,8 +465,9 @@ void ProgramVk::setUniformImpl(GLint location, GLsizei count, const T *v, GLenum
if (linkedUniform.typeInfo->type == entryPointType)
{
for (auto &uniformBlock : mDefaultUniformBlocks)
for (vk::ShaderType shaderType : vk::AllShaderTypes())
{
DefaultUniformBlock &uniformBlock = mDefaultUniformBlocks[shaderType];
const sh::BlockMemberInfo &layoutInfo = uniformBlock.uniformLayout[location];
// Assume an offset of -1 means the block is unused.
......@@ -488,13 +479,14 @@ void ProgramVk::setUniformImpl(GLint location, GLsizei count, const T *v, GLenum
const GLint componentCount = linkedUniform.typeInfo->componentCount;
UpdateDefaultUniformBlock(count, locationInfo.arrayIndex, componentCount, v, layoutInfo,
&uniformBlock.uniformData);
uniformBlock.uniformsDirty = true;
mDefaultUniformBlocksDirty.set(shaderType);
}
}
else
{
for (auto &uniformBlock : mDefaultUniformBlocks)
for (vk::ShaderType shaderType : vk::AllShaderTypes())
{
DefaultUniformBlock &uniformBlock = mDefaultUniformBlocks[shaderType];
const sh::BlockMemberInfo &layoutInfo = uniformBlock.uniformLayout[location];
// Assume an offset of -1 means the block is unused.
......@@ -521,7 +513,8 @@ void ProgramVk::setUniformImpl(GLint location, GLsizei count, const T *v, GLenum
dest[c] = (source[c] == static_cast<T>(0)) ? GL_FALSE : GL_TRUE;
}
}
uniformBlock.uniformsDirty = true;
mDefaultUniformBlocksDirty.set(shaderType);
}
}
}
......@@ -626,8 +619,9 @@ void ProgramVk::setUniformMatrixfv(GLint location,
const gl::VariableLocation &locationInfo = mState.getUniformLocations()[location];
const gl::LinkedUniform &linkedUniform = mState.getUniforms()[locationInfo.index];
for (auto &uniformBlock : mDefaultUniformBlocks)
for (vk::ShaderType shaderType : vk::AllShaderTypes())
{
DefaultUniformBlock &uniformBlock = mDefaultUniformBlocks[shaderType];
const sh::BlockMemberInfo &layoutInfo = uniformBlock.uniformLayout[location];
// Assume an offset of -1 means the block is unused.
......@@ -643,7 +637,10 @@ void ProgramVk::setUniformMatrixfv(GLint location,
// If the uniformsDirty flag was true, we don't want to flip it to false here if the
// setter did not update any data. We still want the uniform to be included when we'll
// update the descriptor sets.
uniformBlock.uniformsDirty = uniformBlock.uniformsDirty || updated;
if (updated)
{
mDefaultUniformBlocksDirty.set(shaderType);
}
}
}
......@@ -787,13 +784,13 @@ angle::Result ProgramVk::updateUniforms(ContextVk *contextVk)
{
DefaultUniformBlock &uniformBlock = mDefaultUniformBlocks[shaderType];
if (uniformBlock.uniformsDirty)
if (mDefaultUniformBlocksDirty[shaderType])
{
bool bufferModified = false;
ANGLE_TRY(SyncDefaultUniformBlock(contextVk, &uniformBlock.storage,
uniformBlock.uniformData,
&mUniformBlocksOffsets[shaderType], &bufferModified));
uniformBlock.uniformsDirty = false;
mDefaultUniformBlocksDirty.reset(shaderType);
if (bufferModified)
{
......
......@@ -116,11 +116,7 @@ class ProgramVk : public ProgramImpl
bool hasTextures() const { return !mState.getSamplerBindings().empty(); }
bool dirtyUniforms() const
{
return (mDefaultUniformBlocks[vk::ShaderType::VertexShader].uniformsDirty ||
mDefaultUniformBlocks[vk::ShaderType::FragmentShader].uniformsDirty);
}
bool dirtyUniforms() const { return mDefaultUniformBlocksDirty.any(); }
private:
template <int cols, int rows>
......@@ -154,7 +150,6 @@ class ProgramVk : public ProgramImpl
// Shadow copies of the shader uniform data.
angle::MemoryBuffer uniformData;
bool uniformsDirty;
// Since the default blocks are laid out in std140, this tells us where to write on a call
// to a setUniform method. They are arranged in uniform location order.
......@@ -162,6 +157,7 @@ class ProgramVk : public ProgramImpl
};
vk::ShaderMap<DefaultUniformBlock> mDefaultUniformBlocks;
vk::ShaderBitSet mDefaultUniformBlocksDirty;
vk::ShaderMap<uint32_t> mUniformBlocksOffsets;
// This is a special "empty" placeholder buffer for when a shader has no uniforms.
......
......@@ -679,6 +679,8 @@ enum class ShaderType
template <typename T>
using ShaderMap = angle::PackedEnumMap<ShaderType, T>;
using ShaderBitSet = angle::PackedEnumBitSet<ShaderType>;
using AllShaderTypes = angle::AllEnums<vk::ShaderType>;
angle::Result InitShaderAndSerial(Context *context,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment