mirror of
https://github.com/KartKrewDev/RingRacers.git
synced 2026-02-05 05:06:24 +00:00
hwr2: Remove pass infrastructure
It's not worth trying to force the engine to conform to deferred drawing.
This commit is contained in:
parent
4eb06392cb
commit
6f580606cd
39 changed files with 1125 additions and 1196 deletions
|
|
@ -15,7 +15,7 @@ add_executable(SRB2SDL2 MACOSX_BUNDLE WIN32
|
|||
deh_tables.c
|
||||
z_zone.c
|
||||
f_finale.c
|
||||
f_wipe.c
|
||||
f_wipe.cpp
|
||||
g_build_ticcmd.cpp
|
||||
g_demo.c
|
||||
g_game.c
|
||||
|
|
|
|||
|
|
@ -2258,11 +2258,13 @@ static boolean CL_ServerConnectionTicker(const char *tmpsave, tic_t *oldtic, tic
|
|||
#endif
|
||||
}
|
||||
I_UpdateNoVsync(); // page flip or blit buffer
|
||||
I_NewTwodeeFrame();
|
||||
#ifdef HWRENDER
|
||||
if (moviemode && rendermode == render_opengl)
|
||||
M_LegacySaveFrame();
|
||||
else
|
||||
#endif
|
||||
if (moviemode && rendermode != render_none)
|
||||
I_CaptureVideoFrame();
|
||||
S_UpdateSounds();
|
||||
S_UpdateClosedCaptions();
|
||||
}
|
||||
|
|
@ -2844,7 +2846,7 @@ void CL_ClearPlayer(INT32 playernum)
|
|||
P_SetTarget(&players[playernum].skybox.viewpoint, NULL);
|
||||
P_SetTarget(&players[playernum].skybox.centerpoint, NULL);
|
||||
P_SetTarget(&players[playernum].awayview.mobj, NULL);
|
||||
|
||||
|
||||
}
|
||||
|
||||
// Handle parties.
|
||||
|
|
|
|||
24
src/d_main.c
24
src/d_main.c
|
|
@ -589,6 +589,12 @@ static void D_Display(void)
|
|||
R_RestoreLevelInterpolators();
|
||||
}
|
||||
|
||||
// rhi: display the software framebuffer to the screen
|
||||
if (rendermode == render_soft)
|
||||
{
|
||||
VID_DisplaySoftwareScreen();
|
||||
}
|
||||
|
||||
if (lastdraw)
|
||||
{
|
||||
if (rendermode == render_soft)
|
||||
|
|
@ -727,9 +733,6 @@ static void D_Display(void)
|
|||
ps_swaptime = I_GetPreciseTime();
|
||||
I_FinishUpdate(); // page flip or blit buffer
|
||||
ps_swaptime = I_GetPreciseTime() - ps_swaptime;
|
||||
|
||||
// We should never do the HWR2 skip 3d drawing hack for more than 1 full draw.
|
||||
g_wipeskiprender = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -829,11 +832,6 @@ void D_SRB2Loop(void)
|
|||
HW3S_BeginFrameUpdate();
|
||||
#endif
|
||||
|
||||
if (rendermode != render_none)
|
||||
{
|
||||
I_NewTwodeeFrame();
|
||||
}
|
||||
|
||||
if (realtics > 0 || singletics)
|
||||
{
|
||||
// don't skip more than 10 frames at a time
|
||||
|
|
@ -910,6 +908,9 @@ void D_SRB2Loop(void)
|
|||
M_DoLegacyGLScreenShot();
|
||||
#endif
|
||||
|
||||
if ((moviemode || takescreenshot) && rendermode == render_soft)
|
||||
I_CaptureVideoFrame();
|
||||
|
||||
// consoleplayer -> displayplayers (hear sounds from viewpoint)
|
||||
S_UpdateSounds(); // move positional sounds
|
||||
if (realtics > 0 || singletics)
|
||||
|
|
@ -1540,15 +1541,10 @@ void D_SRB2Main(void)
|
|||
|
||||
CONS_Printf("I_StartupGraphics()...\n");
|
||||
I_StartupGraphics();
|
||||
I_StartDisplayUpdate();
|
||||
|
||||
I_StartupInput();
|
||||
|
||||
if (rendermode != render_none)
|
||||
{
|
||||
I_NewTwodeeFrame();
|
||||
I_NewImguiFrame();
|
||||
}
|
||||
|
||||
#ifdef HWRENDER
|
||||
// Lactozilla: Add every hardware mode CVAR and CCMD.
|
||||
// Has to be done before the configuration file loads,
|
||||
|
|
|
|||
|
|
@ -432,7 +432,10 @@ void F_IntroTicker(void)
|
|||
#ifdef HWRENDER
|
||||
if (moviemode && rendermode == render_opengl) // make sure we save frames for the white hold too
|
||||
M_LegacySaveFrame();
|
||||
else
|
||||
#endif
|
||||
if (moviemode && rendermode != render_none)
|
||||
I_CaptureVideoFrame();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -129,7 +129,6 @@ extern UINT8 g_wipemode;
|
|||
extern UINT8 g_wipetype;
|
||||
extern UINT8 g_wipeframe;
|
||||
extern boolean g_wipereverse;
|
||||
extern boolean g_wipeskiprender;
|
||||
extern boolean g_wipeencorewiggle;
|
||||
extern boolean WipeStageTitle;
|
||||
|
||||
|
|
|
|||
|
|
@ -45,6 +45,8 @@
|
|||
// SRB2Kart
|
||||
#include "k_menu.h"
|
||||
|
||||
using namespace srb2;
|
||||
|
||||
typedef struct fademask_s {
|
||||
UINT8* mask;
|
||||
UINT16 width, height;
|
||||
|
|
@ -216,7 +218,6 @@ UINT8 g_wipemode = 0;
|
|||
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;
|
||||
|
|
@ -260,7 +261,7 @@ static fademask_t *F_GetFadeMask(UINT8 masknum, UINT8 scrnnum) {
|
|||
if (lumpnum == LUMPERROR)
|
||||
goto freemask;
|
||||
|
||||
lump = W_CacheLumpNum(lumpnum, PU_CACHE);
|
||||
lump = static_cast<UINT8*>(W_CacheLumpNum(lumpnum, PU_CACHE));
|
||||
lsize = W_LumpLength(lumpnum);
|
||||
switch (lsize)
|
||||
{
|
||||
|
|
@ -287,7 +288,7 @@ static fademask_t *F_GetFadeMask(UINT8 masknum, UINT8 scrnnum) {
|
|||
goto freemask;
|
||||
}
|
||||
if (lsize != fm.size)
|
||||
fm.mask = Z_Realloc(fm.mask, lsize, PU_STATIC, NULL);
|
||||
fm.mask = reinterpret_cast<UINT8*>(Z_Realloc(fm.mask, lsize, PU_STATIC, NULL));
|
||||
fm.size = lsize;
|
||||
|
||||
mask = fm.mask;
|
||||
|
|
@ -319,6 +320,38 @@ static fademask_t *F_GetFadeMask(UINT8 masknum, UINT8 scrnnum) {
|
|||
|
||||
#endif
|
||||
|
||||
static void refresh_wipe_screen_texture(rhi::Rhi& rhi, rhi::Handle<rhi::GraphicsContext> ctx, rhi::Handle<rhi::Texture>& tex)
|
||||
{
|
||||
bool recreate = false;
|
||||
if (!tex)
|
||||
{
|
||||
recreate = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
rhi::TextureDetails deets = rhi.get_texture_details(tex);
|
||||
if (deets.width != static_cast<uint32_t>(vid.width) || deets.height != static_cast<uint32_t>(vid.height))
|
||||
{
|
||||
recreate = true;
|
||||
rhi.destroy_texture(tex);
|
||||
tex = rhi::kNullHandle;
|
||||
}
|
||||
}
|
||||
|
||||
if (!recreate)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
tex = rhi.create_texture({
|
||||
rhi::TextureFormat::kRGBA,
|
||||
static_cast<uint32_t>(vid.width),
|
||||
static_cast<uint32_t>(vid.height),
|
||||
rhi::TextureWrapMode::kClamp,
|
||||
rhi::TextureWrapMode::kClamp
|
||||
});
|
||||
}
|
||||
|
||||
/** Save the "before" screen of a wipe.
|
||||
*/
|
||||
void F_WipeStartScreen(void)
|
||||
|
|
@ -331,9 +364,31 @@ void F_WipeStartScreen(void)
|
|||
return;
|
||||
}
|
||||
#endif
|
||||
wipe_scr_start = screens[3];
|
||||
I_ReadScreen(wipe_scr_start);
|
||||
I_FinishUpdateWipeStartScreen();
|
||||
|
||||
rhi::Rhi* rhi = srb2::sys::get_rhi(srb2::sys::g_current_rhi);
|
||||
|
||||
if (!rhi)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
rhi::Handle<rhi::GraphicsContext> ctx = srb2::sys::main_graphics_context();
|
||||
|
||||
if (!ctx)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
hwr2::HardwareState* hw_state = srb2::sys::main_hardware_state();
|
||||
|
||||
refresh_wipe_screen_texture(*rhi, ctx, hw_state->wipe_frames.start);
|
||||
|
||||
hw_state->twodee_renderer->flush(*rhi, ctx, g_2d);
|
||||
|
||||
rhi::Rect copy_region = {0, 0, static_cast<uint32_t>(vid.width), static_cast<uint32_t>(vid.height)};
|
||||
rhi->copy_framebuffer_to_texture(ctx, hw_state->wipe_frames.start, copy_region, copy_region);
|
||||
|
||||
I_FinishUpdate();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
@ -349,10 +404,36 @@ 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);
|
||||
I_FinishUpdateWipeEndScreen();
|
||||
|
||||
rhi::Rhi* rhi = srb2::sys::get_rhi(srb2::sys::g_current_rhi);
|
||||
|
||||
if (!rhi)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
rhi::Handle<rhi::GraphicsContext> ctx = srb2::sys::main_graphics_context();
|
||||
|
||||
if (!ctx)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
hwr2::HardwareState* hw_state = srb2::sys::main_hardware_state();
|
||||
|
||||
refresh_wipe_screen_texture(*rhi, ctx, hw_state->wipe_frames.end);
|
||||
|
||||
hw_state->twodee_renderer->flush(*rhi, ctx, g_2d);
|
||||
|
||||
rhi::Rect copy_region = {0, 0, static_cast<uint32_t>(vid.width), static_cast<uint32_t>(vid.height)};
|
||||
rhi->copy_framebuffer_to_texture(ctx, hw_state->wipe_frames.end, copy_region, copy_region);
|
||||
|
||||
hw_state->blit_rect->set_output(copy_region.w, copy_region.h, false, true);
|
||||
rhi::TextureDetails start_deets = rhi->get_texture_details(hw_state->wipe_frames.start);
|
||||
hw_state->blit_rect->set_texture(hw_state->wipe_frames.start, start_deets.width, start_deets.height);
|
||||
hw_state->blit_rect->draw(*rhi, ctx);
|
||||
|
||||
I_FinishUpdate();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
@ -394,7 +475,7 @@ void F_RunWipe(UINT8 wipemode, UINT8 wipetype, boolean drawMenu, const char *col
|
|||
if (clump != LUMPERROR && wipetype != UINT8_MAX)
|
||||
{
|
||||
pallen = 32;
|
||||
fcolor = Z_MallocAlign((256 * pallen), PU_STATIC, NULL, 8);
|
||||
fcolor = static_cast<lighttable_t*>(Z_MallocAlign((256 * pallen), PU_STATIC, NULL, 8));
|
||||
W_ReadLump(clump, fcolor);
|
||||
}
|
||||
else
|
||||
|
|
@ -407,7 +488,6 @@ void F_RunWipe(UINT8 wipemode, UINT8 wipetype, boolean drawMenu, const char *col
|
|||
|
||||
// Init the wipe
|
||||
WipeInAction = true;
|
||||
g_wipeskiprender = false;
|
||||
wipe_scr = screens[0];
|
||||
|
||||
// lastwipetic should either be 0 or the tic we last wiped
|
||||
|
|
@ -449,6 +529,23 @@ void F_RunWipe(UINT8 wipemode, UINT8 wipetype, boolean drawMenu, const char *col
|
|||
{
|
||||
g_wipeencorewiggle = 0;
|
||||
}
|
||||
rhi::Rhi* rhi = srb2::sys::get_rhi(srb2::sys::g_current_rhi);
|
||||
rhi::Handle<rhi::GraphicsContext> ctx = srb2::sys::main_graphics_context();
|
||||
hwr2::HardwareState* hw_state = srb2::sys::main_hardware_state();
|
||||
|
||||
if (reverse)
|
||||
{
|
||||
hw_state->wipe->set_start(hw_state->wipe_frames.end);
|
||||
hw_state->wipe->set_end(hw_state->wipe_frames.start);
|
||||
}
|
||||
else
|
||||
{
|
||||
hw_state->wipe->set_start(hw_state->wipe_frames.start);
|
||||
hw_state->wipe->set_end(hw_state->wipe_frames.end);
|
||||
}
|
||||
|
||||
hw_state->wipe->set_target_size(static_cast<uint32_t>(vid.width), static_cast<uint32_t>(vid.height));
|
||||
hw_state->wipe->draw(*rhi, ctx);
|
||||
}
|
||||
|
||||
I_OsPolling();
|
||||
|
|
@ -465,24 +562,20 @@ void F_RunWipe(UINT8 wipemode, UINT8 wipetype, boolean drawMenu, const char *col
|
|||
#endif
|
||||
}
|
||||
|
||||
I_FinishUpdateWipe(); // page flip or blit buffer
|
||||
|
||||
if (rendermode != render_none)
|
||||
{
|
||||
// Skip subsequent renders until the end of the wipe to preserve the current frame.
|
||||
g_wipeskiprender = true;
|
||||
}
|
||||
I_FinishUpdate(); // page flip or blit buffer
|
||||
|
||||
#ifdef HWRENDER
|
||||
if (moviemode && rendermode == render_opengl)
|
||||
M_LegacySaveFrame();
|
||||
else
|
||||
#endif
|
||||
if (moviemode && rendermode != render_none)
|
||||
I_CaptureVideoFrame();
|
||||
|
||||
NetKeepAlive(); // Update the network so we don't cause timeouts
|
||||
}
|
||||
|
||||
WipeInAction = false;
|
||||
g_wipeskiprender = false;
|
||||
|
||||
if (fcolor)
|
||||
{
|
||||
|
|
@ -1247,7 +1247,10 @@ void G_PreLevelTitleCard(void)
|
|||
#ifdef HWRENDER
|
||||
if (moviemode && rendermode == render_opengl)
|
||||
M_LegacySaveFrame();
|
||||
else
|
||||
#endif
|
||||
if (moviemode && rendermode != render_none)
|
||||
I_CaptureVideoFrame();
|
||||
|
||||
while (!((nowtime = I_GetTime()) - lasttime))
|
||||
{
|
||||
|
|
@ -2752,7 +2755,7 @@ mapthing_t *G_FindMapStart(INT32 playernum)
|
|||
if (!playeringame[playernum])
|
||||
return NULL;
|
||||
|
||||
// -- Podium --
|
||||
// -- Podium --
|
||||
// Single special behavior
|
||||
if (K_PodiumSequence() == true)
|
||||
spawnpoint = G_FindPodiumStart(playernum);
|
||||
|
|
@ -4898,7 +4901,7 @@ void G_LoadGameData(void)
|
|||
|
||||
if (versionMinor < 3)
|
||||
{
|
||||
// We now require backfilling of placement information.
|
||||
// We now require backfilling of placement information.
|
||||
|
||||
cupwindata_t bestwindata;
|
||||
bestwindata.best_placement = 0;
|
||||
|
|
|
|||
|
|
@ -1,27 +1,30 @@
|
|||
target_sources(SRB2SDL2 PRIVATE
|
||||
blendmode.hpp
|
||||
pass_blit_postimg_screens.cpp
|
||||
pass_blit_postimg_screens.hpp
|
||||
pass_blit_rect.cpp
|
||||
pass_blit_rect.hpp
|
||||
blit_postimg_screens.cpp
|
||||
blit_postimg_screens.hpp
|
||||
blit_rect.cpp
|
||||
blit_rect.hpp
|
||||
hardware_state.hpp
|
||||
pass_imgui.cpp
|
||||
pass_imgui.hpp
|
||||
pass_manager.cpp
|
||||
pass_manager.hpp
|
||||
pass_postprocess.cpp
|
||||
pass_postprocess.hpp
|
||||
pass_resource_managers.cpp
|
||||
pass_resource_managers.hpp
|
||||
pass_screenshot.cpp
|
||||
pass_screenshot.hpp
|
||||
pass_software.cpp
|
||||
pass_software.hpp
|
||||
pass_twodee.cpp
|
||||
pass_twodee.hpp
|
||||
pass.cpp
|
||||
pass.hpp
|
||||
patch_atlas.cpp
|
||||
patch_atlas.hpp
|
||||
postprocess_wipe.cpp
|
||||
postprocess_wipe.hpp
|
||||
resource_management.cpp
|
||||
resource_management.hpp
|
||||
screen_capture.cpp
|
||||
screen_capture.hpp
|
||||
software_screen_renderer.cpp
|
||||
software_screen_renderer.hpp
|
||||
twodee.cpp
|
||||
twodee.hpp
|
||||
twodee_renderer.cpp
|
||||
twodee_renderer.hpp
|
||||
)
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
// See the 'LICENSE' file for more details.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "pass_blit_postimg_screens.hpp"
|
||||
#include "blit_postimg_screens.hpp"
|
||||
|
||||
#include <glm/mat3x3.hpp>
|
||||
#include <glm/mat4x4.hpp>
|
||||
|
|
@ -68,12 +68,53 @@ static const BlitVertex kVerts[] =
|
|||
|
||||
static const uint16_t kIndices[] = {0, 1, 2, 1, 3, 2};
|
||||
|
||||
BlitPostimgScreens::BlitPostimgScreens(const std::shared_ptr<MainPaletteManager>& palette_mgr)
|
||||
|
||||
static Rect get_screen_viewport(uint32_t screen, uint32_t screens, uint32_t w, uint32_t h)
|
||||
{
|
||||
switch (screens)
|
||||
{
|
||||
case 1:
|
||||
return {0, 0, w, h};
|
||||
case 2:
|
||||
return {0, screen == 0 ? (static_cast<int32_t>(h) / 2) : 0, w, (h / 2)};
|
||||
default:
|
||||
switch (screen)
|
||||
{
|
||||
case 2:
|
||||
return {0, 0, w / 2, h / 2};
|
||||
case 3:
|
||||
return {static_cast<int32_t>(w) / 2, 0, w / 2, h / 2};
|
||||
case 0:
|
||||
return {0, static_cast<int32_t>(h) / 2, w / 2, h / 2};
|
||||
case 1:
|
||||
return {static_cast<int32_t>(w) / 2, static_cast<int32_t>(h) / 2, w / 2, h / 2};
|
||||
}
|
||||
}
|
||||
return {0, 0, w, h};
|
||||
}
|
||||
|
||||
BlitPostimgScreens::BlitPostimgScreens(PaletteManager* palette_mgr)
|
||||
: palette_mgr_(palette_mgr)
|
||||
{
|
||||
}
|
||||
|
||||
BlitPostimgScreens::~BlitPostimgScreens() = default;
|
||||
void BlitPostimgScreens::draw(Rhi& rhi, Handle<GraphicsContext> ctx)
|
||||
{
|
||||
prepass(rhi);
|
||||
transfer(rhi, ctx);
|
||||
|
||||
for (uint32_t i = 0; i < screens_; i++)
|
||||
{
|
||||
BlitPostimgScreens::ScreenData& data = screen_data_[i];
|
||||
|
||||
rhi.bind_pipeline(ctx, data.pipeline);
|
||||
rhi.set_viewport(ctx, get_screen_viewport(i, screens_, target_width_, target_height_));
|
||||
rhi.bind_uniform_set(ctx, 0, data.uniform_set);
|
||||
rhi.bind_binding_set(ctx, data.binding_set);
|
||||
rhi.bind_index_buffer(ctx, quad_ibo_);
|
||||
rhi.draw_indexed(ctx, 6, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void BlitPostimgScreens::prepass(Rhi& rhi)
|
||||
{
|
||||
|
|
@ -117,30 +158,6 @@ void BlitPostimgScreens::prepass(Rhi& rhi)
|
|||
screen_data_.clear();
|
||||
}
|
||||
|
||||
static Rect get_screen_viewport(uint32_t screen, uint32_t screens, uint32_t w, uint32_t h)
|
||||
{
|
||||
switch (screens)
|
||||
{
|
||||
case 1:
|
||||
return {0, 0, w, h};
|
||||
case 2:
|
||||
return {0, screen == 0 ? (static_cast<int32_t>(h) / 2) : 0, w, (h / 2)};
|
||||
default:
|
||||
switch (screen)
|
||||
{
|
||||
case 2:
|
||||
return {0, 0, w / 2, h / 2};
|
||||
case 3:
|
||||
return {static_cast<int32_t>(w) / 2, 0, w / 2, h / 2};
|
||||
case 0:
|
||||
return {0, static_cast<int32_t>(h) / 2, w / 2, h / 2};
|
||||
case 1:
|
||||
return {static_cast<int32_t>(w) / 2, static_cast<int32_t>(h) / 2, w / 2, h / 2};
|
||||
}
|
||||
}
|
||||
return {0, 0, w, h};
|
||||
}
|
||||
|
||||
void BlitPostimgScreens::transfer(Rhi& rhi, Handle<GraphicsContext> ctx)
|
||||
{
|
||||
// Upload needed buffers
|
||||
|
|
@ -206,7 +223,7 @@ void BlitPostimgScreens::transfer(Rhi& rhi, Handle<GraphicsContext> ctx)
|
|||
|
||||
UniformVariant uniforms[] =
|
||||
{
|
||||
FixedToFloat(g_time.timefrac) + leveltime,
|
||||
static_cast<float>(leveltime),
|
||||
projection,
|
||||
modelview,
|
||||
texcoord_transform,
|
||||
|
|
@ -221,33 +238,3 @@ void BlitPostimgScreens::transfer(Rhi& rhi, Handle<GraphicsContext> ctx)
|
|||
screen_data_[i] = std::move(data);
|
||||
}
|
||||
}
|
||||
|
||||
void BlitPostimgScreens::graphics(Rhi& rhi, Handle<GraphicsContext> ctx)
|
||||
{
|
||||
if (target_)
|
||||
{
|
||||
rhi.begin_render_pass(ctx, {renderpass_, target_, std::nullopt, glm::vec4(0.0, 0.0, 0.0, 1.0)});
|
||||
}
|
||||
else
|
||||
{
|
||||
rhi.begin_default_render_pass(ctx, true);
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < screens_; i++)
|
||||
{
|
||||
BlitPostimgScreens::ScreenData& data = screen_data_[i];
|
||||
|
||||
rhi.bind_pipeline(ctx, data.pipeline);
|
||||
rhi.set_viewport(ctx, get_screen_viewport(i, screens_, target_ ? target_width_ : vid.width, target_ ? target_height_ : vid.height));
|
||||
rhi.bind_uniform_set(ctx, 0, data.uniform_set);
|
||||
rhi.bind_binding_set(ctx, data.binding_set);
|
||||
rhi.bind_index_buffer(ctx, quad_ibo_);
|
||||
rhi.draw_indexed(ctx, 6, 0);
|
||||
}
|
||||
|
||||
rhi.end_render_pass(ctx);
|
||||
}
|
||||
|
||||
void BlitPostimgScreens::postpass(Rhi& rhi)
|
||||
{
|
||||
}
|
||||
|
|
@ -17,13 +17,12 @@
|
|||
|
||||
#include "../rhi/rhi.hpp"
|
||||
#include "../doomdef.h"
|
||||
#include "pass.hpp"
|
||||
#include "pass_resource_managers.hpp"
|
||||
#include "resource_management.hpp"
|
||||
|
||||
namespace srb2::hwr2
|
||||
{
|
||||
|
||||
class BlitPostimgScreens : public Pass
|
||||
class BlitPostimgScreens
|
||||
{
|
||||
public:
|
||||
struct PostImgConfig
|
||||
|
|
@ -61,20 +60,18 @@ private:
|
|||
uint32_t screens_;
|
||||
std::array<ScreenConfig, 4> screen_configs_;
|
||||
srb2::StaticVec<ScreenData, 4> screen_data_;
|
||||
rhi::Handle<rhi::Texture> target_;
|
||||
uint32_t target_width_;
|
||||
uint32_t target_height_;
|
||||
|
||||
std::shared_ptr<MainPaletteManager> palette_mgr_;
|
||||
PaletteManager* palette_mgr_;
|
||||
|
||||
void prepass(rhi::Rhi& rhi);
|
||||
void transfer(rhi::Rhi& rhi, rhi::Handle<rhi::GraphicsContext> ctx);
|
||||
|
||||
public:
|
||||
BlitPostimgScreens(const std::shared_ptr<MainPaletteManager>& palette_mgr);
|
||||
virtual ~BlitPostimgScreens();
|
||||
explicit BlitPostimgScreens(PaletteManager* palette_mgr);
|
||||
|
||||
virtual void prepass(rhi::Rhi& rhi) override;
|
||||
virtual void transfer(rhi::Rhi& rhi, rhi::Handle<rhi::GraphicsContext> ctx) override;
|
||||
virtual void graphics(rhi::Rhi& rhi, rhi::Handle<rhi::GraphicsContext> ctx) override;
|
||||
virtual void postpass(rhi::Rhi& rhi) override;
|
||||
void draw(rhi::Rhi& rhi, rhi::Handle<rhi::GraphicsContext> ctx);
|
||||
|
||||
void set_num_screens(uint32_t screens) noexcept
|
||||
{
|
||||
|
|
@ -88,9 +85,8 @@ public:
|
|||
screen_configs_[screen_index] = config;
|
||||
}
|
||||
|
||||
void set_target(rhi::Handle<rhi::Texture> target, uint32_t width, uint32_t height) noexcept
|
||||
void set_target(uint32_t width, uint32_t height) noexcept
|
||||
{
|
||||
target_ = target;
|
||||
target_width_ = width;
|
||||
target_height_ = height;
|
||||
}
|
||||
|
|
@ -7,7 +7,7 @@
|
|||
// See the 'LICENSE' file for more details.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "pass_blit_rect.hpp"
|
||||
#include "blit_rect.hpp"
|
||||
|
||||
#include <optional>
|
||||
|
||||
|
|
@ -37,22 +37,6 @@ static const BlitVertex kVerts[] =
|
|||
|
||||
static const uint16_t kIndices[] = {0, 1, 2, 1, 3, 2};
|
||||
|
||||
/// @brief Pipeline used for paletted source textures. Requires the texture and the palette texture.
|
||||
static const PipelineDesc kPalettedPipelineDescription = {
|
||||
PipelineProgram::kUnshadedPaletted,
|
||||
{{{sizeof(BlitVertex)}}, {{VertexAttributeName::kPosition, 0, 0}, {VertexAttributeName::kTexCoord0, 0, 12}}},
|
||||
{{{{UniformName::kProjection}}, {{UniformName::kModelView, UniformName::kTexCoord0Transform}}}},
|
||||
{{// R8 index texture
|
||||
SamplerName::kSampler0,
|
||||
// 256x1 palette texture
|
||||
SamplerName::kSampler1}},
|
||||
std::nullopt,
|
||||
{std::nullopt, {true, true, true, true}},
|
||||
PrimitiveType::kTriangles,
|
||||
CullMode::kNone,
|
||||
FaceWinding::kCounterClockwise,
|
||||
{0.f, 0.f, 0.f, 1.f}};
|
||||
|
||||
/// @brief Pipeline used for non-paletted source textures.
|
||||
static const PipelineDesc kUnshadedPipelineDescription = {
|
||||
PipelineProgram::kUnshaded,
|
||||
|
|
@ -67,33 +51,21 @@ static const PipelineDesc kUnshadedPipelineDescription = {
|
|||
FaceWinding::kCounterClockwise,
|
||||
{0.f, 0.f, 0.f, 1.f}};
|
||||
|
||||
BlitRectPass::BlitRectPass() : Pass()
|
||||
{
|
||||
}
|
||||
|
||||
BlitRectPass::BlitRectPass(bool output_clear) : Pass(), output_clear_(output_clear)
|
||||
{
|
||||
}
|
||||
|
||||
BlitRectPass::BlitRectPass(const std::shared_ptr<MainPaletteManager>& palette_mgr, bool output_clear)
|
||||
: Pass(), output_clear_(output_clear), palette_mgr_(palette_mgr)
|
||||
{
|
||||
}
|
||||
|
||||
BlitRectPass::BlitRectPass() = default;
|
||||
BlitRectPass::~BlitRectPass() = default;
|
||||
|
||||
void BlitRectPass::draw(Rhi& rhi, Handle<GraphicsContext> ctx)
|
||||
{
|
||||
prepass(rhi);
|
||||
transfer(rhi, ctx);
|
||||
graphics(rhi, ctx);
|
||||
}
|
||||
|
||||
void BlitRectPass::prepass(Rhi& rhi)
|
||||
{
|
||||
if (!pipeline_)
|
||||
{
|
||||
if (palette_mgr_)
|
||||
{
|
||||
pipeline_ = rhi.create_pipeline(kPalettedPipelineDescription);
|
||||
}
|
||||
else
|
||||
{
|
||||
pipeline_ = rhi.create_pipeline(kUnshadedPipelineDescription);
|
||||
}
|
||||
pipeline_ = rhi.create_pipeline(kUnshadedPipelineDescription);
|
||||
}
|
||||
|
||||
if (!quad_vbo_)
|
||||
|
|
@ -107,21 +79,6 @@ void BlitRectPass::prepass(Rhi& rhi)
|
|||
quad_ibo_ = rhi.create_buffer({sizeof(kIndices), BufferType::kIndexBuffer, BufferUsage::kImmutable});
|
||||
quad_ibo_needs_upload_ = true;
|
||||
}
|
||||
|
||||
if (!render_pass_)
|
||||
{
|
||||
render_pass_ = rhi.create_render_pass(
|
||||
{
|
||||
false,
|
||||
output_clear_ ? AttachmentLoadOp::kClear : AttachmentLoadOp::kLoad,
|
||||
AttachmentStoreOp::kStore,
|
||||
AttachmentLoadOp::kDontCare,
|
||||
AttachmentStoreOp::kDontCare,
|
||||
AttachmentLoadOp::kDontCare,
|
||||
AttachmentStoreOp::kDontCare
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void BlitRectPass::transfer(Rhi& rhi, Handle<GraphicsContext> ctx)
|
||||
|
|
@ -173,45 +130,17 @@ void BlitRectPass::transfer(Rhi& rhi, Handle<GraphicsContext> ctx)
|
|||
uniform_sets_[1] = rhi.create_uniform_set(ctx, {g2_uniforms});
|
||||
|
||||
std::array<rhi::VertexAttributeBufferBinding, 1> vbs = {{{0, quad_vbo_}}};
|
||||
if (palette_mgr_)
|
||||
{
|
||||
std::array<rhi::TextureBinding, 2> tbs = {
|
||||
{{rhi::SamplerName::kSampler0, texture_}, {rhi::SamplerName::kSampler1, palette_mgr_->palette()}}};
|
||||
binding_set_ = rhi.create_binding_set(ctx, pipeline_, {vbs, tbs});
|
||||
}
|
||||
else
|
||||
{
|
||||
std::array<rhi::TextureBinding, 1> tbs = {{{rhi::SamplerName::kSampler0, texture_}}};
|
||||
binding_set_ = rhi.create_binding_set(ctx, pipeline_, {vbs, tbs});
|
||||
}
|
||||
std::array<rhi::TextureBinding, 1> tbs = {{{rhi::SamplerName::kSampler0, texture_}}};
|
||||
binding_set_ = rhi.create_binding_set(ctx, pipeline_, {vbs, tbs});
|
||||
}
|
||||
|
||||
static constexpr const glm::vec4 kClearColor = {0, 0, 0, 1};
|
||||
|
||||
void BlitRectPass::graphics(Rhi& rhi, Handle<GraphicsContext> ctx)
|
||||
{
|
||||
if (output_)
|
||||
{
|
||||
rhi.begin_render_pass(ctx, {render_pass_, output_, std::nullopt, kClearColor});
|
||||
}
|
||||
else
|
||||
{
|
||||
rhi.begin_default_render_pass(ctx, output_clear_);
|
||||
}
|
||||
|
||||
rhi.bind_pipeline(ctx, pipeline_);
|
||||
if (output_)
|
||||
{
|
||||
rhi.set_viewport(ctx, {0, 0, output_width_, output_height_});
|
||||
}
|
||||
rhi.set_viewport(ctx, {0, 0, output_width_, output_height_});
|
||||
rhi.bind_uniform_set(ctx, 0, uniform_sets_[0]);
|
||||
rhi.bind_uniform_set(ctx, 1, uniform_sets_[1]);
|
||||
rhi.bind_binding_set(ctx, binding_set_);
|
||||
rhi.bind_index_buffer(ctx, quad_ibo_);
|
||||
rhi.draw_indexed(ctx, 6, 0);
|
||||
rhi.end_render_pass(ctx);
|
||||
}
|
||||
|
||||
void BlitRectPass::postpass(Rhi& rhi)
|
||||
{
|
||||
}
|
||||
|
|
@ -7,20 +7,19 @@
|
|||
// See the 'LICENSE' file for more details.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef __SRB2_HWR2_PASS_BLIT_RECT_HPP__
|
||||
#define __SRB2_HWR2_PASS_BLIT_RECT_HPP__
|
||||
#ifndef __SRB2_HWR2_BLIT_RECT_HPP__
|
||||
#define __SRB2_HWR2_BLIT_RECT_HPP__
|
||||
|
||||
#include <array>
|
||||
|
||||
#include "../rhi/rhi.hpp"
|
||||
#include "pass.hpp"
|
||||
#include "pass_resource_managers.hpp"
|
||||
#include "resource_management.hpp"
|
||||
|
||||
namespace srb2::hwr2
|
||||
{
|
||||
|
||||
/// @brief A render pass which blits a rect using a source texture or textures.
|
||||
class BlitRectPass final : public Pass
|
||||
class BlitRectPass
|
||||
{
|
||||
rhi::Handle<rhi::Pipeline> pipeline_;
|
||||
rhi::Handle<rhi::Texture> texture_;
|
||||
|
|
@ -30,9 +29,7 @@ class BlitRectPass final : public Pass
|
|||
uint32_t output_width_ = 0;
|
||||
uint32_t output_height_ = 0;
|
||||
bool output_correct_aspect_ = false;
|
||||
bool output_clear_ = false;
|
||||
bool output_flip_ = false;
|
||||
rhi::Handle<rhi::RenderPass> render_pass_;
|
||||
rhi::Handle<rhi::Buffer> quad_vbo_;
|
||||
rhi::Handle<rhi::Buffer> quad_ibo_;
|
||||
std::array<rhi::Handle<rhi::UniformSet>, 2> uniform_sets_;
|
||||
|
|
@ -41,19 +38,15 @@ class BlitRectPass final : public Pass
|
|||
bool quad_vbo_needs_upload_ = false;
|
||||
bool quad_ibo_needs_upload_ = false;
|
||||
|
||||
// The presence of a palette manager indicates that the source texture will be paletted. This can't be changed.
|
||||
std::shared_ptr<MainPaletteManager> palette_mgr_;
|
||||
void prepass(rhi::Rhi& rhi);
|
||||
void transfer(rhi::Rhi& rhi, rhi::Handle<rhi::GraphicsContext> ctx);
|
||||
void graphics(rhi::Rhi& rhi, rhi::Handle<rhi::GraphicsContext> ctx);
|
||||
|
||||
public:
|
||||
BlitRectPass();
|
||||
BlitRectPass(bool output_clear);
|
||||
BlitRectPass(const std::shared_ptr<MainPaletteManager>& palette_mgr, bool output_clear);
|
||||
virtual ~BlitRectPass();
|
||||
~BlitRectPass();
|
||||
|
||||
virtual void prepass(rhi::Rhi& rhi) override;
|
||||
virtual void transfer(rhi::Rhi& rhi, rhi::Handle<rhi::GraphicsContext> ctx) override;
|
||||
virtual void graphics(rhi::Rhi& rhi, rhi::Handle<rhi::GraphicsContext> ctx) override;
|
||||
virtual void postpass(rhi::Rhi& rhi) override;
|
||||
void draw(rhi::Rhi& rhi, rhi::Handle<rhi::GraphicsContext> ctx);
|
||||
|
||||
/// @brief Set the next blit texture. Don't call during graphics phase!
|
||||
/// @param texture the texture to use when blitting
|
||||
|
|
@ -67,27 +60,22 @@ public:
|
|||
}
|
||||
|
||||
/// @brief Set the next output texture. Don't call during graphics phase!
|
||||
/// @param texture the texture to use as a color buffer
|
||||
/// @param width texture width
|
||||
/// @param height texture height
|
||||
void set_output(
|
||||
rhi::Handle<rhi::Texture> color,
|
||||
uint32_t width,
|
||||
uint32_t height,
|
||||
bool correct_aspect,
|
||||
bool flip
|
||||
) noexcept
|
||||
{
|
||||
output_ = color;
|
||||
output_width_ = width;
|
||||
output_height_ = height;
|
||||
output_correct_aspect_ = correct_aspect;
|
||||
output_flip_ = flip;
|
||||
}
|
||||
|
||||
void clear_output(bool clear) noexcept { output_clear_ = clear; }
|
||||
};
|
||||
|
||||
} // namespace srb2::hwr2
|
||||
|
||||
#endif // __SRB2_HWR2_PASS_SOFTWARE_HPP__
|
||||
#endif // __SRB2_HWR2_BLIT_RECT_HPP__
|
||||
46
src/hwr2/hardware_state.hpp
Normal file
46
src/hwr2/hardware_state.hpp
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
// SONIC ROBO BLAST 2
|
||||
//-----------------------------------------------------------------------------
|
||||
// Copyright (C) 2023 by Ronald "Eidolon" Kinard
|
||||
//
|
||||
// This program is free software distributed under the
|
||||
// terms of the GNU General Public License, version 2.
|
||||
// See the 'LICENSE' file for more details.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef __SRB2_HWR2_HARDWARE_STATE_HPP__
|
||||
#define __SRB2_HWR2_HARDWARE_STATE_HPP__
|
||||
|
||||
#include "blit_postimg_screens.hpp"
|
||||
#include "blit_rect.hpp"
|
||||
#include "postprocess_wipe.hpp"
|
||||
#include "resource_management.hpp"
|
||||
#include "screen_capture.hpp"
|
||||
#include "software_screen_renderer.hpp"
|
||||
#include "twodee_renderer.hpp"
|
||||
|
||||
namespace srb2::hwr2
|
||||
{
|
||||
|
||||
struct WipeFrames
|
||||
{
|
||||
rhi::Handle<rhi::Texture> start;
|
||||
rhi::Handle<rhi::Texture> end;
|
||||
};
|
||||
|
||||
struct HardwareState
|
||||
{
|
||||
std::unique_ptr<PaletteManager> palette_manager;
|
||||
std::unique_ptr<FlatTextureManager> flat_manager;
|
||||
std::unique_ptr<PatchAtlasCache> patch_atlas_cache;
|
||||
std::unique_ptr<TwodeeRenderer> twodee_renderer;
|
||||
std::unique_ptr<SoftwareScreenRenderer> software_screen_renderer;
|
||||
std::unique_ptr<BlitPostimgScreens> blit_postimg_screens;
|
||||
std::unique_ptr<PostprocessWipePass> wipe;
|
||||
std::unique_ptr<BlitRectPass> blit_rect;
|
||||
std::unique_ptr<ScreenshotPass> screen_capture;
|
||||
WipeFrames wipe_frames;
|
||||
};
|
||||
|
||||
} // srb2::hwr2
|
||||
|
||||
#endif // __SRB2_HWR2_HARDWARE_STATE_HPP__
|
||||
|
|
@ -352,113 +352,3 @@ void CommonResourcesManager::postpass(Rhi& rhi)
|
|||
{
|
||||
init_ = true;
|
||||
}
|
||||
|
||||
static uint32_t get_flat_size(lumpnum_t lump)
|
||||
{
|
||||
SRB2_ASSERT(lump != LUMPERROR);
|
||||
|
||||
std::size_t lumplength = W_LumpLength(lump);
|
||||
if (lumplength == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((lumplength & (lumplength - 1)) != 0)
|
||||
{
|
||||
// Lump length is not a power of two and therefore not a flat.
|
||||
return 0;
|
||||
}
|
||||
uint32_t lumpsize = std::pow(2, std::log2(lumplength) / 2);
|
||||
return lumpsize;
|
||||
}
|
||||
|
||||
FlatTextureManager::FlatTextureManager() : Pass()
|
||||
{
|
||||
}
|
||||
|
||||
FlatTextureManager::~FlatTextureManager() = default;
|
||||
|
||||
void FlatTextureManager::prepass(Rhi& rhi)
|
||||
{
|
||||
}
|
||||
|
||||
void FlatTextureManager::transfer(Rhi& rhi, Handle<GraphicsContext> ctx)
|
||||
{
|
||||
std::vector<std::array<uint8_t, 2>> flat_data;
|
||||
for (auto flat_lump : to_upload_)
|
||||
{
|
||||
flat_data.clear();
|
||||
Handle<Texture> flat_texture = flats_[flat_lump];
|
||||
SRB2_ASSERT(flat_texture != kNullHandle);
|
||||
std::size_t lump_length = W_LumpLength(flat_lump);
|
||||
uint32_t flat_size = get_flat_size(flat_lump);
|
||||
flat_data.reserve(flat_size * flat_size);
|
||||
|
||||
const uint8_t* flat_memory = static_cast<const uint8_t*>(W_CacheLumpNum(flat_lump, PU_PATCH));
|
||||
SRB2_ASSERT(flat_memory != nullptr);
|
||||
|
||||
tcb::span<const uint8_t> flat_bytes = tcb::span(flat_memory, lump_length);
|
||||
for (const uint8_t index : flat_bytes)
|
||||
{
|
||||
// The alpha/green channel is set to 0 if it's index 247; this is not usually used but fake floors can be
|
||||
// masked sometimes, so we need to treat it as transparent when rendering them.
|
||||
// See https://zdoom.org/wiki/Palette for remarks on fake 247 transparency
|
||||
flat_data.push_back({index, index == 247 ? static_cast<uint8_t>(0) : static_cast<uint8_t>(255)});
|
||||
}
|
||||
|
||||
// A flat size of 1 would end up being 2 bytes, so we need 2 more bytes to be unpack-aligned on texture upload
|
||||
// Any other size would implicitly be aligned.
|
||||
// Sure hope nobody tries to load any flats that are too big for the gpu!
|
||||
if (flat_size == 1)
|
||||
{
|
||||
flat_data.push_back({0, 0});
|
||||
}
|
||||
|
||||
tcb::span<const std::byte> data_bytes = tcb::as_bytes(tcb::span(flat_data));
|
||||
rhi.update_texture(ctx, flat_texture, {0, 0, flat_size, flat_size}, rhi::PixelFormat::kRG8, data_bytes);
|
||||
}
|
||||
to_upload_.clear();
|
||||
}
|
||||
|
||||
void FlatTextureManager::graphics(Rhi& rhi, Handle<GraphicsContext> ctx)
|
||||
{
|
||||
}
|
||||
|
||||
void FlatTextureManager::postpass(Rhi& rhi)
|
||||
{
|
||||
}
|
||||
|
||||
Handle<Texture> FlatTextureManager::find_or_create_indexed(Rhi& rhi, lumpnum_t lump)
|
||||
{
|
||||
SRB2_ASSERT(lump != LUMPERROR);
|
||||
|
||||
auto flat_itr = flats_.find(lump);
|
||||
if (flat_itr != flats_.end())
|
||||
{
|
||||
return flat_itr->second;
|
||||
}
|
||||
|
||||
uint32_t flat_size = get_flat_size(lump);
|
||||
Handle<Texture> new_tex = rhi.create_texture({
|
||||
TextureFormat::kLuminanceAlpha,
|
||||
flat_size,
|
||||
flat_size,
|
||||
TextureWrapMode::kRepeat,
|
||||
TextureWrapMode::kRepeat
|
||||
});
|
||||
flats_.insert({lump, new_tex});
|
||||
to_upload_.push_back(lump);
|
||||
return new_tex;
|
||||
}
|
||||
|
||||
Handle<Texture> FlatTextureManager::find_indexed(lumpnum_t lump) const
|
||||
{
|
||||
SRB2_ASSERT(lump != LUMPERROR);
|
||||
|
||||
auto flat_itr = flats_.find(lump);
|
||||
if (flat_itr != flats_.end())
|
||||
{
|
||||
return flat_itr->second;
|
||||
}
|
||||
return kNullHandle;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -129,43 +129,6 @@ public:
|
|||
rhi::Handle<rhi::Texture> transparent() const noexcept { return transparent_; }
|
||||
};
|
||||
|
||||
/*
|
||||
A note to the reader:
|
||||
|
||||
RHI/HWR2's architecture is intentionally decoupled in a data-oriented design fashion. Hash map lookups might technically
|
||||
be slower than storing the RHI handle in a hypothetical Flat class object, but it frees us from worrying about the
|
||||
validity of a given Handle when the RHI instance changes -- and it _can_, because this is designed to allow multiple
|
||||
RHI backends -- because any given Pass must be disposed when the RHI changes. The implementation of I_FinishUpdate is
|
||||
such that if the RHI is not the same as before, all passes must be reconstructed, and so we don't have to worry about
|
||||
going around and resetting Handle references everywhere. If you're familiar with old GL, it's like decoupling GLmipmap_t
|
||||
from patch_t.
|
||||
*/
|
||||
|
||||
/// @brief Manages textures corresponding to specific flats indexed by lump number.
|
||||
class FlatTextureManager final : public Pass
|
||||
{
|
||||
std::unordered_map<lumpnum_t, rhi::Handle<rhi::Texture>> flats_;
|
||||
std::vector<lumpnum_t> to_upload_;
|
||||
std::vector<rhi::Handle<rhi::Texture>> disposed_textures_;
|
||||
|
||||
public:
|
||||
FlatTextureManager();
|
||||
virtual ~FlatTextureManager();
|
||||
|
||||
virtual void prepass(rhi::Rhi& rhi) override;
|
||||
virtual void transfer(rhi::Rhi& rhi, rhi::Handle<rhi::GraphicsContext> ctx) override;
|
||||
virtual void graphics(rhi::Rhi& rhi, rhi::Handle<rhi::GraphicsContext> ctx) override;
|
||||
virtual void postpass(rhi::Rhi& rhi) override;
|
||||
|
||||
/// @brief Find the indexed texture for a given flat lump, or create one if it doesn't exist yet. Only call this
|
||||
/// in prepass.
|
||||
/// @param flat_lump
|
||||
/// @return
|
||||
rhi::Handle<rhi::Texture> find_or_create_indexed(rhi::Rhi& rhi, lumpnum_t flat_lump);
|
||||
|
||||
rhi::Handle<rhi::Texture> find_indexed(lumpnum_t flat_lump) const;
|
||||
};
|
||||
|
||||
} // namespace srb2::hwr2
|
||||
|
||||
#endif // __SRB2_HWR2_PASS_RESOURCE_MANAGERS_HPP__
|
||||
|
|
|
|||
|
|
@ -1,80 +0,0 @@
|
|||
// SONIC ROBO BLAST 2
|
||||
//-----------------------------------------------------------------------------
|
||||
// Copyright (C) 2023 by Ronald "Eidolon" Kinard
|
||||
//
|
||||
// This program is free software distributed under the
|
||||
// terms of the GNU General Public License, version 2.
|
||||
// See the 'LICENSE' file for more details.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "pass_screenshot.hpp"
|
||||
|
||||
#include <tcb/span.hpp>
|
||||
|
||||
#include "../m_misc.h"
|
||||
|
||||
using namespace srb2;
|
||||
using namespace srb2::hwr2;
|
||||
using namespace srb2::rhi;
|
||||
|
||||
ScreenshotPass::ScreenshotPass() = default;
|
||||
ScreenshotPass::~ScreenshotPass() = default;
|
||||
|
||||
void ScreenshotPass::prepass(Rhi& rhi)
|
||||
{
|
||||
if (!render_pass_)
|
||||
{
|
||||
render_pass_ = rhi.create_render_pass(
|
||||
{
|
||||
false,
|
||||
AttachmentLoadOp::kLoad,
|
||||
AttachmentStoreOp::kStore,
|
||||
AttachmentLoadOp::kDontCare,
|
||||
AttachmentStoreOp::kDontCare,
|
||||
AttachmentLoadOp::kDontCare,
|
||||
AttachmentStoreOp::kDontCare
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
doing_screenshot_ = takescreenshot || moviemode != MM_OFF;
|
||||
}
|
||||
|
||||
void ScreenshotPass::transfer(Rhi& rhi, Handle<GraphicsContext> ctx)
|
||||
{
|
||||
}
|
||||
|
||||
void ScreenshotPass::graphics(Rhi& rhi, Handle<GraphicsContext> ctx)
|
||||
{
|
||||
if (!doing_screenshot_)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
pixel_data_.clear();
|
||||
pixel_data_.resize(width_ * height_ * 3); // 3 bytes per pixel for RGB8
|
||||
|
||||
rhi.begin_render_pass(ctx, {render_pass_, source_, std::nullopt, {0.f, 0.f, 0.f, 0.f}});
|
||||
rhi.read_pixels(ctx, {0, 0, width_, height_}, PixelFormat::kRGB8, tcb::as_writable_bytes(tcb::span(pixel_data_)));
|
||||
rhi.end_render_pass(ctx);
|
||||
}
|
||||
|
||||
void ScreenshotPass::postpass(Rhi& rhi)
|
||||
{
|
||||
if (!doing_screenshot_)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (takescreenshot)
|
||||
{
|
||||
M_DoScreenShot(width_, height_, tcb::as_bytes(tcb::span(pixel_data_)));
|
||||
}
|
||||
|
||||
if (moviemode != MM_OFF)
|
||||
{
|
||||
M_SaveFrame(width_, height_, tcb::as_bytes(tcb::span(pixel_data_)));
|
||||
}
|
||||
|
||||
doing_screenshot_ = false;
|
||||
}
|
||||
|
|
@ -215,7 +215,7 @@ static PatchAtlas create_atlas(Rhi& rhi, uint32_t size)
|
|||
return new_atlas;
|
||||
}
|
||||
|
||||
void PatchAtlasCache::pack(Rhi& rhi)
|
||||
void PatchAtlasCache::pack(Rhi& rhi, Handle<GraphicsContext> ctx)
|
||||
{
|
||||
// Prepare stbrp rects for patches to be loaded.
|
||||
std::vector<stbrp_rect> rects;
|
||||
|
|
@ -291,9 +291,34 @@ void PatchAtlasCache::pack(Rhi& rhi)
|
|||
}
|
||||
}
|
||||
|
||||
patches_to_pack_.clear();
|
||||
|
||||
// TODO Create large patch "atlases"
|
||||
|
||||
patches_to_pack_.clear();
|
||||
SRB2_ASSERT(ready_for_lookup());
|
||||
|
||||
// Upload atlased patches
|
||||
std::vector<uint8_t> patch_data;
|
||||
for (const patch_t* patch_to_upload : patches_to_upload_)
|
||||
{
|
||||
srb2::NotNull<PatchAtlas*> atlas = find_patch(patch_to_upload);
|
||||
|
||||
std::optional<PatchAtlas::Entry> entry = atlas->find_patch(patch_to_upload);
|
||||
SRB2_ASSERT(entry.has_value());
|
||||
|
||||
convert_patch_to_trimmed_rg8_pixels(patch_to_upload, patch_data);
|
||||
|
||||
rhi.update_texture(
|
||||
ctx,
|
||||
atlas->tex_,
|
||||
{static_cast<int32_t>(entry->x), static_cast<int32_t>(entry->y), entry->w, entry->h},
|
||||
PixelFormat::kRG8,
|
||||
tcb::as_bytes(tcb::span(patch_data))
|
||||
);
|
||||
|
||||
patch_data.clear();
|
||||
}
|
||||
patches_to_upload_.clear();
|
||||
}
|
||||
|
||||
PatchAtlas* PatchAtlasCache::find_patch(srb2::NotNull<const patch_t*> patch)
|
||||
|
|
@ -339,47 +364,3 @@ void PatchAtlasCache::queue_patch(srb2::NotNull<const patch_t*> patch)
|
|||
|
||||
patches_to_pack_.insert(patch);
|
||||
}
|
||||
|
||||
void PatchAtlasCache::prepass(Rhi& rhi)
|
||||
{
|
||||
if (need_to_reset())
|
||||
{
|
||||
reset(rhi);
|
||||
}
|
||||
}
|
||||
|
||||
void PatchAtlasCache::transfer(Rhi& rhi, Handle<GraphicsContext> ctx)
|
||||
{
|
||||
SRB2_ASSERT(ready_for_lookup());
|
||||
|
||||
// Upload atlased patches
|
||||
std::vector<uint8_t> patch_data;
|
||||
for (const patch_t* patch_to_upload : patches_to_upload_)
|
||||
{
|
||||
srb2::NotNull<PatchAtlas*> atlas = find_patch(patch_to_upload);
|
||||
|
||||
std::optional<PatchAtlas::Entry> entry = atlas->find_patch(patch_to_upload);
|
||||
SRB2_ASSERT(entry.has_value());
|
||||
|
||||
convert_patch_to_trimmed_rg8_pixels(patch_to_upload, patch_data);
|
||||
|
||||
rhi.update_texture(
|
||||
ctx,
|
||||
atlas->tex_,
|
||||
{static_cast<int32_t>(entry->x), static_cast<int32_t>(entry->y), entry->w, entry->h},
|
||||
PixelFormat::kRG8,
|
||||
tcb::as_bytes(tcb::span(patch_data))
|
||||
);
|
||||
|
||||
patch_data.clear();
|
||||
}
|
||||
patches_to_upload_.clear();
|
||||
}
|
||||
|
||||
void PatchAtlasCache::graphics(Rhi& rhi, Handle<GraphicsContext> ctx)
|
||||
{
|
||||
}
|
||||
|
||||
void PatchAtlasCache::postpass(Rhi& rhi)
|
||||
{
|
||||
}
|
||||
|
|
|
|||
|
|
@ -81,7 +81,7 @@ public:
|
|||
/// @brief A resource-managing pass which creates and manages a set of Atlas Textures with
|
||||
/// optimally packed Patches, allowing drawing passes to reuse the same texture binds for
|
||||
/// drawing things like sprites and 2D elements.
|
||||
class PatchAtlasCache : public Pass
|
||||
class PatchAtlasCache
|
||||
{
|
||||
std::vector<PatchAtlas> atlases_;
|
||||
std::unordered_map<const patch_t*, size_t> patch_lookup_;
|
||||
|
|
@ -92,10 +92,6 @@ class PatchAtlasCache : public Pass
|
|||
uint32_t tex_size_ = 2048;
|
||||
size_t max_textures_ = 2;
|
||||
|
||||
bool need_to_reset() const;
|
||||
|
||||
/// @brief Clear the atlases and reset for lookup.
|
||||
void reset(rhi::Rhi& rhi);
|
||||
bool ready_for_lookup() const;
|
||||
|
||||
/// @brief Decide if a rect's dimensions are Large, that is, the rect should not be packed and instead its patch
|
||||
|
|
@ -109,14 +105,14 @@ public:
|
|||
PatchAtlasCache(PatchAtlasCache&&);
|
||||
PatchAtlasCache& operator=(const PatchAtlasCache&) = delete;
|
||||
PatchAtlasCache& operator=(PatchAtlasCache&&);
|
||||
virtual ~PatchAtlasCache();
|
||||
~PatchAtlasCache();
|
||||
|
||||
/// @brief Queue a patch to be packed. All patches will be packed after the prepass phase,
|
||||
/// or the owner can explicitly request a pack.
|
||||
void queue_patch(srb2::NotNull<const patch_t*> patch);
|
||||
|
||||
/// @brief Pack queued patches, allowing them to be looked up with find_patch.
|
||||
void pack(rhi::Rhi& rhi);
|
||||
void pack(rhi::Rhi& rhi, rhi::Handle<rhi::GraphicsContext> ctx);
|
||||
|
||||
/// @brief Find the atlas a patch belongs to, or nullopt if it is not cached.
|
||||
/// This may not be called if there are still patches that need to be packed.
|
||||
|
|
@ -124,10 +120,10 @@ public:
|
|||
const PatchAtlas* find_patch(srb2::NotNull<const patch_t*> patch) const;
|
||||
PatchAtlas* find_patch(srb2::NotNull<const patch_t*> patch);
|
||||
|
||||
virtual void prepass(rhi::Rhi& rhi) override;
|
||||
virtual void transfer(rhi::Rhi& rhi, rhi::Handle<rhi::GraphicsContext> ctx) override;
|
||||
virtual void graphics(rhi::Rhi& rhi, rhi::Handle<rhi::GraphicsContext> ctx) override;
|
||||
virtual void postpass(rhi::Rhi& rhi) override;
|
||||
bool need_to_reset() const;
|
||||
|
||||
/// @brief Clear the atlases and reset for lookup.
|
||||
void reset(rhi::Rhi& rhi);
|
||||
};
|
||||
|
||||
/// @brief Calculate the subregion of the patch which excludes empty space on the borders.
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
// See the 'LICENSE' file for more details.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "pass_postprocess.hpp"
|
||||
#include "postprocess_wipe.hpp"
|
||||
|
||||
#include <string>
|
||||
|
||||
|
|
@ -62,23 +62,16 @@ PostprocessWipePass::PostprocessWipePass()
|
|||
|
||||
PostprocessWipePass::~PostprocessWipePass() = default;
|
||||
|
||||
void PostprocessWipePass::draw(Rhi& rhi, Handle<GraphicsContext> ctx)
|
||||
{
|
||||
prepass(rhi);
|
||||
transfer(rhi, ctx);
|
||||
graphics(rhi, ctx);
|
||||
postpass(rhi);
|
||||
}
|
||||
|
||||
void PostprocessWipePass::prepass(Rhi& rhi)
|
||||
{
|
||||
if (!render_pass_)
|
||||
{
|
||||
render_pass_ = rhi.create_render_pass(
|
||||
{
|
||||
false,
|
||||
AttachmentLoadOp::kLoad,
|
||||
AttachmentStoreOp::kStore,
|
||||
AttachmentLoadOp::kDontCare,
|
||||
AttachmentStoreOp::kDontCare,
|
||||
AttachmentLoadOp::kDontCare,
|
||||
AttachmentStoreOp::kDontCare
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
if (!pipeline_)
|
||||
{
|
||||
pipeline_ = rhi.create_pipeline(kWipePipelineDesc);
|
||||
|
|
@ -224,26 +217,12 @@ void PostprocessWipePass::graphics(Rhi& rhi, Handle<GraphicsContext> ctx)
|
|||
return;
|
||||
}
|
||||
|
||||
if (target_)
|
||||
{
|
||||
rhi.begin_render_pass(ctx, {render_pass_, target_, std::nullopt, {0, 0, 0, 1}});
|
||||
}
|
||||
else
|
||||
{
|
||||
rhi.begin_default_render_pass(ctx, false);
|
||||
}
|
||||
|
||||
rhi.bind_pipeline(ctx, pipeline_);
|
||||
if (target_)
|
||||
{
|
||||
rhi.set_viewport(ctx, {0, 0, target_w_, target_h_});
|
||||
}
|
||||
rhi.set_viewport(ctx, {0, 0, width_, height_});
|
||||
rhi.bind_uniform_set(ctx, 0, us_);
|
||||
rhi.bind_binding_set(ctx, bs_);
|
||||
rhi.bind_index_buffer(ctx, ibo_);
|
||||
rhi.draw_indexed(ctx, 6, 0);
|
||||
|
||||
rhi.end_render_pass(ctx);
|
||||
}
|
||||
|
||||
void PostprocessWipePass::postpass(Rhi& rhi)
|
||||
|
|
@ -7,20 +7,19 @@
|
|||
// See the 'LICENSE' file for more details.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef __SRB2_HWR2_PASS_POSTPROCESS_HPP__
|
||||
#define __SRB2_HWR2_PASS_POSTPROCESS_HPP__
|
||||
|
||||
#include "pass.hpp"
|
||||
#ifndef __SRB2_HWR2_POSTPROCESS_WIPE_HPP__
|
||||
#define __SRB2_HWR2_POSTPROCESS_WIPE_HPP__
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "../rhi/rhi.hpp"
|
||||
|
||||
namespace srb2::hwr2
|
||||
{
|
||||
|
||||
class PostprocessWipePass final : public Pass
|
||||
class PostprocessWipePass final
|
||||
{
|
||||
// Internal RHI resources
|
||||
rhi::Handle<rhi::RenderPass> render_pass_;
|
||||
rhi::Handle<rhi::Pipeline> pipeline_;
|
||||
rhi::Handle<rhi::Buffer> vbo_;
|
||||
bool upload_vbo_ = false;
|
||||
|
|
@ -35,36 +34,36 @@ class PostprocessWipePass final : public Pass
|
|||
// 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;
|
||||
uint32_t width_;
|
||||
uint32_t height_;
|
||||
|
||||
// Mask lump loading
|
||||
std::vector<uint8_t> mask_data_;
|
||||
uint32_t mask_w_ = 0;
|
||||
uint32_t mask_h_ = 0;
|
||||
|
||||
void prepass(rhi::Rhi& rhi);
|
||||
void transfer(rhi::Rhi& rhi, rhi::Handle<rhi::GraphicsContext> ctx);
|
||||
void graphics(rhi::Rhi& rhi, rhi::Handle<rhi::GraphicsContext> ctx);
|
||||
void postpass(rhi::Rhi& rhi);
|
||||
|
||||
public:
|
||||
PostprocessWipePass();
|
||||
virtual ~PostprocessWipePass();
|
||||
|
||||
virtual void prepass(rhi::Rhi& rhi) override;
|
||||
virtual void transfer(rhi::Rhi& rhi, rhi::Handle<rhi::GraphicsContext> ctx) override;
|
||||
virtual void graphics(rhi::Rhi& rhi, rhi::Handle<rhi::GraphicsContext> ctx) override;
|
||||
virtual void postpass(rhi::Rhi& rhi) override;
|
||||
void draw(rhi::Rhi& rhi, rhi::Handle<rhi::GraphicsContext> ctx);
|
||||
|
||||
void set_start(rhi::Handle<rhi::Texture> start) noexcept { start_ = start; }
|
||||
|
||||
void set_end(rhi::Handle<rhi::Texture> end) noexcept { end_ = end; }
|
||||
|
||||
void set_target(rhi::Handle<rhi::Texture> target, uint32_t width, uint32_t height) noexcept
|
||||
void set_target_size(uint32_t width, uint32_t height) noexcept
|
||||
{
|
||||
target_ = target;
|
||||
target_w_ = width;
|
||||
target_h_ = height;
|
||||
width_ = width;
|
||||
height_ = height;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace srb2::hwr2
|
||||
|
||||
#endif // __SRB2_HWR2_PASS_POSTPROCESS_HPP__
|
||||
#endif // __SRB2_HWR2_POSTPROCESS_WIPE_HPP__
|
||||
205
src/hwr2/resource_management.cpp
Normal file
205
src/hwr2/resource_management.cpp
Normal file
|
|
@ -0,0 +1,205 @@
|
|||
// SONIC ROBO BLAST 2
|
||||
//-----------------------------------------------------------------------------
|
||||
// Copyright (C) 2023 by Ronald "Eidolon" Kinard
|
||||
//
|
||||
// This program is free software distributed under the
|
||||
// terms of the GNU General Public License, version 2.
|
||||
// See the 'LICENSE' file for more details.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "resource_management.hpp"
|
||||
|
||||
#include "../r_state.h"
|
||||
#include "../v_video.h"
|
||||
#include "../z_zone.h"
|
||||
|
||||
using namespace srb2;
|
||||
using namespace rhi;
|
||||
using namespace hwr2;
|
||||
|
||||
PaletteManager::PaletteManager() = default;
|
||||
PaletteManager::PaletteManager(PaletteManager&&) = default;
|
||||
PaletteManager::~PaletteManager() = default;
|
||||
PaletteManager& PaletteManager::operator=(PaletteManager&&) = default;
|
||||
|
||||
constexpr std::size_t kPaletteSize = 256;
|
||||
constexpr std::size_t kLighttableRows = LIGHTLEVELS;
|
||||
|
||||
void PaletteManager::update(Rhi& rhi, Handle<GraphicsContext> ctx)
|
||||
{
|
||||
if (!palette_)
|
||||
{
|
||||
palette_ = rhi.create_texture({TextureFormat::kRGBA, kPaletteSize, 1, TextureWrapMode::kClamp, TextureWrapMode::kClamp});
|
||||
}
|
||||
|
||||
if (!lighttable_)
|
||||
{
|
||||
lighttable_ = rhi.create_texture({TextureFormat::kLuminance, kPaletteSize, kLighttableRows, TextureWrapMode::kClamp, TextureWrapMode::kClamp});
|
||||
}
|
||||
|
||||
if (!encore_lighttable_)
|
||||
{
|
||||
encore_lighttable_ = rhi.create_texture({TextureFormat::kLuminance, kPaletteSize, kLighttableRows, TextureWrapMode::kClamp, TextureWrapMode::kClamp});
|
||||
}
|
||||
|
||||
if (!default_colormap_)
|
||||
{
|
||||
default_colormap_ = rhi.create_texture({TextureFormat::kLuminance, kPaletteSize, 1, TextureWrapMode::kClamp, TextureWrapMode::kClamp});
|
||||
}
|
||||
|
||||
// Palette
|
||||
{
|
||||
std::array<byteColor_t, kPaletteSize> palette_32;
|
||||
for (std::size_t i = 0; i < kPaletteSize; i++)
|
||||
{
|
||||
palette_32[i] = V_GetColor(i).s;
|
||||
}
|
||||
rhi.update_texture(ctx, palette_, {0, 0, kPaletteSize, 1}, PixelFormat::kRGBA8, tcb::as_bytes(tcb::span(palette_32)));
|
||||
}
|
||||
|
||||
// Lighttables
|
||||
{
|
||||
if (colormaps != nullptr)
|
||||
{
|
||||
tcb::span<const std::byte> colormap_bytes = tcb::as_bytes(tcb::span(colormaps, kPaletteSize * kLighttableRows));
|
||||
rhi.update_texture(ctx, lighttable_, {0, 0, kPaletteSize, kLighttableRows}, PixelFormat::kR8, colormap_bytes);
|
||||
}
|
||||
|
||||
if (encoremap != nullptr)
|
||||
{
|
||||
tcb::span<const std::byte> encoremap_bytes = tcb::as_bytes(tcb::span(encoremap, kPaletteSize * kLighttableRows));
|
||||
rhi.update_texture(ctx, encore_lighttable_, {0, 0, kPaletteSize, kLighttableRows}, PixelFormat::kR8, encoremap_bytes);
|
||||
}
|
||||
}
|
||||
|
||||
// Default colormap
|
||||
{
|
||||
std::array<uint8_t, kPaletteSize> data;
|
||||
for (std::size_t i = 0; i < kPaletteSize; i++)
|
||||
{
|
||||
data[i] = i;
|
||||
}
|
||||
rhi.update_texture(ctx, default_colormap_, {0, 0, kPaletteSize, 1}, PixelFormat::kR8, tcb::as_bytes(tcb::span(data)));
|
||||
}
|
||||
}
|
||||
|
||||
void PaletteManager::destroy_per_frame_resources(Rhi& rhi)
|
||||
{
|
||||
for (auto colormap_tex : colormaps_)
|
||||
{
|
||||
rhi.destroy_texture(colormap_tex.second);
|
||||
}
|
||||
|
||||
colormaps_.clear();
|
||||
|
||||
for (auto lighttable_tex : lighttables_)
|
||||
{
|
||||
rhi.destroy_texture(lighttable_tex.second);
|
||||
}
|
||||
|
||||
lighttables_.clear();
|
||||
}
|
||||
|
||||
Handle<Texture> PaletteManager::find_or_create_colormap(Rhi& rhi, rhi::Handle<rhi::GraphicsContext> ctx, srb2::NotNull<const uint8_t*> colormap)
|
||||
{
|
||||
if (colormaps_.find(colormap) != colormaps_.end())
|
||||
{
|
||||
return colormaps_[colormap];
|
||||
}
|
||||
|
||||
Handle<Texture> texture = rhi.create_texture({TextureFormat::kLuminance, kPaletteSize, 1, TextureWrapMode::kClamp, TextureWrapMode::kClamp});
|
||||
|
||||
tcb::span<const std::byte> map_bytes = tcb::as_bytes(tcb::span(colormap.get(), kPaletteSize));
|
||||
rhi.update_texture(ctx, texture, {0, 0, kPaletteSize, 1}, PixelFormat::kR8, map_bytes);
|
||||
|
||||
colormaps_.insert_or_assign(colormap, texture);
|
||||
return texture;
|
||||
}
|
||||
|
||||
Handle<Texture> PaletteManager::find_or_create_extra_lighttable(Rhi& rhi, rhi::Handle<rhi::GraphicsContext> ctx, srb2::NotNull<const uint8_t*> lighttable)
|
||||
{
|
||||
if (lighttables_.find(lighttable) != lighttables_.end())
|
||||
{
|
||||
return lighttables_[lighttable];
|
||||
}
|
||||
|
||||
Handle<Texture> texture = rhi.create_texture({TextureFormat::kLuminance, kPaletteSize, kLighttableRows, TextureWrapMode::kClamp, TextureWrapMode::kClamp});
|
||||
|
||||
tcb::span<const std::byte> lighttable_bytes = tcb::as_bytes(tcb::span(lighttable.get(), kPaletteSize * kLighttableRows));
|
||||
rhi.update_texture(ctx, texture, {0, 0, kPaletteSize, kLighttableRows}, PixelFormat::kR8, lighttable_bytes);
|
||||
lighttables_.insert_or_assign(lighttable, texture);
|
||||
|
||||
return texture;
|
||||
}
|
||||
|
||||
FlatTextureManager::FlatTextureManager() = default;
|
||||
FlatTextureManager::~FlatTextureManager() = default;
|
||||
|
||||
static uint32_t get_flat_size(lumpnum_t lump)
|
||||
{
|
||||
SRB2_ASSERT(lump != LUMPERROR);
|
||||
|
||||
std::size_t lumplength = W_LumpLength(lump);
|
||||
if (lumplength == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((lumplength & (lumplength - 1)) != 0)
|
||||
{
|
||||
// Lump length is not a power of two and therefore not a flat.
|
||||
return 0;
|
||||
}
|
||||
uint32_t lumpsize = std::pow(2, std::log2(lumplength) / 2);
|
||||
return lumpsize;
|
||||
}
|
||||
|
||||
Handle<Texture> FlatTextureManager::find_or_create_indexed(Rhi& rhi, Handle<GraphicsContext> ctx, lumpnum_t lump)
|
||||
{
|
||||
SRB2_ASSERT(lump != LUMPERROR);
|
||||
|
||||
auto flat_itr = flats_.find(lump);
|
||||
if (flat_itr != flats_.end())
|
||||
{
|
||||
return flat_itr->second;
|
||||
}
|
||||
|
||||
uint32_t flat_size = get_flat_size(lump);
|
||||
Handle<Texture> new_tex = rhi.create_texture({
|
||||
TextureFormat::kLuminanceAlpha,
|
||||
flat_size,
|
||||
flat_size,
|
||||
TextureWrapMode::kRepeat,
|
||||
TextureWrapMode::kRepeat
|
||||
});
|
||||
flats_.insert({lump, new_tex});
|
||||
|
||||
std::vector<std::array<uint8_t, 2>> flat_data;
|
||||
std::size_t lump_length = W_LumpLength(lump);
|
||||
flat_data.reserve(flat_size * flat_size);
|
||||
|
||||
const uint8_t* flat_memory = static_cast<const uint8_t*>(W_CacheLumpNum(lump, PU_PATCH));
|
||||
SRB2_ASSERT(flat_memory != nullptr);
|
||||
|
||||
tcb::span<const uint8_t> flat_bytes = tcb::span(flat_memory, lump_length);
|
||||
for (const uint8_t index : flat_bytes)
|
||||
{
|
||||
// The alpha/green channel is set to 0 if it's index 247; this is not usually used but fake floors can be
|
||||
// masked sometimes, so we need to treat it as transparent when rendering them.
|
||||
// See https://zdoom.org/wiki/Palette for remarks on fake 247 transparency
|
||||
flat_data.push_back({index, index == 247 ? static_cast<uint8_t>(0) : static_cast<uint8_t>(255)});
|
||||
}
|
||||
|
||||
// A flat size of 1 would end up being 2 bytes, so we need 2 more bytes to be unpack-aligned on texture upload
|
||||
// Any other size would implicitly be aligned.
|
||||
// Sure hope nobody tries to load any flats that are too big for the gpu!
|
||||
if (flat_size == 1)
|
||||
{
|
||||
flat_data.push_back({0, 0});
|
||||
}
|
||||
|
||||
tcb::span<const std::byte> data_bytes = tcb::as_bytes(tcb::span(flat_data));
|
||||
rhi.update_texture(ctx, new_tex, {0, 0, flat_size, flat_size}, rhi::PixelFormat::kRG8, data_bytes);
|
||||
|
||||
return new_tex;
|
||||
}
|
||||
80
src/hwr2/resource_management.hpp
Normal file
80
src/hwr2/resource_management.hpp
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
// SONIC ROBO BLAST 2
|
||||
//-----------------------------------------------------------------------------
|
||||
// Copyright (C) 2023 by Ronald "Eidolon" Kinard
|
||||
//
|
||||
// This program is free software distributed under the
|
||||
// terms of the GNU General Public License, version 2.
|
||||
// See the 'LICENSE' file for more details.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef __SRB2_HWR2_RESOURCE_MANAGEMENT_HPP__
|
||||
#define __SRB2_HWR2_RESOURCE_MANAGEMENT_HPP__
|
||||
|
||||
#include "../rhi/rhi.hpp"
|
||||
|
||||
namespace srb2::hwr2
|
||||
{
|
||||
|
||||
class PaletteManager
|
||||
{
|
||||
rhi::Handle<rhi::Texture> palette_;
|
||||
rhi::Handle<rhi::Texture> lighttable_;
|
||||
rhi::Handle<rhi::Texture> encore_lighttable_;
|
||||
rhi::Handle<rhi::Texture> default_colormap_;
|
||||
|
||||
std::unordered_map<const uint8_t*, rhi::Handle<rhi::Texture>> colormaps_;
|
||||
std::unordered_map<const uint8_t*, rhi::Handle<rhi::Texture>> lighttables_;
|
||||
|
||||
public:
|
||||
PaletteManager();
|
||||
PaletteManager(const PaletteManager&) = delete;
|
||||
PaletteManager(PaletteManager&&);
|
||||
~PaletteManager();
|
||||
PaletteManager& operator=(const PaletteManager&) = delete;
|
||||
PaletteManager& operator=(PaletteManager&&);
|
||||
|
||||
rhi::Handle<rhi::Texture> palette() const noexcept { return palette_; }
|
||||
rhi::Handle<rhi::Texture> lighttable() const noexcept { return lighttable_; }
|
||||
rhi::Handle<rhi::Texture> encore_lighttable() const noexcept { return encore_lighttable_; }
|
||||
rhi::Handle<rhi::Texture> default_colormap() const noexcept { return default_colormap_; }
|
||||
|
||||
void update(rhi::Rhi& rhi, rhi::Handle<rhi::GraphicsContext> ctx);
|
||||
void destroy_per_frame_resources(rhi::Rhi& rhi);
|
||||
|
||||
rhi::Handle<rhi::Texture> find_or_create_colormap(rhi::Rhi& rhi, rhi::Handle<rhi::GraphicsContext> ctx, srb2::NotNull<const uint8_t*> colormap);
|
||||
rhi::Handle<rhi::Texture> find_or_create_extra_lighttable(rhi::Rhi& rhi, rhi::Handle<rhi::GraphicsContext> ctx, srb2::NotNull<const uint8_t*> lighttable);
|
||||
};
|
||||
|
||||
/*
|
||||
A note to the reader:
|
||||
|
||||
RHI/HWR2's architecture is intentionally decoupled in a data-oriented design fashion. Hash map lookups might technically
|
||||
be slower than storing the RHI handle in a hypothetical Flat class object, but it frees us from worrying about the
|
||||
validity of a given Handle when the RHI instance changes -- and it _can_, because this is designed to allow multiple
|
||||
RHI backends -- because any given Pass must be disposed when the RHI changes. The implementation of I_FinishUpdate is
|
||||
such that if the RHI is not the same as before, all passes must be reconstructed, and so we don't have to worry about
|
||||
going around and resetting Handle references everywhere. If you're familiar with old GL, it's like decoupling GLmipmap_t
|
||||
from patch_t.
|
||||
*/
|
||||
|
||||
/// @brief Manages textures corresponding to specific flats indexed by lump number.
|
||||
class FlatTextureManager
|
||||
{
|
||||
std::unordered_map<lumpnum_t, rhi::Handle<rhi::Texture>> flats_;
|
||||
std::vector<lumpnum_t> to_upload_;
|
||||
std::vector<rhi::Handle<rhi::Texture>> disposed_textures_;
|
||||
|
||||
public:
|
||||
FlatTextureManager();
|
||||
~FlatTextureManager();
|
||||
|
||||
/// @brief Find the indexed texture for a given flat lump, or create one if it doesn't exist yet. Only call this
|
||||
/// in prepass.
|
||||
/// @param flat_lump
|
||||
/// @return
|
||||
rhi::Handle<rhi::Texture> find_or_create_indexed(rhi::Rhi& rhi, rhi::Handle<rhi::GraphicsContext> ctx, lumpnum_t flat_lump);
|
||||
};
|
||||
|
||||
} // namespace srb2::hwr2
|
||||
|
||||
#endif // __SRB2_HWR2_RESOURCE_MANAGEMENT_HPP__
|
||||
59
src/hwr2/screen_capture.cpp
Normal file
59
src/hwr2/screen_capture.cpp
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
// SONIC ROBO BLAST 2
|
||||
//-----------------------------------------------------------------------------
|
||||
// Copyright (C) 2023 by Ronald "Eidolon" Kinard
|
||||
//
|
||||
// This program is free software distributed under the
|
||||
// terms of the GNU General Public License, version 2.
|
||||
// See the 'LICENSE' file for more details.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "screen_capture.hpp"
|
||||
|
||||
#include <tcb/span.hpp>
|
||||
|
||||
#include "../m_misc.h"
|
||||
|
||||
using namespace srb2;
|
||||
using namespace srb2::hwr2;
|
||||
using namespace srb2::rhi;
|
||||
|
||||
ScreenshotPass::ScreenshotPass() = default;
|
||||
ScreenshotPass::~ScreenshotPass() = default;
|
||||
|
||||
void ScreenshotPass::capture(Rhi& rhi, Handle<GraphicsContext> ctx)
|
||||
{
|
||||
bool doing_screenshot = takescreenshot || moviemode != MM_OFF;
|
||||
|
||||
if (!doing_screenshot)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
pixel_data_.clear();
|
||||
packed_data_.clear();
|
||||
// Pixel data must be in pack alignment (4) so a stride of non-multiple 4 must align to 4
|
||||
uint32_t stride = width_ * 3;
|
||||
uint32_t read_stride = ((width_ + (kPixelRowPackAlignment - 1)) & ~(kPixelRowPackAlignment - 1)) * 3;
|
||||
pixel_data_.resize(read_stride * height_); // 3 bytes per pixel for RGB8
|
||||
packed_data_.resize(stride * height_);
|
||||
|
||||
tcb::span<std::byte> data_bytes = tcb::as_writable_bytes(tcb::span(pixel_data_));
|
||||
rhi.read_pixels(ctx, {0, 0, width_, height_}, PixelFormat::kRGB8, data_bytes);
|
||||
|
||||
for (uint32_t row = 0; row < height_; row++)
|
||||
{
|
||||
// Read the aligned data into unaligned linear memory, flipping the rows in the process.
|
||||
uint32_t pixel_data_row = (height_ - row) - 1;
|
||||
std::move(&pixel_data_[pixel_data_row * read_stride], &pixel_data_[pixel_data_row * read_stride + stride], &packed_data_[row * stride]);
|
||||
}
|
||||
|
||||
if (takescreenshot)
|
||||
{
|
||||
M_DoScreenShot(width_, height_, tcb::as_bytes(tcb::span(packed_data_)));
|
||||
}
|
||||
|
||||
if (moviemode != MM_OFF)
|
||||
{
|
||||
M_SaveFrame(width_, height_, tcb::as_bytes(tcb::span(packed_data_)));
|
||||
}
|
||||
}
|
||||
|
|
@ -7,38 +7,33 @@
|
|||
// See the 'LICENSE' file for more details.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef __SRB2_HWR2_PASS_SCREENSHOT_HPP__
|
||||
#define __SRB2_HWR2_PASS_SCREENSHOT_HPP__
|
||||
#ifndef __SRB2_HWR2_SCREEN_CAPTURE_HPP__
|
||||
#define __SRB2_HWR2_SCREEN_CAPTURE_HPP__
|
||||
|
||||
#include <cstddef>
|
||||
#include <vector>
|
||||
|
||||
#include "pass.hpp"
|
||||
#include "../rhi/rhi.hpp"
|
||||
|
||||
namespace srb2::hwr2
|
||||
{
|
||||
|
||||
class ScreenshotPass : public Pass
|
||||
class ScreenshotPass
|
||||
{
|
||||
bool doing_screenshot_ = false;
|
||||
rhi::Handle<rhi::Texture> source_;
|
||||
rhi::Handle<rhi::RenderPass> render_pass_;
|
||||
std::vector<uint8_t> pixel_data_;
|
||||
std::vector<uint8_t> packed_data_;
|
||||
uint32_t width_ = 0;
|
||||
uint32_t height_ = 0;
|
||||
|
||||
public:
|
||||
ScreenshotPass();
|
||||
virtual ~ScreenshotPass();
|
||||
~ScreenshotPass();
|
||||
|
||||
virtual void prepass(rhi::Rhi& rhi) override;
|
||||
virtual void transfer(rhi::Rhi& rhi, rhi::Handle<rhi::GraphicsContext> ctx) override;
|
||||
virtual void graphics(rhi::Rhi& rhi, rhi::Handle<rhi::GraphicsContext> ctx) override;
|
||||
virtual void postpass(rhi::Rhi& rhi) override;
|
||||
void capture(rhi::Rhi& rhi, rhi::Handle<rhi::GraphicsContext> ctx);
|
||||
|
||||
void set_source(rhi::Handle<rhi::Texture> source, uint32_t width, uint32_t height)
|
||||
void set_source(uint32_t width, uint32_t height)
|
||||
{
|
||||
source_ = source;
|
||||
width_ = width;
|
||||
height_ = height;
|
||||
}
|
||||
|
|
@ -46,4 +41,4 @@ public:
|
|||
|
||||
} // namespace srb2::hwr2
|
||||
|
||||
#endif // __SRB2_HWR2_PASS_SCREENSHOT_HPP__
|
||||
#endif // __SRB2_HWR2_SCREEN_CAPTURE_HPP__
|
||||
|
|
@ -7,7 +7,7 @@
|
|||
// See the 'LICENSE' file for more details.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "pass_software.hpp"
|
||||
#include "software_screen_renderer.hpp"
|
||||
|
||||
#include "../i_video.h"
|
||||
#include "../v_video.h"
|
||||
|
|
@ -16,19 +16,11 @@ using namespace srb2;
|
|||
using namespace srb2::hwr2;
|
||||
using namespace srb2::rhi;
|
||||
|
||||
SoftwarePass::SoftwarePass() : Pass()
|
||||
SoftwareScreenRenderer::SoftwareScreenRenderer() = default;
|
||||
SoftwareScreenRenderer::~SoftwareScreenRenderer() = default;
|
||||
|
||||
void SoftwareScreenRenderer::draw(Rhi& rhi, Handle<GraphicsContext> ctx)
|
||||
{
|
||||
}
|
||||
|
||||
SoftwarePass::~SoftwarePass() = default;
|
||||
|
||||
void SoftwarePass::prepass(Rhi& rhi)
|
||||
{
|
||||
if (rendermode != render_soft)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Render the player views... or not yet? Needs to be moved out of D_Display in d_main.c
|
||||
// Assume it's already been done and vid.buffer contains the composited splitscreen view.
|
||||
// In the future though, we will want to treat each player viewport separately for postprocessing.
|
||||
|
|
@ -75,10 +67,7 @@ void SoftwarePass::prepass(Rhi& rhi)
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SoftwarePass::transfer(Rhi& rhi, Handle<GraphicsContext> ctx)
|
||||
{
|
||||
// Upload screen
|
||||
tcb::span<const std::byte> screen_span;
|
||||
if (width_ % kPixelRowUnpackAlignment > 0)
|
||||
|
|
@ -92,11 +81,3 @@ void SoftwarePass::transfer(Rhi& rhi, Handle<GraphicsContext> ctx)
|
|||
|
||||
rhi.update_texture(ctx, screen_texture_, {0, 0, width_, height_}, PixelFormat::kR8, screen_span);
|
||||
}
|
||||
|
||||
void SoftwarePass::graphics(Rhi& rhi, Handle<GraphicsContext> ctx)
|
||||
{
|
||||
}
|
||||
|
||||
void SoftwarePass::postpass(Rhi& rhi)
|
||||
{
|
||||
}
|
||||
|
|
@ -7,19 +7,19 @@
|
|||
// See the 'LICENSE' file for more details.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef __SRB2_HWR2_PASS_SOFTWARE_HPP_
|
||||
#define __SRB2_HWR2_PASS_SOFTWARE_HPP_
|
||||
#ifndef __SRB2_HWR2_SOFTWARE_SCREEN_RENDERER_HPP_
|
||||
#define __SRB2_HWR2_SOFTWARE_SCREEN_RENDERER_HPP_
|
||||
|
||||
#include <cstddef>
|
||||
#include <vector>
|
||||
|
||||
#include "pass.hpp"
|
||||
#include "../rhi/rhi.hpp"
|
||||
|
||||
namespace srb2::hwr2
|
||||
{
|
||||
|
||||
/// @brief Renders software player views in prepass and uploads the result to a texture in transfer.
|
||||
class SoftwarePass final : public Pass
|
||||
class SoftwareScreenRenderer final
|
||||
{
|
||||
rhi::Handle<rhi::Texture> screen_texture_;
|
||||
uint32_t width_ = 0;
|
||||
|
|
@ -30,17 +30,14 @@ class SoftwarePass final : public Pass
|
|||
std::vector<uint8_t> copy_buffer_;
|
||||
|
||||
public:
|
||||
SoftwarePass();
|
||||
virtual ~SoftwarePass();
|
||||
SoftwareScreenRenderer();
|
||||
~SoftwareScreenRenderer();
|
||||
|
||||
virtual void prepass(rhi::Rhi& rhi) override;
|
||||
virtual void transfer(rhi::Rhi& rhi, rhi::Handle<rhi::GraphicsContext> ctx) override;
|
||||
virtual void graphics(rhi::Rhi& rhi, rhi::Handle<rhi::GraphicsContext> ctx) override;
|
||||
virtual void postpass(rhi::Rhi& rhi) override;
|
||||
void draw(rhi::Rhi& rhi, rhi::Handle<rhi::GraphicsContext> ctx);
|
||||
|
||||
rhi::Handle<rhi::Texture> screen_texture() const noexcept { return screen_texture_; }
|
||||
rhi::Handle<rhi::Texture> screen() const { return screen_texture_; }
|
||||
};
|
||||
|
||||
} // namespace srb2::hwr2
|
||||
|
||||
#endif // __SRB2_HWR2_PASS_SOFTWARE_HPP_
|
||||
#endif // __SRB2_HWR2_SOFTWARE_SCREEN_RENDERER_HPP_
|
||||
|
|
@ -7,7 +7,7 @@
|
|||
// See the 'LICENSE' file for more details.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "pass_twodee.hpp"
|
||||
#include "twodee_renderer.hpp"
|
||||
|
||||
#include <unordered_set>
|
||||
|
||||
|
|
@ -23,23 +23,15 @@ using namespace srb2;
|
|||
using namespace srb2::hwr2;
|
||||
using namespace srb2::rhi;
|
||||
|
||||
struct srb2::hwr2::TwodeePassData
|
||||
{
|
||||
Handle<Texture> default_tex;
|
||||
std::unordered_map<TwodeePipelineKey, Handle<Pipeline>> pipelines;
|
||||
bool upload_default_tex = false;
|
||||
};
|
||||
|
||||
std::shared_ptr<TwodeePassData> srb2::hwr2::make_twodee_pass_data()
|
||||
{
|
||||
return std::make_shared<TwodeePassData>();
|
||||
}
|
||||
|
||||
TwodeePass::TwodeePass() : Pass()
|
||||
{
|
||||
}
|
||||
|
||||
TwodeePass::~TwodeePass() = default;
|
||||
TwodeeRenderer::TwodeeRenderer(
|
||||
srb2::NotNull<PaletteManager*> palette_manager,
|
||||
srb2::NotNull<FlatTextureManager*> flat_manager,
|
||||
srb2::NotNull<PatchAtlasCache*> patch_atlas_cache
|
||||
) : palette_manager_(palette_manager), flat_manager_(flat_manager), patch_atlas_cache_(patch_atlas_cache)
|
||||
{}
|
||||
TwodeeRenderer::TwodeeRenderer(TwodeeRenderer&&) = default;
|
||||
TwodeeRenderer::~TwodeeRenderer() = default;
|
||||
TwodeeRenderer& TwodeeRenderer::operator=(TwodeeRenderer&&) = default;
|
||||
|
||||
static constexpr const uint32_t kVboInitSize = 32768;
|
||||
static constexpr const uint32_t kIboInitSize = 4096;
|
||||
|
|
@ -123,7 +115,7 @@ static PipelineDesc make_pipeline_desc(TwodeePipelineKey key)
|
|||
{0.f, 0.f, 0.f, 1.f}};
|
||||
}
|
||||
|
||||
void TwodeePass::rewrite_patch_quad_vertices(Draw2dList& list, const Draw2dPatchQuad& cmd) const
|
||||
void TwodeeRenderer::rewrite_patch_quad_vertices(Draw2dList& list, const Draw2dPatchQuad& cmd) const
|
||||
{
|
||||
// Patch quads are clipped according to the patch's atlas entry
|
||||
const patch_t* patch = cmd.patch;
|
||||
|
|
@ -237,14 +229,8 @@ void TwodeePass::rewrite_patch_quad_vertices(Draw2dList& list, const Draw2dPatch
|
|||
list.vertices[vtx_offs + 3].v = clipped_vmax;
|
||||
}
|
||||
|
||||
void TwodeePass::prepass(Rhi& rhi)
|
||||
void TwodeeRenderer::initialize(Rhi& rhi, Handle<GraphicsContext> ctx)
|
||||
{
|
||||
if (!ctx_ || !data_)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (data_->pipelines.size() == 0)
|
||||
{
|
||||
TwodeePipelineKey alpha_transparent_tris = {BlendMode::kAlphaTransparent, false};
|
||||
TwodeePipelineKey modulate_tris = {BlendMode::kModulate, false};
|
||||
|
|
@ -258,49 +244,45 @@ void TwodeePass::prepass(Rhi& rhi)
|
|||
TwodeePipelineKey subtractive_lines = {BlendMode::kSubtractive, true};
|
||||
TwodeePipelineKey revsubtractive_lines = {BlendMode::kReverseSubtractive, true};
|
||||
TwodeePipelineKey invertdest_lines = {BlendMode::kInvertDest, true};
|
||||
data_->pipelines.insert({alpha_transparent_tris, rhi.create_pipeline(make_pipeline_desc(alpha_transparent_tris))});
|
||||
data_->pipelines.insert({modulate_tris, rhi.create_pipeline(make_pipeline_desc(modulate_tris))});
|
||||
data_->pipelines.insert({additive_tris, rhi.create_pipeline(make_pipeline_desc(additive_tris))});
|
||||
data_->pipelines.insert({subtractive_tris, rhi.create_pipeline(make_pipeline_desc(subtractive_tris))});
|
||||
data_->pipelines.insert({revsubtractive_tris, rhi.create_pipeline(make_pipeline_desc(revsubtractive_tris))});
|
||||
data_->pipelines.insert({invertdest_tris, rhi.create_pipeline(make_pipeline_desc(invertdest_tris))});
|
||||
data_->pipelines.insert({alpha_transparent_lines, rhi.create_pipeline(make_pipeline_desc(alpha_transparent_lines))});
|
||||
data_->pipelines.insert({modulate_lines, rhi.create_pipeline(make_pipeline_desc(modulate_lines))});
|
||||
data_->pipelines.insert({additive_lines, rhi.create_pipeline(make_pipeline_desc(additive_lines))});
|
||||
data_->pipelines.insert({subtractive_lines, rhi.create_pipeline(make_pipeline_desc(subtractive_lines))});
|
||||
data_->pipelines.insert({revsubtractive_lines, rhi.create_pipeline(make_pipeline_desc(revsubtractive_lines))});
|
||||
data_->pipelines.insert({invertdest_lines, rhi.create_pipeline(make_pipeline_desc(revsubtractive_lines))});
|
||||
pipelines_.insert({alpha_transparent_tris, rhi.create_pipeline(make_pipeline_desc(alpha_transparent_tris))});
|
||||
pipelines_.insert({modulate_tris, rhi.create_pipeline(make_pipeline_desc(modulate_tris))});
|
||||
pipelines_.insert({additive_tris, rhi.create_pipeline(make_pipeline_desc(additive_tris))});
|
||||
pipelines_.insert({subtractive_tris, rhi.create_pipeline(make_pipeline_desc(subtractive_tris))});
|
||||
pipelines_.insert({revsubtractive_tris, rhi.create_pipeline(make_pipeline_desc(revsubtractive_tris))});
|
||||
pipelines_.insert({invertdest_tris, rhi.create_pipeline(make_pipeline_desc(invertdest_tris))});
|
||||
pipelines_.insert({alpha_transparent_lines, rhi.create_pipeline(make_pipeline_desc(alpha_transparent_lines))});
|
||||
pipelines_.insert({modulate_lines, rhi.create_pipeline(make_pipeline_desc(modulate_lines))});
|
||||
pipelines_.insert({additive_lines, rhi.create_pipeline(make_pipeline_desc(additive_lines))});
|
||||
pipelines_.insert({subtractive_lines, rhi.create_pipeline(make_pipeline_desc(subtractive_lines))});
|
||||
pipelines_.insert({revsubtractive_lines, rhi.create_pipeline(make_pipeline_desc(revsubtractive_lines))});
|
||||
pipelines_.insert({invertdest_lines, rhi.create_pipeline(make_pipeline_desc(revsubtractive_lines))});
|
||||
}
|
||||
|
||||
if (!data_->default_tex)
|
||||
{
|
||||
data_->default_tex = rhi.create_texture({
|
||||
default_tex_ = rhi.create_texture({
|
||||
TextureFormat::kLuminanceAlpha,
|
||||
2,
|
||||
1,
|
||||
TextureWrapMode::kClamp,
|
||||
TextureWrapMode::kClamp
|
||||
});
|
||||
data_->upload_default_tex = true;
|
||||
std::array<uint8_t, 4> data = {0, 255, 0, 255};
|
||||
rhi.update_texture(ctx, default_tex_, {0, 0, 2, 1}, PixelFormat::kRG8, tcb::as_bytes(tcb::span(data)));
|
||||
}
|
||||
if (!render_pass_)
|
||||
|
||||
initialized_ = true;
|
||||
}
|
||||
|
||||
void TwodeeRenderer::flush(Rhi& rhi, Handle<GraphicsContext> ctx, Twodee& twodee)
|
||||
{
|
||||
if (!initialized_)
|
||||
{
|
||||
render_pass_ = rhi.create_render_pass(
|
||||
{
|
||||
false,
|
||||
AttachmentLoadOp::kLoad,
|
||||
AttachmentStoreOp::kStore,
|
||||
AttachmentLoadOp::kDontCare,
|
||||
AttachmentStoreOp::kDontCare,
|
||||
AttachmentLoadOp::kDontCare,
|
||||
AttachmentStoreOp::kDontCare
|
||||
}
|
||||
);
|
||||
initialize(rhi, ctx);
|
||||
}
|
||||
|
||||
// Stage 1 - command list patch detection
|
||||
std::unordered_set<const patch_t*> found_patches;
|
||||
for (const auto& list : *ctx_)
|
||||
for (const auto& list : twodee)
|
||||
{
|
||||
for (const auto& cmd : list.cmds)
|
||||
{
|
||||
|
|
@ -313,7 +295,7 @@ void TwodeePass::prepass(Rhi& rhi)
|
|||
}
|
||||
if (cmd.colormap != nullptr)
|
||||
{
|
||||
palette_manager_->find_or_create_colormap(rhi, cmd.colormap);
|
||||
palette_manager_->find_or_create_colormap(rhi, ctx, cmd.colormap);
|
||||
}
|
||||
},
|
||||
[&](const Draw2dVertices& cmd) {}};
|
||||
|
|
@ -325,10 +307,10 @@ void TwodeePass::prepass(Rhi& rhi)
|
|||
{
|
||||
patch_atlas_cache_->queue_patch(patch);
|
||||
}
|
||||
patch_atlas_cache_->pack(rhi);
|
||||
patch_atlas_cache_->pack(rhi, ctx);
|
||||
|
||||
size_t list_index = 0;
|
||||
for (auto& list : *ctx_)
|
||||
for (auto& list : twodee)
|
||||
{
|
||||
Handle<Buffer> vbo;
|
||||
uint32_t vertex_data_size = tcb::as_bytes(tcb::span(list.vertices)).size();
|
||||
|
|
@ -461,7 +443,7 @@ void TwodeePass::prepass(Rhi& rhi)
|
|||
{
|
||||
if (cmd.flat_lump != LUMPERROR)
|
||||
{
|
||||
flat_manager_->find_or_create_indexed(rhi, cmd.flat_lump);
|
||||
flat_manager_->find_or_create_indexed(rhi, ctx, cmd.flat_lump);
|
||||
typeof(the_new_one.texture) t = MergedTwodeeCommandFlatTexture {cmd.flat_lump};
|
||||
the_new_one.texture = t;
|
||||
}
|
||||
|
|
@ -496,28 +478,12 @@ void TwodeePass::prepass(Rhi& rhi)
|
|||
|
||||
list_index++;
|
||||
}
|
||||
}
|
||||
|
||||
void TwodeePass::transfer(Rhi& rhi, Handle<GraphicsContext> ctx)
|
||||
{
|
||||
if (!ctx_ || !data_)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (data_->upload_default_tex)
|
||||
{
|
||||
std::array<uint8_t, 4> data = {0, 255, 0, 255};
|
||||
rhi.update_texture(ctx, data_->default_tex, {0, 0, 2, 1}, PixelFormat::kRG8, tcb::as_bytes(tcb::span(data)));
|
||||
|
||||
data_->upload_default_tex = false;
|
||||
}
|
||||
|
||||
Handle<Texture> palette_tex = palette_manager_->palette();
|
||||
|
||||
// Update the buffers for each list
|
||||
auto ctx_list_itr = ctx_->begin();
|
||||
for (size_t i = 0; i < cmd_lists_.size() && ctx_list_itr != ctx_->end(); i++)
|
||||
auto ctx_list_itr = twodee.begin();
|
||||
for (size_t i = 0; i < cmd_lists_.size() && ctx_list_itr != twodee.end(); i++)
|
||||
{
|
||||
auto& merged_list = cmd_lists_[i];
|
||||
auto& orig_list = *ctx_list_itr;
|
||||
|
|
@ -540,7 +506,7 @@ void TwodeePass::transfer(Rhi& rhi, Handle<GraphicsContext> ctx)
|
|||
},
|
||||
[&](const MergedTwodeeCommandFlatTexture& tex)
|
||||
{
|
||||
Handle<Texture> th = flat_manager_->find_indexed(tex.lump);
|
||||
Handle<Texture> th = flat_manager_->find_or_create_indexed(rhi, ctx, tex.lump);
|
||||
SRB2_ASSERT(th != kNullHandle);
|
||||
tx[0] = {SamplerName::kSampler0, th};
|
||||
tx[1] = {SamplerName::kSampler1, palette_tex};
|
||||
|
|
@ -551,7 +517,7 @@ void TwodeePass::transfer(Rhi& rhi, Handle<GraphicsContext> ctx)
|
|||
}
|
||||
else
|
||||
{
|
||||
tx[0] = {SamplerName::kSampler0, data_->default_tex};
|
||||
tx[0] = {SamplerName::kSampler0, default_tex_};
|
||||
tx[1] = {SamplerName::kSampler1, palette_tex};
|
||||
}
|
||||
|
||||
|
|
@ -559,12 +525,12 @@ void TwodeePass::transfer(Rhi& rhi, Handle<GraphicsContext> ctx)
|
|||
Handle<Texture> colormap_h = palette_manager_->default_colormap();
|
||||
if (colormap)
|
||||
{
|
||||
colormap_h = palette_manager_->find_colormap(colormap);
|
||||
colormap_h = palette_manager_->find_or_create_colormap(rhi, ctx, colormap);
|
||||
SRB2_ASSERT(colormap_h != kNullHandle);
|
||||
}
|
||||
tx[2] = {SamplerName::kSampler2, colormap_h};
|
||||
mcmd.binding_set =
|
||||
rhi.create_binding_set(ctx, data_->pipelines[mcmd.pipeline_key], {tcb::span(vbos), tcb::span(tx)});
|
||||
rhi.create_binding_set(ctx, pipelines_[mcmd.pipeline_key], {tcb::span(vbos), tcb::span(tx)});
|
||||
}
|
||||
|
||||
ctx_list_itr++;
|
||||
|
|
@ -588,28 +554,10 @@ void TwodeePass::transfer(Rhi& rhi, Handle<GraphicsContext> ctx)
|
|||
// Sampler 0 Is Indexed Alpha (yes, it always is)
|
||||
static_cast<int32_t>(1)
|
||||
};
|
||||
us_1 = rhi.create_uniform_set(ctx, {tcb::span(g1_uniforms)});
|
||||
us_2 = rhi.create_uniform_set(ctx, {tcb::span(g2_uniforms)});
|
||||
}
|
||||
|
||||
static constexpr const glm::vec4 kClearColor = {0, 0, 0, 1};
|
||||
|
||||
void TwodeePass::graphics(Rhi& rhi, Handle<GraphicsContext> ctx)
|
||||
{
|
||||
if (!ctx_ || !data_)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (output_)
|
||||
{
|
||||
rhi.begin_render_pass(ctx, {render_pass_, output_, std::nullopt, kClearColor});
|
||||
}
|
||||
else
|
||||
{
|
||||
rhi.begin_default_render_pass(ctx, false);
|
||||
}
|
||||
Handle<UniformSet> us_1 = rhi.create_uniform_set(ctx, {tcb::span(g1_uniforms)});
|
||||
Handle<UniformSet> us_2 = rhi.create_uniform_set(ctx, {tcb::span(g2_uniforms)});
|
||||
|
||||
// Presumably, we're already in a renderpass when flush is called
|
||||
for (auto& list : cmd_lists_)
|
||||
{
|
||||
for (auto& cmd : list.cmds)
|
||||
|
|
@ -620,13 +568,10 @@ void TwodeePass::graphics(Rhi& rhi, Handle<GraphicsContext> ctx)
|
|||
// This shouldn't happen, but, just in case...
|
||||
continue;
|
||||
}
|
||||
SRB2_ASSERT(data_->pipelines.find(cmd.pipeline_key) != data_->pipelines.end());
|
||||
Handle<Pipeline> pl = data_->pipelines[cmd.pipeline_key];
|
||||
SRB2_ASSERT(pipelines_.find(cmd.pipeline_key) != pipelines_.end());
|
||||
Handle<Pipeline> pl = pipelines_[cmd.pipeline_key];
|
||||
rhi.bind_pipeline(ctx, pl);
|
||||
if (output_)
|
||||
{
|
||||
rhi.set_viewport(ctx, {0, 0, output_width_, output_height_});
|
||||
}
|
||||
rhi.set_viewport(ctx, {0, 0, static_cast<uint32_t>(vid.width), static_cast<uint32_t>(vid.height)});
|
||||
rhi.bind_uniform_set(ctx, 0, us_1);
|
||||
rhi.bind_uniform_set(ctx, 1, us_2);
|
||||
rhi.bind_binding_set(ctx, cmd.binding_set);
|
||||
|
|
@ -634,15 +579,15 @@ void TwodeePass::graphics(Rhi& rhi, Handle<GraphicsContext> ctx)
|
|||
rhi.draw_indexed(ctx, cmd.elements, cmd.index_offset);
|
||||
}
|
||||
}
|
||||
rhi.end_render_pass(ctx);
|
||||
}
|
||||
|
||||
void TwodeePass::postpass(Rhi& rhi)
|
||||
{
|
||||
if (!ctx_ || !data_)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
cmd_lists_.clear();
|
||||
|
||||
// Reset context for next drawing batch
|
||||
twodee = Twodee();
|
||||
|
||||
// Reset the patch atlas if needed
|
||||
if (patch_atlas_cache_->need_to_reset())
|
||||
{
|
||||
patch_atlas_cache_->reset(rhi);
|
||||
}
|
||||
}
|
||||
|
|
@ -19,17 +19,13 @@
|
|||
|
||||
#include "../cxxutil.hpp"
|
||||
#include "patch_atlas.hpp"
|
||||
#include "pass.hpp"
|
||||
#include "pass_resource_managers.hpp"
|
||||
#include "resource_management.hpp"
|
||||
#include "twodee.hpp"
|
||||
|
||||
namespace srb2::hwr2
|
||||
{
|
||||
|
||||
class TwodeePass;
|
||||
|
||||
/// @brief Shared structures to allow multiple 2D instances to share the same atlases
|
||||
struct TwodeePassData;
|
||||
class TwodeeRenderer;
|
||||
|
||||
/// @brief Hash map key for caching pipelines
|
||||
struct TwodeePipelineKey
|
||||
|
|
@ -41,6 +37,22 @@ struct TwodeePipelineKey
|
|||
bool operator!=(const TwodeePipelineKey& r) const noexcept { return !(*this == r); }
|
||||
};
|
||||
|
||||
} // namespace srb2::hwr2
|
||||
|
||||
template <>
|
||||
struct std::hash<srb2::hwr2::TwodeePipelineKey>
|
||||
{
|
||||
std::size_t operator()(const srb2::hwr2::TwodeePipelineKey& v) const
|
||||
{
|
||||
std::size_t hash = 0;
|
||||
srb2::hash_combine(hash, v.blend, v.lines);
|
||||
return hash;
|
||||
}
|
||||
};
|
||||
|
||||
namespace srb2::hwr2
|
||||
{
|
||||
|
||||
struct MergedTwodeeCommandFlatTexture
|
||||
{
|
||||
lumpnum_t lump;
|
||||
|
|
@ -69,52 +81,44 @@ struct MergedTwodeeCommandList
|
|||
std::vector<MergedTwodeeCommand> cmds;
|
||||
};
|
||||
|
||||
std::shared_ptr<TwodeePassData> make_twodee_pass_data();
|
||||
|
||||
struct TwodeePass final : public Pass
|
||||
class TwodeeRenderer final
|
||||
{
|
||||
Twodee* ctx_ = nullptr;
|
||||
bool initialized_ = false;
|
||||
std::variant<rhi::Handle<rhi::Texture>, rhi::Handle<rhi::Renderbuffer>> out_color_;
|
||||
|
||||
std::shared_ptr<TwodeePassData> data_;
|
||||
std::shared_ptr<MainPaletteManager> palette_manager_;
|
||||
std::shared_ptr<FlatTextureManager> flat_manager_;
|
||||
std::shared_ptr<PatchAtlasCache> patch_atlas_cache_;
|
||||
rhi::Handle<rhi::UniformSet> us_1;
|
||||
rhi::Handle<rhi::UniformSet> us_2;
|
||||
PaletteManager* palette_manager_;
|
||||
FlatTextureManager* flat_manager_;
|
||||
PatchAtlasCache* patch_atlas_cache_;
|
||||
std::vector<MergedTwodeeCommandList> cmd_lists_;
|
||||
std::vector<std::tuple<rhi::Handle<rhi::Buffer>, std::size_t>> vbos_;
|
||||
std::vector<std::tuple<rhi::Handle<rhi::Buffer>, std::size_t>> ibos_;
|
||||
rhi::Handle<rhi::RenderPass> render_pass_;
|
||||
rhi::Handle<rhi::Texture> output_;
|
||||
uint32_t output_width_ = 0;
|
||||
uint32_t output_height_ = 0;
|
||||
rhi::Handle<rhi::Texture> default_tex_;
|
||||
std::unordered_map<TwodeePipelineKey, rhi::Handle<rhi::Pipeline>> pipelines_;
|
||||
|
||||
void rewrite_patch_quad_vertices(Draw2dList& list, const Draw2dPatchQuad& cmd) const;
|
||||
|
||||
TwodeePass();
|
||||
virtual ~TwodeePass();
|
||||
void initialize(rhi::Rhi& rhi, rhi::Handle<rhi::GraphicsContext> ctx);
|
||||
|
||||
virtual void prepass(rhi::Rhi& rhi) override;
|
||||
public:
|
||||
TwodeeRenderer(
|
||||
srb2::NotNull<PaletteManager*> palette_manager,
|
||||
srb2::NotNull<FlatTextureManager*> flat_manager,
|
||||
srb2::NotNull<PatchAtlasCache*> patch_atlas_cache
|
||||
);
|
||||
TwodeeRenderer(const TwodeeRenderer&) = delete;
|
||||
TwodeeRenderer(TwodeeRenderer&&);
|
||||
~TwodeeRenderer();
|
||||
TwodeeRenderer& operator=(const TwodeeRenderer&) = delete;
|
||||
TwodeeRenderer& operator=(TwodeeRenderer&&);
|
||||
|
||||
virtual void transfer(rhi::Rhi& rhi, rhi::Handle<rhi::GraphicsContext> ctx) override;
|
||||
|
||||
virtual void graphics(rhi::Rhi& rhi, rhi::Handle<rhi::GraphicsContext> ctx) override;
|
||||
|
||||
virtual void postpass(rhi::Rhi& rhi) override;
|
||||
/// @brief Flush accumulated Twodee state and perform draws.
|
||||
/// @param rhi
|
||||
/// @param ctx
|
||||
void flush(rhi::Rhi& rhi, rhi::Handle<rhi::GraphicsContext> ctx, Twodee& twodee);
|
||||
};
|
||||
|
||||
} // namespace srb2::hwr2
|
||||
|
||||
template <>
|
||||
struct std::hash<srb2::hwr2::TwodeePipelineKey>
|
||||
{
|
||||
std::size_t operator()(const srb2::hwr2::TwodeePipelineKey& v) const
|
||||
{
|
||||
std::size_t hash = 0;
|
||||
srb2::hash_combine(hash, v.blend, v.lines);
|
||||
return hash;
|
||||
}
|
||||
};
|
||||
|
||||
#endif // __SRB2_HWR2_PASS_TWODEE_HPP__
|
||||
|
|
@ -18,6 +18,7 @@
|
|||
|
||||
#ifdef __cplusplus
|
||||
|
||||
#include "hwr2/hardware_state.hpp"
|
||||
#include "rhi/rhi.hpp"
|
||||
|
||||
namespace srb2::sys {
|
||||
|
|
@ -26,7 +27,10 @@ extern rhi::Handle<rhi::Rhi> g_current_rhi;
|
|||
|
||||
rhi::Rhi* get_rhi(rhi::Handle<rhi::Rhi> handle);
|
||||
|
||||
} // namespace
|
||||
rhi::Handle<rhi::GraphicsContext> main_graphics_context();
|
||||
hwr2::HardwareState* main_hardware_state();
|
||||
|
||||
} // namespace srb2::sys
|
||||
|
||||
extern "C" {
|
||||
#endif
|
||||
|
|
@ -130,25 +134,14 @@ extern boolean allow_fullscreen;
|
|||
*/
|
||||
void I_UpdateNoBlit(void);
|
||||
|
||||
/** \brief Begin a new Twodee frame.
|
||||
/** \brief Start a display update.
|
||||
*/
|
||||
void I_NewTwodeeFrame(void);
|
||||
|
||||
/** \brief Begin a new dear imgui frame.
|
||||
*/
|
||||
void I_NewImguiFrame(void);
|
||||
void I_StartDisplayUpdate(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);
|
||||
|
|
@ -179,6 +172,8 @@ void I_EndRead(void);
|
|||
|
||||
UINT32 I_GetRefreshRate(void);
|
||||
|
||||
void I_CaptureVideoFrame(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -17,16 +17,9 @@
|
|||
|
||||
#include "cxxutil.hpp"
|
||||
#include "f_finale.h"
|
||||
#include "m_misc.h"
|
||||
#include "hwr2/hardware_state.hpp"
|
||||
#include "hwr2/patch_atlas.hpp"
|
||||
#include "hwr2/pass_blit_postimg_screens.hpp"
|
||||
#include "hwr2/pass_blit_rect.hpp"
|
||||
#include "hwr2/pass_imgui.hpp"
|
||||
#include "hwr2/pass_manager.hpp"
|
||||
#include "hwr2/pass_postprocess.hpp"
|
||||
#include "hwr2/pass_resource_managers.hpp"
|
||||
#include "hwr2/pass_screenshot.hpp"
|
||||
#include "hwr2/pass_software.hpp"
|
||||
#include "hwr2/pass_twodee.hpp"
|
||||
#include "hwr2/twodee.hpp"
|
||||
#include "v_video.h"
|
||||
|
||||
|
|
@ -56,21 +49,10 @@ using namespace srb2;
|
|||
using namespace srb2::hwr2;
|
||||
using namespace srb2::rhi;
|
||||
|
||||
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;
|
||||
static bool g_imgui_frame_active = false;
|
||||
static Handle<GraphicsContext> g_main_graphics_context;
|
||||
static HardwareState g_hw_state;
|
||||
|
||||
Handle<Rhi> srb2::sys::g_current_rhi = kNullHandle;
|
||||
|
||||
|
|
@ -79,6 +61,46 @@ static bool rhi_changed(Rhi* rhi)
|
|||
return g_last_known_rhi != rhi;
|
||||
}
|
||||
|
||||
static void reset_hardware_state(Rhi* rhi)
|
||||
{
|
||||
// The lifetime of objects pointed to by RHI Handles is determined by the RHI itself, so it is enough to simply
|
||||
// "forget" about the resources previously known.
|
||||
g_hw_state = HardwareState {};
|
||||
g_hw_state.palette_manager = std::make_unique<PaletteManager>();
|
||||
g_hw_state.flat_manager = std::make_unique<FlatTextureManager>();
|
||||
g_hw_state.patch_atlas_cache = std::make_unique<PatchAtlasCache>(2048, 3);
|
||||
g_hw_state.twodee_renderer = std::make_unique<TwodeeRenderer>(
|
||||
g_hw_state.palette_manager.get(),
|
||||
g_hw_state.flat_manager.get(),
|
||||
g_hw_state.patch_atlas_cache.get()
|
||||
);
|
||||
g_hw_state.software_screen_renderer = std::make_unique<SoftwareScreenRenderer>();
|
||||
g_hw_state.blit_postimg_screens = std::make_unique<BlitPostimgScreens>(g_hw_state.palette_manager.get());
|
||||
g_hw_state.wipe = std::make_unique<PostprocessWipePass>();
|
||||
g_hw_state.blit_rect = std::make_unique<BlitRectPass>();
|
||||
g_hw_state.screen_capture = std::make_unique<ScreenshotPass>();
|
||||
g_hw_state.wipe_frames = {};
|
||||
|
||||
g_last_known_rhi = rhi;
|
||||
}
|
||||
|
||||
static void new_twodee_frame();
|
||||
static void new_imgui_frame();
|
||||
|
||||
static void preframe_update(Rhi& rhi)
|
||||
{
|
||||
SRB2_ASSERT(g_main_graphics_context != kNullHandle);
|
||||
|
||||
g_hw_state.palette_manager->update(rhi, g_main_graphics_context);
|
||||
new_twodee_frame();
|
||||
new_imgui_frame();
|
||||
}
|
||||
|
||||
static void postframe_update(Rhi& rhi)
|
||||
{
|
||||
g_hw_state.palette_manager->destroy_per_frame_resources(rhi);
|
||||
}
|
||||
|
||||
#ifdef HWRENDER
|
||||
static void finish_legacy_ogl_update()
|
||||
{
|
||||
|
|
@ -187,278 +209,13 @@ static void temp_legacy_finishupdate_draws()
|
|||
ST_drawDebugInfo();
|
||||
}
|
||||
|
||||
static InternalPassData build_pass_manager()
|
||||
{
|
||||
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 patch_atlas_cache = std::make_shared<PatchAtlasCache>(2048, 2);
|
||||
auto resource_manager = std::make_shared<PassManager>();
|
||||
|
||||
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);
|
||||
resource_manager->insert("patch_atlas_cache", patch_atlas_cache);
|
||||
|
||||
// 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_postimg_screens = std::make_shared<BlitPostimgScreens>(palette_manager);
|
||||
auto twodee = std::make_shared<TwodeePass>();
|
||||
twodee->flat_manager_ = flat_texture_manager;
|
||||
twodee->patch_atlas_cache_ = patch_atlas_cache;
|
||||
twodee->data_ = make_twodee_pass_data();
|
||||
twodee->ctx_ = &g_2d;
|
||||
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);
|
||||
|
||||
basic_rendering->insert(
|
||||
"3d_prepare",
|
||||
[framebuffer_manager](PassManager& mgr, Rhi&)
|
||||
{
|
||||
const bool sw_enabled = rendermode == render_soft && gamestate != GS_NULL;
|
||||
|
||||
mgr.set_pass_enabled("software", sw_enabled);
|
||||
mgr.set_pass_enabled("blit_postimg_screens_prepare", sw_enabled);
|
||||
mgr.set_pass_enabled("blit_postimg_screens", sw_enabled && !g_wipeskiprender);
|
||||
}
|
||||
);
|
||||
basic_rendering->insert("software", software_pass);
|
||||
basic_rendering->insert(
|
||||
"blit_postimg_screens_prepare",
|
||||
[blit_postimg_screens, software_pass, framebuffer_manager](PassManager&, Rhi&)
|
||||
{
|
||||
const bool sw_enabled = rendermode == render_soft && gamestate != GS_NULL;
|
||||
const int screens = std::clamp(r_splitscreen + 1, 1, MAXSPLITSCREENPLAYERS);
|
||||
|
||||
blit_postimg_screens->set_num_screens(screens);
|
||||
for (int i = 0; i < screens; i++)
|
||||
{
|
||||
if (sw_enabled)
|
||||
{
|
||||
glm::vec2 uv_offset {0.f, 0.f};
|
||||
glm::vec2 uv_size {1.f, 1.f};
|
||||
|
||||
if (screens > 2)
|
||||
{
|
||||
uv_size = glm::vec2(.5f, .5f);
|
||||
switch (i)
|
||||
{
|
||||
case 0:
|
||||
uv_offset = glm::vec2(0.f, 0.f);
|
||||
break;
|
||||
case 1:
|
||||
uv_offset = glm::vec2(.5f, 0.f);
|
||||
break;
|
||||
case 2:
|
||||
uv_offset = glm::vec2(0.f, .5f);
|
||||
break;
|
||||
case 3:
|
||||
uv_offset = glm::vec2(.5f, .5f);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (screens > 1)
|
||||
{
|
||||
uv_size = glm::vec2(1.0, 0.5);
|
||||
if (i == 1)
|
||||
{
|
||||
uv_offset = glm::vec2(0.f, .5f);
|
||||
}
|
||||
}
|
||||
|
||||
// "You should probably never have more than 3 levels of indentation" -- Eidolon, the author of this
|
||||
|
||||
blit_postimg_screens->set_screen(
|
||||
i,
|
||||
{
|
||||
software_pass->screen_texture(),
|
||||
true,
|
||||
uv_offset,
|
||||
uv_size,
|
||||
{
|
||||
postimgtype[i] == postimg_water,
|
||||
postimgtype[i] == postimg_heat,
|
||||
postimgtype[i] == postimg_flip,
|
||||
postimgtype[i] == postimg_mirror
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
blit_postimg_screens->set_target(framebuffer_manager->main_color(), vid.width, vid.height);
|
||||
}
|
||||
);
|
||||
basic_rendering->insert("blit_postimg_screens", blit_postimg_screens);
|
||||
|
||||
basic_rendering->insert(
|
||||
"2d_prepare",
|
||||
[twodee, framebuffer_manager, palette_manager](PassManager& mgr, Rhi&)
|
||||
{
|
||||
twodee->output_ = framebuffer_manager->main_color();
|
||||
twodee->palette_manager_ = palette_manager;
|
||||
twodee->output_width_ = vid.width;
|
||||
twodee->output_height_ = vid.height;
|
||||
}
|
||||
);
|
||||
basic_rendering->insert("2d", twodee);
|
||||
|
||||
basic_rendering->insert(
|
||||
"pp_final_simple_blit_prepare",
|
||||
[pp_simple_blit_pass, framebuffer_manager](PassManager&, Rhi&)
|
||||
{
|
||||
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, false);
|
||||
}
|
||||
);
|
||||
basic_rendering->insert("pp_final_simple_blit", pp_simple_blit_pass);
|
||||
|
||||
auto screenshot_rendering = std::make_shared<PassManager>();
|
||||
|
||||
screenshot_rendering->insert(
|
||||
"screenshot_prepare",
|
||||
[screenshot_pass, framebuffer_manager](PassManager&, Rhi&)
|
||||
{
|
||||
screenshot_pass->set_source(framebuffer_manager->current_post_color(), vid.width, vid.height);
|
||||
}
|
||||
);
|
||||
screenshot_rendering->insert("screenshot", screenshot_pass);
|
||||
|
||||
// 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->current_post_color(), vid.width, vid.height);
|
||||
final_composite_pass->set_output(kNullHandle, vid.realwidth, vid.realheight, true, false);
|
||||
}
|
||||
);
|
||||
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)
|
||||
{
|
||||
g_imgui_frame_active = false;
|
||||
rhi.present();
|
||||
rhi.finish();
|
||||
framebuffer_manager->reset_post();
|
||||
I_NewImguiFrame();
|
||||
}
|
||||
);
|
||||
|
||||
// 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("screenshot_rendering", screenshot_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>();
|
||||
auto wipe_end_blit_start_to_main = 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, wipe_end_blit_start_to_main](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_end_blit_start_to_main->set_texture(
|
||||
framebuffer_manager->wipe_start_color(),
|
||||
vid.width,
|
||||
vid.height
|
||||
);
|
||||
wipe_end_blit_start_to_main->set_output(
|
||||
framebuffer_manager->main_color(),
|
||||
vid.width,
|
||||
vid.height,
|
||||
false,
|
||||
true
|
||||
);
|
||||
}
|
||||
);
|
||||
wipe_capture_end_rendering->insert("wipe_capture", wipe_end_blit);
|
||||
wipe_capture_end_rendering->insert("wipe_end_blit_start_to_main", wipe_end_blit_start_to_main);
|
||||
|
||||
// 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->main_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("screenshot_rendering", screenshot_rendering);
|
||||
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)
|
||||
static void new_twodee_frame()
|
||||
{
|
||||
g_2d = Twodee();
|
||||
Patch_ResetFreedThisFrame();
|
||||
}
|
||||
|
||||
void I_NewImguiFrame(void)
|
||||
static void new_imgui_frame()
|
||||
{
|
||||
if (g_imgui_frame_active)
|
||||
{
|
||||
|
|
@ -472,13 +229,61 @@ void I_NewImguiFrame(void)
|
|||
g_imgui_frame_active = true;
|
||||
}
|
||||
|
||||
static void maybe_reinit_passes(Rhi* rhi)
|
||||
rhi::Handle<rhi::GraphicsContext> sys::main_graphics_context()
|
||||
{
|
||||
if (rhi_changed(rhi) || !g_passes)
|
||||
return g_main_graphics_context;
|
||||
}
|
||||
|
||||
HardwareState* sys::main_hardware_state()
|
||||
{
|
||||
return &g_hw_state;
|
||||
}
|
||||
|
||||
void I_CaptureVideoFrame()
|
||||
{
|
||||
rhi::Rhi* rhi = srb2::sys::get_rhi(srb2::sys::g_current_rhi);
|
||||
rhi::Handle<rhi::GraphicsContext> ctx = srb2::sys::main_graphics_context();
|
||||
hwr2::HardwareState* hw_state = srb2::sys::main_hardware_state();
|
||||
|
||||
hw_state->screen_capture->set_source(static_cast<uint32_t>(vid.width), static_cast<uint32_t>(vid.height));
|
||||
hw_state->screen_capture->capture(*rhi, ctx);
|
||||
}
|
||||
|
||||
void I_StartDisplayUpdate(void)
|
||||
{
|
||||
if (rendermode == render_none)
|
||||
{
|
||||
g_last_known_rhi = rhi;
|
||||
g_passes = std::make_unique<InternalPassData>(build_pass_manager());
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef HWRENDER
|
||||
if (rendermode == render_opengl)
|
||||
{
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
rhi::Rhi* rhi = sys::get_rhi(sys::g_current_rhi);
|
||||
|
||||
if (rhi == nullptr)
|
||||
{
|
||||
// ???
|
||||
return;
|
||||
}
|
||||
|
||||
if (rhi_changed(rhi))
|
||||
{
|
||||
// Reset all hardware 2 state
|
||||
reset_hardware_state(rhi);
|
||||
}
|
||||
|
||||
rhi::Handle<rhi::GraphicsContext> ctx = rhi->begin_graphics();
|
||||
|
||||
rhi->begin_default_render_pass(ctx, false);
|
||||
|
||||
g_main_graphics_context = ctx;
|
||||
|
||||
preframe_update(*rhi);
|
||||
}
|
||||
|
||||
void I_FinishUpdate(void)
|
||||
|
|
@ -506,99 +311,22 @@ void I_FinishUpdate(void)
|
|||
return;
|
||||
}
|
||||
|
||||
maybe_reinit_passes(rhi);
|
||||
rhi::Handle<rhi::GraphicsContext> ctx = g_main_graphics_context;
|
||||
|
||||
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
|
||||
|
||||
temp_legacy_finishupdate_draws();
|
||||
|
||||
rhi::Rhi* rhi = sys::get_rhi(sys::g_current_rhi);
|
||||
|
||||
if (rhi == nullptr)
|
||||
{
|
||||
// ???
|
||||
return;
|
||||
}
|
||||
|
||||
maybe_reinit_passes(rhi);
|
||||
|
||||
g_passes->wipe_capture_start_rendering->render(*rhi);
|
||||
I_NewImguiFrame();
|
||||
}
|
||||
|
||||
void I_FinishUpdateWipeEndScreen(void)
|
||||
{
|
||||
if (rendermode == render_none)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef HWRENDER
|
||||
if (rendermode == render_opengl)
|
||||
{
|
||||
finish_legacy_ogl_update();
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
temp_legacy_finishupdate_draws();
|
||||
|
||||
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);
|
||||
I_NewImguiFrame();
|
||||
}
|
||||
|
||||
void I_FinishUpdateWipe(void)
|
||||
{
|
||||
if (rendermode == render_none)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef HWRENDER
|
||||
if (rendermode == render_opengl)
|
||||
{
|
||||
finish_legacy_ogl_update();
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
temp_legacy_finishupdate_draws();
|
||||
|
||||
rhi::Rhi* rhi = sys::get_rhi(sys::g_current_rhi);
|
||||
|
||||
if (rhi == nullptr)
|
||||
{
|
||||
// ???
|
||||
return;
|
||||
}
|
||||
|
||||
maybe_reinit_passes(rhi);
|
||||
|
||||
g_passes->wipe_rendering->render(*rhi);
|
||||
if (ctx != kNullHandle)
|
||||
{
|
||||
// better hope the drawing code left the context in a render pass, I guess
|
||||
g_hw_state.twodee_renderer->flush(*rhi, ctx, g_2d);
|
||||
rhi->end_render_pass(ctx);
|
||||
rhi->end_graphics(ctx);
|
||||
g_main_graphics_context = kNullHandle;
|
||||
|
||||
postframe_update(*rhi);
|
||||
}
|
||||
|
||||
rhi->present();
|
||||
rhi->finish();
|
||||
|
||||
// Immediately prepare to begin drawing the next frame
|
||||
I_StartDisplayUpdate();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -796,9 +796,6 @@ void Y_VoteDrawer(void)
|
|||
{
|
||||
static angle_t rubyFloatTime = 0;
|
||||
|
||||
// If we early return, skip drawing the 3D scene (software buffer) so it doesn't clobber the frame for the wipe
|
||||
g_wipeskiprender = true;
|
||||
|
||||
if (rendermode == render_none)
|
||||
{
|
||||
return;
|
||||
|
|
@ -814,8 +811,6 @@ void Y_VoteDrawer(void)
|
|||
return;
|
||||
}
|
||||
|
||||
g_wipeskiprender = false;
|
||||
|
||||
vote_draw.ruby_height = FINESINE(rubyFloatTime >> ANGLETOFINESHIFT);
|
||||
rubyFloatTime += FixedMul(ANGLE_MAX / NEWTICRATE, renderdeltatics);
|
||||
|
||||
|
|
@ -1226,7 +1221,7 @@ static void Y_TryMapAngerVote(void)
|
|||
|
||||
INT32 numPlayers = 0;
|
||||
INT32 i = 0;
|
||||
|
||||
|
||||
for (i = 0; i < MAXPLAYERS; i++)
|
||||
{
|
||||
if (Y_PlayerIDCanVote(i) == false)
|
||||
|
|
|
|||
|
|
@ -8074,14 +8074,9 @@ boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate)
|
|||
// This is needed. Don't touch.
|
||||
maptol = mapheaderinfo[gamemap-1]->typeoflevel;
|
||||
|
||||
// HWR2 skip 3d render draw hack to avoid losing the current wipe screen
|
||||
g_wipeskiprender = true;
|
||||
|
||||
CON_Drawer(); // let the user know what we are going to do
|
||||
I_FinishUpdate(); // page flip or blit buffer
|
||||
|
||||
g_wipeskiprender = false;
|
||||
|
||||
// Reset the palette
|
||||
if (rendermode != render_none)
|
||||
V_SetPaletteLump("PLAYPAL");
|
||||
|
|
@ -8150,6 +8145,8 @@ boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate)
|
|||
lastwipetic = nowtime; \
|
||||
if (moviemode && rendermode == render_opengl) \
|
||||
M_LegacySaveFrame(); \
|
||||
else if (moviemode && rendermode != render_none) \
|
||||
I_CaptureVideoFrame(); \
|
||||
NetKeepAlive(); \
|
||||
} \
|
||||
|
||||
|
|
@ -8451,7 +8448,7 @@ boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate)
|
|||
}
|
||||
|
||||
// Now safe to free.
|
||||
// We do the following silly
|
||||
// We do the following silly
|
||||
// construction because vres_Free
|
||||
// no-sells deletions of pointers
|
||||
// that are == curmapvirt.
|
||||
|
|
|
|||
|
|
@ -27,12 +27,17 @@ using namespace rhi;
|
|||
|
||||
#ifndef NDEBUG
|
||||
#define GL_ASSERT \
|
||||
while (1) \
|
||||
{ \
|
||||
GLenum __err = gl_->GetError(); \
|
||||
if (__err != GL_NO_ERROR) \
|
||||
{ \
|
||||
I_Error("GL Error at %s %d: %d", __FILE__, __LINE__, __err); \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
break; \
|
||||
} \
|
||||
}
|
||||
#else
|
||||
#define GL_ASSERT ;
|
||||
|
|
@ -1193,6 +1198,10 @@ void GlCoreRhi::end_graphics(rhi::Handle<rhi::GraphicsContext> handle)
|
|||
SRB2_ASSERT(graphics_context_active_ == true);
|
||||
SRB2_ASSERT(current_pipeline_.has_value() == false && current_render_pass_.has_value() == false);
|
||||
graphics_context_generation_ += 1;
|
||||
if (graphics_context_generation_ == 0)
|
||||
{
|
||||
graphics_context_generation_ = 1;
|
||||
}
|
||||
graphics_context_active_ = false;
|
||||
gl_->Flush();
|
||||
GL_ASSERT;
|
||||
|
|
@ -1646,6 +1655,7 @@ void GlCoreRhi::set_viewport(Handle<GraphicsContext> ctx, const Rect& rect)
|
|||
SRB2_ASSERT(current_render_pass_.has_value() == true && current_pipeline_.has_value() == true);
|
||||
|
||||
gl_->Viewport(rect.x, rect.y, rect.w, rect.h);
|
||||
GL_ASSERT;
|
||||
}
|
||||
|
||||
void GlCoreRhi::draw(Handle<GraphicsContext> ctx, uint32_t vertex_count, uint32_t first_vertex)
|
||||
|
|
@ -1688,9 +1698,38 @@ void GlCoreRhi::read_pixels(Handle<GraphicsContext> ctx, const Rect& rect, Pixel
|
|||
GLenum type = std::get<1>(gl_format);
|
||||
GLint size = std::get<2>(gl_format);
|
||||
|
||||
SRB2_ASSERT(out.size_bytes() == rect.w * rect.h * size);
|
||||
// Pack alignment comes into play.
|
||||
uint32_t pack_aligned_w = (rect.w + (kPixelRowPackAlignment - 1)) & ~(kPixelRowPackAlignment - 1);
|
||||
|
||||
SRB2_ASSERT(out.size_bytes() == pack_aligned_w * rect.h * size);
|
||||
|
||||
bool is_back;
|
||||
Rect src_dim;
|
||||
auto render_pass_visitor = srb2::Overload {
|
||||
[&](const DefaultRenderPassState& state) {
|
||||
is_back = true;
|
||||
src_dim = platform_->get_default_framebuffer_dimensions();
|
||||
},
|
||||
[&](const RenderPassBeginInfo& state) {
|
||||
is_back = false;
|
||||
SRB2_ASSERT(texture_slab_.is_valid(state.color_attachment));
|
||||
auto& attach_tex = texture_slab_[state.color_attachment];
|
||||
src_dim = {0, 0, attach_tex.desc.width, attach_tex.desc.height};
|
||||
}
|
||||
};
|
||||
std::visit(render_pass_visitor, *current_render_pass_);
|
||||
|
||||
SRB2_ASSERT(rect.x >= 0);
|
||||
SRB2_ASSERT(rect.y >= 0);
|
||||
SRB2_ASSERT(rect.x + rect.w <= src_dim.w);
|
||||
SRB2_ASSERT(rect.y + rect.h <= src_dim.h);
|
||||
|
||||
GLenum read_buffer = is_back ? GL_BACK_LEFT : GL_COLOR_ATTACHMENT0;
|
||||
gl_->ReadBuffer(read_buffer);
|
||||
GL_ASSERT;
|
||||
|
||||
gl_->ReadPixels(rect.x, rect.y, rect.w, rect.h, layout, type, out.data());
|
||||
GL_ASSERT;
|
||||
}
|
||||
|
||||
void GlCoreRhi::set_stencil_reference(Handle<GraphicsContext> ctx, CullMode face, uint8_t reference)
|
||||
|
|
@ -1839,3 +1878,53 @@ void GlCoreRhi::finish()
|
|||
disposal_.clear();
|
||||
GL_ASSERT;
|
||||
}
|
||||
|
||||
void GlCoreRhi::copy_framebuffer_to_texture(
|
||||
Handle<GraphicsContext> ctx,
|
||||
Handle<Texture> dst_tex,
|
||||
const Rect& dst_region,
|
||||
const Rect& src_region
|
||||
)
|
||||
{
|
||||
SRB2_ASSERT(graphics_context_active_ == true);
|
||||
SRB2_ASSERT(current_render_pass_.has_value());
|
||||
SRB2_ASSERT(texture_slab_.is_valid(dst_tex));
|
||||
|
||||
auto& tex = texture_slab_[dst_tex];
|
||||
SRB2_ASSERT(dst_region.w == src_region.w);
|
||||
SRB2_ASSERT(dst_region.h == src_region.h);
|
||||
SRB2_ASSERT(dst_region.x >= 0);
|
||||
SRB2_ASSERT(dst_region.y >= 0);
|
||||
SRB2_ASSERT(dst_region.x + dst_region.w <= tex.desc.width);
|
||||
SRB2_ASSERT(dst_region.y + dst_region.h <= tex.desc.height);
|
||||
|
||||
bool is_back;
|
||||
Rect src_dim;
|
||||
auto render_pass_visitor = srb2::Overload {
|
||||
[&](const DefaultRenderPassState& state) {
|
||||
is_back = true;
|
||||
src_dim = platform_->get_default_framebuffer_dimensions();
|
||||
},
|
||||
[&](const RenderPassBeginInfo& state) {
|
||||
is_back = false;
|
||||
SRB2_ASSERT(texture_slab_.is_valid(state.color_attachment));
|
||||
auto& attach_tex = texture_slab_[state.color_attachment];
|
||||
src_dim = {0, 0, attach_tex.desc.width, attach_tex.desc.height};
|
||||
}
|
||||
};
|
||||
std::visit(render_pass_visitor, *current_render_pass_);
|
||||
|
||||
SRB2_ASSERT(src_region.x >= 0);
|
||||
SRB2_ASSERT(src_region.y >= 0);
|
||||
SRB2_ASSERT(src_region.x + src_region.w <= src_dim.w);
|
||||
SRB2_ASSERT(src_region.y + src_region.h <= src_dim.h);
|
||||
|
||||
GLenum read_buffer = is_back ? GL_BACK_LEFT : GL_COLOR_ATTACHMENT0;
|
||||
gl_->ReadBuffer(read_buffer);
|
||||
GL_ASSERT;
|
||||
|
||||
gl_->BindTexture(GL_TEXTURE_2D, tex.texture);
|
||||
GL_ASSERT;
|
||||
gl_->CopyTexSubImage2D(GL_TEXTURE_2D, 0, dst_region.x, dst_region.y, src_region.x, src_region.y, dst_region.w, dst_region.h);
|
||||
GL_ASSERT;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -155,7 +155,7 @@ class GlCoreRhi final : public Rhi
|
|||
std::optional<Handle<Pipeline>> current_pipeline_;
|
||||
PrimitiveType current_primitive_type_ = PrimitiveType::kPoints;
|
||||
bool graphics_context_active_ = false;
|
||||
uint32_t graphics_context_generation_ = 0;
|
||||
uint32_t graphics_context_generation_ = 1;
|
||||
uint32_t index_buffer_offset_ = 0;
|
||||
|
||||
uint8_t stencil_front_reference_ = 0;
|
||||
|
|
@ -223,6 +223,12 @@ public:
|
|||
virtual void draw_indexed(Handle<GraphicsContext> ctx, uint32_t index_count, uint32_t first_index) override;
|
||||
virtual void
|
||||
read_pixels(Handle<GraphicsContext> ctx, const Rect& rect, PixelFormat format, tcb::span<std::byte> out) override;
|
||||
virtual void copy_framebuffer_to_texture(
|
||||
Handle<GraphicsContext> ctx,
|
||||
Handle<Texture> dst_tex,
|
||||
const Rect& dst_region,
|
||||
const Rect& src_region
|
||||
) override;
|
||||
virtual void set_stencil_reference(Handle<GraphicsContext> ctx, CullMode face, uint8_t reference) override;
|
||||
virtual void set_stencil_compare_mask(Handle<GraphicsContext> ctx, CullMode face, uint8_t mask) override;
|
||||
virtual void set_stencil_write_mask(Handle<GraphicsContext> ctx, CullMode face, uint8_t mask) override;
|
||||
|
|
|
|||
|
|
@ -582,6 +582,7 @@ struct TextureDetails
|
|||
|
||||
/// @brief The unpack alignment of a row span when uploading pixels to the device.
|
||||
constexpr const std::size_t kPixelRowUnpackAlignment = 4;
|
||||
constexpr const std::size_t kPixelRowPackAlignment = 4;
|
||||
|
||||
/// @brief An active handle to a rendering device.
|
||||
struct Rhi
|
||||
|
|
@ -638,6 +639,12 @@ struct Rhi
|
|||
virtual void draw_indexed(Handle<GraphicsContext> ctx, uint32_t index_count, uint32_t first_index) = 0;
|
||||
virtual void
|
||||
read_pixels(Handle<GraphicsContext> ctx, const Rect& rect, PixelFormat format, tcb::span<std::byte> out) = 0;
|
||||
virtual void copy_framebuffer_to_texture(
|
||||
Handle<GraphicsContext> ctx,
|
||||
Handle<Texture> dst_tex,
|
||||
const Rect& dst_region,
|
||||
const Rect& src_region
|
||||
) = 0;
|
||||
virtual void set_stencil_reference(Handle<GraphicsContext> ctx, CullMode face, uint8_t reference) = 0;
|
||||
virtual void set_stencil_compare_mask(Handle<GraphicsContext> ctx, CullMode face, uint8_t mask) = 0;
|
||||
virtual void set_stencil_write_mask(Handle<GraphicsContext> ctx, CullMode face, uint8_t mask) = 0;
|
||||
|
|
|
|||
|
|
@ -190,7 +190,7 @@ static void SDLSetMode(INT32 width, INT32 height, SDL_bool fullscreen, SDL_bool
|
|||
if (fullscreen)
|
||||
{
|
||||
wasfullscreen = SDL_TRUE;
|
||||
SDL_SetWindowFullscreen(window, SDL_WINDOW_FULLSCREEN_DESKTOP);
|
||||
SDL_SetWindowFullscreen(window, SDL_WINDOW_FULLSCREEN);
|
||||
}
|
||||
else // windowed mode
|
||||
{
|
||||
|
|
@ -217,7 +217,7 @@ static void SDLSetMode(INT32 width, INT32 height, SDL_bool fullscreen, SDL_bool
|
|||
SDL_SetWindowSize(window, width, height);
|
||||
if (fullscreen)
|
||||
{
|
||||
SDL_SetWindowFullscreen(window, SDL_WINDOW_FULLSCREEN_DESKTOP);
|
||||
SDL_SetWindowFullscreen(window, SDL_WINDOW_FULLSCREEN);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3195,3 +3195,75 @@ void V_Recalc(void)
|
|||
vid.fsmalldupy = vid.smalldupy*FRACUNIT;
|
||||
#endif
|
||||
}
|
||||
|
||||
void VID_DisplaySoftwareScreen()
|
||||
{
|
||||
// TODO implement
|
||||
// upload framebuffer, bind pipeline, draw
|
||||
rhi::Rhi* rhi = srb2::sys::get_rhi(srb2::sys::g_current_rhi);
|
||||
rhi::Handle<rhi::GraphicsContext> ctx = srb2::sys::main_graphics_context();
|
||||
hwr2::HardwareState* hw_state = srb2::sys::main_hardware_state();
|
||||
|
||||
// Misnomer; this just uploads the screen to the software indexed screen texture
|
||||
hw_state->software_screen_renderer->draw(*rhi, ctx);
|
||||
|
||||
rhi->end_render_pass(ctx);
|
||||
rhi->begin_default_render_pass(ctx, false);
|
||||
|
||||
const int screens = std::clamp(r_splitscreen + 1, 1, MAXSPLITSCREENPLAYERS);
|
||||
hw_state->blit_postimg_screens->set_num_screens(screens);
|
||||
hw_state->blit_postimg_screens->set_target(static_cast<uint32_t>(vid.width), static_cast<uint32_t>(vid.height));
|
||||
|
||||
for (int i = 0; i < screens; i++)
|
||||
{
|
||||
glm::vec2 uv_offset {0.f, 0.f};
|
||||
glm::vec2 uv_size {1.f, 1.f};
|
||||
|
||||
if (screens > 2)
|
||||
{
|
||||
uv_size = glm::vec2(.5f, .5f);
|
||||
switch (i)
|
||||
{
|
||||
case 0:
|
||||
uv_offset = glm::vec2(0.f, 0.f);
|
||||
break;
|
||||
case 1:
|
||||
uv_offset = glm::vec2(.5f, 0.f);
|
||||
break;
|
||||
case 2:
|
||||
uv_offset = glm::vec2(0.f, .5f);
|
||||
break;
|
||||
case 3:
|
||||
uv_offset = glm::vec2(.5f, .5f);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (screens > 1)
|
||||
{
|
||||
uv_size = glm::vec2(1.f, .5f);
|
||||
if (i == 1)
|
||||
{
|
||||
uv_offset = glm::vec2(0.f, .5f);
|
||||
}
|
||||
}
|
||||
|
||||
hw_state->blit_postimg_screens->set_screen(
|
||||
i,
|
||||
{
|
||||
hw_state->software_screen_renderer->screen(),
|
||||
true,
|
||||
uv_offset,
|
||||
uv_size,
|
||||
{
|
||||
postimgtype[i] == postimg_water,
|
||||
postimgtype[i] == postimg_heat,
|
||||
postimgtype[i] == postimg_flip,
|
||||
postimgtype[i] == postimg_mirror
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
// Post-process blit to the 'default' framebuffer
|
||||
hw_state->blit_postimg_screens->draw(*rhi, ctx);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -431,6 +431,12 @@ void V_DrawPatchFill(patch_t *pat);
|
|||
void VID_BlitLinearScreen(const UINT8 *srcptr, UINT8 *destptr, INT32 width, INT32 height, size_t srcrowbytes,
|
||||
size_t destrowbytes);
|
||||
|
||||
/**
|
||||
* Display the software framebuffer to the screen. Added in RHI conversion; software is not implicitly displayed by the
|
||||
* system.
|
||||
*/
|
||||
void VID_DisplaySoftwareScreen(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -1364,14 +1364,9 @@ void Y_IntermissionDrawer(void)
|
|||
|
||||
//player icon 1 (55,79) 2 (55,93) 5 (183,79)
|
||||
|
||||
// If we early return, skip drawing the 3D scene (software buffer) so it doesn't clobber the frame for the wipe
|
||||
g_wipeskiprender = true;
|
||||
|
||||
if (intertype == int_none || rendermode == render_none)
|
||||
return;
|
||||
|
||||
g_wipeskiprender = false;
|
||||
|
||||
fixed_t x;
|
||||
|
||||
// Checker scroll
|
||||
|
|
@ -1390,16 +1385,16 @@ void Y_IntermissionDrawer(void)
|
|||
|
||||
// Draw the background
|
||||
K_DrawMapThumbnail(0, 0, BASEVIDWIDTH<<FRACBITS, (data.encore ? V_FLIP : 0), prevmap, bgcolor);
|
||||
|
||||
|
||||
// Draw a mask over the BG to get the correct colorization
|
||||
V_DrawMappedPatch(0, 0, V_ADD|V_TRANSLUCENT, mask, NULL);
|
||||
|
||||
|
||||
// Draw the marquee (scroll pending)
|
||||
//V_DrawMappedPatch(0, 154, V_SUBTRACT, rrmq, NULL);
|
||||
|
||||
|
||||
// Draw the checker pattern (scroll pending)
|
||||
//V_DrawMappedPatch(0, 0, V_SUBTRACT, rbgchk, NULL);
|
||||
|
||||
|
||||
for (x = -mqscroll; x < (BASEVIDWIDTH * FRACUNIT); x += mqloop)
|
||||
{
|
||||
V_DrawFixedPatch(x, 154<<FRACBITS, FRACUNIT, V_SUBTRACT, rrmq, NULL);
|
||||
|
|
@ -1519,16 +1514,16 @@ finalcounter:
|
|||
{
|
||||
switch (demo.savemode)
|
||||
{
|
||||
case DSM_NOTSAVING:
|
||||
case DSM_NOTSAVING:
|
||||
{
|
||||
INT32 buttonx = BASEVIDWIDTH;
|
||||
INT32 buttony = 2;
|
||||
|
||||
|
||||
K_drawButtonAnim(buttonx - 76, buttony, 0, kp_button_b[1], replayprompttic);
|
||||
V_DrawRightAlignedThinString(buttonx - 55, buttony, highlightflags, "or");
|
||||
K_drawButtonAnim(buttonx - 55, buttony, 0, kp_button_x[1], replayprompttic);
|
||||
V_DrawRightAlignedThinString(buttonx - 2, buttony, highlightflags, "Save replay");
|
||||
break;
|
||||
break;
|
||||
}
|
||||
case DSM_SAVED:
|
||||
V_DrawRightAlignedThinString(BASEVIDWIDTH - 2, 2, highlightflags, "Replay saved!");
|
||||
|
|
@ -1588,8 +1583,8 @@ void Y_Ticker(void)
|
|||
{
|
||||
replayprompttic++;
|
||||
G_CheckDemoTitleEntry();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (demo.savemode == DSM_WILLSAVE || demo.savemode == DSM_WILLAUTOSAVE)
|
||||
G_SaveDemo();
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue