pvr: xform matrix 240p support. screen stretching changes

Use FB_R_CTRL.vclk_div to detect progressive mode.
transform_matrix: Support non-4:3 aspect ratio such as 640x240. Don't
expect 480 height. Issue #690
Add black bars at top and bottom if screen aspect ratio is too low.
Issue #584.
Framebuffer size doesn't depend on screen stretching. Stretching is done
when blitting to screen.
lr: correct subsequent stretching when drawing vmus and xhair
This commit is contained in:
Flyinghead 2022-07-18 18:21:09 +02:00
parent 9d17fc15a3
commit 8e8935b9c4
13 changed files with 105 additions and 144 deletions

View File

@ -371,8 +371,10 @@ void rend_resize_renderer()
{
if (renderer == nullptr)
return;
int fbwidth = VO_CONTROL.pixel_double ? 320 : 640;
int fbheight = (SPG_CONTROL.PAL == SPG_CONTROL.NTSC) || SPG_CONTROL.interlace == 1 ? 480 : 240;
int fbwidth = 640 / (1 + VO_CONTROL.pixel_double) * (1 + SCALER_CTL.hscale);
int fbheight = FB_R_CTRL.vclk_div == 1 || SPG_CONTROL.interlace == 1 ? 480 : 240;
if (SPG_CONTROL.interlace == 0 && SCALER_CTL.vscalefactor > 0x400)
fbheight *= std::roundf((float)SCALER_CTL.vscalefactor / 0x400);
float upscaling = config::RenderResolution / 480.f;
float hres = fbwidth * upscaling;
@ -380,18 +382,10 @@ void rend_resize_renderer()
if (config::Widescreen && !config::Rotate90)
{
if (config::SuperWidescreen)
hres = vres * settings.display.width / settings.display.height;
hres *= (float)settings.display.width / settings.display.height / 4.f * 3.f;
else
hres *= 4.f / 3.f;
}
else if (config::Rotate90)
{
vres *= config::ScreenStretching / 100.f;
}
else
{
hres *= config::ScreenStretching / 100.f;
}
if (!config::Rotate90)
hres = std::roundf(hres / 2.f) * 2.f;
DEBUG_LOG(RENDERER, "rend_resize_renderer: %d x %d", (int)hres, (int)vres);

View File

@ -178,7 +178,10 @@ void pvr_WriteReg(u32 paddr,u32 data)
bool vclk_div_changed = (PvrReg(addr, u32) ^ data) & (1 << 23);
PvrReg(addr, u32) = data;
if (vclk_div_changed)
{
CalculateSync();
rend_needs_resize = true;
}
}
return;

View File

@ -36,30 +36,6 @@ static u32 lightgun_line = 0xffff;
static u32 lightgun_hpos;
static bool maple_int_pending;
static void setFramebufferScaling()
{
float scale_x = 1.f;
float scale_y = 1.f;
if (SPG_CONTROL.interlace)
{
//u32 interl_mode=VO_CONTROL.field_mode;
//if (interl_mode==2)//3 will be funny =P
// scale_y=0.5f;//single interlace
//else
scale_y = 1.f;
}
else
{
if (FB_R_CTRL.vclk_div)
scale_y = 1.0f;//non interlaced VGA mode has full resolution :)
else
scale_y = 0.5f;//non interlaced modes have half resolution
}
rend_set_fb_scale(scale_x, scale_y);
}
void CalculateSync()
{
u32 pixel_clock = PIXEL_CLOCK / (FB_R_CTRL.vclk_div ? 1 : 2);
@ -72,8 +48,6 @@ void CalculateSync()
if (SPG_CONTROL.interlace)
Line_Cycles /= 2;
setFramebufferScaling();
Frame_Cycles = pvr_numscanlines * Line_Cycles;
prv_cur_scanline = 0;
clc_pvr_scanline = 0;
@ -377,6 +351,4 @@ void spg_Deserialize(Deserializer& deser)
}
if (deser.version() < Deserializer::V14)
CalculateSync();
else
setFramebufferScaling();
}

View File

