Hook up thread slices and eliminate some statics hiding in misc functions

This commit is contained in:
Magnus Norddahl 2017-02-04 15:51:54 +01:00
parent f50532af8a
commit d9e545a519
12 changed files with 154 additions and 76 deletions

View file

@ -64,7 +64,6 @@ namespace swrenderer
void SWRenderLine::Render(seg_t *line, subsector_t *subsector, sector_t *sector, sector_t *fakebacksector, VisiblePlane *linefloorplane, VisiblePlane *lineceilingplane, bool infog, FDynamicColormap *colormap) void SWRenderLine::Render(seg_t *line, subsector_t *subsector, sector_t *sector, sector_t *fakebacksector, VisiblePlane *linefloorplane, VisiblePlane *lineceilingplane, bool infog, FDynamicColormap *colormap)
{ {
static sector_t tempsec; // killough 3/8/98: ceiling/water hack
bool solid; bool solid;
DVector2 pt1, pt2; DVector2 pt1, pt2;
@ -284,11 +283,7 @@ namespace swrenderer
rw_floorstat = wallbottom.Project(frontsector->floorplane, &WallC, curline, renderportal->MirrorFlags & RF_XFLIP); rw_floorstat = wallbottom.Project(frontsector->floorplane, &WallC, curline, renderportal->MirrorFlags & RF_XFLIP);
} }
static SWRenderLine *self = this; bool visible = Thread->ClipSegments->Clip(WallC.sx1, WallC.sx2, solid, this);
bool visible = Thread->ClipSegments->Clip(WallC.sx1, WallC.sx2, solid, [](int x1, int x2) -> bool
{
return self->RenderWallSegment(x1, x2);
});
if (visible) if (visible)
{ {

View file

@ -15,6 +15,7 @@
#include "vectors.h" #include "vectors.h"
#include "r_wallsetup.h" #include "r_wallsetup.h"
#include "swrenderer/segments/r_clipsegment.h"
struct seg_t; struct seg_t;
struct subsector_t; struct subsector_t;
@ -48,7 +49,7 @@ namespace swrenderer
void InitFromLine(RenderThread *thread, const DVector2 &left, const DVector2 &right); void InitFromLine(RenderThread *thread, const DVector2 &left, const DVector2 &right);
}; };
class SWRenderLine class SWRenderLine : VisibleSegmentRenderer
{ {
public: public:
SWRenderLine(RenderThread *thread); SWRenderLine(RenderThread *thread);
@ -57,7 +58,7 @@ namespace swrenderer
RenderThread *Thread = nullptr; RenderThread *Thread = nullptr;
private: private:
bool RenderWallSegment(int x1, int x2); bool RenderWallSegment(int x1, int x2) override;
void SetWallVariables(bool needlights); void SetWallVariables(bool needlights);
void RenderWallSegmentTextures(int x1, int x2); void RenderWallSegmentTextures(int x1, int x2);
@ -133,5 +134,7 @@ namespace swrenderer
ProjectedWallLine wallupper; ProjectedWallLine wallupper;
ProjectedWallLine walllower; ProjectedWallLine walllower;
ProjectedWallTexcoords walltexcoords; ProjectedWallTexcoords walltexcoords;
sector_t tempsec; // killough 3/8/98: ceiling/water hack
}; };
} }

View file

