Update to v097r02 release.

byuu says:

Note: balanced/performance profiles still broken, sorry.

Changelog:
- added nall/GNUmakefile unique() function; used on linking phase of
  higan
- added nall/unique_pointer
- target-tomoko and {System}::Video updated to use
  unique_pointer<ClassName> instead of ClassName* [1]
- locate() updated to search multiple paths [2]
- GB: pass gekkio's if_ie_registers and boot_hwio-G test ROMs
- FC, GB, GBA: merge video/ into the PPU cores
- ruby: fixed ~AudioXAudio2() typo

[1] I expected this to cause new crashes on exit due to changing the
order of destruction of objects (and deleting things that weren't
deleted before), but ... so far, so good. I guess we'll see what crops
up, especially on OS X (which is already crashing for unknown reasons on
exit.)

[2] right now, the search paths are: programpath(), {configpath(),
"higan/"}, {localpath(), "higan/"}; but we can add as many more as we
want, and we can also add platform-specific versions.
This commit is contained in:
Tim Allen 2016-01-25 22:27:18 +11:00
parent f1ebef2ea8
commit 344e63d928
55 changed files with 378 additions and 298 deletions

View File

@ -6,7 +6,7 @@ using namespace nall;
namespace Emulator {
static const string Name = "higan";
static const string Version = "097.01";
static const string Version = "097.02";
static const string Author = "byuu";
static const string License = "GPLv3";
static const string Website = "http://byuu.org/";

View File

@ -1,6 +1,6 @@
fc_objects := fc-interface fc-system fc-scheduler fc-input
fc_objects += fc-memory fc-cartridge fc-cpu fc-apu fc-ppu
fc_objects += fc-cheat fc-video
fc_objects += fc-cheat
objects += $(fc_objects)
obj/fc-interface.o: $(fc)/interface/interface.cpp $(call rwildcard,$(fc)/interface/)
@ -13,4 +13,3 @@ obj/fc-cpu.o: $(fc)/cpu/cpu.cpp $(call rwildcard,$(fc)/cpu/)
obj/fc-apu.o: $(fc)/apu/apu.cpp $(call rwildcard,$(fc)/apu/)
obj/fc-ppu.o: $(fc)/ppu/ppu.cpp $(call rwildcard,$(fc)/ppu/)
obj/fc-cheat.o: $(fc)/cheat/cheat.cpp $(call rwildcard,$(fc)/cheat/)
obj/fc-video.o: $(fc)/video/video.cpp $(call rwildcard,$(fc)/video/)

View File

@ -51,7 +51,6 @@ namespace Famicom {
#include <fc/apu/apu.hpp>
#include <fc/ppu/ppu.hpp>
#include <fc/cheat/cheat.hpp>
#include <fc/video/video.hpp>
}
#include <fc/interface/interface.hpp>

View File

@ -2,8 +2,10 @@
namespace Famicom {
#include "serialization.cpp"
PPU ppu;
#include "video.cpp"
#include "serialization.cpp"
auto PPU::Main() -> void {
ppu.main();

View File

@ -1,3 +1,5 @@
#include "video.hpp"
struct PPU : Thread {
static auto Main() -> void;
auto main() -> void;

View File

@ -1,34 +1,27 @@
#include <fc/fc.hpp>
#include <cmath>
#define VIDEO_CPP
namespace Famicom {
Video video;
Video::Video() {
output = new uint32[256 * 480];
paletteLiteral = new uint32[1 << 9];
paletteStandard = new uint32[1 << 9];
paletteEmulation = new uint32[1 << 9];
}
Video::~Video() {
delete[] output;
delete[] paletteStandard;
delete[] paletteEmulation;
}
auto Video::reset() -> void {
memory::fill(output, 256 * 480);
memory::fill(output(), 256 * 480);
for(auto color : range(1 << 9)) {
paletteLiteral[color] = color;
paletteStandard[color] = generateColor(color, 2.0, 0.0, 1.0, 1.0, 2.2);
paletteEmulation[color] = generateColor(color, 2.0, 0.0, 1.0, 1.0, 1.8);
}
}
auto Video::refresh() -> void {
auto palette = settings.colorEmulation ? paletteEmulation : paletteStandard;
auto output = this->output();
auto& palette = settings.colorEmulation ? paletteEmulation : paletteStandard;
if(settings.scanlineEmulation) {
for(uint y = 0; y < 240; y++) {
@ -99,7 +92,5 @@ auto Video::generateColor(
uint g = uclamp<16>(65535.0 * gammaAdjust(y + -0.274788 * i + -0.635691 * q));
uint b = uclamp<16>(65535.0 * gammaAdjust(y + -1.108545 * i + 1.709007 * q));
return (255 << 24) | ((r >> 8) << 16) | ((g >> 8) << 8) | ((b >> 8) << 0);
}
return interface->videoColor(r, g, b);
}

View File

@ -1,16 +1,16 @@
struct Video {
Video();
~Video();
auto reset() -> void;
auto refresh() -> void;
uint32* output = nullptr;
uint32* paletteStandard = nullptr;
uint32* paletteEmulation = nullptr;
private:
auto generateColor(uint, double, double, double, double, double) -> uint32;
unique_pointer<uint32[]> output;
unique_pointer<uint32[]> paletteLiteral;
unique_pointer<uint32[]> paletteStandard;
unique_pointer<uint32[]> paletteEmulation;
};
extern Video video;

View File

@ -1,7 +1,7 @@
gb_objects := gb-interface gb-system gb-scheduler
gb_objects += gb-memory gb-cartridge
gb_objects += gb-cpu gb-ppu gb-apu
gb_objects += gb-cheat gb-video
gb_objects += gb-cheat
objects += $(gb_objects)
obj/gb-interface.o: $(gb)/interface/interface.cpp $(call rwildcard,$(gb)/interface/)
@ -13,4 +13,3 @@ obj/gb-cpu.o: $(gb)/cpu/cpu.cpp $(call rwildcard,$(gb)/cpu/)
obj/gb-ppu.o: $(gb)/ppu/ppu.cpp $(call rwildcard,$(gb)/ppu/)
obj/gb-apu.o: $(gb)/apu/apu.cpp $(call rwildcard,$(gb)/apu/)
obj/gb-cheat.o: $(gb)/cheat/cheat.cpp $(call rwildcard,$(gb)/cheat/)
obj/gb-video.o: $(gb)/video/video.cpp $(call rwildcard,$(gb)/video/)

View File

@ -38,17 +38,19 @@ auto CPU::mmio_read(uint16 addr) -> uint8 {
if(addr == 0xff00) { //JOYP
mmio_joyp_poll();
return (status.p15 << 5)
return 0xc0
| (status.p15 << 5)
| (status.p14 << 4)
| (status.joyp << 0);
}
if(addr == 0xff01) { //SB
return 0xff;
return 0x00;
}
if(addr == 0xff02) { //SC
return (status.serial_transfer << 7)
| 0x7e
| (status.serial_clock << 0);
}
@ -65,12 +67,14 @@ auto CPU::mmio_read(uint16 addr) -> uint8 {
}
if(addr == 0xff07) { //TAC
return (status.timer_enable << 2)
return 0xf8
| (status.timer_enable << 2)
| (status.timer_clock << 0);
}
if(addr == 0xff0f) { //IF
return (status.interrupt_request_joypad << 4)
return 0xe0
| (status.interrupt_request_joypad << 4)
| (status.interrupt_request_serial << 3)
| (status.interrupt_request_timer << 2)
| (status.interrupt_request_stat << 1)
@ -123,7 +127,8 @@ auto CPU::mmio_read(uint16 addr) -> uint8 {
}
if(addr == 0xffff) { //IE
return (status.interrupt_enable_joypad << 4)
return 0xe0
| (status.interrupt_enable_joypad << 4)
| (status.interrupt_enable_serial << 3)
| (status.interrupt_enable_timer << 2)
| (status.interrupt_enable_stat << 1)

View File

@ -50,7 +50,6 @@ namespace GameBoy {
#include <gb/ppu/ppu.hpp>
#include <gb/apu/apu.hpp>
#include <gb/cheat/cheat.hpp>
#include <gb/video/video.hpp>
}
#include <gb/interface/interface.hpp>

View File

@ -8,11 +8,13 @@
namespace GameBoy {
PPU ppu;
#include "video.cpp"
#include "mmio.cpp"
#include "dmg.cpp"
#include "cgb.cpp"
#include "serialization.cpp"
PPU ppu;
auto PPU::Main() -> void {
ppu.main();
@ -141,8 +143,8 @@ auto PPU::power() -> void {
for(auto& n : vram) n = 0x00;
for(auto& n : oam) n = 0x00;
for(auto& n : bgp) n = 0x00;
for(auto& n : obp[0]) n = 0x00;
for(auto& n : obp[1]) n = 0x00;
for(auto& n : obp[0]) n = 3;
for(auto& n : obp[1]) n = 3;
for(auto& n : bgpd) n = 0x0000;
for(auto& n : obpd) n = 0x0000;

View File

@ -1,3 +1,5 @@
#include "video.hpp"
struct PPU : Thread, MMIO {
static auto Main() -> void;
auto main() -> void;

View File

@ -1,37 +1,32 @@
#include <gb/gb.hpp>
namespace GameBoy {
Video video;
Video::Video() {
output = new uint32[160 * 144];
paletteLiteral = new uint32[1 << 15];
paletteStandard = new uint32[1 << 15];
paletteEmulation = new uint32[1 << 15];
}
Video::~Video() {
delete[] output;
delete[] paletteStandard;
delete[] paletteEmulation;
}
auto Video::power() -> void {
memory::fill(output, 160 * 144 * sizeof(uint32));
memory::fill(output(), 160 * 144 * sizeof(uint32));
if(system.dmg()) {
for(auto color : range(1 << 2)) {
uint L = image::normalize(3 - color, 2, 8);
uint R = monochrome[color][0] >> 8;
uint G = monochrome[color][1] >> 8;
uint B = monochrome[color][2] >> 8;
paletteStandard[color] = (255 << 24) | (L << 16) | (L << 8) | (L << 0);
paletteEmulation[color] = (255 << 24) | (R << 16) | (G << 8) | (B << 0);
paletteLiteral[color] = color;
uint L = image::normalize(3 - color, 2, 16);
paletteStandard[color] = interface->videoColor(L, L, L);
uint R = monochrome[color][0];
uint G = monochrome[color][1];
uint B = monochrome[color][2];
paletteEmulation[color] = interface->videoColor(R, G, B);
}
}
if(system.sgb()) {
for(auto color : range(1 << 2)) {
paletteLiteral[color] = color;
paletteStandard[color] = color;
paletteEmulation[color] = color;
}
@ -39,30 +34,31 @@ auto Video::power() -> void {
if(system.cgb()) {
for(auto color : range(1 << 15)) {
paletteLiteral[color] = color;
uint r = (uint5)(color >> 0);
uint g = (uint5)(color >> 5);
uint b = (uint5)(color >> 10);
{ uint R = image::normalize(r, 5, 8);
uint G = image::normalize(g, 5, 8);
uint B = image::normalize(b, 5, 8);
paletteStandard[color] = (255 << 24) | (R << 16) | (G << 8) | (B << 0);
}
uint R = image::normalize(r, 5, 16);
uint G = image::normalize(g, 5, 16);
uint B = image::normalize(b, 5, 16);
paletteStandard[color] = interface->videoColor(R, G, B);
{ uint R = (r * 26 + g * 4 + b * 2);
uint G = ( g * 24 + b * 8);
uint B = (r * 6 + g * 4 + b * 22);
R = min(960, R) >> 2;
G = min(960, G) >> 2;
B = min(960, B) >> 2;
paletteEmulation[color] = (255 << 24) | (R << 16) | (G << 8) | (B << 0);
}
R = (r * 26 + g * 4 + b * 2);
G = ( g * 24 + b * 8);
B = (r * 6 + g * 4 + b * 22);
R = image::normalize(min(960, R), 10, 16);
G = image::normalize(min(960, G), 10, 16);
B = image::normalize(min(960, B), 10, 16);
paletteEmulation[color] = interface->videoColor(R, G, B);
}
}
}
auto Video::refresh() -> void {
auto palette = settings.colorEmulation ? paletteEmulation : paletteStandard;
auto output = this->output();
auto& palette = settings.colorEmulation ? paletteEmulation : paletteStandard;
for(uint y = 0; y < 144; y++) {
auto source = ppu.screen + y * 160;
@ -107,5 +103,3 @@ const uint16 Video::monochrome[4][3] = {
{0x0000, 0x0000, 0x0000},
#endif
};
}

16
higan/gb/ppu/video.hpp Normal file
View File

@ -0,0 +1,16 @@
struct Video {
Video();
auto power() -> void;
auto refresh() -> void;
private:
unique_pointer<uint32[]> output;
unique_pointer<uint32[]> paletteLiteral;
unique_pointer<uint32[]> paletteStandard;
unique_pointer<uint32[]> paletteEmulation;
static const uint16 monochrome[4][3];
};
extern Video video;

View File

@ -1,16 +0,0 @@
struct Video {
Video();
~Video();
auto power() -> void;
auto refresh() -> void;
uint32* output = nullptr;
uint32* paletteStandard = nullptr;
uint32* paletteEmulation = nullptr;
private:
static const uint16 monochrome[4][3];
};
extern Video video;

View File

@ -1,5 +1,5 @@
gba_objects := gba-memory gba-interface gba-scheduler gba-system
gba_objects += gba-video gba-cartridge gba-player
gba_objects += gba-cartridge gba-player
gba_objects += gba-cpu gba-ppu gba-apu
objects += $(gba_objects)
@ -7,7 +7,6 @@ obj/gba-memory.o: $(gba)/memory/memory.cpp $(call rwildcard,$(gba)/memory)
obj/gba-interface.o: $(gba)/interface/interface.cpp $(call rwildcard,$(gba)/interface)
obj/gba-scheduler.o: $(gba)/scheduler/scheduler.cpp $(call rwildcard,$(gba)/scheduler)
obj/gba-system.o: $(gba)/system/system.cpp $(call rwildcard,$(gba)/system)
obj/gba-video.o: $(gba)/video/video.cpp $(call rwildcard,$(gba)/video)
obj/gba-cartridge.o: $(gba)/cartridge/cartridge.cpp $(call rwildcard,$(gba)/cartridge)
obj/gba-player.o: $(gba)/player/player.cpp $(call rwildcard,$(gba)/player)
obj/gba-cpu.o: $(gba)/cpu/cpu.cpp $(call rwildcard,$(gba)/cpu)

View File

@ -62,7 +62,6 @@ namespace GameBoyAdvance {
#include <gba/cpu/cpu.hpp>
#include <gba/ppu/ppu.hpp>
#include <gba/apu/apu.hpp>
#include <gba/video/video.hpp>
}
#include <gba/interface/interface.hpp>

View File

@ -12,6 +12,9 @@
namespace GameBoyAdvance {
PPU ppu;
#include "video.cpp"
#include "registers.cpp"
#include "background.cpp"
#include "object.cpp"
@ -20,7 +23,6 @@ namespace GameBoyAdvance {
#include "mmio.cpp"
#include "memory.cpp"
#include "serialization.cpp"
PPU ppu;
PPU::PPU() {
output = new uint32[240 * 160];

View File

@ -1,3 +1,5 @@
#include "video.hpp"
struct PPU : Thread, MMIO {
#include "registers.hpp"
#include "state.hpp"

59
higan/gba/ppu/video.cpp Normal file
View File

@ -0,0 +1,59 @@
Video video;
Video::Video() {
output = new uint32[240 * 160];
paletteLiteral = new uint32[1 << 15];
paletteStandard = new uint32[1 << 15];
paletteEmulation = new uint32[1 << 15];
}
auto Video::power() -> void {
memory::fill(output(), 240 * 160 * sizeof(uint32));
for(auto color : range(1 << 15)) {
paletteLiteral[color] = color;
uint B = (uint5)(color >> 10);
uint G = (uint5)(color >> 5);
uint R = (uint5)(color >> 0);
uint b = image::normalize(B, 5, 16);
uint g = image::normalize(G, 5, 16);
uint r = image::normalize(R, 5, 16);
paletteStandard[color] = interface->videoColor(r, g, b);
double lcdGamma = 4.0, outGamma = 2.2;
double lb = pow(B / 31.0, lcdGamma);
double lg = pow(G / 31.0, lcdGamma);
double lr = pow(R / 31.0, lcdGamma);
b = pow((220 * lb + 10 * lg + 50 * lr) / 255, 1 / outGamma) * (0xffff * 255 / 280);
g = pow(( 30 * lb + 230 * lg + 10 * lr) / 255, 1 / outGamma) * (0xffff * 255 / 280);
r = pow(( 0 * lb + 50 * lg + 255 * lr) / 255, 1 / outGamma) * (0xffff * 255 / 280);
paletteEmulation[color] = interface->videoColor(r, g, b);
}
}
auto Video::refresh() -> void {
auto output = this->output();
auto& palette = settings.colorEmulation ? paletteEmulation : paletteStandard;
for(uint y = 0; y < 160; y++) {
auto source = ppu.output + y * 240;
auto target = output + y * 240;
if(settings.blurEmulation) {
for(uint x = 0; x < 240; x++) {
auto a = palette[*source++];
auto b = *target;
*target++ = (a + b - ((a ^ b) & 0x01010101)) >> 1;
}
} else {
for(uint x = 0; x < 240; x++) {
auto color = palette[*source++];
*target++ = color;
}
}
}
interface->videoRefresh(output, 240 * sizeof(uint32), 240, 160);
}

13
higan/gba/ppu/video.hpp Normal file
View File

@ -0,0 +1,13 @@
struct Video {
Video();
auto power() -> void;
auto refresh() -> void;
unique_pointer<uint32[]> output;
unique_pointer<uint32[]> paletteLiteral;
unique_pointer<uint32[]> paletteStandard;
unique_pointer<uint32[]> paletteEmulation;
};
extern Video video;

View File

@ -1,69 +0,0 @@
#include <gba/gba.hpp>
namespace GameBoyAdvance {
Video video;
Video::Video() {
output = new uint32[240 * 160];
paletteStandard = new uint32[1 << 15];
paletteEmulation = new uint32[1 << 15];
}
Video::~Video() {
delete[] output;
delete[] paletteStandard;
delete[] paletteEmulation;
}
auto Video::power() -> void {
memory::fill(output, 240 * 160 * sizeof(uint32));
for(auto color : range(1 << 15)) {
uint B = (uint5)(color >> 10);
uint G = (uint5)(color >> 5);
uint R = (uint5)(color >> 0);
{ uint b = image::normalize(B, 5, 8);
uint g = image::normalize(G, 5, 8);
uint r = image::normalize(R, 5, 8);
paletteStandard[color] = (255 << 24) | (r << 16) | (g << 8) | (b << 0);
}
{ double lcdGamma = 4.0, outGamma = 2.2;
double lb = pow(B / 31.0, lcdGamma);
double lg = pow(G / 31.0, lcdGamma);
double lr = pow(R / 31.0, lcdGamma);
uint b = pow((220 * lb + 10 * lg + 50 * lr) / 255, 1 / outGamma) * (0xffff * 255 / 280);
uint g = pow(( 30 * lb + 230 * lg + 10 * lr) / 255, 1 / outGamma) * (0xffff * 255 / 280);
uint r = pow(( 0 * lb + 50 * lg + 255 * lr) / 255, 1 / outGamma) * (0xffff * 255 / 280);
paletteEmulation[color] = (255 << 24) | ((r >> 8) << 16) | ((g >> 8) << 8) | ((b >> 8) << 0);
}
}
}
auto Video::refresh() -> void {
auto palette = settings.colorEmulation ? paletteEmulation : paletteStandard;
for(uint y = 0; y < 160; y++) {
auto source = ppu.output + y * 240;
auto target = output + y * 240;
if(settings.blurEmulation) {
for(uint x = 0; x < 240; x++) {
auto a = palette[*source++];
auto b = *target;
*target++ = (a + b - ((a ^ b) & 0x01010101)) >> 1;
}
} else {
for(uint x = 0; x < 240; x++) {
auto color = palette[*source++];
*target++ = color;
}
}
}
interface->videoRefresh(output, 240 * sizeof(uint32), 240, 160);
}
}

View File

@ -1,13 +0,0 @@
struct Video {
Video();
~Video();
auto power() -> void;
auto refresh() -> void;
uint32* output = nullptr;
uint32* paletteStandard = nullptr;
uint32* paletteEmulation = nullptr;
};
extern Video video;

View File

@ -21,7 +21,7 @@ auto ICD2::enter() -> void {
step(GameBoy::system.clocks_executed);
GameBoy::system.clocks_executed = 0;
} else { //DMG halted
dsp.audio.coprocessorSample(0, 0);
audio.coprocessorSample(0, 0);
step(1);
}
synchronizeCPU();
@ -44,8 +44,8 @@ auto ICD2::unload() -> void {
}
auto ICD2::power() -> void {
dsp.audio.coprocessorEnable(true);
dsp.audio.coprocessorFrequency(2 * 1024 * 1024);
audio.coprocessorEnable(true);
audio.coprocessorFrequency(2 * 1024 * 1024);
}
auto ICD2::reset() -> void {

View File

@ -93,7 +93,7 @@ auto ICD2::videoRefresh(const uint32* data, uint pitch, uint width, uint height)
}
auto ICD2::audioSample(int16 left, int16 right) -> void {
dsp.audio.coprocessorSample(left, right);
audio.coprocessorSample(left, right);
}
auto ICD2::inputPoll(uint port, uint device, uint id) -> int16 {

View File

@ -41,7 +41,7 @@ auto MSU1::enter() -> void {
right = sclamp<16>(rchannel);
if(dsp.mute()) left = 0, right = 0;
dsp.audio.coprocessorSample(left, right);
audio.coprocessorSample(left, right);
step(1);
synchronizeCPU();
}
@ -59,8 +59,8 @@ auto MSU1::unload() -> void {
}
auto MSU1::power() -> void {
dsp.audio.coprocessorEnable(true);
dsp.audio.coprocessorFrequency(44100.0);
audio.coprocessorEnable(true);
audio.coprocessorFrequency(44100.0);
}
auto MSU1::reset() -> void {

View File

@ -1,17 +1,19 @@
auto DSP::Audio::coprocessorEnable(bool enable) -> void {
Audio audio;
auto Audio::coprocessorEnable(bool enable) -> void {
mixer.clear();
mixerEnable = enable;
dsp.read = dsp.write = 0;
mix.read = mix.write = 0;
}
auto DSP::Audio::coprocessorFrequency(double frequency) -> void {
auto Audio::coprocessorFrequency(double frequency) -> void {
mixer.setFrequency(frequency);
mixer.setResampler(nall::DSP::ResampleEngine::Sinc);
mixer.setResamplerFrequency(system.apuFrequency() / 768.0);
}
auto DSP::Audio::sample(int16 left, int16 right) -> void {
auto Audio::sample(int16 left, int16 right) -> void {
if(!mixerEnable) return interface->audioSample(left, right);
dsp.left[dsp.write] = left;
@ -20,7 +22,7 @@ auto DSP::Audio::sample(int16 left, int16 right) -> void {
flush();
}
auto DSP::Audio::coprocessorSample(int16 left, int16 right) -> void {
auto Audio::coprocessorSample(int16 left, int16 right) -> void {
int samples[] = {left, right};
mixer.sample(samples);
while(mixer.pending()) {
@ -32,7 +34,7 @@ auto DSP::Audio::coprocessorSample(int16 left, int16 right) -> void {
}
}
auto DSP::Audio::flush() -> void {
auto Audio::flush() -> void {
while(dsp.read != dsp.write && mix.read != mix.write) {
interface->audioSample(
sclamp<16>(dsp.left[dsp.read] + mix.left[mix.read]),

View File

@ -16,3 +16,5 @@ private:
uint8 write;
} dsp, mix;
};
extern Audio audio;

View File

@ -3,6 +3,7 @@
namespace SuperFamicom {
DSP dsp;
#include "audio.cpp"
#define REG(n) state.regs[n]
#define VREG(n) state.regs[v.vidx + n]
@ -15,7 +16,6 @@ DSP dsp;
#include "voice.cpp"
#include "echo.cpp"
#include "serialization.cpp"
#include "audio.cpp"
DSP::DSP() {
static_assert(sizeof(signed) >= 32 / 8, "signed >= 32-bits");

View File

@ -1,5 +1,7 @@
//Sony CXD1222Q-1
#include "audio.hpp"
struct DSP : Thread {
enum : bool { Threaded = true };
@ -18,9 +20,6 @@ struct DSP : Thread {
auto serialize(serializer&) -> void;
#include "audio.hpp"
Audio audio;
privileged:
#include "modulo-array.hpp"

View File

@ -3,6 +3,7 @@
namespace SuperFamicom {
PPU ppu;
#include "video.cpp"
#include "background/background.cpp"
#include "mmio/mmio.cpp"
@ -10,7 +11,6 @@ PPU ppu;
#include "sprite/sprite.cpp"
#include "window/window.cpp"
#include "serialization.cpp"
#include "video.cpp"
PPU::PPU() :
bg1(*this, Background::ID::BG1),

View File

@ -1,3 +1,5 @@
#include "video.hpp"
struct PPU : Thread, public PPUcounter {
enum : bool { Threaded = true };
@ -38,7 +40,6 @@ privileged:
#include "screen/screen.hpp"
#include "sprite/sprite.hpp"
#include "window/window.hpp"
#include "video.hpp"
Background bg1;
Background bg2;
@ -47,7 +48,6 @@ privileged:
Sprite sprite;
Window window;
Screen screen;
Video video;
static auto Enter() -> void;
alwaysinline auto add_clocks(uint) -> void;
@ -59,6 +59,7 @@ privileged:
friend class PPU::Sprite;
friend class PPU::Window;
friend class PPU::Screen;
friend class Video;
struct Debugger {
hook<void (uint16, uint8)> vram_read;

View File

@ -1,23 +1,14 @@
PPU::Video::Video() {
output = new uint32[512 * 512]();
output += 16 * 512; //overscan padding
Video video;
Video::Video() {
output = new uint32[512 * 512];
paletteLiteral = new uint32[1 << 19];
paletteStandard = new uint32[1 << 19];
paletteEmulation = new uint32[1 << 19];
}
PPU::Video::~Video() {
output -= 16 * 512;
delete[] output;
delete[] paletteLiteral;
delete[] paletteStandard;
delete[] paletteEmulation;
}
auto PPU::Video::reset() -> void {
memory::fill(output, 512 * 480 * sizeof(uint32));
auto Video::reset() -> void {
memory::fill(output(), 512 * 512 * sizeof(uint32));
for(auto color : range(1 << 19)) {
uint l = (uint4)(color >> 15);
@ -25,34 +16,31 @@ auto PPU::Video::reset() -> void {
uint g = (uint5)(color >> 5);
uint r = (uint5)(color >> 0);
paletteLiteral[color] = color;
double L = (1.0 + l) / 16.0 * (l ? 1.0 : 0.5);
{ paletteLiteral[color] = color;
}
{ uint R = L * image::normalize(r, 5, 16);
uint R = L * image::normalize(r, 5, 16);
uint G = L * image::normalize(g, 5, 16);
uint B = L * image::normalize(b, 5, 16);
paletteStandard[color] = interface->videoColor(R, G, B);
}
{ static const uint8 gammaRamp[32] = {
static const uint8 gammaRamp[32] = {
0x00, 0x01, 0x03, 0x06, 0x0a, 0x0f, 0x15, 0x1c,
0x24, 0x2d, 0x37, 0x42, 0x4e, 0x5b, 0x69, 0x78,
0x88, 0x90, 0x98, 0xa0, 0xa8, 0xb0, 0xb8, 0xc0,
0xc8, 0xd0, 0xd8, 0xe0, 0xe8, 0xf0, 0xf8, 0xff,
};
uint R = L * gammaRamp[r] * 0x0101;
uint G = L * gammaRamp[g] * 0x0101;
uint B = L * gammaRamp[b] * 0x0101;
R = L * gammaRamp[r] * 0x0101;
G = L * gammaRamp[g] * 0x0101;
B = L * gammaRamp[b] * 0x0101;
paletteEmulation[color] = interface->videoColor(R, G, B);
}
}
}
auto PPU::Video::refresh() -> void {
auto palette = settings.colorEmulation ? paletteEmulation : paletteStandard;
auto Video::refresh() -> void {
auto output = this->output() + 16 * 512; //add offset for overscan
auto& palette = settings.colorEmulation ? paletteEmulation : paletteStandard;
if(settings.scanlineEmulation) {
for(uint y = 0; y < 240; y++) {
@ -117,7 +105,7 @@ auto PPU::Video::refresh() -> void {
scheduler.exit(Scheduler::ExitReason::FrameEvent);
}
auto PPU::Video::drawCursor(uint32 color, int x, int y) -> void {
auto Video::drawCursor(uint32 color, int x, int y) -> void {
static const uint8 cursor[15 * 15] = {
0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,
0,0,0,0,1,1,2,2,2,1,1,0,0,0,0,
@ -136,9 +124,7 @@ auto PPU::Video::drawCursor(uint32 color, int x, int y) -> void {
0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,
};
auto data = (uint32*)output;
if(ppu.interlace() && ppu.field()) data += 512;
auto output = this->output() + 16 * 512;
for(int cy = 0; cy < 15; cy++) {
int vy = y + cy - 7;
if(vy <= 0 || vy >= 240) continue; //do not draw offscreen
@ -150,15 +136,15 @@ auto PPU::Video::drawCursor(uint32 color, int x, int y) -> void {
if(pixel == 0) continue;
uint32 pixelcolor = pixel == 1 ? 0xff000000 : color;
*(data + vy * 1024 + vx * 2 + 0) = pixelcolor;
*(data + vy * 1024 + vx * 2 + 1) = pixelcolor;
*(data + vy * 1024 + 512 + vx * 2 + 0) = pixelcolor;
*(data + vy * 1024 + 512 + vx * 2 + 1) = pixelcolor;
*(output + vy * 1024 + vx * 2 + 0) = pixelcolor;
*(output + vy * 1024 + vx * 2 + 1) = pixelcolor;
*(output + vy * 1024 + 512 + vx * 2 + 0) = pixelcolor;
*(output + vy * 1024 + 512 + vx * 2 + 1) = pixelcolor;
}
}
}
auto PPU::Video::drawCursors() -> void {
auto Video::drawCursors() -> void {
switch((Device::ID)settings.controllerPort2) {
case Device::ID::SuperScope:
if(dynamic_cast<SuperScope*>(device.controllerPort2)) {

View File

@ -1,6 +1,5 @@
struct Video {
Video();
~Video();
auto reset() -> void;
auto refresh() -> void;
@ -9,8 +8,10 @@ private:
auto drawCursor(uint32 color, int x, int y) -> void;
auto drawCursors() -> void;
uint32* output = nullptr;
uint32* paletteLiteral = nullptr;
uint32* paletteStandard = nullptr;
uint32* paletteEmulation = nullptr;
unique_pointer<uint32[]> output;
unique_pointer<uint32[]> paletteLiteral;
unique_pointer<uint32[]> paletteStandard;
unique_pointer<uint32[]> paletteEmulation;
};
extern Video video;

View File

@ -67,7 +67,7 @@ obj/ui-resource.o:
# targets
build: $(objects)
$(strip $(compiler) -o out/$(name) $(objects) $(link))
$(call unique,$(compiler) -o out/$(name) $(objects) $(link))
ifeq ($(platform),macosx)
@if [ -d out/$(name).app ]; then rm -r out/$(name).app; fi
mkdir -p out/$(name).app/Contents/MacOS/

View File

@ -2,7 +2,7 @@
Settings settings;
Settings::Settings() {
Markup::Node::operator=(BML::unserialize(string::read(locate({localpath(), "higan/"}, "settings.bml"))));
Markup::Node::operator=(BML::unserialize(string::read(locate("settings.bml"))));
auto set = [&](const string& name, const string& value) {
//create node and set to default value only if it does not already exist
@ -48,5 +48,5 @@ Settings::Settings() {
}
auto Settings::quit() -> void {
file::write(locate({localpath(), "higan/"}, "settings.bml"), BML::serialize(*this));
file::write(locate("settings.bml"), BML::serialize(*this));
}

View File

@ -1,6 +1,6 @@
#include "../tomoko.hpp"
#include "hotkeys.cpp"
InputManager* inputManager = nullptr;
unique_pointer<InputManager> inputManager;
auto InputMapping::bind() -> void {
auto token = assignment.split("/");
@ -124,7 +124,10 @@ auto InputMapping::assignmentName() -> string {
if(!device) return "None";
string path;
path.append(device->name());
if(device->name() != "Keyboard") {
//keyboards only have one group; no need to append group name
path.append(".", device->group(group).name());
}
path.append(".", device->group(group).input(input).name());
if(qualifier == Qualifier::Lo) path.append(".Lo");
if(qualifier == Qualifier::Hi) path.append(".Hi");

View File

@ -62,4 +62,4 @@ struct InputManager {
vector<InputHotkey*> hotkeys;
};
extern InputManager* inputManager;
extern unique_pointer<InputManager> inputManager;

View File

@ -1,5 +1,5 @@
#include "../tomoko.hpp"
Presentation* presentation = nullptr;
unique_pointer<Presentation> presentation;
Presentation::Presentation() {
presentation = this;
@ -275,7 +275,7 @@ auto Presentation::drawSplashScreen() -> void {
}
auto Presentation::loadShaders() -> void {
auto pathname = locate({localpath(), "higan/"}, "Video Shaders/");
auto pathname = locate("Video Shaders/");
if(settings["Video/Driver"].text() == "OpenGL") {
for(auto shader : directory::folders(pathname, "*.shader")) {

View File

@ -70,4 +70,4 @@ struct Presentation : Window {
StatusBar statusBar{this};
};
extern Presentation* presentation;
extern unique_pointer<Presentation> presentation;

View File

@ -16,7 +16,7 @@ auto Program::loadMedia(string location) -> void {
auto Program::loadMedia(Emulator::Interface& emulator_, Emulator::Interface::Media& media, const string& location) -> void {
unloadMedia();
mediaPaths(0) = locate({localpath(), "higan/"}, {media.name, ".sys/"});
mediaPaths(0) = locate({media.name, ".sys/"});
mediaPaths(media.id) = location;
folderPaths.append(location);

View File

@ -7,11 +7,10 @@
#include "media.cpp"
#include "state.cpp"
#include "utility.cpp"
Program* program = nullptr;
unique_pointer<Program> program;
Program::Program(lstring args) {
program = this;
directory::create({localpath(), "higan/"});
Application::onMain({&Program::main, this});
emulators.append(new Famicom::Interface);
@ -31,10 +30,7 @@ Program::Program(lstring args) {
video = Video::create(settings["Video/Driver"].text());
video->set(Video::Handle, presentation->viewport.handle());
video->set(Video::Synchronize, settings["Video/Synchronize"].boolean());
if(!video->init()) {
delete video;
video = Video::create("None");
}
if(!video->init()) video = Video::create("None");
audio = Audio::create(settings["Audio/Driver"].text());
audio->set(Audio::Device, settings["Audio/Device"].text());
@ -42,18 +38,12 @@ Program::Program(lstring args) {
audio->set(Audio::Synchronize, settings["Audio/Synchronize"].boolean());
audio->set(Audio::Frequency, 96000u);
audio->set(Audio::Latency, 80u);
if(!audio->init()) {
delete audio;
audio = Audio::create("None");
}
if(!audio->init()) audio = Audio::create("None");
input = Input::create(settings["Input/Driver"].text());
input->set(Input::Handle, presentation->viewport.handle());
input->onChange({&InputManager::onChange, inputManager});
if(!input->init()) {
delete input;
input = Input::create("None");
}
input->onChange({&InputManager::onChange, &inputManager()});
if(!input->init()) input = Input::create("None");
dsp.setPrecision(16);
dsp.setBalance(0.0);
@ -82,7 +72,7 @@ auto Program::load(string location) -> void {
} else if(file::exists(location)) {
//special handling to allow importing the Game Boy Advance BIOS
if(file::size(location) == 16384 && file::sha256(location).beginsWith("fd2547724b505f48")) {
auto target = locate({localpath(), "higan/"}, "Game Boy Advance.sys/");
auto target = locate("Game Boy Advance.sys/");
if(file::copy(location, {target, "bios.rom"})) {
MessageDialog().setTitle(Emulator::Name).setText("Game Boy Advance BIOS imported successfully!").information();
}
@ -113,8 +103,5 @@ auto Program::quit() -> void {
unloadMedia();
settings.quit();
inputManager->quit();
delete video;
delete audio;
delete input;
Application::quit();
}

View File

@ -50,4 +50,4 @@ struct Program : Emulator::Interface::Bind {
time_t statusTime = 0;
};
extern Program* program;
extern unique_pointer<Program> program;

View File

@ -5,7 +5,7 @@
#include "hotkeys.cpp"
#include "timing.cpp"
#include "advanced.cpp"
SettingsManager* settingsManager = nullptr;
unique_pointer<SettingsManager> settingsManager;
SettingsManager::SettingsManager() {
settingsManager = this;
@ -14,7 +14,7 @@ SettingsManager::SettingsManager() {
statusBar.setFont(Font().setBold());
setTitle("Configuration Settings");
setSize({600, 400});
setSize({600, 405});
setAlignment({0.0, 1.0});
onSize([&] {

View File

@ -142,4 +142,4 @@ struct SettingsManager : Window {
StatusBar statusBar{this};
};
extern SettingsManager* settingsManager;
extern unique_pointer<SettingsManager> settingsManager;

View File

@ -1,15 +1,18 @@
#include "tomoko.hpp"
Video* video = nullptr;
Audio* audio = nullptr;
Input* input = nullptr;
Emulator::Interface* emulator = nullptr;
unique_pointer<Video> video;
unique_pointer<Audio> audio;
unique_pointer<Input> input;
unique_pointer<Emulator::Interface> emulator;
//if file already exists in the same path as the binary; use it (portable mode)
//if not, use default requested path (*nix/user mode)
auto locate(string pathname, string filename) -> string {
string location{programpath(), filename};
auto locate(string name) -> string {
string location = {programpath(), name};
if(file_system_object::exists(location)) return location;
return {pathname, filename};
location = {configpath(), "higan/", name};
if(file_system_object::exists(location)) return location;
directory::create({localpath(), "higan/"});
return {localpath(), "higan/", name};
}
#include <nall/main.hpp>

View File

@ -4,12 +4,12 @@
using namespace nall;
using namespace ruby;
using namespace hiro;
extern Video* video;
extern Audio* audio;
extern Input* input;
extern unique_pointer<Video> video;
extern unique_pointer<Audio> audio;
extern unique_pointer<Input> input;
#include <emulator/emulator.hpp>
extern Emulator::Interface* emulator;
extern unique_pointer<Emulator::Interface> emulator;
#include "program/program.hpp"
#include "configuration/configuration.hpp"
@ -18,4 +18,4 @@ extern Emulator::Interface* emulator;
#include "tools/tools.hpp"
#include "presentation/presentation.hpp"
auto locate(string pathname, string filename) -> string;
auto locate(string name) -> string;

View File

@ -20,7 +20,7 @@ auto CheatDatabase::findCodes() -> void {
if(!emulator) return;
auto sha256 = emulator->sha256();
auto contents = string::read(locate({localpath(), "higan/"}, "cheats.bml"));
auto contents = string::read(locate("cheats.bml"));
auto document = BML::unserialize(contents);
for(auto cartridge : document.find("cartridge")) {

View File

@ -3,9 +3,8 @@
#include "cheat-editor.cpp"
#include "state-manager.cpp"
#include "manifest-viewer.cpp"
CheatDatabase* cheatDatabase = nullptr;
ToolsManager* toolsManager = nullptr;
ManifestViewer* manifestViewer = nullptr;
unique_pointer<CheatDatabase> cheatDatabase;
unique_pointer<ToolsManager> toolsManager;
ToolsManager::ToolsManager() {
toolsManager = this;
@ -13,7 +12,7 @@ ToolsManager::ToolsManager() {
layout.setMargin(5);
setTitle("Tools");
setSize({600, 400});
setSize({600, 405});
setAlignment({1.0, 1.0});
onSize([&] {

View File

@ -95,5 +95,5 @@ struct ToolsManager : Window {
ManifestViewer manifestViewer{&panel};
};
extern CheatDatabase* cheatDatabase;
extern ToolsManager* toolsManager;
extern unique_pointer<CheatDatabase> cheatDatabase;
extern unique_pointer<ToolsManager> toolsManager;

View File

@ -113,6 +113,14 @@ rwildcard = \
) \
)
# function unique(source)
unique = \
$(eval __temp :=) \
$(strip \
$(foreach s,$1,$(if $(filter $s,$(__temp)),,$(eval __temp += $s))) \
$(__temp) \
)
# function strtr(source, from, to)
strtr = \
$(eval __temp := $1) \

View File

@ -49,6 +49,7 @@
#include <nall/string.hpp>
#include <nall/thread.hpp>
#include <nall/traits.hpp>
#include <nall/unique-pointer.hpp>
#include <nall/utility.hpp>
#include <nall/varint.hpp>
#include <nall/vector.hpp>

View File

@ -11,9 +11,9 @@ template<typename T> struct shared_pointer;
struct shared_pointer_manager {
void* pointer = nullptr;
function<void (void*)> deleter;
unsigned strong = 0;
unsigned weak = 0;
function<auto (void*) -> void> deleter;
uint strong = 0;
uint weak = 0;
shared_pointer_manager(void* pointer) : pointer(pointer) {
}

102
nall/unique-pointer.hpp Normal file
View File

@ -0,0 +1,102 @@
#pragma once
namespace nall {
template<typename T>
struct unique_pointer {
using type = T;
T* pointer = nullptr;
function<auto (T*) -> void> deleter;
unique_pointer(const unique_pointer&) = delete;
auto operator=(const unique_pointer&) -> unique_pointer& = delete;
unique_pointer(T* pointer = nullptr, const function<void (T*)>& deleter = {}) : pointer(pointer), deleter(deleter) {}
~unique_pointer() { reset(); }
auto operator=(T* source) -> unique_pointer& {
reset();
pointer = source;
return *this;
}
explicit operator bool() const { return pointer; }
auto operator->() -> T* { return pointer; }
auto operator->() const -> const T* { return pointer; }
auto operator*() -> T& { return *pointer; }
auto operator*() const -> const T& { return *pointer; }
auto operator()() -> T& { return *pointer; }
auto operator()() const -> const T& { return *pointer; }
auto data() -> T* { return pointer; }
auto data() const -> const T* { return pointer; }
auto release() -> T* {
auto result = pointer;
pointer = nullptr;
return result;
}
auto reset() -> void {
if(pointer) {
if(deleter) {
deleter(pointer);
} else {
delete pointer;
}
pointer = nullptr;
}
}
};
template<typename T>
struct unique_pointer<T[]> {
using type = T;
T* pointer = nullptr;
function<auto (T*) -> void> deleter;
unique_pointer(const unique_pointer&) = delete;
auto operator=(const unique_pointer&) -> unique_pointer& = delete;
unique_pointer(T* pointer = nullptr, const function<void (T*)>& deleter = {}) : pointer(pointer), deleter(deleter) {}
~unique_pointer() { reset(); }
auto operator=(T* source) -> unique_pointer& {
reset();
pointer = source;
return *this;
}
explicit operator bool() const { return pointer; }
auto operator()() -> T* { return pointer; }
auto operator()() const -> T* { return pointer; }
alwaysinline auto operator[](uint offset) -> T& { return pointer[offset]; }
alwaysinline auto operator[](uint offset) const -> const T& { return pointer[offset]; }
auto data() -> T* { return pointer; }
auto data() const -> const T* { return pointer; }
auto release() -> T* {
auto result = pointer;
pointer = nullptr;
return result;
}
auto reset() -> void {
if(pointer) {
if(deleter) {
deleter(pointer);
} else {
delete[] pointer;
}
pointer = nullptr;
}
}
};
}

View File

@ -2,7 +2,7 @@
#include <windows.h>
struct AudioXAudio2 : Audio, public IXAudio2VoiceCallback {
AudioXAudio2() { term(); }
~AudioXAudio2() { term(); }
IXAudio2* pXAudio2 = nullptr;
IXAudio2MasteringVoice* pMasterVoice = nullptr;