Merge branch 'fix_light_manager_ub' into 'master'

Fix UB in light initialization

See merge request OpenMW/openmw!877
pull/593/head
psi29a 4 years ago
commit 405e634e09

@ -114,15 +114,35 @@ namespace SceneUtil
mOffsets[AttenuationRadius] = 8;
}
LightBuffer(const LightBuffer& copy)
: osg::Referenced()
, mData(copy.mData)
, mEndian(copy.mEndian)
, mCount(copy.mCount)
, mStride(copy.mStride)
, mOffsets(copy.mOffsets)
, mCachedSunPos(copy.mCachedSunPos)
{}
LightBuffer(const LightBuffer&) = delete;
LightBuffer(const LightBuffer& other, int offsetColors, int offsetPosition, int offsetAttenuationRadius, int size, int stride)
: mData(new osg::FloatArray(size / sizeof(GL_FLOAT)))
, mEndian(other.mEndian)
, mCount(other.mCount)
, mStride((offsetAttenuationRadius + sizeof(GL_FLOAT) * osg::Vec4::num_components + stride) / 4)
, mCachedSunPos(other.mCachedSunPos)
{
mData->setBufferObject(other.mData->getBufferObject());
constexpr auto sizeofFloat = sizeof(GL_FLOAT);
const auto diffuseOffset = offsetColors / sizeofFloat;
mOffsets[Diffuse] = diffuseOffset;
mOffsets[Ambient] = diffuseOffset + 1;
mOffsets[Specular] = diffuseOffset + 2;
mOffsets[DiffuseSign] = diffuseOffset + 3;
mOffsets[Position] = offsetPosition / sizeofFloat;
mOffsets[AttenuationRadius] = offsetAttenuationRadius / sizeofFloat;
// Copy over previous buffers light data. Buffers populate before we know the layout.
for (int i = 0; i < other.mCount; ++i)
{
std::memcpy(&(*mData)[getOffset(i, Diffuse)], &(*other.mData)[other.getOffset(i, Diffuse)], sizeof(osg::Vec4f));
std::memcpy(&(*mData)[getOffset(i, Position)], &(*other.mData)[other.getOffset(i, Position)], sizeof(osg::Vec4f));
std::memcpy(&(*mData)[getOffset(i, AttenuationRadius)], &(*other.mData)[other.getOffset(i, AttenuationRadius)], sizeof(osg::Vec4f));
}
}
void setDiffuse(int index, const osg::Vec4& value)
{
@ -192,36 +212,11 @@ namespace SceneUtil
return mEndian == osg::BigEndian ? value.asABGR() : value.asRGBA();
}
int getOffset(int index, LayoutOffset slot)
int getOffset(int index, LayoutOffset slot) const
{
return mStride * index + mOffsets[slot];
}
void configureLayout(int offsetColors, int offsetPosition, int offsetAttenuationRadius, int size, int stride)
{
constexpr auto sizeofFloat = sizeof(GL_FLOAT);
constexpr auto sizeofVec4 = sizeofFloat * osg::Vec4::num_components;
LightBuffer oldBuffer = LightBuffer(*this);
mOffsets[Diffuse] = offsetColors / sizeofFloat;
mOffsets[Ambient] = mOffsets[Diffuse] + 1;
mOffsets[Specular] = mOffsets[Diffuse] + 2;
mOffsets[DiffuseSign] = mOffsets[Diffuse] + 3;
mOffsets[Position] = offsetPosition / sizeofFloat;
mOffsets[AttenuationRadius] = offsetAttenuationRadius / sizeofFloat;
mStride = (offsetAttenuationRadius + sizeofVec4 + stride) / 4;
// Copy over previous buffers light data. Buffers populate before we know the layout.
mData->resize(size / sizeofFloat);
for (int i = 0; i < oldBuffer.mCount; ++i)
{
std::memcpy(&(*mData)[getOffset(i, Diffuse)], &(*oldBuffer.mData)[oldBuffer.getOffset(i, Diffuse)], sizeof(osg::Vec4f));
std::memcpy(&(*mData)[getOffset(i, Position)], &(*oldBuffer.mData)[oldBuffer.getOffset(i, Position)], sizeof(osg::Vec4f));
std::memcpy(&(*mData)[getOffset(i, AttenuationRadius)], &(*oldBuffer.mData)[oldBuffer.getOffset(i, AttenuationRadius)], sizeof(osg::Vec4f));
}
}
private:
osg::ref_ptr<osg::FloatArray> mData;
osg::Endian mEndian;
@ -754,7 +749,7 @@ namespace SceneUtil
for (int i = 0; i < 2; ++i)
{
auto& buf = lightManager.getLightBuffer(i);
buf->configureLayout(offsets[0], offsets[1], offsets[2], totalBlockSize, stride);
buf = new LightBuffer(*buf, offsets[0], offsets[1], offsets[2], totalBlockSize, stride);
}
}

Loading…
Cancel
Save