hwr2: overhaul wipe rendering

This commit is contained in:
Eidolon 2023-02-17 21:19:35 -06:00
parent 0a9e9bbbae
commit 31ce947659
14 changed files with 647 additions and 154 deletions

View file

@ -800,6 +800,9 @@ void D_SRB2Loop(void)
HW3S_BeginFrameUpdate();
#endif
I_NewTwodeeFrame();
I_NewImguiFrame();
if (realtics > 0 || singletics)
{
// don't skip more than 10 frames at a time
@ -1491,6 +1494,9 @@ void D_SRB2Main(void)
CONS_Printf("I_StartupGraphics()...\n");
I_StartupGraphics();
I_NewTwodeeFrame();
I_NewImguiFrame();
#ifdef HWRENDER
// Lactozilla: Add every hardware mode CVAR and CCMD.
// Has to be done before the configuration file loads,

View file

@ -144,6 +144,7 @@ extern UINT8 g_wipetype;
extern UINT8 g_wipeframe;
extern boolean g_wipereverse;
extern boolean g_wipeskiprender;
extern boolean g_wipeencorewiggle;
extern boolean WipeStageTitle;
extern INT32 lastwipetic;
@ -159,6 +160,14 @@ void F_WipeStageTitle(void);
#define F_WipeColorFill(c) V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, c)
tic_t F_GetWipeLength(UINT8 wipetype);
boolean F_WipeExists(UINT8 wipetype);
/// @brief true if the wipetype is to-black
boolean F_WipeIsToBlack(UINT8 wipetype);
/// @brief true if the wipetype is to-white
boolean F_WipeIsToWhite(UINT8 wipetype);
/// @brief true if the wipetype is to-invert
boolean F_WipeIsToInvert(UINT8 wipetype);
/// @brief true if the wipetype is modulated from the previous frame
boolean F_WipeIsCrossfade(UINT8 wipetype);
enum
{

View file

@ -85,6 +85,138 @@ UINT8 wipedefs[NUMWIPEDEFS] = {
99 // wipe_cutscene_final (hardcoded)
};
static boolean g_wipedef_toblack[NUMWIPEDEFS] = {
true, // wipe_credits_intermediate (0)
true, // wipe_level_toblack
true, // wipe_intermission_toblack
true, // wipe_voting_toblack,
true, // wipe_continuing_toblack
true, // wipe_titlescreen_toblack
true, // wipe_menu_toblack
true, // wipe_credits_toblack
true, // wipe_evaluation_toblack
true, // wipe_gameend_toblack
true, // wipe_intro_toblack (hardcoded)
true, // wipe_ending_toblack (hardcoded)
true, // wipe_cutscene_toblack (hardcoded)
false, // wipe_encore_toinvert
false, // wipe_encore_towhite
true, // wipe_level_final
true, // wipe_intermission_final
true, // wipe_voting_final
true, // wipe_continuing_final
true, // wipe_titlescreen_final
true, // wipe_menu_final
true, // wipe_credits_final
true, // wipe_evaluation_final
true, // wipe_gameend_final
true, // wipe_intro_final (hardcoded)
true, // wipe_ending_final (hardcoded)
true // wipe_cutscene_final (hardcoded)
};
static boolean g_wipedef_toinvert[NUMWIPEDEFS] = {
false, // wipe_credits_intermediate (0)
false, // wipe_level_toblack
false, // wipe_intermission_toblack
false, // wipe_voting_toblack,
false, // wipe_continuing_toblack
false, // wipe_titlescreen_toblack
false, // wipe_menu_toblack
false, // wipe_credits_toblack
false, // wipe_evaluation_toblack
false, // wipe_gameend_toblack
false, // wipe_intro_toblack (hardcoded)
false, // wipe_ending_toblack (hardcoded)
false, // wipe_cutscene_toblack (hardcoded)
true, // wipe_encore_toinvert
false, // wipe_encore_towhite
false, // wipe_level_final
false, // wipe_intermission_final
false, // wipe_voting_final
false, // wipe_continuing_final
false, // wipe_titlescreen_final
false, // wipe_menu_final
false, // wipe_credits_final
false, // wipe_evaluation_final
false, // wipe_gameend_final
false, // wipe_intro_final (hardcoded)
false, // wipe_ending_final (hardcoded)
false // wipe_cutscene_final (hardcoded)
};
static boolean g_wipedef_towhite[NUMWIPEDEFS] = {
false, // wipe_credits_intermediate (0)
false, // wipe_level_toblack
false, // wipe_intermission_toblack
false, // wipe_voting_toblack,
false, // wipe_continuing_toblack
false, // wipe_titlescreen_toblack
false, // wipe_menu_toblack
false, // wipe_credits_toblack
false, // wipe_evaluation_toblack
false, // wipe_gameend_toblack
false, // wipe_intro_toblack (hardcoded)
false, // wipe_ending_toblack (hardcoded)
false, // wipe_cutscene_toblack (hardcoded)
false, // wipe_encore_toinvert
true, // wipe_encore_towhite
false, // wipe_level_final
false, // wipe_intermission_final
false, // wipe_voting_final
false, // wipe_continuing_final
false, // wipe_titlescreen_final
false, // wipe_menu_final
false, // wipe_credits_final
false, // wipe_evaluation_final
false, // wipe_gameend_final
false, // wipe_intro_final (hardcoded)
false, // wipe_ending_final (hardcoded)
false // wipe_cutscene_final (hardcoded)
};
static boolean g_wipedef_crossfade[NUMWIPEDEFS] = {
false, // wipe_credits_intermediate (0)
false, // wipe_level_toblack
false, // wipe_intermission_toblack
false, // wipe_voting_toblack,
false, // wipe_continuing_toblack
false, // wipe_titlescreen_toblack
false, // wipe_menu_toblack
false, // wipe_credits_toblack
false, // wipe_evaluation_toblack
false, // wipe_gameend_toblack
false, // wipe_intro_toblack (hardcoded)
false, // wipe_ending_toblack (hardcoded)
false, // wipe_cutscene_toblack (hardcoded)
false, // wipe_encore_toinvert
false, // wipe_encore_towhite
true, // wipe_level_final
true, // wipe_intermission_final
true, // wipe_voting_final
true, // wipe_continuing_final
true, // wipe_titlescreen_final
true, // wipe_menu_final
true, // wipe_credits_final
true, // wipe_evaluation_final
true, // wipe_gameend_final
true, // wipe_intro_final (hardcoded)
true, // wipe_ending_final (hardcoded)
true // wipe_cutscene_final (hardcoded)
};
//--------------------------------------------------------------------------
// SCREEN WIPE PACKAGE
//--------------------------------------------------------------------------
@ -94,6 +226,7 @@ UINT8 g_wipetype = 0;
UINT8 g_wipeframe = 0;
boolean g_wipereverse = false;
boolean g_wipeskiprender = false;
boolean g_wipeencorewiggle = false;
boolean WipeStageTitle = false;
INT32 lastwipetic = 0;
@ -207,8 +340,9 @@ void F_WipeStartScreen(void)
return;
}
#endif
wipe_scr_start = screens[3];
I_ReadScreen(wipe_scr_start);
// wipe_scr_start = screens[3];
// I_ReadScreen(wipe_scr_start);
I_FinishUpdateWipeStartScreen();
#endif
}
@ -224,9 +358,10 @@ void F_WipeEndScreen(void)
return;
}
#endif
wipe_scr_end = screens[4];
I_ReadScreen(wipe_scr_end);
V_DrawBlock(0, 0, 0, vid.width, vid.height, wipe_scr_start);
// wipe_scr_end = screens[4];
// I_ReadScreen(wipe_scr_end);
// V_DrawBlock(0, 0, 0, vid.width, vid.height, wipe_scr_start);
I_FinishUpdateWipeEndScreen();
#endif
}
@ -360,10 +495,11 @@ void F_RunWipe(UINT8 wipetype, boolean drawMenu, const char *colormap, boolean r
if (encorewiggle)
{
#ifdef HWRENDER
if (rendermode != render_opengl)
#endif
F_DoEncoreWiggle(wipeframe);
g_wipeencorewiggle = wipeframe - 1;
}
else
{
g_wipeencorewiggle = 0;
}
}
@ -381,7 +517,7 @@ void F_RunWipe(UINT8 wipetype, boolean drawMenu, const char *colormap, boolean r
#endif
}
I_FinishUpdate(); // page flip or blit buffer
I_FinishUpdateWipe(); // page flip or blit buffer
if (rendermode != render_none)
{
@ -454,3 +590,24 @@ boolean F_WipeExists(UINT8 wipetype)
return !(lumpnum == LUMPERROR);
#endif
}
boolean F_WipeIsToBlack(UINT8 wipetype)
{
return g_wipedef_toblack[wipetype];
}
boolean F_WipeIsToWhite(UINT8 wipetype)
{
return g_wipedef_towhite[wipetype];
}
boolean F_WipeIsToInvert(UINT8 wipetype)
{
return g_wipedef_toinvert[wipetype];
}
boolean F_WipeIsCrossfade(UINT8 wipetype)
{
return g_wipedef_crossfade[wipetype];
}

