update octoshock to Mednafen 1.27.1 (#2989)

* update octoshock to Mednafen 1.27.1

* oh right, gotta add in video changes too
This commit is contained in:
CasualPokePlayer 2021-11-02 20:15:54 -07:00 committed by GitHub
parent 9bcedb2dab
commit f5940e12e2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 721 additions and 464 deletions

Binary file not shown.

View File

@ -62,6 +62,7 @@
<ClCompile Include="..\psx\timer.cpp" />
<ClCompile Include="..\Stream.cpp" />
<ClCompile Include="..\tests.cpp" />
<ClCompile Include="..\video\convert.cpp" />
<ClCompile Include="..\video\Deinterlacer.cpp" />
<ClCompile Include="..\video\surface.cpp" />
</ItemGroup>
@ -103,6 +104,7 @@
<ClInclude Include="..\psx\spu.h" />
<ClInclude Include="..\psx\timer.h" />
<ClInclude Include="..\Stream.h" />
<ClCompile Include="..\video\convert.h" />
<ClInclude Include="..\video\Deinterlacer.h" />
<ClInclude Include="..\video\surface.h" />
</ItemGroup>

View File

@ -96,6 +96,9 @@
<ClCompile Include="..\video\Deinterlacer.cpp">
<Filter>video</Filter>
</ClCompile>
<ClInclude Include="..\video\convert.cpp">
<Filter>video</Filter>
</ClInclude>
<ClCompile Include="..\emuware\EW_state.cpp">
<Filter>emuware</Filter>
</ClCompile>
@ -216,6 +219,9 @@
<ClInclude Include="..\video\Deinterlacer.h">
<Filter>video</Filter>
</ClInclude>
<ClInclude Include="..\video\convert.h">
<Filter>video</Filter>
</ClInclude>
<ClInclude Include="..\emuware\EW_state.h">
<Filter>emuware</Filter>
</ClInclude>

View File

@ -35,7 +35,7 @@
Gran Turismo (missing music; GetLocL must be valid and sector data must be ready simultaneous with clearing of status seek bit and setting of reading bit)
Harukanaru Toki no Naka de - Banjou Yuugi (needs GetLocL to reflect dancing around target seek position after seek completes; otherwise hangs on voice acting)
Incredible Crisis (needs GetLocL to be valid after a SeekL; otherwise hangs without music near start of "Etsuko and the Golden Pig")
Tomb Raider(needs GetLocP to reflect dancing around target seek position after seek completes; otherwise, CD-DA tracks at M:S:F=x:x:0 fail to play and game hangs)
Tomb Raider(needs GetLocP to reflect dancing around just before target seek position after seek completes; otherwise, CD-DA tracks at M:S:F=x:x:0 fail to play and game hangs)
Vib Ribbon, with extra audio CD
Mortal Kombat Trilogy, music resumption after pause.
@ -190,6 +190,9 @@ void PS_CDC::SoftReset(void)
{
ClearAudioBuffers();
ReportLastF = 0;
ReportStartupDelay = 0;
// Not sure about initial volume state
Pending_DecodeVolume[0][0] = 0x80;
Pending_DecodeVolume[0][1] = 0x00;
@ -201,6 +204,10 @@ void PS_CDC::SoftReset(void)
memset(ArgsBuf, 0, sizeof(ArgsBuf));
ArgsWP = ArgsRP = 0;
ArgsReceiveLatch = 0;
memset(ArgsReceiveBuf, 0, sizeof(ArgsReceiveBuf));
ArgsReceiveIn = 0;
memset(ResultsBuffer, 0, sizeof(ResultsBuffer));
ResultsWP = 0;
ResultsRP = 0;
@ -265,6 +272,10 @@ void PS_CDC::Power(void)
{
SPU->Power();
memset(SectorPipe, 0, sizeof(SectorPipe));
memset(SB, 0, sizeof(SB));
memset(AsyncResultsPending, 0, sizeof(AsyncResultsPending));
memset(&DMABuffer.data[0], 0, DMABuffer.data.size());
SoftReset();
HoldLogicalPos = false;
@ -370,10 +381,6 @@ SYNCFUNC(PS_CDC)
NSS(CommandLoc_Dirty);
NSS(xa_previous);
NSS(xa_cur_set);
NSS(xa_cur_file);
NSS(xa_cur_chan);
NSS(ReportLastF);
NSS(ReportStartupDelay);
@ -677,23 +684,6 @@ bool PS_CDC::XA_Test(const uint8 *sdata)
if((Mode & MODE_SF) && (sh->file != FilterFile || sh->channel != FilterChan))
return false;
if(!xa_cur_set || (Mode & MODE_SF))
{
xa_cur_set = true;
xa_cur_file = sh->file;
xa_cur_chan = sh->channel;
}
else if(sh->file != xa_cur_file || sh->channel != xa_cur_chan)
return false;
if(sh->submode & XA_SUBMODE_EOF)
{
//puts("YAY");
xa_cur_set = false;
xa_cur_file = 0;
xa_cur_chan = 0;
}
return true;
}
@ -702,10 +692,6 @@ void PS_CDC::ClearAudioBuffers(void)
memset(&AudioBuffer, 0, sizeof(AudioBuffer));
memset(xa_previous, 0, sizeof(xa_previous));
xa_cur_set = false;
xa_cur_file = 0;
xa_cur_chan = 0;
memset(ADPCM_ResampBuf, 0, sizeof(ADPCM_ResampBuf));
ADPCM_ResampCurPhase = 0;
ADPCM_ResampCurPos = 0;
@ -1161,7 +1147,7 @@ void PS_CDC::HandlePlayRead(void)
if(DriveStatus == DS_PAUSED || DriveStatus == DS_STANDBY) // || DriveStatus == DS_SEEKING_LOGICAL2)
{
if(CurSector >= (SeekTarget + 2))
if(CurSector >= (SeekTarget + (HoldLogicalPos ? 2 : 0)))
CurSector = std::max<int32>(-150, CurSector - 9);
}
else
@ -1258,6 +1244,9 @@ pscpu_timestamp_t PS_CDC::Update(const pscpu_timestamp_t timestamp)
SeekFinished = true;
ReportStartupDelay = 24000000;
if(DriveStatus == DS_PAUSED || DriveStatus == DS_STANDBY)
CurSector = std::max<int32>(-150, CurSector - 9);
PSRCounter = 33868800 / (75 * ((Mode & MODE_SPEED) ? 2 : 1));
}
else if(DriveStatus == DS_SEEKING_LOGICAL)

View File

@ -242,9 +242,6 @@ class PS_CDC
bool XA_Test(const uint8 *sdata);
void XA_ProcessSector(const uint8 *sdata, CD_Audio_Buffer *ab);
int16 xa_previous[2][2];
bool xa_cur_set;
uint8 xa_cur_file;
uint8 xa_cur_chan;
uint8 ReportLastF;
int32 ReportStartupDelay;
@ -263,7 +260,7 @@ class PS_CDC
void PreSeekHack(int32 target);
void ReadBase(void);
static const CDC_CTEntry Commands[0x20];
MDFN_HIDE static const CDC_CTEntry Commands[0x20];
int32 Command_Nop(const int arg_count, const uint8 *args);
int32 Command_Setloc(const int arg_count, const uint8 *args);

View File

@ -1478,7 +1478,7 @@ MDFN_FASTCALL pscpu_timestamp_t GPU_Update(const pscpu_timestamp_t sys_timestamp
}
else
{
PSX_GPULineHook(sys_timestamp, sys_timestamp - ((uint64)gpu_clocks * 65536) / GPUClockRatio, scanline == 0, NULL, &surface->format, 0, 0, 0, 0);
PSX_GPULineHook(sys_timestamp, sys_timestamp - ((uint64)gpu_clocks * 65536) / GPUClockRatio, scanline == 0, NULL, NULL, 0, 0, 0, 0);
}
if(!InVBlank)

View File

@ -147,25 +147,21 @@ InputDevice_Memcard::~InputDevice_Memcard()
void InputDevice_Memcard::Power(void)
{
presence_new = true;
memset(rw_buffer, 0, sizeof(rw_buffer));
write_xor = 0;
dtr = 0;
//buttons[0] = buttons[1] = 0;
command_phase = 0;
bitpos = 0;
receive_buffer = 0;
command = 0;
addr = 0;
calced_xor = 0;
transmit_buffer = 0;
transmit_count = 0;
addr = 0;
presence_new = true;
}
void InputDevice_Memcard::SyncState(bool isReader, EW::NewState *ns)

View File

@ -1399,7 +1399,7 @@ EW_EXPORT s32 shock_Create(void** psx, s32 region, void* firmware512k)
//setup gpu output surfaces
MDFN_PixelFormat nf(MDFN_COLORSPACE_RGB, 16, 8, 0, 24);
MDFN_PixelFormat nf(MDFN_COLORSPACE_RGB, 4, 16, 8, 0, 24);
for(int i=0;i<2;i++)
{
VTBuffer[i] = new MDFN_Surface(NULL, FB_WIDTH, FB_HEIGHT, FB_WIDTH, nf);

View File

@ -178,7 +178,7 @@ void PS_SPU::Power(void)
CWA = 0;
memset(Regs, 0, sizeof(Regs));
memset(AuxRegs, 0, sizeof(AuxRegs));
memset(RDSB, 0, sizeof(RDSB));
memset(RUSB, 0, sizeof(RUSB));
RvbResPos = 0;

View File

@ -219,28 +219,17 @@ void RunReverb(const int32* in, int32* out);
int16 IIR_COEF;
int16 FB_ALPHA;
int16 FB_X;
uint16 IIR_DEST_A0;
uint16 IIR_DEST_A1;
uint16 ACC_SRC_A0;
uint16 ACC_SRC_A1;
uint16 ACC_SRC_B0;
uint16 ACC_SRC_B1;
uint16 IIR_SRC_A0;
uint16 IIR_SRC_A1;
uint16 IIR_DEST_B0;
uint16 IIR_DEST_B1;
uint16 ACC_SRC_C0;
uint16 ACC_SRC_C1;
uint16 ACC_SRC_D0;
uint16 ACC_SRC_D1;
uint16 IIR_SRC_B1;
uint16 IIR_SRC_B0;
uint16 MIX_DEST_A0;
uint16 MIX_DEST_A1;
uint16 MIX_DEST_B0;
uint16 MIX_DEST_B1;
int16 IN_COEF_L;
int16 IN_COEF_R;
uint16 IIR_DEST_A[2];
uint16 ACC_SRC_A[2];
uint16 ACC_SRC_B[2];
uint16 IIR_SRC_A[2];
uint16 IIR_DEST_B[2];
uint16 ACC_SRC_C[2];
uint16 ACC_SRC_D[2];
uint16 IIR_SRC_B[2];
uint16 MIX_DEST_A[2];
uint16 MIX_DEST_B[2];
int16 IN_COEF[2];
};
};
};

View File

@ -31,6 +31,13 @@ static INLINE int16 ReverbSat(int32 samp)
return(samp);
}
static INLINE int16 ReverbNeg(int16 samp)
{
if(samp == -32768)
return 0x7FFF;
return -samp;
}
INLINE uint32 PS_SPU::Get_Reverb_Offset(uint32 in_offset)
{
@ -54,7 +61,8 @@ int16 NO_INLINE PS_SPU::RD_RVB(uint16 raw_offs, int32 extra_offs)
void NO_INLINE PS_SPU::WR_RVB(uint16 raw_offs, int16 sample)
{
WriteSPURAM(Get_Reverb_Offset(raw_offs << 2), sample);
if(SPUControl & 0x80)
WriteSPURAM(Get_Reverb_Offset(raw_offs << 2), sample);
}
//
@ -140,77 +148,70 @@ INLINE void PS_SPU::RunReverb(const int32* in, int32* out)
int32 downsampled[2];
for(unsigned lr = 0; lr < 2; lr++)
downsampled[lr] = Reverb4422(&RDSB[lr][(RvbResPos - 39) & 0x3F]);
downsampled[lr] = Reverb4422(&RDSB[lr][(RvbResPos - 38) & 0x3F]);
//
// Run algorithm
///
if(SPUControl & 0x80)
{
int16 IIR_INPUT_A0, IIR_INPUT_A1, IIR_INPUT_B0, IIR_INPUT_B1;
int16 IIR_A0, IIR_A1, IIR_B0, IIR_B1;
int16 ACC0, ACC1;
int16 FB_A0, FB_A1, FB_B0, FB_B1;
IIR_INPUT_A0 = ReverbSat(((RD_RVB(IIR_SRC_A0) * IIR_COEF) >> 15) + ((downsampled[0] * IN_COEF_L) >> 15));
IIR_INPUT_A1 = ReverbSat(((RD_RVB(IIR_SRC_A1) * IIR_COEF) >> 15) + ((downsampled[1] * IN_COEF_R) >> 15));
IIR_INPUT_B0 = ReverbSat(((RD_RVB(IIR_SRC_B0) * IIR_COEF) >> 15) + ((downsampled[0] * IN_COEF_L) >> 15));
IIR_INPUT_B1 = ReverbSat(((RD_RVB(IIR_SRC_B1) * IIR_COEF) >> 15) + ((downsampled[1] * IN_COEF_R) >> 15));
IIR_A0 = ReverbSat((((IIR_INPUT_A0 * IIR_ALPHA) >> 14) + (IIASM(IIR_ALPHA, RD_RVB(IIR_DEST_A0, -1)) >> 14)) >> 1);
IIR_A1 = ReverbSat((((IIR_INPUT_A1 * IIR_ALPHA) >> 14) + (IIASM(IIR_ALPHA, RD_RVB(IIR_DEST_A1, -1)) >> 14)) >> 1);
IIR_B0 = ReverbSat((((IIR_INPUT_B0 * IIR_ALPHA) >> 14) + (IIASM(IIR_ALPHA, RD_RVB(IIR_DEST_B0, -1)) >> 14)) >> 1);
IIR_B1 = ReverbSat((((IIR_INPUT_B1 * IIR_ALPHA) >> 14) + (IIASM(IIR_ALPHA, RD_RVB(IIR_DEST_B1, -1)) >> 14)) >> 1);
WR_RVB(IIR_DEST_A0, IIR_A0);
WR_RVB(IIR_DEST_A1, IIR_A1);
WR_RVB(IIR_DEST_B0, IIR_B0);
WR_RVB(IIR_DEST_B1, IIR_B1);
ACC0 = ReverbSat((((RD_RVB(ACC_SRC_A0) * ACC_COEF_A) >> 14) +
((RD_RVB(ACC_SRC_B0) * ACC_COEF_B) >> 14) +
((RD_RVB(ACC_SRC_C0) * ACC_COEF_C) >> 14) +
((RD_RVB(ACC_SRC_D0) * ACC_COEF_D) >> 14)) >> 1);
ACC1 = ReverbSat((((RD_RVB(ACC_SRC_A1) * ACC_COEF_A) >> 14) +
((RD_RVB(ACC_SRC_B1) * ACC_COEF_B) >> 14) +
((RD_RVB(ACC_SRC_C1) * ACC_COEF_C) >> 14) +
((RD_RVB(ACC_SRC_D1) * ACC_COEF_D) >> 14)) >> 1);
FB_A0 = RD_RVB(MIX_DEST_A0 - FB_SRC_A);
FB_A1 = RD_RVB(MIX_DEST_A1 - FB_SRC_A);
FB_B0 = RD_RVB(MIX_DEST_B0 - FB_SRC_B);
FB_B1 = RD_RVB(MIX_DEST_B1 - FB_SRC_B);
WR_RVB(MIX_DEST_A0, ReverbSat(ACC0 - ((FB_A0 * FB_ALPHA) >> 15)));
WR_RVB(MIX_DEST_A1, ReverbSat(ACC1 - ((FB_A1 * FB_ALPHA) >> 15)));
WR_RVB(MIX_DEST_B0, ReverbSat(((FB_ALPHA * ACC0) >> 15) - ((FB_A0 * (int16)(0x8000 ^ FB_ALPHA)) >> 15) - ((FB_B0 * FB_X) >> 15)));
WR_RVB(MIX_DEST_B1, ReverbSat(((FB_ALPHA * ACC1) >> 15) - ((FB_A1 * (int16)(0x8000 ^ FB_ALPHA)) >> 15) - ((FB_B1 * FB_X) >> 15)));
}
//
// Get output samples
//
RUSB[0][(RvbResPos >> 1) | 0x20] = RUSB[0][RvbResPos >> 1] = (RD_RVB(MIX_DEST_A0) + RD_RVB(MIX_DEST_B0)) >> 1;
RUSB[1][(RvbResPos >> 1) | 0x20] = RUSB[1][RvbResPos >> 1] = (RD_RVB(MIX_DEST_A1) + RD_RVB(MIX_DEST_B1)) >> 1;
for(unsigned lr = 0; lr < 2; lr++)
{
const int16 IIR_INPUT_A = ReverbSat((((RD_RVB(IIR_SRC_A[lr ^ 0]) * IIR_COEF) >> 14) + ((downsampled[lr] * IN_COEF[lr]) >> 14)) >> 1);
const int16 IIR_INPUT_B = ReverbSat((((RD_RVB(IIR_SRC_B[lr ^ 1]) * IIR_COEF) >> 14) + ((downsampled[lr] * IN_COEF[lr]) >> 14)) >> 1);
const int16 IIR_A = ReverbSat((((IIR_INPUT_A * IIR_ALPHA) >> 14) + (IIASM(IIR_ALPHA, RD_RVB(IIR_DEST_A[lr], -1)) >> 14)) >> 1);
const int16 IIR_B = ReverbSat((((IIR_INPUT_B * IIR_ALPHA) >> 14) + (IIASM(IIR_ALPHA, RD_RVB(IIR_DEST_B[lr], -1)) >> 14)) >> 1);
WR_RVB(IIR_DEST_A[lr], IIR_A);
WR_RVB(IIR_DEST_B[lr], IIR_B);
const int32 ACC = ((RD_RVB(ACC_SRC_A[lr]) * ACC_COEF_A) >> 14) +
((RD_RVB(ACC_SRC_B[lr]) * ACC_COEF_B) >> 14) +
((RD_RVB(ACC_SRC_C[lr]) * ACC_COEF_C) >> 14) +
((RD_RVB(ACC_SRC_D[lr]) * ACC_COEF_D) >> 14);
const int16 FB_A = RD_RVB(MIX_DEST_A[lr] - FB_SRC_A);
const int16 FB_B = RD_RVB(MIX_DEST_B[lr] - FB_SRC_B);
const int16 MDA = ReverbSat((ACC + ((FB_A * ReverbNeg(FB_ALPHA)) >> 14)) >> 1);
const int16 MDB = ReverbSat(FB_A + ((((MDA * FB_ALPHA) >> 14) + ((FB_B * ReverbNeg(FB_X)) >> 14)) >> 1));
const int16 IVB = ReverbSat(FB_B + ((MDB * FB_X) >> 15));
WR_RVB(MIX_DEST_A[lr], MDA);
WR_RVB(MIX_DEST_B[lr], MDB);
#if 0
{
static uint32 sqcounter;
RUSB[lr][(RvbResPos >> 1) | 0x20] = RUSB[lr][RvbResPos >> 1] = ((sqcounter & 0xFF) == 0) ? 0x8000 : 0x0000; //((sqcounter & 0x80) ? 0x7000 : 0x9000);
sqcounter += lr;
}
#else
RUSB[lr][(RvbResPos >> 1) | 0x20] = RUSB[lr][RvbResPos >> 1] = IVB; // Output sample
#endif
}
//
//
//
ReverbCur = (ReverbCur + 1) & 0x3FFFF;
if(!ReverbCur)
ReverbCur = ReverbWA;
for(unsigned lr = 0; lr < 2; lr++)
upsampled[lr] = Reverb2244<true>(&RUSB[lr][((RvbResPos - 39) & 0x3F) >> 1]);
upsampled[lr] = Reverb2244<false>(&RUSB[lr][((RvbResPos >> 1) - 19) & 0x1F]);
}
else
{
for(unsigned lr = 0; lr < 2; lr++)
upsampled[lr] = Reverb2244<false>(&RUSB[lr][((RvbResPos - 39) & 0x3F) >> 1]);
upsampled[lr] = Reverb2244<true>(&RUSB[lr][((RvbResPos >> 1) - 19) & 0x1F]);
}
RvbResPos = (RvbResPos + 1) & 0x3F;
for(unsigned lr = 0; lr < 2; lr++)
{
#if 0
if(!lr)
printf("%d\n", (-upsampled[lr]) >> 1);
#endif
out[lr] = upsampled[lr];
}
}

