Skip to content

Commit

Permalink
Improved ArrayBuffer write performance
Browse files Browse the repository at this point in the history
            Massively improved ArrayBuffer Graphics fill performance for bpp<8
  • Loading branch information
gfwilliams committed Jan 16, 2015
1 parent b983a1b commit 59d7766
Show file tree
Hide file tree
Showing 4 changed files with 62 additions and 14 deletions.
2 changes: 2 additions & 0 deletions ChangeLog
Expand Up @@ -37,6 +37,8 @@
Add Boolean constructor (fix #311)
Fix difference between String() and String(undefined) (fix #312)
Fix I2C/SPI on F401/F411-based boards (fix #470, fix #473)
Improved ArrayBuffer write performance
Massively improved ArrayBuffer Graphics fill performance for bpp<8

1v71 : Allowed WIZnet + CC3000 to be instantiated on any pins
Fix break inside loop inside case inside function (fix 428)
Expand Down
25 changes: 21 additions & 4 deletions libs/graphics/lcd_arraybuffer.c
Expand Up @@ -59,13 +59,30 @@ void lcdSetPixels_ArrayBuffer(JsGraphics *gfx, short x, short y, short pixelCoun
size_t idx = lcdGetPixelIndex_ArrayBuffer(gfx,x,y,pixelCount);
JsvArrayBufferIterator it;
jsvArrayBufferIteratorNew(&it, buf, idx>>3 );
short p;
for (p=0;p<pixelCount;p++) { // writing individual bits

unsigned int whiteMask = (1U<<gfx->data.bpp)-1;
bool shortCut = col==0 || (col&whiteMask)==whiteMask; // simple black or white fill

while (pixelCount--) { // writing individual bits
if (gfx->data.bpp&7/*not a multiple of one byte*/) {
idx = idx & 7;
if (shortCut && idx==0) {
// Basically, if we're aligned and we're filling all 0 or all 1
// then we can go really quickly and can just fill
int wholeBytes = (gfx->data.bpp*(pixelCount+1)) >> 3;
if (wholeBytes) {
char c = (char)(col?0xFF:0);
pixelCount = (short)(pixelCount+1 - (wholeBytes*8/gfx->data.bpp));
while (wholeBytes--) {
jsvArrayBufferIteratorSetByteValue(&it, c);
jsvArrayBufferIteratorNext(&it);
}
continue;
}
}
unsigned int mask = (unsigned int)(1<<gfx->data.bpp)-1;
unsigned int existing = (unsigned int)jsvArrayBufferIteratorGetIntegerValue(&it);
jsvArrayBufferIteratorSetIntegerValue(&it, (JsVarInt)((existing&~(mask<<idx)) | ((col&mask)<<idx)));
jsvArrayBufferIteratorSetByteValue(&it, (char)((existing&~(mask<<idx)) | ((col&mask)<<idx)));
if (gfx->data.flags & JSGRAPHICSFLAGS_ARRAYBUFFER_VERTICAL_BYTE) {
jsvArrayBufferIteratorNext(&it);
} else {
Expand All @@ -75,7 +92,7 @@ void lcdSetPixels_ArrayBuffer(JsGraphics *gfx, short x, short y, short pixelCoun
} else { // we're writing whole bytes
int i;
for (i=0;i<gfx->data.bpp;i+=8) {
jsvArrayBufferIteratorSetIntegerValue(&it, (JsVarInt)(col >> i));
jsvArrayBufferIteratorSetByteValue(&it, (char)(col >> i));
jsvArrayBufferIteratorNext(&it);
}
}
Expand Down
48 changes: 38 additions & 10 deletions src/jsvariterator.c
Expand Up @@ -254,6 +254,32 @@ JsVarFloat jsvArrayBufferIteratorGetFloatValue(JsvArrayBufferIterator *it) {
}
}

void jsvArrayBufferIteratorSetIntegerValue(JsvArrayBufferIterator *it, JsVarInt v) {
if (it->type == ARRAYBUFFERVIEW_UNDEFINED) return;
assert(!it->hasAccessedElement); // we just haven't implemented this case yet
char data[8];
unsigned int i,dataLen = JSV_ARRAYBUFFER_GET_SIZE(it->type);

if (JSV_ARRAYBUFFER_IS_FLOAT(it->type)) {
if (dataLen==4) { float f = (float)v; memcpy(data,&f,dataLen); }
else if (dataLen==8) { double f = (double)v; memcpy(data,&f,dataLen); }
else assert(0);
} else {
// we don't care about sign when writing - as it gets truncated
if (dataLen==1) { data[0] = (char)v; }
else if (dataLen==2) { *(short*)data = (short)v; }
else if (dataLen==4) { *(int*)data = (int)v; }
else if (dataLen==8) { *(long long*)data = (long long)v; }
else assert(0);
}

for (i=0;i<dataLen;i++) {
jsvStringIteratorSetChar(&it->it, data[i]);
if (dataLen!=1) jsvStringIteratorNext(&it->it);
}
if (dataLen!=1) it->hasAccessedElement = true;
}

void jsvArrayBufferIteratorSetValue(JsvArrayBufferIterator *it, JsVar *value) {
if (it->type == ARRAYBUFFERVIEW_UNDEFINED) return;
assert(!it->hasAccessedElement); // we just haven't implemented this case yet
Expand All @@ -268,10 +294,10 @@ void jsvArrayBufferIteratorSetValue(JsvArrayBufferIterator *it, JsVar *value)
} else {
JsVarInt v = jsvGetInteger(value);
// we don't care about sign when writing - as it gets truncated
if (dataLen==1) { char c = (char)v; memcpy(data,&c,dataLen); }
else if (dataLen==2) { short c = (short)v; memcpy(data,&c,dataLen); }
else if (dataLen==4) { int c = (int)v; memcpy(data,&c,dataLen); }
else if (dataLen==8) { long long c = (long long)v; memcpy(data,&c,dataLen); }
if (dataLen==1) { data[0] = (char)v; }
else if (dataLen==2) { *(short*)data = (short)v; }
else if (dataLen==4) { *(int*)data = (int)v; }
else if (dataLen==8) { *(long long*)data = (long long)v; }
else assert(0);
}

Expand All @@ -282,6 +308,14 @@ void jsvArrayBufferIteratorSetValue(JsvArrayBufferIterator *it, JsVar *value)
if (dataLen!=1) it->hasAccessedElement = true;
}

void jsvArrayBufferIteratorSetByteValue(JsvArrayBufferIterator *it, char c) {
if (JSV_ARRAYBUFFER_GET_SIZE(it->type)!=1) {
assert(0);
return;
}
jsvStringIteratorSetChar(&it->it, c);
}

void jsvArrayBufferIteratorSetValueAndRewind(JsvArrayBufferIterator *it, JsVar *value) {
JsvStringIterator oldIt = jsvStringIteratorClone(&it->it);
jsvArrayBufferIteratorSetValue(it, value);
Expand All @@ -290,12 +324,6 @@ void jsvArrayBufferIteratorSetValueAndRewind(JsvArrayBufferIterator *it, JsVar *
it->hasAccessedElement = false;
}

void jsvArrayBufferIteratorSetIntegerValue(JsvArrayBufferIterator *it, JsVarInt value) {
// FIXME: Do this without the allocation!
JsVar *val = jsvNewFromInteger(value);
jsvArrayBufferIteratorSetValue(it, val);
jsvUnLock(val);
}

JsVar* jsvArrayBufferIteratorGetIndex(JsvArrayBufferIterator *it) {
return jsvNewFromInteger((JsVarInt)it->index);
Expand Down
1 change: 1 addition & 0 deletions src/jsvariterator.h
Expand Up @@ -207,6 +207,7 @@ JsVarFloat jsvArrayBufferIteratorGetFloatValue(JsvArrayBufferIterator *it);
void jsvArrayBufferIteratorSetValue(JsvArrayBufferIterator *it, JsVar *value);
void jsvArrayBufferIteratorSetValueAndRewind(JsvArrayBufferIterator *it, JsVar *value);
void jsvArrayBufferIteratorSetIntegerValue(JsvArrayBufferIterator *it, JsVarInt value);
void jsvArrayBufferIteratorSetByteValue(JsvArrayBufferIterator *it, char c); ///< special case for when we know we're writing to a byte array
JsVar* jsvArrayBufferIteratorGetIndex(JsvArrayBufferIterator *it);
bool jsvArrayBufferIteratorHasElement(JsvArrayBufferIterator *it);
void jsvArrayBufferIteratorNext(JsvArrayBufferIterator *it);
Expand Down

0 comments on commit 59d7766

Please sign in to comment.