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)
{
static sector_t tempsec; // killough 3/8/98: ceiling/water hack
bool solid;
DVector2 pt1, pt2;
@ -284,11 +283,7 @@ namespace swrenderer
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, [](int x1, int x2) -> bool
{
return self->RenderWallSegment(x1, x2);
});
bool visible = Thread->ClipSegments->Clip(WallC.sx1, WallC.sx2, solid, this);
if (visible)
{

View file

@ -15,6 +15,7 @@
#include "vectors.h"
#include "r_wallsetup.h"
#include "swrenderer/segments/r_clipsegment.h"
struct seg_t;
struct subsector_t;
@ -48,7 +49,7 @@ namespace swrenderer
void InitFromLine(RenderThread *thread, const DVector2 &left, const DVector2 &right);
};
class SWRenderLine
class SWRenderLine : VisibleSegmentRenderer
{
public:
SWRenderLine(RenderThread *thread);
@ -57,7 +58,7 @@ namespace swrenderer
RenderThread *Thread = nullptr;
private:
bool RenderWallSegment(int x1, int x2);
bool RenderWallSegment(int x1, int x2) override;
void SetWallVariables(bool needlights);
void RenderWallSegmentTextures(int x1, int x2);
@ -133,5 +134,7 @@ namespace swrenderer
ProjectedWallLine wallupper;
ProjectedWallLine walllower;
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_wallsetup.h"
#include "swrenderer/r_renderthread.h"
#include "swrenderer/r_memory.h"
namespace swrenderer
{
@ -188,14 +189,22 @@ namespace swrenderer
drawerargs.dc_viewpos.Z = (float)((viewport->CenterY - y1 - 0.5) / viewport->InvZtoScale * zcol);
drawerargs.dc_viewpos_step.Z = (float)(-zcol / viewport->InvZtoScale);
static TriLight lightbuffer[64 * 1024];
static int nextlightindex = 0;
// Calculate max lights that can touch column so we can allocate memory for the list
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
drawerargs.dc_num_lights = 0;
drawerargs.dc_lights = lightbuffer + nextlightindex;
FLightNode *cur_node = light_list;
while (cur_node && nextlightindex < 64 * 1024)
cur_node = light_list;
while (cur_node)
{
if (!(cur_node->lightsource->flags2&MF2_DORMANT))
{
@ -220,7 +229,6 @@ namespace swrenderer
uint32_t green = cur_node->lightsource->GetGreen();
uint32_t blue = cur_node->lightsource->GetBlue();
nextlightindex++;
auto &light = drawerargs.dc_lights[drawerargs.dc_num_lights++];
light.x = lconstant;
light.y = nlconstant;
@ -232,9 +240,6 @@ namespace swrenderer
cur_node = cur_node->nextLight;
}
if (nextlightindex == 64 * 1024)
nextlightindex = 0;
}
else
{

View file

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

View file

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

View file

@ -52,6 +52,8 @@
EXTERN_CVAR(Bool, r_shadercolormaps)
EXTERN_CVAR(Int, r_clearbuffer)
CVAR(Bool, r_scene_multithreaded, false, 0);
namespace swrenderer
{
cycle_t WallCycles, PlaneCycles, MaskedCycles, WallScanCycles;
@ -100,8 +102,19 @@ namespace swrenderer
{
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)
@ -132,48 +145,7 @@ namespace swrenderer
camera->renderflags |= RF_INVISIBLE;
}
MainThread()->FrameMemory->Clear();
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();
}
RenderThreadSlices();
camera->renderflags = savedflags;
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)
{
auto viewport = RenderViewport::Instance();
@ -202,8 +262,7 @@ namespace swrenderer
viewport->SetViewport(width, height, WidescreenRatio);
RenderActorView(actor, dontmaplines);
DrawerThreads::Execute({ MainThread()->DrawQueue });
RenderDrawQueues();
viewport->RenderTarget = screen;

View file

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

View file

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

View file

@ -17,11 +17,18 @@ namespace swrenderer
{
typedef bool(*VisibleSegmentCallback)(int x1, int x2);
class VisibleSegmentRenderer
{
public:
virtual ~VisibleSegmentRenderer() { }
virtual bool RenderWallSegment(int x1, int x2) { return true; }
};
class RenderClipSegment
{
public:
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 IsVisible(int x1, int x2);

View file

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

View file

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

View file

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