add *.user, Win32, and x64 build dir to ignore list for DebuggerUICommon and Unit Tests

add *.aps to ignore list for DolphinWX dir
add eol-style native to 120 or so files

git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@3689 8ced0084-cf51-0410-be5f-012b33b47a6e
This commit is contained in:
LPFaint99
2009-07-06 02:10:26 +00:00
parent 23f3e327e2
commit a41c1b2d0a
94 changed files with 24089 additions and 24089 deletions

View File

@ -1,42 +1,42 @@
// Copyright (C) 2003-2009 Dolphin Project.
// 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, version 2.0.
// 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 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include "Config.h" // Local
#include "Globals.h"
#include "DSPHandler.h"
#include "HLEMixer.h"
void HLEMixer::MixUCode(short *samples, int numSamples) {
// if this was called directly from the HLE, and not by timeout
if (g_Config.m_EnableHLEAudio && IsHLEReady()) {
IUCode* pUCode = CDSPHandler::GetInstance().GetUCode();
if (pUCode != NULL)
pUCode->MixAdd(samples, numSamples);
}
}
void HLEMixer::Premix(short *samples, int numSamples) {
// first get the DTK Music
// if (g_Config.m_EnableDTKMusic) {
// g_dspInitialize.pGetAudioStreaming(samples, numSamples);
// }
MixUCode(samples, numSamples);
}
// Copyright (C) 2003-2009 Dolphin Project.
// 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, version 2.0.
// 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 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include "Config.h" // Local
#include "Globals.h"
#include "DSPHandler.h"
#include "HLEMixer.h"
void HLEMixer::MixUCode(short *samples, int numSamples) {
// if this was called directly from the HLE, and not by timeout
if (g_Config.m_EnableHLEAudio && IsHLEReady()) {
IUCode* pUCode = CDSPHandler::GetInstance().GetUCode();
if (pUCode != NULL)
pUCode->MixAdd(samples, numSamples);
}
}
void HLEMixer::Premix(short *samples, int numSamples) {
// first get the DTK Music
// if (g_Config.m_EnableDTKMusic) {
// g_dspInitialize.pGetAudioStreaming(samples, numSamples);
// }
MixUCode(samples, numSamples);
}

View File

@ -1,95 +1,95 @@
// Copyright (C) 2003-2008 Dolphin Project.
// 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, version 2.0.
// 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 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include "Common.h"
#include "UCode_Zelda_ADPCM.h"
void AFCdecodebuffer(const s16 *coef, const char *input, signed short *out, short *histp, short *hist2p, int type)
{
short nibbles[16];
short hist = *histp;
short hist2 = *hist2p;
const char *src = input;
char *dst = (char*)out;
// First 2 nibbles are ADPCM scale etc.
short delta = 1 << (((*src) >> 4) & 0xf);
short idx = (*src) & 0xf;
src++;
if (type == 9)
{
for (int i = 0; i < 16; i = i + 2) {
int j = (*src & 255) >> 4;
nibbles[i] = j;
j = *src & 255 & 15;
nibbles[i+1] = j;
src++;
}
for (int i = 0; i < 16; i = i + 1) {
if (nibbles[i] >= 8)
nibbles[i] = nibbles[i] - 16;
}
}
else
{
// untested !!! i havnt seen such a sample yet :)
for (int i = 0; i < 16; i += 4)
{
int j = (*src >> 0) & 0x02;
nibbles[i] = j;
j = (*src >> 2) & 0x02;
nibbles[i+1] = j;
j = (*src >> 4) & 0x02;
nibbles[i+2] = j;
j = (*src >> 6) & 0x02;
nibbles[i+3] = j;
src++;
}
for (int i = 0; i < 16; i++)
{
if (nibbles[i] >= 2)
nibbles[i] = nibbles[i] - 4;
}
}
for (int i = 0; i < 16; i++)
{
int sample = (delta * nibbles[i]) << 11;
sample += ((long)hist * coef[idx * 2]) + ((long)hist2 * coef[idx * 2 + 1]);
sample = sample >> 11;
if (sample > 32767) {
sample = 32767;
}
if (sample < -32768) {
sample = -32768;
}
*(short*)dst = (short)sample;
dst = dst + 2;
hist2 = hist;
hist = (short)sample;
}
*histp = hist;
*hist2p = hist2;
}
// Copyright (C) 2003-2008 Dolphin Project.
// 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, version 2.0.
// 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 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include "Common.h"
#include "UCode_Zelda_ADPCM.h"
void AFCdecodebuffer(const s16 *coef, const char *input, signed short *out, short *histp, short *hist2p, int type)
{
short nibbles[16];
short hist = *histp;
short hist2 = *hist2p;
const char *src = input;
char *dst = (char*)out;
// First 2 nibbles are ADPCM scale etc.
short delta = 1 << (((*src) >> 4) & 0xf);
short idx = (*src) & 0xf;
src++;
if (type == 9)
{
for (int i = 0; i < 16; i = i + 2) {
int j = (*src & 255) >> 4;
nibbles[i] = j;
j = *src & 255 & 15;
nibbles[i+1] = j;
src++;
}
for (int i = 0; i < 16; i = i + 1) {
if (nibbles[i] >= 8)
nibbles[i] = nibbles[i] - 16;
}
}
else
{
// untested !!! i havnt seen such a sample yet :)
for (int i = 0; i < 16; i += 4)
{
int j = (*src >> 0) & 0x02;
nibbles[i] = j;
j = (*src >> 2) & 0x02;
nibbles[i+1] = j;
j = (*src >> 4) & 0x02;
nibbles[i+2] = j;
j = (*src >> 6) & 0x02;
nibbles[i+3] = j;
src++;
}
for (int i = 0; i < 16; i++)
{
if (nibbles[i] >= 2)
nibbles[i] = nibbles[i] - 4;
}
}
for (int i = 0; i < 16; i++)
{
int sample = (delta * nibbles[i]) << 11;
sample += ((long)hist * coef[idx * 2]) + ((long)hist2 * coef[idx * 2 + 1]);
sample = sample >> 11;
if (sample > 32767) {
sample = 32767;
}
if (sample < -32768) {
sample = -32768;
}
*(short*)dst = (short)sample;
dst = dst + 2;
hist2 = hist;
hist = (short)sample;
}
*histp = hist;
*hist2p = hist2;
}

View File

@ -1,20 +1,20 @@
// Copyright (C) 2003-2008 Dolphin Project.
// 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, version 2.0.
// 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 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include "Common.h"
void AFCdecodebuffer(const s16 *coef, const char *input, signed short *out, short *histp, short *hist2p, int type);
// Copyright (C) 2003-2008 Dolphin Project.
// 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, version 2.0.
// 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 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include "Common.h"
void AFCdecodebuffer(const s16 *coef, const char *input, signed short *out, short *histp, short *hist2p, int type);

View File

@ -1,106 +1,106 @@
// Copyright (C) 2003-2009 Dolphin Project.
// 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, version 2.0.
// 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 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include "../Globals.h"
#include "UCodes.h"
#include "UCode_Zelda.h"
#include "UCode_Zelda_ADPCM.h"
#include "../main.h"
#include "Mixer.h"
void CUCode_Zelda::RenderSynth_Waveform(ZeldaVoicePB &PB, s32* _Buffer, int _Size)
{
float ratioFactor = 32000.0f / (float)soundStream->GetMixer()->GetSampleRate();
u32 _ratio = (PB.RatioInt << 16);
s64 ratio = (_ratio * ratioFactor) * 16;
s64 TrueSamplePosition = (s64)(PB.Length - PB.RemLength) << 16;
TrueSamplePosition += PB.CurSampleFrac;
int mask = PB.Format ? 3 : 1, shift = PB.Format ? 2 : 1;
u32 pos[2] = {0, 0};
int i = 0;
if (PB.KeyOff != 0)
return;
if (PB.NeedsReset)
{
PB.RemLength = PB.Length - PB.RestartPos;
PB.CurAddr = PB.StartAddr + (PB.RestartPos << 1);
PB.ReachedEnd = 0;
}
_lRestart:
if (PB.ReachedEnd)
{
PB.ReachedEnd = 0;
if (PB.RepeatMode == 0)
{
PB.KeyOff = 1;
PB.RemLength = 0;
PB.CurAddr = PB.StartAddr + (PB.RestartPos << 1) + PB.Length;
return;
}
else
{
PB.RestartPos = PB.LoopStartPos;
PB.RemLength = PB.Length - PB.RestartPos;
PB.CurAddr = PB.StartAddr + (PB.RestartPos << 1);
pos[1] = 0; pos[0] = 0;
}
}
while(i < _Size)
{
s16 sample = ((pos[1] & mask) == mask) ? 0xc000 : 0x4000;
TrueSamplePosition += (ratio >> 16);
_Buffer[i++] = (s32)sample;
(*(u64*)&pos) += ratio;
if ((pos[1] + ((PB.CurAddr - PB.StartAddr) >> 1)) >= PB.Length)
{
PB.ReachedEnd = 1;
goto _lRestart;
}
}
if (PB.RemLength < pos[1])
{
PB.RemLength = 0;
PB.ReachedEnd = 1;
}
else
PB.RemLength -= pos[1];
PB.CurSampleFrac = TrueSamplePosition & 0xFFFF;
}
void CUCode_Zelda::RenderSynth_Constant(ZeldaVoicePB &PB, s32* _Buffer, int _Size)
{
// TODO: Header, footer and cases this synth actually happens
for (int i = 0; i < _Size; i++)
_Buffer[i++] = (s32)PB.RatioInt;
}
// Copyright (C) 2003-2009 Dolphin Project.
// 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, version 2.0.
// 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 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include "../Globals.h"
#include "UCodes.h"
#include "UCode_Zelda.h"
#include "UCode_Zelda_ADPCM.h"
#include "../main.h"
#include "Mixer.h"
void CUCode_Zelda::RenderSynth_Waveform(ZeldaVoicePB &PB, s32* _Buffer, int _Size)
{
float ratioFactor = 32000.0f / (float)soundStream->GetMixer()->GetSampleRate();
u32 _ratio = (PB.RatioInt << 16);
s64 ratio = (_ratio * ratioFactor) * 16;
s64 TrueSamplePosition = (s64)(PB.Length - PB.RemLength) << 16;
TrueSamplePosition += PB.CurSampleFrac;
int mask = PB.Format ? 3 : 1, shift = PB.Format ? 2 : 1;
u32 pos[2] = {0, 0};
int i = 0;
if (PB.KeyOff != 0)
return;
if (PB.NeedsReset)
{
PB.RemLength = PB.Length - PB.RestartPos;
PB.CurAddr = PB.StartAddr + (PB.RestartPos << 1);
PB.ReachedEnd = 0;
}
_lRestart:
if (PB.ReachedEnd)
{
PB.ReachedEnd = 0;
if (PB.RepeatMode == 0)
{
PB.KeyOff = 1;
PB.RemLength = 0;
PB.CurAddr = PB.StartAddr + (PB.RestartPos << 1) + PB.Length;
return;
}
else
{
PB.RestartPos = PB.LoopStartPos;
PB.RemLength = PB.Length - PB.RestartPos;
PB.CurAddr = PB.StartAddr + (PB.RestartPos << 1);
pos[1] = 0; pos[0] = 0;
}
}
while(i < _Size)
{
s16 sample = ((pos[1] & mask) == mask) ? 0xc000 : 0x4000;
TrueSamplePosition += (ratio >> 16);
_Buffer[i++] = (s32)sample;
(*(u64*)&pos) += ratio;
if ((pos[1] + ((PB.CurAddr - PB.StartAddr) >> 1)) >= PB.Length)
{
PB.ReachedEnd = 1;
goto _lRestart;
}
}
if (PB.RemLength < pos[1])
{
PB.RemLength = 0;
PB.ReachedEnd = 1;
}
else
PB.RemLength -= pos[1];
PB.CurSampleFrac = TrueSamplePosition & 0xFFFF;
}
void CUCode_Zelda::RenderSynth_Constant(ZeldaVoicePB &PB, s32* _Buffer, int _Size)
{
// TODO: Header, footer and cases this synth actually happens
for (int i = 0; i < _Size; i++)
_Buffer[i++] = (s32)PB.RatioInt;
}

View File

@ -1,466 +1,466 @@
// Copyright (C) 2003-2009 Dolphin Project.
// 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, version 2.0.
// 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 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include "../Globals.h"
#include "UCodes.h"
#include "UCode_Zelda.h"
#include "UCode_Zelda_ADPCM.h"
#include "../main.h"
#include "Mixer.h"
void CUCode_Zelda::ReadVoicePB(u32 _Addr, ZeldaVoicePB& PB)
{
u16 *memory = (u16*)g_dspInitialize.pGetMemoryPointer(_Addr);
// Perform byteswap
for (int i = 0; i < (0x180 / 2); i++)
((u16*)&PB)[i] = Common::swap16(memory[i]);
PB.RestartPos = (PB.RestartPos << 16) | (PB.RestartPos >> 16);
PB.CurAddr = (PB.CurAddr << 16) | (PB.CurAddr >> 16);
PB.RemLength = (PB.RemLength << 16) | (PB.RemLength >> 16);
PB.LoopStartPos = (PB.LoopStartPos << 16) | (PB.LoopStartPos >> 16);
PB.Length = (PB.Length << 16) | (PB.Length >> 16);
PB.StartAddr = (PB.StartAddr << 16) | (PB.StartAddr >> 16);
PB.UnkAddr = (PB.UnkAddr << 16) | (PB.UnkAddr >> 16);
}
void CUCode_Zelda::WritebackVoicePB(u32 _Addr, ZeldaVoicePB& PB)
{
u16 *memory = (u16*)g_dspInitialize.pGetMemoryPointer(_Addr);
PB.RestartPos = (PB.RestartPos << 16) | (PB.RestartPos >> 16);
PB.CurAddr = (PB.CurAddr << 16) | (PB.CurAddr >> 16);
PB.RemLength = (PB.RemLength << 16) | (PB.RemLength >> 16);
// Perform byteswap
// Only the first 0x100 bytes are written back
for (int i = 0; i < (0x100 / 2); i++)
memory[i] = Common::swap16(((u16*)&PB)[i]);
}
void CUCode_Zelda::RenderVoice_PCM16(ZeldaVoicePB &PB, s32* _Buffer, int _Size)
{
float ratioFactor = 32000.0f / (float)soundStream->GetMixer()->GetSampleRate();
u32 _ratio = (((PB.RatioInt * 80) + PB.CurSampleFrac) << 4) & 0xFFFF0000;
u64 ratio = (u64)(((_ratio / 80) << 16) * ratioFactor);
u32 pos[2] = {0, 0};
int i = 0;
if (PB.KeyOff != 0)
return;
if (PB.NeedsReset)
{
PB.RemLength = PB.Length - PB.RestartPos;
PB.CurAddr = PB.StartAddr + (PB.RestartPos << 1);
PB.ReachedEnd = 0;
}
_lRestart:
if (PB.ReachedEnd)
{
PB.ReachedEnd = 0;
if (PB.RepeatMode == 0)
{
PB.KeyOff = 1;
PB.RemLength = 0;
PB.CurAddr = PB.StartAddr + (PB.RestartPos << 1) + PB.Length;
return;
}
else
{
PB.RestartPos = PB.LoopStartPos;
PB.RemLength = PB.Length - PB.RestartPos;
PB.CurAddr = PB.StartAddr + (PB.RestartPos << 1);
pos[1] = 0; pos[0] = 0;
}
}
s16 *source;
if (m_CRC == 0xD643001F)
source = (s16*)(g_dspInitialize.pGetMemoryPointer(m_DMABaseAddr) + PB.CurAddr);
else
source = (s16*)(g_dspInitialize.pGetARAMPointer() + PB.CurAddr);
for (; i < _Size;)
{
s16 sample = Common::swap16(source[pos[1]]);
_Buffer[i++] = (s32)sample;
(*(u64*)&pos) += ratio;
if ((pos[1] + ((PB.CurAddr - PB.StartAddr) >> 1)) >= PB.Length)
{
PB.ReachedEnd = 1;
goto _lRestart;
}
}
if (PB.RemLength < pos[1])
{
PB.RemLength = 0;
PB.ReachedEnd = 1;
}
else
PB.RemLength -= pos[1];
PB.CurAddr += pos[1] << 1;
// There should be a position fraction as well.
}
void CUCode_Zelda::RenderVoice_AFC(ZeldaVoicePB &PB, s32* _Buffer, int _Size)
{
float ratioFactor = 32000.0f / (float)soundStream->GetMixer()->GetSampleRate();
u32 _ratio = (PB.RatioInt << 16);// + PB.RatioFrac;
s64 ratio = (_ratio * ratioFactor) * 16; // (s64)(((_ratio / 80) << 16) * ratioFactor);
// initialize "decoder" if the sample is played the first time
if (PB.NeedsReset != 0)
{
// This is 0717_ReadOutPBStuff
// increment 4fb
// zelda:
// perhaps init or "has played before"
PB.CurBlock = 0x00;
PB.YN2 = 0x00; // history1
PB.YN1 = 0x00; // history2
// Length in samples.
PB.RemLength = PB.Length;
// Copy ARAM addr from r to rw area.
PB.CurAddr = PB.StartAddr;
PB.ReachedEnd = 0;
PB.CurSampleFrac = 0;
// Looking at Zelda Four Swords
// WARN_LOG(DSPHLE, "PB -----: %04x", PB.Unk03);
// WARN_LOG(DSPHLE, "PB Unk03: %04x", PB.Unk03); 0
// WARN_LOG(DSPHLE, "PB Unk07: %04x", PB.Unk07[0]); 0
/// WARN_LOG(DSPHLE, "PB Unk78: %04x", PB.Unk78);
// WARN_LOG(DSPHLE, "PB Unk79: %04x", PB.Unk79);
// WARN_LOG(DSPHLE, "PB Unk31: %04x", PB.Unk31);
// WARN_LOG(DSPHLE, "PB Unk36: %04x", PB.Unk36[0]);
// WARN_LOG(DSPHLE, "PB Unk37: %04x", PB.Unk36[1]);
// WARN_LOG(DSPHLE, "PB Unk3c: %04x", PB.Unk3C[0]);
// WARN_LOG(DSPHLE, "PB Unk3d: %04x", PB.Unk3C[1]);
}
if (PB.KeyOff != 0) // 0747 early out... i dunno if this can happen because we filter it above
return;
// round upwards how many samples we need to copy, 0759
// u32 frac = NumberOfSamples & 0xF;
// NumberOfSamples = (NumberOfSamples + 0xf) >> 4; // i think the lower 4 are the fraction
u8 *source;
u32 ram_mask = 1024 * 1024 * 16 - 1;
if (m_CRC == 0xD643001F) {
source = g_dspInitialize.pGetMemoryPointer(m_DMABaseAddr);
ram_mask = 1024 * 1024 * 64 - 1;
}
else
source = g_dspInitialize.pGetARAMPointer();
restart:
if (PB.ReachedEnd)
{
PB.ReachedEnd = 0;
// HACK: Looping doesn't work.
if (true || PB.RepeatMode == 0)
{
PB.KeyOff = 1;
PB.RemLength = 0;
PB.CurAddr = PB.StartAddr + PB.RestartPos + PB.Length;
return;
}
else
{
// This needs adjustment. It's not right for AFC, was just copied from PCM16.
// We should also probably reinitialize YN1 and YN2 with something - but with what?
PB.RestartPos = PB.LoopStartPos;
PB.RemLength = PB.Length - PB.RestartPos;
PB.CurAddr = PB.StartAddr + (PB.RestartPos << 1);
// pos[1] = 0; pos[0] = 0;
}
}
short outbuf[16] = {0};
u16 prev_yn1 = PB.YN1;
u16 prev_yn2 = PB.YN2;
u32 prev_addr = PB.CurAddr;
// Prefill the decode buffer.
AFCdecodebuffer(m_AFCCoefTable, (char*)(source + (PB.CurAddr & ram_mask)), outbuf, (short*)&PB.YN2, (short*)&PB.YN1, PB.Format);
PB.CurAddr += 9;
s64 TrueSamplePosition = (s64)(PB.Length - PB.RemLength) << 16;
TrueSamplePosition += PB.CurSampleFrac;
s64 delta = ratio >> 16; // 0x100000000ULL;
int sampleCount = 0;
while (sampleCount < _Size)
{
int SamplePosition = TrueSamplePosition >> 16;
_Buffer[sampleCount] = outbuf[SamplePosition & 15];
sampleCount++;
TrueSamplePosition += delta;
int TargetPosition = TrueSamplePosition >> 16;
// Decode forwards...
while (SamplePosition < TargetPosition)
{
SamplePosition++;
PB.RemLength--;
if (PB.RemLength == 0)
{
PB.ReachedEnd = 1;
goto restart;
}
// Need new samples!
if ((SamplePosition & 15) == 0) {
prev_yn1 = PB.YN1;
prev_yn2 = PB.YN2;
prev_addr = PB.CurAddr;
AFCdecodebuffer(m_AFCCoefTable, (char*)(source + (PB.CurAddr & ram_mask)), outbuf, (short*)&PB.YN2, (short*)&PB.YN1, PB.Format);
PB.CurAddr += 9;
}
}
}
// Here we should back off to the previous addr/yn1/yn2, since we didn't consume the full last block.
// We'll have to re-decode it the next time around.
// if (SamplePosition & 15) {
PB.YN2 = prev_yn2;
PB.YN1 = prev_yn1;
PB.CurAddr = prev_addr;
// }
PB.NeedsReset = 0;
PB.CurSampleFrac = TrueSamplePosition & 0xFFFF;
// write back
// NumberOfSamples = (NumberOfSamples << 4) | frac; // missing fraction
// i think pTest[0x3a] and pTest[0x3b] got an update after you have decoded some samples...
// just decrement them with the number of samples you have played
// and increase the ARAM Offset in pTest[0x38], pTest[0x39]
// end of block (Zelda 03b2)
}
// Researching what's actually inside the mysterious 0x21 case
void CUCode_Zelda::RenderVoice_Raw(ZeldaVoicePB &PB, s32* _Buffer, int _Size)
{
float ratioFactor = 32000.0f / (float)soundStream->GetMixer()->GetSampleRate();
u32 _ratio = (PB.RatioInt << 16);// + PB.RatioFrac;
s64 ratio = (_ratio * ratioFactor) * 16; // (s64)(((_ratio / 80) << 16) * ratioFactor);
if (PB.NeedsReset != 0)
{
PB.CurBlock = 0x00;
// Length in samples.
PB.RemLength = PB.Length;
// Copy ARAM addr from r to rw area.
PB.CurAddr = PB.StartAddr;
PB.ReachedEnd = 0;
PB.CurSampleFrac = 0;
}
if (PB.KeyOff != 0)
return;
u8 *source;
u32 ram_mask = 1024 * 1024 * 16 - 1;
if (m_CRC == 0xD643001F) {
source = g_dspInitialize.pGetMemoryPointer(m_DMABaseAddr);
ram_mask = 1024 * 1024 * 64 - 1;
}
else
source = g_dspInitialize.pGetARAMPointer();
//restart:
if (PB.ReachedEnd)
{
PB.ReachedEnd = 0;
// HACK: Looping doesn't work.
if (true || PB.RepeatMode == 0)
{
PB.KeyOff = 1;
PB.RemLength = 0;
PB.CurAddr = PB.StartAddr + PB.RestartPos + PB.Length;
return;
}
else
{
// This needs adjustment. It's not right for AFC, was just copied from PCM16.
// We should also probably reinitialize YN1 and YN2 with something - but with what?
PB.RestartPos = PB.LoopStartPos;
PB.RemLength = PB.Length - PB.RestartPos;
PB.CurAddr = PB.StartAddr + (PB.RestartPos << 1);
}
}
u32 prev_addr = PB.CurAddr;
// Prefill the decode buffer.
//AFCdecodebuffer(m_AFCCoefTable, (char*)(source + (PB.CurAddr & ram_mask)), outbuf, (short*)&PB.YN2, (short*)&PB.YN1, PB.Format);
const char *src = (char *)(source + (PB.CurAddr & ram_mask));
PB.CurAddr += 9;
s64 TrueSamplePosition = (s64)(PB.Length - PB.RemLength) << 16;
TrueSamplePosition += PB.CurSampleFrac;
s64 delta = ratio >> 16; // 0x100000000ULL;
int sampleCount = 0, realSample = 0;
while (sampleCount < _Size)
{
_Buffer[sampleCount] = src[realSample] | (src[realSample + 1] << 8) | (src[realSample + 2] << 16)
| (src[realSample + 3] << 24);
//WARN_LOG(DSPHLE, "The sample: %02x", src[sampleCount]);
sampleCount++;
realSample += 4;
TrueSamplePosition += delta;
}
PB.NeedsReset = 0;
PB.CurSampleFrac = TrueSamplePosition & 0xFFFF;
}
void CUCode_Zelda::RenderAddVoice(ZeldaVoicePB &PB, s32* _LeftBuffer, s32* _RightBuffer, int _Size)
{
//static u16 lastLeft = 0x1FF, lastRight = 0x1FF;
memset(m_TempBuffer, 0, _Size * sizeof(s32));
if (PB.IsBlank)
{
s32 sample = (s32)(s16)PB.FixedSample;
for (int i = 0; i < _Size; i++)
m_TempBuffer[i] = sample;
}
else
{
// XK: Use this to disable music (GREAT for testing)
//if(PB.SoundType == 0x0d00) {
// PB.NeedsReset = 0;
// return;
//}
//WARN_LOG(DSPHLE, "Fmt %04x, %04x: %04x %04x",
// PB.Format, PB.SoundType, PB.Unk29, PB.Unk2a);
/*WARN_LOG(DSPHLE, "Fmt %04x, %04x: %04x %04x %04x %04x %04x %04x %04x %04x",
PB.Format, PB.SoundType,
PB.volumeLeft1, PB.volumeLeft2, PB.volumeRight1, PB.volumeRight2,
PB.volumeUnknown1_1, PB.volumeUnknown1_2, PB.volumeUnknown2_1,
PB.volumeUnknown2_2);*/
switch (PB.Format)
{
// Synthesized sounds
case 0x0000: // Example: Magic meter filling up in ZWW
case 0x0001: // Example: "Denied" sound when trying to pull out a sword
// indoors in ZWW
RenderSynth_Waveform(PB, m_TempBuffer, _Size);
break;
case 0x0006:
WARN_LOG(DSPHLE, "Synthesizing 0x0006 (constant sound)");
RenderSynth_Constant(PB, m_TempBuffer, _Size);
break;
// These are more "synth" formats - square wave, saw wave etc.
case 0x0002:
WARN_LOG(DSPHLE, "Synthesizing 0x0002");
break;
// AFC formats
case 0x0005: // AFC with extra low bitrate (32:5 compression). Not yet seen.
WARN_LOG(DSPHLE, "5 byte AFC - does it work?");
case 0x0009: // AFC with normal bitrate (32:9 compression).
RenderVoice_AFC(PB, m_TempBuffer, _Size);
break;
case 0x0010: // PCM16 - normal PCM 16-bit audio.
RenderVoice_PCM16(PB, m_TempBuffer, _Size);
break;
case 0x0008: // Likely PCM8 - normal PCM 8-bit audio. Used in Mario Kart DD.
case 0x0020:
case 0x0021: // Probably raw sound. Important for Zelda WW. Really need to implement - missing it causes hangs.
WARN_LOG(DSPHLE, "Unimplemented MixAddVoice format in zelda %04x", PB.Format);
// This is what 0x20 and 0x21 do on end of voice
PB.RemLength = 0;
PB.KeyOff = 1;
// Caution: Use at your own risk. Sounds awful :)
//RenderVoice_Raw(PB, m_TempBuffer, _Size);
break;
default:
// TODO: Implement general decoder here
ERROR_LOG(DSPHLE, "Unknown MixAddVoice format in zelda %04x", PB.Format);
break;
}
// Necessary for SMG, not for Zelda. Weird.
PB.NeedsReset = 0;
}
for (int i = 0; i < _Size; i++)
{
/*if(PB.volumeLeft2)
lastLeft = PB.volumeLeft2;
if(PB.volumeRight2)
lastRight = PB.volumeRight2;*/
// TODO: Some noises in Zelda WW (birds, etc) have a volume of 0
// Really not sure about the masking here, but it seems to kill off some overly loud
// sounds in Zelda TP. Needs investigation.
s32 left = _LeftBuffer[i] + (m_TempBuffer[i] * (float)(
(PB.volumeLeft1 & 0x1FFF) + (PB.volumeLeft2 & 0x1FFF)) * 0.00005);
s32 right = _RightBuffer[i] + (m_TempBuffer[i] * (float)(
(PB.volumeRight1 & 0x1FFF) + (PB.volumeRight2 & 0x1FFF)) * 0.00005);
if (left < -32768) left = -32768;
if (left > 32767) left = 32767;
_LeftBuffer[i] = left; //(s32)(((float)left * (float)PB.volumeLeft) / 1000.f);
if (right < -32768) right = -32768;
if (right > 32767) right = 32767;
_RightBuffer[i] = right; //(s32)(((float)right * (float)PB.volumeRight) / 1000.0f);
}
}
// Copyright (C) 2003-2009 Dolphin Project.
// 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, version 2.0.
// 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 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include "../Globals.h"
#include "UCodes.h"
#include "UCode_Zelda.h"
#include "UCode_Zelda_ADPCM.h"
#include "../main.h"
#include "Mixer.h"
void CUCode_Zelda::ReadVoicePB(u32 _Addr, ZeldaVoicePB& PB)
{
u16 *memory = (u16*)g_dspInitialize.pGetMemoryPointer(_Addr);
// Perform byteswap
for (int i = 0; i < (0x180 / 2); i++)
((u16*)&PB)[i] = Common::swap16(memory[i]);
PB.RestartPos = (PB.RestartPos << 16) | (PB.RestartPos >> 16);
PB.CurAddr = (PB.CurAddr << 16) | (PB.CurAddr >> 16);
PB.RemLength = (PB.RemLength << 16) | (PB.RemLength >> 16);
PB.LoopStartPos = (PB.LoopStartPos << 16) | (PB.LoopStartPos >> 16);
PB.Length = (PB.Length << 16) | (PB.Length >> 16);
PB.StartAddr = (PB.StartAddr << 16) | (PB.StartAddr >> 16);
PB.UnkAddr = (PB.UnkAddr << 16) | (PB.UnkAddr >> 16);
}
void CUCode_Zelda::WritebackVoicePB(u32 _Addr, ZeldaVoicePB& PB)
{
u16 *memory = (u16*)g_dspInitialize.pGetMemoryPointer(_Addr);
PB.RestartPos = (PB.RestartPos << 16) | (PB.RestartPos >> 16);
PB.CurAddr = (PB.CurAddr << 16) | (PB.CurAddr >> 16);
PB.RemLength = (PB.RemLength << 16) | (PB.RemLength >> 16);
// Perform byteswap
// Only the first 0x100 bytes are written back
for (int i = 0; i < (0x100 / 2); i++)
memory[i] = Common::swap16(((u16*)&PB)[i]);
}
void CUCode_Zelda::RenderVoice_PCM16(ZeldaVoicePB &PB, s32* _Buffer, int _Size)
{
float ratioFactor = 32000.0f / (float)soundStream->GetMixer()->GetSampleRate();
u32 _ratio = (((PB.RatioInt * 80) + PB.CurSampleFrac) << 4) & 0xFFFF0000;
u64 ratio = (u64)(((_ratio / 80) << 16) * ratioFactor);
u32 pos[2] = {0, 0};
int i = 0;
if (PB.KeyOff != 0)
return;
if (PB.NeedsReset)
{
PB.RemLength = PB.Length - PB.RestartPos;
PB.CurAddr = PB.StartAddr + (PB.RestartPos << 1);
PB.ReachedEnd = 0;
}
_lRestart:
if (PB.ReachedEnd)
{
PB.ReachedEnd = 0;
if (PB.RepeatMode == 0)
{
PB.KeyOff = 1;
PB.RemLength = 0;
PB.CurAddr = PB.StartAddr + (PB.RestartPos << 1) + PB.Length;
return;
}
else
{
PB.RestartPos = PB.LoopStartPos;
PB.RemLength = PB.Length - PB.RestartPos;
PB.CurAddr = PB.StartAddr + (PB.RestartPos << 1);
pos[1] = 0; pos[0] = 0;
}
}
s16 *source;
if (m_CRC == 0xD643001F)
source = (s16*)(g_dspInitialize.pGetMemoryPointer(m_DMABaseAddr) + PB.CurAddr);
else
source = (s16*)(g_dspInitialize.pGetARAMPointer() + PB.CurAddr);
for (; i < _Size;)
{
s16 sample = Common::swap16(source[pos[1]]);
_Buffer[i++] = (s32)sample;
(*(u64*)&pos) += ratio;
if ((pos[1] + ((PB.CurAddr - PB.StartAddr) >> 1)) >= PB.Length)
{
PB.ReachedEnd = 1;
goto _lRestart;
}
}
if (PB.RemLength < pos[1])
{
PB.RemLength = 0;
PB.ReachedEnd = 1;
}
else
PB.RemLength -= pos[1];
PB.CurAddr += pos[1] << 1;
// There should be a position fraction as well.
}
void CUCode_Zelda::RenderVoice_AFC(ZeldaVoicePB &PB, s32* _Buffer, int _Size)
{
float ratioFactor = 32000.0f / (float)soundStream->GetMixer()->GetSampleRate();
u32 _ratio = (PB.RatioInt << 16);// + PB.RatioFrac;
s64 ratio = (_ratio * ratioFactor) * 16; // (s64)(((_ratio / 80) << 16) * ratioFactor);
// initialize "decoder" if the sample is played the first time
if (PB.NeedsReset != 0)
{
// This is 0717_ReadOutPBStuff
// increment 4fb
// zelda:
// perhaps init or "has played before"
PB.CurBlock = 0x00;
PB.YN2 = 0x00; // history1
PB.YN1 = 0x00; // history2
// Length in samples.
PB.RemLength = PB.Length;
// Copy ARAM addr from r to rw area.
PB.CurAddr = PB.StartAddr;
PB.ReachedEnd = 0;
PB.CurSampleFrac = 0;
// Looking at Zelda Four Swords
// WARN_LOG(DSPHLE, "PB -----: %04x", PB.Unk03);
// WARN_LOG(DSPHLE, "PB Unk03: %04x", PB.Unk03); 0
// WARN_LOG(DSPHLE, "PB Unk07: %04x", PB.Unk07[0]); 0
/// WARN_LOG(DSPHLE, "PB Unk78: %04x", PB.Unk78);
// WARN_LOG(DSPHLE, "PB Unk79: %04x", PB.Unk79);
// WARN_LOG(DSPHLE, "PB Unk31: %04x", PB.Unk31);
// WARN_LOG(DSPHLE, "PB Unk36: %04x", PB.Unk36[0]);
// WARN_LOG(DSPHLE, "PB Unk37: %04x", PB.Unk36[1]);
// WARN_LOG(DSPHLE, "PB Unk3c: %04x", PB.Unk3C[0]);
// WARN_LOG(DSPHLE, "PB Unk3d: %04x", PB.Unk3C[1]);
}
if (PB.KeyOff != 0) // 0747 early out... i dunno if this can happen because we filter it above
return;
// round upwards how many samples we need to copy, 0759
// u32 frac = NumberOfSamples & 0xF;
// NumberOfSamples = (NumberOfSamples + 0xf) >> 4; // i think the lower 4 are the fraction
u8 *source;
u32 ram_mask = 1024 * 1024 * 16 - 1;
if (m_CRC == 0xD643001F) {
source = g_dspInitialize.pGetMemoryPointer(m_DMABaseAddr);
ram_mask = 1024 * 1024 * 64 - 1;
}
else
source = g_dspInitialize.pGetARAMPointer();
restart:
if (PB.ReachedEnd)
{
PB.ReachedEnd = 0;
// HACK: Looping doesn't work.
if (true || PB.RepeatMode == 0)
{
PB.KeyOff = 1;
PB.RemLength = 0;
PB.CurAddr = PB.StartAddr + PB.RestartPos + PB.Length;
return;
}
else
{
// This needs adjustment. It's not right for AFC, was just copied from PCM16.
// We should also probably reinitialize YN1 and YN2 with something - but with what?
PB.RestartPos = PB.LoopStartPos;
PB.RemLength = PB.Length - PB.RestartPos;
PB.CurAddr = PB.StartAddr + (PB.RestartPos << 1);
// pos[1] = 0; pos[0] = 0;
}
}
short outbuf[16] = {0};
u16 prev_yn1 = PB.YN1;
u16 prev_yn2 = PB.YN2;
u32 prev_addr = PB.CurAddr;
// Prefill the decode buffer.
AFCdecodebuffer(m_AFCCoefTable, (char*)(source + (PB.CurAddr & ram_mask)), outbuf, (short*)&PB.YN2, (short*)&PB.YN1, PB.Format);
PB.CurAddr += 9;
s64 TrueSamplePosition = (s64)(PB.Length - PB.RemLength) << 16;
TrueSamplePosition += PB.CurSampleFrac;
s64 delta = ratio >> 16; // 0x100000000ULL;
int sampleCount = 0;
while (sampleCount < _Size)
{
int SamplePosition = TrueSamplePosition >> 16;
_Buffer[sampleCount] = outbuf[SamplePosition & 15];
sampleCount++;
TrueSamplePosition += delta;
int TargetPosition = TrueSamplePosition >> 16;
// Decode forwards...
while (SamplePosition < TargetPosition)
{
SamplePosition++;
PB.RemLength--;
if (PB.RemLength == 0)
{
PB.ReachedEnd = 1;
goto restart;
}
// Need new samples!
if ((SamplePosition & 15) == 0) {
prev_yn1 = PB.YN1;
prev_yn2 = PB.YN2;
prev_addr = PB.CurAddr;
AFCdecodebuffer(m_AFCCoefTable, (char*)(source + (PB.CurAddr & ram_mask)), outbuf, (short*)&PB.YN2, (short*)&PB.YN1, PB.Format);
PB.CurAddr += 9;
}
}
}
// Here we should back off to the previous addr/yn1/yn2, since we didn't consume the full last block.
// We'll have to re-decode it the next time around.
// if (SamplePosition & 15) {
PB.YN2 = prev_yn2;
PB.YN1 = prev_yn1;
PB.CurAddr = prev_addr;
// }
PB.NeedsReset = 0;
PB.CurSampleFrac = TrueSamplePosition & 0xFFFF;
// write back
// NumberOfSamples = (NumberOfSamples << 4) | frac; // missing fraction
// i think pTest[0x3a] and pTest[0x3b] got an update after you have decoded some samples...
// just decrement them with the number of samples you have played
// and increase the ARAM Offset in pTest[0x38], pTest[0x39]
// end of block (Zelda 03b2)
}
// Researching what's actually inside the mysterious 0x21 case
void CUCode_Zelda::RenderVoice_Raw(ZeldaVoicePB &PB, s32* _Buffer, int _Size)
{
float ratioFactor = 32000.0f / (float)soundStream->GetMixer()->GetSampleRate();
u32 _ratio = (PB.RatioInt << 16);// + PB.RatioFrac;
s64 ratio = (_ratio * ratioFactor) * 16; // (s64)(((_ratio / 80) << 16) * ratioFactor);
if (PB.NeedsReset != 0)
{
PB.CurBlock = 0x00;
// Length in samples.
PB.RemLength = PB.Length;
// Copy ARAM addr from r to rw area.
PB.CurAddr = PB.StartAddr;
PB.ReachedEnd = 0;
PB.CurSampleFrac = 0;
}
if (PB.KeyOff != 0)
return;
u8 *source;
u32 ram_mask = 1024 * 1024 * 16 - 1;
if (m_CRC == 0xD643001F) {
source = g_dspInitialize.pGetMemoryPointer(m_DMABaseAddr);
ram_mask = 1024 * 1024 * 64 - 1;
}
else
source = g_dspInitialize.pGetARAMPointer();
//restart:
if (PB.ReachedEnd)
{
PB.ReachedEnd = 0;
// HACK: Looping doesn't work.
if (true || PB.RepeatMode == 0)
{
PB.KeyOff = 1;
PB.RemLength = 0;
PB.CurAddr = PB.StartAddr + PB.RestartPos + PB.Length;
return;
}
else
{
// This needs adjustment. It's not right for AFC, was just copied from PCM16.
// We should also probably reinitialize YN1 and YN2 with something - but with what?
PB.RestartPos = PB.LoopStartPos;
PB.RemLength = PB.Length - PB.RestartPos;
PB.CurAddr = PB.StartAddr + (PB.RestartPos << 1);
}
}
u32 prev_addr = PB.CurAddr;
// Prefill the decode buffer.
//AFCdecodebuffer(m_AFCCoefTable, (char*)(source + (PB.CurAddr & ram_mask)), outbuf, (short*)&PB.YN2, (short*)&PB.YN1, PB.Format);
const char *src = (char *)(source + (PB.CurAddr & ram_mask));
PB.CurAddr += 9;
s64 TrueSamplePosition = (s64)(PB.Length - PB.RemLength) << 16;
TrueSamplePosition += PB.CurSampleFrac;
s64 delta = ratio >> 16; // 0x100000000ULL;
int sampleCount = 0, realSample = 0;
while (sampleCount < _Size)
{
_Buffer[sampleCount] = src[realSample] | (src[realSample + 1] << 8) | (src[realSample + 2] << 16)
| (src[realSample + 3] << 24);
//WARN_LOG(DSPHLE, "The sample: %02x", src[sampleCount]);
sampleCount++;
realSample += 4;
TrueSamplePosition += delta;
}
PB.NeedsReset = 0;
PB.CurSampleFrac = TrueSamplePosition & 0xFFFF;
}
void CUCode_Zelda::RenderAddVoice(ZeldaVoicePB &PB, s32* _LeftBuffer, s32* _RightBuffer, int _Size)
{
//static u16 lastLeft = 0x1FF, lastRight = 0x1FF;
memset(m_TempBuffer, 0, _Size * sizeof(s32));
if (PB.IsBlank)
{
s32 sample = (s32)(s16)PB.FixedSample;
for (int i = 0; i < _Size; i++)
m_TempBuffer[i] = sample;
}
else
{
// XK: Use this to disable music (GREAT for testing)
//if(PB.SoundType == 0x0d00) {
// PB.NeedsReset = 0;
// return;
//}
//WARN_LOG(DSPHLE, "Fmt %04x, %04x: %04x %04x",
// PB.Format, PB.SoundType, PB.Unk29, PB.Unk2a);
/*WARN_LOG(DSPHLE, "Fmt %04x, %04x: %04x %04x %04x %04x %04x %04x %04x %04x",
PB.Format, PB.SoundType,
PB.volumeLeft1, PB.volumeLeft2, PB.volumeRight1, PB.volumeRight2,
PB.volumeUnknown1_1, PB.volumeUnknown1_2, PB.volumeUnknown2_1,
PB.volumeUnknown2_2);*/
switch (PB.Format)
{
// Synthesized sounds
case 0x0000: // Example: Magic meter filling up in ZWW
case 0x0001: // Example: "Denied" sound when trying to pull out a sword
// indoors in ZWW
RenderSynth_Waveform(PB, m_TempBuffer, _Size);
break;
case 0x0006:
WARN_LOG(DSPHLE, "Synthesizing 0x0006 (constant sound)");
RenderSynth_Constant(PB, m_TempBuffer, _Size);
break;
// These are more "synth" formats - square wave, saw wave etc.
case 0x0002:
WARN_LOG(DSPHLE, "Synthesizing 0x0002");
break;
// AFC formats
case 0x0005: // AFC with extra low bitrate (32:5 compression). Not yet seen.
WARN_LOG(DSPHLE, "5 byte AFC - does it work?");
case 0x0009: // AFC with normal bitrate (32:9 compression).
RenderVoice_AFC(PB, m_TempBuffer, _Size);
break;
case 0x0010: // PCM16 - normal PCM 16-bit audio.
RenderVoice_PCM16(PB, m_TempBuffer, _Size);
break;
case 0x0008: // Likely PCM8 - normal PCM 8-bit audio. Used in Mario Kart DD.
case 0x0020:
case 0x0021: // Probably raw sound. Important for Zelda WW. Really need to implement - missing it causes hangs.
WARN_LOG(DSPHLE, "Unimplemented MixAddVoice format in zelda %04x", PB.Format);
// This is what 0x20 and 0x21 do on end of voice
PB.RemLength = 0;
PB.KeyOff = 1;
// Caution: Use at your own risk. Sounds awful :)
//RenderVoice_Raw(PB, m_TempBuffer, _Size);
break;
default:
// TODO: Implement general decoder here
ERROR_LOG(DSPHLE, "Unknown MixAddVoice format in zelda %04x", PB.Format);
break;
}
// Necessary for SMG, not for Zelda. Weird.
PB.NeedsReset = 0;
}
for (int i = 0; i < _Size; i++)
{
/*if(PB.volumeLeft2)
lastLeft = PB.volumeLeft2;
if(PB.volumeRight2)
lastRight = PB.volumeRight2;*/
// TODO: Some noises in Zelda WW (birds, etc) have a volume of 0
// Really not sure about the masking here, but it seems to kill off some overly loud
// sounds in Zelda TP. Needs investigation.
s32 left = _LeftBuffer[i] + (m_TempBuffer[i] * (float)(
(PB.volumeLeft1 & 0x1FFF) + (PB.volumeLeft2 & 0x1FFF)) * 0.00005);
s32 right = _RightBuffer[i] + (m_TempBuffer[i] * (float)(
(PB.volumeRight1 & 0x1FFF) + (PB.volumeRight2 & 0x1FFF)) * 0.00005);
if (left < -32768) left = -32768;
if (left > 32767) left = 32767;
_LeftBuffer[i] = left; //(s32)(((float)left * (float)PB.volumeLeft) / 1000.f);
if (right < -32768) right = -32768;
if (right > 32767) right = 32767;
_RightBuffer[i] = right; //(s32)(((float)right * (float)PB.volumeRight) / 1000.0f);
}
}

View File

@ -1,179 +1,179 @@
// Copyright (C) 2003-2009 Dolphin Project.
// 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, version 2.0.
// 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 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include "DSPDebugInterface.h"
#include "DSPCore.h"
#include "disassemble.h"
#include "DSPSymbols.h"
#include "DSPMemoryMap.h"
void DSPDebugInterface::disasm(unsigned int address, char *dest, int max_size)
{
// we'll treat addresses as line numbers.
strncpy(dest, DSPSymbols::GetLineText(address), max_size);
dest[max_size-1] = 0;
}
void DSPDebugInterface::getRawMemoryString(int memory, unsigned int address, char *dest, int max_size)
{
switch (memory) {
case 0: // IMEM
switch (address >> 12) {
case 0:
case 0x8:
sprintf(dest, "%04x", dsp_imem_read(address));
break;
default:
sprintf(dest, "----");
break;
}
break;
case 1: // DMEM
switch (address >> 12) {
case 0:
case 1:
sprintf(dest, "%04x", dsp_dmem_read(address));
break;
default:
sprintf(dest, "----");
break;
}
break;
}
}
unsigned int DSPDebugInterface::readMemory(unsigned int address)
{
return 0; //Memory::ReadUnchecked_U32(address);
}
unsigned int DSPDebugInterface::readInstruction(unsigned int address)
{
return 0; //Memory::Read_Instruction(address);
}
bool DSPDebugInterface::isAlive()
{
return true; //Core::GetState() != Core::CORE_UNINITIALIZED;
}
bool DSPDebugInterface::isBreakpoint(unsigned int address)
{
int real_addr = DSPSymbols::Line2Addr(address);
if (real_addr >= 0)
return dsp_breakpoints.IsAddressBreakPoint(real_addr);
else
return false;
}
void DSPDebugInterface::setBreakpoint(unsigned int address)
{
int real_addr = DSPSymbols::Line2Addr(address);
if (real_addr >= 0) {
if (dsp_breakpoints.Add(real_addr))
;
}
}
void DSPDebugInterface::clearBreakpoint(unsigned int address)
{
int real_addr = DSPSymbols::Line2Addr(address);
if (real_addr >= 0) {
if (dsp_breakpoints.Remove(real_addr))
;
}
}
void DSPDebugInterface::clearAllBreakpoints() {
dsp_breakpoints.Clear();
}
void DSPDebugInterface::toggleBreakpoint(unsigned int address)
{
int real_addr = DSPSymbols::Line2Addr(address);
if (real_addr >= 0) {
if (dsp_breakpoints.IsAddressBreakPoint(real_addr))
dsp_breakpoints.Remove(real_addr);
else
dsp_breakpoints.Add(real_addr);
}
}
void DSPDebugInterface::insertBLR(unsigned int address)
{
PanicAlert("insertBLR functionality not supported in DSP module.");
}
// =======================================================
// Separate the blocks with colors.
// -------------
int DSPDebugInterface::getColor(unsigned int address)
{
static const int colors[6] =
{
0xd0FFFF, // light cyan
0xFFd0d0, // light red
0xd8d8FF, // light blue
0xFFd0FF, // light purple
0xd0FFd0, // light green
0xFFFFd0, // light yellow
};
// Scan backwards so we don't miss it. Hm, actually, let's not - it looks pretty good.
int addr = -1;
for (int i = 0; i < 1; i++)
{
addr = DSPSymbols::Line2Addr(address - i);
if (addr >= 0)
break;
}
if (addr == -1)
return 0xFFFFFF;
Symbol *symbol = DSPSymbols::g_dsp_symbol_db.GetSymbolFromAddr(addr);
if (!symbol)
return 0xFFFFFF;
if (symbol->type != Symbol::SYMBOL_FUNCTION)
return 0xEEEEFF;
return colors[symbol->index % 6];
}
// =============
std::string DSPDebugInterface::getDescription(unsigned int address)
{
return ""; // g_symbolDB.GetDescription(address);
}
unsigned int DSPDebugInterface::getPC()
{
return DSPSymbols::Addr2Line(g_dsp.pc);
}
void DSPDebugInterface::setPC(unsigned int address)
{
int new_pc = DSPSymbols::Line2Addr(address);
if (new_pc > 0)
g_dsp.pc = new_pc;
}
void DSPDebugInterface::runToBreakpoint()
{
}
// Copyright (C) 2003-2009 Dolphin Project.
// 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, version 2.0.
// 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 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include "DSPDebugInterface.h"
#include "DSPCore.h"
#include "disassemble.h"
#include "DSPSymbols.h"
#include "DSPMemoryMap.h"
void DSPDebugInterface::disasm(unsigned int address, char *dest, int max_size)
{
// we'll treat addresses as line numbers.
strncpy(dest, DSPSymbols::GetLineText(address), max_size);
dest[max_size-1] = 0;
}
void DSPDebugInterface::getRawMemoryString(int memory, unsigned int address, char *dest, int max_size)
{
switch (memory) {
case 0: // IMEM
switch (address >> 12) {
case 0:
case 0x8:
sprintf(dest, "%04x", dsp_imem_read(address));
break;
default:
sprintf(dest, "----");
break;
}
break;
case 1: // DMEM
switch (address >> 12) {
case 0:
case 1:
sprintf(dest, "%04x", dsp_dmem_read(address));
break;
default:
sprintf(dest, "----");
break;
}
break;
}
}
unsigned int DSPDebugInterface::readMemory(unsigned int address)
{
return 0; //Memory::ReadUnchecked_U32(address);
}
unsigned int DSPDebugInterface::readInstruction(unsigned int address)
{
return 0; //Memory::Read_Instruction(address);
}
bool DSPDebugInterface::isAlive()
{
return true; //Core::GetState() != Core::CORE_UNINITIALIZED;
}
bool DSPDebugInterface::isBreakpoint(unsigned int address)
{
int real_addr = DSPSymbols::Line2Addr(address);
if (real_addr >= 0)
return dsp_breakpoints.IsAddressBreakPoint(real_addr);
else
return false;
}
void DSPDebugInterface::setBreakpoint(unsigned int address)
{
int real_addr = DSPSymbols::Line2Addr(address);
if (real_addr >= 0) {
if (dsp_breakpoints.Add(real_addr))
;
}
}
void DSPDebugInterface::clearBreakpoint(unsigned int address)
{
int real_addr = DSPSymbols::Line2Addr(address);
if (real_addr >= 0) {
if (dsp_breakpoints.Remove(real_addr))
;
}
}
void DSPDebugInterface::clearAllBreakpoints() {
dsp_breakpoints.Clear();
}
void DSPDebugInterface::toggleBreakpoint(unsigned int address)
{
int real_addr = DSPSymbols::Line2Addr(address);
if (real_addr >= 0) {
if (dsp_breakpoints.IsAddressBreakPoint(real_addr))
dsp_breakpoints.Remove(real_addr);
else
dsp_breakpoints.Add(real_addr);
}
}
void DSPDebugInterface::insertBLR(unsigned int address)
{
PanicAlert("insertBLR functionality not supported in DSP module.");
}
// =======================================================
// Separate the blocks with colors.
// -------------
int DSPDebugInterface::getColor(unsigned int address)
{
static const int colors[6] =
{
0xd0FFFF, // light cyan
0xFFd0d0, // light red
0xd8d8FF, // light blue
0xFFd0FF, // light purple
0xd0FFd0, // light green
0xFFFFd0, // light yellow
};
// Scan backwards so we don't miss it. Hm, actually, let's not - it looks pretty good.
int addr = -1;
for (int i = 0; i < 1; i++)
{
addr = DSPSymbols::Line2Addr(address - i);
if (addr >= 0)
break;
}
if (addr == -1)
return 0xFFFFFF;
Symbol *symbol = DSPSymbols::g_dsp_symbol_db.GetSymbolFromAddr(addr);
if (!symbol)
return 0xFFFFFF;
if (symbol->type != Symbol::SYMBOL_FUNCTION)
return 0xEEEEFF;
return colors[symbol->index % 6];
}
// =============
std::string DSPDebugInterface::getDescription(unsigned int address)
{
return ""; // g_symbolDB.GetDescription(address);
}
unsigned int DSPDebugInterface::getPC()
{
return DSPSymbols::Addr2Line(g_dsp.pc);
}
void DSPDebugInterface::setPC(unsigned int address)
{
int new_pc = DSPSymbols::Line2Addr(address);
if (new_pc > 0)
g_dsp.pc = new_pc;
}
void DSPDebugInterface::runToBreakpoint()
{
}

View File

@ -1,33 +1,33 @@
#ifndef _DSPDEBUGINTERFACE_H
#define _DSPDEBUGINTERFACE_H
#include <string>
#include "DebugInterface.h"
#include "Common.h"
class DSPDebugInterface : public DebugInterface
{
public:
DSPDebugInterface(){}
virtual void disasm(unsigned int address, char *dest, int max_size);
virtual void getRawMemoryString(int memory, unsigned int address, char *dest, int max_size);
virtual int getInstructionSize(int instruction) {return 1;}
virtual bool isAlive();
virtual bool isBreakpoint(unsigned int address);
virtual void setBreakpoint(unsigned int address);
virtual void clearBreakpoint(unsigned int address);
virtual void clearAllBreakpoints();
virtual void toggleBreakpoint(unsigned int address);
virtual unsigned int readMemory(unsigned int address);
virtual unsigned int readInstruction(unsigned int address);
virtual unsigned int getPC();
virtual void setPC(unsigned int address);
virtual void step() {}
virtual void runToBreakpoint();
virtual void insertBLR(unsigned int address);
virtual int getColor(unsigned int address);
virtual std::string getDescription(unsigned int address);
};
#endif // _DSPDEBUGINTERFACE_H
#ifndef _DSPDEBUGINTERFACE_H
#define _DSPDEBUGINTERFACE_H
#include <string>
#include "DebugInterface.h"
#include "Common.h"
class DSPDebugInterface : public DebugInterface
{
public:
DSPDebugInterface(){}
virtual void disasm(unsigned int address, char *dest, int max_size);
virtual void getRawMemoryString(int memory, unsigned int address, char *dest, int max_size);
virtual int getInstructionSize(int instruction) {return 1;}
virtual bool isAlive();
virtual bool isBreakpoint(unsigned int address);
virtual void setBreakpoint(unsigned int address);
virtual void clearBreakpoint(unsigned int address);
virtual void clearAllBreakpoints();
virtual void toggleBreakpoint(unsigned int address);
virtual unsigned int readMemory(unsigned int address);
virtual unsigned int readInstruction(unsigned int address);
virtual unsigned int getPC();
virtual void setPC(unsigned int address);
virtual void step() {}
virtual void runToBreakpoint();
virtual void insertBLR(unsigned int address);
virtual int getColor(unsigned int address);
virtual std::string getDescription(unsigned int address);
};
#endif // _DSPDEBUGINTERFACE_H

View File

@ -1,115 +1,115 @@
// Copyright (C) 2003-2009 Dolphin Project.
// 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, version 2.0.
// 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 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include "Common.h"
#include "DSPHost.h"
#include "DSPSymbols.h"
#include "Tools.h"
#include "pluginspecs_dsp.h"
extern DSPInitialize g_dspInitialize;
#if defined(HAVE_WX) && HAVE_WX
#include "DSPConfigDlgLLE.h"
#include "Debugger/Debugger.h" // For the DSPDebuggerLLE class
extern DSPDebuggerLLE* m_DebuggerFrame;
#endif
// The user of the DSPCore library must supply a few functions so that the
// emulation core can access the environment it runs in. If the emulation
// core isn't used, for example in an asm/disasm tool, then most of these
// can be stubbed out.
u8 DSPHost_ReadHostMemory(u32 addr)
{
return g_dspInitialize.pARAM_Read_U8(addr);
}
void DSPHost_WriteHostMemory(u8 value, u32 addr)
{
g_dspInitialize.pARAM_Write_U8(value, addr);
}
bool DSPHost_OnThread()
{
return g_dspInitialize.bOnThread;
}
bool DSPHost_Running()
{
return !(*g_dspInitialize.pEmulatorState);
}
void DSPHost_InterruptRequest()
{
#ifdef DEBUG_EXP
NOTICE_LOG(DSPLLE, "Firing an interrupt on the PPC ASAP");
#endif
// Fire an interrupt on the PPC ASAP.
g_dspInitialize.pGenerateDSPInterrupt();
}
u32 DSPHost_CodeLoaded(const u8 *ptr, int size)
{
u32 crc = GenerateCRC(ptr, size);
DumpDSPCode(ptr, size, crc);
// this crc is comparable with the HLE plugin
u32 ector_crc = 0;
for (int i = 0; i < size; i++)
{
ector_crc ^= ptr[i];
//let's rol
ector_crc = (ector_crc << 3) | (ector_crc >> 29);
}
DSPSymbols::Clear();
// Auto load text file - if none just disassemble.
// TODO: Don't hardcode for Zelda.
NOTICE_LOG(DSPLLE, "CRC: %08x", ector_crc);
DSPSymbols::Clear();
bool success = false;
switch (ector_crc)
{
case 0x86840740: success = DSPSymbols::ReadAnnotatedAssembly("../../docs/DSP/DSP_UC_Zelda.txt"); break;
case 0x42f64ac4: success = DSPSymbols::ReadAnnotatedAssembly("../../docs/DSP/DSP_UC_Luigi.txt"); break;
case 0x4e8a8b21: success = DSPSymbols::ReadAnnotatedAssembly("../../docs/DSP/DSP_UC_AX1.txt"); break;
default: success = false; break;
}
if (!success) {
DSPSymbols::AutoDisassembly(0x0, 0x1000);
}
// Always add the ROM.
DSPSymbols::AutoDisassembly(0x8000, 0x9000);
if (m_DebuggerFrame)
m_DebuggerFrame->Refresh();
return crc;
}
void DSPHost_UpdateDebugger()
{
if (m_DebuggerFrame)
m_DebuggerFrame->Refresh();
}
// Copyright (C) 2003-2009 Dolphin Project.
// 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, version 2.0.
// 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 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include "Common.h"
#include "DSPHost.h"
#include "DSPSymbols.h"
#include "Tools.h"
#include "pluginspecs_dsp.h"
extern DSPInitialize g_dspInitialize;
#if defined(HAVE_WX) && HAVE_WX
#include "DSPConfigDlgLLE.h"
#include "Debugger/Debugger.h" // For the DSPDebuggerLLE class
extern DSPDebuggerLLE* m_DebuggerFrame;
#endif
// The user of the DSPCore library must supply a few functions so that the
// emulation core can access the environment it runs in. If the emulation
// core isn't used, for example in an asm/disasm tool, then most of these
// can be stubbed out.
u8 DSPHost_ReadHostMemory(u32 addr)
{
return g_dspInitialize.pARAM_Read_U8(addr);
}
void DSPHost_WriteHostMemory(u8 value, u32 addr)
{
g_dspInitialize.pARAM_Write_U8(value, addr);
}
bool DSPHost_OnThread()
{
return g_dspInitialize.bOnThread;
}
bool DSPHost_Running()
{
return !(*g_dspInitialize.pEmulatorState);
}
void DSPHost_InterruptRequest()
{
#ifdef DEBUG_EXP
NOTICE_LOG(DSPLLE, "Firing an interrupt on the PPC ASAP");
#endif
// Fire an interrupt on the PPC ASAP.
g_dspInitialize.pGenerateDSPInterrupt();
}
u32 DSPHost_CodeLoaded(const u8 *ptr, int size)
{
u32 crc = GenerateCRC(ptr, size);
DumpDSPCode(ptr, size, crc);
// this crc is comparable with the HLE plugin
u32 ector_crc = 0;
for (int i = 0; i < size; i++)
{
ector_crc ^= ptr[i];
//let's rol
ector_crc = (ector_crc << 3) | (ector_crc >> 29);
}
DSPSymbols::Clear();
// Auto load text file - if none just disassemble.
// TODO: Don't hardcode for Zelda.
NOTICE_LOG(DSPLLE, "CRC: %08x", ector_crc);
DSPSymbols::Clear();
bool success = false;
switch (ector_crc)
{
case 0x86840740: success = DSPSymbols::ReadAnnotatedAssembly("../../docs/DSP/DSP_UC_Zelda.txt"); break;
case 0x42f64ac4: success = DSPSymbols::ReadAnnotatedAssembly("../../docs/DSP/DSP_UC_Luigi.txt"); break;
case 0x4e8a8b21: success = DSPSymbols::ReadAnnotatedAssembly("../../docs/DSP/DSP_UC_AX1.txt"); break;
default: success = false; break;
}
if (!success) {
DSPSymbols::AutoDisassembly(0x0, 0x1000);
}
// Always add the ROM.
DSPSymbols::AutoDisassembly(0x8000, 0x9000);
if (m_DebuggerFrame)
m_DebuggerFrame->Refresh();
return crc;
}
void DSPHost_UpdateDebugger()
{
if (m_DebuggerFrame)
m_DebuggerFrame->Refresh();
}

View File

