Handle device orientation with vulkan pre-rotation

This commit is contained in:
Benau 2022-03-26 00:19:09 +08:00
parent 3d92730a82
commit bed91e67a0
3 changed files with 94 additions and 8 deletions

View File

@ -314,6 +314,10 @@ namespace GE
video::ITexture* getWhiteTexture() const { return m_white_texture; }
video::ITexture* getTransparentTexture() const
{ return m_transparent_texture; }
void getRotatedRect2D(VkRect2D* rect);
void getRotatedViewport(VkViewport* vp);
const core::matrix4& getPreRotationMatrix()
{ return m_pre_rotation_matrix; }
private:
struct SwapChainSupportDetails
{
@ -429,6 +433,7 @@ namespace GE
video::SColor m_clear_color;
core::rect<s32> m_clip;
core::rect<s32> m_viewport;
core::matrix4 m_pre_rotation_matrix;
video::ITexture* m_white_texture;
video::ITexture* m_transparent_texture;
@ -450,6 +455,7 @@ namespace GE
void createRenderPass();
void createFramebuffers();
void createUnicolorTextures();
void initPreRotationMatrix();
std::string getVulkanVersionString() const;
std::string getDriverVersionString() const;
};

View File

@ -473,6 +473,7 @@ void GEVulkan2dRenderer::render()
vp.height = g_vk->getViewPort().getHeight();
vp.minDepth = 0;
vp.maxDepth = 1.0f;
g_vk->getRotatedViewport(&vp);
vkCmdSetViewport(g_vk->getCurrentCommandBuffer(), 0, 1, &vp);
if (GEVulkanFeatures::supportsBindTexturesAtOnce())
@ -506,6 +507,7 @@ void GEVulkan2dRenderer::render()
scissor.offset.y = clip.UpperLeftCorner.Y;
scissor.extent.width = clip.getWidth();
scissor.extent.height = clip.getHeight();
g_vk->getRotatedRect2D(&scissor);
vkCmdSetScissor(g_vk->getCurrentCommandBuffer(), 0, 1, &scissor);
vkCmdDrawIndexed(g_vk->getCurrentCommandBuffer(), idx_count, 1,
@ -532,6 +534,7 @@ void GEVulkan2dRenderer::render()
scissor.offset.y = clip.UpperLeftCorner.Y;
scissor.extent.width = clip.getWidth();
scissor.extent.height = clip.getHeight();
g_vk->getRotatedRect2D(&scissor);
vkCmdSetScissor(g_vk->getCurrentCommandBuffer(), 0, 1, &scissor);
vkCmdDrawIndexed(g_vk->getCurrentCommandBuffer(), idx_count, 1,
@ -576,6 +579,9 @@ void GEVulkan2dRenderer::addVerticesIndices(irr::video::S3DVertex* vertices,
vertex.Pos.Y / g_vk->getCurrentRenderTargetSize().Height);
t.pos = t.pos * 2.0f;
t.pos -= 1.0f;
core::vector3df position = core::vector3df(t.pos.X, t.pos.Y, 0);
g_vk->getPreRotationMatrix().transformVect(position);
t.pos = core::vector2df(position.X, position.Y);
t.color = vertex.Color;
t.uv = vertex.TCoords;
t.sampler_idx = sampler_idx;

View File

@ -461,6 +461,7 @@ GEVulkanDriver::GEVulkanDriver(const SIrrlichtCreationParameters& params,
m_clear_color = video::SColor(0);
m_white_texture = NULL;
m_transparent_texture = NULL;
m_pre_rotation_matrix = core::matrix4(core::matrix4::EM4CONST_IDENTITY);
createInstance(window);
@ -970,12 +971,25 @@ found_mode:
create_info.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
}
create_info.preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
create_info.preTransform = m_surface_capabilities.currentTransform;
create_info.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
create_info.presentMode = present_mode;
create_info.clipped = VK_TRUE;
create_info.oldSwapchain = VK_NULL_HANDLE;
m_swap_chain_extent = image_extent;
ScreenSize.Width = m_swap_chain_extent.width;
ScreenSize.Height = m_swap_chain_extent.height;
m_clip = getFullscreenClip();
setViewPort(core::recti(0, 0, ScreenSize.Width, ScreenSize.Height));
initPreRotationMatrix();
if ((m_surface_capabilities.currentTransform & VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR) != 0 ||
(m_surface_capabilities.currentTransform & VK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR) != 0)
{
std::swap(create_info.imageExtent.width, create_info.imageExtent.height);
std::swap(m_swap_chain_extent.width, m_swap_chain_extent.height);
}
VkResult result = vkCreateSwapchainKHR(m_vk->device, &create_info, NULL,
&m_vk->swap_chain);
@ -988,12 +1002,6 @@ found_mode:
&m_vk->swap_chain_images[0]);
m_swap_chain_image_format = surface_format.format;
m_swap_chain_extent = image_extent;
ScreenSize.Width = m_swap_chain_extent.width;
ScreenSize.Height = m_swap_chain_extent.height;
m_clip = getFullscreenClip();
setViewPort(core::recti(0, 0, ScreenSize.Width, ScreenSize.Height));
for (unsigned int i = 0; i < m_vk->swap_chain_images.size(); i++)
{
VkImageViewCreateInfo create_info = {};
@ -1749,7 +1757,73 @@ void GEVulkanDriver::setViewPort(const core::rect<s32>& area)
vp.clipAgainst(rendert);
if (vp.getHeight() > 0 && vp.getWidth() > 0)
m_viewport = vp;
}
} // setViewPort
// ----------------------------------------------------------------------------
void GEVulkanDriver::getRotatedRect2D(VkRect2D* rect)
{
// https://developer.android.com/games/optimize/vulkan-prerotation
if ((m_surface_capabilities.currentTransform & VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR) != 0)
{
VkRect2D ret =
{
(int)(m_swap_chain_extent.width - rect->extent.height - rect->offset.y),
rect->offset.x,
rect->extent.height,
rect->extent.width
};
*rect = ret;
}
else if ((m_surface_capabilities.currentTransform & VK_SURFACE_TRANSFORM_ROTATE_180_BIT_KHR) != 0)
{
VkRect2D ret =
{
(int)(m_swap_chain_extent.width - rect->extent.width - rect->offset.x),
(int)(m_swap_chain_extent.height - rect->extent.height - rect->offset.y),
rect->extent.width,
rect->extent.height
};
*rect = ret;
}
else if ((m_surface_capabilities.currentTransform & VK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR) != 0)
{
VkRect2D ret =
{
rect->offset.y,
(int)(m_swap_chain_extent.height - rect->extent.width - rect->offset.x),
rect->extent.height,
rect->extent.width
};
*rect = ret;
}
} // getRotatedRect2D
// ----------------------------------------------------------------------------
void GEVulkanDriver::getRotatedViewport(VkViewport* vp)
{
VkRect2D rect;
rect.offset.x = vp->x;
rect.offset.y = vp->y;
rect.extent.width = vp->width;
rect.extent.height = vp->height;
getRotatedRect2D(&rect);
vp->x = rect.offset.x;
vp->y = rect.offset.y;
vp->width = rect.extent.width;
vp->height = rect.extent.height;
} // getRotatedViewport
// ----------------------------------------------------------------------------
void GEVulkanDriver::initPreRotationMatrix()
{
const double pi = 3.14159265358979323846;
if ((m_surface_capabilities.currentTransform & VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR) != 0)
m_pre_rotation_matrix.setRotationAxisRadians(90.0 * pi / 180., core::vector3df(0.0f, 0.0f, 1.0f));
else if ((m_surface_capabilities.currentTransform & VK_SURFACE_TRANSFORM_ROTATE_180_BIT_KHR) != 0)
m_pre_rotation_matrix.setRotationAxisRadians(180.0 * pi / 180., core::vector3df(0.0f, 0.0f, 1.0f));
else if ((m_surface_capabilities.currentTransform & VK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR) != 0)
m_pre_rotation_matrix.setRotationAxisRadians(270.0 * pi / 180., core::vector3df(0.0f, 0.0f, 1.0f));
} // initPreRotationMatrix
}