View file

@ -80,6 +80,8 @@ void LambdaPass::postpass(Rhi& rhi)
}
PassManager::PassManager() = default;
PassManager::PassManager(const PassManager&) = default;
PassManager& PassManager::operator=(const PassManager&) = default;
void PassManager::insert(const std::string& name, std::shared_ptr<Pass> pass)
{
@ -124,13 +126,8 @@ std::weak_ptr<Pass> PassManager::for_name(const std::string& name)
return passes_[itr->second].pass;
}
void PassManager::render(Rhi& rhi) const
void PassManager::prepass(Rhi& rhi)
{
if (passes_.empty())
{
return;
}
for (auto& pass : passes_)
{
if (pass.enabled)
@ -138,27 +135,32 @@ void PassManager::render(Rhi& rhi) const
pass.pass->prepass(rhi);
}
}
}
Handle<TransferContext> tc = rhi.begin_transfer();
void PassManager::transfer(Rhi& rhi, Handle<TransferContext> ctx)
{
for (auto& pass : passes_)
{
if (pass.enabled)
{
pass.pass->transfer(rhi, tc);
pass.pass->transfer(rhi, ctx);
}
}
rhi.end_transfer(tc);
}
Handle<GraphicsContext> gc = rhi.begin_graphics();
void PassManager::graphics(Rhi& rhi, Handle<GraphicsContext> ctx)
{
for (auto& pass : passes_)
{
if (pass.enabled)
{
pass.pass->graphics(rhi, gc);
pass.pass->graphics(rhi, ctx);
}
}
rhi.end_graphics(gc);
}
void PassManager::postpass(Rhi& rhi)
{
for (auto& pass : passes_)
{
if (pass.enabled)
@ -167,3 +169,23 @@ void PassManager::render(Rhi& rhi) const
}
}
}
void PassManager::render(Rhi& rhi)
{
if (passes_.empty())
{
return;
}
prepass(rhi);
Handle<TransferContext> tc = rhi.begin_transfer();
transfer(rhi, tc);
rhi.end_transfer(tc);
Handle<GraphicsContext> gc = rhi.begin_graphics();
graphics(rhi, gc);
rhi.end_graphics(gc);
postpass(rhi);
}

