diff --git a/rewind-alcaro.h b/rewind-alcaro.h
index cc88e812af..8925f88792 100644
--- a/rewind-alcaro.h
+++ b/rewind-alcaro.h
@@ -1,6 +1,8 @@
//#define NO_UNALIGNED_MEM
//Uncomment the above if alignment is enforced.
+#include "boolean.h"
+
//A compressing, lossy stack. Optimized for large, mostly similar, blocks of data; optimized for
// writing, less so for reading. Will discard old data if its capacity is exhausted.
struct rewindstack {
diff --git a/rewind.c b/rewind.c
index 5a7229f422..ae3bae30ae 100644
--- a/rewind.c
+++ b/rewind.c
@@ -1,194 +1,64 @@
-/* RetroArch - A frontend for libretro.
- * Copyright (C) 2010-2014 - Hans-Kristian Arntzen
- *
- * RetroArch is free software: you can redistribute it and/or modify it under the terms
- * of the GNU General Public License as published by the Free Software Found-
- * ation, either version 3 of the License, or (at your option) any later version.
- *
- * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
- * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
- * PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with RetroArch.
- * If not, see .
- */
+/* RetroArch - A frontend for libretro.
+* Copyright (C) 2010-2014 - Hans-Kristian Arntzen
+*
+* RetroArch is free software: you can redistribute it and/or modify it under the terms
+* of the GNU General Public License as published by the Free Software Found-
+* ation, either version 3 of the License, or (at your option) any later version.
+*
+* RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+* PURPOSE. See the GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License along with RetroArch.
+* If not, see .
+*/
#include "rewind.h"
+#include "rewind-alcaro.h"
#include
-#include
-#include "boolean.h"
#include
-#include
-#include "general.h"
-struct state_manager
-{
- uint64_t *buffer;
- size_t buf_size;
- size_t buf_size_mask;
- uint32_t *tmp_state;
- size_t top_ptr;
- size_t bottom_ptr;
- size_t state_size;
- bool first_pop;
+struct state_manager {
+ struct rewindstack * core;
+ unsigned int state_size;
};
-static inline size_t nearest_pow2_size(size_t v)
-{
- size_t orig = v;
- v--;
- v |= v >> 1;
- v |= v >> 2;
- v |= v >> 4;
-#if SIZE_MAX >= UINT16_C(0xffff)
- v |= v >> 8;
-#endif
-#if SIZE_MAX >= UINT32_C(0xffffffff)
- v |= v >> 16;
-#endif
-#if SIZE_MAX >= UINT64_C(0xffffffffffffffff)
- v |= v >> 32;
-#endif
- v++;
-
- size_t next = v;
- size_t prev = v >> 1;
-
- if ((next - orig) < (orig - prev))
- return next;
- else
- return prev;
-}
-
state_manager_t *state_manager_new(size_t state_size, size_t buffer_size, void *init_buffer)
{
- if (buffer_size <= state_size * 4) // Need a sufficient buffer size.
- return NULL;
-
- state_manager_t *state = (state_manager_t*)calloc(1, sizeof(*state));
- if (!state)
- return NULL;
-
- // We need 4-byte aligned state_size to avoid having to enforce this with unneeded memcpy's!
- rarch_assert(state_size % 4 == 0);
- state->top_ptr = 1;
-
- state->state_size = state_size / sizeof(uint32_t); // Works in multiple of 4.
- state->buf_size = nearest_pow2_size(buffer_size) / sizeof(uint64_t); // Works in multiple of 8.
- state->buf_size_mask = state->buf_size - 1;
- RARCH_LOG("Readjusted rewind buffer size to %u MiB\n", (unsigned)(sizeof(uint64_t) * (state->buf_size >> 20)));
-
- if (!(state->buffer = (uint64_t*)calloc(1, state->buf_size * sizeof(uint64_t))))
- goto error;
- if (!(state->tmp_state = (uint32_t*)calloc(1, state->state_size * sizeof(uint32_t))))
- goto error;
-
- memcpy(state->tmp_state, init_buffer, state_size);
-
- return state;
-
-error:
- if (state)
- {
- free(state->buffer);
- free(state->tmp_state);
- free(state);
- }
- return NULL;
+ state_manager_t *state = (state_manager_t*)calloc(1, sizeof(*state));
+ if (!state)
+ return NULL;
+
+ state->state_size=state_size;
+
+ state->core=rewindstack_create(state_size, buffer_size);
+ if (!state->core)
+ {
+ free(state);
+ return NULL;
+ }
+
+ void* first_state=state->core->push_begin(state->core);
+ memcpy(first_state, init_buffer, state_size);
+ state->core->push_end(state->core);
}
void state_manager_free(state_manager_t *state)
{
- free(state->buffer);
- free(state->tmp_state);
- free(state);
+ state->core->free(state->core);
+ free(state);
}
bool state_manager_pop(state_manager_t *state, void **data)
-{
- *data = state->tmp_state;
- if (state->first_pop)
- {
- state->first_pop = false;
- return true;
- }
-
- state->top_ptr = (state->top_ptr - 1) & state->buf_size_mask;
-
- if (state->top_ptr == state->bottom_ptr) // Our stack is completely empty... :v
- {
- state->top_ptr = (state->top_ptr + 1) & state->buf_size_mask;
- return false;
- }
-
- while (state->buffer[state->top_ptr])
- {
- // Apply the xor patch.
- uint32_t addr = state->buffer[state->top_ptr] >> 32;
- uint32_t xor_ = state->buffer[state->top_ptr] & 0xFFFFFFFFU;
- state->tmp_state[addr] ^= xor_;
-
- state->top_ptr = (state->top_ptr - 1) & state->buf_size_mask;
- }
-
- if (state->top_ptr == state->bottom_ptr) // Our stack is completely empty... :v
- {
- state->top_ptr = (state->top_ptr + 1) & state->buf_size_mask;
- return true;
- }
-
- return true;
-}
-
-static void reassign_bottom(state_manager_t *state)
{
- state->bottom_ptr = (state->top_ptr + 1) & state->buf_size_mask;
- while (state->buffer[state->bottom_ptr]) // Skip ahead until we find the first 0 (boundary for state delta).
- state->bottom_ptr = (state->bottom_ptr + 1) & state->buf_size_mask;
-}
-
-static void generate_delta(state_manager_t *state, const void *data)
-{
- uint64_t i;
- bool crossed = false;
- const uint32_t *old_state = state->tmp_state;
- const uint32_t *new_state = (const uint32_t*)data;
-
- state->buffer[state->top_ptr++] = 0; // For each separate delta, we have a 0 value sentinel in between.
- state->top_ptr &= state->buf_size_mask;
-
- // Check if top_ptr and bottom_ptr crossed each other, which means we need to delete old cruft.
- if (state->top_ptr == state->bottom_ptr)
- crossed = true;
-
- for (i = 0; i < state->state_size; i++)
- {
- uint64_t xor_ = old_state[i] ^ new_state[i];
-
- // If the data differs (xor != 0), we push that xor on the stack with index and xor.
- // This can be reversed by reapplying the xor.
- // This, if states don't really differ much, we'll save lots of space :)
- // Hopefully this will work really well with save states.
- if (xor_)
- {
- state->buffer[state->top_ptr] = (i << 32) | xor_;
- state->top_ptr = (state->top_ptr + 1) & state->buf_size_mask;
-
- if (state->top_ptr == state->bottom_ptr)
- crossed = true;
- }
- }
-
- if (crossed)
- reassign_bottom(state);
+ *data=(void*)state->core->pull(state->core);
+ return (*data);
}
bool state_manager_push(state_manager_t *state, const void *data)
{
- generate_delta(state, data);
- memcpy(state->tmp_state, data, state->state_size * sizeof(uint32_t));
- state->first_pop = true;
-
- return true;
+ void* next_state=state->core->push_begin(state->core);
+ memcpy(next_state, data, state->state_size);
+ state->core->push_end(state->core);
+ return true;
}
-