Merge branch 'develop' into feature/paging

This commit is contained in:
David Williams 2013-06-26 22:49:36 +02:00
commit 885a50e781
5 changed files with 88 additions and 57 deletions

View File

@ -4,6 +4,10 @@ This release has focused on... (some introduction here).
This line was added just for testing.
Voxel access
------------
The getVoxelAt() and setVoxelAt() functions have been deprecated and replaced by getVoxel() and setVoxel(). These new functions provide more control over how edge cases are handled and can potentially be faster as well. Please see the 'Volumes' section of the user manual for more information about how voxel access should be performed.
LargeVolume
-----------
It is now possible to provide custom compressors for the data which is stored in a LargeVolume. Two compressor implementation are provided with PolyVox - RLECompressor which is suitable for cubic-style terrain, and MinizCompressor which uses the 'miniz' zlib implementation for smooth terrain or general purpose use. Users can provide their own implementation of the compressor interface if they wish.
@ -14,13 +18,17 @@ These changes regarding compression and paging have also affected the LargeVolum
Error Handling
--------------
PolyVox now has it's own POLYVOX_ASSERT() macro rather than using the standard assert(). This has some advantages such as allowing a message to be printed and providing file/line information, and it is also possible to enable/disable it independantly of whether you are making a debug or release build
PolyVox now has it's own POLYVOX_ASSERT() macro rather than using the standard assert(). This has some advantages such as allowing a message to be printed and providing file/line information, and it is also possible to enable/disable it independantly of whether you are making a debug or release build.
A simple logging system has also been added, and the output can be redirected by user code.
Please see the 'Error Handling' section of the user manual for more information about these changes.
Volume wrap modes
-----------------
This release has seen a overhaul of the way PolyVox handles voxel positions which are outside of the volume. It used to be the case that you could specify a border value which would be returned whenever an out-of-volume access was performed, but this was not flexible enough for all use cases. You can now choose between different wrapping modes (border, clamp, etc) and apply them to both the volume itself or to samplers. If you have multiple samplers pointing at the same volume then you can choose to have different wrap modes for each of them.
Within the Volume class the getVoxelAt() and setBorderValue() functions have been deprecated. You should now call getVoxel() (which does not perform range checking and will crash when out of range) or getVoxelWithWrapping() (which does perform bounds checks and implements the required wrapping). When you call getVoxelWithWrapping() you are able to specify the required wrap mode for that particular call. For a Sampler you can set the wrap mode once with setWrapMode() and it will persist until you set it again.
Within the Volume class the getVoxelAt() and setBorderValue() functions have been deprecated. Please see the 'Volumes' section of the user manual for more information about how voxel access should now be performed.
Various algorithms have also been updated to allow wrap modes to be specified when executing them.

View File

@ -41,7 +41,7 @@ Or you could direct it to std::cout with:
.. sourcecode :: c++
setTraceStream(&(std::cout)));
setTraceStream(&(std::cout));
Note that by default the fatal, error and warning streams go to std::cerr, the info stream goes to std:cout, and the debug and trace streams are suppressed.

View File

