Commit 2219b18c by Tobin Ehlis Committed by Commit Bot

Vulkan:Optimize SecondaryCommandBuffers

Optimize performance of SecondaryCommandBuffers and enable them as the default build option. To disable this set angle_enable_custom_vulkan_cmd_buffers=false in your build args. This CL enhances the PoolAllocator to have a "fast" mode that can be enabled at class creation. This mode uses an alignment of 1 byte and enables a fastAllocation() call that avoids some bookkeeping overhead. The SecondaryCommandBuffer uses this fastAllocation() function. Furthermore the fast path of fast allocate, using the current page, is inlined for maximum speed. Jamie Madill also updated the SecondaryCommandBuffers to pre-allocate blocks so that the commands occur linearly in memory. This speeds up processing with improved cache coherency and minimizes overhead when recording commands. Also the core Draw functions and their state updates are all inlined as well as the common functions to initialize commands and to copy command pointer data. This change also includes some new, custom commands. One is imageBarrier that is a specialized version of pipelineBarrier that only performs a single image layout transition. There are customized versions of various Draw commands to minimize copying of parameters. There are also specialized commands to bind[Graphics|Compute]Pipeline that have the pipeline type built in to the command. More custom commands and command data size optimizations will be made in follow-on commits. Bug: angleproject:3136 Change-Id: I35453cc2656bc8c51f0d84d1adef106900aca9a5 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/1497418 Commit-Queue: Tobin Ehlis <tobine@google.com> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org>
parent 3e8a8d5b
...@@ -86,7 +86,7 @@ declare_args() { ...@@ -86,7 +86,7 @@ declare_args() {
angle_vulkan_conformant_configs_only = is_official_build angle_vulkan_conformant_configs_only = is_official_build
# Enable custom (cpu-side) secondary command buffers # Enable custom (cpu-side) secondary command buffers
angle_enable_custom_vulkan_cmd_buffers = false angle_enable_custom_vulkan_cmd_buffers = true
} }
} }
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
#include "common/angleutils.h" #include "common/angleutils.h"
#include "common/debug.h" #include "common/debug.h"
#include "common/mathutil.h"
#include "common/platform.h" #include "common/platform.h"
#include "common/tls.h" #include "common/tls.h"
...@@ -36,43 +37,48 @@ PoolAllocator::PoolAllocator(int growthIncrement, int allocationAlignment) ...@@ -36,43 +37,48 @@ PoolAllocator::PoolAllocator(int growthIncrement, int allocationAlignment)
#endif #endif
mLocked(false) mLocked(false)
{ {
// if (mAlignment == 1)
// Adjust mAlignment to be at least pointer aligned and {
// power of 2. // This is a special fast-path where fastAllocation() is enabled
// mAlignmentMask = 0;
size_t minAlign = sizeof(void *); mHeaderSkip = sizeof(Header);
mAlignment &= ~(minAlign - 1); }
if (mAlignment < minAlign) else
mAlignment = minAlign; {
size_t a = 1; //
while (a < mAlignment) // Adjust mAlignment to be at least pointer aligned and
a <<= 1; // power of 2.
mAlignment = a; //
mAlignmentMask = a - 1; size_t minAlign = sizeof(void *);
mAlignment &= ~(minAlign - 1);
if (mAlignment < minAlign)
mAlignment = minAlign;
mAlignment = gl::ceilPow2(mAlignment);
mAlignmentMask = mAlignment - 1;
#if !defined(ANGLE_DISABLE_POOL_ALLOC) #if !defined(ANGLE_DISABLE_POOL_ALLOC)
//
// Align header skip
//
mHeaderSkip = minAlign;
if (mHeaderSkip < sizeof(Header))
{
mHeaderSkip = rx::roundUp(sizeof(Header), mAlignment);
}
}
// //
// Don't allow page sizes we know are smaller than all common // Don't allow page sizes we know are smaller than all common
// OS page sizes. // OS page sizes.
// //
if (mPageSize < 4 * 1024) if (mPageSize < 4 * 1024)
mPageSize = 4 * 1024; mPageSize = 4 * 1024;
// //
// A large mCurrentPageOffset indicates a new page needs to // A large mCurrentPageOffset indicates a new page needs to
// be obtained to allocate memory. // be obtained to allocate memory.
// //
mCurrentPageOffset = mPageSize; mCurrentPageOffset = mPageSize;
//
// Align header skip
//
mHeaderSkip = minAlign;
if (mHeaderSkip < sizeof(Header))
{
mHeaderSkip = (sizeof(Header) + mAlignmentMask) & ~mAlignmentMask;
}
#else // !defined(ANGLE_DISABLE_POOL_ALLOC) #else // !defined(ANGLE_DISABLE_POOL_ALLOC)
}
mStack.push_back({}); mStack.push_back({});
#endif #endif
} }
...@@ -262,7 +268,21 @@ void *PoolAllocator::allocate(size_t numBytes) ...@@ -262,7 +268,21 @@ void *PoolAllocator::allocate(size_t numBytes)
reinterpret_cast<void *>(reinterpret_cast<uintptr_t>(memory) + mHeaderSkip); reinterpret_cast<void *>(reinterpret_cast<uintptr_t>(memory) + mHeaderSkip);
return std::align(mAlignment, numBytes, unalignedPtr, allocationSize); return std::align(mAlignment, numBytes, unalignedPtr, allocationSize);
} }
unsigned char *newPageAddr =
static_cast<unsigned char *>(allocateNewPage(numBytes, allocationSize));
return initializeAllocation(mInUseList, newPageAddr, numBytes);
#else // !defined(ANGLE_DISABLE_POOL_ALLOC)
void *alloc = malloc(numBytes + mAlignmentMask);
mStack.back().push_back(alloc);
intptr_t intAlloc = reinterpret_cast<intptr_t>(alloc);
intAlloc = rx::roundUp(intAlloc, mAlignment);
return reinterpret_cast<void *>(intAlloc);
#endif
}
void *PoolAllocator::allocateNewPage(size_t numBytes, size_t allocationSize)
{
// //
// Need a simple page to allocate from. // Need a simple page to allocate from.
// //
...@@ -278,22 +298,13 @@ void *PoolAllocator::allocate(size_t numBytes) ...@@ -278,22 +298,13 @@ void *PoolAllocator::allocate(size_t numBytes)
if (memory == 0) if (memory == 0)
return 0; return 0;
} }
// Use placement-new to initialize header // Use placement-new to initialize header
new (memory) Header(mInUseList, 1); new (memory) Header(mInUseList, 1);
mInUseList = memory; mInUseList = memory;
unsigned char *ret = reinterpret_cast<unsigned char *>(mInUseList) + mHeaderSkip; unsigned char *ret = reinterpret_cast<unsigned char *>(mInUseList) + mHeaderSkip;
mCurrentPageOffset = (mHeaderSkip + allocationSize + mAlignmentMask) & ~mAlignmentMask; mCurrentPageOffset = (mHeaderSkip + allocationSize + mAlignmentMask) & ~mAlignmentMask;
return initializeAllocation(mInUseList, ret, numBytes); return ret;
#else // !defined(ANGLE_DISABLE_POOL_ALLOC)
void *alloc = malloc(numBytes + mAlignmentMask);
mStack.back().push_back(alloc);
intptr_t intAlloc = reinterpret_cast<intptr_t>(alloc);
intAlloc = (intAlloc + mAlignmentMask) & ~mAlignmentMask;
return reinterpret_cast<void *>(intAlloc);
#endif
} }
void PoolAllocator::lock() void PoolAllocator::lock()
......
...@@ -38,6 +38,7 @@ ...@@ -38,6 +38,7 @@
#include <vector> #include <vector>
#include "angleutils.h" #include "angleutils.h"
#include "common/debug.h"
namespace angle namespace angle
{ {
...@@ -123,6 +124,10 @@ class PoolAllocator : angle::NonCopyable ...@@ -123,6 +124,10 @@ class PoolAllocator : angle::NonCopyable
{ {
public: public:
static const int kDefaultAlignment = 16; static const int kDefaultAlignment = 16;
//
// Create PoolAllocator. If alignment is be set to 1 byte then fastAllocate()
// function can be used to make allocations with less overhead.
//
PoolAllocator(int growthIncrement = 8 * 1024, int allocationAlignment = kDefaultAlignment); PoolAllocator(int growthIncrement = 8 * 1024, int allocationAlignment = kDefaultAlignment);
// //
...@@ -154,6 +159,32 @@ class PoolAllocator : angle::NonCopyable ...@@ -154,6 +159,32 @@ class PoolAllocator : angle::NonCopyable
void *allocate(size_t numBytes); void *allocate(size_t numBytes);
// //
// Call fastAllocate() for a faster allocate function that does minimal bookkeeping
// preCondition: Allocator must have been created w/ alignment of 1
ANGLE_INLINE uint8_t *fastAllocate(size_t numBytes)
{
#if defined(ANGLE_DISABLE_POOL_ALLOC)
return allocate(numBytes);
#endif
ASSERT(mAlignment == 1);
// No multi-page allocations
ASSERT(numBytes <= (mPageSize - mHeaderSkip));
//
// Do the allocation, most likely case inline first, for efficiency.
//
if (numBytes <= mPageSize - mCurrentPageOffset)
{
//
// Safe to allocate from mCurrentPageOffset.
//
uint8_t *memory = reinterpret_cast<uint8_t *>(mInUseList) + mCurrentPageOffset;
mCurrentPageOffset += numBytes;
return memory;
}
return reinterpret_cast<uint8_t *>(allocateNewPage(numBytes, numBytes));
}
//
// There is no deallocate. The point of this class is that // There is no deallocate. The point of this class is that
// deallocation can be skipped by the user of it, as the model // deallocation can be skipped by the user of it, as the model
// of use is to simultaneously deallocate everything at once // of use is to simultaneously deallocate everything at once
...@@ -205,6 +236,8 @@ class PoolAllocator : angle::NonCopyable ...@@ -205,6 +236,8 @@ class PoolAllocator : angle::NonCopyable
}; };
using AllocStack = std::vector<AllocState>; using AllocStack = std::vector<AllocState>;
// Slow path of allocation when we have to get a new page.
void *allocateNewPage(size_t numBytes, size_t allocationSize);
// Track allocations if and only if we're using guard blocks // Track allocations if and only if we're using guard blocks
void *initializeAllocation(Header *block, unsigned char *memory, size_t numBytes) void *initializeAllocation(Header *block, unsigned char *memory, size_t numBytes)
{ {
......
...@@ -139,10 +139,9 @@ void MakeDebugUtilsLabel(GLenum source, const char *marker, VkDebugUtilsLabelEXT ...@@ -139,10 +139,9 @@ void MakeDebugUtilsLabel(GLenum source, const char *marker, VkDebugUtilsLabelEXT
} }
#if ANGLE_USE_CUSTOM_VULKAN_CMD_BUFFERS #if ANGLE_USE_CUSTOM_VULKAN_CMD_BUFFERS
static constexpr VkSubpassContents kRenderPassContents = VK_SUBPASS_CONTENTS_INLINE; constexpr VkSubpassContents kRenderPassContents = VK_SUBPASS_CONTENTS_INLINE;
#else #else
static constexpr VkSubpassContents kRenderPassContents = constexpr VkSubpassContents kRenderPassContents = VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS;
VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS;
#endif #endif
// Helpers to unify executeCommands call based on underlying cmd buffer type // Helpers to unify executeCommands call based on underlying cmd buffer type
...@@ -303,7 +302,6 @@ CommandGraphNode::CommandGraphNode(CommandGraphNodeFunction function, ...@@ -303,7 +302,6 @@ CommandGraphNode::CommandGraphNode(CommandGraphNodeFunction function,
CommandGraphNode::~CommandGraphNode() CommandGraphNode::~CommandGraphNode()
{ {
mRenderPassFramebuffer.setHandle(VK_NULL_HANDLE); mRenderPassFramebuffer.setHandle(VK_NULL_HANDLE);
// Command buffers are managed by the command pool, so don't need to be freed. // Command buffers are managed by the command pool, so don't need to be freed.
mOutsideRenderPassCommands.releaseHandle(); mOutsideRenderPassCommands.releaseHandle();
mInsideRenderPassCommands.releaseHandle(); mInsideRenderPassCommands.releaseHandle();
...@@ -503,7 +501,6 @@ angle::Result CommandGraphNode::visitAndExecute(vk::Context *context, ...@@ -503,7 +501,6 @@ angle::Result CommandGraphNode::visitAndExecute(vk::Context *context,
RenderPass *renderPass = nullptr; RenderPass *renderPass = nullptr;
ANGLE_TRY(renderPassCache->getCompatibleRenderPass(context, serial, mRenderPassDesc, ANGLE_TRY(renderPassCache->getCompatibleRenderPass(context, serial, mRenderPassDesc,
&renderPass)); &renderPass));
ANGLE_VK_TRY(context, mInsideRenderPassCommands.end()); ANGLE_VK_TRY(context, mInsideRenderPassCommands.end());
VkRenderPassBeginInfo beginInfo = {}; VkRenderPassBeginInfo beginInfo = {};
...@@ -634,7 +631,10 @@ CommandGraph::CommandGraph(bool enableGraphDiagnostics, angle::PoolAllocator *po ...@@ -634,7 +631,10 @@ CommandGraph::CommandGraph(bool enableGraphDiagnostics, angle::PoolAllocator *po
: mEnableGraphDiagnostics(enableGraphDiagnostics), : mEnableGraphDiagnostics(enableGraphDiagnostics),
mPoolAllocator(poolAllocator), mPoolAllocator(poolAllocator),
mLastBarrierIndex(kInvalidNodeIndex) mLastBarrierIndex(kInvalidNodeIndex)
{} {
// Push so that allocations made from here will be recycled in clear() below.
mPoolAllocator->push();
}
CommandGraph::~CommandGraph() CommandGraph::~CommandGraph()
{ {
...@@ -776,6 +776,12 @@ bool CommandGraph::empty() const ...@@ -776,6 +776,12 @@ bool CommandGraph::empty() const
void CommandGraph::clear() void CommandGraph::clear()
{ {
mLastBarrierIndex = kInvalidNodeIndex; mLastBarrierIndex = kInvalidNodeIndex;
// Release cmd graph pool memory now that cmds are submitted
// NOTE: This frees all memory since last push. Right now only the CommandGraph
// will push the allocator (at creation and below). If other people start
// pushing the allocator this (and/or the allocator) will need to be updated.
mPoolAllocator->pop();
mPoolAllocator->push();
// TODO(jmadill): Use pool allocator for performance. http://anglebug.com/2951 // TODO(jmadill): Use pool allocator for performance. http://anglebug.com/2951
for (CommandGraphNode *node : mNodes) for (CommandGraphNode *node : mNodes)
......
...@@ -24,6 +24,7 @@ namespace rx ...@@ -24,6 +24,7 @@ namespace rx
namespace vk namespace vk
{ {
enum class VisitedState enum class VisitedState
{ {
Unvisited, Unvisited,
...@@ -119,9 +120,11 @@ class CommandGraphNode final : angle::NonCopyable ...@@ -119,9 +120,11 @@ class CommandGraphNode final : angle::NonCopyable
static void SetHappensBeforeDependencies(CommandGraphNode **beforeNodes, static void SetHappensBeforeDependencies(CommandGraphNode **beforeNodes,
size_t beforeNodesCount, size_t beforeNodesCount,
CommandGraphNode *afterNode); CommandGraphNode *afterNode);
static void SetHappensBeforeDependencies(CommandGraphNode *beforeNode, static void SetHappensBeforeDependencies(CommandGraphNode *beforeNode,
CommandGraphNode **afterNodes, CommandGraphNode **afterNodes,
size_t afterNodesCount); size_t afterNodesCount);
bool hasParents() const; bool hasParents() const;
bool hasChildren() const { return mHasChildren; } bool hasChildren() const { return mHasChildren; }
......
...@@ -369,9 +369,7 @@ angle::Result ContextVk::handleDirtyPipeline(const gl::Context *context, ...@@ -369,9 +369,7 @@ angle::Result ContextVk::handleDirtyPipeline(const gl::Context *context,
mGraphicsPipelineTransition.reset(); mGraphicsPipelineTransition.reset();
} }
commandBuffer->bindGraphicsPipeline(mCurrentPipeline->getPipeline());
commandBuffer->bindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, mCurrentPipeline->getPipeline());
// Update the queue serial for the pipeline object. // Update the queue serial for the pipeline object.
ASSERT(mCurrentPipeline && mCurrentPipeline->valid()); ASSERT(mCurrentPipeline && mCurrentPipeline->valid());
mCurrentPipeline->updateSerial(mRenderer->getCurrentQueueSerial()); mCurrentPipeline->updateSerial(mRenderer->getCurrentQueueSerial());
...@@ -449,8 +447,8 @@ angle::Result ContextVk::drawArrays(const gl::Context *context, ...@@ -449,8 +447,8 @@ angle::Result ContextVk::drawArrays(const gl::Context *context,
GLint first, GLint first,
GLsizei count) GLsizei count)
{ {
CommandBufferT *commandBuffer = nullptr; CommandBufferT *commandBuffer = nullptr;
uint32_t clampedVertexCount = gl::GetClampedVertexCount<uint32_t>(count); uint32_t clampedVertexCount = gl::GetClampedVertexCount<uint32_t>(count);
if (mode == gl::PrimitiveMode::LineLoop) if (mode == gl::PrimitiveMode::LineLoop)
{ {
...@@ -462,7 +460,7 @@ angle::Result ContextVk::drawArrays(const gl::Context *context, ...@@ -462,7 +460,7 @@ angle::Result ContextVk::drawArrays(const gl::Context *context,
{ {
ANGLE_TRY(setupDraw(context, mode, first, count, 1, gl::DrawElementsType::InvalidEnum, ANGLE_TRY(setupDraw(context, mode, first, count, 1, gl::DrawElementsType::InvalidEnum,
nullptr, mNonIndexedDirtyBitsMask, &commandBuffer)); nullptr, mNonIndexedDirtyBitsMask, &commandBuffer));
commandBuffer->draw(clampedVertexCount, 1, first, 0); commandBuffer->draw(clampedVertexCount, first);
} }
return angle::Result::Continue; return angle::Result::Continue;
...@@ -484,7 +482,7 @@ angle::Result ContextVk::drawArraysInstanced(const gl::Context *context, ...@@ -484,7 +482,7 @@ angle::Result ContextVk::drawArraysInstanced(const gl::Context *context,
CommandBufferT *commandBuffer = nullptr; CommandBufferT *commandBuffer = nullptr;
ANGLE_TRY(setupDraw(context, mode, first, count, instances, gl::DrawElementsType::InvalidEnum, ANGLE_TRY(setupDraw(context, mode, first, count, instances, gl::DrawElementsType::InvalidEnum,
nullptr, mNonIndexedDirtyBitsMask, &commandBuffer)); nullptr, mNonIndexedDirtyBitsMask, &commandBuffer));
commandBuffer->draw(gl::GetClampedVertexCount<uint32_t>(count), instances, first, 0); commandBuffer->drawInstanced(gl::GetClampedVertexCount<uint32_t>(count), instances, first);
return angle::Result::Continue; return angle::Result::Continue;
} }
...@@ -503,7 +501,7 @@ angle::Result ContextVk::drawElements(const gl::Context *context, ...@@ -503,7 +501,7 @@ angle::Result ContextVk::drawElements(const gl::Context *context,
else else
{ {
ANGLE_TRY(setupIndexedDraw(context, mode, count, 1, type, indices, &commandBuffer)); ANGLE_TRY(setupIndexedDraw(context, mode, count, 1, type, indices, &commandBuffer));
commandBuffer->drawIndexed(count, 1, 0, 0, 0); commandBuffer->drawIndexed(count);
} }
return angle::Result::Continue; return angle::Result::Continue;
...@@ -525,7 +523,7 @@ angle::Result ContextVk::drawElementsInstanced(const gl::Context *context, ...@@ -525,7 +523,7 @@ angle::Result ContextVk::drawElementsInstanced(const gl::Context *context,
CommandBufferT *commandBuffer = nullptr; CommandBufferT *commandBuffer = nullptr;
ANGLE_TRY(setupIndexedDraw(context, mode, count, instances, type, indices, &commandBuffer)); ANGLE_TRY(setupIndexedDraw(context, mode, count, instances, type, indices, &commandBuffer));
commandBuffer->drawIndexed(count, instances, 0, 0, 0); commandBuffer->drawIndexedInstanced(count, instances);
return angle::Result::Continue; return angle::Result::Continue;
} }
......
...@@ -424,7 +424,7 @@ angle::Result FramebufferVk::blitWithCopy(ContextVk *contextVk, ...@@ -424,7 +424,7 @@ angle::Result FramebufferVk::blitWithCopy(ContextVk *contextVk,
VkImageAspectFlags aspectMask = VkImageAspectFlags aspectMask =
vk::GetDepthStencilAspectFlagsForCopy(blitDepthBuffer, blitStencilBuffer); vk::GetDepthStencilAspectFlagsForCopy(blitDepthBuffer, blitStencilBuffer);
CommandBufferT *commandBuffer; CommandBufferT *commandBuffer = nullptr;
ANGLE_TRY(mFramebuffer.recordCommands(contextVk, &commandBuffer)); ANGLE_TRY(mFramebuffer.recordCommands(contextVk, &commandBuffer));
vk::ImageHelper *writeImage = drawRenderTarget->getImageForWrite(&mFramebuffer); vk::ImageHelper *writeImage = drawRenderTarget->getImageForWrite(&mFramebuffer);
...@@ -509,7 +509,7 @@ angle::Result FramebufferVk::blitWithReadback(ContextVk *contextVk, ...@@ -509,7 +509,7 @@ angle::Result FramebufferVk::blitWithReadback(ContextVk *contextVk,
// Reinitialize the commandBuffer after a read pixels because it calls // Reinitialize the commandBuffer after a read pixels because it calls
// renderer->finish which makes command buffers obsolete. // renderer->finish which makes command buffers obsolete.
CommandBufferT *commandBuffer; CommandBufferT *commandBuffer = nullptr;
ANGLE_TRY(mFramebuffer.recordCommands(contextVk, &commandBuffer)); ANGLE_TRY(mFramebuffer.recordCommands(contextVk, &commandBuffer));
// We read the bytes of the image in a buffer, now we have to copy them into the // We read the bytes of the image in a buffer, now we have to copy them into the
...@@ -669,7 +669,7 @@ angle::Result FramebufferVk::blitWithCommand(ContextVk *contextVk, ...@@ -669,7 +669,7 @@ angle::Result FramebufferVk::blitWithCommand(ContextVk *contextVk,
vk::ImageHelper *dstImage = drawRenderTarget->getImageForWrite(&mFramebuffer); vk::ImageHelper *dstImage = drawRenderTarget->getImageForWrite(&mFramebuffer);
CommandBufferT *commandBuffer; CommandBufferT *commandBuffer = nullptr;
ANGLE_TRY(mFramebuffer.recordCommands(contextVk, &commandBuffer)); ANGLE_TRY(mFramebuffer.recordCommands(contextVk, &commandBuffer));
const vk::Format &readImageFormat = readRenderTarget->getImageFormat(); const vk::Format &readImageFormat = readRenderTarget->getImageFormat();
...@@ -903,8 +903,8 @@ angle::Result FramebufferVk::clearWithClearAttachments( ...@@ -903,8 +903,8 @@ angle::Result FramebufferVk::clearWithClearAttachments(
// This command can only happen inside a render pass, so obtain one if its already happening // This command can only happen inside a render pass, so obtain one if its already happening
// or create a new one if not. // or create a new one if not.
CommandBufferT *commandBuffer = nullptr; CommandBufferT *commandBuffer = nullptr;
vk::RecordingMode mode = vk::RecordingMode::Start; vk::RecordingMode mode = vk::RecordingMode::Start;
ANGLE_TRY(getCommandBufferForDraw(contextVk, &commandBuffer, &mode)); ANGLE_TRY(getCommandBufferForDraw(contextVk, &commandBuffer, &mode));
// The array layer is offset by the ImageView. So we shouldn't need to set a base array layer. // The array layer is offset by the ImageView. So we shouldn't need to set a base array layer.
......
...@@ -506,7 +506,7 @@ RendererVk::RendererVk() ...@@ -506,7 +506,7 @@ RendererVk::RendererVk()
mCurrentQueueSerial(mQueueSerialFactory.generate()), mCurrentQueueSerial(mQueueSerialFactory.generate()),
mDeviceLost(false), mDeviceLost(false),
mPipelineCacheVkUpdateTimeout(kPipelineCacheVkUpdatePeriod), mPipelineCacheVkUpdateTimeout(kPipelineCacheVkUpdatePeriod),
mPoolAllocator(kDefaultPoolAllocatorPageSize), mPoolAllocator(kDefaultPoolAllocatorPageSize, 1),
mCommandGraph(kEnableCommandGraphDiagnostics, &mPoolAllocator), mCommandGraph(kEnableCommandGraphDiagnostics, &mPoolAllocator),
mGpuEventsEnabled(false), mGpuEventsEnabled(false),
mGpuClockSync{std::numeric_limits<double>::max(), std::numeric_limits<double>::max()}, mGpuClockSync{std::numeric_limits<double>::max(), std::numeric_limits<double>::max()},
......
...@@ -503,18 +503,18 @@ angle::Result WindowSurfaceVk::recreateSwapchain(DisplayVk *displayVk, ...@@ -503,18 +503,18 @@ angle::Result WindowSurfaceVk::recreateSwapchain(DisplayVk *displayVk,
swapchainInfo.imageFormat = nativeFormat; swapchainInfo.imageFormat = nativeFormat;
swapchainInfo.imageColorSpace = VK_COLORSPACE_SRGB_NONLINEAR_KHR; swapchainInfo.imageColorSpace = VK_COLORSPACE_SRGB_NONLINEAR_KHR;
// Note: Vulkan doesn't allow 0-width/height swapchains. // Note: Vulkan doesn't allow 0-width/height swapchains.
swapchainInfo.imageExtent.width = std::max(extents.width, 1); swapchainInfo.imageExtent.width = std::max(extents.width, 1);
swapchainInfo.imageExtent.height = std::max(extents.height, 1); swapchainInfo.imageExtent.height = std::max(extents.height, 1);
swapchainInfo.imageArrayLayers = 1; swapchainInfo.imageArrayLayers = 1;
swapchainInfo.imageUsage = kImageUsageFlags; swapchainInfo.imageUsage = kImageUsageFlags;
swapchainInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE; swapchainInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
swapchainInfo.queueFamilyIndexCount = 0; swapchainInfo.queueFamilyIndexCount = 0;
swapchainInfo.pQueueFamilyIndices = nullptr; swapchainInfo.pQueueFamilyIndices = nullptr;
swapchainInfo.preTransform = mPreTransform; swapchainInfo.preTransform = mPreTransform;
swapchainInfo.compositeAlpha = mCompositeAlpha; swapchainInfo.compositeAlpha = mCompositeAlpha;
swapchainInfo.presentMode = mDesiredSwapchainPresentMode; swapchainInfo.presentMode = mDesiredSwapchainPresentMode;
swapchainInfo.clipped = VK_TRUE; swapchainInfo.clipped = VK_TRUE;
swapchainInfo.oldSwapchain = oldSwapchain; swapchainInfo.oldSwapchain = oldSwapchain;
// TODO(syoussefi): Once EGL_SWAP_BEHAVIOR_PRESERVED_BIT is supported, the contents of the old // TODO(syoussefi): Once EGL_SWAP_BEHAVIOR_PRESERVED_BIT is supported, the contents of the old
// swapchain need to carry over to the new one. http://anglebug.com/2942 // swapchain need to carry over to the new one. http://anglebug.com/2942
...@@ -738,7 +738,7 @@ angle::Result WindowSurfaceVk::present(DisplayVk *displayVk, ...@@ -738,7 +738,7 @@ angle::Result WindowSurfaceVk::present(DisplayVk *displayVk,
std::vector<VkRectLayerKHR> vk_rects; std::vector<VkRectLayerKHR> vk_rects;
if (renderer->getFeatures().supportsIncrementalPresent && (n_rects > 0)) if (renderer->getFeatures().supportsIncrementalPresent && (n_rects > 0))
{ {
EGLint *egl_rects = rects; EGLint *egl_rects = rects;
presentRegion.rectangleCount = n_rects; presentRegion.rectangleCount = n_rects;
vk_rects.resize(n_rects); vk_rects.resize(n_rects);
for (EGLint rect = 0; rect < n_rects; rect++) for (EGLint rect = 0; rect < n_rects; rect++)
......
...@@ -1004,7 +1004,7 @@ angle::Result TextureVk::generateMipmapsWithCPU(const gl::Context *context) ...@@ -1004,7 +1004,7 @@ angle::Result TextureVk::generateMipmapsWithCPU(const gl::Context *context)
sourceRowPitch, imageData + bufferOffset)); sourceRowPitch, imageData + bufferOffset));
} }
CommandBufferT *commandBuffer; CommandBufferT *commandBuffer = nullptr;
ANGLE_TRY(mImage->recordCommands(contextVk, &commandBuffer)); ANGLE_TRY(mImage->recordCommands(contextVk, &commandBuffer));
return mImage->flushStagedUpdates(contextVk, getNativeImageLevel(0), getLevelCount(), return mImage->flushStagedUpdates(contextVk, getNativeImageLevel(0), getLevelCount(),
commandBuffer); commandBuffer);
......
...@@ -335,7 +335,7 @@ angle::Result UtilsVk::setupProgram(vk::Context *context, ...@@ -335,7 +335,7 @@ angle::Result UtilsVk::setupProgram(vk::Context *context,
program->setShader(gl::ShaderType::Compute, fsCsShader); program->setShader(gl::ShaderType::Compute, fsCsShader);
ANGLE_TRY(program->getComputePipeline(context, pipelineLayout.get(), &pipelineAndSerial)); ANGLE_TRY(program->getComputePipeline(context, pipelineLayout.get(), &pipelineAndSerial));
pipelineAndSerial->updateSerial(serial); pipelineAndSerial->updateSerial(serial);
commandBuffer->bindPipeline(bindPoint, pipelineAndSerial->get()); commandBuffer->bindComputePipeline(pipelineAndSerial->get());
} }
else else
{ {
...@@ -350,7 +350,7 @@ angle::Result UtilsVk::setupProgram(vk::Context *context, ...@@ -350,7 +350,7 @@ angle::Result UtilsVk::setupProgram(vk::Context *context,
context, &renderer->getRenderPassCache(), renderer->getPipelineCache(), serial, context, &renderer->getRenderPassCache(), renderer->getPipelineCache(), serial,
pipelineLayout.get(), *pipelineDesc, gl::AttributesMask(), &descPtr, &helper)); pipelineLayout.get(), *pipelineDesc, gl::AttributesMask(), &descPtr, &helper));
helper->updateSerial(serial); helper->updateSerial(serial);
commandBuffer->bindPipeline(bindPoint, helper->getPipeline()); commandBuffer->bindGraphicsPipeline(helper->getPipeline());
} }
if (descriptorSet != VK_NULL_HANDLE) if (descriptorSet != VK_NULL_HANDLE)
...@@ -657,9 +657,7 @@ angle::Result UtilsVk::clearImage(ContextVk *contextVk, ...@@ -657,9 +657,7 @@ angle::Result UtilsVk::clearImage(ContextVk *contextVk,
ANGLE_TRY(setupProgram(contextVk, Function::ImageClear, fragmentShader, vertexShader, ANGLE_TRY(setupProgram(contextVk, Function::ImageClear, fragmentShader, vertexShader,
&mImageClearProgram, &pipelineDesc, VK_NULL_HANDLE, &shaderParams, &mImageClearProgram, &pipelineDesc, VK_NULL_HANDLE, &shaderParams,
sizeof(shaderParams), commandBuffer)); sizeof(shaderParams), commandBuffer));
commandBuffer->draw(6, 0);
commandBuffer->draw(6, 1, 0, 0);
return angle::Result::Continue; return angle::Result::Continue;
} }
...@@ -783,9 +781,7 @@ angle::Result UtilsVk::copyImage(ContextVk *contextVk, ...@@ -783,9 +781,7 @@ angle::Result UtilsVk::copyImage(ContextVk *contextVk,
ANGLE_TRY(setupProgram(contextVk, Function::ImageCopy, fragmentShader, vertexShader, ANGLE_TRY(setupProgram(contextVk, Function::ImageCopy, fragmentShader, vertexShader,
&mImageCopyPrograms[flags], &pipelineDesc, descriptorSet, &shaderParams, &mImageCopyPrograms[flags], &pipelineDesc, descriptorSet, &shaderParams,
sizeof(shaderParams), commandBuffer)); sizeof(shaderParams), commandBuffer));
commandBuffer->draw(6, 0);
commandBuffer->draw(6, 1, 0, 0);
descriptorPoolBinding.reset(); descriptorPoolBinding.reset();
return angle::Result::Continue; return angle::Result::Continue;
......
...@@ -1064,7 +1064,7 @@ void LineLoopHelper::Draw(uint32_t count, CommandBufferT *commandBuffer) ...@@ -1064,7 +1064,7 @@ void LineLoopHelper::Draw(uint32_t count, CommandBufferT *commandBuffer)
{ {
// Our first index is always 0 because that's how we set it up in createIndexBuffer*. // Our first index is always 0 because that's how we set it up in createIndexBuffer*.
// Note: this could theoretically overflow and wrap to zero. // Note: this could theoretically overflow and wrap to zero.
commandBuffer->drawIndexed(count + 1, 1, 0, 0, 0); commandBuffer->drawIndexed(count + 1);
} }
// BufferHelper implementation. // BufferHelper implementation.
...@@ -1603,10 +1603,9 @@ void ImageHelper::forceChangeLayoutAndQueue(VkImageAspectFlags aspectMask, ...@@ -1603,10 +1603,9 @@ void ImageHelper::forceChangeLayoutAndQueue(VkImageAspectFlags aspectMask,
imageMemoryBarrier.subresourceRange.baseArrayLayer = 0; imageMemoryBarrier.subresourceRange.baseArrayLayer = 0;
imageMemoryBarrier.subresourceRange.layerCount = mLayerCount; imageMemoryBarrier.subresourceRange.layerCount = mLayerCount;
commandBuffer->pipelineBarrier(transitionFrom.srcStageMask, transitionTo.dstStageMask, 0, 0, commandBuffer->imageBarrier(transitionFrom.srcStageMask, transitionTo.dstStageMask,
nullptr, 0, nullptr, 1, &imageMemoryBarrier); &imageMemoryBarrier);
mCurrentLayout = newLayout;
mCurrentLayout = newLayout;
mCurrentQueueFamilyIndex = newQueueFamilyIndex; mCurrentQueueFamilyIndex = newQueueFamilyIndex;
} }
...@@ -1614,7 +1613,6 @@ void ImageHelper::clearColor(const VkClearColorValue &color, ...@@ -1614,7 +1613,6 @@ void ImageHelper::clearColor(const VkClearColorValue &color,
uint32_t baseMipLevel, uint32_t baseMipLevel,
uint32_t levelCount, uint32_t levelCount,
CommandBufferT *commandBuffer) CommandBufferT *commandBuffer)
{ {
clearColorLayer(color, baseMipLevel, levelCount, 0, mLayerCount, commandBuffer); clearColorLayer(color, baseMipLevel, levelCount, 0, mLayerCount, commandBuffer);
} }
...@@ -1738,10 +1736,8 @@ angle::Result ImageHelper::generateMipmapsWithBlit(ContextVk *contextVk, GLuint ...@@ -1738,10 +1736,8 @@ angle::Result ImageHelper::generateMipmapsWithBlit(ContextVk *contextVk, GLuint
barrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT; barrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
// We can do it for all layers at once. // We can do it for all layers at once.
commandBuffer->pipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, commandBuffer->imageBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, nullptr, 0, nullptr, 1, &barrier);
&barrier);
VkImageBlit blit = {}; VkImageBlit blit = {};
blit.srcOffsets[0] = {0, 0, 0}; blit.srcOffsets[0] = {0, 0, 0};
blit.srcOffsets[1] = {mipWidth, mipHeight, 1}; blit.srcOffsets[1] = {mipWidth, mipHeight, 1};
...@@ -1770,9 +1766,8 @@ angle::Result ImageHelper::generateMipmapsWithBlit(ContextVk *contextVk, GLuint ...@@ -1770,9 +1766,8 @@ angle::Result ImageHelper::generateMipmapsWithBlit(ContextVk *contextVk, GLuint
barrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; barrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
// We can do it for all layers at once. // We can do it for all layers at once.
commandBuffer->pipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, commandBuffer->imageBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
0, 0, nullptr, 0, nullptr, 1, &barrier); &barrier);
// This is just changing the internal state of the image helper so that the next call // This is just changing the internal state of the image helper so that the next call
// to changeLayout will use this layout as the "oldLayout" argument. // to changeLayout will use this layout as the "oldLayout" argument.
mCurrentLayout = ImageLayout::TransferSrc; mCurrentLayout = ImageLayout::TransferSrc;
......
...@@ -626,6 +626,7 @@ class ImageHelper final : public CommandGraphResource ...@@ -626,6 +626,7 @@ class ImageHelper final : public CommandGraphResource
VkImageAspectFlags clearAspectFlags, VkImageAspectFlags clearAspectFlags,
const VkClearDepthStencilValue &depthStencil, const VkClearDepthStencilValue &depthStencil,
CommandBufferT *commandBuffer); CommandBufferT *commandBuffer);
gl::Extents getSize(const gl::ImageIndex &index) const; gl::Extents getSize(const gl::ImageIndex &index) const;
static void Copy(ImageHelper *srcImage, static void Copy(ImageHelper *srcImage,
......
...@@ -180,7 +180,9 @@ class CommandBuffer : public WrappedObject<CommandBuffer, VkCommandBuffer> ...@@ -180,7 +180,9 @@ class CommandBuffer : public WrappedObject<CommandBuffer, VkCommandBuffer>
const VkBufferMemoryBarrier *bufferMemoryBarriers, const VkBufferMemoryBarrier *bufferMemoryBarriers,
uint32_t imageMemoryBarrierCount, uint32_t imageMemoryBarrierCount,
const VkImageMemoryBarrier *imageMemoryBarriers); const VkImageMemoryBarrier *imageMemoryBarriers);
void imageBarrier(VkPipelineStageFlags srcStageMask,
VkPipelineStageFlags dstStageMask,
VkImageMemoryBarrier *imageMemoryBarrier);
void clearColorImage(const Image &image, void clearColorImage(const Image &image,
VkImageLayout imageLayout, VkImageLayout imageLayout,
const VkClearColorValue &color, const VkClearColorValue &color,
...@@ -226,16 +228,21 @@ class CommandBuffer : public WrappedObject<CommandBuffer, VkCommandBuffer> ...@@ -226,16 +228,21 @@ class CommandBuffer : public WrappedObject<CommandBuffer, VkCommandBuffer>
uint32_t instanceCount, uint32_t instanceCount,
uint32_t firstVertex, uint32_t firstVertex,
uint32_t firstInstance); uint32_t firstInstance);
void draw(uint32_t vertexCount, uint32_t firstVertex);
void drawInstanced(uint32_t vertexCount, uint32_t instanceCount, uint32_t firstVertex);
void drawIndexed(uint32_t indexCount, void drawIndexed(uint32_t indexCount,
uint32_t instanceCount, uint32_t instanceCount,
uint32_t firstIndex, uint32_t firstIndex,
int32_t vertexOffset, int32_t vertexOffset,
uint32_t firstInstance); uint32_t firstInstance);
void drawIndexed(uint32_t indexCount);
void drawIndexedInstanced(uint32_t indexCount, uint32_t instanceCount);
void dispatch(uint32_t groupCountX, uint32_t groupCountY, uint32_t groupCountZ); void dispatch(uint32_t groupCountX, uint32_t groupCountY, uint32_t groupCountZ);
void bindPipeline(VkPipelineBindPoint pipelineBindPoint, const Pipeline &pipeline); void bindPipeline(VkPipelineBindPoint pipelineBindPoint, const Pipeline &pipeline);
void bindGraphicsPipeline(const Pipeline &pipeline);
void bindComputePipeline(const Pipeline &pipeline);
void bindVertexBuffers(uint32_t firstBinding, void bindVertexBuffers(uint32_t firstBinding,
uint32_t bindingCount, uint32_t bindingCount,
...@@ -573,6 +580,15 @@ ANGLE_INLINE void CommandBuffer::pipelineBarrier(VkPipelineStageFlags srcStageMa ...@@ -573,6 +580,15 @@ ANGLE_INLINE void CommandBuffer::pipelineBarrier(VkPipelineStageFlags srcStageMa
imageMemoryBarrierCount, imageMemoryBarriers); imageMemoryBarrierCount, imageMemoryBarriers);
} }
ANGLE_INLINE void CommandBuffer::imageBarrier(VkPipelineStageFlags srcStageMask,
VkPipelineStageFlags dstStageMask,
VkImageMemoryBarrier *imageMemoryBarrier)
{
ASSERT(valid());
vkCmdPipelineBarrier(mHandle, srcStageMask, dstStageMask, 0, 0, nullptr, 0, nullptr, 1,
imageMemoryBarrier);
}
ANGLE_INLINE void CommandBuffer::destroy(VkDevice device) ANGLE_INLINE void CommandBuffer::destroy(VkDevice device)
{ {
releaseHandle(); releaseHandle();
...@@ -808,6 +824,20 @@ ANGLE_INLINE void CommandBuffer::draw(uint32_t vertexCount, ...@@ -808,6 +824,20 @@ ANGLE_INLINE void CommandBuffer::draw(uint32_t vertexCount,
vkCmdDraw(mHandle, vertexCount, instanceCount, firstVertex, firstInstance); vkCmdDraw(mHandle, vertexCount, instanceCount, firstVertex, firstInstance);
} }
ANGLE_INLINE void CommandBuffer::draw(uint32_t vertexCount, uint32_t firstVertex)
{
ASSERT(valid());
vkCmdDraw(mHandle, vertexCount, 1, firstVertex, 0);
}
ANGLE_INLINE void CommandBuffer::drawInstanced(uint32_t vertexCount,
uint32_t instanceCount,
uint32_t firstVertex)
{
ASSERT(valid());
vkCmdDraw(mHandle, vertexCount, instanceCount, firstVertex, 0);
}
ANGLE_INLINE void CommandBuffer::drawIndexed(uint32_t indexCount, ANGLE_INLINE void CommandBuffer::drawIndexed(uint32_t indexCount,
uint32_t instanceCount, uint32_t instanceCount,
uint32_t firstIndex, uint32_t firstIndex,
...@@ -818,6 +848,18 @@ ANGLE_INLINE void CommandBuffer::drawIndexed(uint32_t indexCount, ...@@ -818,6 +848,18 @@ ANGLE_INLINE void CommandBuffer::drawIndexed(uint32_t indexCount,
vkCmdDrawIndexed(mHandle, indexCount, instanceCount, firstIndex, vertexOffset, firstInstance); vkCmdDrawIndexed(mHandle, indexCount, instanceCount, firstIndex, vertexOffset, firstInstance);
} }
ANGLE_INLINE void CommandBuffer::drawIndexed(uint32_t indexCount)
{
ASSERT(valid());
vkCmdDrawIndexed(mHandle, indexCount, 1, 0, 0, 0);
}
ANGLE_INLINE void CommandBuffer::drawIndexedInstanced(uint32_t indexCount, uint32_t instanceCount)
{
ASSERT(valid());
vkCmdDrawIndexed(mHandle, indexCount, instanceCount, 0, 0, 0);
}
ANGLE_INLINE void CommandBuffer::dispatch(uint32_t groupCountX, ANGLE_INLINE void CommandBuffer::dispatch(uint32_t groupCountX,
uint32_t groupCountY, uint32_t groupCountY,
uint32_t groupCountZ) uint32_t groupCountZ)
...@@ -833,6 +875,18 @@ ANGLE_INLINE void CommandBuffer::bindPipeline(VkPipelineBindPoint pipelineBindPo ...@@ -833,6 +875,18 @@ ANGLE_INLINE void CommandBuffer::bindPipeline(VkPipelineBindPoint pipelineBindPo
vkCmdBindPipeline(mHandle, pipelineBindPoint, pipeline.getHandle()); vkCmdBindPipeline(mHandle, pipelineBindPoint, pipeline.getHandle());
} }
ANGLE_INLINE void CommandBuffer::bindGraphicsPipeline(const Pipeline &pipeline)
{
ASSERT(valid() && pipeline.valid());
vkCmdBindPipeline(mHandle, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline.getHandle());
}
ANGLE_INLINE void CommandBuffer::bindComputePipeline(const Pipeline &pipeline)
{
ASSERT(valid() && pipeline.valid());
vkCmdBindPipeline(mHandle, VK_PIPELINE_BIND_POINT_COMPUTE, pipeline.getHandle());
}
ANGLE_INLINE void CommandBuffer::bindVertexBuffers(uint32_t firstBinding, ANGLE_INLINE void CommandBuffer::bindVertexBuffers(uint32_t firstBinding,
uint32_t bindingCount, uint32_t bindingCount,
const VkBuffer *buffers, const VkBuffer *buffers,
......
...@@ -1404,6 +1404,8 @@ TEST_P(SimpleStateChangeTest, RedefineBufferInUse) ...@@ -1404,6 +1404,8 @@ TEST_P(SimpleStateChangeTest, RedefineBufferInUse)
// Tests updating a buffer's contents while in use, without redefining it. // Tests updating a buffer's contents while in use, without redefining it.
TEST_P(SimpleStateChangeTest, UpdateBufferInUse) TEST_P(SimpleStateChangeTest, UpdateBufferInUse)
{ {
// tobine: Started failing w/ custom cmd buffers. http://anglebug.com/3255
ANGLE_SKIP_TEST_IF(IsAMD() && IsWindows() && IsVulkan());
std::vector<GLColor> redColorData(6, GLColor::red); std::vector<GLColor> redColorData(6, GLColor::red);
GLBuffer buffer; GLBuffer buffer;
......
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