-
Notifications
You must be signed in to change notification settings - Fork 45
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Support for external displays #93
base: master
Are you sure you want to change the base?
Conversation
[v11] introduce no-active-config quirk. JB#56560 Can be used on devices where getActiveConfig is not functional in the v11 backend. Co-authored-by: Franz-Josef Haider <[email protected]>
[v11] Support for external displays. JB#56560 Co-authored-by: elros34 <[email protected]> Co-authored-by: Franz-Josef Haider <[email protected]>
[v11] multiscreen: don't set transform to anything but 0 for now. JB#56560
…frame since it's really slow on some devices. [v11] multiscreen: avoid calling getDisplayAttributes on every frame since it's really slow on some devices. JB#56560
[v11] multiscreen: close releaseFenceFd of framebuffer layer. JB#56560
// glitches and warnings in logcat. By setting the planarAlpha to non- | ||
// opaque, we attempt to force the HWC into using HWC_FRAMEBUFFER for this | ||
// layer so the HWC_FRAMEBUFFER_TARGET layer actually gets used. | ||
bool tryToForceGLES = !qgetenv("QPA_HWC_FORCE_GLES").isEmpty(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What do you think about static bool instead calling qgetenv on every frame.
bool tryToForceGLES = !qgetenv("QPA_HWC_FORCE_GLES").isEmpty(); | |
static bool tryToForceGLES = qEnvironmentVariableIsSet("QPA_HWC_FORCE_GLES"); |
It was quite a long time since I last tried this code but I remember I had crash in hwcomposer when connecting hdmi without this: elros34@9556cd5 (and close fence elros34@a823e4f). hnd pointer is expected to be not NULL: https://github.com/mer-hybris/android_hardware_qcom_display-caf/blob/hybris-11.0-44S/libhwcomposer/hwc_copybit.cpp#L191. This should also prevents "layer handle is NULL" spam in logcat: https://github.com/mer-hybris/android_hardware_qcom_display-caf/blob/hybris-11.0-44S/libhwcomposer/hwc_mdpcomp.cpp#L299. |
{ | ||
free(contents); | ||
|
||
for (auto &screen: screens) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
auto &
-> auto
? Unless you were writing back to the position in the vector I can't think why a reference to a pointer would be favorable to just a pointer.
hwcomposer/hwcomposer_backend_v11.h
Outdated
~RetireFencePool() | ||
{ | ||
for (auto fd: m_fds) { | ||
fprintf(stderr, "Waiting and closing retire fence fd: %d\n", fd); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you add a macro with a environment variable or something for the debug output? A lot of the others are infrequent enough to not really matter but this is going to print every frame.
|
||
// Destination rectangle on the actual screen | ||
const hwc_rect_t dest_rect = { | ||
0, 0, m_screen_width, m_screen_height |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What happens when the screens have different aspect ratios? Is the content just stretched to fit on the external screens?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can only tell that from my old test based on: https://github.com/elros34/qt5-qpa-hwcomposer-plugin/tree/a31 I have only managed to get this code working correctly on native landscape display tablet (screen width > screen height). The content on tv had same aspect ratio as device use. I had to resize content in tv options.
On regular device (moto photon q) which has screen width < screen height content is totally mess up. I have manged to get it working once in portrait mode while messing with width/height parameters in relayout but never managed to rotate content to landscape mode, that is why I dropped it. In nemo bug report (https://bugs.nemomobile.org/show_bug.cgi?id=765: Nemo bug 765 in Hybris-ing "[hammerhead][others] Enable external (Slimport/MHL) screen Mirroring/Extending on Wayland" [Task,New]) there were photos of some nexus devices which worked fine in portrait mode but link is no longer valid and contains some different bug.
…layer." This reverts commit 4c06c77.
[v11] use static variable for QPA_HWC_FORCE_GLES. JB#56560
[v11] use pointer instead of reference to pointer. JB#56560
[v11] move too verbose fence debug behind a macro. JB#56560
}; | ||
|
||
// Don't call getDisplayAttributes too often here since it can cause big slowdowns. | ||
if (m_screen_width <= 0 || m_screen_height <= 0) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This will be still executed because not connected displays (external and virtual) will have m_screen_width/height = 0 until first connection. I wonder whether HwComposerScreen_v11 should be created on demand for external and virtual display. For now relayout is called for 3 displays even without external display connection.
Is it really needed to call relayout() on every frame? From my tests calling it after unblank display was enough but I never manged to get whole code working correctly on native portrait display device so take it with grain of salt.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does it have to be after unblank or is it enough if it's called on hotplug?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have added relayout(HwComposerBackend_v11->widht/height) in hotplug and in createWindow() after width/height are set and indeed both builtin and external display works on A31 based tablet I use for testing.
[v11] don't call relayout on every frame. JB#56560
[v11] update screen sizes on hotplug. JB#56560
…hotplug [v11] update screen sizes not just for the external display on hotplug. JB#56560
[v11] remove unused variable. JB#56560
[v11] set initial screen sizes. JB#56560
[v11] fix QPA_HWC_FORCE_GLES. JB#56560
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The external display support has so far seen limited testing (landscape homescreen exported to external landscape display) so this is probably not fully working yet, but a good first step. Added few comments, but overall looking good. 🙂
} | ||
|
||
((struct HwcProcs_v11*)procs)->backend->screenPlugged(); | ||
((struct HwcProcs_v11*)procs)->content->update_screen_sizes(((struct HwcProcs_v11*)procs)->backend); | ||
} | ||
|
||
HwComposerBackend_v11::~HwComposerBackend_v11() | ||
{ | ||
hwc_device->eventControl(hwc_device, 0, HWC_EVENT_VSYNC, 0); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should there be hwc_device->eventControl(hwc_device, 1, HWC_EVENT_VSYNC, 0) also, i.e. for the external display?
HWC_PLUGIN_EXPECT_ZERO(status); | ||
g_unblanked_displays[display] = (status == blank); | ||
|
||
// on certian devices this is needed |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Typo certain
void | ||
HwComposerBackend_v11::sleepDisplay(bool sleep) | ||
{ | ||
// XXX: For debugging only | ||
//dump_attributes(hwc_device, num_displays); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ideally such debug traces would be put behind Qt logging sub-categories for enabling them without recompilation
@@ -393,7 +687,7 @@ HwComposerBackend_v11::sleepDisplay(bool sleep) | |||
} | |||
} | |||
|
|||
int HwComposerBackend_v11::getSingleAttribute(uint32_t attribute) | |||
int HwComposerBackend_v11::getSingleAttribute(uint32_t attribute, int dpy) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When I see function like "getSingleAttribute(uint32_t attribute, int dpy)" it wass not automatically obvious to me that dpy refered to display's index number. In Qt style abbreviations are avoided (expect in fully local, obvious cases like for (int i; i < count; i++)... Could align with blankDisplay(int display, ..)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also would be good to consistently have display index as the first or second attribute, now both are used
blankDisplay(0, true); | ||
} | ||
fprintf(stderr, "Unblanking external display\n"); | ||
blankDisplay(1, false); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since display 0 is assumed to be always internal display and display 1 the external display would normally avoid hard-coded magical numbers and instead introduce enumerations like InternalDisplay, ExternalDisplay passed to the functions. Now debug prints above are used to document 0=internal, 1=external
// on certian devices this is needed | ||
screenPlugged(); | ||
} | ||
|
||
void | ||
HwComposerBackend_v11::sleepDisplay(bool sleep) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sounds like sleepDisplay() is nowadays sleepDisplays()
HWC_PLUGIN_EXPECT_ZERO(hwc_device->blank(hwc_device, 0, 1)); | ||
for (int i=0; i<num_displays; i++) { | ||
if (g_unblanked_displays[i]) { | ||
blankDisplay(i, true); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As terms go personally I like blanking more than sleeping, but ideally whould stick to one term and at least use it consistently within the scope of internal variables. Now display on/off -> sleepDisplay true/false -> blankDisplay true/false -> device setPowerMode on/off.
|
||
static int g_external_connected = 0; | ||
static int g_external_connected_next = 0; | ||
static int g_unblanked_displays[HWC_NUM_DISPLAY_TYPES] = { 0 }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Non-CamelCase function names get_screen_size and using of fprintf instead of qDebug irks me slightly, but these platform plugin codes are bit in the middle of two words so maybe mixing C-style with C++-style is fine
#if 0 | ||
for (int i=0; i<num_displays; i++) { | ||
blankDisplay(i, false); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wonder if other routines could also have been written to handle n displays instead of hardcoding to 2 (internal, external). Even if initially only two were supported. Maybe not worth the effort at this point
@@ -63,6 +99,7 @@ class HwComposerBackend_v11 : public QObject, public HwComposerBackend { | |||
virtual EGLNativeWindowType createWindow(int width, int height); | |||
virtual void destroyWindow(EGLNativeWindowType window); | |||
virtual void swap(EGLNativeDisplayType display, EGLSurface surface); | |||
virtual void blankDisplay(int display, bool blank); | |||
virtual void sleepDisplay(bool sleep); | |||
virtual float refreshRate(); | |||
virtual bool getScreenSizes(int *width, int *height, float *physical_width, float *physical_height); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
getScreenSize calls getSingleAttribute without display/screen id, which causes getSingleAttribute to default to display 0. If the device has no internal display but only an external one the screen info exposed by the Qt platform plugin reports false values?
Based on @thp s and @elros34 s work. Rebased to latest master, added some workarounds for certain devices.