mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-07-29 00:59:44 -06:00
VideoSoftware: Added Real XFB support.
Massivly increases the accuracy of VideoSoftware, if it's going to be slow, it might as well be accurate. * Fixes flickering issues in games which double render to get Hardware AA, like the Peach's Castle tech demo. * Rouge Squadren 2's Cantina Intro doesn't flicker anymore, but it duplicates the top half of the screen onto the bottom. * Any games which need RealXFB support should now work in Video Software
This commit is contained in:
@ -8,16 +8,13 @@
|
||||
#include "BPMemLoader.h"
|
||||
#include "LookUpTables.h"
|
||||
#include "SWPixelEngine.h"
|
||||
#include "HW/Memmap.h"
|
||||
|
||||
|
||||
u8 efb[EFB_WIDTH*EFB_HEIGHT*6];
|
||||
|
||||
|
||||
namespace EfbInterface
|
||||
{
|
||||
|
||||
u8 efbColorTexture[EFB_WIDTH*EFB_HEIGHT*4];
|
||||
|
||||
inline u32 GetColorOffset(u16 x, u16 y)
|
||||
{
|
||||
return (x + y * EFB_WIDTH) * 3;
|
||||
@ -31,7 +28,6 @@ namespace EfbInterface
|
||||
void DoState(PointerWrap &p)
|
||||
{
|
||||
p.DoArray(efb, EFB_WIDTH*EFB_HEIGHT*6);
|
||||
p.DoArray(efbColorTexture, EFB_WIDTH*EFB_HEIGHT*4);
|
||||
}
|
||||
|
||||
void SetPixelAlphaOnly(u32 offset, u8 a)
|
||||
@ -469,6 +465,19 @@ namespace EfbInterface
|
||||
GetPixelColor(offset, color);
|
||||
}
|
||||
|
||||
// For internal used only, return a non-normalized value, which saves work later.
|
||||
void GetColorYUV(u16 x, u16 y, yuv444 *out)
|
||||
{
|
||||
u8 color[4];
|
||||
GetColor(x, y, color);
|
||||
|
||||
// GameCube/Wii uses the BT.601 standard algorithm for converting to YCbCr; see
|
||||
// http://www.equasys.de/colorconversion.html#YCbCr-RGBColorFormatConversion
|
||||
out->Y = 0.257f * color[RED_C] + 0.504f * color[GRN_C] + 0.098f * color[BLU_C];
|
||||
out->U = -0.148f * color[RED_C] + -0.291f * color[GRN_C] + 0.439f * color[BLU_C];
|
||||
out->V = 0.439f * color[RED_C] + -0.368f * color[GRN_C] + -0.071f * color[BLU_C];
|
||||
}
|
||||
|
||||
u32 GetDepth(u16 x, u16 y)
|
||||
{
|
||||
u32 offset = GetDepthOffset(x, y);
|
||||
@ -482,22 +491,56 @@ namespace EfbInterface
|
||||
return &efb[GetColorOffset(x, y)];
|
||||
}
|
||||
|
||||
void UpdateColorTexture()
|
||||
{
|
||||
u32 color;
|
||||
u8* colorPtr = (u8*)&color;
|
||||
u32* texturePtr = (u32*)efbColorTexture;
|
||||
u32 textureAddress = 0;
|
||||
u32 efbOffset = 0;
|
||||
void CopyToXFB(yuv422_packed* xfb_in_ram, u32 fbWidth, u32 fbHeight, const EFBRectangle& sourceRc, float Gamma) {
|
||||
// FIXME: We should do Gamma correction
|
||||
|
||||
for (u16 y = 0; y < EFB_HEIGHT; y++)
|
||||
if (!xfb_in_ram)
|
||||
{
|
||||
for (u16 x = 0; x < EFB_WIDTH; x++)
|
||||
WARN_LOG(VIDEO, "Tried to copy to invalid XFB address");
|
||||
return;
|
||||
}
|
||||
|
||||
int left = sourceRc.left;
|
||||
int right = sourceRc.right;
|
||||
|
||||
// this assumes copies will always start on an even (YU) pixel and the
|
||||
// copy always has an even width, which might not be true.
|
||||
if (left & 1 || right & 1) {
|
||||
WARN_LOG(VIDEO, "Trying to copy XFB to from unaligned EFB source");
|
||||
// this will show up as wrongly encoded
|
||||
}
|
||||
|
||||
// Scanline buffer, leave room for borders
|
||||
yuv444 scanline[640+2];
|
||||
|
||||
// our internal yuv444 type is not normalized, so black is {0, 0, 0} instead of {16, 128, 128}
|
||||
scanline[0] = {0, 0, 0}; // black border at start
|
||||
scanline[right+1] = {0, 0, 0}; // black border at end
|
||||
|
||||
for (u16 y = sourceRc.top; y < sourceRc.bottom; y++)
|
||||
{
|
||||
// Get a scanline of YUV pixels in 4:4:4 format
|
||||
|
||||
for (int i = 1, x = left; x < right; i++, x++)
|
||||
{
|
||||
GetPixelColor(efbOffset, colorPtr);
|
||||
efbOffset += 3;
|
||||
texturePtr[textureAddress++] = Common::swap32(color); // ABGR->RGBA
|
||||
GetColorYUV(x, y, &scanline[i]);
|
||||
}
|
||||
|
||||
// And Downsample them to 4:2:2
|
||||
for (int i = 1, x = left; x < right; i+=2, x+=2)
|
||||
{
|
||||
// YU pixel
|
||||
xfb_in_ram[x].Y = scanline[i].Y;
|
||||
// U[i] = 1/4 * U[i-1] + 1/2 * U[i] + 1/4 U[i+1]
|
||||
// we add in 10 bit space so it will round more accurately
|
||||
xfb_in_ram[x].UV = 128 + ((scanline[i-1].U + (scanline[i].U << 1) + scanline[i+1].U) >> 2);
|
||||
|
||||
// YV pixel
|
||||
xfb_in_ram[x+1].Y = scanline[i+1].Y;
|
||||
// V[i] = 1/4 * V[i-1] + 1/2 * V[i] + 1/4 V[i+1]
|
||||
xfb_in_ram[x+1].UV = 128 + ((scanline[i].V + (scanline[i+1].V << 1) + scanline[i+2].V) >> 2);
|
||||
}
|
||||
xfb_in_ram += 640;
|
||||
}
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user