Edit

kc3-lang/angle/src/libANGLE/renderer/vulkan/RenderTargetVk.cpp

Branch :

  • Show log

    Commit

  • Author : Shahbaz Youssefi
    Date : 2021-06-15 17:37:45
    Hash : 5b314268
    Message : Vulkan: Support OVR_multiview and OVR_multiview2 Multiview is supported in Vulkan simply by specifying the number of views in the render pass, and creating the appropriate image views. A number of changes to the way image views and render targets are stored are made to support those that don't cover the entire range of layers. One particular detail that is not implemented in this change is the use of queries in combination with multiview. Vulkan specifies that N queries are actually produced (N being the number of views) which must be summed by the application, but this is not currently done. Bug: angleproject:6048 Change-Id: I1d4a9894c232d3a93d7a97c9fa0eedc334e57469 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2967625 Commit-Queue: Shahbaz Youssefi <syoussefi@chromium.org> Reviewed-by: Jamie Madill <jmadill@chromium.org> Reviewed-by: Charlie Lao <cclao@google.com>

  • src/libANGLE/renderer/vulkan/RenderTargetVk.cpp
  • //
    // Copyright 2016 The ANGLE Project Authors. All rights reserved.
    // Use of this source code is governed by a BSD-style license that can be
    // found in the LICENSE file.
    //
    // RenderTargetVk:
    //   Wrapper around a Vulkan renderable resource, using an ImageView.
    //
    
    #include "libANGLE/renderer/vulkan/RenderTargetVk.h"
    
    #include "libANGLE/renderer/vulkan/ContextVk.h"
    #include "libANGLE/renderer/vulkan/ResourceVk.h"
    #include "libANGLE/renderer/vulkan/TextureVk.h"
    #include "libANGLE/renderer/vulkan/vk_format_utils.h"
    #include "libANGLE/renderer/vulkan/vk_helpers.h"
    
    namespace rx
    {
    
    RenderTargetVk::RenderTargetVk()
    {
        reset();
    }
    
    RenderTargetVk::~RenderTargetVk() {}
    
    RenderTargetVk::RenderTargetVk(RenderTargetVk &&other)
        : mImage(other.mImage),
          mImageViews(other.mImageViews),
          mResolveImage(other.mResolveImage),
          mResolveImageViews(other.mResolveImageViews),
          mLevelIndexGL(other.mLevelIndexGL),
          mLayerIndex(other.mLayerIndex),
          mLayerCount(other.mLayerCount)
    {
        other.reset();
    }
    
    void RenderTargetVk::init(vk::ImageHelper *image,
                              vk::ImageViewHelper *imageViews,
                              vk::ImageHelper *resolveImage,
                              vk::ImageViewHelper *resolveImageViews,
                              gl::LevelIndex levelIndexGL,
                              uint32_t layerIndex,
                              uint32_t layerCount,
                              RenderTargetTransience transience)
    {
        mImage             = image;
        mImageViews        = imageViews;
        mResolveImage      = resolveImage;
        mResolveImageViews = resolveImageViews;
        mLevelIndexGL      = levelIndexGL;
        mLayerIndex        = layerIndex;
        mLayerCount        = layerCount;
    
        mTransience = transience;
    }
    
    void RenderTargetVk::reset()
    {
        mImage             = nullptr;
        mImageViews        = nullptr;
        mResolveImage      = nullptr;
        mResolveImageViews = nullptr;
        mLevelIndexGL      = gl::LevelIndex(0);
        mLayerIndex        = 0;
        mLayerCount        = 0;
    }
    
    vk::ImageOrBufferViewSubresourceSerial RenderTargetVk::getSubresourceSerialImpl(
        vk::ImageViewHelper *imageViews) const
    {
        ASSERT(imageViews);
        ASSERT(mLayerIndex < std::numeric_limits<uint16_t>::max());
        ASSERT(mLevelIndexGL.get() < std::numeric_limits<uint16_t>::max());
    
        vk::ImageOrBufferViewSubresourceSerial imageViewSerial = imageViews->getSubresourceSerial(
            mLevelIndexGL, 1, mLayerIndex, vk::GetLayerMode(*mImage, mLayerCount),
            vk::SrgbDecodeMode::SkipDecode, gl::SrgbOverride::Default);
        return imageViewSerial;
    }
    
    vk::ImageOrBufferViewSubresourceSerial RenderTargetVk::getDrawSubresourceSerial() const
    {
        return getSubresourceSerialImpl(mImageViews);
    }
    
    vk::ImageOrBufferViewSubresourceSerial RenderTargetVk::getResolveSubresourceSerial() const
    {
        return getSubresourceSerialImpl(mResolveImageViews);
    }
    
    void RenderTargetVk::onColorDraw(ContextVk *contextVk,
                                     uint32_t framebufferLayerCount,
                                     vk::PackedAttachmentIndex packedAttachmentIndex)
    {
        ASSERT(!mImage->getFormat().actualImageFormat().hasDepthOrStencilBits());
        ASSERT(framebufferLayerCount <= mLayerCount);
    
        contextVk->onColorDraw(mImage, mResolveImage, packedAttachmentIndex);
        mImage->onWrite(mLevelIndexGL, 1, mLayerIndex, framebufferLayerCount,
                        VK_IMAGE_ASPECT_COLOR_BIT);
        if (mResolveImage)
        {
            // Multisampled render to texture framebuffers cannot be layered.
            ASSERT(framebufferLayerCount == 1);
            mResolveImage->onWrite(mLevelIndexGL, 1, mLayerIndex, framebufferLayerCount,
                                   VK_IMAGE_ASPECT_COLOR_BIT);
        }
        retainImageViews(contextVk);
    }
    
    void RenderTargetVk::onColorResolve(ContextVk *contextVk, uint32_t framebufferLayerCount)
    {
        ASSERT(!mImage->getFormat().actualImageFormat().hasDepthOrStencilBits());
        ASSERT(framebufferLayerCount <= mLayerCount);
        ASSERT(mResolveImage == nullptr);
    
        contextVk->onImageRenderPassWrite(mLevelIndexGL, mLayerIndex, framebufferLayerCount,
                                          VK_IMAGE_ASPECT_COLOR_BIT, vk::ImageLayout::ColorAttachment,
                                          mImage);
        retainImageViews(contextVk);
    }
    
    void RenderTargetVk::onDepthStencilDraw(ContextVk *contextVk, uint32_t framebufferLayerCount)
    {
        const angle::Format &format = mImage->getFormat().actualImageFormat();
        ASSERT(format.hasDepthOrStencilBits());
        ASSERT(framebufferLayerCount <= mLayerCount);
    
        contextVk->onDepthStencilDraw(mLevelIndexGL, mLayerIndex, framebufferLayerCount, mImage,
                                      mResolveImage);
        retainImageViews(contextVk);
    }
    
    vk::ImageHelper &RenderTargetVk::getImageForRenderPass()
    {
        ASSERT(mImage && mImage->valid());
        return *mImage;
    }
    
    const vk::ImageHelper &RenderTargetVk::getImageForRenderPass() const
    {
        ASSERT(mImage && mImage->valid());
        return *mImage;
    }
    
    vk::ImageHelper &RenderTargetVk::getResolveImageForRenderPass()
    {
        ASSERT(mResolveImage && mResolveImage->valid());
        return *mResolveImage;
    }
    
    const vk::ImageHelper &RenderTargetVk::getResolveImageForRenderPass() const
    {
        ASSERT(mResolveImage && mResolveImage->valid());
        return *mResolveImage;
    }
    
    angle::Result RenderTargetVk::getImageViewImpl(ContextVk *contextVk,
                                                   const vk::ImageHelper &image,
                                                   gl::SrgbWriteControlMode mode,
                                                   vk::ImageViewHelper *imageViews,
                                                   const vk::ImageView **imageViewOut) const
    {
        ASSERT(image.valid() && imageViews);
        vk::LevelIndex levelVk = mImage->toVkLevel(mLevelIndexGL);
        if (mLayerCount == 1)
        {
            return imageViews->getLevelLayerDrawImageView(contextVk, image, levelVk, mLayerIndex, mode,
                                                          imageViewOut);
        }
    
        // Layered render targets view the whole level or a handful of layers in case of multiview.
        return imageViews->getLevelDrawImageView(contextVk, image, levelVk, mLayerIndex, mLayerCount,
                                                 mode, imageViewOut);
    }
    
    angle::Result RenderTargetVk::getImageView(ContextVk *contextVk,
                                               const vk::ImageView **imageViewOut) const
    {
        ASSERT(mImage);
        return getImageViewImpl(contextVk, *mImage, gl::SrgbWriteControlMode::Default, mImageViews,
                                imageViewOut);
    }
    
    angle::Result RenderTargetVk::getImageViewWithColorspace(ContextVk *contextVk,
                                                             gl::SrgbWriteControlMode mode,
                                                             const vk::ImageView **imageViewOut) const
    {
        ASSERT(mImage);
        return getImageViewImpl(contextVk, *mImage, mode, mImageViews, imageViewOut);
    }
    
    angle::Result RenderTargetVk::getResolveImageView(ContextVk *contextVk,
                                                      const vk::ImageView **imageViewOut) const
    {
        ASSERT(mResolveImage);
        return getImageViewImpl(contextVk, *mResolveImage, gl::SrgbWriteControlMode::Default,
                                mResolveImageViews, imageViewOut);
    }
    
    bool RenderTargetVk::isResolveImageOwnerOfData() const
    {
        // If there's a resolve attachment and the image itself is transient, it's the resolve
        // attachment that owns the data, so all non-render-pass accesses to the render target data
        // should go through the resolve attachment.
        return isImageTransient();
    }
    
    vk::ImageHelper *RenderTargetVk::getOwnerOfData() const
    {
        return isResolveImageOwnerOfData() ? mResolveImage : mImage;
    }
    
    angle::Result RenderTargetVk::getAndRetainCopyImageView(ContextVk *contextVk,
                                                            const vk::ImageView **imageViewOut) const
    {
        retainImageViews(contextVk);
    
        const vk::ImageViewHelper *imageViews =
            isResolveImageOwnerOfData() ? mResolveImageViews : mImageViews;
    
        // If the source of render target is a texture or renderbuffer, this will always be valid.  This
        // is also where 3D or 2DArray images could be the source of the render target.
        if (imageViews->hasCopyImageView())
        {
            *imageViewOut = &imageViews->getCopyImageView();
            return angle::Result::Continue;
        }
    
        // Otherwise, this must come from the surface, in which case the image is 2D, so the image view
        // used to draw is just as good for fetching.  If resolve attachment is present, fetching is
        // done from that.
        return isResolveImageOwnerOfData() ? getResolveImageView(contextVk, imageViewOut)
                                           : getImageView(contextVk, imageViewOut);
    }
    
    const vk::Format &RenderTargetVk::getImageFormat() const
    {
        ASSERT(mImage && mImage->valid());
        return mImage->getFormat();
    }
    
    gl::Extents RenderTargetVk::getExtents() const
    {
        ASSERT(mImage && mImage->valid());
        vk::LevelIndex levelVk = mImage->toVkLevel(mLevelIndexGL);
        return mImage->getLevelExtents2D(levelVk);
    }
    
    gl::Extents RenderTargetVk::getRotatedExtents() const
    {
        ASSERT(mImage && mImage->valid());
        vk::LevelIndex levelVk = mImage->toVkLevel(mLevelIndexGL);
        return mImage->getRotatedLevelExtents2D(levelVk);
    }
    
    void RenderTargetVk::updateSwapchainImage(vk::ImageHelper *image,
                                              vk::ImageViewHelper *imageViews,
                                              vk::ImageHelper *resolveImage,
                                              vk::ImageViewHelper *resolveImageViews)
    {
        ASSERT(image && image->valid() && imageViews);
        mImage             = image;
        mImageViews        = imageViews;
        mResolveImage      = resolveImage;
        mResolveImageViews = resolveImageViews;
    }
    
    vk::ImageHelper &RenderTargetVk::getImageForCopy() const
    {
        ASSERT(mImage && mImage->valid() && (mResolveImage == nullptr || mResolveImage->valid()));
        return *getOwnerOfData();
    }
    
    vk::ImageHelper &RenderTargetVk::getImageForWrite() const
    {
        ASSERT(mImage && mImage->valid() && (mResolveImage == nullptr || mResolveImage->valid()));
        return *getOwnerOfData();
    }
    
    angle::Result RenderTargetVk::flushStagedUpdates(ContextVk *contextVk,
                                                     vk::ClearValuesArray *deferredClears,
                                                     uint32_t deferredClearIndex,
                                                     uint32_t framebufferLayerCount)
    {
        ASSERT(mImage->valid() && (!isResolveImageOwnerOfData() || mResolveImage->valid()));
        ASSERT(framebufferLayerCount != 0);
    
        // It's impossible to defer clears to slices of a 3D images, as the clear applies to all the
        // slices, while deferred clears only clear a single slice (where the framebuffer is attached).
        // Additionally, the layer index for 3D textures is always zero according to Vulkan.
        uint32_t layerIndex = mLayerIndex;
        if (mImage->getType() == VK_IMAGE_TYPE_3D)
        {
            layerIndex         = 0;
            deferredClears     = nullptr;
            deferredClearIndex = 0;
        }
    
        vk::ImageHelper *image = getOwnerOfData();
    
        // All updates should be staged on the image that owns the data as the source of truth.  With
        // multisampled-render-to-texture framebuffers, that is the resolve image.  In that case, even
        // though deferred clears set the loadOp of the transient multisampled image, the clears
        // themselves are staged on the resolve image.  The |flushSingleSubresourceStagedUpdates| call
        // below will either flush all staged updates to the resolve image, or if the only staged update
        // is a clear, it will accumulate it in the |deferredClears| array.  Later, when the render pass
        // is started, the deferred clears are applied to the transient multisampled image.
        ASSERT(!isResolveImageOwnerOfData() ||
               !mImage->hasStagedUpdatesForSubresource(mLevelIndexGL, layerIndex, mLayerCount));
        ASSERT(isResolveImageOwnerOfData() || mResolveImage == nullptr ||
               !mResolveImage->hasStagedUpdatesForSubresource(mLevelIndexGL, layerIndex, mLayerCount));
    
        if (!image->hasStagedUpdatesForSubresource(mLevelIndexGL, layerIndex, framebufferLayerCount))
        {
            return angle::Result::Continue;
        }
    
        return image->flushSingleSubresourceStagedUpdates(contextVk, mLevelIndexGL, layerIndex,
                                                          framebufferLayerCount, deferredClears,
                                                          deferredClearIndex);
    }
    
    void RenderTargetVk::retainImageViews(ContextVk *contextVk) const
    {
        mImageViews->retain(&contextVk->getResourceUseList());
        if (mResolveImageViews)
        {
            mResolveImageViews->retain(&contextVk->getResourceUseList());
        }
    }
    
    bool RenderTargetVk::hasDefinedContent() const
    {
        vk::ImageHelper *image = getOwnerOfData();
        return image->hasSubresourceDefinedContent(mLevelIndexGL, mLayerIndex, mLayerCount);
    }
    
    bool RenderTargetVk::hasDefinedStencilContent() const
    {
        vk::ImageHelper *image = getOwnerOfData();
        return image->hasSubresourceDefinedStencilContent(mLevelIndexGL, mLayerIndex, mLayerCount);
    }
    
    void RenderTargetVk::invalidateEntireContent(ContextVk *contextVk)
    {
        vk::ImageHelper *image = getOwnerOfData();
        image->invalidateSubresourceContent(contextVk, mLevelIndexGL, mLayerIndex, mLayerCount);
    }
    
    void RenderTargetVk::invalidateEntireStencilContent(ContextVk *contextVk)
    {
        vk::ImageHelper *image = getOwnerOfData();
        image->invalidateSubresourceStencilContent(contextVk, mLevelIndexGL, mLayerIndex, mLayerCount);
    }
    
    void RenderTargetVk::restoreEntireContent()
    {
        vk::ImageHelper *image = getOwnerOfData();
        image->restoreSubresourceContent(mLevelIndexGL, mLayerIndex, mLayerCount);
    }
    
    void RenderTargetVk::restoreEntireStencilContent()
    {
        vk::ImageHelper *image = getOwnerOfData();
        image->restoreSubresourceStencilContent(mLevelIndexGL, mLayerIndex, mLayerCount);
    }
    
    gl::ImageIndex RenderTargetVk::getImageIndexForClear(uint32_t layerCount) const
    {
        // Determine the GL type from the Vk Image properties.
        if (mImage->getType() == VK_IMAGE_TYPE_3D || mImage->getLayerCount() > 1)
        {
            // This is used for the sake of staging clears.  The depth slices of the 3D image are
            // threated as layers for this purpose.
            //
            // We also don't need to distinguish 2D array and cube.
            return gl::ImageIndex::Make2DArrayRange(mLevelIndexGL.get(), mLayerIndex, layerCount);
        }
    
        ASSERT(mLayerIndex == 0);
        ASSERT(mLayerCount == 1);
        ASSERT(layerCount == 1);
        return gl::ImageIndex::Make2D(mLevelIndexGL.get());
    }
    }  // namespace rx