xref: /aosp_15_r20/external/pigweed/seed/0104.rst (revision 61c4878ac05f98d0ceed94b57d316916de578985)
1*61c4878aSAndroid Build Coastguard Worker.. _seed-0104:
2*61c4878aSAndroid Build Coastguard Worker
3*61c4878aSAndroid Build Coastguard Worker=====================
4*61c4878aSAndroid Build Coastguard Worker0104: Display Support
5*61c4878aSAndroid Build Coastguard Worker=====================
6*61c4878aSAndroid Build Coastguard Worker.. seed::
7*61c4878aSAndroid Build Coastguard Worker   :number: 104
8*61c4878aSAndroid Build Coastguard Worker   :name: Display Support
9*61c4878aSAndroid Build Coastguard Worker   :status: Accepted
10*61c4878aSAndroid Build Coastguard Worker   :proposal_date: 2023-06-12
11*61c4878aSAndroid Build Coastguard Worker   :cl: 150793
12*61c4878aSAndroid Build Coastguard Worker   :authors: Chris Mumford
13*61c4878aSAndroid Build Coastguard Worker   :facilitator: Anthony DiGirolamo
14*61c4878aSAndroid Build Coastguard Worker
15*61c4878aSAndroid Build Coastguard Worker-------
16*61c4878aSAndroid Build Coastguard WorkerSummary
17*61c4878aSAndroid Build Coastguard Worker-------
18*61c4878aSAndroid Build Coastguard WorkerAdd support for graphics displays. This includes display drivers for a few
19*61c4878aSAndroid Build Coastguard Workerpopular display controllers, framebuffer management, and a framework to simplify
20*61c4878aSAndroid Build Coastguard Workeradding a graphics display to a Pigweed application.
21*61c4878aSAndroid Build Coastguard Worker
22*61c4878aSAndroid Build Coastguard Worker----------
23*61c4878aSAndroid Build Coastguard WorkerMotivation
24*61c4878aSAndroid Build Coastguard Worker----------
25*61c4878aSAndroid Build Coastguard WorkerPigweed currently has no specific support for a display device. Projects that
26*61c4878aSAndroid Build Coastguard Workerrequire a display currently must do the full implementation, including the
27*61c4878aSAndroid Build Coastguard Workerdisplay driver in most instances, to add display support.
28*61c4878aSAndroid Build Coastguard Worker
29*61c4878aSAndroid Build Coastguard WorkerThis proposes the addition of a basic framework for display devices, as well
30*61c4878aSAndroid Build Coastguard Workeras implementations for a few common Pigweed test devices - specifically the
31*61c4878aSAndroid Build Coastguard WorkerSTM32F429I. This enables developers to quickly and easily add display support
32*61c4878aSAndroid Build Coastguard Workerfor supported devices and an implementation to model when adding new device
33*61c4878aSAndroid Build Coastguard Workersupport.
34*61c4878aSAndroid Build Coastguard Worker
35*61c4878aSAndroid Build Coastguard Worker--------
36*61c4878aSAndroid Build Coastguard WorkerProposal
37*61c4878aSAndroid Build Coastguard Worker--------
38*61c4878aSAndroid Build Coastguard WorkerThis proposes no changes to existing modules, but suggests several new libraries
39*61c4878aSAndroid Build Coastguard Workerall within a single new module titled ``pw_display`` that together define a
40*61c4878aSAndroid Build Coastguard Workerframework for rendering to displays.
41*61c4878aSAndroid Build Coastguard Worker
42*61c4878aSAndroid Build Coastguard Worker
43*61c4878aSAndroid Build Coastguard WorkerNew Libraries
44*61c4878aSAndroid Build Coastguard Worker=============
45*61c4878aSAndroid Build Coastguard Worker.. list-table::
46*61c4878aSAndroid Build Coastguard Worker   :widths: 5 45
47*61c4878aSAndroid Build Coastguard Worker   :header-rows: 1
48*61c4878aSAndroid Build Coastguard Worker
49*61c4878aSAndroid Build Coastguard Worker   * - Library
50*61c4878aSAndroid Build Coastguard Worker     - Function
51*61c4878aSAndroid Build Coastguard Worker
52*61c4878aSAndroid Build Coastguard Worker   * - pw_display/display
53*61c4878aSAndroid Build Coastguard Worker     - Manage draw thread, framebuffers, and driver
54*61c4878aSAndroid Build Coastguard Worker
55*61c4878aSAndroid Build Coastguard Worker   * - pw_display/driver
56*61c4878aSAndroid Build Coastguard Worker     - Display driver interface definition
57*61c4878aSAndroid Build Coastguard Worker
58*61c4878aSAndroid Build Coastguard Worker   * - pw_display/pixel_pusher
59*61c4878aSAndroid Build Coastguard Worker     - Transport of pixel data to display controller
60*61c4878aSAndroid Build Coastguard Worker
61*61c4878aSAndroid Build Coastguard Worker   * - pw_display/drivers/ili9341
62*61c4878aSAndroid Build Coastguard Worker     - Display driver for the ILI9341 display controller
63*61c4878aSAndroid Build Coastguard Worker
64*61c4878aSAndroid Build Coastguard Worker   * - pw_display/drivers/imgui
65*61c4878aSAndroid Build Coastguard Worker     - Host display driver using `Dear ImGui <https://www.dearimgui.com/>`_
66*61c4878aSAndroid Build Coastguard Worker
67*61c4878aSAndroid Build Coastguard Worker   * - pw_display/drivers/mipi
68*61c4878aSAndroid Build Coastguard Worker     - Display driver for `MIPI DSI <https://www.mipi.org/specifications/dsi>`_ controllers
69*61c4878aSAndroid Build Coastguard Worker
70*61c4878aSAndroid Build Coastguard Worker   * - pw_display/drivers/null
71*61c4878aSAndroid Build Coastguard Worker     - Null display driver for headless devices
72*61c4878aSAndroid Build Coastguard Worker
73*61c4878aSAndroid Build Coastguard Worker   * - pw_display/drivers/st7735
74*61c4878aSAndroid Build Coastguard Worker     - Display driver for the `ST7735 <https://www.displayfuture.com/Display/datasheet/controller/ST7735.pdf>`_ display controller
75*61c4878aSAndroid Build Coastguard Worker
76*61c4878aSAndroid Build Coastguard Worker   * - pw_display/drivers/st7789
77*61c4878aSAndroid Build Coastguard Worker     - Display driver for the ST7789 display controller
78*61c4878aSAndroid Build Coastguard Worker
79*61c4878aSAndroid Build Coastguard Worker   * - pw_display/draw
80*61c4878aSAndroid Build Coastguard Worker     - Very basic drawing library for test and bring-up purposes
81*61c4878aSAndroid Build Coastguard Worker
82*61c4878aSAndroid Build Coastguard Worker   * - pw_display/framebuffer
83*61c4878aSAndroid Build Coastguard Worker     - Manage access to pixel buffer.
84*61c4878aSAndroid Build Coastguard Worker
85*61c4878aSAndroid Build Coastguard Worker   * - pw_display/framebuffer_mcuxpresso
86*61c4878aSAndroid Build Coastguard Worker     - Specialization of the framebuffer for the MCUxpresso devices
87*61c4878aSAndroid Build Coastguard Worker
88*61c4878aSAndroid Build Coastguard Worker   * - pw_display/geometry
89*61c4878aSAndroid Build Coastguard Worker     - Basic shared math types such as 2D vectors, etc.
90*61c4878aSAndroid Build Coastguard Worker
91*61c4878aSAndroid Build Coastguard Worker
92*61c4878aSAndroid Build Coastguard WorkerGeometry
93*61c4878aSAndroid Build Coastguard Worker========
94*61c4878aSAndroid Build Coastguard Worker``pw_display/geometry`` contains two helper structures for common values usually
95*61c4878aSAndroid Build Coastguard Workerused as a pair.
96*61c4878aSAndroid Build Coastguard Worker
97*61c4878aSAndroid Build Coastguard Worker.. code-block:: cpp
98*61c4878aSAndroid Build Coastguard Worker
99*61c4878aSAndroid Build Coastguard Worker   namespace pw::display {
100*61c4878aSAndroid Build Coastguard Worker
101*61c4878aSAndroid Build Coastguard Worker   template <typename T>
102*61c4878aSAndroid Build Coastguard Worker   struct Size {
103*61c4878aSAndroid Build Coastguard Worker     T width;
104*61c4878aSAndroid Build Coastguard Worker     T height;
105*61c4878aSAndroid Build Coastguard Worker   };
106*61c4878aSAndroid Build Coastguard Worker
107*61c4878aSAndroid Build Coastguard Worker   template <typename T>
108*61c4878aSAndroid Build Coastguard Worker   struct Vector2 {
109*61c4878aSAndroid Build Coastguard Worker     T x;
110*61c4878aSAndroid Build Coastguard Worker     T y;
111*61c4878aSAndroid Build Coastguard Worker   };
112*61c4878aSAndroid Build Coastguard Worker
113*61c4878aSAndroid Build Coastguard Worker   }  // namespace pw::display
114*61c4878aSAndroid Build Coastguard Worker
115*61c4878aSAndroid Build Coastguard Worker
116*61c4878aSAndroid Build Coastguard WorkerFramebuffer
117*61c4878aSAndroid Build Coastguard Worker===========
118*61c4878aSAndroid Build Coastguard WorkerA framebuffer is a small class that provides access to a pixel buffer. It
119*61c4878aSAndroid Build Coastguard Workerkeeps a copy of the pixel buffer metadata and provides accessor methods for
120*61c4878aSAndroid Build Coastguard Workerthose values.
121*61c4878aSAndroid Build Coastguard Worker
122*61c4878aSAndroid Build Coastguard Worker.. code-block:: cpp
123*61c4878aSAndroid Build Coastguard Worker
124*61c4878aSAndroid Build Coastguard Worker   namespace pw::display {
125*61c4878aSAndroid Build Coastguard Worker
126*61c4878aSAndroid Build Coastguard Worker   enum class PixelFormat {
127*61c4878aSAndroid Build Coastguard Worker     None,
128*61c4878aSAndroid Build Coastguard Worker     RGB565,
129*61c4878aSAndroid Build Coastguard Worker   };
130*61c4878aSAndroid Build Coastguard Worker
131*61c4878aSAndroid Build Coastguard Worker   class Framebuffer {
132*61c4878aSAndroid Build Coastguard Worker   public:
133*61c4878aSAndroid Build Coastguard Worker     // Construct a default invalid framebuffer.
134*61c4878aSAndroid Build Coastguard Worker     Framebuffer();
135*61c4878aSAndroid Build Coastguard Worker
136*61c4878aSAndroid Build Coastguard Worker     Framebuffer(void* data,
137*61c4878aSAndroid Build Coastguard Worker                 PixelFormat pixel_format,
138*61c4878aSAndroid Build Coastguard Worker                 pw::math::Size<uint16_t> size,
139*61c4878aSAndroid Build Coastguard Worker                 uint16_t row_bytes);
140*61c4878aSAndroid Build Coastguard Worker
141*61c4878aSAndroid Build Coastguard Worker     Framebuffer(const Framebuffer&) = delete;
142*61c4878aSAndroid Build Coastguard Worker     Framebuffer(Framebuffer&& other);
143*61c4878aSAndroid Build Coastguard Worker
144*61c4878aSAndroid Build Coastguard Worker     Framebuffer& operator=(const Framebuffer&) = delete;
145*61c4878aSAndroid Build Coastguard Worker     Framebuffer& operator=(Framebuffer&&);
146*61c4878aSAndroid Build Coastguard Worker
147*61c4878aSAndroid Build Coastguard Worker     bool is_valid() const;
148*61c4878aSAndroid Build Coastguard Worker
149*61c4878aSAndroid Build Coastguard Worker     pw::ConstByteSpan data() const;
150*61c4878aSAndroid Build Coastguard Worker     pw::ByteSpan data();
151*61c4878aSAndroid Build Coastguard Worker
152*61c4878aSAndroid Build Coastguard Worker     PixelFormat pixel_format() const;
153*61c4878aSAndroid Build Coastguard Worker
154*61c4878aSAndroid Build Coastguard Worker     pw::math::Size<uint16_t> size();
155*61c4878aSAndroid Build Coastguard Worker
156*61c4878aSAndroid Build Coastguard Worker     uint16_t row_bytes() const;
157*61c4878aSAndroid Build Coastguard Worker   };
158*61c4878aSAndroid Build Coastguard Worker
159*61c4878aSAndroid Build Coastguard Worker   }  // namespace pw::display
160*61c4878aSAndroid Build Coastguard Worker
161*61c4878aSAndroid Build Coastguard WorkerFrameBuffer is a moveable class that is intended to signify read/write
162*61c4878aSAndroid Build Coastguard Workerprivileges to the underlying pixel data. This makes it easier to track when the
163*61c4878aSAndroid Build Coastguard Workerpixel data may be read from, or written to, without conflict.
164*61c4878aSAndroid Build Coastguard Worker
165*61c4878aSAndroid Build Coastguard WorkerThe framebuffer does not own the underlying pixel buffer. In other words
166*61c4878aSAndroid Build Coastguard Workerthe deletion of a framebuffer will not free the underlying pixel data.
167*61c4878aSAndroid Build Coastguard Worker
168*61c4878aSAndroid Build Coastguard WorkerFramebuffers do not have methods for reading or writing to the underlying pixel
169*61c4878aSAndroid Build Coastguard Workerbuffer. This is the responsibility of the the selected graphics library which
170*61c4878aSAndroid Build Coastguard Workercan be given the pixel buffer pointer retrieved by calling ``data()``.
171*61c4878aSAndroid Build Coastguard Worker
172*61c4878aSAndroid Build Coastguard Worker.. code-block:: cpp
173*61c4878aSAndroid Build Coastguard Worker
174*61c4878aSAndroid Build Coastguard Worker   constexpr size_t kWidth = 64;
175*61c4878aSAndroid Build Coastguard Worker   constexpr size_t kHeight = 32;
176*61c4878aSAndroid Build Coastguard Worker   uint16_t pixel_data[kWidth * kHeight];
177*61c4878aSAndroid Build Coastguard Worker
178*61c4878aSAndroid Build Coastguard Worker   void DrawScreen(Framebuffer* fb) {
179*61c4878aSAndroid Build Coastguard Worker     // Clear framebuffer to black.
180*61c4878aSAndroid Build Coastguard Worker     std::memset(fb->data(), 0, fb->height() * fb->row_bytes());
181*61c4878aSAndroid Build Coastguard Worker
182*61c4878aSAndroid Build Coastguard Worker     // Set first pixel to white.
183*61c4878aSAndroid Build Coastguard Worker     uint16_t* pixel_data = static_cast<uint16_t*>(fb->data());
184*61c4878aSAndroid Build Coastguard Worker     pixel_data[0] = 0xffff;
185*61c4878aSAndroid Build Coastguard Worker   }
186*61c4878aSAndroid Build Coastguard Worker
187*61c4878aSAndroid Build Coastguard Worker   Framebuffer fb(pixel_data, {kWidth, kHeight},
188*61c4878aSAndroid Build Coastguard Worker                  PixelFormat::RGB565,
189*61c4878aSAndroid Build Coastguard Worker                  kWidth * sizeof(uint16_t));
190*61c4878aSAndroid Build Coastguard Worker   DrawScreen(&fb);
191*61c4878aSAndroid Build Coastguard Worker
192*61c4878aSAndroid Build Coastguard WorkerFramebufferPool
193*61c4878aSAndroid Build Coastguard Worker===============
194*61c4878aSAndroid Build Coastguard WorkerThe FramebufferPool is intended to simplify the use of multiple framebuffers
195*61c4878aSAndroid Build Coastguard Workerwhen multi-buffered rendering is being used. It is a collection of framebuffers
196*61c4878aSAndroid Build Coastguard Workerwhich can be retrieved, used, and then returned to the pool for reuse. All
197*61c4878aSAndroid Build Coastguard Workerframebuffers in the pool share identical attributes. A framebuffer that is
198*61c4878aSAndroid Build Coastguard Workerreturned to a caller of ``GetFramebuffer()`` can be thought of as "on loan" to
199*61c4878aSAndroid Build Coastguard Workerthat caller and will not be given to any other caller of ``GetFramebuffer()``
200*61c4878aSAndroid Build Coastguard Workeruntil it has been returned by calling ``ReleaseFramebuffer()``.
201*61c4878aSAndroid Build Coastguard Worker
202*61c4878aSAndroid Build Coastguard Worker.. code-block:: cpp
203*61c4878aSAndroid Build Coastguard Worker
204*61c4878aSAndroid Build Coastguard Worker   namespace pw::display {
205*61c4878aSAndroid Build Coastguard Worker
206*61c4878aSAndroid Build Coastguard Worker   class FramebufferPool {
207*61c4878aSAndroid Build Coastguard Worker   public:
208*61c4878aSAndroid Build Coastguard Worker     using BufferArray = std::array<void*, FRAMEBUFFER_COUNT>;
209*61c4878aSAndroid Build Coastguard Worker
210*61c4878aSAndroid Build Coastguard Worker     // Constructor parameters.
211*61c4878aSAndroid Build Coastguard Worker     struct Config {
212*61c4878aSAndroid Build Coastguard Worker       BufferArray fb_addr;  // Address of each buffer in this pool.
213*61c4878aSAndroid Build Coastguard Worker       pw::math::Size<uint16_t> dimensions;  // width/height of each buffer.
214*61c4878aSAndroid Build Coastguard Worker       uint16_t row_bytes;                   // row bytes of each buffer.
215*61c4878aSAndroid Build Coastguard Worker       pw::framebuffer::PixelFormat pixel_format;
216*61c4878aSAndroid Build Coastguard Worker     };
217*61c4878aSAndroid Build Coastguard Worker
218*61c4878aSAndroid Build Coastguard Worker     FramebufferPool(const Config& config);
219*61c4878aSAndroid Build Coastguard Worker     virtual ~FramebufferPool();
220*61c4878aSAndroid Build Coastguard Worker
221*61c4878aSAndroid Build Coastguard Worker     uint16_t row_bytes() const;
222*61c4878aSAndroid Build Coastguard Worker
223*61c4878aSAndroid Build Coastguard Worker     pw::math::Size<uint16_t> dimensions() const;
224*61c4878aSAndroid Build Coastguard Worker
225*61c4878aSAndroid Build Coastguard Worker     pw::framebuffer::PixelFormat pixel_format() const;
226*61c4878aSAndroid Build Coastguard Worker
227*61c4878aSAndroid Build Coastguard Worker     // Return a framebuffer to the caller for use. This call WILL BLOCK until a
228*61c4878aSAndroid Build Coastguard Worker     // framebuffer is returned for use. Framebuffers *must* be returned to this
229*61c4878aSAndroid Build Coastguard Worker     // pool by a corresponding call to ReleaseFramebuffer. This function will only
230*61c4878aSAndroid Build Coastguard Worker     // return a valid framebuffer.
231*61c4878aSAndroid Build Coastguard Worker     //
232*61c4878aSAndroid Build Coastguard Worker     // This call is thread-safe, but not interrupt safe.
233*61c4878aSAndroid Build Coastguard Worker     virtual pw::framebuffer::Framebuffer GetFramebuffer();
234*61c4878aSAndroid Build Coastguard Worker
235*61c4878aSAndroid Build Coastguard Worker     // Return the framebuffer to the pool available for use by the next call to
236*61c4878aSAndroid Build Coastguard Worker     // GetFramebuffer.
237*61c4878aSAndroid Build Coastguard Worker     //
238*61c4878aSAndroid Build Coastguard Worker     // This may be called on another thread or during an interrupt.
239*61c4878aSAndroid Build Coastguard Worker     virtual Status ReleaseFramebuffer(pw::framebuffer::Framebuffer framebuffer);
240*61c4878aSAndroid Build Coastguard Worker   };
241*61c4878aSAndroid Build Coastguard Worker
242*61c4878aSAndroid Build Coastguard Worker   }  // namespace pw::display
243*61c4878aSAndroid Build Coastguard Worker
244*61c4878aSAndroid Build Coastguard WorkerAn example use of the framebuffer pool is:
245*61c4878aSAndroid Build Coastguard Worker
246*61c4878aSAndroid Build Coastguard Worker.. code-block:: cpp
247*61c4878aSAndroid Build Coastguard Worker
248*61c4878aSAndroid Build Coastguard Worker   // Retrieve a framebuffer for drawing. May block if pool has no framebuffers
249*61c4878aSAndroid Build Coastguard Worker   // to issue.
250*61c4878aSAndroid Build Coastguard Worker   FrameBuffer fb = framebuffer_pool.GetFramebuffer();
251*61c4878aSAndroid Build Coastguard Worker
252*61c4878aSAndroid Build Coastguard Worker   // Draw to the framebuffer.
253*61c4878aSAndroid Build Coastguard Worker   UpdateDisplay(&fb);
254*61c4878aSAndroid Build Coastguard Worker
255*61c4878aSAndroid Build Coastguard Worker   // Return the framebuffer to the pool for reuse.
256*61c4878aSAndroid Build Coastguard Worker   framebuffer_pool.ReleaseFramebuffer(std::move(fb));
257*61c4878aSAndroid Build Coastguard Worker
258*61c4878aSAndroid Build Coastguard WorkerDisplayDriver
259*61c4878aSAndroid Build Coastguard Worker=============
260*61c4878aSAndroid Build Coastguard WorkerA DisplayDriver is usually the sole class responsible for communicating with the
261*61c4878aSAndroid Build Coastguard Workerdisplay controller. Its primary responsibilities are the display controller
262*61c4878aSAndroid Build Coastguard Workerinitialization, and the writing of pixel data when a display update is needed.
263*61c4878aSAndroid Build Coastguard Worker
264*61c4878aSAndroid Build Coastguard WorkerThis proposal supports multiple heterogenous display controllers. This could be:
265*61c4878aSAndroid Build Coastguard Worker
266*61c4878aSAndroid Build Coastguard Worker1. A single display of any given type (e.g. ILI9341).
267*61c4878aSAndroid Build Coastguard Worker2. Two ILI9341 displays.
268*61c4878aSAndroid Build Coastguard Worker3. Two ILI9341 displays and a second one of a different type.
269*61c4878aSAndroid Build Coastguard Worker
270*61c4878aSAndroid Build Coastguard WorkerBecause of this approach the DisplayDriver is defined as an interface:
271*61c4878aSAndroid Build Coastguard Worker
272*61c4878aSAndroid Build Coastguard Worker.. code-block:: cpp
273*61c4878aSAndroid Build Coastguard Worker
274*61c4878aSAndroid Build Coastguard Worker   namespace pw::display {
275*61c4878aSAndroid Build Coastguard Worker
276*61c4878aSAndroid Build Coastguard Worker   class DisplayDriver {
277*61c4878aSAndroid Build Coastguard Worker   public:
278*61c4878aSAndroid Build Coastguard Worker     // Called on the completion of a write operation.
279*61c4878aSAndroid Build Coastguard Worker     using WriteCallback = Callback<void(framebuffer::Framebuffer, Status)>;
280*61c4878aSAndroid Build Coastguard Worker
281*61c4878aSAndroid Build Coastguard Worker     virtual ~DisplayDriver() = default;
282*61c4878aSAndroid Build Coastguard Worker
283*61c4878aSAndroid Build Coastguard Worker     virtual Status Init() = 0;
284*61c4878aSAndroid Build Coastguard Worker
285*61c4878aSAndroid Build Coastguard Worker     virtual void WriteFramebuffer(pw::framebuffer::Framebuffer framebuffer,
286*61c4878aSAndroid Build Coastguard Worker                                   WriteCallback write_callback) = 0;
287*61c4878aSAndroid Build Coastguard Worker
288*61c4878aSAndroid Build Coastguard Worker     virtual pw::math::Size<uint16_t> size() const = 0;
289*61c4878aSAndroid Build Coastguard Worker   };
290*61c4878aSAndroid Build Coastguard Worker
291*61c4878aSAndroid Build Coastguard Worker   }  // namespace pw::display
292*61c4878aSAndroid Build Coastguard Worker
293*61c4878aSAndroid Build Coastguard WorkerEach driver then provides a concrete implementation of the driver. Below is the
294*61c4878aSAndroid Build Coastguard Workerdefinition of the display driver for the ILI9341:
295*61c4878aSAndroid Build Coastguard Worker
296*61c4878aSAndroid Build Coastguard Worker.. code-block:: cpp
297*61c4878aSAndroid Build Coastguard Worker
298*61c4878aSAndroid Build Coastguard Worker   namespace pw::display {
299*61c4878aSAndroid Build Coastguard Worker
300*61c4878aSAndroid Build Coastguard Worker   class DisplayDriverILI9341 : public DisplayDriver {
301*61c4878aSAndroid Build Coastguard Worker   public:
302*61c4878aSAndroid Build Coastguard Worker     struct Config {
303*61c4878aSAndroid Build Coastguard Worker       // Device specific initialization parameters.
304*61c4878aSAndroid Build Coastguard Worker     };
305*61c4878aSAndroid Build Coastguard Worker
306*61c4878aSAndroid Build Coastguard Worker     DisplayDriverILI9341(const Config& config);
307*61c4878aSAndroid Build Coastguard Worker
308*61c4878aSAndroid Build Coastguard Worker     // DisplayDriver implementation:
309*61c4878aSAndroid Build Coastguard Worker     Status Init() override;
310*61c4878aSAndroid Build Coastguard Worker     void WriteFramebuffer(pw::framebuffer::Framebuffer framebuffer,
311*61c4878aSAndroid Build Coastguard Worker                           WriteCallback write_callback) override;
312*61c4878aSAndroid Build Coastguard Worker     Status WriteRow(span<uint16_t> row_pixels,
313*61c4878aSAndroid Build Coastguard Worker                     uint16_t row_idx,
314*61c4878aSAndroid Build Coastguard Worker                     uint16_t col_idx) override;
315*61c4878aSAndroid Build Coastguard Worker     pw::math::Size<uint16_t> size() const override;
316*61c4878aSAndroid Build Coastguard Worker
317*61c4878aSAndroid Build Coastguard Worker   private:
318*61c4878aSAndroid Build Coastguard Worker     enum class Mode {
319*61c4878aSAndroid Build Coastguard Worker       kData,
320*61c4878aSAndroid Build Coastguard Worker       kCommand,
321*61c4878aSAndroid Build Coastguard Worker     };
322*61c4878aSAndroid Build Coastguard Worker
323*61c4878aSAndroid Build Coastguard Worker     // A command and optional data to write to the ILI9341.
324*61c4878aSAndroid Build Coastguard Worker     struct Command {
325*61c4878aSAndroid Build Coastguard Worker       uint8_t command;
326*61c4878aSAndroid Build Coastguard Worker       ConstByteSpan command_data;
327*61c4878aSAndroid Build Coastguard Worker     };
328*61c4878aSAndroid Build Coastguard Worker
329*61c4878aSAndroid Build Coastguard Worker     // Toggle the reset GPIO line to reset the display controller.
330*61c4878aSAndroid Build Coastguard Worker     Status Reset();
331*61c4878aSAndroid Build Coastguard Worker
332*61c4878aSAndroid Build Coastguard Worker     // Set the command/data mode of the display controller.
333*61c4878aSAndroid Build Coastguard Worker     void SetMode(Mode mode);
334*61c4878aSAndroid Build Coastguard Worker     // Write the command to the display controller.
335*61c4878aSAndroid Build Coastguard Worker     Status WriteCommand(pw::spi::Device::Transaction& transaction,
336*61c4878aSAndroid Build Coastguard Worker                         const Command& command);
337*61c4878aSAndroid Build Coastguard Worker   };
338*61c4878aSAndroid Build Coastguard Worker
339*61c4878aSAndroid Build Coastguard Worker   }  // namespace pw::display
340*61c4878aSAndroid Build Coastguard Worker
341*61c4878aSAndroid Build Coastguard WorkerHere is an example retrieving a framebuffer from the framebuffer pool, drawing
342*61c4878aSAndroid Build Coastguard Workerinto the framebuffer, using the display driver to write the pixel data, and then
343*61c4878aSAndroid Build Coastguard Workerreturning the framebuffer back to the pool for use.
344*61c4878aSAndroid Build Coastguard Worker
345*61c4878aSAndroid Build Coastguard Worker.. code-block:: cpp
346*61c4878aSAndroid Build Coastguard Worker
347*61c4878aSAndroid Build Coastguard Worker   FrameBuffer fb = framebuffer_pool.GetFramebuffer();
348*61c4878aSAndroid Build Coastguard Worker
349*61c4878aSAndroid Build Coastguard Worker   // DrawScreen is a function that will draw to the framebuffer's underlying
350*61c4878aSAndroid Build Coastguard Worker   // pixel buffer using a drawing library. See example above.
351*61c4878aSAndroid Build Coastguard Worker   DrawScreen(&fb);
352*61c4878aSAndroid Build Coastguard Worker
353*61c4878aSAndroid Build Coastguard Worker   display_driver_.WriteFramebuffer(
354*61c4878aSAndroid Build Coastguard Worker       std::move(framebuffer),
355*61c4878aSAndroid Build Coastguard Worker       [&framebuffer_pool](pw::framebuffer::Framebuffer fb, Status status) {
356*61c4878aSAndroid Build Coastguard Worker         // Return the framebuffer back to the pool for reuse once the display
357*61c4878aSAndroid Build Coastguard Worker         // write is complete.
358*61c4878aSAndroid Build Coastguard Worker         framebuffer_pool.ReleaseFramebuffer(std::move(fb));
359*61c4878aSAndroid Build Coastguard Worker       });
360*61c4878aSAndroid Build Coastguard Worker
361*61c4878aSAndroid Build Coastguard WorkerIn the example above that the framebuffer (``fb``) is moved when calling
362*61c4878aSAndroid Build Coastguard Worker``WriteFramebuffer()`` passing ownership to the display driver. From this point
363*61c4878aSAndroid Build Coastguard Workerforward the application code may not access the framebuffer in any way. When the
364*61c4878aSAndroid Build Coastguard Workerframebuffer write is complete the framebuffer is then moved to the callback
365*61c4878aSAndroid Build Coastguard Workerwhich in turn moves it when calling ``ReleaseFramebuffer()``.
366*61c4878aSAndroid Build Coastguard Worker
367*61c4878aSAndroid Build Coastguard Worker``WriteFramebuffer()`` always does a write of the full framebuffer - sending all
368*61c4878aSAndroid Build Coastguard Workerpixel data.
369*61c4878aSAndroid Build Coastguard Worker
370*61c4878aSAndroid Build Coastguard Worker``WriteFramebuffer()`` may be a blocking call, but on some platforms the driver
371*61c4878aSAndroid Build Coastguard Workermay use a background write and the write callback is called when the write
372*61c4878aSAndroid Build Coastguard Workeris complete. The write callback **may be called during an interrupt**.
373*61c4878aSAndroid Build Coastguard Worker
374*61c4878aSAndroid Build Coastguard WorkerPixelPusher
375*61c4878aSAndroid Build Coastguard Worker===========
376*61c4878aSAndroid Build Coastguard WorkerPixel data for Simple SPI based display controllers can be written to the
377*61c4878aSAndroid Build Coastguard Workerdisplay controller using ``pw_spi``. There are some controllers which use
378*61c4878aSAndroid Build Coastguard Workerother interfaces (RGB, MIPI, etc.). Also, some vendors provide an API for
379*61c4878aSAndroid Build Coastguard Workerinteracting with these display controllers for writing pixel data.
380*61c4878aSAndroid Build Coastguard Worker
381*61c4878aSAndroid Build Coastguard WorkerTo allow the drivers to be hardware/vendor independent the ``PixelPusher``
382*61c4878aSAndroid Build Coastguard Workermay be used. This defines an interface whose sole responsibility is to write
383*61c4878aSAndroid Build Coastguard Workera framebuffer to the display controller. Specializations of this will use
384*61c4878aSAndroid Build Coastguard Worker``pw_spi`` or vendor proprietary calls to write pixel data.
385*61c4878aSAndroid Build Coastguard Worker
386*61c4878aSAndroid Build Coastguard Worker.. code-block:: cpp
387*61c4878aSAndroid Build Coastguard Worker
388*61c4878aSAndroid Build Coastguard Worker   namespace pw::display {
389*61c4878aSAndroid Build Coastguard Worker
390*61c4878aSAndroid Build Coastguard Worker   class PixelPusher {
391*61c4878aSAndroid Build Coastguard Worker    public:
392*61c4878aSAndroid Build Coastguard Worker     using WriteCallback = Callback<void(framebuffer::Framebuffer, Status)>;
393*61c4878aSAndroid Build Coastguard Worker
394*61c4878aSAndroid Build Coastguard Worker     virtual ~PixelPusher() = default;
395*61c4878aSAndroid Build Coastguard Worker
396*61c4878aSAndroid Build Coastguard Worker     virtual Status Init(
397*61c4878aSAndroid Build Coastguard Worker         const pw::framebuffer_pool::FramebufferPool& framebuffer_pool) = 0;
398*61c4878aSAndroid Build Coastguard Worker
399*61c4878aSAndroid Build Coastguard Worker     virtual void WriteFramebuffer(framebuffer::Framebuffer framebuffer,
400*61c4878aSAndroid Build Coastguard Worker                                   WriteCallback complete_callback) = 0;
401*61c4878aSAndroid Build Coastguard Worker   };
402*61c4878aSAndroid Build Coastguard Worker
403*61c4878aSAndroid Build Coastguard Worker   }  // namespace pw::display
404*61c4878aSAndroid Build Coastguard Worker
405*61c4878aSAndroid Build Coastguard WorkerDisplay
406*61c4878aSAndroid Build Coastguard Worker=======
407*61c4878aSAndroid Build Coastguard WorkerEach display has:
408*61c4878aSAndroid Build Coastguard Worker
409*61c4878aSAndroid Build Coastguard Worker1. One and only one display driver.
410*61c4878aSAndroid Build Coastguard Worker2. A reference to a single framebuffer pool. This framebuffer pool may be shared
411*61c4878aSAndroid Build Coastguard Worker   with other displays.
412*61c4878aSAndroid Build Coastguard Worker3. A drawing thread, if so configured, for asynchronous display updates.
413*61c4878aSAndroid Build Coastguard Worker
414*61c4878aSAndroid Build Coastguard Worker.. code-block:: cpp
415*61c4878aSAndroid Build Coastguard Worker
416*61c4878aSAndroid Build Coastguard Worker   namespace pw::display {
417*61c4878aSAndroid Build Coastguard Worker
418*61c4878aSAndroid Build Coastguard Worker   class Display {
419*61c4878aSAndroid Build Coastguard Worker   public:
420*61c4878aSAndroid Build Coastguard Worker     // Called on the completion of an update.
421*61c4878aSAndroid Build Coastguard Worker     using WriteCallback = Callback<void(Status)>;
422*61c4878aSAndroid Build Coastguard Worker
423*61c4878aSAndroid Build Coastguard Worker     Display(pw::display_driver::DisplayDriver& display_driver,
424*61c4878aSAndroid Build Coastguard Worker             pw::math::Size<uint16_t> size,
425*61c4878aSAndroid Build Coastguard Worker             pw::framebuffer_pool::FramebufferPool& framebuffer_pool);
426*61c4878aSAndroid Build Coastguard Worker     virtual ~Display();
427*61c4878aSAndroid Build Coastguard Worker
428*61c4878aSAndroid Build Coastguard Worker     pw::framebuffer::Framebuffer GetFramebuffer();
429*61c4878aSAndroid Build Coastguard Worker
430*61c4878aSAndroid Build Coastguard Worker     void ReleaseFramebuffer(pw::framebuffer::Framebuffer framebuffer,
431*61c4878aSAndroid Build Coastguard Worker                             WriteCallback callback);
432*61c4878aSAndroid Build Coastguard Worker
433*61c4878aSAndroid Build Coastguard Worker     pw::math::Size<uint16_t> size() const;
434*61c4878aSAndroid Build Coastguard Worker   };
435*61c4878aSAndroid Build Coastguard Worker
436*61c4878aSAndroid Build Coastguard Worker   }  // namespace pw::display
437*61c4878aSAndroid Build Coastguard Worker
438*61c4878aSAndroid Build Coastguard WorkerOnce applications are initialized they typically will not directly interact with
439*61c4878aSAndroid Build Coastguard Workerdisplay drivers or framebuffer pools. These will be utilized by the display
440*61c4878aSAndroid Build Coastguard Workerwhich will provide a simpler interface.
441*61c4878aSAndroid Build Coastguard Worker
442*61c4878aSAndroid Build Coastguard Worker``Display::GetFramebuffer()`` must always be called on the same thread and is not
443*61c4878aSAndroid Build Coastguard Workerinterrupt safe. It will block if there is no available framebuffer in the
444*61c4878aSAndroid Build Coastguard Workerframebuffer pool waiting for a framebuffer to be returned.
445*61c4878aSAndroid Build Coastguard Worker
446*61c4878aSAndroid Build Coastguard Worker``Display::ReleaseFramebuffer()`` must be called for each framebuffer returned by
447*61c4878aSAndroid Build Coastguard Worker``Display::GetFramebuffer()``. This will initiate the display update using the
448*61c4878aSAndroid Build Coastguard Workerdisplays associated driver. The ``callback`` will be called when this update is
449*61c4878aSAndroid Build Coastguard Workercomplete.
450*61c4878aSAndroid Build Coastguard Worker
451*61c4878aSAndroid Build Coastguard WorkerA simplified application rendering loop would resemble:
452*61c4878aSAndroid Build Coastguard Worker
453*61c4878aSAndroid Build Coastguard Worker.. code-block:: cpp
454*61c4878aSAndroid Build Coastguard Worker
455*61c4878aSAndroid Build Coastguard Worker   // Get a framebuffer for drawing.
456*61c4878aSAndroid Build Coastguard Worker   FrameBuffer fb = display.GetFramebuffer();
457*61c4878aSAndroid Build Coastguard Worker
458*61c4878aSAndroid Build Coastguard Worker   // DrawScreen is a function that will draw to |fb|'s pixel buffer using a
459*61c4878aSAndroid Build Coastguard Worker   // drawing library. See example above.
460*61c4878aSAndroid Build Coastguard Worker   DrawScreen(&fb);
461*61c4878aSAndroid Build Coastguard Worker
462*61c4878aSAndroid Build Coastguard Worker   // Return the framebuffer to the display which will be written to the display
463*61c4878aSAndroid Build Coastguard Worker   // controller by the display's display driver.
464*61c4878aSAndroid Build Coastguard Worker   display.ReleaseFramebuffer(std::move(fb), [](Status){});
465*61c4878aSAndroid Build Coastguard Worker
466*61c4878aSAndroid Build Coastguard WorkerDrawing Library
467*61c4878aSAndroid Build Coastguard Worker===============
468*61c4878aSAndroid Build Coastguard Worker``pw_display/draw`` was created for testing and verification purposes only. It is
469*61c4878aSAndroid Build Coastguard Workernot intended to be feature rich or performant in any way. This is small
470*61c4878aSAndroid Build Coastguard Workercollection of basic drawing primitives not intended to be used by shipping
471*61c4878aSAndroid Build Coastguard Workerapplications.
472*61c4878aSAndroid Build Coastguard Worker
473*61c4878aSAndroid Build Coastguard Worker.. code-block:: cpp
474*61c4878aSAndroid Build Coastguard Worker
475*61c4878aSAndroid Build Coastguard Worker   namespace pw::display {
476*61c4878aSAndroid Build Coastguard Worker
477*61c4878aSAndroid Build Coastguard Worker   void DrawLine(pw::framebuffer::Framebuffer& fb,
478*61c4878aSAndroid Build Coastguard Worker                 int x1,
479*61c4878aSAndroid Build Coastguard Worker                 int y1,
480*61c4878aSAndroid Build Coastguard Worker                 int x2,
481*61c4878aSAndroid Build Coastguard Worker                 int y2,
482*61c4878aSAndroid Build Coastguard Worker                 pw::color::color_rgb565_t pen_color);
483*61c4878aSAndroid Build Coastguard Worker
484*61c4878aSAndroid Build Coastguard Worker   // Draw a circle at center_x, center_y with given radius and color. Only a
485*61c4878aSAndroid Build Coastguard Worker   // one-pixel outline is drawn if filled is false.
486*61c4878aSAndroid Build Coastguard Worker   void DrawCircle(pw::framebuffer::Framebuffer& fb,
487*61c4878aSAndroid Build Coastguard Worker                   int center_x,
488*61c4878aSAndroid Build Coastguard Worker                   int center_y,
489*61c4878aSAndroid Build Coastguard Worker                   int radius,
490*61c4878aSAndroid Build Coastguard Worker                   pw::color::color_rgb565_t pen_color,
491*61c4878aSAndroid Build Coastguard Worker                   bool filled);
492*61c4878aSAndroid Build Coastguard Worker
493*61c4878aSAndroid Build Coastguard Worker   void DrawHLine(pw::framebuffer::Framebuffer& fb,
494*61c4878aSAndroid Build Coastguard Worker                  int x1,
495*61c4878aSAndroid Build Coastguard Worker                  int x2,
496*61c4878aSAndroid Build Coastguard Worker                  int y,
497*61c4878aSAndroid Build Coastguard Worker                  pw::color::color_rgb565_t pen_color);
498*61c4878aSAndroid Build Coastguard Worker
499*61c4878aSAndroid Build Coastguard Worker   void DrawRect(pw::framebuffer::Framebuffer& fb,
500*61c4878aSAndroid Build Coastguard Worker                 int x1,
501*61c4878aSAndroid Build Coastguard Worker                 int y1,
502*61c4878aSAndroid Build Coastguard Worker                 int x2,
503*61c4878aSAndroid Build Coastguard Worker                 int y2,
504*61c4878aSAndroid Build Coastguard Worker                 pw::color::color_rgb565_t pen_color,
505*61c4878aSAndroid Build Coastguard Worker                 bool filled);
506*61c4878aSAndroid Build Coastguard Worker
507*61c4878aSAndroid Build Coastguard Worker   void DrawRectWH(pw::framebuffer::Framebuffer& fb,
508*61c4878aSAndroid Build Coastguard Worker                   int x,
509*61c4878aSAndroid Build Coastguard Worker                   int y,
510*61c4878aSAndroid Build Coastguard Worker                   int w,
511*61c4878aSAndroid Build Coastguard Worker                   int h,
512*61c4878aSAndroid Build Coastguard Worker                   pw::color::color_rgb565_t pen_color,
513*61c4878aSAndroid Build Coastguard Worker                   bool filled);
514*61c4878aSAndroid Build Coastguard Worker
515*61c4878aSAndroid Build Coastguard Worker   void Fill(pw::framebuffer::Framebuffer& fb,
516*61c4878aSAndroid Build Coastguard Worker             pw::color::color_rgb565_t pen_color);
517*61c4878aSAndroid Build Coastguard Worker
518*61c4878aSAndroid Build Coastguard Worker   void DrawSprite(pw::framebuffer::Framebuffer& fb,
519*61c4878aSAndroid Build Coastguard Worker                   int x,
520*61c4878aSAndroid Build Coastguard Worker                   int y,
521*61c4878aSAndroid Build Coastguard Worker                   pw::draw::SpriteSheet* sprite_sheet,
522*61c4878aSAndroid Build Coastguard Worker                   int integer_scale);
523*61c4878aSAndroid Build Coastguard Worker
524*61c4878aSAndroid Build Coastguard Worker   void DrawTestPattern();
525*61c4878aSAndroid Build Coastguard Worker
526*61c4878aSAndroid Build Coastguard Worker   pw::math::Size<int> DrawCharacter(int ch,
527*61c4878aSAndroid Build Coastguard Worker                                     pw::math::Vector2<int> pos,
528*61c4878aSAndroid Build Coastguard Worker                                     pw::color::color_rgb565_t fg_color,
529*61c4878aSAndroid Build Coastguard Worker                                     pw::color::color_rgb565_t bg_color,
530*61c4878aSAndroid Build Coastguard Worker                                     const FontSet& font,
531*61c4878aSAndroid Build Coastguard Worker                                     pw::framebuffer::Framebuffer& framebuffer);
532*61c4878aSAndroid Build Coastguard Worker
533*61c4878aSAndroid Build Coastguard Worker   pw::math::Size<int> DrawString(std::wstring_view str,
534*61c4878aSAndroid Build Coastguard Worker                                  pw::math::Vector2<int> pos,
535*61c4878aSAndroid Build Coastguard Worker                                  pw::color::color_rgb565_t fg_color,
536*61c4878aSAndroid Build Coastguard Worker                                  pw::color::color_rgb565_t bg_color,
537*61c4878aSAndroid Build Coastguard Worker                                  const FontSet& font,
538*61c4878aSAndroid Build Coastguard Worker                                  pw::framebuffer::Framebuffer& framebuffer);
539*61c4878aSAndroid Build Coastguard Worker
540*61c4878aSAndroid Build Coastguard Worker   }  // namespace pw::display
541*61c4878aSAndroid Build Coastguard Worker
542*61c4878aSAndroid Build Coastguard WorkerClass Interaction Diagram
543*61c4878aSAndroid Build Coastguard Worker=========================
544*61c4878aSAndroid Build Coastguard Worker.. mermaid::
545*61c4878aSAndroid Build Coastguard Worker   :alt: Framebuffer Classes
546*61c4878aSAndroid Build Coastguard Worker   :align: center
547*61c4878aSAndroid Build Coastguard Worker
548*61c4878aSAndroid Build Coastguard Worker   classDiagram
549*61c4878aSAndroid Build Coastguard Worker       class FramebufferPool {
550*61c4878aSAndroid Build Coastguard Worker           uint16_t row_bytes()
551*61c4878aSAndroid Build Coastguard Worker           PixelFormat pixel_format()
552*61c4878aSAndroid Build Coastguard Worker           dimensions() : Size~uint16_t~
553*61c4878aSAndroid Build Coastguard Worker           row_bytes() : uint16_t
554*61c4878aSAndroid Build Coastguard Worker           GetFramebuffer() : Framebuffer
555*61c4878aSAndroid Build Coastguard Worker
556*61c4878aSAndroid Build Coastguard Worker           BufferArray buffer_addresses_
557*61c4878aSAndroid Build Coastguard Worker           Size~uint16_t~ buffer_dimensions_
558*61c4878aSAndroid Build Coastguard Worker           uint16_t row_bytes_
559*61c4878aSAndroid Build Coastguard Worker           PixelFormat pixel_format_
560*61c4878aSAndroid Build Coastguard Worker       }
561*61c4878aSAndroid Build Coastguard Worker
562*61c4878aSAndroid Build Coastguard Worker       class Framebuffer {
563*61c4878aSAndroid Build Coastguard Worker           is_valid() : bool const
564*61c4878aSAndroid Build Coastguard Worker           data() : void* const
565*61c4878aSAndroid Build Coastguard Worker           pixel_format() : PixelFormat const
566*61c4878aSAndroid Build Coastguard Worker           size() : Size~uint16_t~ const
567*61c4878aSAndroid Build Coastguard Worker           row_bytes() uint16_t const
568*61c4878aSAndroid Build Coastguard Worker
569*61c4878aSAndroid Build Coastguard Worker           void* pixel_data_
570*61c4878aSAndroid Build Coastguard Worker           Size~uint16_t~ size_
571*61c4878aSAndroid Build Coastguard Worker           PixelFormat pixel_format_
572*61c4878aSAndroid Build Coastguard Worker           uint16_t row_bytes_
573*61c4878aSAndroid Build Coastguard Worker       }
574*61c4878aSAndroid Build Coastguard Worker
575*61c4878aSAndroid Build Coastguard Worker       class DisplayDriver {
576*61c4878aSAndroid Build Coastguard Worker           <<DisplayDriver>>
577*61c4878aSAndroid Build Coastguard Worker           Init() : Status
578*61c4878aSAndroid Build Coastguard Worker           WriteFramebuffer(Framebuffer fb, WriteCallback cb): void
579*61c4878aSAndroid Build Coastguard Worker           dimensions() : Size~uint16_t~
580*61c4878aSAndroid Build Coastguard Worker
581*61c4878aSAndroid Build Coastguard Worker           PixelPusher& pixel_pusher_
582*61c4878aSAndroid Build Coastguard Worker       }
583*61c4878aSAndroid Build Coastguard Worker
584*61c4878aSAndroid Build Coastguard Worker       class Display {
585*61c4878aSAndroid Build Coastguard Worker           DisplayDriver& display_driver_
586*61c4878aSAndroid Build Coastguard Worker           const Size~uint16_t~ size_
587*61c4878aSAndroid Build Coastguard Worker           FramebufferPool& framebuffer_pool_
588*61c4878aSAndroid Build Coastguard Worker
589*61c4878aSAndroid Build Coastguard Worker           GetFramebuffer() : Framebuffer
590*61c4878aSAndroid Build Coastguard Worker       }
591*61c4878aSAndroid Build Coastguard Worker
592*61c4878aSAndroid Build Coastguard Worker       class PixelPusher {
593*61c4878aSAndroid Build Coastguard Worker           Init() : Status
594*61c4878aSAndroid Build Coastguard Worker           WriteFramebuffer(Framebuffer fb, WriteCallback cb) : void
595*61c4878aSAndroid Build Coastguard Worker       }
596*61c4878aSAndroid Build Coastguard Worker
597*61c4878aSAndroid Build Coastguard Worker       <<interface>> DisplayDriver
598*61c4878aSAndroid Build Coastguard Worker       FramebufferPool --> "FRAMEBUFFER_COUNT" Framebuffer : buffer_addresses_
599*61c4878aSAndroid Build Coastguard Worker
600*61c4878aSAndroid Build Coastguard Worker       Display --> "1" DisplayDriver : display_driver_
601*61c4878aSAndroid Build Coastguard Worker       Display --> "1" FramebufferPool : framebuffer_pool_
602*61c4878aSAndroid Build Coastguard Worker       DisplayDriver --> "1" PixelPusher : pixel_pusher_
603*61c4878aSAndroid Build Coastguard Worker
604*61c4878aSAndroid Build Coastguard Worker---------------------
605*61c4878aSAndroid Build Coastguard WorkerProblem investigation
606*61c4878aSAndroid Build Coastguard Worker---------------------
607*61c4878aSAndroid Build Coastguard WorkerWith no direct display support in Pigweed and no example programs implementing
608*61c4878aSAndroid Build Coastguard Workera solution Pigweed developers are essentially on their own. Depending on their
609*61c4878aSAndroid Build Coastguard Workerhardware this means starting with a GitHub project with a sample application
610*61c4878aSAndroid Build Coastguard Workerfrom MCUXpresso or STMCube. Each of these use a specific HAL and may be
611*61c4878aSAndroid Build Coastguard Workercoupled to other frameworks, such as FreeRTOS. This places the burden of
612*61c4878aSAndroid Build Coastguard Workersubstituting the HAL calls with the Pigweed API, making the sample program
613*61c4878aSAndroid Build Coastguard Workerwith the application screen choice, etc.
614*61c4878aSAndroid Build Coastguard Worker
615*61c4878aSAndroid Build Coastguard WorkerThis chore is time consuming and often requires that the application developer
616*61c4878aSAndroid Build Coastguard Workeracquire some level of driver expertise. Having direct display support in
617*61c4878aSAndroid Build Coastguard WorkerPigweed will allow the developer to more quickly add display support.
618*61c4878aSAndroid Build Coastguard Worker
619*61c4878aSAndroid Build Coastguard WorkerThe primary use-case being targeted is an application with a single display
620*61c4878aSAndroid Build Coastguard Workerusing multiple framebuffers with display update notifications delivered during
621*61c4878aSAndroid Build Coastguard Workeran interrupt. The initial implementation is designed to support multiple
622*61c4878aSAndroid Build Coastguard Workerheterogenous displays, but that will not be the focus of development or testing
623*61c4878aSAndroid Build Coastguard Workerfor the first release.
624*61c4878aSAndroid Build Coastguard Worker
625*61c4878aSAndroid Build Coastguard WorkerTouch sensors, or other input devices, are not part of this effort. Display
626*61c4878aSAndroid Build Coastguard Workerand touch input often accompany each other, but to simplify this already large
627*61c4878aSAndroid Build Coastguard Workerdisplay effort, touch will be added in a separate activity.
628*61c4878aSAndroid Build Coastguard Worker
629*61c4878aSAndroid Build Coastguard WorkerThere are many other embedded libraries for embedded drawing. Popular  libraries
630*61c4878aSAndroid Build Coastguard Workerare LVGL, emWin, GUIslice, HAGL, µGFX, and VGLite (to just name a few). These
631*61c4878aSAndroid Build Coastguard Workerexisting solutions generally offer one or more of: display drivers, drawing
632*61c4878aSAndroid Build Coastguard Workerlibrary, widget library. The display drivers usually rely on an abstraction
633*61c4878aSAndroid Build Coastguard Workerlayer, which they often refer to as a HAL, to interface with the underlying
634*61c4878aSAndroid Build Coastguard Workerhardware API. This HAL may rely on macros, or sometimes a structure with
635*61c4878aSAndroid Build Coastguard Workerfunction pointers for specific operations.
636*61c4878aSAndroid Build Coastguard Worker
637*61c4878aSAndroid Build Coastguard WorkerThe approach in this SEED was selected because it offers a low level API focused
638*61c4878aSAndroid Build Coastguard Workeron display update performance. It offers no drawing or GUI library, but should
639*61c4878aSAndroid Build Coastguard Workerbe easily interfaced with those libraries.
640*61c4878aSAndroid Build Coastguard Worker
641*61c4878aSAndroid Build Coastguard Worker---------------
642*61c4878aSAndroid Build Coastguard WorkerDetailed design
643*61c4878aSAndroid Build Coastguard Worker---------------
644*61c4878aSAndroid Build Coastguard WorkerThis proposal suggests no changes to existing APIs. All changes introduce new
645*61c4878aSAndroid Build Coastguard Workermodules that leverage the existing API. It supports static allocation of the
646*61c4878aSAndroid Build Coastguard Workerpixel buffers and all display framework objects. Additionally pixel buffers
647*61c4878aSAndroid Build Coastguard Workermay be hard-coded addresses or dynamically allocated from SRAM.
648*61c4878aSAndroid Build Coastguard Worker
649*61c4878aSAndroid Build Coastguard WorkerThe ``Framebuffer`` class is intended to simplify code that interacts with the
650*61c4878aSAndroid Build Coastguard Workerpixel buffer. It includes the pixel buffer format, dimensions, and the buffer
651*61c4878aSAndroid Build Coastguard Workeraddress. The framebuffer is 16 bytes in size (14 when packed). Framebuffer
652*61c4878aSAndroid Build Coastguard Workerobjects are created when requested and moved as a means of signifying ownership.
653*61c4878aSAndroid Build Coastguard WorkerIn other words, whenever code has an actual framebuffer object it is allowed
654*61c4878aSAndroid Build Coastguard Workerto both write to and read from the pixel buffer.
655*61c4878aSAndroid Build Coastguard Worker
656*61c4878aSAndroid Build Coastguard WorkerThe ``FramebufferPool`` is an object intended to simplify the management of a
657*61c4878aSAndroid Build Coastguard Workercollection of framebuffers. It tracks those that are available for use and
658*61c4878aSAndroid Build Coastguard Workerloans out framebuffers when requested. For single display devices this is
659*61c4878aSAndroid Build Coastguard Workergenerally not a difficult task as the application would maintain an array of
660*61c4878aSAndroid Build Coastguard Workerframebuffers and a next available index. In this case framebuffers are always
661*61c4878aSAndroid Build Coastguard Workerused in order and the buffer collection is implemented as a queue.
662*61c4878aSAndroid Build Coastguard Worker
663*61c4878aSAndroid Build Coastguard WorkerBecause RAM is often limited, the framebuffer pool is designed to be shared
664*61c4878aSAndroid Build Coastguard Workerbetween multiple displays. Because display rendering and update may be at
665*61c4878aSAndroid Build Coastguard Workerdifferent speeds framebuffers do not need to be retrieved
666*61c4878aSAndroid Build Coastguard Worker(via ``GetFramebuffer()``) and returned (via ``ReleaseFramebuffer()``) in the same
667*61c4878aSAndroid Build Coastguard Workerorder.
668*61c4878aSAndroid Build Coastguard Worker
669*61c4878aSAndroid Build Coastguard WorkerWhenever possible asynchronous display updates will be used. Depending on the
670*61c4878aSAndroid Build Coastguard Workerimplementation this usually offloads the CPU from the pixel writing to the
671*61c4878aSAndroid Build Coastguard Workerdisplay controller. In this case the CPU will initiate the update and using
672*61c4878aSAndroid Build Coastguard Workersome type of notification, usually an interrupt raised by a GPIO pin connected
673*61c4878aSAndroid Build Coastguard Workerto the display, will be notified of the completion of the display update.
674*61c4878aSAndroid Build Coastguard WorkerBecause of this the framebuffer pool ``ReleaseFramebuffer()`` call is interrupt
675*61c4878aSAndroid Build Coastguard Workersafe.
676*61c4878aSAndroid Build Coastguard Worker
677*61c4878aSAndroid Build Coastguard Worker``FramebufferPool::GetFramebuffer()`` will block indefinitely if no framebuffer
678*61c4878aSAndroid Build Coastguard Workeris available. This unburdens the application drawing loop from the task of
679*61c4878aSAndroid Build Coastguard Workermanaging framebuffers or tracking screen update completion.
680*61c4878aSAndroid Build Coastguard Worker
681*61c4878aSAndroid Build Coastguard WorkerTesting
682*61c4878aSAndroid Build Coastguard Worker=======
683*61c4878aSAndroid Build Coastguard WorkerAll classes will be accompanied by a robust set of unit tests. These can be
684*61c4878aSAndroid Build Coastguard Workerrun on the host or the device. Test applications will be able to run on a
685*61c4878aSAndroid Build Coastguard Workerworkstation (i.e. not an MCU) in order to enable tests that depend on
686*61c4878aSAndroid Build Coastguard Workerhardware available in most CPUs - like an MMU. This will enable the use of
687*61c4878aSAndroid Build Coastguard Worker`AddressSanitizer <https://github.com/google/sanitizers/wiki/AddressSanitizer>`_
688*61c4878aSAndroid Build Coastguard Workerbased tests. Desktop tests will use
689*61c4878aSAndroid Build Coastguard Worker`Xvfb <https://www.x.org/releases/X11R7.6/doc/man/man1/Xvfb.1.xhtml>`_ to allow
690*61c4878aSAndroid Build Coastguard Workerthem to be run in a headless continuous integration environment.
691*61c4878aSAndroid Build Coastguard Worker
692*61c4878aSAndroid Build Coastguard WorkerPerformance
693*61c4878aSAndroid Build Coastguard Worker===========
694*61c4878aSAndroid Build Coastguard WorkerDisplay support will include performance tests. Although this proposal does not
695*61c4878aSAndroid Build Coastguard Workerinclude a rendering library, it will include support for specific platforms
696*61c4878aSAndroid Build Coastguard Workerthat will utilize means of transferring pixel data to the display controller
697*61c4878aSAndroid Build Coastguard Workerin the background.
698*61c4878aSAndroid Build Coastguard Worker
699*61c4878aSAndroid Build Coastguard Worker------------
700*61c4878aSAndroid Build Coastguard WorkerAlternatives
701*61c4878aSAndroid Build Coastguard Worker------------
702*61c4878aSAndroid Build Coastguard WorkerOne alternative is to create the necessary port/HAL, the terminology varies by
703*61c4878aSAndroid Build Coastguard Workerlibrary, for the popular embedded graphics libraries. This would make it easier
704*61c4878aSAndroid Build Coastguard Workerfor Pigweed applications to add display support - bot only for those supported
705*61c4878aSAndroid Build Coastguard Workerlibraries. This effort is intended to be more focused on performance, which is
706*61c4878aSAndroid Build Coastguard Workernot always the focus of other libraries.
707*61c4878aSAndroid Build Coastguard Worker
708*61c4878aSAndroid Build Coastguard WorkerAnother alternative is to do nothing - leaving the job of adding display
709*61c4878aSAndroid Build Coastguard Workersupport to the developers. As a significant percentage of embedded projects
710*61c4878aSAndroid Build Coastguard Workercontain a display, it will beneficial to have built-in display support in
711*61c4878aSAndroid Build Coastguard WorkerPigweed. This will allow all user to benefit by the shared display expertise,
712*61c4878aSAndroid Build Coastguard Workercontinuous integration, testing, and performance testing.
713*61c4878aSAndroid Build Coastguard Worker
714*61c4878aSAndroid Build Coastguard Worker--------------
715*61c4878aSAndroid Build Coastguard WorkerOpen questions
716*61c4878aSAndroid Build Coastguard Worker--------------
717*61c4878aSAndroid Build Coastguard Worker
718*61c4878aSAndroid Build Coastguard WorkerParameter Configuration
719*61c4878aSAndroid Build Coastguard Worker=======================
720*61c4878aSAndroid Build Coastguard WorkerOne open question is what parameters to specify in initialization parameters
721*61c4878aSAndroid Build Coastguard Workerto a driver ``Init()`` function, which to set in build flags via ``config(...)``
722*61c4878aSAndroid Build Coastguard Workerin GN, and which to hard-code into the driver. The most ideal, from the
723*61c4878aSAndroid Build Coastguard Workerperspective of reducing binary size, is to hard-code all values in a single
724*61c4878aSAndroid Build Coastguard Workerblock of contiguous data. The decision to support multiple displays requires
725*61c4878aSAndroid Build Coastguard Workerthat the display initialization parameters, at least some of them, be defined
726*61c4878aSAndroid Build Coastguard Workerat runtime and cannot be hard-coded into the driver code - that is, if the
727*61c4878aSAndroid Build Coastguard Workergoal is to allow two of the same display to be in use with different settings.
728*61c4878aSAndroid Build Coastguard Worker
729*61c4878aSAndroid Build Coastguard WorkerAdditionally many drivers support dozens of configuration values. The ILI9341
730*61c4878aSAndroid Build Coastguard Workerhas 82 different commands, some with complex values like gamma tables or
731*61c4878aSAndroid Build Coastguard Workermultiple values packed into a single register.
732*61c4878aSAndroid Build Coastguard Worker
733*61c4878aSAndroid Build Coastguard WorkerThe current approach is to strike a balance where the most commonly set
734*61c4878aSAndroid Build Coastguard Workervalues, for example display width/height and pixel format, are configurable
735*61c4878aSAndroid Build Coastguard Workervia build flags, and the remainder is hard-coded in the driver. If a developer
736*61c4878aSAndroid Build Coastguard Workerwants to set a parameter that is currently hard-coded in the driver, for
737*61c4878aSAndroid Build Coastguard Workerexample display refresh rate or gamma table, they would need to copy the display
738*61c4878aSAndroid Build Coastguard Workerdriver from Pigweed, or create a Pigweed branch.
739*61c4878aSAndroid Build Coastguard Worker
740*61c4878aSAndroid Build Coastguard Worker``Display::WriteFramebuffer()`` always writes the full framebuffer. It is expected
741*61c4878aSAndroid Build Coastguard Workerthat partial updates will be supported. This will likely come as a separate
742*61c4878aSAndroid Build Coastguard Workerfunction. This is being pushed off until needed to provide as much experience
743*61c4878aSAndroid Build Coastguard Workerwith the various display controller APIs as possible to increase the likelihood
744*61c4878aSAndroid Build Coastguard Workerof a well crafted API.
745*61c4878aSAndroid Build Coastguard Worker
746*61c4878aSAndroid Build Coastguard WorkerModule Hierarchy
747*61c4878aSAndroid Build Coastguard Worker================
748*61c4878aSAndroid Build Coastguard WorkerAt present Pigweed's module structure is flat and at the project root level.
749*61c4878aSAndroid Build Coastguard WorkerThere are currently 134 top level ``pw_*`` directories. This proposal could
750*61c4878aSAndroid Build Coastguard Workersignificantly increase this count as each new display driver will be a new
751*61c4878aSAndroid Build Coastguard Workermodule. This might be a good time to consider putting modules into a hierarchy.
752*61c4878aSAndroid Build Coastguard Worker
753*61c4878aSAndroid Build Coastguard WorkerPixel Pusher
754*61c4878aSAndroid Build Coastguard Worker============
755*61c4878aSAndroid Build Coastguard Worker``PixelPusher`` was created to remove the details of writing pixels from the
756*61c4878aSAndroid Build Coastguard Workerdisplay driver. Many displays support multiple ways to send pixel data. For
757*61c4878aSAndroid Build Coastguard Workerexample the ILI9341 supports SPI and a parallel bus for pixel transport.
758*61c4878aSAndroid Build Coastguard WorkerThe `STM32F429I-DISC1 <https://www.st.com/en/evaluation-tools/32f429idiscovery.html>`_
759*61c4878aSAndroid Build Coastguard Workeralso has a display controller (`LTDC
760*61c4878aSAndroid Build Coastguard Worker<https://www.st.com/resource/en/application_note/an4861-lcdtft-display-controller-ltdc-on-stm32-mcus-stmicroelectronics.pdf>`_)
761*61c4878aSAndroid Build Coastguard Workerwhich uses an STM proprietary API. The ``PixelPusher`` was essentially created
762*61c4878aSAndroid Build Coastguard Workerto allow that driver to use the LTDC API without the need to be coupled in any
763*61c4878aSAndroid Build Coastguard Workerway to a vendor API.
764*61c4878aSAndroid Build Coastguard Worker
765*61c4878aSAndroid Build Coastguard WorkerAt present some display drivers use ``pw_spi`` to send commands to the display
766*61c4878aSAndroid Build Coastguard Workercontroller, and the ``PixelPusher`` for writing pixel data. It will probably
767*61c4878aSAndroid Build Coastguard Workerbe cleaner to move the command writes into the ``PixelPusher`` and remove any
768*61c4878aSAndroid Build Coastguard Worker``pw_spi`` interaction from the display drivers. At this time ``PixelPusher``
769*61c4878aSAndroid Build Coastguard Workershould be renamed.
770*61c4878aSAndroid Build Coastguard Worker
771*61c4878aSAndroid Build Coastguard WorkerCopyrighted SDKs
772*61c4878aSAndroid Build Coastguard Worker================
773*61c4878aSAndroid Build Coastguard WorkerSome vendors have copyrighted SDKs which cannot be included in the Pigweed
774*61c4878aSAndroid Build Coastguard Workersource code unless the project is willing to have the source covered by more
775*61c4878aSAndroid Build Coastguard Workerthan one license. Additionally some SDKs have no simple download link and the
776*61c4878aSAndroid Build Coastguard Workervendor requires that a developer use a web application to build and download
777*61c4878aSAndroid Build Coastguard Workeran SDK with the desired components. NXP's
778*61c4878aSAndroid Build Coastguard Worker`MCUXpresso SDK Builder <https://mcuxpresso.nxp.com/en/welcome>`_ is an example
779*61c4878aSAndroid Build Coastguard Workerof this. This download process makes it difficult to provide simple instructions
780*61c4878aSAndroid Build Coastguard Workerto the developer and for creating reliable builds as it may be difficult to
781*61c4878aSAndroid Build Coastguard Workerselect an older SDK for download.
782