Implement Android surface pre-rotation for Vulkan (#2955)

This commit is contained in:
Adrian Cojocaru
2024-11-20 15:17:39 +02:00
committed by GitHub
parent 5642b1ffa4
commit d282b3ba6b
24 changed files with 195 additions and 55 deletions

View File

@@ -51,6 +51,9 @@ static_assert(sizeof(GlobalPaintParamsUBO) == 3 * 16);
enum {
idGlobalPaintParamsUBO,
#if MLN_RENDER_BACKEND_VULKAN
PlatformParamsUBO,
#endif
globalUBOCount
};

View File

@@ -25,7 +25,7 @@ layout(set = DRAWABLE_UBO_SET_INDEX, binding = 0) uniform BackgroundDrawableUBO
void main() {
gl_Position = drawable.matrix * vec4(in_position, 0.0, 1.0);
gl_Position.y *= -1.0;
applySurfaceTransform();
}
)";
@@ -101,7 +101,7 @@ void main() {
in_position);
gl_Position = drawable.matrix * vec4(in_position, 0.0, 1.0);
gl_Position.y *= -1.0;
applySurfaceTransform();
}
)";

View File

@@ -150,7 +150,7 @@ void main() {
gl_Position.xy += scaled_extrude * (radius + stroke_width) * factor;
}
gl_Position.y *= -1.0;
applySurfaceTransform();
// This is a minimum blur distance that serves as a faux-antialiasing for
// the circle. since blur is a ratio of the circle's size and the intent is

View File

