Add Android Vulkan backend (#2711)

Co-authored-by: Bart Louwers <bart.louwers@gmail.com>
This commit is contained in:
Adrian Cojocaru
2024-09-06 17:40:57 +03:00
committed by GitHub
parent 4b5d06d908
commit ea09bdf2b6
79 changed files with 2580 additions and 1400 deletions

View File

@@ -15,11 +15,8 @@
#include <mbgl/geometry/feature_index.hpp>
#include <mbgl/gfx/backend_scope.hpp>
#include <mbgl/gfx/renderer_backend.hpp>
#include <mbgl/gl/context.hpp>
#include <mbgl/gl/renderable_resource.hpp>
#include <mbgl/map/transform_state.hpp>
#include <mbgl/math/angles.hpp>
#include <mbgl/platform/gl_functions.hpp>
#include <mbgl/renderer/bucket.hpp>
#include <mbgl/renderer/layers/render_location_indicator_layer.hpp>
#include <mbgl/renderer/paint_parameters.hpp>
@@ -29,11 +26,25 @@
#include <mbgl/util/mat4.hpp>
#include <mapbox/eternal.hpp>
#include <mbgl/renderer/image_manager.hpp>
#if MLN_RENDER_BACKEND_OPENGL
#include <mbgl/platform/gl_functions.hpp>
#include <mbgl/gl/context.hpp>
#include <mbgl/gl/renderable_resource.hpp>
#include <mbgl/gl/defines.hpp>
#include <mbgl/gl/texture.hpp>
#include <mbgl/gl/texture_resource.hpp>
#include <mbgl/gl/types.hpp>
#include <mbgl/renderer/image_manager.hpp>
#else
#define MBGL_CHECK_ERROR(x) \
while (0) { \
}
#endif
#include <numbers>
@@ -75,6 +86,7 @@ struct LocationIndicatorRenderParameters {
std::string puckHatImagePath;
};
#if MLN_RENDER_BACKEND_OPENGL
class RenderLocationIndicatorImpl {
protected:
struct vec2 {
@@ -756,6 +768,25 @@ public:
};
bool RenderLocationIndicatorImpl::anisotropicFilteringAvailable = false;
#else
class RenderLocationIndicatorImpl {
public:
RenderLocationIndicatorImpl(std::string) {}
void release() {}
void updateFeature() {}
void updatePuckGeometry([[maybe_unused]] const mbgl::LocationIndicatorRenderParameters& params) {}
public:
mbgl::LocationIndicatorRenderParameters parameters;
std::shared_ptr<mbgl::Feature> feature;
std::shared_ptr<mapbox::geometry::polygon<int64_t>> featureEnvelope;
static bool anisotropicFilteringAvailable;
};
bool RenderLocationIndicatorImpl::anisotropicFilteringAvailable = false;
#endif
using namespace style;
namespace {
@@ -845,6 +876,7 @@ void RenderLocationIndicatorLayer::prepare(const LayerPrepareParameters& p) {
renderImpl->updatePuckGeometry(renderImpl->parameters);
}
#if MLN_RENDER_BACKEND_OPENGL
void RenderLocationIndicatorLayer::render(PaintParameters& paintParameters) {
auto& glContext = static_cast<gl::Context&>(paintParameters.context);
@@ -863,6 +895,8 @@ void RenderLocationIndicatorLayer::render(PaintParameters& paintParameters) {
glContext.setDirtyState();
}
#endif
void RenderLocationIndicatorLayer::populateDynamicRenderFeatureIndex(DynamicFeatureIndex& index) const {
renderImpl->updateFeature();
if (!renderImpl->featureEnvelope->empty()) index.insert(renderImpl->feature, renderImpl->featureEnvelope);

View File

@@ -20,7 +20,10 @@ private:
void markContextDestroyed() override;
void prepare(const LayerPrepareParameters &) override;
#if MLN_RENDER_BACKEND_OPENGL
void render(PaintParameters &) override;
#endif
void populateDynamicRenderFeatureIndex(DynamicFeatureIndex &) const override;
bool contextDestroyed = false;

View File

@@ -28,6 +28,13 @@
#include <mbgl/renderer/layer_tweaker.hpp>
#include <unordered_set>
#if MLN_RENDER_BACKEND_METAL || (MLN_RENDER_BACKEND_VULKAN && defined(__ANDROID__))
#define MLN_ENABLE_POLYLINE_DRAWABLES 1
#else
#define MLN_ENABLE_POLYLINE_DRAWABLES 0
#endif
#endif
namespace mbgl {
@@ -81,7 +88,7 @@ void TileSourceRenderItem::updateDebugDrawables(DebugLayerGroupMap& debugLayerGr
return builder;
}();
#if MLN_RENDER_BACKEND_METAL
#if MLN_ENABLE_POLYLINE_DRAWABLES
// initialize polyline builder
gfx::ShaderPtr polylineShader;
const auto createPolylineShader = [&]() -> gfx::ShaderPtr {
@@ -185,7 +192,7 @@ void TileSourceRenderItem::updateDebugDrawables(DebugLayerGroupMap& debugLayerGr
}
};
#if MLN_RENDER_BACKEND_METAL
#if MLN_ENABLE_POLYLINE_DRAWABLES
// function to add polylines drawable
const auto addPolylineDrawable = [&](TileLayerGroup* tileLayerGroup, const RenderTile& tile) {
class PolylineDrawableTweaker : public gfx::DrawableTweaker {
@@ -364,7 +371,7 @@ void TileSourceRenderItem::updateDebugDrawables(DebugLayerGroupMap& debugLayerGr
0,
0};
if (0 == updateDrawables(tileLayerGroup, tileID, debugUBO) && tile.getNeedsRendering()) {
#if MLN_RENDER_BACKEND_METAL
#if MLN_ENABLE_POLYLINE_DRAWABLES
addPolylineDrawable(tileLayerGroup, tile);
#else
addDrawable(tileLayerGroup,

View File

@@ -8,7 +8,7 @@ const std::array<UniformBlockInfo, 2> ShaderSource<BuiltIn::BackgroundShader, gf
UniformBlockInfo{false, true, sizeof(BackgroundLayerUBO), idBackgroundLayerUBO},
};
const std::array<AttributeInfo, 1> ShaderSource<BuiltIn::BackgroundShader, gfx::Backend::Type::Vulkan>::attributes = {
AttributeInfo{0, gfx::AttributeDataType::Float3, idBackgroundPosVertexAttribute},
AttributeInfo{0, gfx::AttributeDataType::Short2, idBackgroundPosVertexAttribute},
};
const std::array<UniformBlockInfo, 3>
@@ -19,7 +19,7 @@ const std::array<UniformBlockInfo, 3>
};
const std::array<AttributeInfo, 1>
ShaderSource<BuiltIn::BackgroundPatternShader, gfx::Backend::Type::Vulkan>::attributes = {
AttributeInfo{0, gfx::AttributeDataType::Float3, idBackgroundPosVertexAttribute},
AttributeInfo{0, gfx::AttributeDataType::Short2, idBackgroundPosVertexAttribute},
};
const std::array<TextureInfo, 1> ShaderSource<BuiltIn::BackgroundPatternShader, gfx::Backend::Type::Vulkan>::textures =
{TextureInfo{0, idBackgroundImageTexture}};

View File

@@ -185,7 +185,7 @@ const vk::UniquePipeline& ShaderProgram::getPipeline(const PipelineInfo& pipelin
// vk::DynamicState::eDepthBias,
// vk::DynamicState::eDepthBounds,
const auto& dynamicValues = pipelineInfo.getDynamicStates();
const auto& dynamicValues = pipelineInfo.getDynamicStates(backend);
const vk::PipelineDynamicStateCreateInfo dynamicState({}, dynamicValues);
const auto& device = backend.getDevice();

View File

@@ -0,0 +1,22 @@
#include <mbgl/shaders/vulkan/widevector.hpp>
namespace mbgl {
namespace shaders {
const std::array<UniformBlockInfo, 2> ShaderSource<BuiltIn::WideVectorShader, gfx::Backend::Type::Vulkan>::uniforms = {
UniformBlockInfo{true, false, sizeof(WideVectorUniformsUBO), idWideVectorUniformsUBO},
UniformBlockInfo{true, false, sizeof(WideVectorUniformWideVecUBO), idWideVectorUniformWideVecUBO},
};
const std::array<AttributeInfo, 3> ShaderSource<BuiltIn::WideVectorShader, gfx::Backend::Type::Vulkan>::attributes = {
AttributeInfo{0, gfx::AttributeDataType::Float3, idWideVectorScreenPos},
AttributeInfo{1, gfx::AttributeDataType::Float4, idWideVectorColor},
AttributeInfo{2, gfx::AttributeDataType::Int, idWideVectorIndex}};
const std::array<AttributeInfo, 4>
ShaderSource<BuiltIn::WideVectorShader, gfx::Backend::Type::Vulkan>::instanceAttributes = {
AttributeInfo{3, gfx::AttributeDataType::Float3, idWideVectorInstanceCenter},
AttributeInfo{4, gfx::AttributeDataType::Float4, idWideVectorInstanceColor},
AttributeInfo{5, gfx::AttributeDataType::Int, idWideVectorInstancePrevious},
AttributeInfo{6, gfx::AttributeDataType::Int, idWideVectorInstanceNext}};
} // namespace shaders
} // namespace mbgl

View File

@@ -10,19 +10,27 @@ namespace mbgl {
namespace vulkan {
bool BufferAllocation::create(const VmaAllocationCreateInfo& allocInfo, const vk::BufferCreateInfo& bufferInfo) {
VkResult result = vmaCreateBuffer(
allocator, reinterpret_cast<const VkBufferCreateInfo*>(&bufferInfo), &allocInfo, &buffer, &allocation, nullptr);
VkBuffer buffer_;
VkResult result = vmaCreateBuffer(allocator,
reinterpret_cast<const VkBufferCreateInfo*>(&bufferInfo),
&allocInfo,
&buffer_,
&allocation,
nullptr);
if (result != VK_SUCCESS) {
return false;
}
buffer = vk::Buffer(buffer_);
return true;
}
void BufferAllocation::destroy() {
if (mappedBuffer) vmaUnmapMemory(allocator, allocation);
vmaDestroyBuffer(allocator, buffer, allocation);
vmaDestroyBuffer(allocator, VkBuffer(buffer), allocation);
buffer = nullptr;
mappedBuffer = nullptr;
}

View File

@@ -24,7 +24,9 @@ std::unique_ptr<gfx::RenderPass> CommandEncoder::createRenderPass(const char* na
return std::make_unique<RenderPass>(*this, name, descriptor);
}
void CommandEncoder::present(gfx::Renderable&) {}
void CommandEncoder::present(gfx::Renderable& renderable) {
renderable.getResource<RenderableResource>().swap();
}
void CommandEncoder::pushDebugGroup(const char* name) {
pushDebugGroup(name, {});

View File

@@ -135,7 +135,8 @@ void Context::submitOneTimeCommand(const std::function<void(const vk::UniqueComm
const vk::CommandBufferAllocateInfo allocateInfo(
backend.getCommandPool().get(), vk::CommandBufferLevel::ePrimary, 1);
const auto& commandBuffers = backend.getDevice()->allocateCommandBuffersUnique(allocateInfo);
const auto& device = backend.getDevice();
const auto& commandBuffers = device->allocateCommandBuffersUnique(allocateInfo);
auto& commandBuffer = commandBuffers.front();
backend.setDebugName(commandBuffer.get(), "OneTimeSubmitCommandBuffer");
@@ -146,8 +147,14 @@ void Context::submitOneTimeCommand(const std::function<void(const vk::UniqueComm
const auto submitInfo = vk::SubmitInfo().setCommandBuffers(commandBuffer.get());
backend.getGraphicsQueue().submit(submitInfo);
backend.getDevice()->waitIdle();
const auto& fence = device->createFenceUnique(vk::FenceCreateInfo(vk::FenceCreateFlags()));
backend.getGraphicsQueue().submit(submitInfo, fence.get());
constexpr uint64_t timeout = std::numeric_limits<uint64_t>::max();
const vk::Result waitFenceResult = device->waitForFences(1, &fence.get(), VK_TRUE, timeout);
if (waitFenceResult != vk::Result::eSuccess) {
mbgl::Log::Error(mbgl::Event::Render, "OneTimeCommand - Wait fence failed");
}
}
void Context::waitFrame() const {
@@ -161,10 +168,27 @@ void Context::waitFrame() const {
}
}
void Context::beginFrame() {
backend.startFrameCapture();
const auto& device = backend.getDevice();
auto& renderableResource = backend.getDefaultRenderable().getResource<SurfaceRenderableResource>();
const auto& platformSurface = renderableResource.getPlatformSurface();
if (platformSurface && surfaceUpdateRequested) {
renderableResource.recreateSwapchain();
// we wait for an idle device to recreate the swapchain
// so it's a good opportunity to delete all queued items
for (auto& frame : frameResources) {
device->resetDescriptorPool(frame.descriptorPool.get());
frame.runDeletionQueue(*this);
}
// sync resources with swapchain
frameResourceIndex = 0;
surfaceUpdateRequested = false;
}
backend.startFrameCapture();
auto& frame = frameResources[frameResourceIndex];
constexpr uint64_t timeout = std::numeric_limits<uint64_t>::max();
@@ -173,18 +197,26 @@ void Context::beginFrame() {
device->resetDescriptorPool(getCurrentDescriptorPool().get());
frame.runDeletionQueue(*this);
if (renderableResource.getPlatformSurface()) {
if (platformSurface) {
try {
const vk::ResultValue acquireImageResult = device->acquireNextImageKHR(
renderableResource.getSwapchain().get(), timeout, frame.surfaceSemaphore.get(), nullptr);
if (acquireImageResult.result == vk::Result::eSuccess)
if (acquireImageResult.result == vk::Result::eSuccess) {
renderableResource.setAcquiredImageIndex(acquireImageResult.value);
else if (acquireImageResult.result == vk::Result::eSuboptimalKHR)
renderableResource.recreateSwapchain();
} else if (acquireImageResult.result == vk::Result::eSuboptimalKHR) {
renderableResource.setAcquiredImageIndex(acquireImageResult.value);
// TODO implement pre-rotation transform for surface orientation
// requestSurfaceUpdate();
// beginFrame();
// return;
}
} catch (const vk::OutOfDateKHRError& e) {
renderableResource.recreateSwapchain();
// request an update and restart frame
requestSurfaceUpdate();
beginFrame();
return;
}
} else {
renderableResource.setAcquiredImageIndex(frameResourceIndex);
@@ -197,18 +229,23 @@ void Context::beginFrame() {
}
void Context::endFrame() {
frameResourceIndex = (frameResourceIndex + 1) % frameResources.size();
}
void Context::submitFrame() {
const auto& frame = frameResources[frameResourceIndex];
frame.commandBuffer->end();
const auto& device = backend.getDevice();
const auto& graphicsQueue = backend.getGraphicsQueue();
auto& renderableResource = backend.getDefaultRenderable().getResource<SurfaceRenderableResource>();
const auto& platformSurface = renderableResource.getPlatformSurface();
// submit frame commands
const vk::PipelineStageFlags waitStageMask[] = {vk::PipelineStageFlagBits::eColorAttachmentOutput};
auto submitInfo = vk::SubmitInfo().setCommandBuffers(frame.commandBuffer.get());
if (renderableResource.getPlatformSurface()) {
if (platformSurface) {
submitInfo.setSignalSemaphores(frame.frameSemaphore.get())
.setWaitSemaphores(frame.surfaceSemaphore.get())
.setWaitDstStageMask(waitStageMask);
@@ -222,7 +259,7 @@ void Context::endFrame() {
graphicsQueue.submit(submitInfo, frame.flightFrameFence.get());
// present rendered frame
if (renderableResource.getPlatformSurface()) {
if (platformSurface) {
const auto acquiredImage = renderableResource.getAcquiredImageIndex();
const auto presentInfo = vk::PresentInfoKHR()
.setSwapchains(renderableResource.getSwapchain().get())
@@ -232,14 +269,15 @@ void Context::endFrame() {
try {
const auto& presentQueue = backend.getPresentQueue();
const vk::Result presentResult = presentQueue.presentKHR(presentInfo);
if (presentResult == vk::Result::eSuboptimalKHR) renderableResource.recreateSwapchain();
if (presentResult == vk::Result::eSuboptimalKHR) {
// TODO implement pre-rotation transform for surface orientation
// requestSurfaceUpdate();
}
} catch (const vk::OutOfDateKHRError& e) {
renderableResource.recreateSwapchain();
requestSurfaceUpdate();
}
}
frameResourceIndex = (frameResourceIndex + 1) % frameResources.size();
backend.endFrameCapture();
}
@@ -419,7 +457,7 @@ bool Context::renderTileClippingMasks(gfx::RenderPass& renderPass,
const auto& pipeline = shaderImpl.getPipeline(clipping.pipelineInfo);
commandBuffer->bindPipeline(vk::PipelineBindPoint::eGraphics, pipeline.get());
clipping.pipelineInfo.setDynamicValues(commandBuffer);
clipping.pipelineInfo.setDynamicValues(backend, commandBuffer);
const std::array<vk::Buffer, 1> vertexBuffers = {clipping.vertexBuffer->getVulkanBuffer()};
const std::array<vk::DeviceSize, 1> offset = {0};

View File

@@ -247,7 +247,7 @@ void Drawable::draw(PaintParameters& parameters) const {
// update pipeline info with per segment modifiers
impl->pipelineInfo.setDrawMode(seg->getMode());
impl->pipelineInfo.setDynamicValues(commandBuffer);
impl->pipelineInfo.setDynamicValues(context.getBackend(), commandBuffer);
const auto& pipeline = shaderImpl.getPipeline(impl->pipelineInfo);
commandBuffer->bindPipeline(vk::PipelineBindPoint::eGraphics, pipeline.get());

View File

@@ -9,37 +9,37 @@ namespace vulkan {
vk::Format PipelineInfo::vulkanFormat(const gfx::AttributeDataType& value) {
switch (value) {
case gfx::AttributeDataType::Byte:
return vk::Format::eR8Sscaled;
return vk::Format::eR8Sint;
case gfx::AttributeDataType::Byte2:
return vk::Format::eR8G8Sscaled;
return vk::Format::eR8G8Sint;
case gfx::AttributeDataType::Byte3:
return vk::Format::eR8G8B8Sscaled;
return vk::Format::eR8G8B8Sint;
case gfx::AttributeDataType::Byte4:
return vk::Format::eR8G8B8A8Sscaled;
return vk::Format::eR8G8B8A8Sint;
case gfx::AttributeDataType::UByte:
return vk::Format::eR8Uscaled;
return vk::Format::eR8Uint;
case gfx::AttributeDataType::UByte2:
return vk::Format::eR8G8Uscaled;
return vk::Format::eR8G8Uint;
case gfx::AttributeDataType::UByte3:
return vk::Format::eR8G8B8Uscaled;
return vk::Format::eR8G8B8Uint;
case gfx::AttributeDataType::UByte4:
return vk::Format::eR8G8B8A8Uscaled;
return vk::Format::eR8G8B8A8Uint;
case gfx::AttributeDataType::Short:
return vk::Format::eR16Sscaled;
return vk::Format::eR16Sint;
case gfx::AttributeDataType::Short2:
return vk::Format::eR16G16Sscaled;
return vk::Format::eR16G16Sint;
case gfx::AttributeDataType::Short3:
return vk::Format::eR16G16B16Sscaled;
return vk::Format::eR16G16B16Sint;
case gfx::AttributeDataType::Short4:
return vk::Format::eR16G16B16A16Sscaled;
return vk::Format::eR16G16B16A16Sint;
case gfx::AttributeDataType::UShort:
return vk::Format::eR16Uscaled;
return vk::Format::eR16Uint;
case gfx::AttributeDataType::UShort2:
return vk::Format::eR16G16Uscaled;
return vk::Format::eR16G16Uint;
case gfx::AttributeDataType::UShort3:
return vk::Format::eR16G16B16Uscaled;
return vk::Format::eR16G16B16Uint;
case gfx::AttributeDataType::UShort4:
return vk::Format::eR16G16B16A16Uscaled;
return vk::Format::eR16G16B16A16Uint;
case gfx::AttributeDataType::Int:
return vk::Format::eR32Sint;
case gfx::AttributeDataType::Int2:
@@ -401,7 +401,7 @@ std::size_t PipelineInfo::hash() const {
vertexInputHash);
}
void PipelineInfo::setDynamicValues(const vk::UniqueCommandBuffer& buffer) const {
void PipelineInfo::setDynamicValues(const RendererBackend& backend, const vk::UniqueCommandBuffer& buffer) const {
if (dynamicValues.blendConstants.has_value()) {
buffer->setBlendConstants(dynamicValues.blendConstants.value().data());
}
@@ -412,12 +412,12 @@ void PipelineInfo::setDynamicValues(const vk::UniqueCommandBuffer& buffer) const
buffer->setStencilReference(vk::StencilFaceFlagBits::eFrontAndBack, dynamicValues.stencilRef);
}
if (wideLines) {
if (backend.getDeviceFeatures().wideLines && wideLines) {
buffer->setLineWidth(dynamicValues.lineWidth);
}
}
std::vector<vk::DynamicState> PipelineInfo::getDynamicStates() const {
std::vector<vk::DynamicState> PipelineInfo::getDynamicStates(const RendererBackend& backend) const {
std::vector<vk::DynamicState> dynamicStates;
if (usesBlendConstants()) {
@@ -430,7 +430,7 @@ std::vector<vk::DynamicState> PipelineInfo::getDynamicStates() const {
dynamicStates.push_back(vk::DynamicState::eStencilReference);
}
if (wideLines) {
if (backend.getDeviceFeatures().wideLines && wideLines) {
dynamicStates.push_back(vk::DynamicState::eLineWidth);
}

View File

@@ -70,7 +70,7 @@ void SurfaceRenderableResource::initColor(uint32_t w, uint32_t h) {
}
}
void SurfaceRenderableResource::initSwapchain(uint32_t w, uint32_t h) {
void SurfaceRenderableResource::initSwapchain(uint32_t w, uint32_t h, vk::PresentModeKHR presentMode) {
const auto& physicalDevice = backend.getPhysicalDevice();
const auto& device = backend.getDevice();
@@ -83,7 +83,16 @@ void SurfaceRenderableResource::initSwapchain(uint32_t w, uint32_t h) {
if (formatIt == formats.end()) throw std::runtime_error("No suitable swapchain format found");
// only vk::PresentModeKHR::eFifo (vsync on) is guaranteed
// TODO check for vk::PresentModeKHR::eImmediate when uncapped
if (presentMode != vk::PresentModeKHR::eFifo) {
const std::vector<vk::PresentModeKHR>& presentModes = physicalDevice.getSurfacePresentModesKHR(surface.get());
if (std::find(presentModes.begin(), presentModes.end(), presentMode) == presentModes.end()) {
mbgl::Log::Error(
mbgl::Event::Render,
"Requested PresentModeKHR not available (" + std::to_string(static_cast<int>(presentMode)) + ")");
presentMode = vk::PresentModeKHR::eFifo;
}
}
// pick surface size
const vk::SurfaceCapabilitiesKHR& capabilities = physicalDevice.getSurfaceCapabilitiesKHR(surface.get());
@@ -105,7 +114,7 @@ void SurfaceRenderableResource::initSwapchain(uint32_t w, uint32_t h) {
.setMinImageCount(swapchainImageCount)
.setImageFormat(formatIt->format)
.setImageColorSpace(formatIt->colorSpace)
.setPresentMode(vk::PresentModeKHR::eFifo)
.setPresentMode(presentMode)
.setImageExtent(extent)
.setImageArrayLayers(1)
.setImageUsage(vk::ImageUsageFlagBits::eColorAttachment);
@@ -114,7 +123,7 @@ void SurfaceRenderableResource::initSwapchain(uint32_t w, uint32_t h) {
int32_t presentQueueIndex = backend.getPresentQueueIndex();
if (graphicsQueueIndex != presentQueueIndex) {
// TODO if this scenario is widespred and performance is a problem (shouldn't be the case on most hardware)
// TODO if this scenario is widespread and performance is a problem (shouldn't be the case on most hardware)
// rework to vk::SharingMode::eExclusive + queue ownership
swapchainCreateInfo.setImageSharingMode(vk::SharingMode::eConcurrent);
const std::array<uint32_t, 2> queueIndices = {static_cast<uint32_t>(graphicsQueueIndex),
@@ -124,7 +133,7 @@ void SurfaceRenderableResource::initSwapchain(uint32_t w, uint32_t h) {
swapchainCreateInfo.setImageSharingMode(vk::SharingMode::eExclusive);
}
swapchainCreateInfo.setPreTransform(capabilities.currentTransform);
swapchainCreateInfo.setPreTransform(vk::SurfaceTransformFlagBitsKHR::eIdentity);
swapchainCreateInfo.setClipped(VK_TRUE);
if (capabilities.supportedCompositeAlpha & vk::CompositeAlphaFlagBitsKHR::eInherit) {
@@ -209,6 +218,11 @@ void SurfaceRenderableResource::initDepthStencil() {
backend.setDebugName(depthAllocation->imageView.get(), "SwapchainDepthImageView");
}
void SurfaceRenderableResource::swap() {
auto& context = static_cast<Context&>(backend.getContext());
context.submitFrame();
}
const vk::Image SurfaceRenderableResource::getAcquiredImage() const {
if (surface) {
return swapchainImages[acquiredImageIndex];
@@ -233,8 +247,7 @@ void SurfaceRenderableResource::init(uint32_t w, uint32_t h) {
.setViewType(vk::ImageViewType::e2D)
.setFormat(colorFormat)
.setComponents(vk::ComponentMapping()) // defaults to vk::ComponentSwizzle::eIdentity
.setSubresourceRange(
vk::ImageSubresourceRange(vk::ImageAspectFlagBits::eColor, 0, 1, 0, 1));
.setSubresourceRange({vk::ImageAspectFlagBits::eColor, 0, 1, 0, 1});
for (const auto& image : swapchainImages) {
imageViewCreateInfo.setImage(image);
@@ -267,7 +280,7 @@ void SurfaceRenderableResource::init(uint32_t w, uint32_t h) {
.setSamples(vk::SampleCountFlagBits::e1)
.setLoadOp(vk::AttachmentLoadOp::eClear)
.setStoreOp(vk::AttachmentStoreOp::eDontCare)
.setStencilLoadOp(vk::AttachmentLoadOp::eDontCare)
.setStencilLoadOp(vk::AttachmentLoadOp::eClear)
.setStencilStoreOp(vk::AttachmentStoreOp::eDontCare)
.setInitialLayout(vk::ImageLayout::eUndefined)
.setFinalLayout(vk::ImageLayout::eDepthStencilAttachmentOptimal);
@@ -337,7 +350,7 @@ void SurfaceRenderableResource::recreateSwapchain() {
}
const vk::UniqueFramebuffer& SurfaceRenderableResource::getFramebuffer() const {
return swapchainFramebuffers[backend.getContext<Context&>().getCurrentFrameResourceIndex()];
return swapchainFramebuffers[acquiredImageIndex];
}
} // namespace vulkan

View File

@@ -19,6 +19,7 @@
#include <mbgl/shaders/vulkan/line.hpp>
#include <mbgl/shaders/vulkan/raster.hpp>
#include <mbgl/shaders/vulkan/symbol.hpp>
#include <mbgl/shaders/vulkan/widevector.hpp>
#include <cassert>
#include <string>
@@ -443,13 +444,15 @@ void RendererBackend::initDevice() {
const auto& queues = candidate.getQueueFamilyProperties();
// Use to test on specific GPU type (if multiple)
// if (candidate.getProperties().deviceType != vk::PhysicalDeviceType::eIntegratedGpu) return false;
for (auto i = 0u; i < queues.size(); ++i) {
const auto& queue = queues[i];
if (queue.queueCount == 0) continue;
if (queue.queueFlags & vk::QueueFlagBits::eGraphics) graphicsQueueIndex = i;
if (surface && candidate.getSurfaceSupportKHR(i, surface)) presentQueueIndex = i;
if (graphicsQueueIndex != -1 && (!surface || presentQueueIndex != -1)) break;
@@ -476,9 +479,9 @@ void RendererBackend::initDevice() {
}
}
physicalDeviceProperties = physicalDevice.getProperties();
if (!physicalDevice) throw std::runtime_error("No suitable GPU found");
physicalDeviceProperties = physicalDevice.getProperties();
};
pickPhysicalDevice();
@@ -492,12 +495,15 @@ void RendererBackend::initDevice() {
if (surface && graphicsQueueIndex != presentQueueIndex)
queueCreateInfos.emplace_back(vk::DeviceQueueCreateFlags(), presentQueueIndex, 1, &queuePriority);
const auto& supportedDeviceFeatures = physicalDevice.getFeatures();
vk::PhysicalDeviceFeatures enabledDeviceFeatures;
[[maybe_unused]] const auto& supportedDeviceFeatures = physicalDevice.getFeatures();
physicalDeviceFeatures = vk::PhysicalDeviceFeatures();
// TODO
// - WideLines disabled on Android (20.77% device coverage https://vulkan.gpuinfo.org/listfeaturescore10.php)
// - Rework this to a dynamic toggle based on MLN_TRIANGULATE_FILL_OUTLINES/MLN_ENABLE_POLYLINE_DRAWABLES
#if !defined(__ANDROID__) && !defined(__apple__)
if (supportedDeviceFeatures.wideLines) {
enabledDeviceFeatures.setWideLines(true);
physicalDeviceFeatures.setWideLines(true);
// more wideLines info
// physicalDeviceProperties.limits.lineWidthRange;
@@ -505,12 +511,13 @@ void RendererBackend::initDevice() {
} else {
mbgl::Log::Error(mbgl::Event::Render, "Wide line support not available");
}
#endif
auto createInfo = vk::DeviceCreateInfo()
.setQueueCreateInfos(queueCreateInfos)
.setEnabledExtensionCount(static_cast<uint32_t>(extensions.size()))
.setPpEnabledExtensionNames(extensions.data())
.setPEnabledFeatures(&enabledDeviceFeatures);
.setPEnabledFeatures(&physicalDeviceFeatures);
// this is not needed for newer implementations
createInfo.setPEnabledLayerNames(layers);
@@ -528,11 +535,12 @@ void RendererBackend::initSwapchain() {
const auto& renderable = getDefaultRenderable();
auto& renderableResource = renderable.getResource<SurfaceRenderableResource>();
const auto& size = renderable.getSize();
renderableResource.init(size.width, size.height);
if (renderableResource.getPlatformSurface()) {
maxFrames = renderableResource.getImageCount();
}
// use triple buffering if rendering to a surface
// no buffering when using headless
maxFrames = renderableResource.getPlatformSurface() ? 3 : 1;
renderableResource.init(size.width, size.height);
}
void RendererBackend::initCommandPool() {

View File

@@ -10,19 +10,22 @@ namespace mbgl {
namespace vulkan {
bool ImageAllocation::create(const VmaAllocationCreateInfo& allocInfo, const vk::ImageCreateInfo& imageInfo) {
VkImage image_;
VkResult result = vmaCreateImage(
allocator, reinterpret_cast<const VkImageCreateInfo*>(&imageInfo), &allocInfo, &image, &allocation, nullptr);
allocator, reinterpret_cast<const VkImageCreateInfo*>(&imageInfo), &allocInfo, &image_, &allocation, nullptr);
if (result != VK_SUCCESS) {
return false;
}
image = vk::Image(image_);
return true;
}
void ImageAllocation::destroy() {
imageView.reset();
vmaDestroyImage(allocator, image, allocation);
vmaDestroyImage(allocator, VkImage(image), allocation);
image = nullptr;
}
void ImageAllocation::setName([[maybe_unused]] const std::string& name) const {