hwr2: integrate avrecorder with RHI and legacy GL

This commit is contained in:
Eidolon 2023-02-27 19:49:45 -06:00
parent a19b476d3d
commit 98ce714614
15 changed files with 105 additions and 69 deletions

View file

@ -1879,7 +1879,7 @@ static boolean CL_ServerConnectionTicker(const char *tmpsave, tic_t *oldtic, tic
return false;
}
case CL_LOADFILES:
if (CL_LoadServerFiles())
if (CL_LoadServerFiles())
cl_mode = CL_SETUPFILES;
break;
@ -2021,8 +2021,10 @@ static boolean CL_ServerConnectionTicker(const char *tmpsave, tic_t *oldtic, tic
#endif
}
I_UpdateNoVsync(); // page flip or blit buffer
if (moviemode)
#ifdef HWRENDER
if (moviemode && rendermode == render_opengl)
M_LegacySaveFrame();
#endif
S_UpdateSounds();
S_UpdateClosedCaptions();
}
@ -2540,7 +2542,7 @@ void CL_ClearPlayer(INT32 playernum)
if (gamestate == GS_LEVEL)
{
if (players[playernum].follower)
{
{
K_RemoveFollower(&players[playernum]);
}

View file

@ -871,10 +871,10 @@ void D_SRB2Loop(void)
D_Display();
}
// Only take screenshots after drawing.
if (moviemode)
M_LegacySaveFrame();
#ifdef HWRENDER
// Only take screenshots after drawing.
if (moviemode && rendermode == render_opengl)
M_LegacySaveFrame();
if (rendermode == render_opengl && takescreenshot)
M_DoLegacyGLScreenShot();
#endif

View file

@ -437,8 +437,10 @@ void F_IntroTicker(void)
#endif
I_FinishUpdate(); // Update the screen with the image Tails 06-19-2001
if (moviemode) // make sure we save frames for the white hold too
#ifdef HWRENDER
if (moviemode && rendermode == render_opengl) // make sure we save frames for the white hold too
M_LegacySaveFrame();
#endif
}
}
@ -464,7 +466,7 @@ void F_IntroTicker(void)
// check for skipping
if (keypressed)
keypressed = false;
if (animtimer > 0)
animtimer--;
}

View file

@ -525,8 +525,10 @@ void F_RunWipe(UINT8 wipetype, boolean drawMenu, const char *colormap, boolean r
g_wipeskiprender = true;
}
if (moviemode)
#ifdef HWRENDER
if (moviemode && rendermode == render_opengl)
M_LegacySaveFrame();
#endif
NetKeepAlive(); // Update the network so we don't cause timeouts
}

View file

@ -1601,8 +1601,10 @@ void G_PreLevelTitleCard(void)
I_FinishUpdate(); // page flip or blit buffer
NetKeepAlive(); // Prevent timeouts
if (moviemode)
#ifdef HWRENDER
if (moviemode && rendermode == render_opengl)
M_LegacySaveFrame();
#endif
while (!((nowtime = I_GetTime()) - lasttime))
{

View file

@ -34,7 +34,7 @@ void ScreenshotPass::prepass(Rhi& rhi)
);
}
doing_screenshot_ = takescreenshot || moviemode == MM_GIF;
doing_screenshot_ = takescreenshot || moviemode != MM_OFF;
}
void ScreenshotPass::transfer(Rhi& rhi, Handle<TransferContext> ctx)
@ -68,7 +68,7 @@ void ScreenshotPass::postpass(Rhi& rhi)
M_DoScreenShot(width_, height_, tcb::as_bytes(tcb::span(pixel_data_)));
}
if (moviemode == MM_GIF)
if (moviemode != MM_OFF)
{
M_SaveFrame(width_, height_, tcb::as_bytes(tcb::span(pixel_data_)));
}

View file

@ -188,7 +188,7 @@ static InternalPassData build_pass_manager()
framebuffer_manager->swap_post();
pp_simple_blit_pass->set_texture(framebuffer_manager->main_color(), vid.width, vid.height);
pp_simple_blit_pass
->set_output(framebuffer_manager->current_post_color(), vid.width, vid.height, false, true);
->set_output(framebuffer_manager->current_post_color(), vid.width, vid.height, false, false);
}
);
basic_rendering->insert("pp_final_simple_blit", pp_simple_blit_pass);
@ -211,7 +211,7 @@ static InternalPassData build_pass_manager()
[final_composite_pass, framebuffer_manager](PassManager&, Rhi&)
{
final_composite_pass->set_texture(framebuffer_manager->current_post_color(), vid.width, vid.height);
final_composite_pass->set_output(kNullHandle, vid.realwidth, vid.realheight, true, true);
final_composite_pass->set_output(kNullHandle, vid.realwidth, vid.realheight, true, false);
}
);
composite_present_rendering->insert("final_composite", final_composite_pass);
@ -305,6 +305,14 @@ static InternalPassData build_pass_manager()
}
);
wipe_rendering->insert("pp_final_wipe", pp_wipe_pass);
wipe_rendering->insert(
"screenshot_prepare",
[screenshot_pass, framebuffer_manager](PassManager&, Rhi&)
{
screenshot_pass->set_source(framebuffer_manager->current_post_color(), vid.width, vid.height);
}
);
wipe_rendering->insert("screenshot", screenshot_pass);
wipe_rendering->insert("composite_present_rendering", composite_present_rendering);
InternalPassData ret;