@ -31,32 +31,32 @@ Alternatively you can modify the behaviour which occurs when a position is outsi
// This will return the voxel, or '42' if the position is outside the volume
uint8_t uVoxelValue = volume->getVoxel(x, y, z, WrapModes::Border, 42);
Please see the documentation for WrapMode for more information on the avaiable options here. Note in particular that WrapModes::AssumeValid can be used to skip any bounds checking and so you should use this *if you are certain* that you are accessing a valid position, as it may be noticably faster in some cases.
Please see the documentation for WrapMode for more information on the avaiable options here. Note in particular that WrapModes::AssumeValid can be used to skip any bounds checking and so you should use this *if you are certain* that you are accessing a valid position, as it may be noticably faster in some cases.
.. sourcecode :: c++
.. sourcecode :: c++
// This will result in undefined behaviour if the position is outside the volume
uint8_t uVoxelValue = volume->getVoxel(x, y, z, WrapModes::AssumeValid);
Fast access to voxel data is very important in PolyVox, but the above functions have a drawback in that they need to contain logic to evaluate the provided WrapMode and decide how to proceed. This introduces branching into the execution flow and results in larger functions which may prevent inlining. For even more speed you can use version of the above functions which are templatised on the WrapMode rather than taking it as a parameter. This means the condition can be evaluated at compile time rather than run time: For example:
Fast access to voxel data is very important in PolyVox, but the above functions have a drawback in that they need to contain logic to evaluate the provided WrapMode and decide how to proceed. This introduces branching into the execution flow and results in larger functions which may prevent inlining. For even more speed you can use version of the above functions which are templatised on the WrapMode rather than taking it as a parameter. This means the condition can be evaluated at compile time rather than run time: For example:
.. sourcecode :: c++
.. sourcecode :: c++
// This will return the voxel, or '42' if the position is outside the volume
uint8_t uVoxelValue = volume->getVoxel<WrapModes::Border>(x, y, z, 42);
Writing voxels
--------------
The setVoxel() function is used for writting to voxels instread of reading from them, and besides this it has two main behavoural differences when compared to getVoxel(). The first difference is that it is not templatised because the speed of setVoxel() is typically less important than getVoxel() (as writing to voxels is much less common than reading from them). However, we could add these temlatised version in the future if they are needed.
Writing voxels
--------------
The setVoxel() function is used for writting to voxels instread of reading from them, and besides this it has two main behavoural differences when compared to getVoxel(). The first difference is that it is not templatised because the speed of setVoxel() is typically less important than getVoxel() (as writing to voxels is much less common than reading from them). However, we could add these temlatised version in the future if they are needed.
The second difference is that certain wrap modes such as WrapModes::Border or WrapModes::Clamp do not make much sense when writting to voxel data, and so these are no permitted and will result in an exception being thrown. You should only use WrapModes::Validate (the default) and WrapModes::AssumeValid. For example:
The second difference is that certain wrap modes such as WrapModes::Border or WrapModes::Clamp do not make much sense when writting to voxel data, and so these are no permitted and will result in an exception being thrown. You should only use WrapModes::Validate (the default) and WrapModes::AssumeValid. For example:
.. sourcecode :: c++
.. sourcecode :: c++
RawVolume<uint8_t>* volume = ... // Get a volume from somewhere.
volume->setVoxel(x, y, z, 57); // Write the voxel at the given position.
volume->setVoxel(x, y, z, 57, WrapMopdes::AssumeValid); // No bounds checks
Notes on error handling and performance
---------------------------------------
Overall, you should set the wrap mode to WrapModes::AssumeValid for maximum performance (and use templatised versions where available), but note that even this fast version does still contain a POLYVOX_ASSERT() to try and catch mistakes. It appears that this assert prevents inlining (probably due to the logging it performs), but it is anticipated that you will disable such asserts in the final build of your software.
Notes on error handling and performance
---------------------------------------
Overall, you should set the wrap mode to WrapModes::AssumeValid for maximum performance (and use templatised versions where available), but note that even this fast version does still contain a POLYVOX_ASSERT() to try and catch mistakes. It appears that this assert prevents inlining (probably due to the logging it performs), but it is anticipated that you will disable such asserts in the final build of your software.

View File

