A modern Music Player Daemon based on Rockbox open source high quality audio player
libadwaita audio rust zig deno mpris rockbox mpd
at master 754 lines 20 kB view raw
1/*************************************************************************** 2 * __________ __ ___. 3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___ 4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / 5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < 6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ 7 * \/ \/ \/ \/ \/ 8 * $Id$ 9 * 10 * Copyright (C) 2006 Jens Arnold 11 * 12 * Rockbox driver for 2bit vertically interleaved LCDs 13 * 14 * This program is free software; you can redistribute it and/or 15 * modify it under the terms of the GNU General Public License 16 * as published by the Free Software Foundation; either version 2 17 * of the License, or (at your option) any later version. 18 * 19 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY 20 * KIND, either express or implied. 21 * 22 ****************************************************************************/ 23 24#include "config.h" 25 26#include "lcd.h" 27#include "kernel.h" 28#include "thread.h" 29#include <stdlib.h> 30#include "string-extra.h" /* mem*() */ 31#include "file.h" 32#include "debug.h" 33#include "system.h" 34#include "font.h" 35#include "rbunicode.h" 36#include "bidi.h" 37#include "scroll_engine.h" 38 39#ifndef LCDFN /* Not compiling for remote - define macros for main LCD. */ 40#define LCDFN(fn) lcd_ ## fn 41#define FBFN(fn) fb_ ## fn 42#define LCDM(ma) LCD_ ## ma 43#define FBSIZE FRAMEBUFFER_SIZE 44#define LCDNAME "lcd_" 45#define LCDFB(x,y) FBADDR(x, y) 46#define MAIN_LCD 47#endif 48 49#ifdef MAIN_LCD 50#define THIS_STRIDE STRIDE_MAIN 51#else 52#define THIS_STRIDE STRIDE_REMOTE 53#endif 54 55#define CURRENT_VP LCDFN(current_viewport) 56/*** globals ***/ 57 58static FBFN(data) LCDFN(static_framebuffer)[LCDM(FBHEIGHT)][LCDM(FBWIDTH)] IRAM_LCDFRAMEBUFFER; 59static void *LCDFN(frameaddress_default)(int x, int y); 60 61static const FBFN(data) patterns[4] = {0xFFFF, 0xFF00, 0x00FF, 0x0000}; 62 63static FBFN(data) *backdrop = NULL; 64static long backdrop_offset IDATA_ATTR = 0; 65 66/* shouldn't be changed unless you want system-wide framebuffer changes! */ 67struct frame_buffer_t LCDFN(framebuffer_default) = 68{ 69 .FBFN(ptr) = &LCDFN(static_framebuffer)[0][0], 70 .get_address_fn = &LCDFN(frameaddress_default), 71 .stride = THIS_STRIDE(LCDM(WIDTH), LCDM(HEIGHT)), 72 .elems = (LCDM(FBWIDTH)*LCDM(FBHEIGHT)), 73}; 74 75static struct viewport default_vp = 76{ 77 .x = 0, 78 .y = 0, 79 .width = LCDM(WIDTH), 80 .height = LCDM(HEIGHT), 81 .flags = 0, 82 .font = FONT_SYSFIXED, 83 .drawmode = DRMODE_SOLID, 84 .buffer = NULL, 85 .fg_pattern = LCDM(DEFAULT_FG), 86 .bg_pattern = LCDM(DEFAULT_BG) 87}; 88 89struct viewport * CURRENT_VP IBSS_ATTR; 90 91static unsigned fg_pattern IBSS_ATTR; 92static unsigned bg_pattern IBSS_ATTR; 93 94static void *LCDFN(frameaddress_default)(int x, int y) 95{ 96 /* the default expects a buffer the same size as the screen */ 97 struct frame_buffer_t *fb = CURRENT_VP->buffer; 98#if defined(MAIN_LCD) && LCD_STRIDEFORMAT == VERTICAL_STRIDE 99 size_t element = (x * LCDM(NATIVE_STRIDE)(fb->stride)) + y; 100#else 101 size_t element = (y * LCDM(NATIVE_STRIDE)(fb->stride)) + x; 102#endif 103 return fb->FBFN(ptr) + element;/*(element % fb->elems);*/ 104} 105 106#include "lcd-bitmap-common.c" 107 108/* LCD init */ 109void LCDFN(init)(void) 110{ 111 /* Initialize the viewport */ 112 LCDFN(set_viewport)(NULL); 113 114 LCDFN(clear_display)(); 115 LCDFN(init_device)(); 116#ifdef MAIN_LCD 117 scroll_init(); 118#endif 119} 120 121/*** parameter handling ***/ 122 123#if !defined(MAIN_LCD) && defined(HAVE_LCD_COLOR) 124/* When compiling for remote LCD and the main LCD is colour. */ 125unsigned lcd_remote_color_to_native(unsigned color) 126{ 127 unsigned r = (color & 0xf800) >> 10; 128 unsigned g = (color & 0x07e0) >> 5; 129 unsigned b = (color & 0x001f) << 2; 130 /* 131 * |R| 132 * |Y'| = |0.299000 0.587000 0.114000| |G| 133 * |B| 134 */ 135 return (5*r + 9*g + b) >> 8; 136} 137#endif 138 139void LCDFN(set_foreground)(unsigned brightness) 140{ 141 CURRENT_VP->fg_pattern = brightness; 142 fg_pattern = patterns[brightness & 3]; 143} 144 145unsigned LCDFN(get_foreground)(void) 146{ 147 return CURRENT_VP->fg_pattern; 148} 149 150void LCDFN(set_background)(unsigned brightness) 151{ 152 CURRENT_VP->bg_pattern = brightness; 153 bg_pattern = patterns[brightness & 3]; 154} 155 156unsigned LCDFN(get_background)(void) 157{ 158 return CURRENT_VP->bg_pattern; 159} 160 161/*** low-level drawing functions ***/ 162 163static void setpixel(int x, int y) 164{ 165 unsigned mask = 0x0101 << (y & 7); 166 FBFN(data) *address = LCDFB(x,y>>3); 167 unsigned data = *address; 168 169 *address = data ^ ((data ^ fg_pattern) & mask); 170} 171 172static void clearpixel(int x, int y) 173{ 174 unsigned mask = 0x0101 << (y & 7); 175 FBFN(data) *address = LCDFB(x,y>>3); 176 unsigned data = *address; 177 178 *address = data ^ ((data ^ bg_pattern) & mask); 179} 180 181static void clearimgpixel(int x, int y) 182{ 183 unsigned mask = 0x0101 << (y & 7); 184 FBFN(data) *address = LCDFB(x,y>>3); 185 unsigned data = *address; 186 187 *address = data ^ ((data ^ *(FBFN(data) *)((long)address 188 + backdrop_offset)) & mask); 189} 190 191static void flippixel(int x, int y) 192{ 193 unsigned mask = 0x0101 << (y & 7); 194 FBFN(data) *address = LCDFB(x,y>>3); 195 196 *address ^= mask; 197} 198 199static void nopixel(int x, int y) 200{ 201 (void)x; 202 (void)y; 203} 204 205LCDFN(pixelfunc_type)* const LCDFN(pixelfuncs_bgcolor)[8] = { 206 flippixel, nopixel, setpixel, setpixel, 207 nopixel, clearpixel, nopixel, clearpixel 208}; 209 210LCDFN(pixelfunc_type)* const LCDFN(pixelfuncs_backdrop)[8] = { 211 flippixel, nopixel, setpixel, setpixel, 212 nopixel, clearimgpixel, nopixel, clearimgpixel 213}; 214 215LCDFN(pixelfunc_type)* const *LCDFN(pixelfuncs) = LCDFN(pixelfuncs_bgcolor); 216 217/* 'mask' and 'bits' contain 2 bits per pixel */ 218static void ICODE_ATTR flipblock(FBFN(data) *address, unsigned mask, 219 unsigned bits) 220{ 221 *address ^= bits & mask; 222} 223 224static void ICODE_ATTR bgblock(FBFN(data) *address, unsigned mask, 225 unsigned bits) 226{ 227 unsigned data = *address; 228 229 *address = data ^ ((data ^ bg_pattern) & mask & ~bits); 230} 231 232static void ICODE_ATTR bgimgblock(FBFN(data) *address, unsigned mask, 233 unsigned bits) 234{ 235 unsigned data = *address; 236 237 *address = data ^ ((data ^ *(FBFN(data) *)((long)address 238 + backdrop_offset)) & mask & ~bits); 239} 240 241static void ICODE_ATTR fgblock(FBFN(data) *address, unsigned mask, 242 unsigned bits) 243{ 244 unsigned data = *address; 245 246 *address = data ^ ((data ^ fg_pattern) & mask & bits); 247} 248 249static void ICODE_ATTR solidblock(FBFN(data) *address, unsigned mask, 250 unsigned bits) 251{ 252 unsigned data = *address; 253 unsigned bgp = bg_pattern; 254 255 bits = bgp ^ ((bgp ^ fg_pattern) & bits); 256 *address = data ^ ((data ^ bits) & mask); 257} 258 259static void ICODE_ATTR solidimgblock(FBFN(data) *address, unsigned mask, 260 unsigned bits) 261{ 262 unsigned data = *address; 263 unsigned bgp = *(FBFN(data) *)((long)address + backdrop_offset); 264 265 bits = bgp ^ ((bgp ^ fg_pattern) & bits); 266 *address = data ^ ((data ^ bits) & mask); 267} 268 269static void ICODE_ATTR flipinvblock(FBFN(data) *address, unsigned mask, 270 unsigned bits) 271{ 272 *address ^= ~bits & mask; 273} 274 275static void ICODE_ATTR bginvblock(FBFN(data) *address, unsigned mask, 276 unsigned bits) 277{ 278 unsigned data = *address; 279 280 *address = data ^ ((data ^ bg_pattern) & mask & bits); 281} 282 283static void ICODE_ATTR bgimginvblock(FBFN(data) *address, unsigned mask, 284 unsigned bits) 285{ 286 unsigned data = *address; 287 288 *address = data ^ ((data ^ *(FBFN(data) *)((long)address 289 + backdrop_offset)) & mask & bits); 290} 291 292static void ICODE_ATTR fginvblock(FBFN(data) *address, unsigned mask, 293 unsigned bits) 294{ 295 unsigned data = *address; 296 297 *address = data ^ ((data ^ fg_pattern) & mask & ~bits); 298} 299 300static void ICODE_ATTR solidinvblock(FBFN(data) *address, unsigned mask, 301 unsigned bits) 302{ 303 unsigned data = *address; 304 unsigned fgp = fg_pattern; 305 306 bits = fgp ^ ((fgp ^ bg_pattern) & bits); 307 *address = data ^ ((data ^ bits) & mask); 308} 309 310static void ICODE_ATTR solidimginvblock(FBFN(data) *address, unsigned mask, 311 unsigned bits) 312{ 313 unsigned data = *address; 314 unsigned fgp = fg_pattern; 315 316 bits = fgp ^ ((fgp ^ *(FBFN(data) *)((long)address 317 + backdrop_offset)) & bits); 318 *address = data ^ ((data ^ bits) & mask); 319} 320 321LCDFN(blockfunc_type)* const LCDFN(blockfuncs_bgcolor)[8] = { 322 flipblock, bgblock, fgblock, solidblock, 323 flipinvblock, bginvblock, fginvblock, solidinvblock 324}; 325 326LCDFN(blockfunc_type)* const LCDFN(blockfuncs_backdrop)[8] = { 327 flipblock, bgimgblock, fgblock, solidimgblock, 328 flipinvblock, bgimginvblock, fginvblock, solidimginvblock 329}; 330 331LCDFN(blockfunc_type)* const *LCDFN(blockfuncs) = LCDFN(blockfuncs_bgcolor); 332 333 334void LCDFN(set_backdrop)(FBFN(data) *bd) 335{ 336 backdrop = bd; 337 if (bd) 338 { 339 backdrop_offset = (long)bd - (long)LCDFB(0, 0); 340 LCDFN(pixelfuncs) = LCDFN(pixelfuncs_backdrop); 341 LCDFN(blockfuncs) = LCDFN(blockfuncs_backdrop); 342 } 343 else 344 { 345 backdrop_offset = 0; 346 LCDFN(pixelfuncs) = LCDFN(pixelfuncs_bgcolor); 347 LCDFN(blockfuncs) = LCDFN(blockfuncs_bgcolor); 348 } 349} 350 351FBFN(data)* LCDFN(get_backdrop)(void) 352{ 353 return backdrop; 354} 355 356static inline void setblock(FBFN(data) *address, unsigned mask, unsigned bits) 357{ 358 unsigned data = *address; 359 360 bits ^= data; 361 *address = data ^ (bits & mask); 362} 363 364/*** drawing functions ***/ 365 366/* Clear the whole display */ 367void LCDFN(clear_display)(void) 368{ 369 if (default_vp.drawmode & DRMODE_INVERSEVID) 370 { 371 memset(LCDFB(0, 0), patterns[default_vp.fg_pattern & 3], 372 FBSIZE); 373 } 374 else 375 { 376 if (backdrop) 377 memcpy(LCDFB(0, 0), backdrop, FBSIZE); 378 else 379 memset(LCDFB(0, 0), patterns[default_vp.bg_pattern & 3], 380 FBSIZE); 381 } 382 383 LCDFN(scroll_stop)(); 384} 385 386/* Draw a horizontal line (optimised) */ 387void LCDFN(hline)(int x1, int x2, int y) 388{ 389 struct viewport *vp = CURRENT_VP; 390 int width; 391 FBFN(data) *dst, *dst_end; 392 unsigned mask; 393 LCDFN(blockfunc_type) *bfunc; 394 395 if (!clip_viewport_hline(vp, &x1, &x2, &y)) 396 return; 397 398 width = x2 - x1 + 1; 399 400 bfunc = LCDFN(blockfuncs)[vp->drawmode]; 401 dst = LCDFB(x1,y>>3); 402 mask = 0x0101 << (y & 7); 403 404 dst_end = dst + width; 405 do 406 bfunc(dst++, mask, 0xFFFFu); 407 while (dst < dst_end); 408} 409 410/* Draw a vertical line (optimised) */ 411void LCDFN(vline)(int x, int y1, int y2) 412{ 413 struct viewport *vp = CURRENT_VP; 414 int ny; 415 FBFN(data) *dst; 416 int stride_dst; 417 unsigned mask, mask_bottom; 418 LCDFN(blockfunc_type) *bfunc; 419 420 if (!clip_viewport_vline(vp, &x, &y1, &y2)) 421 return; 422 423 bfunc = LCDFN(blockfuncs)[vp->drawmode]; 424 dst = LCDFB(x,y1>>3); 425 stride_dst = vp->buffer->stride; 426 ny = y2 - (y1 & ~7); 427 mask = (0xFFu << (y1 & 7)) & 0xFFu; 428 mask |= mask << 8; 429 mask_bottom = 0xFFu >> (~ny & 7); 430 mask_bottom |= mask_bottom << 8; 431 432 for (; ny >= 8; ny -= 8) 433 { 434 bfunc(dst, mask, 0xFFFFu); 435 dst += stride_dst; 436 mask = 0xFFFFu; 437 } 438 mask &= mask_bottom; 439 bfunc(dst, mask, 0xFFFFu); 440} 441 442/* Fill a rectangular area */ 443void LCDFN(fillrect)(int x, int y, int width, int height) 444{ 445 struct viewport *vp = CURRENT_VP; 446 int ny; 447 FBFN(data) *dst, *dst_end; 448 int stride_dst; 449 unsigned mask, mask_bottom; 450 unsigned bits = 0; 451 LCDFN(blockfunc_type) *bfunc; 452 bool fillopt = false; 453 454 if (!clip_viewport_rect(vp, &x, &y, &width, &height, NULL, NULL)) 455 return; 456 457 if (vp->drawmode & DRMODE_INVERSEVID) 458 { 459 if ((vp->drawmode & DRMODE_BG) && !backdrop) 460 { 461 fillopt = true; 462 bits = bg_pattern; 463 } 464 } 465 else 466 { 467 if (vp->drawmode & DRMODE_FG) 468 { 469 fillopt = true; 470 bits = fg_pattern; 471 } 472 } 473 bfunc = LCDFN(blockfuncs)[vp->drawmode]; 474 dst = LCDFB(x,y>>3); 475 stride_dst = vp->buffer->stride; 476 ny = height - 1 + (y & 7); 477 mask = (0xFFu << (y & 7)) & 0xFFu; 478 mask |= mask << 8; 479 mask_bottom = 0xFFu >> (~ny & 7); 480 mask_bottom |= mask_bottom << 8; 481 482 for (; ny >= 8; ny -= 8) 483 { 484 if (fillopt && (mask == 0xFFFFu)) 485 memset16(dst, bits, width); 486 else 487 { 488 FBFN(data) *dst_row = dst; 489 490 dst_end = dst_row + width; 491 do 492 bfunc(dst_row++, mask, 0xFFFFu); 493 while (dst_row < dst_end); 494 } 495 496 dst += stride_dst; 497 mask = 0xFFFFu; 498 } 499 mask &= mask_bottom; 500 501 if (fillopt && (mask == 0xFFFFu)) 502 memset16(dst, bits, width); 503 else 504 { 505 dst_end = dst + width; 506 do 507 bfunc(dst++, mask, 0xFFFFu); 508 while (dst < dst_end); 509 } 510} 511 512/* About Rockbox' internal monochrome bitmap format: 513 * 514 * A bitmap contains one bit for every pixel that defines if that pixel is 515 * black (1) or white (0). Bits within a byte are arranged vertically, LSB 516 * at top. 517 * The bytes are stored in row-major order, with byte 0 being top left, 518 * byte 1 2nd from left etc. The first row of bytes defines pixel rows 519 * 0..7, the second row defines pixel row 8..15 etc. 520 * 521 * This is similar to the internal lcd hw format. */ 522 523/* Draw a partial monochrome bitmap */ 524void ICODE_ATTR LCDFN(mono_bitmap_part)(const unsigned char *src, int src_x, 525 int src_y, int stride, int x, int y, 526 int width, int height) 527{ 528 struct viewport *vp = CURRENT_VP; 529 int shift, ny; 530 FBFN(data) *dst, *dst_end; 531 int stride_dst; 532 unsigned data, mask, mask_bottom; 533 LCDFN(blockfunc_type) *bfunc; 534 535 if (!clip_viewport_rect(vp, &x, &y, &width, &height, &src_x, &src_y)) 536 return; 537 538 src += stride * (src_y >> 3) + src_x; /* move starting point */ 539 src_y &= 7; 540 y -= src_y; 541 dst = LCDFB(x,y>>3); 542 stride_dst = vp->buffer->stride; 543 shift = y & 7; 544 ny = height - 1 + shift + src_y; 545 546 bfunc = LCDFN(blockfuncs)[vp->drawmode]; 547 mask = 0xFFu << (shift + src_y); 548 /* not byte-doubled here because shift+src_y can be > 7 */ 549 mask_bottom = 0xFFu >> (~ny & 7); 550 mask_bottom |= mask_bottom << 8; 551 552 if (shift == 0) 553 { 554 mask &= 0xFFu; 555 mask |= mask << 8; 556 557 for (; ny >= 8; ny -= 8) 558 { 559 const unsigned char *src_row = src; 560 FBFN(data) *dst_row = dst; 561 562 dst_end = dst_row + width; 563 do 564 { 565 data = *src_row++; 566 bfunc(dst_row++, mask, data | (data << 8)); 567 } 568 while (dst_row < dst_end); 569 570 src += stride; 571 dst += stride_dst; 572 mask = 0xFFFFu; 573 } 574 mask &= mask_bottom; 575 576 dst_end = dst + width; 577 do 578 { 579 data = *src++; 580 bfunc(dst++, mask, data | (data << 8)); 581 } 582 while (dst < dst_end); 583 } 584 else 585 { 586 unsigned ddata; 587 588 dst_end = dst + width; 589 do 590 { 591 const unsigned char *src_col = src++; 592 FBFN(data) *dst_col = dst++; 593 unsigned mask_col = mask & 0xFFu; 594 595 mask_col |= mask_col << 8; 596 data = 0; 597 598 for (y = ny; y >= 8; y -= 8) 599 { 600 data |= *src_col << shift; 601 602 if (mask_col) 603 { 604 ddata = data & 0xFFu; 605 bfunc(dst_col, mask_col, ddata | (ddata << 8)); 606 mask_col = 0xFFFFu; 607 } 608 else 609 { 610 mask_col = (mask >> 8) & 0xFFu; 611 mask_col |= mask_col << 8; 612 } 613 614 src_col += stride; 615 dst_col += stride_dst; 616 data >>= 8; 617 } 618 data |= *src_col << shift; 619 mask_col &= mask_bottom; 620 ddata = data & 0xFFu; 621 bfunc(dst_col, mask_col, ddata | (ddata << 8)); 622 } 623 while (dst < dst_end); 624 } 625} 626 627/* Draw a full monochrome bitmap */ 628void LCDFN(mono_bitmap)(const unsigned char *src, int x, int y, int width, 629 int height) 630{ 631 LCDFN(mono_bitmap_part)(src, 0, 0, width, x, y, width, height); 632} 633 634/* About Rockbox' internal native bitmap format: 635 * 636 * A bitmap contains one bit in each byte of a pair of bytes for every pixel. 637 * 00 = white, 01 = light grey, 10 = dark grey, 11 = black. Bits within a byte 638 * are arranged vertically, LSB at top. 639 * The pairs of bytes are stored as shorts, in row-major order, with word 0 640 * being top left, word 1 2nd from left etc. The first row of words defines 641 * pixel rows 0..7, the second row defines pixel row 8..15 etc. 642 * 643 * This is the same as the internal lcd hw format. */ 644 645/* Draw a partial native bitmap */ 646void ICODE_ATTR LCDFN(bitmap_part)(const FBFN(data) *src, int src_x, 647 int src_y, int stride, int x, int y, 648 int width, int height) 649{ 650 struct viewport *vp = CURRENT_VP; 651 int shift, ny; 652 FBFN(data) *dst, *dst_end; 653 int stride_dst; 654 unsigned mask, mask_bottom; 655 656 if (!clip_viewport_rect(vp, &x, &y, &width, &height, &src_x, &src_y)) 657 return; 658 659 src += stride * (src_y >> 3) + src_x; /* move starting point */ 660 src_y &= 7; 661 y -= src_y; 662 dst = LCDFB(x,y>>3); 663 stride_dst = vp->buffer->stride; 664 shift = y & 7; 665 ny = height - 1 + shift + src_y; 666 667 mask = 0xFFu << (shift + src_y); 668 /* not byte-doubled here because shift+src_y can be > 7 */ 669 mask_bottom = 0xFFu >> (~ny & 7); 670 mask_bottom |= mask_bottom << 8; 671 672 if (shift == 0) 673 { 674 mask &= 0xFFu; 675 mask |= mask << 8; 676 677 for (; ny >= 8; ny -= 8) 678 { 679 if (mask == 0xFFFFu) 680 memcpy(dst, src, width * sizeof(FBFN(data))); 681 else 682 { 683 const FBFN(data) *src_row = src; 684 FBFN(data) *dst_row = dst; 685 686 dst_end = dst_row + width; 687 do 688 setblock(dst_row++, mask, *src_row++); 689 while (dst_row < dst_end); 690 } 691 src += stride; 692 dst += stride_dst; 693 mask = 0xFFFFu; 694 } 695 mask &= mask_bottom; 696 697 if (mask == 0xFFFFu) 698 memcpy(dst, src, width * sizeof(FBFN(data))); 699 else 700 { 701 dst_end = dst + width; 702 do 703 setblock(dst++, mask, *src++); 704 while (dst < dst_end); 705 } 706 } 707 else 708 { 709 unsigned datamask = (0xFFu << shift) & 0xFFu; 710 711 datamask |= datamask << 8; 712 713 dst_end = dst + width; 714 do 715 { 716 const FBFN(data) *src_col = src++; 717 FBFN(data) *dst_col = dst++; 718 unsigned mask_col = mask & 0xFFu; 719 unsigned data, olddata = 0; 720 721 mask_col |= mask_col << 8; 722 723 for (y = ny; y >= 8; y -= 8) 724 { 725 data = *src_col << shift; 726 727 if (mask_col) 728 { 729 setblock(dst_col, mask_col, 730 olddata ^((olddata ^ data) & datamask)); 731 mask_col = 0xFFFFu; 732 } 733 else 734 { 735 mask_col = (mask >> 8) & 0xFFu; 736 mask_col |= mask_col << 8; 737 } 738 src_col += stride; 739 dst_col += stride_dst; 740 olddata = data >> 8; 741 } 742 data = *src_col << shift; 743 setblock(dst_col, mask_col & mask_bottom, 744 olddata ^((olddata ^ data) & datamask)); 745 } 746 while (dst < dst_end); 747 } 748} 749 750/* Draw a full native bitmap */ 751void LCDFN(bitmap)(const FBFN(data) *src, int x, int y, int width, int height) 752{ 753 LCDFN(bitmap_part)(src, 0, 0, width, x, y, width, height); 754}