diff --git a/src/rendering/swrenderer/line/r_walldraw.cpp b/src/rendering/swrenderer/line/r_walldraw.cpp index 61945fefb01..1d4a4c64cb8 100644 --- a/src/rendering/swrenderer/line/r_walldraw.cpp +++ b/src/rendering/swrenderer/line/r_walldraw.cpp @@ -81,8 +81,6 @@ namespace swrenderer mLight.SetColormap(lightsector, curline); mLight.SetLightLeft(Thread, WallC); - Thread->PrepareTexture(pic, DefaultRenderStyle()); // Get correct render style? Shaded won't get here. - CameraLight* cameraLight = CameraLight::Instance(); if (cameraLight->FixedColormap() || cameraLight->FixedLightLevel() >= 0 || !(lightsector->e && lightsector->e->XFloor.lightlist.Size())) { diff --git a/src/rendering/swrenderer/plane/r_skyplane.cpp b/src/rendering/swrenderer/plane/r_skyplane.cpp index 4027c6401c6..48639768ac2 100644 --- a/src/rendering/swrenderer/plane/r_skyplane.cpp +++ b/src/rendering/swrenderer/plane/r_skyplane.cpp @@ -214,9 +214,6 @@ namespace swrenderer drawerargs.SetStyle(); - Thread->PrepareTexture(frontskytex, DefaultRenderStyle()); - Thread->PrepareTexture(backskytex, DefaultRenderStyle()); - DrawSky(pl); } diff --git a/src/rendering/swrenderer/r_renderthread.cpp b/src/rendering/swrenderer/r_renderthread.cpp index 5dac0c11b1e..4c3e4d2c665 100644 --- a/src/rendering/swrenderer/r_renderthread.cpp +++ b/src/rendering/swrenderer/r_renderthread.cpp @@ -92,35 +92,7 @@ namespace swrenderer return pal_drawers.get(); } - static std::mutex loadmutex; - void RenderThread::PrepareTexture(FSoftwareTexture *texture, FRenderStyle style) - { - if (texture == nullptr) - return; - - // Textures may not have loaded/refreshed yet. The shared code doing - // this is not thread safe. By calling GetPixels in a mutex lock we - // make sure that only one thread is loading a texture at any given - // time. - // - // It is critical that this function is called before any direct - // calls to GetPixels for this to work. - - std::unique_lock lock(loadmutex); - - const FSoftwareTextureSpan *spans; - if (Viewport->RenderTarget->IsBgra()) - { - texture->GetPixelsBgra(); - texture->GetColumnBgra(0, &spans); - } - else - { - bool alpha = !!(style.Flags & STYLEF_RedIsAlpha); - texture->GetPixels(alpha); - texture->GetColumn(alpha, 0, &spans); - } - } + std::mutex loadmutex; std::pair RenderThread::GetSkyCapColor(FSoftwareTexture* tex) { diff --git a/src/rendering/swrenderer/r_renderthread.h b/src/rendering/swrenderer/r_renderthread.h index 325b8ffa1bf..ba862c77524 100644 --- a/src/rendering/swrenderer/r_renderthread.h +++ b/src/rendering/swrenderer/r_renderthread.h @@ -87,9 +87,6 @@ namespace swrenderer SWPixelFormatDrawers *Drawers(RenderViewport *viewport); - // Make sure texture can accessed safely - void PrepareTexture(FSoftwareTexture *texture, FRenderStyle style); - // Setup poly object in a threadsafe manner void PreparePolyObject(subsector_t *sub); diff --git a/src/rendering/swrenderer/scene/r_scene.cpp b/src/rendering/swrenderer/scene/r_scene.cpp index d419fea3e5a..2558a2f2aff 100644 --- a/src/rendering/swrenderer/scene/r_scene.cpp +++ b/src/rendering/swrenderer/scene/r_scene.cpp @@ -219,6 +219,7 @@ namespace swrenderer Threads[i]->X2 = viewwidth * (i + 1) / numThreads; } run_id++; + FSoftwareTexture::CurrentUpdate = run_id; start_lock.unlock(); // Notify threads to run diff --git a/src/rendering/swrenderer/textures/r_swtexture.cpp b/src/rendering/swrenderer/textures/r_swtexture.cpp index e45bd797863..662c12d573f 100644 --- a/src/rendering/swrenderer/textures/r_swtexture.cpp +++ b/src/rendering/swrenderer/textures/r_swtexture.cpp @@ -119,7 +119,7 @@ void FSoftwareTexture::CalcBitSize () // //========================================================================== -const uint8_t *FSoftwareTexture::GetPixels(int style) +const uint8_t *FSoftwareTexture::GetPixelsLocked(int style) { if (Pixels.Size() == 0 || CheckModified(style)) { @@ -158,13 +158,7 @@ const uint8_t *FSoftwareTexture::GetPixels(int style) return Pixels.Data(); } -//========================================================================== -// -// -// -//========================================================================== - -const uint32_t *FSoftwareTexture::GetPixelsBgra() +const uint32_t *FSoftwareTexture::GetPixelsBgraLocked() { if (PixelsBgra.Size() == 0 || CheckModified(2)) { @@ -197,60 +191,31 @@ const uint32_t *FSoftwareTexture::GetPixelsBgra() // //========================================================================== -const uint8_t *FSoftwareTexture::GetColumn(int index, unsigned int column, const FSoftwareTextureSpan **spans_out) -{ - auto Pixeldata = GetPixels(index); - if ((unsigned)column >= (unsigned)GetPhysicalWidth()) - { - if (WidthMask + 1 == GetPhysicalWidth()) - { - column &= WidthMask; - } - else - { - column %= GetPhysicalWidth(); - } - } - if (spans_out != nullptr) - { - if (Spandata[index] == nullptr) - { - Spandata[index] = CreateSpans(Pixeldata); - } - *spans_out = Spandata[index][column]; - } - return Pixeldata + column * GetPhysicalHeight(); -} - -//========================================================================== -// -// -// -//========================================================================== +int FSoftwareTexture::CurrentUpdate = 0; +namespace swrenderer { extern std::mutex loadmutex; } -const uint32_t *FSoftwareTexture::GetColumnBgra(unsigned int column, const FSoftwareTextureSpan **spans_out) +void FSoftwareTexture::UpdatePixels(int index) { - auto Pixeldata = GetPixelsBgra(); - if ((unsigned)column >= (unsigned)GetPhysicalWidth()) + std::unique_lock lock(swrenderer::loadmutex); + if (Unlockeddata[index].LastUpdate != CurrentUpdate) { - if (WidthMask + 1 == GetPhysicalWidth()) + if (index != 2) { - column &= WidthMask; + const uint8_t* Pixeldata = GetPixelsLocked(index); + if (Spandata[index] == nullptr) + Spandata[index] = CreateSpans(Pixeldata); + Unlockeddata[index].Pixels = Pixeldata; + Unlockeddata[index].LastUpdate = CurrentUpdate; } else { - column %= GetPhysicalWidth(); - } - } - if (spans_out != nullptr) - { - if (Spandata[2] == nullptr) - { - Spandata[2] = CreateSpans(Pixeldata); + const uint32_t* Pixeldata = GetPixelsBgraLocked(); + if (Spandata[index] == nullptr) + Spandata[index] = CreateSpans(Pixeldata); + Unlockeddata[index].Pixels = Pixeldata; + Unlockeddata[index].LastUpdate = CurrentUpdate; } - *spans_out = Spandata[2][column]; } - return Pixeldata + column * GetPhysicalHeight(); } //========================================================================== diff --git a/src/rendering/swrenderer/textures/r_swtexture.h b/src/rendering/swrenderer/textures/r_swtexture.h index f053f8552d2..54597d0c6de 100644 --- a/src/rendering/swrenderer/textures/r_swtexture.h +++ b/src/rendering/swrenderer/textures/r_swtexture.h @@ -20,6 +20,11 @@ class FSoftwareTexture : public ISoftwareTexture FTexture *mSource; TArray Pixels; TArray PixelsBgra; + struct + { + const void* Pixels = nullptr; + int LastUpdate = -1; + } Unlockeddata[3]; FSoftwareTextureSpan **Spandata[3] = { }; DVector2 Scale; uint8_t WidthBits = 0, HeightBits = 0; @@ -94,6 +99,7 @@ class FSoftwareTexture : public ISoftwareTexture { Pixels.Reset(); PixelsBgra.Reset(); + for (auto& d : Unlockeddata) d = {}; } // Returns true if the next call to GetPixels() will return an image different from the @@ -110,16 +116,69 @@ class FSoftwareTexture : public ISoftwareTexture virtual bool Mipmapped() { return true; } // Returns a single column of the texture - virtual const uint8_t *GetColumn(int style, unsigned int column, const FSoftwareTextureSpan **spans_out); + const uint8_t* GetColumn(int style, unsigned int column, const FSoftwareTextureSpan** spans_out) + { + column = WrapColumn(column); + const uint8_t* pixels = GetPixels(style); + if (spans_out) + *spans_out = Spandata[style][column]; + return pixels + column * GetPhysicalHeight(); + } // Returns a single column of the texture, in BGRA8 format - virtual const uint32_t *GetColumnBgra(unsigned int column, const FSoftwareTextureSpan **spans_out); + const uint32_t* GetColumnBgra(unsigned int column, const FSoftwareTextureSpan** spans_out) + { + column = WrapColumn(column); + const uint32_t* pixels = GetPixelsBgra(); + if (spans_out) + *spans_out = Spandata[2][column]; + return pixels + column * GetPhysicalHeight(); + } + + unsigned int WrapColumn(unsigned int column) + { + if ((unsigned)column >= (unsigned)GetPhysicalWidth()) + { + if (WidthMask + 1 == GetPhysicalWidth()) + { + column &= WidthMask; + } + else + { + column %= GetPhysicalWidth(); + } + } + return column; + } // Returns the whole texture, stored in column-major order, in BGRA8 format - virtual const uint32_t *GetPixelsBgra(); + const uint32_t* GetPixelsBgra() + { + int style = 2; + if (Unlockeddata[2].LastUpdate == CurrentUpdate) + { + return static_cast(Unlockeddata[style].Pixels); + } + else + { + UpdatePixels(style); + return static_cast(Unlockeddata[style].Pixels); + } + } // Returns the whole texture, stored in column-major order - virtual const uint8_t *GetPixels(int style); + const uint8_t* GetPixels(int style) + { + if (Unlockeddata[style].LastUpdate == CurrentUpdate) + { + return static_cast(Unlockeddata[style].Pixels); + } + else + { + UpdatePixels(style); + return static_cast(Unlockeddata[style].Pixels); + } + } const uint8_t *GetPixels(FRenderStyle style) { @@ -139,6 +198,11 @@ class FSoftwareTexture : public ISoftwareTexture return GetColumn(alpha, column, spans_out); } + static int CurrentUpdate; + void UpdatePixels(int style); + + virtual const uint32_t* GetPixelsBgraLocked(); + virtual const uint8_t* GetPixelsLocked(int style); }; // A texture that returns a wiggly version of another texture. @@ -154,8 +218,8 @@ class FWarpTexture : public FSoftwareTexture public: FWarpTexture (FGameTexture *source, int warptype); - const uint32_t *GetPixelsBgra() override; - const uint8_t *GetPixels(int style) override; + const uint32_t *GetPixelsBgraLocked() override; + const uint8_t *GetPixelsLocked(int style) override; bool CheckModified (int which) override; void GenerateBgraMipmapsFast(); @@ -179,8 +243,8 @@ class FSWCanvasTexture : public FSoftwareTexture ~FSWCanvasTexture(); // Returns the whole texture, stored in column-major order - const uint32_t *GetPixelsBgra() override; - const uint8_t *GetPixels(int style) override; + const uint32_t *GetPixelsBgraLocked() override; + const uint8_t *GetPixelsLocked(int style) override; virtual void Unload() override; void UpdatePixels(bool truecolor); diff --git a/src/rendering/swrenderer/textures/swcanvastexture.cpp b/src/rendering/swrenderer/textures/swcanvastexture.cpp index db9471774b2..91385fe0cd0 100644 --- a/src/rendering/swrenderer/textures/swcanvastexture.cpp +++ b/src/rendering/swrenderer/textures/swcanvastexture.cpp @@ -77,7 +77,7 @@ FSWCanvasTexture::~FSWCanvasTexture() // //========================================================================== -const uint8_t *FSWCanvasTexture::GetPixels(int style) +const uint8_t *FSWCanvasTexture::GetPixelsLocked(int style) { static_cast(mSource)->NeedUpdate(); if (Canvas == nullptr) @@ -94,7 +94,7 @@ const uint8_t *FSWCanvasTexture::GetPixels(int style) // //========================================================================== -const uint32_t *FSWCanvasTexture::GetPixelsBgra() +const uint32_t *FSWCanvasTexture::GetPixelsBgraLocked() { static_cast(mSource)->NeedUpdate(); if (CanvasBgra == nullptr) diff --git a/src/rendering/swrenderer/textures/warptexture.cpp b/src/rendering/swrenderer/textures/warptexture.cpp index 49869f8d6da..ce3cb2f522c 100644 --- a/src/rendering/swrenderer/textures/warptexture.cpp +++ b/src/rendering/swrenderer/textures/warptexture.cpp @@ -57,7 +57,7 @@ bool FWarpTexture::CheckModified (int style) return screen->FrameTime != GenTime[style]; } -const uint32_t *FWarpTexture::GetPixelsBgra() +const uint32_t *FWarpTexture::GetPixelsBgraLocked() { uint64_t time = screen->FrameTime; uint64_t resizeMult = gl_texture_hqresizemult; @@ -67,7 +67,7 @@ const uint32_t *FWarpTexture::GetPixelsBgra() if (gl_texture_hqresizemode == 0 || gl_texture_hqresizemult < 1 || !(gl_texture_hqresize_targets & 1)) resizeMult = 1; - auto otherpix = FSoftwareTexture::GetPixelsBgra(); + auto otherpix = FSoftwareTexture::GetPixelsBgraLocked(); WarpedPixelsRgba.Resize(unsigned(GetWidth() * GetHeight() * resizeMult * resizeMult * 4 / 3 + 1)); WarpBuffer(WarpedPixelsRgba.Data(), otherpix, int(GetWidth() * resizeMult), int(GetHeight() * resizeMult), WidthOffsetMultiplier, HeightOffsetMultiplier, time, mTexture->GetShaderSpeed(), bWarped); GenerateBgraMipmapsFast(); @@ -78,7 +78,7 @@ const uint32_t *FWarpTexture::GetPixelsBgra() } -const uint8_t *FWarpTexture::GetPixels(int index) +const uint8_t *FWarpTexture::GetPixelsLocked(int index) { uint64_t time = screen->FrameTime; uint64_t resizeMult = gl_texture_hqresizemult; @@ -88,7 +88,7 @@ const uint8_t *FWarpTexture::GetPixels(int index) if (gl_texture_hqresizemode == 0 || gl_texture_hqresizemult < 1 || !(gl_texture_hqresize_targets & 1)) resizeMult = 1; - const uint8_t *otherpix = FSoftwareTexture::GetPixels(index); + const uint8_t *otherpix = FSoftwareTexture::GetPixelsLocked(index); WarpedPixels[index].Resize(unsigned(GetWidth() * GetHeight() * resizeMult * resizeMult)); WarpBuffer(WarpedPixels[index].Data(), otherpix, int(GetWidth() * resizeMult), int(GetHeight() * resizeMult), WidthOffsetMultiplier, HeightOffsetMultiplier, time, mTexture->GetShaderSpeed(), bWarped); FreeAllSpans(); diff --git a/src/rendering/swrenderer/things/r_decal.cpp b/src/rendering/swrenderer/things/r_decal.cpp index df8f6fb387b..ffe06c0a1bd 100644 --- a/src/rendering/swrenderer/things/r_decal.cpp +++ b/src/rendering/swrenderer/things/r_decal.cpp @@ -240,7 +240,6 @@ namespace swrenderer bool visible = drawerargs.SetStyle(thread->Viewport.get(), decal->RenderStyle, (float)decal->Alpha, decal->Translation, decal->AlphaColor, cmlight); if (visible) { - thread->PrepareTexture(WallSpriteTile, decal->RenderStyle); drawerargs.DrawMasked(thread, zpos + WallSpriteTile->GetTopOffset(0) * decal->ScaleY, decal->ScaleY, decal->RenderFlags & RF_XFLIP, decal->RenderFlags & RF_YFLIP, WallC, clipper->x1, clipper->x2, light, WallSpriteTile, mfloorclip, mceilingclip, decal->RenderStyle); } diff --git a/src/rendering/swrenderer/things/r_sprite.cpp b/src/rendering/swrenderer/things/r_sprite.cpp index 2873b914951..8f47c524b7b 100644 --- a/src/rendering/swrenderer/things/r_sprite.cpp +++ b/src/rendering/swrenderer/things/r_sprite.cpp @@ -270,8 +270,6 @@ namespace swrenderer portalfloorclip[x] = mfloorclip[x]; } - thread->PrepareTexture(pic, RenderStyle); - ProjectedWallLight mlight; mlight.SetSpriteLight(); diff --git a/src/rendering/swrenderer/things/r_wallsprite.cpp b/src/rendering/swrenderer/things/r_wallsprite.cpp index bccea75a6eb..bc14fc148ee 100644 --- a/src/rendering/swrenderer/things/r_wallsprite.cpp +++ b/src/rendering/swrenderer/things/r_wallsprite.cpp @@ -176,8 +176,6 @@ namespace swrenderer // Draw it auto WallSpriteTile = spr->pic; - thread->PrepareTexture(WallSpriteTile, spr->RenderStyle); - RenderTranslucentPass* translucentPass = thread->TranslucentPass.get(); short floorclip[MAXWIDTH]; for (int x = x1; x < x2; x++) diff --git a/src/rendering/swrenderer/viewport/r_spandrawer.cpp b/src/rendering/swrenderer/viewport/r_spandrawer.cpp index 51da4fb4630..c101ac80c4d 100644 --- a/src/rendering/swrenderer/viewport/r_spandrawer.cpp +++ b/src/rendering/swrenderer/viewport/r_spandrawer.cpp @@ -32,8 +32,6 @@ namespace swrenderer void SpanDrawerArgs::SetTexture(RenderThread *thread, FSoftwareTexture *tex) { - thread->PrepareTexture(tex, DefaultRenderStyle()); - ds_texwidth = tex->GetPhysicalWidth(); ds_texheight = tex->GetPhysicalHeight(); ds_xbits = tex->GetWidthBits();