@ -1,287 +1,287 @@
// Copyright (C) 2003-2009 Dolphin Project.
// 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, version 2.0.
// 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 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include <iostream> // I hope this doesn't break anything
#include <stdio.h>
#include <stdarg.h>
#include <list>
#include <map>
#include <string>
#include "Common.h"
#include "StringUtil.h"
#include "DSPCore.h"
#include "DSPSymbols.h"
#include "disassemble.h"
namespace DSPSymbols {
DSPSymbolDB g_dsp_symbol_db;
std::map<u16, int> addr_to_line;
std::map<int, u16> line_to_addr;
std::map<int, const char *> line_to_symbol;
std::vector<std::string> lines;
int line_counter = 0;
int Addr2Line(u16 address) // -1 for not found
{
std::map<u16, int>::iterator iter = addr_to_line.find(address);
if (iter != addr_to_line.end())
return iter->second;
else
return -1;
}
int Line2Addr(int line) // -1 for not found
{
std::map<int, u16>::iterator iter = line_to_addr.find(line);
if (iter != line_to_addr.end())
return iter->second;
else
return -1;
}
const char *GetLineText(int line)
{
if (line > 0 && line < (int)lines.size())
{
return lines[line].c_str();
}
else
return "----";
}
Symbol *DSPSymbolDB::GetSymbolFromAddr(u32 addr)
{
XFuncMap::iterator it = functions.find(addr);
if (it != functions.end())
return &it->second;
else
{
for (XFuncMap::iterator iter = functions.begin(); iter != functions.end(); iter++)
{
if (addr >= iter->second.address && addr < iter->second.address + iter->second.size)
return &iter->second;
}
}
return 0;
}
// lower case only
bool IsHexDigit(char c) {
switch (c) {
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
case 'a':
case 'b':
case 'c':
case 'd':
case 'e':
case 'f':
return true;
default:
return false;
}
}
bool IsAlpha(char c) {
return (c >= 'A' && c <= 'Z') ||
(c >= 'a' && c <= 'z');
}
void DisasssembleRange(u16 start, u16 end)
{
}
bool ReadAnnotatedAssembly(const char *filename)
{
FILE *f = fopen(filename, "r");
if (!f) {
ERROR_LOG(DSPLLE, "Bah! ReadAnnotatedAssembly couldn't find the file %s", filename);
return false;
}
char line[512];
int last_addr = 0;
lines.reserve(3000);
// Symbol generation
int brace_count = 0;
bool symbol_in_progress = false;
int symbol_count = 0;
Symbol current_symbol;
while (fgets(line, 512, f))
{
// Scan string for the first 4-digit hex string.
size_t len = strlen(line);
int first_hex = -1;
bool hex_found = false;
for (unsigned int i = 0; i < strlen(line); i++)
{
const char c = line[i];
if (IsHexDigit(c))
{
if (first_hex == -1)
{
first_hex = i;
}
else
{
// Remove hex notation
if (i == first_hex + 3 &&
(first_hex == 0 || line[first_hex - 1] != 'x') &&
(i >= len - 1 || line[i + 1] == ' '))
{
hex_found = true;
break;
}
}
} else {
if (i - first_hex < 3)
{
first_hex = -1;
}
if (IsAlpha(c))
break;
}
}
// Scan for function starts
if (!memcmp(line, "void", 4)) {
char temp[256];
for (int i = 6; i < len; i++) {
if (line[i] == '(') {
// Yep, got one.
memcpy(temp, line + 5, i - 5);
temp[i - 5] = 0;
// Mark symbol so the next hex sets the address
current_symbol.name = temp;
current_symbol.address = 0xFFFF;
current_symbol.index = symbol_count++;
symbol_in_progress = true;
// Reset brace count.
brace_count = 0;
}
}
}
// Scan for braces
for (int i = 0; i < (int)len; i++) {
if (line[i] == '{')
brace_count++;
if (line[i] == '}')
{
brace_count--;
if (brace_count == 0 && symbol_in_progress) {
// Commit this symbol.
current_symbol.size = last_addr - current_symbol.address + 1;
g_dsp_symbol_db.AddCompleteSymbol(current_symbol);
current_symbol.address = 0xFFFF;
symbol_in_progress = false;
}
}
}
if (hex_found)
{
int hex = 0;
sscanf(line + first_hex, "%04x", &hex);
// Sanity check
if (hex > last_addr + 3 || hex < last_addr - 3) {
static int errors = 0;
ERROR_LOG(DSPLLE, "Got Insane Hex Digit %04x (%04x) from %s", hex, last_addr, line);
errors++;
if (errors > 10)
{
fclose(f);
return false;
}
}
else
{
// if (line_counter >= 200 && line_counter <= 220)
// NOTICE_LOG(DSPLLE, "Got Hex Digit %04x from %s, line %i", hex, line, line_counter);
if (symbol_in_progress && current_symbol.address == 0xFFFF)
current_symbol.address = hex;
line_to_addr[line_counter] = hex;
addr_to_line[hex] = line_counter;
last_addr = hex;
}
}
lines.push_back(TabsToSpaces(4, line));
line_counter++;
}
fclose(f);
return true;
}
void AutoDisassembly(u16 start_addr, u16 end_addr)
{
AssemblerSettings settings;
settings.show_pc = true;
settings.show_hex = true;
DSPDisassembler disasm(settings);
u16 addr = start_addr;
const u16 *ptr = (start_addr >> 15) ? g_dsp.irom : g_dsp.iram;
while (addr < end_addr)
{
line_to_addr[line_counter] = addr;
addr_to_line[addr] = line_counter;
std::string buf;
if (!disasm.DisOpcode(ptr, 0, 2, &addr, buf))
{
ERROR_LOG(DSPLLE, "disasm failed at %04x", addr);
break;
}
//NOTICE_LOG(DSPLLE, "added %04x %i %s", addr, line_counter, buf.c_str());
lines.push_back(buf);
line_counter++;
}
}
void Clear()
{
addr_to_line.clear();
line_to_addr.clear();
lines.clear();
line_counter = 0;
}
} // namespace DSPSymbols
// Copyright (C) 2003-2009 Dolphin Project.
// 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, version 2.0.
// 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 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include <iostream> // I hope this doesn't break anything
#include <stdio.h>
#include <stdarg.h>
#include <list>
#include <map>
#include <string>
#include "Common.h"
#include "StringUtil.h"
#include "DSPCore.h"
#include "DSPSymbols.h"
#include "disassemble.h"
namespace DSPSymbols {
DSPSymbolDB g_dsp_symbol_db;
std::map<u16, int> addr_to_line;
std::map<int, u16> line_to_addr;
std::map<int, const char *> line_to_symbol;
std::vector<std::string> lines;
int line_counter = 0;
int Addr2Line(u16 address) // -1 for not found
{
std::map<u16, int>::iterator iter = addr_to_line.find(address);
if (iter != addr_to_line.end())
return iter->second;
else
return -1;
}
int Line2Addr(int line) // -1 for not found
{
std::map<int, u16>::iterator iter = line_to_addr.find(line);
if (iter != line_to_addr.end())
return iter->second;
else
return -1;
}
const char *GetLineText(int line)
{
if (line > 0 && line < (int)lines.size())
{
return lines[line].c_str();
}
else
return "----";
}
Symbol *DSPSymbolDB::GetSymbolFromAddr(u32 addr)
{
XFuncMap::iterator it = functions.find(addr);
if (it != functions.end())
return &it->second;
else
{
for (XFuncMap::iterator iter = functions.begin(); iter != functions.end(); iter++)
{
if (addr >= iter->second.address && addr < iter->second.address + iter->second.size)
return &iter->second;
}
}
return 0;
}
// lower case only
bool IsHexDigit(char c) {
switch (c) {
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
case 'a':
case 'b':
case 'c':
case 'd':
case 'e':
case 'f':
return true;
default:
return false;
}
}
bool IsAlpha(char c) {
return (c >= 'A' && c <= 'Z') ||
(c >= 'a' && c <= 'z');
}
void DisasssembleRange(u16 start, u16 end)
{
}
bool ReadAnnotatedAssembly(const char *filename)
{
FILE *f = fopen(filename, "r");
if (!f) {
ERROR_LOG(DSPLLE, "Bah! ReadAnnotatedAssembly couldn't find the file %s", filename);
return false;
}
char line[512];
int last_addr = 0;
lines.reserve(3000);
// Symbol generation
int brace_count = 0;
bool symbol_in_progress = false;
int symbol_count = 0;
Symbol current_symbol;
while (fgets(line, 512, f))
{
// Scan string for the first 4-digit hex string.
size_t len = strlen(line);
int first_hex = -1;
bool hex_found = false;
for (unsigned int i = 0; i < strlen(line); i++)
{
const char c = line[i];
if (IsHexDigit(c))
{
if (first_hex == -1)
{
first_hex = i;
}
else
{
// Remove hex notation
if (i == first_hex + 3 &&
(first_hex == 0 || line[first_hex - 1] != 'x') &&
(i >= len - 1 || line[i + 1] == ' '))
{
hex_found = true;
break;
}
}
} else {
if (i - first_hex < 3)
{
first_hex = -1;
}
if (IsAlpha(c))
break;
}
}
// Scan for function starts
if (!memcmp(line, "void", 4)) {
char temp[256];
for (int i = 6; i < len; i++) {
if (line[i] == '(') {
// Yep, got one.
memcpy(temp, line + 5, i - 5);
temp[i - 5] = 0;
// Mark symbol so the next hex sets the address
current_symbol.name = temp;
current_symbol.address = 0xFFFF;
current_symbol.index = symbol_count++;
symbol_in_progress = true;
// Reset brace count.
brace_count = 0;
}
}
}
// Scan for braces
for (int i = 0; i < (int)len; i++) {
if (line[i] == '{')
brace_count++;
if (line[i] == '}')
{
brace_count--;
if (brace_count == 0 && symbol_in_progress) {
// Commit this symbol.
current_symbol.size = last_addr - current_symbol.address + 1;
g_dsp_symbol_db.AddCompleteSymbol(current_symbol);
current_symbol.address = 0xFFFF;
symbol_in_progress = false;
}
}
}
if (hex_found)
{
int hex = 0;
sscanf(line + first_hex, "%04x", &hex);
// Sanity check
if (hex > last_addr + 3 || hex < last_addr - 3) {
static int errors = 0;
ERROR_LOG(DSPLLE, "Got Insane Hex Digit %04x (%04x) from %s", hex, last_addr, line);
errors++;
if (errors > 10)
{
fclose(f);
return false;
}
}
else
{
// if (line_counter >= 200 && line_counter <= 220)
// NOTICE_LOG(DSPLLE, "Got Hex Digit %04x from %s, line %i", hex, line, line_counter);
if (symbol_in_progress && current_symbol.address == 0xFFFF)
current_symbol.address = hex;
line_to_addr[line_counter] = hex;
addr_to_line[hex] = line_counter;
last_addr = hex;
}
}
lines.push_back(TabsToSpaces(4, line));
line_counter++;
}
fclose(f);
return true;
}
void AutoDisassembly(u16 start_addr, u16 end_addr)
{
AssemblerSettings settings;
settings.show_pc = true;
settings.show_hex = true;
DSPDisassembler disasm(settings);
u16 addr = start_addr;
const u16 *ptr = (start_addr >> 15) ? g_dsp.irom : g_dsp.iram;
while (addr < end_addr)
{
line_to_addr[line_counter] = addr;
addr_to_line[addr] = line_counter;
std::string buf;
if (!disasm.DisOpcode(ptr, 0, 2, &addr, buf))
{
ERROR_LOG(DSPLLE, "disasm failed at %04x", addr);
break;
}
//NOTICE_LOG(DSPLLE, "added %04x %i %s", addr, line_counter, buf.c_str());
lines.push_back(buf);
line_counter++;
}
}
void Clear()
{
addr_to_line.clear();
line_to_addr.clear();
lines.clear();
line_counter = 0;
}
} // namespace DSPSymbols

View File

@ -1,54 +1,54 @@
// Copyright (C) 2003-2009 Dolphin Project.
// 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, version 2.0.
// 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 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#ifndef _DSPSYMBOLS_H
#define _DSPSYMBOLS_H
#include "Common.h"
#include "SymbolDB.h"
#include "AudioCommon.h"
#include <stdio.h>
namespace DSPSymbols {
class DSPSymbolDB : public SymbolDB
{
public:
DSPSymbolDB() {}
~DSPSymbolDB() {}
Symbol *GetSymbolFromAddr(u32 addr);
};
extern DSPSymbolDB g_dsp_symbol_db;
bool ReadAnnotatedAssembly(const char *filename);
void AutoDisassembly(u16 start_addr, u16 end_addr);
void Clear();
int Addr2Line(u16 address);
int Line2Addr(int line); // -1 for not found
const char *GetLineText(int line);
} // namespace DSPSymbols
#endif
// Copyright (C) 2003-2009 Dolphin Project.
// 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, version 2.0.
// 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 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#ifndef _DSPSYMBOLS_H
#define _DSPSYMBOLS_H
#include "Common.h"
#include "SymbolDB.h"
#include "AudioCommon.h"
#include <stdio.h>
namespace DSPSymbols {
class DSPSymbolDB : public SymbolDB
{
public:
DSPSymbolDB() {}
~DSPSymbolDB() {}
Symbol *GetSymbolFromAddr(u32 addr);
};
extern DSPSymbolDB g_dsp_symbol_db;
bool ReadAnnotatedAssembly(const char *filename);
void AutoDisassembly(u16 start_addr, u16 end_addr);
void Clear();
int Addr2Line(u16 address);
int Line2Addr(int line); // -1 for not found
const char *GetLineText(int line);
} // namespace DSPSymbols
#endif

View File

@ -1,228 +1,228 @@
// Copyright (C) 2003-2009 Dolphin Project.
// 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, version 2.0.
// 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 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include "Common.h" // Common
#include <iostream> // System
#include <fstream>
#include <sstream>
#include "Debugger.h"
#include "DSPRegisterView.h"
#include "CodeView.h"
#include "../DSPSymbols.h"
// Event table and class
BEGIN_EVENT_TABLE(DSPDebuggerLLE, wxFrame)
EVT_CLOSE(DSPDebuggerLLE::OnClose)
EVT_MENU_RANGE(ID_RUNTOOL, ID_STEPTOOL, DSPDebuggerLLE::OnChangeState)
EVT_MENU(ID_SHOWPCTOOL, DSPDebuggerLLE::OnShowPC)
EVT_TEXT(ID_ADDRBOX, DSPDebuggerLLE::OnAddrBoxChange)
EVT_LISTBOX(ID_SYMBOLLIST, DSPDebuggerLLE::OnSymbolListChange)
END_EVENT_TABLE()
DSPDebuggerLLE::DSPDebuggerLLE(wxWindow *parent, wxWindowID id, const wxString &title,
const wxPoint &position, const wxSize& size, long style)
: wxFrame(parent, id, title, position, size, style)
, m_CachedStepCounter(-1)
{
CreateGUIControls();
}
DSPDebuggerLLE::~DSPDebuggerLLE()
{
}
void DSPDebuggerLLE::CreateGUIControls()
{
// Basic settings
SetSize(700, 800);
this->SetSizeHints(700, 800);
this->SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE));
m_Toolbar = CreateToolBar(wxTB_NODIVIDER|wxTB_NOICONS|wxTB_HORZ_TEXT|wxTB_DOCKABLE, ID_TOOLBAR);
m_Toolbar->AddTool(ID_RUNTOOL, wxT("Run"), wxNullBitmap, wxEmptyString, wxITEM_NORMAL);
m_Toolbar->AddTool(ID_STEPTOOL, wxT("Step"), wxNullBitmap, wxT("Step Code "), wxITEM_NORMAL);
m_Toolbar->AddTool(ID_SHOWPCTOOL, wxT("Show Pc"), wxNullBitmap, wxT("Show where PC is"), wxITEM_NORMAL);
m_Toolbar->AddTool(ID_JUMPTOTOOL, wxT("Jump"), wxNullBitmap, wxT("Jump to a specific Address"), wxITEM_NORMAL);
m_Toolbar->AddSeparator();
m_Toolbar->AddControl(new wxTextCtrl(m_Toolbar, ID_ADDRBOX, _T("")));
m_Toolbar->Realize();
wxBoxSizer* sMain = new wxBoxSizer(wxHORIZONTAL);
wxBoxSizer* sizerLeft = new wxBoxSizer(wxVERTICAL);
sizerLeft->Add(m_SymbolList = new wxListBox(this, ID_SYMBOLLIST, wxDefaultPosition, wxSize(140, 100), 0, NULL, wxLB_SORT),
1, wxEXPAND);
m_CodeView = new CCodeView(&debug_interface, &DSPSymbols::g_dsp_symbol_db, this, ID_CODEVIEW);
m_CodeView->SetPlain();
sMain->Add(sizerLeft, 0, wxEXPAND, 0);
sMain->Add(m_CodeView, 4, wxEXPAND, 0);
wxStaticLine* m_staticline = new wxStaticLine(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_VERTICAL);
sMain->Add(m_staticline, 0, wxEXPAND|wxALL, 0);
m_Regs = new DSPRegisterView(this, ID_DSP_REGS);
sMain->Add(m_Regs, 0, wxEXPAND|wxALL, 5);
this->SetSizer(sMain);
this->Layout();
UpdateState();
}
void DSPDebuggerLLE::OnClose(wxCloseEvent& event)
{
Hide();
}
void DSPDebuggerLLE::OnChangeState(wxCommandEvent& event)
{
switch (event.GetId())
{
case ID_RUNTOOL:
if (DSPCore_GetState() == DSPCORE_RUNNING)
DSPCore_SetState(DSPCORE_STEPPING);
else
DSPCore_SetState(DSPCORE_RUNNING);
break;
case ID_STEPTOOL:
if (DSPCore_GetState() == DSPCORE_STEPPING)
DSPCore_Step();
break;
case ID_SHOWPCTOOL:
FocusOnPC();
break;
}
UpdateState();
}
void DSPDebuggerLLE::OnShowPC(wxCommandEvent& event)
{
Refresh();
FocusOnPC();
}
void DSPDebuggerLLE::Refresh()
{
UpdateSymbolMap();
UpdateDisAsmListView();
UpdateRegisterFlags();
UpdateState();
}
void DSPDebuggerLLE::FocusOnPC()
{
JumpToAddress(g_dsp.pc);
}
void DSPDebuggerLLE::UpdateState()
{
if (DSPCore_GetState() == DSPCORE_RUNNING) {
m_Toolbar->FindById(ID_RUNTOOL)->SetLabel(wxT("Pause"));
m_Toolbar->FindById(ID_STEPTOOL)->Enable(false);
}
else {
m_Toolbar->FindById(ID_RUNTOOL)->SetLabel(wxT("Run"));
m_Toolbar->FindById(ID_STEPTOOL)->Enable(true);
}
m_Toolbar->Realize();
}
void DSPDebuggerLLE::UpdateDisAsmListView()
{
if (m_CachedStepCounter == g_dsp.step_counter)
return;
// show PC
FocusOnPC();
m_CachedStepCounter = g_dsp.step_counter;
m_Regs->Update();
}
void DSPDebuggerLLE::UpdateSymbolMap()
{
if (g_dsp.dram == NULL)
return;
m_SymbolList->Freeze(); // HyperIris: wx style fast filling
m_SymbolList->Clear();
for (SymbolDB::XFuncMap::iterator iter = DSPSymbols::g_dsp_symbol_db.GetIterator();
iter != DSPSymbols::g_dsp_symbol_db.End(); iter++)
{
int idx = m_SymbolList->Append(wxString::FromAscii(iter->second.name.c_str()));
m_SymbolList->SetClientData(idx, (void*)&iter->second);
}
m_SymbolList->Thaw();
}
void DSPDebuggerLLE::OnSymbolListChange(wxCommandEvent& event)
{
int index = m_SymbolList->GetSelection();
if (index >= 0) {
Symbol* pSymbol = static_cast<Symbol *>(m_SymbolList->GetClientData(index));
if (pSymbol != NULL)
{
if (pSymbol->type == Symbol::SYMBOL_FUNCTION)
{
JumpToAddress(pSymbol->address);
}
}
}
}
void DSPDebuggerLLE::UpdateRegisterFlags()
{
}
void DSPDebuggerLLE::OnAddrBoxChange(wxCommandEvent& event)
{
wxTextCtrl* pAddrCtrl = (wxTextCtrl*)GetToolBar()->FindControl(ID_ADDRBOX);
wxString txt = pAddrCtrl->GetValue();
std::string text(txt.mb_str());
text = StripSpaces(text);
if (text.size())
{
u32 addr;
sscanf(text.c_str(), "%04x", &addr);
if (JumpToAddress(addr))
pAddrCtrl->SetBackgroundColour(*wxWHITE);
else
pAddrCtrl->SetBackgroundColour(*wxRED);
}
event.Skip(1);
}
bool DSPDebuggerLLE::JumpToAddress(u16 addr)
{
int new_line = DSPSymbols::Addr2Line(addr);
if (new_line >= 0) {
m_CodeView->Center(new_line);
return true;
} else {
return false;
}
}
// Copyright (C) 2003-2009 Dolphin Project.
// 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, version 2.0.
// 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 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include "Common.h" // Common
#include <iostream> // System
#include <fstream>
#include <sstream>
#include "Debugger.h"
#include "DSPRegisterView.h"
#include "CodeView.h"
#include "../DSPSymbols.h"
// Event table and class
BEGIN_EVENT_TABLE(DSPDebuggerLLE, wxFrame)
EVT_CLOSE(DSPDebuggerLLE::OnClose)
EVT_MENU_RANGE(ID_RUNTOOL, ID_STEPTOOL, DSPDebuggerLLE::OnChangeState)
EVT_MENU(ID_SHOWPCTOOL, DSPDebuggerLLE::OnShowPC)
EVT_TEXT(ID_ADDRBOX, DSPDebuggerLLE::OnAddrBoxChange)
EVT_LISTBOX(ID_SYMBOLLIST, DSPDebuggerLLE::OnSymbolListChange)
END_EVENT_TABLE()
DSPDebuggerLLE::DSPDebuggerLLE(wxWindow *parent, wxWindowID id, const wxString &title,
const wxPoint &position, const wxSize& size, long style)
: wxFrame(parent, id, title, position, size, style)
, m_CachedStepCounter(-1)
{
CreateGUIControls();
}
DSPDebuggerLLE::~DSPDebuggerLLE()
{
}
void DSPDebuggerLLE::CreateGUIControls()
{
// Basic settings
SetSize(700, 800);
this->SetSizeHints(700, 800);
this->SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE));
m_Toolbar = CreateToolBar(wxTB_NODIVIDER|wxTB_NOICONS|wxTB_HORZ_TEXT|wxTB_DOCKABLE, ID_TOOLBAR);
m_Toolbar->AddTool(ID_RUNTOOL, wxT("Run"), wxNullBitmap, wxEmptyString, wxITEM_NORMAL);
m_Toolbar->AddTool(ID_STEPTOOL, wxT("Step"), wxNullBitmap, wxT("Step Code "), wxITEM_NORMAL);
m_Toolbar->AddTool(ID_SHOWPCTOOL, wxT("Show Pc"), wxNullBitmap, wxT("Show where PC is"), wxITEM_NORMAL);
m_Toolbar->AddTool(ID_JUMPTOTOOL, wxT("Jump"), wxNullBitmap, wxT("Jump to a specific Address"), wxITEM_NORMAL);
m_Toolbar->AddSeparator();
m_Toolbar->AddControl(new wxTextCtrl(m_Toolbar, ID_ADDRBOX, _T("")));
m_Toolbar->Realize();
wxBoxSizer* sMain = new wxBoxSizer(wxHORIZONTAL);
wxBoxSizer* sizerLeft = new wxBoxSizer(wxVERTICAL);
sizerLeft->Add(m_SymbolList = new wxListBox(this, ID_SYMBOLLIST, wxDefaultPosition, wxSize(140, 100), 0, NULL, wxLB_SORT),
1, wxEXPAND);
m_CodeView = new CCodeView(&debug_interface, &DSPSymbols::g_dsp_symbol_db, this, ID_CODEVIEW);
m_CodeView->SetPlain();
sMain->Add(sizerLeft, 0, wxEXPAND, 0);
sMain->Add(m_CodeView, 4, wxEXPAND, 0);
wxStaticLine* m_staticline = new wxStaticLine(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_VERTICAL);
sMain->Add(m_staticline, 0, wxEXPAND|wxALL, 0);
m_Regs = new DSPRegisterView(this, ID_DSP_REGS);
sMain->Add(m_Regs, 0, wxEXPAND|wxALL, 5);
this->SetSizer(sMain);
this->Layout();
UpdateState();
}
void DSPDebuggerLLE::OnClose(wxCloseEvent& event)
{
Hide();
}
void DSPDebuggerLLE::OnChangeState(wxCommandEvent& event)
{
switch (event.GetId())
{
case ID_RUNTOOL:
if (DSPCore_GetState() == DSPCORE_RUNNING)
DSPCore_SetState(DSPCORE_STEPPING);
else
DSPCore_SetState(DSPCORE_RUNNING);
break;
case ID_STEPTOOL:
if (DSPCore_GetState() == DSPCORE_STEPPING)
DSPCore_Step();
break;
case ID_SHOWPCTOOL:
FocusOnPC();
break;
}
UpdateState();
}
void DSPDebuggerLLE::OnShowPC(wxCommandEvent& event)
{
Refresh();
FocusOnPC();
}
void DSPDebuggerLLE::Refresh()
{
UpdateSymbolMap();
UpdateDisAsmListView();
UpdateRegisterFlags();
UpdateState();
}
void DSPDebuggerLLE::FocusOnPC()
{
JumpToAddress(g_dsp.pc);
}
void DSPDebuggerLLE::UpdateState()
{
if (DSPCore_GetState() == DSPCORE_RUNNING) {
m_Toolbar->FindById(ID_RUNTOOL)->SetLabel(wxT("Pause"));
m_Toolbar->FindById(ID_STEPTOOL)->Enable(false);
}
else {
m_Toolbar->FindById(ID_RUNTOOL)->SetLabel(wxT("Run"));
m_Toolbar->FindById(ID_STEPTOOL)->Enable(true);
}
m_Toolbar->Realize();
}
void DSPDebuggerLLE::UpdateDisAsmListView()
{
if (m_CachedStepCounter == g_dsp.step_counter)
return;
// show PC
FocusOnPC();
m_CachedStepCounter = g_dsp.step_counter;
m_Regs->Update();
}
void DSPDebuggerLLE::UpdateSymbolMap()
{
if (g_dsp.dram == NULL)
return;
m_SymbolList->Freeze(); // HyperIris: wx style fast filling
m_SymbolList->Clear();
for (SymbolDB::XFuncMap::iterator iter = DSPSymbols::g_dsp_symbol_db.GetIterator();
iter != DSPSymbols::g_dsp_symbol_db.End(); iter++)
{
int idx = m_SymbolList->Append(wxString::FromAscii(iter->second.name.c_str()));
m_SymbolList->SetClientData(idx, (void*)&iter->second);
}
m_SymbolList->Thaw();
}
void DSPDebuggerLLE::OnSymbolListChange(wxCommandEvent& event)
{
int index = m_SymbolList->GetSelection();
if (index >= 0) {
Symbol* pSymbol = static_cast<Symbol *>(m_SymbolList->GetClientData(index));
if (pSymbol != NULL)
{
if (pSymbol->type == Symbol::SYMBOL_FUNCTION)
{
JumpToAddress(pSymbol->address);
}
}
}
}
void DSPDebuggerLLE::UpdateRegisterFlags()
{
}
void DSPDebuggerLLE::OnAddrBoxChange(wxCommandEvent& event)
{
wxTextCtrl* pAddrCtrl = (wxTextCtrl*)GetToolBar()->FindControl(ID_ADDRBOX);
wxString txt = pAddrCtrl->GetValue();
std::string text(txt.mb_str());
text = StripSpaces(text);
if (text.size())
{
u32 addr;
sscanf(text.c_str(), "%04x", &addr);
if (JumpToAddress(addr))
pAddrCtrl->SetBackgroundColour(*wxWHITE);
else
pAddrCtrl->SetBackgroundColour(*wxRED);
}
event.Skip(1);
}
bool DSPDebuggerLLE::JumpToAddress(u16 addr)
{
int new_line = DSPSymbols::Addr2Line(addr);
if (new_line >= 0) {
m_CodeView->Center(new_line);
return true;
} else {
return false;
}
}

