Skip to content

Endianness handling for RGB565 framebuf mode. #3536

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

Closed
wants to merge 1 commit into from

Conversation

jimmo
Copy link
Member

@jimmo jimmo commented Jan 2, 2018

The current behavior uses the CPU endianness, which I found surprising:

b = bytearray(2)
f = framebuf.FrameBuffer(b, 1, 1, framebuf.RGB565)
f.fill(0xabcd)
print(b)  # bytearray(b'\xcd\xab')

I would expect that to result in bytearray(b'\xab\xcd'). The RGB565
OLED that I'm using needs the bytes arranged big-endian, so currently
this means pushing the endianness-handling to the user of FrameBuffer.

This commits retains the existing behavior for backwards-compatibility
but adds two new modes RGB565_BE and RGB565_LE to allow the user
to explicitly set the behavior. The existing RGB565 will use
whatever the CPU endianness is.

@dpgeorge
Copy link
Member

Thanks @jimmo for the patch. At the very least the byte order of this RGB565 format should be documented, so that it's not a surprise when it comes out "reverse". But do you think it's worth an entire new format id and extra code to handle it? As an alternative, wouldn't it be possible to just provide (in Python, maybe in C...) an rgb-creation function rgb(r, g, b) which yields the right byte order for the given display?

OTOH, if/when we blit supports conversion of colour then it would need to know the precise RGB layout including byte order.

Also note that it might be possible to optimise your patch here (for code size and/or speed) by swapping the byte order of the incoming colour value, instead of using mp_binary_set_int().

@jimmo
Copy link
Member Author

jimmo commented Feb 1, 2018

Thanks Damien -- I can't quite see a nice way to support a conversion function (it's not clear whether it should live on the display or the framebuf, but like you say there are good reasons for putting it on the framebuf for blit/conversion etc - I was keen to work on this next). It's confusing for the programmer to ever see a "backwards" value, and it's a bit burdensome to have to remember when to flip the bytes (i.e. it's fine if I always use the rgb function, but what if my program has hardcoded values or perhaps loads RGB565 values from somewhere else).

To be honest I can't think of a reason why you'd ever not want BE, so for code size/speed I think I'd prefer to just retain the one mode and making it always BE... the current behaviour is surprising enough that maybe this would count as a bug fix rather than a breaking backwards-compatibility?

The two cases I can see for the current behaviour:

  • You really care about accessing individual bytes in the framebuf for a purpose other than sending it directly to a display. I think at this point your code needs to be device-endian aware anyway.
  • You're using a display that expects the bytes in LE -- I think this would be the case for adding RGB565_LE as a framebuffer mode.

@deshipu did you have any thoughts on this? When you added this mode which display were you using? Did you use an rgb() function that was device-endian aware?

@deshipu
Copy link
Contributor

deshipu commented Feb 1, 2018

I originally added that mode to handle ST7735, SSD1331, SSD1351 and ILI9341 displays — they all use the same endianness, some even allow you to change it. I have done much thinking about the general problem of handling displays — you can for example look at my pull request that adds a color mapping option to blit — but ultimately I concluded that framebuffer is the wrong approach to the particular problems of displaying user interfaces and games on the displays that already have their own memory, and I went with a completely different approach which uses a fraction of the memory and is much faster.

@jimmo jimmo force-pushed the framebuf-endian branch from fb43f96 to 48eb3e2 Compare June 18, 2019 00:51
The current behavior uses the CPU endianness, which I found surprising:

```
b = bytearray(2)
f = framebuf.FrameBuffer(b, 1, 1, framebuf.RGB565)
f.fill(0xabcd)
print(b)  # bytearray(b'\xcd\xab')
```

I would expect that to result in `bytearray(b'\xab\xcd')`. The RGB565
OLED that I'm using needs the bytes arranged big-endian, so currently
this means pushing the endianness-handling to the user of FrameBuffer.

This commits retains the existing behavior for backwards-compatibility
but adds two new modes `RGB565_BE` and `RGB565_LE` to allow the user
to explicitly set the behavior. The existing `RGB565` will use
whatever the CPU endianness is.
@jimmo jimmo force-pushed the framebuf-endian branch from 48eb3e2 to 619ce67 Compare June 18, 2019 01:34
@jimmo
Copy link
Member Author

jimmo commented Jun 18, 2019

@peterhinch's comment on #2973 (comment) reminded me that I was still sitting on this...

I still feel the current behavior of framebuf.RGB565 is confusing, so I would like to fix this. Even if the display allows you to change its mode, then the (Python) driver needs to be aware of the host endianness etc.

Also note that it might be possible to optimise your patch here (for code size and/or speed) by swapping the byte order of the incoming colour value, instead of using mp_binary_set_int().

@dpgeorge I tried this and it made the code size larger (+8 bytes). But it would definitely be a speed improvement for all three methods (always for fill, and when the endianess matches for the other two). I've now included this change, happy to go back to the original mp_binary_set_int way though. (Overall this PR is +156 bytes).

@pulkin
Copy link

pulkin commented Nov 26, 2019

I just want to bump this PR because I think that the framebuffer without big-little endiannes option is incomplete. I think that having an out-of-the-box solution for the cheapest display on the market, from my point of view, is much more important than every other mode implemented in framebuffer.

tannewt pushed a commit to tannewt/circuitpython that referenced this pull request Feb 9, 2021
@dpgeorge dpgeorge added the extmod Relates to extmod/ directory in source label May 11, 2021
@jimmo
Copy link
Member Author

jimmo commented May 11, 2021

Discussion moving to #7253

@jimmo jimmo closed this May 11, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
extmod Relates to extmod/ directory in source
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy