diff --git a/src/common/heap_array.h b/src/common/heap_array.h index 900611bc2..21d98ff68 100644 --- a/src/common/heap_array.h +++ b/src/common/heap_array.h @@ -1,13 +1,18 @@ -// SPDX-FileCopyrightText: 2019-2022 Connor McLaughlin +// SPDX-FileCopyrightText: 2019-2023 Connor McLaughlin // SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0) #pragma once + +#include "common/assert.h" + #include #include +#include +#include #include template -class HeapArray +class FixedHeapArray { public: using value_type = T; @@ -17,23 +22,23 @@ public: using const_reference = const T&; using pointer = T*; using const_pointer = const T*; - using this_type = HeapArray; + using this_type = FixedHeapArray; - HeapArray() { m_data = new T[SIZE]; } + FixedHeapArray() { m_data = new T[SIZE]; } - HeapArray(const this_type& copy) + FixedHeapArray(const this_type& copy) { m_data = new T[SIZE]; std::copy(copy.cbegin(), copy.cend(), begin()); } - HeapArray(this_type&& move) + FixedHeapArray(this_type&& move) { m_data = move.m_data; move.m_data = nullptr; } - ~HeapArray() { delete[] m_data; } + ~FixedHeapArray() { delete[] m_data; } size_type size() const { return SIZE; } size_type capacity() const { return SIZE; } @@ -104,3 +109,249 @@ public: private: T* m_data; }; + +template +class DynamicHeapArray +{ + static_assert(std::is_trivially_copyable_v, "T is trivially copyable"); + static_assert(std::is_standard_layout_v, "T is standard layout"); + +public: + using value_type = T; + using size_type = std::size_t; + using difference_type = std::ptrdiff_t; + using reference = T&; + using const_reference = const T&; + using pointer = T*; + using const_pointer = const T*; + using this_type = DynamicHeapArray; + + DynamicHeapArray() : m_data(nullptr), m_size(0) {} + DynamicHeapArray(size_t size) { internal_resize(size, nullptr, 0); } + DynamicHeapArray(const T* begin, const T* end) + { + const size_t size = reinterpret_cast(end) - reinterpret_cast(begin); + if (size > 0) + { + internal_resize(size / sizeof(T), nullptr, 0); + std::memcpy(m_data, begin, size); + } + else + { + m_data = nullptr; + m_size = 0; + } + } + DynamicHeapArray(const T* begin, size_t count) + { + if (count > 0) + { + internal_resize(count, nullptr, 0); + std::memcpy(m_data, begin, sizeof(T) * count); + } + else + { + m_data = nullptr; + m_size = 0; + } + } + + DynamicHeapArray(const this_type& copy) + { + if (copy.m_size > 0) + { + internal_resize(copy.m_size, nullptr, 0); + std::memcpy(m_data, copy.m_data, sizeof(T) * copy.m_size); + } + else + { + m_data = nullptr; + m_size = 0; + } + } + + DynamicHeapArray(this_type&& move) + { + m_data = move.m_data; + m_size = move.m_size; + move.m_data = nullptr; + move.m_size = 0; + } + + ~DynamicHeapArray() { internal_deallocate(); } + + size_type size() const { return m_size; } + size_type capacity() const { return m_size; } + bool empty() const { return (m_size == 0); } + + pointer begin() { return m_data; } + pointer end() { return m_data + m_size; } + + const_pointer data() const { return m_data; } + pointer data() { return m_data; } + + const_pointer cbegin() const { return m_data; } + const_pointer cend() const { return m_data + m_size; } + + const_reference operator[](size_type index) const + { + assert(index < m_size); + return m_data[index]; + } + reference operator[](size_type index) + { + assert(index < m_size); + return m_data[index]; + } + + const_reference front() const { return m_data[0]; } + const_reference back() const { return m_data[m_size - 1]; } + reference front() { return m_data[0]; } + reference back() { return m_data[m_size - 1]; } + + void fill(const_reference value) { std::fill(begin(), end(), value); } + + void swap(this_type& move) { std::swap(m_data, move.m_data); } + + void resize(size_t new_size) { internal_resize(new_size, m_data, m_size); } + + void deallocate() + { + internal_deallocate(); + m_data = nullptr; + m_size = 0; + } + + void assign(const T* begin, const T* end) + { + const size_t size = reinterpret_cast(end) - reinterpret_cast(begin); + const size_t count = size / sizeof(T); + if (count > 0) + { + if (m_size != count) + { + internal_deallocate(); + internal_resize(count, nullptr, 0); + } + + std::memcpy(m_data, begin, size); + } + else + { + internal_deallocate(); + + m_data = nullptr; + m_size = 0; + } + } + void assign(const T* begin, size_t count) + { + if (count > 0) + { + if (m_size != count) + { + internal_deallocate(); + internal_resize(count, nullptr, 0); + } + + std::memcpy(m_data, begin, sizeof(T) * count); + } + else + { + internal_deallocate(); + + m_data = nullptr; + m_size = 0; + } + } + void assign(const this_type& copy) { assign(copy.m_data, copy.m_size); } + void assign(this_type&& move) + { + internal_deallocate(); + m_data = move.m_data; + m_size = move.m_size; + move.m_data = nullptr; + move.m_size = 0; + } + + this_type& operator=(const this_type& rhs) + { + assign(rhs); + return *this; + } + + this_type& operator=(this_type&& move) + { + assign(std::move(move)); + return *this; + } + +#define RELATIONAL_OPERATOR(op, size_op) \ + bool operator op(const this_type& rhs) const \ + { \ + if (m_size != rhs.m_size) \ + return m_size size_op rhs.m_size; \ + for (size_type i = 0; i < m_size; i++) \ + { \ + if (!(m_data[i] op rhs.m_data[i])) \ + return false; \ + } \ + } + + RELATIONAL_OPERATOR(==, !=); + RELATIONAL_OPERATOR(!=, ==); + RELATIONAL_OPERATOR(<, <); + RELATIONAL_OPERATOR(<=, <=); + RELATIONAL_OPERATOR(>, >); + RELATIONAL_OPERATOR(>=, >=); + +#undef RELATIONAL_OPERATOR + +private: + void internal_resize(size_t size, T* prev_ptr, size_t prev_size) + { + if constexpr (alignment > 0) + { +#ifdef _MSC_VER + m_data = _aligned_realloc(prev_ptr, size, alignment); + if (!m_data) + Panic("Memory allocation failed."); +#else + if (posix_memalign(reinterpret_cast(&m_data), alignment, size) != 0) + Panic("Memory allocation failed."); + + if (prev_ptr) + { + std::memcpy(m_data, prev_ptr, prev_size); + std::free(prev_ptr); + } +#endif + } + else + { + m_data = static_cast(std::realloc(prev_ptr, size)); + if (!m_data) + Panic("Memory allocation failed."); + } + + m_size = size; + } + void internal_deallocate() + { + if constexpr (alignment > 0) + { +#ifdef _MSC_VER + _aligned_free(m_data); +#else + std::free(m_data); +#endif + } + else + { + std::free(m_data); + } + } + + T* m_data; + size_t m_size; +}; diff --git a/src/core/cdrom.cpp b/src/core/cdrom.cpp index b924082e3..2ce94d20a 100644 --- a/src/core/cdrom.cpp +++ b/src/core/cdrom.cpp @@ -351,7 +351,7 @@ static HeapFIFOQueue s_data_fifo; struct SectorBuffer { - HeapArray data; + FixedHeapArray data; u32 size; }; diff --git a/src/core/gpu.cpp b/src/core/gpu.cpp index 1b4f8c67c..305207fc6 100644 --- a/src/core/gpu.cpp +++ b/src/core/gpu.cpp @@ -269,7 +269,7 @@ bool GPU::DoState(StateWrapper& sw, GPUTexture** host_texture, bool update_displ if (sw.IsReading()) { // Still need a temporary here. - HeapArray temp; + FixedHeapArray temp; sw.DoBytes(temp.data(), VRAM_WIDTH * VRAM_HEIGHT * sizeof(u16)); UpdateVRAM(0, 0, VRAM_WIDTH, VRAM_HEIGHT, temp.data(), false, false); } diff --git a/src/core/gpu_backend.h b/src/core/gpu_backend.h index a1a573da2..f34f0e0b9 100644 --- a/src/core/gpu_backend.h +++ b/src/core/gpu_backend.h @@ -85,7 +85,7 @@ protected: THRESHOLD_TO_WAKE_GPU = 256 }; - HeapArray m_command_fifo_data; + FixedHeapArray m_command_fifo_data; alignas(64) std::atomic m_command_fifo_read_ptr{0}; alignas(64) std::atomic m_command_fifo_write_ptr{0}; }; diff --git a/src/core/gpu_hw.h b/src/core/gpu_hw.h index bb352a5d3..f0392ffde 100644 --- a/src/core/gpu_hw.h +++ b/src/core/gpu_hw.h @@ -355,7 +355,7 @@ protected: SmoothingUBOData GetSmoothingUBO(u32 level, u32 left, u32 top, u32 width, u32 height, u32 tex_width, u32 tex_height) const; - HeapArray m_vram_shadow; + FixedHeapArray m_vram_shadow; std::unique_ptr m_sw_renderer; BatchVertex* m_batch_start_vertex_ptr = nullptr; diff --git a/src/core/gpu_sw.h b/src/core/gpu_sw.h index 83d3dccad..d3ddf6b61 100644 --- a/src/core/gpu_sw.h +++ b/src/core/gpu_sw.h @@ -60,7 +60,7 @@ protected: GPUTexture* GetDisplayTexture(u32 width, u32 height, GPUTexture::Format format); - HeapArray m_display_texture_buffer; + FixedHeapArray m_display_texture_buffer; GPUTexture::Format m_16bit_display_format = GPUTexture::Format::RGB565; GPUTexture::Format m_24bit_display_format = GPUTexture::Format::RGBA8; std::unique_ptr m_display_texture; diff --git a/src/util/state_wrapper.h b/src/util/state_wrapper.h index d9ec78058..6c2b1eb55 100644 --- a/src/util/state_wrapper.h +++ b/src/util/state_wrapper.h @@ -117,7 +117,7 @@ public: } template - void Do(HeapArray* data) + void Do(FixedHeapArray* data) { DoArray(data->data(), data->size()); }