mirror of
https://github.com/dingusdev/dingusppc.git
synced 2025-01-10 13:29:38 +00:00
Handling host events in video controllers.
This commit is contained in:
parent
f1c898b17e
commit
3e545bdef9
@ -1,6 +1,6 @@
|
||||
/*
|
||||
DingusPPC - The Experimental PowerPC Macintosh emulator
|
||||
Copyright (C) 2018-22 divingkatae and maximum
|
||||
Copyright (C) 2018-23 divingkatae and maximum
|
||||
(theweirdo) spatium
|
||||
|
||||
(Contact divingkatae#1017 or powermax#2286 on Discord for more info)
|
||||
@ -40,7 +40,7 @@ AtiMach64Gx::AtiMach64Gx()
|
||||
{
|
||||
supports_types(HWCompType::MMIO_DEV | HWCompType::PCI_DEV);
|
||||
|
||||
/* set up PCI configuration space header */
|
||||
// set up PCI configuration space header
|
||||
this->vendor_id = PCI_VENDOR_ATI;
|
||||
this->device_id = ATI_MACH64_GX_DEV_ID;
|
||||
this->class_rev = (0x030000 << 8) | 3;
|
||||
@ -53,7 +53,8 @@ AtiMach64Gx::AtiMach64Gx()
|
||||
|
||||
// declare expansion ROM containing FCode and Mac OS drivers
|
||||
if (this->attach_exp_rom_image(std::string("113-32900-004_Apple_MACH64.bin"))) {
|
||||
LOG_F(WARNING, "AtiMach64Gx: could not load ROM - this device won't work properly!");
|
||||
ABORT_F("%s: could not load ROM - this device won't work properly!",
|
||||
this->name.c_str());
|
||||
}
|
||||
|
||||
// initialize display identification
|
||||
@ -180,6 +181,15 @@ void AtiMach64Gx::write_reg(uint32_t offset, uint32_t value, uint32_t size)
|
||||
|
||||
switch (offset & ~3) {
|
||||
case ATI_CRTC_GEN_CNTL:
|
||||
if (value & 0x40) {
|
||||
this->mm_regs[ATI_CRTC_GEN_CNTL] |= (1 << 6);
|
||||
this->blank_on = true;
|
||||
this->blank_display();
|
||||
} else {
|
||||
this->mm_regs[ATI_CRTC_GEN_CNTL] &= ~(1 << 6);
|
||||
this->blank_on = false;
|
||||
}
|
||||
|
||||
crtc_en = (this->mm_regs[ATI_CRTC_GEN_CNTL+3] >> 1) & 1;
|
||||
if (crtc_en != this->crtc_enable) {
|
||||
if (!crtc_en) {
|
||||
@ -246,7 +256,7 @@ void AtiMach64Gx::enable_crtc_internal()
|
||||
LOG_F(WARNING, "AtiMach64Gx: display window resizing not implemented yet!");
|
||||
}
|
||||
|
||||
/* calculate display refresh rate */
|
||||
// calculate display refresh rate
|
||||
int hori_total = (this->mm_regs[ATI_CRTC_H_TOTAL_DISP] + 1) * 8;
|
||||
|
||||
int vert_total = (READ_WORD_LE_A(&this->mm_regs[ATI_CRTC_V_TOTAL_DISP]) & 0x7FFUL) + 1;
|
||||
@ -270,16 +280,18 @@ void AtiMach64Gx::enable_crtc_internal()
|
||||
ABORT_F("AtiMach64Gx: unsupported pixel depth %d", this->pixel_depth);
|
||||
}
|
||||
|
||||
if (this->refresh_task_id) {
|
||||
TimerManager::get_instance()->cancel_timer(this->refresh_task_id);
|
||||
}
|
||||
|
||||
uint64_t refresh_interval = static_cast<uint64_t>(1.0f / this->refresh_rate * NS_PER_SEC + 0.5);
|
||||
TimerManager::get_instance()->add_cyclic_timer(
|
||||
this->refresh_task_id = TimerManager::get_instance()->add_cyclic_timer(
|
||||
refresh_interval,
|
||||
[this]() {
|
||||
this->update_screen();
|
||||
}
|
||||
);
|
||||
|
||||
this->update_screen();
|
||||
|
||||
this->crtc_on = true;
|
||||
|
||||
this->crtc_enable = 1;
|
||||
|
@ -534,15 +534,17 @@ void ATIRage::crtc_enable() {
|
||||
LOG_F(INFO, "Pixel (dot) clock: %f MHz", this->pixel_clock * 1e-6);
|
||||
LOG_F(INFO, "Refresh rate: %f Hz", this->refresh_rate);
|
||||
|
||||
if (this->refresh_task_id) {
|
||||
TimerManager::get_instance()->cancel_timer(this->refresh_task_id);
|
||||
}
|
||||
|
||||
uint64_t refresh_interval = static_cast<uint64_t>(1.0f / this->refresh_rate * NS_PER_SEC + 0.5);
|
||||
TimerManager::get_instance()->add_cyclic_timer(
|
||||
this->refresh_task_id = TimerManager::get_instance()->add_cyclic_timer(
|
||||
refresh_interval,
|
||||
[this]() {
|
||||
this->update_screen();
|
||||
}
|
||||
);
|
||||
|
||||
this->update_screen();
|
||||
} else {
|
||||
LOG_F(WARNING, "ATI Rage: VLCK source != VPLL!");
|
||||
}
|
||||
|
@ -293,16 +293,20 @@ void ControlVideo::enable_display()
|
||||
/ (new_height + vert_blank);
|
||||
LOG_F(INFO, "Control: refresh rate set to %f Hz", this->refresh_rate);
|
||||
|
||||
if (this->refresh_task_id) {
|
||||
TimerManager::get_instance()->cancel_timer(this->refresh_task_id);
|
||||
}
|
||||
|
||||
// set up periodic timer for display updates
|
||||
uint64_t refresh_interval = static_cast<uint64_t>(1.0f / refresh_rate * NS_PER_SEC + 0.5);
|
||||
TimerManager::get_instance()->add_cyclic_timer(
|
||||
this->refresh_task_id = TimerManager::get_instance()->add_cyclic_timer(
|
||||
refresh_interval,
|
||||
[this]() {
|
||||
this->update_screen();
|
||||
}
|
||||
);
|
||||
|
||||
this->update_screen();
|
||||
this->blank_on = false;
|
||||
|
||||
LOG_F(INFO, "Control: display enabled");
|
||||
this->crtc_on = true;
|
||||
|
@ -46,6 +46,15 @@ PdmOnboardVideo::PdmOnboardVideo()
|
||||
|
||||
void PdmOnboardVideo::set_video_mode(uint8_t new_mode)
|
||||
{
|
||||
if (this->blanking != (new_mode & 0x80)) {
|
||||
if (new_mode & 0x80) {
|
||||
this->disable_video_internal();
|
||||
} else {
|
||||
this->blank_on = false;
|
||||
this->blanking = 0;
|
||||
}
|
||||
}
|
||||
|
||||
switch(new_mode & 0x7F) {
|
||||
case PdmVideoMode::Portrait:
|
||||
case PdmVideoMode::Rgb12in:
|
||||
@ -56,20 +65,14 @@ void PdmOnboardVideo::set_video_mode(uint8_t new_mode)
|
||||
this->video_mode = new_mode & 0x1F;
|
||||
LOG_F(INFO, "PDM-Video: video mode set to 0x%X", this->video_mode);
|
||||
}
|
||||
if (this->blanking != (new_mode & 0x80)) {
|
||||
this->blanking = new_mode & 0x80;
|
||||
if (this->blanking) {
|
||||
this->disable_video_internal();
|
||||
} else {
|
||||
this->enable_video_internal();
|
||||
}
|
||||
if (!this->blanking) {
|
||||
this->enable_video_internal();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
LOG_F(9, "PDM-Video: video disabled, new mode = 0x%X", new_mode & 0x1F);
|
||||
this->video_mode = new_mode & 0x1F;
|
||||
this->blanking = 0x80;
|
||||
this->crtc_on = false;
|
||||
this->disable_video_internal();
|
||||
}
|
||||
}
|
||||
|
||||
@ -207,27 +210,32 @@ void PdmOnboardVideo::enable_video_internal()
|
||||
|
||||
this->set_depth_internal(new_width);
|
||||
|
||||
if (this->refresh_task_id) {
|
||||
TimerManager::get_instance()->cancel_timer(this->refresh_task_id);
|
||||
}
|
||||
|
||||
// set up video refresh timer
|
||||
double refresh_rate_hz = (double)(this->pixel_clock) / (new_width + hori_blank) / (new_height + vert_blank);
|
||||
LOG_F(INFO, "PDM-Video: refresh rate set to %f Hz", refresh_rate_hz);
|
||||
uint64_t refresh_interval = static_cast<uint64_t>(1.0f / refresh_rate_hz * NS_PER_SEC + 0.5);
|
||||
TimerManager::get_instance()->add_cyclic_timer(
|
||||
this->refresh_task_id = TimerManager::get_instance()->add_cyclic_timer(
|
||||
refresh_interval,
|
||||
[this]() {
|
||||
this->update_screen();
|
||||
}
|
||||
);
|
||||
|
||||
this->update_screen();
|
||||
|
||||
LOG_F(INFO, "PDM-Video: video enabled");
|
||||
LOG_F(9, "PDM-Video: video enabled");
|
||||
this->crtc_on = true;
|
||||
}
|
||||
|
||||
void PdmOnboardVideo::disable_video_internal()
|
||||
{
|
||||
this->blank_on = true;
|
||||
this->blank_display();
|
||||
this->blanking = 0x80;
|
||||
this->crtc_on = false;
|
||||
LOG_F(INFO, "PDM-Video: video disabled");
|
||||
LOG_F(9, "PDM-Video: video disabled");
|
||||
}
|
||||
|
||||
/** Ariel II has a weird 1bpp mode where a white pixel is mapped to
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
DingusPPC - The Experimental PowerPC Macintosh emulator
|
||||
Copyright (C) 2018-21 divingkatae and maximum
|
||||
Copyright (C) 2018-23 divingkatae and maximum
|
||||
(theweirdo) spatium
|
||||
|
||||
(Contact divingkatae#1017 or powermax#2286 on Discord for more info)
|
||||
@ -21,8 +21,10 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
/** @file Video Conroller base class implementation. */
|
||||
|
||||
#include "videoctrl.h"
|
||||
#include <core/hostevents.h>
|
||||
#include <devices/video/videoctrl.h>
|
||||
#include <loguru.hpp>
|
||||
#include <memaccess.h>
|
||||
#include <SDL.h>
|
||||
|
||||
#include <chrono>
|
||||
@ -30,51 +32,15 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
VideoCtrlBase::VideoCtrlBase(int width, int height)
|
||||
{
|
||||
LOG_F(INFO, "Create display window...");
|
||||
EventManager::get_instance()->register_handler(EventType::EVENT_WINDOW,
|
||||
[this](const BaseEvent& event) {
|
||||
const WindowEvent& wnd_event = static_cast<const WindowEvent&>(event);
|
||||
if (wnd_event.sub_type == SDL_WINDOWEVENT_SIZE_CHANGED &&
|
||||
wnd_event.window_id == this->disp_wnd_id)
|
||||
this->resizing = false;
|
||||
});
|
||||
|
||||
this->active_width = width;
|
||||
this->active_height = height;
|
||||
|
||||
// Create display window
|
||||
this->display_wnd = SDL_CreateWindow(
|
||||
"DingusPPC Display",
|
||||
SDL_WINDOWPOS_UNDEFINED,
|
||||
SDL_WINDOWPOS_UNDEFINED,
|
||||
this->active_width,
|
||||
this->active_height,
|
||||
SDL_WINDOW_OPENGL
|
||||
);
|
||||
|
||||
if (this->display_wnd == NULL) {
|
||||
LOG_F(ERROR, "Display: SDL_CreateWindow failed with %s", SDL_GetError());
|
||||
}
|
||||
|
||||
this->renderer = SDL_CreateRenderer(this->display_wnd, -1, SDL_RENDERER_ACCELERATED);
|
||||
if (this->renderer == NULL) {
|
||||
LOG_F(ERROR, "Display: SDL_CreateRenderer failed with %s", SDL_GetError());
|
||||
}
|
||||
|
||||
SDL_SetRenderDrawColor(this->renderer, 0, 0, 0, 255);
|
||||
SDL_RenderClear(this->renderer);
|
||||
SDL_RenderPresent(this->renderer);
|
||||
|
||||
// Stupidly poll for 10 events.
|
||||
// Otherwise no window will be shown on mac OS!
|
||||
SDL_Event e;
|
||||
for (int i = 0; i < 10; i++) {
|
||||
SDL_PollEvent(&e);
|
||||
}
|
||||
|
||||
this->disp_texture = SDL_CreateTexture(
|
||||
this->renderer,
|
||||
SDL_PIXELFORMAT_ARGB8888,
|
||||
SDL_TEXTUREACCESS_STREAMING,
|
||||
width, height
|
||||
);
|
||||
|
||||
if (this->disp_texture == NULL) {
|
||||
LOG_F(ERROR, "Display: SDL_CreateTexture failed with %s", SDL_GetError());
|
||||
}
|
||||
this->create_display_window(width, height);
|
||||
}
|
||||
|
||||
VideoCtrlBase::~VideoCtrlBase()
|
||||
@ -92,6 +58,61 @@ VideoCtrlBase::~VideoCtrlBase()
|
||||
}
|
||||
}
|
||||
|
||||
void VideoCtrlBase::create_display_window(int width, int height)
|
||||
{
|
||||
if (!this->display_wnd) { // create display window
|
||||
this->display_wnd = SDL_CreateWindow(
|
||||
"DingusPPC Display",
|
||||
SDL_WINDOWPOS_UNDEFINED,
|
||||
SDL_WINDOWPOS_UNDEFINED,
|
||||
width, height,
|
||||
SDL_WINDOW_OPENGL
|
||||
);
|
||||
|
||||
this->disp_wnd_id = SDL_GetWindowID(this->display_wnd);
|
||||
|
||||
if (this->display_wnd == NULL) {
|
||||
ABORT_F("Display: SDL_CreateWindow failed with %s", SDL_GetError());
|
||||
}
|
||||
|
||||
this->renderer = SDL_CreateRenderer(this->display_wnd, -1, SDL_RENDERER_ACCELERATED);
|
||||
if (this->renderer == NULL) {
|
||||
ABORT_F("Display: SDL_CreateRenderer failed with %s", SDL_GetError());
|
||||
}
|
||||
|
||||
this->blank_on = true; // TODO: should be true!
|
||||
|
||||
this->blank_display();
|
||||
} else { // resize display window
|
||||
SDL_SetWindowSize(this->display_wnd, width, height);
|
||||
this->resizing = true;
|
||||
}
|
||||
|
||||
this->active_width = width;
|
||||
this->active_height = height;
|
||||
|
||||
if (this->disp_texture) {
|
||||
SDL_DestroyTexture(this->disp_texture);
|
||||
}
|
||||
|
||||
this->disp_texture = SDL_CreateTexture(
|
||||
this->renderer,
|
||||
SDL_PIXELFORMAT_ARGB8888,
|
||||
SDL_TEXTUREACCESS_STREAMING,
|
||||
width, height
|
||||
);
|
||||
|
||||
if (this->disp_texture == NULL) {
|
||||
ABORT_F("Display: SDL_CreateTexture failed with %s", SDL_GetError());
|
||||
}
|
||||
}
|
||||
|
||||
void VideoCtrlBase::blank_display() {
|
||||
SDL_SetRenderDrawColor(this->renderer, 0, 0, 0, 255);
|
||||
SDL_RenderClear(this->renderer);
|
||||
SDL_RenderPresent(this->renderer);
|
||||
}
|
||||
|
||||
void VideoCtrlBase::update_screen()
|
||||
{
|
||||
uint8_t* dst_buf;
|
||||
@ -99,6 +120,14 @@ void VideoCtrlBase::update_screen()
|
||||
|
||||
//auto start_time = std::chrono::steady_clock::now();
|
||||
|
||||
if (this->resizing)
|
||||
return;
|
||||
|
||||
if (this->blank_on) {
|
||||
this->blank_display();
|
||||
return;
|
||||
}
|
||||
|
||||
SDL_LockTexture(this->disp_texture, NULL, (void **)&dst_buf, &dst_pitch);
|
||||
|
||||
// texture update callback to get ARGB data from guest framebuffer
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
DingusPPC - The Experimental PowerPC Macintosh emulator
|
||||
Copyright (C) 2018-21 divingkatae and maximum
|
||||
Copyright (C) 2018-23 divingkatae and maximum
|
||||
(theweirdo) spatium
|
||||
|
||||
(Contact divingkatae#1017 or powermax#2286 on Discord for more info)
|
||||
@ -34,6 +34,8 @@ public:
|
||||
VideoCtrlBase(int width = 640, int height = 480);
|
||||
~VideoCtrlBase();
|
||||
|
||||
void create_display_window(int width, int height);
|
||||
void blank_display();
|
||||
void update_screen(void);
|
||||
|
||||
void get_palette_colors(uint8_t index, uint8_t& r, uint8_t& g, uint8_t& b,
|
||||
@ -45,10 +47,14 @@ public:
|
||||
virtual void convert_frame_8bpp(uint8_t *dst_buf, int dst_pitch);
|
||||
|
||||
protected:
|
||||
/* CRT controller parameters */
|
||||
// CRT controller parameters
|
||||
bool crtc_on = false;
|
||||
bool blank_on = true;
|
||||
bool resizing = false;
|
||||
int active_width; // width of the visible display area
|
||||
int active_height; // height of the visible display area
|
||||
int hori_total;
|
||||
int vert_total;
|
||||
int pixel_depth;
|
||||
float pixel_clock;
|
||||
float refresh_rate;
|
||||
@ -58,13 +64,15 @@ protected:
|
||||
// Framebuffer parameters
|
||||
uint8_t* fb_ptr;
|
||||
int fb_pitch;
|
||||
uint32_t refresh_task_id = 0;
|
||||
|
||||
std::function<void(uint8_t *dst_buf, int dst_pitch)> convert_fb_cb;
|
||||
|
||||
private:
|
||||
SDL_Window *display_wnd;
|
||||
SDL_Renderer *renderer;
|
||||
SDL_Texture *disp_texture;
|
||||
uint32_t disp_wnd_id = 0;
|
||||
SDL_Window* display_wnd = 0;
|
||||
SDL_Renderer* renderer = 0;
|
||||
SDL_Texture* disp_texture = 0;
|
||||
};
|
||||
|
||||
#endif // VIDEO_CTRL_H
|
||||
|
Loading…
x
Reference in New Issue
Block a user