Removing new frame callback

This commit is contained in:
Selim Mustafaev 2025-09-17 18:05:41 +03:00
parent fbf80723d6
commit 3d8b37aff4
6 changed files with 38 additions and 29 deletions

4
.gitignore vendored
View File

@ -1,4 +1,6 @@
cmake-build-debug/ cmake-build-debug/
.idea/ .idea/
.vs/ .vs/
out/ out/
build/
CMakeLists.txt.user

View File

@ -2,7 +2,6 @@
#include "Window.h" #include "Window.h"
#include "SdlKeyboardController.h" #include "SdlKeyboardController.h"
#include <functional>
#include <thread> #include <thread>
int main() { int main() {
@ -12,25 +11,34 @@ int main() {
nes::System device; nes::System device;
nes::SdlWindow window(nes::Ppu::SCREEN_WIDTH, nes::Ppu::SCREEN_HEIGHT); nes::SdlWindow window(nes::Ppu::SCREEN_WIDTH, nes::Ppu::SCREEN_HEIGHT);
window.setSize(nes::Ppu::SCREEN_WIDTH*2, nes::Ppu::SCREEN_HEIGHT*2); window.setSize(nes::Ppu::SCREEN_WIDTH*2, nes::Ppu::SCREEN_HEIGHT*2);
bool working = true;
SDL_Event e; SDL_Event e;
bool frameRendered = false;
device.setNewFrameCallback([&window, &e, &frameRendered](auto buffer){
window.drawFrame(buffer);
while(SDL_PollEvent(&e));
frameRendered = true;
});
device.connect(std::make_shared<SdlKeyboardController>()); device.connect(std::make_shared<SdlKeyboardController>());
//device.insertCartridge("/home/selim/Downloads/dk.nes"); //device.insertCartridge("/home/selim/Downloads/dk.nes");
device.insertCartridge("/Users/selim/Documents/nes/ppu_tests/sprite_ram.nes"); device.insertCartridge("/Users/selim/Documents/nes/ppu_tests/vram_access.nes");
//device.insertCartridge("/Users/selim/Documents/nes/ff.nes"); //device.insertCartridge("/Users/selim/Documents/nes/ff.nes");
//device.insertCartridge("C:\\Users\\selim\\Documents\\nestest.nes"); //device.insertCartridge("C:\\Users\\selim\\Documents\\nestest.nes");
auto frameStart = std::chrono::steady_clock::now(); auto frameStart = std::chrono::steady_clock::now();
while (true) { while (working) {
device.tick();
if(frameRendered) { if(auto frameBuffer = device.tick()) {
// Draw frame
window.drawFrame(frameBuffer);
// Poll all accumulated events
while(SDL_PollEvent(&e)) {
switch(e.type) {
case SDL_EVENT_WINDOW_CLOSE_REQUESTED:
case SDL_EVENT_QUIT:
working = false;
break;
}
}
// Wait some time for slowing down to 60 fps
auto renderingTime = std::chrono::steady_clock::now(); auto renderingTime = std::chrono::steady_clock::now();
auto elapsedTime = std::chrono::duration_cast<std::chrono::nanoseconds>(renderingTime - frameStart).count(); auto elapsedTime = std::chrono::duration_cast<std::chrono::nanoseconds>(renderingTime - frameStart).count();
int64_t waitTime = 1000000000/60 - elapsedTime; int64_t waitTime = 1000000000/60 - elapsedTime;
@ -38,7 +46,6 @@ int main() {
std::this_thread::sleep_for(std::chrono::nanoseconds(waitTime)); std::this_thread::sleep_for(std::chrono::nanoseconds(waitTime));
} }
frameStart = std::chrono::steady_clock::now(); frameStart = std::chrono::steady_clock::now();
frameRendered = false;
} }
} }

View File

@ -34,7 +34,7 @@ namespace nes {
}; };
} }
bool Ppu::tick() { std::tuple<bool, const Pixel*> Ppu::tick() {
_needEmitNmi = false; _needEmitNmi = false;
@ -148,17 +148,22 @@ namespace nes {
} }
_column++; _column++;
bool frameReady = false;
if(_column >= 341) { if(_column >= 341) {
_column = 0; _column = 0;
_scanline++; _scanline++;
if(_scanline >= 261) { if(_scanline >= 261) {
_scanline = -1; _scanline = -1;
onNewFrame(_frameBuffer.get()); frameReady = true;
} }
} }
return _needEmitNmi; return {
_needEmitNmi,
frameReady ? _frameBuffer.get() : nullptr
};
} }
uint8_t Ppu::read(uint16_t address) { uint8_t Ppu::read(uint16_t address) {

View File

@ -13,6 +13,7 @@
#include <memory> #include <memory>
#include <functional> #include <functional>
#include <vector> #include <vector>
#include <tuple>
namespace nes { namespace nes {
@ -101,7 +102,7 @@ namespace nes {
public: public:
Ppu(); Ppu();
bool tick(); std::tuple<bool, const Pixel*> tick();
void write(uint16_t address, uint8_t value); void write(uint16_t address, uint8_t value);
uint8_t read(uint16_t address); uint8_t read(uint16_t address);
void setPixel(uint16_t row, uint16_t column, Pixel pixel); void setPixel(uint16_t row, uint16_t column, Pixel pixel);
@ -115,9 +116,6 @@ namespace nes {
void dmaTick(uint64_t cycles) const; void dmaTick(uint64_t cycles) const;
void startDma(uint8_t page) const; void startDma(uint8_t page) const;
public:
std::function<void(const Pixel*)> onNewFrame;
private: private:
Pixel getColor(uint8_t palette, uint8_t pixel); Pixel getColor(uint8_t palette, uint8_t pixel);
void prepareNextBgTile(uint16_t column); void prepareNextBgTile(uint16_t column);

View File

@ -44,12 +44,8 @@ namespace nes {
} }
} }
void System::setNewFrameCallback(std::function<void(const Pixel *)> onNewFrame) { const Pixel* System::tick() {
_ppu->onNewFrame = std::move(onNewFrame); auto [needInterrupt, frameBuffer] = _ppu->tick();
}
void System::tick() {
bool needInterrupt = _ppu->tick();
if(_cycles % 3 == 0) { if(_cycles % 3 == 0) {
if(_ppu->dmaActive()) { if(_ppu->dmaActive()) {
@ -64,6 +60,8 @@ namespace nes {
} }
_cycles++; _cycles++;
return frameBuffer;
} }
// For debug // For debug

View File

@ -27,8 +27,7 @@ namespace nes {
void insertCartridge(const fs::path& path, std::optional<uint16_t> address = std::nullopt); void insertCartridge(const fs::path& path, std::optional<uint16_t> address = std::nullopt);
void connect(std::shared_ptr<Controller> controller); void connect(std::shared_ptr<Controller> controller);
void reset(std::optional<uint16_t> address = std::nullopt); void reset(std::optional<uint16_t> address = std::nullopt);
void setNewFrameCallback(std::function<void(const Pixel*)> onNewFrame); const Pixel* tick();
void tick();
[[nodiscard]] uint32_t zpHash() const; [[nodiscard]] uint32_t zpHash() const;