This is a first go at it, done by naive replacing of all array
operations with corresponding operations on the list. Note that
there is a lot of unnecessary type conversions, here. Also, list_pop
has been copied, because it's decalerd STATIC in py/objlist.h
Since we want to expose the list of group's children to the user,
we should only have the original objects in it, without any other
additional data, and compute the native object as needed.
* Comment on the reason for scaling by 256
* Divide by 256 instead of shifting
* fix a cast; eliminate an unneeded roundf() to get a few bytes code back
On the Pico, this increases the "fill rate" of
pixels[:] = newvalues
considerably. On a strip of 240 RGB LEDs, auto_write=False, the timings
are:
|| Brightness || Before || After || Improvement ||
|| 1.0 || 117 kpix/s || 307 kpix/s || 2.62x ||
|| 0.07 || 117 kpix/s || 273 kpix/s || 2.33x ||
It's worth noting that even the "before" rate is fast compared to the
time to transmit a single neopixel, but any time we can gain back
in the whole pipeline will let marginal animations work a little better.
To set all the pixels in this way and then show() gives a pleasant bump
to the framerate, from about 108Hz to 124Hz (1.15x)
The main source of speed-up is using integer math instead of floating
point math for the calculation of the post-scaled pixel values. A slight
secondary gain is achieved by avoiding the scaling altogether when
the scale factor is 1.0.
Because the math is not exactly the same, some scaled pixel values may
change by +- 1 RGBW "step". In practice, this is unlikely to matter.
The gains are bigger on the Pico and other M0 microcontrollers than M4
microcontrollers with floating point math in the hardware.
Happily, flash size is also improved a bit on the Pico build I did,
going from
> 542552 bytes used, 506024 bytes free in flash firmware space out of 1048576 bytes (1024.0kB).
to
> 542376 bytes used, 506200 bytes free in flash firmware space out of 1048576 bytes (1024.0kB).
Also found a race condition between timer_disable and redraw, which
would happen if I debugger-paused inside common_hal_rgbmatrix_timer_disable
or put a delay or print inside it. That's what pausing inside reconstruct
fixes.
So that the "right timer" can be chosen, `timer_allocate` now gets the `self`
pointer. It's guaranteed at this point that the pin information is accurate,
so you can e.g., find a PWM unit related to the pins themselves.
This required touching each port to add the parameter even though it's
unused everywhere but raspberrypi.
* Introduce explicit serpentine: bool argument instead of using negative
numbers (thanks, ghost of @tannewt sitting on one shoulder)
* Fix several calculations of height
Testing performed (matrixportal):
* set up a serpentine 64x64 virtual display with 2 64x32 tiles
* tried all 4 rotations
* looked at output of REPL
Changed calls: PointSize(), LineWidth(), VertexTranslateX() and VertexTranslateY()
Units for all the above are now pixels, not fixed-point integers. This matches OpenGL.
Docstrings updated accordingly
The RP2040 is new microcontroller from Raspberry Pi that features
two Cortex M0s and eight PIO state machines that are good for
crunching lots of data. It has 264k RAM and a built in UF2
bootloader too.
Datasheet: https://pico.raspberrypi.org/files/rp2040_datasheet.pdf
Microsoft documentation says:
> If biCompression equals BI_RGB and the bitmap uses 8 bpp or less, the bitmap has a color table immediatelly following the BITMAPINFOHEADER structure. The color table consists of an array of RGBQUAD values. The size of the array is given by the biClrUsed member. If biClrUsed is zero, the array contains the maximum number of colors for the given bitdepth; that is, 2^biBitCount colors.
Formerly, we treated 0 colors as "no image palette" during construction,
but then during common_hal_displayio_ondiskbitmap_get_pixel indexed into
the palette anyway. This could have unpredictable results. On a pygamer,
it gave an image that was blue and black. On magtag, it gave a crash.
The transparent_color field was never initialized. I _think_ this means
its value was always set to 0, or the blackest of blacks. Instead,
initialize it to the sentinel value, newly given the name
NO_TRANSPARENT_COLOR.
This exposed a second problem: The test for whether there was an existing
transparent color was wrong (backwards). I am guessing that this was not
found due to the first bug; since the converter had a transparent color,
the correct test would have led to always getting the error "Only one
color can be transparent at a time".
Closes#3723
Hybrid allocation is now part of the infrastructure. Moving memory contents would not be necessary because displayio can recreate them, but does not hurt.
Hybrid allocation is now part of the infrastructure. Moving memory contents would not be necessary because displayio can recreate them, but does not hurt.
This allows calls to `allocate_memory()` while the VM is running, it will then allocate from the GC heap (unless there is a suitable hole among the supervisor allocations), and when the VM exits and the GC heap is freed, the allocation will be moved to the bottom of the former GC heap and transformed into a proper supervisor allocation. Existing movable allocations will also be moved to defragment the supervisor heap and ensure that the next VM run gets as much memory as possible for the GC heap.
By itself this breaks terminalio because it violates the assumption that supervisor_display_move_memory() still has access to an undisturbed heap to copy the tilegrid from. It will work in many cases, but if you're unlucky you will get garbled terminal contents after exiting from the vm run that created the display. This will be fixed in the following commit, which is separate to simplify review.
* Initialize the EPaper display on the MagTag at start.
* Tweak the display send to take a const buffer.
* Correct Luma math
* Multiply the blue component, not add.
* Add all of the components together before dividing. This
reduces the impact of truncated division.