mirror of
https://github.com/PCSX2/pcsx2.git
synced 2026-10-02 17:25:49 +02:00
This pull request is for the pending reorganization of the folder structure on GSdx, making it better organized and easier to work with. Also remove unused GSTextureFX.cpp file.
278 lines
8.0 KiB
C++
278 lines
8.0 KiB
C++
/*
|
|
* Copyright (C) 2017-2017 Alessandro Vetere
|
|
* Copyright (C) 2007-2009 Gabest
|
|
* http://www.gabest.org
|
|
*
|
|
* This Program 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 Foundation; either version 2, or (at your option)
|
|
* any later version.
|
|
*
|
|
* This Program 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 GNU Make; see the file COPYING. If not, write to
|
|
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA USA.
|
|
* http://www.gnu.org/copyleft/gpl.html
|
|
*
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
template <class T>
|
|
struct Element {
|
|
T data;
|
|
uint16 next_index;
|
|
uint16 prev_index;
|
|
};
|
|
|
|
template <class T>
|
|
class FastListIterator;
|
|
|
|
template <class T>
|
|
class FastList {
|
|
friend class FastListIterator<T>;
|
|
private:
|
|
// The index of the first element of the list is m_buffer[0].next_index
|
|
// The first Element<T> of the list has prev_index equal to 0
|
|
// The index of the last element of the list is m_buffer[0].prev_index
|
|
// The last Element<T> of the list has next_index equal to 0
|
|
// All the other Element<T> of the list are chained by next_index and prev_index
|
|
// m_buffer has dynamic size m_capacity
|
|
// Due to m_buffer reallocation, the pointers to Element<T> stored into the array
|
|
// are invalidated every time Grow() is executed. But FastListIterator<T> is
|
|
// index based, not pointer based, and the elements are copied in order on Grow(),
|
|
// so there is no iterator invalidation (which is an index invalidation) until
|
|
// the relevant iterator (or the index alone) are erased from the list.
|
|
// m_buffer[0] is always present as auxiliary Element<T> of the list
|
|
Element<T>* m_buffer;
|
|
uint16 m_capacity;
|
|
uint16 m_free_indexes_stack_top;
|
|
// m_free_indexes_stack has dynamic size (m_capacity - 1)
|
|
// m_buffer indexes that are free to be used are stacked here
|
|
uint16* m_free_indexes_stack;
|
|
|
|
public:
|
|
__forceinline FastList() {
|
|
m_buffer = nullptr;
|
|
clear();
|
|
}
|
|
|
|
__forceinline ~FastList() {
|
|
_aligned_free(m_buffer);
|
|
}
|
|
|
|
void clear() {
|
|
// Initialize m_capacity to 4 so we avoid to Grow() on initial insertions
|
|
// The code doesn't break if this value is changed with anything from 1 to USHRT_MAX
|
|
m_capacity = 4;
|
|
|
|
// Initialize m_buffer and m_free_indexes_stack as a contiguous block of memory starting at m_buffer
|
|
// This should increase cache locality and reduce memory fragmentation
|
|
_aligned_free(m_buffer);
|
|
m_buffer = (Element<T>*)_aligned_malloc(m_capacity * sizeof(Element<T>) + (m_capacity - 1) * sizeof(uint16), 64);
|
|
m_free_indexes_stack = (uint16*)&m_buffer[m_capacity];
|
|
|
|
// Initialize m_buffer[0], data field is unused but initialized using default T constructor
|
|
m_buffer[0] = { T(), 0, 0 };
|
|
|
|
// m_free_indexes_stack top index is 0, bottom index is m_capacity - 2
|
|
m_free_indexes_stack_top = 0;
|
|
|
|
// m_buffer index 0 is reserved for auxiliary element
|
|
for (uint16 i = 0; i < m_capacity - 1; i++) {
|
|
m_free_indexes_stack[i] = i + 1;
|
|
}
|
|
}
|
|
|
|
// Insert the element in front of the list and return its position in m_buffer
|
|
__forceinline uint16 InsertFront(const T& data) {
|
|
if (Full()) {
|
|
Grow();
|
|
}
|
|
|
|
// Pop a free index from the stack
|
|
const uint16 free_index = m_free_indexes_stack[m_free_indexes_stack_top++];
|
|
m_buffer[free_index].data = data;
|
|
ListInsertFront(free_index);
|
|
return free_index;
|
|
}
|
|
|
|
__forceinline void push_front(const T& data) {
|
|
InsertFront(data);
|
|
}
|
|
|
|
__forceinline const T& back() const {
|
|
return m_buffer[LastIndex()].data;
|
|
}
|
|
|
|
__forceinline void pop_back() {
|
|
EraseIndex(LastIndex());
|
|
}
|
|
|
|
__forceinline uint16 size() const {
|
|
return m_free_indexes_stack_top;
|
|
}
|
|
|
|
__forceinline bool empty() const {
|
|
return size() == 0;
|
|
}
|
|
|
|
__forceinline void EraseIndex(const uint16 index) {
|
|
ListRemove(index);
|
|
m_free_indexes_stack[--m_free_indexes_stack_top] = index;
|
|
}
|
|
|
|
__forceinline void MoveFront(const uint16 index) {
|
|
if (FirstIndex() != index) {
|
|
ListRemove(index);
|
|
ListInsertFront(index);
|
|
}
|
|
}
|
|
|
|
__forceinline const FastListIterator<T> begin() const {
|
|
return FastListIterator<T>(this, FirstIndex());
|
|
}
|
|
|
|
__forceinline const FastListIterator<T> end() const {
|
|
return FastListIterator<T>(this, 0);
|
|
}
|
|
|
|
__forceinline FastListIterator<T> erase(FastListIterator<T> i) {
|
|
EraseIndex(i.Index());
|
|
return ++i;
|
|
}
|
|
|
|
private:
|
|
// Accessed by FastListIterator<T> using class friendship
|
|
__forceinline const T& Data(const uint16 index) const {
|
|
return m_buffer[index].data;
|
|
}
|
|
|
|
// Accessed by FastListIterator<T> using class friendship
|
|
__forceinline uint16 NextIndex(const uint16 index) const {
|
|
return m_buffer[index].next_index;
|
|
}
|
|
|
|
// Accessed by FastListIterator<T> using class friendship
|
|
__forceinline uint16 PrevIndex(const uint16 index) const {
|
|
return m_buffer[index].prev_index;
|
|
}
|
|
|
|
__forceinline uint16 FirstIndex() const {
|
|
return m_buffer[0].next_index;
|
|
}
|
|
|
|
__forceinline uint16 LastIndex() const {
|
|
return m_buffer[0].prev_index;
|
|
}
|
|
|
|
__forceinline bool Full() const {
|
|
// The minus one is due to the presence of the auxiliary element
|
|
return size() == m_capacity - 1;
|
|
}
|
|
|
|
__forceinline void ListInsertFront(const uint16 index) {
|
|
// Update prev / next indexes to add m_buffer[index] to the chain
|
|
Element<T>& head = m_buffer[0];
|
|
m_buffer[index].prev_index = 0;
|
|
m_buffer[index].next_index = head.next_index;
|
|
m_buffer[head.next_index].prev_index = index;
|
|
head.next_index = index;
|
|
}
|
|
|
|
__forceinline void ListRemove(const uint16 index) {
|
|
// Update prev / next indexes to remove m_buffer[index] from the chain
|
|
const Element<T>& to_remove = m_buffer[index];
|
|
m_buffer[to_remove.prev_index].next_index = to_remove.next_index;
|
|
m_buffer[to_remove.next_index].prev_index = to_remove.prev_index;
|
|
}
|
|
|
|
void Grow() {
|
|
if (m_capacity == USHRT_MAX) {
|
|
throw std::runtime_error("FastList size maxed out at USHRT_MAX (65535) elements, cannot grow futhermore.");
|
|
}
|
|
|
|
const uint16 new_capacity = m_capacity <= (USHRT_MAX / 2) ? (m_capacity * 2) : USHRT_MAX;
|
|
|
|
Element<T>* new_buffer = (Element<T>*)_aligned_malloc(new_capacity * sizeof(Element<T>) + (new_capacity - 1) * sizeof(uint16), 64);
|
|
uint16* new_free_indexes_stack = (uint16*)&new_buffer[new_capacity];
|
|
|
|
memcpy(new_buffer, m_buffer, m_capacity * sizeof(Element<T>));
|
|
memcpy(new_free_indexes_stack, m_free_indexes_stack, (m_capacity - 1) * sizeof(uint16));
|
|
|
|
_aligned_free(m_buffer);
|
|
|
|
m_buffer = new_buffer;
|
|
m_free_indexes_stack = new_free_indexes_stack;
|
|
|
|
// Initialize the additional space in the stack
|
|
for (uint16 i = m_capacity - 1; i < new_capacity - 1; i++) {
|
|
m_free_indexes_stack[i] = i + 1;
|
|
}
|
|
|
|
m_capacity = new_capacity;
|
|
}
|
|
};
|
|
|
|
|
|
template <class T>
|
|
// This iterator is const_iterator
|
|
class FastListIterator
|
|
{
|
|
private:
|
|
const FastList<T>* m_fastlist;
|
|
uint16 m_index;
|
|
|
|
public:
|
|
__forceinline FastListIterator(const FastList<T>* fastlist, const uint16 index) {
|
|
m_fastlist = fastlist;
|
|
m_index = index;
|
|
}
|
|
|
|
__forceinline bool operator!=(const FastListIterator<T>& other) const {
|
|
return (m_index != other.m_index);
|
|
}
|
|
|
|
__forceinline bool operator==(const FastListIterator<T>& other) const {
|
|
return (m_index == other.m_index);
|
|
}
|
|
|
|
// Prefix increment
|
|
__forceinline const FastListIterator<T>& operator++() {
|
|
m_index = m_fastlist->NextIndex(m_index);
|
|
return *this;
|
|
}
|
|
|
|
// Postfix increment
|
|
__forceinline const FastListIterator<T> operator++(int) {
|
|
FastListIterator<T> copy(*this);
|
|
++(*this);
|
|
return copy;
|
|
}
|
|
|
|
// Prefix decrement
|
|
__forceinline const FastListIterator<T>& operator--() {
|
|
m_index = m_fastlist->PrevIndex(m_index);
|
|
return *this;
|
|
}
|
|
|
|
// Postfix decrement
|
|
__forceinline const FastListIterator<T> operator--(int) {
|
|
FastListIterator<T> copy(*this);
|
|
--(*this);
|
|
return copy;
|
|
}
|
|
|
|
__forceinline const T& operator*() const {
|
|
return m_fastlist->Data(m_index);
|
|
}
|
|
|
|
__forceinline uint16 Index() const {
|
|
return m_index;
|
|
}
|
|
};
|