View file

@ -23,7 +23,7 @@
namespace srb2::hwr2
{
class PassManager
class PassManager final : public Pass
{
struct PassManagerEntry
{
@ -37,11 +37,16 @@ class PassManager
public:
PassManager();
PassManager(const PassManager&) = delete;
PassManager(const PassManager&);
PassManager(PassManager&&) = delete;
PassManager& operator=(const PassManager&) = delete;
PassManager& operator=(const PassManager&);
PassManager& operator=(PassManager&&) = delete;
virtual void prepass(rhi::Rhi& rhi) override;
virtual void transfer(rhi::Rhi& rhi, rhi::Handle<rhi::TransferContext> ctx) override;
virtual void graphics(rhi::Rhi& rhi, rhi::Handle<rhi::GraphicsContext> ctx) override;
virtual void postpass(rhi::Rhi& rhi) override;
void insert(const std::string& name, std::shared_ptr<Pass> pass);
void insert(const std::string& name, std::function<void(PassManager&, rhi::Rhi&)> prepass_func);
void insert(
@ -52,7 +57,7 @@ public:
std::weak_ptr<Pass> for_name(const std::string& name);
void set_pass_enabled(const std::string& name, bool enabled);
void render(rhi::Rhi& rhi) const;
void render(rhi::Rhi& rhi);
};
} // namespace srb2::hwr2

View file

@ -46,8 +46,8 @@ static const PipelineDesc kWipePipelineDesc = {
{VertexAttributeName::kPosition, 0, 0},
{VertexAttributeName::kTexCoord0, 0, 12},
}},
{{{{UniformName::kProjection}}}},
{{SamplerName::kSampler0, SamplerName::kSampler1}},
{{{{UniformName::kProjection, UniformName::kWipeColorizeMode, UniformName::kWipeEncoreSwizzle}}}},
{{SamplerName::kSampler0, SamplerName::kSampler1, SamplerName::kSampler2}},
std::nullopt,
{PixelFormat::kRGBA8, std::nullopt, {true, true, true, true}},
PrimitiveType::kTriangles,
@ -55,7 +55,7 @@ static const PipelineDesc kWipePipelineDesc = {
FaceWinding::kCounterClockwise,
{0.f, 0.f, 0.f, 1.f}};
PostprocessWipePass::PostprocessWipePass() : Pass()
PostprocessWipePass::PostprocessWipePass()
{
}
@ -89,6 +89,27 @@ void PostprocessWipePass::prepass(Rhi& rhi)
uint32_t wipe_type = g_wipetype;
uint32_t wipe_frame = g_wipeframe;
bool wipe_reverse = g_wipereverse;
wipe_color_mode_ = 0; // TODO 0 = modulate, 1 = invert, 2 = MD to black, 3 = MD to white
if (F_WipeIsToBlack(wipe_type))
{
wipe_color_mode_ = 2;
}
else if (F_WipeIsToWhite(wipe_type))
{
wipe_color_mode_ = 3;
}
else if (F_WipeIsToInvert(wipe_type))
{
wipe_color_mode_ = 1;
}
else if (F_WipeIsCrossfade(wipe_type))
{
wipe_color_mode_ = 0;
}
wipe_swizzle_ = g_wipeencorewiggle;
if (wipe_type >= 100 || wipe_frame >= 100)
{
return;
@ -145,7 +166,7 @@ void PostprocessWipePass::transfer(Rhi& rhi, Handle<TransferContext> ctx)
return;
}
if (source_ == kNullHandle)
if (start_ == kNullHandle || end_ == kNullHandle)
{
return;
}
@ -166,13 +187,17 @@ void PostprocessWipePass::transfer(Rhi& rhi, Handle<TransferContext> ctx)
rhi.update_texture(ctx, wipe_tex_, {0, 0, mask_w_, mask_h_}, PixelFormat::kR8, data);
UniformVariant uniforms[] = {
{// Projection
std::array<std::array<float, 4>, 4> {
{{2.f, 0.f, 0.f, 0.f}, {0.f, 2.f, 0.f, 0.f}, {0.f, 0.f, 1.f, 0.f}, {0.f, 0.f, 0.f, 1.f}}}}};
{std::array<std::array<float, 4>, 4> {
{{2.f, 0.f, 0.f, 0.f}, {0.f, 2.f, 0.f, 0.f}, {0.f, 0.f, 1.f, 0.f}, {0.f, 0.f, 0.f, 1.f}}}},
{static_cast<int32_t>(wipe_color_mode_)},
{static_cast<int32_t>(wipe_swizzle_)}};
us_ = rhi.create_uniform_set(ctx, {tcb::span(uniforms)});
VertexAttributeBufferBinding vbos[] = {{0, vbo_}};
TextureBinding tx[] = {{SamplerName::kSampler0, source_}, {SamplerName::kSampler1, wipe_tex_}};
TextureBinding tx[] = {
{SamplerName::kSampler0, start_},
{SamplerName::kSampler1, end_},
{SamplerName::kSampler2, wipe_tex_}};
bs_ = rhi.create_binding_set(ctx, pipeline_, {vbos, tx});
}

View file