View File

@ -181,19 +181,19 @@ void Deinterlacer::Process(MDFN_Surface *surface, MDFN_Rect &DisplayRect, int32
}
}
switch(surface->format.bpp)
switch (surface->format.opp)
{
case 8:
InternalProcess<uint8>(surface, DisplayRect, LineWidths, field);
break;
case 1:
InternalProcess<uint8>(surface, DisplayRect, LineWidths, field);
break;
case 16:
InternalProcess<uint16>(surface, DisplayRect, LineWidths, field);
break;
case 2:
InternalProcess<uint16>(surface, DisplayRect, LineWidths, field);
break;
case 32:
InternalProcess<uint32>(surface, DisplayRect, LineWidths, field);
break;
case 4:
InternalProcess<uint32>(surface, DisplayRect, LineWidths, field);
break;
}
PrevDRect = DisplayRect_Original;

View File

@ -0,0 +1,248 @@
/******************************************************************************/
/* Mednafen - Multi-system Emulator */
/******************************************************************************/
/* convert.cpp - Pixel format conversion
** Copyright (C) 2020 Mednafen Team
**
** This program is free software; you can redistribute it and/or
** modify it under the terms of the GNU General Public License
** as published by the Free Software Foundation; either version 2
** of the License, or (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program; if not, write to the Free Software Foundation, Inc.,
** 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "octoshock.h"
#include "surface.h"
#include "convert.h"
template<bool src_equals_dest, typename OT, typename NT, uint8 old_colorspace, uint8 new_colorspace>
static NO_INLINE void Convert_Slow(const void* src, void* dest, uint32 count, const MDFN_PixelFormatConverter::convert_context* ctx)
{
MDFN_PixelFormat old_pf = ctx->spf;
MDFN_PixelFormat new_pf = ctx->dpf;
old_pf.opp = sizeof(OT);
new_pf.opp = sizeof(NT);
old_pf.colorspace = old_colorspace;
new_pf.colorspace = new_colorspace;
//
//
OT* src_row = (OT*)src;
NT* dest_row = src_equals_dest ? (NT*)src_row : (NT*)dest;
for(unsigned x = 0; MDFN_LIKELY(x < count); x++)
{
if(sizeof(OT) == 1)
dest_row[x] = ctx->palconv[src_row[x]];
else
{
int r, g, b, a;
old_pf.DecodeColor(src_row[x], r, g, b, a);
dest_row[x] = new_pf.MakeColor(r, g, b, a);
}
}
}
template<bool src_equals_dest, typename OT, typename NT, uint64 old_pftag, uint64 new_pftag>
static NO_INLINE void Convert_Fast(const void* src, void* dest, uint32 count, const MDFN_PixelFormatConverter::convert_context* ctx)
{
const MDFN_PixelFormat old_pf = MDFN_PixelFormat(old_pftag);
const MDFN_PixelFormat new_pf = MDFN_PixelFormat(new_pftag);
OT* src_row = (OT*)src;
NT* dest_row = src_equals_dest ? (NT*)src_row : (NT*)dest;
for(unsigned x = 0; MDFN_LIKELY(x < count); x++)
{
uint32 c = src_row[x];
if(sizeof(OT) == 1)
dest_row[x] = ctx->palconv[c];
else if(old_pftag == MDFN_PixelFormat::IRGB16_1555 && new_pftag == MDFN_PixelFormat::RGB16_565)
dest_row[x] = (c & 0x1F) | ((c << 1) & 0xF800) | (MDFN_PixelFormat::LUT8to6[MDFN_PixelFormat::LUT5to8[(c >> 5) & 0x1F]] << 5);
else if(old_pftag == MDFN_PixelFormat::RGB16_565 && new_pftag == MDFN_PixelFormat::IRGB16_1555)
dest_row[x] = (c & 0x1F) | ((c >> 1) & 0x7C00) | (MDFN_PixelFormat::LUT8to5[MDFN_PixelFormat::LUT6to8[(c >> 5) & 0x3F]] << 5);
else
{
int r, g, b, a;
if(old_pftag == MDFN_PixelFormat::IRGB16_1555)
{
r = MDFN_PixelFormat::LUT5to8[(c >> 10) & 0x1F];
g = MDFN_PixelFormat::LUT5to8[(c >> 5) & 0x1F];
b = MDFN_PixelFormat::LUT5to8[(c >> 0) & 0x1F];
a = 0;
}
else if(old_pftag == MDFN_PixelFormat::RGB16_565)
{
r = MDFN_PixelFormat::LUT5to8[(c >> 11) & 0x1F];
g = MDFN_PixelFormat::LUT6to8[(c >> 5) & 0x3F];
b = MDFN_PixelFormat::LUT5to8[(c >> 0) & 0x1F];
a = 0;
}
else if(old_pftag == MDFN_PixelFormat::ARGB16_4444)
{
a = ((c & 0xF000) >> 8) | ((c & 0xF000) >> 12);
r = ((c & 0xF00) >> 4) | ((c & 0xF00) >> 8);
g = ((c & 0xF0) >> 0) | ((c & 0xF0) >> 4);
b = ((c & 0xF) << 4) | ((c & 0xF) >> 0);
}
else
old_pf.DecodeColor(c, r, g, b, a);
/*
if(new_pftag == MDFN_PixelFormat::RGB8X3_888 || new_pftag == MDFN_PixelFormat::BGR8X3_888)
{
if(new_pftag == MDFN_PixelFormat::RGB8X3_888)
{
dest_row[x * 3 + 0] = r;
dest_row[x * 3 + 1] = g;
dest_row[x * 3 + 2] = b;
}
else
{
dest_row[x * 3 + 0] = b;
dest_row[x * 3 + 1] = g;
dest_row[x * 3 + 2] = r;
}
}
else
*/
{
if(new_pftag == MDFN_PixelFormat::IRGB16_1555)
c = (MDFN_PixelFormat::LUT8to5[r] << 10) | (MDFN_PixelFormat::LUT8to5[g] << 5) | (MDFN_PixelFormat::LUT8to5[b] << 0);
else if(new_pftag == MDFN_PixelFormat::RGB16_565)
c = (MDFN_PixelFormat::LUT8to5[r] << 11) | (MDFN_PixelFormat::LUT8to6[g] << 5) | (MDFN_PixelFormat::LUT8to5[b] << 0);
else
c = new_pf.MakeColor(r, g, b, a);
dest_row[x] = c;
}
}
}
}
template<bool src_equals_dest>
static void Convert_xxxx8888(const void* src, void* dest, uint32 count, const MDFN_PixelFormatConverter::convert_context* ctx)
{
const MDFN_PixelFormat spf = ctx->spf;
const MDFN_PixelFormat dpf = ctx->dpf;
const unsigned tmp = (0 << spf.Rshift) | (1 << spf.Gshift) | (2 << spf.Bshift) | (3 << spf.Ashift);
const unsigned drs[4] = { dpf.Rshift, dpf.Gshift, dpf.Bshift, dpf.Ashift };
const unsigned sh[4] = { (uint8)drs[(tmp >> 0) & 3], (uint8)drs[(tmp >> 8) & 3], (uint8)drs[(tmp >> 16) & 3], (uint8)drs[(tmp >> 24) & 3] };
uint32* src_row = (uint32*)src;
uint32* dest_row = src_equals_dest ? src_row : (uint32*)dest;
for(unsigned x = 0; MDFN_LIKELY(x < count); x++)
{
uint32 c = src_row[x];
dest_row[x] = ((uint8)(c >> 0) << sh[0]) | ((uint8)(c >> 8) << sh[1]) | ((uint8)(c >> 16) << sh[2]) | ((uint8)(c >> 24) << sh[3]);
}
}
template<bool src_equals_dest>
static MDFN_PixelFormatConverter::convert_func CalcConversionFunction(const MDFN_PixelFormat& spf, const MDFN_PixelFormat& dpf)
{
#if 1
switch(spf.tag)
{
#define CROWE(st, sft, dt, dft) case MDFN_PixelFormat::dft: return Convert_Fast<src_equals_dest, st, dt, MDFN_PixelFormat::sft, MDFN_PixelFormat::dft>;
#define CROW(st, sft) case MDFN_PixelFormat::sft: \
switch(dpf.tag) \
{ \
default: break; \
CROWE(st, sft, uint32, ABGR32_8888) \
CROWE(st, sft, uint32, ARGB32_8888) \
CROWE(st, sft, uint32, RGBA32_8888) \
CROWE(st, sft, uint32, BGRA32_8888) \
CROWE(st, sft, uint16, IRGB16_1555) \
CROWE(st, sft, uint16, RGB16_565) \
CROWE(st, sft, uint16, ARGB16_4444) \
/*CROWE(st, sft, uint8, RGB8X3_888)*/ \
/*CROWE(st, sft, uint8, RGB8X3_888)*/ \
} \
break;
default: break;
CROW(uint32, ABGR32_8888)
CROW(uint32, ARGB32_8888)
CROW(uint32, RGBA32_8888)
CROW(uint32, BGRA32_8888)
CROW(uint16, IRGB16_1555)
CROW(uint16, RGB16_565)
CROW(uint16, ARGB16_4444)
//
//CROW(uint8, RGB8P_888)
//CROW(uint8, RGB8P_666)
#undef CROWE
#undef CROW
}
#endif
#if 1
if(spf.opp == dpf.opp && spf.colorspace == dpf.colorspace)
{
if(spf.opp == 4 && !((spf.Rshift | spf.Gshift | spf.Bshift | spf.Ashift | dpf.Rshift | dpf.Gshift | dpf.Bshift | dpf.Ashift) & 7))
{
return Convert_xxxx8888<src_equals_dest>;
}
}
#endif
//
// Slow fallback:
//
#define CROWE(scs, stype, dcs, dtype) case (dcs << 4) | sizeof(dtype): return Convert_Slow<src_equals_dest, stype, dtype, scs, dcs>; break;
#define CROW(scs, stype) \
case (scs << 4) | sizeof(stype): \
switch((dpf.colorspace << 4) | dpf.opp) \
{ \
CROWE(scs, stype, MDFN_COLORSPACE_RGB, uint8) \
CROWE(scs, stype, MDFN_COLORSPACE_RGB, uint16) \
CROWE(scs, stype, MDFN_COLORSPACE_RGB, uint32) \
} \
break;
switch((spf.colorspace << 4) | spf.opp)
{
CROW(MDFN_COLORSPACE_RGB, uint8)
CROW(MDFN_COLORSPACE_RGB, uint16)
CROW(MDFN_COLORSPACE_RGB, uint32)
}
#undef CROWE
#undef CROW
return nullptr;
}
MDFN_PixelFormatConverter::MDFN_PixelFormatConverter(const MDFN_PixelFormat& src_pf, const MDFN_PixelFormat& dest_pf, const MDFN_PaletteEntry* palette)
{
ctx.spf = src_pf;
ctx.dpf = dest_pf;
if(palette)
{
ctx.palconv.reset(new uint32[256]);
for(unsigned i = 0; i < 256; i++)
{
uint8 r, g, b;
ctx.spf.DecodePColor(palette[i], r, g, b);
ctx.palconv[i] = ctx.dpf.MakeColor(r, g, b, 0);
}
}
convert1 = CalcConversionFunction<true>(ctx.spf, ctx.dpf);
convert2 = CalcConversionFunction<false>(ctx.spf, ctx.dpf);
}

