From 3dc51b233a21f663ba7cb2463456ba91c4b197bf Mon Sep 17 00:00:00 2001 From: Gergely Nagy Date: Sun, 12 Feb 2017 22:23:30 +0100 Subject: [PATCH 1/3] Cache the keymap when changing layers Instead of going through all the active layers each time we are looking for a key, whenever we switch layers, compute the effective keymap, and store the indexes. This makes the lookup a considerably faster operation, and lookups happen far more often than layer switching. This comes at a cost of ROWS*COLS amount of memory, and a bit of code, but on the flip side, the lookup operation is now O(1), which is a very nice property to have, if you want responsiveness. Changing layers is marginally slower, however, but even with 32 active layers, doing the computation once, instead of potentially many dozens of time, is still worth it. We could further reduce the memory requirements if we stored more columns per byte, but that's for a future optimization. Signed-off-by: Gergely Nagy --- src/layers.cpp | 39 ++++++++++++++++++++++++++++++--------- src/layers.h | 4 ++++ 2 files changed, 34 insertions(+), 9 deletions(-) diff --git a/src/layers.cpp b/src/layers.cpp index 00814752..a37ede50 100644 --- a/src/layers.cpp +++ b/src/layers.cpp @@ -5,6 +5,7 @@ static uint8_t DefaultLayer; static uint32_t LayerState; uint8_t Layer_::highestLayer; +uint8_t Layer_::keyMap[ROWS][COLS]; static void handle_keymap_key_event(Key keymapEntry, uint8_t keyState) { if (keymapEntry.keyCode >= MOMENTARY_OFFSET) { @@ -51,18 +52,36 @@ Layer_::Layer_ (void) { defaultLayer (0); } -Key Layer_::lookup(byte row, byte col) { - Key mappedKey; - int8_t layer = highestLayer; +void +Layer_::mergeLayers(void) { + + memset (keyMap, DefaultLayer, ROWS * COLS); - mappedKey.raw = Key_Transparent.raw; + for (uint8_t r = 0; r < ROWS; r++) { + for (uint8_t c = 0; c < COLS; c++) { + int8_t layer = highestLayer; - while (mappedKey.raw == Key_Transparent.raw && - layer >= DefaultLayer) { - if (Layer.isOn (layer)) - mappedKey.raw = pgm_read_word(&(keymaps[layer][row][col])); - layer--; + while (layer >= DefaultLayer) { + if (Layer.isOn (layer)) { + Key mappedKey; + + mappedKey.raw = pgm_read_word(&(keymaps[layer][r][c])); + + if (mappedKey != Key_Transparent) { + keyMap[r][c] = layer; + break; + } + } + layer--; + } + } } +} + +Key Layer_::lookup(byte row, byte col) { + uint8_t layer = keyMap[row][col]; + Key mappedKey; + mappedKey.raw = pgm_read_word(&(keymaps[layer][row][col])); return mappedKey; } @@ -84,12 +103,14 @@ void Layer_::on (uint8_t layer) { bitSet (LayerState, layer); if (layer > highestLayer) highestLayer = layer; + mergeLayers(); } void Layer_::off (uint8_t layer) { bitClear (LayerState, layer); if (layer == highestLayer) highestLayer = top(); + mergeLayers(); } boolean Layer_::isOn (uint8_t layer) { diff --git a/src/layers.h b/src/layers.h index 1d0714dd..74737df1 100644 --- a/src/layers.h +++ b/src/layers.h @@ -3,6 +3,7 @@ #include #include "key_defs.h" #include "plugin.h" +#include KALEIDOSCOPE_HARDWARE_H class Layer_ { public: @@ -28,6 +29,9 @@ class Layer_ { private: static uint8_t highestLayer; + static uint8_t keyMap[ROWS][COLS]; + + static void mergeLayers(void); }; extern Layer_ Layer; From 0bdbe7385afeeb094588f407eac3b23467eaa92a Mon Sep 17 00:00:00 2001 From: Gergely Nagy Date: Sun, 12 Feb 2017 22:34:01 +0100 Subject: [PATCH 2/3] Minor improvement for mergeLayers We fill the cached `keyMap` with the value of `DefaultLayer`, so if that is the only layer active, then we can bail out early. Signed-off-by: Gergely Nagy --- src/layers.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/layers.cpp b/src/layers.cpp index a37ede50..b1bfff86 100644 --- a/src/layers.cpp +++ b/src/layers.cpp @@ -57,6 +57,9 @@ Layer_::mergeLayers(void) { memset (keyMap, DefaultLayer, ROWS * COLS); + if (LayerState == (uint32_t)(1 << DefaultLayer)) + return; + for (uint8_t r = 0; r < ROWS; r++) { for (uint8_t c = 0; c < COLS; c++) { int8_t layer = highestLayer; From 67e906bc15d82b7e8d1670e9c41a56f63eae0d91 Mon Sep 17 00:00:00 2001 From: Gergely Nagy Date: Sun, 12 Feb 2017 22:35:01 +0100 Subject: [PATCH 3/3] Another mergeLayers optimization Since we pre-fill the cached `keyMap` with the value of `DefaultLayer`, there is no need to check that layer again, looking for a non-transparent key. Whatever is there, will be used anyway. This way we save a cycle for keys that are transparent everywhere but the default layer. Signed-off-by: Gergely Nagy --- src/layers.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/layers.cpp b/src/layers.cpp index b1bfff86..d9dfa497 100644 --- a/src/layers.cpp +++ b/src/layers.cpp @@ -64,7 +64,7 @@ Layer_::mergeLayers(void) { for (uint8_t c = 0; c < COLS; c++) { int8_t layer = highestLayer; - while (layer >= DefaultLayer) { + while (layer > DefaultLayer) { if (Layer.isOn (layer)) { Key mappedKey;