diff --git a/src/app/emu/debug/emu.cc b/src/app/emu/debug/emu.cc new file mode 100644 index 00000000..290c80a1 --- /dev/null +++ b/src/app/emu/debug/emu.cc @@ -0,0 +1,217 @@ +#if defined(_WIN32) +#define main SDL_main +#elif __APPLE__ +#include "app/core/platform/app_delegate.h" +#endif + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "absl/base/internal/raw_logging.h" +#include "absl/base/macros.h" +#include "absl/container/flat_hash_map.h" +#include "absl/debugging/failure_signal_handler.h" +#include "absl/debugging/leak_check.h" +#include "absl/debugging/stacktrace.h" +#include "absl/debugging/symbolize.h" +#include "absl/flags/flag.h" +#include "absl/status/status.h" +#include "absl/status/statusor.h" +#include "absl/strings/str_format.h" +#include "app/emu/snes.h" +#include "app/rom.h" + +using namespace yaze::app; + +struct sdl_deleter { + void operator()(SDL_Window *p) const { + if (p) { + SDL_DestroyWindow(p); + } + } + void operator()(SDL_Renderer *p) const { + if (p) { + SDL_DestroyRenderer(p); + } + } + void operator()(SDL_Texture *p) const { SDL_DestroyTexture(p); } +}; + +int main(int argc, char **argv) { + absl::InitializeSymbolizer(argv[0]); + + absl::FailureSignalHandlerOptions options; + options.symbolize_stacktrace = true; + options.alarm_on_failure_secs = true; + absl::InstallFailureSignalHandler(options); + + std::unique_ptr window_; + std::unique_ptr renderer_; + if (SDL_Init(SDL_INIT_EVERYTHING) != 0) { + return EXIT_FAILURE; + } else { + SDL_DisplayMode displayMode; + SDL_GetCurrentDisplayMode(0, &displayMode); + int screenWidth = displayMode.w * 0.8; + int screenHeight = displayMode.h * 0.8; + + window_ = std::unique_ptr( + SDL_CreateWindow("Yaze Emulator", // window title + SDL_WINDOWPOS_UNDEFINED, // initial x position + SDL_WINDOWPOS_UNDEFINED, // initial y position + 512, // width, in pixels + 480, // height, in pixels + SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI), + sdl_deleter()); + if (window_ == nullptr) { + return EXIT_FAILURE; + } + } + + renderer_ = std::unique_ptr( + SDL_CreateRenderer(window_.get(), -1, + SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC), + sdl_deleter()); + if (renderer_ == nullptr) { + return EXIT_FAILURE; + } else { + SDL_SetRenderDrawBlendMode(renderer_.get(), SDL_BLENDMODE_BLEND); + SDL_SetRenderDrawColor(renderer_.get(), 0x00, 0x00, 0x00, 0x00); + } + + int audio_frequency_ = 48000; + SDL_AudioSpec want, have; + SDL_memset(&want, 0, sizeof(want)); + want.freq = audio_frequency_; + want.format = AUDIO_S16; + want.channels = 2; + want.samples = 2048; + want.callback = NULL; // Uses the queue + auto audio_device_ = SDL_OpenAudioDevice(NULL, 0, &want, &have, 0); + if (audio_device_ == 0) { + return EXIT_FAILURE; + } + auto audio_buffer_ = new int16_t[audio_frequency_ / 50 * 4]; + SDL_PauseAudioDevice(audio_device_, 0); + +#ifdef __APPLE__ + InitializeCocoa(); +#endif + + auto ppu_texture_ = + SDL_CreateTexture(renderer_.get(), SDL_PIXELFORMAT_RGBX8888, + SDL_TEXTUREACCESS_STREAMING, 512, 480); + if (ppu_texture_ == NULL) { + printf("Failed to create texture: %s\n", SDL_GetError()); + return EXIT_FAILURE; + } + + Rom rom_; + emu::SNES snes_; + Bytes rom_data_; + + bool running = true; + bool loaded = false; + auto count_frequency = SDL_GetPerformanceFrequency(); + auto last_count = SDL_GetPerformanceCounter(); + auto time_adder = 0.0; + int wanted_frames_ = 0; + int wanted_samples_ = 0; + SDL_Event event; + + rom_.LoadFromFile("inidisp_hammer_0f00.sfc"); + if (rom_.is_loaded()) { + rom_data_ = rom_.vector(); + snes_.Init(rom_data_); + wanted_frames_ = 1.0 / (snes_.Memory().pal_timing() ? 50.0 : 60.0); + wanted_samples_ = 48000 / (snes_.Memory().pal_timing() ? 50 : 60); + loaded = true; + } + + while (running) { + while (SDL_PollEvent(&event)) { + switch (event.type) { + case SDL_DROPFILE: + rom_.LoadFromFile(event.drop.file); + if (rom_.is_loaded()) { + rom_data_ = rom_.vector(); + snes_.Init(rom_data_); + wanted_frames_ = 1.0 / (snes_.Memory().pal_timing() ? 50.0 : 60.0); + wanted_samples_ = 48000 / (snes_.Memory().pal_timing() ? 50 : 60); + loaded = true; + } + SDL_free(event.drop.file); + break; + case SDL_KEYDOWN: + break; + case SDL_KEYUP: + break; + case SDL_WINDOWEVENT: + switch (event.window.event) { + case SDL_WINDOWEVENT_CLOSE: + running = false; + break; + case SDL_WINDOWEVENT_SIZE_CHANGED: + break; + default: + break; + } + break; + default: + break; + } + } + + uint64_t current_count = SDL_GetPerformanceCounter(); + uint64_t delta = current_count - last_count; + last_count = current_count; + float seconds = delta / (float)count_frequency; + time_adder += seconds; + // allow 2 ms earlier, to prevent skipping due to being just below wanted + while (time_adder >= wanted_frames_ - 0.002) { + time_adder -= wanted_frames_; + + if (loaded) { + snes_.RunFrame(); + + snes_.SetSamples(audio_buffer_, wanted_samples_); + if (SDL_GetQueuedAudioSize(audio_device_) <= wanted_samples_ * 4 * 6) { + SDL_QueueAudio(audio_device_, audio_buffer_, wanted_samples_ * 4); + } + + void *ppu_pixels_; + int ppu_pitch_; + if (SDL_LockTexture(ppu_texture_, NULL, &ppu_pixels_, &ppu_pitch_) != + 0) { + printf("Failed to lock texture: %s\n", SDL_GetError()); + return EXIT_FAILURE; + } + snes_.SetPixels(static_cast(ppu_pixels_)); + SDL_UnlockTexture(ppu_texture_); + } + } + + SDL_RenderClear(renderer_.get()); + SDL_RenderCopy(renderer_.get(), ppu_texture_, NULL, NULL); + SDL_RenderPresent(renderer_.get()); // should vsync + } + + SDL_PauseAudioDevice(audio_device_, 1); + SDL_CloseAudioDevice(audio_device_); + delete audio_buffer_; + // ImGui_ImplSDLRenderer2_Shutdown(); + // ImGui_ImplSDL2_Shutdown(); + // ImGui::DestroyContext(); + SDL_Quit(); + + return EXIT_SUCCESS; +} \ No newline at end of file