mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-07-30 01:29:42 -06:00
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:
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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()
|
||||
{
|
||||
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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 ©fmt, 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 ©fmt, 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
|
||||
}
|
||||
};
|
@ -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 ©fmt, 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 ©fmt, 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
|
||||
}
|
||||
};
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
Reference in New Issue
Block a user