mirror of
https://github.com/FelipePrado0/SpartanPort.git
synced 2026-11-07 10:45:59 -10:00
EN-US - Fixed texture cache image references moving when the cache grows, out-of-range slot IDs, per-dimension extent checks, view clamping, padding-only overlaps and in-flight sampler destruction - Fixed depth and colour buffer copies to copy every shared mip and layer - Fixed scheduler null chunks at 0x20000, exit 23 from oversized recording data and stale idle signals releasing new submissions - Fixed IRQ heap corruption at startup and saved packet sizes before running packets - Fixed shader cache loss: queued writes drained at exit, partial loads rejected, damaged records skipped - Fixed draws whose pipelines the driver refuses, speculative specialization exceptions and null user-data tables at area loads - Updated texture pressure to start at 60% of the budget on cards below 8 GB, unblocked evictions behind retained images and kept GPU-only images below the critical mark - Added tests for the slot vector, subresource extents, IRQ controller, record data, cache storage, cache flush, serdes and shader user data --- PT-BR - Corrigidos no cache de texturas: referências de imagem que mudavam de lugar quando o cache crescia, IDs de slot fora do intervalo, checagem de tamanho por dimensão, recorte de views, sobreposição só de padding e destruição de samplers em uso - Corrigidas as cópias de buffers de depth e color para copiar todos os mips e layers compartilhados - Corrigidos no scheduler: chunks nulos em 0x20000, exit 23 com dados de gravação grandes demais e sinais de ocioso antigos liberando submissões novas - Corrigida a corrupção do heap de IRQ na inicialização, e o tamanho dos pacotes passou a ser salvo antes de executá-los - Corrigida a perda do cache de shaders: gravações na fila esvaziadas ao sair, cargas parciais rejeitadas e registros danificados pulados - Corrigidos os draws com pipeline recusado pelo driver, as exceções de especialização especulativa e as tabelas de user data nulas na troca de área - Atualizada a pressão de texturas para começar em 60% do orçamento em placas com menos de 8 GB, desbloqueadas as remoções atrás de imagens retidas e mantidas as imagens só da GPU abaixo da marca crítica - Adicionados testes de slot vector, subresource extents, controlador de IRQ, record data, cache storage, flush do cache, serdes e shader user data
168 lines
4.1 KiB
C++
168 lines
4.1 KiB
C++
// SPDX-FileCopyrightText: Copyright 2025-2026 shadPS4 Emulator Project
|
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
|
|
#pragma once
|
|
|
|
#include "common/assert.h"
|
|
#include "common/types.h"
|
|
|
|
#include <cstddef>
|
|
// spartanport: report damaged cache records through recoverable exceptions.
|
|
#include <stdexcept>
|
|
#include <vector>
|
|
|
|
namespace Serialization {
|
|
|
|
// spartanport: let cache loaders skip damaged records instead of stopping startup.
|
|
struct CorruptData : std::runtime_error {
|
|
CorruptData()
|
|
: std::runtime_error{"Invalid or corrupted deserialization container/shader cache"} {}
|
|
};
|
|
|
|
template <typename T>
|
|
concept Container = requires(T t) {
|
|
typename T::iterator;
|
|
{ t.begin() } -> std::same_as<typename T::iterator>;
|
|
{ t.end() } -> std::same_as<typename T::iterator>;
|
|
{ t.size() } -> std::convertible_to<std::size_t>;
|
|
};
|
|
|
|
struct Archive {
|
|
void Alloc(size_t size) {
|
|
container.resize(size);
|
|
}
|
|
|
|
void Grow(size_t size) {
|
|
container.resize(container.size() + size);
|
|
}
|
|
|
|
void Merge(const Archive& ar) {
|
|
container.insert(container.end(), ar.container.cbegin(), ar.container.cend());
|
|
offset = container.size();
|
|
}
|
|
|
|
[[nodiscard]] size_t SizeBytes() const {
|
|
return container.size();
|
|
}
|
|
|
|
u8* CurrPtr() {
|
|
return container.data() + offset;
|
|
}
|
|
|
|
// spartanport: check against remaining bytes without overflowing offset + size.
|
|
[[nodiscard]] size_t Remaining() const {
|
|
return container.size() - offset;
|
|
}
|
|
|
|
void Advance(size_t size) {
|
|
if (size > Remaining()) {
|
|
throw CorruptData{};
|
|
}
|
|
offset += size;
|
|
}
|
|
|
|
std::vector<u8>&& TakeOff() {
|
|
offset = 0;
|
|
return std::move(container);
|
|
}
|
|
|
|
[[nodiscard]] bool IsEoS() const {
|
|
return offset >= container.size();
|
|
}
|
|
|
|
Archive() = default;
|
|
explicit Archive(std::vector<u8>&& v) : container{v} {}
|
|
|
|
private:
|
|
u32 offset{};
|
|
std::vector<u8> container{};
|
|
|
|
friend struct Writer;
|
|
friend struct Reader;
|
|
};
|
|
|
|
struct Writer {
|
|
template <typename T>
|
|
void Write(const T* ptr, size_t size) {
|
|
if (ar.offset + size >= ar.container.size()) {
|
|
ar.Grow(size);
|
|
}
|
|
std::memcpy(ar.CurrPtr(), reinterpret_cast<const void*>(ptr), size);
|
|
ar.Advance(size);
|
|
}
|
|
|
|
template <typename T>
|
|
requires(!Container<T>)
|
|
void Write(const T& value) {
|
|
const auto size = sizeof(value);
|
|
Write(&value, size);
|
|
}
|
|
|
|
void Write(const auto& v) {
|
|
Write(v.size());
|
|
for (const auto& elem : v) {
|
|
Write(elem);
|
|
}
|
|
}
|
|
|
|
void Write(const std::string& s) {
|
|
Write(s.size());
|
|
Write(s.c_str(), s.size());
|
|
}
|
|
|
|
Writer() = delete;
|
|
explicit Writer(Archive& ar_) : ar{ar_} {}
|
|
|
|
Archive& ar;
|
|
};
|
|
|
|
struct Reader {
|
|
template <typename T>
|
|
void Read(T* ptr, size_t size) {
|
|
// spartanport: reject truncated records before copying from them.
|
|
if (size > ar.Remaining()) {
|
|
throw CorruptData{};
|
|
}
|
|
std::memcpy(reinterpret_cast<void*>(ptr), ar.CurrPtr(), size);
|
|
ar.Advance(size);
|
|
}
|
|
|
|
template <typename T>
|
|
requires(!Container<T>)
|
|
void Read(T& value) {
|
|
const auto size = sizeof(value);
|
|
Read(&value, size);
|
|
}
|
|
|
|
void Read(auto& v) {
|
|
size_t num_elements{};
|
|
Read(num_elements);
|
|
// spartanport: every element needs a byte; reject corrupt counts before allocating.
|
|
if (num_elements > ar.Remaining()) {
|
|
throw CorruptData{};
|
|
}
|
|
for (size_t i = 0; i < num_elements; ++i) {
|
|
v.emplace_back();
|
|
Read(v.back());
|
|
}
|
|
}
|
|
|
|
void Read(std::string& s) {
|
|
size_t length{};
|
|
Read(length);
|
|
// spartanport: reject corrupt string lengths before resizing the destination.
|
|
if (length > ar.Remaining()) {
|
|
throw CorruptData{};
|
|
}
|
|
s.resize(length);
|
|
Read(s.data(), length);
|
|
}
|
|
|
|
Reader() = delete;
|
|
explicit Reader(Archive& ar_) : ar{ar_} {}
|
|
|
|
Archive& ar;
|
|
};
|
|
|
|
} // namespace Serialization
|