Skip to content
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

Dispmanx API stops working after HDMI resolution change #461

Open
juj opened this issue Apr 22, 2018 · 5 comments
Open

Dispmanx API stops working after HDMI resolution change #461

juj opened this issue Apr 22, 2018 · 5 comments
Labels
Close within 30 days Issue will be closed within 30 days unless requested to stay open Waiting for input from originator

Comments

@juj
Copy link

juj commented Apr 22, 2018

gba_quake2

I've been poking on a project that fits a Raspberry Pi 3 CM inside the shell of a Gameboy Advance (video), running a Waveshare32b SPI based display. In this configuration, there is no display connected to HDMI, but instead I run a custom software driver fbcp-ili9341 that interfaces with the dispmanx API to grab framebuffer display and push the pixel data out to SPI.

One issue that is happening is that it looks like the dispmanx_ APIs stop working if the system changes resolution, by an application, or also when changed via tvservice command line interface. To reproduce, try

test.cpp

#include <stdio.h>
#include <bcm_host.h>

int main()
{
  bcm_host_init();
  DISPMANX_DISPLAY_HANDLE_T display = vc_dispmanx_display_open(0);
  if (!display) { printf("vc_dispmanx_display_open failed!\n"); exit(1); }

  DISPMANX_MODEINFO_T display_info;
  int ret = vc_dispmanx_display_get_info(display, &display_info);
  if (ret) { printf("vc_dispmanx_display_get_info failed!\n"); exit(1); }

  int framebufferSizeBytes = display_info.width * display_info.height * 2;
  uint16_t *videoCoreFramebuffer = (uint16_t *)malloc(framebufferSizeBytes);
  memset(videoCoreFramebuffer, 0, framebufferSizeBytes);

  uint32_t image_prt;
  DISPMANX_RESOURCE_HANDLE_T screen_resource = vc_dispmanx_resource_create(VC_IMAGE_RGB565, display_info.width, display_info.height, &image_prt);
  if (!screen_resource) { printf("vc_dispmanx_resource_create failed!\n"); exit(1); }
  VC_RECT_T rect;
  vc_dispmanx_rect_set(&rect, 0, 0, display_info.width, display_info.height);

  vc_dispmanx_snapshot(display, screen_resource, (DISPMANX_TRANSFORM_T)0);
  vc_dispmanx_resource_read_data(screen_resource, &rect, videoCoreFramebuffer, display_info.width*2);

  uint32_t data = 0;
  for(int i = 0; i < framebufferSizeBytes/2; ++i)
  	data += videoCoreFramebuffer[i];
  printf("Data: %u\n", data);
}

and build with g++ test.cpp -o test -I/opt/vc/include -L/opt/vc/lib -lbcm_host.

Running with the following /boot/config.txt for display configuration:

hdmi_force_hotplug=1
hdmi_group=2
hdmi_mode=87
hdmi_cvt=320 240 60 1 0 0 0

and after boot of the Pi, with no HDMI display connected, no applications open but the Pi open in console, the above test code gives

pi@retropie:~ $ tvservice -s
state 0x12000a [HDMI DMT (87) RGB full 4:3 x4], 320x240 @ 59.00Hz, progressive
pi@retropie:~ $ ./test
Data: 3470187170

which is good, the application was able to capture some pixel data.

However, the following scenarios cause the above test code to begin to fail:

Change resolution

pi@retropie:~ $ tvservice -s
state 0x12000a [HDMI DMT (87) RGB full 4:3 x4], 320x240 @ 59.00Hz, progressive
pi@retropie:~ $ ./test
Data: 3470187170 ## Good
pi@retropie:~ $ tvservice --modes=CEA
Group CEA has 2 modes:
           mode 4: 1280x720 @ 60Hz 16:9, clock:74MHz progressive
           mode 16: 1920x1080 @ 60Hz 16:9, clock:148MHz progressive
pi@retropie:~ $ tvservice --explicit="CEA 4 HDMI"
Powering on HDMI with explicit settings (CEA mode 4)
pi@retropie:~ $ tvservice -s
state 0x12000a [HDMI CEA (4) RGB lim 16:9], 1280x720 @ 60.00Hz, progressive
pi@retropie:~ $ ./test
Data: 0 ## Bad

Here after changing the display mode, dispmanx snapshots no longer work but start to return black frames.

Change resolution, but change it back to original

Changing resolution back to "what was working originally" 320x240 does not restore dispmanx to work:

pi@retropie:~ $ tvservice -s
state 0x12000a [HDMI DMT (87) RGB full 4:3 x4], 320x240 @ 59.00Hz, progressive
pi@retropie:~ $ ./test
Data: 3470187170
pi@retropie:~ $ tvservice --explicit="CEA 4 HDMI"
Powering on HDMI with explicit settings (CEA mode 4)
pi@retropie:~ $ tvservice --explicit="DMT 87 HDMI"
Powering on HDMI with explicit settings (DMT mode 87)
pi@retropie:~ $ tvservice -s
state 0x12000a [HDMI DMT (87) RGB full 4:3 x4], 320x240 @ 59.00Hz, progressive
pi@retropie:~ $ ./test
Data: 0

Change resolution to what is already set

It looks like changing the resolution to the same mode that is already currently set causes dispmanx to start outputting black as well:

pi@retropie:~ $ tvservice -s
state 0x12000a [HDMI DMT (87) RGB full 4:3 x4], 320x240 @ 59.00Hz, progressive
pi@retropie:~ $ ./test
Data: 3470187170
pi@retropie:~ $ tvservice --explicit="DMT 87 HDMI"
Powering on HDMI with explicit settings (DMT mode 87)
pi@retropie:~ $ tvservice -s
state 0x12000a [HDMI DMT (87) RGB full 4:3 x4], 320x240 @ 59.00Hz, progressive
pi@retropie:~ $ ./test
Data: 0

