flycast/core/hw/pvr/ta_ctx.cpp

285 lines
5.2 KiB
C++
Raw Normal View History

2013-12-19 17:10:14 +00:00
#include "ta_ctx.h"
#include "spg.h"
#include "cfg/option.h"
#include "Renderer_if.h"
#include "serialize.h"
2013-12-19 17:10:14 +00:00
extern u32 fskip;
extern u32 FrameCount;
static int RenderCount;
2013-12-19 17:10:14 +00:00
TA_context* ta_ctx;
tad_context ta_tad;
void SetCurrentTARC(u32 addr)
{
if (addr != TACTX_NONE)
{
if (ta_ctx)
SetCurrentTARC(TACTX_NONE);
verify(ta_ctx == 0);
//set new context
ta_ctx = tactx_Find(addr,true);
//copy cached params
ta_tad = ta_ctx->tad;
}
else
{
//Flush cache to context
verify(ta_ctx != 0);
ta_ctx->tad=ta_tad;
//clear context
ta_ctx=0;
ta_tad.Reset(0);
2013-12-19 17:10:14 +00:00
}
}
TA_context* rqueue;
cResetEvent frame_finished;
bool QueueRender(TA_context* ctx)
2013-12-19 17:10:14 +00:00
{
verify(ctx != 0);
2021-09-02 15:51:23 +00:00
bool skipFrame = settings.disableRenderer;
if (!skipFrame)
{
RenderCount++;
if (RenderCount % (config::SkipFrame + 1) != 0)
skipFrame = true;
else if (config::ThreadedRendering && rqueue != nullptr
&& (config::AutoSkipFrame == 0 || (config::AutoSkipFrame == 1 && SH4FastEnough)))
// The previous render hasn't completed yet so we wait.
// If autoskipframe is enabled (normal level), we only do so if the CPU is running
// fast enough over the last frames
frame_finished.Wait();
}
if (skipFrame || rqueue)
{
tactx_Recycle(ctx);
2021-09-02 15:51:23 +00:00
if (!settings.disableRenderer)
fskip++;
return false;
}
// disable net rollbacks until the render thread has processed the frame
rend_disable_rollback();
frame_finished.Reset();
verify(rqueue == nullptr);
rqueue = ctx;
2013-12-19 17:10:14 +00:00
return true;
2013-12-19 17:10:14 +00:00
}
TA_context* DequeueRender()
{
if (rqueue != nullptr)
2013-12-19 17:10:14 +00:00
FrameCount++;
return rqueue;
2013-12-19 17:10:14 +00:00
}
bool rend_framePending() {
return rqueue != nullptr;
}
void FinishRender(TA_context* ctx)
{
if (ctx != nullptr)
{
verify(rqueue == ctx);
rqueue = nullptr;
2019-02-06 18:57:13 +00:00
tactx_Recycle(ctx);
}
frame_finished.Set();
}
2020-03-30 12:24:33 +00:00
static std::mutex mtx_pool;
2013-12-19 17:10:14 +00:00
2020-03-29 17:29:14 +00:00
static std::vector<TA_context*> ctx_pool;
static std::vector<TA_context*> ctx_list;
2013-12-19 17:10:14 +00:00
TA_context* tactx_Alloc()
{
TA_context* rv = 0;
2020-03-30 12:24:33 +00:00
mtx_pool.lock();
if (!ctx_pool.empty())
2013-12-19 17:10:14 +00:00
{
rv = ctx_pool[ctx_pool.size()-1];
ctx_pool.pop_back();
}
2020-03-30 12:24:33 +00:00
mtx_pool.unlock();
2013-12-19 17:10:14 +00:00
if (!rv)
{
rv = new TA_context();
rv->Alloc();
}
return rv;
}
void tactx_Recycle(TA_context* poped_ctx)
{
2020-03-30 12:24:33 +00:00
mtx_pool.lock();
2013-12-19 17:10:14 +00:00
{
if (ctx_pool.size()>2)
{
poped_ctx->Free();
delete poped_ctx;
}
else
{
poped_ctx->Reset();
ctx_pool.push_back(poped_ctx);
}
}
2020-03-30 12:24:33 +00:00
mtx_pool.unlock();
2013-12-19 17:10:14 +00:00
}
TA_context* tactx_Find(u32 addr, bool allocnew)
{
for (size_t i=0; i<ctx_list.size(); i++)
2013-12-19 17:10:14 +00:00
{
if (ctx_list[i]->Address==addr)
return ctx_list[i];
}
if (allocnew)
{
TA_context* rv = tactx_Alloc();
rv->Address=addr;
ctx_list.push_back(rv);
return rv;
}
return 0;
2013-12-19 17:10:14 +00:00
}
TA_context* tactx_Pop(u32 addr)
{
for (size_t i=0; i<ctx_list.size(); i++)
2013-12-19 17:10:14 +00:00
{
if (ctx_list[i]->Address==addr)
{
TA_context* rv = ctx_list[i];
if (ta_ctx == rv)
SetCurrentTARC(TACTX_NONE);
ctx_list.erase(ctx_list.begin() + i);
return rv;
}
}
return 0;
}
2018-10-29 19:02:12 +00:00
void tactx_Term()
{
2021-03-05 17:20:09 +00:00
if (ta_ctx != nullptr)
SetCurrentTARC(TACTX_NONE);
2018-10-29 19:02:12 +00:00
for (size_t i = 0; i < ctx_list.size(); i++)
{
ctx_list[i]->Free();
delete ctx_list[i];
}
ctx_list.clear();
2020-03-30 12:24:33 +00:00
mtx_pool.lock();
2018-10-29 19:02:12 +00:00
{
for (size_t i = 0; i < ctx_pool.size(); i++)
{
ctx_pool[i]->Free();
delete ctx_pool[i];
}
}
ctx_pool.clear();
2020-03-30 12:24:33 +00:00
mtx_pool.unlock();
2018-10-29 19:02:12 +00:00
}
const u32 NULL_CONTEXT = ~0u;
static void serializeContext(Serializer& ser, const TA_context *ctx)
{
if (ser.dryrun())
{
// Maximum size: address, size, data, render pass count, render passes
ser.skip(4 + 4 + TA_DATA_SIZE + 4 + ARRAY_SIZE(tad_context::render_passes) * 4);
return;
}
if (ctx == nullptr)
{
ser << NULL_CONTEXT;
return;
}
ser << ctx->Address;
const tad_context& tad = ctx == ::ta_ctx ? ta_tad : ctx->tad;
const u32 taSize = tad.thd_data - tad.thd_root;
ser << taSize;
ser.serialize(tad.thd_root, taSize);
ser << tad.render_pass_count;
for (u32 i = 0; i < tad.render_pass_count; i++)
{
u32 offset = (u32)(tad.render_passes[i] - tad.thd_root);
ser << offset;
}
}
static void deserializeContext(Deserializer& deser, TA_context **pctx)
{
u32 address;
deser >> address;
if (address == NULL_CONTEXT)
{
*pctx = nullptr;
return;
}
*pctx = tactx_Find(address, true);
u32 size;
deser >> size;
tad_context& tad = (*pctx)->tad;
deser.deserialize(tad.thd_root, size);
tad.thd_data = tad.thd_root + size;
if (deser.version() >= Deserializer::V12 || (deser.version() >= Deserializer::V12_LIBRETRO && deser.version() < Deserializer::V5))
{
deser >> tad.render_pass_count;
for (u32 i = 0; i < tad.render_pass_count; i++)
{
u32 offset;
deser >> offset;
tad.render_passes[i] = tad.thd_root + offset;
}
}
else
{
tad.render_pass_count = 0;
}
}
void SerializeTAContext(Serializer& ser)
{
serializeContext(ser, ta_ctx);
if (TA_CURRENT_CTX != CORE_CURRENT_CTX)
serializeContext(ser, tactx_Find(TA_CURRENT_CTX, false));
else
serializeContext(ser, nullptr);
}
void DeserializeTAContext(Deserializer& deser)
{
if (::ta_ctx != nullptr)
SetCurrentTARC(TACTX_NONE);
TA_context *ta_cur_ctx;
deserializeContext(deser, &ta_cur_ctx);
if (ta_cur_ctx != nullptr)
SetCurrentTARC(ta_cur_ctx->Address);
if (deser.version() >= Deserializer::V20)
deserializeContext(deser, &ta_cur_ctx);
}