@ -19,6 +19,7 @@ namespace srb2::hwr2
class PostprocessWipePass final : public Pass
{
// Internal RHI resources
rhi::Handle<rhi::RenderPass> render_pass_;
rhi::Handle<rhi::Pipeline> pipeline_;
rhi::Handle<rhi::Buffer> vbo_;
@ -28,14 +29,17 @@ class PostprocessWipePass final : public Pass
rhi::Handle<rhi::UniformSet> us_;
rhi::Handle<rhi::BindingSet> bs_;
rhi::Handle<rhi::Texture> wipe_tex_;
rhi::Handle<rhi::Texture> source_;
uint32_t source_w_ = 0;
uint32_t source_h_ = 0;
int wipe_color_mode_ = 0;
int wipe_swizzle_ = 0;
// Pass parameters
rhi::Handle<rhi::Texture> start_;
rhi::Handle<rhi::Texture> end_;
rhi::Handle<rhi::Texture> target_;
uint32_t target_w_ = 0;
uint32_t target_h_ = 0;
// Mask lump loading
std::vector<uint8_t> mask_data_;
uint32_t mask_w_ = 0;
uint32_t mask_h_ = 0;
@ -49,12 +53,7 @@ public:
virtual void graphics(rhi::Rhi& rhi, rhi::Handle<rhi::GraphicsContext> ctx) override;
virtual void postpass(rhi::Rhi& rhi) override;
void set_source(rhi::Handle<rhi::Texture> source, uint32_t width, uint32_t height) noexcept
{
source_ = source;
source_w_ = width;
source_h_ = height;
}
void set_start(rhi::Handle<rhi::Texture> start) noexcept { start_ = start; }
void set_end(rhi::Handle<rhi::Texture> end) noexcept { end_ = end; }

View file

@ -59,6 +59,16 @@ void FramebufferManager::prepass(Rhi& rhi)
rhi.destroy_texture(post_colors_[1]);
post_colors_[1] = kNullHandle;
}
if (wipe_start_color_ != kNullHandle)
{
rhi.destroy_texture(wipe_start_color_);
wipe_start_color_ = kNullHandle;
}
if (wipe_end_color_ != kNullHandle)
{
rhi.destroy_texture(wipe_end_color_);
wipe_end_color_ = kNullHandle;
}
}
width_ = current_width;
height_ = current_height;
@ -85,6 +95,15 @@ void FramebufferManager::prepass(Rhi& rhi)
{
post_colors_[1] = rhi.create_texture({TextureFormat::kRGBA, current_width, current_height});
}
if (wipe_start_color_ == kNullHandle)
{
wipe_start_color_ = rhi.create_texture({TextureFormat::kRGBA, current_width, current_height});
}
if (wipe_end_color_ == kNullHandle)
{
wipe_end_color_ = rhi.create_texture({TextureFormat::kRGBA, current_width, current_height});
}
}
void FramebufferManager::transfer(Rhi& rhi, Handle<TransferContext> ctx)
@ -131,6 +150,45 @@ void MainPaletteManager::postpass(Rhi& rhi)
{
}
CommonResourcesManager::CommonResourcesManager() = default;
CommonResourcesManager::~CommonResourcesManager() = default;
void CommonResourcesManager::prepass(Rhi& rhi)
{
if (!init_)
{
black_ = rhi.create_texture({TextureFormat::kRGBA, 1, 1});
white_ = rhi.create_texture({TextureFormat::kRGBA, 1, 1});
transparent_ = rhi.create_texture({TextureFormat::kRGBA, 1, 1});
}
}
void CommonResourcesManager::transfer(Rhi& rhi, Handle<TransferContext> ctx)
{
if (!init_)
{
uint8_t black[4] = {0, 0, 0, 255};
tcb::span<const std::byte> black_bytes = tcb::as_bytes(tcb::span(black, 4));
uint8_t white[4] = {255, 255, 255, 255};
tcb::span<const std::byte> white_bytes = tcb::as_bytes(tcb::span(white, 4));
uint8_t transparent[4] = {0, 0, 0, 0};
tcb::span<const std::byte> transparent_bytes = tcb::as_bytes(tcb::span(transparent, 4));
rhi.update_texture(ctx, black_, {0, 0, 1, 1}, PixelFormat::kRGBA8, black_bytes);
rhi.update_texture(ctx, white_, {0, 0, 1, 1}, PixelFormat::kRGBA8, white_bytes);
rhi.update_texture(ctx, transparent_, {0, 0, 1, 1}, PixelFormat::kRGBA8, transparent_bytes);
}
}
void CommonResourcesManager::graphics(Rhi& rhi, Handle<GraphicsContext> ctx)
{
}
void CommonResourcesManager::postpass(Rhi& rhi)
{
init_ = true;
}
static uint32_t get_flat_size(lumpnum_t lump)
{
SRB2_ASSERT(lump != LUMPERROR);

View file

@ -25,6 +25,8 @@ class FramebufferManager final : public Pass
std::array<rhi::Handle<rhi::Texture>, 2> main_colors_;
rhi::Handle<rhi::Renderbuffer> main_depth_;
std::array<rhi::Handle<rhi::Texture>, 2> post_colors_;
rhi::Handle<rhi::Texture> wipe_start_color_;
rhi::Handle<rhi::Texture> wipe_end_color_;
std::size_t main_index_ = 0;
std::size_t post_index_ = 0;
std::size_t width_ = 0;
@ -67,6 +69,9 @@ public:
return post_colors_[1 - post_index_];
};
rhi::Handle<rhi::Texture> wipe_start_color() const noexcept { return wipe_start_color_; }
rhi::Handle<rhi::Texture> wipe_end_color() const noexcept { return wipe_end_color_; }
std::size_t width() const noexcept { return width_; }
std::size_t height() const noexcept { return height_; }
};
@ -87,6 +92,27 @@ public:
rhi::Handle<rhi::Texture> palette() const noexcept { return palette_; }
};
class CommonResourcesManager final : public Pass
{
bool init_ = false;
rhi::Handle<rhi::Texture> black_;
rhi::Handle<rhi::Texture> white_;
rhi::Handle<rhi::Texture> transparent_;
public:
CommonResourcesManager();
virtual ~CommonResourcesManager();
virtual void prepass(rhi::Rhi& rhi) override;
virtual void transfer(rhi::Rhi& rhi, rhi::Handle<rhi::TransferContext> ctx) override;
virtual void graphics(rhi::Rhi& rhi, rhi::Handle<rhi::GraphicsContext> ctx) override;
virtual void postpass(rhi::Rhi& rhi) override;
rhi::Handle<rhi::Texture> black() const noexcept { return black_; }
rhi::Handle<rhi::Texture> white() const noexcept { return white_; }
rhi::Handle<rhi::Texture> transparent() const noexcept { return transparent_; }
};
/*
A note to the reader:

View file

@ -130,10 +130,25 @@ extern boolean allow_fullscreen;
*/
void I_UpdateNoBlit(void);
/** \brief Begin a new Twodee frame.
*/
void I_NewTwodeeFrame(void);
/** \brief Begin a new dear imgui frame.
*/
void I_NewImguiFrame(void);
/** \brief Update video system with updating frame
*/
void I_FinishUpdate(void);
void I_FinishUpdateWipeStartScreen(void);
void I_FinishUpdateWipeEndScreen(void);
/** \brief Update video system during a wipe
*/
void I_FinishUpdateWipe(void);
/** \brief I_FinishUpdate(), but vsync disabled
*/
void I_UpdateNoVsync(void);

