1
0
mirror of https://github.com/RPCS3/rpcs3.git synced 2024-11-22 10:42:36 +01:00

Some errors fixed

This commit is contained in:
Nekotekina 2014-02-27 22:25:32 +04:00
parent 8b952bf98c
commit dbdae77780
9 changed files with 456 additions and 57 deletions

2
.gitignore vendored
View File

@ -41,6 +41,8 @@
/bin/VertexProgram.txt
/bin/BreakPoints.dat
/bin/textures
/bin/*.lib
/bin/*.exp
rpcs3/git-version.h
# Copyrighted files

View File

@ -117,10 +117,12 @@ thread::thread()
}
void thread::start(std::function<void()> func)
{ // got a crash related with strings
m_thr = std::thread([this, func]()
{
NamedThreadBase info(m_name);
std::string name = m_name;
m_thr = std::thread([func, name]()
{
NamedThreadBase info(name);
g_tls_this_thread = &info;
try
@ -130,7 +132,7 @@ void thread::start(std::function<void()> func)
catch(...)
{
ConLog.Error("Crash :(");
std::terminate();
//std::terminate();
}
});
}

View File

@ -18,7 +18,7 @@ void dmuxQueryEsAttr(u32 info_addr /* may be 0 */, const mem_ptr_t<CellCodecEsFi
const u32 esSpecificInfo_addr, mem_ptr_t<CellDmuxEsAttr> attr)
{
if (esFilterId->filterIdMajor >= 0xe0)
attr->memSize = 0x500000; // 0x45fa49 from ps3
attr->memSize = 0x600000; // 0x45fa49 from ps3
else
attr->memSize = 0x10000; // 0x73d9 from ps3
@ -40,16 +40,13 @@ u32 dmuxOpen(Demuxer* data)
DemuxerTask task;
DemuxerStream stream;
/*
ElementaryStream* esAVC[16]; memset(esAVC, 0, sizeof(esAVC));
ElementaryStream* esM2V[16]; memset(esM2V, 0, sizeof(esM2V));
ElementaryStream* esDATA[16]; memset(esDATA, 0, sizeof(esDATA));
ElementaryStream* esATRAX[48]; memset(esATRAX, 0, sizeof(esATRAX));
ElementaryStream* esAC3[48]; memset(esAC3, 0, sizeof(esAC3));
ElementaryStream* esLPCM[48]; memset(esLPCM, 0, sizeof(esLPCM));
*/
ElementaryStream* esALL[192]; memset(esALL, 0, sizeof(esALL));
ElementaryStream** esAVC = &esALL[0];
ElementaryStream** esAVC = &esALL[0]; // AVC (max 16)
ElementaryStream** esM2V = &esALL[16]; // MPEG-2 (max 16)
ElementaryStream** esDATA = &esALL[32]; // user data (max 16)
ElementaryStream** esATX = &esALL[48]; // ATRAC3+ (max 48)
ElementaryStream** esAC3 = &esALL[96]; // AC3 (max 48)
ElementaryStream** esPCM = &esALL[144]; // LPCM (max 48)
u32 cb_add = 0;
@ -124,6 +121,8 @@ u32 dmuxOpen(Demuxer* data)
continue;
}
DemuxerStream backup = stream;
stream.skip(4);
stream.get(len);
PesHeader pes(stream);
@ -136,6 +135,11 @@ u32 dmuxOpen(Demuxer* data)
if (pes.size && es.hasdata()) // new AU detected
{
/*if (es.hasunseen())
{
stream = backup;
continue;
}*/
es.finish(stream);
// callback
mem_ptr_t<CellDmuxEsMsg> esMsg(a128(dmux.memAddr) + (cb_add ^= 16));
@ -149,7 +153,13 @@ u32 dmuxOpen(Demuxer* data)
if (pes.size)
{
ConLog.Write("*** AVC AU detected (pts=0x%x, dts=0x%x)", pes.pts, pes.dts);
ConLog.Write("*** AVC AU detected (pts=0x%llx, dts=0x%llx)", pes.pts, pes.dts);
}
if (es.isfull())
{
stream = backup;
continue;
}
es.push(stream, len - pes.size - 3, pes);
@ -173,6 +183,7 @@ u32 dmuxOpen(Demuxer* data)
case 0x1dc: case 0x1dd: case 0x1de: case 0x1df:
{
// unknown
ConLog.Warning("Unknown MPEG stream found");
stream.skip(4);
stream.get(len);
stream.skip(len);

View File

@ -321,7 +321,7 @@ struct DemuxerStream
{
if (sizeof(T) > size) return false;
out = *mem_ptr_t<T>(addr);
out = *(T*)Memory.VirtualToRealAddr(addr);
addr += sizeof(T);
size -= sizeof(T);
@ -333,7 +333,7 @@ struct DemuxerStream
{
if (sizeof(T) > size) return false;
out = *mem_ptr_t<T>(addr);
out = *(T*)Memory.VirtualToRealAddr(addr);
return true;
}
@ -343,13 +343,17 @@ struct DemuxerStream
size = size > count ? size - count : 0;
}
u32 get_ts(u8 c)
u64 get_ts(u8 c)
{
u16 v1, v2; get(v1); get(v2);
return (((u32) (c & 0x0E)) << 29) | ((v1 >> 1) << 15) | (v2 >> 1);
u8 v[4]; get((u32&)v);
return
(((u64)c & 0x0e) << 29) |
(((u64)v[0]) << 21) |
(((u64)v[1] & 0x7e) << 15) |
(((u64)v[2]) << 7) | ((u64)v[3] >> 1);
}
u32 get_ts()
u64 get_ts()
{
u8 v; get(v);
return get_ts(v);
@ -358,8 +362,8 @@ struct DemuxerStream
struct PesHeader
{
u32 pts;
u32 dts;
u64 pts;
u64 dts;
u8 ch;
u8 size;
@ -505,6 +509,11 @@ public:
{
}
volatile bool hasunseen()
{
return peek_addr;
}
volatile bool hasdata()
{
return last_size;
@ -532,7 +541,7 @@ public:
void finish(DemuxerStream& stream) // not multithread-safe
{
SMutexLocker lock(mutex);
//ConLog.Write("es::finish(): peek=0x%x, first=0x%x, last=0x%x, size=0x%x", peek_addr, first_addr, last_addr, last_size);
if (!first_addr)
{
first_addr = last_addr;
@ -556,6 +565,7 @@ public:
void push(DemuxerStream& stream, u32 size, PesHeader& pes)
{
SMutexLocker lock(mutex);
//ConLog.Write("es::push(): peek=0x%x, first=0x%x, last=0x%x, size=0x%x", peek_addr, first_addr, last_addr, last_size);
if (isfull())
{
ConLog.Error("ElementaryStream::push(): buffer is full");
@ -565,7 +575,12 @@ public:
u32 data_addr = last_addr + 128 + last_size;
last_size += size;
Memory.Copy(data_addr, stream.addr, size);
if (!Memory.Copy(data_addr, stream.addr, size))
{
ConLog.Error("ElementaryStream::push(): data copying failed");
Emu.Pause();
return;
}
stream.skip(size);
mem_ptr_t<CellDmuxAuInfoEx> info(last_addr);
@ -573,10 +588,10 @@ public:
info->auSize = last_size;
if (pes.size)
{
info->dts.lower = pes.dts;
info->dts.upper = 0;
info->pts.lower = pes.pts;
info->pts.upper = 0;
info->dts.lower = (u32)pes.dts;
info->dts.upper = (u32)(pes.dts >> 32);
info->pts.lower = (u32)pes.pts;
info->pts.upper = (u32)(pes.pts >> 32);
info->isRap = false; // TODO: set valid value
info->reserved = 0;
info->userData = stream.userdata;
@ -590,10 +605,10 @@ public:
inf->auSize = last_size;
if (pes.size)
{
inf->dtsLower = pes.dts;
inf->dtsUpper = 0;
inf->ptsLower = pes.pts;
inf->ptsUpper = 0;
inf->dtsLower = (u32)pes.dts;
inf->dtsUpper = (u32)(pes.dts >> 32);
inf->ptsLower = (u32)pes.pts;
inf->ptsUpper = (u32)(pes.pts >> 32);
inf->auMaxSize = 0; // ?????
inf->userData = stream.userdata;
}
@ -607,6 +622,7 @@ public:
void release()
{
SMutexLocker lock(mutex);
ConLog.Write("es::release(): peek=0x%x, first=0x%x, last=0x%x, size=0x%x", peek_addr, first_addr, last_addr, last_size);
if (!canrelease())
{
ConLog.Error("ElementaryStream::release(): buffer is empty");
@ -634,7 +650,8 @@ public:
bool peek(u32& out_data, bool no_ex, u32& out_spec, bool update_index)
{
SMutexLocker lock(mutex);
ConLog.Write("es::peek(): peek_addr=0x%x", peek_addr);
/*ConLog.Write("es::peek(%sAu%s): peek=0x%x, first=0x%x, last=0x%x, size=0x%x", wxString(update_index ? "Get" : "Peek").wx_str(),
wxString(no_ex ? "" : "Ex").wx_str(), peek_addr, first_addr, last_addr, last_size);*/
if (!peek_addr) return false;
out_data = peek_addr;

View File

@ -1,81 +1,327 @@
#include "stdafx.h"
#include "Emu/SysCalls/SysCalls.h"
#include "Emu/SysCalls/SC_FUNC.h"
#include "cellVdec.h"
#include "cellPamf.h"
extern "C"
{
#include "libavformat\avformat.h"
#include "libavcodec\avcodec.h"
}
#include "cellVdec.h"
void cellVdec_init();
Module cellVdec(0x0005, cellVdec_init);
u32 vdecQueryAttr(CellVdecCodecType type, u32 profile, u32 spec_addr /* may be 0 */, mem_ptr_t<CellVdecAttr> attr)
{
switch (type) // TODO: check profile levels
{
case CELL_VDEC_CODEC_TYPE_AVC: cellVdec.Warning("cellVdecQueryAttr: AVC (profile=%d)", profile); break;
case CELL_VDEC_CODEC_TYPE_MPEG2: cellVdec.Error("TODO: MPEG2 not supported"); break;
case CELL_VDEC_CODEC_TYPE_DIVX: cellVdec.Error("TODO: DIVX not supported"); break;
default: return CELL_VDEC_ERROR_ARG;
}
// TODO: check values
attr->decoderVerLower = 0x280000; // from dmux
attr->decoderVerUpper = 0x260000;
attr->memSize = 64 * 1024 * 1024;
attr->cmdDepth = 15;
return CELL_OK;
}
u32 vdecOpen(VideoDecoder* data)
{
VideoDecoder& vdec = *data;
u32 vdec_id = cellVdec.GetNewId(data);
vdec.id = vdec_id;
thread t("Video Decoder[" + std::to_string(vdec_id) + "] Thread", [&]()
{
ConLog.Write("Video Decoder enter()");
VdecTask task;
while (true)
{
if (Emu.IsStopped())
{
break;
}
if (vdec.job.IsEmpty() && vdec.is_running)
{
// TODO: default task (not needed?)
Sleep(1);
continue;
}
if (!vdec.job.Pop(task))
{
break;
}
switch (task.type)
{
case vdecStartSeq:
{
// TODO: reset data
ConLog.Warning("vdecStartSeq()");
vdec.is_running = true;
}
break;
case vdecEndSeq:
{
// TODO: send callback
ConLog.Warning("vdecEndSeq()");
vdec.is_running = false;
}
break;
case vdecDecodeAu:
{
struct vdecPacket : AVPacket
{
vdecPacket(u32 size)
{
av_new_packet(this, size + FF_INPUT_BUFFER_PADDING_SIZE);
memset(data + size, 0, FF_INPUT_BUFFER_PADDING_SIZE);
}
~vdecPacket()
{
av_free_packet(this);
}
} au(task.size);
au.pts = task.pts;
au.dts = task.dts;
if (task.mode != CELL_VDEC_DEC_MODE_NORMAL)
{
ConLog.Error("vdecDecodeAu: unsupported decoding mode(%d)", task.mode);
break;
}
if (!Memory.CopyToReal(au.data, task.addr, task.size))
{
ConLog.Error("vdecDecodeAu: AU data accessing failed(addr=0x%x, size=0x%x)", task.addr, task.size);
break;
}
int got_picture = 0;
int decode = avcodec_decode_video2(vdec.ctx, vdec.frame, &got_picture, &au);
if (decode < 0)
{
ConLog.Error("vdecDecodeAu: AU decoding error(%d)", decode);
break;
}
ConLog.Write("Frame decoded (%d)", decode);
}
break;
case vdecClose:
{
vdec.is_finished = true;
ConLog.Write("Video Decoder exit");
return;
}
case vdecSetFrameRate:
{
ConLog.Error("TODO: vdecSetFrameRate(%d)", task.frc);
}
default:
ConLog.Error("Video Decoder error: unknown task(%d)", task.type);
return;
}
}
ConLog.Warning("Video Decoder aborted");
});
t.detach();
return vdec_id;
}
int cellVdecQueryAttr(const mem_ptr_t<CellVdecType> type, mem_ptr_t<CellVdecAttr> attr)
{
cellVdec.Error("cellVdecQueryAttr(type_addr=0x%x, attr_addr=0x%x)", type.GetAddr(), attr.GetAddr());
return CELL_OK;
cellVdec.Warning("cellVdecQueryAttr(type_addr=0x%x, attr_addr=0x%x)", type.GetAddr(), attr.GetAddr());
if (!type.IsGood() || !attr.IsGood())
{
return CELL_VDEC_ERROR_FATAL;
}
return vdecQueryAttr(type->codecType, type->profileLevel, 0, attr);
}
int cellVdecQueryAttrEx(const mem_ptr_t<CellVdecTypeEx> type, mem_ptr_t<CellVdecAttr> attr)
{
cellVdec.Error("cellVdecQueryAttrEx(type_addr=0x%x, attr_addr=0x%x)", type.GetAddr(), attr.GetAddr());
return CELL_OK;
cellVdec.Warning("cellVdecQueryAttrEx(type_addr=0x%x, attr_addr=0x%x)", type.GetAddr(), attr.GetAddr());
if (!type.IsGood() || !attr.IsGood())
{
return CELL_VDEC_ERROR_FATAL;
}
return vdecQueryAttr(type->codecType, type->profileLevel, type->codecSpecificInfo_addr, attr);
}
int cellVdecOpen(const mem_ptr_t<CellVdecType> type, const mem_ptr_t<CellVdecResource> res, const mem_ptr_t<CellVdecCb> cb, mem32_t handle)
{
cellVdec.Error("cellVdecOpen(type_addr=0x%x, res_addr=0x%x, cb_addr=0x%x, handle_addr=0x%x)",
cellVdec.Warning("cellVdecOpen(type_addr=0x%x, res_addr=0x%x, cb_addr=0x%x, handle_addr=0x%x)",
type.GetAddr(), res.GetAddr(), cb.GetAddr(), handle.GetAddr());
if (!type.IsGood() || !res.IsGood() || !cb.IsGood() || !handle.IsGood())
{
return CELL_VDEC_ERROR_FATAL;
}
if (!Memory.IsGoodAddr(res->memAddr, res->memSize) || !Memory.IsGoodAddr(cb->cbFunc))
{
return CELL_VDEC_ERROR_FATAL;
}
handle = vdecOpen(new VideoDecoder(type->codecType, type->profileLevel, res->memAddr, res->memSize, cb->cbFunc, cb->cbArg));
return CELL_OK;
}
int cellVdecOpenEx(const mem_ptr_t<CellVdecTypeEx> type, const mem_ptr_t<CellVdecResourceEx> res, const mem_ptr_t<CellVdecCb> cb, mem32_t handle)
{
cellVdec.Error("cellVdecOpenEx(type_addr=0x%x, res_addr=0x%x, cb_addr=0x%x, handle_addr=0x%x)",
cellVdec.Warning("cellVdecOpenEx(type_addr=0x%x, res_addr=0x%x, cb_addr=0x%x, handle_addr=0x%x)",
type.GetAddr(), res.GetAddr(), cb.GetAddr(), handle.GetAddr());
if (!type.IsGood() || !res.IsGood() || !cb.IsGood() || !handle.IsGood())
{
return CELL_VDEC_ERROR_FATAL;
}
if (!Memory.IsGoodAddr(res->memAddr, res->memSize) || !Memory.IsGoodAddr(cb->cbFunc))
{
return CELL_VDEC_ERROR_FATAL;
}
handle = vdecOpen(new VideoDecoder(type->codecType, type->profileLevel, res->memAddr, res->memSize, cb->cbFunc, cb->cbArg));
return CELL_OK;
}
int cellVdecClose(u32 handle)
{
cellVdec.Error("cellVdecClose(handle=0x%x)", handle);
cellVdec.Warning("cellVdecClose(handle=%d)", handle);
VideoDecoder* vdec;
if (!Emu.GetIdManager().GetIDData(handle, vdec))
{
return CELL_VDEC_ERROR_ARG;
}
vdec->job.Push(VdecTask(vdecClose));
while (!vdec->is_finished)
{
if (Emu.IsStopped())
{
ConLog.Warning("cellVdecClose(%d) aborted", handle);
break;
}
Sleep(1);
}
Emu.GetIdManager().RemoveID(handle);
return CELL_OK;
}
int cellVdecStartSeq(u32 handle)
{
cellVdec.Error("cellVdecStartSeq(handle=0x%x)", handle);
cellVdec.Log("cellVdecStartSeq(handle=%d)", handle);
VideoDecoder* vdec;
if (!Emu.GetIdManager().GetIDData(handle, vdec))
{
return CELL_VDEC_ERROR_ARG;
}
vdec->job.Push(VdecTask(vdecStartSeq));
return CELL_OK;
}
int cellVdecEndSeq(u32 handle)
{
cellVdec.Error("cellVdecEndSeq(handle=0x%x)", handle);
cellVdec.Log("cellVdecEndSeq(handle=%d)", handle);
VideoDecoder* vdec;
if (!Emu.GetIdManager().GetIDData(handle, vdec))
{
return CELL_VDEC_ERROR_ARG;
}
vdec->job.Push(VdecTask(vdecEndSeq));
return CELL_OK;
}
int cellVdecDecodeAu(u32 handle, CellVdecDecodeMode mode, const mem_ptr_t<CellVdecAuInfo> auInfo)
{
cellVdec.Error("cellVdecDecodeAu(handle=0x%x, mode=0x%x, auInfo_addr=0x%x)", handle, mode, auInfo.GetAddr());
cellVdec.Log("cellVdecDecodeAu(handle=%d, mode=0x%x, auInfo_addr=0x%x)", handle, mode, auInfo.GetAddr());
VideoDecoder* vdec;
if (!Emu.GetIdManager().GetIDData(handle, vdec))
{
return CELL_VDEC_ERROR_ARG;
}
// TODO: check info
VdecTask task(vdecDecodeAu);
task.mode = mode;
task.addr = auInfo->startAddr;
task.size = auInfo->size;
task.dts = (u64)auInfo->dts.lower | ((u64)auInfo->dts.upper << 32);
task.pts = (u64)auInfo->pts.lower | ((u64)auInfo->pts.upper << 32);
task.userData = auInfo->userData;
task.specData = auInfo->codecSpecificData;
vdec->job.Push(task);
return CELL_OK;
}
int cellVdecGetPicture(u32 handle, const mem_ptr_t<CellVdecPicFormat> format, u32 out_addr)
{
cellVdec.Error("cellVdecGetPicture(handle=0x%x, format_addr=0x%x, out_addr=0x%x)", handle, format.GetAddr(), out_addr);
cellVdec.Error("cellVdecGetPicture(handle=%d, format_addr=0x%x, out_addr=0x%x)", handle, format.GetAddr(), out_addr);
return CELL_OK;
}
int cellVdecGetPicItem(u32 handle, const u32 picItem_ptr_addr)
{
cellVdec.Error("cellVdecGetPicItem(handle=0x%x, picItem_ptr_addr=0x%x)", handle, picItem_ptr_addr);
cellVdec.Error("cellVdecGetPicItem(handle=%d, picItem_ptr_addr=0x%x)", handle, picItem_ptr_addr);
return CELL_OK;
}
int cellVdecSetFrameRate(u32 handle, CellVdecFrameRate frc)
{
cellVdec.Error("cellVdecSetFrameRate(handle=0x%x, frc=0x%x)", handle, frc);
cellVdec.Log("cellVdecSetFrameRate(handle=%d, frc=0x%x)", handle, frc);
VideoDecoder* vdec;
if (!Emu.GetIdManager().GetIDData(handle, vdec))
{
return CELL_VDEC_ERROR_ARG;
}
// TODO: check frc value and set frame rate
VdecTask task(vdecSetFrameRate);
task.frc = frc;
vdec->job.Push(task);
return CELL_OK;
}
@ -92,4 +338,6 @@ void cellVdec_init()
cellVdec.AddFunc(0x807c861a, cellVdecGetPicture);
cellVdec.AddFunc(0x17c702b9, cellVdecGetPicItem);
cellVdec.AddFunc(0xe13ef6fc, cellVdecSetFrameRate);
avcodec_register_all();
}

View File

@ -1,5 +1,6 @@
#pragma once
#include "cellPamf.h"
#include "Utilities/SQueue.h"
// Error Codes
enum
@ -30,7 +31,7 @@ enum CellVdecMsgType
};
// Decoder Operation Mode
enum CellVdecDecodeMode
enum CellVdecDecodeMode : u32
{
CELL_VDEC_DEC_MODE_NORMAL,
CELL_VDEC_DEC_MODE_B_SKIP,
@ -164,11 +165,13 @@ struct CellVdecPicFormat
u8 alpha;
};
typedef mem_func_ptr_t<void (*)(u32 handle_addr, CellVdecMsgType msgType, int msgData, u32 cbArg_addr)> CellVdecCbMsg;
// Callback Function Information
struct CellVdecCb
{
be_t<mem_func_ptr_t<void (*)(u32 handle_addr, CellVdecMsgType msgType, int msgData, u32 cbArg_addr)>> cbFunc;
be_t<u32> cbArg_addr;
be_t<u32> cbFunc;
be_t<u32> cbArg;
};
// Max CC Data Length
@ -635,3 +638,108 @@ struct CellVdecMpeg2Info
u8 ccData[2][128];
be_t<u64> reserved[2];
};
/* Video Decoder Thread Classes */
enum VdecJobType : u32
{
vdecStartSeq,
vdecEndSeq,
vdecDecodeAu,
vdecSetFrameRate,
vdecClose,
};
struct VdecTask
{
VdecJobType type;
union
{
u32 frc;
CellVdecDecodeMode mode;
};
u32 addr;
u32 size;
u64 pts;
u64 dts;
u64 userData;
u64 specData;
VdecTask(VdecJobType type)
: type(type)
{
}
VdecTask()
{
}
};
class VideoDecoder
{
public:
SQueue<VdecTask> job;
u32 id;
volatile bool is_running;
volatile bool is_finished;
AVCodec* codec;
AVCodecContext* ctx;
AVFrame* frame;
const u32 type;
const u32 profile;
const u32 memAddr;
const u32 memSize;
const u32 cbFunc;
const u32 cbArg;
VideoDecoder(u32 type, u32 profile, u32 addr, u32 size, u32 func, u32 arg)
: type(type)
, profile(profile)
, memAddr(addr)
, memSize(size)
, cbFunc(func)
, cbArg(arg)
, is_finished(false)
, is_running(false)
{
codec = avcodec_find_decoder(AV_CODEC_ID_H264);
if (!codec)
{
ConLog.Error("VideoDecoder(): avcodec_find_decoder failed");
Emu.Pause();
return;
}
ctx = avcodec_alloc_context3(codec);
if (!ctx)
{
ConLog.Error("VideoDecoder(): avcodec_alloc_context3 failed");
Emu.Pause();
return;
}
if (int err = avcodec_open2(ctx, codec, NULL)) // TODO: not multithread safe
{
ConLog.Error("VideoDecoder(): avcodec_open2 failed(%d)", err);
Emu.Pause();
return;
}
frame = av_frame_alloc();
if (!frame)
{
ConLog.Error("VideoDecoder(): av_frame_alloc failed");
Emu.Pause();
return;
}
}
~VideoDecoder()
{
if (frame) av_frame_free(&frame);
if (ctx)
{
avcodec_close(ctx);
av_free(ctx);
}
}
};

View File

@ -28,7 +28,7 @@ int sys_lwmutex_create(mem_ptr_t<sys_lwmutex_t> lwmutex, mem_ptr_t<sys_lwmutex_a
}
lwmutex->attribute = attr->attr_protocol | attr->attr_recursive;
lwmutex->all_info() = 0;
lwmutex->all_info() = ~0;
lwmutex->mutex.initialize();
//lwmutex->waiter = lwmutex->owner.GetOwner();
lwmutex->pad = 0;

View File

@ -65,7 +65,7 @@ struct SleepQueue
struct sys_lwmutex_t
{
/* volatile */ SMutexBase<be_t<u32>, 0xffffffff, 0> mutex;
/* volatile */ SMutexBase<be_t<u32>, ~0, 0> mutex;
/* volatile */ be_t<u32> waiter; // not used
u64 &all_info(){return *(reinterpret_cast<u64*>(this));}
be_t<u32> attribute;

View File

@ -136,11 +136,22 @@ void LogWriter::WriteToLog(std::string prefix, std::string value, std::string co
if(wxThread::IsMain())
#endif
{
while(LogBuffer.IsBusy()) wxYieldIfNeeded();
while(LogBuffer.IsBusy())
{
// need extra break condition?
wxYieldIfNeeded();
}
}
else
{
while(LogBuffer.IsBusy()) Sleep(1);
while (LogBuffer.IsBusy())
{
if (Emu.IsStopped())
{
break;
}
Sleep(1);
}
}
//if(LogBuffer.put == LogBuffer.get) LogBuffer.Flush();