View File

@ -1,126 +1,126 @@
// Copyright (C) 2003-2009 Dolphin Project.
// 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, version 2.0.
// 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 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#ifndef _DSP_DEBUGGER_LLE_H
#define _DSP_DEBUGGER_LLE_H
// general things
#include <iostream>
#include <vector>
#include <list>
#include <map>
#include <algorithm>
#include <wx/wx.h>
#include <wx/frame.h>
#include <wx/button.h>
#include <wx/stattext.h>
#include <wx/statbox.h>
#include <wx/sizer.h>
#include <wx/listctrl.h>
#include <wx/statline.h>
#include "disassemble.h"
#include "DSPInterpreter.h"
#include "DSPMemoryMap.h"
#include "../DSPDebugInterface.h"
class DSPRegisterView;
class CCodeView;
class DSPDebuggerLLE : public wxFrame
{
public:
DSPDebuggerLLE(wxWindow *parent,
wxWindowID id = wxID_ANY,
const wxString &title = wxT("DSP LLE Debugger"),
const wxPoint& pos = wxDefaultPosition,
const wxSize& size = wxDefaultSize,
long style = wxDEFAULT_FRAME_STYLE);
virtual ~DSPDebuggerLLE();
void Refresh();
private:
DECLARE_EVENT_TABLE();
enum
{
// Toolbar
ID_TOOLBAR = 1000,
ID_RUNTOOL,
ID_STEPTOOL,
ID_SHOWPCTOOL,
ID_ADDRBOX,
ID_JUMPTOTOOL,
ID_DISASMDUMPTOOL,
ID_CHECK_ASSERTINT,
ID_CHECK_HALT,
ID_CHECK_INIT,
ID_SYMBOLLIST,
// Code view
ID_CODEVIEW,
// Register View
ID_DSP_REGS,
};
// Disasm listctrl columns
enum
{
COLUMN_BP,
COLUMN_FUNCTION,
COLUMN_ADDRESS,
COLUMN_MNEMONIC,
COLUMN_OPCODE,
COLUMN_EXT,
COLUMN_PARAM,
};
DSPDebugInterface debug_interface;
u64 m_CachedStepCounter;
// GUI updaters
void UpdateDisAsmListView();
void UpdateRegisterFlags();
void UpdateSymbolMap();
void UpdateState();
// GUI items
wxToolBar* m_Toolbar;
CCodeView* m_CodeView;
DSPRegisterView* m_Regs;
wxListBox* m_SymbolList;
void OnClose(wxCloseEvent& event);
void OnChangeState(wxCommandEvent& event);
void OnShowPC(wxCommandEvent& event);
void OnRightClick(wxListEvent& event);
void OnDoubleClick(wxListEvent& event);
void OnAddrBoxChange(wxCommandEvent& event);
void OnSymbolListChange(wxCommandEvent& event);
bool JumpToAddress(u16 addr);
void CreateGUIControls();
void FocusOnPC();
void UnselectAll();
};
#endif //_DSP_DEBUGGER_LLE_H
// Copyright (C) 2003-2009 Dolphin Project.
// 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, version 2.0.
// 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 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#ifndef _DSP_DEBUGGER_LLE_H
#define _DSP_DEBUGGER_LLE_H
// general things
#include <iostream>
#include <vector>
#include <list>
#include <map>
#include <algorithm>
#include <wx/wx.h>
#include <wx/frame.h>
#include <wx/button.h>
#include <wx/stattext.h>
#include <wx/statbox.h>
#include <wx/sizer.h>
#include <wx/listctrl.h>
#include <wx/statline.h>
#include "disassemble.h"
#include "DSPInterpreter.h"
#include "DSPMemoryMap.h"
#include "../DSPDebugInterface.h"
class DSPRegisterView;
class CCodeView;
class DSPDebuggerLLE : public wxFrame
{
public:
DSPDebuggerLLE(wxWindow *parent,
wxWindowID id = wxID_ANY,
const wxString &title = wxT("DSP LLE Debugger"),
const wxPoint& pos = wxDefaultPosition,
const wxSize& size = wxDefaultSize,
long style = wxDEFAULT_FRAME_STYLE);
virtual ~DSPDebuggerLLE();
void Refresh();
private:
DECLARE_EVENT_TABLE();
enum
{
// Toolbar
ID_TOOLBAR = 1000,
ID_RUNTOOL,
ID_STEPTOOL,
ID_SHOWPCTOOL,
ID_ADDRBOX,
ID_JUMPTOTOOL,
ID_DISASMDUMPTOOL,
ID_CHECK_ASSERTINT,
ID_CHECK_HALT,
ID_CHECK_INIT,
ID_SYMBOLLIST,
// Code view
ID_CODEVIEW,
// Register View
ID_DSP_REGS,
};
// Disasm listctrl columns
enum
{
COLUMN_BP,
COLUMN_FUNCTION,
COLUMN_ADDRESS,
COLUMN_MNEMONIC,
COLUMN_OPCODE,
COLUMN_EXT,
COLUMN_PARAM,
};
DSPDebugInterface debug_interface;
u64 m_CachedStepCounter;
// GUI updaters
void UpdateDisAsmListView();
void UpdateRegisterFlags();
void UpdateSymbolMap();
void UpdateState();
// GUI items
wxToolBar* m_Toolbar;
CCodeView* m_CodeView;
DSPRegisterView* m_Regs;
wxListBox* m_SymbolList;
void OnClose(wxCloseEvent& event);
void OnChangeState(wxCommandEvent& event);
void OnShowPC(wxCommandEvent& event);
void OnRightClick(wxListEvent& event);
void OnDoubleClick(wxListEvent& event);
void OnAddrBoxChange(wxCommandEvent& event);
void OnSymbolListChange(wxCommandEvent& event);
bool JumpToAddress(u16 addr);
void CreateGUIControls();
void FocusOnPC();
void UnselectAll();
};
#endif //_DSP_DEBUGGER_LLE_H

View File

@ -1,336 +1,336 @@
// Copyright (C) 2003-2009 Dolphin Project.
// 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, version 2.0.
// 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 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include "BPFunctions.h"
#include "D3DBase.h"
#include "Config.h"
#include "Common.h"
#include "TextureCache.h"
#include "VertexManager.h"
#include "VertexShaderManager.h"
#include "Utils.h"
bool textureChanged[8];
const bool renderFog = false;
using namespace D3D;
// State translation lookup tables
static const D3DBLEND d3dSrcFactors[8] =
{
D3DBLEND_ZERO,
D3DBLEND_ONE,
D3DBLEND_DESTCOLOR,
D3DBLEND_INVDESTCOLOR,
D3DBLEND_SRCALPHA,
D3DBLEND_INVSRCALPHA,
D3DBLEND_DESTALPHA,
D3DBLEND_INVDESTALPHA
};
static const D3DBLEND d3dDestFactors[8] =
{
D3DBLEND_ZERO,
D3DBLEND_ONE,
D3DBLEND_SRCCOLOR,
D3DBLEND_INVSRCCOLOR,
D3DBLEND_SRCALPHA,
D3DBLEND_INVSRCALPHA,
D3DBLEND_DESTALPHA,
D3DBLEND_INVDESTALPHA
};
static const D3DCULL d3dCullModes[4] =
{
D3DCULL_NONE,
D3DCULL_CCW,
D3DCULL_CW,
D3DCULL_CCW
};
static const D3DCMPFUNC d3dCmpFuncs[8] =
{
D3DCMP_NEVER,
D3DCMP_LESS,
D3DCMP_EQUAL,
D3DCMP_LESSEQUAL,
D3DCMP_GREATER,
D3DCMP_NOTEQUAL,
D3DCMP_GREATEREQUAL,
D3DCMP_ALWAYS
};
static const D3DTEXTUREFILTERTYPE d3dMipFilters[4] =
{
D3DTEXF_NONE,
D3DTEXF_POINT,
D3DTEXF_ANISOTROPIC,
D3DTEXF_LINEAR, //reserved
};
static const D3DTEXTUREADDRESS d3dClamps[4] =
{
D3DTADDRESS_CLAMP,
D3DTADDRESS_WRAP,
D3DTADDRESS_MIRROR,
D3DTADDRESS_WRAP //reserved
};
namespace BPFunctions
{
void FlushPipeline()
{
VertexManager::Flush();
}
void SetGenerationMode(const Bypass &bp)
{
// dev->SetRenderState(D3DRS_CULLMODE, d3dCullModes[bpmem.genMode.cullmode]);
Renderer::SetRenderState(D3DRS_CULLMODE, d3dCullModes[bpmem.genMode.cullmode]);
if (bpmem.genMode.cullmode == 3)
{
// dev->SetRenderState(D3DRS_COLORWRITEENABLE, 0);
Renderer::SetRenderState(D3DRS_COLORWRITEENABLE, 0);
}
else
{
DWORD write = 0;
if (bpmem.blendmode.alphaupdate)
write = D3DCOLORWRITEENABLE_ALPHA;
if (bpmem.blendmode.colorupdate)
write |= D3DCOLORWRITEENABLE_RED | D3DCOLORWRITEENABLE_GREEN | D3DCOLORWRITEENABLE_BLUE;
// dev->SetRenderState(D3DRS_COLORWRITEENABLE, write);
Renderer::SetRenderState(D3DRS_COLORWRITEENABLE, write);
}
}
void SetScissor(const Bypass &bp)
{
Renderer::SetScissorRect();
}
void SetLineWidth(const Bypass &bp)
{
// We can't change line width in D3D unless we use ID3DXLine
float psize = float(bpmem.lineptwidth.pointsize) * 6.0f;
Renderer::SetRenderState(D3DRS_POINTSIZE, *((DWORD*)&psize));
}
void SetDepthMode(const Bypass &bp)
{
if (bpmem.zmode.testenable)
{
// dev->SetRenderState(D3DRS_ZENABLE, TRUE);
// dev->SetRenderState(D3DRS_ZWRITEENABLE, bpmem.zmode.updateenable);
// dev->SetRenderState(D3DRS_ZFUNC,d3dCmpFuncs[bpmem.zmode.func]);
Renderer::SetRenderState(D3DRS_ZENABLE, TRUE);
Renderer::SetRenderState(D3DRS_ZWRITEENABLE, bpmem.zmode.updateenable);
Renderer::SetRenderState(D3DRS_ZFUNC, d3dCmpFuncs[bpmem.zmode.func]);
}
else
{
// if the test is disabled write is disabled too
// dev->SetRenderState(D3DRS_ZENABLE, FALSE);
// dev->SetRenderState(D3DRS_ZWRITEENABLE, FALSE);
Renderer::SetRenderState(D3DRS_ZENABLE, FALSE);
Renderer::SetRenderState(D3DRS_ZWRITEENABLE, FALSE);
}
//if (!bpmem.zmode.updateenable)
// Renderer::SetRenderMode(Renderer::RM_Normal);
}
void SetBlendMode(const Bypass &bp)
{
if (bp.changes & 1)
Renderer::SetRenderState(D3DRS_ALPHABLENDENABLE, bpmem.blendmode.blendenable);
D3DBLEND src = d3dSrcFactors[bpmem.blendmode.srcfactor];
D3DBLEND dst = d3dDestFactors[bpmem.blendmode.dstfactor];
if (bp.changes & 0x700)
Renderer::SetRenderState(D3DRS_SRCBLEND, src);
if (bp.changes & 0xE0) {
if (!bpmem.blendmode.subtract)
{
Renderer::SetRenderState(D3DRS_DESTBLEND, dst);
}
else
{
Renderer::SetRenderState(D3DRS_DESTBLEND, D3DBLEND_ONE);
}
}
if (bp.changes & 0x800)
{
if (bpmem.blendmode.subtract)
{
Renderer::SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ONE);
Renderer::SetRenderState(D3DRS_DESTBLEND, D3DBLEND_ONE);
}
else
{
Renderer::SetRenderState(D3DRS_SRCBLEND, src);
Renderer::SetRenderState(D3DRS_DESTBLEND, dst);
}
Renderer::SetRenderState(D3DRS_BLENDOP, bpmem.blendmode.subtract ? D3DBLENDOP_SUBTRACT : D3DBLENDOP_ADD);
}
}
void SetDitherMode(const Bypass &bp)
{
Renderer::SetRenderState(D3DRS_DITHERENABLE,bpmem.blendmode.dither);
}
void SetLogicOpMode(const Bypass &bp)
{
// Logic op blending. D3D can't do this but can fake some modes.
}
void SetColorMask(const Bypass &bp)
{
DWORD write = 0;
if (bpmem.blendmode.alphaupdate)
write = D3DCOLORWRITEENABLE_ALPHA;
if (bpmem.blendmode.colorupdate)
write |= D3DCOLORWRITEENABLE_RED | D3DCOLORWRITEENABLE_GREEN | D3DCOLORWRITEENABLE_BLUE;
Renderer::SetRenderState(D3DRS_COLORWRITEENABLE, write);
}
float GetRendererTargetScaleX()
{
return Renderer::GetXScale();
}
float GetRendererTargetScaleY()
{
return Renderer::GetYScale();
}
void CopyEFB(const Bypass &bp, const TRectangle &rc, const u32 &address, const bool &fromZBuffer, const bool &isIntensityFmt, const u32 &copyfmt, const bool &scaleByHalf)
{
RECT rec = { rc.left, rc.top, rc.right, rc.bottom };
TextureCache::CopyEFBToRenderTarget(bpmem.copyTexDest<<5, &rec);
}
void RenderToXFB(const Bypass &bp, const TRectangle &multirc, const float &yScale, const float &xfbLines, u32 xfbAddr, const u32 &dstWidth, const u32 &dstHeight)
{
Renderer::SwapBuffers();
PRIM_LOG("Renderer::SwapBuffers()");
g_VideoInitialize.pCopiedToXFB();
}
void ClearScreen(const Bypass &bp, const TRectangle &multirc)
{
// it seems that the GC is able to alpha blend on color-fill
// we cant do that so if alpha is != 255 we skip it
VertexShaderManager::SetViewportChanged();
// Since clear operations use the source rectangle, we have to do
// regular renders
DWORD clearflags = 0;
D3DCOLOR col = 0;
float clearZ = 0;
if (bpmem.blendmode.colorupdate || bpmem.blendmode.alphaupdate)
{
if (bpmem.blendmode.colorupdate || bpmem.blendmode.alphaupdate)
col = (bpmem.clearcolorAR << 16) | bpmem.clearcolorGB;
// clearflags |= D3DCLEAR_TARGET; set to break animal crossing :p
}
// clear z-buffer
if (bpmem.zmode.updateenable)
{
clearZ = (float)(bpmem.clearZValue & 0xFFFFFF) / float(0xFFFFFF);
if (clearZ > 1.0f) clearZ = 1.0f;
if (clearZ < 0.0f) clearZ = 0.0f;
clearflags |= D3DCLEAR_ZBUFFER | D3DCLEAR_STENCIL;
}
D3D::dev->Clear(0, NULL, clearflags, col, clearZ, 0);
}
void RestoreRenderState(const Bypass &bp)
{
//Renderer::SetRenderMode(Renderer::RM_Normal);
}
bool GetConfig(const int &type)
{
switch (type)
{
case CONFIG_ISWII:
return g_VideoInitialize.bWii;
case CONFIG_DISABLEFOG:
return false;
case CONFIG_SHOWEFBREGIONS:
return false;
default:
PanicAlert("GetConfig Error: Unknown Config Type!");
return false;
}
}
u8 *GetPointer(const u32 &address)
{
return g_VideoInitialize.pGetMemoryPointer(address);
}
void SetSamplerState(const Bypass &bp)
{
FourTexUnits &tex = bpmem.tex[(bp.address & 0xE0) == 0xA0];
int stage = (bp.address & 3);//(addr>>4)&2;
TexMode0 &tm0 = tex.texMode0[stage];
D3DTEXTUREFILTERTYPE min, mag, mip;
if (g_Config.bForceFiltering)
{
min = mag = mip = D3DTEXF_LINEAR;
}
else
{
min = (tm0.min_filter & 4) ? D3DTEXF_LINEAR : D3DTEXF_POINT;
mag = tm0.mag_filter ? D3DTEXF_LINEAR : D3DTEXF_POINT;
mip = d3dMipFilters[tm0.min_filter & 3];
}
if ((bp.address & 0xE0) == 0xA0)
stage += 4;
if (g_Config.bForceMaxAniso)
{
mag = D3DTEXF_ANISOTROPIC;
mip = D3DTEXF_ANISOTROPIC;
min = D3DTEXF_ANISOTROPIC;
}
dev->SetSamplerState(stage, D3DSAMP_MINFILTER, min);
dev->SetSamplerState(stage, D3DSAMP_MAGFILTER, mag);
dev->SetSamplerState(stage, D3DSAMP_MIPFILTER, mip);
dev->SetSamplerState(stage, D3DSAMP_MAXANISOTROPY, 16);
dev->SetSamplerState(stage, D3DSAMP_ADDRESSU, d3dClamps[tm0.wrap_s]);
dev->SetSamplerState(stage, D3DSAMP_ADDRESSV, d3dClamps[tm0.wrap_t]);
//wip
//dev->SetSamplerState(stage,D3DSAMP_MIPMAPLODBIAS,tm0.lod_bias/4.0f);
//char temp[256];
//sprintf(temp,"lod %f",tm0.lod_bias/4.0f);
//g_VideoInitialize.pLog(temp);
}
void SetInterlacingMode(const Bypass &bp)
{
// TODO
}
// Copyright (C) 2003-2009 Dolphin Project.
// 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, version 2.0.
// 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 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include "BPFunctions.h"
#include "D3DBase.h"
#include "Config.h"
#include "Common.h"
#include "TextureCache.h"
#include "VertexManager.h"
#include "VertexShaderManager.h"
#include "Utils.h"
bool textureChanged[8];
const bool renderFog = false;
using namespace D3D;
// State translation lookup tables
static const D3DBLEND d3dSrcFactors[8] =
{
D3DBLEND_ZERO,
D3DBLEND_ONE,
D3DBLEND_DESTCOLOR,
D3DBLEND_INVDESTCOLOR,
D3DBLEND_SRCALPHA,
D3DBLEND_INVSRCALPHA,
D3DBLEND_DESTALPHA,
D3DBLEND_INVDESTALPHA
};
static const D3DBLEND d3dDestFactors[8] =
{
D3DBLEND_ZERO,
D3DBLEND_ONE,
D3DBLEND_SRCCOLOR,
D3DBLEND_INVSRCCOLOR,
D3DBLEND_SRCALPHA,
D3DBLEND_INVSRCALPHA,
D3DBLEND_DESTALPHA,
D3DBLEND_INVDESTALPHA
};
static const D3DCULL d3dCullModes[4] =
{
D3DCULL_NONE,
D3DCULL_CCW,
D3DCULL_CW,
D3DCULL_CCW
};
static const D3DCMPFUNC d3dCmpFuncs[8] =
{
D3DCMP_NEVER,
D3DCMP_LESS,
D3DCMP_EQUAL,
D3DCMP_LESSEQUAL,
D3DCMP_GREATER,
D3DCMP_NOTEQUAL,
D3DCMP_GREATEREQUAL,
D3DCMP_ALWAYS
};
static const D3DTEXTUREFILTERTYPE d3dMipFilters[4] =
{
D3DTEXF_NONE,
D3DTEXF_POINT,
D3DTEXF_ANISOTROPIC,
D3DTEXF_LINEAR, //reserved
};
static const D3DTEXTUREADDRESS d3dClamps[4] =
{
D3DTADDRESS_CLAMP,
D3DTADDRESS_WRAP,
D3DTADDRESS_MIRROR,
D3DTADDRESS_WRAP //reserved
};
namespace BPFunctions
{
void FlushPipeline()
{
VertexManager::Flush();
}
void SetGenerationMode(const Bypass &bp)
{
// dev->SetRenderState(D3DRS_CULLMODE, d3dCullModes[bpmem.genMode.cullmode]);
Renderer::SetRenderState(D3DRS_CULLMODE, d3dCullModes[bpmem.genMode.cullmode]);
if (bpmem.genMode.cullmode == 3)
{
// dev->SetRenderState(D3DRS_COLORWRITEENABLE, 0);
Renderer::SetRenderState(D3DRS_COLORWRITEENABLE, 0);
}
else
{
DWORD write = 0;
if (bpmem.blendmode.alphaupdate)
write = D3DCOLORWRITEENABLE_ALPHA;
if (bpmem.blendmode.colorupdate)
write |= D3DCOLORWRITEENABLE_RED | D3DCOLORWRITEENABLE_GREEN | D3DCOLORWRITEENABLE_BLUE;
// dev->SetRenderState(D3DRS_COLORWRITEENABLE, write);
Renderer::SetRenderState(D3DRS_COLORWRITEENABLE, write);
}
}
void SetScissor(const Bypass &bp)
{
Renderer::SetScissorRect();
}
void SetLineWidth(const Bypass &bp)
{
// We can't change line width in D3D unless we use ID3DXLine
float psize = float(bpmem.lineptwidth.pointsize) * 6.0f;
Renderer::SetRenderState(D3DRS_POINTSIZE, *((DWORD*)&psize));
}
void SetDepthMode(const Bypass &bp)
{
if (bpmem.zmode.testenable)
{
// dev->SetRenderState(D3DRS_ZENABLE, TRUE);
// dev->SetRenderState(D3DRS_ZWRITEENABLE, bpmem.zmode.updateenable);
// dev->SetRenderState(D3DRS_ZFUNC,d3dCmpFuncs[bpmem.zmode.func]);
Renderer::SetRenderState(D3DRS_ZENABLE, TRUE);
Renderer::SetRenderState(D3DRS_ZWRITEENABLE, bpmem.zmode.updateenable);
Renderer::SetRenderState(D3DRS_ZFUNC, d3dCmpFuncs[bpmem.zmode.func]);
}
else
{
// if the test is disabled write is disabled too
// dev->SetRenderState(D3DRS_ZENABLE, FALSE);
// dev->SetRenderState(D3DRS_ZWRITEENABLE, FALSE);
Renderer::SetRenderState(D3DRS_ZENABLE, FALSE);
Renderer::SetRenderState(D3DRS_ZWRITEENABLE, FALSE);
}
//if (!bpmem.zmode.updateenable)
// Renderer::SetRenderMode(Renderer::RM_Normal);
}
void SetBlendMode(const Bypass &bp)
{
if (bp.changes & 1)
Renderer::SetRenderState(D3DRS_ALPHABLENDENABLE, bpmem.blendmode.blendenable);
D3DBLEND src = d3dSrcFactors[bpmem.blendmode.srcfactor];
D3DBLEND dst = d3dDestFactors[bpmem.blendmode.dstfactor];
if (bp.changes & 0x700)
Renderer::SetRenderState(D3DRS_SRCBLEND, src);
if (bp.changes & 0xE0) {
if (!bpmem.blendmode.subtract)
{
Renderer::SetRenderState(D3DRS_DESTBLEND, dst);
}
else
{
Renderer::SetRenderState(D3DRS_DESTBLEND, D3DBLEND_ONE);
}
}
if (bp.changes & 0x800)
{
if (bpmem.blendmode.subtract)
{
Renderer::SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ONE);
Renderer::SetRenderState(D3DRS_DESTBLEND, D3DBLEND_ONE);
}
else
{
Renderer::SetRenderState(D3DRS_SRCBLEND, src);
Renderer::SetRenderState(D3DRS_DESTBLEND, dst);
}
Renderer::SetRenderState(D3DRS_BLENDOP, bpmem.blendmode.subtract ? D3DBLENDOP_SUBTRACT : D3DBLENDOP_ADD);
}
}
void SetDitherMode(const Bypass &bp)
{
Renderer::SetRenderState(D3DRS_DITHERENABLE,bpmem.blendmode.dither);
}
void SetLogicOpMode(const Bypass &bp)
{
// Logic op blending. D3D can't do this but can fake some modes.
}
void SetColorMask(const Bypass &bp)
{
DWORD write = 0;
if (bpmem.blendmode.alphaupdate)
write = D3DCOLORWRITEENABLE_ALPHA;
if (bpmem.blendmode.colorupdate)
write |= D3DCOLORWRITEENABLE_RED | D3DCOLORWRITEENABLE_GREEN | D3DCOLORWRITEENABLE_BLUE;
Renderer::SetRenderState(D3DRS_COLORWRITEENABLE, write);
}
float GetRendererTargetScaleX()
{
return Renderer::GetXScale();
}
float GetRendererTargetScaleY()
{
return Renderer::GetYScale();
}
void CopyEFB(const Bypass &bp, const TRectangle &rc, const u32 &address, const bool &fromZBuffer, const bool &isIntensityFmt, const u32 &copyfmt, const bool &scaleByHalf)
{
RECT rec = { rc.left, rc.top, rc.right, rc.bottom };
TextureCache::CopyEFBToRenderTarget(bpmem.copyTexDest<<5, &rec);
}
void RenderToXFB(const Bypass &bp, const TRectangle &multirc, const float &yScale, const float &xfbLines, u32 xfbAddr, const u32 &dstWidth, const u32 &dstHeight)
{
Renderer::SwapBuffers();
PRIM_LOG("Renderer::SwapBuffers()");
g_VideoInitialize.pCopiedToXFB();
}
void ClearScreen(const Bypass &bp, const TRectangle &multirc)
{
// it seems that the GC is able to alpha blend on color-fill
// we cant do that so if alpha is != 255 we skip it
VertexShaderManager::SetViewportChanged();
// Since clear operations use the source rectangle, we have to do
// regular renders
DWORD clearflags = 0;
D3DCOLOR col = 0;
float clearZ = 0;
if (bpmem.blendmode.colorupdate || bpmem.blendmode.alphaupdate)
{
if (bpmem.blendmode.colorupdate || bpmem.blendmode.alphaupdate)
col = (bpmem.clearcolorAR << 16) | bpmem.clearcolorGB;
// clearflags |= D3DCLEAR_TARGET; set to break animal crossing :p
}
// clear z-buffer
if (bpmem.zmode.updateenable)
{
clearZ = (float)(bpmem.clearZValue & 0xFFFFFF) / float(0xFFFFFF);
if (clearZ > 1.0f) clearZ = 1.0f;
if (clearZ < 0.0f) clearZ = 0.0f;
clearflags |= D3DCLEAR_ZBUFFER | D3DCLEAR_STENCIL;
}
D3D::dev->Clear(0, NULL, clearflags, col, clearZ, 0);
}
void RestoreRenderState(const Bypass &bp)
{
//Renderer::SetRenderMode(Renderer::RM_Normal);
}
bool GetConfig(const int &type)
{
switch (type)
{
case CONFIG_ISWII:
return g_VideoInitialize.bWii;
case CONFIG_DISABLEFOG:
return false;
case CONFIG_SHOWEFBREGIONS:
return false;
default:
PanicAlert("GetConfig Error: Unknown Config Type!");
return false;
}
}
u8 *GetPointer(const u32 &address)
{
return g_VideoInitialize.pGetMemoryPointer(address);
}
void SetSamplerState(const Bypass &bp)
{
FourTexUnits &tex = bpmem.tex[(bp.address & 0xE0) == 0xA0];
int stage = (bp.address & 3);//(addr>>4)&2;
TexMode0 &tm0 = tex.texMode0[stage];
D3DTEXTUREFILTERTYPE min, mag, mip;
if (g_Config.bForceFiltering)
{
min = mag = mip = D3DTEXF_LINEAR;
}
else
{
min = (tm0.min_filter & 4) ? D3DTEXF_LINEAR : D3DTEXF_POINT;
mag = tm0.mag_filter ? D3DTEXF_LINEAR : D3DTEXF_POINT;
mip = d3dMipFilters[tm0.min_filter & 3];
}
if ((bp.address & 0xE0) == 0xA0)
stage += 4;
if (g_Config.bForceMaxAniso)
{
mag = D3DTEXF_ANISOTROPIC;
mip = D3DTEXF_ANISOTROPIC;
min = D3DTEXF_ANISOTROPIC;
}
dev->SetSamplerState(stage, D3DSAMP_MINFILTER, min);
dev->SetSamplerState(stage, D3DSAMP_MAGFILTER, mag);
dev->SetSamplerState(stage, D3DSAMP_MIPFILTER, mip);
dev->SetSamplerState(stage, D3DSAMP_MAXANISOTROPY, 16);
dev->SetSamplerState(stage, D3DSAMP_ADDRESSU, d3dClamps[tm0.wrap_s]);
dev->SetSamplerState(stage, D3DSAMP_ADDRESSV, d3dClamps[tm0.wrap_t]);
//wip
//dev->SetSamplerState(stage,D3DSAMP_MIPMAPLODBIAS,tm0.lod_bias/4.0f);
//char temp[256];
//sprintf(temp,"lod %f",tm0.lod_bias/4.0f);
//g_VideoInitialize.pLog(temp);
}
void SetInterlacingMode(const Bypass &bp)
{
// TODO
}
};

