Edit

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

Branch :

  • Show log

    Commit

  • Author : Charlie Lao
    Date : 2021-08-17 10:48:23
    Hash : cf24931a
    Message : Vulkan: Add ImageHelper::getActualFormat() This is preparation for future CLs. In the future vk::Format may not tell you what actual format is. This CL adds a new method of ImageHelper::getActualFormatID() and ImageHelper::getActualFormat() so that we can use these two APIs and avoid using vk::Format, thus reduce reliance on vk::Format. Bug: b/196456356 Change-Id: Ic50e664e033feb5e066f40269c33cffe96024172 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/3100319 Commit-Queue: Charlie Lao <cclao@google.com> Reviewed-by: Jamie Madill <jmadill@chromium.org> Reviewed-by: Shahbaz Youssefi <syoussefi@chromium.org> Reviewed-by: Ian Elliott <ianelliott@google.com>

  • src/libANGLE/renderer/vulkan/OverlayVk.cpp
  • //
    // Copyright 2019 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.
    //
    // OverlayVk.cpp:
    //    Implements the OverlayVk class.
    //
    
    #include "libANGLE/renderer/vulkan/OverlayVk.h"
    
    #include "common/system_utils.h"
    #include "libANGLE/Context.h"
    #include "libANGLE/Overlay_font_autogen.h"
    #include "libANGLE/renderer/vulkan/ContextVk.h"
    
    #include <numeric>
    
    namespace rx
    {
    OverlayVk::OverlayVk(const gl::OverlayState &state)
        : OverlayImpl(state),
          mSupportsSubgroupBallot(false),
          mSupportsSubgroupArithmetic(false),
          mRefreshCulledWidgets(false),
          mSubgroupSize{},
          mPresentImageExtent{}
    {}
    OverlayVk::~OverlayVk() = default;
    
    angle::Result OverlayVk::init(const gl::Context *context, bool *successOut)
    {
        *successOut = false;
    
        ContextVk *contextVk   = vk::GetImpl(context);
        RendererVk *rendererVk = contextVk->getRenderer();
    
        const VkPhysicalDeviceSubgroupProperties &subgroupProperties =
            rendererVk->getPhysicalDeviceSubgroupProperties();
        uint32_t subgroupSize = subgroupProperties.subgroupSize;
    
        // Currently, only subgroup sizes 32 and 64 are supported.
        if (subgroupSize != 32 && subgroupSize != 64)
        {
            return angle::Result::Continue;
        }
    
        mSubgroupSize[0] = 8;
        mSubgroupSize[1] = subgroupSize / 8;
    
        constexpr VkSubgroupFeatureFlags kSubgroupBallotOperations =
            VK_SUBGROUP_FEATURE_BASIC_BIT | VK_SUBGROUP_FEATURE_BALLOT_BIT;
        constexpr VkSubgroupFeatureFlags kSubgroupArithmeticOperations =
            VK_SUBGROUP_FEATURE_BASIC_BIT | VK_SUBGROUP_FEATURE_ARITHMETIC_BIT;
    
        // If not all operations used in the shaders are supported, disable the overlay.
        if ((subgroupProperties.supportedOperations & kSubgroupBallotOperations) ==
            kSubgroupBallotOperations)
        {
            mSupportsSubgroupBallot = true;
        }
        else if ((subgroupProperties.supportedOperations & kSubgroupArithmeticOperations) ==
                 kSubgroupArithmeticOperations)
        {
            mSupportsSubgroupArithmetic = true;
        }
    
        ANGLE_TRY(createFont(contextVk));
    
        mRefreshCulledWidgets = true;
    
        ANGLE_TRY(contextVk->flushImpl(nullptr));
        *successOut = true;
        return angle::Result::Continue;
    }
    
    void OverlayVk::onDestroy(const gl::Context *context)
    {
        RendererVk *renderer = vk::GetImpl(context)->getRenderer();
        VkDevice device      = renderer->getDevice();
    
        mCulledWidgets.destroy(renderer);
        mCulledWidgetsView.destroy(device);
    
        mFontImage.destroy(renderer);
        mFontImageView.destroy(device);
    }
    
    angle::Result OverlayVk::createFont(ContextVk *contextVk)
    {
        RendererVk *renderer = contextVk->getRenderer();
    
        // Create a buffer to stage font data upload.
        VkBufferCreateInfo bufferCreateInfo = {};
        bufferCreateInfo.sType              = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
        bufferCreateInfo.size =
            gl::overlay::kFontCount * gl::overlay::kFontImageWidth * gl::overlay::kFontImageHeight;
        bufferCreateInfo.usage       = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
        bufferCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
    
        vk::RendererScoped<vk::BufferHelper> fontDataBuffer(renderer);
    
        ANGLE_TRY(fontDataBuffer.get().init(contextVk, bufferCreateInfo,
                                            VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT));
    
        uint8_t *fontData;
        ANGLE_TRY(fontDataBuffer.get().map(contextVk, &fontData));
    
        mState.initFontData(fontData);
    
        ANGLE_TRY(fontDataBuffer.get().flush(renderer, 0, fontDataBuffer.get().getSize()));
        fontDataBuffer.get().unmap(renderer);
    
        // Don't use robust resource init for overlay widgets.
        bool useRobustInit = false;
    
        // Create the font image.
        ANGLE_TRY(
            mFontImage.init(contextVk, gl::TextureType::_2D,
                            VkExtent3D{gl::overlay::kFontImageWidth, gl::overlay::kFontImageHeight, 1},
                            renderer->getFormat(angle::FormatID::R8_UNORM), 1,
                            VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT,
                            gl::LevelIndex(0), 1, gl::overlay::kFontCount, useRobustInit, false));
        ANGLE_TRY(mFontImage.initMemory(contextVk, false, renderer->getMemoryProperties(),
                                        VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT));
        ANGLE_TRY(mFontImage.initImageView(contextVk, gl::TextureType::_2DArray,
                                           VK_IMAGE_ASPECT_COLOR_BIT, gl::SwizzleState(),
                                           &mFontImageView, vk::LevelIndex(0), 1));
    
        // Copy font data from staging buffer.
        vk::CommandBufferAccess access;
        access.onBufferTransferRead(&fontDataBuffer.get());
        access.onImageTransferWrite(gl::LevelIndex(0), 1, 0, gl::overlay::kFontCount,
                                    VK_IMAGE_ASPECT_COLOR_BIT, &mFontImage);
        vk::CommandBuffer *fontDataUpload;
        ANGLE_TRY(contextVk->getOutsideRenderPassCommandBuffer(access, &fontDataUpload));
    
        VkBufferImageCopy copy           = {};
        copy.bufferRowLength             = gl::overlay::kFontImageWidth;
        copy.bufferImageHeight           = gl::overlay::kFontImageHeight;
        copy.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
        copy.imageSubresource.layerCount = gl::overlay::kFontCount;
        copy.imageExtent.width           = gl::overlay::kFontImageWidth;
        copy.imageExtent.height          = gl::overlay::kFontImageHeight;
        copy.imageExtent.depth           = 1;
    
        fontDataUpload->copyBufferToImage(fontDataBuffer.get().getBuffer().getHandle(),
                                          mFontImage.getImage(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
                                          1, &copy);
    
        return angle::Result::Continue;
    }
    
    angle::Result OverlayVk::cullWidgets(ContextVk *contextVk)
    {
        RendererVk *renderer = contextVk->getRenderer();
    
        // Release old culledWidgets image
        mCulledWidgets.releaseImageFromShareContexts(renderer, contextVk);
        contextVk->addGarbage(&mCulledWidgetsView);
    
        // Create a buffer to contain coordinates of enabled text and graph widgets.  This buffer will
        // be used to perform tiled culling and can be discarded immediately after.
        VkBufferCreateInfo bufferCreateInfo = {};
        bufferCreateInfo.sType              = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
        bufferCreateInfo.size               = mState.getWidgetCoordinatesBufferSize();
        bufferCreateInfo.usage              = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT;
        bufferCreateInfo.sharingMode        = VK_SHARING_MODE_EXCLUSIVE;
    
        vk::RendererScoped<vk::BufferHelper> enabledWidgetsBuffer(renderer);
    
        ANGLE_TRY(enabledWidgetsBuffer.get().init(contextVk, bufferCreateInfo,
                                                  VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT));
    
        // Fill the buffer with coordinate information from enabled widgets.
        uint8_t *enabledWidgets;
        ANGLE_TRY(enabledWidgetsBuffer.get().map(contextVk, &enabledWidgets));
    
        gl::Extents presentImageExtents(mPresentImageExtent.width, mPresentImageExtent.height, 1);
        mState.fillEnabledWidgetCoordinates(presentImageExtents, enabledWidgets);
    
        ANGLE_TRY(enabledWidgetsBuffer.get().flush(renderer, 0, enabledWidgetsBuffer.get().getSize()));
        enabledWidgetsBuffer.get().unmap(renderer);
    
        // Allocate mCulledWidget and its view.
        VkExtent3D culledWidgetsExtent = {
            UnsignedCeilDivide(mPresentImageExtent.width, mSubgroupSize[0]),
            UnsignedCeilDivide(mPresentImageExtent.height, mSubgroupSize[1]), 1};
    
        // Don't use robust resource init for overlay widgets.
        bool useRobustInit = false;
    
        ANGLE_TRY(mCulledWidgets.init(contextVk, gl::TextureType::_2D, culledWidgetsExtent,
                                      renderer->getFormat(angle::FormatID::R32G32_UINT), 1,
                                      VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_SAMPLED_BIT,
                                      gl::LevelIndex(0), 1, 1, useRobustInit, false));
        ANGLE_TRY(mCulledWidgets.initMemory(contextVk, false, renderer->getMemoryProperties(),
                                            VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT));
        ANGLE_TRY(mCulledWidgets.initImageView(contextVk, gl::TextureType::_2D,
                                               VK_IMAGE_ASPECT_COLOR_BIT, gl::SwizzleState(),
                                               &mCulledWidgetsView, vk::LevelIndex(0), 1));
    
        UtilsVk::OverlayCullParameters params;
        params.subgroupSize[0]            = mSubgroupSize[0];
        params.subgroupSize[1]            = mSubgroupSize[1];
        params.supportsSubgroupBallot     = mSupportsSubgroupBallot;
        params.supportsSubgroupArithmetic = mSupportsSubgroupArithmetic;
    
        return contextVk->getUtils().cullOverlayWidgets(contextVk, &enabledWidgetsBuffer.get(),
                                                        &mCulledWidgets, &mCulledWidgetsView, params);
    }
    
    angle::Result OverlayVk::onPresent(ContextVk *contextVk,
                                       vk::ImageHelper *imageToPresent,
                                       const vk::ImageView *imageToPresentView,
                                       bool is90DegreeRotation)
    {
        if (mState.getEnabledWidgetCount() == 0)
        {
            return angle::Result::Continue;
        }
    
        RendererVk *renderer = contextVk->getRenderer();
    
        // If the swapchain image doesn't support storage image, we can't output to it.
        VkFormatFeatureFlags featureBits = renderer->getImageFormatFeatureBits(
            imageToPresent->getActualFormatID(), VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT);
        if ((featureBits & VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT) == 0)
        {
            return angle::Result::Continue;
        }
    
        const VkExtent3D &imageExtent = imageToPresent->getExtents();
    
        mRefreshCulledWidgets = mRefreshCulledWidgets ||
                                mPresentImageExtent.width != imageExtent.width ||
                                mPresentImageExtent.height != imageExtent.height;
    
        if (mRefreshCulledWidgets)
        {
            mPresentImageExtent.width  = imageExtent.width;
            mPresentImageExtent.height = imageExtent.height;
    
            ANGLE_TRY(cullWidgets(contextVk));
    
            mRefreshCulledWidgets = false;
        }
    
        vk::RendererScoped<vk::BufferHelper> textDataBuffer(renderer);
        vk::RendererScoped<vk::BufferHelper> graphDataBuffer(renderer);
    
        VkBufferCreateInfo textBufferCreateInfo = {};
        textBufferCreateInfo.sType              = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
        textBufferCreateInfo.size               = mState.getTextWidgetsBufferSize();
        textBufferCreateInfo.usage              = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT;
        textBufferCreateInfo.sharingMode        = VK_SHARING_MODE_EXCLUSIVE;
    
        VkBufferCreateInfo graphBufferCreateInfo = textBufferCreateInfo;
        graphBufferCreateInfo.size               = mState.getGraphWidgetsBufferSize();
    
        ANGLE_TRY(textDataBuffer.get().init(contextVk, textBufferCreateInfo,
                                            VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT));
        ANGLE_TRY(graphDataBuffer.get().init(contextVk, graphBufferCreateInfo,
                                             VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT));
    
        uint8_t *textData;
        uint8_t *graphData;
        ANGLE_TRY(textDataBuffer.get().map(contextVk, &textData));
        ANGLE_TRY(graphDataBuffer.get().map(contextVk, &graphData));
    
        gl::Extents presentImageExtents(mPresentImageExtent.width, mPresentImageExtent.height, 1);
        mState.fillWidgetData(presentImageExtents, textData, graphData);
    
        ANGLE_TRY(textDataBuffer.get().flush(renderer, 0, textDataBuffer.get().getSize()));
        ANGLE_TRY(graphDataBuffer.get().flush(renderer, 0, graphDataBuffer.get().getSize()));
        textDataBuffer.get().unmap(renderer);
        graphDataBuffer.get().unmap(renderer);
    
        UtilsVk::OverlayDrawParameters params;
        params.subgroupSize[0] = mSubgroupSize[0];
        params.subgroupSize[1] = mSubgroupSize[1];
        params.rotateXY        = is90DegreeRotation;
    
        return contextVk->getUtils().drawOverlay(
            contextVk, &textDataBuffer.get(), &graphDataBuffer.get(), &mFontImage, &mFontImageView,
            &mCulledWidgets, &mCulledWidgetsView, imageToPresent, imageToPresentView, params);
    }
    
    }  // namespace rx