mirror of
https://github.com/ZDoom/gzdoom-gles.git
synced 2025-01-31 12:30:32 +00:00
Fix texture loading race condition and improve performance by only locking the load mutex if data hasn't already been updated for this frame
This commit is contained in:
parent
d1f47afd96
commit
61d49a2007
13 changed files with 99 additions and 112 deletions
|
@ -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()))
|
||||
{
|
||||
|
|
|
@ -214,9 +214,6 @@ namespace swrenderer
|
|||
|
||||
drawerargs.SetStyle();
|
||||
|
||||
Thread->PrepareTexture(frontskytex, DefaultRenderStyle());
|
||||
Thread->PrepareTexture(backskytex, DefaultRenderStyle());
|
||||
|
||||
DrawSky(pl);
|
||||
}
|
||||
|
||||
|
|
|
@ -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<std::mutex> 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<PalEntry, PalEntry> RenderThread::GetSkyCapColor(FSoftwareTexture* tex)
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
int FSoftwareTexture::CurrentUpdate = 0;
|
||||
namespace swrenderer { extern std::mutex loadmutex; }
|
||||
|
||||
void FSoftwareTexture::UpdatePixels(int index)
|
||||
{
|
||||
auto Pixeldata = GetPixels(index);
|
||||
if ((unsigned)column >= (unsigned)GetPhysicalWidth())
|
||||
std::unique_lock<std::mutex> 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();
|
||||
const uint32_t* Pixeldata = GetPixelsBgraLocked();
|
||||
if (Spandata[index] == nullptr)
|
||||
Spandata[index] = CreateSpans(Pixeldata);
|
||||
Unlockeddata[index].Pixels = Pixeldata;
|
||||
Unlockeddata[index].LastUpdate = CurrentUpdate;
|
||||
}
|
||||
}
|
||||
if (spans_out != nullptr)
|
||||
{
|
||||
if (Spandata[index] == nullptr)
|
||||
{
|
||||
Spandata[index] = CreateSpans(Pixeldata);
|
||||
}
|
||||
*spans_out = Spandata[index][column];
|
||||
}
|
||||
return Pixeldata + column * GetPhysicalHeight();
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
const uint32_t *FSoftwareTexture::GetColumnBgra(unsigned int column, const FSoftwareTextureSpan **spans_out)
|
||||
{
|
||||
auto Pixeldata = GetPixelsBgra();
|
||||
if ((unsigned)column >= (unsigned)GetPhysicalWidth())
|
||||
{
|
||||
if (WidthMask + 1 == GetPhysicalWidth())
|
||||
{
|
||||
column &= WidthMask;
|
||||
}
|
||||
else
|
||||
{
|
||||
column %= GetPhysicalWidth();
|
||||
}
|
||||
}
|
||||
if (spans_out != nullptr)
|
||||
{
|
||||
if (Spandata[2] == nullptr)
|
||||
{
|
||||
Spandata[2] = CreateSpans(Pixeldata);
|
||||
}
|
||||
*spans_out = Spandata[2][column];
|
||||
}
|
||||
return Pixeldata + column * GetPhysicalHeight();
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
|
|
|
@ -20,6 +20,11 @@ protected:
|
|||
FTexture *mSource;
|
||||
TArray<uint8_t> Pixels;
|
||||
TArray<uint32_t> 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 @@ public:
|
|||
{
|
||||
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 @@ public:
|
|||
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<const uint32_t*>(Unlockeddata[style].Pixels);
|
||||
}
|
||||
else
|
||||
{
|
||||
UpdatePixels(style);
|
||||
return static_cast<const uint32_t*>(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<const uint8_t*>(Unlockeddata[style].Pixels);
|
||||
}
|
||||
else
|
||||
{
|
||||
UpdatePixels(style);
|
||||
return static_cast<const uint8_t*>(Unlockeddata[style].Pixels);
|
||||
}
|
||||
}
|
||||
|
||||
const uint8_t *GetPixels(FRenderStyle style)
|
||||
{
|
||||
|
@ -139,6 +198,11 @@ public:
|
|||
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 @@ public:
|
|||
~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);
|
||||
|
|
|
@ -77,7 +77,7 @@ FSWCanvasTexture::~FSWCanvasTexture()
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
const uint8_t *FSWCanvasTexture::GetPixels(int style)
|
||||
const uint8_t *FSWCanvasTexture::GetPixelsLocked(int style)
|
||||
{
|
||||
static_cast<FCanvasTexture*>(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<FCanvasTexture*>(mSource)->NeedUpdate();
|
||||
if (CanvasBgra == nullptr)
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -270,8 +270,6 @@ namespace swrenderer
|
|||
portalfloorclip[x] = mfloorclip[x];
|
||||
}
|
||||
|
||||
thread->PrepareTexture(pic, RenderStyle);
|
||||
|
||||
ProjectedWallLight mlight;
|
||||
mlight.SetSpriteLight();
|
||||
|
||||
|
|
|
@ -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++)
|
||||
|
|
|
@ -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();
|
||||
|
|
Loading…
Reference in a new issue