2 Copyright (C) 2016 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 #include <cairomm/region.h>
21 #include <cairomm/surface.h>
22 #include <cairomm/context.h>
24 #include "pbd/compose.h"
26 #include "ardour/debug.h"
33 #define Rect ArdourCanvas::Rect
36 using namespace ArdourCanvas;
37 using namespace ArdourSurface;
40 const int Push2Canvas::pixels_per_row = 1024;
42 Push2Canvas::Push2Canvas (Push2& pr, int c, int r)
46 , frame_buffer (Cairo::ImageSurface::create (Cairo::FORMAT_ARGB32, _cols, _rows))
48 context = Cairo::Context::create (frame_buffer);
49 expose_region = Cairo::Region::create ();
51 device_frame_buffer = new uint16_t[pixel_area()];
52 memset (device_frame_buffer, 0, sizeof (uint16_t) * pixel_area());
54 frame_header[0] = 0xef;
55 frame_header[1] = 0xcd;
56 frame_header[2] = 0xab;
57 frame_header[3] = 0x89;
59 memset (&frame_header[4], 0, 12);
62 Push2Canvas::~Push2Canvas ()
64 delete [] device_frame_buffer;
65 device_frame_buffer = 0;
69 Push2Canvas::vblank ()
71 /* re-render dirty areas, if any */
74 /* something rendered, update device_frame_buffer */
75 blit_to_device_frame_buffer ();
79 if (p2.current_layout()) {
80 std::string s = p2.current_layout()->name();
82 frame_buffer->write_to_png (s);
88 const int timeout_msecs = 1000;
91 /* transfer to device */
93 if ((err = libusb_bulk_transfer (p2.usb_handle(), 0x01, frame_header, sizeof (frame_header), &transferred, timeout_msecs))) {
97 if ((err = libusb_bulk_transfer (p2.usb_handle(), 0x01, (uint8_t*) device_frame_buffer, 2 * pixel_area (), &transferred, timeout_msecs))) {
105 Push2Canvas::request_redraw ()
107 request_redraw (Rect (0, 0, _cols, _rows));
111 Push2Canvas::request_redraw (Rect const & r)
113 Cairo::RectangleInt cr;
117 cr.width = r.width();
118 cr.height = r.height();
120 // DEBUG_TRACE (DEBUG::Push2, string_compose ("invalidate rect %1\n", r));
122 expose_region->do_union (cr);
124 /* next vblank will redraw */
128 Push2Canvas::expose ()
130 if (expose_region->empty()) {
131 return false; /* nothing drawn */
134 /* set up clipping */
136 const int nrects = expose_region->get_num_rectangles ();
138 //DEBUG_TRACE (DEBUG::Push2, string_compose ("expose with %1 rects\n", nrects));
140 for (int n = 0; n < nrects; ++n) {
141 Cairo::RectangleInt r = expose_region->get_rectangle (n);
142 context->rectangle (r.x, r.y, r.width, r.height);
147 Push2Layout* layout = p2.current_layout();
150 /* all layouts cover (at least) the full size of the video
151 display, so we do not need to check if the layout intersects
152 the bounding box of the full expose region.
154 Cairo::RectangleInt r = expose_region->get_extents();
155 Rect rr (r.x, r.y, r.x + r.width, r.y + r.height);
156 //DEBUG_TRACE (DEBUG::Push2, string_compose ("render layout with %1\n", rr));
157 layout->render (Rect (r.x, r.y, r.x + r.width, r.y + r.height), context);
160 context->reset_clip ();
162 /* why is there no "reset()" method for Cairo::Region? */
164 expose_region = Cairo::Region::create ();
169 /** render host-side frame buffer (a Cairo ImageSurface) to the current
170 * device-side frame buffer. The device frame buffer will be pushed to the
171 * device on the next call to vblank()
175 Push2Canvas::blit_to_device_frame_buffer ()
177 /* ensure that all drawing has been done before we fetch pixel data */
179 frame_buffer->flush ();
181 const int stride = 3840; /* bytes per row for Cairo::FORMAT_ARGB32 */
182 const uint8_t* data = frame_buffer->get_data ();
184 /* fill frame buffer (320kB) */
186 uint16_t* fb = (uint16_t*) device_frame_buffer;
188 for (int row = 0; row < _rows; ++row) {
190 const uint8_t* dp = data + row * stride;
192 for (int col = 0; col < _cols; ++col) {
194 /* fetch r, g, b (range 0..255). Ignore alpha */
196 const int r = (*((const uint32_t*)dp) >> 16) & 0xff;
197 const int g = (*((const uint32_t*)dp) >> 8) & 0xff;
198 const int b = *((const uint32_t*)dp) & 0xff;
200 /* convert to 5 bits, 6 bits, 5 bits, respectively */
201 /* generate 16 bit BGB565 value */
203 *fb++ = (r >> 3) | ((g & 0xfc) << 3) | ((b & 0xf8) << 8);
205 /* the push2 docs state that we should xor the pixel
206 * data. Doing so doesn't work correctly, and not doing
207 * so seems to work fine (colors roughly match intended
214 /* skip 128 bytes to next line. This is filler, used to avoid line borders occuring in the middle of 512
218 fb += 64; /* 128 bytes = 64 int16_t */
225 Push2Canvas::request_size (Duple)
227 /* fixed size canvas */
231 Push2Canvas::visible_area () const
233 /* may need to get more sophisticated once we do scrolling */
234 return Rect (0, 0, 960, 160);