View file

@ -40,13 +40,26 @@ using namespace srb2;
using namespace srb2::hwr2;
using namespace srb2::rhi;
static std::shared_ptr<PassManager> g_passmanager;
namespace
{
struct InternalPassData
{
std::shared_ptr<PassManager> resource_passmanager;
std::shared_ptr<PassManager> normal_rendering;
std::shared_ptr<PassManager> wipe_capture_start_rendering;
std::shared_ptr<PassManager> wipe_capture_end_rendering;
std::shared_ptr<PassManager> wipe_rendering;
};
} // namespace
static std::unique_ptr<InternalPassData> g_passes;
static Rhi* g_last_known_rhi = nullptr;
Handle<Rhi> srb2::sys::g_current_rhi = kNullHandle;
static bool rhi_changed()
static bool rhi_changed(Rhi* rhi)
{
return false;
return g_last_known_rhi != rhi;
}
#ifdef HWRENDER
@ -103,50 +116,49 @@ static void finish_legacy_ogl_update()
}
#endif
static std::shared_ptr<PassManager> build_pass_manager()
static InternalPassData build_pass_manager()
{
std::shared_ptr<PassManager> manager = std::make_shared<PassManager>();
auto framebuffer_manager = std::make_shared<FramebufferManager>();
auto palette_manager = std::make_shared<MainPaletteManager>();
auto common_resources_manager = std::make_shared<CommonResourcesManager>();
auto flat_texture_manager = std::make_shared<FlatTextureManager>();
auto resource_manager = std::make_shared<PassManager>();
std::shared_ptr<FramebufferManager> framebuffer_manager = std::make_shared<FramebufferManager>();
std::shared_ptr<MainPaletteManager> palette_manager = std::make_shared<MainPaletteManager>();
std::shared_ptr<FlatTextureManager> flat_texture_manager = std::make_shared<FlatTextureManager>();
resource_manager->insert("framebuffer_manager", framebuffer_manager);
resource_manager->insert("palette_manager", palette_manager);
resource_manager->insert("common_resources_manager", common_resources_manager);
resource_manager->insert("flat_texture_manager", flat_texture_manager);
std::shared_ptr<SoftwarePass> software_pass = std::make_shared<SoftwarePass>();
std::shared_ptr<BlitRectPass> blit_sw_pass = std::make_shared<BlitRectPass>(palette_manager, true);
std::shared_ptr<TwodeePass> twodee = std::make_shared<TwodeePass>();
// Basic Rendering is responsible for drawing 3d, 2d, and postprocessing the image.
// This is drawn to an alternating internal color buffer.
// Normal Rendering will output the result via final composite and present.
// Wipe Start Screen and Wipe End Screen will save to special color buffers used for Wipe Rendering.
auto basic_rendering = std::make_shared<PassManager>();
auto software_pass = std::make_shared<SoftwarePass>();
auto blit_sw_pass = std::make_shared<BlitRectPass>(palette_manager, true);
auto twodee = std::make_shared<TwodeePass>();
twodee->flat_manager_ = flat_texture_manager;
twodee->data_ = make_twodee_pass_data();
twodee->ctx_ = &g_2d;
std::shared_ptr<BlitRectPass> pp_simple_blit_pass = std::make_shared<BlitRectPass>(false);
std::shared_ptr<PostprocessWipePass> pp_wipe_pass = std::make_shared<PostprocessWipePass>();
std::shared_ptr<ScreenshotPass> screenshot_pass = std::make_shared<ScreenshotPass>();
std::shared_ptr<ImguiPass> imgui_pass = std::make_shared<ImguiPass>();
std::shared_ptr<BlitRectPass> final_composite_pass = std::make_shared<BlitRectPass>(true);
auto pp_simple_blit_pass = std::make_shared<BlitRectPass>(false);
auto screenshot_pass = std::make_shared<ScreenshotPass>();
auto imgui_pass = std::make_shared<ImguiPass>();
auto final_composite_pass = std::make_shared<BlitRectPass>(true);
manager->insert("framebuffer_manager", framebuffer_manager);
manager->insert("palette_manager", palette_manager);
manager->insert("flat_texture_manager", flat_texture_manager);
manager->insert(
basic_rendering->insert(
"3d_prepare",
[framebuffer_manager](PassManager& mgr, Rhi&)
{
const bool sw_enabled = rendermode == render_soft;
mgr.set_pass_enabled("software", !g_wipeskiprender && sw_enabled);
mgr.set_pass_enabled("blit_sw_prepare", !g_wipeskiprender && sw_enabled);
mgr.set_pass_enabled("blit_sw", !g_wipeskiprender && sw_enabled);
},
[framebuffer_manager](PassManager&, Rhi&)
{
if (!WipeInAction)
{
framebuffer_manager->swap_main();
}
mgr.set_pass_enabled("software", sw_enabled);
mgr.set_pass_enabled("blit_sw_prepare", sw_enabled);
mgr.set_pass_enabled("blit_sw", sw_enabled);
}
);
manager->insert("software", software_pass);
manager->insert(
basic_rendering->insert("software", software_pass);
basic_rendering->insert(
"blit_sw_prepare",
[blit_sw_pass, software_pass, framebuffer_manager](PassManager&, Rhi&)
{
@ -154,9 +166,9 @@ static std::shared_ptr<PassManager> build_pass_manager()
blit_sw_pass->set_output(framebuffer_manager->current_main_color(), vid.width, vid.height, false, false);
}
);
manager->insert("blit_sw", blit_sw_pass);
basic_rendering->insert("blit_sw", blit_sw_pass);
manager->insert(
basic_rendering->insert(
"2d_prepare",
[twodee, framebuffer_manager, palette_manager](PassManager& mgr, Rhi&)
{
@ -166,74 +178,62 @@ static std::shared_ptr<PassManager> build_pass_manager()
twodee->output_height_ = vid.height;
}
);
manager->insert("2d", twodee);
basic_rendering->insert("2d", twodee);
manager->insert(
"pp_final_prepare",
[](PassManager& mgr, Rhi&)
{
mgr.set_pass_enabled("pp_final_wipe_prepare", WipeInAction);
mgr.set_pass_enabled("pp_final_wipe", WipeInAction);
mgr.set_pass_enabled("pp_final_wipe_flip", WipeInAction);
}
);
manager->insert(
// basic_rendering->insert(
// "pp_final_prepare",
// [](PassManager& mgr, Rhi&)
// {
// mgr.set_pass_enabled("pp_final_wipe_prepare", WipeInAction);
// mgr.set_pass_enabled("pp_final_wipe", WipeInAction);
// mgr.set_pass_enabled("pp_final_wipe_flip", WipeInAction);
// }
// );
basic_rendering->insert(
"pp_final_simple_blit_prepare",
[pp_simple_blit_pass, framebuffer_manager](PassManager&, Rhi&)
{
Handle<Texture> color = framebuffer_manager->current_main_color();
if (WipeInAction && !g_wipereverse)
{
// Non-reverse wipes are "fade-outs" from the previous frame.
color = framebuffer_manager->previous_main_color();
}
pp_simple_blit_pass->set_texture(color, vid.width, vid.height);
framebuffer_manager->swap_post();
pp_simple_blit_pass->set_texture(framebuffer_manager->current_main_color(), vid.width, vid.height);
pp_simple_blit_pass
->set_output(framebuffer_manager->current_post_color(), vid.width, vid.height, false, false);
->set_output(framebuffer_manager->current_post_color(), vid.width, vid.height, false, true);
}
);
manager->insert("pp_final_simple_blit", pp_simple_blit_pass);
manager->insert(
"pp_final_simple_blit_flip",
[framebuffer_manager](PassManager&, Rhi&) { framebuffer_manager->swap_post(); }
);
manager->insert(
"pp_final_wipe_prepare",
[pp_wipe_pass, framebuffer_manager](PassManager&, Rhi&)
{
pp_wipe_pass->set_source(framebuffer_manager->previous_post_color(), vid.width, vid.height);
pp_wipe_pass->set_end(framebuffer_manager->current_main_color());
pp_wipe_pass->set_target(framebuffer_manager->current_post_color(), vid.width, vid.height);
}
);
manager->insert("pp_final_wipe", pp_wipe_pass);
manager->insert(
"pp_final_wipe_flip",
[framebuffer_manager](PassManager&, Rhi&) { framebuffer_manager->swap_post(); }
);
basic_rendering->insert("pp_final_simple_blit", pp_simple_blit_pass);
// basic_rendering->insert(
// "pp_final_simple_blit_flip",
// [framebuffer_manager](PassManager&, Rhi&) { framebuffer_manager->swap_post(); }
// );
manager->insert(
// basic_rendering->insert(
// "pp_final_wipe_flip",
// [framebuffer_manager](PassManager&, Rhi&) { framebuffer_manager->swap_post(); }
// );
basic_rendering->insert(
"screenshot_prepare",
[screenshot_pass, framebuffer_manager](PassManager&, Rhi&)
{
screenshot_pass->set_source(framebuffer_manager->previous_post_color(), vid.width, vid.height);
screenshot_pass->set_source(framebuffer_manager->current_post_color(), vid.width, vid.height);
}
);
manager->insert("screenshot", screenshot_pass);
basic_rendering->insert("screenshot", screenshot_pass);
manager->insert(
// Composite-present takes the current postprocess result and outputs it to the default framebuffer.
// It also renders imgui and presents the screen.
auto composite_present_rendering = std::make_shared<PassManager>();
composite_present_rendering->insert(
"final_composite_prepare",
[final_composite_pass, framebuffer_manager](PassManager&, Rhi&)
{
final_composite_pass->set_texture(framebuffer_manager->previous_post_color(), vid.width, vid.height);
final_composite_pass->set_output(kNullHandle, vid.realwidth, vid.realheight, true, false);
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);
}
);
manager->insert("final_composite", final_composite_pass);
manager->insert("imgui", imgui_pass);
manager->insert(
composite_present_rendering->insert("final_composite", final_composite_pass);
composite_present_rendering->insert("imgui", imgui_pass);
composite_present_rendering->insert(
"present",
[](PassManager&, Rhi& rhi) {},
[framebuffer_manager](PassManager&, Rhi& rhi)
@ -241,25 +241,104 @@ static std::shared_ptr<PassManager> build_pass_manager()
rhi.present();
rhi.finish();
framebuffer_manager->reset_post();
// TODO fix this: it's an ugly hack to work around issues with wipes
// Why this works:
// - Menus run F_RunWipe which is an inner update loop calling I_FinishUpdate, with this global set
// - After exiting F_RunWipe, g_2d should normally be cleared by I_FinishUpdate
// - Unfortunately, the menu has already run all its draw calls when exiting F_RunWipe
// - That causes a single-frame flash of no 2d content, which is an epilepsy risk.
// - By not clearing the 2d context, we are redrawing 2d every frame of the wipe
// - This "works" because we draw 2d to the normal color buffer, not the postprocessed screen.
// - It does result in the FPS counter being mangled during the wipe though.
// - To fix the issues around wipes, wipes need to be a "sub" game state, and eliminate the inner tic loops.
if (!WipeInAction)
{
g_2d = Twodee();
}
}
);
return manager;
// Normal rendering combines basic rendering and composite-present.
auto normal_rendering = std::make_shared<PassManager>();
normal_rendering->insert("resource_manager", resource_manager);
normal_rendering->insert("basic_rendering", basic_rendering);
normal_rendering->insert("composite_present_rendering", composite_present_rendering);
// Wipe Start Screen Capture rendering
auto wipe_capture_start_rendering = std::make_shared<PassManager>();
auto wipe_start_blit = std::make_shared<BlitRectPass>();
wipe_capture_start_rendering->insert("resource_manager", resource_manager);
wipe_capture_start_rendering->insert("basic_rendering", basic_rendering);
wipe_capture_start_rendering->insert(
"wipe_capture_prepare",
[framebuffer_manager, wipe_start_blit](PassManager&, Rhi&)
{
wipe_start_blit->set_texture(framebuffer_manager->previous_post_color(), vid.width, vid.height);
wipe_start_blit->set_output(framebuffer_manager->wipe_start_color(), vid.width, vid.height, false, true);
}
);
wipe_capture_start_rendering->insert("wipe_capture", wipe_start_blit);
// Wipe End Screen Capture rendering
auto wipe_capture_end_rendering = std::make_shared<PassManager>();
auto wipe_end_blit = std::make_shared<BlitRectPass>();
wipe_capture_end_rendering->insert("resource_manager", resource_manager);
wipe_capture_end_rendering->insert("basic_rendering", basic_rendering);
wipe_capture_end_rendering->insert(
"wipe_capture_prepare",
[framebuffer_manager, wipe_end_blit](PassManager&, Rhi&)
{
wipe_end_blit->set_texture(framebuffer_manager->current_post_color(), vid.width, vid.height);
wipe_end_blit->set_output(framebuffer_manager->wipe_end_color(), vid.width, vid.height, false, true);
}
);
wipe_capture_end_rendering->insert("wipe_capture", wipe_end_blit);
// Wipe rendering only runs the wipe shader on the start and end screens, and adds composite-present.
auto wipe_rendering = std::make_shared<PassManager>();
auto pp_wipe_pass = std::make_shared<PostprocessWipePass>();
wipe_rendering->insert("resource_manager", resource_manager);
wipe_rendering->insert(
"pp_final_wipe_prepare",
[pp_wipe_pass, framebuffer_manager, common_resources_manager](PassManager&, Rhi&)
{
framebuffer_manager->swap_post();
Handle<Texture> start = framebuffer_manager->wipe_start_color();
Handle<Texture> end = framebuffer_manager->wipe_end_color();
if (g_wipereverse)
{
std::swap(start, end);
}
pp_wipe_pass->set_start(start);
pp_wipe_pass->set_end(end);
pp_wipe_pass->set_target(framebuffer_manager->current_post_color(), vid.width, vid.height);
}
);
wipe_rendering->insert("pp_final_wipe", pp_wipe_pass);
wipe_rendering->insert("composite_present_rendering", composite_present_rendering);
InternalPassData ret;
ret.resource_passmanager = resource_manager;
ret.normal_rendering = normal_rendering;
ret.wipe_capture_start_rendering = wipe_capture_start_rendering;
ret.wipe_capture_end_rendering = wipe_capture_end_rendering;
ret.wipe_rendering = wipe_rendering;
return ret;
}
void I_NewTwodeeFrame(void)
{
g_2d = Twodee();
}
void I_NewImguiFrame(void)
{
// TODO move this to srb2loop
ImGuiIO& io = ImGui::GetIO();
io.DisplaySize.x = vid.realwidth;
io.DisplaySize.y = vid.realheight;
ImGui::NewFrame();
}
static void maybe_reinit_passes(Rhi* rhi)
{
if (rhi_changed(rhi) || !g_passes)
{
g_last_known_rhi = rhi;
g_passes = std::make_unique<InternalPassData>(build_pass_manager());
}
}
void I_FinishUpdate(void)
@ -277,17 +356,34 @@ void I_FinishUpdate(void)
}
#endif
// TODO move this to srb2loop
ImGuiIO& io = ImGui::GetIO();
io.DisplaySize.x = vid.realwidth;
io.DisplaySize.y = vid.realheight;
ImGui::NewFrame();
rhi::Rhi* rhi = sys::get_rhi(sys::g_current_rhi);
if (rhi_changed() || !g_passmanager)
if (rhi == nullptr)
{
g_passmanager = build_pass_manager();
// ???
return;
}
maybe_reinit_passes(rhi);
g_passes->normal_rendering->render(*rhi);
}
void I_FinishUpdateWipeStartScreen(void)
{
if (rendermode == render_none)
{
return;
}
#ifdef HWRENDER
if (rendermode == render_opengl)
{
finish_legacy_ogl_update();
return;
}
#endif
rhi::Rhi* rhi = sys::get_rhi(sys::g_current_rhi);
if (rhi == nullptr)
@ -296,5 +392,63 @@ void I_FinishUpdate(void)
return;
}
g_passmanager->render(*rhi);
maybe_reinit_passes(rhi);
g_passes->wipe_capture_start_rendering->render(*rhi);
}
void I_FinishUpdateWipeEndScreen(void)
{
if (rendermode == render_none)
{
return;
}
#ifdef HWRENDER
if (rendermode == render_opengl)
{
finish_legacy_ogl_update();
return;
}
#endif
rhi::Rhi* rhi = sys::get_rhi(sys::g_current_rhi);
if (rhi == nullptr)
{
// ???
return;
}
maybe_reinit_passes(rhi);
g_passes->wipe_capture_end_rendering->render(*rhi);
}
void I_FinishUpdateWipe(void)
{
if (rendermode == render_none)
{
return;
}
#ifdef HWRENDER
if (rendermode == render_opengl)
{
finish_legacy_ogl_update();
return;
}
#endif
rhi::Rhi* rhi = sys::get_rhi(sys::g_current_rhi);
if (rhi == nullptr)
{
// ???
return;
}
maybe_reinit_passes(rhi);
g_passes->wipe_rendering->render(*rhi);
}

View file

@ -334,6 +334,10 @@ constexpr const char* map_uniform_attribute_symbol_name(rhi::UniformName name)
return "u_texcoord0_transform";
case rhi::UniformName::kSampler0IsIndexedAlpha:
return "u_sampler0_is_indexed_alpha";
case rhi::UniformName::kWipeColorizeMode:
return "u_wipe_colorize_mode";
case rhi::UniformName::kWipeEncoreSwizzle:
return "u_wipe_encore_swizzle";
default:
return nullptr;
}
@ -353,6 +357,10 @@ constexpr const char* map_uniform_enable_define(rhi::UniformName name)
return "ENABLE_U_TEXCOORD0_TRANSFORM";
case rhi::UniformName::kSampler0IsIndexedAlpha:
return "ENABLE_U_SAMPLER0_IS_INDEXED_ALPHA";
case rhi::UniformName::kWipeColorizeMode:
return "ENABLE_U_WIPE_COLORIZE_MODE";
case rhi::UniformName::kWipeEncoreSwizzle:
return "ENABLE_U_WIPE_ENCORE_SWIZZLE";
default:
return nullptr;
}