View File

@ -1,212 +1,212 @@
// Copyright (C) 2003-2009 Dolphin Project.
// 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, version 2.0.
// 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 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include "BPFunctions.h"
#include "Globals.h"
#include "Profiler.h"
#include "Config.h"
#include "VertexManager.h"
#include "Render.h"
#include "TextureMngr.h"
#include "TextureConverter.h"
#include "VertexShaderManager.h"
#include "XFB.h"
#include "main.h"
namespace BPFunctions
{
// ----------------------------------------------
// State translation lookup tables
// Reference: Yet Another Gamecube Documentation
// ----------------------------------------------
static const GLenum glCmpFuncs[8] = {
GL_NEVER, GL_LESS, GL_EQUAL, GL_LEQUAL, GL_GREATER, GL_NOTEQUAL, GL_GEQUAL, GL_ALWAYS
};
static const GLenum glLogicOpCodes[16] = {
GL_CLEAR, GL_AND, GL_AND_REVERSE, GL_COPY, GL_AND_INVERTED, GL_NOOP, GL_XOR,
GL_OR, GL_NOR, GL_EQUIV, GL_INVERT, GL_OR_REVERSE, GL_COPY_INVERTED, GL_OR_INVERTED, GL_NAND, GL_SET
};
void FlushPipeline()
{
VertexManager::Flush();
}
void SetGenerationMode(const Bypass &bp)
{
// none, ccw, cw, ccw
if (bpmem.genMode.cullmode > 0)
{
glEnable(GL_CULL_FACE);
glFrontFace(bpmem.genMode.cullmode == 2 ? GL_CCW : GL_CW);
}
else
glDisable(GL_CULL_FACE);
}
void SetScissor(const Bypass &bp)
{
if (!Renderer::SetScissorRect())
if (bp.address == BPMEM_SCISSORBR)
ERROR_LOG(VIDEO, "bad scissor!");
}
void SetLineWidth(const Bypass &bp)
{
float fratio = xfregs.rawViewport[0] != 0 ? ((float)Renderer::GetTargetWidth() / EFB_WIDTH) : 1.0f;
if (bpmem.lineptwidth.linesize > 0)
glLineWidth((float)bpmem.lineptwidth.linesize * fratio / 6.0f); // scale by ratio of widths
if (bpmem.lineptwidth.pointsize > 0)
glPointSize((float)bpmem.lineptwidth.pointsize * fratio / 6.0f);
}
void SetDepthMode(const Bypass &bp)
{
if (bpmem.zmode.testenable)
{
glEnable(GL_DEPTH_TEST);
glDepthMask(bpmem.zmode.updateenable ? GL_TRUE : GL_FALSE);
glDepthFunc(glCmpFuncs[bpmem.zmode.func]);
}
else
{
// if the test is disabled write is disabled too
glDisable(GL_DEPTH_TEST);
glDepthMask(GL_FALSE);
}
}
void SetBlendMode(const Bypass &bp)
{
Renderer::SetBlendMode(false);
}
void SetDitherMode(const Bypass &bp)
{
if (bpmem.blendmode.dither)
glEnable(GL_DITHER);
else
glDisable(GL_DITHER);
}
void SetLogicOpMode(const Bypass &bp)
{
if (bpmem.blendmode.logicopenable)
{
glEnable(GL_COLOR_LOGIC_OP);
glLogicOp(glLogicOpCodes[bpmem.blendmode.logicmode]);
}
else
glDisable(GL_COLOR_LOGIC_OP);
}
void SetColorMask(const Bypass &bp)
{
Renderer::SetColorMask();
}
float GetRendererTargetScaleX()
{
return Renderer::GetTargetScaleX();
}
float GetRendererTargetScaleY()
{
return Renderer::GetTargetScaleY();
}
void CopyEFB(const Bypass &bp, const TRectangle &rc, const u32 &address, const bool &fromZBuffer, const bool &isIntensityFmt, const u32 &copyfmt, const bool &scaleByHalf)
{
// bpmem.zcontrol.pixel_format to PIXELFMT_Z24 is when the game wants to copy from ZBuffer (Zbuffer uses 24-bit Format)
if (!g_Config.bEFBCopyDisable)
if (g_Config.bCopyEFBToRAM) // To RAM
TextureConverter::EncodeToRam(address, fromZBuffer, isIntensityFmt, copyfmt, scaleByHalf, rc);
else // To OGL Texture
TextureMngr::CopyRenderTargetToTexture(address, fromZBuffer, isIntensityFmt, copyfmt, scaleByHalf, rc);
}
void RenderToXFB(const Bypass &bp, const TRectangle &multirc, const float &yScale, const float &xfbLines, u32 xfbAddr, const u32 &dstWidth, const u32 &dstHeight)
{
Renderer::RenderToXFB(xfbAddr, dstWidth, dstHeight, multirc);
}
void ClearScreen(const Bypass &bp, const TRectangle &multirc)
{
// Update the view port for clearing the picture
glViewport(0, 0, Renderer::GetTargetWidth(), Renderer::GetTargetHeight());
// Always set the scissor in case it was set by the game and has not been reset
glScissor(multirc.left, (Renderer::GetTargetHeight() - multirc.bottom),
(multirc.right - multirc.left), (multirc.bottom - multirc.top));
// ---------------------------
VertexShaderManager::SetViewportChanged();
// Since clear operations use the source rectangle, we have to do
// regular renders (glClear clears the entire buffer)
if (bpmem.blendmode.colorupdate || bpmem.blendmode.alphaupdate || bpmem.zmode.updateenable)
{
GLbitfield bits = 0;
if (bpmem.blendmode.colorupdate || bpmem.blendmode.alphaupdate)
{
u32 clearColor = (bpmem.clearcolorAR << 16) | bpmem.clearcolorGB;
// Alpha may or may not be present depending on the EFB pixel format.
GLclampf clearAlpha = (bpmem.zcontrol.pixel_format == PIXELFMT_RGBA6_Z24) ?
((clearColor>>24) & 0xff)*(1/255.0f) : 1.0f;
glClearColor(((clearColor>>16) & 0xff)*(1/255.0f),
((clearColor>>8 ) & 0xff)*(1/255.0f),
((clearColor>>0 ) & 0xff)*(1/255.0f),
clearAlpha);
bits |= GL_COLOR_BUFFER_BIT;
}
if (bpmem.zmode.updateenable)
{
glClearDepth((float)(bpmem.clearZValue & 0xFFFFFF) / float(0xFFFFFF));
bits |= GL_DEPTH_BUFFER_BIT;
}
glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
glClear(bits);
}
}
void RestoreRenderState(const Bypass &bp)
{
Renderer::RestoreGLState();
}
bool GetConfig(const int &type)
{
switch (type)
{
case CONFIG_ISWII:
return g_VideoInitialize.bWii;
case CONFIG_DISABLEFOG:
return g_Config.bDisableFog;
case CONFIG_SHOWEFBREGIONS:
return g_Config.bShowEFBCopyRegions;
default:
PanicAlert("GetConfig Error: Unknown Config Type!");
return false;
}
}
u8 *GetPointer(const u32 &address)
{
return g_VideoInitialize.pGetMemoryPointer(address);
}
void SetSamplerState(const Bypass &bp)
{
// TODO
}
void SetInterlacingMode(const Bypass &bp)
{
// TODO
}
};
// Copyright (C) 2003-2009 Dolphin Project.
// 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, version 2.0.
// 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 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include "BPFunctions.h"
#include "Globals.h"
#include "Profiler.h"
#include "Config.h"
#include "VertexManager.h"
#include "Render.h"
#include "TextureMngr.h"
#include "TextureConverter.h"
#include "VertexShaderManager.h"
#include "XFB.h"
#include "main.h"
namespace BPFunctions
{
// ----------------------------------------------
// State translation lookup tables
// Reference: Yet Another Gamecube Documentation
// ----------------------------------------------
static const GLenum glCmpFuncs[8] = {
GL_NEVER, GL_LESS, GL_EQUAL, GL_LEQUAL, GL_GREATER, GL_NOTEQUAL, GL_GEQUAL, GL_ALWAYS
};
static const GLenum glLogicOpCodes[16] = {
GL_CLEAR, GL_AND, GL_AND_REVERSE, GL_COPY, GL_AND_INVERTED, GL_NOOP, GL_XOR,
GL_OR, GL_NOR, GL_EQUIV, GL_INVERT, GL_OR_REVERSE, GL_COPY_INVERTED, GL_OR_INVERTED, GL_NAND, GL_SET
};
void FlushPipeline()
{
VertexManager::Flush();
}
void SetGenerationMode(const Bypass &bp)
{
// none, ccw, cw, ccw
if (bpmem.genMode.cullmode > 0)
{
glEnable(GL_CULL_FACE);
glFrontFace(bpmem.genMode.cullmode == 2 ? GL_CCW : GL_CW);
}
else
glDisable(GL_CULL_FACE);
}
void SetScissor(const Bypass &bp)
{
if (!Renderer::SetScissorRect())
if (bp.address == BPMEM_SCISSORBR)
ERROR_LOG(VIDEO, "bad scissor!");
}
void SetLineWidth(const Bypass &bp)
{
float fratio = xfregs.rawViewport[0] != 0 ? ((float)Renderer::GetTargetWidth() / EFB_WIDTH) : 1.0f;
if (bpmem.lineptwidth.linesize > 0)
glLineWidth((float)bpmem.lineptwidth.linesize * fratio / 6.0f); // scale by ratio of widths
if (bpmem.lineptwidth.pointsize > 0)
glPointSize((float)bpmem.lineptwidth.pointsize * fratio / 6.0f);
}
void SetDepthMode(const Bypass &bp)
{
if (bpmem.zmode.testenable)
{
glEnable(GL_DEPTH_TEST);
glDepthMask(bpmem.zmode.updateenable ? GL_TRUE : GL_FALSE);
glDepthFunc(glCmpFuncs[bpmem.zmode.func]);
}
else
{
// if the test is disabled write is disabled too
glDisable(GL_DEPTH_TEST);
glDepthMask(GL_FALSE);
}
}
void SetBlendMode(const Bypass &bp)
{
Renderer::SetBlendMode(false);
}
void SetDitherMode(const Bypass &bp)
{
if (bpmem.blendmode.dither)
glEnable(GL_DITHER);
else
glDisable(GL_DITHER);
}
void SetLogicOpMode(const Bypass &bp)
{
if (bpmem.blendmode.logicopenable)
{
glEnable(GL_COLOR_LOGIC_OP);
glLogicOp(glLogicOpCodes[bpmem.blendmode.logicmode]);
}
else
glDisable(GL_COLOR_LOGIC_OP);
}
void SetColorMask(const Bypass &bp)
{
Renderer::SetColorMask();
}
float GetRendererTargetScaleX()
{
return Renderer::GetTargetScaleX();
}
float GetRendererTargetScaleY()
{
return Renderer::GetTargetScaleY();
}
void CopyEFB(const Bypass &bp, const TRectangle &rc, const u32 &address, const bool &fromZBuffer, const bool &isIntensityFmt, const u32 &copyfmt, const bool &scaleByHalf)
{
// bpmem.zcontrol.pixel_format to PIXELFMT_Z24 is when the game wants to copy from ZBuffer (Zbuffer uses 24-bit Format)
if (!g_Config.bEFBCopyDisable)
if (g_Config.bCopyEFBToRAM) // To RAM
TextureConverter::EncodeToRam(address, fromZBuffer, isIntensityFmt, copyfmt, scaleByHalf, rc);
else // To OGL Texture
TextureMngr::CopyRenderTargetToTexture(address, fromZBuffer, isIntensityFmt, copyfmt, scaleByHalf, rc);
}
void RenderToXFB(const Bypass &bp, const TRectangle &multirc, const float &yScale, const float &xfbLines, u32 xfbAddr, const u32 &dstWidth, const u32 &dstHeight)
{
Renderer::RenderToXFB(xfbAddr, dstWidth, dstHeight, multirc);
}
void ClearScreen(const Bypass &bp, const TRectangle &multirc)
{
// Update the view port for clearing the picture
glViewport(0, 0, Renderer::GetTargetWidth(), Renderer::GetTargetHeight());
// Always set the scissor in case it was set by the game and has not been reset
glScissor(multirc.left, (Renderer::GetTargetHeight() - multirc.bottom),
(multirc.right - multirc.left), (multirc.bottom - multirc.top));
// ---------------------------
VertexShaderManager::SetViewportChanged();
// Since clear operations use the source rectangle, we have to do
// regular renders (glClear clears the entire buffer)
if (bpmem.blendmode.colorupdate || bpmem.blendmode.alphaupdate || bpmem.zmode.updateenable)
{
GLbitfield bits = 0;
if (bpmem.blendmode.colorupdate || bpmem.blendmode.alphaupdate)
{
u32 clearColor = (bpmem.clearcolorAR << 16) | bpmem.clearcolorGB;
// Alpha may or may not be present depending on the EFB pixel format.
GLclampf clearAlpha = (bpmem.zcontrol.pixel_format == PIXELFMT_RGBA6_Z24) ?
((clearColor>>24) & 0xff)*(1/255.0f) : 1.0f;
glClearColor(((clearColor>>16) & 0xff)*(1/255.0f),
((clearColor>>8 ) & 0xff)*(1/255.0f),
((clearColor>>0 ) & 0xff)*(1/255.0f),
clearAlpha);
bits |= GL_COLOR_BUFFER_BIT;
}
if (bpmem.zmode.updateenable)
{
glClearDepth((float)(bpmem.clearZValue & 0xFFFFFF) / float(0xFFFFFF));
bits |= GL_DEPTH_BUFFER_BIT;
}
glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
glClear(bits);
}
}
void RestoreRenderState(const Bypass &bp)
{
Renderer::RestoreGLState();
}
bool GetConfig(const int &type)
{
switch (type)
{
case CONFIG_ISWII:
return g_VideoInitialize.bWii;
case CONFIG_DISABLEFOG:
return g_Config.bDisableFog;
case CONFIG_SHOWEFBREGIONS:
return g_Config.bShowEFBCopyRegions;
default:
PanicAlert("GetConfig Error: Unknown Config Type!");
return false;
}
}
u8 *GetPointer(const u32 &address)
{
return g_VideoInitialize.pGetMemoryPointer(address);
}
void SetSamplerState(const Bypass &bp)
{
// TODO
}
void SetInterlacingMode(const Bypass &bp)
{
// TODO
}
};

