Commit 06ca634e by Jamie Madill Committed by Commit Bot

Vulkan: Refactor for draw call shader patching.

This refactors a few methods to enable draw call shader patching. The shader serials in the Pipeline description are inserted right before we query the pipeline cache. This is done during a draw call. Also renames the 'QueueSerial' member of the ObjectAndSerial class to just 'Serial' to more accurately reflect it usage in ShaderAndSerial. Also changes the GlslangWrapper class to have all static methods. If we need to store state we can revert these changes at some point. Also splits the GlslangWrapper link call into two static calls. One call is called to get the linked source code. The second call compiles the linked sources into shader code. Only the second call will be necessary for draw call shader patching to implement OpenGL line rasterization in Vulkan. Bug: angleproject:2598 Change-Id: I7bad3c3eeab1fb062c15a840836db4a28f841a26 Reviewed-on: https://chromium-review.googlesource.com/1127158 Commit-Queue: Jamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarGeoff Lang <geofflang@chromium.org>
parent d9618bf4
......@@ -141,7 +141,7 @@ gl::Error ContextVk::finish(const gl::Context *context)
return mRenderer->finish(this);
}
gl::Error ContextVk::initPipeline()
gl::Error ContextVk::initPipeline(const gl::DrawCallParams &drawCallParams)
{
ASSERT(!mCurrentPipeline);
......@@ -161,9 +161,20 @@ gl::Error ContextVk::initPipeline()
// Ensure that the RenderPass description is updated.
mPipelineDesc->updateRenderPassDesc(framebufferVk->getRenderPassDesc());
// TODO(jmadill): Validate with ASSERT against physical device limits/caps?
ANGLE_TRY(mRenderer->getAppPipeline(this, programVk, *mPipelineDesc, activeAttribLocationsMask,
&mCurrentPipeline));
// Trigger draw call shader patching and fill out the pipeline desc.
const vk::ShaderAndSerial *vertexShaderAndSerial = nullptr;
const vk::ShaderAndSerial *fragmentShaderAndSerial = nullptr;
ANGLE_TRY(programVk->initShaders(this, drawCallParams, &vertexShaderAndSerial,
&fragmentShaderAndSerial));
mPipelineDesc->updateShaders(vertexShaderAndSerial->getSerial(),
fragmentShaderAndSerial->getSerial());
const vk::PipelineLayout &pipelineLayout = programVk->getPipelineLayout();
ANGLE_TRY(mRenderer->getPipeline(this, *vertexShaderAndSerial, *fragmentShaderAndSerial,
pipelineLayout, *mPipelineDesc, activeAttribLocationsMask,
&mCurrentPipeline));
return gl::NoError();
}
......@@ -181,7 +192,7 @@ gl::Error ContextVk::setupDraw(const gl::Context *context,
if (!mCurrentPipeline)
{
ANGLE_TRY(initPipeline());
ANGLE_TRY(initPipeline(drawCallParams));
}
const auto &state = mState.getState();
......@@ -603,7 +614,6 @@ gl::Error ContextVk::syncState(const gl::Context *context, const gl::State::Dirt
case gl::State::DIRTY_BIT_RENDERBUFFER_BINDING:
break;
case gl::State::DIRTY_BIT_VERTEX_ARRAY_BINDING:
invalidateCurrentPipeline();
mVertexArrayBindingHasChanged = true;
break;
case gl::State::DIRTY_BIT_DRAW_INDIRECT_BUFFER_BINDING:
......@@ -614,10 +624,8 @@ gl::Error ContextVk::syncState(const gl::Context *context, const gl::State::Dirt
break;
case gl::State::DIRTY_BIT_PROGRAM_EXECUTABLE:
{
ProgramVk *programVk = vk::GetImpl(glState.getProgram());
mPipelineDesc->updateShaders(programVk->getVertexModuleSerial(),
programVk->getFragmentModuleSerial());
dirtyTextures = true;
// No additional work is needed here. We will update the pipeline desc later.
break;
}
case gl::State::DIRTY_BIT_TEXTURE_BINDINGS:
......
......@@ -172,7 +172,7 @@ class ContextVk : public ContextImpl, public vk::Context
void handleError(VkResult errorCode, const char *file, unsigned int line) override;
private:
gl::Error initPipeline();
gl::Error initPipeline(const gl::DrawCallParams &drawCallParams);
gl::Error setupDraw(const gl::Context *context,
const gl::DrawCallParams &drawCallParams,
vk::CommandBuffer **commandBufferOut,
......
......@@ -1022,7 +1022,7 @@ angle::Result FramebufferVk::clearWithDraw(ContextVk *contextVk,
pipelineDesc.initDefaults();
pipelineDesc.updateColorWriteMask(colorMaskFlags, getEmulatedAlphaAttachmentMask());
pipelineDesc.updateRenderPassDesc(getRenderPassDesc());
pipelineDesc.updateShaders(fullScreenQuad->queueSerial(), pushConstantColor->queueSerial());
pipelineDesc.updateShaders(fullScreenQuad->getSerial(), pushConstantColor->getSerial());
pipelineDesc.updateViewport(this, renderArea, 0.0f, 1.0f, invertViewport);
const gl::State &glState = contextVk->getGLState();
......@@ -1042,9 +1042,9 @@ angle::Result FramebufferVk::clearWithDraw(ContextVk *contextVk,
}
vk::PipelineAndSerial *pipeline = nullptr;
ANGLE_TRY(renderer->getInternalPipeline(contextVk, *fullScreenQuad, *pushConstantColor,
pipelineLayout.get(), pipelineDesc,
gl::AttributesMask(), &pipeline));
ANGLE_TRY(renderer->getPipeline(contextVk, *fullScreenQuad, *pushConstantColor,
pipelineLayout.get(), pipelineDesc, gl::AttributesMask(),
&pipeline));
pipeline->updateSerial(renderer->getCurrentQueueSerial());
vk::CommandBuffer *writeCommands = nullptr;
......
......@@ -121,53 +121,25 @@ std::string GetMappedSamplerName(const std::string &originalName)
} // anonymous namespace
// static
GlslangWrapper *GlslangWrapper::mInstance = nullptr;
// static
GlslangWrapper *GlslangWrapper::GetReference()
{
if (!mInstance)
{
mInstance = new GlslangWrapper();
}
mInstance->addRef();
return mInstance;
}
// static
void GlslangWrapper::ReleaseReference()
{
if (mInstance->getRefCount() == 1)
{
mInstance->release();
mInstance = nullptr;
}
else
{
mInstance->release();
}
}
GlslangWrapper::GlslangWrapper()
void GlslangWrapper::Initialize()
{
int result = ShInitialize();
ASSERT(result != 0);
}
GlslangWrapper::~GlslangWrapper()
// static
void GlslangWrapper::Release()
{
int result = ShFinalize();
ASSERT(result != 0);
}
gl::LinkResult GlslangWrapper::linkProgram(const gl::Context *glContext,
const gl::ProgramState &programState,
const gl::ProgramLinkedResources &resources,
const gl::Caps &glCaps,
std::vector<uint32_t> *vertexCodeOut,
std::vector<uint32_t> *fragmentCodeOut)
// static
void GlslangWrapper::GetShaderSource(const gl::Context *glContext,
const gl::ProgramState &programState,
const gl::ProgramLinkedResources &resources,
std::string *vertexSourceOut,
std::string *fragmentSourceOut)
{
gl::Shader *glVertexShader = programState.getAttachedShader(gl::ShaderType::Vertex);
gl::Shader *glFragmentShader = programState.getAttachedShader(gl::ShaderType::Fragment);
......@@ -308,6 +280,17 @@ gl::LinkResult GlslangWrapper::linkProgram(const gl::Context *glContext,
InsertQualifierSpecifierString(&vertexSource, kDriverBlockName, kUniformQualifier);
InsertQualifierSpecifierString(&fragmentSource, kDriverBlockName, kUniformQualifier);
*vertexSourceOut = vertexSource;
*fragmentSourceOut = fragmentSource;
}
// static
gl::LinkResult GlslangWrapper::GetShaderCode(const gl::Caps &glCaps,
const std::string &vertexSource,
const std::string &fragmentSource,
std::vector<uint32_t> *vertexCodeOut,
std::vector<uint32_t> *fragmentCodeOut)
{
std::array<const char *, 2> strings = {{vertexSource.c_str(), fragmentSource.c_str()}};
std::array<int, 2> lengths = {
{static_cast<int>(vertexSource.length()), static_cast<int>(fragmentSource.length())}};
......@@ -360,5 +343,4 @@ gl::LinkResult GlslangWrapper::linkProgram(const gl::Context *glContext,
return true;
}
} // namespace rx
......@@ -9,32 +9,29 @@
#ifndef LIBANGLE_RENDERER_VULKAN_GLSLANG_WRAPPER_H_
#define LIBANGLE_RENDERER_VULKAN_GLSLANG_WRAPPER_H_
#include "libANGLE/RefCountObject.h"
#include "libANGLE/renderer/ProgramImpl.h"
namespace rx
{
class GlslangWrapper : public gl::RefCountObjectNoID
// This class currently holds no state. If we want to hold state we would need to solve the
// potential race conditions with multiple threads.
class GlslangWrapper
{
public:
// Increases the reference count.
// TODO(jmadill): Determine how to handle this atomically.
static GlslangWrapper *GetReference();
static void ReleaseReference();
gl::LinkResult linkProgram(const gl::Context *glContext,
const gl::ProgramState &programState,
const gl::ProgramLinkedResources &resources,
const gl::Caps &glCaps,
std::vector<uint32_t> *vertexCodeOut,
std::vector<uint32_t> *fragmentCodeOut);
private:
GlslangWrapper();
~GlslangWrapper() override;
static GlslangWrapper *mInstance;
static void Initialize();
static void Release();
static void GetShaderSource(const gl::Context *glContext,
const gl::ProgramState &programState,
const gl::ProgramLinkedResources &resources,
std::string *vertexSourceOut,
std::string *fragmentSourceOut);
static gl::LinkResult GetShaderCode(const gl::Caps &glCaps,
const std::string &vertexSource,
const std::string &fragmentSource,
std::vector<uint32_t> *vertexCodeOut,
std::vector<uint32_t> *fragmentCodeOut);
};
} // namespace rx
......
......@@ -186,10 +186,8 @@ angle::Result ProgramVk::reset(ContextVk *contextVk)
renderer->releaseObject(currentSerial, &mEmptyUniformBlockStorage.memory);
renderer->releaseObject(currentSerial, &mEmptyUniformBlockStorage.buffer);
mLinkedFragmentModule.destroy(device);
mLinkedVertexModule.destroy(device);
mVertexModuleSerial = Serial();
mFragmentModuleSerial = Serial();
mDefaultVertexShaderAndSerial.destroy(device);
mDefaultFragmentShaderAndSerial.destroy(device);
mDescriptorSets.clear();
mUsedDescriptorSetRange.invalidate();
......@@ -225,17 +223,20 @@ gl::LinkResult ProgramVk::link(const gl::Context *glContext,
const gl::ProgramLinkedResources &resources,
gl::InfoLog &infoLog)
{
ContextVk *contextVk = vk::GetImpl(glContext);
RendererVk *renderer = contextVk->getRenderer();
GlslangWrapper *glslangWrapper = renderer->getGlslangWrapper();
ContextVk *contextVk = vk::GetImpl(glContext);
RendererVk *renderer = contextVk->getRenderer();
ANGLE_TRY(reset(contextVk));
std::string vertexSource;
std::string fragmentSource;
GlslangWrapper::GetShaderSource(glContext, mState, resources, &vertexSource, &fragmentSource);
std::vector<uint32_t> vertexCode;
std::vector<uint32_t> fragmentCode;
bool linkSuccess = false;
ANGLE_TRY_RESULT(glslangWrapper->linkProgram(glContext, mState, resources, glContext->getCaps(),
&vertexCode, &fragmentCode),
ANGLE_TRY_RESULT(GlslangWrapper::GetShaderCode(glContext->getCaps(), vertexSource,
fragmentSource, &vertexCode, &fragmentCode),
linkSuccess);
if (!linkSuccess)
{
......@@ -250,8 +251,8 @@ gl::LinkResult ProgramVk::link(const gl::Context *glContext,
vertexShaderInfo.codeSize = vertexCode.size() * sizeof(uint32_t);
vertexShaderInfo.pCode = vertexCode.data();
ANGLE_TRY(mLinkedVertexModule.init(contextVk, vertexShaderInfo));
mVertexModuleSerial = renderer->issueShaderSerial();
ANGLE_TRY(mDefaultVertexShaderAndSerial.get().init(contextVk, vertexShaderInfo));
mDefaultVertexShaderAndSerial.updateSerial(renderer->issueShaderSerial());
}
{
......@@ -262,8 +263,8 @@ gl::LinkResult ProgramVk::link(const gl::Context *glContext,
fragmentShaderInfo.codeSize = fragmentCode.size() * sizeof(uint32_t);
fragmentShaderInfo.pCode = fragmentCode.data();
ANGLE_TRY(mLinkedFragmentModule.init(contextVk, fragmentShaderInfo));
mFragmentModuleSerial = renderer->issueShaderSerial();
ANGLE_TRY(mDefaultFragmentShaderAndSerial.get().init(contextVk, fragmentShaderInfo));
mDefaultFragmentShaderAndSerial.updateSerial(renderer->issueShaderSerial());
}
ANGLE_TRY(initDefaultUniformBlocks(glContext));
......@@ -717,26 +718,18 @@ void ProgramVk::setPathFragmentInputGen(const std::string &inputName,
UNIMPLEMENTED();
}
const vk::ShaderModule &ProgramVk::getLinkedVertexModule() const
gl::Error ProgramVk::initShaders(const ContextVk *contextVk,
const gl::DrawCallParams &drawCallParams,
const vk::ShaderAndSerial **vertexShaderAndSerialOut,
const vk::ShaderAndSerial **fragmentShaderAndSerialOut)
{
ASSERT(mLinkedVertexModule.getHandle() != VK_NULL_HANDLE);
return mLinkedVertexModule;
}
Serial ProgramVk::getVertexModuleSerial() const
{
return mVertexModuleSerial;
}
const vk::ShaderModule &ProgramVk::getLinkedFragmentModule() const
{
ASSERT(mLinkedFragmentModule.getHandle() != VK_NULL_HANDLE);
return mLinkedFragmentModule;
}
Serial ProgramVk::getFragmentModuleSerial() const
{
return mFragmentModuleSerial;
// TODO(jmadill): Move more init into this method. http://anglebug.com/2598
// TODO(jmadill): Line rasterization emulation shaders. http://anglebug.com/2598
ASSERT(mDefaultVertexShaderAndSerial.valid());
ASSERT(mDefaultFragmentShaderAndSerial.valid());
*vertexShaderAndSerialOut = &mDefaultVertexShaderAndSerial;
*fragmentShaderAndSerialOut = &mDefaultFragmentShaderAndSerial;
return gl::NoError();
}
angle::Result ProgramVk::allocateDescriptorSet(ContextVk *contextVk, uint32_t descriptorSetIndex)
......
......@@ -99,10 +99,11 @@ class ProgramVk : public ProgramImpl
GLint components,
const GLfloat *coeffs) override;
const vk::ShaderModule &getLinkedVertexModule() const;
Serial getVertexModuleSerial() const;
const vk::ShaderModule &getLinkedFragmentModule() const;
Serial getFragmentModuleSerial() const;
// Also initializes the pipeline layout, descriptor set layouts, and used descriptor ranges.
gl::Error initShaders(const ContextVk *contextVk,
const gl::DrawCallParams &drawCallParams,
const vk::ShaderAndSerial **vertexShaderAndSerialOut,
const vk::ShaderAndSerial **fragmentShaderAndSerialOut);
angle::Result updateUniforms(ContextVk *contextVk);
......@@ -144,10 +145,8 @@ class ProgramVk : public ProgramImpl
template <typename T>
void setUniformImpl(GLint location, GLsizei count, const T *v, GLenum entryPointType);
vk::ShaderModule mLinkedVertexModule;
Serial mVertexModuleSerial;
vk::ShaderModule mLinkedFragmentModule;
Serial mFragmentModuleSerial;
vk::ShaderAndSerial mDefaultVertexShaderAndSerial;
vk::ShaderAndSerial mDefaultFragmentShaderAndSerial;
// State for the default uniform blocks.
struct DefaultUniformBlock final : private angle::NonCopyable
......
......@@ -259,7 +259,6 @@ RendererVk::RendererVk()
mQueue(VK_NULL_HANDLE),
mCurrentQueueFamilyIndex(std::numeric_limits<uint32_t>::max()),
mDevice(VK_NULL_HANDLE),
mGlslangWrapper(nullptr),
mLastCompletedQueueSerial(mQueueSerialFactory.generate()),
mCurrentQueueSerial(mQueueSerialFactory.generate())
{
......@@ -284,11 +283,7 @@ void RendererVk::onDestroy(vk::Context *context)
mPipelineCache.destroy(mDevice);
mShaderLibrary.destroy(mDevice);
if (mGlslangWrapper)
{
GlslangWrapper::ReleaseReference();
mGlslangWrapper = nullptr;
}
GlslangWrapper::Release();
if (mCommandPool.valid())
{
......@@ -469,7 +464,7 @@ angle::Result RendererVk::initialize(vk::Context *context,
// Store the physical device memory properties so we can find the right memory pools.
mMemoryProperties.init(mPhysicalDevice);
mGlslangWrapper = GlslangWrapper::GetReference();
GlslangWrapper::Initialize();
// Initialize the format table.
mFormatTable.initialize(mPhysicalDevice, &mNativeTextureCaps,
......@@ -830,11 +825,6 @@ angle::Result RendererVk::submitFrame(vk::Context *context,
return angle::Result::Continue();
}
GlslangWrapper *RendererVk::getGlslangWrapper() const
{
return mGlslangWrapper;
}
Serial RendererVk::getCurrentQueueSerial() const
{
return mCurrentQueueSerial;
......@@ -902,39 +892,17 @@ Serial RendererVk::issueShaderSerial()
return mShaderSerialFactory.generate();
}
angle::Result RendererVk::getAppPipeline(vk::Context *context,
const ProgramVk *programVk,
const vk::PipelineDesc &desc,
const gl::AttributesMask &activeAttribLocationsMask,
vk::PipelineAndSerial **pipelineOut)
{
ASSERT(programVk->getVertexModuleSerial() ==
desc.getShaderStageInfo()[vk::ShaderType::VertexShader].moduleSerial);
ASSERT(programVk->getFragmentModuleSerial() ==
desc.getShaderStageInfo()[vk::ShaderType::FragmentShader].moduleSerial);
// Pull in a compatible RenderPass.
vk::RenderPass *compatibleRenderPass = nullptr;
ANGLE_TRY(getCompatibleRenderPass(context, desc.getRenderPassDesc(), &compatibleRenderPass));
const vk::PipelineLayout &pipelineLayout = programVk->getPipelineLayout();
return mPipelineCache.getPipeline(context, *compatibleRenderPass, pipelineLayout,
activeAttribLocationsMask, programVk->getLinkedVertexModule(),
programVk->getLinkedFragmentModule(), desc, pipelineOut);
}
angle::Result RendererVk::getInternalPipeline(vk::Context *context,
const vk::ShaderAndSerial &vertexShader,
const vk::ShaderAndSerial &fragmentShader,
const vk::PipelineLayout &pipelineLayout,
const vk::PipelineDesc &pipelineDesc,
const gl::AttributesMask &activeAttribLocationsMask,
vk::PipelineAndSerial **pipelineOut)
angle::Result RendererVk::getPipeline(vk::Context *context,
const vk::ShaderAndSerial &vertexShader,
const vk::ShaderAndSerial &fragmentShader,
const vk::PipelineLayout &pipelineLayout,
const vk::PipelineDesc &pipelineDesc,
const gl::AttributesMask &activeAttribLocationsMask,
vk::PipelineAndSerial **pipelineOut)
{
ASSERT(vertexShader.queueSerial() ==
ASSERT(vertexShader.getSerial() ==
pipelineDesc.getShaderStageInfo()[vk::ShaderType::VertexShader].moduleSerial);
ASSERT(fragmentShader.queueSerial() ==
ASSERT(fragmentShader.getSerial() ==
pipelineDesc.getShaderStageInfo()[vk::ShaderType::FragmentShader].moduleSerial);
// Pull in a compatible RenderPass.
......
......@@ -28,7 +28,6 @@ class AttributeMap;
namespace rx
{
class FramebufferVk;
class GlslangWrapper;
namespace vk
{
......@@ -75,8 +74,6 @@ class RendererVk : angle::NonCopyable
const gl::Limitations &getNativeLimitations() const;
uint32_t getMaxActiveTextures();
GlslangWrapper *getGlslangWrapper() const;
Serial getCurrentQueueSerial() const;
bool isSerialInUse(Serial serial) const;
......@@ -114,21 +111,14 @@ class RendererVk : angle::NonCopyable
const vk::AttachmentOpsArray &ops,
vk::RenderPass **renderPassOut);
// For getting a vk::Pipeline for the an application's draw call. RenderPassDesc is automatic.
angle::Result getAppPipeline(vk::Context *context,
const ProgramVk *programVk,
const vk::PipelineDesc &desc,
const gl::AttributesMask &activeAttribLocationsMask,
vk::PipelineAndSerial **pipelineOut);
// For getting a vk::Pipeline for an internal draw call. Use an explicit RenderPass.
angle::Result getInternalPipeline(vk::Context *context,
const vk::ShaderAndSerial &vertexShader,
const vk::ShaderAndSerial &fragmentShader,
const vk::PipelineLayout &pipelineLayout,
const vk::PipelineDesc &pipelineDesc,
const gl::AttributesMask &activeAttribLocationsMask,
vk::PipelineAndSerial **pipelineOut);
// For getting a vk::Pipeline and checking the pipeline cache.
angle::Result getPipeline(vk::Context *context,
const vk::ShaderAndSerial &vertexShader,
const vk::ShaderAndSerial &fragmentShader,
const vk::PipelineLayout &pipelineLayout,
const vk::PipelineDesc &pipelineDesc,
const gl::AttributesMask &activeAttribLocationsMask,
vk::PipelineAndSerial **pipelineOut);
// Queries the descriptor set layout cache. Creates the layout if not present.
angle::Result getDescriptorSetLayout(
......@@ -180,7 +170,6 @@ class RendererVk : angle::NonCopyable
uint32_t mCurrentQueueFamilyIndex;
VkDevice mDevice;
vk::CommandPool mCommandPool;
GlslangWrapper *mGlslangWrapper;
SerialFactory mQueueSerialFactory;
SerialFactory mShaderSerialFactory;
Serial mLastCompletedQueueSerial;
......
......@@ -611,37 +611,36 @@ class ObjectAndSerial final : angle::NonCopyable
public:
ObjectAndSerial() {}
ObjectAndSerial(ObjT &&object, Serial queueSerial)
: mObject(std::move(object)), mQueueSerial(queueSerial)
{
}
ObjectAndSerial(ObjT &&object, Serial serial) : mObject(std::move(object)), mSerial(serial) {}
ObjectAndSerial(ObjectAndSerial &&other)
: mObject(std::move(other.mObject)), mQueueSerial(std::move(other.mQueueSerial))
: mObject(std::move(other.mObject)), mSerial(std::move(other.mSerial))
{
}
ObjectAndSerial &operator=(ObjectAndSerial &&other)
{
mObject = std::move(other.mObject);
mQueueSerial = std::move(other.mQueueSerial);
mObject = std::move(other.mObject);
mSerial = std::move(other.mSerial);
return *this;
}
Serial queueSerial() const { return mQueueSerial; }
void updateSerial(Serial newSerial)
{
ASSERT(newSerial >= mQueueSerial);
mQueueSerial = newSerial;
}
Serial getSerial() const { return mSerial; }
void updateSerial(Serial newSerial) { mSerial = newSerial; }
const ObjT &get() const { return mObject; }
ObjT &get() { return mObject; }
bool valid() const { return mObject.valid(); }
void destroy(VkDevice device)
{
mObject.destroy(device);
mSerial = Serial();
}
private:
ObjT mObject;
Serial mQueueSerial;
Serial mSerial;
};
angle::Result AllocateBufferMemory(vk::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