Skip to content

Commit

Permalink
1.5.81 release
Browse files Browse the repository at this point in the history
* Imagine: Rework RingBuffer indexing fixing freeSpace() check causing issues in Saturn.emu VDP2 code
* Imagine: Add RingBufferRWFlags allowing blocking mode selection per read/write call
* Imagine: Fix RingBuffer::reset() causing a crash in EmuAudio code due to the capacity not being reset after pointer reset
* EmuFramework: Only send DocumentPickerEvent to top view when not showing emulation
* Saturn.emu: Simplify VDP2 work queue and eliminate DrawCounter variable
  • Loading branch information
Robert Broglia committed Apr 13, 2024
1 parent 9f4e373 commit 12f8a0c
Show file tree
Hide file tree
Showing 7 changed files with 68 additions and 64 deletions.
2 changes: 1 addition & 1 deletion EmuFramework/metadata/conf.mk
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
metadata_version = 1.5.80
metadata_version = 1.5.81
metadata_supportedMIMETypes = application/zip
metadata_supportedFileExtensions = rar 7z
android_metadata_versionCodeExtra = 16
Expand Down
2 changes: 1 addition & 1 deletion EmuFramework/src/EmuApp.cc
Original file line number Diff line number Diff line change
Expand Up @@ -541,7 +541,7 @@ void EmuApp::mainInitCommon(IG::ApplicationInitParams initParams, IG::Applicatio
[&](DocumentPickerEvent& e)
{
log.info("document picked with URI:{}", e.uri);
if(viewController().top().onDocumentPicked(e))
if(!viewController().isShowingEmulation() && viewController().top().onDocumentPicked(e))
return;
handleOpenFileCommand(e.uri);
},
Expand Down
38 changes: 8 additions & 30 deletions Saturn.emu/src/ss/vdp2_render.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3211,32 +3211,11 @@ struct WQ_Entry
uint32 Arg32;
};

static IG::RingBuffer<WQ_Entry, IG::RingBufferConf{.fixedSize = 0x2000}> WQ;
static std::atomic_int_least32_t DrawCounter;

template<class T>
static void atomicWait(const std::atomic<T> &val, T oldVal)
{
if(MDFN_UNLIKELY(val.load(std::memory_order_acquire) == oldVal))
{
//fprintf(stderr, "waiting for change from:%d\n", oldVal);
val.wait(oldVal, std::memory_order_acquire);
}
}

template<class T>
static void atomicWaitForValue(const std::atomic<T> &val, T wantedVal)
{
for(auto c = val.load(std::memory_order_acquire); c != wantedVal; c = val.load(std::memory_order_acquire))
{
//fprintf(stderr, "waiting for value\n");
val.wait(c, std::memory_order_acquire);
}
}
static IG::RingBuffer<WQ_Entry, IG::RingBufferConf{.fixedSize = 0x4000}> WQ;

static INLINE void WWQ(uint16 command, uint32 arg32 = 0, uint16 arg16 = 0)
{
WQ.push({command, arg16, arg32});
WQ.push({command, arg16, arg32}, IG::RingBufferRWFlags{.blocking = true, .notifyOnBlock = true});
}

static int RThreadEntry(void* data)
Expand All @@ -3246,9 +3225,8 @@ static int RThreadEntry(void* data)