@ -41,6 +41,7 @@
#include "swrenderer/line/r_walldraw.h" #include "swrenderer/line/r_walldraw.h"
#include "swrenderer/line/r_wallsetup.h" #include "swrenderer/line/r_wallsetup.h"
#include "swrenderer/r_renderthread.h" #include "swrenderer/r_renderthread.h"
#include "swrenderer/r_memory.h"
namespace swrenderer namespace swrenderer
{ {
@ -188,14 +189,22 @@ namespace swrenderer
drawerargs.dc_viewpos.Z = (float)((viewport->CenterY - y1 - 0.5) / viewport->InvZtoScale * zcol); drawerargs.dc_viewpos.Z = (float)((viewport->CenterY - y1 - 0.5) / viewport->InvZtoScale * zcol);
drawerargs.dc_viewpos_step.Z = (float)(-zcol / viewport->InvZtoScale); drawerargs.dc_viewpos_step.Z = (float)(-zcol / viewport->InvZtoScale);
static TriLight lightbuffer[64 * 1024]; // Calculate max lights that can touch column so we can allocate memory for the list
static int nextlightindex = 0; int max_lights = 0;
FLightNode *cur_node = light_list;
while (cur_node)
{
if (!(cur_node->lightsource->flags2&MF2_DORMANT))
max_lights++;
cur_node = cur_node->nextLight;
}
drawerargs.dc_num_lights = 0;
drawerargs.dc_lights = Thread->FrameMemory->AllocMemory<TriLight>(max_lights);
// Setup lights for column // Setup lights for column
drawerargs.dc_num_lights = 0; cur_node = light_list;
drawerargs.dc_lights = lightbuffer + nextlightindex; while (cur_node)
FLightNode *cur_node = light_list;
while (cur_node && nextlightindex < 64 * 1024)
{ {
if (!(cur_node->lightsource->flags2&MF2_DORMANT)) if (!(cur_node->lightsource->flags2&MF2_DORMANT))
{ {
@ -220,7 +229,6 @@ namespace swrenderer
uint32_t green = cur_node->lightsource->GetGreen(); uint32_t green = cur_node->lightsource->GetGreen();
uint32_t blue = cur_node->lightsource->GetBlue(); uint32_t blue = cur_node->lightsource->GetBlue();
nextlightindex++;
auto &light = drawerargs.dc_lights[drawerargs.dc_num_lights++]; auto &light = drawerargs.dc_lights[drawerargs.dc_num_lights++];
light.x = lconstant; light.x = lconstant;
light.y = nlconstant; light.y = nlconstant;
@ -232,9 +240,6 @@ namespace swrenderer
cur_node = cur_node->nextLight; cur_node = cur_node->nextLight;
} }
if (nextlightindex == 64 * 1024)
nextlightindex = 0;
} }
else else
{ {

View file

@ -56,9 +56,10 @@
namespace swrenderer namespace swrenderer
{ {
RenderThread::RenderThread(RenderScene *scene) RenderThread::RenderThread(RenderScene *scene, bool mainThread)
{ {
Scene = scene; Scene = scene;
MainThread = mainThread;
FrameMemory = std::make_unique<RenderMemory>(); FrameMemory = std::make_unique<RenderMemory>();
DrawQueue = std::make_shared<DrawerCommandQueue>(this); DrawQueue = std::make_shared<DrawerCommandQueue>(this);
OpaquePass = std::make_unique<RenderOpaquePass>(this); OpaquePass = std::make_unique<RenderOpaquePass>(this);

View file

@ -47,12 +47,13 @@ namespace swrenderer
class RenderThread class RenderThread
{ {
public: public:
RenderThread(RenderScene *scene); RenderThread(RenderScene *scene, bool mainThread = true);
~RenderThread(); ~RenderThread();
RenderScene *Scene; RenderScene *Scene;
int X1 = 0; int X1 = 0;
int X2 = MAXWIDTH; int X2 = MAXWIDTH;
bool MainThread = false;
std::unique_ptr<RenderMemory> FrameMemory; std::unique_ptr<RenderMemory> FrameMemory;
std::unique_ptr<RenderOpaquePass> OpaquePass; std::unique_ptr<RenderOpaquePass> OpaquePass;
@ -65,7 +66,11 @@ namespace swrenderer
std::unique_ptr<DrawSegmentList> DrawSegments; std::unique_ptr<DrawSegmentList> DrawSegments;
std::unique_ptr<RenderClipSegment> ClipSegments; std::unique_ptr<RenderClipSegment> ClipSegments;
DrawerCommandQueuePtr DrawQueue; DrawerCommandQueuePtr DrawQueue;
// VisibleSprite working buffers
short clipbot[MAXWIDTH];
short cliptop[MAXWIDTH];
SWPixelFormatDrawers *Drawers(); SWPixelFormatDrawers *Drawers();
private: private:

View file

@ -52,6 +52,8 @@
EXTERN_CVAR(Bool, r_shadercolormaps) EXTERN_CVAR(Bool, r_shadercolormaps)
EXTERN_CVAR(Int, r_clearbuffer) EXTERN_CVAR(Int, r_clearbuffer)
CVAR(Bool, r_scene_multithreaded, false, 0);
namespace swrenderer namespace swrenderer
{ {
cycle_t WallCycles, PlaneCycles, MaskedCycles, WallScanCycles; cycle_t WallCycles, PlaneCycles, MaskedCycles, WallScanCycles;
@ -100,8 +102,19 @@ namespace swrenderer
{ {
MainThread()->DrawQueue->Push<ApplySpecialColormapRGBACommand>(CameraLight::Instance()->ShaderColormap(), screen); MainThread()->DrawQueue->Push<ApplySpecialColormapRGBACommand>(CameraLight::Instance()->ShaderColormap(), screen);
} }
DrawerThreads::Execute({ MainThread()->DrawQueue }); RenderDrawQueues();
}
void RenderScene::RenderDrawQueues()
{
// Use reverse order so main thread is drawn last
std::vector<DrawerCommandQueuePtr> queues;
for (auto it = Threads.rbegin(); it != Threads.rend(); ++it)
{
queues.push_back((*it)->DrawQueue);
}
DrawerThreads::Execute(queues);
} }
void RenderScene::RenderActorView(AActor *actor, bool dontmaplines) void RenderScene::RenderActorView(AActor *actor, bool dontmaplines)
@ -132,48 +145,7 @@ namespace swrenderer
camera->renderflags |= RF_INVISIBLE; camera->renderflags |= RF_INVISIBLE;
} }
MainThread()->FrameMemory->Clear(); RenderThreadSlices();
MainThread()->Clip3DFloors->Cleanup();
MainThread()->Clip3DFloors->ResetClip(); // reset clips (floor/ceiling)
MainThread()->Portal->CopyStackedViewParameters();
MainThread()->ClipSegments->Clear(0, viewwidth);
MainThread()->DrawSegments->Clear();
MainThread()->PlaneList->Clear();
MainThread()->TranslucentPass->Clear();
MainThread()->OpaquePass->ClearClip();
MainThread()->OpaquePass->ResetFakingUnderwater(); // [RH] Hack to make windows into underwater areas possible
MainThread()->Portal->SetMainPortal();
// Cull things outside the range seen by this thread
if (MainThread()->X1 > 0)
MainThread()->ClipSegments->Clip(0, MainThread()->X1, true, [](int, int) { return true; });
if (MainThread()->X2 < viewwidth)
MainThread()->ClipSegments->Clip(MainThread()->X2, viewwidth, true, [](int, int) { return true; });
WallCycles.Clock();
MainThread()->OpaquePass->RenderScene();
MainThread()->Clip3DFloors->ResetClip(); // reset clips (floor/ceiling)
WallCycles.Unclock();
NetUpdate();
if (viewactive)
{
PlaneCycles.Clock();
MainThread()->PlaneList->Render();
MainThread()->Portal->RenderPlanePortals();
PlaneCycles.Unclock();
MainThread()->Portal->RenderLinePortals();
NetUpdate();
MaskedCycles.Clock();
MainThread()->TranslucentPass->Render();
MaskedCycles.Unclock();
NetUpdate();
}
camera->renderflags = savedflags; camera->renderflags = savedflags;
interpolator.RestoreInterpolations(); interpolator.RestoreInterpolations();
@ -186,6 +158,94 @@ namespace swrenderer
} }
} }
void RenderScene::RenderThreadSlices()
{
int numThreads = r_scene_multithreaded ? 8 : 1;
while (Threads.size() > (size_t)numThreads)
{
Threads.pop_back();
}
while (Threads.size() < (size_t)numThreads)
{
Threads.push_back(std::make_unique<RenderThread>(this));
}
for (int i = 0; i < numThreads; i++)
{
Threads[i]->X1 = viewwidth * i / numThreads;
Threads[i]->X2 = viewwidth * (i + 1) / numThreads;
}
for (int i = 0; i < numThreads; i++)
{
RenderThreadSlice(Threads[i].get());
}
}
void RenderScene::RenderThreadSlice(RenderThread *thread)
{
thread->FrameMemory->Clear();
thread->Clip3DFloors->Cleanup();
thread->Clip3DFloors->ResetClip(); // reset clips (floor/ceiling)
thread->Portal->CopyStackedViewParameters();
thread->ClipSegments->Clear(0, viewwidth);
thread->DrawSegments->Clear();
thread->PlaneList->Clear();
thread->TranslucentPass->Clear();
thread->OpaquePass->ClearClip();
thread->OpaquePass->ResetFakingUnderwater(); // [RH] Hack to make windows into underwater areas possible
thread->Portal->SetMainPortal();
// Cull things outside the range seen by this thread
VisibleSegmentRenderer visitor;
if (thread->X1 > 0)
thread->ClipSegments->Clip(0, thread->X1, true, &visitor);
if (thread->X2 < viewwidth)
thread->ClipSegments->Clip(thread->X2, viewwidth, true, &visitor);
if (thread->MainThread)
WallCycles.Clock();
thread->OpaquePass->RenderScene();
thread->Clip3DFloors->ResetClip(); // reset clips (floor/ceiling)
if (thread == MainThread())
WallCycles.Unclock();
if (thread->MainThread)
NetUpdate();
if (viewactive)
{
if (thread->MainThread)
PlaneCycles.Clock();
thread->PlaneList->Render();
thread->Portal->RenderPlanePortals();
if (thread->MainThread)
PlaneCycles.Unclock();
thread->Portal->RenderLinePortals();
if (thread->MainThread)
NetUpdate();
if (thread->MainThread)
MaskedCycles.Clock();
thread->TranslucentPass->Render();
if (thread->MainThread)
MaskedCycles.Unclock();
if (thread->MainThread)
NetUpdate();
}
}
void RenderScene::RenderViewToCanvas(AActor *actor, DCanvas *canvas, int x, int y, int width, int height, bool dontmaplines) void RenderScene::RenderViewToCanvas(AActor *actor, DCanvas *canvas, int x, int y, int width, int height, bool dontmaplines)
{ {
auto viewport = RenderViewport::Instance(); auto viewport = RenderViewport::Instance();
@ -202,8 +262,7 @@ namespace swrenderer
viewport->SetViewport(width, height, WidescreenRatio); viewport->SetViewport(width, height, WidescreenRatio);
RenderActorView(actor, dontmaplines); RenderActorView(actor, dontmaplines);
RenderDrawQueues();
DrawerThreads::Execute({ MainThread()->DrawQueue });
viewport->RenderTarget = screen; viewport->RenderTarget = screen;

View file

@ -46,6 +46,9 @@ namespace swrenderer
private: private:
void RenderActorView(AActor *actor, bool dontmaplines = false); void RenderActorView(AActor *actor, bool dontmaplines = false);
void RenderDrawQueues();
void RenderThreadSlices();
void RenderThreadSlice(RenderThread *thread);
bool dontmaplines = false; bool dontmaplines = false;
int clearcolor = 0; int clearcolor = 0;

View file

@ -86,7 +86,7 @@ namespace swrenderer
return true; return true;
} }
bool RenderClipSegment::Clip(int first, int last, bool solid, VisibleSegmentCallback callback) bool RenderClipSegment::Clip(int first, int last, bool solid, VisibleSegmentRenderer *visitor)
{ {
cliprange_t *next, *start; cliprange_t *next, *start;
int i, j; int i, j;
@ -104,7 +104,7 @@ namespace swrenderer
if (last <= start->first) if (last <= start->first)
{ {
// Post is entirely visible (above start). // Post is entirely visible (above start).
if (!callback(first, last)) if (!visitor->RenderWallSegment(first, last))
return true; return true;
// Insert a new clippost for solid walls. // Insert a new clippost for solid walls.
@ -131,7 +131,7 @@ namespace swrenderer
} }
// There is a fragment above *start. // There is a fragment above *start.
if (callback(first, start->first) && solid) if (visitor->RenderWallSegment(first, start->first) && solid)
{ {
start->first = first; // Adjust the clip size for solid walls start->first = first; // Adjust the clip size for solid walls
} }
@ -146,7 +146,7 @@ namespace swrenderer
while (last >= (next + 1)->first) while (last >= (next + 1)->first)
{ {
// There is a fragment between two posts. // There is a fragment between two posts.
clipsegment = callback(next->last, (next + 1)->first); clipsegment = visitor->RenderWallSegment(next->last, (next + 1)->first);
next++; next++;
if (last <= next->last) if (last <= next->last)
@ -158,7 +158,7 @@ namespace swrenderer
} }
// There is a fragment after *next. // There is a fragment after *next.
clipsegment = callback(next->last, last); clipsegment = visitor->RenderWallSegment(next->last, last);
crunch: crunch:
if (!clipsegment) if (!clipsegment)

View file

@ -17,11 +17,18 @@ namespace swrenderer
{ {
typedef bool(*VisibleSegmentCallback)(int x1, int x2); typedef bool(*VisibleSegmentCallback)(int x1, int x2);
class VisibleSegmentRenderer
{
public:
virtual ~VisibleSegmentRenderer() { }
virtual bool RenderWallSegment(int x1, int x2) { return true; }
};
class RenderClipSegment class RenderClipSegment
{ {
public: public:
void Clear(short left, short right); void Clear(short left, short right);
bool Clip(int x1, int x2, bool solid, VisibleSegmentCallback callback); bool Clip(int x1, int x2, bool solid, VisibleSegmentRenderer *visitor);
bool Check(int first, int last); bool Check(int first, int last);
bool IsVisible(int x1, int x2); bool IsVisible(int x1, int x2);

View file

@ -78,7 +78,6 @@ namespace swrenderer
DPSprite* psp; DPSprite* psp;
DPSprite* weapon; DPSprite* weapon;
sector_t* sec = NULL; sector_t* sec = NULL;
static sector_t tempsec;
int floorlight, ceilinglight; int floorlight, ceilinglight;
F3DFloor *rover; F3DFloor *rover;

View file

@ -88,5 +88,6 @@ namespace swrenderer
enum { BASEYCENTER = 100 }; enum { BASEYCENTER = 100 };
TArray<HWAccelPlayerSprite> AcceleratedSprites; TArray<HWAccelPlayerSprite> AcceleratedSprites;
sector_t tempsec;
}; };
} }

View file

@ -43,8 +43,8 @@ namespace swrenderer
{ {
void VisibleSprite::Render(RenderThread *thread) void VisibleSprite::Render(RenderThread *thread)
{ {
static short clipbot[MAXWIDTH]; short *clipbot = thread->clipbot;
static short cliptop[MAXWIDTH]; short *cliptop = thread->cliptop;
VisibleSprite *spr = this; VisibleSprite *spr = this;