flycast/core/hw/pvr/Renderer_if.cpp

394 lines
7.6 KiB
C++
Raw Normal View History

2013-12-19 17:10:14 +00:00
#include "Renderer_if.h"
#include "spg.h"
2013-12-19 17:10:14 +00:00
#include "hw/pvr/pvr_mem.h"
2020-03-28 16:58:01 +00:00
#include "rend/TexCache.h"
#include "cfg/option.h"
2021-09-02 15:51:23 +00:00
#include "network/ggpo.h"
#include "emulator.h"
#include "serialize.h"
2013-12-19 17:10:14 +00:00
#include <mutex>
2015-01-16 20:37:30 +00:00
2021-07-07 11:12:16 +00:00
void retro_rend_present();
#ifndef LIBRETRO
void retro_rend_present()
{
if (!config::ThreadedRendering)
sh4_cpu.Stop();
}
2021-07-07 11:12:16 +00:00
#endif
2013-12-19 17:10:14 +00:00
u32 VertexCount=0;
u32 FrameCount=1;
2013-12-19 17:10:14 +00:00
Renderer* renderer;
2015-07-29 04:22:59 +00:00
cResetEvent rs, re;
static bool do_swap;
std::mutex swap_mutex;
u32 fb_w_cur = 1;
static cResetEvent vramRollback;
2013-12-19 17:10:14 +00:00
// direct framebuffer write detection
2018-08-26 14:58:10 +00:00
static bool render_called = false;
u32 fb_watch_addr_start;
u32 fb_watch_addr_end;
2018-08-26 14:58:10 +00:00
bool fb_dirty;
static bool pend_rend;
2013-12-19 17:10:14 +00:00
TA_context* _pvrrc;
static bool rend_frame(TA_context* ctx)
{
2015-01-16 20:37:30 +00:00
bool proc = renderer->Process(ctx);
2018-08-26 14:58:10 +00:00
if (!proc || (!ctx->rend.isRTT && !ctx->rend.isRenderFramebuffer))
// If rendering to texture, continue locking until the frame is rendered
re.Set();
rend_allow_rollback();
2015-01-16 20:37:30 +00:00
return proc && renderer->Render();
2015-01-16 20:37:30 +00:00
}
2014-12-11 01:57:23 +00:00
bool rend_single_frame(const bool& enabled)
2013-12-19 17:10:14 +00:00
{
do
2013-12-19 17:10:14 +00:00
{
2021-07-07 11:12:16 +00:00
if (config::ThreadedRendering && !rs.Wait(50))
return false;
if (do_swap)
2019-02-06 18:57:13 +00:00
{
do_swap = false;
if (renderer->Present())
{
rs.Set(); // don't miss any render
2021-07-07 11:12:16 +00:00
retro_rend_present();
return true;
}
2019-02-06 18:57:13 +00:00
}
if (!enabled)
return false;
2013-12-19 17:10:14 +00:00
_pvrrc = DequeueRender();
2021-07-07 11:12:16 +00:00
if (!config::ThreadedRendering && _pvrrc == nullptr)
return false;
2013-12-19 17:10:14 +00:00
}
2021-07-07 11:12:16 +00:00
while (_pvrrc == nullptr);
2013-12-19 17:10:14 +00:00
bool frame_rendered = rend_frame(_pvrrc);
if (frame_rendered)
{
{
std::lock_guard<std::mutex> lock(swap_mutex);
if (config::DelayFrameSwapping && !_pvrrc->rend.isRenderFramebuffer && fb_w_cur != FB_R_SOF1 && !do_swap)
// Delay swap
frame_rendered = false;
else
// Swap now
do_swap = false;
}
if (frame_rendered)
2021-07-07 11:12:16 +00:00
{
frame_rendered = renderer->Present();
2021-07-07 11:12:16 +00:00
if (frame_rendered)
retro_rend_present();
}
}
if (_pvrrc->rend.isRTT)
re.Set();
2013-12-19 17:10:14 +00:00
//clear up & free data ..
FinishRender(_pvrrc);
_pvrrc = nullptr;
2013-12-19 17:10:14 +00:00
return frame_rendered;
2013-12-19 17:10:14 +00:00
}
Renderer* rend_GLES2();
Renderer* rend_GL4();
Renderer* rend_norend();
Renderer* rend_Vulkan();
Renderer* rend_OITVulkan();
2021-04-12 20:49:04 +00:00
Renderer* rend_DirectX9();
2021-11-26 17:08:41 +00:00
Renderer* rend_DirectX11();
2021-12-11 17:53:35 +00:00
Renderer* rend_OITDirectX11();
static void rend_create_renderer()
{
#ifdef NO_REND
renderer = rend_norend();
#else
switch (config::RendererType)
{
default:
#ifdef USE_OPENGL
case RenderType::OpenGL:
renderer = rend_GLES2();
break;
2020-04-26 08:03:57 +00:00
#if !defined(GLES) && !defined(__APPLE__)
case RenderType::OpenGL_OIT:
renderer = rend_GL4();
break;
2019-10-05 09:50:14 +00:00
#endif
#endif
2019-10-05 09:50:14 +00:00
#ifdef USE_VULKAN
case RenderType::Vulkan:
2019-10-05 09:50:14 +00:00
renderer = rend_Vulkan();
break;
case RenderType::Vulkan_OIT:
renderer = rend_OITVulkan();
break;
2021-04-12 20:49:04 +00:00
#endif
2021-11-19 22:18:45 +00:00
#ifdef USE_DX9
2021-04-12 20:49:04 +00:00
case RenderType::DirectX9:
renderer = rend_DirectX9();
break;
2021-11-26 17:08:41 +00:00
#endif
#if (defined(_WIN32) && !defined(LIBRETRO)) || defined(HAVE_D3D11)
2021-11-26 17:08:41 +00:00
case RenderType::DirectX11:
renderer = rend_DirectX11();
break;
2021-12-11 17:53:35 +00:00
case RenderType::DirectX11_OIT:
renderer = rend_OITDirectX11();
break;
2018-10-04 18:01:14 +00:00
#endif
}
#endif
}
void rend_init_renderer()
{
if (renderer == nullptr)
rend_create_renderer();
if (!renderer->Init())
die("Renderer initialization failed\n");
}
void rend_term_renderer()
{
if (renderer != nullptr)
2020-02-26 22:41:05 +00:00
{
renderer->Term();
delete renderer;
renderer = nullptr;
}
}
void rend_reset()
2013-12-19 17:10:14 +00:00
{
FinishRender(DequeueRender());
do_swap = false;
render_called = false;
pend_rend = false;
FrameCount = 1;
VertexCount = 0;
fb_w_cur = 1;
2013-12-19 17:10:14 +00:00
}
void rend_start_render(TA_context *ctx)
2013-12-19 17:10:14 +00:00
{
2018-08-26 14:58:10 +00:00
render_called = true;
pend_rend = false;
if (ctx == nullptr)
{
u32 addresses[MAX_PASSES];
int count = getTAContextAddresses(addresses);
if (count > 0)
{
ctx = tactx_Pop(addresses[0]);
if (ctx != nullptr)
{
TA_context *linkedCtx = ctx;
for (int i = 1; i < count; i++)
{
linkedCtx->nextContext = tactx_Pop(addresses[i]);
if (linkedCtx->nextContext != nullptr)
linkedCtx = linkedCtx->nextContext;
}
}
}
}
2013-12-19 17:10:14 +00:00
2018-08-26 14:58:10 +00:00
// No end of render interrupt when rendering the framebuffer
if (!ctx || !ctx->rend.isRenderFramebuffer)
SetREP(ctx);
2013-12-19 17:10:14 +00:00
if (ctx)
{
if (ctx->rend.isRenderFramebuffer)
{
ctx->rend.isRTT = false;
ctx->rend.fb_X_CLIP.min = 0;
ctx->rend.fb_X_CLIP.max = 639;
ctx->rend.fb_Y_CLIP.min = 0;
ctx->rend.fb_Y_CLIP.max = 479;
ctx->rend.fog_clamp_min.full = 0;
ctx->rend.fog_clamp_max.full = 0xffffffff;
}
else
{
FillBGP(ctx);
ctx->rend.isRTT = (FB_W_SOF1 & 0x1000000) != 0;
ctx->rend.fb_X_CLIP = FB_X_CLIP;
ctx->rend.fb_Y_CLIP = FB_Y_CLIP;
ctx->rend.fb_W_LINESTRIDE = FB_W_LINESTRIDE.stride;
ctx->rend.fog_clamp_min = FOG_CLAMP_MIN;
ctx->rend.fog_clamp_max = FOG_CLAMP_MAX;
}
if (!config::DelayFrameSwapping && !ctx->rend.isRTT)
ggpo::endOfFrame();
palette_update();
if (QueueRender(ctx))
2013-12-19 17:10:14 +00:00
{
pend_rend = true;
2021-07-07 11:12:16 +00:00
if (!config::ThreadedRendering)
rend_single_frame(true);
else
rs.Set();
2013-12-19 17:10:14 +00:00
}
}
}
void rend_end_render()
{
2021-07-07 11:12:16 +00:00
if (pend_rend && config::ThreadedRendering)
re.Wait();
2013-12-19 17:10:14 +00:00
}
void rend_vblank()
{
2018-08-26 14:58:10 +00:00
if (!render_called && fb_dirty && FB_R_CTRL.fb_enable)
{
2019-07-01 09:42:00 +00:00
DEBUG_LOG(PVR, "Direct framebuffer write detected");
TA_context *ctx = new TA_context();
ctx->Alloc();
ctx->rend.isRenderFramebuffer = true;
rend_start_render(ctx);
2018-08-26 14:58:10 +00:00
fb_dirty = false;
}
render_called = false;
check_framebuffer_write();
emu.vblank();
2013-12-19 17:10:14 +00:00
}
2018-08-26 14:58:10 +00:00
void check_framebuffer_write()
{
u32 fb_size = (FB_R_SIZE.fb_y_size + 1) * (FB_R_SIZE.fb_x_size + FB_R_SIZE.fb_modulus) * 4;
fb_watch_addr_start = (SPG_CONTROL.interlace ? FB_R_SOF2 : FB_R_SOF1) & VRAM_MASK;
fb_watch_addr_end = fb_watch_addr_start + fb_size;
2018-08-26 14:58:10 +00:00
}
2018-09-23 14:18:35 +00:00
void rend_cancel_emu_wait()
{
2021-07-07 11:12:16 +00:00
if (config::ThreadedRendering)
{
FinishRender(NULL);
re.Set();
rend_allow_rollback();
2021-07-07 11:12:16 +00:00
}
2018-09-23 14:18:35 +00:00
}
void rend_set_fb_write_addr(u32 fb_w_sof1)
{
if (fb_w_sof1 & 0x1000000)
// render to texture
return;
fb_w_cur = fb_w_sof1;
}
void rend_swap_frame(u32 fb_r_sof)
{
swap_mutex.lock();
if (fb_r_sof == fb_w_cur)
{
do_swap = true;
2021-07-07 11:12:16 +00:00
if (config::ThreadedRendering)
rs.Set();
else
{
swap_mutex.unlock();
2021-07-07 11:12:16 +00:00
rend_single_frame(true);
swap_mutex.lock();
}
if (config::DelayFrameSwapping)
ggpo::endOfFrame();
}
swap_mutex.unlock();
}
void rend_disable_rollback()
{
vramRollback.Reset();
}
void rend_allow_rollback()
{
vramRollback.Set();
}
void rend_start_rollback()
{
if (config::ThreadedRendering)
vramRollback.Wait();
}
void rend_serialize(Serializer& ser)
{
ser << fb_w_cur;
ser << render_called;
ser << fb_dirty;
ser << fb_watch_addr_start;
ser << fb_watch_addr_end;
}
void rend_deserialize(Deserializer& deser)
{
if ((deser.version() >= Deserializer::V12_LIBRETRO && deser.version() < Deserializer::V5) || deser.version() >= Deserializer::V12)
deser >> fb_w_cur;
else
fb_w_cur = 1;
if (deser.version() >= Deserializer::V20)
{
deser >> render_called;
deser >> fb_dirty;
deser >> fb_watch_addr_start;
deser >> fb_watch_addr_end;
}
pend_rend = false;
}
2021-09-27 18:29:23 +00:00
void rend_resize_renderer()
{
if (renderer == nullptr)
return;
float hres;
int vres = config::RenderResolution;
if (config::Widescreen && !config::Rotate90)
{
if (config::SuperWidescreen)
hres = (float)config::RenderResolution * settings.display.width / settings.display.height;
else
hres = config::RenderResolution * 16.f / 9.f;
}
else if (config::Rotate90)
{
vres = vres * config::ScreenStretching / 100;
hres = config::RenderResolution * 4.f / 3.f;
}
else
{
hres = config::RenderResolution * 4.f * config::ScreenStretching / 3.f / 100.f;
}
if (!config::Rotate90)
hres = std::roundf(hres / 2.f) * 2.f;
DEBUG_LOG(RENDERER, "rend_resize_renderer: %d x %d", (int)hres, vres);
renderer->Resize((int)hres, vres);
}