Powering HDMI off and then on

pi@retropie:~ $ tvservice -s
state 0x12000a [HDMI DMT (87) RGB full 4:3 x4], 320x240 @ 59.00Hz, progressive
pi@retropie:~ $ ./test
Data: 3470187170
pi@retropie:~ $ tvservice -o
Powering off HDMI
pi@retropie:~ $ tvservice -s
state 0x120002 [TV is off]
pi@retropie:~ $ tvservice --explicit="DMT 87 HDMI"
Powering on HDMI with explicit settings (DMT mode 87)
pi@retropie:~ $ tvservice -s
state 0x12000a [HDMI DMT (87) RGB full 4:3 x4], 320x240 @ 59.00Hz, progressive
pi@retropie:~ $ ./test
vc_dispmanx_display_open failed!

causes dispmanx to no longer initialize.


Are the above scenarios expected to work? Or I wonder if the relationship between tvservice and dispmanx is not as 1:1, but there's some initialization/setup steps missing when changing the display?

Also, what is the role of tvservice versus other methods for changing the HDMI display resolution? Is tvservice the utility through which all applications must go when switching display modes, or are there other utilities? (I wonder if the above test method is flawed for example if tvservice should not be used in this kind of way, or something similar)

Thanks for reading through, any suggestions would be most welcome!

@juj
Copy link
Author

juj commented Apr 22, 2018

Searching the web for related discussions, this link suggests that calling fbset -depth 8 && fbset -depth 16 might have an effect here. Trying this out with

pi@retropie:~ $ tvservice -s
state 0x12000a [HDMI DMT (87) RGB full 4:3 x4], 320x240 @ 59.00Hz, progressive
pi@retropie:~ $ ./test
Data: 1388129224
pi@retropie:~ $ tvservice --explicit="DMT 87 HDMI"
Powering on HDMI with explicit settings (DMT mode 87)
pi@retropie:~ $ tvservice -s
state 0x12000a [HDMI DMT (87) RGB full 4:3 x4], 320x240 @ 59.00Hz, progressive
pi@retropie:~ $ ./test
Data: 0
pi@retropie:~ $ fbset -depth 8 && fbset -depth 16
pi@retropie:~ $ ./test
Data: 0
pi@retropie:~ $ vcgencmd display_power
display_power=1
pi@retropie:~ $ fbset

mode "320x240"
    geometry 320 240 320 240 16
    timings 0 0 0 0 0 0 0
    rgba 5/11,6/5,5/0,0/16
endmode

is no luck unfortunately. Attempting some combos of fbset -xres 320 -yres 240 -vxres 320 -vyres 240 from here and/or vcgencmd display_power 0 followed by vcgencmd display_power 1 from here did not have working effect on this either.

@JamesH65
Copy link
Collaborator

JamesH65 commented Jan 8, 2019

Sorry about delay on this - just going through the backlog and found it.

This is expected behaviour if using tvservice on its own.

When the HDMI mode is changed, dispmanx discards all framebuffers etc to do with the mode as sizes etc will have changed. This results in a blank screen, both on HDMI but also, I believe, any snapshots.

To get dispmanx to reinitilaise all the required buffers, and get HDMI displaying again, you need to run fbset with the appropriate parameters. fbset ensures that the firmware creates a new framebuffer and attaches it to dispmanx. One proviso, fbset is a no op if the thing you are setting to is the same as what it already thinks is there, so you may need to fbset <something else>. then go back to your original framebuffer size (e.g. -depth 16 then -depth 24).

As an example, check out the way omxplayer does this - see the script that runs it for details, which omxplayer will get its location.

@JamesH65 JamesH65 added Waiting for input from originator Close within 30 days Issue will be closed within 30 days unless requested to stay open labels Jan 8, 2019
@jamesc2151
Copy link

Just got a my TFT working on the newest copy of buster .. I have a 320x240 SPI Serial ILI9341 from amazon and compiled using the command ..
`` cmake -DSPI_BUS_CLOCK_DIVISOR=30 -DSTATISTICS=0 -DGPIO_TFT_DATA_CONTROL=24 -DGPIO_TFT_RESET_PIN=20 -DGPIO_TFT_BACKLIGHT=23 -DBACKLIGHT_CONTROL=ON -DDISPLAY_BREAK_ASPECT_RATIO_WHEN_SCALING=ON -DILI9341=ON -DDISPLAY_ROTATE_180_DEGREES=ON ..

It works like a charm so for those f you with this screen it works my config text has the fake dtoverlay=vc4-fkms-v3d for hdmi and
dtparam=spi=off
framebuffer_width=1024
framebuffer_height=768
hdmi_group=2
hdmi_mode=1
hdmi_mode=87
hdmi_cvt 640 480 60 6 0 0 0
display_rotate=90
avoid_warnings=1

Took me about 10 minutes after I found a wiring setup that it liked as I have other hardware installed 2 OLE displays and a RTC that default wiring kept interfering with.

@6by9
Copy link
Contributor

6by9 commented Dec 19, 2023

Buster is deprecated, as is DispmanX.

There is a TinyDRM driver for ILI9341 panels, and an overlay on https://github.com/6by9/linux/tree/rpi-6.1.y-tinydrm that will configure and load it (dtoverlay=tinydrm,waveshare24).
Wayfire will then happily extend the desktop onto that display, or use any application that talks to a DRM backend with it.

@jamesc2151
Copy link

Sorry didn't mean buster... I meant to type bookworm... I use my system headless and watch this little console for Cava to display my sound bar graphs

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Close within 30 days Issue will be closed within 30 days unless requested to stay open Waiting for input from originator
Projects
None yet
Development

No branches or pull requests

4 participants