Implement save state support, with backwards compatibility.

This commit is contained in:
Henrik Rydgård committed 2025-03-18 09:36:33 +01:00
1 parent 89a73be155
commit 6d7625ea6b
5 files changed
+68 -23

No files matched your search

+3 -1
View File
@@ -229,7 +229,7 @@ public:
virtual int GetSoundSample(int *endSample, int *loopStartSample, int *loopEndSample) const = 0;
virtual bool IsNewAtracImpl() const { return false; }
virtual int GetContextVersion() const = 0;
protected:
u16 outputChannels_ = 2;
@@ -325,6 +325,8 @@ public:
void UpdateContextFromPSPMem() override;
void WriteContextToPSPMem();
int GetContextVersion() const override { return 1; }
private:
void UpdateBufferState();
void ResetData();
+28 -8
View File
@@ -1,4 +1,7 @@
#include <algorithm>
#include "Common/Serialize/Serializer.h"
#include "Common/Serialize/SerializeFuncs.h"
#include "Common/Log.h"
#include "Core/MemMapHelpers.h"
#include "Core/HLE/HLE.h"
@@ -162,15 +165,32 @@ int Atrac2::RemainingFrames() const {
}
Atrac2::Atrac2(u32 contextAddr, int codecType) {
context_ = PSPPointer<SceAtracContext>::Create(contextAddr);
SceAtracIdInfo &info = context_->info;
info.codec = codecType;
info.state = ATRAC_STATUS_NO_DATA;
info.curBuffer = 0;
if (contextAddr) {
context_ = PSPPointer<SceAtracContext>::Create(contextAddr);
// First-time initialization.
SceAtracIdInfo &info = context_->info;
info.codec = codecType;
info.state = ATRAC_STATUS_NO_DATA;
info.curBuffer = 0;
} else {
// We're loading state, we'll restore the context in DoState.
}
}
void Atrac2::DoState(PointerWrap &p) {
_assert_msg_(false, "Savestates not yet support with new Atrac implementation.\n\nTurn it off in Developer settings.\n\n");
auto s = p.Section("Atrac2", 1, 1);
if (!s)
return;
Do(p, outputChannels_);
// The only thing we need to save now is the outputChannels_ and the context pointer. And technically, not even that since
// it can be computed. Still, for future proofing, let's save it.
Do(p, context_);
const SceAtracIdInfo &info = context_->info;
if (p.mode == p.MODE_READ && info.state != ATRAC_STATUS_NO_DATA) {
CreateDecoder(info.codec, info.sampleSize, info.numChan);
}
}
bool Atrac2::HasSecondBuffer() const {
@@ -299,7 +319,7 @@ int Atrac2::GetResetBufferInfo(AtracResetBufferInfo *bufferInfo, int seekPos, bo
seekPos += info.firstValidSample;
if ((u32)seekPos > info.endSample) {
if ((u32)seekPos > (u32)info.endSample) {
return SCE_ERROR_ATRAC_BAD_SAMPLE;
}
@@ -935,7 +955,7 @@ int Atrac2::SetSecondBuffer(u32 secondBuffer, u32 secondBufferSize) {
u32 loopEndFileOffset = ComputeLoopEndFileOffset(info, info.loopEnd);
if ((info.sampleSize * 3 <= (int)secondBufferSize ||
(info.fileDataEnd - loopEndFileOffset) <= (int)secondBufferSize)) {
if (info.state == 6) {
if (info.state == ATRAC_STATUS_STREAMED_LOOP_WITH_TRAILER) {
info.secondBuffer = secondBuffer;
info.secondBufferByte = secondBufferSize;
info.secondStreamOff = 0;
+3 -2
View File
@@ -6,7 +6,8 @@
class Atrac2 : public AtracBase {
public:
Atrac2(u32 contextAddr, int codecType);
// The default values are only used during save state load, in which case they get restored by DoState.
Atrac2(u32 contextAddr = 0, int codecType = 0);
~Atrac2() {
delete[] decodeTemp_;
}
@@ -51,7 +52,7 @@ public:
void UpdateContextFromPSPMem() override {}
void NotifyGetContextAddress() override {}
bool IsNewAtracImpl() const override { return true; }
int GetContextVersion() const override { return 2; }
u32 GetInternalCodecError() const override;
+32 -10
View File
@@ -152,30 +152,54 @@ static u32 GetAtracContextAddress(int atracID) {
}
void __AtracDoState(PointerWrap &p) {
auto s = p.Section("sceAtrac", 1, 2);
auto s = p.Section("sceAtrac", 1, 4);
if (!s)
return;
Do(p, atracInited);
if (s >= 4) {
Do(p, g_atracBSS);
Do(p, g_atracMaxContexts);
if (g_atracMaxContexts > PSP_MAX_ATRAC_IDS) // paranoia
g_atracMaxContexts = PSP_MAX_ATRAC_IDS;
} else {
g_atracBSS = 0;
g_atracMaxContexts = 6;
}
for (int i = 0; i < PSP_MAX_ATRAC_IDS; ++i) {
bool valid = atracContexts[i] != nullptr;
Do(p, valid);
if (valid) {
DoSubClass<AtracBase, Atrac>(p, atracContexts[i], i);
int version = atracContexts[i] ? atracContexts[i]->GetContextVersion() : 0;
if (s >= 4) {
Do(p, version);
_dbg_assert_(version != 0);
} else {
// Old versions only support old contexts.
version = 1;
}
switch (version) {
case 1:
DoSubClass<AtracBase, Atrac>(p, atracContexts[i], i);
break;
case 2:
DoSubClass<AtracBase, Atrac2>(p, atracContexts[i]);
break;
}
} else {
delete atracContexts[i];
atracContexts[i] = nullptr;
}
}
DoArray(p, atracContextTypes, PSP_MAX_ATRAC_IDS);
if (s < 2) {
atracLibVersion = 0;
atracLibCrc = 0;
}
else {
if (s >= 2) {
Do(p, atracLibVersion);
Do(p, atracLibCrc);
}
else {
atracLibVersion = 0;
atracLibCrc = 0;
}
}
static AtracBase *getAtrac(int atracID) {
@@ -192,9 +216,7 @@ static AtracBase *getAtrac(int atracID) {
static int AllocAndRegisterAtrac(int codecType) {
for (int i = 0; i < g_atracMaxContexts; ++i) {
if (atracContextTypes[i] == codecType && atracContexts[i] == 0) {
if (g_Config.bUseExperimentalAtrac) {
// Note: This assert isn't really valid until we savestate the new contexts.
_dbg_assert_(g_atracBSS != 0);
if (g_Config.bUseExperimentalAtrac && g_atracBSS != 0) {
atracContexts[i] = new Atrac2(GetAtracContextAddress(i), codecType);
} else {
atracContexts[i] = new Atrac(i, codecType);
+2 -2
View File
@@ -1006,7 +1006,7 @@ void DrawAudioDecodersView(ImConfig &cfg, ImControl &control) {
ImGui::TableNextColumn();
ImGui::Text("%d", ctx->RemainingFrames());
ImGui::TableNextColumn();
ImGui::TextUnformatted(ctx->IsNewAtracImpl() ? "NewImpl" : "Legacy");
ImGui::TextUnformatted(ctx->GetContextVersion() >= 2 ? "NewImpl" : "Legacy");
}
ImGui::EndTable();
@@ -1031,7 +1031,7 @@ void DrawAudioDecodersView(ImConfig &cfg, ImControl &control) {
ImGui::SameLine();
ImClickableValue("ctx", ctx->context_.ptr, control, ImCmd::SHOW_IN_MEMORY_VIEWER);
}
if (ctx->context_.IsValid() && ctx->IsNewAtracImpl()) {
if (ctx->context_.IsValid() && ctx->GetContextVersion() >= 2) {
const auto &info = ctx->context_->info;
ImGui::Text("Buffer: (size: %d / %08x) Frame: %d", info.bufferByte, info.bufferByte, info.sampleSize);
ImGui::SameLine();