diff --git a/Documentation/components/net/delay_act_and_tcp_perf.rst b/Documentation/components/net/delay_act_and_tcp_perf.rst new file mode 100644 index 00000000000..50247b9a57f --- /dev/null +++ b/Documentation/components/net/delay_act_and_tcp_perf.rst @@ -0,0 +1,195 @@ +=============================== +Delayed ACK and TCP Performance +=============================== + +.. warning:: + Migrated from: + https://cwiki.apache.org/confluence/display/NUTTX/Delayed+ACK+and+TCP+Performance + +uIP and NuttX +============= + +The heart of the NuttX IP stack derived from Adam Dunkel's tiny `uIP +stack `_ back at version 1.0. +The NuttX TCP/IP stack contains the uIP TCP state machine and +some uIP "ways of doing things," but otherwise, there is +now little in common between these two designs. + +**NOTE**: uIP is also built into Adam Dunkel's +`Contiki `_ +operating system. + +uIP, Delayed ACKs, and Split Packets +==================================== + +In uIP, TCP packets are sent and ACK'ed one at a time. +That is, after one TCP packet is sent, the next packet cannot +be sent until the previous packet has been ACKed by the +receiving side. +The TCP protocol, of course, supports sending multiple packets +which can be ACKed be the receiving time asynchronously. +This one-packet-at-a-time logic is a simplification in the +uIP design; because of this, uIP needs only a single packet +buffer any you can use uIP in even the tiniest environments. +This is a good thing for the objectives of uIP. + +Improvements in packet buffering is the essential improvement +that you get if upgrade from Adam Dunkel's uIP to his +`lwIP `_ stack. +The price that you pay is in memory usage. + +This one-at-a-time packet transfer does create a performance +problem for uIP: +RFC 1122 states that a host may delay ACKing a packet for up +to 500ms but must respond with an ACK to every second segment. +In the baseline uIP, the effectively adds a one half second +delay between the transfer of every packet to a recipient +that employs this delayed ACK policy! + +uIP has an option to work around this: +It has logic that can be enable to split each packet into half, +sending half as much data in each packet. +Sending more, smaller packets does not sound like a performance +improvement. +This tricks the recipient that follows RFC 1122 into receiving +the two, smaller back-to-back packets and ACKing the second +immediately. +References: `uip-split.c `_ +and `uip-split.h `_. + +The NuttX TCP/IP Stack and Delay ACKs +===================================== + +The NuttX, low-level TCP/IP stack does not have the +limitations of the uIP TCP/IP stack. +It can send numerous TCP/IP packets regardless of +whether they have been ACKed or not. +That is because in NuttX, the accounting for which +packets have been ACKed and which have not has been +moved to a higher level in the architecture. + +NuttX includes a standard, BSD socket interface on top +of the low-level TCP/IP stack. +It is in this higer-level, socket layer where the ACK +accounting is done, specifically in the function +`send() `_. +If you send a large, multi-packet buffer via ``send()``, +it will be broken up into individual packets and each +packet will be sent as quickly as possible, with no +concern for whether the previous packet has been ACKed or not. + +However, the NuttX ``send()`` function will not return to +the caller until the final packet has been ACKed. +It does this to assure that the callers data was sent +successfully (or not). +This behavior means that if an odd number of packets +were sent, there could still be a delay after the final +packet before ``send()`` receives the ACK and returns. + +So the NuttX approach is similar to the uIP way of doing +things, but does add one more buffer, the user provided +buffer to ``send()``, that can be used to improve TCP/IP +performance (of course, this user provided buffer is +also required by in order to be compliant with ``send()``"" +`specification `_. + +The NuttX Split Packet Configuration +==================================== + +But what happens if all of the user buffer is smaller than +the MSS of one TCP packet? +Suppose the MTU is 1500 and the user I/O buffer is only +512 bytes? +In this case, ``send()`` performance degenerates to the same +behavior as uIP: +An ACK is required for each packet before ``send()`` can +return and before ``send()`` can be called again to send +the next packet. + +And the fix? A fix has recently been contributed by +Yan T that works in a similar way to uIP split +packet logic: +In ``send()``, the logic normally tries to send a full packet +of data each time it has the opportunity to do so. +However, if the configuration option ``CONFIG_NET_TCP_SPLIT=y`` +is defined, the behavior of ``send()`` will change in the +following way: + +* ``send()`` will keep track of `even` and `odd` packets; `even` + packets being those that we do not expect to be ACKed + and `odd` packets being the those that we do expect to + be ACKed. +* ``send()`` will then reduce the size of even packets as + necessary to assure that an even number of packets is + always sent. Every call to send will result in an even + number of packets being sent. + +This clever solution tricks the RFC 1122 recipient in the +same way that uIP split logic does. +So if you are working with hosts the following the RFC 1122 +ACKing behavior and you have MSS sizes that are larger that +the average size of the user buffers, then your throughput +can probably be greatly improved by enabling ``CONFIG_NET_TCP_SPLIT=y`` + +NOTE: NuttX is `not` an RFC 1122 recipient; NuttX will ACK +every TCP/IP packet that it receives. + +Write Buffering +=============== + +The best technical solution to the delayed ACK problem +would be to support `write buffering`. +Write buffering is enabled with ``CONFIG_NET_TCP_WRITE_BUFFERS``. +If this option is selected, the NuttX networking layer will +pre-allocate several write buffers at system initialization +time. The sending a buffer of data then works like this: + +* ``send()`` (1) obtains a pre-allocated write buffer from a free + list, and then (2) simply copies the buffer of data that the + user wishes to send into the allocated write buffer. If no + write buffer is available, ``send()`` would have to block waiting + for free write buffer space. +* ``send()`` then (3) adds the write buffer to a queue of outgoing + data for a TCP socket. Each open TCP socket has to support + such a queue. ``send()`` could then (4) return success to the + caller (even thought the transfer could still fail later). +* Logic outside of the ``send()`` implementation manages the actual + transfer of data from the write buffer. When the Ethernet + driver is able to send a packet on the TCP connection, this + external logic (5) copies a packet of data from the write + buffer so that the Ethernet driver can perform the + transmission (a `zero-copy` implementation would be preferable). + Note that the data has to remain in the write buffer for now; + it may need to be re-transmitted. +* This external logic would also manage the receipt TCP ACKs. + When TCP peer acknowledges the receipt of data, the + acknowledged portion of the data can the (6) finally + be deleted from the write buffer. + +The following options configure TCP write buffering: + +* ``CONFIG_NET_TCP_WRITE_BUFSIZE``: The size of one TCP write buffer. +* ``CONFIG_NET_NTCP_WRITE_BUFFERS``: The number of TCP + write buffers (may be zero to disable TCP/IP write buffering) + +NuttX also supports TCP read-ahead buffering. This option +is enabled with ``CONFIG_NET_TCP_READAHEAD``. TCP read-ahead +buffer is necessary on TCP connections; otherwise data +received while there is no ``recv()`` in place would be lost. +For consistency, it would be best if such a TCP write +buffer implementation worked in a manner similar to the +existing TCP read-ahead buffering. + +The following lists the NuttX configuration options +available to configure the TCP read-ahead buffering feature: + +* ``CONFIG_NET_TCP_READAHEAD_BUFSIZE``: The size of one TCP read-ahead buffer. +* ``CONFIG_NET_NTCP_READAHEAD_BUFFERS``: The number of TCP + read-ahead buffers (may be zero to disable TCP/IP read-ahead buffering) + +A future enhancement is to combine the TCP write buffer +management logic and the TCP read-ahead buffer management +so that one common pool of buffers can be used for both +functions (this would probably also require additional logic +to `throttle` read-buffering so that received messages do not +consume all of the buffers). \ No newline at end of file diff --git a/Documentation/components/net/index.rst b/Documentation/components/net/index.rst index ebefe8d32c1..025966919b6 100644 --- a/Documentation/components/net/index.rst +++ b/Documentation/components/net/index.rst @@ -16,6 +16,8 @@ Network Support netlink.rst slip.rst wqueuedeadlocks.rst + tcp_network_perf.rst + delay_act_and_tcp_perf.rst ``net`` Directory Structure :: diff --git a/Documentation/components/net/tcp_network_perf.rst b/Documentation/components/net/tcp_network_perf.rst new file mode 100644 index 00000000000..33e89d8efd2 --- /dev/null +++ b/Documentation/components/net/tcp_network_perf.rst @@ -0,0 +1,193 @@ +======================= +TCP Network Performance +======================= + +.. warning:: + Migrated from: + https://cwiki.apache.org/confluence/display/NUTTX/TCP+Network+Performance + + +(Abstracted and extended from a discussion from the NuttX Google group) + +Question +======== + +For some unknown reason, I am seeing poor TCP network performance. + +Answer +====== + +First let's talk about TCP send performance. + +Source of Performance Bottlenecks +--------------------------------- + +General TCP send performance is not determined by the TCP stack as much +as it is by the network device driver. Bad network performance is due +to time lost `BETWEEN` packet transfers. The packet transfers themselves +go at the wire speed*. So if you want to improve performance on a +given network, you have to reduce time lost between transfers. +There is no other way. + +Ignoring Ethernet issues like collisions, back-off delays, +inter-packet gaps (IPG), etc. + +The time between packets is limited primarily by the buffering +design of the network driver. If you want to improve performance, +then you must improve the buffering at the network driver. +You need to support many full size (1500 byte) packet buffers. +You must be able to query the network for new data to transfer, +and queue those transfers in packet buffers. In order to reach +peak performance, the network driver must have the next transfer +buffered and ready-to-go before the previous transfer is finished +to minimize the GAP between packet transfers. + +Different network devices also support more or less efficient +interfaces: The worst performing support interfaces that can +handle only one packet at a time, the best performing are able +to retain linked lists of packet buffers in memory and perform +scatter-gather DMA for a sequence of packets. + +In the NuttX TCP stack, you can also improve performance by +enabling TCP write buffering. But the driver is the real key. + +It would be good to have a real in-depth analysis of the +network stack performance to identify bottlenecks and +generate ideas for performance improvement. No one has +ever done that. If I were aware of any stack related +performance issue, I would certainly address it. + +RFC 1122 +-------- + +There is one important feature missing the NuttX TCP that +can help when there is no write buffering: Without write +buffering send() will not return until the transfer has +been ACKed by the recipient. But under RFC 1122, the host +need not ACK each packet immediately; the host may wait +for 500 MS before ACKing. This combination can cause very +slow performance when small, non-buffered transfers are +made to an RFC 1122 client. However, the RFC 1122 must +ACK at least every second (odd) packet so sequences of +packets with write buffering enabled do not suffer from +this problem. + +`Update: RFC 1122 support was added to the NuttX TCP +stack with commit 66ef6d143a627738ad7f3ce1c065f9b1f3f303b0 +in December of 2019. That, however, that affects only +received packet ACK behavior and has no impact on transmitted +packet performance; write buffering is still recommended.` + +TCPBlaster +---------- + +I created a new test application at ``apps/examples/tcpblaster`` to +measure TCP performance and collected some data for the +configuration that happens to be on my desk. The `tcpblaster` +test gives you the read and write transfer rates in ``Kb/sec`` +(I won't mention the numbers because I don't believe they +would translate any other setup and, hence, would be +misleading). + +There is a nifty `TCP Throughput Tool `_ +that gives some theoretical upper limits on performance. +The tool needs to know the ``MSS`` (which is the Ethernet +packet size that you configured minus the size of the +Ethernet header, 14), the round-trip time (``RTT``)in +milliseconds (which you can +get from the Linux host ping), and a loss constant (which +I left at the default). With these values, I can determine +that the throughput for the NuttX TCP stack is approximately +at the theoretical limits. You should not be able to do +better any better than that (actually, it performs above +the theoretical limit, but I suppose that is why it is +"theoretical"). + +So, If you are unhappy with your network performance, the I +suggest you run the `tcpblaster` test, use that data +(along with the ``RTT`` from ping) with the +`TCP Throughput Tool `_. +If you are still unhappy with the performance, don't go +immediately pointing fingers at the stack (which everyone does). +Instead, you should focus on optimizing your network +configuration settings and reviewing the buffer handling +of the Ethernet driver in you MCU. + +If you do discover any significant performance issues +with the stack I will of course gladly help you resolve +them. Or if you have ideas for improved performance, +I would also be happy to hear those. + +What about Receive Performance? +------------------------------- + +All of the above discussion concerns `transmit performance`, +i.e., "How fast can we send data over the network?" The other +side is receive performance. Receive performance is very +different thing. In this case it is the remote peer who is +in complete control of the rate at which packets appear on +the network and, hence, responsible for all of the raw bit +transfer rates. + +However, we might also redefine performance as the number of +bytes that were `successfully` transferred. In order for the +bytes to be successfully transferred they must be successfully +received and processed on the NuttX target. If we fail in +this if the packet is `lost` or `dropped`. A packet is lost if +the network driver is not prepared to receive the packet when +it was sent. A packet is dropped by the network if it is +received but could not be processed either because there +is some logical issue with the packet (not the case here) +or if we have no space to buffer the newly received packet. + +If a TCP packet is lost or dropped, then the penalty is big: +The packet will not be ACKed, the remote peer may send a +few more out-of-sequence packets which will also be dropped. +Eventually, the remote peer will time out and retransmit +the data from the point of the lost packet. + +There is logic in the TCP protocol to help manage these data +overruns. The TCP header includes a TCP `receive window` which +tells the remote peer how much data the receiver is able to +buffer. This value is sent in the ACK to each received +packet. If well tuned, this receive window could possibly +prevent packets from being lost due to the lack of +read-ahead storage. This is a little better. The remote +peer will hold off sending data instead of timing out and +re-transmitting. But this is still a loss of performance; +the gap between the transfer of packets caused by the hold-off +will result in a reduced transfer rate. + +So the issues for good reception are buffering and processing +time. Buffering again applies to handling within the driver +but unlike the transmit performance, this is not typically +the bottleneck. And there is also a NuttX configuration +option that controls `read-ahead` buffering of TCP packets. +The buffering in the driver must be optimized to avoid lost +packets; the ` buffering can be tuned to minimize +the number packets dropped because we have no space to buffer them. + +But the key to receive perform is management of processing +delays. Small processing delays can occur in the network +driver or in the TCP stack. But the major source of +processing delay is the application which is the ultimate +consumer of the incoming data. Imagine, for example, +and FTP application that is receiving a file over a +TCP and writing the file into FLASH memory. The primary +bottleneck here will be the write to FLASH memory which +is out of the control of software. + +We obtain optimal receive performance when the processing +delays keep up with the rate of the incoming packets. +If the processing data rate is even slightly slower +then the receive data rate, then there will be a +growing `backlog` of buffered, incoming data to be +processed. If this backlog continues to grow then +eventually our ability to buffer data will be exhausted, +packets will be held off or dropped, and performance +will deteriorate. In an environment where a high-end, +remote peer is interacting with the low-end, embedded +system, that remote peer can easily overrun the +embedded system due to the embedded system's limited +buffering space, its much lower processing capability, +and its slower storage peripherals. \ No newline at end of file diff --git a/Documentation/components/nxgraphics/GraphicsInterfaces.png b/Documentation/components/nxgraphics/GraphicsInterfaces.png new file mode 100644 index 00000000000..4fe1177b2ce Binary files /dev/null and b/Documentation/components/nxgraphics/GraphicsInterfaces.png differ diff --git a/Documentation/components/nxgraphics/framebuffer_char_driver.rst b/Documentation/components/nxgraphics/framebuffer_char_driver.rst new file mode 100644 index 00000000000..a7afce5b170 --- /dev/null +++ b/Documentation/components/nxgraphics/framebuffer_char_driver.rst @@ -0,0 +1,383 @@ +============================ +Framebuffer Character Driver +============================ + +.. warning:: + Migrated from: + https://cwiki.apache.org/confluence/display/NUTTX/Framebuffer+Character+Driver + + +NX Graphics +=========== + +NuttX has supported higher level graphics for some time with +the OS's :doc:`/components/nxgraphics/index` and application +oriented :doc:`NxWidgets ` and the tiny +window manager :doc:`NxWM `. +These are higher level in the sense that the primary +graphical function is to support windowing and control +of tools and toolbars within windows. These graphics +tools often do not meet the needs +of developers with very low end graphics and minimal display +requirements. + +Figure 1 +======== + +The framebuffer character driver, along with the option LCD +framebuffer interface, is an optional lighter-weight graphics interface. + +.. image:: GraphicsInterfaces.png + +Framebuffer Character Driver details +==================================== + +A `framebuffer character driver` has been recently been added +to bypass the complexity of `NX` and to provide a direct +application interface to the framebuffer graphic device. +The framebuffer buffer character devices, as with all +character devices, provides the interface to the graphics +device via stand POSIX VFS commands (``open()``, ``close()``, +``read()``, ``write()``, ``seek()``, ...), through IOCTL commands, +and for this driver via the ``mmap()`` function. These +interfaces are described below, + +The framebuffer character driver is located in the NuttX +source tree at ``drivers/video/fb.c``. It is enabled in the +build with ``CONFIG_VIDEO_FB=y``. In order to register the +framebuffer driver, you will need to include logic in the +your board-specific start-up function that calls +``fb_register()`` That code sequence might look something +like: + +.. code-block:: c + + #include + + #ifdef CONFIG_VIDEO_FB + /* Initialize and register the simulated framebuffer driver */ + + ret = fb_register(0, 0); + if (ret < 0) + { + syslog(LOG_ERR, "ERROR: fb_register() failed: %d\n", ret); + } + #endif + +The ``fb_register()`` function takes two parameters: + +* `display`. The display number for the case of boards + supporting multiple displays or for hardware that supports + multiple layers (each layer is consider a display). Typically zero. +* `plane`. Identifies the color plane on hardware that supports + separate framebuffer "planes" for each color component. + Should be zero because no planar hardware is currently + supported by NuttX. + +``fb_register()`` will register the framebuffer character device +at ``/dev/fb`` `N` where `N` is the display number if the devices +supports only a single plane. If the hardware supports +multiple color planes, then the device will be registered +at ``/dev/fb`` `N-M` where `N` is the again display number but `M` +is the display plane. + +There is a simple example at ``apps/examples/fb`` that provides +an illustration of most of the following interfacing methods. + +POSIX Interfaces +================ + +The interaction with the framebuffer character driver via POSIX +VFS interface calls is the same as for other character drivers. +The only aspect that might require some additional discussion +is the use of ``read()``, ``write()``, and ``seek()``. + +* ``read()`` returns data from the framebuffer memory and + updates the file position based on the number of bytes read. +* ``write()`` puts data into the framebuffer memory and + also updates the file position. + +That file position is initially set to the position +zero meaning the beginning of the framebuffer. It is +advanced each time you ``read()`` from or ``write()`` to the +framebuffer. Is also updated by ``seek()``: + +* ``seek()`` sets the file position to any desired + location within the framebuffer. + +The file position is in units of `bytes`. This can be +confusing because other positional data may be in units +`pixels`. Pixels have different `depth` in different displays, +that is, different graphic hardware may support pixels with +differing bits-per-pixel. The pixel depth can be obtained +using one of the IOCTL commands listed below. Since the file +position is in bytes, the bits-per-pixel must be taken account +when using ``read()``, ``write()``, and ``seek()``. The usual conversion +from pixels to bytes is: + +.. code-block:: C + + start_byte = (start_pixel * bits_per_pixel) >> 3; + end_byte = (end_pixel * bits_per_pixel + 7) >> 3; + +While the framebuffer may be accessed with these POSIX interfaces, +a more typical way of interacting with the framebuffer from an +application would involve use of ``mmap()`` as described below. + +IOCTL Commands +============== + +* ``FBIOGET_VIDEOINFO``. Get color plane info. Its argument is + pointer a writable instance of ``struct fb_videoinfo_s``: + + .. code-block:: c + + struct fb_videoinfo_s + { + uint8_t fmt; /* see FB_FMT_* */ + fb_coord_t xres; /* Horizontal resolution in pixel columns */ + fb_coord_t yres; /* Vertical resolution in pixel rows */ + uint8_t nplanes; /* Number of color planes supported */ + }; + +* ``FBIOGET_PLANEINFO``. Get video plane info. It received + a pointer to a writable instance of ``struct fb_planeinfo_s`` as its argument: + + .. code-block:: C + + struct fb_planeinfo_s + { + FAR void *fbmem; /* Start of frame buffer memory */ + uint32_t fblen; /* Length of frame buffer memory in bytes */ + fb_coord_t stride; /* Length of a line in bytes */ + uint8_t display; /* Display number */ + uint8_t bpp; /* Bits per pixel */ + }; + +* ``FBIOGET_CMAP`` and ``FBIOPUT_CMAP``. Get/Put RGB color mapping. + These commands are available only if the hardware and + framebuffer driver support color mapping (``CONFIG_FB_CMAP=y``). + They each take a pointer to an instance of ``struct fb_cmap_s`` + as an argument (writeable for ``FBIOGET_CMAP`` and read-only + for ``FBIOPUT_CMAP``). + + .. code-block:: c + + #ifdef CONFIG_FB_CMAP + struct fb_cmap_s + { + uint16_t first; /* Offset offset first color entry in tables */ + uint16_t len; /* Number of color entries in tables */ + + /* Tables of color component. Any may be NULL if not used */ + + uint8_t *red; /* Table of 8-bit red values */ + uint8_t *green; /* Table of 8-bit green values */ + uint8_t *blue; /* Table of 8-bit blue values */ + #ifdef CONFIG_FB_TRANSPARENCY + uint8_t *transp; /* Table of 8-bit transparency */ + #endif + }; + #endif + +* ``FBIOGET_CURSOR``. Get cursor attributes. This command is + available only if the hardware and framebuffer driver + support cursors (``CONFIG_FB_HWCURSOR=y``). It take a pointer + to a writable instance of ``struct fb_cursorattrib_s``: + + .. code-block:: c + + #ifdef CONFIG_FB_HWCURSOR + #ifdef CONFIG_FB_HWCURSORIMAGE + struct fb_cursorimage_s + { + fb_coord_t width; /* Width of the cursor image in pixels */ + fb_coord_t height /* Height of the cursor image in pixels */ + const uint8_t *image; /* Pointer to image data */ + }; + #endif + + struct fb_cursorpos_s + { + fb_coord_t x; /* X position in pixels */ + fb_coord_t y; /* Y position in rows */ + }; + + #ifdef CONFIG_FB_HWCURSORSIZE + struct fb_cursorsize_s + { + fb_coord_t h; /* Height in rows */ + fb_coord_t w; /* Width in pixels */ + }; + #endif + + struct fb_cursorattrib_s + { + #ifdef CONFIG_FB_HWCURSORIMAGE + uint8_t fmt; /* Video format of cursor */ + #endif + struct fb_cursorpos_s pos; /* Current cursor position */ + #ifdef CONFIG_FB_HWCURSORSIZE + struct fb_cursorsize_s mxsize; /* Maximum cursor size */ + struct fb_cursorsize_s size; /* Current size */ + #endif + }; + #endif + +* ``FBIOPUT_CURSOR``. Set cursor attributes. This command is + available only if the hardware and framebuffer driver + support cursors (``CONFIG_FB_HWCURSOR=y``). It take a + pointer to a writable instance of ``struct fb_setcursor_s``: + + .. code-block:: c + + #ifdef CONFIG_FB_HWCURSOR + struct fb_setcursor_s + { + uint8_t flags; /* See FB_CUR_* definitions */ + struct fb_cursorpos_s pos; /* Cursor position */ + #ifdef CONFIG_FB_HWCURSORSIZE + struct fb_cursorsize_s size; /* Cursor size */ + #endif + #ifdef CONFIG_FB_HWCURSORIMAGE + struct fb_cursorimage_s img; /* Cursor image */ + #endif + }; + #endif + +* ``FBIO_UPDATE``. This IOCTL command updates a rectangular region + in the framebuffer. Some hardware requires that there be + such a notification when a change is made to the + framebuffer (see, for example, the discussion of LCD drivers + below). This IOTCL command is if ``CONFIG_NX_UPDATE=y`` is + defined. It takes a pointer to a read-only instance of + ``struct nxgl_rect_s`` that describes the region to be updated: + + .. code-block:: c + + struct nxgl_rect_s + { + struct nxgl_point_s pt1; /* Upper, left-hand corner */ + struct nxgl_point_s pt2; /* Lower, right-hand corner */ + }; + +``mmap()`` +========== + +Above we talked about using ``read()``, ``write()``, and ``seek()`` to +access the framebuffer. The simplest way to access the +framebuffer, however, is by using the ``mmap()`` to map +the framebuffer memory into the application memory +space. The following ``mmap()`` command, for example, can +be used to obtain a pointer to a read-able, write-able +copy of the framebuffer: + +.. code-block:: c + + FAR void *fbmem; + + fbmem = mmap(NULL, fblen, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_FILE, fd, 0); + if (state.fbmem == MAP_FAILED) + { + /* Handle failure */ + ... + } + + printf("Mapped FB: %p\n", fbmem); + +Where fd is the file descriptor of the opened framebuffer +character driver and ``fblen`` was obtained via an IOCTL +command as described above. NOTE that the framebuffer +buffer pointer is also available within the values +returned by the IOCTL commands. The address is a +kernel memory address and may not be valid in all +build configurations. Hence, ``mmap()`` is the preferred, +portable way to get the framebuffer address. + +Framebuffer vs. LCD Graphics Drivers +==================================== + +Framebuffer graphics drivers are very common in high-end CPUs +but most low-end, embedded hardware will not support a +framebuffer. + +A framebuffer graphics driver supports a region of memory +that is shared both by the software and by the graphics +hardware. Any modification to the framebuffer memory +results in a corresponding modification on the display +with no intervening software interaction. Some video +memory is dual ported to support concurrent video processor +and application processor accesses; or perhaps the LCD +peripheral just constantly DMAs the framebuffer memory +to the graphics hardware. + +Most low-end embedded MCUs have a much simpler hardware +interface: The interface to the LCD may be through a simple +parallel interface or, more commonly, through a slower serial +interface such as SPI. In order to support such low-end +hardware with the framebuffer character driver, a special +software layer called the `Framebuffer LCD Front End` has +been developed. This is the topic of the next paragraph. + +LCD Framebuffer Front-End +========================= + +The `LCD Framebuffer Front-End` provides a standard NuttX +framebuffer interface, but works on top of a standard +parallel or serial LCD driver. It provides the framebuffer, +the framebuffer interface, and the hooks to adapt the LCD +driver. The LCD framebuffer front-end can be found in the +NuttX source tree at ``drivers/lcd/lcd_framebuffer.c``. + +In order to provide updates to the LCD hardware after +updates to the framebuffer, the LCD framebuffer front-end +must be notified when significant changes to the framebuffer +have been made. This notification is supported when +``CONFIG_NX_UPDATE=y`` is defined in the configuration. In +this case, the LCD framebuffer front-end will support +the special. OS-internal interface function ``nx_notify_rectangle()`` +which defines the rectangular region in the framebuffer that +has been changed. In response to a call to ``nx_notify_rectangle()`` +will use the lower-level LCD interface to update only that +rectangular region on the display. + +This kind of update for standard LCD drivers is very efficient: +It is usually more efficient to update a region on the +display than it is for form a complex image with text and +line drawing; the updated region seems to update very +quickly because of that. In fact, many of the low-end +LCD drivers already include an internal framebuffer to +support this style of LCD update. + +When used with LCD character driver, the ``nx_notify_rectangle()`` +function will be called by the character river in response +to the ``FBIO_UPDATE IOCTL`` command. + +Another advantage of the framebuffer, both the LCD internal +framebuffer and the framebuffer character driver, is +that super-efficient reading of the LCD display memory: +The LCD display memory is not read at all! The read is +from the copy in the framebuffer. + +Of course, using both an LCD internal framebuffer with the +framebuffer character drivers is wasteful; one framebuffer +is enough! + +As a caution, it is important to remember that a framebuffer +can be quite large. For example, a 480x320 display with +16-bit RGB pixels would require an allocated framebuffer +of size 300 KiB. This is inappropriate with most small +MCUs (unless they support external memory). For tiny displays, +such as 128x64 1-bit monochromatic displays, the framebuffer +memory usage is not bad: 1 KiB in that example. + +Framebuffer Graphics Library +============================ + +Now the missing part is some kind of application-space +framebuffer graphics library. The NuttX framebuffer +driver is superficially similar to the Linux framebuffer +driver so there is a lot of support for Linux +framebuffer graphics support that should be easily ported to +NuttX – Perhaps DirectFB would be an GPL option? SDL with its +MIT license might be a more compatible source for such a port. \ No newline at end of file diff --git a/Documentation/components/nxgraphics/index.rst b/Documentation/components/nxgraphics/index.rst index f5740a45c8d..318f3bd98ec 100644 --- a/Documentation/components/nxgraphics/index.rst +++ b/Documentation/components/nxgraphics/index.rst @@ -171,6 +171,8 @@ NX Header Files nxtk.rst nxfonts.rst nxcursor.rst + nxwm_threading.rst + framebuffer_char_driver.rst sample.rst appendix.rst diff --git a/Documentation/components/nxgraphics/nxwm_threading.rst b/Documentation/components/nxgraphics/nxwm_threading.rst new file mode 100644 index 00000000000..ea5c8ac9658 --- /dev/null +++ b/Documentation/components/nxgraphics/nxwm_threading.rst @@ -0,0 +1,13 @@ +============== +NxWM Threading +============== + +.. warning:: + Migrated from: + https://cwiki.apache.org/confluence/display/NUTTX/NxWM+Threading + +.. image:: nxwm_threading_model/nxwm_theading_model_page_0.png +.. image:: nxwm_threading_model/nxwm_theading_model_page_1.png +.. image:: nxwm_threading_model/nxwm_theading_model_page_2.png +.. image:: nxwm_threading_model/nxwm_theading_model_page_3.png +.. image:: nxwm_threading_model/nxwm_theading_model_page_4.png diff --git a/Documentation/components/nxgraphics/nxwm_threading_model/nxwm_theading_model_page_0.png b/Documentation/components/nxgraphics/nxwm_threading_model/nxwm_theading_model_page_0.png new file mode 100644 index 00000000000..eb95bc5a3f6 Binary files /dev/null and b/Documentation/components/nxgraphics/nxwm_threading_model/nxwm_theading_model_page_0.png differ diff --git a/Documentation/components/nxgraphics/nxwm_threading_model/nxwm_theading_model_page_1.png b/Documentation/components/nxgraphics/nxwm_threading_model/nxwm_theading_model_page_1.png new file mode 100644 index 00000000000..3e38e9b0db7 Binary files /dev/null and b/Documentation/components/nxgraphics/nxwm_threading_model/nxwm_theading_model_page_1.png differ diff --git a/Documentation/components/nxgraphics/nxwm_threading_model/nxwm_theading_model_page_2.png b/Documentation/components/nxgraphics/nxwm_threading_model/nxwm_theading_model_page_2.png new file mode 100644 index 00000000000..8bde18ebf76 Binary files /dev/null and b/Documentation/components/nxgraphics/nxwm_threading_model/nxwm_theading_model_page_2.png differ diff --git a/Documentation/components/nxgraphics/nxwm_threading_model/nxwm_theading_model_page_3.png b/Documentation/components/nxgraphics/nxwm_threading_model/nxwm_theading_model_page_3.png new file mode 100644 index 00000000000..80020f0e34d Binary files /dev/null and b/Documentation/components/nxgraphics/nxwm_threading_model/nxwm_theading_model_page_3.png differ diff --git a/Documentation/components/nxgraphics/nxwm_threading_model/nxwm_theading_model_page_4.png b/Documentation/components/nxgraphics/nxwm_threading_model/nxwm_theading_model_page_4.png new file mode 100644 index 00000000000..cbdc132904e Binary files /dev/null and b/Documentation/components/nxgraphics/nxwm_threading_model/nxwm_theading_model_page_4.png differ