while(MDFN_LIKELY(Running))
{
WQ_Entry entry = WQ.pop();
WQ_Entry entry = WQ.pop(IG::RingBufferRWFlags{.blocking = true});
WQ_Entry* wqe = &entry;
WQ.notifyRead();

switch(wqe->Command)
{
Expand All @@ -3264,8 +3242,6 @@ static int RThreadEntry(void* data)
//for(unsigned i = 0; i < 2; i++)
DrawLine((uint16)wqe->Arg32, wqe->Arg32 >> 16, wqe->Arg16);
//
DrawCounter.fetch_sub(1, std::memory_order_release);
DrawCounter.notify_all();
break;

case COMMAND_RESET:
Expand All @@ -3283,6 +3259,8 @@ static int RThreadEntry(void* data)
//
//
//

WQ.notifyRead();
}

return 0;
Expand All @@ -3302,7 +3280,7 @@ void VDP2REND_Init(const bool IsPAL, const uint64 affinity)
UserLayerEnableMask = ~0U;
Clock28M = false;
//
DrawCounter.store(0, std::memory_order_release);
WQ.clear();
RThread = MThreading::Thread_Create(RThreadEntry, NULL, "MDFN VDP2 Render");
if(affinity)
MThreading::Thread_SetAffinity(RThread, affinity);
Expand Down Expand Up @@ -3401,7 +3379,8 @@ void VDP2REND_StartFrame(EmulateSpecStruct* espec_arg, const bool clock28m, cons

void VDP2REND_EndFrame(void)
{
atomicWaitForValue(DrawCounter, 0);
WQ.notifyWrite();
WQ.waitForSize(0);

if(NextOutLine < VisibleLines)
{
Expand Down Expand Up @@ -3443,7 +3422,6 @@ void VDP2REND_DrawLine(const int vdp2_line, const uint32 crt_line, const bool fi
if(espec->InterlaceOn)
out_line = (out_line << 1) | espec->InterlaceField;

auto wdcq = DrawCounter.fetch_add(1, std::memory_order_release);
WWQ(COMMAND_DRAW_LINE, ((uint16)vdp2_line << 16) | out_line, field);
//
//
Expand Down
2 changes: 1 addition & 1 deletion imagine/build.mk
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ prefix ?= $(IMAGINE_SDK_PLATFORM_PATH)
imaginePkgconfigTemplate := $(IMAGINE_PATH)/pkgconfig/imagine.pc
pkgName := $(libName)
pkgDescription := Game/Multimedia Engine
pkgVersion := 1.5.80
pkgVersion := 1.5.81
LDLIBS := -l$(libName) $(LDLIBS)
ifdef libNameExt
pkgCFlags := -DIMAGINE_CONFIG_H=$(configFilename)
Expand Down
2 changes: 1 addition & 1 deletion imagine/include/imagine/config/version.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
You should have received a copy of the GNU General Public License
along with Imagine. If not, see <http://www.gnu.org/licenses/> */

#define IMAGINE_VERSION_BASE "1.5.80"
#define IMAGINE_VERSION_BASE "1.5.81"

#ifdef NDEBUG
#define IMAGINE_VERSION IMAGINE_VERSION_BASE
Expand Down
80 changes: 50 additions & 30 deletions imagine/include/imagine/util/container/RingBuffer.hh
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,12 @@ struct RingBufferConf
size_t fixedSize{};
};

struct RingBufferRWFlags
{
bool blocking:1{};
bool notifyOnBlock:1{};
};

struct RingBufferIdxPair
{
size_t read{}, write{};
Expand All @@ -46,6 +52,7 @@ class RingBuffer
{
public:
using IdxPair = RingBufferIdxPair;
using RWFlags = RingBufferRWFlags;
static constexpr bool isFixedSize = conf.fixedSize;

struct RWSpan : public std::span<T>
Expand Down Expand Up @@ -98,23 +105,30 @@ public:
bool full() const { return size() == capacity(); }

[[nodiscard]]
RWSpan beginRead(size_t s)
RWSpan beginRead(size_t s, RWFlags flags = {})
{
IdxPair idxs{.read = readIdx.load(std::memory_order_relaxed), .write = writeIdx.load(std::memory_order_acquire)};
if(flags.blocking && empty(idxs))
{
if(flags.notifyOnBlock)
notifyWrite();
writeIdx.wait(idxs.write, std::memory_order_acquire);
idxs.write = writeIdx.load(std::memory_order_acquire);
}
s = std::min(s, size(idxs));
std::span<T> span{&buff[idxs.read], s};
std::span<T> span{&buff[wrapIdx(idxs.read)], s};
assertAddrRange(span);
return {span, idxs};
}

void endRead(RWSpan span)
{
readIdx.store(wrapSize(span.idxs.read + span.size()), std::memory_order_release);
readIdx.store(span.idxs.read + span.size(), std::memory_order_release);
}

size_t read(std::span<T> buff)
size_t read(std::span<T> buff, RWFlags flags = {})
{
auto span = beginRead(buff.size());
auto span = beginRead(buff.size(), flags);
copy_n(span.data(), span.size(), buff.data());
endRead(span);
return span.size();
Expand All @@ -129,14 +143,12 @@ public:
return std::optional<T>{tmp};
}

T pop()
T pop(RWFlags flags = {})
{
IdxPair idxs = loadIdxs();
if(empty(idxs))
writeIdx.wait(idxs.write, std::memory_order_relaxed);
T tmp;
read({&tmp, 1});
return tmp;
if(read({&tmp, 1}, flags))
return tmp;
return {};
}

void notifyRead()
Expand All @@ -145,39 +157,38 @@ public:
}

[[nodiscard]]
RWSpan beginWrite(size_t s)
RWSpan beginWrite(size_t s, RWFlags flags = {})
{
IdxPair idxs{.read = readIdx.load(std::memory_order_acquire), .write = writeIdx.load(std::memory_order_relaxed)};
if(flags.blocking && !freeSpace(idxs))
{
if(flags.notifyOnBlock)
notifyRead();
readIdx.wait(idxs.read, std::memory_order_acquire);
idxs.read = readIdx.load(std::memory_order_acquire);
}
s = std::min(s, freeSpace(idxs));
std::span<T> span{&buff[idxs.write], s};
std::span<T> span{&buff[wrapIdx(idxs.write)], s};
assertAddrRange(span);
return {span, idxs};
}

void endWrite(RWSpan span)
{
writeIdx.store(wrapSize(span.idxs.write + span.size()), std::memory_order_release);
writeIdx.store(span.idxs.write + span.size(), std::memory_order_release);
}

size_t write(std::span<const T> buff)
size_t write(std::span<const T> buff, RWFlags flags = {})
{
auto span = beginWrite(buff.size());
auto span = beginWrite(buff.size(), flags);
copy_n(buff.data(), span.size(), span.data());
endWrite(span);
return span.size();
}

bool tryPush(const T& val)
bool push(const T& val, RWFlags flags = {})
{
return write({&val, 1});
}

void push(const T& val)
{
IdxPair idxs = loadIdxs();
if(!freeSpace(idxs))
readIdx.wait(idxs.read, std::memory_order_relaxed);
write({&val, 1});
return write({&val, 1}, flags);
}

void notifyWrite()
Expand All @@ -192,7 +203,7 @@ public:
return newCapacity;
size_t oldSize = size();
auto newBuff = allocBuffer(newCapacity);
if(newCapacity > oldSize) // maintain buffer content if increasing size
if(oldSize && newCapacity > oldSize) // maintain buffer content if increasing size
{
copy_n(buff.get(), oldSize, newBuff.get());
}
Expand All @@ -204,14 +215,18 @@ public:
return newCapacity;
}

void reset() requires(!isFixedSize) { buff.reset(); }
void reset() requires(!isFixedSize)
{
resetVPtr(buff);
clear();
}

void waitForSize(size_t s)
{
IdxPair idxs = loadIdxs();
while(size(idxs) != s)
{
readIdx.wait(idxs.read, std::memory_order_relaxed);
readIdx.wait(idxs.read, std::memory_order_acquire);
idxs = loadIdxs();
}
}
Expand All @@ -231,13 +246,18 @@ private:
}

size_t wrapSize(size_t s) const
{
return s & (capacity() | (capacity() - 1));
}

size_t wrapIdx(size_t s) const
{
return s & (capacity() - 1);
}

IdxPair loadIdxs() const
{
return {.read = readIdx.load(std::memory_order_relaxed), .write = writeIdx.load(std::memory_order_relaxed)};
return {.read = readIdx.load(std::memory_order_acquire), .write = writeIdx.load(std::memory_order_acquire)};
}

size_t bufferCapacity() const requires(!isFixedSize) { return buff.get_deleter().size; }
Expand Down
6 changes: 6 additions & 0 deletions imagine/include/imagine/vmem/memory.hh
Original file line number Diff line number Diff line change
Expand Up @@ -107,4 +107,10 @@ inline UniqueVPtr<T> makeUniqueMirroredVPtr(size_t size)
return {buff.data(), VPtrDeleter<T>{buff.size()}};
}

template<class T>
inline void resetVPtr(UniqueVPtr<T> &ptr)
{
ptr = {nullptr, VPtrDeleter<T>{}};
}

}

0 comments on commit 12f8a0c

Please sign in to comment.