Files
pico-launcher/arm9/source/gui/AdvancedPaletteManager.cpp
2025-11-25 17:41:31 +01:00

258 lines
6.2 KiB
C++

#include "common.h"
#include <libtwl/gfx/gfxStatus.h>
#include <algorithm>
#include "AdvancedPaletteManager.h"
bool AdvancedPaletteManagerBase::PaletteRow::ColorsEqualTo(const PaletteRow& other) const
{
if (hash != other.hash)
{
return false;
}
for (int i = 0; i < 16; i++)
{
if (colors[i] != other.colors[i])
{
return false;
}
}
return true;
}
int AdvancedPaletteManagerBase::HwPaletteRow::FindPlace(const PaletteRow* rows, u32 yStart, u32 yEnd) const
{
if (count == 0)
{
return 0xFF;
}
u32 idx = first;
u32 prevIdx = 0xFF;
while (idx != 0xFF && rows[idx].endY < yStart)
{
prevIdx = idx;
idx = rows[idx].next;
}
if (idx == 0xFF || rows[idx].startY >= yEnd)
{
return prevIdx;
}
return -1;
}
u32 AdvancedPaletteManagerBase::TryMerge(PaletteRow* rows, const PaletteRow& newRow, int yStart, int yEnd)
{
for (u32 i = 0; i < _usedRows; i++)
{
if (rows[i].ColorsEqualTo(newRow))
{
if (yStart < rows[i].startY)
{
u32 prev = rows[i].prev;
if (prev != 0xFF && yStart - rows[prev].endY <= 1)
{
continue;
}
}
if (yEnd > rows[i].endY)
{
u32 next = rows[i].next;
if (next != 0xFF && rows[next].startY - yEnd <= 1)
{
continue;
}
}
// LOG_DEBUG("Could merge [%d,%d) into [%d,%d)\n", yStart, yEnd, rows[i].startY, rows[i].endY);
if ((yEnd < rows[i].startY && rows[i].startY - yEnd > 1) ||
(yStart > rows[i].endY && yStart - rows[i].endY > 1))
{
continue;
}
// LOG_DEBUG("Merging [%d,%d) into [%d,%d)\n", yStart, yEnd, rows[i].startY, rows[i].endY);
// merging
rows[i].startY = std::min((int)rows[i].startY, yStart);
rows[i].endY = std::max((int)rows[i].endY, yEnd);
return rows[i].hwRow;
}
}
return PALETTE_MANAGER_ROW_IDX_INVALID;
}
u32 AdvancedPaletteManagerBase::AllocRowInternal(PaletteRow* rows, const IPalette& palette, int yStart, int yEnd)
{
if (yStart < 0)
{
yStart = 0;
}
if (yEnd > 192)
{
yEnd = 192;
}
u32 newIdx = _usedRows;
PaletteRow& newRow = rows[newIdx];
newRow.hash = palette.GetHashCode();
palette.GetColors(newRow.colors);
u32 rowIdx = TryMerge(rows, newRow, yStart, yEnd);
if (rowIdx != PALETTE_MANAGER_ROW_IDX_INVALID)
{
return rowIdx;
}
_usedRows++;
int bestSlack = 0x100;//-1;
u32 bestPrevIdx = 0xFF;
u32 bestHwRow = 0xFF;
for (int i = 0; i < HW_PALETTE_ROWS; i++)
{
int result = _hwRows[i].FindPlace(rows, yStart, yEnd);
if (result < 0)
{
continue;
}
int slack = result >= 0xFF ? result : yStart - rows[result].endY;
if (slack /*>*/ < bestSlack && slack > 1)
{
bestSlack = slack;
bestPrevIdx = result;
bestHwRow = i;
}
}
rowIdx = bestHwRow;
if (bestHwRow == 0xFF)
{
LOG_FATAL("Failed to allocate palette row\n");
while (true);
return PALETTE_MANAGER_ROW_IDX_INVALID;
}
// LOG_DEBUG("Allocated hw palette row %d for y range %d - %d\n", bestHwRow, yStart, yEnd);
newRow.startY = yStart;
newRow.endY = yEnd;
if (bestPrevIdx >= 0xFF)
{
newRow.next = _hwRows[bestHwRow].first;
if (newRow.next != 0xFF)
{
rows[newRow.next].prev = newIdx;
}
newRow.prev = 0xFF;
_hwRows[bestHwRow].first = newIdx;
}
else
{
newRow.prev = bestPrevIdx;
newRow.next = rows[bestPrevIdx].next;
rows[bestPrevIdx].next = newIdx;
if (newRow.next != 0xFF)
{
rows[newRow.next].prev = newIdx;
}
}
_hwRows[bestHwRow].count++;
newRow.hwRow = rowIdx;
return rowIdx;
}
void AdvancedPaletteManagerBase::Reset()
{
_usedRows = 0;
for (int i = 0; i < HW_PALETTE_ROWS; i++)
{
_hwRows[i].count = 0;
_hwRows[i].first = 0xFF;
}
}
void AdvancedPaletteManagerBase::CreateScheme(const PaletteRow* rows, SchemeEntry* scheme)
{
_nextSchemeEntry = scheme;
u32 y = 0;
u8 curRow[HW_PALETTE_ROWS];
for (int i = 0; i < HW_PALETTE_ROWS; i++)
{
curRow[i] = _hwRows[i].first;
}
while (y != 0xFF)
{
u32 minY = 0xFF;
for (int i = 0; i < HW_PALETTE_ROWS; i++)
{
if (curRow[i] == 0xFF)
{
continue;
}
const PaletteRow& row = rows[curRow[i]];
u32 uploadLine = row.prev == 0xFF ? 0 : rows[row.prev].endY;
if (uploadLine == y)
{
// LOG_DEBUG("At %d upload row %d (%d-%d) to hw row %d\n", uploadLine, curRow[i], row.startY, row.endY, i);
scheme->src = row.colors;
scheme->dst = _targetPalette + i * 16;
scheme++;
curRow[i] = row.next;
uploadLine = row.endY;
}
if (curRow[i] == 0xFF)
{
continue;
}
minY = std::min(minY, uploadLine);
}
if (y != minY)
{
scheme->endMarker = 0;
scheme->nextVCount = minY == 255 ? 0 : minY;
scheme++;
}
y = minY;
}
scheme->endMarker = 0;
scheme->nextVCount = 0;
}
void AdvancedPaletteManagerBase::VCount()
{
while (_curSchemeEntry->endMarker != 0)
{
struct palette_row_t
{
u32 data[8];
};
*(palette_row_t*)_curSchemeEntry->dst = *(palette_row_t*)_curSchemeEntry->src;
_curSchemeEntry++;
}
if (_curSchemeEntry->nextVCount == 0)
{
gfx_setVCountMatchIrqEnabled(false);
}
else
{
// LOG_DEBUG("vcount %d\n", _curSchemeEntry->nextVCount);
gfx_setVCountMatchLine(_curSchemeEntry->nextVCount);
gfx_setVCountMatchIrqEnabled(true);
_curSchemeEntry++;
}
}