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; VkViewport vk_vp;
VkRenderPass render_pass; VkRenderPass render_pass;
struct video_viewport vp; struct video_viewport vp;
float translate_x;
float translate_y;
struct vk_per_frame swapchain[VULKAN_MAX_SWAPCHAIN_IMAGES]; struct vk_per_frame swapchain[VULKAN_MAX_SWAPCHAIN_IMAGES];
struct vk_image backbuffers[VULKAN_MAX_SWAPCHAIN_IMAGES]; struct vk_image backbuffers[VULKAN_MAX_SWAPCHAIN_IMAGES];
struct vk_texture default_texture; 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); video_driver_get_size(&temp_width, &temp_height);
vk->video_width = temp_width; vk->video_width = temp_width;
vk->video_height = temp_height; 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); RARCH_LOG("[Vulkan]: Using resolution %ux%u.\n", temp_width, temp_height);
@ -3762,17 +3764,30 @@ static void vulkan_set_projection(vk_t *vk,
0.0f, 0.0f, 0.0f, 0.0f , 0.0f, 0.0f, 0.0f, 0.0f ,
0.0f, 0.0f, 0.0f, 1.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. */ /* Calculate projection. */
matrix_4x4_ortho(vk->mvp_no_rot, ortho->left, ortho->right, matrix_4x4_ortho(vk->mvp_no_rot, ortho->left, ortho->right,
ortho->bottom, ortho->top, ortho->znear, ortho->zfar); ortho->bottom, ortho->top, ortho->znear, ortho->zfar);
if (!allow_rotate) if (!allow_rotate)
tmp = vk->mvp_no_rot;
else
{ {
vk->mvp = vk->mvp_no_rot;
return;
}
radians = M_PI * vk->rotation / 180.0f; radians = M_PI * vk->rotation / 180.0f;
cosine = cosf(radians); cosine = cosf(radians);
sine = sinf(radians); sine = sinf(radians);
@ -3780,7 +3795,9 @@ static void vulkan_set_projection(vk_t *vk,
MAT_ELEM_4X4(rot, 0, 1) = -sine; MAT_ELEM_4X4(rot, 0, 1) = -sine;
MAT_ELEM_4X4(rot, 1, 0) = sine; MAT_ELEM_4X4(rot, 1, 0) = sine;
MAT_ELEM_4X4(rot, 1, 1) = cosine; MAT_ELEM_4X4(rot, 1, 1) = cosine;
matrix_4x4_multiply(vk->mvp, rot, vk->mvp_no_rot); matrix_4x4_multiply(tmp, rot, vk->mvp_no_rot);
}
matrix_4x4_multiply(vk->mvp, trn, tmp);
} }
static void vulkan_set_rotation(void *data, unsigned rotation) 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(), video_driver_get_aspect_ratio(),
vk->flags & VK_FLAG_KEEP_ASPECT, vk->flags & VK_FLAG_KEEP_ASPECT,
true); true);
vk->vp.x = MAX(vk->vp.x, 0);
vk->vp.y = MAX(vk->vp.y, 0);
viewport_width = vk->vp.width; viewport_width = vk->vp.width;
viewport_height = vk->vp.height; viewport_height = vk->vp.height;
} }
@ -3846,6 +3861,21 @@ static void vulkan_set_viewport(void *data, unsigned viewport_width,
vk->vp.height = viewport_height; 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); vulkan_set_projection(vk, &ortho, allow_rotate);
/* Set last backbuffer viewport. */ /* Set last backbuffer viewport. */