View File

@ -1,451 +1,451 @@
// Copyright (C) 2003-2009 Dolphin Project.
// 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, version 2.0.
// 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 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include "Globals.h"
#include "FramebufferManager.h"
#include "TextureConverter.h"
#include "XFB.h"
extern bool s_bHaveFramebufferBlit; // comes from Render.cpp
void FramebufferManager::Init(int targetWidth, int targetHeight, int msaaSamples, int msaaCoverageSamples)
{
m_targetWidth = targetWidth;
m_targetHeight = targetHeight;
m_msaaSamples = msaaSamples;
m_msaaCoverageSamples = msaaCoverageSamples;
// The EFB can be set to different pixel formats by the game through the
// BPMEM_ZCOMPARE register (which should probably have a different name).
// They are:
// - 24-bit RGB (8-bit components) with 24-bit Z
// - 24-bit RGBA (6-bit components) with 24-bit Z
// - Multisampled 16-bit RGB (5-6-5 format) with 16-bit Z
// We only use one EFB format here: 32-bit ARGB with 24-bit Z.
// Multisampling depends on user settings.
// The distinction becomes important for certain operations, i.e. the
// alpha channel should be ignored if the EFB does not have one.
// Create EFB target.
glGenFramebuffersEXT(1, &m_efbFramebuffer);
if (m_msaaSamples <= 1)
{
// EFB targets will be textures in non-MSAA mode.
GLuint glObj[2];
glGenTextures(2, glObj);
m_efbColor = glObj[0];
m_efbDepth = glObj[1];
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, m_efbColor);
glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA8, m_targetWidth, m_targetHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, m_efbDepth);
glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_DEPTH_COMPONENT24, m_targetWidth, m_targetHeight, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, NULL);
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);
// Bind target textures to the EFB framebuffer.
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_efbFramebuffer);
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_RECTANGLE_ARB, m_efbColor, 0);
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_RECTANGLE_ARB, m_efbDepth, 0);
GL_REPORT_FBO_ERROR();
}
else
{
// EFB targets will be renderbuffers in MSAA mode (required by OpenGL).
// Resolve targets will be created to transfer EFB to RAM textures.
// XFB framebuffer will be created to transfer EFB to XFB texture.
// Create EFB target renderbuffers.
GLuint glObj[2];
glGenRenderbuffersEXT(2, glObj);
m_efbColor = glObj[0];
m_efbDepth = glObj[1];
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, m_efbColor);
if (m_msaaCoverageSamples)
glRenderbufferStorageMultisampleCoverageNV(GL_RENDERBUFFER_EXT, m_msaaCoverageSamples, m_msaaSamples, GL_RGBA8, m_targetWidth, m_targetHeight);
else
glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, m_msaaSamples, GL_RGBA8, m_targetWidth, m_targetHeight);
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, m_efbDepth);
if (m_msaaCoverageSamples)
glRenderbufferStorageMultisampleCoverageNV(GL_RENDERBUFFER_EXT, m_msaaCoverageSamples, m_msaaSamples, GL_DEPTH_COMPONENT24, m_targetWidth, m_targetHeight);
else
glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, m_msaaSamples, GL_DEPTH_COMPONENT24, m_targetWidth, m_targetHeight);
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0);
// Bind target renderbuffers to EFB framebuffer.
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_efbFramebuffer);
glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_RENDERBUFFER_EXT, m_efbColor);
glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, m_efbDepth);
GL_REPORT_FBO_ERROR();
// Create resolved targets for transferring multisampled EFB to texture.
glGenFramebuffersEXT(1, &m_resolvedFramebuffer);
glGenTextures(2, glObj);
m_resolvedColorTexture = glObj[0];
m_resolvedDepthTexture = glObj[1];
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, m_resolvedColorTexture);
glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA8, m_targetWidth, m_targetHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, m_resolvedDepthTexture);
glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_DEPTH_COMPONENT24, m_targetWidth, m_targetHeight, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, NULL);
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);
// Bind resolved textures to resolved framebuffer.
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_resolvedFramebuffer);
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_RECTANGLE_ARB, m_resolvedColorTexture, 0);
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_RECTANGLE_ARB, m_resolvedDepthTexture, 0);
GL_REPORT_FBO_ERROR();
// Return to EFB framebuffer.
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_efbFramebuffer);
}
// Create XFB framebuffer; targets will be created elsewhere.
glGenFramebuffersEXT(1, &m_xfbFramebuffer);
// EFB framebuffer is currently bound.
}
void FramebufferManager::Shutdown()
{
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
GLuint glObj[3];
// Note: OpenGL deletion functions silently ignore parameters of "0".
glObj[0] = m_efbFramebuffer;
glObj[1] = m_resolvedFramebuffer;
glObj[2] = m_xfbFramebuffer;
glDeleteFramebuffersEXT(3, glObj);
m_efbFramebuffer = 0;
m_xfbFramebuffer = 0;
glObj[0] = m_resolvedColorTexture;
glObj[1] = m_resolvedDepthTexture;
glObj[2] = m_realXFBSource.texture;
glDeleteTextures(3, glObj);
m_resolvedColorTexture = 0;
m_resolvedDepthTexture = 0;
m_realXFBSource.texture = 0;
glObj[0] = m_efbColor;
glObj[1] = m_efbDepth;
if (m_msaaSamples <= 1)
glDeleteTextures(2, glObj);
else
glDeleteRenderbuffersEXT(2, glObj);
m_efbColor = 0;
m_efbDepth = 0;
for (VirtualXFBListType::iterator it = m_virtualXFBList.begin(); it != m_virtualXFBList.end(); ++it)
{
glDeleteTextures(1, &it->xfbSource.texture);
}
m_virtualXFBList.clear();
}
void FramebufferManager::CopyToXFB(u32 xfbAddr, u32 dstWidth, u32 dstHeight, const TRectangle& sourceRc)
{
if (g_Config.bUseXFB)
copyToRealXFB(xfbAddr, dstWidth, dstHeight, sourceRc);
else
copyToVirtualXFB(xfbAddr, dstWidth, dstHeight, sourceRc);
}
const XFBSource* FramebufferManager::GetXFBSource(u32 xfbAddr, u32 srcWidth, u32 srcHeight)
{
if (g_Config.bUseXFB)
return getRealXFBSource(xfbAddr, srcWidth, srcHeight);
else
return getVirtualXFBSource(xfbAddr, srcWidth, srcHeight);
}
GLuint FramebufferManager::GetEFBColorTexture(const TRectangle& sourceRc) const
{
if (m_msaaSamples <= 1)
{
return m_efbColor;
}
else
{
// Transfer the EFB to a resolved texture. EXT_framebuffer_blit is
// required.
// Flip source rectangle upside-down for OpenGL.
TRectangle glRect;
sourceRc.FlipYPosition(m_targetHeight, &glRect);
glRect.Clamp(0, 0, m_targetWidth, m_targetHeight);
// Resolve.
glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, m_efbFramebuffer);
glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, m_resolvedFramebuffer);
glBlitFramebufferEXT(
glRect.left, glRect.top, glRect.right, glRect.bottom,
glRect.left, glRect.top, glRect.right, glRect.bottom,
GL_COLOR_BUFFER_BIT, GL_NEAREST
);
// Return to EFB.
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_efbFramebuffer);
return m_resolvedColorTexture;
}
}
GLuint FramebufferManager::GetEFBDepthTexture(const TRectangle& sourceRc) const
{
if (m_msaaSamples <= 1)
{
return m_efbDepth;
}
else
{
// Transfer the EFB to a resolved texture. EXT_framebuffer_blit is
// required.
// Flip source rectangle upside-down for OpenGL.
TRectangle glRect;
sourceRc.FlipYPosition(m_targetHeight, &glRect);
glRect.Clamp(0, 0, m_targetWidth, m_targetHeight);
// Resolve.
glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, m_efbFramebuffer);
glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, m_resolvedFramebuffer);
glBlitFramebufferEXT(
glRect.left, glRect.top, glRect.right, glRect.bottom,
glRect.left, glRect.top, glRect.right, glRect.bottom,
GL_DEPTH_BUFFER_BIT, GL_NEAREST
);
// Return to EFB.
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_efbFramebuffer);
return m_resolvedDepthTexture;
}
}
FramebufferManager::VirtualXFBListType::iterator
FramebufferManager::findVirtualXFB(u32 xfbAddr, u32 width, u32 height)
{
u32 srcLower = xfbAddr;
u32 srcUpper = xfbAddr + 2 * width * height;
VirtualXFBListType::iterator it;
for (it = m_virtualXFBList.begin(); it != m_virtualXFBList.end(); ++it)
{
u32 dstLower = it->xfbAddr;
u32 dstUpper = it->xfbAddr + 2 * it->xfbWidth * it->xfbHeight;
if (addrRangesOverlap(srcLower, srcUpper, dstLower, dstUpper))
return it;
}
// That address is not in the Virtual XFB list.
return m_virtualXFBList.end();
}
void FramebufferManager::copyToRealXFB(u32 xfbAddr, u32 dstWidth, u32 dstHeight, const TRectangle& sourceRc)
{
u8* pXFB = Memory_GetPtr(xfbAddr);
if (!pXFB)
{
WARN_LOG(VIDEO, "Tried to copy to invalid XFB address");
return;
}
XFB_Write(pXFB, sourceRc, dstWidth, dstHeight);
}
void FramebufferManager::copyToVirtualXFB(u32 xfbAddr, u32 dstWidth, u32 dstHeight, const TRectangle& sourceRc)
{
GLuint xfbTexture;
VirtualXFBListType::iterator it = findVirtualXFB(xfbAddr, dstWidth, dstHeight);
if (it != m_virtualXFBList.end())
{
// Overwrite an existing Virtual XFB.
it->xfbAddr = xfbAddr;
it->xfbWidth = dstWidth;
it->xfbHeight = dstHeight;
it->xfbSource.texWidth = m_targetWidth;
it->xfbSource.texHeight = m_targetHeight;
it->xfbSource.sourceRc = sourceRc;
xfbTexture = it->xfbSource.texture;
// Move this Virtual XFB to the front of the list.
m_virtualXFBList.splice(m_virtualXFBList.begin(), m_virtualXFBList, it);
}
else
{
// Create a new Virtual XFB and place it at the front of the list.
glGenTextures(1, &xfbTexture);
#if 0 // XXX: Some video drivers don't handle glCopyTexImage2D correctly, so use EXT_framebuffer_blit whenever possible.
if (m_msaaSamples > 1)
#else
if (s_bHaveFramebufferBlit)
#endif
{
// In MSAA mode, allocate the texture image here. In non-MSAA mode,
// the image will be allocated by glCopyTexImage2D (later).
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, xfbTexture);
glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, 4, m_targetWidth, m_targetHeight, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);
}
VirtualXFB newVirt;
newVirt.xfbAddr = xfbAddr;
newVirt.xfbWidth = dstWidth;
newVirt.xfbHeight = dstHeight;
newVirt.xfbSource.texture = xfbTexture;
newVirt.xfbSource.texWidth = m_targetWidth;
newVirt.xfbSource.texHeight = m_targetHeight;
newVirt.xfbSource.sourceRc = sourceRc;
// Add the new Virtual XFB to the list
if (m_virtualXFBList.size() >= MAX_VIRTUAL_XFB)
{
// List overflowed; delete the oldest.
glDeleteTextures(1, &m_virtualXFBList.back().xfbSource.texture);
m_virtualXFBList.pop_back();
}
m_virtualXFBList.push_front(newVirt);
}
// Copy EFB to XFB texture
#if 0
if (m_msaaSamples <= 1)
#else
if (!s_bHaveFramebufferBlit)
#endif
{
// Just copy the EFB directly.
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_efbFramebuffer);
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, xfbTexture);
glCopyTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, 4, 0, 0, m_targetWidth, m_targetHeight, 0);
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);
}
else
{
// OpenGL cannot copy directly from a multisampled framebuffer, so use
// EXT_framebuffer_blit.
glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, m_efbFramebuffer);
glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, m_xfbFramebuffer);
// Bind texture.
glFramebufferTexture2DEXT(GL_DRAW_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_RECTANGLE_ARB, xfbTexture, 0);
GL_REPORT_FBO_ERROR();
glBlitFramebufferEXT(
0, 0, m_targetWidth, m_targetHeight,
0, 0, m_targetWidth, m_targetHeight,
GL_COLOR_BUFFER_BIT, GL_NEAREST
);
// Unbind texture.
glFramebufferTexture2DEXT(GL_DRAW_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_RECTANGLE_ARB, 0, 0);
// Return to EFB.
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_efbFramebuffer);
}
}
const XFBSource* FramebufferManager::getRealXFBSource(u32 xfbAddr, u32 srcWidth, u32 srcHeight)
{
m_realXFBSource.texWidth = XFB_WIDTH;
m_realXFBSource.texHeight = XFB_HEIGHT;
m_realXFBSource.sourceRc.left = 0;
m_realXFBSource.sourceRc.top = 0;
m_realXFBSource.sourceRc.right = srcWidth;
m_realXFBSource.sourceRc.bottom = srcHeight;
if (!m_realXFBSource.texture)
{
glGenTextures(1, &m_realXFBSource.texture);
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, m_realXFBSource.texture);
glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, 4, XFB_WIDTH, XFB_HEIGHT, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);
}
// Decode YUYV data from GameCube RAM
TextureConverter::DecodeToTexture(xfbAddr, srcWidth, srcHeight, m_realXFBSource.texture);
return &m_realXFBSource;
}
const XFBSource* FramebufferManager::getVirtualXFBSource(u32 xfbAddr, u32 srcWidth, u32 srcHeight)
{
if (m_virtualXFBList.size() == 0)
{
// No Virtual XFBs available.
return NULL;
}
VirtualXFBListType::iterator it = findVirtualXFB(xfbAddr, srcWidth, srcHeight);
if (it == m_virtualXFBList.end())
{
// Virtual XFB is not in the list, so return the most recently rendered
// one.
it = m_virtualXFBList.begin();
}
return &it->xfbSource;
}
// Copyright (C) 2003-2009 Dolphin Project.
// 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, version 2.0.
// 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 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include "Globals.h"
#include "FramebufferManager.h"
#include "TextureConverter.h"
#include "XFB.h"
extern bool s_bHaveFramebufferBlit; // comes from Render.cpp
void FramebufferManager::Init(int targetWidth, int targetHeight, int msaaSamples, int msaaCoverageSamples)
{
m_targetWidth = targetWidth;
m_targetHeight = targetHeight;
m_msaaSamples = msaaSamples;
m_msaaCoverageSamples = msaaCoverageSamples;
// The EFB can be set to different pixel formats by the game through the
// BPMEM_ZCOMPARE register (which should probably have a different name).
// They are:
// - 24-bit RGB (8-bit components) with 24-bit Z
// - 24-bit RGBA (6-bit components) with 24-bit Z
// - Multisampled 16-bit RGB (5-6-5 format) with 16-bit Z
// We only use one EFB format here: 32-bit ARGB with 24-bit Z.
// Multisampling depends on user settings.
// The distinction becomes important for certain operations, i.e. the
// alpha channel should be ignored if the EFB does not have one.
// Create EFB target.
glGenFramebuffersEXT(1, &m_efbFramebuffer);
if (m_msaaSamples <= 1)
{
// EFB targets will be textures in non-MSAA mode.
GLuint glObj[2];
glGenTextures(2, glObj);
m_efbColor = glObj[0];
m_efbDepth = glObj[1];
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, m_efbColor);
glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA8, m_targetWidth, m_targetHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, m_efbDepth);
glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_DEPTH_COMPONENT24, m_targetWidth, m_targetHeight, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, NULL);
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);
// Bind target textures to the EFB framebuffer.
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_efbFramebuffer);
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_RECTANGLE_ARB, m_efbColor, 0);
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_RECTANGLE_ARB, m_efbDepth, 0);
GL_REPORT_FBO_ERROR();
}
else
{
// EFB targets will be renderbuffers in MSAA mode (required by OpenGL).
// Resolve targets will be created to transfer EFB to RAM textures.
// XFB framebuffer will be created to transfer EFB to XFB texture.
// Create EFB target renderbuffers.
GLuint glObj[2];
glGenRenderbuffersEXT(2, glObj);
m_efbColor = glObj[0];
m_efbDepth = glObj[1];
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, m_efbColor);
if (m_msaaCoverageSamples)
glRenderbufferStorageMultisampleCoverageNV(GL_RENDERBUFFER_EXT, m_msaaCoverageSamples, m_msaaSamples, GL_RGBA8, m_targetWidth, m_targetHeight);
else
glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, m_msaaSamples, GL_RGBA8, m_targetWidth, m_targetHeight);
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, m_efbDepth);
if (m_msaaCoverageSamples)
glRenderbufferStorageMultisampleCoverageNV(GL_RENDERBUFFER_EXT, m_msaaCoverageSamples, m_msaaSamples, GL_DEPTH_COMPONENT24, m_targetWidth, m_targetHeight);
else
glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, m_msaaSamples, GL_DEPTH_COMPONENT24, m_targetWidth, m_targetHeight);
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0);
// Bind target renderbuffers to EFB framebuffer.
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_efbFramebuffer);
glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_RENDERBUFFER_EXT, m_efbColor);
glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, m_efbDepth);
GL_REPORT_FBO_ERROR();
// Create resolved targets for transferring multisampled EFB to texture.
glGenFramebuffersEXT(1, &m_resolvedFramebuffer);
glGenTextures(2, glObj);
m_resolvedColorTexture = glObj[0];
m_resolvedDepthTexture = glObj[1];
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, m_resolvedColorTexture);
glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA8, m_targetWidth, m_targetHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, m_resolvedDepthTexture);
glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_DEPTH_COMPONENT24, m_targetWidth, m_targetHeight, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, NULL);
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);
// Bind resolved textures to resolved framebuffer.
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_resolvedFramebuffer);
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_RECTANGLE_ARB, m_resolvedColorTexture, 0);
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_RECTANGLE_ARB, m_resolvedDepthTexture, 0);
GL_REPORT_FBO_ERROR();
// Return to EFB framebuffer.
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_efbFramebuffer);
}
// Create XFB framebuffer; targets will be created elsewhere.
glGenFramebuffersEXT(1, &m_xfbFramebuffer);
// EFB framebuffer is currently bound.
}
void FramebufferManager::Shutdown()
{
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
GLuint glObj[3];
// Note: OpenGL deletion functions silently ignore parameters of "0".
glObj[0] = m_efbFramebuffer;
glObj[1] = m_resolvedFramebuffer;
glObj[2] = m_xfbFramebuffer;
glDeleteFramebuffersEXT(3, glObj);
m_efbFramebuffer = 0;
m_xfbFramebuffer = 0;
glObj[0] = m_resolvedColorTexture;
glObj[1] = m_resolvedDepthTexture;
glObj[2] = m_realXFBSource.texture;
glDeleteTextures(3, glObj);
m_resolvedColorTexture = 0;
m_resolvedDepthTexture = 0;
m_realXFBSource.texture = 0;
glObj[0] = m_efbColor;
glObj[1] = m_efbDepth;
if (m_msaaSamples <= 1)
glDeleteTextures(2, glObj);
else
glDeleteRenderbuffersEXT(2, glObj);
m_efbColor = 0;
m_efbDepth = 0;
for (VirtualXFBListType::iterator it = m_virtualXFBList.begin(); it != m_virtualXFBList.end(); ++it)
{
glDeleteTextures(1, &it->xfbSource.texture);
}
m_virtualXFBList.clear();
}
void FramebufferManager::CopyToXFB(u32 xfbAddr, u32 dstWidth, u32 dstHeight, const TRectangle& sourceRc)
{
if (g_Config.bUseXFB)
copyToRealXFB(xfbAddr, dstWidth, dstHeight, sourceRc);
else
copyToVirtualXFB(xfbAddr, dstWidth, dstHeight, sourceRc);
}
const XFBSource* FramebufferManager::GetXFBSource(u32 xfbAddr, u32 srcWidth, u32 srcHeight)
{
if (g_Config.bUseXFB)
return getRealXFBSource(xfbAddr, srcWidth, srcHeight);
else
return getVirtualXFBSource(xfbAddr, srcWidth, srcHeight);
}
GLuint FramebufferManager::GetEFBColorTexture(const TRectangle& sourceRc) const
{
if (m_msaaSamples <= 1)
{
return m_efbColor;
}
else
{
// Transfer the EFB to a resolved texture. EXT_framebuffer_blit is
// required.
// Flip source rectangle upside-down for OpenGL.
TRectangle glRect;
sourceRc.FlipYPosition(m_targetHeight, &glRect);
glRect.Clamp(0, 0, m_targetWidth, m_targetHeight);
// Resolve.
glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, m_efbFramebuffer);
glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, m_resolvedFramebuffer);
glBlitFramebufferEXT(
glRect.left, glRect.top, glRect.right, glRect.bottom,
glRect.left, glRect.top, glRect.right, glRect.bottom,
GL_COLOR_BUFFER_BIT, GL_NEAREST
);
// Return to EFB.
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_efbFramebuffer);
return m_resolvedColorTexture;
}
}
GLuint FramebufferManager::GetEFBDepthTexture(const TRectangle& sourceRc) const
{
if (m_msaaSamples <= 1)
{
return m_efbDepth;
}
else
{
// Transfer the EFB to a resolved texture. EXT_framebuffer_blit is
// required.
// Flip source rectangle upside-down for OpenGL.
TRectangle glRect;
sourceRc.FlipYPosition(m_targetHeight, &glRect);
glRect.Clamp(0, 0, m_targetWidth, m_targetHeight);
// Resolve.
glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, m_efbFramebuffer);
glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, m_resolvedFramebuffer);
glBlitFramebufferEXT(
glRect.left, glRect.top, glRect.right, glRect.bottom,
glRect.left, glRect.top, glRect.right, glRect.bottom,
GL_DEPTH_BUFFER_BIT, GL_NEAREST
);
// Return to EFB.
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_efbFramebuffer);
return m_resolvedDepthTexture;
}
}
FramebufferManager::VirtualXFBListType::iterator
FramebufferManager::findVirtualXFB(u32 xfbAddr, u32 width, u32 height)
{
u32 srcLower = xfbAddr;
u32 srcUpper = xfbAddr + 2 * width * height;
VirtualXFBListType::iterator it;
for (it = m_virtualXFBList.begin(); it != m_virtualXFBList.end(); ++it)
{
u32 dstLower = it->xfbAddr;
u32 dstUpper = it->xfbAddr + 2 * it->xfbWidth * it->xfbHeight;
if (addrRangesOverlap(srcLower, srcUpper, dstLower, dstUpper))
return it;
}
// That address is not in the Virtual XFB list.
return m_virtualXFBList.end();
}
void FramebufferManager::copyToRealXFB(u32 xfbAddr, u32 dstWidth, u32 dstHeight, const TRectangle& sourceRc)
{
u8* pXFB = Memory_GetPtr(xfbAddr);
if (!pXFB)
{
WARN_LOG(VIDEO, "Tried to copy to invalid XFB address");
return;
}
XFB_Write(pXFB, sourceRc, dstWidth, dstHeight);
}
void FramebufferManager::copyToVirtualXFB(u32 xfbAddr, u32 dstWidth, u32 dstHeight, const TRectangle& sourceRc)
{
GLuint xfbTexture;
VirtualXFBListType::iterator it = findVirtualXFB(xfbAddr, dstWidth, dstHeight);
if (it != m_virtualXFBList.end())
{
// Overwrite an existing Virtual XFB.
it->xfbAddr = xfbAddr;
it->xfbWidth = dstWidth;
it->xfbHeight = dstHeight;
it->xfbSource.texWidth = m_targetWidth;
it->xfbSource.texHeight = m_targetHeight;
it->xfbSource.sourceRc = sourceRc;
xfbTexture = it->xfbSource.texture;
// Move this Virtual XFB to the front of the list.
m_virtualXFBList.splice(m_virtualXFBList.begin(), m_virtualXFBList, it);
}
else
{
// Create a new Virtual XFB and place it at the front of the list.
glGenTextures(1, &xfbTexture);
#if 0 // XXX: Some video drivers don't handle glCopyTexImage2D correctly, so use EXT_framebuffer_blit whenever possible.
if (m_msaaSamples > 1)
#else
if (s_bHaveFramebufferBlit)
#endif
{
// In MSAA mode, allocate the texture image here. In non-MSAA mode,
// the image will be allocated by glCopyTexImage2D (later).
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, xfbTexture);
glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, 4, m_targetWidth, m_targetHeight, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);
}
VirtualXFB newVirt;
newVirt.xfbAddr = xfbAddr;
newVirt.xfbWidth = dstWidth;
newVirt.xfbHeight = dstHeight;
newVirt.xfbSource.texture = xfbTexture;
newVirt.xfbSource.texWidth = m_targetWidth;
newVirt.xfbSource.texHeight = m_targetHeight;
newVirt.xfbSource.sourceRc = sourceRc;
// Add the new Virtual XFB to the list
if (m_virtualXFBList.size() >= MAX_VIRTUAL_XFB)
{
// List overflowed; delete the oldest.
glDeleteTextures(1, &m_virtualXFBList.back().xfbSource.texture);
m_virtualXFBList.pop_back();
}
m_virtualXFBList.push_front(newVirt);
}
// Copy EFB to XFB texture
#if 0
if (m_msaaSamples <= 1)
#else
if (!s_bHaveFramebufferBlit)
#endif
{
// Just copy the EFB directly.
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_efbFramebuffer);
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, xfbTexture);
glCopyTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, 4, 0, 0, m_targetWidth, m_targetHeight, 0);
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);
}
else
{
// OpenGL cannot copy directly from a multisampled framebuffer, so use
// EXT_framebuffer_blit.
glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, m_efbFramebuffer);
glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, m_xfbFramebuffer);
// Bind texture.
glFramebufferTexture2DEXT(GL_DRAW_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_RECTANGLE_ARB, xfbTexture, 0);
GL_REPORT_FBO_ERROR();
glBlitFramebufferEXT(
0, 0, m_targetWidth, m_targetHeight,
0, 0, m_targetWidth, m_targetHeight,
GL_COLOR_BUFFER_BIT, GL_NEAREST
);
// Unbind texture.
glFramebufferTexture2DEXT(GL_DRAW_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_RECTANGLE_ARB, 0, 0);
// Return to EFB.
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_efbFramebuffer);
}
}
const XFBSource* FramebufferManager::getRealXFBSource(u32 xfbAddr, u32 srcWidth, u32 srcHeight)
{
m_realXFBSource.texWidth = XFB_WIDTH;
m_realXFBSource.texHeight = XFB_HEIGHT;
m_realXFBSource.sourceRc.left = 0;
m_realXFBSource.sourceRc.top = 0;
m_realXFBSource.sourceRc.right = srcWidth;
m_realXFBSource.sourceRc.bottom = srcHeight;
if (!m_realXFBSource.texture)
{
glGenTextures(1, &m_realXFBSource.texture);
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, m_realXFBSource.texture);
glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, 4, XFB_WIDTH, XFB_HEIGHT, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);
}
// Decode YUYV data from GameCube RAM
TextureConverter::DecodeToTexture(xfbAddr, srcWidth, srcHeight, m_realXFBSource.texture);
return &m_realXFBSource;
}
const XFBSource* FramebufferManager::getVirtualXFBSource(u32 xfbAddr, u32 srcWidth, u32 srcHeight)
{
if (m_virtualXFBList.size() == 0)
{
// No Virtual XFBs available.
return NULL;
}
VirtualXFBListType::iterator it = findVirtualXFB(xfbAddr, srcWidth, srcHeight);
if (it == m_virtualXFBList.end())
{
// Virtual XFB is not in the list, so return the most recently rendered
// one.
it = m_virtualXFBList.begin();
}
return &it->xfbSource;
}

