Full-screen bug?

General FreeBASIC programming questions.
Post Reply
neil
Posts: 594
Joined: Mar 17, 2022 23:26

Full-screen bug?

Post by neil »

FreeBasic's full-screen mode seems to squash images on Windows 10.
I also noticed full-screen does not work in 8 bit mode. Such as Screen 19,8,1,1.
However 32 bit mode works. Screen 19,32,1,1

This code below works fine on Linux. Is there a workaround for Windows?

Code: Select all

#lang "fb"
' Windows 10 bug 3D cube and orb test

'Screenres 800,600,32  ' This works 
'Screen 19,32  ' This works 
Screenres 800,600,32,1,1 ' FullScreen This squashes cube and orb
'Screen 19,32,1,1 ' FullScreen This squashes cube and orb

Dim As Single x,y
Dim As Ubyte Alpha,i,r, Red, Green, Blue

Cls

Line (100,100)-(100,300)
Line (100,100)-(300,100)
Line (300,100)-(300,300)
Line (300,300)-(100,300)

Line (200,200)-(200,400)
Line (200,200)-(400,200)
Line (400,200)-(400,400)
Line (400,400)-(200,400)

Line (100,100)-(200,200)
Line (100,300)-(200,400)
Line (300,100)-(400,200)
Line (300,300)-(400,400)

x = 250: y = 250
Alpha = 255:Red = 255:Green = 255
r = 31: blue = 0

FOR i = 1 TO r
  CIRCLE (x, y ),i, RGBA(Red, Green, Blue, Alpha)
  CIRCLE (x, y + 1), i, RGBA(Red, Green, Blue, Alpha)
  red -= 6:green -= 6
 next
sleep
Jattenalle
Posts: 12
Joined: Nov 17, 2023 14:41
Contact:

Re: Full-screen bug?

Post by Jattenalle »

FreeBasic's full-screen mode seems to squash images on Windows 10.
I also noticed full-screen does not work in 8 bit mode.
FBGFX screen, and screenres, with the fullscreen flag have been broken for quite a while on Windows.

Fullscreen only work as expected if the screen res is the exact same as the desktop, including any scaling the user has set.
The bit depth issue is related, as using a bit depth other than the desktop one in fullscreen will require a mode switch, which is the broken part.

There is no easy workaround. Using a different window and context initializer (A common one being SDL2 for example) is your best bet as a quick fix is unlikely. Do note that using a different window and context initializer will also make fbgfx functions (line, etc) not work!

The reason nobody has stepped up to fix it is probably related to the amount of boilerplate code and work required to properly handle scaling awareness, while also still supporting everything all the way back to DOS in a transparent manner.
adeyblue
Posts: 300
Joined: Nov 07, 2019 20:08

Re: Full-screen bug?

Post by adeyblue »

It's because usually your FB app doesn't opt-in to do its own scaling, so when you/fbgfx creates the 800x600 window, Windows scales it up to keep the effective 800x600 resolution. In full screen mode, the resolution really is 800x600 but Windows still scales the window hence it looks wrong despite the output being exactly the same, its just cropped to the top left 800x600 corner of the window.

Opting in to DPI scaling before the Screen/ScreenRes will create an 800x600 window, with no scaling so fullscreen looks great. You're then on the hook for scaling up things in windowed mode to keep your effective 800x600 resolution. If not, at 150% scaling you'll have an equivalent window size of 533x400 and it'll only get smaller from there.

A solution where you opt-in and leave it all to fbgfx will have the same results as now whichever way it works. If it scales up, it will look a bit blurry as the 800x600 canvas will have to be blown up to keep the effective resolution or if it leaves it alone, the window will get smaller and smaller as the scaling factor increases.

You can opt in by saving this as <your-exe-name>.manifest
So if your exe is superfile.exe, you'd save it in the same directory as superfile.exe.manifest

Code: Select all

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0"  xmlns:asmv3="urn:schemas-microsoft-com:asm.v3">
  <asmv3:application>
    <asmv3:windowsSettings>
      <dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true</dpiAware>
      <dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">PerMonitorV2</dpiAwareness>
    </asmv3:windowsSettings>
  </asmv3:application>
</assembly>
Here's a slightly modified version of the OP that displays the dpi status

Code: Select all

' Windows 10 bug 3D cube and orb test
#include "fbgfx.bi"
#include "windows.bi"
#include "crt/stdio.bi"

#define GPA(x, dll) x = cast(TypeOf(x), GetProcAddress(dll, #x))

