From a841602d70425693d96eafdb677f97b70bccd0b1 Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Fri, 20 Jul 2018 05:48:15 +0200 Subject: [PATCH] - change the software renderer to render to a DSimpleCanvas like the old D3D9 target did. Then use the drawer threads to memcpy the result to the PBO --- src/gl/textures/gl_hwtexture.cpp | 16 ++----------- src/polyrenderer/drawers/poly_triangle.cpp | 2 ++ src/polyrenderer/drawers/screen_triangle.cpp | 4 ++-- src/polyrenderer/drawers/screen_triangle.h | 1 + src/polyrenderer/poly_renderer.cpp | 7 +++++- src/polyrenderer/poly_renderer.h | 2 +- src/r_renderer.h | 2 +- src/swrenderer/drawers/r_thread.cpp | 24 ++++++++++++++++++++ src/swrenderer/drawers/r_thread.h | 16 +++++++++++++ src/swrenderer/r_swrenderer.cpp | 6 ++--- src/swrenderer/r_swrenderer.h | 2 +- src/swrenderer/r_swscene.cpp | 7 +++--- src/swrenderer/r_swscene.h | 1 + src/swrenderer/scene/r_scene.cpp | 6 ++++- src/swrenderer/scene/r_scene.h | 2 +- 15 files changed, 70 insertions(+), 28 deletions(-) diff --git a/src/gl/textures/gl_hwtexture.cpp b/src/gl/textures/gl_hwtexture.cpp index 6d53fd57db..03a31a2e1f 100644 --- a/src/gl/textures/gl_hwtexture.cpp +++ b/src/gl/textures/gl_hwtexture.cpp @@ -296,10 +296,7 @@ void FHardwareTexture::AllocateBuffer(int w, int h, int texelsize) { glGenBuffers(1, &glBufferID); glBindBuffer(GL_PIXEL_UNPACK_BUFFER, glBufferID); - if (screen->hwcaps & RFL_BUFFER_STORAGE) - glBufferStorage(GL_PIXEL_UNPACK_BUFFER, w*h*texelsize, nullptr, GL_MAP_READ_BIT | GL_MAP_WRITE_BIT | GL_CLIENT_STORAGE_BIT); - else - glBufferData(GL_PIXEL_UNPACK_BUFFER, w*h*texelsize, nullptr, GL_STREAM_DRAW); + glBufferData(GL_PIXEL_UNPACK_BUFFER, w*h*texelsize, nullptr, GL_STREAM_DRAW); glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); } } @@ -308,16 +305,7 @@ void FHardwareTexture::AllocateBuffer(int w, int h, int texelsize) uint8_t *FHardwareTexture::MapBuffer() { glBindBuffer(GL_PIXEL_UNPACK_BUFFER, glBufferID); - if (screen->hwcaps & RFL_BUFFER_STORAGE) - { - GLint size = -1; - glGetBufferParameteriv(GL_PIXEL_UNPACK_BUFFER, GL_BUFFER_SIZE, &size); - return (uint8_t*)glMapBufferRange(GL_PIXEL_UNPACK_BUFFER, 0, size, GL_MAP_READ_BIT | GL_MAP_WRITE_BIT); - } - else - { - return (uint8_t*)glMapBuffer(GL_PIXEL_UNPACK_BUFFER, GL_READ_WRITE); - } + return (uint8_t*)glMapBuffer(GL_PIXEL_UNPACK_BUFFER, GL_WRITE_ONLY); } //=========================================================================== diff --git a/src/polyrenderer/drawers/poly_triangle.cpp b/src/polyrenderer/drawers/poly_triangle.cpp index bc10b98c2c..53face08c8 100644 --- a/src/polyrenderer/drawers/poly_triangle.cpp +++ b/src/polyrenderer/drawers/poly_triangle.cpp @@ -169,6 +169,7 @@ void PolyTriangleThreadData::DrawElements(const PolyDrawArgs &drawargs, const vo args.uniforms = &drawargs; args.destBgra = dest_bgra; args.stencilbuffer = PolyStencilBuffer::Instance()->Values(); + args.stencilpitch = PolyStencilBuffer::Instance()->Width(); args.zbuffer = PolyZBuffer::Instance()->Values(); args.depthOffset = weaponScene ? 1.0f : 0.0f; @@ -222,6 +223,7 @@ void PolyTriangleThreadData::DrawArray(const PolyDrawArgs &drawargs, const void args.uniforms = &drawargs; args.destBgra = dest_bgra; args.stencilbuffer = PolyStencilBuffer::Instance()->Values(); + args.stencilpitch = PolyStencilBuffer::Instance()->Width(); args.zbuffer = PolyZBuffer::Instance()->Values(); args.depthOffset = weaponScene ? 1.0f : 0.0f; diff --git a/src/polyrenderer/drawers/screen_triangle.cpp b/src/polyrenderer/drawers/screen_triangle.cpp index 2c63816059..f8b1a51f49 100644 --- a/src/polyrenderer/drawers/screen_triangle.cpp +++ b/src/polyrenderer/drawers/screen_triangle.cpp @@ -153,8 +153,8 @@ void ScreenTriangle::Draw(const TriDrawTriangleArgs *args, PolyTriangleThreadDat int x = leftEdge[y]; int xend = rightEdge[y]; - float *zbufferLine = args->zbuffer + args->pitch * y; - uint8_t *stencilLine = args->stencilbuffer + args->pitch * y; + float *zbufferLine = args->zbuffer + args->stencilpitch * y; + uint8_t *stencilLine = args->stencilbuffer + args->stencilpitch * y; float startX = x + (0.5f - v1X); float startY = y + (0.5f - v1Y); diff --git a/src/polyrenderer/drawers/screen_triangle.h b/src/polyrenderer/drawers/screen_triangle.h index a52d897c29..72c8f82654 100644 --- a/src/polyrenderer/drawers/screen_triangle.h +++ b/src/polyrenderer/drawers/screen_triangle.h @@ -53,6 +53,7 @@ struct TriDrawTriangleArgs int32_t clipright; int32_t clipbottom; uint8_t *stencilbuffer; + int stencilpitch; float *zbuffer; const PolyDrawArgs *uniforms; bool destBgra; diff --git a/src/polyrenderer/poly_renderer.cpp b/src/polyrenderer/poly_renderer.cpp index 43622b1b4b..e878623fd4 100644 --- a/src/polyrenderer/poly_renderer.cpp +++ b/src/polyrenderer/poly_renderer.cpp @@ -58,7 +58,7 @@ PolyRenderer::PolyRenderer() { } -void PolyRenderer::RenderView(player_t *player, DCanvas *target) +void PolyRenderer::RenderView(player_t *player, DCanvas *target, void *videobuffer) { using namespace swrenderer; @@ -70,6 +70,11 @@ void PolyRenderer::RenderView(player_t *player, DCanvas *target) RenderActorView(player->mo, false); Threads.MainThread()->FlushDrawQueue(); + + auto copyqueue = std::make_shared(Threads.MainThread()->FrameMemory.get()); + copyqueue->Push(videobuffer, target->GetPixels(), target->GetWidth(), target->GetHeight(), target->GetPitch(), target->IsBgra() ? 4 : 1); + DrawerThreads::Execute(copyqueue); + PolyDrawerWaitCycles.Clock(); DrawerThreads::WaitForWorkers(); PolyDrawerWaitCycles.Unclock(); diff --git a/src/polyrenderer/poly_renderer.h b/src/polyrenderer/poly_renderer.h index 20a5a61bea..34b880e1cb 100644 --- a/src/polyrenderer/poly_renderer.h +++ b/src/polyrenderer/poly_renderer.h @@ -49,7 +49,7 @@ class PolyRenderer public: PolyRenderer(); - void RenderView(player_t *player, DCanvas *target); + void RenderView(player_t *player, DCanvas *target, void *videobuffer); void RenderViewToCanvas(AActor *actor, DCanvas *canvas, int x, int y, int width, int height, bool dontmaplines); void RenderRemainingPlayerSprites(); diff --git a/src/r_renderer.h b/src/r_renderer.h index db8968ba05..225d577403 100644 --- a/src/r_renderer.h +++ b/src/r_renderer.h @@ -23,7 +23,7 @@ struct FRenderer virtual void Precache(uint8_t *texhitlist, TMap &actorhitlist) = 0; // render 3D view - virtual void RenderView(player_t *player, DCanvas *target) = 0; + virtual void RenderView(player_t *player, DCanvas *target, void *videobuffer) = 0; // renders view to a savegame picture virtual void WriteSavePic(player_t *player, FileWriter *file, int width, int height) = 0; diff --git a/src/swrenderer/drawers/r_thread.cpp b/src/swrenderer/drawers/r_thread.cpp index 8ecb7b0ecd..b23ef58da2 100644 --- a/src/swrenderer/drawers/r_thread.cpp +++ b/src/swrenderer/drawers/r_thread.cpp @@ -223,3 +223,27 @@ void GroupMemoryBarrierCommand::Execute(DrawerThread *thread) condition.notify_all(); condition.wait(lock, [&]() { return count >= (size_t)thread->num_cores; }); } + +///////////////////////////////////////////////////////////////////////////// + +MemcpyCommand::MemcpyCommand(void *dest, const void *src, int width, int height, int srcpitch, int pixelsize) + : dest(dest), src(src), width(width), height(height), srcpitch(srcpitch), pixelsize(pixelsize) +{ +} + +void MemcpyCommand::Execute(DrawerThread *thread) +{ + int start = thread->skipped_by_thread(0); + int count = thread->count_for_thread(0, height); + int sstep = thread->num_cores * srcpitch * pixelsize; + int dstep = thread->num_cores * width * pixelsize; + int size = width * pixelsize; + uint8_t *d = (uint8_t*)dest + start * width * pixelsize; + const uint8_t *s = (const uint8_t*)src + start * srcpitch * pixelsize; + for (int i = 0; i < count; i++) + { + memcpy(d, s, size); + d += dstep; + s += sstep; + } +} diff --git a/src/swrenderer/drawers/r_thread.h b/src/swrenderer/drawers/r_thread.h index 76e6510384..dc7e0d8c42 100644 --- a/src/swrenderer/drawers/r_thread.h +++ b/src/swrenderer/drawers/r_thread.h @@ -109,6 +109,22 @@ private: size_t count = 0; }; +// Copy finished rows to video memory +class MemcpyCommand : public DrawerCommand +{ +public: + MemcpyCommand(void *dest, const void *src, int width, int height, int srcpitch, int pixelsize); + void Execute(DrawerThread *thread); + +private: + void *dest; + const void *src; + int width; + int height; + int srcpitch; + int pixelsize; +}; + class DrawerCommandQueue; typedef std::shared_ptr DrawerCommandQueuePtr; diff --git a/src/swrenderer/r_swrenderer.cpp b/src/swrenderer/r_swrenderer.cpp index 6490702c4c..9dbba63cb8 100644 --- a/src/swrenderer/r_swrenderer.cpp +++ b/src/swrenderer/r_swrenderer.cpp @@ -157,13 +157,13 @@ void FSoftwareRenderer::Precache(uint8_t *texhitlist, TMap & } } -void FSoftwareRenderer::RenderView(player_t *player, DCanvas *target) +void FSoftwareRenderer::RenderView(player_t *player, DCanvas *target, void *videobuffer) { if (V_IsPolyRenderer()) { PolyRenderer::Instance()->Viewpoint = r_viewpoint; PolyRenderer::Instance()->Viewwindow = r_viewwindow; - PolyRenderer::Instance()->RenderView(player, target); + PolyRenderer::Instance()->RenderView(player, target, videobuffer); r_viewpoint = PolyRenderer::Instance()->Viewpoint; r_viewwindow = PolyRenderer::Instance()->Viewwindow; } @@ -171,7 +171,7 @@ void FSoftwareRenderer::RenderView(player_t *player, DCanvas *target) { mScene.MainThread()->Viewport->viewpoint = r_viewpoint; mScene.MainThread()->Viewport->viewwindow = r_viewwindow; - mScene.RenderView(player, target); + mScene.RenderView(player, target, videobuffer); r_viewpoint = mScene.MainThread()->Viewport->viewpoint; r_viewwindow = mScene.MainThread()->Viewport->viewwindow; } diff --git a/src/swrenderer/r_swrenderer.h b/src/swrenderer/r_swrenderer.h index 6c14012461..864cbb6654 100644 --- a/src/swrenderer/r_swrenderer.h +++ b/src/swrenderer/r_swrenderer.h @@ -12,7 +12,7 @@ struct FSoftwareRenderer : public FRenderer void Precache(uint8_t *texhitlist, TMap &actorhitlist) override; // render 3D view - void RenderView(player_t *player, DCanvas *target) override; + void RenderView(player_t *player, DCanvas *target, void *videobuffer) override; // renders view to a savegame picture void WriteSavePic (player_t *player, FileWriter *file, int width, int height) override; diff --git a/src/swrenderer/r_swscene.cpp b/src/swrenderer/r_swscene.cpp index 3773bf89f5..2a1b05b07e 100644 --- a/src/swrenderer/r_swscene.cpp +++ b/src/swrenderer/r_swscene.cpp @@ -99,7 +99,6 @@ sector_t *SWSceneDrawer::RenderView(player_t *player) FBTextureIndex = (FBTextureIndex + 1) % 2; auto &fbtex = FBTexture[FBTextureIndex]; - DCanvas buffer(screen->GetWidth(), screen->GetHeight(), V_IsTrueColor()); if (fbtex == nullptr || fbtex->SystemTexture[0] == nullptr || fbtex->GetWidth() != screen->GetWidth() || fbtex->GetHeight() != screen->GetHeight() || @@ -111,12 +110,14 @@ sector_t *SWSceneDrawer::RenderView(player_t *player) fbtex->SystemTexture[0]->AllocateBuffer(screen->GetWidth(), screen->GetHeight(), V_IsTrueColor() ? 4 : 1); auto mat = FMaterial::ValidateTexture(fbtex.get(), false); mat->AddTextureLayer(PaletteTexture.get()); + + Canvas.reset(); + Canvas.reset(new DSimpleCanvas(screen->GetWidth(), screen->GetHeight(), V_IsTrueColor())); } auto buf = fbtex->SystemTexture[0]->MapBuffer(); if (!buf) I_FatalError("Unable to map buffer for software rendering"); - buffer.SetBuffer(screen->GetWidth(), screen->GetHeight(), screen->GetWidth(), buf); - SWRenderer->RenderView(player, &buffer); + SWRenderer->RenderView(player, Canvas.get(), buf); fbtex->SystemTexture[0]->CreateTexture(nullptr, screen->GetWidth(), screen->GetHeight(), 0, false, 0, "swbuffer"); auto map = swrenderer::CameraLight::Instance()->ShaderColormap(); diff --git a/src/swrenderer/r_swscene.h b/src/swrenderer/r_swscene.h index 9c6921ee41..b57e3b947a 100644 --- a/src/swrenderer/r_swscene.h +++ b/src/swrenderer/r_swscene.h @@ -16,6 +16,7 @@ class SWSceneDrawer std::unique_ptr FBTexture[2]; int FBTextureIndex = 0; bool FBIsTruecolor = false; + std::unique_ptr Canvas; public: SWSceneDrawer(); diff --git a/src/swrenderer/scene/r_scene.cpp b/src/swrenderer/scene/r_scene.cpp index 18808c4c6c..e9f973d64f 100644 --- a/src/swrenderer/scene/r_scene.cpp +++ b/src/swrenderer/scene/r_scene.cpp @@ -90,7 +90,7 @@ namespace swrenderer clearcolor = color; } - void RenderScene::RenderView(player_t *player, DCanvas *target) + void RenderScene::RenderView(player_t *player, DCanvas *target, void *videobuffer) { auto viewport = MainThread()->Viewport.get(); viewport->RenderTarget = target; @@ -131,6 +131,10 @@ namespace swrenderer RenderActorView(player->mo); + auto copyqueue = std::make_shared(MainThread()->FrameMemory.get()); + copyqueue->Push(videobuffer, target->GetPixels(), target->GetWidth(), target->GetHeight(), target->GetPitch(), target->IsBgra() ? 4 : 1); + DrawerThreads::Execute(copyqueue); + DrawerWaitCycles.Clock(); DrawerThreads::WaitForWorkers(); DrawerWaitCycles.Unclock(); diff --git a/src/swrenderer/scene/r_scene.h b/src/swrenderer/scene/r_scene.h index a935d1cda2..1df9c292b5 100644 --- a/src/swrenderer/scene/r_scene.h +++ b/src/swrenderer/scene/r_scene.h @@ -48,7 +48,7 @@ namespace swrenderer void SetClearColor(int color); - void RenderView(player_t *player, DCanvas *target); + void RenderView(player_t *player, DCanvas *target, void *videobuffer); void RenderViewToCanvas(AActor *actor, DCanvas *canvas, int x, int y, int width, int height, bool dontmaplines = false); bool DontMapLines() const { return dontmaplines; }