From 932e9815726182b332c52d4d4e8be1e0d2642507 Mon Sep 17 00:00:00 2001 From: rdb Date: Mon, 12 Aug 2019 19:34:17 +0200 Subject: [PATCH 1/3] device: fix deadlock when building with SIMPLE_THREADS=1 GetMessage blocks without yielding, so we need to use an alternative message pump using PeekMessage instead. Fixes #704 --- panda/src/device/winInputDeviceManager.cxx | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/panda/src/device/winInputDeviceManager.cxx b/panda/src/device/winInputDeviceManager.cxx index 232c612186..303400a380 100644 --- a/panda/src/device/winInputDeviceManager.cxx +++ b/panda/src/device/winInputDeviceManager.cxx @@ -62,7 +62,9 @@ WinInputDeviceManager() : } // If we have threading enabled, start a thread with a message-only window - // loop to listen for input events. + // loop to listen for input events. We can't actually just let this be + // handled by the main window loop, because the main window might actually + // have been created in a different thread. #ifdef HAVE_THREADS if (Thread::is_threading_supported()) { PT(Thread) thread = new InputThread(this); @@ -518,10 +520,26 @@ thread_main() { } MSG msg; +#ifdef SIMPLE_THREADS + // In the simple threading case, we can't block the thread waiting for a + // message; we yield control back if there are no more messages. + while (true) { + if (PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE)) { + if (msg.message == WM_QUIT) { + break; + } + TranslateMessage(&msg); + DispatchMessage(&msg); + } else { + Thread::force_yield(); + } + } +#else while (GetMessage(&msg, nullptr, 0, 0) > 0) { TranslateMessage(&msg); DispatchMessage(&msg); } +#endif if (device_cat.is_debug()) { device_cat.debug() From dc599901bc4c10947c77aed609290d72b06da693 Mon Sep 17 00:00:00 2001 From: rdb Date: Mon, 12 Aug 2019 19:37:11 +0200 Subject: [PATCH 2/3] Work around shutdown hang when compiling with SIMPLE_THREADS=1 This is a workaround for a specific case of #508 --- panda/src/device/winInputDeviceManager.cxx | 17 +++++++++++++++++ panda/src/device/winInputDeviceManager.h | 2 ++ panda/src/display/graphicsEngine.cxx | 10 ++++++++++ 3 files changed, 29 insertions(+) diff --git a/panda/src/device/winInputDeviceManager.cxx b/panda/src/device/winInputDeviceManager.cxx index 303400a380..2ca4540ae6 100644 --- a/panda/src/device/winInputDeviceManager.cxx +++ b/panda/src/device/winInputDeviceManager.cxx @@ -464,6 +464,23 @@ destroy_message_loop() { } } +/** + * Sends a signal to the thread input thread, asking it to shut itself down. + */ +void WinInputDeviceManager:: +stop_thread() { +#ifdef HAVE_THREADS + WinInputDeviceManager *mgr = (WinInputDeviceManager *)_global_ptr; + if (mgr != nullptr) { + LightMutexHolder holder(mgr->_lock); + HWND hwnd = mgr->_message_hwnd; + if (hwnd) { + PostMessage(hwnd, WM_QUIT, 0, 0); + } + } +#endif +} + /** * Implementation of the message loop. */ diff --git a/panda/src/device/winInputDeviceManager.h b/panda/src/device/winInputDeviceManager.h index 44eaa053dc..13cab3d7c0 100644 --- a/panda/src/device/winInputDeviceManager.h +++ b/panda/src/device/winInputDeviceManager.h @@ -44,6 +44,8 @@ public: HWND setup_message_loop(); void destroy_message_loop(); + static void stop_thread(); + private: // There are always exactly four of these in existence. XInputDevice _xinput_device0; diff --git a/panda/src/display/graphicsEngine.cxx b/panda/src/display/graphicsEngine.cxx index 80973ae071..c7951ee95a 100644 --- a/panda/src/display/graphicsEngine.cxx +++ b/panda/src/display/graphicsEngine.cxx @@ -49,6 +49,10 @@ #include "callbackGraphicsWindow.h" #include "depthTestAttrib.h" +#if defined(_WIN32) && defined(HAVE_THREADS) && defined(SIMPLE_THREADS) +#include "winInputDeviceManager.h" +#endif + #if defined(WIN32) #define WINDOWS_LEAN_AND_MEAN #include @@ -637,6 +641,12 @@ remove_all_windows() { PStatClient::get_global_pstats()->disconnect(); #endif +#if defined(_WIN32) && defined(HAVE_THREADS) && defined(SIMPLE_THREADS) + // Send a message to the input message pump asking it to shut itself down. + // If we don't do that, the next call will deadlock. + WinInputDeviceManager::stop_thread(); +#endif + // Well, and why not clean up all threads here? Thread::prepare_for_exit(); } From 8be70ed16d9096282c12cb60e0e979f4edfb9858 Mon Sep 17 00:00:00 2001 From: rdb Date: Mon, 12 Aug 2019 21:04:48 +0200 Subject: [PATCH 3/3] glgsg: auto convert to srgb(a) if sluminance not supported This is particularly the case when requesting a core-only profile (gl-version 3 2) where luminance textures are deprecated. There is apparently no way to emulate them with swizzles (as we do with luminance textures), so we'll have to duplicate the channels out. Fixes #693 --- .../glstuff/glGraphicsStateGuardian_src.cxx | 97 ++++++++++++++++++- 1 file changed, 93 insertions(+), 4 deletions(-) diff --git a/panda/src/glstuff/glGraphicsStateGuardian_src.cxx b/panda/src/glstuff/glGraphicsStateGuardian_src.cxx index c913d1ff34..42b29f5944 100644 --- a/panda/src/glstuff/glGraphicsStateGuardian_src.cxx +++ b/panda/src/glstuff/glGraphicsStateGuardian_src.cxx @@ -275,6 +275,22 @@ uchar_bgr_to_rgb(unsigned char *dest, const unsigned char *source, } } +/** + * Recopies the given array of pixels, converting from luminance to RGB + * arrangement. + */ +static void +uchar_l_to_rgb(unsigned char *dest, const unsigned char *source, + int num_pixels) { + for (int i = 0; i < num_pixels; i++) { + dest[0] = source[0]; + dest[1] = source[0]; + dest[2] = source[0]; + dest += 3; + source += 1; + } +} + /** * Recopies the given array of pixels, converting from BGRA to RGBA * arrangement. @@ -292,6 +308,23 @@ uchar_bgra_to_rgba(unsigned char *dest, const unsigned char *source, } } +/** + * Recopies the given array of pixels, converting from luminance-alpha to RGBA + * arrangement. + */ +static void +uchar_la_to_rgba(unsigned char *dest, const unsigned char *source, + int num_pixels) { + for (int i = 0; i < num_pixels; i++) { + dest[0] = source[0]; + dest[1] = source[0]; + dest[2] = source[0]; + dest[3] = source[1]; + dest += 4; + source += 2; + } +} + /** * Recopies the given array of pixels, converting from BGR to RGB arrangement. */ @@ -307,6 +340,22 @@ ushort_bgr_to_rgb(unsigned short *dest, const unsigned short *source, } } +/** + * Recopies the given array of pixels, converting from luminance to RGB + * arrangement. + */ +static void +ushort_l_to_rgb(unsigned short *dest, const unsigned short *source, + int num_pixels) { + for (int i = 0; i < num_pixels; i++) { + dest[0] = source[0]; + dest[1] = source[0]; + dest[2] = source[0]; + dest += 3; + source += 1; + } +} + /** * Recopies the given array of pixels, converting from BGRA to RGBA * arrangement. @@ -324,6 +373,23 @@ ushort_bgra_to_rgba(unsigned short *dest, const unsigned short *source, } } +/** + * Recopies the given array of pixels, converting from luminance-alpha to RGBA + * arrangement. + */ +static void +ushort_la_to_rgba(unsigned short *dest, const unsigned short *source, + int num_pixels) { + for (int i = 0; i < num_pixels; i++) { + dest[0] = source[0]; + dest[1] = source[0]; + dest[2] = source[0]; + dest[3] = source[1]; + dest += 4; + source += 2; + } +} + /** * Reverses the order of the components within the image, to convert (for * instance) GL_BGR to GL_RGB. Returns the byte pointer representing the @@ -343,6 +409,12 @@ fix_component_ordering(PTA_uchar &new_image, switch (external_format) { case GL_RGB: + if (tex->get_num_components() == 1) { + new_image = PTA_uchar::empty_array(orig_image_size * 3); + uchar_l_to_rgb(new_image, orig_image, orig_image_size); + result = new_image; + break; + } switch (tex->get_component_type()) { case Texture::T_unsigned_byte: case Texture::T_byte: @@ -366,6 +438,12 @@ fix_component_ordering(PTA_uchar &new_image, break; case GL_RGBA: + if (tex->get_num_components() == 2) { + new_image = PTA_uchar::empty_array(orig_image_size * 2); + uchar_la_to_rgba(new_image, orig_image, orig_image_size / 2); + result = new_image; + break; + } switch (tex->get_component_type()) { case Texture::T_unsigned_byte: case Texture::T_byte: @@ -9450,7 +9528,6 @@ get_external_image_format(Texture *tex) const { return _supports_bgr ? GL_BGRA : GL_RGBA; case Texture::F_luminance: - case Texture::F_sluminance: #ifdef OPENGLES return GL_LUMINANCE; #else @@ -9458,13 +9535,25 @@ get_external_image_format(Texture *tex) const { #endif case Texture::F_luminance_alphamask: case Texture::F_luminance_alpha: - case Texture::F_sluminance_alpha: #ifdef OPENGLES return GL_LUMINANCE_ALPHA; #else return _supports_luminance_texture ? GL_LUMINANCE_ALPHA : GL_RG; #endif + case Texture::F_sluminance: +#ifdef OPENGLES + return GL_LUMINANCE; +#else + return _supports_luminance_texture ? GL_LUMINANCE : GL_RGB; +#endif + case Texture::F_sluminance_alpha: +#ifdef OPENGLES + return GL_LUMINANCE_ALPHA; +#else + return _supports_luminance_texture ? GL_LUMINANCE_ALPHA : GL_RGBA; +#endif + #ifndef OPENGLES_1 case Texture::F_r8i: case Texture::F_r16i: @@ -10200,9 +10289,9 @@ get_internal_image_format(Texture *tex, bool force_sized) const { #endif #ifndef OPENGLES case Texture::F_sluminance: - return GL_SLUMINANCE8; + return _core_profile ? GL_SRGB8 : GL_SLUMINANCE8; case Texture::F_sluminance_alpha: - return GL_SLUMINANCE8_ALPHA8; + return _core_profile ? GL_SRGB8_ALPHA8 : GL_SLUMINANCE8_ALPHA8; #endif #ifndef OPENGLES