View File

@ -1,152 +1,152 @@
// Copyright (C) 2003-2009 Dolphin Project.
// 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, version 2.0.
// 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 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#ifndef _FRAMEBUFFERMANAGER_H_
#define _FRAMEBUFFERMANAGER_H_
#include <list>
#include "GLUtil.h"
// On the GameCube, the game sends a request for the graphics processor to
// transfer its internal EFB (Embedded Framebuffer) to an area in GameCube RAM
// called the XFB (External Framebuffer). The size and location of the XFB is
// decided at the time of the copy, and the format is always YUYV. The video
// interface is given a pointer to the XFB, which will be decoded and
// displayed on the TV.
//
// There are two ways for Dolphin to emulate this:
//
// Real XFB mode:
//
// Dolphin will behave like the GameCube and encode the EFB to
// a portion of GameCube RAM. The emulated video interface will decode the data
// for output to the screen.
//
// Advantages: Behaves exactly like the GameCube.
// Disadvantages: Resolution will be limited.
//
// Virtual XFB mode:
//
// When a request is made to copy the EFB to an XFB, Dolphin
// will remember the RAM location and size of the XFB in a Virtual XFB list.
// The video interface will look up the XFB in the list and use the enhanced
// data stored there, if available.
//
// Advantages: Enables high resolution graphics, better than real hardware.
// Disadvantages: If the GameCube CPU writes directly to the XFB (which is
// possible but uncommon), the Virtual XFB will not capture this information.
// There may be multiple XFBs in GameCube RAM. This is the maximum number to
// virtualize.
const int MAX_VIRTUAL_XFB = 4;
inline bool addrRangesOverlap(u32 aLower, u32 aUpper, u32 bLower, u32 bUpper)
{
return (
(aLower >= bLower && aLower < bUpper) ||
(aUpper >= bLower && aUpper < bUpper) ||
(bLower >= aLower && bLower < aUpper) ||
(bUpper >= aLower && bUpper < aUpper)
);
}
struct XFBSource
{
XFBSource() :
texture(0)
{}
GLuint texture;
int texWidth;
int texHeight;
TRectangle sourceRc;
};
class FramebufferManager
{
public:
FramebufferManager() :
m_efbFramebuffer(0),
m_efbColor(0),
m_efbDepth(0),
m_resolvedFramebuffer(0),
m_resolvedColorTexture(0),
m_resolvedDepthTexture(0),
m_xfbFramebuffer(0)
{}
void Init(int targetWidth, int targetHeight, int msaaSamples, int msaaCoverageSamples);
void Shutdown();
// sourceRc is in GL target coordinates, not GameCube EFB coordinates!
// TODO: Clean that up.
void CopyToXFB(u32 xfbAddr, u32 dstWidth, u32 dstHeight, const TRectangle& sourceRc);
const XFBSource* GetXFBSource(u32 xfbAddr, u32 srcWidth, u32 srcHeight);
// To get the EFB in texture form, these functions may have to transfer
// the EFB to a resolved texture first.
GLuint GetEFBColorTexture(const TRectangle& sourceRc) const;
GLuint GetEFBDepthTexture(const TRectangle& sourceRc) const;
GLuint GetEFBFramebuffer() const { return m_efbFramebuffer; }
private:
struct VirtualXFB
{
// Address and size in GameCube RAM
u32 xfbAddr;
u32 xfbWidth;
u32 xfbHeight;
XFBSource xfbSource;
};
typedef std::list<VirtualXFB> VirtualXFBListType;
VirtualXFBListType::iterator findVirtualXFB(u32 xfbAddr, u32 width, u32 height);
void copyToRealXFB(u32 xfbAddr, u32 dstWidth, u32 dstHeight, const TRectangle& sourceRc);
void copyToVirtualXFB(u32 xfbAddr, u32 dstWidth, u32 dstHeight, const TRectangle& sourceRc);
const XFBSource* getRealXFBSource(u32 xfbAddr, u32 srcWidth, u32 srcHeight);
const XFBSource* getVirtualXFBSource(u32 xfbAddr, u32 srcWidth, u32 srcHeight);
int m_targetWidth;
int m_targetHeight;
int m_msaaSamples;
int m_msaaCoverageSamples;
GLuint m_efbFramebuffer;
GLuint m_efbColor; // Renderbuffer in MSAA mode; Texture otherwise
GLuint m_efbDepth; // Renderbuffer in MSAA mode; Texture otherwise
// Only used in MSAA mode.
GLuint m_resolvedFramebuffer;
GLuint m_resolvedColorTexture;
GLuint m_resolvedDepthTexture;
GLuint m_xfbFramebuffer; // Only used in MSAA mode
XFBSource m_realXFBSource; // Only used in Real XFB mode
VirtualXFBListType m_virtualXFBList; // Only used in Virtual XFB mode
};
#endif
// Copyright (C) 2003-2009 Dolphin Project.
// 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, version 2.0.
// 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 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#ifndef _FRAMEBUFFERMANAGER_H_
#define _FRAMEBUFFERMANAGER_H_
#include <list>
#include "GLUtil.h"
// On the GameCube, the game sends a request for the graphics processor to
// transfer its internal EFB (Embedded Framebuffer) to an area in GameCube RAM
// called the XFB (External Framebuffer). The size and location of the XFB is
// decided at the time of the copy, and the format is always YUYV. The video
// interface is given a pointer to the XFB, which will be decoded and
// displayed on the TV.
//
// There are two ways for Dolphin to emulate this:
//
// Real XFB mode:
//
// Dolphin will behave like the GameCube and encode the EFB to
// a portion of GameCube RAM. The emulated video interface will decode the data
// for output to the screen.
//
// Advantages: Behaves exactly like the GameCube.
// Disadvantages: Resolution will be limited.
//
// Virtual XFB mode:
//
// When a request is made to copy the EFB to an XFB, Dolphin
// will remember the RAM location and size of the XFB in a Virtual XFB list.
// The video interface will look up the XFB in the list and use the enhanced
// data stored there, if available.
//
// Advantages: Enables high resolution graphics, better than real hardware.
// Disadvantages: If the GameCube CPU writes directly to the XFB (which is
// possible but uncommon), the Virtual XFB will not capture this information.
// There may be multiple XFBs in GameCube RAM. This is the maximum number to
// virtualize.
const int MAX_VIRTUAL_XFB = 4;
inline bool addrRangesOverlap(u32 aLower, u32 aUpper, u32 bLower, u32 bUpper)
{
return (
(aLower >= bLower && aLower < bUpper) ||
(aUpper >= bLower && aUpper < bUpper) ||
(bLower >= aLower && bLower < aUpper) ||
(bUpper >= aLower && bUpper < aUpper)
);
}
struct XFBSource
{
XFBSource() :
texture(0)
{}
GLuint texture;
int texWidth;
int texHeight;
TRectangle sourceRc;
};
class FramebufferManager
{
public:
FramebufferManager() :
m_efbFramebuffer(0),
m_efbColor(0),
m_efbDepth(0),
m_resolvedFramebuffer(0),
m_resolvedColorTexture(0),
m_resolvedDepthTexture(0),
m_xfbFramebuffer(0)
{}
void Init(int targetWidth, int targetHeight, int msaaSamples, int msaaCoverageSamples);
void Shutdown();
// sourceRc is in GL target coordinates, not GameCube EFB coordinates!
// TODO: Clean that up.
void CopyToXFB(u32 xfbAddr, u32 dstWidth, u32 dstHeight, const TRectangle& sourceRc);
const XFBSource* GetXFBSource(u32 xfbAddr, u32 srcWidth, u32 srcHeight);
// To get the EFB in texture form, these functions may have to transfer
// the EFB to a resolved texture first.
GLuint GetEFBColorTexture(const TRectangle& sourceRc) const;
GLuint GetEFBDepthTexture(const TRectangle& sourceRc) const;
GLuint GetEFBFramebuffer() const { return m_efbFramebuffer; }
private:
struct VirtualXFB
{
// Address and size in GameCube RAM
u32 xfbAddr;
u32 xfbWidth;
u32 xfbHeight;
XFBSource xfbSource;
};
typedef std::list<VirtualXFB> VirtualXFBListType;
VirtualXFBListType::iterator findVirtualXFB(u32 xfbAddr, u32 width, u32 height);
void copyToRealXFB(u32 xfbAddr, u32 dstWidth, u32 dstHeight, const TRectangle& sourceRc);
void copyToVirtualXFB(u32 xfbAddr, u32 dstWidth, u32 dstHeight, const TRectangle& sourceRc);
const XFBSource* getRealXFBSource(u32 xfbAddr, u32 srcWidth, u32 srcHeight);
const XFBSource* getVirtualXFBSource(u32 xfbAddr, u32 srcWidth, u32 srcHeight);
int m_targetWidth;
int m_targetHeight;
int m_msaaSamples;
int m_msaaCoverageSamples;
GLuint m_efbFramebuffer;
GLuint m_efbColor; // Renderbuffer in MSAA mode; Texture otherwise
GLuint m_efbDepth; // Renderbuffer in MSAA mode; Texture otherwise
// Only used in MSAA mode.
GLuint m_resolvedFramebuffer;
GLuint m_resolvedColorTexture;
GLuint m_resolvedDepthTexture;
GLuint m_xfbFramebuffer; // Only used in MSAA mode
XFBSource m_realXFBSource; // Only used in Real XFB mode
VirtualXFBListType m_virtualXFBList; // Only used in Virtual XFB mode
};
#endif

View File

@ -1,89 +1,89 @@
// Copyright (C) 2003-2009 Dolphin Project.
// 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, version 2.0.
// 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 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include "VideoCommon.h"
#include "FileUtil.h"
#include "Config.h"
#include "GLUtil.h"
#include "PostProcessing.h"
#include "PixelShaderCache.h"
namespace PostProcessing
{
static std::string s_currentShader;
static FRAGMENTSHADER s_shader;
void Init()
{
s_currentShader = "";
}
void Shutdown()
{
s_shader.Destroy();
}
void ReloadShader()
{
s_currentShader = "";
}
bool ApplyShader()
{
if (s_currentShader != "User/Shaders/" + g_Config.sPostProcessingShader + ".txt")
{
// Set immediately to prevent endless recompiles on failure.
if (!g_Config.sPostProcessingShader.empty())
s_currentShader = "User/Shaders/" + g_Config.sPostProcessingShader + ".txt";
else
s_currentShader.clear();
s_shader.Destroy();
if (!s_currentShader.empty())
{
std::string code;
if (File::ReadFileToString(true, s_currentShader.c_str(), code))
{
if (!PixelShaderCache::CompilePixelShader(s_shader, code.c_str()))
{
ERROR_LOG(VIDEO, "Failed to compile post-processing shader %s", s_currentShader.c_str());
}
}
else
{
ERROR_LOG(VIDEO, "Failed to load post-processing shader %s - does not exist?", s_currentShader.c_str());
}
}
}
if (s_shader.glprogid != 0)
{
glEnable(GL_FRAGMENT_PROGRAM_ARB);
glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, s_shader.glprogid);
return true;
}
else
{
glDisable(GL_FRAGMENT_PROGRAM_ARB);
glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, 0);
return false;
}
}
} // namespace
// Copyright (C) 2003-2009 Dolphin Project.
// 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, version 2.0.
// 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 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include "VideoCommon.h"
#include "FileUtil.h"
#include "Config.h"
#include "GLUtil.h"
#include "PostProcessing.h"
#include "PixelShaderCache.h"
namespace PostProcessing
{
static std::string s_currentShader;
static FRAGMENTSHADER s_shader;
void Init()
{
s_currentShader = "";
}
void Shutdown()
{
s_shader.Destroy();
}
void ReloadShader()
{
s_currentShader = "";
}
bool ApplyShader()
{
if (s_currentShader != "User/Shaders/" + g_Config.sPostProcessingShader + ".txt")
{
// Set immediately to prevent endless recompiles on failure.
if (!g_Config.sPostProcessingShader.empty())
s_currentShader = "User/Shaders/" + g_Config.sPostProcessingShader + ".txt";
else
s_currentShader.clear();
s_shader.Destroy();
if (!s_currentShader.empty())
{
std::string code;
if (File::ReadFileToString(true, s_currentShader.c_str(), code))
{
if (!PixelShaderCache::CompilePixelShader(s_shader, code.c_str()))
{
ERROR_LOG(VIDEO, "Failed to compile post-processing shader %s", s_currentShader.c_str());
}
}
else
{
ERROR_LOG(VIDEO, "Failed to load post-processing shader %s - does not exist?", s_currentShader.c_str());
}
}
}
if (s_shader.glprogid != 0)
{
glEnable(GL_FRAGMENT_PROGRAM_ARB);
glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, s_shader.glprogid);
return true;
}
else
{
glDisable(GL_FRAGMENT_PROGRAM_ARB);
glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, 0);
return false;
}
}
} // namespace

View File

@ -1,36 +1,36 @@
// Copyright (C) 2003-2009 Dolphin Project.
// 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, version 2.0.
// 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 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#ifndef _POSTPROCESSING_H_
#define _POSTPROCESSING_H_
#include "VideoCommon.h"
#include "GLUtil.h"
namespace PostProcessing
{
void Init();
void Shutdown();
void ReloadShader();
// Returns false if no shader was applied.
bool ApplyShader();
} // namespace
#endif // _POSTPROCESSING_H_
// Copyright (C) 2003-2009 Dolphin Project.
// 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, version 2.0.
// 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 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#ifndef _POSTPROCESSING_H_
#define _POSTPROCESSING_H_
#include "VideoCommon.h"
#include "GLUtil.h"
namespace PostProcessing
{
void Init();
void Shutdown();
void ReloadShader();
// Returns false if no shader was applied.
bool ApplyShader();
} // namespace
#endif // _POSTPROCESSING_H_

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff