Skip to content

Commit

Permalink
Fix race condition
Browse files Browse the repository at this point in the history
Values are accessed from main thread and cell preloader threads.
  • Loading branch information
elsid committed Aug 11, 2018
1 parent 52d4e25 commit c2b8c70
Showing 1 changed file with 133 additions and 66 deletions.
199 changes: 133 additions & 66 deletions components/terrain/material.cpp
Expand Up @@ -12,66 +12,150 @@

#include <components/shader/shadermanager.hpp>

#include <mutex>

namespace Terrain
namespace
{
class BlendmapTexMat
{
public:
static const osg::ref_ptr<osg::TexMat>& value(const int blendmapScale)
{
static BlendmapTexMat instance;
return instance.get(blendmapScale);
}

osg::ref_ptr<osg::TexMat> getBlendmapTexMat(int blendmapScale)
const osg::ref_ptr<osg::TexMat>& get(const int blendmapScale)
{
const std::lock_guard<std::mutex> lock(mMutex);
auto texMat = mTexMatMap.find(blendmapScale);
if (texMat == mTexMatMap.end())
{
osg::Matrixf matrix;
float scale = (blendmapScale/(static_cast<float>(blendmapScale)+1.f));
matrix.preMultTranslate(osg::Vec3f(0.5f, 0.5f, 0.f));
matrix.preMultScale(osg::Vec3f(scale, scale, 1.f));
matrix.preMultTranslate(osg::Vec3f(-0.5f, -0.5f, 0.f));
// We need to nudge the blendmap to look like vanilla.
// This causes visible seams unless the blendmap's resolution is doubled, but Vanilla also doubles the blendmap, apparently.
matrix.preMultTranslate(osg::Vec3f(1.0f/blendmapScale/4.0f, 1.0f/blendmapScale/4.0f, 0.f));

texMat = mTexMatMap.insert(std::make_pair(blendmapScale, new osg::TexMat(matrix))).first;
}
return texMat->second;
}

private:
std::mutex mMutex;
std::map<float, osg::ref_ptr<osg::TexMat>> mTexMatMap;
};

class LayerTexMat
{
static std::map<int, osg::ref_ptr<osg::TexMat> > texMatMap;
osg::ref_ptr<osg::TexMat> texMat = texMatMap[blendmapScale];
if (!texMat)
public:
static const osg::ref_ptr<osg::TexMat>& value(const float layerTileSize)
{
osg::Matrixf matrix;
float scale = (blendmapScale/(static_cast<float>(blendmapScale)+1.f));
matrix.preMultTranslate(osg::Vec3f(0.5f, 0.5f, 0.f));
matrix.preMultScale(osg::Vec3f(scale, scale, 1.f));
matrix.preMultTranslate(osg::Vec3f(-0.5f, -0.5f, 0.f));
// We need to nudge the blendmap to look like vanilla.
// This causes visible seams unless the blendmap's resolution is doubled, but Vanilla also doubles the blendmap, apparently.
matrix.preMultTranslate(osg::Vec3f(1.0f/blendmapScale/4.0f, 1.0f/blendmapScale/4.0f, 0.f));

texMat = new osg::TexMat(matrix);

texMatMap[blendmapScale] = texMat;
static LayerTexMat instance;
return instance.get(layerTileSize);
}
return texMat;
}

osg::ref_ptr<osg::TexMat> getLayerTexMat(float layerTileSize)
const osg::ref_ptr<osg::TexMat>& get(const float layerTileSize)
{
const std::lock_guard<std::mutex> lock(mMutex);
auto texMat = mTexMatMap.find(layerTileSize);
if (texMat == mTexMatMap.end())
{
texMat = mTexMatMap.insert(std::make_pair(layerTileSize,
new osg::TexMat(osg::Matrix::scale(osg::Vec3f(layerTileSize, layerTileSize, 1.f))))).first;
}
return texMat->second;
}

private:
std::mutex mMutex;
std::map<float, osg::ref_ptr<osg::TexMat>> mTexMatMap;
};

class EqualDepth
{
static std::map<float, osg::ref_ptr<osg::TexMat> > texMatMap;
osg::ref_ptr<osg::TexMat> texMat = texMatMap[layerTileSize];
if (!texMat)
public:
static const osg::ref_ptr<osg::Depth>& value()
{
texMat = new osg::TexMat(osg::Matrix::scale(osg::Vec3f(layerTileSize,layerTileSize,1.f)));
static EqualDepth instance;
return instance.mValue;
}

private:
osg::ref_ptr<osg::Depth> mValue;

texMatMap[layerTileSize] = texMat;
EqualDepth()
: mValue(new osg::Depth)
{
mValue->setFunction(osg::Depth::EQUAL);
}
return texMat;
}
};

osg::ref_ptr<osg::Depth> getEqualDepth()
class LequalDepth
{
static osg::ref_ptr<osg::Depth> depth;
if (!depth)
public:
static const osg::ref_ptr<osg::Depth>& value()
{
depth = new osg::Depth;
depth->setFunction(osg::Depth::EQUAL);
static LequalDepth instance;
return instance.mValue;
}
return depth;
}
osg::ref_ptr<osg::Depth> getLequalDepth()

private:
osg::ref_ptr<osg::Depth> mValue;

LequalDepth()
: mValue(new osg::Depth)
{
mValue->setFunction(osg::Depth::LEQUAL);
}
};

class BlendFunc
{
static osg::ref_ptr<osg::Depth> depth;
if (!depth)
public:
static const osg::ref_ptr<osg::BlendFunc>& value()
{
depth = new osg::Depth;
depth->setFunction(osg::Depth::LEQUAL);
static BlendFunc instance;
return instance.mValue;
}
return depth;
}

private:
osg::ref_ptr<osg::BlendFunc> mValue;

BlendFunc()
: mValue(new osg::BlendFunc)
{
mValue->setFunction(osg::BlendFunc::SRC_ALPHA, osg::BlendFunc::ONE);
}
};

class TexEnvCombine
{
public:
static const osg::ref_ptr<osg::TexEnvCombine>& value()
{
static TexEnvCombine instance;
return instance.mValue;
}

private:
osg::ref_ptr<osg::TexEnvCombine> mValue;

TexEnvCombine()
: mValue(new osg::TexEnvCombine)
{
mValue->setCombine_RGB(osg::TexEnvCombine::REPLACE);
mValue->setSource0_RGB(osg::TexEnvCombine::PREVIOUS);
}
};
}

namespace Terrain
{
std::vector<osg::ref_ptr<osg::StateSet> > createPasses(bool useShaders, bool forcePerPixelLighting, bool clampLighting, Shader::ShaderManager* shaderManager, const std::vector<TextureLayer> &layers,
const std::vector<osg::ref_ptr<osg::Texture2D> > &blendmaps, int blendmapScale, float layerTileSize)
{
Expand All @@ -87,16 +171,9 @@ namespace Terrain

if (!firstLayer)
{
static osg::ref_ptr<osg::BlendFunc> blendFunc;
if (!blendFunc)
{
blendFunc= new osg::BlendFunc();
blendFunc->setFunction(osg::BlendFunc::SRC_ALPHA, osg::BlendFunc::ONE);
}
stateset->setMode(GL_BLEND, osg::StateAttribute::ON);
stateset->setAttributeAndModes(blendFunc, osg::StateAttribute::ON);

stateset->setAttributeAndModes(getEqualDepth(), osg::StateAttribute::ON);
stateset->setAttributeAndModes(BlendFunc::value(), osg::StateAttribute::ON);
stateset->setAttributeAndModes(EqualDepth::value(), osg::StateAttribute::ON);
}
// disable fog if we're the first layer of several - supposed to be completely black
if (firstLayer && blendmaps.size() > 0)
Expand All @@ -105,7 +182,7 @@ namespace Terrain
fog->setStart(10000000);
fog->setEnd(10000000);
stateset->setAttributeAndModes(fog, osg::StateAttribute::OFF|osg::StateAttribute::OVERRIDE);
stateset->setAttributeAndModes(getLequalDepth(), osg::StateAttribute::ON);
stateset->setAttributeAndModes(LequalDepth::value(), osg::StateAttribute::ON);
}

int texunit = 0;
Expand All @@ -115,7 +192,7 @@ namespace Terrain
stateset->setTextureAttributeAndModes(texunit, it->mDiffuseMap);

if (layerTileSize != 1.f)
stateset->setTextureAttributeAndModes(texunit, getLayerTexMat(layerTileSize), osg::StateAttribute::ON);
stateset->setTextureAttributeAndModes(texunit, LayerTexMat::value(layerTileSize), osg::StateAttribute::ON);

stateset->addUniform(new osg::Uniform("diffuseMap", texunit));

Expand All @@ -125,8 +202,7 @@ namespace Terrain
osg::ref_ptr<osg::Texture2D> blendmap = blendmaps.at(blendmapIndex++);

stateset->setTextureAttributeAndModes(texunit, blendmap.get());

stateset->setTextureAttributeAndModes(texunit, getBlendmapTexMat(blendmapScale));
stateset->setTextureAttributeAndModes(texunit, BlendmapTexMat::value(blendmapScale));
stateset->addUniform(new osg::Uniform("blendMap", texunit));
}

Expand Down Expand Up @@ -165,17 +241,8 @@ namespace Terrain
stateset->setTextureAttributeAndModes(texunit, blendmap.get());

// This is to map corner vertices directly to the center of a blendmap texel.
stateset->setTextureAttributeAndModes(texunit, getBlendmapTexMat(blendmapScale));

static osg::ref_ptr<osg::TexEnvCombine> texEnvCombine;
if (!texEnvCombine)
{
texEnvCombine = new osg::TexEnvCombine;
texEnvCombine->setCombine_RGB(osg::TexEnvCombine::REPLACE);
texEnvCombine->setSource0_RGB(osg::TexEnvCombine::PREVIOUS);
}

stateset->setTextureAttributeAndModes(texunit, texEnvCombine, osg::StateAttribute::ON);
stateset->setTextureAttributeAndModes(texunit, BlendmapTexMat::value(blendmapScale));
stateset->setTextureAttributeAndModes(texunit, TexEnvCombine::value(), osg::StateAttribute::ON);

++texunit;
}
Expand All @@ -185,7 +252,7 @@ namespace Terrain
stateset->setTextureAttributeAndModes(texunit, tex.get());

if (layerTileSize != 1.f)
stateset->setTextureAttributeAndModes(texunit, getLayerTexMat(layerTileSize), osg::StateAttribute::ON);
stateset->setTextureAttributeAndModes(texunit, LayerTexMat::value(layerTileSize), osg::StateAttribute::ON);
}

stateset->setRenderBinDetails(passIndex++, "RenderBin");
Expand Down

0 comments on commit c2b8c70

Please sign in to comment.