View File

@ -0,0 +1,59 @@
/******************************************************************************/
/* Mednafen - Multi-system Emulator */
/******************************************************************************/
/* convert.h - Pixel format conversion
** Copyright (C) 2020 Mednafen Team
**
** This program is free software; you can redistribute it and/or
** modify it under the terms of the GNU General Public License
** as published by the Free Software Foundation; either version 2
** of the License, or (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program; if not, write to the Free Software Foundation, Inc.,
** 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef __MDFN_VIDEO_CONVERT_H
#define __MDFN_VIDEO_CONVERT_H
#include <memory>
#include "octoshock.h"
#include "surface.h"
class MDFN_PixelFormatConverter
{
public:
MDFN_PixelFormatConverter(const MDFN_PixelFormat& src_pf, const MDFN_PixelFormat& dest_pf, const MDFN_PaletteEntry* palette = nullptr);
INLINE void Convert(void* dest, uint32 count)
{
convert1(dest, dest, count, &ctx);
}
INLINE void Convert(const void* src, void* dest, uint32 count)
{
convert2(src, dest, count, &ctx);
}
struct convert_context
{
MDFN_PixelFormat spf;
MDFN_PixelFormat dpf;
std::unique_ptr<uint32[]> palconv;
};
typedef void (*convert_func)(const void*, void*, uint32, const convert_context*);
private:
convert_func convert1;
convert_func convert2;
convert_context ctx;
};
#endif

View File

@ -22,38 +22,7 @@
#include <math.h>
#include "octoshock.h"
#include "surface.h"
MDFN_PixelFormat::MDFN_PixelFormat()
{
bpp = 0;
colorspace = 0;
Rshift = 0;
Gshift = 0;
Bshift = 0;
Ashift = 0;
Rprec = 0;
Gprec = 0;
Bprec = 0;
Aprec = 0;
}
MDFN_PixelFormat::MDFN_PixelFormat(const unsigned int p_colorspace, const uint8 p_rs, const uint8 p_gs, const uint8 p_bs, const uint8 p_as)
{
bpp = 32;
colorspace = p_colorspace;
Rshift = p_rs;
Gshift = p_gs;
Bshift = p_bs;
Ashift = p_as;
Rprec = 8;
Gprec = 8;
Bprec = 8;
Aprec = 8;
}
#include "convert.h"
MDFN_Surface::MDFN_Surface()
{
@ -101,16 +70,16 @@ void MDFN_Surface::Resize(const uint32 p_width, const uint32 p_height, const uin
void MDFN_Surface::Init(void *const p_pixels, const uint32 p_width, const uint32 p_height, const uint32 p_pitchinpix, const MDFN_PixelFormat &nf, const bool alloc_init_pixels)
{
void *rpix = NULL;
assert(nf.bpp == 8 || nf.bpp == 16 || nf.bpp == 32);
assert(nf.opp == 1 || nf.opp == 2 || nf.opp == 4);
format = nf;
if(nf.bpp == 8)
if(nf.opp == 1)
{
//assert(!nf.Rshift && !nf.Gshift && !nf.Bshift && !nf.Ashift);
//assert(!nf.Rprec && !nf.Gprec && !nf.Bprec && !nf.Aprec);
}
else if(nf.bpp == 16)
else if(nf.opp == 2)
{
assert(nf.Rprec && nf.Gprec && nf.Bprec && nf.Aprec);
}
@ -140,9 +109,9 @@ void MDFN_Surface::Init(void *const p_pixels, const uint32 p_width, const uint32
else
{
if(alloc_init_pixels)
rpix = calloc(1, p_pitchinpix * p_height * (nf.bpp / 8));
rpix = calloc(1, p_pitchinpix * p_height * nf.opp);
else
rpix = malloc(p_pitchinpix * p_height * (nf.bpp / 8));
rpix = malloc(p_pitchinpix * p_height * nf.opp);
if(!rpix)
{
@ -153,7 +122,7 @@ void MDFN_Surface::Init(void *const p_pixels, const uint32 p_width, const uint32
}
}
if(nf.bpp == 8)
if(nf.opp == 1)
{
if(!(palette = (MDFN_PaletteEntry*) calloc(sizeof(MDFN_PaletteEntry), 256)))
{
@ -167,9 +136,9 @@ void MDFN_Surface::Init(void *const p_pixels, const uint32 p_width, const uint32
}
}
if(nf.bpp == 16)
if(nf.opp == 2)
pixels16 = (uint16 *)rpix;
else if(nf.bpp == 8)
else if(nf.opp == 1)
pixels8 = (uint8 *)rpix;
else
pixels = (uint32 *)rpix;
@ -180,224 +149,135 @@ void MDFN_Surface::Init(void *const p_pixels, const uint32 p_width, const uint32
pitchinpix = p_pitchinpix;
}
const uint8 MDFN_PixelFormat::LUT5to8[32] =
{
0x00, 0x08, 0x10, 0x18, 0x20, 0x29, 0x31, 0x39, 0x41, 0x4a, 0x52, 0x5a, 0x62, 0x6a, 0x73, 0x7b,
0x83, 0x8b, 0x94, 0x9c, 0xa4, 0xac, 0xb4, 0xbd, 0xc5, 0xcd, 0xd5, 0xde, 0xe6, 0xee, 0xf6, 0xff
};
const uint8 MDFN_PixelFormat::LUT6to8[64] =
{
0x00, 0x04, 0x08, 0x0c, 0x10, 0x14, 0x18, 0x1c, 0x20, 0x24, 0x28, 0x2c, 0x30, 0x34, 0x38, 0x3c,
0x40, 0x44, 0x48, 0x4c, 0x50, 0x55, 0x59, 0x5d, 0x61, 0x65, 0x69, 0x6d, 0x71, 0x75, 0x79, 0x7d,
0x81, 0x85, 0x89, 0x8d, 0x91, 0x95, 0x99, 0x9d, 0xa1, 0xa5, 0xaa, 0xae, 0xb2, 0xb6, 0xba, 0xbe,
0xc2, 0xc6, 0xca, 0xce, 0xd2, 0xd6, 0xda, 0xde, 0xe2, 0xe6, 0xea, 0xee, 0xf2, 0xf6, 0xfa, 0xff
};
const uint8 MDFN_PixelFormat::LUT8to5[256] =
{
0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02,
0x02, 0x02, 0x02, 0x02, 0x02, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x04, 0x04, 0x04,
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x06, 0x06,
0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x08, 0x08,
0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x0a,
0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0c,
0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d,
0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13,
0x13, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15,
0x15, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17,
0x17, 0x17, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19,
0x19, 0x19, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b,
0x1b, 0x1b, 0x1b, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d,
0x1d, 0x1d, 0x1d, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f
};
const uint8 MDFN_PixelFormat::LUT8to6[256] =
{
0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02, 0x03, 0x03, 0x03, 0x03, 0x04,
0x04, 0x04, 0x04, 0x05, 0x05, 0x05, 0x05, 0x06, 0x06, 0x06, 0x06, 0x07, 0x07, 0x07, 0x07, 0x08,
0x08, 0x08, 0x08, 0x09, 0x09, 0x09, 0x09, 0x0a, 0x0a, 0x0a, 0x0a, 0x0b, 0x0b, 0x0b, 0x0b, 0x0c,
0x0c, 0x0c, 0x0c, 0x0d, 0x0d, 0x0d, 0x0d, 0x0e, 0x0e, 0x0e, 0x0e, 0x0f, 0x0f, 0x0f, 0x0f, 0x10,
0x10, 0x10, 0x10, 0x11, 0x11, 0x11, 0x11, 0x12, 0x12, 0x12, 0x12, 0x13, 0x13, 0x13, 0x13, 0x14,
0x14, 0x14, 0x14, 0x15, 0x15, 0x15, 0x15, 0x15, 0x16, 0x16, 0x16, 0x16, 0x17, 0x17, 0x17, 0x17,
0x18, 0x18, 0x18, 0x18, 0x19, 0x19, 0x19, 0x19, 0x1a, 0x1a, 0x1a, 0x1a, 0x1b, 0x1b, 0x1b, 0x1b,
0x1c, 0x1c, 0x1c, 0x1c, 0x1d, 0x1d, 0x1d, 0x1d, 0x1e, 0x1e, 0x1e, 0x1e, 0x1f, 0x1f, 0x1f, 0x1f,
0x20, 0x20, 0x20, 0x20, 0x21, 0x21, 0x21, 0x21, 0x22, 0x22, 0x22, 0x22, 0x23, 0x23, 0x23, 0x23,
0x24, 0x24, 0x24, 0x24, 0x25, 0x25, 0x25, 0x25, 0x26, 0x26, 0x26, 0x26, 0x27, 0x27, 0x27, 0x27,
0x28, 0x28, 0x28, 0x28, 0x29, 0x29, 0x29, 0x29, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2b, 0x2b, 0x2b,
0x2b, 0x2c, 0x2c, 0x2c, 0x2c, 0x2d, 0x2d, 0x2d, 0x2d, 0x2e, 0x2e, 0x2e, 0x2e, 0x2f, 0x2f, 0x2f,
0x2f, 0x30, 0x30, 0x30, 0x30, 0x31, 0x31, 0x31, 0x31, 0x32, 0x32, 0x32, 0x32, 0x33, 0x33, 0x33,
0x33, 0x34, 0x34, 0x34, 0x34, 0x35, 0x35, 0x35, 0x35, 0x36, 0x36, 0x36, 0x36, 0x37, 0x37, 0x37,
0x37, 0x38, 0x38, 0x38, 0x38, 0x39, 0x39, 0x39, 0x39, 0x3a, 0x3a, 0x3a, 0x3a, 0x3b, 0x3b, 0x3b,
0x3b, 0x3c, 0x3c, 0x3c, 0x3c, 0x3d, 0x3d, 0x3d, 0x3d, 0x3e, 0x3e, 0x3e, 0x3e, 0x3f, 0x3f, 0x3f
};
// When we're converting, only convert the w*h area(AKA leave the last part of the line, pitch32 - w, alone),
// for places where we store auxillary information there(graphics viewer in the debugger), and it'll be faster
// to boot.
void MDFN_Surface::SetFormat(const MDFN_PixelFormat &nf, bool convert)
{
if(format.bpp != 32 || nf.bpp != 32)
printf("%u->%u\n",format.bpp, nf.bpp);
if(format == nf)
return;
//
void* old_pixels = nullptr;
void* new_pixels = nullptr;
void* new_palette = nullptr;
assert(format.bpp == 8 || format.bpp == 16 || format.bpp == 32);
assert((nf.bpp == 8 && !convert) || nf.bpp == 16 || nf.bpp == 32);
if(nf.bpp == 8)
switch(format.opp)
{
}
else if(nf.bpp == 16)
{
}
else
{
assert((nf.Rshift + nf.Gshift + nf.Bshift + nf.Ashift) == 48);
assert(!((nf.Rshift | nf.Gshift | nf.Bshift | nf.Ashift) & 0x7));
case 1: old_pixels = pix<uint8>(); break;
case 2: old_pixels = pix<uint16>(); break;
case 4: old_pixels = pix<uint32>(); break;
}
if(nf.bpp != format.bpp)
if(nf.opp != format.opp)
{
void *rpix = calloc(1, pitchinpix * h * (nf.bpp / 8));
void *oldpix;
new_pixels = calloc(1, pitchinpix * h * nf.opp);
if(nf.bpp == 8)
{
assert(!convert);
pixels8 = (uint8 *)rpix;
palette = (MDFN_PaletteEntry*)calloc(sizeof(MDFN_PaletteEntry), 256);
}
else if(nf.bpp == 16) // 32bpp or 8bpp to 16bpp
{
pixels16 = (uint16 *)rpix;
if(convert)
{
if(format.bpp == 8)
{
uint16 palconv[256];
for(unsigned i = 0; i < 256; i++)
{
uint8 r, g, b;
format.DecodePColor(palette[i], r, g, b);
palconv[i] = nf.MakeColor(r, g, b, 0);
}
puts("8bpp to 16bpp convert");
for(int y = 0; y < h; y++)
{
uint8 *srow = &pixels8[y * pitchinpix];
uint16 *drow = &pixels16[y * pitchinpix];
for(int x = 0; x < w; x++)
{
drow[x] = palconv[srow[x]];
}
}
}
else
{
puts("32bpp to 16bpp convert");
for(int y = 0; y < h; y++)
{
uint32 *srow = &pixels[y * pitchinpix];
uint16 *drow = &pixels16[y * pitchinpix];
for(int x = 0; x < w; x++)
{
uint32 c = srow[x];
int r, g, b, a;
DecodeColor(c, r, g, b, a);
drow[x] = nf.MakeColor(r, g, b, a);
}
}
}
}
}
else // 16bpp or 8bpp to 32bpp
{
pixels = (uint32 *)rpix;
if(convert)
{
if(format.bpp == 8)
{
uint32 palconv[256];
for(unsigned i = 0; i < 256; i++)
{
uint8 r, g, b;
format.DecodePColor(palette[i], r, g, b);
palconv[i] = nf.MakeColor(r, g, b, 0);
}
puts("8bpp to 32bpp convert");
for(int y = 0; y < h; y++)
{
uint8 *srow = &pixels8[y * pitchinpix];
uint32 *drow = &pixels[y * pitchinpix];
for(int x = 0; x < w; x++)
{
drow[x] = palconv[srow[x]];
}
}
}
else
{
puts("16bpp to 32bpp convert");
for(int y = 0; y < h; y++)
{
uint16 *srow = &pixels16[y * pitchinpix];
uint32 *drow = &pixels[y * pitchinpix];
for(int x = 0; x < w; x++)
{
uint32 c = srow[x];
int r, g, b, a;
DecodeColor(c, r, g, b, a);
drow[x] = nf.MakeColor(r, g, b, a);
}
}
}
}
}
switch(format.bpp)
{
default:
case 32: oldpix = pixels;
pixels = NULL;
break;
case 16: oldpix = pixels16;
pixels16 = NULL;
break;
case 8: oldpix = pixels8;
pixels8 = NULL;
if(palette)
{
free(palette);
palette = NULL;
}
break;
}
if(oldpix && !pixels_is_external)
free(oldpix);
pixels_is_external = false;
// We already handled surface conversion above.
convert = false;
if(nf.opp == 1)
new_palette = calloc(sizeof(MDFN_PaletteEntry), 256);
}
//
//
if(convert)
{
if(format.bpp == 16)
MDFN_PixelFormatConverter fconv(format, nf, (MDFN_PaletteEntry*)(palette ? palette : new_palette));
size_t old_pitchinbytes = pitchinpix * format.opp;
size_t new_pitchinbytes = pitchinpix * nf.opp;
if(new_pixels)
{
// We should assert that surface->pixels is non-NULL even if we don't need to convert the surface, to catch more insidious bugs.
assert(pixels16);
if(memcmp(&format, &nf, sizeof(MDFN_PixelFormat)))
{
//puts("Converting");
for(int y = 0; y < h; y++)
{
uint16 *row = &pixels16[y * pitchinpix];
for(int x = 0; x < w; x++)
{
uint32 c = row[x];
int r, g, b, a;
DecodeColor(c, r, g, b, a);
row[x] = nf.MakeColor(r, g, b, a);
}
}
}
for(int32 y = 0; y < h; y++)
fconv.Convert((uint8*)old_pixels + y * old_pitchinbytes, (uint8*)new_pixels + y * new_pitchinbytes, w);
}
else
{
// We should assert that surface->pixels is non-NULL even if we don't need to convert the surface, to catch more insidious bugs.
assert(pixels);
if(memcmp(&format, &nf, sizeof(MDFN_PixelFormat)))
{
//puts("Converting");
for(int y = 0; y < h; y++)
{
uint32 *row = &pixels[y * pitchinpix];
for(int x = 0; x < w; x++)
{
uint32 c = row[x];
int r, g, b, a;
DecodeColor(c, r, g, b, a);
row[x] = nf.MakeColor(r, g, b, a);
}
}
}
for(int32 y = 0; y < h; y++)
fconv.Convert((uint8*)old_pixels + y * old_pitchinbytes, w);
}
}
//
//
if(nf.opp != format.opp)
{
switch(format.opp)
{
case 1: pixels8 = nullptr; break;
case 2: pixels16 = nullptr; break;
case 4: pixels = nullptr; break;
}
if(palette)
{
free(palette);
palette = nullptr;
}
if(!pixels_is_external)
free(old_pixels);
pixels_is_external = false;
switch(nf.opp)
{
case 1: pixels8 = (uint8*)new_pixels; palette = (MDFN_PaletteEntry*)new_palette; break;
case 2: pixels16 = (uint16*)new_pixels; break;
case 4: pixels = (uint32*)new_pixels; break;
}
}
format = nf;
}
@ -405,14 +285,14 @@ void MDFN_Surface::Fill(uint8 r, uint8 g, uint8 b, uint8 a)
{
uint32 color = MakeColor(r, g, b, a);
if(format.bpp == 8)
if(format.opp == 1)
{
assert(pixels8);
for(int32 i = 0; i < pitchinpix * h; i++)
pixels8[i] = color;
}
else if(format.bpp == 16)
else if(format.opp == 2)
{
assert(pixels16);

View File

@ -9,7 +9,7 @@ struct MDFN_Rect
enum
{
MDFN_COLORSPACE_RGB = 0,
MDFN_COLORSPACE_YCbCr = 1,
//MDFN_COLORSPACE_LRGB = 1, // Linear RGB, 16-bit per component, TODO in the future?
//MDFN_COLORSPACE_YUV = 2, // TODO, maybe.
};
@ -18,36 +18,99 @@ struct MDFN_PaletteEntry
uint8 r, g, b;
};
/*
template<typename T>
static constexpr INLINE uint64 MDFN_PixelFormat_SetTagT(const uint64 tag)
{
return (tag & ~0xFF) | (sizeof(T) * 8);
}
*/
static constexpr INLINE uint64 MDFN_PixelFormat_MakeTag(const uint8 colorspace,
const uint8 opp,
const uint8 rs, const uint8 gs, const uint8 bs, const uint8 as,
const uint8 rp, const uint8 gp, const uint8 bp, const uint8 ap)
{
// (8 * 6) = 48
return ((uint64)colorspace << 56) | ((uint64)opp << 48) |
((uint64)rs << (0 * 6)) | ((uint64)gs << (1 * 6)) | ((uint64)bs << (2 * 6)) | ((uint64)as << (3 * 6)) |
((uint64)rp << (4 * 6)) | ((uint64)gp << (5 * 6)) | ((uint64)bp << (6 * 6)) | ((uint64)ap << (7 * 6));
}
class MDFN_PixelFormat
{
public:
MDFN_PixelFormat();
MDFN_PixelFormat(const unsigned int p_colorspace, const uint8 p_rs, const uint8 p_gs, const uint8 p_bs, const uint8 p_as);
unsigned int bpp; // 32 only for now(16 and 8 wip)
unsigned int colorspace;
union
//
// MDFN_PixelFormat constructors must remain inline for various code to be optimized
// properly by the compiler.
//
INLINE MDFN_PixelFormat(const uint64 tag_) :
tag(tag_),
colorspace((uint8)(tag_ >> 56)),
opp((uint8)(tag_ >> 48)),
Rshift((tag_ >> (0 * 6)) & 0x3F),
Gshift((tag_ >> (1 * 6)) & 0x3F),
Bshift((tag_ >> (2 * 6)) & 0x3F),
Ashift((tag_ >> (3 * 6)) & 0x3F),
Rprec((tag_ >> (4 * 6)) & 0x3F),
Gprec((tag_ >> (5 * 6)) & 0x3F),
Bprec((tag_ >> (6 * 6)) & 0x3F),
Aprec((tag_ >> (7 * 6)) & 0x3F)
{
uint8 Rshift; // Bit position of the lowest bit of the red component
uint8 Yshift;
};
//
}
union
INLINE MDFN_PixelFormat() :
tag(0),
colorspace(0),
opp(0),
Rshift(0), Gshift(0), Bshift(0), Ashift(0),
Rprec(0), Gprec(0), Bprec(0), Aprec(0)
{
uint8 Gshift; // [...] green component
uint8 Ushift;
uint8 Cbshift;
};
//
}
union
INLINE MDFN_PixelFormat(const unsigned int colorspace_,
const uint8 opp_,
const uint8 rs, const uint8 gs, const uint8 bs, const uint8 as,
const uint8 rp = 8, const uint8 gp = 8, const uint8 bp = 8, const uint8 ap = 8) :
tag(MDFN_PixelFormat_MakeTag(colorspace_, opp_, rs, gs, bs, as, rp, gp, bp, ap)),
colorspace(colorspace_),
opp(opp_),
Rshift(rs), Gshift(gs), Bshift(bs), Ashift(as),
Rprec(rp), Gprec(gp), Bprec(bp), Aprec(ap)
{
uint8 Bshift; // [...] blue component
uint8 Vshift;
uint8 Crshift;
};
//
}
//constexpr MDFN_PixelFormat(MDFN_PixelFormat&) = default;
//constexpr MDFN_PixelFormat(MDFN_PixelFormat&&) = default;
//MDFN_PixelFormat& operator=(MDFN_PixelFormat&) = default;
bool operator==(const uint64& t)
{
return tag == t;
}
bool operator==(const MDFN_PixelFormat& a)
{
return tag == a.tag;
}
bool operator!=(const MDFN_PixelFormat& a)
{
return !(*this == a);
}
uint64 tag;
uint8 colorspace;
uint8 opp; // Bytes per pixel; 1, 2, 4 (1 is WIP)
uint8 Rshift; // Bit position of the lowest bit of the red component
uint8 Gshift; // [...] green component
uint8 Bshift; // [...] blue component
uint8 Ashift; // [...] alpha component.
// For 16bpp, WIP
@ -59,36 +122,19 @@ class MDFN_PixelFormat
// Creates a color value for the surface corresponding to the 8-bit R/G/B/A color passed.
INLINE uint32 MakeColor(uint8 r, uint8 g, uint8 b, uint8 a = 0) const
{
if(colorspace == MDFN_COLORSPACE_YCbCr)
if(opp == 2)
{
uint32 y, u, v;
uint32 ret;
y = 16 + ((r * 16842 + g * 33030 + b * 6422) >> 16);
u = 128 + ((r * -9699 + g * -19071 + b * 28770) >> 16);
v = 128 + ((r * 28770 + g * -24117 + b * -4653) >> 16);
ret = ((r * ((1 << Rprec) - 1) + 127) / 255) << Rshift;
ret |= ((g * ((1 << Gprec) - 1) + 127) / 255) << Gshift;
ret |= ((b * ((1 << Bprec) - 1) + 127) / 255) << Bshift;
ret |= ((a * ((1 << Aprec) - 1) + 127) / 255) << Ashift;
return((y << Yshift) | (u << Ushift) | (v << Vshift) | (a << Ashift));
return ret;
}
else
{
if(bpp == 16)
{
uint32 ret = 0;
/*
ret |= std::min(((r * ((1 << Rprec) - 1) + 127) / 255), 255) << Rshift;
ret |= std::min(((g * ((1 << Gprec) - 1) + 127) / 255), 255) << Gshift;
ret |= std::min(((b * ((1 << Bprec) - 1) + 127) / 255), 255) << Bshift;
ret |= std::min(((a * ((1 << Aprec) - 1) + 127) / 255), 255) << Ashift;
*/
ret |= ((r * ((1 << Rprec) - 1) + 127) / 255) << Rshift;
ret |= ((g * ((1 << Gprec) - 1) + 127) / 255) << Gshift;
ret |= ((b * ((1 << Bprec) - 1) + 127) / 255) << Bshift;
ret |= ((a * ((1 << Aprec) - 1) + 127) / 255) << Ashift;
return(ret);
}
else
return((r << Rshift) | (g << Gshift) | (b << Bshift) | (a << Ashift));
}
return (r << Rshift) | (g << Gshift) | (b << Bshift) | (a << Ashift);
}
INLINE MDFN_PaletteEntry MakePColor(uint8 r, uint8 g, uint8 b) const
@ -112,70 +158,114 @@ class MDFN_PixelFormat
// Gets the R/G/B/A values for the passed 32-bit surface pixel value
INLINE void DecodeColor(uint32 value, int &r, int &g, int &b, int &a) const
{
if(colorspace == MDFN_COLORSPACE_YCbCr)
if(opp == 2)
{
int32 y = (value >> Yshift) & 0xFF;
int32 cb = (value >> Cbshift) & 0xFF;
int32 cr = (value >> Crshift) & 0xFF;
int32 r_tmp, g_tmp, b_tmp;
r_tmp = g_tmp = b_tmp = 76284 * (y - 16);
r_tmp = r_tmp + 104595 * (cr - 128);
g_tmp = g_tmp - 53281 * (cr - 128) - 25690 * (cb - 128);
b_tmp = b_tmp + 132186 * (cb - 128);
r_tmp >>= 16;
g_tmp >>= 16;
b_tmp >>= 16;
if(r_tmp < 0) r_tmp = 0;
if(r_tmp > 255) r_tmp = 255;
if(g_tmp < 0) g_tmp = 0;
if(g_tmp > 255) g_tmp = 255;
if(b_tmp < 0) b_tmp = 0;
if(b_tmp > 255) b_tmp = 255;
r = r_tmp;
g = g_tmp;
b = b_tmp;
a = (value >> Ashift) & 0xFF;
r = ((value >> Rshift) & ((1 << Rprec) - 1)) * 255 / ((1 << Rprec) - 1);
g = ((value >> Gshift) & ((1 << Gprec) - 1)) * 255 / ((1 << Gprec) - 1);
b = ((value >> Bshift) & ((1 << Bprec) - 1)) * 255 / ((1 << Bprec) - 1);
a = ((value >> Ashift) & ((1 << Aprec) - 1)) * 255 / ((1 << Aprec) - 1);
}
else
{
if(bpp == 16)
{
r = ((value >> Rshift) & ((1 << Rprec) - 1)) * 255 / ((1 << Rprec) - 1);
g = ((value >> Gshift) & ((1 << Gprec) - 1)) * 255 / ((1 << Gprec) - 1);
b = ((value >> Bshift) & ((1 << Bprec) - 1)) * 255 / ((1 << Bprec) - 1);
a = ((value >> Ashift) & ((1 << Aprec) - 1)) * 255 / ((1 << Aprec) - 1);
}
else
{
r = (value >> Rshift) & 0xFF;
g = (value >> Gshift) & 0xFF;
b = (value >> Bshift) & 0xFF;
a = (value >> Ashift) & 0xFF;
}
r = (value >> Rshift) & 0xFF;
g = (value >> Gshift) & 0xFF;
b = (value >> Bshift) & 0xFF;
a = (value >> Ashift) & 0xFF;
}
}
MDFN_HIDE static const uint8 LUT5to8[32];
MDFN_HIDE static const uint8 LUT6to8[64];
MDFN_HIDE static const uint8 LUT8to5[256];
MDFN_HIDE static const uint8 LUT8to6[256];
INLINE void DecodeColor(uint32 value, int &r, int &g, int &b) const
{
int dummy_a;
DecodeColor(value, r, g, b, dummy_a);
}
static INLINE void TDecodeColor(uint64 tag, uint32 c, int* r, int* g, int* b)
{
if(tag == IRGB16_1555)
{
*r = LUT5to8[(c >> 10) & 0x1F];
*g = LUT5to8[(c >> 5) & 0x1F];
*b = LUT5to8[(c >> 0) & 0x1F];
//*a = 0;
}
else if(tag == RGB16_565)
{
*r = LUT5to8[(c >> 11) & 0x1F];
*g = LUT6to8[(c >> 5) & 0x3F];
*b = LUT5to8[(c >> 0) & 0x1F];
//*a = 0;
}
else
{
MDFN_PixelFormat pf = tag;
pf.DecodeColor(c, *r, *g, *b);
}
}
static INLINE uint32 TMakeColor(uint64 tag, uint8 r, uint8 g, uint8 b)
{
if(tag == IRGB16_1555)
return (LUT8to5[r] << 10) | (LUT8to5[g] << 5) | (LUT8to5[b] << 0);
else if(tag == RGB16_565)
return (LUT8to5[r] << 11) | (LUT8to6[g] << 5) | (LUT8to5[b] << 0);
else
{
MDFN_PixelFormat pf = tag;
return pf.MakeColor(r, g, b);
}
}
enum : uint64
{
//
// All 24 possible RGB-colorspace xxxx32_8888 formats are supported by core Mednafen and emulation modules,
// but the ones not enumerated here will be less performant.
//
// In regards to emulation modules' video output, the alpha channel is for internal use,
// and should be ignored by driver-side/frontend code.
//
ABGR32_8888 = MDFN_PixelFormat_MakeTag(MDFN_COLORSPACE_RGB, 4, /**/ 0, 8, 16, 24, /**/ 8, 8, 8, 8),
ARGB32_8888 = MDFN_PixelFormat_MakeTag(MDFN_COLORSPACE_RGB, 4, /**/ 16, 8, 0, 24, /**/ 8, 8, 8, 8),
RGBA32_8888 = MDFN_PixelFormat_MakeTag(MDFN_COLORSPACE_RGB, 4, /**/ 24, 16, 8, 0, /**/ 8, 8, 8, 8),
BGRA32_8888 = MDFN_PixelFormat_MakeTag(MDFN_COLORSPACE_RGB, 4, /**/ 8, 16, 24, 0, /**/ 8, 8, 8, 8),
//
// These two RGB16 formats are the only 16-bit formats fully supported by core Mednafen code,
// and most emulation modules(also see MDFNGI::ExtraVideoFormatSupport)
//
// Alpha shift/precision weirdness for internal emulation module use.
//
IRGB16_1555 = MDFN_PixelFormat_MakeTag(MDFN_COLORSPACE_RGB, 2, /**/ 10, 5, 0, 16, /**/ 5, 5, 5, 8),
RGB16_565 = MDFN_PixelFormat_MakeTag(MDFN_COLORSPACE_RGB, 2, /**/ 11, 5, 0, 16, /**/ 5, 6, 5, 8),
//
// Following formats are not supported by emulation modules, and only partially supported by core
// Mednafen code:
//
ARGB16_4444 = MDFN_PixelFormat_MakeTag(MDFN_COLORSPACE_RGB, 2, /**/ 8, 4, 0, 12, /**/ 4, 4, 4, 4),
//
// TODO: Following two hackyish formats are only valid when used as a destination pixel format with
// MDFN_PixelFormatConverter
//
// RGB8X3_888 = MDFN_PixelFormat_MakeTag(MDFN_COLORSPACE_RGB, 3, /**/ 0, 1, 2, 0, /**/ 8, 8, 8, 0),
// BGR8X3_888 = MDFN_PixelFormat_MakeTag(MDFN_COLORSPACE_RGB, 3, /**/ 2, 1, 0, 0, /**/ 8, 8, 8, 0),
//
// TODO:
//RGB8P_888 = MDFN_PixelFormat_MakeTag(MDFN_COLORSPACE_RGB, 1, /**/ 0, 0, 0, 8, /**/ 8, 8, 8, 0),
//RGB8P_666 = MDFN_PixelFormat_MakeTag(MDFN_COLORSPACE_RGB, 1, /**/ 0, 0, 0, 8, /**/ 6, 6, 6, 0),
};
}; // MDFN_PixelFormat;
// Supports 32-bit RGBA
// 16-bit is WIP
// 8-bit is even WIPier.
class MDFN_Surface //typedef struct
// 8bpp support is incomplete
class MDFN_Surface
{
public: