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