fake negative x/y viewport positions under vulkan

Since Vulkan doesn't support negative x or y viewport positions, this
patch concatenates a translation matrix to the projection matrix used in
Vulkan rendering. In this way, if a negative x or y coordinate would
be necessary, we can instead use a 0 coordinate and a
leftwards/upwards translation to achieve the same effect.  This seems
to work alright with overlays, so as far as I can tell this patch
seems sufficient to get the behavior we want?
This commit is contained in:
Joseph C. Osborn 2024-07-12 11:11:25 -07:00 committed by LibretroAdmin
parent 708a1469fb
commit 6701c0999b
2 changed files with 45 additions and 13 deletions

View File

@ -577,6 +577,8 @@ typedef struct vk
VkViewport vk_vp;
VkRenderPass render_pass;
struct video_viewport vp;
float translate_x;
float translate_y;
struct vk_per_frame swapchain[VULKAN_MAX_SWAPCHAIN_IMAGES];
struct vk_image backbuffers[VULKAN_MAX_SWAPCHAIN_IMAGES];
struct vk_texture default_texture;

View File

@ -3411,6 +3411,8 @@ static void *vulkan_init(const video_info_t *video,
video_driver_get_size(&temp_width, &temp_height);
vk->video_width = temp_width;
vk->video_height = temp_height;
vk->translate_x = 0.0;
vk->translate_y = 0.0;
RARCH_LOG("[Vulkan]: Using resolution %ux%u.\n", temp_width, temp_height);
@ -3762,25 +3764,40 @@ static void vulkan_set_projection(vk_t *vk,
0.0f, 0.0f, 0.0f, 0.0f ,
0.0f, 0.0f, 0.0f, 1.0f }
};
math_matrix_4x4 trn = {
{ 1.0f, 0.0f, 0.0f, 0.0f ,
0.0f, 1.0f, 0.0f, 0.0f ,
0.0f, 0.0f, 1.0f, 0.0f ,
vk->translate_x/(float)vk->vp.width,
vk->translate_y/(float)vk->vp.height,
0.0f,
1.0f }
};
math_matrix_4x4 tmp = {
{ 1.0f, 0.0f, 0.0f, 0.0f ,
0.0f, 1.0f, 0.0f, 0.0f ,
0.0f, 0.0f, 1.0f, 0.0f ,
0.0f, 0.0f, 0.0f, 1.0f }
};
/* Calculate projection. */
matrix_4x4_ortho(vk->mvp_no_rot, ortho->left, ortho->right,
ortho->bottom, ortho->top, ortho->znear, ortho->zfar);
if (!allow_rotate)
tmp = vk->mvp_no_rot;
else
{
vk->mvp = vk->mvp_no_rot;
return;
radians = M_PI * vk->rotation / 180.0f;
cosine = cosf(radians);
sine = sinf(radians);
MAT_ELEM_4X4(rot, 0, 0) = cosine;
MAT_ELEM_4X4(rot, 0, 1) = -sine;
MAT_ELEM_4X4(rot, 1, 0) = sine;
MAT_ELEM_4X4(rot, 1, 1) = cosine;
matrix_4x4_multiply(tmp, rot, vk->mvp_no_rot);
}
radians = M_PI * vk->rotation / 180.0f;
cosine = cosf(radians);
sine = sinf(radians);
MAT_ELEM_4X4(rot, 0, 0) = cosine;
MAT_ELEM_4X4(rot, 0, 1) = -sine;
MAT_ELEM_4X4(rot, 1, 0) = sine;
MAT_ELEM_4X4(rot, 1, 1) = cosine;
matrix_4x4_multiply(vk->mvp, rot, vk->mvp_no_rot);
matrix_4x4_multiply(vk->mvp, trn, tmp);
}
static void vulkan_set_rotation(void *data, unsigned rotation)
@ -3827,8 +3844,6 @@ static void vulkan_set_viewport(void *data, unsigned viewport_width,
video_driver_get_aspect_ratio(),
vk->flags & VK_FLAG_KEEP_ASPECT,
true);
vk->vp.x = MAX(vk->vp.x, 0);
vk->vp.y = MAX(vk->vp.y, 0);
viewport_width = vk->vp.width;
viewport_height = vk->vp.height;
}
@ -3846,6 +3861,21 @@ static void vulkan_set_viewport(void *data, unsigned viewport_width,
vk->vp.height = viewport_height;
}
if (vk->vp.x < 0)
{
vk->translate_x = (float)vk->vp.x;
vk->vp.x = 0.0;
}
else
vk->translate_x = 0.0;
if (vk->vp.y < 0)
{
vk->translate_y = (float)vk->vp.y;
vk->vp.y = 0.0;
}
else
vk->translate_y = 0.0;
vulkan_set_projection(vk, &ortho, allow_rotate);
/* Set last backbuffer viewport. */