Files
SpartanPort/gpu/shadps4/common/serdes.h
T
Mahdi Akbari Zarkesh c22329f13b Fix(GPU): ported texture, GPU and shader cache fixes (#1124)
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
2026-11-01 21:31:31 -03:00

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