@ -82,7 +82,7 @@ void DX11Overlay::draw(u32 width, u32 height, bool vmu, bool crosshair)
#ifdef LIBRETRO
if (i & 1)
continue;
w *= vmu_screen_params[i / 2].vmu_screen_size_mult;
w *= (float)vmu_screen_params[i / 2].vmu_screen_size_mult / config::ScreenStretching * 100.f;
h *= vmu_screen_params[i / 2].vmu_screen_size_mult;
switch (vmu_screen_params[i / 2].vmu_screen_position)
{
@ -170,15 +170,18 @@ void DX11Overlay::draw(u32 width, u32 height, bool vmu, bool crosshair)
float x, y;
std::tie(x, y) = getCrosshairPosition(i);
#ifdef LIBRETRO
float halfWidth = LIGHTGUN_CROSSHAIR_SIZE / 2.f;
float halfWidth = LIGHTGUN_CROSSHAIR_SIZE / 2.f / config::ScreenStretching * 100.f;
float halfHeight = LIGHTGUN_CROSSHAIR_SIZE / 2.f;
x /= config::ScreenStretching / 100.f;
#else
float halfWidth = XHAIR_WIDTH * settings.display.uiScale / 2.f;
float halfHeight = halfWidth;
#endif
D3D11_VIEWPORT vp{};
vp.TopLeftX = x - halfWidth;
vp.TopLeftY = y - halfWidth;
vp.TopLeftY = y - halfHeight;
vp.Width = halfWidth * 2;
vp.Height = halfWidth * 2;
vp.Height = halfHeight * 2;
vp.MinDepth = 0.f;
vp.MaxDepth = 1.f;
deviceContext->RSSetViewports(1, &vp);

View File

@ -503,28 +503,22 @@ void DX11Renderer::renderFramebuffer()
deviceContext->ClearRenderTargetView(theDX11Context.getRenderTarget(), colors);
int outwidth = settings.display.width;
int outheight = settings.display.height;
float renderAR = getOutputFramebufferAspectRatio();
float screenAR = (float)outwidth / outheight;
if (config::Rotate90)
std::swap(outwidth, outheight);
float renderAR = (float)width / height;
float screenAR = (float)outwidth / outheight;
int dy = 0;
int dx = 0;
if (renderAR > screenAR)
dy = (int)roundf((outheight - outwidth / renderAR) / 2.f);
dy = (int)roundf(outheight * (1 - screenAR / renderAR) / 2.f);
else
dx = (int)roundf((outwidth - outheight * renderAR) / 2.f);
dx = (int)roundf(outwidth * (1 - renderAR / screenAR) / 2.f);
float x = (float)dx;
float y = (float)dy;
float w = (float)(outwidth - 2 * dx);
float h = (float)(outheight - 2 * dy);
float x = 0, y = 0, w = (float)outwidth, h = (float)outheight;
if (dx != 0)
{
x = (float)dx;
w = (float)(outwidth - 2 * dx);
}
else
{
y = (float)dy;
h = (float)(outheight - 2 * dy);
}
// Normalize
x = x * 2.f / outwidth - 1.f;
w *= 2.f / outwidth;

View File

@ -1103,33 +1103,19 @@ void D3DRenderer::renderFramebuffer()
{
devCache.SetRenderState(D3DRS_SCISSORTESTENABLE, FALSE);
device->ColorFill(backbuffer, 0, D3DCOLOR_ARGB(255, VO_BORDER_COL._red, VO_BORDER_COL._green, VO_BORDER_COL._blue));
int fx = 0;
int sx = 0;
float renderAR = getOutputFramebufferAspectRatio();
float screenAR = (float)settings.display.width / settings.display.height;
int fbwidth = width;
int fbheight = height;
if (config::Rotate90)
std::swap(fbwidth, fbheight);
float renderAR = (float)fbwidth / fbheight;
int dx = 0;
int dy = 0;
if (renderAR > screenAR)
fx = (int)roundf((fbwidth - screenAR * fbheight) / 2.f);
dy = (int)roundf(settings.display.height * (1 - screenAR / renderAR) / 2.f);
else
sx = (int)roundf((settings.display.width - renderAR * settings.display.height) / 2.f);
dx = (int)roundf(settings.display.width * (1 - renderAR / screenAR) / 2.f);
if (!config::Rotate90)
{
RECT rs { 0, 0, (long)width, (long)height };
RECT rd { 0, 0, settings.display.width, settings.display.height };
if (sx != 0)
{
rd.left = sx;
rd.right = settings.display.width - sx;
}
else
{
rs.left = fx;
rs.right = width - fx;
}
RECT rd { dx, dy, settings.display.width - dx, settings.display.height - dy };
device->StretchRect(framebufferSurface, &rs, backbuffer, &rd,
config::TextureFiltering == 1 ? D3DTEXF_POINT : D3DTEXF_LINEAR); // This can fail if window is minimized
}
@ -1154,10 +1140,10 @@ void D3DRenderer::renderFramebuffer()
device->SetFVF(D3DFVF_XYZ | D3DFVF_TEX1);
D3DVIEWPORT9 viewport;
viewport.X = sx;
viewport.Y = fx * settings.display.width / height;
viewport.Width = settings.display.width - sx * 2;
viewport.Height = settings.display.height - 2 * fx * settings.display.width / height;
viewport.X = dx;
viewport.Y = dy;
viewport.Width = settings.display.width - dx * 2;
viewport.Height = settings.display.height - dy * 2;
viewport.MinZ = 0;
viewport.MaxZ = 1;
verifyWin(device->SetViewport(&viewport));

View File

@ -4,6 +4,7 @@
#include "rend/tileclip.h"
#include "rend/osd.h"
#include "naomi2.h"
#include "rend/transform_matrix.h"
/*
@ -700,12 +701,7 @@ void DrawStrips()
void DrawFramebuffer()
{
float aspectRatio = 4.f / 3.f;
if (config::Rotate90)
aspectRatio /= config::ScreenStretching / 100.f;
else
aspectRatio *= config::ScreenStretching / 100.f;
int sx = (int)roundf((gl.ofbo.width - aspectRatio * gl.ofbo.height) / 2.f);
int sx = (int)roundf((gl.ofbo.width - 4.f / 3.f * gl.ofbo.height) / 2.f);
glViewport(sx, 0, gl.ofbo.width - sx * 2, gl.ofbo.height);
drawQuad(fbTextureId, false, true);
glcache.DeleteTextures(1, &fbTextureId);
@ -715,27 +711,21 @@ void DrawFramebuffer()
bool render_output_framebuffer()
{
glcache.Disable(GL_SCISSOR_TEST);
int fx = 0;
int sx = 0;
float screenAR = (float)settings.display.width / settings.display.height;
int fbwidth = gl.ofbo.width;
int fbheight = gl.ofbo.height;
if (config::Rotate90)
std::swap(fbwidth, fbheight);
float renderAR = (float)fbwidth / fbheight;
float renderAR = getOutputFramebufferAspectRatio();
int dx = 0;
int dy = 0;
if (renderAR > screenAR)
fx = (int)roundf((fbwidth - screenAR * fbheight) / 2.f);
dy = (int)roundf(settings.display.height * (1 - screenAR / renderAR) / 2.f);
else
sx = (int)roundf((settings.display.width - renderAR * settings.display.height) / 2.f);
dx = (int)roundf(settings.display.width * (1 - renderAR / screenAR) / 2.f);
if (gl.gl_major < 3 || config::Rotate90)
{
if (gl.ofbo.tex == 0)
return false;
if (sx != 0)
glViewport(sx, 0, settings.display.width - sx * 2, settings.display.height);
else
glViewport(-fx, 0, settings.display.width + fx * 2, settings.display.height);
glViewport(dx, dy, settings.display.width - dx * 2, settings.display.height - dy * 2);
glBindFramebuffer(GL_FRAMEBUFFER, gl.ofbo.origFbo);
glcache.ClearColor(VO_BORDER_COL.red(), VO_BORDER_COL.green(), VO_BORDER_COL.blue(), 1.f);
glClear(GL_COLOR_BUFFER_BIT);
@ -752,8 +742,8 @@ bool render_output_framebuffer()
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, gl.ofbo.origFbo);
glcache.ClearColor(VO_BORDER_COL.red(), VO_BORDER_COL.green(), VO_BORDER_COL.blue(), 1.f);
glClear(GL_COLOR_BUFFER_BIT);
glBlitFramebuffer(fx, 0, gl.ofbo.width - fx, gl.ofbo.height,
sx, 0, settings.display.width - sx, settings.display.height,
glBlitFramebuffer(0, 0, gl.ofbo.width, gl.ofbo.height,
dx, dy, settings.display.width - dx, settings.display.height - dy,
GL_COLOR_BUFFER_BIT, config::TextureFiltering == 1 ? GL_NEAREST : GL_LINEAR);
glBindFramebuffer(GL_FRAMEBUFFER, gl.ofbo.origFbo);
#endif
@ -834,7 +824,7 @@ void DrawVmuTexture(u8 vmu_screen_number)
const float vmu_padding = 8.f;
float x = (config::Widescreen && config::ScreenStretching == 100 ? -(640.f * 4.f / 3.f - 640.f) / 2 : 0) + vmu_padding;
float y = vmu_padding;
float w = VMU_SCREEN_WIDTH * vmu_screen_params[vmu_screen_number].vmu_screen_size_mult;
float w = (float)VMU_SCREEN_WIDTH * vmu_screen_params[vmu_screen_number].vmu_screen_size_mult / config::ScreenStretching * 100.f;
float h = VMU_SCREEN_HEIGHT * vmu_screen_params[vmu_screen_number].vmu_screen_size_mult;
if (vmu_lcd_changed[vmu_screen_number * 2] || vmuTextureId[vmu_screen_number] == 0)
@ -938,11 +928,12 @@ void DrawGunCrosshair(u8 port)
glActiveTexture(GL_TEXTURE0);
float x = lightgun_params[port].x;
float stretch = config::ScreenStretching / 100.f;
float x = lightgun_params[port].x / stretch;
float y = lightgun_params[port].y;
float w = LIGHTGUN_CROSSHAIR_SIZE;
float h = LIGHTGUN_CROSSHAIR_SIZE;
float w = (float)LIGHTGUN_CROSSHAIR_SIZE / stretch;
float h = (float)LIGHTGUN_CROSSHAIR_SIZE;
x -= w / 2;
y -= h / 2;

View File

@ -41,7 +41,7 @@ class TransformMatrix
{
public:
TransformMatrix() = default;
TransformMatrix(const rend_context& renderingContext, int width = 0, int height = 0)
TransformMatrix(const rend_context& renderingContext, int width, int height)
{
CalcMatrices(&renderingContext, width, height);
}
@ -141,36 +141,28 @@ public:
normalMatrix = glm::translate(glm::vec3(startx, starty, 0));
scissorMatrix = normalMatrix;
const float screen_stretching = config::ScreenStretching / 100.f;
float scissoring_scale_x, scissoring_scale_y;
GetFramebufferScaling(true, scissoring_scale_x, scissoring_scale_y);
float x_coef;
float y_coef;
glm::mat4 trans_rot;
if (config::Rotate90)
if (config::Widescreen && !config::Rotate90)
{
float dc2s_scale_h = renderViewport.x / 640.0f;
sidebarWidth = 0;
y_coef = 2.0f / (renderViewport.y / dc2s_scale_h * scale_y) * screen_stretching * screenFlipY;
x_coef = 2.0f / dcViewport.x;
sidebarWidth = (1 - dcViewport.x / dcViewport.y * renderViewport.y / renderViewport.x) / 2;
if (config::SuperWidescreen)
dcViewport.x *= (float)settings.display.width / settings.display.height / 4.f * 3.f;
else
dcViewport.x *= 4.f / 3.f;
}
else
{
float dc2s_scale_h = renderViewport.y / 480.0f;
sidebarWidth = 0;
float x_coef = 2.0f / dcViewport.x;
float y_coef = 2.0f / dcViewport.y * screenFlipY;
sidebarWidth = (renderViewport.x - dc2s_scale_h * 640.0f * screen_stretching) / 2;
x_coef = 2.0f / (renderViewport.x / dc2s_scale_h * scale_x) * screen_stretching;
y_coef = 2.0f / dcViewport.y * screenFlipY;
}
trans_rot = glm::translate(glm::vec3(-1 + 2 * sidebarWidth / renderViewport.x, -screenFlipY, 0));
glm::mat4 trans = glm::translate(glm::vec3(-1 + 2 * sidebarWidth, -screenFlipY, 0));
normalMatrix = trans_rot
normalMatrix = trans
* glm::scale(glm::vec3(x_coef, y_coef, 1.f))
* normalMatrix;
scissorMatrix = trans_rot
scissorMatrix = trans
* glm::scale(glm::vec3(x_coef * scissoring_scale_x, y_coef * scissoring_scale_y, 1.f))
* scissorMatrix;
}
@ -200,11 +192,8 @@ private:
if (!renderingContext->isRTT && !renderingContext->isRenderFramebuffer)
{
if (!scissor)
{
scale_x = fb_scale_x;
scale_y = fb_scale_y;
}
if (!scissor && (FB_R_CTRL.vclk_div == 0 && SPG_CONTROL.interlace == 0))
scale_y /= 2.f;
if (SCALER_CTL.vscalefactor > 0x400)
{
// Interlace mode A (single framebuffer)
@ -216,9 +205,8 @@ private:
}
// VO pixel doubling is done after fb rendering/clipping
// so it should be used for scissoring as well
if (VO_CONTROL.pixel_double && !scissor)
scale_x *= 0.5f;
scale_x /= 2.f;
// the X Scaler halves the horizontal resolution but
// before clipping/scissoring
@ -238,3 +226,25 @@ private:
float scale_y = 0;
float sidebarWidth = 0;
};
inline static float getOutputFramebufferAspectRatio()
{
float renderAR;
if (config::Rotate90)
{
renderAR = 3.f / 4.f;
}
else
{
if (config::Widescreen)
{
if (config::SuperWidescreen)
renderAR = (float)settings.display.width / settings.display.height;
else
renderAR = 16.f / 9.f;
}
else
renderAR = 4.f / 3.f;
}
return renderAR * config::ScreenStretching / 100.f;
}

View File

@ -54,6 +54,7 @@ public:
if ((u32)w == viewport.width && (u32)h == viewport.height)
return;
BaseVulkanRenderer::Resize(w, h);
GetContext()->WaitIdle();
screenDrawer.Init(&samplerManager, &oitShaderManager, &oitBuffers, viewport);
}

View File

@ -132,6 +132,8 @@ void VulkanOverlay::Draw(vk::CommandBuffer commandBuffer, vk::Extent2D viewport,
vmu_width *= 2.f;
float blendConstants[4] = { 0.75f, 0.75f, 0.75f, 0.75f };
color = blendConstants;
#else
vmu_width /= config::ScreenStretching / 100.f;
#endif
for (size_t i = 0; i < vmuTextures.size(); i++)
@ -207,8 +209,9 @@ void VulkanOverlay::Draw(vk::CommandBuffer commandBuffer, vk::Extent2D viewport,
std::tie(x, y) = getCrosshairPosition(i);
#ifdef LIBRETRO
float w = LIGHTGUN_CROSSHAIR_SIZE * scaling;
float w = LIGHTGUN_CROSSHAIR_SIZE * scaling / config::ScreenStretching * 100.f;
float h = LIGHTGUN_CROSSHAIR_SIZE * scaling;
x /= config::ScreenStretching / 100.f;
#else
float w = XHAIR_WIDTH * scaling;
float h = XHAIR_HEIGHT * scaling;

View File

@ -32,6 +32,7 @@
#include "emulator.h"
#include "oslib/oslib.h"
#include "vulkan_driver.h"
#include "rend/transform_matrix.h"
void ReInitOSD();
@ -861,14 +862,18 @@ void VulkanContext::DrawFrame(vk::ImageView imageView, const vk::Extent2D& exten
else
quadPipeline->BindPipeline(commandBuffer);
float marginWidth;
if (config::Rotate90)
marginWidth = ((float)width - (float)extent.height / extent.width * height) / 2.f;
float renderAR = getOutputFramebufferAspectRatio();
float screenAR = (float)width / height;
float dx = 0;
float dy = 0;
if (renderAR > screenAR)
dy = height * (1 - screenAR / renderAR) / 2;
else
marginWidth = ((float)width - (float)extent.width / extent.height * height) / 2.f;
vk::Viewport viewport(marginWidth, 0, width - marginWidth * 2.f, height);
dx = width * (1 - renderAR / screenAR) / 2;
vk::Viewport viewport(dx, dy, width - dx * 2, height - dy * 2);
commandBuffer.setViewport(0, 1, &viewport);
commandBuffer.setScissor(0, vk::Rect2D(vk::Offset2D(std::max(0.f, marginWidth), 0), vk::Extent2D(width - marginWidth * 2.f, height)));
commandBuffer.setScissor(0, vk::Rect2D(vk::Offset2D(dx, dy), vk::Extent2D(width - dx * 2, height - dy * 2)));
if (config::Rotate90)
quadRotateDrawer->Draw(commandBuffer, imageView, vtx, config::TextureFiltering == 1);
else

View File

@ -45,6 +45,7 @@ public:
if ((u32)w == viewport.width && (u32)h == viewport.height)
return;
BaseVulkanRenderer::Resize(w, h);
GetContext()->WaitIdle();
screenDrawer.Init(&samplerManager, &shaderManager, viewport);
}

View File

@ -153,8 +153,6 @@ public:
void Resize(int w, int h) override
{
if ((u32)w == viewport.width && (u32)h == viewport.height)
return;
viewport.width = w;
viewport.height = h;
}