Try this:
#version 450
// CRT 240p Scale Shader
// by Tim C. Schroeder (visit www.blitzcode.net to learn more)
// published under MIT License
// adapted to slang format by hunterk as retrieved from github.com/blitzcode/crt-240p-scale-shader
// on 5/26/2022
layout(push_constant) uniform Push
{
	vec4 SourceSize;
	vec4 OriginalSize;
	vec4 OutputSize;
	uint FrameCount;
} params;
layout(std140, set = 0, binding = 0) uniform UBO
{
	mat4 MVP;
} global;
#define InputSize params.SourceSize.xy
#define TextureSize params.SourceSize.xy
#define OutputSize params.OutputSize.xy
// Screen rotation in RA is implemented by rotating the output geometry, detect this here
bool is_vertical() { return global.MVP[0].y != 0.0; }
#pragma stage vertex
layout(location = 0) in vec4 Position;
layout(location = 1) in vec2 TexCoord;
layout(location = 0) out vec2 vTexCoord;
layout(location = 1) out vec2 filter_offs;
void main()
{
    // Output position in clip space [-1, 1]
    vec4 clip_space_pos = global.MVP * vec4(Position.x, Position.y, 0.0, 1.0);
    bool is_vertical = is_vertical();
    // Scale factor for the vertical axis. Do nothing if input / output resolution
    // matches, center if input is lower than output, shrink to output if input is higher
    // than output. Keep in mind that our geometry might be rotated
    float vert_center = min(1.0, (is_vertical ? InputSize.x : InputSize.y) / OutputSize.y);
    clip_space_pos.y *= vert_center;
    // Handheld consoles get centered on the screen and have their correct aspect ratio
    bool is_handheld = true;
    float handheld_ar = 1.0;
         if (InputSize.x == 160.0 && InputSize.y == 144.0) handheld_ar = 1.11; // GB(C) / GG *
    else if (InputSize.x == 160.0 && InputSize.y == 152.0) handheld_ar = 1.05; // NGP(C)
    else if (InputSize.x == 224.0 && InputSize.y == 144.0) handheld_ar = 1.55; // WonderSwan
    else if (InputSize.x == 160.0 && InputSize.y == 102.0) handheld_ar = 1.57; // Atari Lynx
    else if (InputSize.x == 102.0 && InputSize.y == 160.0) handheld_ar = 0.64; // Atari Lynx Vertical **
    else if (InputSize.x == 240.0 && InputSize.y == 160.0) handheld_ar = 1.50; // GBA
    else
        is_handheld = false;
    // *  We unfortunately can't distinguish between the Game Gear and the Nintendo
    //    handhelds, causing the former to have the wrong aspect ratio as it uses
    //    non-square pixels. Feel free to change the aspect to 1.33 to reverse the
    //    situation in favor of Sega's system
    // ** This is a weird special case. Lynx seems to be the only system where vertical
    //    mode does not rotate the image in post, but the emulator actually outputs a
    //    different resolution. So it's not treated as a vertical system, is_vertical ==
    //    false and we simply treat it as a horizontal system having a tall aspect ratio
    // Fix for 2 & 3 screen wide Darius games. This is not going to look terribly good but
    // at least they're playable (sort of)
    if (InputSize.x == 640.0 && InputSize.y == 224.0)
        clip_space_pos.y /= 2.0;
    else if (InputSize.x == 864.0 && InputSize.y == 224.0)
        clip_space_pos.y /= 3.0;
    if (is_handheld)
    {
        clip_space_pos.x = clip_space_pos.x
            // This gets us to a square display
            * vert_center * (3.0 / 4.0)
            // Now it has the same AR as the physical screen of the device
            * handheld_ar
            // Aspect ratio correction when in vertical orientation
            * (is_vertical ? (1.0 / handheld_ar) * (1.0 / handheld_ar) : 1.0);
    }
    else if (is_vertical)
    {
#if 0
        // Overscan adjustment for TATE games. Most of these games don't seem to have any
        // consideration for the typical overscan present on consumer CRTs and place
        // critical elements like score and bomb counters right at the margin. Here we
        // shrink the image a little bit so it's not cut off on CRTs calibrated for
        // typical home consoles
        float overscan_adj = 1.045;
        clip_space_pos.x /= overscan_adj;
        clip_space_pos.y /= overscan_adj;
#endif
        // Correct the aspect ratio for 3:4 image in 4:3 frame
        clip_space_pos.x *= (3.0 / 4.0) * (3.0 / 4.0);
    }
    // Setup texture filtering offsets for downscaling. We do this here so we don't have
    // to repeat these calculations per-pixel
    {
        // If we want to properly filter the input texture we need to know the radius
        // which one screen pixel (pixel radius / number of output pixels) represents in
        // the normalized texture coordinates of the input texture. It's important to keep
        // in mind that the input texture might not be fully used, so we have to adjust
        // with the input-res-to-texture-size ratio to prevent an oversized filter kernel
        //
        // Why do we not simply use the automatic derivative functions dFdx() / dFdy() to
        // figure out the proper offsets? Because RPi 3B's GPU doesn't support those
        float pixel_r = 0.7;
        float support = (pixel_r / OutputSize.y) *
                        (is_vertical ? InputSize.x / TextureSize.x : InputSize.y / TextureSize.y);
        // Make sure we super-sample along the correct axis of the input texture and use
        // the filter support we just computed
        filter_offs = is_vertical ? vec2(support, 0.0) : vec2(0.0, support);
    }
    // Output
   gl_Position = clip_space_pos;
   vTexCoord = TexCoord;
}
#pragma stage fragment
layout(location = 0) in vec2 vTexCoord;
layout(location = 1) in vec2 filter_offs;
layout(location = 0) out vec4 FragColor;
layout(set = 0, binding = 2) uniform sampler2D Source;
void main()
{
    bool is_vertical = is_vertical();
    // Disable texture filtering on the horizontal axis by sampling at the texel center.
    // The super-resolution output in combination with the softness of the CRT already
    // takes care of all filtering, additional bilinear lookups just introduce blurring
    // and a loss of brightness in slim features. Filtering on the vertical is fine since
    // we either match input texture to screen lines perfectly and it has no effect or
    // we're downscaling and want filtering.
    //
    // In vertical mode, disable filtering on the vertical input texture axis as it runs along
    // the horizontal screen axis due to the rotated output geometry
    vec2 tex_coord_center = vTexCoord;
    if (is_vertical)
        tex_coord_center.y = (floor(tex_coord_center.y * TextureSize.y) + 0.5) / TextureSize.y;
    else
        tex_coord_center.x = (floor(tex_coord_center.x * TextureSize.x) + 0.5) / TextureSize.x;
    // Do we have to downscale on the vertical axis (high-res arcade games, TATE games)?
    //
    // Vertical games have the horizontal input texture axis run along the vertical screen axis,
    // swap as with the filtering adjustment code above
    if (is_vertical ? OutputSize.y < InputSize.x : OutputSize.y < InputSize.y)
    {
        // Super-sampling with a tent filter and a bit of sharpening. This can never look
        // perfect and our filter is rather simplistic, but the result already looks
        // significantly better than default RA scaling and strikes a good balance between
        // shimmering and blurriness
        float sharpen = 0.7;
        FragColor =
            ( texture(Source, tex_coord_center - filter_offs * 1.5) * -sharpen +
              texture(Source, tex_coord_center - filter_offs      ) * 0.5      +
              texture(Source, tex_coord_center - filter_offs * 0.5)            +
              texture(Source, tex_coord_center)                     * 1.5      +
              texture(Source, tex_coord_center + filter_offs * 0.5)            +
              texture(Source, tex_coord_center + filter_offs      ) * 0.5      +
              texture(Source, tex_coord_center + filter_offs * 1.5) * -sharpen
            ) * (1.0 / (4.5 - 2.0 * sharpen));
    }
    else
        FragColor = texture(Source, tex_coord_center);
}