/*========================================================================= Program: Visualization Toolkit Module: vtkVolumeTexture.h Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen All rights reserved. See Copyright.txt or http://www.kitware.com/Copyright.htm for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notice for more information. =========================================================================*/ /** * @class vtkVolumeTexture * @brief Creates and manages the volume texture rendered by * vtkOpenGLGPUVolumeRayCastMapper. * * Wraps a vtkTextureObject for which it selects the appropriate format (depending * on the input vtkDataArray type, number of components, etc.) and loads input data. * The class maintains a set of members of interest to the parent mapper, such as: * * * Active vtkDataArray scalar range. * * Volume's scale and bias (pixel transfer functions). * * HandleLargeDataType flag. * * This class supports streaming the volume data in separate blocks to make it fit * in graphics memory (sometimes referred to as bricking). The data is split into * a user-defined number of blocks in such a way that a single sub-block (brick) fits * completely into GPU memory. A stride is passed to OpenGL so that it can access * the underlying vtkDataArray adequately for each of the blocks to be streamed * into GPU memory (back-to-front for correct composition). * Streaming the volume as separate texture bricks certainly imposes a performance * trade-off but acts as a graphics memory expansion scheme for devices that would * not be able to render higher resoulution volumes otherwise. * * @warning There are certain caveats when texture streaming is enabled, given the * locality constraint that rendering a single block imposes. * * - Quality might suffer near the block seams with ShadeOn() (gradient computation at * the boundaries needs adjustment). * * - Not all of the features supported by the mapper currently work correctly. This * is a list of known issues: * -# Volume masks are currently not being streamed. They need to use a vtkVolumeTexture * object instead. This will be fixed in a future commit. * -# Blending modes such as average and additive might compute a different value near * the edges. * * - Future work will extend the API to be able to compute an ideal number of * partitions and extents based on the platform capabilities. * * @warning This is an internal class of vtkOpenGLGPUVolumeRayCastMapper. It assumes * there is an active OpenGL context in each of its methods involving GL calls * (MakeCurrent() is expected to be called in the mapper before any member calls * involving gl functions). */ #ifndef vtkVolumeTexture_h #define vtkVolumeTexture_h #include // For ImageDataBlockMap #include // For ImageDataBlocks #include "vtkRenderingVolumeOpenGL2Module.h" // For export macro #include "vtkObject.h" #include "vtkTimeStamp.h" // For UploadTime #include "vtkTuple.h" // For Size6 and Size3 class vtkDataArray; class vtkImageData; class vtkMatrix4x4; class vtkOpenGLGPUVolumeRayCastMapper; class vtkRenderer; class vtkTextureObject; class vtkWindow; class VTKRENDERINGVOLUMEOPENGL2_EXPORT vtkVolumeTexture : public vtkObject { typedef vtkTuple Size6; typedef vtkTuple Size3; public: static vtkVolumeTexture* New(); struct VolumeBlock { VolumeBlock(vtkImageData* imData, vtkTextureObject* tex, Size3 const& texSize) { // Block extent is stored in vtkImageData ImageData = imData; TextureObject = tex; TextureSize = texSize; TupleIndex = 0; } vtkImageData* ImageData; vtkTextureObject* TextureObject; Size3 TextureSize; vtkIdType TupleIndex; }; vtkTypeMacro(vtkVolumeTexture, vtkObject); void PrintSelf( ostream& os, vtkIndent indent ) override; /** * Set the parent volume mapper and initialize internals. */ void SetMapper(vtkOpenGLGPUVolumeRayCastMapper* mapper); /** * Set a number of blocks per axis. */ void SetPartitions(int const x, int const y, int const z); const Size3& GetPartitions(); /** * Loads the data array into the texture in the case only a single block is * is defined. Does not load when the input data is divided in multiple blocks * (in which case they will be loaded into GPU memory by GetNextBlock()). * Requires an active OpenGL context. */ bool LoadVolume(vtkRenderer* ren, vtkImageData* data, vtkDataArray* scalars, int const interpolation); void UpdateInterpolationType(int const interpolation); /** * If streaming the data array as separate blocks, sort them back to front. * This method does nothing if there is a single block. */ void SortBlocksBackToFront(vtkRenderer *ren, vtkMatrix4x4* volumeMat); /** * Return the next volume block to be rendered. When streaming is active (number * of blocks > 1), this method will upload and release graphics resources of * each block. */ VolumeBlock* GetNextBlock(); /** * Clean-up acquired graphics resources. */ void ReleaseGraphicsResources(vtkWindow* win); /** * Get the scale and bias values given a VTK scalar type and a finite range. * The scale and bias values computed using this method can be useful for * custom shader code. For example, when looking up color values through the * transfer function texture, the scalar value must be scaled and offset. */ static void GetScaleAndBias(const int scalarType, double * scalarRange, float& scale, float& bias); //---------------------------------------------------------------------------- bool HandleLargeDataTypes; float Scale[4]; float Bias[4]; double ScalarRange[4][2]; int InterpolationType; vtkTimeStamp UploadTime; protected: vtkVolumeTexture(); ~vtkVolumeTexture() override; private: /** * Load an image block as defined in volBlock into GPU memory. * Requires an active OpenGL context. */ bool LoadTexture(int const interpolation, VolumeBlock* volBlock); /** * Divide the image data in NxMxO user-defined blocks. */ void SplitVolume(vtkImageData* imageData, Size3 const & part); /** * Requires an active OpenGL context. */ void SetInterpolation(int const interpolation); void CreateBlocks(unsigned int const format, unsigned int const internalFormat, int const type); void AdjustExtentForCell(Size6& extent); Size3 ComputeBlockSize(int* extent); /** * Defines OpenGL's texture type, format and internal format based on the * vtkDataArray type (scalarType) and the number of array components. */ void SelectTextureFormat(unsigned int& format, unsigned int& internalFormat, int& type, int const scalarType, int const noOfComponents); /** * Clean-up any acquired host side resources (image blocks, etc.). */ void ClearBlocks(); vtkVolumeTexture(const vtkVolumeTexture&) = delete; void operator=(const vtkVolumeTexture&) = delete; //@{ /** * @brief Helper functions to catch potential issues when doing GPU * texture allocations. * * They make use of the available OpenGL mechanisms to try to detect whether * a volume would not fit in the GPU (due to MAX_TEXTURE_SIZE limitations, * memory availability, etc.). */ bool AreDimensionsValid(vtkTextureObject* texture, int const width, int const height, int const depth); bool SafeLoadTexture(vtkTextureObject* texture, int const width, int const height, int const depth, int numComps, int dataType, void* dataPtr); //@} //---------------------------------------------------------------------------- vtkTextureObject* Texture; std::vector ImageDataBlocks; std::map ImageDataBlockMap; std::vector SortedVolumeBlocks; size_t CurrentBlockIdx; bool StreamBlocks; std::vector TextureSizes; Size6 FullExtent; Size3 FullSize; Size3 FullSizeAdjusted; /* Cell Adjusted */ Size3 Partitions; vtkDataArray* Scalars; vtkOpenGLGPUVolumeRayCastMapper* Mapper; }; #endif //vtkVolumeTexture_h