blob: 807533175a3083d8f0625688de9206f2c2ad86ba [file] [log] [blame]
//
// 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)
{}
OverlayVk::~OverlayVk() = default;
angle::Result OverlayVk::init(const gl::Context *context)
{
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;
return contextVk->flushImpl(nullptr);
}
void OverlayVk::onDestroy(const gl::Context *context)
{
VkDevice device = vk::GetImpl(context)->getDevice();
mCulledWidgets.destroy(device);
mCulledWidgetsView.destroy(device);
mFontImage.destroy(device);
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(contextVk, 0, fontDataBuffer.get().getSize()));
fontDataBuffer.get().unmap(contextVk->getDevice());
fontDataBuffer.get().onExternalWrite(VK_ACCESS_HOST_WRITE_BIT);
// 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, 0, 0, 1,
gl::overlay::kFontCount));
ANGLE_TRY(mFontImage.initMemory(contextVk, renderer->getMemoryProperties(),
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT));
ANGLE_TRY(mFontImage.initImageView(contextVk, gl::TextureType::_2DArray,
VK_IMAGE_ASPECT_COLOR_BIT, gl::SwizzleState(),
&mFontImageView, 0, 1));
// Copy font data from staging buffer.
vk::CommandBuffer *fontDataUpload;
ANGLE_TRY(mFontImage.recordCommands(contextVk, &fontDataUpload));
fontDataBuffer.get().onRead(contextVk, &mFontImage, VK_ACCESS_TRANSFER_READ_BIT);
mFontImage.changeLayout(VK_IMAGE_ASPECT_COLOR_BIT, vk::ImageLayout::TransferDst,
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);
mFontImage.changeLayout(VK_IMAGE_ASPECT_COLOR_BIT, vk::ImageLayout::ComputeShaderReadOnly,
fontDataUpload);
return angle::Result::Continue;
}
angle::Result OverlayVk::cullWidgets(ContextVk *contextVk)
{
RendererVk *renderer = contextVk->getRenderer();
// Release old culledWidgets image
mCulledWidgets.releaseImage(renderer);
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(contextVk, 0, enabledWidgetsBuffer.get().getSize()));
enabledWidgetsBuffer.get().unmap(contextVk->getDevice());
enabledWidgetsBuffer.get().onExternalWrite(VK_ACCESS_HOST_WRITE_BIT);
// Allocate mCulledWidget and its view.
VkExtent3D culledWidgetsExtent = {
UnsignedCeilDivide(mPresentImageExtent.width, mSubgroupSize[0]),
UnsignedCeilDivide(mPresentImageExtent.height, mSubgroupSize[1]), 1};
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, 0, 0, 1,
1));
ANGLE_TRY(mCulledWidgets.initMemory(contextVk, renderer->getMemoryProperties(),
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT));
ANGLE_TRY(mCulledWidgets.initImageView(contextVk, gl::TextureType::_2D,
VK_IMAGE_ASPECT_COLOR_BIT, gl::SwizzleState(),
&mCulledWidgetsView, 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)
{
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->getFormat().vkImageFormat, 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(contextVk, 0, textDataBuffer.get().getSize()));
ANGLE_TRY(graphDataBuffer.get().flush(contextVk, 0, graphDataBuffer.get().getSize()));
textDataBuffer.get().unmap(contextVk->getDevice());
graphDataBuffer.get().unmap(contextVk->getDevice());
UtilsVk::OverlayDrawParameters params;
params.subgroupSize[0] = mSubgroupSize[0];
params.subgroupSize[1] = mSubgroupSize[1];
return contextVk->getUtils().drawOverlay(
contextVk, &textDataBuffer.get(), &graphDataBuffer.get(), &mFontImage, &mFontImageView,
&mCulledWidgets, &mCulledWidgetsView, imageToPresent, imageToPresentView, params);
}
} // namespace rx