WinUAE/od-win32/win32gfx.cpp

4397 lines
134 KiB
C++

/*
/*
* UAE - The Un*x Amiga Emulator
*
* Win32 Drawing and DirectX interface
*
* Copyright 1997-1998 Mathias Ortmann
* Copyright 1997-2000 Brian King
*/
#define FORCE16BIT 0
#include "sysconfig.h"
#include <stdlib.h>
#include <stdarg.h>
#include <windows.h>
#include <commctrl.h>
#include <shellapi.h>
#include <dwmapi.h>
#include <D3dkmthk.h>
#include <process.h>
#include "sysdeps.h"
#include "resource.h"
#include "options.h"
#include "audio.h"
#include "uae.h"
#include "memory.h"
#include "custom.h"
#include "events.h"
#include "newcpu.h"
#include "traps.h"
#include "xwin.h"
#include "keyboard.h"
#include "drawing.h"
#include "render.h"
#include "picasso96_win.h"
#include "registry.h"
#include "win32.h"
#include "win32gfx.h"
#include "win32gui.h"
#include "sound.h"
#include "inputdevice.h"
#include "direct3d.h"
#include "midi.h"
#include "gui.h"
#include "serial.h"
#include "avioutput.h"
#include "gfxfilter.h"
#include "parser.h"
#include "lcd.h"
#include "sampler.h"
#include "gfxboard.h"
#include "cpuboard.h"
#include "x86.h"
#ifdef RETROPLATFORM
#include "rp.h"
#endif
#include "statusline.h"
#include "devices.h"
#ifdef WITH_MIDIEMU
#include "midiemu.h"
#endif
#include "darkmode.h"
#define DM_DX_FULLSCREEN 1
#define DM_W_FULLSCREEN 2
#define DM_D3D_FULLSCREEN 16
#define DM_PICASSO96 32
#define DM_D3D 256
#define DM_SWSCALE 1024
#define SM_WINDOW 0
#define SM_FULLSCREEN_DX 2
#define SM_D3D_WINDOW 5
#define SM_D3D_FULLWINDOW 10
#define SM_D3D_FULLSCREEN_DX 6
#define SM_FULLWINDOW 7
#define SM_NONE 11
static int deskhz;
struct MultiDisplay Displays[MAX_DISPLAYS + 1];
struct AmigaMonitor AMonitors[MAX_AMIGAMONITORS];
struct AmigaMonitor *amon = NULL;
static int display_change_requested;
int window_led_drives, window_led_drives_end;
int window_led_hd, window_led_hd_end;
int window_led_joys, window_led_joys_end, window_led_joy_start;
int window_led_msg, window_led_msg_end, window_led_msg_start;
extern int console_logging;
static int wasfullwindow_a, wasfullwindow_p;
int vsync_modechangetimeout = 10;
int vsync_activeheight, vsync_totalheight;
float vsync_vblank, vsync_hblank;
bool beamracer_debug;
bool gfx_hdr;
int reopen(struct AmigaMonitor *, int, bool);
static CRITICAL_SECTION screen_cs;
static bool screen_cs_allocated;
void gfx_lock (void)
{
EnterCriticalSection (&screen_cs);
}
void gfx_unlock (void)
{
LeaveCriticalSection (&screen_cs);
}
int WIN32GFX_IsPicassoScreen(struct AmigaMonitor *mon)
{
return mon->screen_is_picasso ? 1 : 0;
}
static int isscreen(struct AmigaMonitor *mon)
{
return mon->hMainWnd ? 1 : 0;
}
static int isfullscreen_2(struct uae_prefs *p)
{
struct AmigaMonitor *mon = &AMonitors[0];
int idx = mon->screen_is_picasso ? 1 : 0;
return p->gfx_apmode[idx].gfx_fullscreen == GFX_FULLSCREEN ? 1 : (p->gfx_apmode[idx].gfx_fullscreen == GFX_FULLWINDOW ? -1 : 0);
}
int isfullscreen(void)
{
return isfullscreen_2(&currprefs);
}
int WIN32GFX_GetDepth(struct AmigaMonitor *mon, int real)
{
if (!mon->currentmode.native_depth)
return mon->currentmode.current_depth;
return real ? mon->currentmode.native_depth : mon->currentmode.current_depth;
}
int WIN32GFX_GetWidth(struct AmigaMonitor *mon)
{
return mon->currentmode.current_width;
}
int WIN32GFX_GetHeight(struct AmigaMonitor *mon)
{
return mon->currentmode.current_height;
}
static BOOL doInit (struct AmigaMonitor*);
int default_freq = 60;
static uae_u8 *scrlinebuf;
static struct MultiDisplay *getdisplay2(struct uae_prefs *p, int index)
{
struct AmigaMonitor *mon = &AMonitors[0];
static int max;
int display = index < 0 ? p->gfx_apmode[mon->screen_is_picasso ? APMODE_RTG : APMODE_NATIVE].gfx_display - 1 : index;
if (!max || (max > 0 && Displays[max].monitorname != NULL)) {
max = 0;
while (Displays[max].monitorname)
max++;
if (max == 0) {
gui_message(_T("no display adapters! Exiting"));
exit(0);
}
}
if (index >= 0 && display >= max)
return NULL;
if (display >= max)
display = 0;
if (display < 0)
display = 0;
return &Displays[display];
}
struct MultiDisplay *getdisplay(struct uae_prefs *p, int monid)
{
struct AmigaMonitor *mon = &AMonitors[monid];
if (monid > 0 && mon->md)
return mon->md;
return getdisplay2(p, -1);
}
void desktop_coords(int monid, int *dw, int *dh, int *ax, int *ay, int *aw, int *ah)
{
struct AmigaMonitor *mon = &AMonitors[monid];
struct MultiDisplay *md = getdisplay(&currprefs, monid);
*dw = md->rect.right - md->rect.left;
*dh = md->rect.bottom - md->rect.top;
*ax = mon->amigawin_rect.left;
*ay = mon->amigawin_rect.top;
*aw = mon->amigawin_rect.right - *ax;
*ah = mon->amigawin_rect.bottom - *ay;
}
static int target_get_display2(const TCHAR *name, int mode)
{
int found, found2;
found = -1;
found2 = -1;
for (int i = 0; Displays[i].monitorname; i++) {
struct MultiDisplay *md = &Displays[i];
if (mode == 1 && md->monitorid[0] == '\\')
continue;
if (mode == 2 && md->monitorid[0] != '\\')
continue;
if (!_tcscmp (md->monitorid, name)) {
if (found < 0) {
found = i + 1;
} else {
found2 = found;
found = -1;
break;
}
}
}
if (found >= 0)
return found;
found = -1;
for (int i = 0; Displays[i].monitorname; i++) {
struct MultiDisplay *md = &Displays[i];
if (mode == 1 && md->adapterid[0] == '\\')
continue;
if (mode == 2 && md->adapterid[0] != '\\')
continue;
if (!_tcscmp (md->adapterid, name)) {
if (found < 0) {
found = i + 1;
} else {
if (found2 < 0)
found2 = found;
found = -1;
break;
}
}
}
if (found >= 0)
return found;
for (int i = 0; Displays[i].monitorname; i++) {
struct MultiDisplay *md = &Displays[i];
if (mode == 1 && md->adaptername[0] == '\\')
continue;
if (mode == 2 && md->adaptername[0] != '\\')
continue;
if (!_tcscmp (md->adaptername, name)) {
if (found < 0) {
found = i + 1;
} else {
if (found2 < 0)
found2 = found;
found = -1;
break;
}
}
}
if (found >= 0)
return found;
for (int i = 0; Displays[i].monitorname; i++) {
struct MultiDisplay *md = &Displays[i];
if (mode == 1 && md->monitorname[0] == '\\')
continue;
if (mode == 2 && md->monitorname[0] != '\\')
continue;
if (!_tcscmp (md->monitorname, name)) {
if (found < 0) {
found = i + 1;
} else {
if (found2 < 0)
found2 = found;
found = -1;
break;
}
}
}
if (found >= 0)
return found;
if (mode == 3) {
if (found2 >= 0)
return found2;
}
return -1;
}
int target_get_display(const TCHAR *name)
{
int disp;
//write_log(_T("target_get_display '%s'\n"), name);
disp = target_get_display2(name, 0);
//write_log(_T("Scan 0: %d\n"), disp);
if (disp >= 0)
return disp;
disp = target_get_display2(name, 1);
//write_log(_T("Scan 1: %d\n"), disp);
if (disp >= 0)
return disp;
disp = target_get_display2(name, 2);
//write_log(_T("Scan 2: %d\n"), disp);
if (disp >= 0)
return disp;
disp = target_get_display2(name, 3);
//write_log(_T("Scan 3: %d\n"), disp);
if (disp >= 0)
return disp;
return -1;
}
static volatile int waitvblankthread_mode;
HANDLE waitvblankevent;
static frame_time_t wait_vblank_timestamp;
static MultiDisplay *wait_vblank_display;
static volatile bool vsync_active;
static bool scanlinecalibrating;
typedef NTSTATUS(CALLBACK* D3DKMTOPENADAPTERFROMHDC)(D3DKMT_OPENADAPTERFROMHDC*);
static D3DKMTOPENADAPTERFROMHDC pD3DKMTOpenAdapterFromHdc;
typedef NTSTATUS(CALLBACK* D3DKMTGETSCANLINE)(D3DKMT_GETSCANLINE*);
static D3DKMTGETSCANLINE pD3DKMTGetScanLine;
typedef NTSTATUS(CALLBACK* D3DKMTWAITFORVERTICALBLANKEVENT)(const D3DKMT_WAITFORVERTICALBLANKEVENT*);
static D3DKMTWAITFORVERTICALBLANKEVENT pD3DKMTWaitForVerticalBlankEvent;
#define STATUS_SUCCESS ((NTSTATUS)0)
static int target_get_display_scanline2(int displayindex)
{
if (pD3DKMTGetScanLine) {
D3DKMT_GETSCANLINE sl = { 0 };
struct MultiDisplay *md = displayindex < 0 ? getdisplay(&currprefs, 0) : &Displays[displayindex];
if (!md->HasAdapterData)
return -11;
sl.VidPnSourceId = md->VidPnSourceId;
sl.hAdapter = md->AdapterHandle;
NTSTATUS status = pD3DKMTGetScanLine(&sl);
if (status == STATUS_SUCCESS) {
if (sl.InVerticalBlank)
return -1;
return sl.ScanLine;
} else {
if ((int)status > 0)
return -(int)status;
return status;
}
return -12;
} else if (D3D_getscanline) {
int scanline;
bool invblank;
if (D3D_getscanline(&scanline, &invblank)) {
if (invblank)
return -1;
return scanline;
}
return -14;
}
return -13;
}
extern uae_s64 spincount;
bool calculated_scanline = true;
int target_get_display_scanline(int displayindex)
{
if (!scanlinecalibrating && calculated_scanline) {
static int lastline;
float diff = (float)(read_processor_time() - wait_vblank_timestamp);
if (diff < 0)
return -1;
int sl = (int)(diff * (vsync_activeheight + (vsync_totalheight - vsync_activeheight) / 10) * vsync_vblank / syncbase);
if (sl < 0)
sl = -1;
return sl;
} else {
static uae_s64 lastrdtsc;
static int lastvpos;
if (spincount == 0 || currprefs.m68k_speed >= 0) {
lastrdtsc = 0;
lastvpos = target_get_display_scanline2(displayindex);
return lastvpos;
}
uae_s64 v = read_processor_time_rdtsc();
if (lastrdtsc > v)
return lastvpos;
lastvpos = target_get_display_scanline2(displayindex);
lastrdtsc = read_processor_time_rdtsc() + spincount * 4;
return lastvpos;
}
}
typedef LONG(CALLBACK* QUERYDISPLAYCONFIG)(UINT32, UINT32*, DISPLAYCONFIG_PATH_INFO*, UINT32*, DISPLAYCONFIG_MODE_INFO*, DISPLAYCONFIG_TOPOLOGY_ID*);
typedef LONG(CALLBACK* GETDISPLAYCONFIGBUFFERSIZES)(UINT32, UINT32*, UINT32*);
typedef LONG(CALLBACK* DISPLAYCONFIGGETDEVICEINFO)(DISPLAYCONFIG_DEVICE_INFO_HEADER*);
static bool get_display_vblank_params(int displayindex, int *activeheightp, int *totalheightp, float *vblankp, float *hblankp)
{
static QUERYDISPLAYCONFIG pQueryDisplayConfig;
static GETDISPLAYCONFIGBUFFERSIZES pGetDisplayConfigBufferSizes;
static DISPLAYCONFIGGETDEVICEINFO pDisplayConfigGetDeviceInfo;
if (!pQueryDisplayConfig)
pQueryDisplayConfig = (QUERYDISPLAYCONFIG)GetProcAddress(userdll, "QueryDisplayConfig");
if (!pGetDisplayConfigBufferSizes)
pGetDisplayConfigBufferSizes = (GETDISPLAYCONFIGBUFFERSIZES)GetProcAddress(userdll, "GetDisplayConfigBufferSizes");
if (!pDisplayConfigGetDeviceInfo)
pDisplayConfigGetDeviceInfo = (DISPLAYCONFIGGETDEVICEINFO)GetProcAddress(userdll, "DisplayConfigGetDeviceInfo");
if (!pQueryDisplayConfig || !pGetDisplayConfigBufferSizes || !pDisplayConfigGetDeviceInfo)
return false;
struct MultiDisplay *md = displayindex < 0 ? getdisplay(&currprefs, 0) : &Displays[displayindex];
UINT32 pathCount, modeCount;
bool ret = false;
if (pGetDisplayConfigBufferSizes(QDC_ONLY_ACTIVE_PATHS, &pathCount, &modeCount) == ERROR_SUCCESS) {
DISPLAYCONFIG_PATH_INFO *displayPaths;
DISPLAYCONFIG_MODE_INFO *displayModes;
displayPaths = xmalloc(DISPLAYCONFIG_PATH_INFO, pathCount);
displayModes = xmalloc(DISPLAYCONFIG_MODE_INFO, modeCount);
if (pQueryDisplayConfig(QDC_ONLY_ACTIVE_PATHS, &pathCount, displayPaths, &modeCount, displayModes, NULL) == ERROR_SUCCESS) {
for (int i = 0; i < pathCount; i++) {
DISPLAYCONFIG_PATH_INFO *path = &displayPaths[i];
DISPLAYCONFIG_MODE_INFO *target = &displayModes[path->targetInfo.modeInfoIdx];
DISPLAYCONFIG_MODE_INFO *source = &displayModes[path->sourceInfo.modeInfoIdx];
DISPLAYCONFIG_SOURCE_DEVICE_NAME dcsdn;
DISPLAYCONFIG_DEVICE_INFO_HEADER *dcdih = &dcsdn.header;
dcdih->size = sizeof dcsdn;
dcdih->adapterId = source->adapterId;
dcdih->id = source->id;
dcdih->type = DISPLAYCONFIG_DEVICE_INFO_GET_SOURCE_NAME;
if (pDisplayConfigGetDeviceInfo(dcdih) == ERROR_SUCCESS) {
if (!_tcscmp(md->adapterid, dcsdn.viewGdiDeviceName)) {
DISPLAYCONFIG_VIDEO_SIGNAL_INFO *si = &target->targetMode.targetVideoSignalInfo;
if (activeheightp)
*activeheightp = si->activeSize.cy;
if (totalheightp)
*totalheightp = si->totalSize.cy;
float vblank = (float)si->vSyncFreq.Numerator / si->vSyncFreq.Denominator;
float hblank = (float)si->hSyncFreq.Numerator / si->hSyncFreq.Denominator;
if (vblankp)
*vblankp = vblank;
if (hblankp)
*hblankp = hblank;
write_log(_T("ActiveHeight: %d TotalHeight: %d VFreq=%d/%d=%.2fHz HFreq=%d/%d=%.3fKHz\n"),
target->targetMode.targetVideoSignalInfo.activeSize.cy,
target->targetMode.targetVideoSignalInfo.totalSize.cy,
target->targetMode.targetVideoSignalInfo.vSyncFreq.Numerator,
target->targetMode.targetVideoSignalInfo.vSyncFreq.Denominator,
vblank,
target->targetMode.targetVideoSignalInfo.hSyncFreq.Numerator,
target->targetMode.targetVideoSignalInfo.hSyncFreq.Denominator,
hblank / 1000.0);
ret = true;
break;
}
}
}
}
xfree(displayModes);
xfree(displayPaths);
}
return ret;
}
static unsigned int __stdcall waitvblankthread(void *dummy)
{
waitvblankthread_mode = 2;
SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_ABOVE_NORMAL);
while (waitvblankthread_mode) {
D3DKMT_WAITFORVERTICALBLANKEVENT e = { 0 };
e.hAdapter = wait_vblank_display->AdapterHandle;
e.VidPnSourceId = wait_vblank_display->VidPnSourceId;
pD3DKMTWaitForVerticalBlankEvent(&e);
wait_vblank_timestamp = read_processor_time();
vsync_active = true;
SetEvent(waitvblankevent);
}
waitvblankthread_mode = -1;
return 0;
}
static void display_vblank_thread_kill(void)
{
if (waitvblankthread_mode == 2) {
waitvblankthread_mode = 0;
while (waitvblankthread_mode != -1) {
Sleep(10);
}
waitvblankthread_mode = 0;
CloseHandle(waitvblankevent);
waitvblankevent = NULL;
}
}
static void display_vblank_thread(struct AmigaMonitor *mon)
{
struct amigadisplay *ad = &adisplays[mon->monitor_id];
struct apmode *ap = ad->picasso_on ? &currprefs.gfx_apmode[1] : &currprefs.gfx_apmode[0];
if (waitvblankthread_mode > 0)
return;
// It seems some Windows 7 drivers stall if D3DKMTWaitForVerticalBlankEvent()
// and D3DKMTGetScanLine() is used simultaneously.
if ((calculated_scanline || os_win8) && ap->gfx_vsyncmode && pD3DKMTWaitForVerticalBlankEvent && wait_vblank_display && wait_vblank_display->HasAdapterData) {
waitvblankevent = CreateEvent(NULL, FALSE, FALSE, NULL);
waitvblankthread_mode = 1;
unsigned int th;
_beginthreadex(NULL, 0, waitvblankthread, 0, 0, &th);
} else {
calculated_scanline = false;
}
}
void target_cpu_speed(void)
{
display_vblank_thread(&AMonitors[0]);
}
extern void target_calibrate_spin(void);
static void display_param_init(struct AmigaMonitor *mon)
{
struct amigadisplay *ad = &adisplays[mon->monitor_id];
struct apmode *ap = ad->picasso_on ? &currprefs.gfx_apmode[1] : &currprefs.gfx_apmode[0];
vsync_activeheight = mon->currentmode.current_height;
vsync_totalheight = vsync_activeheight * 1125 / 1080;
vsync_vblank = 0;
vsync_hblank = 0;
get_display_vblank_params(-1, &vsync_activeheight, &vsync_totalheight, &vsync_vblank, &vsync_hblank);
if (vsync_vblank <= 0)
vsync_vblank = (float)mon->currentmode.freq;
// GPU scaled mode?
if (vsync_activeheight > mon->currentmode.current_height) {
float m = (float)vsync_activeheight / mon->currentmode.current_height;
vsync_hblank = vsync_hblank / m + 0.5f;
vsync_activeheight = mon->currentmode.current_height;
}
wait_vblank_display = getdisplay(&currprefs, mon->monitor_id);
if (!wait_vblank_display || !wait_vblank_display->HasAdapterData) {
write_log(_T("Selected display mode does not have adapter data!\n"));
}
Sleep(10);
scanlinecalibrating = true;
target_calibrate_spin();
scanlinecalibrating = false;
display_vblank_thread(mon);
}
const TCHAR *target_get_display_name (int num, bool friendlyname)
{
if (num <= 0)
return NULL;
struct MultiDisplay *md = getdisplay2(NULL, num - 1);
if (!md)
return NULL;
if (friendlyname)
return md->monitorname;
return md->monitorid;
}
void centerdstrect(struct AmigaMonitor *mon, RECT *dr)
{
struct uae_filter *usedfilter = mon->usedfilter;
if(!(mon->currentmode.flags & (DM_DX_FULLSCREEN | DM_D3D_FULLSCREEN | DM_W_FULLSCREEN)))
OffsetRect (dr, mon->amigawin_rect.left, mon->amigawin_rect.top);
if (mon->currentmode.flags & DM_W_FULLSCREEN) {
if (mon->scalepicasso && mon->screen_is_picasso)
return;
if (usedfilter && !mon->screen_is_picasso)
return;
if (mon->currentmode.fullfill && (mon->currentmode.current_width > mon->currentmode.native_width || mon->currentmode.current_height > mon->currentmode.native_height))
return;
OffsetRect (dr, (mon->currentmode.native_width - mon->currentmode.current_width) / 2,
(mon->currentmode.native_height - mon->currentmode.current_height) / 2);
}
}
static int picasso_offset_x, picasso_offset_y;
static float picasso_offset_mx, picasso_offset_my;
void getgfxoffset(int monid, float *dxp, float *dyp, float *mxp, float *myp)
{
struct AmigaMonitor *mon = &AMonitors[monid];
struct amigadisplay *ad = &adisplays[monid];
struct uae_filter *usedfilter = mon->usedfilter;
float dx, dy, mx, my;
getfilteroffset(monid, &dx, &dy, &mx, &my);
if (ad->picasso_on) {
dx = picasso_offset_x * picasso_offset_mx;
dy = picasso_offset_y * picasso_offset_my;
mx = picasso_offset_mx;
my = picasso_offset_my;
}
//write_log(_T("%.2fx%.2f %.2fx%.2f\n"), dx, dy, mx, my);
if (mon->currentmode.flags & DM_W_FULLSCREEN) {
for (;;) {
if (mon->scalepicasso && mon->screen_is_picasso)
break;
if (usedfilter && !mon->screen_is_picasso)
break;
if (mon->currentmode.fullfill && (mon->currentmode.current_width > mon->currentmode.native_width || mon->currentmode.current_height > mon->currentmode.native_height))
break;
dx += (mon->currentmode.native_width - mon->currentmode.current_width) / 2;
dy += (mon->currentmode.native_height - mon->currentmode.current_height) / 2;
break;
}
}
*dxp = dx;
*dyp = dy;
*mxp = 1.0f / mx;
*myp = 1.0f / my;
}
static int rgbformat_bits (RGBFTYPE t)
{
unsigned long f = 1 << t;
return ((f & RGBMASK_8BIT) != 0 ? 8
: (f & RGBMASK_15BIT) != 0 ? 15
: (f & RGBMASK_16BIT) != 0 ? 16
: (f & RGBMASK_24BIT) != 0 ? 24
: (f & RGBMASK_32BIT) != 0 ? 32
: 0);
}
int getrefreshrate(int monid, int width, int height)
{
struct amigadisplay *ad = &adisplays[monid];
struct apmode *ap = ad->picasso_on ? &currprefs.gfx_apmode[APMODE_RTG] : &currprefs.gfx_apmode[APMODE_NATIVE];
int freq = 0;
if (ap->gfx_refreshrate <= 0)
return 0;
struct MultiDisplay *md = getdisplay(&currprefs, monid);
for (int i = 0; md->DisplayModes[i].depth >= 0; i++) {
struct PicassoResolution *pr = &md->DisplayModes[i];
if (pr->res.width == width && pr->res.height == height) {
for (int j = 0; pr->refresh[j] > 0; j++) {
if (pr->refresh[j] == ap->gfx_refreshrate)
return ap->gfx_refreshrate;
if (pr->refresh[j] > freq && pr->refresh[j] < ap->gfx_refreshrate)
freq = pr->refresh[j];
}
}
}
write_log (_T("Refresh rate %d not supported, using %d\n"), ap->gfx_refreshrate, freq);
return freq;
}
static void addmode (struct MultiDisplay *md, DEVMODE *dm, int rawmode)
{
int ct;
int i, j;
int w = dm->dmPelsWidth;
int h = dm->dmPelsHeight;
int d = dm->dmBitsPerPel;
bool lace = false;
int freq = 0;
if (w > max_uae_width || h > max_uae_height) {
write_log (_T("Ignored mode %d*%d\n"), w, h);
return;
}
if (dm->dmFields & DM_DISPLAYFREQUENCY) {
freq = dm->dmDisplayFrequency;
if (freq < 10)
freq = 0;
}
if (dm->dmFields & DM_DISPLAYFLAGS) {
lace = (dm->dmDisplayFlags & DM_INTERLACED) != 0;
}
ct = 0;
if (d == 8)
ct = RGBMASK_8BIT;
if (d == 15)
ct = RGBMASK_15BIT;
if (d == 16)
ct = RGBMASK_16BIT;
if (d == 24)
ct = RGBMASK_24BIT;
if (d == 32)
ct = RGBMASK_32BIT;
if (ct == 0)
return;
d /= 8;
i = 0;
while (md->DisplayModes[i].depth >= 0) {
if (md->DisplayModes[i].depth == d && md->DisplayModes[i].res.width == w && md->DisplayModes[i].res.height == h) {
for (j = 0; j < MAX_REFRESH_RATES; j++) {
if (md->DisplayModes[i].refresh[j] == 0 || md->DisplayModes[i].refresh[j] == freq)
break;
}
if (j < MAX_REFRESH_RATES) {
md->DisplayModes[i].refresh[j] = freq;
md->DisplayModes[i].refreshtype[j] = (lace ? REFRESH_RATE_LACE : 0) | (rawmode ? REFRESH_RATE_RAW : 0);
md->DisplayModes[i].refresh[j + 1] = 0;
if (!lace)
md->DisplayModes[i].lace = false;
return;
}
}
i++;
}
i = 0;
while (md->DisplayModes[i].depth >= 0)
i++;
if (i >= MAX_PICASSO_MODES - 1)
return;
md->DisplayModes[i].rawmode = rawmode;
md->DisplayModes[i].lace = lace;
md->DisplayModes[i].res.width = w;
md->DisplayModes[i].res.height = h;
md->DisplayModes[i].depth = d;
md->DisplayModes[i].refresh[0] = freq;
md->DisplayModes[i].refreshtype[0] = (lace ? REFRESH_RATE_LACE : 0) | (rawmode ? REFRESH_RATE_RAW : 0);
md->DisplayModes[i].refresh[1] = 0;
md->DisplayModes[i].colormodes = ct;
md->DisplayModes[i + 1].depth = -1;
_stprintf (md->DisplayModes[i].name, _T("%dx%d%s, %d-bit"),
md->DisplayModes[i].res.width, md->DisplayModes[i].res.height,
lace ? _T("i") : _T(""),
md->DisplayModes[i].depth * 8);
}
static int _cdecl resolution_compare (const void *a, const void *b)
{
struct PicassoResolution *ma = (struct PicassoResolution *)a;
struct PicassoResolution *mb = (struct PicassoResolution *)b;
if (ma->res.width < mb->res.width)
return -1;
if (ma->res.width > mb->res.width)
return 1;
if (ma->res.height < mb->res.height)
return -1;
if (ma->res.height > mb->res.height)
return 1;
return ma->depth - mb->depth;
}
static void sortmodes (struct MultiDisplay *md)
{
int i, idx = -1;
int pw = -1, ph = -1;
i = 0;
while (md->DisplayModes[i].depth >= 0)
i++;
qsort (md->DisplayModes, i, sizeof (struct PicassoResolution), resolution_compare);
for (i = 0; md->DisplayModes[i].depth >= 0; i++) {
int j, k;
for (j = 0; md->DisplayModes[i].refresh[j]; j++) {
for (k = j + 1; md->DisplayModes[i].refresh[k]; k++) {
if (md->DisplayModes[i].refresh[j] > md->DisplayModes[i].refresh[k]) {
int t = md->DisplayModes[i].refresh[j];
md->DisplayModes[i].refresh[j] = md->DisplayModes[i].refresh[k];
md->DisplayModes[i].refresh[k] = t;
t = md->DisplayModes[i].refreshtype[j];
md->DisplayModes[i].refreshtype[j] = md->DisplayModes[i].refreshtype[k];
md->DisplayModes[i].refreshtype[k] = t;
}
}
}
if (md->DisplayModes[i].res.height != ph || md->DisplayModes[i].res.width != pw) {
ph = md->DisplayModes[i].res.height;
pw = md->DisplayModes[i].res.width;
idx++;
}
md->DisplayModes[i].residx = idx;
}
}
#if 0
static void sortmonitors (void)
{
for (int i = 0; Displays[i].monitorid; i++) {
for (int j = i + 1; Displays[j].monitorid; j++) {
int comp = (Displays[j].primary ? 1 : 0) - (Displays[i].primary ? 1 : 0);
if (!comp)
comp = _tcsicmp (Displays[i].adapterid, Displays[j].adapterid);
if (comp > 0) {
struct MultiDisplay md;
memcpy (&md, &Displays[i], sizeof MultiDisplay);
memcpy (&Displays[i], &Displays[j], sizeof MultiDisplay);
memcpy (&Displays[j], &md, sizeof MultiDisplay);
}
}
}
}
#endif
static void modesList (struct MultiDisplay *md)
{
int i, j;
i = 0;
while (md->DisplayModes[i].depth >= 0) {
write_log (_T("%d: %s%s ("), i, md->DisplayModes[i].rawmode ? _T("!") : _T(""), md->DisplayModes[i].name);
j = 0;
while (md->DisplayModes[i].refresh[j] > 0) {
if (j > 0)
write_log (_T(","));
if (md->DisplayModes[i].refreshtype[j] & REFRESH_RATE_RAW)
write_log (_T("!"));
write_log (_T("%d"), md->DisplayModes[i].refresh[j]);
if (md->DisplayModes[i].refreshtype[j] & REFRESH_RATE_LACE)
write_log (_T("i"));
j++;
}
write_log (_T(")\n"));
i++;
}
}
static void adjustappbar(RECT *monitor, RECT *workrect)
{
APPBARDATA abd;
// Isn't this ugly API?
for (int i = 0; i < 4; i++) {
abd.cbSize = sizeof abd;
abd.rc = *monitor;
abd.uEdge = i; // ABE_LEFT, TOP, RIGHT, BOTTOM
HWND hwndAutoHide = (HWND) SHAppBarMessage(ABM_GETAUTOHIDEBAREX, &abd);
if (hwndAutoHide == NULL)
continue;
WINDOWINFO wi;
wi.cbSize = sizeof wi;
if (!GetWindowInfo(hwndAutoHide, &wi))
continue;
int edge;
switch (i)
{
case ABE_LEFT:
edge = monitor->left + (wi.rcWindow.right - wi.rcWindow.left);
if (edge > workrect->left && edge < workrect->right)
workrect->left = edge;
break;
case ABE_RIGHT:
edge = monitor->right - (wi.rcWindow.right - wi.rcWindow.left);
if (edge < workrect->right && edge > workrect->left)
workrect->right = edge;
break;
case ABE_TOP:
edge = monitor->top + (wi.rcWindow.bottom - wi.rcWindow.top);
if (edge > workrect->top && edge < workrect->bottom)
workrect->top = edge;
break;
case ABE_BOTTOM:
edge = monitor->bottom - (wi.rcWindow.bottom - wi.rcWindow.top);
if (edge < workrect->bottom && edge > workrect->top)
workrect->bottom = edge;
break;
}
}
}
static BOOL CALLBACK monitorEnumProc (HMONITOR h, HDC hdc, LPRECT rect, LPARAM data)
{
struct MultiDisplay *md = Displays;
MONITORINFOEX lpmi;
lpmi.cbSize = sizeof lpmi;
GetMonitorInfo(h, (LPMONITORINFO)&lpmi);
while (md - Displays < MAX_DISPLAYS && md->monitorid) {
if (!_tcscmp (md->adapterid, lpmi.szDevice)) {
TCHAR tmp[1000];
md->monitor = h;
md->rect = lpmi.rcMonitor;
md->workrect = lpmi.rcWork;
adjustappbar(&md->rect, &md->workrect);
if (md->rect.left == 0 && md->rect.top == 0)
_stprintf (tmp, _T("%s (%d*%d)"), md->monitorname, md->rect.right - md->rect.left, md->rect.bottom - md->rect.top);
else
_stprintf (tmp, _T("%s (%d*%d) [%d*%d]"), md->monitorname, md->rect.right - md->rect.left, md->rect.bottom - md->rect.top, md->rect.left, md->rect.top);
if (md->primary)
_tcscat (tmp, _T(" *"));
xfree (md->fullname);
md->fullname = my_strdup (tmp);
return TRUE;
}
md++;
}
return TRUE;
}
static BOOL CALLBACK monitorEnumProc2(HMONITOR h, HDC hdc, LPRECT rect, LPARAM data)
{
MONITORINFOEX lpmi;
lpmi.cbSize = sizeof lpmi;
GetMonitorInfo(h, (LPMONITORINFO)&lpmi);
for (int i = 0; i < MAX_DISPLAYS && Displays[i].monitorid; i++) {
struct MultiDisplay *md = &Displays[i];
if (!_tcscmp (md->adapterid, lpmi.szDevice) && !memcmp(&md->rect, &lpmi.rcMonitor, sizeof RECT)) {
md->workrect = lpmi.rcWork;
md->monitor = h;
adjustappbar(&md->rect, &md->workrect);
return TRUE;
}
}
return TRUE;
}
void reenumeratemonitors(void)
{
for (int i = 0; i < MAX_DISPLAYS; i++) {
struct MultiDisplay *md = &Displays[i];
memcpy(&md->workrect, &md->rect, sizeof RECT);
}
EnumDisplayMonitors (NULL, NULL, monitorEnumProc2, NULL);
}
static void getd3dmonitornames (void)
{
// XP does not support hybrid displays, don't load Direct3D
// Windows 10+ seems to use same names by default
if (os_win10)
return;
IDirect3D9 *d3d = Direct3DCreate9 (D3D_SDK_VERSION);
if (!d3d)
return;
int max = d3d->GetAdapterCount ();
struct MultiDisplay* md = Displays;
while (md - Displays < MAX_DISPLAYS && md->monitorid) {
POINT pt;
HMONITOR winmon;
pt.x = (md->rect.right - md->rect.left) / 2 + md->rect.left;
pt.y = (md->rect.bottom - md->rect.top) / 2 + md->rect.top;
winmon = MonitorFromPoint (pt, MONITOR_DEFAULTTONEAREST);
for (int i = 0; i < max; i++) {
D3DADAPTER_IDENTIFIER9 did;
HMONITOR d3dmon = d3d->GetAdapterMonitor (i);
if (d3dmon != winmon)
continue;
if (SUCCEEDED (d3d->GetAdapterIdentifier (i, 0, &did))) {
TCHAR *name = au (did.Description);
my_trim (name);
if (_tcsicmp (name, md->adaptername)) {
write_log (_T("%d: '%s' -> '%s'\n"), i, md->adaptername, name);
xfree (md->adaptername);
md->adaptername = name;
name = NULL;
}
xfree (name);
}
break;
}
md++;
}
d3d->Release ();
}
static bool enumeratedisplays2 (bool selectall)
{
struct MultiDisplay *md = Displays;
int adapterindex = 0;
DISPLAY_DEVICE add;
add.cb = sizeof add;
while (EnumDisplayDevices (NULL, adapterindex, &add, 0)) {
adapterindex++;
if (!selectall) {
if (!(add.StateFlags & DISPLAY_DEVICE_ATTACHED_TO_DESKTOP))
continue;
if (add.StateFlags & DISPLAY_DEVICE_MIRRORING_DRIVER)
continue;
}
if (md - Displays >= MAX_DISPLAYS)
break;
int monitorindex = 0;
DISPLAY_DEVICE mdd;
mdd.cb = sizeof mdd;
while (EnumDisplayDevices (add.DeviceName, monitorindex, &mdd, 0)) {
monitorindex++;
if (md - Displays >= MAX_DISPLAYS)
break;
if (!selectall) {
if (!(mdd.StateFlags & DISPLAY_DEVICE_ATTACHED_TO_DESKTOP))
continue;
if (mdd.StateFlags & DISPLAY_DEVICE_MIRRORING_DRIVER)
continue;
}
md->adaptername = my_strdup_trim (add.DeviceString);
md->adapterid = my_strdup (add.DeviceName);
md->adapterkey = my_strdup (add.DeviceID);
md->monitorname = my_strdup_trim (mdd.DeviceString);
md->monitorid = my_strdup (mdd.DeviceKey);
if (add.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE)
md->primary = true;
if (pD3DKMTOpenAdapterFromHdc) {
HDC hdc = CreateDC(NULL, add.DeviceName, NULL, NULL);
if (hdc != NULL) {
D3DKMT_OPENADAPTERFROMHDC OpenAdapterData = { 0 };
OpenAdapterData.hDc = hdc;
NTSTATUS status = pD3DKMTOpenAdapterFromHdc(&OpenAdapterData);
if (status == STATUS_SUCCESS) {
md->AdapterLuid = OpenAdapterData.AdapterLuid;
md->VidPnSourceId = OpenAdapterData.VidPnSourceId;
md->AdapterHandle = OpenAdapterData.hAdapter;
md->HasAdapterData = true;
}
DeleteDC(hdc);
}
}
md++;
}
if (md - Displays >= MAX_DISPLAYS)
return true;
if (monitorindex == 0) {
md->adaptername = my_strdup_trim (add.DeviceString);
md->adapterid = my_strdup (add.DeviceName);
md->adapterkey = my_strdup (add.DeviceID);
md->monitorname = my_strdup_trim (add.DeviceString);
md->monitorid = my_strdup (add.DeviceKey);
md->primary = true;
md++;
}
}
if (md == Displays)
return false;
EnumDisplayMonitors (NULL, NULL, monitorEnumProc, NULL);
md = Displays;
while (md->monitorname) {
if (!md->fullname)
md->fullname = my_strdup (md->adapterid);
md++;
}
getd3dmonitornames ();
//sortmonitors ();
return true;
}
void enumeratedisplays (void)
{
if (!pD3DKMTWaitForVerticalBlankEvent) {
pD3DKMTOpenAdapterFromHdc = (D3DKMTOPENADAPTERFROMHDC)GetProcAddress(GetModuleHandle(_T("Gdi32.dll")), "D3DKMTOpenAdapterFromHdc");
pD3DKMTGetScanLine = (D3DKMTGETSCANLINE)GetProcAddress(GetModuleHandle(_T("Gdi32.dll")), "D3DKMTGetScanLine");
pD3DKMTWaitForVerticalBlankEvent = (D3DKMTWAITFORVERTICALBLANKEVENT)GetProcAddress(GetModuleHandle(_T("Gdi32.dll")), "D3DKMTWaitForVerticalBlankEvent");
}
if (!enumeratedisplays2 (false))
enumeratedisplays2(true);
}
void sortdisplays (void)
{
struct MultiDisplay *md;
int i, idx;
int w = GetSystemMetrics (SM_CXSCREEN);
int h = GetSystemMetrics (SM_CYSCREEN);
int wv = GetSystemMetrics(SM_CXVIRTUALSCREEN);
int hv = GetSystemMetrics(SM_CYVIRTUALSCREEN);
int b = 0;
deskhz = 0;
HDC hdc = GetDC (NULL);
if (hdc) {
b = GetDeviceCaps(hdc, BITSPIXEL) * GetDeviceCaps(hdc, PLANES);
ReleaseDC (NULL, hdc);
}
md = Displays;
while (md->monitorname) {
md->DisplayModes = xmalloc (struct PicassoResolution, MAX_PICASSO_MODES);
md->DisplayModes[0].depth = -1;
write_log (_T("%s '%s' [%s]\n"), md->adaptername, md->adapterid, md->adapterkey);
write_log (_T("-: %s [%s]\n"), md->fullname, md->monitorid);
for (int mode = 0; mode < 2; mode++) {
DEVMODE dm;
dm.dmSize = sizeof dm;
dm.dmDriverExtra = 0;
idx = 0;
while (EnumDisplaySettingsEx (md->adapterid, idx, &dm, mode ? EDS_RAWMODE : 0)) {
int found = 0;
int idx2 = 0;
while (md->DisplayModes[idx2].depth >= 0 && !found) {
struct PicassoResolution *pr = &md->DisplayModes[idx2];
if (dm.dmPelsWidth == w && dm.dmPelsHeight == h && dm.dmBitsPerPel == b) {
if (dm.dmDisplayFrequency > deskhz)
deskhz = dm.dmDisplayFrequency;
}
if (pr->res.width == dm.dmPelsWidth && pr->res.height == dm.dmPelsHeight && pr->depth == dm.dmBitsPerPel / 8) {
for (i = 0; pr->refresh[i]; i++) {
if (pr->refresh[i] == dm.dmDisplayFrequency) {
found = 1;
break;
}
}
}
idx2++;
}
if (!found && dm.dmBitsPerPel > 8) {
int freq = 0;
#if 0
write_log (_T("EnumDisplaySettings(%dx%dx%d %dHz %08x)\n"),
dm.dmPelsWidth, dm.dmPelsHeight, dm.dmBitsPerPel, dm.dmDisplayFrequency, dm.dmFields);
#endif
if ((dm.dmFields & DM_PELSWIDTH) && (dm.dmFields & DM_PELSHEIGHT) && (dm.dmFields & DM_BITSPERPEL)) {
addmode (md, &dm, mode);
}
}
idx++;
}
}
//dhack();
sortmodes (md);
modesList (md);
i = 0;
while (md->DisplayModes[i].depth > 0)
i++;
write_log (_T("%d display modes.\n"), i);
md++;
}
write_log(_T("Desktop: W=%d H=%d B=%d HZ=%d. CXVS=%d CYVS=%d\n"), w, h, b, deskhz, wv, hv);
}
/* DirectX will fail with "Mode not supported" if we try to switch to a full
* screen mode that doesn't match one of the dimensions we got during enumeration.
* So try to find a best match for the given resolution in our list. */
int WIN32GFX_AdjustScreenmode (struct MultiDisplay *md, int *pwidth, int *pheight, int *ppixbits)
{
struct PicassoResolution *best;
uae_u32 selected_mask = (*ppixbits == 8 ? RGBMASK_8BIT
: *ppixbits == 15 ? RGBMASK_15BIT
: *ppixbits == 16 ? RGBMASK_16BIT
: *ppixbits == 24 ? RGBMASK_24BIT
: RGBMASK_32BIT);
int pass, i = 0, index = 0;
for (pass = 0; pass < 2; pass++) {
struct PicassoResolution *dm;
uae_u32 mask = (pass == 0
? selected_mask
: RGBMASK_8BIT | RGBMASK_15BIT | RGBMASK_16BIT | RGBMASK_24BIT | RGBMASK_32BIT); /* %%% - BERND, were you missing 15-bit here??? */
i = 0;
index = 0;
best = &md->DisplayModes[0];
dm = &md->DisplayModes[1];
while (dm->depth >= 0) {
/* do we already have supported resolution? */
if (dm->res.width == *pwidth && dm->res.height == *pheight && dm->depth == (*ppixbits / 8))
return i;
if ((dm->colormodes & mask) != 0) {
if (dm->res.width <= best->res.width && dm->res.height <= best->res.height
&& dm->res.width >= *pwidth && dm->res.height >= *pheight)
{
best = dm;
index = i;
}
if (dm->res.width >= best->res.width && dm->res.height >= best->res.height
&& dm->res.width <= *pwidth && dm->res.height <= *pheight)
{
best = dm;
index = i;
}
}
dm++;
i++;
}
if (best->res.width == *pwidth && best->res.height == *pheight) {
selected_mask = mask; /* %%% - BERND, I added this - does it make sense? Otherwise, I'd specify a 16-bit display-mode for my
Workbench (using -H 2, but SHOULD have been -H 1), and end up with an 8-bit mode instead*/
break;
}
}
*pwidth = best->res.width;
*pheight = best->res.height;
if (best->colormodes & selected_mask)
return index;
/* Ordering here is done such that 16-bit is preferred, followed by 15-bit, 8-bit, 32-bit and 24-bit */
if (best->colormodes & RGBMASK_16BIT)
*ppixbits = 16;
else if (best->colormodes & RGBMASK_15BIT) /* %%% - BERND, this possibility was missing? */
*ppixbits = 15;
else if (best->colormodes & RGBMASK_8BIT)
*ppixbits = 8;
else if (best->colormodes & RGBMASK_32BIT)
*ppixbits = 32;
else if (best->colormodes & RGBMASK_24BIT)
*ppixbits = 24;
else
index = -1;
return index;
}
#if 0
static int flushymin, flushymax;
#define FLUSH_DIFF 50
static void flushit (struct vidbuffer *vb, int lineno)
{
if (!currprefs.gfx_api)
return;
if (mon->currentmode.flags & DM_SWSCALE)
return;
if (flushymin > lineno) {
if (flushymin - lineno > FLUSH_DIFF && flushymax != 0) {
D3D_flushtexture (flushymin, flushymax);
flushymin = mon->currentmode.amiga_height;
flushymax = 0;
} else {
flushymin = lineno;
}
}
if (flushymax < lineno) {
if (lineno - flushymax > FLUSH_DIFF && flushymax != 0) {
D3D_flushtexture (flushymin, flushymax);
flushymin = mon->currentmode.amiga_height;
flushymax = 0;
} else {
flushymax = lineno;
}
}
}
void flush_line (struct vidbuffer *vb, int lineno)
{
flushit (vb, lineno);
}
void flush_block (struct vidbuffer *vb, int first, int last)
{
flushit (vb, first);
flushit (vb, last);
}
void flush_screen (struct vidbuffer *vb, int a, int b)
{
}
#endif
bool render_screen(int monid, int mode, bool immediate)
{
struct AmigaMonitor *mon = &AMonitors[monid];
struct amigadisplay *ad = &adisplays[monid];
bool v = false;
int cnt;
mon->render_ok = false;
if (ad->picasso_on || monitor_off) {
return mon->render_ok;
}
cnt = 0;
while (mon->wait_render) {
sleep_millis (1);
cnt++;
if (cnt > 500) {
return mon->render_ok;
}
}
// flushymin = 0;
// flushymax = mon->currentmode.amiga_height;
gfx_lock();
if (mon->currentmode.flags & DM_D3D) {
v = D3D_renderframe(monid, mode, immediate);
} else if (mon->currentmode.flags & DM_SWSCALE) {
S2X_render(monid, -1, -1);
v = true;
}
mon->render_ok = v;
gfx_unlock();
return mon->render_ok;
}
bool show_screen_maybe(int monid, bool show)
{
struct AmigaMonitor *mon = &AMonitors[monid];
struct amigadisplay *ad = &adisplays[monid];
struct apmode *ap = ad->picasso_on ? &currprefs.gfx_apmode[1] : &currprefs.gfx_apmode[0];
if (!ap->gfx_vflip || ap->gfx_vsyncmode == 0 || ap->gfx_vsync <= 0) {
if (show)
show_screen(monid, 0);
return false;
}
#if 0
if (ap->gfx_vflip < 0) {
doflipevent ();
return true;
}
#endif
return false;
}
void show_screen_special (void)
{
struct AmigaMonitor *mon = &AMonitors[0];
if (!mon->screen_is_initialized)
return;
if (!D3D_showframe_special)
return;
if (mon->currentmode.flags & DM_D3D) {
gfx_lock();
D3D_showframe_special(0, 1);
gfx_unlock();
}
}
static frame_time_t strobo_time;
static volatile int strobo_active;
static volatile bool strobo_active2;
static void CALLBACK blackinsertion_cb(
UINT uTimerID,
UINT uMsg,
DWORD_PTR dwUser,
DWORD_PTR dw1,
DWORD_PTR dw2
)
{
struct AmigaMonitor *mon = &AMonitors[0];
if (mon->screen_is_initialized) {
if (strobo_active) {
}
while (strobo_active) {
frame_time_t ct = read_processor_time();
frame_time_t diff = strobo_time - ct;
if (diff < -vsynctimebase / 2) {
break;
}
if (diff <= 0) {
if (strobo_active) {
gfx_lock();
D3D_showframe_special(0, 1);
gfx_unlock();
}
break;
}
if (diff > vsynctimebase / 4) {
break;
}
}
}
strobo_active = 0;
}
float target_adjust_vblank_hz(int monid, float hz)
{
struct AmigaMonitor *mon = &AMonitors[monid];
int maxrate;
if (!currprefs.lightboost_strobo)
return hz;
if (isfullscreen() > 0) {
maxrate = mon->currentmode.freq;
} else {
maxrate = deskhz;
}
double nhz = hz * 2.0;
if (nhz >= maxrate - 1 && nhz < maxrate + 1)
hz -= 0.5;
return hz;
}
void show_screen(int monid, int mode)
{
struct AmigaMonitor *mon = &AMonitors[monid];
struct amigadisplay *ad = &adisplays[monid];
strobo_active = false;
strobo_active2 = false;
struct apmode *ap = ad->picasso_on ? &currprefs.gfx_apmode[1] : &currprefs.gfx_apmode[0];
gfx_lock();
if (mode == 2 || mode == 3 || mode == 4) {
if ((mon->currentmode.flags & DM_D3D) && D3D_showframe_special && ap->gfx_strobo) {
if (mode == 4) {
// erase + render
D3D_showframe_special(0, 2);
D3D_showframe_special(0, 1);
} else {
// erase or render
D3D_showframe_special(0, mode == 3 ? 2 : 1);
}
}
gfx_unlock();
return;
}
if (mode >= 0 && !mon->render_ok) {
gfx_unlock();
return;
}
if (mon->currentmode.flags & DM_D3D) {
if (ap->gfx_strobo && currprefs.gfx_variable_sync) {
float vblank = vblank_hz;
int ratio = currprefs.lightboost_strobo_ratio;
int ms = (int)(1000 / vblank);
int waitms = ms * ratio / 100 - 1;
strobo_active = -1;
strobo_time = read_processor_time() + vsynctimebase * ratio / 100;
timeSetEvent(waitms, 0, blackinsertion_cb, NULL, TIME_ONESHOT | TIME_CALLBACK_FUNCTION);
}
#if 0
if (ap->gfx_vsync < 0 && ap->gfx_strobo && currprefs.gfx_api < 2) {
float vblank = vblank_hz;
if (WIN32GFX_IsPicassoScreen(mon)) {
if (currprefs.win32_rtgvblankrate > 0)
vblank = currprefs.win32_rtgvblankrate;
}
bool ok = true;
int ratio = currprefs.lightboost_strobo_ratio;
int ms = (int)(1000 / vblank);
int waitms = ms * ratio / 100 - 1;
int maxrate;
if (isfullscreen() > 0) {
maxrate = mon->currentmode.freq;
} else {
maxrate = deskhz;
}
if (maxrate > 0) {
double rate = vblank * 2.0;
rate *= ratio > 50 ? ratio / 50.0 : 50.0 / ratio;
if (rate > maxrate + 1.0)
ok = false;
}
if (ok) {
strobo_time = read_processor_time() + vsynctimebase * ratio / 100;
strobo_active = true;
timeSetEvent(waitms, 0, blackinsertion_cb, NULL, TIME_ONESHOT | TIME_CALLBACK_FUNCTION);
}
}
#endif
D3D_showframe(monid);
if (monid == 0) {
strobo_active2 = true;
if (strobo_active < 0) {
D3D_showframe_special(0, 2);
}
}
}
gfx_unlock();
mon->render_ok = false;
}
bool lockscr3d(struct vidbuffer *vb)
{
struct AmigaMonitor *mon = &AMonitors[vb->monitor_id];
if (mon->currentmode.flags & DM_D3D) {
if (!(mon->currentmode.flags & DM_SWSCALE)) {
vb->bufmem = D3D_locktexture(vb->monitor_id, &vb->rowbytes, NULL, NULL, false);
if (vb->bufmem)
return true;
}
}
return false;
}
void unlockscr3d(struct vidbuffer *vb)
{
struct AmigaMonitor *mon = &AMonitors[vb->monitor_id];
if (mon->currentmode.flags & DM_D3D) {
if (!(mon->currentmode.flags & DM_SWSCALE)) {
D3D_unlocktexture(vb->monitor_id, -1, -1);
}
}
}
int lockscr(struct vidbuffer *vb, bool fullupdate, bool first, bool skip)
{
struct AmigaMonitor *mon = &AMonitors[vb->monitor_id];
int ret = 0;
if (!isscreen(mon))
return ret;
#if 0
flushymin = mon->currentmode.amiga_height;
flushymax = 0;
#endif
gfx_lock();
ret = 1;
if (mon->currentmode.flags & DM_D3D) {
#ifdef D3D
if (mon->currentmode.flags & DM_SWSCALE) {
ret = 1;
} else {
ret = 0;
vb->bufmem = D3D_locktexture(vb->monitor_id, &vb->rowbytes, NULL, NULL, skip ? -1 : (fullupdate ? 1 : 0));
if (vb->bufmem) {
if (first)
init_row_map();
ret = 1;
}
}
#endif
} else if (mon->currentmode.flags & DM_SWSCALE) {
ret = 1;
}
gfx_unlock();
return ret;
}
void unlockscr(struct vidbuffer *vb, int y_start, int y_end)
{
struct AmigaMonitor *mon = &AMonitors[vb->monitor_id];
gfx_lock();
if (mon->currentmode.flags & DM_D3D) {
if (mon->currentmode.flags & DM_SWSCALE) {
S2X_render(vb->monitor_id, y_start, y_end);
} else {
vb->bufmem = NULL;
}
D3D_unlocktexture(vb->monitor_id, y_start, y_end);
}
gfx_unlock();
}
void flush_clear_screen (struct vidbuffer *vb)
{
if (!vb)
return;
if (lockscr(vb, true, true, false)) {
int y;
for (y = 0; y < vb->height_allocated; y++) {
memset(vb->bufmem + y * vb->rowbytes, 0, vb->width_allocated * vb->pixbytes);
}
unlockscr(vb, -1, -1);
}
}
float filterrectmult(int v1, float v2, int dmode)
{
float v = v1 / v2;
int vv = (int)(v + 0.5f);
if (v > 1.5f && vv * v2 <= v1 && vv * (v2 + vv - 1) >= v1) {
return (float)vv;
}
if (!dmode) {
return v;
}
if (v > 0.2f && v < 0.3f) {
return 0.25f;
}
if (v > 0.4f && v < 0.6f) {
return 0.5f;
}
return (float)(int)(v + 0.5f);
}
void getrtgfilterrect2(int monid, RECT *sr, RECT *dr, RECT *zr, int *mode, int dst_width, int dst_height)
{
struct AmigaMonitor *mon = &AMonitors[monid];
struct amigadisplay *ad = &adisplays[monid];
struct picasso96_state_struct *state = &picasso96_state[monid];
SetRect (sr, 0, 0, mon->currentmode.native_width, mon->currentmode.native_height);
SetRect (dr, 0, 0, state->Width, state->Height);
SetRect (zr, 0, 0, 0, 0);
picasso_offset_x = 0;
picasso_offset_y = 0;
picasso_offset_mx = 1.0;
picasso_offset_my = 1.0;
*mode = 0;
if (!ad->picasso_on)
return;
if (currprefs.gf[GF_RTG].gfx_filter_horiz_zoom_mult > 0) {
picasso_offset_mx *= currprefs.gf[GF_RTG].gfx_filter_horiz_zoom_mult;
}
if (currprefs.gf[GF_RTG].gfx_filter_vert_zoom_mult > 0) {
picasso_offset_my *= currprefs.gf[GF_RTG].gfx_filter_vert_zoom_mult;
}
if (!mon->scalepicasso)
return;
int srcratio, dstratio;
int srcwidth, srcheight;
srcwidth = state->Width;
srcheight = state->Height;
if (!srcwidth || !srcheight)
return;
float mx = (float)mon->currentmode.native_width / srcwidth;
float my = (float)mon->currentmode.native_height / srcheight;
int outwidth;
int outheight;
if (mon->scalepicasso == RTG_MODE_INTEGER_SCALE) {
int divx = mon->currentmode.native_width / srcwidth;
int divy = mon->currentmode.native_height / srcheight;
float mul = (float)(!divx || !divy ? 1 : (divx > divy ? divy : divx));
if (!divx || !divy) {
if ((float)mon->currentmode.native_width / srcwidth <= 0.95f || ((float)mon->currentmode.native_height / srcheight <= 0.95f)) {
mul = 0.5f;
}
if ((float)mon->currentmode.native_width / srcwidth <= 0.45f || ((float)mon->currentmode.native_height / srcheight <= 0.45f)) {
mul = 0.25f;
}
}
SetRect(dr, 0, 0, (int)(mon->currentmode.native_width / mul), (int)(mon->currentmode.native_height / mul));
int xx = (int)((mon->currentmode.native_width / mul - srcwidth) / 2);
int yy = (int)((mon->currentmode.native_height / mul - srcheight) / 2);
picasso_offset_x = -xx;
picasso_offset_y = -yy;
mx = mul;
my = mul;
outwidth = srcwidth;
outheight = srcheight;
*mode = 1;
} else if (mon->scalepicasso == RTG_MODE_CENTER) {
int xx = (mon->currentmode.native_width - srcwidth) / 2;
int yy = (mon->currentmode.native_height - srcheight) / 2;
picasso_offset_x = -xx;
picasso_offset_y = -yy;
SetRect (sr, 0, 0, mon->currentmode.native_width, mon->currentmode.native_height);
SetRect (dr, 0, 0, mon->currentmode.native_width, mon->currentmode.native_height);
outwidth = dr->right - dr->left;
outheight = dr->bottom - dr->top;
mx = my = 1.0;
} else {
if (currprefs.win32_rtgscaleaspectratio < 0) {
// automatic
srcratio = srcwidth * ASPECTMULT / srcheight;
dstratio = mon->currentmode.native_width * ASPECTMULT / mon->currentmode.native_height;
} else if (currprefs.win32_rtgscaleaspectratio == 0) {
// none
srcratio = dstratio = 0;
} else {
// manual
dstratio = (currprefs.win32_rtgscaleaspectratio / ASPECTMULT) * ASPECTMULT / (currprefs.win32_rtgscaleaspectratio & (ASPECTMULT - 1));
srcratio = srcwidth * ASPECTMULT / srcheight;
}
if (srcratio == dstratio) {
SetRect (dr, 0, 0, srcwidth, srcheight);
} else if (srcratio > dstratio) {
int yy = srcheight * srcratio / dstratio;
SetRect (dr, 0, 0, srcwidth, yy);
picasso_offset_y = (state->Height - yy) / 2;
} else {
int xx = srcwidth * dstratio / srcratio;
SetRect (dr, 0, 0, xx, srcheight);
picasso_offset_x = (state->Width - xx) / 2;
}
outwidth = dr->right - dr->left;
outheight = dr->bottom - dr->top;
}
OffsetRect (zr, picasso_offset_x, picasso_offset_y);
picasso_offset_x /= state->HLineDBL;
picasso_offset_y /= state->VLineDBL;
picasso_offset_mx = (float)(srcwidth * mx * state->HLineDBL) / outwidth;
picasso_offset_my = (float)(srcheight * my * state->VLineDBL) / outheight;
}
static uae_u8 *gfx_lock_picasso2(int monid, bool fullupdate)
{
struct picasso_vidbuf_description *vidinfo = &picasso_vidinfo[monid];
uae_u8 *p = D3D_locktexture(monid, &vidinfo->rowbytes, &vidinfo->maxwidth, &vidinfo->maxheight, fullupdate);
return p;
}
uae_u8 *gfx_lock_picasso(int monid, bool fullupdate)
{
struct AmigaMonitor *mon = &AMonitors[monid];
struct picasso_vidbuf_description *vidinfo = &picasso_vidinfo[monid];
static uae_u8 *p;
if (mon->rtg_locked) {
return p;
}
gfx_lock();
p = gfx_lock_picasso2(monid, fullupdate);
if (!p) {
gfx_unlock();
} else {
mon->rtg_locked = true;
}
return p;
}
void gfx_unlock_picasso(int monid, bool dorender)
{
struct AmigaMonitor *mon = &AMonitors[monid];
if (!mon->rtg_locked)
gfx_lock();
mon->rtg_locked = false;
if (dorender) {
if (mon->p96_double_buffer_needs_flushing) {
D3D_flushtexture(monid, mon->p96_double_buffer_first, mon->p96_double_buffer_last);
mon->p96_double_buffer_needs_flushing = 0;
}
}
D3D_unlocktexture(monid, -1, -1);
if (dorender) {
if (D3D_renderframe(monid, true, false)) {
gfx_unlock();
mon->render_ok = true;
show_screen_maybe(monid, true);
} else {
gfx_unlock();
}
} else {
gfx_unlock();
}
}
static HWND blankwindows[MAX_DISPLAYS];
static void closeblankwindows (void)
{
for (int i = 0; i < MAX_DISPLAYS; i++) {
HWND h = blankwindows[i];
if (h) {
ShowWindow (h, SW_HIDE);
DestroyWindow (h);
blankwindows[i] = NULL;
}
}
}
static void createblankwindows (void)
{
struct MultiDisplay *mdx = getdisplay(&currprefs, 0);
int i;
if (!currprefs.win32_blankmonitors)
return;
for (i = 0; Displays[i].monitorname; i++) {
struct MultiDisplay *md = &Displays[i];
TCHAR name[100];
if (mdx == md)
continue;
_stprintf (name, _T("WinUAE_Blank_%d"), i);
blankwindows[i] = CreateWindowEx (
WS_EX_TOPMOST,
_T("Blank"), name,
WS_POPUP | WS_VISIBLE,
md->rect.left, md->rect.top, md->rect.right - md->rect.left, md->rect.bottom - md->rect.top,
NULL,
NULL, hInst, NULL);
}
}
static void close_hwnds(struct AmigaMonitor *mon)
{
if (mon->screen_is_initialized)
releasecapture(mon);
mon->screen_is_initialized = 0;
if (!mon->monitor_id) {
display_vblank_thread_kill();
#ifdef AVIOUTPUT
AVIOutput_Restart(true);
#endif
#ifdef RETROPLATFORM
rp_set_hwnd(NULL);
#endif
closeblankwindows();
rawinput_release();
}
if (mon->monitor_id > 0 && mon->hMainWnd)
setmouseactive(mon->monitor_id, 0);
deletestatusline(mon->monitor_id);
if (mon->hStatusWnd) {
ShowWindow(mon->hStatusWnd, SW_HIDE);
DestroyWindow(mon->hStatusWnd);
mon->hStatusWnd = 0;
if (mon->hStatusBkgB)
DeleteObject(mon->hStatusBkgB);
mon->hStatusBkgB = NULL;
}
if (mon->hAmigaWnd) {
addnotifications (mon->hAmigaWnd, TRUE, FALSE);
#ifdef D3D
D3D_free(mon->monitor_id, true);
#endif
ShowWindow (mon->hAmigaWnd, SW_HIDE);
DestroyWindow (mon->hAmigaWnd);
if (mon->hAmigaWnd == mon->hMainWnd)
mon->hMainWnd = 0;
mon->hAmigaWnd = 0;
}
if (mon->hMainWnd) {
ShowWindow(mon->hMainWnd, SW_HIDE);
DestroyWindow(mon->hMainWnd);
mon->hMainWnd = 0;
}
gfx_hdr = false;
}
static bool canmatchdepth(void)
{
if (!currprefs.win32_rtgmatchdepth)
return false;
if (currprefs.gfx_api >= 2)
return false;
return true;
}
static void updatemodes(struct AmigaMonitor *mon)
{
struct uae_filter *usedfilter = mon->usedfilter;
DWORD flags = 0;
mon->currentmode.fullfill = 0;
if (isfullscreen () > 0)
flags |= DM_DX_FULLSCREEN;
else if (isfullscreen () < 0)
flags |= DM_W_FULLSCREEN;
#if defined (GFXFILTER)
if (usedfilter) {
flags |= DM_SWSCALE;
if (mon->currentmode.current_depth < 15)
mon->currentmode.current_depth = 16;
}
#endif
flags |= DM_D3D;
if (flags & DM_DX_FULLSCREEN) {
flags &= ~DM_DX_FULLSCREEN;
flags |= DM_D3D_FULLSCREEN;
}
mon->currentmode.flags = flags;
if (flags & DM_SWSCALE)
mon->currentmode.fullfill = 1;
if (flags & DM_W_FULLSCREEN) {
RECT rc = getdisplay(&currprefs, mon->monitor_id)->rect;
mon->currentmode.native_width = rc.right - rc.left;
mon->currentmode.native_height = rc.bottom - rc.top;
mon->currentmode.current_width = mon->currentmode.native_width;
mon->currentmode.current_height = mon->currentmode.native_height;
} else {
mon->currentmode.native_width = mon->currentmode.current_width;
mon->currentmode.native_height = mon->currentmode.current_height;
}
}
static void update_gfxparams(struct AmigaMonitor *mon)
{
struct picasso96_state_struct *state = &picasso96_state[mon->monitor_id];
updatewinfsmode(mon->monitor_id, &currprefs);
#ifdef PICASSO96
mon->currentmode.vsync = 0;
if (mon->screen_is_picasso) {
float mx = 1.0;
float my = 1.0;
if (currprefs.gf[GF_RTG].gfx_filter_horiz_zoom_mult > 0) {
mx *= currprefs.gf[GF_RTG].gfx_filter_horiz_zoom_mult;
}
if (currprefs.gf[GF_RTG].gfx_filter_vert_zoom_mult > 0) {
my *= currprefs.gf[GF_RTG].gfx_filter_vert_zoom_mult;
}
mon->currentmode.current_width = (int)(state->Width * currprefs.rtg_horiz_zoom_mult * mx);
mon->currentmode.current_height = (int)(state->Height * currprefs.rtg_vert_zoom_mult * my);
currprefs.gfx_apmode[1].gfx_interlaced = false;
if (currprefs.win32_rtgvblankrate == 0) {
currprefs.gfx_apmode[1].gfx_refreshrate = currprefs.gfx_apmode[0].gfx_refreshrate;
if (currprefs.gfx_apmode[0].gfx_interlaced) {
currprefs.gfx_apmode[1].gfx_refreshrate *= 2;
}
} else if (currprefs.win32_rtgvblankrate < 0) {
currprefs.gfx_apmode[1].gfx_refreshrate = 0;
} else {
currprefs.gfx_apmode[1].gfx_refreshrate = currprefs.win32_rtgvblankrate;
}
if (currprefs.gfx_apmode[1].gfx_vsync)
mon->currentmode.vsync = 1 + currprefs.gfx_apmode[1].gfx_vsyncmode;
} else {
#endif
mon->currentmode.current_width = currprefs.gfx_monitor[mon->monitor_id].gfx_size.width;
mon->currentmode.current_height = currprefs.gfx_monitor[mon->monitor_id].gfx_size.height;
if (currprefs.gfx_apmode[0].gfx_vsync)
mon->currentmode.vsync = 1 + currprefs.gfx_apmode[0].gfx_vsyncmode;
#ifdef PICASSO96
}
#endif
#if FORCE16BIT
mon->currentmode.current_depth = 16;
#else
mon->currentmode.current_depth = currprefs.color_mode < 5 ? 16 : 32;
#endif
if (mon->screen_is_picasso && canmatchdepth() && isfullscreen () > 0) {
int pbits = state->BytesPerPixel * 8;
if (pbits <= 8) {
if (mon->currentmode.current_depth == 32)
pbits = 32;
else
pbits = 16;
}
if (pbits == 24)
pbits = 32;
mon->currentmode.current_depth = pbits;
}
mon->currentmode.amiga_width = mon->currentmode.current_width;
mon->currentmode.amiga_height = mon->currentmode.current_height;
mon->scalepicasso = 0;
if (mon->screen_is_picasso) {
bool diff = state->Width != mon->currentmode.native_width || state->Height != mon->currentmode.native_height;
if (isfullscreen () < 0) {
if ((currprefs.gf[GF_RTG].gfx_filter_autoscale == RTG_MODE_CENTER || currprefs.gf[GF_RTG].gfx_filter_autoscale == RTG_MODE_SCALE || currprefs.win32_rtgallowscaling) && diff) {
mon->scalepicasso = RTG_MODE_SCALE;
}
if (currprefs.gf[GF_RTG].gfx_filter_autoscale == RTG_MODE_INTEGER_SCALE && diff) {
mon->scalepicasso = RTG_MODE_INTEGER_SCALE;
}
if (currprefs.gf[GF_RTG].gfx_filter_autoscale == RTG_MODE_CENTER && diff) {
mon->scalepicasso = currprefs.gf[GF_RTG].gfx_filter_autoscale;
}
if (!mon->scalepicasso && currprefs.win32_rtgscaleaspectratio) {
mon->scalepicasso = -1;
}
} else if (isfullscreen () > 0) {
if (!canmatchdepth()) { // can't scale to different color depth
if (mon->currentmode.native_width > state->Width && mon->currentmode.native_height > state->Height) {
if (currprefs.gf[GF_RTG].gfx_filter_autoscale)
mon->scalepicasso = RTG_MODE_SCALE;
if (currprefs.gf[GF_RTG].gfx_filter_autoscale == RTG_MODE_INTEGER_SCALE) {
mon->scalepicasso = RTG_MODE_INTEGER_SCALE;
}
}
if (currprefs.gf[GF_RTG].gfx_filter_autoscale == RTG_MODE_CENTER)
mon->scalepicasso = currprefs.gf[GF_RTG].gfx_filter_autoscale;
if (!mon->scalepicasso && currprefs.win32_rtgscaleaspectratio)
mon->scalepicasso = -1;
}
} else if (isfullscreen () == 0) {
if (currprefs.gf[GF_RTG].gfx_filter_autoscale == RTG_MODE_INTEGER_SCALE) {
mon->scalepicasso = RTG_MODE_INTEGER_SCALE;
mon->currentmode.current_width = currprefs.gfx_monitor[mon->monitor_id].gfx_size.width;
mon->currentmode.current_height = currprefs.gfx_monitor[mon->monitor_id].gfx_size.height;
} else if (currprefs.gf[GF_RTG].gfx_filter_autoscale == RTG_MODE_CENTER) {
if (currprefs.gfx_monitor[mon->monitor_id].gfx_size.width < state->Width || currprefs.gfx_monitor[mon->monitor_id].gfx_size.height < state->Height) {
if (!currprefs.win32_rtgallowscaling) {
;
} else if (currprefs.win32_rtgscaleaspectratio) {
mon->scalepicasso = -1;
mon->currentmode.current_width = currprefs.gfx_monitor[mon->monitor_id].gfx_size.width;
mon->currentmode.current_height = currprefs.gfx_monitor[mon->monitor_id].gfx_size.height;
}
} else {
mon->scalepicasso = RTG_MODE_CENTER;
mon->currentmode.current_width = currprefs.gfx_monitor[mon->monitor_id].gfx_size.width;
mon->currentmode.current_height = currprefs.gfx_monitor[mon->monitor_id].gfx_size.height;
}
} else if (currprefs.gf[GF_RTG].gfx_filter_autoscale == RTG_MODE_SCALE) {
if (currprefs.gfx_monitor[mon->monitor_id].gfx_size.width > state->Width || currprefs.gfx_monitor[mon->monitor_id].gfx_size.height > state->Height)
mon->scalepicasso = RTG_MODE_SCALE;
if ((currprefs.gfx_monitor[mon->monitor_id].gfx_size.width != state->Width || currprefs.gfx_monitor[mon->monitor_id].gfx_size.height != state->Height) && currprefs.win32_rtgallowscaling) {
mon->scalepicasso = RTG_MODE_SCALE;
} else if (currprefs.gfx_monitor[mon->monitor_id].gfx_size.width < state->Width || currprefs.gfx_monitor[mon->monitor_id].gfx_size.height < state->Height) {
// no always scaling and smaller? Back to normal size and set new configured max size
mon->currentmode.current_width = changed_prefs.gfx_monitor[mon->monitor_id].gfx_size_win.width = state->Width;
mon->currentmode.current_height = changed_prefs.gfx_monitor[mon->monitor_id].gfx_size_win.height = state->Height;
} else if (currprefs.gfx_monitor[mon->monitor_id].gfx_size.width == state->Width || currprefs.gfx_monitor[mon->monitor_id].gfx_size.height == state->Height) {
;
} else if (!mon->scalepicasso && currprefs.win32_rtgscaleaspectratio) {
mon->scalepicasso = -1;
}
} else {
if ((currprefs.gfx_monitor[mon->monitor_id].gfx_size.width != state->Width || currprefs.gfx_monitor[mon->monitor_id].gfx_size.height != state->Height) && currprefs.win32_rtgallowscaling)
mon->scalepicasso = RTG_MODE_SCALE;
if (!mon->scalepicasso && currprefs.win32_rtgscaleaspectratio)
mon->scalepicasso = -1;
}
}
if (mon->scalepicasso > 0 && (currprefs.gfx_monitor[mon->monitor_id].gfx_size.width != state->Width || currprefs.gfx_monitor[mon->monitor_id].gfx_size.height != state->Height)) {
mon->currentmode.current_width = currprefs.gfx_monitor[mon->monitor_id].gfx_size.width;
mon->currentmode.current_height = currprefs.gfx_monitor[mon->monitor_id].gfx_size.height;
}
}
}
static int open_windows(struct AmigaMonitor *mon, bool mousecapture, bool started)
{
bool recapture = false;
int ret;
mon->screen_is_initialized = 0;
if (mon->monitor_id && mouseactive)
recapture = true;
inputdevice_unacquire();
reset_sound();
if (mon->hAmigaWnd == NULL)
wait_keyrelease();
mon->in_sizemove = 0;
updatewinfsmode(mon->monitor_id, &currprefs);
int init_round = 0;
ret = -2;
do {
if (ret < -1) {
updatemodes(mon);
update_gfxparams(mon);
}
ret = doInit(mon);
init_round++;
if (ret < -9) {
return 0;
}
} while (ret < 0);
if (!ret) {
return ret;
}
bool startactive = (started && mouseactive) || (!started && !currprefs.win32_start_uncaptured && !currprefs.win32_start_minimized);
bool startpaused = !started && ((currprefs.win32_start_minimized && currprefs.win32_iconified_pause) || (currprefs.win32_start_uncaptured && currprefs.win32_inactive_pause && isfullscreen() <= 0));
bool startminimized = !started && currprefs.win32_start_minimized && isfullscreen() <= 0;
int input = 0;
if ((mousecapture && startactive) || recapture)
setmouseactive(mon->monitor_id, -1);
int upd = 0;
if (startactive) {
setpriority(&priorities[currprefs.win32_active_capture_priority]);
upd = 2;
} else if (startminimized) {
setpriority(&priorities[currprefs.win32_iconified_priority]);
setminimized(mon->monitor_id);
input = currprefs.win32_inactive_input;
upd = 1;
} else {
setpriority(&priorities[currprefs.win32_inactive_priority]);
input = currprefs.win32_inactive_input;
upd = 2;
}
if (upd > 1) {
for (int i = 0; i < NUM_LEDS; i++)
gui_flicker_led(i, -1, -1);
gui_led(LED_POWER, gui_data.powerled, gui_data.powerled_brightness);
gui_fps(0, 0, 0);
if (gui_data.md >= 0)
gui_led(LED_MD, 0, -1);
for (int i = 0; i < 4; i++) {
if (currprefs.floppyslots[i].dfxtype >= 0)
gui_led(LED_DF0 + i, 0, -1);
}
}
if (upd > 0) {
inputdevice_acquire(TRUE);
if (!isfocus())
inputdevice_unacquire(input);
}
if (startpaused)
setpaused(1);
statusline_updated(mon->monitor_id);
refreshtitle();
return ret;
}
static void reopen_gfx(struct AmigaMonitor *mon)
{
open_windows(mon, false, true);
render_screen(mon->monitor_id, 1, true);
}
static int getstatuswindowheight(int monid, HWND hwnd)
{
if (monid > 0)
return 0;
int def = GetSystemMetrics (SM_CYMENU) + 3;
WINDOWINFO wi;
HWND h = CreateWindowEx (
0, STATUSCLASSNAME, (LPCTSTR) NULL, SBARS_TOOLTIPS | WS_CHILD,
0, 0, 0, 0, hwnd ? hwnd : hHiddenWnd, (HMENU) 1, hInst, NULL);
if (!h)
return def;
wi.cbSize = sizeof wi;
if (GetWindowInfo(h, &wi)) {
def = wi.rcWindow.bottom - wi.rcWindow.top;
}
DestroyWindow(h);
return def;
}
void graphics_reset(bool forced)
{
if (forced) {
display_change_requested = 2;
} else {
// full reset if display size can't changed.
if (currprefs.gfx_api) {
display_change_requested = 3;
} else {
display_change_requested = 2;
}
}
}
void WIN32GFX_DisplayChangeRequested(int mode)
{
display_change_requested = mode;
}
int check_prefs_changed_gfx(void)
{
int c = 0;
bool monitors[MAX_AMIGAMONITORS];
if (!config_changed && !display_change_requested)
return 0;
c |= currprefs.win32_statusbar != changed_prefs.win32_statusbar ? 512 : 0;
for (int i = 0; i < MAX_AMIGADISPLAYS; i++) {
monitors[i] = false;
int c2 = 0;
c2 |= currprefs.gfx_monitor[i].gfx_size_fs.width != changed_prefs.gfx_monitor[i].gfx_size_fs.width ? 16 : 0;
c2 |= currprefs.gfx_monitor[i].gfx_size_fs.height != changed_prefs.gfx_monitor[i].gfx_size_fs.height ? 16 : 0;
c2 |= ((currprefs.gfx_monitor[i].gfx_size_win.width + 7) & ~7) != ((changed_prefs.gfx_monitor[i].gfx_size_win.width + 7) & ~7) ? 16 : 0;
c2 |= currprefs.gfx_monitor[i].gfx_size_win.height != changed_prefs.gfx_monitor[i].gfx_size_win.height ? 16 : 0;
if (c2) {
c |= c2;
monitors[i] = true;
}
if (WIN32GFX_IsPicassoScreen(&AMonitors[i])) {
struct gfx_filterdata *gfc = &changed_prefs.gf[1];
if (gfc->changed) {
gfc->changed = false;
c |= 16;
}
} else {
struct gfx_filterdata *gfc1 = &changed_prefs.gf[0];
struct gfx_filterdata *gfc2 = &changed_prefs.gf[2];
if (gfc1->changed || gfc2->changed) {
gfc1->changed = false;
gfc2->changed = false;
c |= 16;
}
}
}
if (currprefs.gf[2].enable != changed_prefs.gf[2].enable) {
currprefs.gf[2].enable = changed_prefs.gf[2].enable;
c |= 512;
}
monitors[0] = true;
#if 0
c |= currprefs.gfx_size_win.x != changed_prefs.gfx_size_win.x ? 16 : 0;
c |= currprefs.gfx_size_win.y != changed_prefs.gfx_size_win.y ? 16 : 0;
#endif
c |= currprefs.color_mode != changed_prefs.color_mode ? 2 | 16 : 0;
c |= currprefs.gfx_apmode[0].gfx_fullscreen != changed_prefs.gfx_apmode[0].gfx_fullscreen ? 16 : 0;
c |= currprefs.gfx_apmode[1].gfx_fullscreen != changed_prefs.gfx_apmode[1].gfx_fullscreen ? 16 : 0;
c |= currprefs.gfx_apmode[0].gfx_vsync != changed_prefs.gfx_apmode[0].gfx_vsync ? 2 | 16 : 0;
c |= currprefs.gfx_apmode[1].gfx_vsync != changed_prefs.gfx_apmode[1].gfx_vsync ? 2 | 16 : 0;
c |= currprefs.gfx_apmode[0].gfx_vsyncmode != changed_prefs.gfx_apmode[0].gfx_vsyncmode ? 2 | 16 : 0;
c |= currprefs.gfx_apmode[1].gfx_vsyncmode != changed_prefs.gfx_apmode[1].gfx_vsyncmode ? 2 | 16 : 0;
c |= currprefs.gfx_apmode[0].gfx_refreshrate != changed_prefs.gfx_apmode[0].gfx_refreshrate ? 2 | 16 : 0;
#if 0
c |= currprefs.gfx_apmode[1].gfx_refreshrate != changed_prefs.gfx_apmode[1].gfx_refreshrate ? 2 | 16 : 0;
#endif
c |= currprefs.gfx_autoresolution != changed_prefs.gfx_autoresolution ? (2|8|16) : 0;
c |= currprefs.gfx_autoresolution_vga != changed_prefs.gfx_autoresolution_vga ? (2|8|16) : 0;
c |= currprefs.gfx_api != changed_prefs.gfx_api ? (1 | 8 | 32) : 0;
c |= currprefs.gfx_api_options != changed_prefs.gfx_api_options ? (1 | 8 | 32) : 0;
c |= currprefs.lightboost_strobo != changed_prefs.lightboost_strobo ? (2|16) : 0;
for (int j = 0; j < MAX_FILTERDATA; j++) {
struct gfx_filterdata *gf = &currprefs.gf[j];
struct gfx_filterdata *gfc = &changed_prefs.gf[j];
c |= gf->gfx_filter != gfc->gfx_filter ? (2 | 8) : 0;
c |= gf->gfx_filter != gfc->gfx_filter ? (2 | 8) : 0;
for (int i = 0; i <= 2 * MAX_FILTERSHADERS; i++) {
c |= _tcscmp (gf->gfx_filtershader[i], gfc->gfx_filtershader[i]) ? (2|8) : 0;
c |= _tcscmp (gf->gfx_filtermask[i], gfc->gfx_filtermask[i]) ? (2|8) : 0;
}
c |= _tcscmp (gf->gfx_filteroverlay, gfc->gfx_filteroverlay) ? (2|8) : 0;
c |= gf->gfx_filter_scanlines != gfc->gfx_filter_scanlines ? (1|8) : 0;
c |= gf->gfx_filter_scanlinelevel != gfc->gfx_filter_scanlinelevel ? (1|8) : 0;
c |= gf->gfx_filter_scanlineratio != gfc->gfx_filter_scanlineratio ? (1 | 8) : 0;
c |= gf->gfx_filter_scanlineoffset != gfc->gfx_filter_scanlineoffset ? (1 | 8) : 0;
c |= gf->gfx_filter_horiz_zoom_mult != gfc->gfx_filter_horiz_zoom_mult ? (1) : 0;
c |= gf->gfx_filter_vert_zoom_mult != gfc->gfx_filter_vert_zoom_mult ? (1) : 0;
c |= gf->gfx_filter_filtermodeh != gfc->gfx_filter_filtermodeh ? (2 | 8) : 0;
c |= gf->gfx_filter_filtermodev != gfc->gfx_filter_filtermodev ? (2 | 8) : 0;
c |= gf->gfx_filter_bilinear != gfc->gfx_filter_bilinear ? (2|8|16) : 0;
c |= gf->gfx_filter_noise != gfc->gfx_filter_noise ? (1) : 0;
c |= gf->gfx_filter_blur != gfc->gfx_filter_blur ? (1) : 0;
c |= gf->gfx_filter_aspect != gfc->gfx_filter_aspect ? (1) : 0;
c |= gf->gfx_filter_rotation != gfc->gfx_filter_rotation ? (1) : 0;
c |= gf->gfx_filter_keep_aspect != gfc->gfx_filter_keep_aspect ? (1) : 0;
c |= gf->gfx_filter_keep_autoscale_aspect != gfc->gfx_filter_keep_autoscale_aspect ? (1) : 0;
c |= gf->gfx_filter_luminance != gfc->gfx_filter_luminance ? (1) : 0;
c |= gf->gfx_filter_contrast != gfc->gfx_filter_contrast ? (1) : 0;
c |= gf->gfx_filter_saturation != gfc->gfx_filter_saturation ? (1) : 0;
c |= gf->gfx_filter_gamma != gfc->gfx_filter_gamma ? (1) : 0;
c |= gf->gfx_filter_integerscalelimit != gfc->gfx_filter_integerscalelimit ? (1) : 0;
if (j && gf->gfx_filter_autoscale != gfc->gfx_filter_autoscale)
c |= 8 | 64;
//c |= gf->gfx_filter_ != gfc->gfx_filter_ ? (1|8) : 0;
}
c |= currprefs.rtg_horiz_zoom_mult != changed_prefs.rtg_horiz_zoom_mult ? 16 : 0;
c |= currprefs.rtg_vert_zoom_mult != changed_prefs.rtg_vert_zoom_mult ? 16 : 0;
c |= currprefs.gfx_luminance != changed_prefs.gfx_luminance ? (1 | 256) : 0;
c |= currprefs.gfx_contrast != changed_prefs.gfx_contrast ? (1 | 256) : 0;
c |= currprefs.gfx_gamma != changed_prefs.gfx_gamma ? (1 | 256) : 0;
c |= currprefs.gfx_resolution != changed_prefs.gfx_resolution ? (128) : 0;
c |= currprefs.gfx_vresolution != changed_prefs.gfx_vresolution ? (128) : 0;
c |= currprefs.gfx_autoresolution_minh != changed_prefs.gfx_autoresolution_minh ? (128) : 0;
c |= currprefs.gfx_autoresolution_minv != changed_prefs.gfx_autoresolution_minv ? (128) : 0;
c |= currprefs.gfx_iscanlines != changed_prefs.gfx_iscanlines ? (2 | 8) : 0;
c |= currprefs.gfx_pscanlines != changed_prefs.gfx_pscanlines ? (2 | 8) : 0;
c |= currprefs.monitoremu != changed_prefs.monitoremu ? (2 | 8) : 0;
c |= currprefs.genlock_image != changed_prefs.genlock_image ? (2 | 8) : 0;
c |= currprefs.genlock != changed_prefs.genlock ? (2 | 8) : 0;
c |= currprefs.genlock_alpha != changed_prefs.genlock_alpha ? (1 | 8) : 0;
c |= currprefs.genlock_mix != changed_prefs.genlock_mix ? (1 | 256) : 0;
c |= currprefs.genlock_aspect != changed_prefs.genlock_aspect ? (1 | 256) : 0;
c |= currprefs.genlock_scale != changed_prefs.genlock_scale ? (1 | 256) : 0;
c |= _tcsicmp(currprefs.genlock_image_file, changed_prefs.genlock_image_file) ? (2 | 8) : 0;
c |= _tcsicmp(currprefs.genlock_video_file, changed_prefs.genlock_video_file) ? (2 | 8) : 0;
c |= currprefs.gfx_lores_mode != changed_prefs.gfx_lores_mode ? (2 | 8) : 0;
c |= currprefs.gfx_overscanmode != changed_prefs.gfx_overscanmode ? (2 | 8) : 0;
c |= currprefs.gfx_scandoubler != changed_prefs.gfx_scandoubler ? (2 | 8) : 0;
c |= currprefs.gfx_threebitcolors != changed_prefs.gfx_threebitcolors ? (256) : 0;
c |= currprefs.gfx_grayscale != changed_prefs.gfx_grayscale ? (512) : 0;
c |= currprefs.gfx_monitorblankdelay != changed_prefs.gfx_monitorblankdelay ? (512) : 0;
c |= currprefs.gfx_display_sections != changed_prefs.gfx_display_sections ? (512) : 0;
c |= currprefs.gfx_variable_sync != changed_prefs.gfx_variable_sync ? 1 : 0;
c |= currprefs.gfx_windowed_resize != changed_prefs.gfx_windowed_resize ? 1 : 0;
c |= currprefs.gfx_apmode[APMODE_NATIVE].gfx_display != changed_prefs.gfx_apmode[APMODE_NATIVE].gfx_display ? (2|4|8) : 0;
c |= currprefs.gfx_apmode[APMODE_RTG].gfx_display != changed_prefs.gfx_apmode[APMODE_RTG].gfx_display ? (2|4|8) : 0;
c |= currprefs.gfx_blackerthanblack != changed_prefs.gfx_blackerthanblack ? (2 | 8) : 0;
c |= currprefs.gfx_apmode[APMODE_NATIVE].gfx_backbuffers != changed_prefs.gfx_apmode[APMODE_NATIVE].gfx_backbuffers ? (2 | 16) : 0;
c |= currprefs.gfx_apmode[APMODE_NATIVE].gfx_interlaced != changed_prefs.gfx_apmode[APMODE_NATIVE].gfx_interlaced ? (2 | 8) : 0;
c |= currprefs.gfx_apmode[APMODE_RTG].gfx_backbuffers != changed_prefs.gfx_apmode[APMODE_RTG].gfx_backbuffers ? (2 | 16) : 0;
c |= currprefs.win32_main_alwaysontop != changed_prefs.win32_main_alwaysontop ? 32 : 0;
c |= currprefs.win32_gui_alwaysontop != changed_prefs.win32_gui_alwaysontop ? 2 : 0;
c |= currprefs.win32_notaskbarbutton != changed_prefs.win32_notaskbarbutton ? 32 : 0;
c |= currprefs.win32_nonotificationicon != changed_prefs.win32_nonotificationicon ? 32 : 0;
c |= currprefs.win32_borderless != changed_prefs.win32_borderless ? 32 : 0;
c |= currprefs.win32_blankmonitors != changed_prefs.win32_blankmonitors ? 32 : 0;
c |= currprefs.win32_rtgmatchdepth != changed_prefs.win32_rtgmatchdepth ? 2 : 0;
// c |= currprefs.win32_rtgscalemode != changed_prefs.win32_rtgscalemode ? (2 | 8 | 64) : 0;
c |= currprefs.win32_rtgallowscaling != changed_prefs.win32_rtgallowscaling ? (2 | 8 | 64) : 0;
c |= currprefs.win32_rtgscaleaspectratio != changed_prefs.win32_rtgscaleaspectratio ? (8 | 64) : 0;
c |= currprefs.win32_rtgvblankrate != changed_prefs.win32_rtgvblankrate ? 8 : 0;
if (display_change_requested || c)
{
bool setpause = false;
bool dontcapture = false;
int keepfsmode =
currprefs.gfx_apmode[0].gfx_fullscreen == changed_prefs.gfx_apmode[0].gfx_fullscreen &&
currprefs.gfx_apmode[1].gfx_fullscreen == changed_prefs.gfx_apmode[1].gfx_fullscreen;
currprefs.gfx_autoresolution = changed_prefs.gfx_autoresolution;
currprefs.gfx_autoresolution_vga = changed_prefs.gfx_autoresolution_vga;
currprefs.color_mode = changed_prefs.color_mode;
currprefs.lightboost_strobo = changed_prefs.lightboost_strobo;
if (currprefs.gfx_api != changed_prefs.gfx_api) {
display_change_requested = 1;
}
if (c & 128) {
// hres/vres change
rp_screenmode_changed();
}
if (display_change_requested) {
if (display_change_requested == 3) {
c = 1024;
} else if (display_change_requested == 2) {
c = 512;
} else if (display_change_requested == 4) {
c = 32;
} else {
c = 2;
keepfsmode = 0;
if (display_change_requested <= -1) {
dontcapture = true;
if (display_change_requested == -2)
setpause = true;
if (pause_emulation)
setpause = true;
}
}
display_change_requested = 0;
}
for (int j = 0; j < MAX_FILTERDATA; j++) {
struct gfx_filterdata *gf = &currprefs.gf[j];
struct gfx_filterdata *gfc = &changed_prefs.gf[j];
memcpy(gf, gfc, sizeof(struct gfx_filterdata));
}
currprefs.rtg_horiz_zoom_mult = changed_prefs.rtg_horiz_zoom_mult;
currprefs.rtg_vert_zoom_mult = changed_prefs.rtg_vert_zoom_mult;
currprefs.gfx_luminance = changed_prefs.gfx_luminance;
currprefs.gfx_contrast = changed_prefs.gfx_contrast;
currprefs.gfx_gamma = changed_prefs.gfx_gamma;
currprefs.gfx_resolution = changed_prefs.gfx_resolution;
currprefs.gfx_vresolution = changed_prefs.gfx_vresolution;
currprefs.gfx_autoresolution_minh = changed_prefs.gfx_autoresolution_minh;
currprefs.gfx_autoresolution_minv = changed_prefs.gfx_autoresolution_minv;
currprefs.gfx_iscanlines = changed_prefs.gfx_iscanlines;
currprefs.gfx_pscanlines = changed_prefs.gfx_pscanlines;
currprefs.monitoremu = changed_prefs.monitoremu;
currprefs.genlock_image = changed_prefs.genlock_image;
currprefs.genlock = changed_prefs.genlock;
currprefs.genlock_mix = changed_prefs.genlock_mix;
currprefs.genlock_alpha = changed_prefs.genlock_alpha;
currprefs.genlock_aspect = changed_prefs.genlock_aspect;
currprefs.genlock_scale = changed_prefs.genlock_scale;
_tcscpy(currprefs.genlock_image_file, changed_prefs.genlock_image_file);
_tcscpy(currprefs.genlock_video_file, changed_prefs.genlock_video_file);
currprefs.gfx_lores_mode = changed_prefs.gfx_lores_mode;
currprefs.gfx_overscanmode = changed_prefs.gfx_overscanmode;
currprefs.gfx_scandoubler = changed_prefs.gfx_scandoubler;
currprefs.gfx_threebitcolors = changed_prefs.gfx_threebitcolors;
currprefs.gfx_grayscale = changed_prefs.gfx_grayscale;
currprefs.gfx_monitorblankdelay = changed_prefs.gfx_monitorblankdelay;
currprefs.gfx_display_sections = changed_prefs.gfx_display_sections;
currprefs.gfx_variable_sync = changed_prefs.gfx_variable_sync;
currprefs.gfx_windowed_resize = changed_prefs.gfx_windowed_resize;
currprefs.gfx_apmode[APMODE_NATIVE].gfx_display = changed_prefs.gfx_apmode[APMODE_NATIVE].gfx_display;
currprefs.gfx_apmode[APMODE_RTG].gfx_display = changed_prefs.gfx_apmode[APMODE_RTG].gfx_display;
currprefs.gfx_blackerthanblack = changed_prefs.gfx_blackerthanblack;
currprefs.gfx_apmode[APMODE_NATIVE].gfx_backbuffers = changed_prefs.gfx_apmode[APMODE_NATIVE].gfx_backbuffers;
currprefs.gfx_apmode[APMODE_NATIVE].gfx_interlaced = changed_prefs.gfx_apmode[APMODE_NATIVE].gfx_interlaced;
currprefs.gfx_apmode[APMODE_RTG].gfx_backbuffers = changed_prefs.gfx_apmode[APMODE_RTG].gfx_backbuffers;
currprefs.win32_main_alwaysontop = changed_prefs.win32_main_alwaysontop;
currprefs.win32_gui_alwaysontop = changed_prefs.win32_gui_alwaysontop;
currprefs.win32_nonotificationicon = changed_prefs.win32_nonotificationicon;
currprefs.win32_notaskbarbutton = changed_prefs.win32_notaskbarbutton;
currprefs.win32_borderless = changed_prefs.win32_borderless;
currprefs.win32_blankmonitors = changed_prefs.win32_blankmonitors;
currprefs.win32_statusbar = changed_prefs.win32_statusbar;
currprefs.win32_rtgmatchdepth = changed_prefs.win32_rtgmatchdepth;
// currprefs.win32_rtgscalemode = changed_prefs.win32_rtgscalemode;
currprefs.win32_rtgallowscaling = changed_prefs.win32_rtgallowscaling;
currprefs.win32_rtgscaleaspectratio = changed_prefs.win32_rtgscaleaspectratio;
currprefs.win32_rtgvblankrate = changed_prefs.win32_rtgvblankrate;
bool unacquired = false;
for (int monid = MAX_AMIGAMONITORS - 1; monid >= 0; monid--) {
if (!monitors[monid])
continue;
struct AmigaMonitor *mon = &AMonitors[monid];
if (c & 64) {
if (!unacquired) {
inputdevice_unacquire();
unacquired = true;
}
}
if (c & 256) {
init_colors(mon->monitor_id);
reset_drawing();
}
if (c & 128) {
if (currprefs.gfx_autoresolution) {
c |= 2 | 8;
} else {
c |= 16;
reset_drawing();
S2X_reset(mon->monitor_id);
}
}
if (c & 1024) {
target_graphics_buffer_update(mon->monitor_id);
}
if (c & 512) {
reopen_gfx(mon);
}
if ((c & 16) || ((c & 8) && keepfsmode)) {
if (reopen(mon, c & 2, unacquired == false)) {
c |= 2;
} else {
unacquired = true;
}
}
if ((c & 32) || ((c & 2) && !keepfsmode)) {
if (!unacquired) {
inputdevice_unacquire();
unacquired = true;
}
close_windows(mon);
if (currprefs.gfx_api != changed_prefs.gfx_api || currprefs.gfx_api_options != changed_prefs.gfx_api_options) {
currprefs.gfx_api = changed_prefs.gfx_api;
currprefs.gfx_api_options = changed_prefs.gfx_api_options;
d3d_select(&currprefs);
}
graphics_init(dontcapture ? false : true);
}
}
init_custom();
if (c & 4) {
pause_sound();
reset_sound();
resume_sound();
}
if (setpause || dontcapture) {
if (!unacquired)
inputdevice_unacquire();
unacquired = false;
}
if (unacquired)
inputdevice_acquire(TRUE);
if (setpause)
setpaused(1);
return 1;
}
bool changed = false;
for (int i = 0; i < MAX_CHIPSET_REFRESH_TOTAL; i++) {
if (currprefs.cr[i].rate != changed_prefs.cr[i].rate ||
currprefs.cr[i].locked != changed_prefs.cr[i].locked) {
memcpy (&currprefs.cr[i], &changed_prefs.cr[i], sizeof (struct chipset_refresh));
changed = true;
}
}
if (changed) {
init_hz_normal();
}
if (currprefs.chipset_refreshrate != changed_prefs.chipset_refreshrate) {
currprefs.chipset_refreshrate = changed_prefs.chipset_refreshrate;
init_hz_normal();
return 1;
}
if (
currprefs.gf[0].gfx_filter_autoscale != changed_prefs.gf[0].gfx_filter_autoscale ||
currprefs.gf[2].gfx_filter_autoscale != changed_prefs.gf[2].gfx_filter_autoscale ||
currprefs.gfx_xcenter_pos != changed_prefs.gfx_xcenter_pos ||
currprefs.gfx_ycenter_pos != changed_prefs.gfx_ycenter_pos ||
currprefs.gfx_xcenter_size != changed_prefs.gfx_xcenter_size ||
currprefs.gfx_ycenter_size != changed_prefs.gfx_ycenter_size ||
currprefs.gfx_xcenter != changed_prefs.gfx_xcenter ||
currprefs.gfx_ycenter != changed_prefs.gfx_ycenter)
{
currprefs.gfx_xcenter_pos = changed_prefs.gfx_xcenter_pos;
currprefs.gfx_ycenter_pos = changed_prefs.gfx_ycenter_pos;
currprefs.gfx_xcenter_size = changed_prefs.gfx_xcenter_size;
currprefs.gfx_ycenter_size = changed_prefs.gfx_ycenter_size;
currprefs.gfx_xcenter = changed_prefs.gfx_xcenter;
currprefs.gfx_ycenter = changed_prefs.gfx_ycenter;
currprefs.gf[0].gfx_filter_autoscale = changed_prefs.gf[0].gfx_filter_autoscale;
currprefs.gf[2].gfx_filter_autoscale = changed_prefs.gf[2].gfx_filter_autoscale;
get_custom_limits (NULL, NULL, NULL, NULL, NULL);
fixup_prefs_dimensions (&changed_prefs);
return 1;
}
currprefs.win32_norecyclebin = changed_prefs.win32_norecyclebin;
currprefs.filesys_limit = changed_prefs.filesys_limit;
currprefs.harddrive_read_only = changed_prefs.harddrive_read_only;
if (currprefs.win32_logfile != changed_prefs.win32_logfile) {
currprefs.win32_logfile = changed_prefs.win32_logfile;
if (currprefs.win32_logfile)
logging_open (0, 1);
else
logging_cleanup ();
}
if (currprefs.leds_on_screen != changed_prefs.leds_on_screen ||
currprefs.keyboard_leds[0] != changed_prefs.keyboard_leds[0] ||
currprefs.keyboard_leds[1] != changed_prefs.keyboard_leds[1] ||
currprefs.keyboard_leds[2] != changed_prefs.keyboard_leds[2] ||
currprefs.input_mouse_untrap != changed_prefs.input_mouse_untrap ||
currprefs.win32_minimize_inactive != changed_prefs.win32_minimize_inactive ||
currprefs.win32_active_capture_priority != changed_prefs.win32_active_capture_priority ||
currprefs.win32_inactive_priority != changed_prefs.win32_inactive_priority ||
currprefs.win32_iconified_priority != changed_prefs.win32_iconified_priority ||
currprefs.win32_active_nocapture_nosound != changed_prefs.win32_active_nocapture_nosound ||
currprefs.win32_active_nocapture_pause != changed_prefs.win32_active_nocapture_pause ||
currprefs.win32_active_input != changed_prefs.win32_active_input ||
currprefs.win32_inactive_nosound != changed_prefs.win32_inactive_nosound ||
currprefs.win32_inactive_pause != changed_prefs.win32_inactive_pause ||
currprefs.win32_inactive_input != changed_prefs.win32_inactive_input ||
currprefs.win32_iconified_nosound != changed_prefs.win32_iconified_nosound ||
currprefs.win32_iconified_pause != changed_prefs.win32_iconified_pause ||
currprefs.win32_iconified_input != changed_prefs.win32_iconified_input ||
currprefs.win32_ctrl_F11_is_quit != changed_prefs.win32_ctrl_F11_is_quit ||
currprefs.win32_shutdown_notification != changed_prefs.win32_shutdown_notification ||
currprefs.win32_warn_exit != changed_prefs.win32_warn_exit ||
currprefs.right_control_is_right_win_key != changed_prefs.right_control_is_right_win_key)
{
currprefs.win32_minimize_inactive = changed_prefs.win32_minimize_inactive;
currprefs.leds_on_screen = changed_prefs.leds_on_screen;
currprefs.keyboard_leds[0] = changed_prefs.keyboard_leds[0];
currprefs.keyboard_leds[1] = changed_prefs.keyboard_leds[1];
currprefs.keyboard_leds[2] = changed_prefs.keyboard_leds[2];
currprefs.input_mouse_untrap = changed_prefs.input_mouse_untrap;
currprefs.win32_active_capture_priority = changed_prefs.win32_active_capture_priority;
currprefs.win32_inactive_priority = changed_prefs.win32_inactive_priority;
currprefs.win32_iconified_priority = changed_prefs.win32_iconified_priority;
currprefs.win32_active_nocapture_nosound = changed_prefs.win32_active_nocapture_nosound;
currprefs.win32_active_input = changed_prefs.win32_active_input;
currprefs.win32_active_nocapture_pause = changed_prefs.win32_active_nocapture_pause;
currprefs.win32_inactive_nosound = changed_prefs.win32_inactive_nosound;
currprefs.win32_inactive_pause = changed_prefs.win32_inactive_pause;
currprefs.win32_inactive_input = changed_prefs.win32_inactive_input;
currprefs.win32_iconified_nosound = changed_prefs.win32_iconified_nosound;
currprefs.win32_iconified_pause = changed_prefs.win32_iconified_pause;
currprefs.win32_iconified_input = changed_prefs.win32_iconified_input;
currprefs.win32_ctrl_F11_is_quit = changed_prefs.win32_ctrl_F11_is_quit;
currprefs.win32_shutdown_notification = changed_prefs.win32_shutdown_notification;
currprefs.win32_warn_exit = changed_prefs.win32_warn_exit;
currprefs.right_control_is_right_win_key = changed_prefs.right_control_is_right_win_key;
inputdevice_unacquire ();
currprefs.keyboard_leds_in_use = changed_prefs.keyboard_leds_in_use = (currprefs.keyboard_leds[0] | currprefs.keyboard_leds[1] | currprefs.keyboard_leds[2]) != 0;
pause_sound ();
resume_sound ();
refreshtitle();
inputdevice_acquire (TRUE);
#ifndef _DEBUG
setpriority (&priorities[currprefs.win32_active_capture_priority]);
#endif
return 1;
}
if (currprefs.win32_samplersoundcard != changed_prefs.win32_samplersoundcard ||
currprefs.sampler_stereo != changed_prefs.sampler_stereo) {
currprefs.win32_samplersoundcard = changed_prefs.win32_samplersoundcard;
currprefs.sampler_stereo = changed_prefs.sampler_stereo;
sampler_free ();
}
if (_tcscmp (currprefs.prtname, changed_prefs.prtname) ||
currprefs.parallel_autoflush_time != changed_prefs.parallel_autoflush_time ||
currprefs.parallel_matrix_emulation != changed_prefs.parallel_matrix_emulation ||
currprefs.parallel_postscript_emulation != changed_prefs.parallel_postscript_emulation ||
currprefs.parallel_postscript_detection != changed_prefs.parallel_postscript_detection ||
_tcscmp (currprefs.ghostscript_parameters, changed_prefs.ghostscript_parameters)) {
_tcscpy (currprefs.prtname, changed_prefs.prtname);
currprefs.parallel_autoflush_time = changed_prefs.parallel_autoflush_time;
currprefs.parallel_matrix_emulation = changed_prefs.parallel_matrix_emulation;
currprefs.parallel_postscript_emulation = changed_prefs.parallel_postscript_emulation;
currprefs.parallel_postscript_detection = changed_prefs.parallel_postscript_detection;
_tcscpy (currprefs.ghostscript_parameters, changed_prefs.ghostscript_parameters);
#ifdef PARALLEL_PORT
closeprinter ();
#endif
}
if (_tcscmp (currprefs.sername, changed_prefs.sername) ||
currprefs.serial_hwctsrts != changed_prefs.serial_hwctsrts ||
currprefs.serial_direct != changed_prefs.serial_direct ||
currprefs.serial_demand != changed_prefs.serial_demand) {
_tcscpy (currprefs.sername, changed_prefs.sername);
currprefs.serial_hwctsrts = changed_prefs.serial_hwctsrts;
currprefs.serial_demand = changed_prefs.serial_demand;
currprefs.serial_direct = changed_prefs.serial_direct;
#ifdef SERIAL_PORT
serial_exit ();
serial_init ();
#endif
}
if (currprefs.win32_midiindev != changed_prefs.win32_midiindev ||
currprefs.win32_midioutdev != changed_prefs.win32_midioutdev ||
currprefs.win32_midirouter != changed_prefs.win32_midirouter)
{
currprefs.win32_midiindev = changed_prefs.win32_midiindev;
currprefs.win32_midioutdev = changed_prefs.win32_midioutdev;
currprefs.win32_midirouter = changed_prefs.win32_midirouter;
#ifdef SERIAL_PORT
serial_exit();
serial_init();
Midi_Reopen();
#endif
#ifdef WITH_MIDIEMU
midi_emu_reopen();
#endif
}
if (currprefs.win32_powersavedisabled != changed_prefs.win32_powersavedisabled) {
currprefs.win32_powersavedisabled = changed_prefs.win32_powersavedisabled;
}
return 0;
}
/* Color management */
static xcolnr xcol8[4096];
static int red_bits, green_bits, blue_bits, alpha_bits;
static int red_shift, green_shift, blue_shift, alpha_shift;
static int alpha;
void init_colors(int monid)
{
struct AmigaMonitor *mon = &AMonitors[monid];
/* init colors */
D3D_getpixelformat (mon->currentmode.current_depth,
&red_bits, &green_bits, &blue_bits, &red_shift, &green_shift, &blue_shift, &alpha_bits, &alpha_shift, &alpha);
if (!(mon->currentmode.flags & (DM_D3D))) {
if (mon->currentmode.current_depth != mon->currentmode.native_depth) {
if (mon->currentmode.current_depth == 16) {
red_bits = 5; green_bits = 6; blue_bits = 5;
red_shift = 11; green_shift = 5; blue_shift = 0;
} else {
red_bits = green_bits = blue_bits = 8;
red_shift = 16; green_shift = 8; blue_shift = 0;
}
}
}
alloc_colors64k(monid, red_bits, green_bits, blue_bits, red_shift,green_shift, blue_shift, alpha_bits, alpha_shift, alpha, 0, mon->usedfilter && mon->usedfilter->yuv);
notice_new_xcolors ();
#ifdef GFXFILTER
S2X_configure(monid, red_bits, green_bits, blue_bits, red_shift,green_shift, blue_shift);
#endif
#ifdef AVIOUTPUT
AVIOutput_RGBinfo (red_bits, green_bits, blue_bits, alpha_bits, red_shift, green_shift, blue_shift, alpha_shift);
#endif
Screenshot_RGBinfo (red_bits, green_bits, blue_bits, alpha_bits, red_shift, green_shift, blue_shift, alpha_shift);
}
#ifdef PICASSO96
int picasso_palette(struct MyCLUTEntry *CLUT, uae_u32 *clut)
{
int changed = 0;
for (int i = 0; i < 256 * 2; i++) {
int r = CLUT[i].Red;
int g = CLUT[i].Green;
int b = CLUT[i].Blue;
uae_u32 v = (doMask256 (r, red_bits, red_shift)
| doMask256 (g, green_bits, green_shift)
| doMask256 (b, blue_bits, blue_shift))
| doMask256 ((1 << alpha_bits) - 1, alpha_bits, alpha_shift);
if (v != clut[i]) {
//write_log (_T("%d:%08x\n"), i, v);
clut[i] = v;
changed = 1;
}
}
return changed;
}
void DX_Invalidate(struct AmigaMonitor *mon, int x, int y, int width, int height)
{
struct picasso_vidbuf_description *vidinfo = &picasso_vidinfo[mon->monitor_id];
int last, lastx;
if (width == 0 || height == 0)
return;
if (y < 0 || height < 0) {
y = 0;
height = vidinfo->height;
}
if (x < 0 || width < 0) {
x = 0;
width = vidinfo->width;
}
last = y + height - 1;
lastx = x + width - 1;
mon->p96_double_buffer_first = y;
mon->p96_double_buffer_last = last;
mon->p96_double_buffer_firstx = x;
mon->p96_double_buffer_lastx = lastx;
mon->p96_double_buffer_needs_flushing = 1;
}
#endif
static void open_screen(struct AmigaMonitor *mon)
{
close_windows(mon);
open_windows(mon, true, true);
}
static int ifs(struct AmigaMonitor *mon, struct uae_prefs *p)
{
int idx = mon->screen_is_picasso ? 1 : 0;
return p->gfx_apmode[idx].gfx_fullscreen == GFX_FULLSCREEN ? 1 : (p->gfx_apmode[idx].gfx_fullscreen == GFX_FULLWINDOW ? -1 : 0);
}
static int reopen(struct AmigaMonitor *mon, int full, bool unacquire)
{
struct amigadisplay *ad = &adisplays[mon->monitor_id];
int quick = 0;
int idx = mon->screen_is_picasso ? 1 : 0;
struct apmode *ap = ad->picasso_on ? &currprefs.gfx_apmode[1] : &currprefs.gfx_apmode[0];
updatewinfsmode(mon->monitor_id, &changed_prefs);
if (changed_prefs.gfx_apmode[0].gfx_fullscreen != currprefs.gfx_apmode[0].gfx_fullscreen && !mon->screen_is_picasso)
full = 1;
if (changed_prefs.gfx_apmode[1].gfx_fullscreen != currprefs.gfx_apmode[1].gfx_fullscreen && mon->screen_is_picasso)
full = 1;
/* fullscreen to fullscreen? */
if (isfullscreen () > 0 && currprefs.gfx_apmode[0].gfx_fullscreen == changed_prefs.gfx_apmode[0].gfx_fullscreen &&
currprefs.gfx_apmode[1].gfx_fullscreen == changed_prefs.gfx_apmode[1].gfx_fullscreen && currprefs.gfx_apmode[0].gfx_fullscreen == GFX_FULLSCREEN) {
quick = 1;
}
/* windowed to windowed */
if (isfullscreen () <= 0 && currprefs.gfx_apmode[0].gfx_fullscreen == changed_prefs.gfx_apmode[0].gfx_fullscreen &&
currprefs.gfx_apmode[1].gfx_fullscreen == changed_prefs.gfx_apmode[1].gfx_fullscreen) {
quick = 1;
}
currprefs.gfx_monitor[mon->monitor_id].gfx_size_fs.width = changed_prefs.gfx_monitor[mon->monitor_id].gfx_size_fs.width;
currprefs.gfx_monitor[mon->monitor_id].gfx_size_fs.height = changed_prefs.gfx_monitor[mon->monitor_id].gfx_size_fs.height;
currprefs.gfx_monitor[mon->monitor_id].gfx_size_win.width = changed_prefs.gfx_monitor[mon->monitor_id].gfx_size_win.width;
currprefs.gfx_monitor[mon->monitor_id].gfx_size_win.height = changed_prefs.gfx_monitor[mon->monitor_id].gfx_size_win.height;
currprefs.gfx_monitor[mon->monitor_id].gfx_size_win.x = changed_prefs.gfx_monitor[mon->monitor_id].gfx_size_win.x;
currprefs.gfx_monitor[mon->monitor_id].gfx_size_win.y = changed_prefs.gfx_monitor[mon->monitor_id].gfx_size_win.y;
currprefs.gfx_apmode[0].gfx_fullscreen = changed_prefs.gfx_apmode[0].gfx_fullscreen;
currprefs.gfx_apmode[1].gfx_fullscreen = changed_prefs.gfx_apmode[1].gfx_fullscreen;
currprefs.gfx_apmode[0].gfx_vsync = changed_prefs.gfx_apmode[0].gfx_vsync;
currprefs.gfx_apmode[1].gfx_vsync = changed_prefs.gfx_apmode[1].gfx_vsync;
currprefs.gfx_apmode[0].gfx_vsyncmode = changed_prefs.gfx_apmode[0].gfx_vsyncmode;
currprefs.gfx_apmode[1].gfx_vsyncmode = changed_prefs.gfx_apmode[1].gfx_vsyncmode;
currprefs.gfx_apmode[0].gfx_refreshrate = changed_prefs.gfx_apmode[0].gfx_refreshrate;
currprefs.rtg_horiz_zoom_mult = changed_prefs.rtg_horiz_zoom_mult;
currprefs.rtg_vert_zoom_mult = changed_prefs.rtg_vert_zoom_mult;
#if 0
currprefs.gfx_apmode[1].gfx_refreshrate = changed_prefs.gfx_apmode[1].gfx_refreshrate;
#endif
set_config_changed ();
if (!quick)
return 1;
if (unacquire) {
inputdevice_unacquire ();
}
reopen_gfx(mon);
return 0;
}
bool vsync_switchmode(int monid, int hz)
{
struct AmigaMonitor *mon = &AMonitors[monid];
static struct PicassoResolution *oldmode;
static int oldhz;
int w = mon->currentmode.native_width;
int h = mon->currentmode.native_height;
int d = mon->currentmode.native_depth / 8;
struct MultiDisplay *md = getdisplay(&currprefs, monid);
struct PicassoResolution *found;
int newh, i, cnt;
bool preferdouble = 0, preferlace = 0;
bool lace = false;
if (currprefs.gfx_apmode[APMODE_NATIVE].gfx_refreshrate > 85) {
preferdouble = 1;
} else if (currprefs.gfx_apmode[APMODE_NATIVE].gfx_interlaced) {
preferlace = 1;
}
if (hz >= 55)
hz = 60;
else
hz = 50;
newh = h * (currprefs.ntscmode ? 60 : 50) / hz;
found = NULL;
for (cnt = 0; cnt <= abs (newh - h) + 1 && !found; cnt++) {
for (int dbl = 0; dbl < 2 && !found; dbl++) {
bool doublecheck = false;
bool lacecheck = false;
if (preferdouble && dbl == 0)
doublecheck = true;
else if (preferlace && dbl == 0)
lacecheck = true;
for (int extra = 1; extra >= -1 && !found; extra--) {
for (i = 0; md->DisplayModes[i].depth >= 0 && !found; i++) {
struct PicassoResolution *r = &md->DisplayModes[i];
if (r->res.width == w && (r->res.height == newh + cnt || r->res.height == newh - cnt) && r->depth == d) {
int j;
for (j = 0; r->refresh[j] > 0; j++) {
if (doublecheck) {
if (r->refreshtype[j] & REFRESH_RATE_LACE)
continue;
if (r->refresh[j] == hz * 2 + extra) {
found = r;
hz = r->refresh[j];
break;
}
} else if (lacecheck) {
if (!(r->refreshtype[j] & REFRESH_RATE_LACE))
continue;
if (r->refresh[j] * 2 == hz + extra) {
found = r;
lace = true;
hz = r->refresh[j];
break;
}
} else {
if (r->refresh[j] == hz + extra) {
found = r;
hz = r->refresh[j];
break;
}
}
}
}
}
}
}
}
if (found == oldmode && hz == oldhz)
return true;
oldmode = found;
oldhz = hz;
if (!found) {
changed_prefs.gfx_apmode[APMODE_NATIVE].gfx_vsync = 0;
if (currprefs.gfx_apmode[APMODE_NATIVE].gfx_vsync != changed_prefs.gfx_apmode[APMODE_NATIVE].gfx_vsync) {
set_config_changed ();
}
write_log (_T("refresh rate changed to %d%s but no matching screenmode found, vsync disabled\n"), hz, lace ? _T("i") : _T("p"));
return false;
} else {
newh = found->res.height;
changed_prefs.gfx_monitor[mon->monitor_id].gfx_size_fs.height = newh;
changed_prefs.gfx_apmode[APMODE_NATIVE].gfx_refreshrate = hz;
changed_prefs.gfx_apmode[APMODE_NATIVE].gfx_interlaced = lace;
if (changed_prefs.gfx_monitor[mon->monitor_id].gfx_size_fs.height != currprefs.gfx_monitor[mon->monitor_id].gfx_size_fs.height ||
changed_prefs.gfx_apmode[APMODE_NATIVE].gfx_refreshrate != currprefs.gfx_apmode[APMODE_NATIVE].gfx_refreshrate) {
write_log (_T("refresh rate changed to %d%s, new screenmode %dx%d\n"), hz, lace ? _T("i") : _T("p"), w, newh);
set_config_changed ();
}
return true;
}
}
void vsync_clear(void)
{
vsync_active = false;
if (waitvblankevent)
ResetEvent(waitvblankevent);
}
int vsync_isdone(frame_time_t *dt)
{
if (isvsync() == 0)
return -1;
if (waitvblankthread_mode <= 0)
return -2;
if (dt)
*dt = wait_vblank_timestamp;
return vsync_active ? 1 : 0;
}
#ifdef PICASSO96
static int modeswitchneeded(struct AmigaMonitor *mon, struct winuae_currentmode *wc)
{
struct vidbuf_description *avidinfo = &adisplays[mon->monitor_id].gfxvidinfo;
struct picasso96_state_struct *state = &picasso96_state[mon->monitor_id];
if (isfullscreen () > 0) {
/* fullscreen to fullscreen */
if (mon->screen_is_picasso) {
if (state->BytesPerPixel > 1 && state->BytesPerPixel * 8 != wc->current_depth && canmatchdepth())
return -1;
if (state->Width < wc->current_width && state->Height < wc->current_height) {
if ((currprefs.gf[GF_RTG].gfx_filter_autoscale == 1 || (currprefs.gf[GF_RTG].gfx_filter_autoscale == 2 && currprefs.win32_rtgallowscaling)) && !canmatchdepth())
return 0;
}
if (state->Width != wc->current_width ||
state->Height != wc->current_height)
return 1;
if (state->Width == wc->current_width &&
state->Height == wc->current_height) {
if (state->BytesPerPixel * 8 == wc->current_depth || state->BytesPerPixel == 1)
return 0;
if (!canmatchdepth())
return 0;
}
return 1;
} else {
if (mon->currentmode.current_width != wc->current_width ||
mon->currentmode.current_height != wc->current_height ||
mon->currentmode.current_depth != wc->current_depth)
return -1;
if (!avidinfo->outbuffer->bufmem_lockable)
return -1;
}
} else if (isfullscreen () == 0) {
/* windowed to windowed */
return -1;
} else {
/* fullwindow to fullwindow */
if (mon->screen_is_picasso) {
if (currprefs.gf[GF_RTG].gfx_filter_autoscale && ((wc->native_width > state->Width && wc->native_height >= state->Height) || (wc->native_height > state->Height && wc->native_width >= state->Width)))
return -1;
if (currprefs.win32_rtgallowscaling && (state->Width != wc->native_width || state->Height != wc->native_height))
return -1;
#if 0
if (wc->native_width < state->Width || wc->native_height < state->Height)
return 1;
#endif
}
return -1;
}
return 0;
}
void gfx_set_picasso_state(int monid, int on)
{
struct AmigaMonitor *mon = &AMonitors[monid];
struct winuae_currentmode wc;
struct apmode *newmode, *oldmode;
struct gfx_filterdata *newf, *oldf;
int mode;
if (mon->screen_is_picasso == on)
return;
mon->screen_is_picasso = on;
rp_rtg_switch ();
memcpy (&wc, &mon->currentmode, sizeof (wc));
newmode = &currprefs.gfx_apmode[on ? 1 : 0];
oldmode = &currprefs.gfx_apmode[on ? 0 : 1];
newf = &currprefs.gf[on ? 1 : 0];
oldf = &currprefs.gf[on ? 0 : 1];
updatemodes(mon);
update_gfxparams(mon);
// if filter changes, need to reset
mode = 0;
if (newf->gfx_filter != oldf->gfx_filter)
mode = -1;
for (int i = 0; i <= 2 * MAX_FILTERSHADERS; i++) {
if (_tcscmp(newf->gfx_filtershader[i], oldf->gfx_filtershader[i]))
mode = -1;
if (_tcscmp(newf->gfx_filtermask[i], oldf->gfx_filtermask[i]))
mode = -1;
}
// if screen parameter changes, need to reopen window
if (newmode->gfx_fullscreen != oldmode->gfx_fullscreen ||
(newmode->gfx_fullscreen && (
newmode->gfx_backbuffers != oldmode->gfx_backbuffers ||
newmode->gfx_display != oldmode->gfx_display ||
newmode->gfx_refreshrate != oldmode->gfx_refreshrate ||
newmode->gfx_strobo != oldmode->gfx_strobo ||
newmode->gfx_vflip != oldmode->gfx_vflip ||
newmode->gfx_vsync != oldmode->gfx_vsync))) {
mode = 1;
}
if (mode <= 0) {
int m = modeswitchneeded(mon, &wc);
if (m > 0)
mode = m;
if (m < 0 && !mode)
mode = m;
if (!mode)
goto end;
}
if (mode < 0) {
open_windows(mon, true, true);
} else {
open_screen(mon); // reopen everything
}
end:
#ifdef RETROPLATFORM
rp_set_hwnd (mon->hAmigaWnd);
#endif
}
static void updatepicasso96(struct AmigaMonitor *mon)
{
#ifdef PICASSO96
struct picasso_vidbuf_description *vidinfo = &picasso_vidinfo[mon->monitor_id];
vidinfo->rowbytes = 0;
vidinfo->pixbytes = mon->currentmode.current_depth / 8;
vidinfo->rgbformat = 0;
vidinfo->extra_mem = 1;
vidinfo->height = mon->currentmode.current_height;
vidinfo->width = mon->currentmode.current_width;
vidinfo->depth = mon->currentmode.current_depth;
vidinfo->offset = 0;
vidinfo->splitypos = -1;
#endif
}
void gfx_set_picasso_modeinfo(int monid, RGBFTYPE rgbfmt)
{
struct AmigaMonitor *mon = &AMonitors[monid];
struct picasso96_state_struct *state = &picasso96_state[mon->monitor_id];
int need;
if (!mon->screen_is_picasso)
return;
gfx_set_picasso_colors(monid, rgbfmt);
updatemodes(mon);
need = modeswitchneeded(mon, &mon->currentmode);
update_gfxparams(mon);
if (need > 0) {
open_screen(mon);
} else if (need < 0) {
struct winuae_currentmode *wc = &mon->currentmode;
if (state->ModeChanged) {
open_windows(mon, true, true);
}
}
state->ModeChanged = false;
#ifdef RETROPLATFORM
rp_set_hwnd(mon->hAmigaWnd);
#endif
target_graphics_buffer_update(monid);
}
#endif
void gfx_set_picasso_colors(int monid, RGBFTYPE rgbfmt)
{
alloc_colors_picasso(red_bits, green_bits, blue_bits, red_shift, green_shift, blue_shift, rgbfmt, p96_rgbx16);
}
static void gfxmode_reset(int monid)
{
struct amigadisplay *ad = &adisplays[monid];
struct uae_filter **usedfilter = &AMonitors[monid].usedfilter;
#ifdef GFXFILTER
*usedfilter = NULL;
if (currprefs.gf[ad->gf_index].gfx_filter > 0) {
int i = 0;
while (uaefilters[i].name) {
if (uaefilters[i].type == currprefs.gf[ad->gf_index].gfx_filter) {
*usedfilter = &uaefilters[i];
break;
}
i++;
}
}
#endif
}
int machdep_init(void)
{
for (int i = 0; i < MAX_AMIGAMONITORS; i++) {
struct AmigaMonitor *mon = &AMonitors[i];
struct amigadisplay *ad = &adisplays[i];
mon->monitor_id = i;
ad->picasso_requested_on = 0;
ad->picasso_on = 0;
mon->screen_is_picasso = 0;
memset(&mon->currentmode, 0, sizeof(*&mon->currentmode));
}
#ifdef LOGITECHLCD
lcd_open ();
#endif
systray (hHiddenWnd, FALSE);
return 1;
}
void machdep_free(void)
{
#ifdef LOGITECHLCD
lcd_close ();
#endif
}
int graphics_init(bool mousecapture)
{
systray (hHiddenWnd, TRUE);
systray (hHiddenWnd, FALSE);
d3d_select(&currprefs);
gfxmode_reset(0);
if (open_windows(&AMonitors[0], mousecapture, false)) {
if (currprefs.monitoremu_mon > 0 && currprefs.monitoremu) {
gfxmode_reset(currprefs.monitoremu_mon);
open_windows(&AMonitors[currprefs.monitoremu_mon], mousecapture, false);
}
return true;
}
return false;
}
int graphics_setup(void)
{
if (!screen_cs_allocated) {
InitializeCriticalSection(&screen_cs);
screen_cs_allocated = true;
}
#ifdef PICASSO96
InitPicasso96(0);
#endif
return 1;
}
void graphics_leave(void)
{
for (int i = 0; i < MAX_AMIGAMONITORS; i++) {
close_windows(&AMonitors[i]);
}
}
uae_u32 OSDEP_minimize_uae (void)
{
struct AmigaMonitor *mon = &AMonitors[0];
return ShowWindow(mon->hAmigaWnd, SW_MINIMIZE);
}
typedef HRESULT (CALLBACK* DWMENABLEMMCSS)(BOOL);
static void setDwmEnableMMCSS (bool state)
{
HMODULE hm = GetModuleHandle(_T("dwmapi.dll"));
if (hm) {
DWMENABLEMMCSS pDwmEnableMMCSS;
pDwmEnableMMCSS = (DWMENABLEMMCSS)GetProcAddress(hm, "DwmEnableMMCSS");
if (pDwmEnableMMCSS)
pDwmEnableMMCSS(state);
}
}
void close_windows(struct AmigaMonitor *mon)
{
struct vidbuf_description *avidinfo = &adisplays[mon->monitor_id].gfxvidinfo;
setDwmEnableMMCSS (FALSE);
reset_sound ();
#if defined (GFXFILTER)
S2X_free(mon->monitor_id);
#endif
freevidbuffer(mon->monitor_id, &avidinfo->drawbuffer);
freevidbuffer(mon->monitor_id, &avidinfo->tempbuffer);
close_hwnds(mon);
}
static void createstatuswindow(struct AmigaMonitor *mon)
{
RECT rc;
HLOCAL hloc;
LPINT lpParts;
int drive_width, hd_width, cd_width, power_width;
int fps_width, idle_width, snd_width, joy_width, net_width;
int joys = currprefs.win32_statusbar > 1 ? 2 : 0;
int num_parts = 12 + joys + 1;
float scale = 1.0;
WINDOWINFO wi;
int extra;
if (mon->hStatusWnd) {
ShowWindow(mon->hStatusWnd, SW_HIDE);
DestroyWindow(mon->hStatusWnd);
mon->hStatusWnd = NULL;
}
if (currprefs.win32_statusbar == 0 || mon->monitor_id > 0)
return;
if (isfullscreen () != 0)
return;
if (currprefs.win32_borderless)
return;
mon->hStatusWnd = CreateWindowEx (
WS_EX_COMPOSITED, STATUSCLASSNAME, (LPCTSTR) NULL, SBARS_TOOLTIPS | WS_CHILD | WS_VISIBLE,
0, 0, 0, 0, mon->hMainWnd, (HMENU) 1, hInst, NULL);
if (!mon->hStatusWnd)
return;
if (g_darkModeSupported) {
BOOL value = g_darkModeEnabled;
DwmSetWindowAttribute(mon->hStatusWnd, DWMWA_USE_IMMERSIVE_DARK_MODE, &value, sizeof(value));
if (g_darkModeEnabled) {
SubClassStatusBar(mon->hStatusWnd);
}
}
wi.cbSize = sizeof wi;
GetWindowInfo(mon->hMainWnd, &wi);
extra = wi.rcClient.top - wi.rcWindow.top;
scale = getdpiforwindow(mon->hStatusWnd) / 96.0f;
drive_width = (int)(24 * scale);
hd_width = (int)(24 * scale);
cd_width = (int)(24 * scale);
power_width = (int)(42 * scale);
fps_width = (int)(64 * scale);
idle_width = (int)(64 * scale);
net_width = (int)(24 * scale);
if (is_ppc_cpu(&currprefs))
idle_width += (int)(68 * scale);
if (is_x86_cpu(&currprefs))
idle_width += (int)(68 * scale);
snd_width = (int)(72 * scale);
joy_width = (int)(24 * scale);
GetClientRect(mon->hMainWnd, &rc);
/* Allocate an array for holding the right edge coordinates. */
hloc = LocalAlloc (LHND, sizeof (int) * (num_parts + 1));
if (hloc) {
lpParts = (LPINT)LocalLock(hloc);
if (lpParts) {
int i = 0, i1;
// left side, msg area
lpParts[i] = rc.left;
i++;
window_led_msg_start = i;
/* Calculate the right edge coordinate for each part, and copy the coords to the array. */
int startx = rc.right - (drive_width * 4) - power_width - idle_width - fps_width - cd_width - hd_width - snd_width - net_width - joys * joy_width - extra;
for (int j = 0; j < joys; j++) {
lpParts[i] = startx;
i++;
startx += joy_width;
}
window_led_joy_start = i;
if (lpParts[0] >= startx)
lpParts[0] = startx - 1;
// snd
lpParts[i] = startx;
i++;
// cpu
lpParts[i] = lpParts[i - 1] + snd_width;
i++;
// fps
lpParts[i] = lpParts[i - 1] + idle_width;
i++;
// power
lpParts[i] = lpParts[i - 1] + fps_width;
i++;
i1 = i;
// hd
lpParts[i] = lpParts[i - 1] + power_width;
i++;
// cd
lpParts[i] = lpParts[i - 1] + hd_width;
i++;
// net
lpParts[i] = lpParts[i - 1] + cd_width;
i++;
// df0
lpParts[i] = lpParts[i - 1] + net_width;
i++;
// df1
lpParts[i] = lpParts[i - 1] + drive_width;
i++;
// df2
lpParts[i] = lpParts[i - 1] + drive_width;
i++;
// df3
lpParts[i] = lpParts[i - 1] + drive_width;
i++;
// edge
lpParts[i] = lpParts[i - 1] + drive_width;
window_led_msg = lpParts[window_led_msg_start - 1];
window_led_msg_end = lpParts[window_led_msg_start - 1 + 1];
window_led_joys = lpParts[window_led_joy_start - joys];
window_led_joys_end = lpParts[window_led_joy_start - joys + 1];
window_led_hd = lpParts[i1];
window_led_hd_end = lpParts[i1 + 1];
window_led_drives = lpParts[i1 + 3];
window_led_drives_end = lpParts[i1 + 3 + 4];
/* Create the parts */
SendMessage(mon->hStatusWnd, SB_SETPARTS, (WPARAM)num_parts, (LPARAM)lpParts);
LocalUnlock(hloc);
LocalFree(hloc);
}
}
registertouch(mon->hStatusWnd);
}
#if 0
#include <dbt.h>
static int createnotification (HWND hwnd)
{
DEV_BROADCAST_DEVICEINTERFACE NotificationFilter;
HDEVNOTIFY hDevNotify;
ZeroMemory(&NotificationFilter, sizeof(NotificationFilter));
NotificationFilter.dbcc_size = sizeof(DEV_BROADCAST_DEVICEINTERFACE);
NotificationFilter.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
hDevNotify = RegisterDeviceNotification(hMainWnd,
&NotificationFilter, DEVICE_NOTIFY_ALL_INTERFACE_CLASSES);
if(!hDevNotify)
{
write_log (_T("RegisterDeviceNotification failed: %d\n"), GetLastError());
return FALSE;
}
return TRUE;
}
#endif
static int getbestmode(struct AmigaMonitor *mon, int nextbest)
{
int i, startidx;
struct MultiDisplay *md;
int ratio;
int index = -1;
for(;;) {
md = getdisplay2(&currprefs, index);
if (!md)
return 0;
ratio = mon->currentmode.native_width > mon->currentmode.native_height ? 1 : 0;
for (i = 0; md->DisplayModes[i].depth >= 0; i++) {
struct PicassoResolution *pr = &md->DisplayModes[i];
if (pr->res.width == mon->currentmode.native_width && pr->res.height == mon->currentmode.native_height)
break;
}
if (md->DisplayModes[i].depth >= 0) {
if (!nextbest)
break;
while (md->DisplayModes[i].res.width == mon->currentmode.native_width && md->DisplayModes[i].res.height == mon->currentmode.native_height)
i++;
} else {
i = 0;
}
// first iterate only modes that have similar aspect ratio
startidx = i;
for (; md->DisplayModes[i].depth >= 0; i++) {
struct PicassoResolution *pr = &md->DisplayModes[i];
int r = pr->res.width > pr->res.height ? 1 : 0;
if (pr->res.width >= mon->currentmode.native_width && pr->res.height >= mon->currentmode.native_height && r == ratio) {
write_log (_T("FS: %dx%d -> %dx%d %d %d\n"), mon->currentmode.native_width, mon->currentmode.native_height,
pr->res.width, pr->res.height, ratio, index);
mon->currentmode.native_width = pr->res.width;
mon->currentmode.native_height = pr->res.height;
mon->currentmode.current_width = mon->currentmode.native_width;
mon->currentmode.current_height = mon->currentmode.native_height;
goto end;
}
}
// still not match? check all modes
i = startidx;
for (; md->DisplayModes[i].depth >= 0; i++) {
struct PicassoResolution *pr = &md->DisplayModes[i];
int r = pr->res.width > pr->res.height ? 1 : 0;
if (pr->res.width >= mon->currentmode.native_width && pr->res.height >= mon->currentmode.native_height) {
write_log (_T("FS: %dx%d -> %dx%d\n"), mon->currentmode.native_width, mon->currentmode.native_height,
pr->res.width, pr->res.height);
mon->currentmode.native_width = pr->res.width;
mon->currentmode.native_height = pr->res.height;
mon->currentmode.current_width = mon->currentmode.native_width;
mon->currentmode.current_height = mon->currentmode.native_height;
goto end;
}
}
index++;
}
end:
if (index >= 0) {
currprefs.gfx_apmode[mon->screen_is_picasso ? APMODE_RTG : APMODE_NATIVE].gfx_display =
changed_prefs.gfx_apmode[mon->screen_is_picasso ? APMODE_RTG : APMODE_NATIVE].gfx_display = index;
write_log (L"Can't find mode %dx%d ->\n", mon->currentmode.native_width, mon->currentmode.native_height);
write_log (L"Monitor switched to '%s'\n", md->adaptername);
}
return 1;
}
float target_getcurrentvblankrate(int monid)
{
struct AmigaMonitor *mon = &AMonitors[monid];
float vb;
if (currprefs.gfx_variable_sync)
return (float)mon->currentmode.freq;
if (get_display_vblank_params(-1, NULL, NULL, &vb, NULL)) {
return vb;
} else {
return D3D_getrefreshrate(0);
}
}
static void movecursor (int x, int y)
{
write_log (_T("SetCursorPos %dx%d\n"), x, y);
SetCursorPos (x, y);
}
static void getextramonitorpos(struct AmigaMonitor *mon, RECT *r)
{
TCHAR buf[100];
RECT r1, r2;
int x, y;
bool got = true;
_stprintf(buf, _T("MainPosX_%d"), mon->monitor_id);
if (!regqueryint(NULL, buf, &x)) {
got = false;
}
_stprintf(buf, _T("MainPosY_%d"), mon->monitor_id);
if (!regqueryint(NULL, buf, &y)) {
got = false;
}
if (got) {
POINT pt;
pt.x = x;
pt.y = y;
if (!MonitorFromPoint(pt, MONITOR_DEFAULTTONULL)) {
got = false;
}
}
// find rightmost window edge
int monid = MAX_AMIGAMONITORS - 1;
int rightmon = -1;
int rightedge = 0;
HWND hwnd = NULL;
for (;;) {
if (monid < 1)
break;
monid--;
hwnd = AMonitors[monid].hMainWnd;
if (!hwnd)
continue;
GetWindowRect(hwnd, &r1);
if (r1.right > rightedge) {
rightedge = r1.right;
rightmon = monid;
}
}
if (rightmon < 0 && !got)
return;
hwnd = AMonitors[rightmon].hMainWnd;
GetWindowRect(hwnd, &r1);
r2 = r1;
getextendedframebounds(hwnd, &r2);
int width = r->right - r->left;
int height = r->bottom - r->top;
if (got) {
r->left = x;
r->top = y;
} else {
r->left = r1.right - ((r2.left - r1.left) + (r1.right - r2.right));
r->top = r1.top;
}
r->bottom = r->top + height;
r->right = r->left + width;
}
static int create_windows(struct AmigaMonitor *mon)
{
static bool firstwindow = true;
int dxfs = mon->currentmode.flags & (DM_DX_FULLSCREEN);
int d3dfs = mon->currentmode.flags & (DM_D3D_FULLSCREEN);
int fsw = mon->currentmode.flags & (DM_W_FULLSCREEN);
DWORD exstyle = (currprefs.win32_notaskbarbutton ? WS_EX_TOOLWINDOW : WS_EX_APPWINDOW) | 0;
DWORD flags = 0;
int borderless = currprefs.win32_borderless;
DWORD style = WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN | WS_CLIPSIBLINGS;
int cyborder = GetSystemMetrics (SM_CYFRAME);
int gap = 0;
int x, y, w, h;
struct MultiDisplay *md;
md = getdisplay(&currprefs, mon->monitor_id);
if (mon->monitor_id && fsw) {
struct MultiDisplay *md2 = NULL;
int idx = 0;
for (;;) {
md2 = getdisplay2(&currprefs, idx);
if (md2 == md)
break;
if (!md2)
break;
idx++;
}
for (int i = 0; i <= mon->monitor_id; i++) {
md2 = getdisplay2(&currprefs, idx);
if (!md2)
idx = 0;
else
idx++;
}
if (md2)
md = md2;
}
mon->md = md;
if (mon->hAmigaWnd) {
RECT r;
int w, h, x, y;
int nw, nh, nx, ny;
if (minimized) {
minimized = -1;
return 1;
}
#if 0
if (minimized && hMainWnd) {
unsetminimized ();
ShowWindow (hMainWnd, SW_SHOW);
ShowWindow (hMainWnd, SW_RESTORE);
}
#endif
GetWindowRect (mon->hAmigaWnd, &r);
int sbheight = currprefs.win32_statusbar && !currprefs.win32_borderless ? getstatuswindowheight(mon->monitor_id, mon->hAmigaWnd) : 0;
int dpi = getdpiforwindow(mon->hAmigaWnd);
x = r.left;
y = r.top;
w = r.right - r.left;
h = r.bottom - r.top;
nx = x;
ny = y;
if (mon->screen_is_picasso) {
nw = mon->currentmode.current_width;
nh = mon->currentmode.current_height;
} else {
nw = currprefs.gfx_monitor[mon->monitor_id].gfx_size_win.width;
nh = currprefs.gfx_monitor[mon->monitor_id].gfx_size_win.height;
}
if (fsw || dxfs) {
RECT rc = md->rect;
nx = rc.left;
ny = rc.top;
nw = rc.right - rc.left;
nh = rc.bottom - rc.top;
} else if (d3dfs) {
RECT rc = md->rect;
nw = mon->currentmode.native_width;
nh = mon->currentmode.native_height;
if (rc.left >= 0)
nx = rc.left;
else
nx = rc.left + (rc.right - rc.left - nw);
if (rc.top >= 0)
ny = rc.top;
else
ny = rc.top + (rc.bottom - rc.top - nh);
}
if (w != nw || h != nh || x != nx || y != ny || sbheight != mon->window_extra_height_bar || dpi != mon->dpi) {
w = nw;
h = nh;
x = nx;
y = ny;
mon->in_sizemove++;
if (mon->hMainWnd && !fsw && !dxfs && !d3dfs && !rp_isactive()) {
if (dpi != mon->dpi) {
mon->window_extra_height -= mon->window_extra_height_bar;
mon->window_extra_height += sbheight;
} else {
mon->window_extra_height += (sbheight - mon->window_extra_height_bar);
}
GetWindowRect(mon->hMainWnd, &r);
#if 0
RECT r2;
GetClientRect(mon->hMainWnd, &r2);
if (pAdjustWindowRectExForDpi) {
HMONITOR mon = MonitorFromRect(&r, MONITOR_DEFAULTTONEAREST);
pAdjustWindowRectExForDpi(&r, borderless ? WS_POPUP : style, FALSE, exstyle, getdpiformonitor(mon));
} else {
AdjustWindowRectEx(&r, borderless ? WS_POPUP : style, FALSE, exstyle);
}
#endif
x = r.left;
y = r.top;
SetWindowPos(mon->hMainWnd, HWND_TOP, x, y, w + mon->window_extra_width, h + mon->window_extra_height,
SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOSENDCHANGING | SWP_NOZORDER);
x = gap;
y = gap;
}
SetWindowPos(mon->hAmigaWnd, HWND_TOP, x, y, w, h,
SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOSENDCHANGING | SWP_NOZORDER);
mon->in_sizemove--;
mon->dpi = dpi;
} else {
w = nw;
h = nh;
x = nx;
y = ny;
}
createstatuswindow(mon);
createstatusline(mon->hAmigaWnd, mon->monitor_id);
updatewinrect(mon, false);
GetWindowRect (mon->hMainWnd, &mon->mainwin_rect);
if (d3dfs || dxfs)
movecursor (x + w / 2, y + h / 2);
write_log (_T("window already open (%dx%d %dx%d)\n"),
mon->amigawin_rect.left, mon->amigawin_rect.top, mon->amigawin_rect.right - mon->amigawin_rect.left, mon->amigawin_rect.bottom - mon->amigawin_rect.top);
updatemouseclip(mon);
rp_screenmode_changed ();
mon->window_extra_height_bar = sbheight;
return 1;
}
gfx_lock();
D3D_free(mon->monitor_id, false);
gfx_unlock();
if (fsw && !borderless)
borderless = 1;
window_led_drives = 0;
window_led_drives_end = 0;
mon->hMainWnd = NULL;
x = 0; y = 0;
int sbheight = currprefs.win32_statusbar && !currprefs.win32_borderless ? getstatuswindowheight(mon->monitor_id, NULL) : 0;
if (borderless)
sbheight = cyborder = 0;
if (!dxfs && !d3dfs) {
RECT rc;
int stored_x = 1, stored_y = sbheight + cyborder;
int oldx, oldy;
int first = 2;
regqueryint (NULL, _T("MainPosX"), &stored_x);
regqueryint (NULL, _T("MainPosY"), &stored_y);
if (borderless) {
stored_x = currprefs.gfx_monitor[mon->monitor_id].gfx_size_win.x;
stored_y = currprefs.gfx_monitor[mon->monitor_id].gfx_size_win.y;
}
while (first) {
first--;
if (stored_x < GetSystemMetrics (SM_XVIRTUALSCREEN))
stored_x = GetSystemMetrics (SM_XVIRTUALSCREEN);
if (stored_y < GetSystemMetrics (SM_YVIRTUALSCREEN) + sbheight + cyborder)
stored_y = GetSystemMetrics (SM_YVIRTUALSCREEN) + sbheight + cyborder;
if (stored_x > GetSystemMetrics (SM_CXVIRTUALSCREEN))
rc.left = 1;
else
rc.left = stored_x;
if (stored_y > GetSystemMetrics (SM_CYVIRTUALSCREEN))
rc.top = 1;
else
rc.top = stored_y;
rc.right = rc.left + gap + mon->currentmode.current_width + gap;
rc.bottom = rc.top + gap + mon->currentmode.current_height + gap + sbheight;
oldx = rc.left;
oldy = rc.top;
if (pAdjustWindowRectExForDpi) {
HMONITOR mon = MonitorFromRect(&rc, MONITOR_DEFAULTTONEAREST);
pAdjustWindowRectExForDpi(&rc, borderless ? WS_POPUP : style, FALSE, exstyle, getdpiformonitor(mon));
} else {
AdjustWindowRectEx(&rc, borderless ? WS_POPUP : style, FALSE, exstyle);
}
mon->win_x_diff = rc.left - oldx;
mon->win_y_diff = rc.top - oldy;
if (MonitorFromRect (&rc, MONITOR_DEFAULTTONULL) == NULL) {
write_log (_T("window coordinates are not visible on any monitor, reseting..\n"));
stored_x = stored_y = 0;
continue;
}
if (mon->monitor_id > 0) {
getextramonitorpos(mon, &rc);
}
break;
}
if (fsw) {
rc = md->rect;
flags |= WS_EX_TOPMOST;
style = WS_POPUP;
mon->currentmode.native_width = rc.right - rc.left;
mon->currentmode.native_height = rc.bottom - rc.top;
}
flags |= currprefs.win32_main_alwaysontop ? WS_EX_TOPMOST : 0;
if (!borderless) {
RECT rc2;
int sbheight2 = -1;
for (;;) {
mon->hMainWnd = CreateWindowEx(WS_EX_ACCEPTFILES | exstyle | flags,
_T("PCsuxRox"), _T("WinUAE"),
style,
rc.left, rc.top,
rc.right - rc.left, rc.bottom - rc.top,
NULL, NULL, hInst, NULL);
if (!mon->hMainWnd) {
write_log(_T("main window creation failed\n"));
return 0;
}
if (sbheight && sbheight2 < 0 && !fsw) {
// recheck, system could have multiple monitors with different DPI
sbheight2 = getstatuswindowheight(mon->monitor_id, mon->hMainWnd);
if (sbheight2 != sbheight) {
rc.bottom -= sbheight;
rc.bottom += sbheight2;
sbheight = sbheight2;
DestroyWindow(mon->hMainWnd);
mon->hMainWnd = NULL;
continue;
}
}
break;
}
if (g_darkModeSupported) {
BOOL value = g_darkModeEnabled;
DwmSetWindowAttribute(mon->hMainWnd, DWMWA_USE_IMMERSIVE_DARK_MODE, &value, sizeof(value));
}
GetWindowRect(mon->hMainWnd, &rc2);
mon->window_extra_width = rc2.right - rc2.left - mon->currentmode.current_width;
mon->window_extra_height = rc2.bottom - rc2.top - mon->currentmode.current_height;
createstatuswindow(mon);
createstatusline(mon->hMainWnd, mon->monitor_id);
} else {
x = rc.left;
y = rc.top;
}
w = mon->currentmode.native_width;
h = mon->currentmode.native_height;
} else {
RECT rc;
getbestmode(mon, 0);
w = mon->currentmode.native_width;
h = mon->currentmode.native_height;
rc = md->rect;
if (rc.left >= 0)
x = rc.left;
else
x = rc.left + (rc.right - rc.left - w);
if (rc.top >= 0)
y = rc.top;
else
y = rc.top + (rc.bottom - rc.top - h);
}
if (rp_isactive () && !dxfs && !d3dfs && !fsw) {
HWND parent = rp_getparent ();
mon->hAmigaWnd = CreateWindowEx (dxfs || d3dfs ? WS_EX_ACCEPTFILES | WS_EX_TOPMOST : WS_EX_ACCEPTFILES | WS_EX_TOOLWINDOW | (currprefs.win32_main_alwaysontop ? WS_EX_TOPMOST : 0),
_T("AmigaPowah"), _T("WinUAE"),
WS_POPUP,
0, 0, w, h,
parent, NULL, hInst, NULL);
} else {
mon->hAmigaWnd = CreateWindowEx (
((dxfs || d3dfs || currprefs.win32_main_alwaysontop) ? WS_EX_TOPMOST : WS_EX_ACCEPTFILES) | exstyle,
_T("AmigaPowah"), _T("WinUAE"),
((dxfs || d3dfs || currprefs.headless) ? WS_POPUP : (WS_CLIPCHILDREN | WS_CLIPSIBLINGS | (mon->hMainWnd ? WS_VISIBLE | WS_CHILD : WS_VISIBLE | WS_POPUP | WS_SYSMENU | WS_MINIMIZEBOX))),
x, y, w, h,
borderless ? NULL : (mon->hMainWnd ? mon->hMainWnd : NULL),
NULL, hInst, NULL);
}
if (!mon->hAmigaWnd) {
write_log (_T("creation of amiga window failed\n"));
close_hwnds(mon);
return 0;
}
if (g_darkModeSupported) {
BOOL value = g_darkModeEnabled;
DwmSetWindowAttribute(mon->hAmigaWnd, DWMWA_USE_IMMERSIVE_DARK_MODE, &value, sizeof(value));
}
if (mon->hMainWnd == NULL) {
mon->hMainWnd = mon->hAmigaWnd;
registertouch(mon->hAmigaWnd);
} else {
registertouch(mon->hMainWnd);
registertouch(mon->hAmigaWnd);
}
updatewinrect(mon, true);
GetWindowRect(mon->hMainWnd, &mon->mainwin_rect);
if (dxfs || d3dfs)
movecursor (x + w / 2, y + h / 2);
addnotifications (mon->hAmigaWnd, FALSE, FALSE);
mon->window_extra_height_bar = sbheight;
mon->dpi = getdpiforwindow(mon->hAmigaWnd);
if (mon->monitor_id) {
ShowWindow(mon->hMainWnd, SW_SHOWNOACTIVATE);
UpdateWindow(mon->hMainWnd);
ShowWindow(mon->hAmigaWnd, SW_SHOWNOACTIVATE);
UpdateWindow(mon->hAmigaWnd);
} else {
createblankwindows();
if (mon->hMainWnd != mon->hAmigaWnd) {
if (!currprefs.headless && !rp_isactive())
ShowWindow(mon->hMainWnd, firstwindow ? (currprefs.win32_start_minimized ? SW_SHOWMINIMIZED : SW_SHOWDEFAULT) : SW_SHOWNORMAL);
UpdateWindow(mon->hMainWnd);
}
if (!currprefs.headless && !rp_isactive())
ShowWindow(mon->hAmigaWnd, SW_SHOWNORMAL);
UpdateWindow(mon->hAmigaWnd);
firstwindow = false;
setDwmEnableMMCSS(true);
rawinput_alloc();
if (currprefs.win32_shutdown_notification && !rp_isactive()) {
typedef BOOL(WINAPI *SHUTDOWNBLOCKREASONCREATE)(HWND, LPCWSTR);
SHUTDOWNBLOCKREASONCREATE pShutdownBlockReasonCreate;
pShutdownBlockReasonCreate = (SHUTDOWNBLOCKREASONCREATE)GetProcAddress(userdll, "ShutdownBlockReasonCreate");
if (pShutdownBlockReasonCreate) {
TCHAR tmp[MAX_DPATH];
WIN32GUI_LoadUIString(IDS_SHUTDOWN_NOTIFICATION, tmp, MAX_DPATH);
if (!pShutdownBlockReasonCreate(mon->hMainWnd, tmp)) {
write_log(_T("ShutdownBlockReasonCreate %08x\n"), GetLastError());
}
}
}
}
return 1;
}
static void allocsoftbuffer(int monid, const TCHAR *name, struct vidbuffer *buf, int flags, int width, int height, int depth)
{
struct vidbuf_description *vidinfo = &adisplays[monid].gfxvidinfo;
buf->monitor_id = monid;
buf->pixbytes = (depth + 7) / 8;
buf->width_allocated = (width + 7) & ~7;
buf->height_allocated = height;
if (!(flags & DM_SWSCALE)) {
if (buf != &vidinfo->drawbuffer)
return;
buf->bufmem = NULL;
buf->bufmemend = NULL;
buf->realbufmem = NULL;
buf->bufmem_allocated = NULL;
buf->bufmem_lockable = true;
write_log (_T("Mon %d reserved %s temp buffer (%d*%d*%d)\n"), monid, name, width, height, depth);
} else if (flags & DM_SWSCALE) {
int w = buf->width_allocated;
int h = buf->height_allocated;
int size = (w * 2) * (h * 2) * buf->pixbytes;
buf->rowbytes = w * 2 * buf->pixbytes;
buf->realbufmem = xcalloc(uae_u8, size);
buf->bufmem_allocated = buf->bufmem = buf->realbufmem + (h / 2) * buf->rowbytes + (w / 2) * buf->pixbytes;
buf->bufmemend = buf->realbufmem + size - buf->rowbytes;
buf->bufmem_lockable = true;
write_log (_T("Mon %d allocated %s temp buffer (%d*%d*%d) = %p\n"), monid, name, width, height, depth, buf->realbufmem);
}
}
static int oldtex_w[MAX_AMIGAMONITORS], oldtex_h[MAX_AMIGAMONITORS], oldtex_rtg[MAX_AMIGAMONITORS];
static BOOL doInit(struct AmigaMonitor *mon)
{
int tmp_depth;
int ret = 0;
retry:
struct vidbuf_description *avidinfo = &adisplays[mon->monitor_id].gfxvidinfo;
struct amigadisplay *ad = &adisplays[mon->monitor_id];
if (wasfullwindow_a == 0)
wasfullwindow_a = currprefs.gfx_apmode[0].gfx_fullscreen == GFX_FULLWINDOW ? 1 : -1;
if (wasfullwindow_p == 0)
wasfullwindow_p = currprefs.gfx_apmode[1].gfx_fullscreen == GFX_FULLWINDOW ? 1 : -1;
gfxmode_reset(mon->monitor_id);
freevidbuffer(mon->monitor_id, &avidinfo->drawbuffer);
freevidbuffer(mon->monitor_id, &avidinfo->tempbuffer);
for (;;) {
updatemodes(mon);
mon->currentmode.native_depth = 0;
tmp_depth = mon->currentmode.current_depth;
if (mon->currentmode.flags & DM_W_FULLSCREEN) {
RECT rc = getdisplay(&currprefs, mon->monitor_id)->rect;
mon->currentmode.native_width = rc.right - rc.left;
mon->currentmode.native_height = rc.bottom - rc.top;
}
if (!create_windows(mon))
goto oops;
#ifdef PICASSO96
if (mon->screen_is_picasso) {
break;
} else {
#endif
struct uae_filter *usedfilter = mon->usedfilter;
mon->currentmode.native_depth = mon->currentmode.current_depth;
if (currprefs.gfx_resolution > avidinfo->gfx_resolution_reserved)
avidinfo->gfx_resolution_reserved = currprefs.gfx_resolution;
if (currprefs.gfx_vresolution > avidinfo->gfx_vresolution_reserved)
avidinfo->gfx_vresolution_reserved = currprefs.gfx_vresolution;
//gfxvidinfo.drawbuffer.gfx_resolution_reserved = RES_SUPERHIRES;
#if defined (GFXFILTER)
if (mon->currentmode.flags & (DM_D3D | DM_SWSCALE)) {
if (!currprefs.gfx_autoresolution) {
mon->currentmode.amiga_width = AMIGA_WIDTH_MAX << currprefs.gfx_resolution;
mon->currentmode.amiga_height = AMIGA_HEIGHT_MAX << currprefs.gfx_vresolution;
} else {
mon->currentmode.amiga_width = AMIGA_WIDTH_MAX << avidinfo->gfx_resolution_reserved;
mon->currentmode.amiga_height = AMIGA_HEIGHT_MAX << avidinfo->gfx_vresolution_reserved;
}
if (avidinfo->gfx_resolution_reserved == RES_SUPERHIRES)
mon->currentmode.amiga_height *= 2;
if (mon->currentmode.amiga_height > 1280)
mon->currentmode.amiga_height = 1280;
avidinfo->drawbuffer.inwidth = avidinfo->drawbuffer.outwidth = mon->currentmode.amiga_width;
avidinfo->drawbuffer.inheight = avidinfo->drawbuffer.outheight = mon->currentmode.amiga_height;
if (usedfilter) {
if ((usedfilter->flags & (UAE_FILTER_MODE_16 | UAE_FILTER_MODE_32)) == (UAE_FILTER_MODE_16 | UAE_FILTER_MODE_32)) {
mon->currentmode.current_depth = mon->currentmode.native_depth;
} else {
mon->currentmode.current_depth = (usedfilter->flags & UAE_FILTER_MODE_32) ? 32 : 16;
}
}
mon->currentmode.pitch = mon->currentmode.amiga_width * mon->currentmode.current_depth >> 3;
}
else
#endif
{
mon->currentmode.amiga_width = mon->currentmode.current_width;
mon->currentmode.amiga_height = mon->currentmode.current_height;
}
avidinfo->drawbuffer.pixbytes = mon->currentmode.current_depth >> 3;
avidinfo->drawbuffer.bufmem = NULL;
avidinfo->drawbuffer.linemem = NULL;
avidinfo->drawbuffer.rowbytes = mon->currentmode.pitch;
break;
#ifdef PICASSO96
}
#endif
}
updatepicasso96(mon);
if (!scrlinebuf)
scrlinebuf = xmalloc (uae_u8, max_uae_width * 4);
avidinfo->drawbuffer.emergmem = scrlinebuf; // memcpy from system-memory to video-memory
avidinfo->drawbuffer.realbufmem = NULL;
avidinfo->drawbuffer.bufmem = NULL;
avidinfo->drawbuffer.bufmem_allocated = NULL;
avidinfo->drawbuffer.bufmem_lockable = false;
avidinfo->outbuffer = &avidinfo->drawbuffer;
avidinfo->inbuffer = &avidinfo->drawbuffer;
if (!mon->screen_is_picasso) {
allocsoftbuffer(mon->monitor_id, _T("draw"), &avidinfo->drawbuffer, mon->currentmode.flags,
1920, 1280, mon->currentmode.current_depth);
if (currprefs.monitoremu || currprefs.cs_cd32fmv || ((currprefs.genlock || currprefs.genlock_effects) && currprefs.genlock_image) || currprefs.cs_color_burst || currprefs.gfx_grayscale) {
allocsoftbuffer(mon->monitor_id, _T("monemu"), &avidinfo->tempbuffer, mon->currentmode.flags,
mon->currentmode.amiga_width > 1024 ? mon->currentmode.amiga_width : 1024,
mon->currentmode.amiga_height > 1024 ? mon->currentmode.amiga_height : 1024,
mon->currentmode.current_depth);
}
init_row_map ();
}
S2X_free(mon->monitor_id);
if (!D3D_isenabled(mon->monitor_id)) {
for (int i = 0; i < MAX_AMIGAMONITORS; i++) {
oldtex_w[i] = oldtex_h[i] = -1;
}
}
if (mon->currentmode.flags & DM_D3D) {
int fmh = mon->screen_is_picasso ? 1 : currprefs.gf[ad->gf_index].gfx_filter_filtermodeh + 1;
int fmv = mon->screen_is_picasso ? 1 : currprefs.gf[ad->gf_index].gfx_filter_filtermodev + 1 - 1;
if (currprefs.gf[ad->gf_index].gfx_filter_filtermodev == 0) {
fmv = fmh;
}
int errv = 0;
const TCHAR *err = D3D_init(mon->hAmigaWnd, mon->monitor_id, mon->currentmode.native_width, mon->currentmode.native_height,
mon->currentmode.current_depth, &mon->currentmode.freq, fmh, fmv, &errv);
if (errv) {
if (errv == -1 && currprefs.gfx_api == 0) {
write_log("Retrying D3D %s\n", err);
changed_prefs.gfx_api = currprefs.gfx_api = 2;
changed_prefs.color_mode = currprefs.color_mode = 5;
update_gfxparams(mon);
goto retry;
}
gfx_hdr = false;
if (currprefs.gfx_api >= 2) {
D3D_free(0, true);
if (err[0] == 0 && currprefs.color_mode != 5) {
changed_prefs.color_mode = currprefs.color_mode = 5;
update_gfxparams(mon);
goto retry;
}
changed_prefs.gfx_api = currprefs.gfx_api = 1;
d3d_select(&currprefs);
error_log(_T("Direct3D11 failed to initialize ('%s'), falling back to Direct3D9."), err);
errv = 0;
err = D3D_init(mon->hAmigaWnd, mon->monitor_id, mon->currentmode.native_width, mon->currentmode.native_height,
mon->currentmode.current_depth, &mon->currentmode.freq, fmh, fmv, &errv);
}
if (errv) {
D3D_free(0, true);
if (isfullscreen() > 0) {
int idx = mon->screen_is_picasso ? 1 : 0;
changed_prefs.gfx_apmode[idx].gfx_fullscreen = currprefs.gfx_apmode[idx].gfx_fullscreen = GFX_FULLWINDOW;
goto retry;
} else if (currprefs.gfx_api > 0) {
changed_prefs.gfx_api = currprefs.gfx_api = 0;
changed_prefs.color_mode = currprefs.color_mode = 5;
changed_prefs.gf[ad->gf_index].gfx_filter = currprefs.gf[ad->gf_index].gfx_filter = 1;
update_gfxparams(mon);
d3d_select(&currprefs);
error_log(_T("Direct3D9/11 failed to initialize ('%s'), falling back to GDI."), err);
errv = 0;
err = D3D_init(mon->hAmigaWnd, mon->monitor_id, mon->currentmode.native_width, mon->currentmode.native_height,
mon->currentmode.current_depth, &mon->currentmode.freq, fmh, fmv, &errv);
if (errv) {
error_log(_T("Failed to initialize any rendering modes."));
}
}
mon->currentmode.current_depth = mon->currentmode.native_depth;
gfxmode_reset(mon->monitor_id);
ret = -1;
goto oops;
}
}
target_graphics_buffer_update(mon->monitor_id);
updatewinrect(mon, true);
}
init_colors(mon->monitor_id);
mon->screen_is_initialized = 1;
display_param_init(mon);
createstatusline(mon->hAmigaWnd, mon->monitor_id);
picasso_refresh(mon->monitor_id);
#ifdef RETROPLATFORM
rp_set_hwnd_delayed ();
#endif
if (isfullscreen () != 0)
setmouseactive(mon->monitor_id, -1);
return 1;
oops:
close_hwnds(mon);
return ret;
}
bool target_graphics_buffer_update(int monid)
{
struct AmigaMonitor *mon = &AMonitors[monid];
struct picasso_vidbuf_description *vidinfo = &picasso_vidinfo[monid];
struct vidbuf_description *avidinfo = &adisplays[monid].gfxvidinfo;
struct picasso96_state_struct *state = &picasso96_state[monid];
static bool graphicsbuffer_retry;
int w, h;
graphicsbuffer_retry = false;
if (mon->screen_is_picasso) {
w = state->Width;
h = state->Height;
} else {
struct vidbuffer *vb = avidinfo->drawbuffer.tempbufferinuse ? &avidinfo->tempbuffer : &avidinfo->drawbuffer;
avidinfo->outbuffer = vb;
w = vb->outwidth;
h = vb->outheight;
}
if (oldtex_w[monid] == w && oldtex_h[monid] == h && oldtex_rtg[monid] == mon->screen_is_picasso)
return false;
if (!w || !h) {
oldtex_w[monid] = w;
oldtex_h[monid] = h;
oldtex_rtg[monid] = mon->screen_is_picasso;
return false;
}
S2X_free(mon->monitor_id);
if (!D3D_alloctexture(mon->monitor_id, w, h)) {
graphicsbuffer_retry = true;
return false;
}
oldtex_w[monid] = w;
oldtex_h[monid] = h;
oldtex_rtg[monid] = mon->screen_is_picasso;
write_log (_T("Buffer %d size (%d*%d) %s\n"), monid, w, h, mon->screen_is_picasso ? _T("RTG") : _T("Native"));
if ((mon->currentmode.flags & DM_SWSCALE) && !mon->screen_is_picasso) {
if (!S2X_init(mon->monitor_id, mon->currentmode.native_width, mon->currentmode.native_height, mon->currentmode.native_depth))
return false;
}
return true;
}
static void updatedisplayarea2(int monid)
{
struct AmigaMonitor *mon = &AMonitors[monid];
struct amigadisplay *ad = &adisplays[monid];
if (!mon->screen_is_initialized)
return;
D3D_refresh(monid);
}
void updatedisplayarea(int monid)
{
set_custom_limits(-1, -1, -1, -1, false);
if (monid >= 0) {
updatedisplayarea2(monid);
} else {
for (int i = 0; i < MAX_AMIGAMONITORS; i++) {
updatedisplayarea2(i);
}
}
}
void updatewinfsmode(int monid, struct uae_prefs *p)
{
struct MultiDisplay *md;
fixup_prefs_dimensions (p);
if (isfullscreen_2 (p) != 0) {
p->gfx_monitor[monid].gfx_size = p->gfx_monitor[monid].gfx_size_fs;
} else {
p->gfx_monitor[monid].gfx_size = p->gfx_monitor[monid].gfx_size_win;
}
md = getdisplay(p, monid);
set_config_changed ();
}
bool toggle_3d_debug(void)
{
if (isvsync_chipset() < 0) {
beamracer_debug = !beamracer_debug;
if (D3D_debug) {
D3D_debug(0, beamracer_debug);
}
reset_drawing();
return true;
}
return false;
}
int rtg_index = -1;
// -2 = default
// -1 = prev
// 0 = chipset
// 1..4 = rtg
// 5 = next
bool toggle_rtg (int monid, int mode)
{
struct amigadisplay *ad = &adisplays[monid];
int old_index = rtg_index;
if (monid > 0) {
return true;
}
if (mode < -1 && rtg_index >= 0)
return true;
for (;;) {
if (mode == -1) {
rtg_index--;
} else if (mode >= 0 && mode <= MAX_RTG_BOARDS) {
rtg_index = mode - 1;
} else {
rtg_index++;
}
if (rtg_index >= MAX_RTG_BOARDS) {
rtg_index = -1;
} else if (rtg_index < -1) {
rtg_index = MAX_RTG_BOARDS - 1;
}
if (rtg_index < 0) {
if (ad->picasso_on) {
gfxboard_rtg_disable(monid, old_index);
ad->picasso_requested_on = false;
statusline_add_message(STATUSTYPE_DISPLAY, _T("Chipset display"));
set_config_changed();
return false;
}
return false;
}
struct rtgboardconfig *r = &currprefs.rtgboards[rtg_index];
if (r->rtgmem_size > 0 && r->monitor_id == monid) {
if (r->rtgmem_type >= GFXBOARD_HARDWARE) {
int idx = gfxboard_toggle(r->monitor_id, rtg_index, mode >= -1);
if (idx >= 0) {
rtg_index = idx;
return true;
}
if (idx < -1) {
rtg_index = -1;
return false;
}
} else {
gfxboard_toggle(r->monitor_id, -1, -1);
if (mode < -1)
return true;
devices_unsafeperiod();
gfxboard_rtg_disable(monid, old_index);
// can always switch from RTG to custom
if (ad->picasso_requested_on && ad->picasso_on) {
ad->picasso_requested_on = false;
rtg_index = -1;
set_config_changed();
return true;
}
if (ad->picasso_on)
return false;
// can only switch from custom to RTG if there is some mode active
if (picasso_is_active(r->monitor_id)) {
picasso_enablescreen(r->monitor_id, 1);
ad->picasso_requested_on = true;
statusline_add_message(STATUSTYPE_DISPLAY, _T("RTG %d: %s"), rtg_index + 1, _T("UAEGFX"));
set_config_changed();
return true;
}
}
}
if (mode >= 0 && mode <= MAX_RTG_BOARDS) {
rtg_index = old_index;
return false;
}
}
return false;
}
void close_rtg(int monid, bool reset)
{
struct AmigaMonitor *mon = &AMonitors[monid];
close_windows(mon);
if (reset) {
mon->screen_is_picasso = false;
}
}
void toggle_fullscreen(int monid, int mode)
{
struct amigadisplay *ad = &adisplays[monid];
int *p = ad->picasso_on ? &changed_prefs.gfx_apmode[1].gfx_fullscreen : &changed_prefs.gfx_apmode[0].gfx_fullscreen;
int wfw = ad->picasso_on ? wasfullwindow_p : wasfullwindow_a;
int v = *p;
static int prevmode = -1;
if (mode < 0) {
// fullwindow->window->fullwindow.
// fullscreen->window->fullscreen.
// window->fullscreen->window.
if (v == GFX_FULLWINDOW) {
prevmode = v;
v = GFX_WINDOW;
} else if (v == GFX_WINDOW) {
if (prevmode < 0) {
v = GFX_FULLSCREEN;
prevmode = v;
} else {
v = prevmode;
}
} else if (v == GFX_FULLSCREEN) {
if (wfw > 0)
v = GFX_FULLWINDOW;
else
v = GFX_WINDOW;
}
} else if (mode == 0) {
prevmode = v;
// fullscreen <> window
if (v == GFX_FULLSCREEN)
v = GFX_WINDOW;
else
v = GFX_FULLSCREEN;
} else if (mode == 1) {
prevmode = v;
// fullscreen <> fullwindow
if (v == GFX_FULLSCREEN)
v = GFX_FULLWINDOW;
else
v = GFX_FULLSCREEN;
} else if (mode == 2) {
prevmode = v;
// window <> fullwindow
if (v == GFX_FULLWINDOW)
v = GFX_WINDOW;
else
v = GFX_FULLWINDOW;
} else if (mode == 10) {
v = GFX_WINDOW;
}
*p = v;
devices_unsafeperiod();
updatewinfsmode(monid, &changed_prefs);
}
HDC gethdc(int monid)
{
HDC hdc = 0;
if (D3D_isenabled(0))
return D3D_getDC(monid, 0);
return hdc;
}
void releasehdc(int monid, HDC hdc)
{
if (D3D_isenabled(0)) {
D3D_getDC(monid, hdc);
return;
}
}
TCHAR *outGUID(const GUID *guid)
{
static TCHAR gb[64];
if (guid == NULL)
return _T("NULL");
_stprintf(gb, _T("{%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}"),
guid->Data1, guid->Data2, guid->Data3,
guid->Data4[0], guid->Data4[1], guid->Data4[2], guid->Data4[3],
guid->Data4[4], guid->Data4[5], guid->Data4[6], guid->Data4[7]);
return gb;
}
const TCHAR *DXError(HRESULT ddrval)
{
static TCHAR dderr[1000];
_stprintf(dderr, _T("%08X S=%d F=%04X C=%04X (%d)"),
ddrval, (ddrval & 0x80000000) ? 1 : 0,
HRESULT_FACILITY(ddrval),
HRESULT_CODE(ddrval),
HRESULT_CODE(ddrval));
return dderr;
}