summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAidan MacDonald <amachronic@protonmail.com>2021-11-21 18:07:13 +0000
committerAidan MacDonald <amachronic@protonmail.com>2021-12-05 13:13:36 -0500
commit34b7b715e8ac83142a8f16e26a7b17c47f2d5642 (patch)
tree71fd9d0761b0f158f4f480686ed5dcdcf04dd251
parent46a8fe0b72330c58bd8d96739746b9e4f962f735 (diff)
downloadrockbox-34b7b715e8ac83142a8f16e26a7b17c47f2d5642.tar.gz
rockbox-34b7b715e8ac83142a8f16e26a7b17c47f2d5642.zip
lcd-16bit: rewrite mono_bitmap_part
Rewrite the loop to update the framebuffer by rows rather than by columns. This should (a) be more efficient on the majority of targets using horizontal stride framebuffers, (b) skimp a bit on code size and (c) avoid AddressSanitizer errors caused by reading past the end of the source buffer. Change-Id: I238d191d63bfdecd25336fd8879a63d9d6ab7087
-rw-r--r--firmware/drivers/lcd-16bit-common.c168
1 files changed, 72 insertions, 96 deletions
diff --git a/firmware/drivers/lcd-16bit-common.c b/firmware/drivers/lcd-16bit-common.c
index b9c9060216..1b84847929 100644
--- a/firmware/drivers/lcd-16bit-common.c
+++ b/firmware/drivers/lcd-16bit-common.c
@@ -283,12 +283,6 @@ void ICODE_ATTR lcd_mono_bitmap_part(const unsigned char *src, int src_x,
283 int src_y, int stride, int x, int y, 283 int src_y, int stride, int x, int y,
284 int width, int height) 284 int width, int height)
285{ 285{
286 const unsigned char *src_end;
287 fb_data *dst, *dst_col;
288 unsigned dmask = 0x100; /* bit 8 == sentinel */
289 int drmode = lcd_current_viewport->drawmode;
290 int row;
291
292 /******************** Image in viewport clipping **********************/ 286 /******************** Image in viewport clipping **********************/
293 /* nothing to draw? */ 287 /* nothing to draw? */
294 if ((width <= 0) || (height <= 0) || (x >= lcd_current_viewport->width) || 288 if ((width <= 0) || (height <= 0) || (x >= lcd_current_viewport->width) ||
@@ -312,22 +306,10 @@ void ICODE_ATTR lcd_mono_bitmap_part(const unsigned char *src, int src_x,
312 if (y + height > lcd_current_viewport->height) 306 if (y + height > lcd_current_viewport->height)
313 height = lcd_current_viewport->height - y; 307 height = lcd_current_viewport->height - y;
314 308
315 /* adjust for viewport */ 309 /* convert to viewport coordinates */
316 x += lcd_current_viewport->x; 310 x += lcd_current_viewport->x;
317 y += lcd_current_viewport->y; 311 y += lcd_current_viewport->y;
318 312
319 /* 'Bugfix' mono_bitmap_part reads ahead in the buffer, While this is a bug
320 * if the height is <= char bit pixels other memory gets read but is not used
321 * the other option is to check in the hot code path but this appears
322 * sufficient, limit to the sim to stop Address Sanitizer errors
323 */
324#if defined(SIMULATOR) && \
325 (!defined(LCD_STRIDEFORMAT) || LCD_STRIDEFORMAT != VERTICAL_STRIDE)
326 /* vertical stride targets don't seem affected by this */
327 if (height <= CHAR_BIT)
328 stride = 0;
329#endif
330
331#if defined(HAVE_VIEWPORT_CLIP) 313#if defined(HAVE_VIEWPORT_CLIP)
332 /********************* Viewport on screen clipping ********************/ 314 /********************* Viewport on screen clipping ********************/
333 /* nothing to draw? */ 315 /* nothing to draw? */
@@ -342,7 +324,6 @@ void ICODE_ATTR lcd_mono_bitmap_part(const unsigned char *src, int src_x,
342 src_x -= x; 324 src_x -= x;
343 x = 0; 325 x = 0;
344 } 326 }
345
346 if (y < 0) 327 if (y < 0)
347 { 328 {
348 height += y; 329 height += y;
@@ -354,14 +335,17 @@ void ICODE_ATTR lcd_mono_bitmap_part(const unsigned char *src, int src_x,
354 if (y + height > LCD_HEIGHT) 335 if (y + height > LCD_HEIGHT)
355 height = LCD_HEIGHT - y; 336 height = LCD_HEIGHT - y;
356#endif 337#endif
357 src += stride * (src_y >> 3) + src_x; /* move starting point */ 338
358 src_y &= 7; 339 /* move starting point */
359 src_end = src + width; 340 src += stride * (src_y >> 3) + src_x;
360 dst_col = FBADDR(x, y); 341 src_y &= 7;
342
343 unsigned dmask = 0;
344 int drmode = lcd_current_viewport->drawmode;
361 345
362 if (drmode & DRMODE_INVERSEVID) 346 if (drmode & DRMODE_INVERSEVID)
363 { 347 {
364 dmask = 0x1ff; /* bit 8 == sentinel */ 348 dmask = 0xff;
365 drmode &= DRMODE_SOLID; /* mask out inversevid */ 349 drmode &= DRMODE_SOLID; /* mask out inversevid */
366 } 350 }
367 351
@@ -369,107 +353,99 @@ void ICODE_ATTR lcd_mono_bitmap_part(const unsigned char *src, int src_x,
369 if ((drmode & DRMODE_BG) && lcd_backdrop) 353 if ((drmode & DRMODE_BG) && lcd_backdrop)
370 drmode |= DRMODE_INT_BD; 354 drmode |= DRMODE_INT_BD;
371 355
372 /* go through each column and update each pixel */ 356 fb_data* dst = FBADDR(x, y);
373 do 357 while(height > 0)
374 { 358 {
375 const unsigned char *src_col = src++; 359 const unsigned char* src_col = src;
376 unsigned data = (*src_col ^ dmask) >> src_y; 360 const unsigned char* src_end = src + width;
361 fb_data* dst_col = dst;
362
363 unsigned data;
377 int fg, bg; 364 int fg, bg;
378 uintptr_t bo; 365 uintptr_t bo;
379 366
380 dst = dst_col; 367 switch (drmode) {
381 dst_col += COL_INC; 368 case DRMODE_COMPLEMENT:
382 row = height; 369 do {
383 370 data = (*src_col++ ^ dmask) >> src_y;
384#define UPDATE_SRC do { \ 371 if(data & 0x01)
385 data >>= 1; \ 372 *dst_col = ~(*dst_col);
386 if (data == 0x001) { \
387 src_col += stride; \
388 data = *src_col ^ dmask; \
389 } \
390 } while (0)
391
392 switch (drmode)
393 {
394 case DRMODE_COMPLEMENT:
395 do
396 {
397 if (data & 0x01)
398 *dst = ~(*dst);
399 373
400 dst += ROW_INC; 374 dst_col += COL_INC;
401 UPDATE_SRC; 375 } while(src_col != src_end);
402 }
403 while (--row);
404 break; 376 break;
405 377
406 case DRMODE_BG|DRMODE_INT_BD: 378 case DRMODE_BG|DRMODE_INT_BD:
407 bo = lcd_backdrop_offset; 379 bo = lcd_backdrop_offset;
408 do 380 do {
409 { 381 data = (*src_col++ ^ dmask) >> src_y;
410 if (!(data & 0x01)) 382 if(!(data & 0x01))
411 *dst = *PTR_ADD(dst, bo); 383 *dst_col = *PTR_ADD(dst_col, bo);
412 384
413 dst += ROW_INC; 385 dst_col += COL_INC;
414 UPDATE_SRC; 386 } while(src_col != src_end);
415 }
416 while (--row);
417 break; 387 break;
418 388
419 case DRMODE_BG: 389 case DRMODE_BG:
420 bg = lcd_current_viewport->bg_pattern; 390 bg = lcd_current_viewport->bg_pattern;
421 do 391 do {
422 { 392 data = (*src_col++ ^ dmask) >> src_y;
423 if (!(data & 0x01)) 393 if(!(data & 0x01))
424 *dst = bg; 394 *dst_col = bg;
425 395
426 dst += ROW_INC; 396 dst_col += COL_INC;
427 UPDATE_SRC; 397 } while(src_col != src_end);
428 }
429 while (--row);
430 break; 398 break;
431 399
432 case DRMODE_FG: 400 case DRMODE_FG:
433 fg = lcd_current_viewport->fg_pattern; 401 fg = lcd_current_viewport->fg_pattern;
434 do 402 do {
435 { 403 data = (*src_col++ ^ dmask) >> src_y;
436 if (data & 0x01) 404 if(data & 0x01)
437 *dst = fg; 405 *dst_col = fg;
438 406
439 dst += ROW_INC; 407 dst_col += COL_INC;
440 UPDATE_SRC; 408 } while(src_col != src_end);
441 }
442 while (--row);
443 break; 409 break;
444 410
445 case DRMODE_SOLID|DRMODE_INT_BD: 411 case DRMODE_SOLID|DRMODE_INT_BD:
446 fg = lcd_current_viewport->fg_pattern; 412 fg = lcd_current_viewport->fg_pattern;
447 bo = lcd_backdrop_offset; 413 bo = lcd_backdrop_offset;
448 do 414 do {
449 { 415 data = (*src_col++ ^ dmask) >> src_y;
450 *dst = (data & 0x01) ? fg 416 if(data & 0x01)
451 : *PTR_ADD(dst, bo); 417 *dst_col = fg;
452 dst += ROW_INC; 418 else
453 UPDATE_SRC; 419 *dst_col = *PTR_ADD(dst_col, bo);
454 } 420
455 while (--row); 421 dst_col += COL_INC;
422 } while(src_col != src_end);
456 break; 423 break;
457 424
458 case DRMODE_SOLID: 425 case DRMODE_SOLID:
459 fg = lcd_current_viewport->fg_pattern; 426 fg = lcd_current_viewport->fg_pattern;
460 bg = lcd_current_viewport->bg_pattern; 427 bg = lcd_current_viewport->bg_pattern;
461 do 428 do {
462 { 429 data = (*src_col++ ^ dmask) >> src_y;
463 *dst = (data & 0x01) ? fg : bg; 430 if(data & 0x01)
464 dst += ROW_INC; 431 *dst_col = fg;
465 UPDATE_SRC; 432 else
466 } 433 *dst_col = bg;
467 while (--row); 434
435 dst_col += COL_INC;
436 } while(src_col != src_end);
468 break; 437 break;
469 } 438 }
439
440 src_y = (src_y + 1) & 7;
441 if(src_y == 0)
442 src += stride;
443
444 dst += ROW_INC;
445 height--;
470 } 446 }
471 while (src < src_end);
472} 447}
448
473/* Draw a full monochrome bitmap */ 449/* Draw a full monochrome bitmap */
474void lcd_mono_bitmap(const unsigned char *src, int x, int y, int width, int height) 450void lcd_mono_bitmap(const unsigned char *src, int x, int y, int width, int height)
475{ 451{