internal/goglfw: separate the Windows version detection to a new package winver

This commit is contained in:
Hajime Hoshi 2023-03-31 02:07:35 +09:00
parent c0adcee12c
commit 182ac21866
10 changed files with 221 additions and 228 deletions

View File

@ -164,11 +164,6 @@ const (
_TME_LEAVE = 0x00000002
_UNICODE_NOCHAR = 0xffff
_USER_DEFAULT_SCREEN_DPI = 96
_VER_BUILDNUMBER = 0x00000004
_VER_GREATER_EQUAL = 3
_VER_MAJORVERSION = 0x00000002
_VER_MINORVERSION = 0x00000001
_VER_SERVICEPACKMAJOR = 0x00000020
_VERTSIZE = 6
_VK_ADD = 0x6B
_VK_CAPITAL = 0x14
@ -262,11 +257,6 @@ const (
_WGL_TRANSPARENT_INDEX_VALUE_ARB = 0x203B
_WGL_TRANSPARENT_RED_VALUE_ARB = 0x2037
_WGL_TYPE_RGBA_ARB = 0x202B
_WIN32_WINNT_VISTA = 0x0600
_WIN32_WINNT_WIN7 = 0x0601
_WIN32_WINNT_WIN8 = 0x0602
_WIN32_WINNT_WINBLUE = 0x0603
_WIN32_WINNT_WINXP = 0x0501
_WM_CAPTURECHANGED = 0x0215
_WM_CHAR = 0x0102
_WM_CLOSE = 0x0010
@ -387,18 +377,11 @@ func _GET_XBUTTON_WPARAM(wParam _WPARAM) uint16 {
func _GET_Y_LPARAM(lp _LPARAM) int {
return int(_HIWORD(uint32(lp)))
}
func _HIBYTE(wValue uint16) byte {
return byte(wValue >> 8)
}
func _HIWORD(dwValue uint32) uint16 {
return uint16(dwValue >> 16)
}
func _LOBYTE(wValue uint16) byte {
return byte(wValue)
}
func _LOWORD(dwValue uint32) uint16 {
return uint16(dwValue)
}
@ -590,20 +573,6 @@ type _MSG struct {
lPrivate uint32
}
type _OSVERSIONINFOEXW struct {
dwOSVersionInfoSize uint32
dwMajorVersion uint32
dwMinorVersion uint32
dwBuildNumber uint32
dwPlatformId uint32
szCSDVersion [128]uint16
wServicePackMajor uint16
wServicePackMinor uint16
wSuiteMask uint16
wProductType byte
wReserved byte
}
type _PIXELFORMATDESCRIPTOR struct {
nSize uint16
nVersion uint16
@ -722,7 +691,6 @@ var (
dwmapi = windows.NewLazySystemDLL("dwmapi.dll")
gdi32 = windows.NewLazySystemDLL("gdi32.dll")
kernel32 = windows.NewLazySystemDLL("kernel32.dll")
ntdll = windows.NewLazySystemDLL("ntdll.dll")
opengl32 = windows.NewLazySystemDLL("opengl32.dll")
shcore = windows.NewLazySystemDLL("shcore.dll")
shell32 = windows.NewLazySystemDLL("shell32.dll")
@ -749,9 +717,6 @@ var (
procTlsFree = kernel32.NewProc("TlsFree")
procTlsGetValue = kernel32.NewProc("TlsGetValue")
procTlsSetValue = kernel32.NewProc("TlsSetValue")
procVerSetConditionMask = kernel32.NewProc("VerSetConditionMask")
procRtlVerifyVersionInfo = ntdll.NewProc("RtlVerifyVersionInfo")
procWGLCreateContext = opengl32.NewProc("wglCreateContext")
procWGLDeleteContext = opengl32.NewProc("wglDeleteContext")
@ -1522,24 +1487,6 @@ func _ReleaseDC(hWnd windows.HWND, hDC _HDC) int32 {
return int32(r)
}
func _RtlVerifyVersionInfo(versionInfo *_OSVERSIONINFOEXW, typeMask uint32, conditionMask uint64) int32 {
var r uintptr
if unsafe.Sizeof(uintptr(0)) == unsafe.Sizeof(uint64(0)) {
r, _, _ = procRtlVerifyVersionInfo.Call(uintptr(unsafe.Pointer(versionInfo)), uintptr(typeMask), uintptr(conditionMask))
} else {
switch runtime.GOARCH {
case "386":
r, _, _ = procRtlVerifyVersionInfo.Call(uintptr(unsafe.Pointer(versionInfo)), uintptr(typeMask), uintptr(conditionMask), uintptr(conditionMask>>32))
case "arm":
// Adjust the alignment for ARM.
r, _, _ = procRtlVerifyVersionInfo.Call(uintptr(unsafe.Pointer(versionInfo)), uintptr(typeMask), 0, uintptr(conditionMask), uintptr(conditionMask>>32))
default:
panic(fmt.Sprintf("goglfw: GOARCH=%s is not supported", runtime.GOARCH))
}
}
return int32(r)
}
func _ScreenToClient(hWnd windows.HWND, lpPoint *_POINT) error {
r, _, e := procScreenToClient.Call(uintptr(hWnd), uintptr(unsafe.Pointer(lpPoint)))
if int32(r) == 0 && !errors.Is(e, windows.ERROR_SUCCESS) {
@ -1777,16 +1724,6 @@ func _UnregisterDeviceNotification(handle _HDEVNOTIFY) error {
return nil
}
func _VerSetConditionMask(conditionMask uint64, typeMask uint32, condition byte) uint64 {
if unsafe.Sizeof(uintptr(0)) == unsafe.Sizeof(uint64(0)) {
r, _, _ := procVerSetConditionMask.Call(uintptr(conditionMask), uintptr(typeMask), uintptr(condition))
return uint64(r)
} else {
r1, r2, _ := procVerSetConditionMask.Call(uintptr(conditionMask), uintptr(conditionMask>>32), uintptr(typeMask), uintptr(condition))
return uint64(r1) | (uint64(r2) << 32)
}
}
func _WaitMessage() error {
r, _, e := procWaitMessage.Call()
if int32(r) == 0 && !errors.Is(e, windows.ERROR_SUCCESS) {

View File

@ -14,6 +14,7 @@ import (
"golang.org/x/sys/windows"
"github.com/hajimehoshi/ebiten/v2/internal/microsoftgdk"
"github.com/hajimehoshi/ebiten/v2/internal/winver"
)
func findPixelFormatAttribValue(attribs []int32, values []int32, attrib int32) int32 {
@ -230,9 +231,9 @@ func makeContextCurrentWGL(window *Window) error {
}
func swapBuffersWGL(window *Window) error {
if window.monitor == nil && _IsWindowsVistaOrGreater() {
if window.monitor == nil && winver.IsWindowsVistaOrGreater() {
// DWM Composition is always enabled on Win8+
enabled := _IsWindows8OrGreater()
enabled := winver.IsWindows8OrGreater()
if !enabled {
var err error
@ -266,9 +267,9 @@ func swapIntervalWGL(interval int) error {
window.context.platform.interval = interval
if window.monitor == nil && _IsWindowsVistaOrGreater() {
if window.monitor == nil && winver.IsWindowsVistaOrGreater() {
// DWM Composition is always enabled on Win8+
enabled := _IsWindows8OrGreater()
enabled := winver.IsWindows8OrGreater()
if !enabled {
e, err := _DwmIsCompositionEnabled()

View File

@ -12,6 +12,7 @@ import (
"golang.org/x/sys/windows"
"github.com/hajimehoshi/ebiten/v2/internal/microsoftgdk"
"github.com/hajimehoshi/ebiten/v2/internal/winver"
)
func createKeyTables() {
@ -238,41 +239,6 @@ func createHelperWindow() error {
return nil
}
func isWindowsVersionOrGreaterWin32(major, minor, sp uint16) bool {
osvi := _OSVERSIONINFOEXW{
dwMajorVersion: uint32(major),
dwMinorVersion: uint32(minor),
wServicePackMajor: sp,
}
osvi.dwOSVersionInfoSize = uint32(unsafe.Sizeof(osvi))
var mask uint32 = _VER_MAJORVERSION | _VER_MINORVERSION | _VER_SERVICEPACKMAJOR
cond := _VerSetConditionMask(0, _VER_MAJORVERSION, _VER_GREATER_EQUAL)
cond = _VerSetConditionMask(cond, _VER_MINORVERSION, _VER_GREATER_EQUAL)
cond = _VerSetConditionMask(cond, _VER_SERVICEPACKMAJOR, _VER_GREATER_EQUAL)
// HACK: Use RtlVerifyVersionInfo instead of VerifyVersionInfoW as the
// latter lies unless the user knew to embed a non-default manifest
// announcing support for Windows 10 via supportedOS GUID
return _RtlVerifyVersionInfo(&osvi, mask, cond) == 0
}
func isWindows10BuildOrGreaterWin32(build uint16) bool {
osvi := _OSVERSIONINFOEXW{
dwMajorVersion: 10,
dwMinorVersion: 0,
dwBuildNumber: uint32(build),
}
osvi.dwOSVersionInfoSize = uint32(unsafe.Sizeof(osvi))
var mask uint32 = _VER_MAJORVERSION | _VER_MINORVERSION | _VER_BUILDNUMBER
cond := _VerSetConditionMask(0, _VER_MAJORVERSION, _VER_GREATER_EQUAL)
cond = _VerSetConditionMask(cond, _VER_MINORVERSION, _VER_GREATER_EQUAL)
cond = _VerSetConditionMask(cond, _VER_BUILDNUMBER, _VER_GREATER_EQUAL)
// HACK: Use RtlVerifyVersionInfo instead of VerifyVersionInfoW as the
// latter lies unless the user knew to embed a non-default manifest
// announcing support for Windows 10 via supportedOS GUID
return _RtlVerifyVersionInfo(&osvi, mask, cond) == 0
}
func platformInit() error {
// Changing the foreground lock timeout was removed from the original code.
// See https://github.com/glfw/glfw/commit/58b48a3a00d9c2a5ca10cc23069a71d8773cc7a4
@ -286,17 +252,17 @@ func platformInit() error {
createKeyTables()
updateKeyNamesWin32()
if isWindows10CreatorsUpdateOrGreaterWin32() {
if winver.IsWindows10CreatorsUpdateOrGreater() {
if !microsoftgdk.IsXbox() {
// Ignore the error as SetProcessDpiAwarenessContext returns an error on Steam Deck (#2113).
// This seems an issue in Wine and/or Proton, but there is nothing we can do.
_ = _SetProcessDpiAwarenessContext(_DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2)
}
} else if _IsWindows8Point1OrGreater() {
} else if winver.IsWindows8Point1OrGreater() {
if err := _SetProcessDpiAwareness(_PROCESS_PER_MONITOR_DPI_AWARE); err != nil && !errors.Is(err, handleError(windows.E_ACCESSDENIED)) {
return err
}
} else if _IsWindowsVistaOrGreater() {
} else if winver.IsWindowsVistaOrGreater() {
_SetProcessDPIAware()
}

View File

@ -12,6 +12,7 @@ import (
"golang.org/x/sys/windows"
"github.com/hajimehoshi/ebiten/v2/internal/microsoftgdk"
"github.com/hajimehoshi/ebiten/v2/internal/winver"
)
func monitorCallback(handle _HMONITOR, dc _HDC, rect *_RECT, monitor *Monitor /* _LPARAM */) uintptr /* _BOOL */ {
@ -217,7 +218,7 @@ func (m *Monitor) restoreVideoModeWin32() {
func getMonitorContentScaleWin32(handle _HMONITOR) (xscale, yscale float32, err error) {
var xdpi, ydpi uint32
if _IsWindows8Point1OrGreater() {
if winver.IsWindows8Point1OrGreater() {
var err error
xdpi, ydpi, err = _GetDpiForMonitor(handle, _MDT_EFFECTIVE_DPI)
if err != nil {

View File

@ -5,7 +5,9 @@
package goglfw
import "golang.org/x/sys/windows"
import (
"golang.org/x/sys/windows"
)
const (
_GLFW_WNDCLASSNAME = "GLFW30"
@ -96,31 +98,3 @@ type platformLibraryContextState struct {
ARB_create_context_no_error bool
ARB_context_flush_control bool
}
func _IsWindowsXPOrGreater() bool {
return isWindowsVersionOrGreaterWin32(uint16(_HIBYTE(_WIN32_WINNT_WINXP)), uint16(_LOBYTE(_WIN32_WINNT_WINXP)), 0)
}
func _IsWindowsVistaOrGreater() bool {
return isWindowsVersionOrGreaterWin32(uint16(_HIBYTE(_WIN32_WINNT_VISTA)), uint16(_LOBYTE(_WIN32_WINNT_VISTA)), 0)
}
func _IsWindows7OrGreater() bool {
return isWindowsVersionOrGreaterWin32(uint16(_HIBYTE(_WIN32_WINNT_WIN7)), uint16(_LOBYTE(_WIN32_WINNT_WIN7)), 0)
}
func _IsWindows8OrGreater() bool {
return isWindowsVersionOrGreaterWin32(uint16(_HIBYTE(_WIN32_WINNT_WIN8)), uint16(_LOBYTE(_WIN32_WINNT_WIN8)), 0)
}
func _IsWindows8Point1OrGreater() bool {
return isWindowsVersionOrGreaterWin32(uint16(_HIBYTE(_WIN32_WINNT_WINBLUE)), uint16(_LOBYTE(_WIN32_WINNT_WINBLUE)), 0)
}
func isWindows10AnniversaryUpdateOrGreaterWin32() bool {
return isWindows10BuildOrGreaterWin32(14393)
}
func isWindows10CreatorsUpdateOrGreaterWin32() bool {
return isWindows10BuildOrGreaterWin32(15063)
}

View File

@ -15,6 +15,7 @@ import (
"golang.org/x/sys/windows"
"github.com/hajimehoshi/ebiten/v2/internal/microsoftgdk"
"github.com/hajimehoshi/ebiten/v2/internal/winver"
)
func (w *Window) getWindowStyle() uint32 {
@ -137,7 +138,7 @@ func getFullWindowSize(style uint32, exStyle uint32, contentWidth, contentHeight
right: int32(contentWidth),
bottom: int32(contentHeight),
}
if isWindows10AnniversaryUpdateOrGreaterWin32() {
if winver.IsWindows10AnniversaryUpdateOrGreater() {
if err := _AdjustWindowRectExForDpi(&rect, style, false, exStyle, dpi); err != nil {
return 0, 0, err
}
@ -153,7 +154,7 @@ func (w *Window) applyAspectRatio(edge int, area *_RECT) error {
ratio := float32(w.numer) / float32(w.denom)
var dpi uint32 = _USER_DEFAULT_SCREEN_DPI
if isWindows10AnniversaryUpdateOrGreaterWin32() {
if winver.IsWindows10AnniversaryUpdateOrGreater() {
dpi = _GetDpiForWindow(w.platform.handle)
}
@ -343,7 +344,7 @@ func (w *Window) updateWindowStyles() error {
return err
}
if isWindows10AnniversaryUpdateOrGreaterWin32() {
if winver.IsWindows10AnniversaryUpdateOrGreater() {
if err := _AdjustWindowRectExForDpi(&rect, style, false, w.getWindowExStyle(), _GetDpiForWindow(w.platform.handle)); err != nil {
return err
}
@ -368,7 +369,7 @@ func (w *Window) updateWindowStyles() error {
}
func (w *Window) updateFramebufferTransparency() error {
if !_IsWindowsVistaOrGreater() {
if !winver.IsWindowsVistaOrGreater() {
return nil
}
@ -382,7 +383,7 @@ func (w *Window) updateFramebufferTransparency() error {
}
var opaque bool
if !_IsWindows8OrGreater() {
if !winver.IsWindows8OrGreater() {
_, opaque, err = _DwmGetColorizationColor()
if err != nil {
// Ignore an error from DWM functions as they might not be implemented e.g. on Proton (#2113).
@ -390,7 +391,7 @@ func (w *Window) updateFramebufferTransparency() error {
}
}
if _IsWindows8OrGreater() || !opaque {
if winver.IsWindows8OrGreater() || !opaque {
region, err := _CreateRectRgn(0, 0, -1, -1)
if err != nil {
return err
@ -473,7 +474,7 @@ func (w *Window) acquireMonitor() error {
// HACK: When mouse trails are enabled the cursor becomes invisible when
// the OpenGL ICD switches to page flipping
if _IsWindowsXPOrGreater() {
if winver.IsWindowsXPOrGreater() {
if err := _SystemParametersInfoW(_SPI_GETMOUSETRAILS, 0, uintptr(unsafe.Pointer(&_glfw.platformWindow.mouseTrailSize)), 0); err != nil {
return err
}
@ -504,7 +505,7 @@ func (w *Window) releaseMonitor() error {
_SetThreadExecutionState(_ES_CONTINUOUS)
// HACK: Restore mouse trail length saved in acquireMonitor
if _IsWindowsXPOrGreater() {
if winver.IsWindowsXPOrGreater() {
if err := _SystemParametersInfoW(_SPI_SETMOUSETRAILS, _glfw.platformWindow.mouseTrailSize, 0, 0); err != nil {
return err
}
@ -546,7 +547,7 @@ func (w *Window) maximizeWindowManually() error {
return err
}
exStyle := uint32(s)
if isWindows10AnniversaryUpdateOrGreaterWin32() {
if winver.IsWindows10AnniversaryUpdateOrGreater() {
dpi := _GetDpiForWindow(w.platform.handle)
if err := _AdjustWindowRectExForDpi(&rect, style, false, exStyle, dpi); err != nil {
return err
@ -588,7 +589,7 @@ func windowProc(hWnd windows.HWND, uMsg uint32, wParam _WPARAM, lParam _LPARAM)
// and for a regular window during its initial creation
switch uMsg {
case _WM_NCCREATE:
if isWindows10AnniversaryUpdateOrGreaterWin32() {
if winver.IsWindows10AnniversaryUpdateOrGreater() {
cs := (*_CREATESTRUCTW)(unsafe.Pointer(lParam))
wndconfig := (*wndconfig)(cs.lpCreateParams)
@ -1062,7 +1063,7 @@ func windowProc(hWnd windows.HWND, uMsg uint32, wParam _WPARAM, lParam _LPARAM)
break
}
if isWindows10AnniversaryUpdateOrGreaterWin32() {
if winver.IsWindows10AnniversaryUpdateOrGreater() {
dpi = _GetDpiForWindow(window.platform.handle)
}
@ -1122,7 +1123,7 @@ func windowProc(hWnd windows.HWND, uMsg uint32, wParam _WPARAM, lParam _LPARAM)
}
// Adjust the window size to keep the content area size constant
if isWindows10CreatorsUpdateOrGreaterWin32() {
if winver.IsWindows10CreatorsUpdateOrGreater() {
var source, target _RECT
size := (*_SIZE)(unsafe.Pointer(lParam))
@ -1146,7 +1147,7 @@ func windowProc(hWnd windows.HWND, uMsg uint32, wParam _WPARAM, lParam _LPARAM)
// Resize windowed mode windows that either permit rescaling or that
// need it to compensate for non-client area scaling
if window.monitor == nil && (window.platform.scaleToMonitor || isWindows10CreatorsUpdateOrGreaterWin32()) {
if window.monitor == nil && (window.platform.scaleToMonitor || winver.IsWindows10CreatorsUpdateOrGreater()) {
suggested := (*_RECT)(unsafe.Pointer(lParam))
if err := _SetWindowPos(window.platform.handle, _HWND_TOP,
suggested.left,
@ -1244,7 +1245,7 @@ func (w *Window) createNativeWindow(wndconfig *wndconfig, fbconfig *fbconfig) er
handleToWindow[w.platform.handle] = w
if !microsoftgdk.IsXbox() && _IsWindows7OrGreater() {
if !microsoftgdk.IsXbox() && winver.IsWindows7OrGreater() {
if err := _ChangeWindowMessageFilterEx(w.platform.handle, _WM_DROPFILES, _MSGFLT_ALLOW, nil); err != nil {
return err
}
@ -1291,7 +1292,7 @@ func (w *Window) createNativeWindow(wndconfig *wndconfig, fbconfig *fbconfig) er
return err
}
if isWindows10AnniversaryUpdateOrGreaterWin32() {
if winver.IsWindows10AnniversaryUpdateOrGreater() {
if err := _AdjustWindowRectExForDpi(&rect, style, false, exStyle, _GetDpiForWindow(w.platform.handle)); err != nil {
return err
}
@ -1577,7 +1578,7 @@ func (w *Window) platformSetWindowPos(xpos, ypos int) error {
right: int32(xpos),
bottom: int32(ypos),
}
if isWindows10AnniversaryUpdateOrGreaterWin32() {
if winver.IsWindows10AnniversaryUpdateOrGreater() {
if err := _AdjustWindowRectExForDpi(&rect, w.getWindowStyle(), false, w.getWindowExStyle(), _GetDpiForWindow(w.platform.handle)); err != nil {
return err
}
@ -1619,7 +1620,7 @@ func (w *Window) platformSetWindowSize(width, height int) error {
bottom: int32(height),
}
if isWindows10AnniversaryUpdateOrGreaterWin32() {
if winver.IsWindows10AnniversaryUpdateOrGreater() {
if err := _AdjustWindowRectExForDpi(&rect, w.getWindowStyle(), false, w.getWindowExStyle(), _GetDpiForWindow(w.platform.handle)); err != nil {
return err
}
@ -1688,7 +1689,7 @@ func (w *Window) platformGetWindowFrameSize() (left, top, right, bottom int, err
right: int32(width),
bottom: int32(height),
}
if isWindows10AnniversaryUpdateOrGreaterWin32() {
if winver.IsWindows10AnniversaryUpdateOrGreater() {
if err := _AdjustWindowRectExForDpi(&rect, w.getWindowStyle(), false, w.getWindowExStyle(), _GetDpiForWindow(w.platform.handle)); err != nil {
return 0, 0, 0, 0, err
}
@ -1770,7 +1771,7 @@ func (w *Window) platformSetWindowMonitor(monitor *Monitor, xpos, ypos, width, h
right: int32(xpos + width),
bottom: int32(ypos + height),
}
if isWindows10AnniversaryUpdateOrGreaterWin32() {
if winver.IsWindows10AnniversaryUpdateOrGreater() {
if err := _AdjustWindowRectExForDpi(&rect, w.getWindowStyle(), false, w.getWindowExStyle(), _GetDpiForWindow(w.platform.handle)); err != nil {
return err
}
@ -1853,7 +1854,7 @@ func (w *Window) platformSetWindowMonitor(monitor *Monitor, xpos, ypos, width, h
right: int32(xpos + width),
bottom: int32(ypos + height),
}
if isWindows10AnniversaryUpdateOrGreaterWin32() {
if winver.IsWindows10AnniversaryUpdateOrGreater() {
if err := _AdjustWindowRectExForDpi(&rect, w.getWindowStyle(),
false, w.getWindowExStyle(),
_GetDpiForWindow(w.platform.handle)); err != nil {
@ -1926,7 +1927,7 @@ func (w *Window) platformFramebufferTransparent() bool {
return false
}
if !_IsWindowsVistaOrGreater() {
if !winver.IsWindowsVistaOrGreater() {
return false
}
@ -1935,7 +1936,7 @@ func (w *Window) platformFramebufferTransparent() bool {
return false
}
if !_IsWindows8OrGreater() {
if !winver.IsWindows8OrGreater() {
// HACK: Disable framebuffer transparency on Windows 7 when the
// colorization color is opaque, because otherwise the window
// contents is blended additively with the previous frame instead

View File

@ -16,7 +16,6 @@ package directx
import (
"fmt"
"runtime"
"unsafe"
"golang.org/x/sys/windows"
@ -24,13 +23,6 @@ import (
const is64bit = unsafe.Sizeof(uintptr(0)) == 8
const (
_VER_BUILDNUMBER = 0x00000004
_VER_GREATER_EQUAL = 3
_VER_MAJORVERSION = 0x00000002
_VER_MINORVERSION = 0x00000001
)
type handleError windows.Handle
func (h handleError) Error() string {
@ -48,33 +40,13 @@ func boolToUintptr(v bool) uintptr {
return 0
}
type _OSVERSIONINFOEXW struct {
dwOSVersionInfoSize uint32
dwMajorVersion uint32
dwMinorVersion uint32
dwBuildNumber uint32
dwPlatformId uint32
szCSDVersion [128]uint16
wServicePackMajor uint16
wServicePackMinor uint16
wSuiteMask uint16
wProductType byte
wReserved byte
}
type _PAPPSTATE_CHANGE_ROUTINE func(quiesced bool, context unsafe.Pointer) uintptr
var (
// https://github.com/MicrosoftDocs/sdk-api/blob/docs/sdk-api-src/content/appnotify/nf-appnotify-registerappstatechangenotification.md
appnotify = windows.NewLazySystemDLL("API-MS-Win-Core-psm-appnotify-l1-1-0.dll")
kernel32 = windows.NewLazySystemDLL("kernel32.dll")
ntdll = windows.NewLazySystemDLL("ntdll.dll")
procRegisterAppStateChangeNotification = appnotify.NewProc("RegisterAppStateChangeNotification")
procVerSetConditionMask = kernel32.NewProc("VerSetConditionMask")
procRtlVerifyVersionInfo = ntdll.NewProc("RtlVerifyVersionInfo")
)
func _RegisterAppStateChangeNotification(routine _PAPPSTATE_CHANGE_ROUTINE, context unsafe.Pointer) (unsafe.Pointer, error) {
@ -86,45 +58,3 @@ func _RegisterAppStateChangeNotification(routine _PAPPSTATE_CHANGE_ROUTINE, cont
}
return registration, nil
}
func _RtlVerifyVersionInfo(versionInfo *_OSVERSIONINFOEXW, typeMask uint32, conditionMask uint64) int32 {
var r uintptr
if is64bit {
r, _, _ = procRtlVerifyVersionInfo.Call(uintptr(unsafe.Pointer(versionInfo)), uintptr(typeMask), uintptr(conditionMask))
} else {
switch runtime.GOARCH {
case "386":
r, _, _ = procRtlVerifyVersionInfo.Call(uintptr(unsafe.Pointer(versionInfo)), uintptr(typeMask), uintptr(conditionMask), uintptr(conditionMask>>32))
case "arm":
// Adjust the alignment for ARM.
r, _, _ = procRtlVerifyVersionInfo.Call(uintptr(unsafe.Pointer(versionInfo)), uintptr(typeMask), 0, uintptr(conditionMask), uintptr(conditionMask>>32))
default:
panic(fmt.Sprintf("directx: GOARCH=%s is not supported", runtime.GOARCH))
}
}
return int32(r)
}
func _VerSetConditionMask(conditionMask uint64, typeMask uint32, condition byte) uint64 {
if is64bit {
r, _, _ := procVerSetConditionMask.Call(uintptr(conditionMask), uintptr(typeMask), uintptr(condition))
return uint64(r)
} else {
r1, r2, _ := procVerSetConditionMask.Call(uintptr(conditionMask), uintptr(conditionMask>>32), uintptr(typeMask), uintptr(condition))
return uint64(r1) | (uint64(r2) << 32)
}
}
func isWindows10OrGreaterWin32() bool {
osvi := _OSVERSIONINFOEXW{
dwMajorVersion: 10,
dwMinorVersion: 0,
dwBuildNumber: 0,
}
osvi.dwOSVersionInfoSize = uint32(unsafe.Sizeof(osvi))
var mask uint32 = _VER_MAJORVERSION | _VER_MINORVERSION | _VER_BUILDNUMBER
cond := _VerSetConditionMask(0, _VER_MAJORVERSION, _VER_GREATER_EQUAL)
cond = _VerSetConditionMask(cond, _VER_MINORVERSION, _VER_GREATER_EQUAL)
cond = _VerSetConditionMask(cond, _VER_BUILDNUMBER, _VER_GREATER_EQUAL)
return _RtlVerifyVersionInfo(&osvi, mask, cond) == 0
}

View File

@ -29,6 +29,7 @@ import (
"github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver"
"github.com/hajimehoshi/ebiten/v2/internal/microsoftgdk"
"github.com/hajimehoshi/ebiten/v2/internal/winver"
)
type stencilMode int
@ -275,7 +276,7 @@ func (g *graphicsInfra) initSwapChain(width, height int, device unsafe.Pointer,
// DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL/DISCARD are not supported for older Windows than 10 or DirectX 12.
// https://learn.microsoft.com/en-us/windows/win32/api/dxgi/ne-dxgi-dxgi_swap_effect
if !isWindows10OrGreaterWin32() {
if !winver.IsWindows10OrGreater() {
desc.SwapEffect = _DXGI_SWAP_EFFECT_SEQUENTIAL
desc.BufferCount = 1
}

View File

@ -0,0 +1,95 @@
// Copyright 2023 The Ebitengine Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package winver
import (
"fmt"
"runtime"
"unsafe"
"golang.org/x/sys/windows"
)
const (
_VER_BUILDNUMBER = 0x00000004
_VER_GREATER_EQUAL = 3
_VER_MAJORVERSION = 0x00000002
_VER_MINORVERSION = 0x00000001
_VER_SERVICEPACKMAJOR = 0x00000020
_WIN32_WINNT_VISTA = 0x0600
_WIN32_WINNT_WIN7 = 0x0601
_WIN32_WINNT_WIN8 = 0x0602
_WIN32_WINNT_WINBLUE = 0x0603
_WIN32_WINNT_WINXP = 0x0501
)
type _OSVERSIONINFOEXW struct {
dwOSVersionInfoSize uint32
dwMajorVersion uint32
dwMinorVersion uint32
dwBuildNumber uint32
dwPlatformId uint32
szCSDVersion [128]uint16
wServicePackMajor uint16
wServicePackMinor uint16
wSuiteMask uint16
wProductType byte
wReserved byte
}
func _HIBYTE(wValue uint16) byte {
return byte(wValue >> 8)
}
func _LOBYTE(wValue uint16) byte {
return byte(wValue)
}
var (
kernel32 = windows.NewLazySystemDLL("kernel32.dll")
ntdll = windows.NewLazySystemDLL("ntdll.dll")
procVerSetConditionMask = kernel32.NewProc("VerSetConditionMask")
procRtlVerifyVersionInfo = ntdll.NewProc("RtlVerifyVersionInfo")
)
func _RtlVerifyVersionInfo(versionInfo *_OSVERSIONINFOEXW, typeMask uint32, conditionMask uint64) int32 {
var r uintptr
if unsafe.Sizeof(uintptr(0)) == unsafe.Sizeof(uint64(0)) {
r, _, _ = procRtlVerifyVersionInfo.Call(uintptr(unsafe.Pointer(versionInfo)), uintptr(typeMask), uintptr(conditionMask))
} else {
switch runtime.GOARCH {
case "386":
r, _, _ = procRtlVerifyVersionInfo.Call(uintptr(unsafe.Pointer(versionInfo)), uintptr(typeMask), uintptr(conditionMask), uintptr(conditionMask>>32))
case "arm":
// Adjust the alignment for ARM.
r, _, _ = procRtlVerifyVersionInfo.Call(uintptr(unsafe.Pointer(versionInfo)), uintptr(typeMask), 0, uintptr(conditionMask), uintptr(conditionMask>>32))
default:
panic(fmt.Sprintf("goglfw: GOARCH=%s is not supported", runtime.GOARCH))
}
}
return int32(r)
}
func _VerSetConditionMask(conditionMask uint64, typeMask uint32, condition byte) uint64 {
if unsafe.Sizeof(uintptr(0)) == unsafe.Sizeof(uint64(0)) {
r, _, _ := procVerSetConditionMask.Call(uintptr(conditionMask), uintptr(typeMask), uintptr(condition))
return uint64(r)
} else {
r1, r2, _ := procVerSetConditionMask.Call(uintptr(conditionMask), uintptr(conditionMask>>32), uintptr(typeMask), uintptr(condition))
return uint64(r1) | (uint64(r2) << 32)
}
}

View File

@ -0,0 +1,87 @@
// Copyright 2023 The Ebitengine Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package winver
import (
"unsafe"
)
func isWindowsVersionOrGreater(major, minor, sp uint16) bool {
osvi := _OSVERSIONINFOEXW{
dwMajorVersion: uint32(major),
dwMinorVersion: uint32(minor),
wServicePackMajor: sp,
}
osvi.dwOSVersionInfoSize = uint32(unsafe.Sizeof(osvi))
var mask uint32 = _VER_MAJORVERSION | _VER_MINORVERSION | _VER_SERVICEPACKMAJOR
cond := _VerSetConditionMask(0, _VER_MAJORVERSION, _VER_GREATER_EQUAL)
cond = _VerSetConditionMask(cond, _VER_MINORVERSION, _VER_GREATER_EQUAL)
cond = _VerSetConditionMask(cond, _VER_SERVICEPACKMAJOR, _VER_GREATER_EQUAL)
// HACK: Use RtlVerifyVersionInfo instead of VerifyVersionInfoW as the
// latter lies unless the user knew to embed a non-default manifest
// announcing support for Windows 10 via supportedOS GUID
return _RtlVerifyVersionInfo(&osvi, mask, cond) == 0
}
func isWindows10BuildOrGreater(build uint16) bool {
osvi := _OSVERSIONINFOEXW{
dwMajorVersion: 10,
dwMinorVersion: 0,
dwBuildNumber: uint32(build),
}
osvi.dwOSVersionInfoSize = uint32(unsafe.Sizeof(osvi))
var mask uint32 = _VER_MAJORVERSION | _VER_MINORVERSION | _VER_BUILDNUMBER
cond := _VerSetConditionMask(0, _VER_MAJORVERSION, _VER_GREATER_EQUAL)
cond = _VerSetConditionMask(cond, _VER_MINORVERSION, _VER_GREATER_EQUAL)
cond = _VerSetConditionMask(cond, _VER_BUILDNUMBER, _VER_GREATER_EQUAL)
// HACK: Use RtlVerifyVersionInfo instead of VerifyVersionInfoW as the
// latter lies unless the user knew to embed a non-default manifest
// announcing support for Windows 10 via supportedOS GUID
return _RtlVerifyVersionInfo(&osvi, mask, cond) == 0
}
func IsWindowsXPOrGreater() bool {
return isWindowsVersionOrGreater(uint16(_HIBYTE(_WIN32_WINNT_WINXP)), uint16(_LOBYTE(_WIN32_WINNT_WINXP)), 0)
}
func IsWindowsVistaOrGreater() bool {
return isWindowsVersionOrGreater(uint16(_HIBYTE(_WIN32_WINNT_VISTA)), uint16(_LOBYTE(_WIN32_WINNT_VISTA)), 0)
}
func IsWindows7OrGreater() bool {
return isWindowsVersionOrGreater(uint16(_HIBYTE(_WIN32_WINNT_WIN7)), uint16(_LOBYTE(_WIN32_WINNT_WIN7)), 0)
}
func IsWindows8OrGreater() bool {
return isWindowsVersionOrGreater(uint16(_HIBYTE(_WIN32_WINNT_WIN8)), uint16(_LOBYTE(_WIN32_WINNT_WIN8)), 0)
}
func IsWindows8Point1OrGreater() bool {
return isWindowsVersionOrGreater(uint16(_HIBYTE(_WIN32_WINNT_WINBLUE)), uint16(_LOBYTE(_WIN32_WINNT_WINBLUE)), 0)
}
func IsWindows10OrGreater() bool {
return isWindows10BuildOrGreater(0)
}
func IsWindows10AnniversaryUpdateOrGreater() bool {
return isWindows10BuildOrGreater(14393)
}
func IsWindows10CreatorsUpdateOrGreater() bool {
return isWindows10BuildOrGreater(15063)
}