1
0
Fork 0

Codechange: swap x/y axes for dirty blocks around

pull/13639/head
Rubidium 2025-01-18 16:39:43 +01:00 committed by rubidium42
parent ec1b9e53f4
commit 3880cc1b57
1 changed files with 53 additions and 86 deletions

View File

@ -77,7 +77,8 @@ static uint8_t _string_colourremap[3]; ///< Recoloursprite for stringdrawing. Th
static const uint DIRTY_BLOCK_HEIGHT = 8;
static const uint DIRTY_BLOCK_WIDTH = 64;
static uint _dirty_bytes_per_line = 0;
static size_t _dirty_blocks_per_row = 0;
static size_t _dirty_blocks_per_column = 0;
static std::vector<uint8_t> _dirty_blocks;
extern uint _dirty_block_colour;
@ -1271,8 +1272,9 @@ std::pair<uint8_t, uint8_t> GetBroadestDigit(FontSize size)
void ScreenSizeChanged()
{
_dirty_bytes_per_line = CeilDiv(_screen.width, DIRTY_BLOCK_WIDTH);
_dirty_blocks.resize(static_cast<size_t>(_dirty_bytes_per_line) * CeilDiv(_screen.height, DIRTY_BLOCK_HEIGHT));
_dirty_blocks_per_row = CeilDiv(_screen.width, DIRTY_BLOCK_WIDTH);
_dirty_blocks_per_column = CeilDiv(_screen.height, DIRTY_BLOCK_HEIGHT);
_dirty_blocks.resize(_dirty_blocks_per_column * _dirty_blocks_per_row);
/* check the dirty rect */
if (_invalid_rect.right >= _screen.width) _invalid_rect.right = _screen.width;
@ -1400,77 +1402,52 @@ void RedrawScreenRect(int left, int top, int right, int bottom)
*/
void DrawDirtyBlocks()
{
uint8_t *b = _dirty_blocks.data();
const int w = Align(_screen.width, DIRTY_BLOCK_WIDTH);
const int h = Align(_screen.height, DIRTY_BLOCK_HEIGHT);
int x;
int y;
auto is_dirty = [](auto block) -> bool { return block != 0; };
auto block = _dirty_blocks.begin();
y = 0;
do {
x = 0;
do {
if (*b != 0) {
int left;
int top;
int right = x + DIRTY_BLOCK_WIDTH;
int bottom = y;
uint8_t *p = b;
int h2;
for (size_t x = 0; x < _dirty_blocks_per_row; ++x) {
auto last_of_column = block + _dirty_blocks_per_column;
for (size_t y = 0; y < _dirty_blocks_per_column; ++y, ++block) {
if (!is_dirty(*block)) continue;
/* First try coalescing downwards */
do {
*p = 0;
p += _dirty_bytes_per_line;
bottom += DIRTY_BLOCK_HEIGHT;
} while (bottom != h && *p != 0);
/* First try coalescing downwards */
size_t height = std::find_if_not(block + 1, last_of_column, is_dirty) - block;
size_t width = 1;
/* Try coalescing to the right too. */
h2 = (bottom - y) / DIRTY_BLOCK_HEIGHT;
assert(h2 > 0);
p = b;
/* Clear dirty state. */
std::fill_n(block, height, 0);
while (right != w) {
uint8_t *p2 = ++p;
int i = h2;
/* Check if a full line of dirty flags is set. */
do {
if (!*p2) goto no_more_coalesc;
p2 += _dirty_bytes_per_line;
} while (--i != 0);
/* Try coalescing to the right too. */
auto block_right = block;
for (size_t x_right = x + 1; x_right < _dirty_blocks_per_row; ++x_right, ++width) {
block_right += _dirty_blocks_per_column;
auto last_right = block_right + height;
/* Wohoo, can combine it one step to the right!
* Do that, and clear the bits. */
right += DIRTY_BLOCK_WIDTH;
i = h2;
p2 = p;
do {
*p2 = 0;
p2 += _dirty_bytes_per_line;
} while (--i != 0);
}
no_more_coalesc:
left = x;
top = y;
if (left < _invalid_rect.left ) left = _invalid_rect.left;
if (top < _invalid_rect.top ) top = _invalid_rect.top;
if (right > _invalid_rect.right ) right = _invalid_rect.right;
if (bottom > _invalid_rect.bottom) bottom = _invalid_rect.bottom;
if (left < right && top < bottom) {
RedrawScreenRect(left, top, right, bottom);
}
if (std::find_if_not(block_right, last_right, is_dirty) != last_right) break;
/* Clear dirty state. */
std::fill_n(block_right, height, 0);
}
} while (b++, (x += DIRTY_BLOCK_WIDTH) != w);
} while (b += -(int)(w / DIRTY_BLOCK_WIDTH) + _dirty_bytes_per_line, (y += DIRTY_BLOCK_HEIGHT) != h);
int left = static_cast<int>(x * DIRTY_BLOCK_WIDTH);
int top = static_cast<int>(y * DIRTY_BLOCK_HEIGHT);
int right = left + static_cast<int>(width * DIRTY_BLOCK_WIDTH);
int bottom = top + static_cast<int>(height * DIRTY_BLOCK_HEIGHT);
left = std::max(_invalid_rect.left, left);
top = std::max(_invalid_rect.top, top);
right = std::min(_invalid_rect.right, right);
bottom = std::min(_invalid_rect.bottom, bottom);
if (left < right && top < bottom) {
RedrawScreenRect(left, top, right, bottom);
}
}
}
++_dirty_block_colour;
_invalid_rect.left = w;
_invalid_rect.top = h;
_invalid_rect.left = _screen.width;
_invalid_rect.top = _screen.height;
_invalid_rect.right = 0;
_invalid_rect.bottom = 0;
}
@ -1489,10 +1466,6 @@ void DrawDirtyBlocks()
*/
void AddDirtyBlock(int left, int top, int right, int bottom)
{
uint8_t *b;
int width;
int height;
if (left < 0) left = 0;
if (top < 0) top = 0;
if (right > _screen.width) right = _screen.width;
@ -1500,28 +1473,22 @@ void AddDirtyBlock(int left, int top, int right, int bottom)
if (left >= right || top >= bottom) return;
if (left < _invalid_rect.left ) _invalid_rect.left = left;
if (top < _invalid_rect.top ) _invalid_rect.top = top;
if (right > _invalid_rect.right ) _invalid_rect.right = right;
if (bottom > _invalid_rect.bottom) _invalid_rect.bottom = bottom;
_invalid_rect.left = std::min(_invalid_rect.left, left);
_invalid_rect.top = std::min(_invalid_rect.top, top);
_invalid_rect.right = std::max(_invalid_rect.right, right);
_invalid_rect.bottom = std::max(_invalid_rect.bottom, bottom);
left /= DIRTY_BLOCK_WIDTH;
top /= DIRTY_BLOCK_HEIGHT;
right = CeilDiv(right, DIRTY_BLOCK_WIDTH);
int height = CeilDiv(bottom, DIRTY_BLOCK_HEIGHT) - top;
b = _dirty_blocks.data() + top * _dirty_bytes_per_line + left;
assert(left < right && height > 0);
width = ((right - 1) / DIRTY_BLOCK_WIDTH) - left + 1;
height = ((bottom - 1) / DIRTY_BLOCK_HEIGHT) - top + 1;
assert(width > 0 && height > 0);
do {
int i = width;
do b[--i] = 0xFF; while (i != 0);
b += _dirty_bytes_per_line;
} while (--height != 0);
for (; left < right; ++left) {
size_t offset = _dirty_blocks_per_column * left + top;
std::fill_n(_dirty_blocks.begin() + offset, height, 0xFF);
}
}
/**