Bug in LinearSparseFieldInterp::sample()

15 views
Skip to first unread message

jam...@moving-picture.com

unread,
Dec 18, 2013, 5:40:31 AM12/18/13
to field...@googlegroups.com

In Field3d 1.4, SparseField::LinearInterp typedef was changed from:

typedef LinearGenericFieldInterp<SparseField<Data_T> > LinearInterp;

to:

typedef LinearSparseFieldInterp<Data_T> LinearInterp;

However the function LinearSparseFieldInterp::sample() seems to not work when the SparseFileManager memory limit is enabled.

When the lookup is in the middle of a block, the code accesses the block data directly via:  field.blockData().
But this block may not even have been loaded yet. If not, the returned pointer is NULL, which leads to the empty block value being returned.
This leads to artifacts where blocks are missing in the render.

In the old LinearGenericFieldInterp, all block data was accessed via field.fastValue(),  which has the logic to load and cache the block.

Our workaround is to just make sure to use LinearGenericFieldInterp for the lookup, avoiding this new sampling code.
If this is genuinely a mistake, it would be good to get it fixed.

Cheers,
Jamie




Magnus Wrenninge

unread,
Dec 18, 2013, 1:17:31 PM12/18/13
to field...@googlegroups.com
Hi Jamie,

Indeed, that's a bug that needs fixing. The new LinearSparseFieldInterp needs to make sure the block truly is unallocated before returning the empty value, if not, it should fall back to calling fastValue();

Also, I realize that LinearSparseFieldInterp isn't quite thread safe when using the load cache - it doesn't guarantee that the block data stays in memory while the pointer dereferencing happens. I need to add calls to the manager->incBlockRef.

The solution to the first part should be the following, so if you want to give that a spin it should definitely help.

   if (vi < blockSize - 1 && vj < blockSize - 1 && vk < blockSize - 1) {
    // Only do work if the block is allocated
  const Data_T * const p = field.blockData(bi, bj, bk);
  if (p) {
    const Data_T * const c111 = p + vi + vj * blockSize + vk * blockSize * blockSize;
    const Data_T * const c121 = c111 + blockSize * (c2.y - c1.y);
    const Data_T * const c112 = c111 + blockSize * blockSize * (c2.z - c1.z);
    const Data_T * const c122 = c112 + blockSize * (c2.y - c1.y);
    int xInc = c2.x - c1.x;
    return static_cast<Data_T>
      (f1.x * (f1.y * (f1.z * *c111 +
                      f2.z * *c112) +
               f2.y * (f1.z * *c121 +
                       f2.z * *c122)) +
       f2.x * (f1.y * (f1.z * *(c111 + xInc) +
                       f2.z * *(c112 + xInc)) +
               f2.y * (f1.z * *(c121 + xInc) +
                       f2.z * *(c122 + xInc))));
  } else if (!field.blockIsAllocated(bi, bj, bk) {
    return static_cast<Data_T>(field.getBlockEmptyValue(bi, bj, bk));
  }
}
return static_cast<Data_T>
  (f1.x * (f1.y * (f1.z * field.fastValue(c1.x, c1.y, c1.z) +
                   f2.z * field.fastValue(c1.x, c1.y, c2.z)) +
           f2.y * (f1.z * field.fastValue(c1.x, c2.y, c1.z) +
                   f2.z * field.fastValue(c1.x, c2.y, c2.z))) +
   f2.x * (f1.y * (f1.z * field.fastValue(c2.x, c1.y, c1.z) +
                   f2.z * field.fastValue(c2.x, c1.y, c2.z)) +
           f2.y * (f1.z * field.fastValue(c2.x, c2.y, c1.z) +
                   f2.z * field.fastValue(c2.x, c2.y, c2.z))));

I'll make updates for thread safety once I can run it through some tests to verify.

Magnus


--
You received this message because you are subscribed to the Google Groups "Field3D dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email to field3d-dev...@googlegroups.com.
To post to this group, send email to field...@googlegroups.com.
Visit this group at http://groups.google.com/group/field3d-dev.
For more options, visit https://groups.google.com/groups/opt_out.

Reply all
Reply to author
Forward
0 new messages