Dim GetProcessDpiAwareness as Function stdcall (ByVal h as Any Ptr, ByVal awareness as Long Ptr) as Long
Dim GetThreadDpiAwarenessContext as Function stdcall() As Any Ptr
Dim GetDpiForWindow as Function stdcall (ByVal h as Any Ptr) as ULong
Dim GetSystemDpiForProcess as Function stdcall(ByVal h As Any Ptr) As ULong
Dim GetDpiForSystem  As Function stdcall() As ULong
Dim AreDpiAwarenessContextsEqual as Function stdcall(ByVal a as Any Ptr, ByVal b as Any Ptr) As Long

Dim as HMODULE hShCore = LoadLibrary("shcore.dll")
Dim as HMODULE hUser32 = GetModuleHandle("user32.dll")
GPA(GetProcessDpiAwareness, hShCore)
GPA(GetThreadDpiAwarenessContext, hUser32)
GPA(GetDpiForWindow, hUser32)
GPA(GetDpiForSystem, hUser32)
GPA(GetSystemDpiForProcess, hUser32)
GPA(AreDpiAwarenessContextsEqual, hUser32)

enum DpiAwareness
   DA_None = 0,
   DA_SystemAware = 1,
   DA_PerMonitorAware = 2
End Enum

const DAC_Unaware = -1
const DAC_System_Aware = -2
const DAC_Per_Monitor_Aware = -3
const DAC_Per_Monitor_V2_Aware = -4
const DAC_Unaware_GDIScaled = -5

''Screenres 800,600,32  ' This works 
'Screen 19,32  ' This works 
Screenres 800,600,32,1,1 ' FullScreen This squashes cube and orb
'Screen 19,32,1,1 ' FullScreen This squashes cube and orb

cls

Dim msg as ZString * 250
Dim as integer pwnd
ScreenControl fb.GET_WINDOW_HANDLE, pwnd
If (GetThreadDpiAwarenessContext) AndAlso (AreDpiAwarenessContextsEqual) Then
    dim as Any Ptr threadCtx = GetThreadDpiAwarenessContext()
    Dim as Any Ptr pmv2Ctx = cast(Any Ptr, DAC_Per_Monitor_V2_Aware)
    Dim as Long isPMV2 = AreDpiAwarenessContextsEqual(threadCtx, pmV2Ctx)
    snprintf(msg, 250, "Thread Awareness Context: %s/%#x", IIf(isPMV2 <> 0, "PMv2", "Not PMv2"), threadCtx)
    Draw String (0, 0), msg
End If
dim as Any Ptr curProc = GetCurrentProcess()
Dim as DpiAwareness procAwareness = DA_None
If(GetProcessDpiAwareness) Then
    GetProcessDpiAwareness(curProc, @procAwareness)
    snprintf(msg, 250, "Proc Awareness: %#x", procAwareness)
    Draw String (0, 30), msg
End If
If GetSystemDpiForProcess Then
    Dim as ULong sysAwareness = GetSystemDpiForProcess(curProc)
    snprintf(msg, 250, "Sys Proc Dpi: %lu", sysAwareness)
    Draw String (250, 30), msg
End If
If GetDpiForWindow Then
    Dim as ULong winDpi = GetDpiForWindow(cast(any Ptr, pwnd))
    snprintf(msg, 250, "Window DPI: %lu", winDpi)
    Draw String (0, 45), msg
End If
If GetDpiForSystem Then
    Dim as ULong sysDpi = GetDpiForSystem()
    snprintf(msg, 250, "System DPI: %lu", sysDpi)
    Draw String (250, 45), msg
End If

Dim As Single x,y
Dim As Ubyte Alpha,i,r, Red, Green, Blue

Line (100,100)-(100,300)
Line (100,100)-(300,100)
Line (300,100)-(300,300)
Line (300,300)-(100,300)

Line (200,200)-(200,400)
Line (200,200)-(400,200)
Line (400,200)-(400,400)
Line (400,400)-(200,400)

Line (100,100)-(200,200)
Line (100,300)-(200,400)
Line (300,100)-(400,200)
Line (300,300)-(400,400)

x = 250: y = 250
Alpha = 255:Red = 255:Green = 255
r = 31: blue = 0

FOR i = 1 TO r
  CIRCLE (x, y ),i, RGBA(Red, Green, Blue, Alpha)
  CIRCLE (x, y + 1), i, RGBA(Red, Green, Blue, Alpha)
  red -= 6:green -= 6
 next
 
 FreeLibrary(hShCore)
 
sleep
Without the manifest all the numbers should be 96, with it, they should be different (unless you're still at 100% scaling) and the window will look smaller.
neil
Posts: 594
Joined: Mar 17, 2022 23:26

Re: Full-screen bug?

Post by neil »

@adeyblue
I appreciate your workaround solution.
Thank You!
Post Reply