@@ -8,7 +8,7 @@ namespace mbgl {
namespace shaders {
struct ClipUBO {
matf4 matrix;
mat4 matrix;
std::uint32_t stencil_ref;
};

View File

@@ -44,7 +44,7 @@ void main() {
gl_Position = drawable.matrix * vec4(in_position, 0.0, 1.0);
gl_Position.xy += (in_extrude + in_shift) * drawable.extrude_scale * gl_Position.w * collision_perspective_ratio;
gl_Position.y *= -1.0;
applySurfaceTransform();
frag_placed = in_placed.x;
frag_notUsed = in_placed.y;
@@ -128,7 +128,7 @@ void main() {
float padding_factor = 1.2; // Pad the vertices slightly to make room for anti-alias blur
gl_Position = drawable.matrix * vec4(in_position, 0.0, 1.0);
gl_Position.xy += in_extrude * drawable.extrude_scale * padding_factor * gl_Position.w * collision_perspective_ratio;
gl_Position.y *= -1.0;
applySurfaceTransform();
frag_placed = in_placed.x;
frag_notUsed = in_placed.y;

View File

@@ -84,6 +84,20 @@ layout(set = GLOBAL_SET_INDEX, binding = 0) uniform GlobalPaintParamsUBO {
float pad1;
} global;
#ifdef USE_SURFACE_TRANSFORM
layout(set = GLOBAL_SET_INDEX, binding = 1) uniform PlatformParamsUBO {
mat2 rotation;
} platform;
#endif
void applySurfaceTransform() {
#ifdef USE_SURFACE_TRANSFORM
gl_Position.xy = platform.rotation * gl_Position.xy;
#endif
gl_Position.y *= -1.0;
}
)";
static constexpr auto fragment = R"(
@@ -130,7 +144,7 @@ layout(set = DRAWABLE_UBO_SET_INDEX, binding = 0) uniform CommonUBO {
void main() {
gl_Position = ubo.matrix * vec4(in_position, 0, 1);
gl_Position.y *= -1.0;
applySurfaceTransform();
}
)";
@@ -170,7 +184,7 @@ layout(location = 0) out vec2 frag_uv;
void main() {
gl_Position = ubo.matrix * vec4(in_position, 0, 1);
gl_Position.y *= -1.0;
applySurfaceTransform();
frag_uv = in_texcoord;
}

View File

@@ -31,7 +31,7 @@ layout(location = 0) out vec2 frag_uv;
void main() {
gl_Position = debug.matrix * vec4(in_position * debug.overlay_scale, 0, 1);
gl_Position.y *= -1.0;
applySurfaceTransform();
// This vertex shader expects a EXTENT x EXTENT quad,
// The UV co-ordinates for the overlay texture can be calculated using that knowledge

View File

@@ -55,7 +55,7 @@ void main() {
#endif
gl_Position = drawable.matrix * vec4(in_position, 0.0, 1.0);
gl_Position.y *= -1.0;
applySurfaceTransform();
}
)";
@@ -150,7 +150,7 @@ void main() {
#endif
gl_Position = drawable.matrix * vec4(in_position, 0.0, 1.0);
gl_Position.y *= -1.0;
applySurfaceTransform();
frag_position = (gl_Position.xy / gl_Position.w + 1.0) / 2.0 * global.world_size;
}
@@ -309,7 +309,7 @@ void main() {
frag_pos_b = get_pattern_pos(drawable.pixel_coord_upper, drawable.pixel_coord_lower, toScale * display_size_b, tileZoomRatio, in_position),
gl_Position = drawable.matrix * vec4(in_position, 0.0, 1.0);
gl_Position.y *= -1.0;
applySurfaceTransform();
}
)";
@@ -502,14 +502,12 @@ void main() {
const vec2 display_size_b = vec2((pattern_br_b.x - pattern_tl_b.x) / pixelRatio, (pattern_br_b.y - pattern_tl_b.y) / pixelRatio);
const vec2 position2 = in_position.xy;
vec4 position = drawable.matrix * vec4(in_position, 0.0, 1.0);
position.y *= -1.0;
gl_Position = drawable.matrix * vec4(in_position, 0.0, 1.0);
applySurfaceTransform();
frag_pos_a = get_pattern_pos(drawable.pixel_coord_upper, drawable.pixel_coord_lower, fromScale * display_size_a, tileZoomRatio, position2),
frag_pos_b = get_pattern_pos(drawable.pixel_coord_upper, drawable.pixel_coord_lower, toScale * display_size_b, tileZoomRatio, position2),
frag_pos = (position.xy / position.w + 1.0) / 2.0 * global.world_size;
gl_Position = position;
frag_pos = (gl_Position.xy / gl_Position.w + 1.0) / 2.0 * global.world_size;
}
)";
@@ -655,7 +653,7 @@ void main() {
vec4 projected_extrude = drawable.matrix * vec4(dist / drawable.ratio, 0.0, 0.0);
gl_Position = drawable.matrix * vec4(pos, 0.0, 1.0) + projected_extrude;
gl_Position.y *= -1.0;
applySurfaceTransform();
// calculate how much the perspective view squishes or stretches the extrude
float extrude_length_without_perspective = length(dist);
@@ -788,7 +786,7 @@ void main() {
const float z = t != 0.0 ? height : base;
gl_Position = drawable.matrix * vec4(in_position, z, 1.0);
gl_Position.y *= -1.0;
applySurfaceTransform();
#if defined(OVERDRAW_INSPECTOR)
frag_color = vec4(1.0);
@@ -944,7 +942,7 @@ void main() {
const float z = t != 0.0 ? height : base;
gl_Position = drawable.matrix * vec4(in_position, z, 1.0);
gl_Position.y *= -1.0;
applySurfaceTransform();
#if defined(OVERDRAW_INSPECTOR)
frag_color = vec4(1.0);

View File

@@ -98,7 +98,7 @@ void main() {
// multiply a_pos by 0.5, since we had it * 2 in order to sneak
// in extrusion data
gl_Position = drawable.matrix * vec4(floor(in_position * 0.5) + scaled_extrude, 0, 1);
gl_Position.y *= -1.0;
applySurfaceTransform();
frag_weight = weight;
frag_extrude = extrude;
@@ -162,7 +162,7 @@ layout(location = 0) out vec2 frag_position;
void main() {
gl_Position = props.matrix * vec4(in_position * global.world_size, 0, 1);
gl_Position.y *= -1.0;
applySurfaceTransform();
frag_position = in_position;
}

View File

@@ -33,7 +33,7 @@ layout(location = 0) out vec2 frag_position;
void main() {
gl_Position = drawable.matrix * vec4(in_position, 0.0, 1.0);
gl_Position.y *= -1.0;
applySurfaceTransform();
const vec2 epsilon = vec2(1.0) / drawable.dimension;
const float scale = (drawable.dimension.x - 2.0) / drawable.dimension.x;
@@ -149,7 +149,7 @@ layout(location = 0) out vec2 frag_position;
void main() {
gl_Position = drawable.matrix * vec4(in_position, 0.0, 1.0);
gl_Position.y *= -1.0;
applySurfaceTransform();
frag_position = vec2(in_texture_position) / 8192.0;
frag_position.y = 1.0 - frag_position.y; // TODO check this. prepare should ignore the flip

View File

@@ -155,7 +155,7 @@ void main() {
vec4 projected_extrude = drawable.matrix * vec4(dist / drawable.ratio, 0.0, 0.0);
gl_Position = drawable.matrix * vec4(pos + offset2 / drawable.ratio, 0.0, 1.0) + projected_extrude;
gl_Position.y *= -1.0;
applySurfaceTransform();
// calculate how much the perspective view squishes or stretches the extrude
float extrude_length_without_perspective = length(dist);
@@ -376,7 +376,7 @@ void main() {
vec4 projected_extrude = drawable.matrix * vec4(dist / drawable.ratio, 0.0, 0.0);
gl_Position = drawable.matrix * vec4(pos + offset2 / drawable.ratio, 0.0, 1.0) + projected_extrude;
gl_Position.y *= -1.0;
applySurfaceTransform();
// calculate how much the perspective view squishes or stretches the extrude
float extrude_length_without_perspective = length(dist);
@@ -626,7 +626,7 @@ void main() {
vec4 projected_extrude = drawable.matrix * vec4(dist / drawable.ratio, 0.0, 0.0);
gl_Position = drawable.matrix * vec4(pos + offset2 / drawable.ratio, 0.0, 1.0) + projected_extrude;
gl_Position.y *= -1.0;
applySurfaceTransform();
// calculate how much the perspective view squishes or stretches the extrude
float extrude_length_without_perspective = length(dist);
@@ -941,7 +941,7 @@ void main() {
vec4 projected_extrude = drawable.matrix * vec4(dist / drawable.ratio, 0.0, 0.0);
gl_Position = drawable.matrix * vec4(pos + offset2 / drawable.ratio, 0.0, 1.0) + projected_extrude;
gl_Position.y *= -1.0;
applySurfaceTransform();
// calculate how much the perspective view squishes or stretches the extrude
float extrude_length_without_perspective = length(dist);

View File

@@ -44,7 +44,7 @@ layout(location = 1) out vec2 frag_position1;
void main() {
gl_Position = drawable.matrix * vec4(in_position, 0, 1);
gl_Position.y *= -1.0;
applySurfaceTransform();
// We are using Int16 for texture position coordinates to give us enough precision for
// fractional coordinates. We use 8192 to scale the texture coordinates in the buffer

View File

@@ -117,7 +117,7 @@ void main() {
const vec2 pos0 = projected_pos.xy / projected_pos.w;
const vec2 posOffset = a_offset * max(a_minFontScale, fontScale) / 32.0 + a_pxoffset / 16.0;
gl_Position = drawable.coord_matrix * vec4(pos0 + rotation_matrix * posOffset, 0.0, 1.0);
gl_Position.y *= -1.0;
applySurfaceTransform();
const vec2 raw_fade_opacity = unpack_opacity(in_fade_opacity);
const float fade_change = raw_fade_opacity[1] > 0.5 ? global.symbol_fade_change : -global.symbol_fade_change;
@@ -339,8 +339,8 @@ void main() {
const vec2 pos_rot = a_offset / 32.0 * fontScale + a_pxoffset;
const vec2 pos0 = projected_pos.xy / projected_pos.w + rotation_matrix * pos_rot;
gl_Position = drawable.coord_matrix * vec4(pos0, 0.0, 1.0);
gl_Position.y *= -1.0;
applySurfaceTransform();
const vec2 raw_fade_opacity = unpack_opacity(in_fade_opacity);
const float fade_change = raw_fade_opacity[1] > 0.5 ? global.symbol_fade_change : -global.symbol_fade_change;
@@ -640,7 +640,7 @@ void main() {
const vec2 pos_rot = a_offset / 32.0 * fontScale;
const vec2 pos0 = projected_pos.xy / projected_pos.w + rotation_matrix * pos_rot;
gl_Position = drawable.coord_matrix * vec4(pos0, 0.0, 1.0);
gl_Position.y *= -1.0;
applySurfaceTransform();
const vec2 raw_fade_opacity = unpack_opacity(in_fade_opacity);
const float fade_change = raw_fade_opacity[1] > 0.5 ? global.symbol_fade_change : -global.symbol_fade_change;
@@ -862,7 +862,7 @@ void main() {
}
gl_Position = position;
gl_Position.y *= -1.0;
applySurfaceTransform();
frag_tex = in_tex;
}

View File

@@ -197,6 +197,7 @@ private:
uint8_t frameResourceIndex = 0;
std::vector<FrameResources> frameResources;
bool surfaceUpdateRequested{false};
int32_t currentFrameCount{0};
struct {
gfx::ShaderProgramBasePtr shader;

View File

@@ -58,12 +58,22 @@ public:
void setAcquiredImageIndex(uint32_t index) { acquiredImageIndex = index; };
const vk::Image getAcquiredImage() const;
bool hasSurfaceTransformSupport() const;
bool didSurfaceTransformUpdate() const;
// rotation needed to align framebuffer contents with device surface
float getRotation();
void setSurfaceTransformPollingInterval(int32_t value) { surfaceTransformPollingInterval = value; }
int32_t getSurfaceTransformPollingInterval() const { return surfaceTransformPollingInterval; }
void init(uint32_t w, uint32_t h);
void recreateSwapchain();
protected:
vk::UniqueSurfaceKHR surface;
vk::UniqueSwapchainKHR swapchain;
vk::SurfaceCapabilitiesKHR capabilities;
uint32_t acquiredImageIndex{0};
@@ -77,6 +87,18 @@ protected:
UniqueImageAllocation depthAllocation;
vk::Format depthFormat{vk::Format::eUndefined};
int32_t surfaceTransformPollingInterval{-1};
};
class Renderable : public gfx::Renderable {
protected:
Renderable(const Size size_, std::unique_ptr<gfx::RenderableResource> resource_)
: gfx::Renderable(size_, std::move(resource_)) {}
virtual ~Renderable() override = default;
public:
void setSize(const Size& size_) { size = size_; }
};
} // namespace vulkan

View File

@@ -25,6 +25,11 @@ public:
auto& backendImpl = static_cast<AndroidVulkanRendererBackend&>(backend);
const vk::AndroidSurfaceCreateInfoKHR createInfo({}, backendImpl.getWindow());
surface = backendImpl.getInstance()->createAndroidSurfaceKHRUnique(createInfo);
const int apiLevel = android_get_device_api_level();
if (apiLevel < __ANDROID_API_Q__) {
setSurfaceTransformPollingInterval(30);
}
}
void bind() override {}
@@ -42,7 +47,7 @@ private:
AndroidVulkanRendererBackend::AndroidVulkanRendererBackend(ANativeWindow* window_)
: vulkan::RendererBackend(gfx::ContextMode::Unique),
mbgl::gfx::Renderable({64, 64}, std::make_unique<AndroidVulkanRenderableResource>(*this)),
vulkan::Renderable({64, 64}, std::make_unique<AndroidVulkanRenderableResource>(*this)),
window(window_) {
init();
}

View File

@@ -1,6 +1,6 @@
#pragma once
#include <mbgl/gfx/renderable.hpp>
#include <mbgl/vulkan/renderable_resource.hpp>
#include <mbgl/vulkan/renderer_backend.hpp>
#include "android_renderer_backend.hpp"
#include <android/native_window.h>
@@ -10,7 +10,7 @@ namespace android {
class AndroidVulkanRendererBackend : public AndroidRendererBackend,
public vulkan::RendererBackend,
public mbgl::gfx::Renderable {
public vulkan::Renderable {
public:
AndroidVulkanRendererBackend(ANativeWindow*);
~AndroidVulkanRendererBackend() override;

View File

@@ -36,7 +36,7 @@ public:
GLFWVulkanBackend::GLFWVulkanBackend(GLFWwindow* window_, const bool)
: mbgl::vulkan::RendererBackend(mbgl::gfx::ContextMode::Unique),
mbgl::gfx::Renderable(
mbgl::vulkan::Renderable(
[window_] {
int fbWidth;
int fbHeight;

View File

@@ -2,12 +2,14 @@
#include "glfw_backend.hpp"
#include <mbgl/gfx/renderable.hpp>
#include <mbgl/vulkan/renderable_resource.hpp>
#include <mbgl/vulkan/renderer_backend.hpp>
struct GLFWwindow;
class GLFWVulkanBackend final : public GLFWBackend, public mbgl::vulkan::RendererBackend, public mbgl::gfx::Renderable {
class GLFWVulkanBackend final : public GLFWBackend,
public mbgl::vulkan::RendererBackend,
public mbgl::vulkan::Renderable {
public:
GLFWVulkanBackend(GLFWwindow*, bool capFrameRate);
~GLFWVulkanBackend() override;

View File

@@ -229,7 +229,7 @@ void PaintParameters::renderTileClippingMasks(const RenderTiles& renderTiles) {
tileUBOs.reserve(count);
}
tileUBOs.emplace_back(shaders::ClipUBO{util::cast<float>(matrixForTile(tileID)), stencilID});
tileUBOs.emplace_back(shaders::ClipUBO{matrixForTile(tileID), stencilID});
}
if (!tileUBOs.empty()) {

View File

@@ -41,6 +41,12 @@ ShaderProgram::ShaderProgram(shaders::BuiltIn shaderID,
for (const auto& define : additionalDefines) {
defineStr += "#define " + define.first + " " + define.second + "\n";
}
const auto& renderableResource = backend.getDefaultRenderable().getResource<SurfaceRenderableResource>();
if (renderableResource.hasSurfaceTransformSupport()) {
defineStr += "#define USE_SURFACE_TRANSFORM";
}
observer.onPreCompileShader(shaderID, gfx::Backend::Type::Metal, defineStr);
constexpr auto targetClientVersion = glslang::EShTargetVulkan_1_0;

View File

@@ -189,6 +189,20 @@ void Context::beginFrame() {
auto& renderableResource = backend.getDefaultRenderable().getResource<SurfaceRenderableResource>();
const auto& platformSurface = renderableResource.getPlatformSurface();
// poll for surface transform updates if enabled
const int32_t surfaceTransformPollingInterval = renderableResource.getSurfaceTransformPollingInterval();
if (surfaceTransformPollingInterval >= 0 && !surfaceUpdateRequested) {
if (currentFrameCount > surfaceTransformPollingInterval) {
if (renderableResource.didSurfaceTransformUpdate()) {
requestSurfaceUpdate();
}
currentFrameCount = 0;
} else {
++currentFrameCount;
}
}
if (platformSurface && surfaceUpdateRequested) {
renderableResource.recreateSwapchain();
@@ -201,6 +215,14 @@ void Context::beginFrame() {
// sync resources with swapchain
frameResourceIndex = 0;
surfaceUpdateRequested = false;
// update renderable size
if (renderableResource.hasSurfaceTransformSupport()) {
const auto& extent = renderableResource.getExtent();
auto& renderable = static_cast<Renderable&>(backend.getDefaultRenderable());
renderable.setSize({extent.width, extent.height});
}
}
backend.startFrameCapture();
@@ -221,13 +243,9 @@ void Context::beginFrame() {
if (acquireImageResult.result == vk::Result::eSuccess) {
renderableResource.setAcquiredImageIndex(acquireImageResult.value);
} else if (acquireImageResult.result == vk::Result::eSuboptimalKHR) {
renderableResource.setAcquiredImageIndex(acquireImageResult.value);
// TODO implement pre-rotation transform for surface orientation
#if defined(__APPLE__)
requestSurfaceUpdate();
beginFrame();
return;
#endif
}
} catch (const vk::OutOfDateKHRError& e) {
@@ -289,10 +307,7 @@ void Context::submitFrame() {
const auto& presentQueue = backend.getPresentQueue();
const vk::Result presentResult = presentQueue.presentKHR(presentInfo);
if (presentResult == vk::Result::eSuboptimalKHR) {
// TODO implement pre-rotation transform for surface orientation
#if defined(__APPLE__)
requestSurfaceUpdate();
#endif
}
} catch (const vk::OutOfDateKHRError& e) {
requestSurfaceUpdate();
@@ -409,7 +424,22 @@ void Context::clearStencilBuffer(int32_t) {
void Context::bindGlobalUniformBuffers(gfx::RenderPass& renderPass) const noexcept {
auto& renderPassImpl = static_cast<RenderPass&>(renderPass);
const_cast<Context*>(this)->globalUniformBuffers.bindDescriptorSets(renderPassImpl.getEncoder());
auto& context = const_cast<Context&>(*this);
auto& renderableResource = renderPassImpl.getDescriptor().renderable.getResource<SurfaceRenderableResource>();
if (renderableResource.hasSurfaceTransformSupport()) {
float surfaceRotation = renderableResource.getRotation();
struct alignas(16) {
alignas(16) std::array<float, 2> rotation0;
alignas(16) std::array<float, 2> rotation1;
} data;
data = {{cosf(surfaceRotation), -sinf(surfaceRotation)}, {sinf(surfaceRotation), cosf(surfaceRotation)}};
context.globalUniformBuffers.createOrUpdate(shaders::PlatformParamsUBO, &data, sizeof(data), context);
}
context.globalUniformBuffers.bindDescriptorSets(renderPassImpl.getEncoder());
}
bool Context::renderTileClippingMasks(gfx::RenderPass& renderPass,
@@ -489,15 +519,23 @@ bool Context::renderTileClippingMasks(gfx::RenderPass& renderPass,
commandBuffer->bindVertexBuffers(0, vertexBuffers, offset);
commandBuffer->bindIndexBuffer(clipping.indexBuffer->getVulkanBuffer(), 0, vk::IndexType::eUint16);
auto& renderableResource = renderPassImpl.getDescriptor().renderable.getResource<SurfaceRenderableResource>();
const float rad = renderableResource.getRotation();
const mat4 rotationMat = {cos(rad), -sin(rad), 0, 0, sin(rad), cos(rad), 0, 0, 0, 0, 1, 0, 0, 0, 0, 1};
for (const auto& tileInfo : tileUBOs) {
commandBuffer->setStencilReference(vk::StencilFaceFlagBits::eFrontAndBack, tileInfo.stencil_ref);
mat4 matrix;
matrix::multiply(matrix, rotationMat, tileInfo.matrix);
const auto& matrixf = util::cast<float>(matrix);
commandBuffer->pushConstants(
getPushConstantPipelineLayout().get(),
vk::ShaderStageFlags() | vk::ShaderStageFlagBits::eVertex | vk::ShaderStageFlagBits::eFragment,
0,
sizeof(tileInfo.matrix),
&tileInfo.matrix);
sizeof(matrixf),
&matrixf);
commandBuffer->drawIndexed(clipping.indexCount, 1, 0, 0, 0);
}

View File

@@ -1,6 +1,7 @@
#include <mbgl/vulkan/renderable_resource.hpp>
#include <mbgl/vulkan/context.hpp>
#include <mbgl/util/logging.hpp>
#include <mbgl/util/constants.hpp>
namespace mbgl {
namespace vulkan {
@@ -95,7 +96,7 @@ void SurfaceRenderableResource::initSwapchain(uint32_t w, uint32_t h, vk::Presen
}
// pick surface size
const vk::SurfaceCapabilitiesKHR& capabilities = physicalDevice.getSurfaceCapabilitiesKHR(surface.get());
capabilities = physicalDevice.getSurfaceCapabilitiesKHR(surface.get());
if (capabilities.currentExtent.width != std::numeric_limits<uint32_t>::max()) {
extent = capabilities.currentExtent;
@@ -105,6 +106,13 @@ void SurfaceRenderableResource::initSwapchain(uint32_t w, uint32_t h, vk::Presen
extent.height = std::min(std::max(h, capabilities.minImageExtent.height), capabilities.maxImageExtent.height);
}
if (hasSurfaceTransformSupport()) {
if (capabilities.currentTransform & vk::SurfaceTransformFlagBitsKHR::eRotate90 ||
capabilities.currentTransform & vk::SurfaceTransformFlagBitsKHR::eRotate270) {
std::swap(extent.width, extent.height);
}
}
uint32_t swapchainImageCount = capabilities.minImageCount + 1;
// check surface limits (0 is unlimited)
if (capabilities.maxImageCount > 0) swapchainImageCount = std::min(swapchainImageCount, capabilities.maxImageCount);
@@ -133,7 +141,8 @@ void SurfaceRenderableResource::initSwapchain(uint32_t w, uint32_t h, vk::Presen
swapchainCreateInfo.setImageSharingMode(vk::SharingMode::eExclusive);
}
swapchainCreateInfo.setPreTransform(vk::SurfaceTransformFlagBitsKHR::eIdentity);
swapchainCreateInfo.setPreTransform(hasSurfaceTransformSupport() ? capabilities.currentTransform
: vk::SurfaceTransformFlagBitsKHR::eIdentity);
swapchainCreateInfo.setClipped(VK_TRUE);
if (capabilities.supportedCompositeAlpha & vk::CompositeAlphaFlagBitsKHR::eInherit) {
@@ -143,7 +152,7 @@ void SurfaceRenderableResource::initSwapchain(uint32_t w, uint32_t h, vk::Presen
}
// update this when recreating
swapchainCreateInfo.setOldSwapchain(vk::SwapchainKHR(swapchain.get()));
swapchainCreateInfo.setOldSwapchain(swapchain.get());
swapchain = device->createSwapchainKHRUnique(swapchainCreateInfo);
swapchainImages = device->getSwapchainImagesKHR(swapchain.get());
@@ -231,6 +240,41 @@ const vk::Image SurfaceRenderableResource::getAcquiredImage() const {
return colorAllocations[acquiredImageIndex]->image;
}
bool SurfaceRenderableResource::hasSurfaceTransformSupport() const {
#ifdef __ANDROID__
return surface && capabilities.supportedTransforms != vk::SurfaceTransformFlagBitsKHR::eIdentity;
#else
return false;
#endif
}
bool SurfaceRenderableResource::didSurfaceTransformUpdate() const {
const auto& physicalDevice = backend.getPhysicalDevice();
const auto& updatedCapabilities = physicalDevice.getSurfaceCapabilitiesKHR(surface.get());
return capabilities.currentTransform != updatedCapabilities.currentTransform;
}
float SurfaceRenderableResource::getRotation() {
switch (capabilities.currentTransform) {
default:
case vk::SurfaceTransformFlagBitsKHR::eIdentity:
return 0.0f * M_PI / 180.0f;
case vk::SurfaceTransformFlagBitsKHR::eRotate90:
case vk::SurfaceTransformFlagBitsKHR::eHorizontalMirrorRotate90:
return 90.0f * M_PI / 180.0f;
case vk::SurfaceTransformFlagBitsKHR::eRotate180:
case vk::SurfaceTransformFlagBitsKHR::eHorizontalMirrorRotate180:
return 180.0f * M_PI / 180.0f;
case vk::SurfaceTransformFlagBitsKHR::eRotate270:
case vk::SurfaceTransformFlagBitsKHR::eHorizontalMirrorRotate270:
return 270.0f * M_PI / 180.0f;
}
}
void SurfaceRenderableResource::init(uint32_t w, uint32_t h) {
if (surface) {
initSwapchain(w, h);

View File

@@ -557,7 +557,7 @@ void RendererBackend::initDevice() {
}
void RendererBackend::initSwapchain() {
const auto& renderable = getDefaultRenderable();
auto& renderable = getDefaultRenderable();
auto& renderableResource = renderable.getResource<SurfaceRenderableResource>();
const auto& size = renderable.getSize();
@@ -566,6 +566,13 @@ void RendererBackend::initSwapchain() {
maxFrames = renderableResource.getPlatformSurface() ? 3 : 1;
renderableResource.init(size.width, size.height);
if (renderableResource.hasSurfaceTransformSupport()) {
auto& renderableImpl = static_cast<Renderable&>(renderable);
const auto& extent = renderableResource.getExtent();
renderableImpl.setSize({extent.width, extent.height});
}
}
void RendererBackend::initCommandPool() {