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"
32 using namespace ArdourCanvas;
33 using namespace ArdourSurface;
36 const int Push2Canvas::pixels_per_row = 1024;
38 Push2Canvas::Push2Canvas (Push2& pr, int c, int r)
42 , frame_buffer (Cairo::ImageSurface::create (Cairo::FORMAT_ARGB32, _cols, _rows))
44 context = Cairo::Context::create (frame_buffer);
45 expose_region = Cairo::Region::create ();
47 device_frame_buffer = new uint16_t[pixel_area()];
48 memset (device_frame_buffer, 0, sizeof (uint16_t) * pixel_area());
50 frame_header[0] = 0xef;
51 frame_header[1] = 0xcd;
52 frame_header[2] = 0xab;
53 frame_header[3] = 0x89;
55 memset (&frame_header[4], 0, 12);
58 Push2Canvas::~Push2Canvas ()
60 delete [] device_frame_buffer;
61 device_frame_buffer = 0;
65 Push2Canvas::vblank ()
67 /* re-render dirty areas, if any */
70 DEBUG_TRACE (DEBUG::Push2, "re-blit to device frame buffer\n");
71 /* something rendered, update device_frame_buffer */
72 blit_to_device_frame_buffer ();
74 #define RENDER_LAYOUTS
76 if (p2.current_layout()) {
77 std::string s = p2.current_layout()->name();
79 frame_buffer->write_to_png (s);
85 const int timeout_msecs = 1000;
88 /* transfer to device */
90 if ((err = libusb_bulk_transfer (p2.usb_handle(), 0x01, frame_header, sizeof (frame_header), &transferred, timeout_msecs))) {
94 if ((err = libusb_bulk_transfer (p2.usb_handle(), 0x01, (uint8_t*) device_frame_buffer, 2 * pixel_area (), &transferred, timeout_msecs))) {
102 Push2Canvas::request_redraw ()
104 request_redraw (Rect (0, 0, _cols, _rows));
108 Push2Canvas::request_redraw (Rect const & r)
110 Cairo::RectangleInt cr;
114 cr.width = r.width();
115 cr.height = r.height();
117 // DEBUG_TRACE (DEBUG::Push2, string_compose ("invalidate rect %1\n", r));
119 expose_region->do_union (cr);
121 /* next vblank will redraw */
125 Push2Canvas::expose ()
127 if (expose_region->empty()) {
128 return false; /* nothing drawn */
131 /* set up clipping */
133 const int nrects = expose_region->get_num_rectangles ();
135 //DEBUG_TRACE (DEBUG::Push2, string_compose ("expose with %1 rects\n", nrects));
137 for (int n = 0; n < nrects; ++n) {
138 Cairo::RectangleInt r = expose_region->get_rectangle (n);
139 context->rectangle (r.x, r.y, r.width, r.height);
144 Push2Layout* layout = p2.current_layout();
147 /* all layouts cover (at least) the full size of the video
148 display, so we do not need to check if the layout intersects
149 the bounding box of the full expose region.
151 Cairo::RectangleInt r = expose_region->get_extents();
152 Rect rr (r.x, r.y, r.x + r.width, r.y + r.height);
153 //DEBUG_TRACE (DEBUG::Push2, string_compose ("render layout with %1\n", rr));
154 layout->render (Rect (r.x, r.y, r.x + r.width, r.y + r.height), context);
157 context->reset_clip ();
159 /* why is there no "reset()" method for Cairo::Region? */
161 expose_region = Cairo::Region::create ();
166 /** render host-side frame buffer (a Cairo ImageSurface) to the current
167 * device-side frame buffer. The device frame buffer will be pushed to the
168 * device on the next call to vblank()
172 Push2Canvas::blit_to_device_frame_buffer ()
174 /* ensure that all drawing has been done before we fetch pixel data */
176 frame_buffer->flush ();
178 const int stride = 3840; /* bytes per row for Cairo::FORMAT_ARGB32 */
179 const uint8_t* data = frame_buffer->get_data ();
181 /* fill frame buffer (320kB) */
183 uint16_t* fb = (uint16_t*) device_frame_buffer;
185 for (int row = 0; row < _rows; ++row) {
187 const uint8_t* dp = data + row * stride;
189 for (int col = 0; col < _cols; ++col) {
191 /* fetch r, g, b (range 0..255). Ignore alpha */
193 const int r = (*((const uint32_t*)dp) >> 16) & 0xff;
194 const int g = (*((const uint32_t*)dp) >> 8) & 0xff;
195 const int b = *((const uint32_t*)dp) & 0xff;
197 /* convert to 5 bits, 6 bits, 5 bits, respectively */
198 /* generate 16 bit BGB565 value */
200 *fb++ = (r >> 3) | ((g & 0xfc) << 3) | ((b & 0xf8) << 8);
202 /* the push2 docs state that we should xor the pixel
203 * data. Doing so doesn't work correctly, and not doing
204 * so seems to work fine (colors roughly match intended
211 /* skip 128 bytes to next line. This is filler, used to avoid line borders occuring in the middle of 512
215 fb += 64; /* 128 bytes = 64 int16_t */
222 Push2Canvas::request_size (Duple)
224 /* fixed size canvas */
228 Push2Canvas::visible_area () const
230 /* may need to get more sophisticated once we do scrolling */
231 return Rect (0, 0, 960, 160);