View file

@ -229,24 +229,3 @@ void M_AVRecorder_DrawFrameRate(void)
g_av_recorder->draw_statistics();
}
// TODO: remove once hwr2 twodee is finished
void M_AVRecorder_CopySoftwareScreen(void)
{
SRB2_ASSERT(g_av_recorder != nullptr);
auto frame = g_av_recorder->new_indexed_video_frame(vid.width, vid.height);
if (!frame)
{
return;
}
tcb::span<RGBA_t> pal(&pLocalPalette[std::max(st_palette, 0) * 256], 256);
tcb::span<uint8_t> scr(screens[0], vid.width * vid.height);
std::copy(pal.begin(), pal.end(), frame->palette.begin());
std::copy(scr.begin(), scr.end(), frame->screen.begin());
g_av_recorder->push_indexed_video_frame(std::move(frame));
}

View file

@ -34,9 +34,6 @@ void M_AVRecorder_PrintCurrentConfiguration(void);
void M_AVRecorder_DrawFrameRate(void);
// TODO: remove once hwr2 twodee is finished
void M_AVRecorder_CopySoftwareScreen(void);
extern consvar_t
cv_movie_custom_resolution,
cv_movie_duration,

View file

@ -47,6 +47,7 @@
#include "m_anigif.h"
#ifdef SRB2_CONFIG_ENABLE_WEBM_MOVIES
#include "m_avrecorder.h"
#include "m_avrecorder.hpp"
#endif
// So that the screenshot menu auto-updates...
@ -1384,6 +1385,8 @@ void M_StartMovie(void)
#endif
}
static void M_SaveFrame_AVRecorder(uint32_t width, uint32_t height, tcb::span<const std::byte> data);
void M_LegacySaveFrame(void)
{
#if NUMSCREENS > 2
@ -1402,17 +1405,11 @@ void M_LegacySaveFrame(void)
#ifdef SRB2_CONFIG_ENABLE_WEBM_MOVIES
if (moviemode == MM_AVRECORDER)
{
// TODO: replace once hwr2 twodee is finished
if (rendermode == render_soft)
{
M_AVRecorder_CopySoftwareScreen();
}
if (M_AVRecorder_IsExpired())
{
M_StopMovie();
return;
}
return;
}
#endif
@ -1464,6 +1461,15 @@ void M_LegacySaveFrame(void)
}
#else
moviemode = MM_OFF;
#endif
return;
case MM_AVRECORDER:
#if defined(SRB2_CONFIG_ENABLE_WEBM_MOVIES) && defined(HWRENDER)
{
UINT8 *linear = HWR_GetScreenshot();
M_SaveFrame_AVRecorder(vid.width, vid.height, tcb::as_bytes(tcb::span(linear, 3 * vid.width * vid.height)));
free(linear);
}
#endif
return;
default:
@ -1472,7 +1478,7 @@ void M_LegacySaveFrame(void)
#endif
}
void M_SaveFrame(uint32_t width, uint32_t height, tcb::span<const std::byte> data)
static void M_SaveFrame_GIF(uint32_t width, uint32_t height, tcb::span<const std::byte> data)
{
if (moviemode != MM_GIF)
{
@ -1492,6 +1498,44 @@ void M_SaveFrame(uint32_t width, uint32_t height, tcb::span<const std::byte> dat
GIF_frame_rgb24(width, height, reinterpret_cast<const uint8_t*>(data.data()));
}
static void M_SaveFrame_AVRecorder(uint32_t width, uint32_t height, tcb::span<const std::byte> data)
{
#ifdef SRB2_CONFIG_ENABLE_WEBM_MOVIES
if (M_AVRecorder_IsExpired())
{
M_StopMovie();
return;
}
auto frame = g_av_recorder->new_staging_video_frame(width, height);
if (!frame)
{
// Not time to submit a frame!
return;
}
auto data_begin = reinterpret_cast<const uint8_t*>(data.data());
auto data_end = reinterpret_cast<const uint8_t*>(data.data() + data.size_bytes());
std::copy(data_begin, data_end, frame->screen.begin());
g_av_recorder->push_staging_video_frame(std::move(frame));
#endif
}
void M_SaveFrame(uint32_t width, uint32_t height, tcb::span<const std::byte> data)
{
switch (moviemode)
{
case MM_GIF:
M_SaveFrame_GIF(width, height, data);
break;
case MM_AVRECORDER:
M_SaveFrame_AVRecorder(width, height, data);
break;
default:
break;
}
}
void M_StopMovie(void)
{
#if NUMSCREENS > 2

View file

@ -58,17 +58,16 @@ public:
};
// TODO: remove once hwr2 twodee is finished
struct IndexedVideoFrame
struct StagingVideoFrame
{
using instance_t = std::unique_ptr<IndexedVideoFrame>;
using instance_t = std::unique_ptr<StagingVideoFrame>;
std::array<RGBA_t, 256> palette;
std::vector<uint8_t> screen;
uint32_t width, height;
int pts;
IndexedVideoFrame(uint32_t width_, uint32_t height_, int pts_) :
screen(width_ * height_), width(width_), height(height_), pts(pts_)
StagingVideoFrame(uint32_t width_, uint32_t height_, int pts_) :
screen(width_ * height_ * 3), width(width_), height(height_), pts(pts_)
{
}
};
@ -87,9 +86,9 @@ public:
// May return nullptr in case called between units of
// Config::frame_rate
IndexedVideoFrame::instance_t new_indexed_video_frame(uint32_t width, uint32_t height);
StagingVideoFrame::instance_t new_staging_video_frame(uint32_t width, uint32_t height);
void push_indexed_video_frame(IndexedVideoFrame::instance_t frame);
void push_staging_video_frame(StagingVideoFrame::instance_t frame);
// Proper name of the container format.
const char* format_name() const;

View file

@ -53,7 +53,7 @@ public:
template <typename _>
struct Traits<VideoEncoder, _>
{
using frame_type = IndexedVideoFrame::instance_t;
using frame_type = StagingVideoFrame::instance_t;
};
std::vector<typename Traits<T>::frame_type> vec_;
@ -151,8 +151,7 @@ private:
void container_dtor_handler(const MediaContainer& container) const;
// TODO: remove once hwr2 twodee is finished
VideoFrame::instance_t convert_indexed_video_frame(const IndexedVideoFrame& indexed);
VideoFrame::instance_t convert_staging_video_frame(const StagingVideoFrame& indexed);
};
template <>

View file

@ -21,34 +21,36 @@ using namespace srb2::media;
using Impl = AVRecorder::Impl;
VideoFrame::instance_t Impl::convert_indexed_video_frame(const IndexedVideoFrame& indexed)
VideoFrame::instance_t Impl::convert_staging_video_frame(const StagingVideoFrame& staging)
{
VideoFrame::instance_t frame = video_encoder_->new_frame(indexed.width, indexed.height, indexed.pts);
VideoFrame::instance_t frame = video_encoder_->new_frame(staging.width, staging.height, staging.pts);
SRB2_ASSERT(frame != nullptr);
const VideoFrame::Buffer& buffer = frame->rgba_buffer();
const uint8_t* s = indexed.screen.data();
const uint8_t* s = staging.screen.data();
uint8_t* p = buffer.plane.data();
// Convert from RGB8 to RGBA8
for (int y = 0; y < frame->height(); ++y)
{
for (int x = 0; x < frame->width(); ++x)
{
const RGBA_t& c = indexed.palette[s[x]];
reinterpret_cast<uint32_t*>(p)[x] = c.rgba;
p[x * 4] = s[x * 3];
p[x * 4 + 1] = s[x * 3 + 1];
p[x * 4 + 2] = s[x * 3 + 2];
p[x * 4 + 3] = 255;
}
s += indexed.width;
s += staging.width * 3;
p += buffer.row_stride;
}
return frame;
}
AVRecorder::IndexedVideoFrame::instance_t AVRecorder::new_indexed_video_frame(uint32_t width, uint32_t height)
AVRecorder::StagingVideoFrame::instance_t AVRecorder::new_staging_video_frame(uint32_t width, uint32_t height)
{
std::optional<int> pts = impl_->advance_video_pts();
@ -57,10 +59,10 @@ AVRecorder::IndexedVideoFrame::instance_t AVRecorder::new_indexed_video_frame(ui
return nullptr;
}
return std::make_unique<IndexedVideoFrame>(width, height, *pts);
return std::make_unique<StagingVideoFrame>(width, height, *pts);
}
void AVRecorder::push_indexed_video_frame(IndexedVideoFrame::instance_t frame)
void AVRecorder::push_staging_video_frame(StagingVideoFrame::instance_t frame)
{
auto _ = impl_->queue_guard();

View file

@ -125,7 +125,7 @@ Impl::QueueState Impl::encode_queues()
{
for (auto& p : copy)
{
auto frame = convert_indexed_video_frame(*p);
auto frame = convert_staging_video_frame(*p);
video_encoder_->encode(std::move(frame));
}

View file

@ -380,7 +380,7 @@ void P_DeleteFlickies(INT16 i)
static void P_ClearSingleMapHeaderInfo(INT16 num)
{
UINT8 i = 0;
mapheaderinfo[num]->lvlttl[0] = '\0';
mapheaderinfo[num]->subttl[0] = '\0';
mapheaderinfo[num]->zonttl[0] = '\0';
@ -7570,7 +7570,7 @@ boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate)
I_UpdateTime(cv_timescale.value); \
} \
lastwipetic = nowtime; \
if (moviemode) \
if (moviemode && rendermode == render_opengl) \
M_LegacySaveFrame(); \
NetKeepAlive(); \
} \