@ -73,10 +73,7 @@ namespace PolyVox
template <uint32_t noOfDims, typename ElementType>
SubArray<noOfDims-1, ElementType> Array<noOfDims, ElementType>::operator[](uint32_t uIndex)
{
if(uIndex >= m_pDimensions[0])
{
POLYVOX_THROW(std::out_of_range, "Array index out of range");
}
POLYVOX_THROW_IF(uIndex >= m_pDimensions[0], std::out_of_range, "Array index out of range");
return
SubArray<noOfDims-1, ElementType>(&m_pElements[uIndex*m_pOffsets[0]],
@ -95,10 +92,7 @@ namespace PolyVox
template <uint32_t noOfDims, typename ElementType>
const SubArray<noOfDims-1, ElementType> Array<noOfDims, ElementType>::operator[](uint32_t uIndex) const
{
if(uIndex >= m_pDimensions[0])
{
POLYVOX_THROW(std::out_of_range, "Array index out of range");
}
POLYVOX_THROW_IF(uIndex >= m_pDimensions[0], std::out_of_range, "Array index out of range");
return
SubArray<noOfDims-1, ElementType>(&m_pElements[uIndex*m_pOffsets[0]],
@ -147,10 +141,7 @@ namespace PolyVox
m_uNoOfElements = 1;
for (uint32_t i = 0; i<noOfDims; i++)
{
if(pDimensions[i] == 0)
{
POLYVOX_THROW(std::out_of_range, "Invalid array dimension");
}
POLYVOX_THROW_IF(pDimensions[i] == 0, std::out_of_range, "Invalid array dimension");
m_uNoOfElements *= pDimensions[i];
m_pDimensions[i] = pDimensions[i];
@ -197,10 +188,7 @@ namespace PolyVox
template <uint32_t noOfDims, typename ElementType>
uint32_t Array<noOfDims, ElementType>::getDimension(uint32_t uDimension)
{
if(uDimension >= noOfDims)
{
POLYVOX_THROW(std::out_of_range, "Array dimension out of range");
}
POLYVOX_THROW_IF(uDimension >= noOfDims, std::out_of_range, "Array dimension out of range");
return m_pDimensions[uDimension];
}
@ -266,10 +254,7 @@ namespace PolyVox
template <typename ElementType>
ElementType& Array<1, ElementType>::operator[] (uint32_t uIndex)
{
if(uIndex >= m_pDimensions[0])
{
POLYVOX_THROW(std::out_of_range, "Array index out of range");
}
POLYVOX_THROW_IF(uIndex >= m_pDimensions[0], std::out_of_range, "Array index out of range");
return m_pElements[uIndex];
}
@ -277,10 +262,7 @@ namespace PolyVox
template <typename ElementType>
const ElementType& Array<1, ElementType>::operator[] (uint32_t uIndex) const
{
if(uIndex >= m_pDimensions[0])
{
POLYVOX_THROW(std::out_of_range, "Array index out of range");
}
POLYVOX_THROW_IF(uIndex >= m_pDimensions[0], std::out_of_range, "Array index out of range");
return m_pElements[uIndex];
}

View File

@ -255,15 +255,36 @@ namespace PolyVox
* ...
*/
#ifdef POLYVOX_THROW_ENABLED
#define POLYVOX_THROW(type, message) \
PolyVox::logError() << (message); \
throw type((message))
// Some fast functions (getVoxel(), etc) use exceptions for error handling but don't want the overhead of logging.
// This overhead is present even if no exception is thrown, probably because the presence of the logging code prevents
// some inlining. Therefore we provide this macro which doesn't log for such specialised circumstances.
#define POLYVOX_THROW_DONT_LOG(type, message) \
throw type((message))
#define POLYVOX_THROW_IF(condition, type, message) \
/* We use the do...while(0) construct in our macros (for reasons see here: http://stackoverflow.com/a/154138) \
but Visual Studio gives unhelpful 'conditional expression is constant' warnings. The recommended solution \
(http://stackoverflow.com/a/1946485) is to disable these warnings. */ \
POLYVOX_MSC_WARNING_PUSH \
POLYVOX_DISABLE_MSC_WARNING(4127) \
do \
{ \
if ((condition)) \
{ \
PolyVox::logError() << (message); \
throw type((message)); \
} \
} while(0) \
POLYVOX_MSC_WARNING_POP
#define POLYVOX_THROW(type, message) \
/* We use the do...while(0) construct in our macros (for reasons see here: http://stackoverflow.com/a/154138) \
but Visual Studio gives unhelpful 'conditional expression is constant' warnings. The recommended solution \
(http://stackoverflow.com/a/1946485) is to disable these warnings. */ \
POLYVOX_MSC_WARNING_PUSH \
POLYVOX_DISABLE_MSC_WARNING(4127) \
do \
{ \
PolyVox::logError() << (message); \
throw type((message)); \
} while(0) \
POLYVOX_MSC_WARNING_POP
#else
namespace PolyVox
{
@ -273,17 +294,37 @@ namespace PolyVox
void setThrowHandler(ThrowHandler newHandler);
}
#define POLYVOX_THROW(type, message) \
PolyVox::logError() << (message); \
type except = (type)((message)); \
getThrowHandler()((except), __FILE__, __LINE__)
#define POLYVOX_THROW_IF(condition, type, message) \
/* We use the do...while(0) construct in our macros (for reasons see here: http://stackoverflow.com/a/154138) \
but Visual Studio gives unhelpful 'conditional expression is constant' warnings. The recommended solution \
(http://stackoverflow.com/a/1946485) is to disable these warnings. */ \
POLYVOX_MSC_WARNING_PUSH \
POLYVOX_DISABLE_MSC_WARNING(4127) \
do \
{ \
if ((condition)) \
{ \
PolyVox::logError() << (message); \
type except = (type)((message)); \
getThrowHandler()((except), __FILE__, __LINE__); \
} \
} while(0) \
POLYVOX_MSC_WARNING_POP
#define POLYVOX_THROW(type, message) \
/* We use the do...while(0) construct in our macros (for reasons see here: http://stackoverflow.com/a/154138) \
but Visual Studio gives unhelpful 'conditional expression is constant' warnings. The recommended solution \
(http://stackoverflow.com/a/1946485) is to disable these warnings. */ \
POLYVOX_MSC_WARNING_PUSH \
POLYVOX_DISABLE_MSC_WARNING(4127) \
do \
{ \
PolyVox::logError() << (message); \
type except = (type)((message)); \
getThrowHandler()((except), __FILE__, __LINE__); \
} while(0) \
POLYVOX_MSC_WARNING_POP
// Some fast functions (getVoxel(), etc) use exceptions for error handling but don't want the overhead of logging.
// This overhead is present even if no exception is thrown, probably because the presence of the logging code prevents
// some inlining. Therefore we provide this macro which doesn't log for such specialised circumstances.
#define POLYVOX_THROW_DONT_LOG(type, message) \
type except = (type)((message)); \
getThrowHandler()((except), __FILE__, __LINE__)
#endif
namespace PolyVox