Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 10 additions & 4 deletions Source/AliveLibAE/Psx.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#include "PsxRender.hpp"
#include "Renderer/IRenderer.hpp"
#include <gmock/gmock.h>
#include <thread>

void Psx_ForceLink()
{ }
Expand Down Expand Up @@ -891,16 +892,21 @@ EXPORT s32 CC PSX_VSync_4F6170(s32 mode)
s32 frameTimeInMilliseconds = currentTime - sVSyncLastMillisecond_BD0F2C;
if (mode > 0 && frameTimeInMilliseconds < 1000 * mode / 60)
{
s32 timeSinceLastFrame = 0;
sVSync_Unused_578325 = 1;

do
auto current = SYS_GetTime();
const auto max_time = current + std::chrono::milliseconds(1000 * mode / 60);

while (SsSeqCalledTbyT_4FDC80_sleep_until_due_time_if_before_max_time(current, max_time))
{
timeSinceLastFrame = SYS_GetTicks() - sVSyncLastMillisecond_BD0F2C;
SsSeqCalledTbyT_4FDC80();
current = SYS_GetTime();
}
while (timeSinceLastFrame < 1000 * mode / 60);

if (current < max_time)
{
std::this_thread::sleep_until(max_time);
}
frameTimeInMilliseconds = 1000 * mode / 60;
}

Expand Down
39 changes: 36 additions & 3 deletions Source/AliveLibAE/Sound/PsxSpuApi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include "PathData.hpp" // SoundBlockInfo, SeqPathDataRecord
#include "../AliveLibAE/Io.hpp"
#include <assert.h>
#include <thread>

struct VagAtr final
{
Expand Down Expand Up @@ -1346,19 +1347,51 @@ EXPORT void CC SsSetTickMode_4FDC20(s32)
// Stub
}

// TODO: Removed 4FDC30
EXPORT bool CC SsSeqCalledTbyT_4FDC80_sleep_until_due_time_if_before_max_time(SYS_time_point_t current_time, SYS_time_point_t max_time)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

_4FDC80 needs to be at the end of the function as exported function names are parsed at runtime for installing hooks into the game when running as a DLL. This name is super verbose too, I would have just left it as SsSeqCalledTbyT_4FDC80 tbh since the waiting/sleeping is an implementation detail.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I meant to avoid breaking existing SsSeqCalledTbyT_4FDC80 ABI with "max_time" new argument.
(because I understood that number-suffixed functions are meant to be interchangeable with original binaries)
Unless I miss something, I thus can simplify the name but not use the original one.

{
if (!gSpuVars->sbDisableSeqs())
{
const auto lastTime = gSpuVars->sLastTime();
if (lastTime == 0xFFFFFFFF)
{
return true;
}
else
{
const auto nextDueTime = lastTime + 30;

if ((s32) (SYS_AsU32Ms(max_time) - nextDueTime) < 0)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use static_cast instead of a C cast

{
// we won't make it in time, skip
return false;
}

const auto timeToWait = (s32) (nextDueTime - SYS_AsU32Ms(current_time));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use static_cast instead of a C cast

if (timeToWait <= 0)
{
// we're late or right on time, hurry!
return true;
}

std::this_thread::sleep_for(std::chrono::milliseconds{timeToWait});
return true;
}
}
return false;
}

