From eec66c585e882db4ce0dcde8d79f7575e4eee70e Mon Sep 17 00:00:00 2001 From: rdb Date: Mon, 16 Oct 2023 16:10:56 +0200 Subject: [PATCH 1/4] display: Add method for querying current display mode index Note that it doesn't work on macOS with high-DPI displays, this requires #1308 (which is on master), otherwise it will just report -1 for now Fixes #1550 --- panda/src/cocoadisplay/cocoaGraphicsPipe.mm | 16 ++++++++++++++++ panda/src/display/displayInformation.cxx | 14 +++++++++++--- panda/src/display/displayInformation.h | 4 +++- panda/src/windisplay/winDetectDx.h | 15 ++++++++++++--- panda/src/windisplay/winGraphicsPipe.cxx | 16 ++++++++++++++++ panda/src/x11display/x11GraphicsPipe.cxx | 14 ++++++++++++++ 6 files changed, 72 insertions(+), 7 deletions(-) diff --git a/panda/src/cocoadisplay/cocoaGraphicsPipe.mm b/panda/src/cocoadisplay/cocoaGraphicsPipe.mm index 91bd0fbbb9..3ad9099545 100644 --- a/panda/src/cocoadisplay/cocoaGraphicsPipe.mm +++ b/panda/src/cocoadisplay/cocoaGraphicsPipe.mm @@ -69,11 +69,19 @@ load_display_information() { // Display modes size_t num_modes = 0; #if __MAC_OS_X_VERSION_MAX_ALLOWED >= 1060 + int32_t current_mode_id = -1; CFArrayRef modes = CGDisplayCopyAllDisplayModes(_display, NULL); if (modes != NULL) { num_modes = CFArrayGetCount(modes); _display_information->_total_display_modes = num_modes; _display_information->_display_mode_array = new DisplayMode[num_modes]; + + // Get information about the current mode. + CGDisplayModeRef mode = CGDisplayCopyDisplayMode(_display); + if (mode) { + current_mode_id = CGDisplayModeGetIODisplayModeID(mode); + CGDisplayModeRelease(mode); + } } for (size_t i = 0; i < num_modes; ++i) { @@ -109,6 +117,14 @@ load_display_information() { // pixel can be deduced from the string length. Nifty! _display_information->_display_mode_array[i].bits_per_pixel = CFStringGetLength(encoding); } + + if (current_mode_id >= 0 && current_mode_id == CGDisplayModeGetIODisplayModeID(mode)) { + _display_information->_current_display_mode_index = i; + + // Stop checking + current_mode_id = -1; + } + CFRelease(encoding); } if (modes != NULL) { diff --git a/panda/src/display/displayInformation.cxx b/panda/src/display/displayInformation.cxx index 337da59699..a51c39ffa9 100644 --- a/panda/src/display/displayInformation.cxx +++ b/panda/src/display/displayInformation.cxx @@ -75,7 +75,6 @@ DisplayInformation:: DisplayInformation:: DisplayInformation() { DisplayInformation::DetectionState state; - int get_adapter_display_mode_state; int get_device_caps_state; int window_width; int window_height; @@ -88,7 +87,6 @@ DisplayInformation() { uint64_t available_physical_memory; state = DisplayInformation::DS_unknown; - get_adapter_display_mode_state = false; get_device_caps_state = false; window_width = 0; window_height = 0; @@ -101,7 +99,7 @@ DisplayInformation() { available_physical_memory = 0; _state = state; - _get_adapter_display_mode_state = get_adapter_display_mode_state; + _current_display_mode_index = -1; _get_device_caps_state = get_device_caps_state; _maximum_window_width = window_width; _maximum_window_height = window_height; @@ -209,6 +207,16 @@ get_display_mode(int display_index) { return _display_mode_array[display_index]; } +/** + * Returns the index of the current display mode (determined at the time of + * application start) in the display mode array, or -1 if this could not be + * determined. + */ +int DisplayInformation:: +get_current_display_mode_index() const { + return _current_display_mode_index; +} + /** * */ diff --git a/panda/src/display/displayInformation.h b/panda/src/display/displayInformation.h index 2869c8320a..9cb4c8d6ea 100644 --- a/panda/src/display/displayInformation.h +++ b/panda/src/display/displayInformation.h @@ -57,6 +57,8 @@ PUBLISHED: const DisplayMode &get_display_mode(int display_index); MAKE_SEQ(get_display_modes, get_total_display_modes, get_display_mode); + int get_current_display_mode_index() const; + // Older interface for display modes. int get_display_mode_width(int display_index); int get_display_mode_height(int display_index); @@ -116,7 +118,7 @@ PUBLISHED: public: DetectionState _state; - int _get_adapter_display_mode_state; + int _current_display_mode_index; int _get_device_caps_state; int _maximum_window_width; int _maximum_window_height; diff --git a/panda/src/windisplay/winDetectDx.h b/panda/src/windisplay/winDetectDx.h index 4b979de6f0..68645b196e 100644 --- a/panda/src/windisplay/winDetectDx.h +++ b/panda/src/windisplay/winDetectDx.h @@ -101,7 +101,6 @@ static int get_display_information (DisplaySearchParameters &display_search_para int success; DisplayInformation::DetectionState state; - int get_adapter_display_mode_state; int get_device_caps_state; GraphicsStateGuardian::ShaderModel shader_model; @@ -119,6 +118,7 @@ static int get_display_information (DisplaySearchParameters &display_search_para int window_height; int window_bits_per_pixel; int total_display_modes; + int current_display_mode_index; DisplayMode *display_mode_array; uint64_t physical_memory; @@ -141,6 +141,7 @@ static int get_display_information (DisplaySearchParameters &display_search_para window_height = 0; window_bits_per_pixel = 0; total_display_modes = 0; + current_display_mode_index = -1; display_mode_array = nullptr; minimum_width = display_search_parameters._minimum_width; @@ -155,7 +156,6 @@ static int get_display_information (DisplaySearchParameters &display_search_para texture_memory = 0; state = DisplayInformation::DS_unknown; - get_adapter_display_mode_state = false; get_device_caps_state = false; physical_memory = 0; @@ -195,6 +195,7 @@ static int get_display_information (DisplaySearchParameters &display_search_para device_type = D3DDEVTYPE_HAL; // windowed mode max res and format + bool get_adapter_display_mode_state = false; if (direct_3d -> GetAdapterDisplayMode (adapter, ¤t_d3d_display_mode) == D3D_OK) { if (debug) { printf ("current mode w = %d h = %d r = %d f = %d \n", @@ -430,6 +431,14 @@ static int get_display_information (DisplaySearchParameters &display_search_para display_mode -> refresh_rate = d3d_display_mode.RefreshRate; display_mode -> fullscreen_only = display_format_array [format_index].fullscreen_only; + if (get_adapter_display_mode_state && + d3d_display_mode.Width == current_d3d_display_mode.Width && + d3d_display_mode.Height == current_d3d_display_mode.Height && + d3d_display_mode.RefreshRate == current_d3d_display_mode.RefreshRate && + d3d_display_mode.Format == current_d3d_display_mode.Format) { + current_display_mode_index = total_display_modes; + } + total_display_modes++; } } @@ -589,7 +598,7 @@ static int get_display_information (DisplaySearchParameters &display_search_para if (success) { display_information -> _state = state; - display_information -> _get_adapter_display_mode_state = get_adapter_display_mode_state; + display_information -> _current_display_mode_index = current_display_mode_index; display_information -> _get_device_caps_state = get_device_caps_state; display_information -> _maximum_window_width = window_width; display_information -> _maximum_window_height = window_height; diff --git a/panda/src/windisplay/winGraphicsPipe.cxx b/panda/src/windisplay/winGraphicsPipe.cxx index eb29048c65..f24b25edad 100644 --- a/panda/src/windisplay/winGraphicsPipe.cxx +++ b/panda/src/windisplay/winGraphicsPipe.cxx @@ -340,9 +340,21 @@ WinGraphicsPipe() { if (windisplay_cat.is_debug()) { windisplay_cat.debug() << "Using EnumDisplaySettings to fetch display information.\n"; } + pvector display_modes; + DisplayMode current_mode = {0}; + int current_mode_index = -1; DEVMODE dm{}; dm.dmSize = sizeof(dm); + + if (EnumDisplaySettings(nullptr, ENUM_CURRENT_SETTINGS, &dm) != 0) { + current_mode.width = dm.dmPelsWidth; + current_mode.height = dm.dmPelsHeight; + current_mode.bits_per_pixel = dm.dmBitsPerPel; + current_mode.refresh_rate = dm.dmDisplayFrequency; + current_mode.fullscreen_only = 0; + } + for (int i = 0; EnumDisplaySettings(nullptr, i, &dm) != 0; ++i) { DisplayMode mode; mode.width = dm.dmPelsWidth; @@ -351,6 +363,9 @@ WinGraphicsPipe() { mode.refresh_rate = dm.dmDisplayFrequency; mode.fullscreen_only = 0; if (i == 0 || mode != display_modes.back()) { + if (current_mode_index < 0 && mode == current_mode) { + current_mode_index = (int)display_modes.size(); + } display_modes.push_back(mode); } } @@ -358,6 +373,7 @@ WinGraphicsPipe() { // Copy this information to the DisplayInformation object. _display_information->_total_display_modes = display_modes.size(); if (!display_modes.empty()) { + _display_information->_current_display_mode_index = current_mode_index; _display_information->_display_mode_array = new DisplayMode[display_modes.size()]; std::copy(display_modes.begin(), display_modes.end(), _display_information->_display_mode_array); diff --git a/panda/src/x11display/x11GraphicsPipe.cxx b/panda/src/x11display/x11GraphicsPipe.cxx index e871cb20a7..974e67dd3c 100644 --- a/panda/src/x11display/x11GraphicsPipe.cxx +++ b/panda/src/x11display/x11GraphicsPipe.cxx @@ -224,11 +224,25 @@ x11GraphicsPipe(const std::string &display) : x11display_cat.debug() << "Using XRRScreenResources to obtain display modes\n"; } + + // Query current configuration, we just grab the first CRTC for now, + // since we don't have a way to represent multiple monitors. + RRMode current_mode_id = 0; + if (res->ncrtc > 0) { + if (auto info = get_crtc_info(res.get(), res->crtcs[0])) { + current_mode_id = info->mode; + } + } + _display_information->_total_display_modes = res->nmode; _display_information->_display_mode_array = new DisplayMode[res->nmode]; for (int i = 0; i < res->nmode; ++i) { XRRModeInfo &mode = res->modes[i]; + if (mode.id == current_mode_id) { + _display_information->_current_display_mode_index = i; + } + DisplayMode *dm = _display_information->_display_mode_array + i; dm->width = mode.width; dm->height = mode.height; From 2539de14fce58bee5738629696a158a8a376f8ae Mon Sep 17 00:00:00 2001 From: rdb Date: Sun, 22 Oct 2023 11:26:59 +0200 Subject: [PATCH 2/4] wxwidgets: Fix some issues with WxSlider, code cleanup --- direct/src/wxwidgets/WxSlider.py | 52 ++++++++++++++++++-------------- 1 file changed, 29 insertions(+), 23 deletions(-) diff --git a/direct/src/wxwidgets/WxSlider.py b/direct/src/wxwidgets/WxSlider.py index f42026ee25..d92a28e206 100755 --- a/direct/src/wxwidgets/WxSlider.py +++ b/direct/src/wxwidgets/WxSlider.py @@ -7,14 +7,16 @@ __all__ = ['WxSlider'] import wx + class WxSlider(wx.Slider): - def __init__(self, parent, id, value, minValue, maxValue,\ - pos=wx.DefaultPosition, size=wx.DefaultSize,\ - style=wx.SL_HORIZONTAL, validator=wx.DefaultValidator, name="slider", textSize=(40,20)): + def __init__(self, parent, id, value, minValue, maxValue, + pos=wx.DefaultPosition, size=wx.DefaultSize, + style=wx.SL_HORIZONTAL, validator=wx.DefaultValidator, + name="slider", textSize=(40, 20)): self.maxValue = maxValue self.minValue = minValue - intVal = 100.0 / (self.maxValue - self.minValue) * (value - self.minValue) + intVal = int(100.0 / (self.maxValue - self.minValue) * (value - self.minValue)) intMin = 0 intMax = 100 @@ -24,42 +26,46 @@ class WxSlider(wx.Slider): if style & wx.SL_HORIZONTAL: newStyle = wx.SL_HORIZONTAL if style & wx.SL_LABELS: - wx.StaticText(parent, -1, "%.2f"%minValue, (pos[0], pos[1])) - strMaxValue = "%.2f"%maxValue - wx.StaticText(parent, -1, strMaxValue, (pos[0] + size[0] - len(strMaxValue) * 8 , pos[1])) - strValue = "%.2f"%value - self.textValue = wx.TextCtrl(parent, -1, strValue,\ - (pos[0] + size[0] /2 - textSize[0]/2, pos[1]), textSize,\ - wx.TE_CENTER | wx.TE_PROCESS_ENTER) + wx.StaticText(parent, -1, "%.2f" % minValue, (pos[0], pos[1])) + strMaxValue = "%.2f" % maxValue + wx.StaticText(parent, -1, strMaxValue, (pos[0] + size[0] - len(strMaxValue) * 8, pos[1])) + strValue = "%.2f" % value + self.textValue = wx.TextCtrl(parent, -1, strValue, + (pos[0] + size[0] / 2 - textSize[0] / 2, pos[1]), + textSize, wx.TE_CENTER | wx.TE_PROCESS_ENTER) self.textValue.Disable() - newPos = (pos[0], pos[1] + 20) + pos = (pos[0], pos[1] + 20) else: newStyle = wx.SL_VERTICAL - newPos = (pos[0], pos[1] + 40) + pos = (pos[0], pos[1] + 40) if style & wx.SL_AUTOTICKS: newStyle |= wx.SL_AUTOTICKS - wx.Slider.__init__(self, parent, id, intVal, intMin, intMax, newPos, size, style=newStyle) + wx.Slider.__init__(self, parent, id, intVal, intMin, intMax, pos, size, style=newStyle) self.Disable() def GetValue(self): # overriding wx.Slider.GetValue() - #return (wx.Slider.GetValue(self) * (self.maxValue - self.minValue) / 100.0 + self.minValue) - return float(self.textValue.GetValue()) # [gjeon] since the value from the slider is not as precise as the value entered by the user + if self.textValue is not None: # Horizontal with labels + return float(self.textValue.GetValue()) # [gjeon] since the value from the slider is not as precise as the value entered by the user + else: + return (wx.Slider.GetValue(self) * (self.maxValue - self.minValue) / 100.0 + self.minValue) def SetValue(self, value): # overriding wx.Slider.SetValue() - self.textValue.SetValue("%.2f"%value) + if self.textValue is not None: + self.textValue.SetValue("%.2f" % value) intVal = 100.0 / (self.maxValue - self.minValue) * (value - self.minValue) wx.Slider.SetValue(self, intVal) def onChange(self, event): # update textValue from slider - self.textValue.Clear() - floatVal = wx.Slider.GetValue(self) * (self.maxValue - self.minValue) / 100.0 + self.minValue - self.textValue.WriteText("%.2f"%floatVal) + if self.textValue is not None: + self.textValue.Clear() + floatVal = wx.Slider.GetValue(self) * (self.maxValue - self.minValue) / 100.0 + self.minValue + self.textValue.WriteText("%.2f" % floatVal) if self.updateCB: # callback function sould receive event as the argument self.updateCB(event) event.Skip() @@ -80,14 +86,14 @@ class WxSlider(wx.Slider): def Disable(self): # overriding wx.Slider.Disable() wx.Slider.Disable(self) - self.textValue.Disable() + if self.textValue is not None: + self.textValue.Disable() def Enable(self): # overriding wx.Slider.Enable() wx.Slider.Enable(self) self.Bind(wx.EVT_SLIDER, self.onChange) - if not self.textValue is None: + if self.textValue is not None: self.textValue.Enable() self.textValue.Bind(wx.EVT_TEXT_ENTER, self.onEnter) - From b4e8cf695864919d3073e0d6489129996ad21ce4 Mon Sep 17 00:00:00 2001 From: rdb Date: Sun, 22 Oct 2023 11:27:36 +0200 Subject: [PATCH 3/4] dist: Fix crash running deploy-stub on arm64 with 16 KiB pages arm64/aarch64 kernels may be configured with 4K, 16K or 64K pages, 16K seems to be most common. The alignment does cause a big waste of space, we may have to revisit the use of mmap, or just mmap the whole executable --- direct/src/dist/FreezeTool.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/direct/src/dist/FreezeTool.py b/direct/src/dist/FreezeTool.py index 5d9d785e4e..93981a9c81 100644 --- a/direct/src/dist/FreezeTool.py +++ b/direct/src/dist/FreezeTool.py @@ -2057,6 +2057,9 @@ class Freezer: if self.platform.startswith('win'): # We don't use mmap on Windows. Align just for good measure. blob_align = 32 + elif self.platform.endswith('_aarch64') or self.platform.endswith('_arm64'): + # Most arm64 operating systems are configured with 16 KiB pages. + blob_align = 16384 else: # Align to page size, so that it can be mmapped. blob_align = 4096 From 0121e74aa48fda10300c5809667ade67e86c5db0 Mon Sep 17 00:00:00 2001 From: rdb Date: Sun, 22 Oct 2023 11:59:30 +0200 Subject: [PATCH 4/4] assimp: Add assimp-disable-extensions config var (for #1537) This can be used to disable certain extensions from being loaded via Assimp Also makes the `get_additional_extensions()` method a bit more efficient by having it avoid string concatenation, using a temporary buffer instead --- pandatool/src/assimp/loaderFileTypeAssimp.cxx | 41 +++++++++++++++---- 1 file changed, 34 insertions(+), 7 deletions(-) diff --git a/pandatool/src/assimp/loaderFileTypeAssimp.cxx b/pandatool/src/assimp/loaderFileTypeAssimp.cxx index bd2eb19d53..2b82e34e2a 100644 --- a/pandatool/src/assimp/loaderFileTypeAssimp.cxx +++ b/pandatool/src/assimp/loaderFileTypeAssimp.cxx @@ -57,22 +57,49 @@ get_extension() const { */ string LoaderFileTypeAssimp:: get_additional_extensions() const { + // This may be called at static init time, so ensure it is constructed now. + static ConfigVariableString assimp_disable_extensions + ("assimp-disable-extensions", "", + PRC_DESC("A list of extensions (without preceding dot) that should not be " + "loaded via the Assimp loader, even if Assimp supports these " + "formats. It is useful to set this for eg. gltf and glb files " + "to prevent them from being accidentally loaded via the Assimp " + "plug-in instead of via a superior plug-in like panda3d-gltf.")); + + bool has_disabled_exts = !assimp_disable_extensions.empty(); + aiString aexts; aiGetExtensionList(&aexts); + char *buffer = (char *)alloca(aexts.length + 2); + char *p = buffer; + // The format is like: *.mdc;*.mdl;*.mesh.xml;*.mot - std::string ext; char *sub = strtok(aexts.data, ";"); while (sub != nullptr) { - ext += sub + 2; - sub = strtok(nullptr, ";"); - - if (sub != nullptr) { - ext += ' '; + bool enabled = true; + if (has_disabled_exts) { + for (size_t i = 0; i < assimp_disable_extensions.get_num_words(); ++i) { + std::string disabled_ext = assimp_disable_extensions.get_word(i); + if (strcmp(sub + 2, disabled_ext.c_str()) == 0) { + enabled = false; + break; + } + } } + if (enabled) { + *(p++) = ' '; + size_t len = strlen(sub + 2); + memcpy(p, sub + 2, len); + p += len; + } + + sub = strtok(nullptr, ";"); } - return ext; + // Strip first space + ++buffer; + return std::string(buffer, p - buffer); } /**