1 /* 2 * Copyright (C) 2012 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #include <stdint.h> 18 #include <sys/types.h> 19 20 #include <fcntl.h> 21 #include <sys/ioctl.h> 22 #include <linux/fb.h> 23 #include <linux/input.h> 24 #include <errno.h> 25 #include <string.h> 26 #include <stdio.h> 27 #include <cutils/memory.h> 28 #include <asm-generic/mman.h> 29 #include <sys/mman.h> 30 #include <utils/threads.h> 31 #include <unistd.h> 32 #include <math.h> 33 34 using namespace android; 35 36 #ifndef FBIO_WAITFORVSYNC 37 #define FBIO_WAITFORVSYNC _IOW('F', 0x20, __u32) 38 #endif 39 40 struct Buffer { 41 size_t w; 42 size_t h; 43 size_t s; 44 union { 45 void* addr; 46 uint32_t* pixels; 47 }; 48 }; 49 50 void clearBuffer(Buffer* buf, uint32_t pixel) { 51 android_memset32(buf->pixels, pixel, buf->s * buf->h * 4); 52 } 53 54 void drawTwoPixels(Buffer* buf, uint32_t pixel, ssize_t x, ssize_t y, size_t w) { 55 if (y>0 && y<ssize_t(buf->h)) { 56 uint32_t* bits = buf->pixels + y * buf->s; 57 if (x>=0 && x<ssize_t(buf->w)) { 58 bits[x] = pixel; 59 } 60 ssize_t W(w); 61 if ((x+W)>=0 && (x+W)<ssize_t(buf->w)) { 62 bits[x+W] = pixel; 63 } 64 } 65 } 66 67 void drawHLine(Buffer* buf, uint32_t pixel, ssize_t x, ssize_t y, size_t w) { 68 if (y>0 && y<ssize_t(buf->h)) { 69 ssize_t W(w); 70 if (x<0) { 71 W += x; 72 x = 0; 73 } 74 if (x+w > buf->w) { 75 W = buf->w - x; 76 } 77 if (W>0) { 78 uint32_t* bits = buf->pixels + y * buf->s + x; 79 android_memset32(bits, pixel, W*4); 80 } 81 } 82 } 83 84 void drawRect(Buffer* buf, uint32_t pixel, ssize_t x, ssize_t y, size_t w, size_t h) { 85 ssize_t W(w), H(h); 86 if (x<0) { 87 w += x; 88 x = 0; 89 } 90 if (y<0) { 91 h += y; 92 y = 0; 93 } 94 if (x+w > buf->w) W = buf->w - x; 95 if (y+h > buf->h) H = buf->h - y; 96 if (W>0 && H>0) { 97 uint32_t* bits = buf->pixels + y * buf->s + x; 98 for (ssize_t i=0 ; i<H ; i++) { 99 android_memset32(bits, pixel, W*4); 100 bits += buf->s; 101 } 102 } 103 } 104 105 void drawCircle(Buffer* buf, uint32_t pixel, 106 size_t x0, size_t y0, size_t radius, bool filled = false) { 107 ssize_t f = 1 - radius; 108 ssize_t ddF_x = 1; 109 ssize_t ddF_y = -2 * radius; 110 ssize_t x = 0; 111 ssize_t y = radius; 112 if (filled) { 113 drawHLine(buf, pixel, x0-radius, y0, 2*radius); 114 } else { 115 drawTwoPixels(buf, pixel, x0-radius, y0, 2*radius); 116 } 117 while (x < y) { 118 if (f >= 0) { 119 y--; 120 ddF_y += 2; 121 f += ddF_y; 122 } 123 x++; 124 ddF_x += 2; 125 f += ddF_x; 126 if (filled) { 127 drawHLine(buf, pixel, x0-x, y0+y, 2*x); 128 drawHLine(buf, pixel, x0-x, y0-y, 2*x); 129 drawHLine(buf, pixel, x0-y, y0+x, 2*y); 130 drawHLine(buf, pixel, x0-y, y0-x, 2*y); 131 } else { 132 drawTwoPixels(buf, pixel, x0-x, y0+y, 2*x); 133 drawTwoPixels(buf, pixel, x0-x, y0-y, 2*x); 134 drawTwoPixels(buf, pixel, x0-y, y0+x, 2*y); 135 drawTwoPixels(buf, pixel, x0-y, y0-x, 2*y); 136 } 137 } 138 } 139 140 class TouchEvents { 141 class EventThread : public Thread { 142 int fd; 143 144 virtual bool threadLoop() { 145 input_event event; 146 int first_down = 0; 147 do { 148 read(fd, &event, sizeof(event)); 149 if (event.type == EV_ABS) { 150 if (event.code == ABS_MT_TRACKING_ID) { 151 down = event.value == -1 ? 0 : 1; 152 first_down = down; 153 } 154 if (event.code == ABS_MT_POSITION_X) { 155 x = event.value; 156 } 157 if (event.code == ABS_MT_POSITION_Y) { 158 y = event.value; 159 } 160 } 161 } while (event.type == EV_SYN); 162 return true; 163 } 164 165 public: 166 int x, y, down; 167 EventThread() : Thread(false), 168 x(0), y(0), down(0) 169 { 170 fd = open("/dev/input/event1", O_RDONLY); 171 } 172 }; 173 sp<EventThread> thread; 174 175 public: 176 TouchEvents() { 177 thread = new EventThread(); 178 thread->run("EventThread", PRIORITY_URGENT_DISPLAY); 179 } 180 181 int getMostRecentPosition(int* x, int* y) { 182 *x = thread->x; 183 *y = thread->y; 184 return thread->down; 185 } 186 }; 187 188 189 struct Queue { 190 struct position { 191 int x, y; 192 }; 193 int index; 194 position q[16]; 195 Queue() : index(0) { } 196 void push(int x, int y) { 197 index++; 198 index &= 0xF; 199 q[index].x = x; 200 q[index].y = y; 201 } 202 void get(int lag, int* x, int* y) { 203 const int i = (index - lag) & 0xF; 204 *x = q[i].x; 205 *y = q[i].y; 206 } 207 }; 208 209 extern char *optarg; 210 extern int optind; 211 extern int optopt; 212 extern int opterr; 213 extern int optreset; 214 215 void usage(const char* name) { 216 printf("\nusage: %s [-h] [-l lag]\n", name); 217 } 218 219 int main(int argc, char** argv) { 220 fb_var_screeninfo vi; 221 fb_fix_screeninfo fi; 222 223 int lag = 0; 224 int fd = open("/dev/graphics/fb0", O_RDWR); 225 ioctl(fd, FBIOGET_VSCREENINFO, &vi); 226 ioctl(fd, FBIOGET_FSCREENINFO, &fi); 227 void* bits = mmap(0, fi.smem_len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); 228 Buffer framebuffer; 229 framebuffer.w = vi.xres; 230 framebuffer.h = vi.yres; 231 framebuffer.s = fi.line_length / (vi.bits_per_pixel >> 3); 232 framebuffer.addr = bits; 233 234 int ch; 235 while ((ch = getopt(argc, argv, "hl:")) != -1) { 236 switch (ch) { 237 case 'l': 238 lag = atoi(optarg); 239 break; 240 case 'h': 241 default: 242 usage(argv[0]); 243 exit(0); 244 } 245 } 246 argc -= optind; 247 argv += optind; 248 249 250 TouchEvents touch; 251 Queue queue; 252 253 254 int x=0, y=0; 255 int lag_x=0, lag_y=0; 256 257 clearBuffer(&framebuffer, 0); 258 while (true) { 259 uint32_t crt = 0; 260 ioctl(fd, FBIO_WAITFORVSYNC, &crt); 261 262 // draw beam marker 263 drawRect(&framebuffer, 0x400000, framebuffer.w-2, 0, 2, framebuffer.h); 264 // erase screen 265 if (lag) { 266 drawCircle(&framebuffer, 0, lag_x, lag_y, 100); 267 drawHLine(&framebuffer, 0, 0, lag_y, 32); 268 } 269 drawCircle(&framebuffer, 0, x, y, 100, true); 270 drawHLine(&framebuffer, 0, 0, y, 32); 271 272 // draw a line at y=1000 273 drawHLine(&framebuffer, 0x808080, 0, 1000, framebuffer.w); 274 275 // get touch events 276 touch.getMostRecentPosition(&x, &y); 277 queue.push(x, y); 278 queue.get(lag, &lag_x, &lag_y); 279 280 if (lag) { 281 drawCircle(&framebuffer, 0x00FF00, lag_x, lag_y, 100); 282 drawHLine(&framebuffer, 0x00FF00, 0, lag_y, 32); 283 } 284 285 drawCircle(&framebuffer, 0xFFFFFF, x, y, 100, true); 286 drawHLine(&framebuffer, 0xFFFFFF, 0, y, 32); 287 288 // draw end of frame beam marker 289 drawRect(&framebuffer, 0x004000, framebuffer.w-2, 0, 2, framebuffer.h); 290 } 291 292 close(fd); 293 return 0; 294 } 295