mirror of
https://github.com/blawar/GLideN64.git
synced 2024-07-04 10:03:36 +00:00
Correct mapping of RDP frame buffer to output one.
Code of RdpUpdate::update is based on angrylion's rdp_update(). Main visible difference: VI cuts several pixels on left and right of original image. Cite from angrylion's commit message: "rdp: new tests revealed the shocking truth: the VI aggresssively and regardlessly of any data alignment specificities cuts off either 7 or 8 pixels closest to h_start and h_end, so that nothing ever appears on the screen unless (h_end - h_start) is 16 pixels or greater (this removes marginal garbage graphics on the far right in Mario Tennis, Turok 2 Seeds of Evil intro and probably other games)"
This commit is contained in:
parent
0f1b45cfa6
commit
1e84099521
|
@ -551,6 +551,7 @@ void FrameBufferList::init()
|
|||
gfxContext.bindFramebuffer(bufferTarget::DRAW_FRAMEBUFFER, ObjectHandle::defaultFramebuffer);
|
||||
m_prevColorImageHeight = 0;
|
||||
m_overscan.init();
|
||||
m_rdpUpdate.init();
|
||||
}
|
||||
|
||||
void FrameBufferList::destroy() {
|
||||
|
@ -1028,31 +1029,21 @@ void FrameBufferList::_renderScreenSizeBuffer()
|
|||
gDP.changed |= CHANGED_SCISSOR;
|
||||
}
|
||||
|
||||
struct RdpUpdateResult {
|
||||
u32 vi_vres;
|
||||
u32 vi_hres;
|
||||
u32 vi_v_start;
|
||||
u32 vi_h_start;
|
||||
u32 vi_x_start;
|
||||
u32 vi_y_start;
|
||||
u32 vi_x_add;
|
||||
u32 vi_y_add;
|
||||
u32 vi_width;
|
||||
u32 vi_origin;
|
||||
bool vi_lowerfield;
|
||||
bool vi_fsaa;
|
||||
bool vi_divot;
|
||||
bool vi_ispal;
|
||||
};
|
||||
|
||||
/* This function taken from angrylion's code and adopted for my needs */
|
||||
static
|
||||
bool rdp_update(RdpUpdateResult & _result)
|
||||
void FrameBufferList::RdpUpdate::init()
|
||||
{
|
||||
static const u32 PRESCALE_WIDTH = 640;
|
||||
static const u32 PRESCALE_HEIGHT = 625;
|
||||
static u32 oldvstart = 0;
|
||||
static bool prevwasblank = false;
|
||||
oldvstart = 0U;
|
||||
prevvicurrent = 0U;
|
||||
prevwasblank = false;
|
||||
prevserrate = false;
|
||||
oldlowerfield = false;
|
||||
emucontrolsvicurrent = -1;
|
||||
}
|
||||
|
||||
/* This function was taken from angrylion's code and adopted for my needs */
|
||||
bool FrameBufferList::RdpUpdate::update(RdpUpdateResult & _result)
|
||||
{
|
||||
static const u32 PRESCALE_WIDTH = 640U;
|
||||
static const u32 PRESCALE_HEIGHT = 625U;
|
||||
|
||||
const u32 x_add = _SHIFTR(*REG.VI_X_SCALE, 0, 12);
|
||||
const u32 y_add = _SHIFTR(*REG.VI_Y_SCALE, 0, 12);
|
||||
|
@ -1067,31 +1058,61 @@ bool rdp_update(RdpUpdateResult & _result)
|
|||
const u32 delta_y = y2 - y1;
|
||||
const u32 vitype = _SHIFTR( *REG.VI_STATUS, 0, 2 );
|
||||
|
||||
const bool interlaced = (*REG.VI_STATUS & 0x40) != 0;
|
||||
const bool lowerfield = interlaced ? y1 > oldvstart : false;
|
||||
const bool serration_pulses = (*REG.VI_STATUS & 0x40) != 0;
|
||||
const bool validinterlace = ((vitype & 2) != 0 ) && serration_pulses;
|
||||
if (validinterlace && prevserrate && emucontrolsvicurrent < 0)
|
||||
emucontrolsvicurrent = (*REG.VI_V_CURRENT_LINE & 1) != prevvicurrent ? 1 : 0;
|
||||
|
||||
bool lowerfield = 0;
|
||||
if (validinterlace) {
|
||||
if (emucontrolsvicurrent == 1)
|
||||
lowerfield = (*REG.VI_V_CURRENT_LINE & 1) == 0;
|
||||
else if (!emucontrolsvicurrent) {
|
||||
if (y1 == oldvstart)
|
||||
lowerfield = !oldlowerfield;
|
||||
else
|
||||
lowerfield = y1 < oldvstart;
|
||||
}
|
||||
}
|
||||
|
||||
oldlowerfield = lowerfield;
|
||||
|
||||
if (validinterlace) {
|
||||
prevserrate = true;
|
||||
prevvicurrent = *REG.VI_V_CURRENT_LINE & 1;
|
||||
oldvstart = y1;
|
||||
} else
|
||||
prevserrate = false;
|
||||
|
||||
u32 hres = delta_x;
|
||||
u32 vres = delta_y;
|
||||
s32 h_start = x1 - (ispal ? 128 : 108);
|
||||
s32 v_start = y1 - (ispal ? 47 : 37);
|
||||
s32 v_start = (y1 - (ispal ? 44 : 34)) / 2;
|
||||
u32 x_start = _SHIFTR(*REG.VI_X_SCALE, 16, 12);
|
||||
u32 y_start = _SHIFTR(*REG.VI_Y_SCALE, 16, 12);
|
||||
|
||||
bool h_start_clamped = h_start < 0;
|
||||
if (h_start < 0) {
|
||||
x_start -= x_add * h_start;
|
||||
hres += h_start;
|
||||
|
||||
h_start = 0;
|
||||
}
|
||||
v_start >>= 1;
|
||||
v_start &= -int(v_start >= 0);
|
||||
|
||||
if (v_start < 0) {
|
||||
y_start += (y_add * (u32)(-v_start));
|
||||
v_start = 0;
|
||||
}
|
||||
|
||||
vres >>= 1;
|
||||
|
||||
if (hres > PRESCALE_WIDTH - h_start)
|
||||
const bool hres_clamped = hres + h_start > PRESCALE_WIDTH;
|
||||
if (hres_clamped)
|
||||
hres = PRESCALE_WIDTH - h_start;
|
||||
if (vres > PRESCALE_HEIGHT - v_start)
|
||||
if (vres + v_start > PRESCALE_HEIGHT)
|
||||
vres = PRESCALE_HEIGHT - v_start;
|
||||
|
||||
s32 vactivelines = v_sync - (ispal ? 47 : 37);
|
||||
s32 vactivelines = v_sync - (ispal ? 44 : 34);
|
||||
if (vactivelines > PRESCALE_HEIGHT) {
|
||||
LOG(LOG_MINIMAL, "VI_V_SYNC_REG too big\n");
|
||||
return false;
|
||||
|
@ -1105,7 +1126,7 @@ bool rdp_update(RdpUpdateResult & _result)
|
|||
if (hres <= 0 || vres <= 0 || ((vitype & 2) == 0 && prevwasblank)) /* early return. */
|
||||
return false;
|
||||
|
||||
if (vitype >> 1 == 0) {
|
||||
if ((vitype & 2) == 0) {
|
||||
prevwasblank = true;
|
||||
return false;
|
||||
}
|
||||
|
@ -1121,6 +1142,8 @@ bool rdp_update(RdpUpdateResult & _result)
|
|||
_result.vi_y_start = y_start;
|
||||
_result.vi_x_add = x_add;
|
||||
_result.vi_y_add = y_add;
|
||||
_result.vi_minhpass = h_start_clamped ? 0 : 8;
|
||||
_result.vi_maxhpass = hres_clamped ? 0 : 7;
|
||||
_result.vi_width = _SHIFTR(*REG.VI_WIDTH, 0, 12);
|
||||
_result.vi_lowerfield = lowerfield;
|
||||
_result.vi_origin = _SHIFTR(*REG.VI_ORIGIN, 0, 24);
|
||||
|
@ -1311,7 +1334,7 @@ void FrameBufferList::renderBuffer()
|
|||
}
|
||||
|
||||
RdpUpdateResult rdpRes;
|
||||
if (!rdp_update(rdpRes)) {
|
||||
if (!m_rdpUpdate.update(rdpRes)) {
|
||||
gfxContext.bindFramebuffer(bufferTarget::DRAW_FRAMEBUFFER, ObjectHandle::defaultFramebuffer);
|
||||
gfxContext.clearColorBuffer(0.0f, 0.0f, 0.0f, 0.0f);
|
||||
dwnd().swapBuffers();
|
||||
|
@ -1332,7 +1355,6 @@ void FrameBufferList::renderBuffer()
|
|||
s32 dstX0, dstX1, dstY0, dstY1;
|
||||
s32 srcWidth, srcHeight;
|
||||
s32 XoffsetLeft = 0, XoffsetRight = 0;
|
||||
s32 Xdivot = 0;
|
||||
s32 srcPartHeight = 0;
|
||||
s32 dstPartHeight = 0;
|
||||
|
||||
|
@ -1355,7 +1377,7 @@ void FrameBufferList::renderBuffer()
|
|||
XoffsetLeft = addrOffset % rdpRes.vi_width;
|
||||
}
|
||||
|
||||
if (rdpRes.vi_lowerfield && rdpRes.vi_width > 320) {
|
||||
if (!rdpRes.vi_lowerfield && rdpRes.vi_width > 320) {
|
||||
if (srcY0 > 0)
|
||||
--srcY0;
|
||||
if (dstY0 > 0)
|
||||
|
@ -1389,25 +1411,24 @@ void FrameBufferList::renderBuffer()
|
|||
for (const auto & f : postProcessor.getPostprocessingList())
|
||||
pFilteredBuffer = f(postProcessor, pFilteredBuffer);
|
||||
|
||||
if (rdpRes.vi_fsaa && rdpRes.vi_divot)
|
||||
Xdivot = 1;
|
||||
|
||||
const f32 viScaleX = _FIXED2FLOAT(_SHIFTR(*REG.VI_X_SCALE, 0, 12), 10);
|
||||
const f32 srcScaleX = pFilteredBuffer->m_scale;
|
||||
const f32 dstScaleX = m_overscan.getScaleX();
|
||||
const s32 hx0 = rdpRes.vi_h_start;
|
||||
const f32 dstScaleX = dwnd().getWidth() / (640 * viScaleX);
|
||||
const s32 hx0 = rdpRes.vi_h_start + rdpRes.vi_minhpass;
|
||||
const s32 h0 = (rdpRes.vi_ispal ? 128 : 108);
|
||||
const s32 hEnd = _SHIFTR(*REG.VI_H_START, 0, 10);
|
||||
const s32 hx1 = max(0, h0 + 640 - hEnd);
|
||||
const s32 hx1 = max(0, h0 + 640 - hEnd + (s32)rdpRes.vi_maxhpass);
|
||||
//const s32 hx1 = hx0 + rdpRes.vi_hres;
|
||||
dstX0 = (s32)((hx0 * viScaleX + XoffsetRight) * dstScaleX);
|
||||
dstX1 = m_overscan.getDrawingWidth() - (s32)((hx1 * viScaleX + Xdivot) * dstScaleX);
|
||||
dstX0 = (s32)((hx0 * viScaleX + f32(XoffsetRight)) * dstScaleX);
|
||||
dstX1 = m_overscan.getDrawingWidth() - (s32)(hx1 * viScaleX * dstScaleX);
|
||||
|
||||
const f32 srcScaleY = pFilteredBuffer->m_scale;
|
||||
CachedTexture * pBufferTexture = pFilteredBuffer->m_pTexture;
|
||||
s32 srcCoord[4] = { (s32)(XoffsetLeft * srcScaleX),
|
||||
const s32 cutleft = static_cast<s32>(rdpRes.vi_minhpass * viScaleX);
|
||||
const s32 cutright = static_cast<s32>(rdpRes.vi_maxhpass * viScaleX);
|
||||
s32 srcCoord[4] = { (s32)((XoffsetLeft + cutleft) * srcScaleX),
|
||||
(s32)(srcY0*srcScaleY),
|
||||
(s32)((srcWidth + XoffsetLeft - XoffsetRight - Xdivot) * srcScaleX),
|
||||
(s32)((srcWidth + XoffsetLeft - XoffsetRight - cutright) * srcScaleX),
|
||||
min((s32)(srcY1*srcScaleY), (s32)pBufferTexture->realHeight) };
|
||||
if (srcCoord[2] > pBufferTexture->realWidth || srcCoord[3] > pBufferTexture->realHeight) {
|
||||
removeBuffer(pBuffer->m_startAddress);
|
||||
|
@ -1479,9 +1500,7 @@ void FrameBufferList::renderBuffer()
|
|||
blitParams.srcY1 = min((s32)(srcY1*srcScaleY), (s32)pFilteredBuffer->m_pTexture->realHeight);
|
||||
blitParams.srcWidth = pBufferTexture->realWidth;
|
||||
blitParams.srcHeight = pBufferTexture->realHeight;
|
||||
blitParams.dstX0 = hOffset;
|
||||
blitParams.dstY0 = vOffset + (s32)(dstY0*dstScaleY);
|
||||
blitParams.dstX1 = hOffset + dstX1;
|
||||
blitParams.dstY1 = vOffset + (s32)(dstY1*dstScaleY);
|
||||
blitParams.dstWidth = m_overscan.getBufferWidth();
|
||||
blitParams.dstHeight = m_overscan.getBufferHeight();
|
||||
|
|
|
@ -170,6 +170,40 @@ private:
|
|||
FrameBuffer * m_pCopy;
|
||||
u32 m_prevColorImageHeight;
|
||||
OverscanBuffer m_overscan;
|
||||
|
||||
struct RdpUpdateResult {
|
||||
u32 vi_vres;
|
||||
u32 vi_hres;
|
||||
u32 vi_v_start;
|
||||
u32 vi_h_start;
|
||||
u32 vi_x_start;
|
||||
u32 vi_y_start;
|
||||
u32 vi_x_add;
|
||||
u32 vi_y_add;
|
||||
u32 vi_width;
|
||||
u32 vi_origin;
|
||||
u32 vi_minhpass;
|
||||
u32 vi_maxhpass;
|
||||
bool vi_lowerfield;
|
||||
bool vi_fsaa;
|
||||
bool vi_divot;
|
||||
bool vi_ispal;
|
||||
};
|
||||
|
||||
class RdpUpdate
|
||||
{
|
||||
public:
|
||||
void init();
|
||||
bool update(RdpUpdateResult & _result);
|
||||
|
||||
private:
|
||||
u32 oldvstart = 0U;
|
||||
u32 prevvicurrent = 0U;
|
||||
bool prevwasblank = false;
|
||||
bool prevserrate = false;
|
||||
bool oldlowerfield = false;
|
||||
s32 emucontrolsvicurrent = -1;
|
||||
} m_rdpUpdate;
|
||||
};
|
||||
|
||||
inline
|
||||
|
|
Loading…
Reference in New Issue
Block a user