mirror of
https://github.com/espruino/Espruino.git
synced 2025-12-08 19:06:15 +00:00
Enable Graphics arraybuffer optimisations on all but low-end devices
Add specific Graphics optimisations for 1 and 8 bit rendering
This commit is contained in:
parent
278abac468
commit
d29a7cdf09
@ -11,6 +11,8 @@
|
||||
Puck.js v1: Fix regression that stopped Puck.IR(data) working - Puck.IR(data,D26,D25) required
|
||||
Puck.js v2: Ensure FET is used for IR output, fix selfTest errors for IR and Blue LED
|
||||
Bangle.js: Big speed improvements for 120x120 and 80x80 gfx modes
|
||||
Enable Graphics arraybuffer optimisations on all but low-end devices
|
||||
Add specific Graphics optimisations for 1 and 8 bit rendering
|
||||
|
||||
2v05 : Add Array.includes
|
||||
Fix (Number.toFixed) rounding, eg (1234.505).toFixed(2)
|
||||
|
||||
@ -31,15 +31,6 @@
|
||||
#include "bitmap_font_4x6.h"
|
||||
#include "bitmap_font_6x8.h"
|
||||
|
||||
#ifndef SAVE_ON_FLASH
|
||||
#ifndef ESPRUINOBOARD
|
||||
#define GRAPHICS_DRAWIMAGE_ROTATED
|
||||
#endif
|
||||
#endif
|
||||
#if defined(LINUX) || defined(BANGLEJS)
|
||||
#define GRAPHICS_FAST_PATHS // execute more optimised code when no rotation/etc
|
||||
#endif
|
||||
|
||||
#ifdef GRAPHICS_PALETTED_IMAGES
|
||||
// 16 color MAC OS palette
|
||||
const uint16_t PALETTE_4BIT[16] = { 0x0,0x4228,0x8c51,0xbdd7,0x9b26,0x6180,0x320,0x540,0x4df,0x19,0x3013,0xf813,0xd800,0xfb20,0xffe0,0xffff };
|
||||
|
||||
@ -17,6 +17,15 @@
|
||||
#include "jsvar.h"
|
||||
#include "graphics.h"
|
||||
|
||||
#ifndef SAVE_ON_FLASH
|
||||
#ifndef ESPRUINOBOARD
|
||||
#define GRAPHICS_DRAWIMAGE_ROTATED
|
||||
#endif
|
||||
#endif
|
||||
#if defined(LINUX) || defined(BANGLEJS)
|
||||
#define GRAPHICS_FAST_PATHS // execute more optimised code when no rotation/etc
|
||||
#endif
|
||||
|
||||
#ifdef GRAPHICS_PALETTED_IMAGES
|
||||
// 16 color MAC OS palette
|
||||
extern const uint16_t PALETTE_4BIT[16];
|
||||
|
||||
@ -12,6 +12,7 @@
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
#include "jswrap_arraybuffer.h"
|
||||
#include "jswrap_graphics.h"
|
||||
#include "lcd_arraybuffer.h"
|
||||
#include "jsvar.h"
|
||||
#include "jsvariterator.h"
|
||||
@ -129,7 +130,7 @@ void lcdFillRect_ArrayBuffer(struct JsGraphics *gfx, int x1, int y1, int x2, in
|
||||
lcdSetPixels_ArrayBuffer(gfx, x1, y, 1+x2-x1, col);
|
||||
}
|
||||
|
||||
#ifndef GRAPHICS_ARRAYBUFFER_OPTIMISATIONS
|
||||
#ifdef GRAPHICS_ARRAYBUFFER_OPTIMISATIONS
|
||||
// Faster implementation for where we have a flat memory area
|
||||
unsigned int lcdGetPixel_ArrayBuffer_flat(JsGraphics *gfx, int x, int y) {
|
||||
unsigned int col = 0;
|
||||
@ -216,8 +217,53 @@ void lcdFillRect_ArrayBuffer_flat(struct JsGraphics *gfx, int x1, int y1, int x
|
||||
for (y=y1;y<=y2;y++)
|
||||
lcdSetPixels_ArrayBuffer_flat(gfx, x1, y, 1+x2-x1, col);
|
||||
}
|
||||
|
||||
#ifdef GRAPHICS_FAST_PATHS
|
||||
void lcdSetPixel_ArrayBuffer_flat1(JsGraphics *gfx, int x, int y, unsigned int col) {
|
||||
int p = x + y*gfx->data.width;
|
||||
if (col) ((uint8_t*)gfx->backendData)[p>>3] |= (uint8_t)(0x80 >> (p&7));
|
||||
else ((uint8_t*)gfx->backendData)[p>>3] &= (uint8_t)(0xFF7F >> (p&7));
|
||||
}
|
||||
|
||||
void lcdFillRect_ArrayBuffer_flat1(JsGraphics *gfx, int x1, int y1, int x2, int y2, unsigned int col) {
|
||||
for (int y=y1;y<=y2;y++) {
|
||||
int p = x1 + y*gfx->data.width;
|
||||
for (int x=x1;x<=x2;x++) {
|
||||
if (col) ((uint8_t*)gfx->backendData)[p>>3] |= (uint8_t)(0x80 >> (p&7));
|
||||
else ((uint8_t*)gfx->backendData)[p>>3] &= (uint8_t)(0xFF7F >> (p&7));
|
||||
p++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void lcdSetPixel_ArrayBuffer_flat8(JsGraphics *gfx, int x, int y, unsigned int col) {
|
||||
((uint8_t*)gfx->backendData)[x + y*gfx->data.width] = col;
|
||||
}
|
||||
|
||||
unsigned int lcdGetPixel_ArrayBuffer_flat8(struct JsGraphics *gfx, int x, int y) {
|
||||
return ((uint8_t*)gfx->backendData)[x + y*gfx->data.width];
|
||||
}
|
||||
|
||||
void lcdFillRect_ArrayBuffer_flat8(JsGraphics *gfx, int x1, int y1, int x2, int y2, unsigned int col) {
|
||||
for (int y=y1;y<=y2;y++) {
|
||||
uint8_t *p = &((uint8_t*)gfx->backendData)[x1 + y*gfx->data.width];
|
||||
for (int x=x1;x<=x2;x++)
|
||||
*(p++) = col;
|
||||
}
|
||||
}
|
||||
|
||||
void lcdScroll_ArrayBuffer_flat8(JsGraphics *gfx, int xdir, int ydir) {
|
||||
int pixels = -(xdir + ydir*gfx->data.width);
|
||||
int l = gfx->data.width*gfx->data.height;
|
||||
if (pixels>0) memcpy(&((uint8_t*)gfx->backendData)[0],&((uint8_t*)gfx->backendData)[pixels],l-pixels);
|
||||
else if (pixels<0) memcpy(&((uint8_t*)gfx->backendData)[-pixels],&((uint8_t*)gfx->backendData)[0],l+pixels);
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // GRAPHICS_ARRAYBUFFER_OPTIMISATIONS
|
||||
|
||||
|
||||
|
||||
void lcdInit_ArrayBuffer(JsGraphics *gfx) {
|
||||
// create buffer
|
||||
JsVar *buf = jswrap_arraybuffer_constructor(graphicsGetMemoryRequired(gfx));
|
||||
@ -226,18 +272,37 @@ void lcdInit_ArrayBuffer(JsGraphics *gfx) {
|
||||
|
||||
void lcdSetCallbacks_ArrayBuffer(JsGraphics *gfx) {
|
||||
JsVar *buf = jsvObjectGetChild(gfx->graphicsVar, "buffer", 0);
|
||||
#ifndef GRAPHICS_ARRAYBUFFER_OPTIMISATIONS
|
||||
#ifdef GRAPHICS_ARRAYBUFFER_OPTIMISATIONS
|
||||
size_t len = 0;
|
||||
char *dataPtr = jsvGetDataPointer(buf, &len);
|
||||
#endif
|
||||
jsvUnLock(buf);
|
||||
#ifndef GRAPHICS_ARRAYBUFFER_OPTIMISATIONS
|
||||
if (dataPtr && len>=graphicsGetMemoryRequired(gfx)) {
|
||||
// nice fast mode
|
||||
#ifdef GRAPHICS_ARRAYBUFFER_OPTIMISATIONS
|
||||
if (dataPtr && len>=graphicsGetMemoryRequired(gfx) && !(gfx->data.flags & JSGRAPHICSFLAGS_ARRAYBUFFER_ZIGZAG)) {
|
||||
gfx->backendData = dataPtr;
|
||||
gfx->setPixel = lcdSetPixel_ArrayBuffer_flat;
|
||||
gfx->getPixel = lcdGetPixel_ArrayBuffer_flat;
|
||||
gfx->fillRect = lcdFillRect_ArrayBuffer_flat;
|
||||
#ifdef GRAPHICS_FAST_PATHS
|
||||
if (gfx->data.bpp==1 &&
|
||||
(gfx->data.flags & JSGRAPHICSFLAGS_ARRAYBUFFER_MSB) &&
|
||||
!(gfx->data.flags & (JSGRAPHICSFLAGS_ARRAYBUFFER_ZIGZAG|JSGRAPHICSFLAGS_ARRAYBUFFER_VERTICAL_BYTE|JSGRAPHICSFLAGS_ARRAYBUFFER_INTERLEAVEX))
|
||||
) { // super fast path for 1 bit
|
||||
gfx->setPixel = lcdSetPixel_ArrayBuffer_flat1;
|
||||
gfx->getPixel = lcdSetPixel_ArrayBuffer_flat;
|
||||
gfx->fillRect = lcdFillRect_ArrayBuffer_flat1;
|
||||
} else if (gfx->data.bpp==8 &&
|
||||
!(gfx->data.flags & (JSGRAPHICSFLAGS_ARRAYBUFFER_ZIGZAG|JSGRAPHICSFLAGS_ARRAYBUFFER_VERTICAL_BYTE|JSGRAPHICSFLAGS_ARRAYBUFFER_INTERLEAVEX))
|
||||
) { // super fast path for 8 bits
|
||||
gfx->setPixel = lcdSetPixel_ArrayBuffer_flat8;
|
||||
gfx->getPixel = lcdGetPixel_ArrayBuffer_flat8;
|
||||
gfx->fillRect = lcdFillRect_ArrayBuffer_flat8;
|
||||
gfx->scroll = lcdScroll_ArrayBuffer_flat8;
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
// nice fast mode
|
||||
gfx->setPixel = lcdSetPixel_ArrayBuffer_flat;
|
||||
gfx->getPixel = lcdGetPixel_ArrayBuffer_flat;
|
||||
gfx->fillRect = lcdFillRect_ArrayBuffer_flat;
|
||||
}
|
||||
#else
|
||||
if (false) {
|
||||
#endif
|
||||
|
||||
@ -15,3 +15,9 @@
|
||||
|
||||
void lcdInit_ArrayBuffer(JsGraphics *gfx);
|
||||
void lcdSetCallbacks_ArrayBuffer(JsGraphics *gfx);
|
||||
|
||||
// these use gfx->backendData as a pointer to data. They're exported so lcd_st7789_8bit can use them for fast offscreen rendering
|
||||
void lcdSetPixel_ArrayBuffer_flat8(JsGraphics *gfx, int x, int y, unsigned int col);
|
||||
unsigned int lcdGetPixel_ArrayBuffer_flat8(struct JsGraphics *gfx, int x, int y);
|
||||
void lcdFillRect_ArrayBuffer_flat8(JsGraphics *gfx, int x1, int y1, int x2, int y2, unsigned int col);
|
||||
void lcdScroll_ArrayBuffer_flat8(JsGraphics *gfx, int xdir, int ydir);
|
||||
|
||||
@ -16,6 +16,7 @@
|
||||
#include "jsutils.h"
|
||||
#include "lcd_st7789_8bit.h"
|
||||
#include "jswrap_graphics.h"
|
||||
#include "lcd_arraybuffer.h" // for lcd*_ArrayBuffer_flat8
|
||||
#ifndef EMSCRIPTEN
|
||||
#include "jshardware.h"
|
||||
#include "nrf_gpio.h"
|
||||
@ -203,14 +204,12 @@ LCDST7789Mode lcdST7789_getMode() {
|
||||
}
|
||||
|
||||
void lcdST7789_flip(JsGraphics *gfx) {
|
||||
unsigned char buf[2];
|
||||
switch (lcdMode) {
|
||||
case LCDST7789_MODE_UNBUFFERED:
|
||||
// unbuffered - flip has no effect
|
||||
break;
|
||||
case LCDST7789_MODE_DOUBLEBUFFERED: {
|
||||
// buffered - flip using LCD itself
|
||||
unsigned short offs;
|
||||
if (lcdScrollY==0) {
|
||||
lcdScrollY = 160;
|
||||
} else {
|
||||
@ -467,34 +466,6 @@ void lcdST7789_scroll(JsGraphics *gfx, int xdir, int ydir) {
|
||||
lcdST7789_scrollCmd();
|
||||
}
|
||||
|
||||
|
||||
// ====================================================================================
|
||||
void lcdST7789buf_setPixel(JsGraphics *gfx, int x, int y, unsigned int col) {
|
||||
if (!gfx->backendData) return;
|
||||
((uint8_t*)gfx->backendData)[x + y*gfx->data.width] = col;
|
||||
}
|
||||
|
||||
unsigned int lcdST7789buf_getPixel(struct JsGraphics *gfx, int x, int y) {
|
||||
if (!gfx->backendData) return 0;
|
||||
return ((uint8_t*)gfx->backendData)[x + y*gfx->data.width];
|
||||
}
|
||||
|
||||
void lcdST7789buf_fillRect(JsGraphics *gfx, int x1, int y1, int x2, int y2, unsigned int col) {
|
||||
if (!gfx->backendData) return;
|
||||
for (int y=y1;y<=y2;y++) {
|
||||
uint8_t *p = &((uint8_t*)gfx->backendData)[x1 + y*gfx->data.width];
|
||||
for (int x=x1;x<=x2;x++)
|
||||
*(p++) = col;
|
||||
}
|
||||
}
|
||||
|
||||
void lcdST7789buf_scroll(JsGraphics *gfx, int xdir, int ydir) {
|
||||
if (!gfx->backendData) return;
|
||||
int pixels = -(xdir + ydir*gfx->data.width);
|
||||
int l = gfx->data.width*gfx->data.height;
|
||||
if (pixels>0) memcpy(&((uint8_t*)gfx->backendData)[0],&((uint8_t*)gfx->backendData)[pixels],l-pixels);
|
||||
else if (pixels<0) memcpy(&((uint8_t*)gfx->backendData)[-pixels],&((uint8_t*)gfx->backendData)[0],l+pixels);
|
||||
}
|
||||
// ====================================================================================
|
||||
|
||||
void lcdST7789_init(JsGraphics *gfx) {
|
||||
@ -531,10 +502,10 @@ void lcdST7789_setCallbacks(JsGraphics *gfx) {
|
||||
jsvUnLock(buf);
|
||||
if (dataPtr && len>=expectedLen) {
|
||||
gfx->backendData = dataPtr;
|
||||
gfx->setPixel = lcdST7789buf_setPixel;
|
||||
gfx->getPixel = lcdST7789buf_getPixel;
|
||||
gfx->fillRect = lcdST7789buf_fillRect;
|
||||
gfx->scroll = lcdST7789buf_scroll;
|
||||
gfx->setPixel = lcdSetPixel_ArrayBuffer_flat8;
|
||||
gfx->getPixel = lcdGetPixel_ArrayBuffer_flat8;
|
||||
gfx->fillRect = lcdFillRect_ArrayBuffer_flat8;
|
||||
gfx->scroll = lcdScroll_ArrayBuffer_flat8;
|
||||
}
|
||||
} else {
|
||||
gfx->setPixel = lcdST7789_setPixel;
|
||||
|
||||
@ -1,5 +1,11 @@
|
||||
var LCD = Graphics.createArrayBuffer(8,8,1);
|
||||
LCD.drawLine(0,0,8,8);
|
||||
print(LCD.buffer);
|
||||
result = LCD.buffer == "1,2,4,8,16,32,64,128";
|
||||
var g;
|
||||
g = Graphics.createArrayBuffer(8,8,1);
|
||||
g.drawLine(0,0,8,8);
|
||||
print(g.buffer);
|
||||
result = g.buffer == "1,2,4,8,16,32,64,128";
|
||||
|
||||
g = Graphics.createArrayBuffer(8,8,1,{msb:true});
|
||||
g.drawLine(0,0,8,8);
|
||||
print(g.buffer);
|
||||
result &= g.buffer == "128,64,32,16,8,4,2,1";
|
||||
|
||||
|
||||
77
tests/test_graphics_drawImageScaled.js
Normal file
77
tests/test_graphics_drawImageScaled.js
Normal file
@ -0,0 +1,77 @@
|
||||
var g = Graphics.createArrayBuffer(32,32,8);
|
||||
g.dump = _=>{
|
||||
var s = "";
|
||||
var b = new Uint8Array(g.buffer);
|
||||
var n = 0;
|
||||
for (var y=0;y<g.getHeight();y++) {
|
||||
s+="\n";
|
||||
for (var x=0;x<g.getWidth();x++)
|
||||
s+=".#0"[b[n++]];
|
||||
}
|
||||
return s;
|
||||
}
|
||||
g.print = _=>{
|
||||
print("`"+g.dump()+"`");
|
||||
}
|
||||
var ok = true;
|
||||
function SHOULD_BE(a) {
|
||||
var b = g.dump();
|
||||
if (a!=b) {
|
||||
console.log("GOT :"+b+"\nSHOULD BE:"+a+"\n================");
|
||||
ok = false;
|
||||
}
|
||||
}
|
||||
|
||||
var img = {
|
||||
width : 8, height : 8, bpp : 8,
|
||||
transparent : 0,
|
||||
buffer : new Uint8Array([
|
||||
1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,
|
||||
1,2,2,2,0,0,0,1,
|
||||
1,2,2,0,0,0,0,1,
|
||||
1,2,0,0,0,0,0,1,
|
||||
1,0,0,0,0,0,0,1,
|
||||
1,0,0,0,0,0,0,1,
|
||||
1,1,1,1,1,1,1,1,
|
||||
]).buffer
|
||||
};
|
||||
|
||||
g.clear();
|
||||
g.drawImage(img,2,2,{scale:2});
|
||||
//g.print();
|
||||
SHOULD_BE(`
|
||||
................................
|
||||
................................
|
||||
..################..............
|
||||
..################..............
|
||||
..################..............
|
||||
..################..............
|
||||
..##000000......##..............
|
||||
..##000000......##..............
|
||||
..##0000........##..............
|
||||
..##0000........##..............
|
||||
..##00..........##..............
|
||||
..##00..........##..............
|
||||
..##............##..............
|
||||
..##............##..............
|
||||
..##............##..............
|
||||
..##............##..............
|
||||
..################..............
|
||||
..################..............
|
||||
................................
|
||||
................................
|
||||
................................
|
||||
................................
|
||||
................................
|
||||
................................
|
||||
................................
|
||||
................................
|
||||
................................
|
||||
................................
|
||||
................................
|
||||
................................
|
||||
................................
|
||||
................................`);
|
||||
|
||||
result = ok;
|
||||
Loading…
x
Reference in New Issue
Block a user