зеркало из https://github.com/AvaloniaUI/angle.git
Vulkan: Defer RenderPass image barriers.
We accumulate image barriers in two places: * for GL sampler textures * for GL framebuffer attachments (Render Targets) Then we issue the barriers together in a single call before the RP. This fixes a bug where we were missing a layout transition in some cases when transitioning between a sampler and a render target. It should also be faster to issue a single barrier before a RP than issue several smaller barriers. Bug: angleproject:3539 Bug: angleproject:4029 Change-Id: I180b770f0df6b44d209e5c618ba36bcc1c6372e4 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2044236 Commit-Queue: Jamie Madill <jmadill@chromium.org> Reviewed-by: Cody Northrop <cnorthrop@google.com>
This commit is contained in:
Родитель
788fa36035
Коммит
8257ac3051
|
@ -1093,19 +1093,54 @@ ANGLE_INLINE angle::Result ContextVk::handleDirtyTexturesImpl(const gl::Context
|
|||
vk::CommandBuffer *commandBuffer,
|
||||
vk::CommandGraphResource *recorder)
|
||||
{
|
||||
if (commandGraphEnabled())
|
||||
{
|
||||
ANGLE_TRY(updateActiveTextures(context));
|
||||
|
||||
const gl::ActiveTextureMask &activeTextures = mProgram->getState().getActiveSamplersMask();
|
||||
|
||||
for (size_t textureUnit : activeTextures)
|
||||
{
|
||||
vk::TextureUnit &unit = mActiveTextures[textureUnit];
|
||||
const vk::TextureUnit &unit = mActiveTextures[textureUnit];
|
||||
TextureVk *textureVk = unit.texture;
|
||||
ASSERT(textureVk);
|
||||
vk::ImageHelper &image = textureVk->getImage();
|
||||
|
||||
// The image should be flushed and ready to use at this point. There may still be
|
||||
// lingering staged updates in its staging buffer for unused texture mip levels or
|
||||
// layers. Therefore we can't verify it has no staged updates right here.
|
||||
|
||||
vk::ImageLayout textureLayout = vk::ImageLayout::AllGraphicsShadersReadOnly;
|
||||
if (mProgram->getState().isCompute())
|
||||
{
|
||||
textureLayout = vk::ImageLayout::ComputeShaderReadOnly;
|
||||
}
|
||||
|
||||
// Ensure the image is in read-only layout
|
||||
if (commandGraphEnabled())
|
||||
{
|
||||
if (image.isLayoutChangeNecessary(textureLayout))
|
||||
{
|
||||
vk::CommandBuffer *srcLayoutChange;
|
||||
VkImageAspectFlags aspectFlags = image.getAspectFlags();
|
||||
ASSERT(aspectFlags != 0);
|
||||
ANGLE_TRY(image.recordCommands(this, &srcLayoutChange));
|
||||
image.changeLayout(aspectFlags, textureLayout, srcLayoutChange);
|
||||
}
|
||||
|
||||
image.addReadDependency(this, recorder);
|
||||
}
|
||||
else
|
||||
{
|
||||
mRenderPassCommands.imageRead(&mResourceUseList, image.getAspectFlags(), textureLayout,
|
||||
&image);
|
||||
}
|
||||
|
||||
textureVk->onImageViewUse(&mResourceUseList);
|
||||
|
||||
if (unit.sampler)
|
||||
{
|
||||
unit.sampler->onSamplerAccess(&mResourceUseList);
|
||||
}
|
||||
else
|
||||
{
|
||||
textureVk->onSamplerUse(&mResourceUseList);
|
||||
}
|
||||
}
|
||||
|
||||
if (mProgram->hasTextures())
|
||||
|
@ -2831,10 +2866,7 @@ angle::Result ContextVk::invalidateCurrentTextures(const gl::Context *context)
|
|||
mGraphicsDirtyBits.set(DIRTY_BIT_DESCRIPTOR_SETS);
|
||||
mComputeDirtyBits.set(DIRTY_BIT_TEXTURES);
|
||||
mComputeDirtyBits.set(DIRTY_BIT_DESCRIPTOR_SETS);
|
||||
}
|
||||
|
||||
if (!commandGraphEnabled())
|
||||
{
|
||||
ANGLE_TRY(updateActiveTextures(context));
|
||||
}
|
||||
|
||||
|
@ -3294,46 +3326,13 @@ angle::Result ContextVk::updateActiveTextures(const gl::Context *context)
|
|||
{
|
||||
samplerVk = nullptr;
|
||||
samplerSerial = kZeroSerial;
|
||||
textureVk->onSamplerUse(&mResourceUseList);
|
||||
}
|
||||
else
|
||||
{
|
||||
samplerVk = vk::GetImpl(sampler);
|
||||
samplerSerial = samplerVk->getSerial();
|
||||
samplerVk->onSamplerAccess(&mResourceUseList);
|
||||
}
|
||||
|
||||
vk::ImageHelper &image = textureVk->getImage();
|
||||
|
||||
// The image should be flushed and ready to use at this point. There may still be
|
||||
// lingering staged updates in its staging buffer for unused texture mip levels or
|
||||
// layers. Therefore we can't verify it has no staged updates right here.
|
||||
|
||||
vk::ImageLayout textureLayout = vk::ImageLayout::AllGraphicsShadersReadOnly;
|
||||
if (program->isCompute())
|
||||
{
|
||||
textureLayout = vk::ImageLayout::ComputeShaderReadOnly;
|
||||
}
|
||||
|
||||
// Ensure the image is in read-only layout
|
||||
if (commandGraphEnabled())
|
||||
{
|
||||
if (image.isLayoutChangeNecessary(textureLayout))
|
||||
{
|
||||
vk::CommandBuffer *srcLayoutChange;
|
||||
VkImageAspectFlags aspectFlags = image.getAspectFlags();
|
||||
ASSERT(aspectFlags != 0);
|
||||
ANGLE_TRY(image.recordCommands(this, &srcLayoutChange));
|
||||
image.changeLayout(aspectFlags, textureLayout, srcLayoutChange);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ANGLE_TRY(onImageRead(image.getAspectFlags(), textureLayout, &image));
|
||||
}
|
||||
|
||||
textureVk->onImageViewUse(&mResourceUseList);
|
||||
|
||||
mActiveTextures[textureUnit].texture = textureVk;
|
||||
mActiveTextures[textureUnit].sampler = samplerVk;
|
||||
// Cache serials from sampler and texture, but re-use texture if no sampler bound
|
||||
|
@ -3860,8 +3859,17 @@ angle::Result ContextVk::endRenderPass()
|
|||
return mRenderPassCommands.flushToPrimary(this, &mPrimaryCommands);
|
||||
}
|
||||
|
||||
void ContextVk::onRenderPassImageWrite(VkImageAspectFlags aspectFlags,
|
||||
vk::ImageLayout imageLayout,
|
||||
vk::ImageHelper *image)
|
||||
{
|
||||
mRenderPassCommands.imageWrite(&mResourceUseList, aspectFlags, imageLayout, image);
|
||||
}
|
||||
|
||||
CommandBufferHelper::CommandBufferHelper()
|
||||
: mGlobalMemoryBarrierSrcAccess(0),
|
||||
: mImageBarrierSrcStageMask(0),
|
||||
mImageBarrierDstStageMask(0),
|
||||
mGlobalMemoryBarrierSrcAccess(0),
|
||||
mGlobalMemoryBarrierDstAccess(0),
|
||||
mGlobalMemoryBarrierStages(0)
|
||||
{}
|
||||
|
@ -3888,23 +3896,81 @@ void CommandBufferHelper::bufferWrite(vk::ResourceUseList *resourceUseList,
|
|||
mGlobalMemoryBarrierStages = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT;
|
||||
}
|
||||
|
||||
void CommandBufferHelper::recordBarrier(vk::PrimaryCommandBuffer *primary)
|
||||
void CommandBufferHelper::imageBarrier(VkPipelineStageFlags srcStageMask,
|
||||
VkPipelineStageFlags dstStageMask,
|
||||
const VkImageMemoryBarrier &imageMemoryBarrier)
|
||||
{
|
||||
if (mGlobalMemoryBarrierSrcAccess == 0)
|
||||
ASSERT(imageMemoryBarrier.pNext == nullptr);
|
||||
mImageBarrierSrcStageMask |= srcStageMask;
|
||||
mImageBarrierDstStageMask |= dstStageMask;
|
||||
mImageMemoryBarriers.push_back(imageMemoryBarrier);
|
||||
}
|
||||
|
||||
void CommandBufferHelper::imageRead(vk::ResourceUseList *resourceUseList,
|
||||
VkImageAspectFlags aspectFlags,
|
||||
vk::ImageLayout imageLayout,
|
||||
vk::ImageHelper *image)
|
||||
{
|
||||
image->onResourceAccess(resourceUseList);
|
||||
if (image->isLayoutChangeNecessary(imageLayout))
|
||||
{
|
||||
image->changeLayout(aspectFlags, imageLayout, this);
|
||||
}
|
||||
}
|
||||
|
||||
void CommandBufferHelper::imageWrite(vk::ResourceUseList *resourceUseList,
|
||||
VkImageAspectFlags aspectFlags,
|
||||
vk::ImageLayout imageLayout,
|
||||
vk::ImageHelper *image)
|
||||
{
|
||||
image->onResourceAccess(resourceUseList);
|
||||
image->changeLayout(aspectFlags, imageLayout, this);
|
||||
}
|
||||
|
||||
void CommandBufferHelper::executeBarriers(vk::PrimaryCommandBuffer *primary)
|
||||
{
|
||||
if (mImageMemoryBarriers.empty() && mGlobalMemoryBarrierSrcAccess == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
VkPipelineStageFlags srcStages = 0;
|
||||
VkPipelineStageFlags dstStages = 0;
|
||||
|
||||
VkMemoryBarrier memoryBarrier = {};
|
||||
uint32_t memoryBarrierCount = 0;
|
||||
|
||||
if (mGlobalMemoryBarrierSrcAccess != 0)
|
||||
{
|
||||
memoryBarrier.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER;
|
||||
memoryBarrier.srcAccessMask = mGlobalMemoryBarrierSrcAccess;
|
||||
memoryBarrier.dstAccessMask = mGlobalMemoryBarrierDstAccess;
|
||||
|
||||
primary->memoryBarrier(mGlobalMemoryBarrierStages, mGlobalMemoryBarrierStages, &memoryBarrier);
|
||||
memoryBarrierCount++;
|
||||
srcStages |= mGlobalMemoryBarrierStages;
|
||||
dstStages |= mGlobalMemoryBarrierStages;
|
||||
|
||||
mGlobalMemoryBarrierSrcAccess = 0;
|
||||
mGlobalMemoryBarrierDstAccess = 0;
|
||||
mGlobalMemoryBarrierStages = 0;
|
||||
}
|
||||
|
||||
if (!mImageMemoryBarriers.empty())
|
||||
{
|
||||
srcStages |= mImageBarrierSrcStageMask;
|
||||
dstStages |= mImageBarrierDstStageMask;
|
||||
primary->pipelineBarrier(srcStages, dstStages, 0, memoryBarrierCount, &memoryBarrier, 0,
|
||||
nullptr, static_cast<uint32_t>(mImageMemoryBarriers.size()),
|
||||
mImageMemoryBarriers.data());
|
||||
mImageMemoryBarriers.clear();
|
||||
mImageBarrierSrcStageMask = 0;
|
||||
mImageBarrierDstStageMask = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
primary->pipelineBarrier(srcStages, dstStages, 0, memoryBarrierCount, &memoryBarrier, 0,
|
||||
nullptr, 0, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
OutsideRenderPassCommandBuffer::OutsideRenderPassCommandBuffer() = default;
|
||||
|
@ -3916,7 +3982,7 @@ void OutsideRenderPassCommandBuffer::flushToPrimary(vk::PrimaryCommandBuffer *pr
|
|||
if (empty())
|
||||
return;
|
||||
|
||||
recordBarrier(primary);
|
||||
executeBarriers(primary);
|
||||
mCommandBuffer.executeCommands(primary->getHandle());
|
||||
|
||||
// Restart secondary buffer.
|
||||
|
@ -3969,7 +4035,7 @@ angle::Result RenderPassCommandBuffer::flushToPrimary(ContextVk *contextVk,
|
|||
if (empty())
|
||||
return angle::Result::Continue;
|
||||
|
||||
recordBarrier(primary);
|
||||
executeBarriers(primary);
|
||||
|
||||
// Pull a RenderPass from the cache.
|
||||
RenderPassCache &renderPassCache = contextVk->getRenderPassCache();
|
||||
|
|
|
@ -105,14 +105,31 @@ struct CommandBufferHelper : angle::NonCopyable
|
|||
VkAccessFlags writeAccessType,
|
||||
vk::BufferHelper *buffer);
|
||||
|
||||
void imageRead(vk::ResourceUseList *resourceUseList,
|
||||
VkImageAspectFlags aspectFlags,
|
||||
vk::ImageLayout imageLayout,
|
||||
vk::ImageHelper *image);
|
||||
|
||||
void imageWrite(vk::ResourceUseList *resourceUseList,
|
||||
VkImageAspectFlags aspectFlags,
|
||||
vk::ImageLayout imageLayout,
|
||||
vk::ImageHelper *image);
|
||||
|
||||
void imageBarrier(VkPipelineStageFlags srcStageMask,
|
||||
VkPipelineStageFlags dstStageMask,
|
||||
const VkImageMemoryBarrier &imageMemoryBarrier);
|
||||
|
||||
vk::CommandBuffer &getCommandBuffer() { return mCommandBuffer; }
|
||||
|
||||
protected:
|
||||
CommandBufferHelper();
|
||||
~CommandBufferHelper();
|
||||
|
||||
void recordBarrier(vk::PrimaryCommandBuffer *primary);
|
||||
void executeBarriers(vk::PrimaryCommandBuffer *primary);
|
||||
|
||||
VkPipelineStageFlags mImageBarrierSrcStageMask;
|
||||
VkPipelineStageFlags mImageBarrierDstStageMask;
|
||||
std::vector<VkImageMemoryBarrier> mImageMemoryBarriers;
|
||||
VkFlags mGlobalMemoryBarrierSrcAccess;
|
||||
VkFlags mGlobalMemoryBarrierDstAccess;
|
||||
VkPipelineStageFlags mGlobalMemoryBarrierStages;
|
||||
|
@ -559,6 +576,10 @@ class ContextVk : public ContextImpl, public vk::Context, public vk::RenderPassO
|
|||
vk::ImageLayout imageLayout,
|
||||
vk::ImageHelper *image);
|
||||
|
||||
void onRenderPassImageWrite(VkImageAspectFlags aspectFlags,
|
||||
vk::ImageLayout imageLayout,
|
||||
vk::ImageHelper *image);
|
||||
|
||||
angle::Result getOutsideRenderPassCommandBuffer(vk::CommandBuffer **commandBufferOut)
|
||||
{
|
||||
if (!mRenderPassCommands.empty())
|
||||
|
|
|
@ -71,8 +71,8 @@ angle::Result RenderTargetVk::onColorDraw(ContextVk *contextVk,
|
|||
}
|
||||
else
|
||||
{
|
||||
ANGLE_TRY(contextVk->onImageWrite(VK_IMAGE_ASPECT_COLOR_BIT,
|
||||
vk::ImageLayout::ColorAttachment, mImage));
|
||||
contextVk->onRenderPassImageWrite(VK_IMAGE_ASPECT_COLOR_BIT,
|
||||
vk::ImageLayout::ColorAttachment, mImage);
|
||||
}
|
||||
|
||||
onImageViewAccess(contextVk);
|
||||
|
@ -99,8 +99,8 @@ angle::Result RenderTargetVk::onDepthStencilDraw(ContextVk *contextVk,
|
|||
}
|
||||
else
|
||||
{
|
||||
ANGLE_TRY(
|
||||
contextVk->onImageWrite(aspectFlags, vk::ImageLayout::DepthStencilAttachment, mImage));
|
||||
contextVk->onRenderPassImageWrite(aspectFlags, vk::ImageLayout::DepthStencilAttachment,
|
||||
mImage);
|
||||
}
|
||||
|
||||
onImageViewAccess(contextVk);
|
||||
|
|
|
@ -559,7 +559,7 @@ class SecondaryCommandBuffer final : angle::NonCopyable
|
|||
|
||||
void imageBarrier(VkPipelineStageFlags srcStageMask,
|
||||
VkPipelineStageFlags dstStageMask,
|
||||
const VkImageMemoryBarrier *imageMemoryBarrier);
|
||||
const VkImageMemoryBarrier &imageMemoryBarrier);
|
||||
|
||||
void memoryBarrier(VkPipelineStageFlags srcStageMask,
|
||||
VkPipelineStageFlags dstStageMask,
|
||||
|
@ -1129,12 +1129,13 @@ ANGLE_INLINE void SecondaryCommandBuffer::fillBuffer(const Buffer &dstBuffer,
|
|||
ANGLE_INLINE void SecondaryCommandBuffer::imageBarrier(
|
||||
VkPipelineStageFlags srcStageMask,
|
||||
VkPipelineStageFlags dstStageMask,
|
||||
const VkImageMemoryBarrier *imageMemoryBarrier)
|
||||
const VkImageMemoryBarrier &imageMemoryBarrier)
|
||||
{
|
||||
ImageBarrierParams *paramStruct = initCommand<ImageBarrierParams>(CommandID::ImageBarrier);
|
||||
ASSERT(imageMemoryBarrier.pNext == nullptr);
|
||||
paramStruct->srcStageMask = srcStageMask;
|
||||
paramStruct->dstStageMask = dstStageMask;
|
||||
paramStruct->imageMemoryBarrier = *imageMemoryBarrier;
|
||||
paramStruct->imageMemoryBarrier = imageMemoryBarrier;
|
||||
}
|
||||
|
||||
ANGLE_INLINE void SecondaryCommandBuffer::memoryBarrier(VkPipelineStageFlags srcStageMask,
|
||||
|
|
|
@ -2053,18 +2053,6 @@ bool ImageHelper::isLayoutChangeNecessary(ImageLayout newLayout) const
|
|||
return !sameLayoutAndNoNeedForBarrier;
|
||||
}
|
||||
|
||||
void ImageHelper::changeLayout(VkImageAspectFlags aspectMask,
|
||||
ImageLayout newLayout,
|
||||
CommandBuffer *commandBuffer)
|
||||
{
|
||||
if (!isLayoutChangeNecessary(newLayout))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
forceChangeLayoutAndQueue(aspectMask, newLayout, mCurrentQueueFamilyIndex, commandBuffer);
|
||||
}
|
||||
|
||||
void ImageHelper::changeLayoutAndQueue(VkImageAspectFlags aspectMask,
|
||||
ImageLayout newLayout,
|
||||
uint32_t newQueueFamilyIndex,
|
||||
|
@ -2094,10 +2082,12 @@ void ImageHelper::setBaseAndMaxLevels(uint32_t baseLevel, uint32_t maxLevel)
|
|||
mMaxLevel = maxLevel;
|
||||
}
|
||||
|
||||
// Generalized to accept both "primary" and "secondary" command buffers.
|
||||
template <typename CommandBufferT>
|
||||
void ImageHelper::forceChangeLayoutAndQueue(VkImageAspectFlags aspectMask,
|
||||
ImageLayout newLayout,
|
||||
uint32_t newQueueFamilyIndex,
|
||||
CommandBuffer *commandBuffer)
|
||||
CommandBufferT *commandBuffer)
|
||||
{
|
||||
const ImageMemoryBarrierData &transitionFrom = kImageMemoryBarrierData[mCurrentLayout];
|
||||
const ImageMemoryBarrierData &transitionTo = kImageMemoryBarrierData[newLayout];
|
||||
|
@ -2112,7 +2102,7 @@ void ImageHelper::forceChangeLayoutAndQueue(VkImageAspectFlags aspectMask,
|
|||
imageMemoryBarrier.dstQueueFamilyIndex = newQueueFamilyIndex;
|
||||
imageMemoryBarrier.image = mImage.getHandle();
|
||||
|
||||
// TODO(jmadill): Is this needed for mipped/layer images?
|
||||
// Transition the whole resource.
|
||||
imageMemoryBarrier.subresourceRange.aspectMask = aspectMask;
|
||||
imageMemoryBarrier.subresourceRange.baseMipLevel = 0;
|
||||
imageMemoryBarrier.subresourceRange.levelCount = mLevelCount;
|
||||
|
@ -2120,11 +2110,17 @@ void ImageHelper::forceChangeLayoutAndQueue(VkImageAspectFlags aspectMask,
|
|||
imageMemoryBarrier.subresourceRange.layerCount = mLayerCount;
|
||||
|
||||
commandBuffer->imageBarrier(transitionFrom.srcStageMask, transitionTo.dstStageMask,
|
||||
&imageMemoryBarrier);
|
||||
imageMemoryBarrier);
|
||||
mCurrentLayout = newLayout;
|
||||
mCurrentQueueFamilyIndex = newQueueFamilyIndex;
|
||||
}
|
||||
|
||||
// Explicitly instantiate forceChangeLayoutAndQueue with CommandBufferHelper.
|
||||
template void ImageHelper::forceChangeLayoutAndQueue(VkImageAspectFlags aspectMask,
|
||||
ImageLayout newLayout,
|
||||
uint32_t newQueueFamilyIndex,
|
||||
CommandBufferHelper *commandBuffer);
|
||||
|
||||
void ImageHelper::clearColor(const VkClearColorValue &color,
|
||||
uint32_t baseMipLevel,
|
||||
uint32_t levelCount,
|
||||
|
@ -2278,7 +2274,7 @@ angle::Result ImageHelper::generateMipmapsWithBlit(ContextVk *contextVk, GLuint
|
|||
|
||||
// We can do it for all layers at once.
|
||||
commandBuffer->imageBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
|
||||
&barrier);
|
||||
barrier);
|
||||
VkImageBlit blit = {};
|
||||
blit.srcOffsets[0] = {0, 0, 0};
|
||||
blit.srcOffsets[1] = {mipWidth, mipHeight, 1};
|
||||
|
@ -2313,7 +2309,7 @@ angle::Result ImageHelper::generateMipmapsWithBlit(ContextVk *contextVk, GLuint
|
|||
|
||||
// We can do it for all layers at once.
|
||||
commandBuffer->imageBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
|
||||
&barrier);
|
||||
barrier);
|
||||
// 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.
|
||||
mCurrentLayout = ImageLayout::TransferSrc;
|
||||
|
|
|
@ -892,9 +892,18 @@ class ImageHelper final : public CommandGraphResource
|
|||
// purpose of performing a transition (which may then not be issued).
|
||||
bool isLayoutChangeNecessary(ImageLayout newLayout) const;
|
||||
|
||||
template <typename CommandBufferT>
|
||||
void changeLayout(VkImageAspectFlags aspectMask,
|
||||
ImageLayout newLayout,
|
||||
CommandBuffer *commandBuffer);
|
||||
CommandBufferT *commandBuffer)
|
||||
{
|
||||
if (!isLayoutChangeNecessary(newLayout))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
forceChangeLayoutAndQueue(aspectMask, newLayout, mCurrentQueueFamilyIndex, commandBuffer);
|
||||
}
|
||||
|
||||
bool isQueueChangeNeccesary(uint32_t newQueueFamilyIndex) const
|
||||
{
|
||||
|
@ -962,10 +971,12 @@ class ImageHelper final : public CommandGraphResource
|
|||
GLuint *inputSkipBytes);
|
||||
|
||||
private:
|
||||
// Generalized to accept both "primary" and "secondary" command buffers.
|
||||
template <typename CommandBufferT>
|
||||
void forceChangeLayoutAndQueue(VkImageAspectFlags aspectMask,
|
||||
ImageLayout newLayout,
|
||||
uint32_t newQueueFamilyIndex,
|
||||
CommandBuffer *commandBuffer);
|
||||
CommandBufferT *commandBuffer);
|
||||
|
||||
void stageSubresourceClear(const gl::ImageIndex &index,
|
||||
const angle::Format &format,
|
||||
|
|
|
@ -310,7 +310,7 @@ class CommandBuffer : public WrappedObject<CommandBuffer, VkCommandBuffer>
|
|||
|
||||
void imageBarrier(VkPipelineStageFlags srcStageMask,
|
||||
VkPipelineStageFlags dstStageMask,
|
||||
const VkImageMemoryBarrier *imageMemoryBarrier);
|
||||
const VkImageMemoryBarrier &imageMemoryBarrier);
|
||||
|
||||
void memoryBarrier(VkPipelineStageFlags srcStageMask,
|
||||
VkPipelineStageFlags dstStageMask,
|
||||
|
@ -702,11 +702,11 @@ ANGLE_INLINE void CommandBuffer::bufferBarrier(VkPipelineStageFlags srcStageMask
|
|||
|
||||
ANGLE_INLINE void CommandBuffer::imageBarrier(VkPipelineStageFlags srcStageMask,
|
||||
VkPipelineStageFlags dstStageMask,
|
||||
const VkImageMemoryBarrier *imageMemoryBarrier)
|
||||
const VkImageMemoryBarrier &imageMemoryBarrier)
|
||||
{
|
||||
ASSERT(valid());
|
||||
vkCmdPipelineBarrier(mHandle, srcStageMask, dstStageMask, 0, 0, nullptr, 0, nullptr, 1,
|
||||
imageMemoryBarrier);
|
||||
&imageMemoryBarrier);
|
||||
}
|
||||
|
||||
ANGLE_INLINE void CommandBuffer::destroy(VkDevice device)
|
||||
|
|
|
@ -15,26 +15,6 @@ using namespace angle;
|
|||
|
||||
namespace
|
||||
{
|
||||
|
||||
Vector4 RandomVec4(int seed, float minValue, float maxValue)
|
||||
{
|
||||
RNG rng(seed);
|
||||
srand(seed);
|
||||
return Vector4(
|
||||
rng.randomFloatBetween(minValue, maxValue), rng.randomFloatBetween(minValue, maxValue),
|
||||
rng.randomFloatBetween(minValue, maxValue), rng.randomFloatBetween(minValue, maxValue));
|
||||
}
|
||||
|
||||
GLColor Vec4ToColor(const Vector4 &vec)
|
||||
{
|
||||
GLColor color;
|
||||
color.R = static_cast<uint8_t>(vec.x() * 255.0f);
|
||||
color.G = static_cast<uint8_t>(vec.y() * 255.0f);
|
||||
color.B = static_cast<uint8_t>(vec.z() * 255.0f);
|
||||
color.A = static_cast<uint8_t>(vec.w() * 255.0f);
|
||||
return color;
|
||||
}
|
||||
|
||||
class ClearTestBase : public ANGLETest
|
||||
{
|
||||
protected:
|
||||
|
@ -1216,7 +1196,7 @@ TEST_P(ClearTestES3, RepeatedClear)
|
|||
{
|
||||
int seed = cellX + cellY * numRowsCols;
|
||||
const Vector4 color = RandomVec4(seed, fmtValueMin, fmtValueMax);
|
||||
GLColor expectedColor = Vec4ToColor(color);
|
||||
GLColor expectedColor(color);
|
||||
|
||||
int testN = cellX * cellSize + cellY * backFBOSize * cellSize + backFBOSize + 1;
|
||||
GLColor actualColor = pixelData[testN];
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
|
||||
#include "test_utils/ANGLETest.h"
|
||||
#include "test_utils/gl_raii.h"
|
||||
#include "util/random_utils.h"
|
||||
|
||||
using namespace angle;
|
||||
|
||||
|
@ -2596,6 +2597,82 @@ TEST_P(SimpleStateChangeTest, RedefineFramebufferTexture)
|
|||
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green) << "second draw should be green";
|
||||
}
|
||||
|
||||
// Trips a bug in the Vulkan back-end where a Texture wouldn't transition correctly.
|
||||
TEST_P(SimpleStateChangeTest, DrawAndClearTextureRepeatedly)
|
||||
{
|
||||
// Fails on 431.02 driver. http://anglebug.com/3748
|
||||
ANGLE_SKIP_TEST_IF(IsWindows() && IsNVIDIA() && IsVulkan());
|
||||
|
||||
// Fails on AMD OpenGL Windows. This configuration isn't maintained.
|
||||
ANGLE_SKIP_TEST_IF(IsWindows() && IsAMD() && IsOpenGL());
|
||||
|
||||
ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Texture2D(), essl1_shaders::fs::Texture2D());
|
||||
|
||||
GLTexture tex;
|
||||
glBindTexture(GL_TEXTURE_2D, tex);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, &GLColor::red);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
ASSERT_GL_NO_ERROR();
|
||||
|
||||
GLFramebuffer fbo;
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex, 0);
|
||||
ASSERT_GL_NO_ERROR();
|
||||
ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
|
||||
|
||||
glUseProgram(program);
|
||||
|
||||
GLint uniLoc = glGetUniformLocation(program, essl1_shaders::Texture2DUniform());
|
||||
ASSERT_NE(-1, uniLoc);
|
||||
glUniform1i(uniLoc, 0);
|
||||
|
||||
const int numRowsCols = 2;
|
||||
const int cellSize = getWindowWidth() / 2;
|
||||
|
||||
for (int cellY = 0; cellY < numRowsCols; cellY++)
|
||||
{
|
||||
for (int cellX = 0; cellX < numRowsCols; cellX++)
|
||||
{
|
||||
int seed = cellX + cellY * numRowsCols;
|
||||
const Vector4 color = RandomVec4(seed, 0.0f, 1.0f);
|
||||
|
||||
// Set the texture to a constant color using glClear and a user FBO.
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
|
||||
glClearColor(color[0], color[1], color[2], color[3]);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
|
||||
// Draw a small colored quad to the default FBO using the viewport.
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
glViewport(cellX * cellSize, cellY * cellSize, cellSize, cellSize);
|
||||
drawQuad(program, essl1_shaders::PositionAttrib(), 0.5f);
|
||||
}
|
||||
}
|
||||
|
||||
// Verify the colored quads were drawn correctly despite no flushing.
|
||||
std::vector<GLColor> pixelData(getWindowWidth() * getWindowHeight());
|
||||
glReadPixels(0, 0, getWindowWidth(), getWindowHeight(), GL_RGBA, GL_UNSIGNED_BYTE,
|
||||
pixelData.data());
|
||||
|
||||
ASSERT_GL_NO_ERROR();
|
||||
|
||||
for (int cellY = 0; cellY < numRowsCols; cellY++)
|
||||
{
|
||||
for (int cellX = 0; cellX < numRowsCols; cellX++)
|
||||
{
|
||||
int seed = cellX + cellY * numRowsCols;
|
||||
const Vector4 color = RandomVec4(seed, 0.0f, 1.0f);
|
||||
|
||||
GLColor expectedColor(color);
|
||||
|
||||
int testN =
|
||||
cellX * cellSize + cellY * getWindowWidth() * cellSize + getWindowWidth() + 1;
|
||||
GLColor actualColor = pixelData[testN];
|
||||
EXPECT_COLOR_NEAR(expectedColor, actualColor, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Validates disabling cull face really disables it.
|
||||
TEST_P(SimpleStateChangeTest, EnableAndDisableCullFace)
|
||||
{
|
||||
|
|
|
@ -10,10 +10,10 @@
|
|||
#ifndef UTIL_RANDOM_UTILS_H
|
||||
#define UTIL_RANDOM_UTILS_H
|
||||
|
||||
// TODO(jmadill): Rework this if Chromium decides to ban <random>
|
||||
#include <random>
|
||||
#include <vector>
|
||||
|
||||
#include "common/vector_utils.h"
|
||||
#include "util/util_export.h"
|
||||
|
||||
namespace angle
|
||||
|
@ -70,6 +70,14 @@ inline void FillVectorWithRandomUBytes(std::vector<uint8_t> *data)
|
|||
FillVectorWithRandomUBytes(&rng, data);
|
||||
}
|
||||
|
||||
inline Vector4 RandomVec4(int seed, float minValue, float maxValue)
|
||||
{
|
||||
RNG rng(seed);
|
||||
srand(seed);
|
||||
return Vector4(
|
||||
rng.randomFloatBetween(minValue, maxValue), rng.randomFloatBetween(minValue, maxValue),
|
||||
rng.randomFloatBetween(minValue, maxValue), rng.randomFloatBetween(minValue, maxValue));
|
||||
}
|
||||
} // namespace angle
|
||||
|
||||
#endif // UTIL_RANDOM_UTILS_H
|
||||
|
|
Загрузка…
Ссылка в новой задаче