// TODO: Removed 4FDC30
EXPORT void CC SsSeqCalledTbyT_4FDC80()
{
if (!gSpuVars->sbDisableSeqs())
{
const u32 currentTime = SYS_GetTicks();
gSpuVars->sMidiTime() = currentTime;
// First time or 30 passed?
if (gSpuVars->sLastTime() == 0xFFFFFFFF || (s32)(currentTime - gSpuVars->sLastTime()) >= 30)
auto& lastTime = gSpuVars->sLastTime();
if (lastTime == 0xFFFFFFFF || (s32) (currentTime - lastTime) >= 30)
{
gSpuVars->sLastTime() = currentTime;
lastTime = currentTime;
for (s32 i = 0; i < kNumChannels; i++)
{
if (gSpuVars->sMidiSeqSongs(i).field_0_seq_data)
Expand Down
7 changes: 7 additions & 0 deletions Source/AliveLibAE/Sound/PsxSpuApi.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include "../AliveLibCommon/FunctionFwd.hpp"
#include "Sound/Sound.hpp"
#include "Io.hpp"
#include "Sys_common.hpp"

struct ProgAtr final
{
Expand Down Expand Up @@ -239,6 +240,12 @@ EXPORT void CC VSyncCallback_4F8C40(TVSyncCallBackFn callBack);
EXPORT void CC SND_CallBack_4020A4(); // TODO: Naming??
EXPORT void CC SsSeqCalledTbyT_4FDC80();

// returns
// true, after having slept for the correct duration, if SsSeqCalledTbyT_4FDC80 must be called
// false if time to wait would have gone over max_time
// Note that this does *not* call SsSeqCalledTbyT_4FDC80
EXPORT bool CC SsSeqCalledTbyT_4FDC80_sleep_until_due_time_if_before_max_time(SYS_time_point_t current_time, SYS_time_point_t max_time);

// Most likely PC specific extensions that have been inlined
void SsExt_CloseAllVabs();

Expand Down
16 changes: 16 additions & 0 deletions Source/AliveLibAE/Sound/SDLSoundSystem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,11 @@ HRESULT SDLSoundSystem::Release()

// Stop audio rendering thread
mRenderAudioThreadQuit = true;
{
std::lock_guard g{mAudioRingBufferMutex};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

instead of 'g' can we at least called it 'lock' or something

mAudioRingBufferConditionVariable.notify_one();
}

if (mRenderAudioThread && mRenderAudioThread->joinable())
{
mRenderAudioThread->join();
Expand Down Expand Up @@ -139,6 +144,11 @@ void SDLSoundSystem::AudioCallBack(Uint8* stream, s32 len)
{
LOG_ERROR("Ring buffer read failure!");
}

{
std::lock_guard g{mAudioRingBufferMutex};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ditto for naming

mAudioRingBufferConditionVariable.notify_one();
}
}


Expand All @@ -159,6 +169,12 @@ void SDLSoundSystem::RenderAudioThread()
LOG_ERROR("Ring buffer write failed");
}
}
else
{
std::unique_lock g{mAudioRingBufferMutex};
mAudioRingBufferConditionVariable.wait(g, [&]
{ return mRenderAudioThreadQuit || mAudioRingBuffer.getAvailableWrite() > 0; });
}
}
LOG_INFO("Quit");
}
Expand Down
7 changes: 7 additions & 0 deletions Source/AliveLibAE/Sound/SDLSoundSystem.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
#include "Sound.hpp"
#include "SoundSDL.hpp"
#include <thread>
#include <condition_variable>
#include <mutex>

#define CI_DISABLE_ASSERTS
#include <cinder/audio/dsp/RingBuffer.h>
Expand Down Expand Up @@ -53,6 +55,11 @@ class SDLSoundSystem final
std::vector<StereoSample_S16> mTempSoundBuffer;
std::vector<StereoSample_S16> mNoReverbBuffer;
cinder::audio::dsp::RingBufferT<StereoSample_S16> mAudioRingBuffer;

// to avoid busy loop
std::mutex mAudioRingBufferMutex;
std::condition_variable mAudioRingBufferConditionVariable;

std::atomic_bool mRenderAudioThreadQuit{false};
std::unique_ptr<std::thread> mRenderAudioThread;

Expand Down
9 changes: 5 additions & 4 deletions Source/AliveLibAO/Movie.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -444,7 +444,7 @@ void Movie::VUpdate_489EA0()
Bitmap tmpBmp = {};

// Till EOF decoding loop
const auto movieStartTimeStamp = SYS_GetTicks();
const auto movieStartTimeStamp = SYS_GetTime();
while (psxStr.DecodeAudioAndVideo())
{
fmv_num_read_frames++;
Expand Down Expand Up @@ -492,11 +492,12 @@ void Movie::VUpdate_489EA0()

Render_Str_Frame(tmpBmp);

const int maxAudioSyncTimeWait = 1000 * fmv_num_read_frames / kFmvFrameRate - 200;

while ((signed int) (SYS_GetTicks() - movieStartTimeStamp) <= maxAudioSyncTimeWait)
const auto maxAudioSyncTimeWait = std::chrono::milliseconds{1000 * fmv_num_read_frames / kFmvFrameRate - 200};
const auto timeToWait = maxAudioSyncTimeWait - (SYS_GetTime() - movieStartTimeStamp);
if (timeToWait.count() > 0)
{
// Wait for the amount of time the frame would take to display at the given framerate
std::this_thread::sleep_for(timeToWait);
}

SYS_EventsPump_44FF90();
Expand Down
17 changes: 10 additions & 7 deletions Source/AliveLibCommon/Sys_common.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,19 @@
abort();
}

SYS_time_point_t SYS_GetTime()
{
return std::chrono::steady_clock::now();
}

u32 SYS_AsU32Ms(SYS_time_point_t t)
{
return (u32) std::chrono::duration_cast<std::chrono::milliseconds>(t.time_since_epoch()).count();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

static_cast instead of C cast

}

u32 SYS_GetTicks()
{
#if USE_SDL2
// Using this instead of SDL_GetTicks resolves a weird x64 issue on windows where
// the tick returned is a lot faster on some machines.
return static_cast<u32>(SDL_GetPerformanceCounter() / (SDL_GetPerformanceFrequency() / 1000));
#else
return timeGetTime();
#endif
return SYS_AsU32Ms(SYS_GetTime());
}

MessageBoxButton CC Sys_MessageBox(TWindowHandleType windowHandle, const char_type* message, const char_type* title, MessageBoxType type)
Expand Down
4 changes: 4 additions & 0 deletions Source/AliveLibCommon/Sys_common.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

#include "../AliveLibCommon/FunctionFwd.hpp"
#include "relive_config.h"
#include <chrono>

#if _WIN32
using TWindowProcFilter = LRESULT(CC*)(HWND, UINT, WPARAM, LPARAM);
Expand Down Expand Up @@ -77,4 +78,7 @@ inline void Alive_Show_ErrorMsg(const char_type* msg)

[[noreturn]] void ALIVE_FATAL(const char_type* errMsg);

using SYS_time_point_t = std::chrono::steady_clock::time_point;
SYS_time_point_t SYS_GetTime();
u32 SYS_AsU32Ms(SYS_time_point_t);
u32 SYS_GetTicks();