Double buffer and shader fixes (#273)

* DoubleBufferFixes

* Add NeoBitmapFile Render
This commit is contained in:
Michael Miller
2019-06-12 23:10:42 -07:00
committed by GitHub
parent 0eed256d33
commit 2d3609e15d
12 changed files with 113 additions and 34 deletions

View File

@@ -57,8 +57,9 @@ License along with NeoPixel. If not, see
#include "internal/NeoBufferMethods.h"
#include "internal/NeoBuffer.h"
#include "internal/NeoSpriteSheet.h"
#include "internal/NeoBitmapFile.h"
#include "internal/NeoDib.h"
#include "internal/NeoBitmapFile.h"
#include "internal/NeoEase.h"
#include "internal/NeoGamma.h"
@@ -145,14 +146,14 @@ public:
Dirty();
}
void Show()
void Show(bool maintainBufferConsistency = true)
{
if (!IsDirty())
{
return;
}
_method.Update();
_method.Update(maintainBufferConsistency);
ResetDirty();
}

View File

@@ -68,7 +68,7 @@ public:
digitalWrite(_pinData, LOW);
}
void Update()
void Update(bool)
{
// start frame
for (int startFrameByte = 0; startFrameByte < 4; startFrameByte++)

View File

@@ -60,7 +60,7 @@ public:
digitalWrite(_pinData, LOW);
}
void Update()
void Update(bool)
{
// start frame
for (int startFrameByte = 0; startFrameByte < 4; startFrameByte++)

View File

@@ -63,7 +63,7 @@ public:
SPI.begin();
}
void Update()
void Update(bool)
{
SPI.beginTransaction(SPISettings(20000000L, MSBFIRST, SPI_MODE0));
#if defined(ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_ESP32)

View File

@@ -66,7 +66,7 @@ public:
_endTime = micros();
}
void Update()
void Update(bool)
{
// Data latch = 50+ microsecond pause in the output stream. Rather than
// put a delay at the end of the function, the ending time is noted and

View File

@@ -148,7 +148,7 @@ public:
_endTime = micros();
}
void Update()
void Update(bool)
{
// Data latch = 50+ microsecond pause in the output stream. Rather than
// put a delay at the end of the function, the ending time is noted and

View File

@@ -189,7 +189,9 @@ public:
return color;
};
void Blt(NeoBufferContext<T_COLOR_FEATURE> destBuffer,
template <typename T_SHADER> void Render(NeoBufferContext<T_COLOR_FEATURE> destBuffer,
T_SHADER& shader,
uint16_t indexPixel,
int16_t xSrc,
int16_t ySrc,
@@ -208,6 +210,7 @@ public:
{
if (readPixel(&color))
{
color = shader.Apply(indexPixel, color);
xSrc++;
}
}
@@ -218,6 +221,18 @@ public:
}
void Blt(NeoBufferContext<T_COLOR_FEATURE> destBuffer,
uint16_t indexPixel,
int16_t xSrc,
int16_t ySrc,
int16_t wSrc)
{
NeoShaderNop<typename T_COLOR_FEATURE::ColorObject> shaderNop;
Render<NeoShaderNop<typename T_COLOR_FEATURE::ColorObject>>(destBuffer, shaderNop, indexPixel, xSrc, ySrc, wSrc);
};
template <typename T_SHADER> void Render(NeoBufferContext<T_COLOR_FEATURE> destBuffer,
T_SHADER& shader,
int16_t xDest,
int16_t yDest,
int16_t xSrc,
@@ -238,16 +253,17 @@ public:
{
for (int16_t x = 0; x < wSrc; x++)
{
uint16_t indexDest = layoutMap(xDest + x, yDest + y);
if ((uint16_t)xFile < _width)
{
if (readPixel(&color))
{
color = shader.Apply(indexDest, color);
xFile++;
}
}
uint16_t indexDest = layoutMap(xDest + x, yDest + y);
if (indexDest < destPixelCount)
{
T_COLOR_FEATURE::applyPixelColor(destBuffer.Pixels, indexDest, color);
@@ -257,6 +273,28 @@ public:
}
};
void Blt(NeoBufferContext<T_COLOR_FEATURE> destBuffer,
int16_t xDest,
int16_t yDest,
int16_t xSrc,
int16_t ySrc,
int16_t wSrc,
int16_t hSrc,
LayoutMapCallback layoutMap)
{
NeoShaderNop<typename T_COLOR_FEATURE::ColorObject> shaderNop;
Render<NeoShaderNop<typename T_COLOR_FEATURE::ColorObject>>(destBuffer,
shaderNop,
xDest,
yDest,
xSrc,
ySrc,
wSrc,
hSrc,
layoutMap);
};
private:
T_FILE_METHOD _file;

View File

@@ -25,6 +25,32 @@ License along with NeoPixel. If not, see
-------------------------------------------------------------------------*/
#pragma once
template<typename T_COLOR_OBJECT> class NeoShaderNop
{
public:
NeoShaderNop()
{
}
bool IsDirty() const
{
return true;
};
void Dirty()
{
};
void ResetDirty()
{
};
T_COLOR_OBJECT Apply(uint16_t, T_COLOR_OBJECT color)
{
return color;
};
};
class NeoShaderBase
{
public:
@@ -118,7 +144,8 @@ public:
Dirty();
};
template <typename T_COLOR_FEATURE, typename T_SHADER> void Render(NeoBufferContext<T_COLOR_FEATURE> destBuffer, T_SHADER& shader)
template <typename T_COLOR_FEATURE, typename T_SHADER> void Render(NeoBufferContext<T_COLOR_FEATURE> destBuffer,
T_SHADER& shader)
{
if (IsDirty() || shader.IsDirty())
{

View File

@@ -128,7 +128,7 @@ public:
i2sSetPins(T_BUS::I2sBusNumber, _pin, -1, -1, -1);
}
void Update()
void Update(bool)
{
// wait for not actively sending data
while (!IsReadyToUpdate())

View File

@@ -51,7 +51,7 @@ public:
public:
// ClkDiv of 2 provides for good resolution and plenty of reset resolution; but
// a ClkDiv of 1 will provide enough space for the longest reset and does show
// little better pulse accuracy
// little better pulse accuracy
const static uint8_t RmtClockDivider = 2;
inline constexpr static uint32_t FromNs(uint32_t ns)
@@ -207,20 +207,26 @@ public:
rmt_driver_install(T_CHANNEL::RmtChannelNumber, 0, 0);
rmt_translator_init(T_CHANNEL::RmtChannelNumber, _translate);
}
void Update(bool maintainBufferConsistency)
{
// wait for not actively sending data
// this will time out at 10 seconds, an arbitrarily long period of time
// and do nothing if this happens
if (ESP_OK == rmt_wait_tx_done(T_CHANNEL::RmtChannelNumber, 10000 / portTICK_PERIOD_MS))
{
// copy editing to sending,
// this maintains the contract that colors present before this will
// be the same as it just was using GetPixelColor
{
// now start the RMT transmit with the editing buffer before we swap
rmt_write_sample(T_CHANNEL::RmtChannelNumber, _pixelsEditing, _pixelsSize, false);
// now start the RMT transmit
if (maintainBufferConsistency)
{
// copy editing to sending,
// this maintains the contract that "colors present before will
// be the same after", otherwise GetPixelColor will be inconsistent
memcpy(_pixelsSending, _pixelsEditing, _pixelsSize);
}
// swap so the user can modify without affecting the async operation
std::swap(_pixelsSending, _pixelsEditing);
}
}

View File

@@ -184,7 +184,7 @@ protected:
T_UARTFEATURE::Init(uartBaud);
}
void UpdateUart()
void UpdateUart(bool)
{
// Since the UART can finish sending queued bytes in the FIFO in
// the background, instead of waiting for the FIFO to flush
@@ -221,12 +221,12 @@ protected:
NeoEsp8266AsyncUart(uint16_t pixelCount, size_t elementSize) :
NeoEsp8266UartBase(pixelCount, elementSize)
{
_asyncPixels = (uint8_t*)malloc(_sizePixels);
_pixelsSending = (uint8_t*)malloc(_sizePixels);
}
~NeoEsp8266AsyncUart()
{
// Remember: the UART interrupt can be sending data from _asyncPixels in the background
// Remember: the UART interrupt can be sending data from _pixelsSending in the background
while (_context.IsSending())
{
yield();
@@ -234,7 +234,7 @@ protected:
// detach context, which will disable intr, may disable ISR
_context.Detach(T_UARTFEATURE::Index);
free(_asyncPixels);
free(_pixelsSending);
}
void ICACHE_RAM_ATTR InitializeUart(uint32_t uartBaud)
@@ -245,7 +245,7 @@ protected:
_context.Attach(T_UARTFEATURE::Index);
}
void UpdateUart()
void UpdateUart(bool maintainBufferConsistency)
{
// Instruct ESP8266 hardware uart to send the pixels asynchronously
_context.StartSending(T_UARTFEATURE::Index,
@@ -255,15 +255,22 @@ protected:
// Annotate when we started to send bytes, so we can calculate when we are ready to send again
_startTime = micros();
// Copy the pixels to the idle buffer and swap them
memcpy(_asyncPixels, _pixels, _sizePixels);
std::swap(_asyncPixels, _pixels);
if (maintainBufferConsistency)
{
// copy editing to sending,
// this maintains the contract that "colors present before will
// be the same after", otherwise GetPixelColor will be inconsistent
memcpy(_pixelsSending, _pixels, _sizePixels);
}
// swap so the user can modify without affecting the async operation
std::swap(_pixelsSending, _pixels);
}
private:
T_UARTCONTEXT _context;
uint8_t* _asyncPixels; // Holds a copy of LED color values taken when UpdateUart began
uint8_t* _pixelsSending; // Holds a copy of LED color values taken when UpdateUart began
};
class NeoEsp8266UartSpeed800KbpsBase
@@ -334,7 +341,7 @@ public:
this->_startTime = micros() - getPixelTime();
}
void Update()
void Update(bool maintainBufferConsistency)
{
// Data latch = 50+ microsecond pause in the output stream. Rather than
// put a delay at the end of the function, the ending time is noted and
@@ -346,7 +353,7 @@ public:
{
yield();
}
this->UpdateUart();
this->UpdateUart(maintainBufferConsistency);
}
uint8_t* getPixels() const

View File

@@ -113,7 +113,7 @@ public:
_endTime = micros();
}
void Update()
void Update(bool)
{
// Data latch = 50+ microsecond pause in the output stream. Rather than
// put a delay at the end of the function, the ending time is noted and