Commit f92fc916 by Shahbaz Youssefi Committed by Commit Bot

Vulkan: Compute shader support

A DispatchHelper class is created as the equivalent of FramebufferHelper as a command graph resource. There's currently a single dispatcher and all dispatch calls are recorded on that. Context dirty bits are set up in such a way that graphics and compute workloads are independently handled, so that issuing a dispatch call wouldn't cause a framebuffer's render pass to rebind resources. Bug: angleproject:3562 Change-Id: Ib96db48297074d99b04324e44b067cfbfd43e333 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/1688504 Commit-Queue: Shahbaz Youssefi <syoussefi@chromium.org> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org>
parent 6e7dd1ef
......@@ -1429,6 +1429,16 @@ bool TCompiler::isVaryingDefined(const char *varyingName)
return false;
}
void EmitWorkGroupSizeGLSL(const TCompiler &compiler, TInfoSinkBase &sink)
{
if (compiler.isComputeShaderLocalSizeDeclared())
{
const sh::WorkGroupSize &localSize = compiler.getComputeShaderLocalSize();
sink << "layout (local_size_x=" << localSize[0] << ", local_size_y=" << localSize[1]
<< ", local_size_z=" << localSize[2] << ") in;\n";
}
}
void EmitMultiviewGLSL(const TCompiler &compiler,
const ShCompileOptions &compileOptions,
const TBehavior behavior,
......
......@@ -296,6 +296,7 @@ class TCompiler : public TShHandleBase
TCompiler *ConstructCompiler(sh::GLenum type, ShShaderSpec spec, ShShaderOutput output);
void DeleteCompiler(TCompiler *);
void EmitWorkGroupSizeGLSL(const TCompiler &, TInfoSinkBase &sink);
void EmitMultiviewGLSL(const TCompiler &, const ShCompileOptions &, TBehavior, TInfoSinkBase &sink);
} // namespace sh
......
......@@ -84,11 +84,9 @@ void TranslatorESSL::translate(TIntermBlock *root,
// Write array bounds clamping emulation if needed.
getArrayBoundsClamper().OutputClampingFunctionDefinition(sink);
if (getShaderType() == GL_COMPUTE_SHADER && isComputeShaderLocalSizeDeclared())
if (getShaderType() == GL_COMPUTE_SHADER)
{
const sh::WorkGroupSize &localSize = getComputeShaderLocalSize();
sink << "layout (local_size_x=" << localSize[0] << ", local_size_y=" << localSize[1]
<< ", local_size_z=" << localSize[2] << ") in;\n";
EmitWorkGroupSizeGLSL(*this, sink);
}
if (getShaderType() == GL_GEOMETRY_SHADER_EXT)
......
......@@ -194,11 +194,9 @@ void TranslatorGLSL::translate(TIntermBlock *root,
}
}
if (getShaderType() == GL_COMPUTE_SHADER && isComputeShaderLocalSizeDeclared())
if (getShaderType() == GL_COMPUTE_SHADER)
{
const sh::WorkGroupSize &localSize = getComputeShaderLocalSize();
sink << "layout (local_size_x=" << localSize[0] << ", local_size_y=" << localSize[1]
<< ", local_size_z=" << localSize[2] << ") in;\n";
EmitWorkGroupSizeGLSL(*this, sink);
}
if (getShaderType() == GL_GEOMETRY_SHADER_EXT)
......
......@@ -692,9 +692,12 @@ void TranslatorVulkan::translate(TIntermBlock *root,
sink << "};\n";
}
const TVariable *driverUniforms = AddDriverUniformsToShader(root, &getSymbolTable());
ReplaceGLDepthRangeWithDriverUniform(root, driverUniforms, &getSymbolTable());
const TVariable *driverUniforms = nullptr;
if (getShaderType() != GL_COMPUTE_SHADER)
{
driverUniforms = AddDriverUniformsToShader(root, &getSymbolTable());
ReplaceGLDepthRangeWithDriverUniform(root, driverUniforms, &getSymbolTable());
}
// Declare gl_FragColor and glFragData as webgl_FragColor and webgl_FragData
// if it's core profile shaders and they are used.
......@@ -775,10 +778,8 @@ void TranslatorVulkan::translate(TIntermBlock *root,
RewriteDfdy(root, getSymbolTable(), getShaderVersion(), viewportYScale);
}
}
else
else if (getShaderType() == GL_VERTEX_SHADER)
{
ASSERT(getShaderType() == GL_VERTEX_SHADER);
AddANGLEPositionVarying(root, &getSymbolTable());
// Add a macro to declare transform feedback buffers.
......@@ -790,6 +791,11 @@ void TranslatorVulkan::translate(TIntermBlock *root,
// Append depth range translation to main.
AppendVertexShaderDepthCorrectionToMain(root, &getSymbolTable());
}
else
{
ASSERT(getShaderType() == GL_COMPUTE_SHADER);
EmitWorkGroupSizeGLSL(*this, sink);
}
// Write translated shader.
root->traverse(&outputGLSL);
......
......@@ -3344,18 +3344,22 @@ void Context::initCaps()
// Limit textures as well, so we can use fast bitsets with texture bindings.
LimitCap(&mState.mCaps.maxCombinedTextureImageUnits, IMPLEMENTATION_MAX_ACTIVE_TEXTURES);
LimitCap(&mState.mCaps.maxShaderTextureImageUnits[ShaderType::Vertex],
IMPLEMENTATION_MAX_ACTIVE_TEXTURES / 2);
LimitCap(&mState.mCaps.maxShaderTextureImageUnits[ShaderType::Fragment],
IMPLEMENTATION_MAX_ACTIVE_TEXTURES / 2);
for (ShaderType shaderType : AllShaderTypes())
{
LimitCap(&mState.mCaps.maxShaderTextureImageUnits[shaderType],
IMPLEMENTATION_MAX_SHADER_TEXTURES);
}
LimitCap(&mState.mCaps.maxImageUnits, IMPLEMENTATION_MAX_IMAGE_UNITS);
LimitCap(&mState.mCaps.maxCombinedAtomicCounterBuffers,
IMPLEMENTATION_MAX_ATOMIC_COUNTER_BUFFERS);
LimitCap(&mState.mCaps.maxShaderStorageBlocks[ShaderType::Compute],
IMPLEMENTATION_MAX_SHADER_STORAGE_BUFFER_BINDINGS);
for (ShaderType shaderType : AllShaderTypes())
{
LimitCap(&mState.mCaps.maxShaderStorageBlocks[shaderType],
IMPLEMENTATION_MAX_SHADER_STORAGE_BUFFER_BINDINGS);
}
LimitCap(&mState.mCaps.maxShaderStorageBufferBindings,
IMPLEMENTATION_MAX_SHADER_STORAGE_BUFFER_BINDINGS);
LimitCap(&mState.mCaps.maxCombinedShaderStorageBlocks,
......
......@@ -384,9 +384,10 @@ class ProgramState final : angle::NonCopyable
const ShaderBitSet &getLinkedShaderStages() const { return mLinkedShaderStages; }
bool hasLinkedShaderStage(ShaderType shaderType) const
{
return mLinkedShaderStages.test(shaderType);
return mLinkedShaderStages[shaderType];
}
size_t getLinkedShaderStageCount() const { return mLinkedShaderStages.count(); }
bool isCompute() const { return hasLinkedShaderStage(ShaderType::Compute); }
bool hasAttachedShader() const;
......@@ -588,8 +589,9 @@ class Program final : angle::NonCopyable, public LabeledObject
bool hasLinkedShaderStage(ShaderType shaderType) const
{
ASSERT(shaderType != ShaderType::InvalidEnum);
return mState.mLinkedShaderStages[shaderType];
return mState.hasLinkedShaderStage(shaderType);
}
bool isCompute() const { return mState.isCompute(); }
angle::Result loadBinary(const Context *context,
GLenum binaryFormat,
......
......@@ -231,10 +231,16 @@ angle::Result BufferVk::mapRangeImpl(ContextVk *contextVk,
angle::Result BufferVk::unmap(const gl::Context *context, GLboolean *result)
{
return unmapImpl(vk::GetImpl(context));
unmapImpl(vk::GetImpl(context));
// This should be false if the contents have been corrupted through external means. Vulkan
// doesn't provide such information.
*result = true;
return angle::Result::Continue;
}
angle::Result BufferVk::unmapImpl(ContextVk *contextVk)
void BufferVk::unmapImpl(ContextVk *contextVk)
{
ASSERT(mBuffer.valid());
......@@ -242,8 +248,6 @@ angle::Result BufferVk::unmapImpl(ContextVk *contextVk)
mBuffer.onExternalWrite(VK_ACCESS_HOST_WRITE_BIT);
markConversionBuffersDirty();
return angle::Result::Continue;
}
angle::Result BufferVk::getIndexRange(const gl::Context *context,
......
......@@ -97,7 +97,7 @@ class BufferVk : public BufferImpl
VkDeviceSize length,
GLbitfield access,
void **mapPtr);
angle::Result unmapImpl(ContextVk *contextVk);
void unmapImpl(ContextVk *contextVk);
// Calls copyBuffer internally.
angle::Result copyToBuffer(ContextVk *contextVk,
......
......@@ -88,6 +88,8 @@ const char *GetResourceTypeName(CommandGraphResourceType resourceType,
UNREACHABLE();
return "Query";
}
case CommandGraphResourceType::Dispatcher:
return "Dispatcher";
case CommandGraphResourceType::EmulatedQuery:
switch (function)
{
......@@ -1032,6 +1034,7 @@ void CommandGraph::dumpGraphDotFile(std::ostream &out) const
int framebufferIDCounter = 1;
int imageIDCounter = 1;
int queryIDCounter = 1;
int dispatcherIDCounter = 1;
int fenceIDCounter = 1;
int xfbIDCounter = 1;
......@@ -1107,6 +1110,9 @@ void CommandGraph::dumpGraphDotFile(std::ostream &out) const
case CommandGraphResourceType::Image:
id = imageIDCounter++;
break;
case CommandGraphResourceType::Dispatcher:
id = dispatcherIDCounter++;
break;
case CommandGraphResourceType::FenceSync:
id = fenceIDCounter++;
break;
......
......@@ -32,6 +32,7 @@ enum class CommandGraphResourceType
Framebuffer,
Image,
Query,
Dispatcher,
// Transform feedback queries could be handled entirely on the CPU (if not using
// VK_EXT_transform_feedback), but still need to generate a command graph barrier node.
EmulatedQuery,
......
......@@ -171,6 +171,7 @@ ContextVk::ContextVk(const gl::State &state, gl::ErrorSet *errorSet, RendererVk
: ContextImpl(state, errorSet),
vk::Context(renderer),
mCurrentGraphicsPipeline(nullptr),
mCurrentComputePipeline(nullptr),
mCurrentDrawMode(gl::PrimitiveMode::InvalidEnum),
mCurrentWindowSurface(nullptr),
mVertexArray(nullptr),
......@@ -209,6 +210,11 @@ ContextVk::ContextVk(const gl::State &state, gl::ErrorSet *errorSet, RendererVk
mNewGraphicsCommandBufferDirtyBits.set(DIRTY_BIT_TRANSFORM_FEEDBACK_BUFFERS);
mNewGraphicsCommandBufferDirtyBits.set(DIRTY_BIT_DESCRIPTOR_SETS);
mNewComputeCommandBufferDirtyBits.set(DIRTY_BIT_PIPELINE);
mNewComputeCommandBufferDirtyBits.set(DIRTY_BIT_TEXTURES);
mNewComputeCommandBufferDirtyBits.set(DIRTY_BIT_UNIFORM_AND_STORAGE_BUFFERS);
mNewComputeCommandBufferDirtyBits.set(DIRTY_BIT_DESCRIPTOR_SETS);
mGraphicsDirtyBitHandlers[DIRTY_BIT_DEFAULT_ATTRIBS] =
&ContextVk::handleDirtyGraphicsDefaultAttribs;
mGraphicsDirtyBitHandlers[DIRTY_BIT_PIPELINE] = &ContextVk::handleDirtyGraphicsPipeline;
......@@ -225,7 +231,15 @@ ContextVk::ContextVk(const gl::State &state, gl::ErrorSet *errorSet, RendererVk
mGraphicsDirtyBitHandlers[DIRTY_BIT_DESCRIPTOR_SETS] =
&ContextVk::handleDirtyGraphicsDescriptorSets;
mComputeDirtyBitHandlers[DIRTY_BIT_PIPELINE] = &ContextVk::handleDirtyComputePipeline;
mComputeDirtyBitHandlers[DIRTY_BIT_TEXTURES] = &ContextVk::handleDirtyComputeTextures;
mComputeDirtyBitHandlers[DIRTY_BIT_UNIFORM_AND_STORAGE_BUFFERS] =
&ContextVk::handleDirtyComputeUniformAndStorageBuffers;
mComputeDirtyBitHandlers[DIRTY_BIT_DESCRIPTOR_SETS] =
&ContextVk::handleDirtyComputeDescriptorSets;
mGraphicsDirtyBits = mNewGraphicsCommandBufferDirtyBits;
mComputeDirtyBits = mNewComputeCommandBufferDirtyBits;
mActiveTextures.fill(nullptr);
......@@ -502,6 +516,30 @@ angle::Result ContextVk::setupLineLoopDraw(const gl::Context *context,
mIndexedDirtyBitsMask, commandBufferOut);
}
angle::Result ContextVk::setupDispatch(const gl::Context *context,
vk::CommandBuffer **commandBufferOut)
{
ANGLE_TRY(mDispatcher.recordCommands(this, commandBufferOut));
if (mProgram->dirtyUniforms())
{
ANGLE_TRY(mProgram->updateUniforms(this));
mComputeDirtyBits.set(DIRTY_BIT_DESCRIPTOR_SETS);
}
DirtyBits dirtyBits = mComputeDirtyBits;
// Flush any relevant dirty bits.
for (size_t dirtyBit : dirtyBits)
{
ANGLE_TRY((this->*mComputeDirtyBitHandlers[dirtyBit])(context, *commandBufferOut));
}
mComputeDirtyBits.reset();
return angle::Result::Continue;
}
angle::Result ContextVk::handleDirtyGraphicsDefaultAttribs(const gl::Context *context,
vk::CommandBuffer *commandBuffer)
{
......@@ -557,18 +595,47 @@ angle::Result ContextVk::handleDirtyGraphicsPipeline(const gl::Context *context,
return angle::Result::Continue;
}
angle::Result ContextVk::handleDirtyGraphicsTextures(const gl::Context *context,
vk::CommandBuffer *commandBuffer)
angle::Result ContextVk::handleDirtyComputePipeline(const gl::Context *context,
vk::CommandBuffer *commandBuffer)
{
ANGLE_TRY(updateActiveTextures(context));
if (!mCurrentComputePipeline)
{
ANGLE_TRY(mProgram->getComputePipeline(this, &mCurrentComputePipeline));
}
commandBuffer->bindComputePipeline(mCurrentComputePipeline->get());
mCurrentComputePipeline->updateSerial(getCurrentQueueSerial());
return angle::Result::Continue;
}
ANGLE_INLINE angle::Result ContextVk::handleDirtyTexturesImpl(const gl::Context *context,
vk::CommandBuffer *commandBuffer,
vk::CommandGraphResource *recorder)
{
ANGLE_TRY(updateActiveTextures(context, recorder));
if (mProgram->hasTextures())
{
ANGLE_TRY(mProgram->updateTexturesDescriptorSet(this, mDrawFramebuffer->getFramebuffer()));
ANGLE_TRY(mProgram->updateTexturesDescriptorSet(this));
}
return angle::Result::Continue;
}
angle::Result ContextVk::handleDirtyGraphicsTextures(const gl::Context *context,
vk::CommandBuffer *commandBuffer)
{
return handleDirtyTexturesImpl(context, commandBuffer, mDrawFramebuffer->getFramebuffer());
}
angle::Result ContextVk::handleDirtyComputeTextures(const gl::Context *context,
vk::CommandBuffer *commandBuffer)
{
return handleDirtyTexturesImpl(context, commandBuffer, &mDispatcher);
}
angle::Result ContextVk::handleDirtyGraphicsVertexBuffers(const gl::Context *context,
vk::CommandBuffer *commandBuffer)
{
......@@ -611,18 +678,33 @@ angle::Result ContextVk::handleDirtyGraphicsIndexBuffer(const gl::Context *conte
return angle::Result::Continue;
}
angle::Result ContextVk::handleDirtyGraphicsUniformAndStorageBuffers(
ANGLE_INLINE angle::Result ContextVk::handleDirtyUniformAndStorageBuffersImpl(
const gl::Context *context,
vk::CommandBuffer *commandBuffer)
vk::CommandBuffer *commandBuffer,
vk::CommandGraphResource *recorder)
{
if (mProgram->hasUniformBuffers() || mProgram->hasStorageBuffers())
{
ANGLE_TRY(mProgram->updateUniformAndStorageBuffersDescriptorSet(
this, mDrawFramebuffer->getFramebuffer()));
ANGLE_TRY(mProgram->updateUniformAndStorageBuffersDescriptorSet(this, recorder));
}
return angle::Result::Continue;
}
angle::Result ContextVk::handleDirtyGraphicsUniformAndStorageBuffers(
const gl::Context *context,
vk::CommandBuffer *commandBuffer)
{
return handleDirtyUniformAndStorageBuffersImpl(context, commandBuffer,
mDrawFramebuffer->getFramebuffer());
}
angle::Result ContextVk::handleDirtyComputeUniformAndStorageBuffers(
const gl::Context *context,
vk::CommandBuffer *commandBuffer)
{
return handleDirtyUniformAndStorageBuffersImpl(context, commandBuffer, &mDispatcher);
}
angle::Result ContextVk::handleDirtyGraphicsTransformFeedbackBuffers(
const gl::Context *context,
vk::CommandBuffer *commandBuffer)
......@@ -648,6 +730,12 @@ angle::Result ContextVk::handleDirtyGraphicsDescriptorSets(const gl::Context *co
return angle::Result::Continue;
}
angle::Result ContextVk::handleDirtyComputeDescriptorSets(const gl::Context *context,
vk::CommandBuffer *commandBuffer)
{
return mProgram->updateDescriptorSets(this, commandBuffer);
}
angle::Result ContextVk::submitFrame(const VkSubmitInfo &submitInfo,
vk::PrimaryCommandBuffer &&commandBuffer)
{
......@@ -671,6 +759,7 @@ angle::Result ContextVk::submitFrame(const VkSubmitInfo &submitInfo,
// recording command buffer is valid. Thus we need to explicitly notify every other Context
// using this VkQueue that they their current command buffer is no longer valid.
onRenderPassFinished();
mComputeDirtyBits |= mNewComputeCommandBufferDirtyBits;
// Store this command buffer in the in-flight list.
batch.commandPool = std::move(mCommandPool);
......@@ -1376,13 +1465,14 @@ angle::Result ContextVk::syncState(const gl::Context *context,
const gl::State::DirtyBits &dirtyBits,
const gl::State::DirtyBits &bitMask)
{
if ((dirtyBits & mPipelineDirtyBitsMask).any())
const gl::State &glState = context->getState();
if ((dirtyBits & mPipelineDirtyBitsMask).any() &&
(glState.getProgram() == nullptr || !glState.getProgram()->isCompute()))
{
invalidateVertexAndIndexBuffers();
}
const gl::State &glState = context->getState();
for (size_t dirtyBit : dirtyBits)
{
switch (dirtyBit)
......@@ -1609,13 +1699,21 @@ angle::Result ContextVk::syncState(const gl::Context *context,
{
invalidateCurrentTextures();
invalidateCurrentUniformAndStorageBuffers();
// No additional work is needed here. We will update the pipeline desc later.
invalidateDefaultAttributes(context->getStateCache().getActiveDefaultAttribsMask());
bool useVertexBuffer = (mProgram->getState().getMaxActiveAttribLocation());
mNonIndexedDirtyBitsMask.set(DIRTY_BIT_VERTEX_BUFFERS, useVertexBuffer);
mIndexedDirtyBitsMask.set(DIRTY_BIT_VERTEX_BUFFERS, useVertexBuffer);
mCurrentGraphicsPipeline = nullptr;
mGraphicsPipelineTransition.reset();
if (glState.getProgram()->isCompute())
{
invalidateCurrentComputePipeline();
}
else
{
// No additional work is needed here. We will update the pipeline desc later.
invalidateDefaultAttributes(
context->getStateCache().getActiveDefaultAttribsMask());
bool useVertexBuffer = (mProgram->getState().getMaxActiveAttribLocation());
mNonIndexedDirtyBitsMask.set(DIRTY_BIT_VERTEX_BUFFERS, useVertexBuffer);
mIndexedDirtyBitsMask.set(DIRTY_BIT_VERTEX_BUFFERS, useVertexBuffer);
mCurrentGraphicsPipeline = nullptr;
mGraphicsPipelineTransition.reset();
}
break;
}
case gl::State::DIRTY_BIT_TEXTURE_BINDINGS:
......@@ -1848,6 +1946,8 @@ void ContextVk::invalidateCurrentTextures()
{
mGraphicsDirtyBits.set(DIRTY_BIT_TEXTURES);
mGraphicsDirtyBits.set(DIRTY_BIT_DESCRIPTOR_SETS);
mComputeDirtyBits.set(DIRTY_BIT_TEXTURES);
mComputeDirtyBits.set(DIRTY_BIT_DESCRIPTOR_SETS);
}
}
......@@ -1858,6 +1958,8 @@ void ContextVk::invalidateCurrentUniformAndStorageBuffers()
{
mGraphicsDirtyBits.set(DIRTY_BIT_UNIFORM_AND_STORAGE_BUFFERS);
mGraphicsDirtyBits.set(DIRTY_BIT_DESCRIPTOR_SETS);
mComputeDirtyBits.set(DIRTY_BIT_UNIFORM_AND_STORAGE_BUFFERS);
mComputeDirtyBits.set(DIRTY_BIT_DESCRIPTOR_SETS);
}
}
......@@ -1892,8 +1994,12 @@ angle::Result ContextVk::dispatchCompute(const gl::Context *context,
GLuint numGroupsY,
GLuint numGroupsZ)
{
ANGLE_VK_UNREACHABLE(this);
return angle::Result::Stop;
vk::CommandBuffer *commandBuffer;
ANGLE_TRY(setupDispatch(context, &commandBuffer));
commandBuffer->dispatch(numGroupsX, numGroupsY, numGroupsZ);
return angle::Result::Continue;
}
angle::Result ContextVk::dispatchComputeIndirect(const gl::Context *context, GLintptr indirect)
......@@ -2039,7 +2145,8 @@ void ContextVk::handleError(VkResult errorCode,
mErrors->handleError(glErrorCode, errorStream.str().c_str(), file, function, line);
}
angle::Result ContextVk::updateActiveTextures(const gl::Context *context)
angle::Result ContextVk::updateActiveTextures(const gl::Context *context,
vk::CommandGraphResource *recorder)
{
const gl::State &glState = mState;
const gl::Program *program = glState.getProgram();
......@@ -2052,6 +2159,10 @@ angle::Result ContextVk::updateActiveTextures(const gl::Context *context)
const gl::ActiveTextureMask &activeTextures = program->getActiveSamplersMask();
const gl::ActiveTextureTypeArray &textureTypes = program->getActiveSamplerTypes();
const vk::ImageLayout textureLayout = program->isCompute()
? vk::ImageLayout::ComputeShaderReadOnly
: vk::ImageLayout::FragmentShaderReadOnly;
for (size_t textureUnit : activeTextures)
{
gl::Texture *texture = textures[textureUnit];
......@@ -2072,18 +2183,17 @@ angle::Result ContextVk::updateActiveTextures(const gl::Context *context)
// we can't verify it has no staged updates right here.
// Ensure the image is in read-only layout
if (image.isLayoutChangeNecessary(vk::ImageLayout::FragmentShaderReadOnly))
if (image.isLayoutChangeNecessary(textureLayout))
{
vk::CommandBuffer *srcLayoutChange;
ANGLE_TRY(image.recordCommands(this, &srcLayoutChange));
VkImageAspectFlags aspectFlags = image.getAspectFlags();
ASSERT(aspectFlags != 0);
image.changeLayout(aspectFlags, vk::ImageLayout::FragmentShaderReadOnly,
srcLayoutChange);
image.changeLayout(aspectFlags, textureLayout, srcLayoutChange);
}
image.addReadDependency(mDrawFramebuffer->getFramebuffer());
image.addReadDependency(recorder);
mActiveTextures[textureUnit] = textureVk;
mActiveTexturesDesc.update(textureUnit, textureVk->getSerial());
......
......@@ -331,6 +331,7 @@ class ContextVk : public ContextImpl, public vk::Context, public vk::RenderPassO
vk::CommandBuffer *commandBuffer);
std::array<DirtyBitHandler, DIRTY_BIT_MAX> mGraphicsDirtyBitHandlers;
std::array<DirtyBitHandler, DIRTY_BIT_MAX> mComputeDirtyBitHandlers;
angle::Result setupDraw(const gl::Context *context,
gl::PrimitiveMode mode,
......@@ -356,6 +357,7 @@ class ContextVk : public ContextImpl, public vk::Context, public vk::RenderPassO
const void *indices,
vk::CommandBuffer **commandBufferOut,
size_t *numIndicesOut);
angle::Result setupDispatch(const gl::Context *context, vk::CommandBuffer **commandBufferOut);
void updateViewport(FramebufferVk *framebufferVk,
const gl::Rectangle &viewport,
......@@ -367,13 +369,19 @@ class ContextVk : public ContextImpl, public vk::Context, public vk::RenderPassO
void updateFlipViewportDrawFramebuffer(const gl::State &glState);
void updateFlipViewportReadFramebuffer(const gl::State &glState);
angle::Result updateActiveTextures(const gl::Context *context);
angle::Result updateActiveTextures(const gl::Context *context,
vk::CommandGraphResource *recorder);
angle::Result updateDefaultAttribute(size_t attribIndex);
ANGLE_INLINE void invalidateCurrentGraphicsPipeline()
{
mGraphicsDirtyBits.set(DIRTY_BIT_PIPELINE);
}
ANGLE_INLINE void invalidateCurrentComputePipeline()
{
mComputeDirtyBits.set(DIRTY_BIT_PIPELINE);
mCurrentComputePipeline = nullptr;
}
void invalidateCurrentTextures();
void invalidateCurrentUniformAndStorageBuffers();
......@@ -399,6 +407,24 @@ class ContextVk : public ContextImpl, public vk::Context, public vk::RenderPassO
angle::Result handleDirtyGraphicsDescriptorSets(const gl::Context *context,
vk::CommandBuffer *commandBuffer);
// Handlers for compute pipeline dirty bits.
angle::Result handleDirtyComputePipeline(const gl::Context *context,
vk::CommandBuffer *commandBuffer);
angle::Result handleDirtyComputeTextures(const gl::Context *context,
vk::CommandBuffer *commandBuffer);
angle::Result handleDirtyComputeUniformAndStorageBuffers(const gl::Context *context,
vk::CommandBuffer *commandBuffer);
angle::Result handleDirtyComputeDescriptorSets(const gl::Context *context,
vk::CommandBuffer *commandBuffer);
// Common parts of the common dirty bit handlers.
angle::Result handleDirtyTexturesImpl(const gl::Context *context,
vk::CommandBuffer *commandBuffer,
vk::CommandGraphResource *recorder);
angle::Result handleDirtyUniformAndStorageBuffersImpl(const gl::Context *context,
vk::CommandBuffer *commandBuffer,
vk::CommandGraphResource *recorder);
angle::Result submitFrame(const VkSubmitInfo &submitInfo,
vk::PrimaryCommandBuffer &&commandBuffer);
void freeAllInFlightResources();
......@@ -416,6 +442,7 @@ class ContextVk : public ContextImpl, public vk::Context, public vk::RenderPassO
void waitForSwapchainImageIfNecessary();
vk::PipelineHelper *mCurrentGraphicsPipeline;
vk::PipelineAndSerial *mCurrentComputePipeline;
gl::PrimitiveMode mCurrentDrawMode;
WindowSurfaceVk *mCurrentWindowSurface;
......@@ -434,15 +461,20 @@ class ContextVk : public ContextImpl, public vk::Context, public vk::RenderPassO
// Dirty bits.
DirtyBits mGraphicsDirtyBits;
DirtyBits mComputeDirtyBits;
DirtyBits mNonIndexedDirtyBitsMask;
DirtyBits mIndexedDirtyBitsMask;
DirtyBits mNewGraphicsCommandBufferDirtyBits;
DirtyBits mNewComputeCommandBufferDirtyBits;
// Cached back-end objects.
VertexArrayVk *mVertexArray;
FramebufferVk *mDrawFramebuffer;
ProgramVk *mProgram;
// Graph resource used to record dispatch commands and hold resource dependencies.
vk::DispatchHelper mDispatcher;
// The offset we had the last time we bound the index buffer.
const GLvoid *mLastIndexBufferOffset;
gl::DrawElementsType mCurrentDrawElementsType;
......
......@@ -98,7 +98,8 @@ void GetBuiltInResourcesFromCaps(const gl::Caps &caps, TBuiltInResource *outBuil
class IntermediateShaderSource final : angle::NonCopyable
{
public:
IntermediateShaderSource(const std::string &source);
void init(const std::string &source);
bool empty() const { return mTokens.empty(); }
// Find @@ LAYOUT-name(extra, args) @@ and replace it with:
//
......@@ -217,7 +218,7 @@ size_t ExtractNameAndArgs(const std::string &source,
return readCount;
}
IntermediateShaderSource::IntermediateShaderSource(const std::string &source)
void IntermediateShaderSource::init(const std::string &source)
{
size_t cur = 0;
......@@ -491,7 +492,7 @@ void GenerateTransformFeedbackOutputs(const gl::ProgramState &programState,
void AssignAttributeLocations(const gl::ProgramState &programState,
IntermediateShaderSource *vertexSource)
{
ASSERT(vertexSource != nullptr);
ASSERT(!vertexSource->empty());
// Parse attribute locations and replace them in the vertex shader.
// See corresponding code in OutputVulkanGLSL.cpp.
......@@ -510,7 +511,7 @@ void AssignAttributeLocations(const gl::ProgramState &programState,
void AssignOutputLocations(const gl::ProgramState &programState,
IntermediateShaderSource *fragmentSource)
{
ASSERT(fragmentSource != nullptr);
ASSERT(!fragmentSource->empty());
// Parse output locations and replace them in the fragment shader.
// See corresponding code in OutputVulkanGLSL.cpp.
......@@ -549,6 +550,9 @@ void AssignVaryingLocations(const gl::ProgramLinkedResources &resources,
IntermediateShaderSource *outStageSource,
IntermediateShaderSource *inStageSource)
{
ASSERT(!outStageSource->empty());
ASSERT(!inStageSource->empty());
// Assign varying locations.
for (const gl::PackedVaryingRegister &varyingReg : resources.varyingPacking.getRegisterList())
{
......@@ -623,7 +627,7 @@ void AssignVaryingLocations(const gl::ProgramLinkedResources &resources,
inStageSource->insertQualifierSpecifier(kVaryingName, "in");
}
void AssignUniformBindings(const gl::ShaderMap<IntermediateShaderSource *> &shaderSources)
void AssignUniformBindings(gl::ShaderMap<IntermediateShaderSource> *shaderSources)
{
// Bind the default uniforms for vertex and fragment shaders.
// See corresponding code in OutputVulkanGLSL.cpp.
......@@ -631,18 +635,18 @@ void AssignUniformBindings(const gl::ShaderMap<IntermediateShaderSource *> &shad
constexpr char kDefaultUniformsBlockName[] = "defaultUniforms";
size_t bindingIndex = 0;
for (IntermediateShaderSource *shaderSource : shaderSources)
for (IntermediateShaderSource &shaderSource : *shaderSources)
{
if (shaderSource)
if (!shaderSource.empty())
{
std::string defaultUniformsBinding =
uniformsDescriptorSet + ", binding = " + Str(bindingIndex++);
shaderSource->insertLayoutSpecifier(kDefaultUniformsBlockName, defaultUniformsBinding);
shaderSource.insertLayoutSpecifier(kDefaultUniformsBlockName, defaultUniformsBinding);
}
}
if (shaderSources[gl::ShaderType::Compute] != nullptr)
if (!(*shaderSources)[gl::ShaderType::Compute].empty())
{
// Compute doesn't need driver uniforms.
return;
......@@ -653,13 +657,10 @@ void AssignUniformBindings(const gl::ShaderMap<IntermediateShaderSource *> &shad
"set = " + Str(kDriverUniformsDescriptorSetIndex) + ", binding = 0";
constexpr char kDriverBlockName[] = "ANGLEUniformBlock";
for (IntermediateShaderSource *shaderSource : shaderSources)
for (IntermediateShaderSource &shaderSource : *shaderSources)
{
if (shaderSource)
{
shaderSource->insertLayoutSpecifier(kDriverBlockName, driverBlockLayoutString);
shaderSource->insertQualifierSpecifier(kDriverBlockName, kUniformQualifier);
}
shaderSource.insertLayoutSpecifier(kDriverBlockName, driverBlockLayoutString);
shaderSource.insertQualifierSpecifier(kDriverBlockName, kUniformQualifier);
}
}
......@@ -669,31 +670,30 @@ void AssignResourceBinding(gl::ShaderBitSet activeShaders,
const std::string &bindingString,
const char *qualifier,
const char *unusedSubstitution,
const gl::ShaderMap<IntermediateShaderSource *> &shaderSources)
gl::ShaderMap<IntermediateShaderSource> *shaderSources)
{
for (const gl::ShaderType shaderType : gl::AllShaderTypes())
{
IntermediateShaderSource *shaderSource = shaderSources[shaderType];
if (shaderSource)
IntermediateShaderSource &shaderSource = (*shaderSources)[shaderType];
if (!shaderSource.empty())
{
if (activeShaders[shaderType])
{
shaderSource->insertLayoutSpecifier(name, bindingString);
shaderSource->insertQualifierSpecifier(name, qualifier);
shaderSource.insertLayoutSpecifier(name, bindingString);
shaderSource.insertQualifierSpecifier(name, qualifier);
}
else
{
shaderSource->eraseLayoutAndQualifierSpecifiers(name, unusedSubstitution);
shaderSource.eraseLayoutAndQualifierSpecifiers(name, unusedSubstitution);
}
}
}
}
uint32_t AssignInterfaceBlockBindings(
const std::vector<gl::InterfaceBlock> &blocks,
const char *qualifier,
uint32_t bindingStart,
const gl::ShaderMap<IntermediateShaderSource *> &shaderSources)
uint32_t AssignInterfaceBlockBindings(const std::vector<gl::InterfaceBlock> &blocks,
const char *qualifier,
uint32_t bindingStart,
gl::ShaderMap<IntermediateShaderSource> *shaderSources)
{
const std::string buffersDescriptorSet = "set = " + Str(kBufferDescriptorSetIndex);
......@@ -714,7 +714,7 @@ uint32_t AssignInterfaceBlockBindings(
}
void AssignBufferBindings(const gl::ProgramState &programState,
const gl::ShaderMap<IntermediateShaderSource *> &shaderSources)
gl::ShaderMap<IntermediateShaderSource> *shaderSources)
{
uint32_t bindingStart = 0;
......@@ -730,7 +730,7 @@ void AssignBufferBindings(const gl::ProgramState &programState,
}
void AssignTextureBindings(const gl::ProgramState &programState,
const gl::ShaderMap<IntermediateShaderSource *> &shaderSources)
gl::ShaderMap<IntermediateShaderSource> *shaderSources)
{
const std::string texturesDescriptorSet = "set = " + Str(kTextureDescriptorSetIndex);
......@@ -755,10 +755,10 @@ void AssignTextureBindings(const gl::ProgramState &programState,
void CleanupUnusedEntities(const gl::ProgramState &programState,
const gl::ProgramLinkedResources &resources,
gl::Shader *glVertexShader,
const gl::ShaderMap<IntermediateShaderSource *> &shaderSources)
gl::ShaderMap<IntermediateShaderSource> *shaderSources)
{
IntermediateShaderSource *vertexSource = shaderSources[gl::ShaderType::Vertex];
if (vertexSource)
IntermediateShaderSource &vertexSource = (*shaderSources)[gl::ShaderType::Vertex];
if (!vertexSource.empty())
{
ASSERT(glVertexShader != nullptr);
......@@ -772,32 +772,26 @@ void CleanupUnusedEntities(const gl::ProgramState &programState,
continue;
}
vertexSource->eraseLayoutAndQualifierSpecifiers(attribute.name, "");
vertexSource.eraseLayoutAndQualifierSpecifiers(attribute.name, "");
}
}
// Remove all the markers for unused varyings.
for (const std::string &varyingName : resources.varyingPacking.getInactiveVaryingNames())
{
for (IntermediateShaderSource *shaderSource : shaderSources)
for (IntermediateShaderSource &shaderSource : *shaderSources)
{
if (shaderSource)
{
shaderSource->eraseLayoutAndQualifierSpecifiers(varyingName, "");
}
shaderSource.eraseLayoutAndQualifierSpecifiers(varyingName, "");
}
}
// Remove all the markers for unused interface blocks, and replace them with |struct|.
for (const std::string &unusedInterfaceBlock : resources.unusedInterfaceBlocks)
{
for (IntermediateShaderSource *shaderSource : shaderSources)
for (IntermediateShaderSource &shaderSource : *shaderSources)
{
if (shaderSource)
{
shaderSource->eraseLayoutAndQualifierSpecifiers(unusedInterfaceBlock,
kUnusedBlockSubstitution);
}
shaderSource.eraseLayoutAndQualifierSpecifiers(unusedInterfaceBlock,
kUnusedBlockSubstitution);
}
}
......@@ -808,16 +802,19 @@ void CleanupUnusedEntities(const gl::ProgramState &programState,
std::string uniformName =
unusedUniform.isSampler ? GetMappedSamplerName(unusedUniform.name) : unusedUniform.name;
for (IntermediateShaderSource *shaderSource : shaderSources)
for (IntermediateShaderSource &shaderSource : *shaderSources)
{
if (shaderSource)
{
shaderSource->eraseLayoutAndQualifierSpecifiers(uniformName,
kUnusedUniformSubstitution);
}
shaderSource.eraseLayoutAndQualifierSpecifiers(uniformName, kUnusedUniformSubstitution);
}
}
}
constexpr gl::ShaderMap<EShLanguage> kShLanguageMap = {
{gl::ShaderType::Vertex, EShLangVertex},
{gl::ShaderType::Geometry, EShLangGeometry},
{gl::ShaderType::Fragment, EShLangFragment},
{gl::ShaderType::Compute, EShLangCompute},
};
} // anonymous namespace
// static
......@@ -837,127 +834,138 @@ void GlslangWrapper::Release()
// static
void GlslangWrapper::GetShaderSource(const gl::ProgramState &programState,
const gl::ProgramLinkedResources &resources,
std::string *vertexSourceOut,
std::string *fragmentSourceOut)
gl::ShaderMap<std::string> *shaderSourcesOut)
{
gl::Shader *glVertexShader = programState.getAttachedShader(gl::ShaderType::Vertex);
gl::Shader *glFragmentShader = programState.getAttachedShader(gl::ShaderType::Fragment);
IntermediateShaderSource vertexSource(glVertexShader->getTranslatedSource());
IntermediateShaderSource fragmentSource(glFragmentShader->getTranslatedSource());
gl::ShaderMap<IntermediateShaderSource> intermediateSources;
gl::ShaderMap<IntermediateShaderSource *> shaderSources{};
for (const gl::ShaderType shaderType : gl::AllShaderTypes())
{
gl::Shader *glShader = programState.getAttachedShader(shaderType);
if (glShader)
{
intermediateSources[shaderType].init(glShader->getTranslatedSource());
}
}
shaderSources[gl::ShaderType::Vertex] = &vertexSource;
shaderSources[gl::ShaderType::Fragment] = &fragmentSource;
IntermediateShaderSource *vertexSource = &intermediateSources[gl::ShaderType::Vertex];
IntermediateShaderSource *fragmentSource = &intermediateSources[gl::ShaderType::Fragment];
AssignAttributeLocations(programState, shaderSources[gl::ShaderType::Vertex]);
AssignOutputLocations(programState, shaderSources[gl::ShaderType::Fragment]);
AssignVaryingLocations(resources, shaderSources[gl::ShaderType::Vertex],
shaderSources[gl::ShaderType::Fragment]);
AssignUniformBindings(shaderSources);
AssignBufferBindings(programState, shaderSources);
AssignTextureBindings(programState, shaderSources);
if (!vertexSource->empty())
{
AssignAttributeLocations(programState, vertexSource);
AssignOutputLocations(programState, fragmentSource);
AssignVaryingLocations(resources, vertexSource, fragmentSource);
}
AssignUniformBindings(&intermediateSources);
AssignBufferBindings(programState, &intermediateSources);
AssignTextureBindings(programState, &intermediateSources);
CleanupUnusedEntities(programState, resources, glVertexShader, shaderSources);
CleanupUnusedEntities(programState, resources,
programState.getAttachedShader(gl::ShaderType::Vertex),
&intermediateSources);
// Write transform feedback output code.
if (programState.getLinkedTransformFeedbackVaryings().empty())
if (!vertexSource->empty())
{
vertexSource.insertTransformFeedbackDeclaration("");
vertexSource.insertTransformFeedbackOutput("");
if (programState.getLinkedTransformFeedbackVaryings().empty())
{
vertexSource->insertTransformFeedbackDeclaration("");
vertexSource->insertTransformFeedbackOutput("");
}
else
{
GenerateTransformFeedbackOutputs(programState, vertexSource);
}
}
else
for (const gl::ShaderType shaderType : gl::AllShaderTypes())
{
GenerateTransformFeedbackOutputs(programState, &vertexSource);
(*shaderSourcesOut)[shaderType] = intermediateSources[shaderType].getShaderSource();
}
*vertexSourceOut = vertexSource.getShaderSource();
*fragmentSourceOut = fragmentSource.getShaderSource();
}
// static
angle::Result GlslangWrapper::GetShaderCode(vk::Context *context,
const gl::Caps &glCaps,
bool enableLineRasterEmulation,
const std::string &vertexSource,
const std::string &fragmentSource,
std::vector<uint32_t> *vertexCodeOut,
std::vector<uint32_t> *fragmentCodeOut)
const gl::ShaderMap<std::string> &shaderSources,
gl::ShaderMap<std::vector<uint32_t>> *shaderCodeOut)
{
if (enableLineRasterEmulation)
{
std::string patchedVertexSource = vertexSource;
std::string patchedFragmentSource = fragmentSource;
ASSERT(shaderSources[gl::ShaderType::Compute].empty());
gl::ShaderMap<std::string> patchedSources = shaderSources;
// #defines must come after the #version directive.
ANGLE_VK_CHECK(
context,
angle::ReplaceSubstring(&patchedVertexSource, kVersionDefine, kLineRasterDefine),
VK_ERROR_INVALID_SHADER_NV);
ANGLE_VK_CHECK(
context,
angle::ReplaceSubstring(&patchedFragmentSource, kVersionDefine, kLineRasterDefine),
VK_ERROR_INVALID_SHADER_NV);
return GetShaderCodeImpl(context, glCaps, patchedVertexSource, patchedFragmentSource,
vertexCodeOut, fragmentCodeOut);
ANGLE_VK_CHECK(context,
angle::ReplaceSubstring(&patchedSources[gl::ShaderType::Vertex],
kVersionDefine, kLineRasterDefine),
VK_ERROR_INVALID_SHADER_NV);
ANGLE_VK_CHECK(context,
angle::ReplaceSubstring(&patchedSources[gl::ShaderType::Fragment],
kVersionDefine, kLineRasterDefine),
VK_ERROR_INVALID_SHADER_NV);
return GetShaderCodeImpl(context, glCaps, patchedSources, shaderCodeOut);
}
else
{
return GetShaderCodeImpl(context, glCaps, vertexSource, fragmentSource, vertexCodeOut,
fragmentCodeOut);
return GetShaderCodeImpl(context, glCaps, shaderSources, shaderCodeOut);
}
}
// static
angle::Result GlslangWrapper::GetShaderCodeImpl(vk::Context *context,
const gl::Caps &glCaps,
const std::string &vertexSource,
const std::string &fragmentSource,
std::vector<uint32_t> *vertexCodeOut,
std::vector<uint32_t> *fragmentCodeOut)
const gl::ShaderMap<std::string> &shaderSources,
gl::ShaderMap<std::vector<uint32_t>> *shaderCodeOut)
{
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())}};
// Enable SPIR-V and Vulkan rules when parsing GLSL
EShMessages messages = static_cast<EShMessages>(EShMsgSpvRules | EShMsgVulkanRules);
glslang::TShader vertexShader(EShLangVertex);
vertexShader.setStringsWithLengths(&strings[0], &lengths[0], 1);
vertexShader.setEntryPoint("main");
TBuiltInResource builtInResources(glslang::DefaultTBuiltInResource);
GetBuiltInResourcesFromCaps(glCaps, &builtInResources);
bool vertexResult =
vertexShader.parse(&builtInResources, 450, ECoreProfile, false, false, messages);
if (!vertexResult)
glslang::TShader vertexShader(EShLangVertex);
glslang::TShader fragmentShader(EShLangFragment);
glslang::TShader geometryShader(EShLangGeometry);
glslang::TShader computeShader(EShLangCompute);
gl::ShaderMap<glslang::TShader *> shaders = {
{gl::ShaderType::Vertex, &vertexShader},
{gl::ShaderType::Fragment, &fragmentShader},
{gl::ShaderType::Geometry, &geometryShader},
{gl::ShaderType::Compute, &computeShader},
};
glslang::TProgram program;
for (const gl::ShaderType shaderType : gl::AllShaderTypes())
{
ERR() << "Internal error parsing Vulkan vertex shader:\n"
<< vertexShader.getInfoLog() << "\n"
<< vertexShader.getInfoDebugLog() << "\n";
ANGLE_VK_CHECK(context, false, VK_ERROR_INVALID_SHADER_NV);
}
if (shaderSources[shaderType].empty())
{
continue;
}
glslang::TShader fragmentShader(EShLangFragment);
fragmentShader.setStringsWithLengths(&strings[1], &lengths[1], 1);
fragmentShader.setEntryPoint("main");
bool fragmentResult =
fragmentShader.parse(&builtInResources, 450, ECoreProfile, false, false, messages);
if (!fragmentResult)
{
ERR() << "Internal error parsing Vulkan fragment shader:\n"
<< fragmentShader.getInfoLog() << "\n"
<< fragmentShader.getInfoDebugLog() << "\n";
ANGLE_VK_CHECK(context, false, VK_ERROR_INVALID_SHADER_NV);
const char *shaderString = shaderSources[shaderType].c_str();
int shaderLength = static_cast<int>(shaderSources[shaderType].size());
glslang::TShader *shader = shaders[shaderType];
shader->setStringsWithLengths(&shaderString, &shaderLength, 1);
shader->setEntryPoint("main");
bool result = shader->parse(&builtInResources, 450, ECoreProfile, false, false, messages);
if (!result)
{
ERR() << "Internal error parsing Vulkan shader corresponding to " << shaderType << ":\n"
<< shader->getInfoLog() << "\n"
<< shader->getInfoDebugLog() << "\n";
ANGLE_VK_CHECK(context, false, VK_ERROR_INVALID_SHADER_NV);
}
program.addShader(shader);
}
glslang::TProgram program;
program.addShader(&vertexShader);
program.addShader(&fragmentShader);
bool linkResult = program.link(messages);
if (!linkResult)
{
......@@ -965,10 +973,16 @@ angle::Result GlslangWrapper::GetShaderCodeImpl(vk::Context *context,
ANGLE_VK_CHECK(context, false, VK_ERROR_INVALID_SHADER_NV);
}
glslang::TIntermediate *vertexStage = program.getIntermediate(EShLangVertex);
glslang::TIntermediate *fragmentStage = program.getIntermediate(EShLangFragment);
glslang::GlslangToSpv(*vertexStage, *vertexCodeOut);
glslang::GlslangToSpv(*fragmentStage, *fragmentCodeOut);
for (const gl::ShaderType shaderType : gl::AllShaderTypes())
{
if (shaderSources[shaderType].empty())
{
continue;
}
glslang::TIntermediate *intermediate = program.getIntermediate(kShLanguageMap[shaderType]);
glslang::GlslangToSpv(*intermediate, (*shaderCodeOut)[shaderType]);
}
return angle::Result::Continue;
}
......
......@@ -24,24 +24,19 @@ class GlslangWrapper
static void GetShaderSource(const gl::ProgramState &programState,
const gl::ProgramLinkedResources &resources,
std::string *vertexSourceOut,
std::string *fragmentSourceOut);
gl::ShaderMap<std::string> *shaderSourcesOut);
static angle::Result GetShaderCode(vk::Context *context,
const gl::Caps &glCaps,
bool enableLineRasterEmulation,
const std::string &vertexSource,
const std::string &fragmentSource,
std::vector<uint32_t> *vertexCodeOut,
std::vector<uint32_t> *fragmentCodeOut);
const gl::ShaderMap<std::string> &shaderSources,
gl::ShaderMap<std::vector<uint32_t>> *shaderCodesOut);
private:
static angle::Result GetShaderCodeImpl(vk::Context *context,
const gl::Caps &glCaps,
const std::string &vertexSource,
const std::string &fragmentSource,
std::vector<uint32_t> *vertexCodeOut,
std::vector<uint32_t> *fragmentCodeOut);
const gl::ShaderMap<std::string> &shaderSources,
gl::ShaderMap<std::vector<uint32_t>> *shaderCodesOut);
};
} // namespace rx
......
......@@ -195,25 +195,26 @@ ProgramVk::ShaderInfo::ShaderInfo() {}
ProgramVk::ShaderInfo::~ShaderInfo() = default;
angle::Result ProgramVk::ShaderInfo::initShaders(ContextVk *contextVk,
const std::string &vertexSource,
const std::string &fragmentSource,
const gl::ShaderMap<std::string> &shaderSources,
bool enableLineRasterEmulation)
{
ASSERT(!valid());
std::vector<uint32_t> vertexCode;
std::vector<uint32_t> fragmentCode;
ANGLE_TRY(GlslangWrapper::GetShaderCode(contextVk, contextVk->getCaps(),
enableLineRasterEmulation, vertexSource, fragmentSource,
&vertexCode, &fragmentCode));
gl::ShaderMap<std::vector<uint32_t>> shaderCodes;
ANGLE_TRY(GlslangWrapper::GetShaderCode(
contextVk, contextVk->getCaps(), enableLineRasterEmulation, shaderSources, &shaderCodes));
ANGLE_TRY(vk::InitShaderAndSerial(contextVk, &mShaders[gl::ShaderType::Vertex].get(),
vertexCode.data(), vertexCode.size() * sizeof(uint32_t)));
ANGLE_TRY(vk::InitShaderAndSerial(contextVk, &mShaders[gl::ShaderType::Fragment].get(),
fragmentCode.data(), fragmentCode.size() * sizeof(uint32_t)));
for (const gl::ShaderType shaderType : gl::AllShaderTypes())
{
if (!shaderSources[shaderType].empty())
{
ANGLE_TRY(vk::InitShaderAndSerial(contextVk, &mShaders[shaderType].get(),
shaderCodes[shaderType].data(),
shaderCodes[shaderType].size() * sizeof(uint32_t)));
mProgramHelper.setShader(gl::ShaderType::Vertex, &mShaders[gl::ShaderType::Vertex]);
mProgramHelper.setShader(gl::ShaderType::Fragment, &mShaders[gl::ShaderType::Fragment]);
mProgramHelper.setShader(shaderType, &mShaders[shaderType]);
}
}
return angle::Result::Continue;
}
......@@ -223,7 +224,7 @@ angle::Result ProgramVk::loadShaderSource(ContextVk *contextVk, gl::BinaryInputS
// Read in shader sources for all shader types
for (const gl::ShaderType shaderType : gl::AllShaderTypes())
{
mShaderSource[shaderType] = stream->readString();
mShaderSources[shaderType] = stream->readString();
}
return angle::Result::Continue;
......@@ -234,7 +235,7 @@ void ProgramVk::saveShaderSource(gl::BinaryOutputStream *stream)
// Write out shader sources for all shader types
for (const gl::ShaderType shaderType : gl::AllShaderTypes())
{
stream->writeString(mShaderSource[shaderType]);
stream->writeString(mShaderSources[shaderType]);
}
}
......@@ -338,8 +339,7 @@ std::unique_ptr<LinkEvent> ProgramVk::link(const gl::Context *context,
// assignment done in that function.
linkResources(resources);
GlslangWrapper::GetShaderSource(mState, resources, &mShaderSource[gl::ShaderType::Vertex],
&mShaderSource[gl::ShaderType::Fragment]);
GlslangWrapper::GetShaderSource(mState, resources, &mShaderSources);
// TODO(jie.a.chen@intel.com): Parallelize linking.
// http://crbug.com/849576
......@@ -1013,7 +1013,7 @@ void ProgramVk::updateDefaultUniformsDescriptorSet(ContextVk *contextVk)
}
void ProgramVk::updateBuffersDescriptorSet(ContextVk *contextVk,
vk::FramebufferHelper *framebufferVk,
vk::CommandGraphResource *recorder,
const std::vector<gl::InterfaceBlock> &blocks,
VkDescriptorType descriptorType)
{
......@@ -1074,19 +1074,23 @@ void ProgramVk::updateBuffersDescriptorSet(ContextVk *contextVk,
if (isStorageBuffer)
{
bufferHelper.onWrite(contextVk, framebufferVk, VK_ACCESS_SHADER_READ_BIT,
bufferHelper.onWrite(contextVk, recorder, VK_ACCESS_SHADER_READ_BIT,
VK_ACCESS_SHADER_WRITE_BIT);
}
else
{
bufferHelper.onRead(framebufferVk, VK_ACCESS_UNIFORM_READ_BIT);
bufferHelper.onRead(recorder, VK_ACCESS_UNIFORM_READ_BIT);
}
// If size is 0, we can't always use VK_WHOLE_SIZE (or bufferHelper.getSize()), as the
// backing buffer may be larger than max*BufferRange. In that case, we use the minimum of
// the backing buffer size (what's left after offset) and the buffer size as defined by the
// shader.
size = std::min(size > 0 ? size : (bufferHelper.getSize() - offset), blockSize);
// shader. That latter is only valid for UBOs, as SSBOs may have variable length arrays.
size = size > 0 ? size : (bufferHelper.getSize() - offset);
if (!isStorageBuffer)
{
size = std::min(size, blockSize);
}
VkDescriptorBufferInfo &bufferInfo = descriptorBufferInfo[writeCount];
......@@ -1118,13 +1122,13 @@ void ProgramVk::updateBuffersDescriptorSet(ContextVk *contextVk,
angle::Result ProgramVk::updateUniformAndStorageBuffersDescriptorSet(
ContextVk *contextVk,
vk::FramebufferHelper *framebufferVk)
vk::CommandGraphResource *recorder)
{
ANGLE_TRY(allocateDescriptorSet(contextVk, kBufferDescriptorSetIndex));
updateBuffersDescriptorSet(contextVk, framebufferVk, mState.getUniformBlocks(),
updateBuffersDescriptorSet(contextVk, recorder, mState.getUniformBlocks(),
VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER);
updateBuffersDescriptorSet(contextVk, framebufferVk, mState.getShaderStorageBlocks(),
updateBuffersDescriptorSet(contextVk, recorder, mState.getShaderStorageBlocks(),
VK_DESCRIPTOR_TYPE_STORAGE_BUFFER);
return angle::Result::Continue;
......@@ -1163,8 +1167,7 @@ void ProgramVk::updateTransformFeedbackDescriptorSetImpl(ContextVk *contextVk)
mDescriptorSets[kUniformsAndXfbDescriptorSetIndex]);
}
angle::Result ProgramVk::updateTexturesDescriptorSet(ContextVk *contextVk,
vk::FramebufferHelper *framebuffer)
angle::Result ProgramVk::updateTexturesDescriptorSet(ContextVk *contextVk)
{
const vk::TextureDescriptorDesc &texturesDesc = contextVk->getActiveTexturesDesc();
......@@ -1272,6 +1275,9 @@ angle::Result ProgramVk::updateDescriptorSets(ContextVk *contextVk,
}
}
const VkPipelineBindPoint pipelineBindPoint =
mState.isCompute() ? VK_PIPELINE_BIND_POINT_COMPUTE : VK_PIPELINE_BIND_POINT_GRAPHICS;
for (size_t descriptorSetIndex = 0; descriptorSetIndex < descriptorSetRange;
++descriptorSetIndex)
{
......@@ -1305,7 +1311,7 @@ angle::Result ProgramVk::updateDescriptorSets(ContextVk *contextVk,
descriptorSetIndex == kUniformsAndXfbDescriptorSetIndex ? mDynamicBufferOffsets.size()
: 0;
commandBuffer->bindDescriptorSets(mPipelineLayout.get(), VK_PIPELINE_BIND_POINT_GRAPHICS,
commandBuffer->bindDescriptorSets(mPipelineLayout.get(), pipelineBindPoint,
descriptorSetIndex, 1, &descSet, uniformBlockOffsetCount,
mDynamicBufferOffsets.data());
}
......
......@@ -106,10 +106,9 @@ class ProgramVk : public ProgramImpl
// Also initializes the pipeline layout, descriptor set layouts, and used descriptor ranges.
angle::Result updateUniforms(ContextVk *contextVk);
angle::Result updateTexturesDescriptorSet(ContextVk *contextVk,
vk::FramebufferHelper *framebuffer);
angle::Result updateTexturesDescriptorSet(ContextVk *contextVk);
angle::Result updateUniformAndStorageBuffersDescriptorSet(ContextVk *contextVk,
vk::FramebufferHelper *framebuffer);
vk::CommandGraphResource *recorder);
angle::Result updateTransformFeedbackDescriptorSet(ContextVk *contextVk,
vk::FramebufferHelper *framebuffer);
......@@ -138,7 +137,7 @@ class ProgramVk : public ProgramImpl
vk::PipelineHelper **pipelineOut)
{
vk::ShaderProgramHelper *shaderProgram;
ANGLE_TRY(initShaders(contextVk, mode, &shaderProgram));
ANGLE_TRY(initGraphicsShaders(contextVk, mode, &shaderProgram));
ASSERT(shaderProgram->isGraphicsProgram());
RendererVk *renderer = contextVk->getRenderer();
return shaderProgram->getGraphicsPipeline(
......@@ -147,6 +146,14 @@ class ProgramVk : public ProgramImpl
mState.getAttributesTypeMask(), descPtrOut, pipelineOut);
}
angle::Result getComputePipeline(ContextVk *contextVk, vk::PipelineAndSerial **pipelineOut)
{
vk::ShaderProgramHelper *shaderProgram;
ANGLE_TRY(initComputeShader(contextVk, &shaderProgram));
ASSERT(!shaderProgram->isGraphicsProgram());
return shaderProgram->getComputePipeline(contextVk, mPipelineLayout.get(), pipelineOut);
}
// Used in testing only.
vk::DynamicDescriptorPool *getDynamicDescriptorPool(uint32_t poolIndex)
{
......@@ -170,7 +177,7 @@ class ProgramVk : public ProgramImpl
void updateDefaultUniformsDescriptorSet(ContextVk *contextVk);
void updateTransformFeedbackDescriptorSetImpl(ContextVk *contextVk);
void updateBuffersDescriptorSet(ContextVk *contextVk,
vk::FramebufferHelper *framebufferVk,
vk::CommandGraphResource *recorder,
const std::vector<gl::InterfaceBlock> &blocks,
VkDescriptorType descriptorType);
......@@ -186,26 +193,40 @@ class ProgramVk : public ProgramImpl
uint32_t getUniformBlockBindingsOffset() const { return 0; }
uint32_t getStorageBlockBindingsOffset() const { return mStorageBlockBindingsOffset; }
class ShaderInfo;
ANGLE_INLINE angle::Result initShaders(ContextVk *contextVk,
gl::PrimitiveMode mode,
bool enableLineRasterEmulation,
ShaderInfo *shaderInfo,
vk::ShaderProgramHelper **shaderProgramOut)
{
if (!shaderInfo->valid())
{
ANGLE_TRY(
shaderInfo->initShaders(contextVk, mShaderSources, enableLineRasterEmulation));
}
ASSERT(shaderInfo->valid());
*shaderProgramOut = &shaderInfo->getShaderProgram();
return angle::Result::Continue;
}
ANGLE_INLINE angle::Result initGraphicsShaders(ContextVk *contextVk,
gl::PrimitiveMode mode,
vk::ShaderProgramHelper **shaderProgramOut)
{
bool enableLineRasterEmulation = UseLineRaster(contextVk, mode);
ShaderInfo &shaderInfo =
enableLineRasterEmulation ? mLineRasterShaderInfo : mDefaultShaderInfo;
if (!shaderInfo.valid())
{
ANGLE_TRY(shaderInfo.initShaders(contextVk, mShaderSource[gl::ShaderType::Vertex],
mShaderSource[gl::ShaderType::Fragment],
enableLineRasterEmulation));
}
ASSERT(shaderInfo.valid());
*shaderProgramOut = &shaderInfo.getShaderProgram();
return initShaders(contextVk, enableLineRasterEmulation, &shaderInfo, shaderProgramOut);
}
return angle::Result::Continue;
ANGLE_INLINE angle::Result initComputeShader(ContextVk *contextVk,
vk::ShaderProgramHelper **shaderProgramOut)
{
return initShaders(contextVk, false, &mDefaultShaderInfo, shaderProgramOut);
}
// Save and load implementation for GLES Program Binary support.
......@@ -260,12 +281,15 @@ class ProgramVk : public ProgramImpl
~ShaderInfo();
angle::Result initShaders(ContextVk *contextVk,
const std::string &vertexSource,
const std::string &fragmentSource,
const gl::ShaderMap<std::string> &shaderSources,
bool enableLineRasterEmulation);
void release(ContextVk *contextVk);
ANGLE_INLINE bool valid() const { return mShaders[gl::ShaderType::Vertex].get().valid(); }
ANGLE_INLINE bool valid() const
{
return mShaders[gl::ShaderType::Vertex].get().valid() ||
mShaders[gl::ShaderType::Compute].get().valid();
}
vk::ShaderProgramHelper &getShaderProgram() { return mProgramHelper; }
......@@ -278,7 +302,7 @@ class ProgramVk : public ProgramImpl
ShaderInfo mLineRasterShaderInfo;
// We keep the translated linked shader sources to use with shader draw call patching.
gl::ShaderMap<std::string> mShaderSource;
gl::ShaderMap<std::string> mShaderSources;
// Storage buffers are placed after uniform buffers in their descriptor set. This cached value
// contains the offset where storage buffer bindings start.
......
......@@ -304,7 +304,7 @@ angle::Result VertexArrayVk::convertVertexBufferCPU(ContextVk *contextVk,
0, numVertices, binding.getStride(), vertexFormat.vertexLoadFunction,
&mCurrentArrayBuffers[attribIndex],
&conversion->lastAllocationOffset));
ANGLE_TRY(srcBuffer->unmapImpl(contextVk));
srcBuffer->unmapImpl(contextVk);
ASSERT(conversion->dirty);
conversion->dirty = false;
......
......@@ -35,6 +35,7 @@ void RendererVk::ensureCapsInitialized() const
ASSERT(mCurrentQueueFamilyIndex < mQueueFamilyProperties.size());
const VkQueueFamilyProperties &queueFamilyProperties =
mQueueFamilyProperties[mCurrentQueueFamilyIndex];
const VkPhysicalDeviceLimits &limitsVk = mPhysicalDeviceProperties.limits;
mNativeExtensions.setTextureExtensionSupport(mNativeTextureCaps);
......@@ -98,12 +99,9 @@ void RendererVk::ensureCapsInitialized() const
mNativeExtensions.queryCounterBitsTimestamp = queueFamilyProperties.timestampValidBits;
mNativeExtensions.textureFilterAnisotropic =
mPhysicalDeviceFeatures.samplerAnisotropy &&
mPhysicalDeviceProperties.limits.maxSamplerAnisotropy > 1.0f;
mPhysicalDeviceFeatures.samplerAnisotropy && limitsVk.maxSamplerAnisotropy > 1.0f;
mNativeExtensions.maxTextureAnisotropy =
mNativeExtensions.textureFilterAnisotropic
? mPhysicalDeviceProperties.limits.maxSamplerAnisotropy
: 0.0f;
mNativeExtensions.textureFilterAnisotropic ? limitsVk.maxSamplerAnisotropy : 0.0f;
// Vulkan natively supports non power-of-two textures
mNativeExtensions.textureNPOT = true;
......@@ -118,41 +116,34 @@ void RendererVk::ensureCapsInitialized() const
// https://vulkan.lunarg.com/doc/view/1.0.30.0/linux/vkspec.chunked/ch31s02.html
mNativeCaps.maxElementIndex = std::numeric_limits<GLuint>::max() - 1;
mNativeCaps.max3DTextureSize = mPhysicalDeviceProperties.limits.maxImageDimension3D;
mNativeCaps.max2DTextureSize = mPhysicalDeviceProperties.limits.maxImageDimension2D;
mNativeCaps.maxArrayTextureLayers = mPhysicalDeviceProperties.limits.maxImageArrayLayers;
mNativeCaps.maxLODBias = mPhysicalDeviceProperties.limits.maxSamplerLodBias;
mNativeCaps.maxCubeMapTextureSize = mPhysicalDeviceProperties.limits.maxImageDimensionCube;
mNativeCaps.max3DTextureSize = limitsVk.maxImageDimension3D;
mNativeCaps.max2DTextureSize = limitsVk.maxImageDimension2D;
mNativeCaps.maxArrayTextureLayers = limitsVk.maxImageArrayLayers;
mNativeCaps.maxLODBias = limitsVk.maxSamplerLodBias;
mNativeCaps.maxCubeMapTextureSize = limitsVk.maxImageDimensionCube;
mNativeCaps.maxRenderbufferSize = mNativeCaps.max2DTextureSize;
mNativeCaps.minAliasedPointSize =
std::max(1.0f, mPhysicalDeviceProperties.limits.pointSizeRange[0]);
mNativeCaps.maxAliasedPointSize = mPhysicalDeviceProperties.limits.pointSizeRange[1];
mNativeCaps.minAliasedPointSize = std::max(1.0f, limitsVk.pointSizeRange[0]);
mNativeCaps.maxAliasedPointSize = limitsVk.pointSizeRange[1];
mNativeCaps.minAliasedLineWidth = 1.0f;
mNativeCaps.maxAliasedLineWidth = 1.0f;
mNativeCaps.maxDrawBuffers =
std::min<uint32_t>(mPhysicalDeviceProperties.limits.maxColorAttachments,
mPhysicalDeviceProperties.limits.maxFragmentOutputAttachments);
mNativeCaps.maxFramebufferWidth = mPhysicalDeviceProperties.limits.maxFramebufferWidth;
mNativeCaps.maxFramebufferHeight = mPhysicalDeviceProperties.limits.maxFramebufferHeight;
mNativeCaps.maxColorAttachments = mPhysicalDeviceProperties.limits.maxColorAttachments;
mNativeCaps.maxViewportWidth = mPhysicalDeviceProperties.limits.maxViewportDimensions[0];
mNativeCaps.maxViewportHeight = mPhysicalDeviceProperties.limits.maxViewportDimensions[1];
mNativeCaps.maxSampleMaskWords = mPhysicalDeviceProperties.limits.maxSampleMaskWords;
mNativeCaps.maxColorTextureSamples =
mPhysicalDeviceProperties.limits.sampledImageColorSampleCounts;
mNativeCaps.maxDepthTextureSamples =
mPhysicalDeviceProperties.limits.sampledImageDepthSampleCounts;
mNativeCaps.maxIntegerSamples =
mPhysicalDeviceProperties.limits.sampledImageIntegerSampleCounts;
mNativeCaps.maxVertexAttributes = mPhysicalDeviceProperties.limits.maxVertexInputAttributes;
mNativeCaps.maxVertexAttribBindings = mPhysicalDeviceProperties.limits.maxVertexInputBindings;
mNativeCaps.maxVertexAttribRelativeOffset =
mPhysicalDeviceProperties.limits.maxVertexInputAttributeOffset;
mNativeCaps.maxVertexAttribStride =
mPhysicalDeviceProperties.limits.maxVertexInputBindingStride;
std::min<uint32_t>(limitsVk.maxColorAttachments, limitsVk.maxFragmentOutputAttachments);
mNativeCaps.maxFramebufferWidth = limitsVk.maxFramebufferWidth;
mNativeCaps.maxFramebufferHeight = limitsVk.maxFramebufferHeight;
mNativeCaps.maxColorAttachments = limitsVk.maxColorAttachments;
mNativeCaps.maxViewportWidth = limitsVk.maxViewportDimensions[0];
mNativeCaps.maxViewportHeight = limitsVk.maxViewportDimensions[1];
mNativeCaps.maxSampleMaskWords = limitsVk.maxSampleMaskWords;
mNativeCaps.maxColorTextureSamples = limitsVk.sampledImageColorSampleCounts;
mNativeCaps.maxDepthTextureSamples = limitsVk.sampledImageDepthSampleCounts;
mNativeCaps.maxIntegerSamples = limitsVk.sampledImageIntegerSampleCounts;
mNativeCaps.maxVertexAttributes = limitsVk.maxVertexInputAttributes;
mNativeCaps.maxVertexAttribBindings = limitsVk.maxVertexInputBindings;
mNativeCaps.maxVertexAttribRelativeOffset = limitsVk.maxVertexInputAttributeOffset;
mNativeCaps.maxVertexAttribStride = limitsVk.maxVertexInputBindingStride;
mNativeCaps.maxElementsIndices = std::numeric_limits<GLint>::max();
mNativeCaps.maxElementsVertices = std::numeric_limits<GLint>::max();
......@@ -174,13 +165,23 @@ void RendererVk::ensureCapsInitialized() const
mNativeCaps.fragmentMediumpInt.setTwosComplementInt(32);
mNativeCaps.fragmentLowpInt.setTwosComplementInt(32);
// Compute shader limits.
mNativeCaps.maxComputeWorkGroupCount[0] = limitsVk.maxComputeWorkGroupCount[0];
mNativeCaps.maxComputeWorkGroupCount[1] = limitsVk.maxComputeWorkGroupCount[1];
mNativeCaps.maxComputeWorkGroupCount[2] = limitsVk.maxComputeWorkGroupCount[2];
mNativeCaps.maxComputeWorkGroupSize[0] = limitsVk.maxComputeWorkGroupSize[0];
mNativeCaps.maxComputeWorkGroupSize[1] = limitsVk.maxComputeWorkGroupSize[1];
mNativeCaps.maxComputeWorkGroupSize[2] = limitsVk.maxComputeWorkGroupSize[2];
mNativeCaps.maxComputeWorkGroupInvocations = limitsVk.maxComputeWorkGroupInvocations;
mNativeCaps.maxComputeSharedMemorySize = limitsVk.maxComputeSharedMemorySize;
// TODO(lucferron): This is something we'll need to implement custom in the back-end.
// Vulkan doesn't do any waiting for you, our back-end code is going to manage sync objects,
// and we'll have to check that we've exceeded the max wait timeout. Also, this is ES 3.0 so
// we'll defer the implementation until we tackle the next version.
// mNativeCaps.maxServerWaitTimeout
GLuint maxUniformBlockSize = mPhysicalDeviceProperties.limits.maxUniformBufferRange;
GLuint maxUniformBlockSize = limitsVk.maxUniformBufferRange;
// Clamp the maxUniformBlockSize to 64KB (majority of devices support up to this size
// currently), on AMD the maxUniformBufferRange is near uint32_t max.
......@@ -192,10 +193,11 @@ void RendererVk::ensureCapsInitialized() const
// Uniforms are implemented using a uniform buffer, so the max number of uniforms we can
// support is the max buffer range divided by the size of a single uniform (4X float).
mNativeCaps.maxVertexUniformVectors = maxUniformVectors;
mNativeCaps.maxShaderUniformComponents[gl::ShaderType::Vertex] = maxUniformComponents;
mNativeCaps.maxFragmentUniformVectors = maxUniformVectors;
mNativeCaps.maxFragmentInputComponents = maxUniformComponents;
mNativeCaps.maxShaderUniformComponents[gl::ShaderType::Vertex] = maxUniformComponents;
mNativeCaps.maxShaderUniformComponents[gl::ShaderType::Fragment] = maxUniformComponents;
mNativeCaps.maxShaderUniformComponents[gl::ShaderType::Compute] = maxUniformComponents;
// Every stage has 1 reserved uniform buffer for the default uniforms, and 1 for the driver
// uniforms.
......@@ -205,41 +207,33 @@ void RendererVk::ensureCapsInitialized() const
kReservedDriverUniformBindingCount + kReservedDefaultUniformBindingCount;
const uint32_t maxPerStageUniformBuffers =
mPhysicalDeviceProperties.limits.maxPerStageDescriptorUniformBuffers -
kTotalReservedPerStageUniformBuffers;
limitsVk.maxPerStageDescriptorUniformBuffers - kTotalReservedPerStageUniformBuffers;
const uint32_t maxCombinedUniformBuffers =
mPhysicalDeviceProperties.limits.maxDescriptorSetUniformBuffers -
kTotalReservedUniformBuffers;
limitsVk.maxDescriptorSetUniformBuffers - kTotalReservedUniformBuffers;
mNativeCaps.maxShaderUniformBlocks[gl::ShaderType::Vertex] = maxPerStageUniformBuffers;
mNativeCaps.maxShaderUniformBlocks[gl::ShaderType::Fragment] = maxPerStageUniformBuffers;
mNativeCaps.maxShaderUniformBlocks[gl::ShaderType::Compute] = maxPerStageUniformBuffers;
mNativeCaps.maxCombinedUniformBlocks = maxCombinedUniformBuffers;
mNativeCaps.maxUniformBufferBindings = maxCombinedUniformBuffers;
mNativeCaps.maxUniformBlockSize = maxUniformBlockSize;
mNativeCaps.uniformBufferOffsetAlignment =
static_cast<GLuint>(mPhysicalDeviceProperties.limits.minUniformBufferOffsetAlignment);
static_cast<GLuint>(limitsVk.minUniformBufferOffsetAlignment);
// Note that Vulkan currently implements textures as combined image+samplers, so the limit is
// the minimum of supported samplers and sampled images.
const uint32_t maxPerStageTextures =
std::min(mPhysicalDeviceProperties.limits.maxPerStageDescriptorSamplers,
mPhysicalDeviceProperties.limits.maxPerStageDescriptorSampledImages);
const uint32_t maxPerStageTextures = std::min(limitsVk.maxPerStageDescriptorSamplers,
limitsVk.maxPerStageDescriptorSampledImages);
const uint32_t maxCombinedTextures =
std::min(mPhysicalDeviceProperties.limits.maxDescriptorSetSamplers,
mPhysicalDeviceProperties.limits.maxDescriptorSetSampledImages);
std::min(limitsVk.maxDescriptorSetSamplers, limitsVk.maxDescriptorSetSampledImages);
mNativeCaps.maxShaderTextureImageUnits[gl::ShaderType::Vertex] = maxPerStageTextures;
mNativeCaps.maxShaderTextureImageUnits[gl::ShaderType::Fragment] = maxPerStageTextures;
mNativeCaps.maxShaderTextureImageUnits[gl::ShaderType::Compute] = maxPerStageTextures;
mNativeCaps.maxCombinedTextureImageUnits = maxCombinedTextures;
const uint32_t maxPerStageStorageBuffers =
mPhysicalDeviceProperties.limits.maxPerStageDescriptorStorageBuffers;
const uint32_t maxCombinedStorageBuffers =
mPhysicalDeviceProperties.limits.maxDescriptorSetStorageBuffers;
mNativeCaps.maxShaderStorageBlocks[gl::ShaderType::Vertex] =
mPhysicalDeviceFeatures.vertexPipelineStoresAndAtomics ? maxPerStageStorageBuffers : 0;
mNativeCaps.maxShaderStorageBlocks[gl::ShaderType::Fragment] =
mPhysicalDeviceFeatures.fragmentStoresAndAtomics ? maxPerStageStorageBuffers : 0;
mNativeCaps.maxCombinedShaderStorageBlocks = maxCombinedStorageBuffers;
uint32_t maxPerStageStorageBuffers = limitsVk.maxPerStageDescriptorStorageBuffers;
uint32_t maxVertexStageStorageBuffers = maxPerStageStorageBuffers;
uint32_t maxCombinedStorageBuffers = limitsVk.maxDescriptorSetStorageBuffers;
// A number of storage buffer slots are used in the vertex shader to emulate transform feedback.
// Note that Vulkan requires maxPerStageDescriptorStorageBuffers to be at least 4 (i.e. the same
......@@ -253,17 +247,26 @@ void RendererVk::ensureCapsInitialized() const
"Limit to ES2.0 if supported SSBO count < supporting transform feedback buffer count");
if (mPhysicalDeviceFeatures.vertexPipelineStoresAndAtomics)
{
ASSERT(maxPerStageStorageBuffers >= gl::IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS);
mNativeCaps.maxShaderStorageBlocks[gl::ShaderType::Vertex] -=
gl::IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS;
mNativeCaps.maxCombinedShaderStorageBlocks -=
gl::IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS;
ASSERT(maxVertexStageStorageBuffers >= gl::IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS);
maxVertexStageStorageBuffers -= gl::IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS;
maxCombinedStorageBuffers -= gl::IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS;
// Cap the per-stage limit of the other stages to the combined limit, in case the combined
// limit is now lower than that.
maxPerStageStorageBuffers = std::min(maxPerStageStorageBuffers, maxCombinedStorageBuffers);
}
mNativeCaps.maxShaderStorageBlocks[gl::ShaderType::Vertex] =
mPhysicalDeviceFeatures.vertexPipelineStoresAndAtomics ? maxVertexStageStorageBuffers : 0;
mNativeCaps.maxShaderStorageBlocks[gl::ShaderType::Fragment] =
mPhysicalDeviceFeatures.fragmentStoresAndAtomics ? maxPerStageStorageBuffers : 0;
mNativeCaps.maxShaderStorageBlocks[gl::ShaderType::Compute] = maxPerStageStorageBuffers;
mNativeCaps.maxCombinedShaderStorageBlocks = maxCombinedStorageBuffers;
mNativeCaps.maxShaderStorageBufferBindings = maxCombinedStorageBuffers;
mNativeCaps.maxShaderStorageBlockSize = mPhysicalDeviceProperties.limits.maxStorageBufferRange;
mNativeCaps.maxShaderStorageBlockSize = limitsVk.maxStorageBufferRange;
mNativeCaps.shaderStorageBufferOffsetAlignment =
static_cast<GLuint>(mPhysicalDeviceProperties.limits.minStorageBufferOffsetAlignment);
static_cast<GLuint>(limitsVk.minStorageBufferOffsetAlignment);
mNativeCaps.minProgramTexelOffset = mPhysicalDeviceProperties.limits.minTexelOffset;
mNativeCaps.maxProgramTexelOffset = mPhysicalDeviceProperties.limits.maxTexelOffset;
......@@ -274,7 +277,7 @@ void RendererVk::ensureCapsInitialized() const
const uint32_t maxCombinedUniformComponents =
(maxPerStageUniformBuffers + kReservedPerStageDefaultUniformBindingCount) *
maxUniformComponents;
for (gl::ShaderType shaderType : gl::kAllGraphicsShaderTypes)
for (gl::ShaderType shaderType : gl::AllShaderTypes())
{
mNativeCaps.maxCombinedShaderUniformComponents[shaderType] = maxCombinedUniformComponents;
}
......@@ -294,8 +297,8 @@ void RendererVk::ensureCapsInitialized() const
// which total a minimum of 44 resources, so no underflow is possible here. Limit the total
// number of resources reported by Vulkan to 2 billion though to avoid seeing negative numbers
// in applications that take the value as signed int (including dEQP).
const uint32_t maxPerStageResources = std::min<uint32_t>(
std::numeric_limits<int32_t>::max(), mPhysicalDeviceProperties.limits.maxPerStageResources);
const uint32_t maxPerStageResources =
std::min<uint32_t>(std::numeric_limits<int32_t>::max(), limitsVk.maxPerStageResources);
mNativeCaps.maxCombinedShaderOutputResources =
maxPerStageResources - kReservedPerStageBindingCount;
......@@ -308,7 +311,7 @@ void RendererVk::ensureCapsInitialized() const
// often crash. Reserving an additional varying just for them bringing the total to 2.
constexpr GLint kReservedVaryingCount = 2;
mNativeCaps.maxVaryingVectors =
(mPhysicalDeviceProperties.limits.maxVertexOutputComponents / 4) - kReservedVaryingCount;
(limitsVk.maxVertexOutputComponents / 4) - kReservedVaryingCount;
mNativeCaps.maxVertexOutputComponents = mNativeCaps.maxVaryingVectors * 4;
mNativeCaps.maxTransformFeedbackInterleavedComponents =
......@@ -318,17 +321,16 @@ void RendererVk::ensureCapsInitialized() const
mNativeCaps.maxTransformFeedbackSeparateComponents =
gl::IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS;
mNativeCaps.minProgramTexelOffset = mPhysicalDeviceProperties.limits.minTexelOffset;
mNativeCaps.maxProgramTexelOffset = mPhysicalDeviceProperties.limits.maxTexelOffset;
mNativeCaps.minProgramTexelOffset = limitsVk.minTexelOffset;
mNativeCaps.maxProgramTexelOffset = limitsVk.maxTexelOffset;
const VkPhysicalDeviceLimits &limits = mPhysicalDeviceProperties.limits;
const uint32_t sampleCounts = limits.framebufferColorSampleCounts &
limits.framebufferDepthSampleCounts &
limits.framebufferStencilSampleCounts;
const uint32_t sampleCounts = limitsVk.framebufferColorSampleCounts &
limitsVk.framebufferDepthSampleCounts &
limitsVk.framebufferStencilSampleCounts;
mNativeCaps.maxSamples = vk_gl::GetMaxSampleCount(sampleCounts);
mNativeCaps.subPixelBits = mPhysicalDeviceProperties.limits.subPixelPrecisionBits;
mNativeCaps.subPixelBits = limitsVk.subPixelPrecisionBits;
}
namespace egl_vk
......
......@@ -1136,7 +1136,7 @@ angle::Result LineLoopHelper::getIndexBufferForElementArrayBuffer(ContextVk *con
ANGLE_TRY(streamIndices(contextVk, glIndexType, indexCount,
static_cast<const uint8_t *>(srcDataMapping) + elementArrayOffset,
bufferOut, bufferOffsetOut, indexCountOut));
ANGLE_TRY(elementArrayBufferVk->unmapImpl(contextVk));
elementArrayBufferVk->unmapImpl(contextVk);
return angle::Result::Continue;
}
......@@ -2628,6 +2628,11 @@ void FramebufferHelper::release(ContextVk *contextVk)
contextVk->releaseObject(getStoredQueueSerial(), &mFramebuffer);
}
// FramebufferHelper implementation.
DispatchHelper::DispatchHelper() : CommandGraphResource(CommandGraphResourceType::Dispatcher) {}
DispatchHelper::~DispatchHelper() = default;
// ShaderProgramHelper implementation.
ShaderProgramHelper::ShaderProgramHelper() = default;
......
......@@ -970,6 +970,15 @@ class FramebufferHelper : public CommandGraphResource
Framebuffer mFramebuffer;
};
// A special command graph resource to hold resource dependencies for dispatch calls. It's the
// equivalent of FramebufferHelper, though it doesn't contain a Vulkan object.
class DispatchHelper : public CommandGraphResource
{
public:
DispatchHelper();
~DispatchHelper() override;
};
class ShaderProgramHelper : angle::NonCopyable
{
public:
......
......@@ -627,17 +627,17 @@
// GL_MIN/MAX_PROGRAM_TEXTURE_GATHER_OFFSET not set.
3605 VULKAN : dEQP-GLES31.functional.texture.gather.offset.* = FAIL
// Compute shaders:
3562 VULKAN : dEQP-GLES31.functional.shaders.builtin_var.compute.* = FAIL
3562 VULKAN : dEQP-GLES31.functional.compute.* = FAIL
3566 VULKAN : dEQP-GLES31.functional.ssbo.* = FAIL
3561 VULKAN : dEQP-GLES31.functional.synchronization.*.ssbo* = FAIL
3562 VULKAN : dEQP-GLES31.functional.shaders.builtin_functions.common.*compute = FAIL
3562 VULKAN : dEQP-GLES31.functional.shaders.builtin_functions.precision*compute* = FAIL
3563 VULKAN : dEQP-GLES31.functional.state_query.*compute* = SKIP
3562 VULKAN : dEQP-GLES31.functional.state_query.program.compute_work_group_size_get_programiv = FAIL
3562 VULKAN : dEQP-GLES31.functional.program_interface_query.buffer_limited_query.resource_*query = FAIL
3562 VULKAN : dEQP-GLES31.functional.program_interface_query.program_*.resource_list.compute.empty = FAIL
// Front-end query bugs:
3520 VULKAN : dEQP-GLES31.functional.program_interface_query.buffer_limited_query.resource_*query = FAIL
3520 VULKAN : dEQP-GLES31.functional.program_interface_query.program_*.resource_list.compute.empty = FAIL
3520 VULKAN : dEQP-GLES31.functional.program_interface_query.shader_storage_block.buffer_data_size.* = FAIL
// glMemoryBarrier support:
3574 VULKAN : dEQP-GLES31.functional.compute.*barrier* = SKIP
3574 VULKAN : dEQP-GLES31.functional.synchronization.*memory_barrier* = SKIP
// Indirect dispatch:
3601 VULKAN : dEQP-GLES31.functional.compute.*indirect* = SKIP
// Shader support:
3569 VULKAN : dEQP-GLES31.functional.shaders.builtin_functions.common.frexp.* = FAIL
......@@ -655,10 +655,14 @@
3569 VULKAN : dEQP-GLES31.functional.shaders.builtin_constants.core.min_program_texel_offset = FAIL
3569 VULKAN : dEQP-GLES31.functional.shaders.uniform_block.es31.valid.* = FAIL
// SSBO and Image qualifiers:
3602 VULKAN : dEQP-GLES31.functional.synchronization.in_invocation.ssbo_alias_overwrite = FAIL
// Array of array and struct default uniforms:
3604 VULKAN : dEQP-GLES31.functional.program_interface_query.*float_struct = FAIL
3604 VULKAN : dEQP-GLES31.functional.program_interface_query.*float_struct_struct = FAIL
3604 VULKAN : dEQP-GLES31.functional.program_interface_query.*random* = FAIL
3604 VULKAN : dEQP-GLES31.functional.program_interface_query.program_output.* = SKIP
3604 VULKAN : dEQP-GLES31.functional.program_interface_query.*array*array* = SKIP
// Block name matching failure:
3459 VULKAN : dEQP-GLES31.functional.shaders.linkage.es31.shader_storage_block.mismatch_with_and_without_instance_name = FAIL
......@@ -674,10 +678,12 @@
// Atomic counters:
3566 VULKAN : dEQP-GLES31.functional.*atomic_counter* = FAIL
3566 VULKAN : dEQP-GLES31.functional.ssbo.layout.* = FAIL
// Storage image:
3563 VULKAN : dEQP-GLES31.functional.state_query.*image* = FAIL
3563 VULKAN : dEQP-GLES31.functional.synchronization.*.image* = FAIL
3563 VULKAN : dEQP-GLES31.functional.compute.*image* = FAIL
// Framebuffer parameters (FRAMEBUFFER_DEFAULT_SAMPLES):
3520 VULKAN : dEQP-GLES31.functional.state_query.framebuffer_default.framebuffer_default_samples_get_framebuffer_parameteriv = FAIL
......
......@@ -36,12 +36,12 @@
// General Vulkan expectations
// Limits:
// GL_MIN/MAX_PROGRAM_TEXTURE_GATHER_OFFSET not set.
3605 VULKAN : KHR-GLES31.core.texture_gather* = FAIL
// GL_MIN/MAX_PROGRAM_TEXTURE_GATHER_OFFSET not set. Also crashes on memory barrier support missing.
3605 VULKAN : KHR-GLES31.core.texture_gather.* = SKIP
// Compute shaders
3562 VULKAN : KHR-GLES31.core.constant_expressions.* = SKIP
3520 VULKAN : KHR-GLES31.core.compute_shader* = SKIP
// Memory barriers
3574 VULKAN : KHR-GLES31.core.compute_shader* = SKIP
3574 VULKAN : KHR-GLES31.core.shader_atomic_counters.basic-glsl-built-in = SKIP
// Multisampled textures:
3565 VULKAN : KHR-GLES31.core.texture_storage_multisample.* = SKIP
......@@ -67,14 +67,21 @@
3570 VULKAN : KHR-GLES31.core.sepshaderobjs* = FAIL
// Shader support:
3569 VULKAN : KHR-GLES31.core.shader_bitfield_operation* = FAIL
3569 VULKAN : KHR-GLES31.core.shader_integer_mix.* = FAIL
3569 VULKAN : KHR-GLES31.core.shader_image* = SKIP
3569 VULKAN : KHR-GLES31.core.shader_macros* = FAIL
3569 VULKAN : KHR-GLES31.core.shader_bitfield_operation.frexp.* = SKIP
3569 VULKAN : KHR-GLES31.core.shader_bitfield_operation.uaddCarry.* = SKIP
3569 VULKAN : KHR-GLES31.core.shader_bitfield_operation.usubBorrow.* = SKIP
3569 VULKAN : KHR-GLES31.core.shader_bitfield_operation.umulExtended.* = SKIP
3569 VULKAN : KHR-GLES31.core.shader_bitfield_operation.imulExtended.* = SKIP
/// Crash due to missing unsupported check in dEQP
3571 VULKAN : KHR-GLES31.core.shader_macros*_geometry = SKIP
3571 VULKAN : KHR-GLES31.core.shader_macros*_tess_control = SKIP
3571 VULKAN : KHR-GLES31.core.shader_macros*_tess_eval = SKIP
3571 VULKAN : KHR-GLES31.core.constant_expressions.*geometry = SKIP
3571 VULKAN : KHR-GLES31.core.constant_expressions.*tess_control = SKIP
3571 VULKAN : KHR-GLES31.core.constant_expressions.*tess_eval = SKIP
3520 VULKAN : KHR-GLES31.core.vertex_attrib_binding* = SKIP
3520 VULKAN : KHR-GLES31.core.internalformat.texture2d.* = FAIL
......@@ -85,7 +92,8 @@
// Draw indirect:
3564 VULKAN : KHR-GLES31.core.draw_indirect.* = SKIP
3520 VULKAN : KHR-GLES31.core.explicit_uniform_location.* = FAIL
// Explicit uniform locations:
3597 VULKAN : KHR-GLES31.core.explicit_uniform_location.* = SKIP
3520 VULKAN : KHR-GLES31.core.program_interface_query.* = SKIP
......@@ -97,6 +105,10 @@
// Blend equations:
3586 VULKAN : KHR-GLES31.core.blend_equation_advanced.* = SKIP
// Storage image:
3563 VULKAN : KHR-GLES31.core.layout_binding.sampler2D_layout_binding_texture_ComputeShader = FAIL
3563 VULKAN : KHR-GLES31.core.layout_binding.block_layout_binding_block_ComputeShader = FAIL
3520 VULKAN : KHR-GLES31.core.internalformat.copy_tex_image* = FAIL
3520 VULKAN : KHR-GLES31.core.internalformat.renderbuffer* = FAIL
......
......@@ -315,6 +315,9 @@ TEST_P(ShaderStorageBufferTest31, ShaderStorageBufferReadWrite)
// Tests modifying an existing shader storage buffer
TEST_P(ShaderStorageBufferTest31, ShaderStorageBufferReadWriteSame)
{
// Vulkan doesn't support memory barriers yet. http://anglebug.com/3574
ANGLE_SKIP_TEST_IF(IsVulkan());
constexpr char kComputeShaderSource[] =
R"(#version 310 es
layout(local_size_x=1, local_size_y=1, local_size_z=1) in;
......@@ -410,6 +413,9 @@ void main()
// Tests reading and writing to a shader storage buffer bound at an offset.
TEST_P(ShaderStorageBufferTest31, ShaderStorageBufferReadWriteOffset)
{
// Vulkan doesn't support memory barriers yet. http://anglebug.com/3574
ANGLE_SKIP_TEST_IF(IsVulkan());
constexpr char kCS[] = R"(#version 310 es
layout(local_size_x=1, local_size_y=1, local_size_z=1) in;
......@@ -1593,8 +1599,10 @@ TEST_P(ShaderStorageBufferTest31, LoadAndStoreBooleanValue)
// http://anglebug.com/1951
ANGLE_SKIP_TEST_IF(IsIntel() && IsLinux());
// Seems to fail on Windows NVIDIA GL when tests are run without interruption.
// Seems to fail on Windows NVIDIA GL when tests are run without interruption. It also happens
// on Vulkan. http://anglebug.com/3694
ANGLE_SKIP_TEST_IF(IsWindows() && IsNVIDIA() && IsOpenGL());
ANGLE_SKIP_TEST_IF(IsWindows() && IsVulkan());
constexpr char kComputeShaderSource[] = R"(#version 310 es
layout (local_size_x=1) in;
......@@ -2072,6 +2080,10 @@ void main()
EXPECT_GL_NO_ERROR();
}
ANGLE_INSTANTIATE_TEST(ShaderStorageBufferTest31, ES31_OPENGL(), ES31_OPENGLES(), ES31_D3D11());
ANGLE_INSTANTIATE_TEST(ShaderStorageBufferTest31,
ES31_OPENGL(),
ES31_OPENGLES(),
ES31_D3D11(),
ES31_VULKAN());
} // namespace
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