View file

@ -44,8 +44,11 @@ const ProgramRequirements srb2::rhi::kProgramRequirementsPostprocessWipe = {
ProgramVertexInputRequirements {
{ProgramVertexInput {VertexAttributeName::kPosition, VertexAttributeFormat::kFloat3, true},
ProgramVertexInput {VertexAttributeName::kTexCoord0, VertexAttributeFormat::kFloat2, true}}},
ProgramUniformRequirements {{{{{UniformName::kProjection, true}, {UniformName::kModelView, true}}}}},
ProgramSamplerRequirements {{{SamplerName::kSampler0, true}, {SamplerName::kSampler1, true}}}};
ProgramUniformRequirements {
{{{{UniformName::kProjection, true},
{UniformName::kWipeColorizeMode, true},
{UniformName::kWipeEncoreSwizzle, true}}}}},
ProgramSamplerRequirements {{{SamplerName::kSampler0, true}, {SamplerName::kSampler1, true}, {SamplerName::kSampler2, true}}}};
const ProgramRequirements& rhi::program_requirements_for_program(PipelineProgram program) noexcept
{

View file

@ -196,7 +196,9 @@ enum class UniformName
kModelView,
kProjection,
kTexCoord0Transform,
kSampler0IsIndexedAlpha
kSampler0IsIndexedAlpha,
kWipeColorizeMode,
kWipeEncoreSwizzle
};
enum class SamplerName
@ -306,6 +308,10 @@ inline constexpr const UniformFormat uniform_format(UniformName name) noexcept
return UniformFormat::kMat3;
case UniformName::kSampler0IsIndexedAlpha:
return UniformFormat::kInt;
case UniformName::kWipeColorizeMode:
return UniformFormat::kInt;
case UniformName::kWipeEncoreSwizzle:
return UniformFormat::kInt;
default:
return UniformFormat::kFloat;
}