 /******************************************************************************
 * Copyright 2020 NVIDIA Corporation. All rights reserved.
 *****************************************************************************/
/// \file
/// \brief Asynchronous texture generation for use with shapes.

#ifndef NVIDIA_INDEX_IDISTRIBUTED_COMPUTE_DESTINATION_BUFFER_H
#define NVIDIA_INDEX_IDISTRIBUTED_COMPUTE_DESTINATION_BUFFER_H

#include <mi/dice.h>
#include <mi/base/interface_declare.h>

#include <nv/index/idistributed_data_subset.h>

#include <nv/index/iirregular_volume_subset.h>

#include <nv/index/isparse_volume_subset.h>

namespace nv {
namespace index {

/// The interface class enables the asynchronous generation of 2D texture
/// buffers and 3D volume data. Once the generation of compute-destination buffers
/// has been triggered, for example, by means of the interface class
/// \c IDistributed_compute_technique, the user-defined technique can populate the buffer
/// contents with the values required for later texture mapping and rendering.
/// Meanwhile, the rendering system may proceed to render datasets that
/// don't require a particular user-defined texturing technique.
///
/// In particular, the interface class enables leveraging designated compute
/// clusters for data generation while hiding the common network transfer and latency
/// issues.
///
/// If a compute-destination buffer has been filled the buffer can be made available to
/// the calling rendering system.
///
/// \ingroup nv_index_data_computing
///
class IDistributed_compute_destination_buffer :
    public mi::base::Interface_declare<0xfaae5c5,0x2701,0x442e,0x8f,0x77,0xe3,0x3,0xed,0xd,0x6f,0x5c>
{
public:
    /// The interface method returns the bounding box of the subregion for which
    /// the compute technique has been invoked. The rendering system
    /// initializes the bounding box that then can be accessed by an
    /// user-defined technique to control the texture generation.
    ///
    /// \return     The bounding box of the subregion, which is defined in the
    ///             global coordinate system.
    ///
    virtual mi::math::Bbox_struct<mi::Float32, 3>   get_subregion_bbox() const = 0;

    /// Returns the 2D area that the subregion covers in screen space. Based on
    /// the given screen-space area a user-defined technique can choose, for
    /// instance, the least compute-intensive generation technique.
    ///
    /// The rendering system computes and initializes the screen-space coverage.
    ///
    /// \return     The screen-space area that the subregion covers defined in
    ///             window coordinates.
    ///
    virtual mi::math::Bbox_struct<mi::Uint32, 2>    get_screen_space_area() const = 0;

    /// GPU-device id if the destination buffer is located on a GPU-device.
    ///
    /// \returns GPU-device id, negative values indicate that the data is currently not stored on any device.
    ///
    virtual mi::Sint32                              get_gpu_device_id() const = 0;

    /// 
    struct Compute_frame_id {
        mi::Uint32      frame_id;   ///< globally unique frame identifier
        mi::Uint32      scope_id;   ///< scope id the compute task is issued under
        mi::Uint32      host_id;    ///< host-id of the host issuing the compute task
    };

    /// Returns the frame-id the compute task was issued under
    ///
    virtual Compute_frame_id                        get_compute_frame_id() const = 0;

};

/// Compute-destination buffer for 3D volume generation techniques.
///
/// Upon applying an \c IDistributed_compute_technique attribute to a \c IRegular_volume scene element
/// a \c IDistributed_compute_destination_buffer_3d_volume is passed to the \c IDistributed_compute_technique::launch_compute()
/// method. In order to support type safe volume data generation typed specializations of this base
/// class are provided (e.g. \c IDistributed_compute_destination_buffer_3d_volume_uint8,
/// \c IDistributed_compute_destination_buffer_3d_volume_rgba8).
///
/// \ingroup nv_index_data_computing
///
class IDistributed_compute_destination_buffer_3d_volume :
    public mi::base::Interface_declare<0xcb42c8dd,0x4f80,0x4dc3,0x8a,0x20,0x98,0xe1,0x58,0x6,0x37,0x14,
                                       nv::index::IDistributed_compute_destination_buffer>
{
public:
    /// Transformation that should be applied on the written data.
    ///
    /// \note Experimental, subject to change!
    enum Data_transformation
    {
        DATA_TRANSFORMATION_NONE            = 0,  ///< Pass through unchanged
        DATA_TRANSFORMATION_FLIP_AXIS_ORDER = 1   ///< Change voxel storage order (x/y/z to z/y/x)
    };

    /// Returns the bounding box of the volume brick for which the compute technique
    /// is required to generate values. This bounding box includes border voxels
    /// of the volume brick.
    ///
    /// The rendering system computes and initializes the bounding box of the volume brick.
    ///
    /// \return     The bounding box of the volume brick, defined in non-normalized
    ///             volume coordinates.
    ///
    virtual mi::math::Bbox_struct<mi::Sint32, 3> get_volume_brick_bbox() const = 0;

    /// Returns the clipped bounding box of the volume brick for which the compute technique
    /// is required to generate values. This bounding box describes the part of the 
    /// complete volume brick which is potentially visible due to clipping the volume
    /// dataset by the global or volume defined regions of interest. This bounding box
    /// includes border voxels of the volume brick.
    ///
    /// The clipped bounding box describes the parts of the volume that are required to
    /// be written in order to achieve a consistent rendered image of the volume dataset.
    ///
    /// The rendering system computes and initializes the bounding box of the volume brick.
    ///
    /// \return     The clipped bounding box of the volume brick, defined in non-normalized
    ///             volume coordinates.
    ///
    virtual mi::math::Bbox_struct<mi::Sint32, 3> get_clipped_volume_brick_bbox() const = 0;

    /// Returns the bounding box of the volume brick for which the compute technique
    /// is required to generate values containing already computed voxel values.
    ///
    /// This bounding box can be used to reduce the computing workload when parts of
    /// the volume brick were already generated by a previous invocation of the compute
    /// technique, for instance when the global or volume defined regions of interest
    /// have changed.
    ///
    /// The rendering system computes and initializes the bounding box of the volume brick.
    ///
    /// \return     The bounding box of the volume brick containing already computed voxel
    ///             values, defined in non-normalized volume coordinates.
    ///
    virtual mi::math::Bbox_struct<mi::Sint32, 3> get_already_computed_volume_brick_bbox() const = 0;
};

/// Intermediate-interface class for all typed volume compute-destination buffer interfaces. According
/// to the actual dataset component type (e.g. Uint8, Uint16, Float32, Rgba8) the volume data can be
/// written to the destination buffer.
///
/// \ingroup nv_index_data_computing
///
template<typename T>
class IDistributed_compute_destination_buffer_3d_volume_typed :
    public mi::base::Interface_declare<0x7b12fdb4,0xd84c,0x40a2,0x9d,0x6f,0x24,0xda,0x8c,0xc1,0xdd,0x72,
                                       nv::index::IDistributed_compute_destination_buffer_3d_volume>
{
public:
    typedef T Value_type;

    /// Definition of internal buffer information.
    ///
    /// The internal buffer information can be queried using the \c get_internal_buffer_info() method
    /// to gain access to the internal buffer data for direct write operations. This enables zero-copy
    /// optimizations for implementations of \c IDistributed_compute_technique where large parts of the destination
    /// buffer can be written directly without going through the \c write() methods.
    ///
    /// \note The internal layout of the buffer of a volume brick is in a linear IJK layout with the
    ///       K-component running fastest.
    ///
    struct Internal_buffer_info
    {
        Value_type*     data;               ///< Typed pointer to internal buffer data.
        mi::Size        size;               ///< The size of the buffer in number of type elements.
        mi::Sint32      gpu_device_id;      ///< GPU device id if the buffer is located on a GPU device,
                                            ///< -1 to indicate a host buffer.
        bool            is_pinned_memory;   ///< Flag indicating if a host buffer is a pinned (page-locked)
                                            ///< memory area.
    };

public:
    /// Write a volume block to the destination buffer from a memory block in main memory.
    ///
    /// \param[in]  dst_range       Bounding box describing the offset and size of the volume
    ///                             block that will be written, defined in non-normalized
    ///                             volume coordinates.
    /// \param[in]  src_values      Source array of voxel values that will be written to
    ///                             this destination buffer.
    /// \param[in]  gpu_device_id   GPU device id if the passed buffer is located on a GPU device,
    ///                             otherwise this needs to be -1 to for a host memory buffer.
    /// \param[in]  transformation  Data transformation that should be applied while writing the
    ///                             volume block to the destination buffer.
    ///
    /// \returns                    True if the write operation was successful, false otherwise.
    ///
    virtual bool write(
        const mi::math::Bbox_struct<mi::Sint32, 3>& dst_range,
        const T*                                    src_values,
        mi::Sint32                                  gpu_device_id,
        Data_transformation                         transformation = DATA_TRANSFORMATION_NONE) = 0;

    /// Write a volume block to the destination buffer from a \c IRDMA_buffer.
    /// 
    /// \note The \c IRDMA_buffer can be located either in CPU or GPU memory. If a GPU-memory
    ///       buffer is passed additional memory copy operations may occur.
    ///
    /// \param[in]  dst_range       Bounding box describing the offset and size of the volume
    ///                             block that will be written, defined in non-normalized
    ///                             volume coordinates.
    /// \param[in]  src_rdma_buffer Source RDMA buffer of voxel values that will be written to
    ///                             this destination buffer.
    ///
    /// \returns                    True if the write operation was successful, false otherwise.
    ///
    virtual bool write(
        const mi::math::Bbox_struct<mi::Sint32, 3>& dst_range,
        const mi::neuraylib::IRDMA_buffer*          src_rdma_buffer) = 0;

    /// Write multiple volume blocks to the destination buffer from a single \c IRDMA_buffer.
    /// The packing of the volume sub-blocks to be written from the \c IRDMA_buffer is defined
    /// in the passed \c src_rdma_buffer_offsets parameter. It this parameter is 0, the volume
    /// sub-blocks need to be tightly packed after each other in the source buffer.
    /// 
    /// \note The \c IRDMA_buffer can be located either in CPU or GPU memory. If a GPU-memory
    ///       buffer is passed additional memory copy operations may occur.
    ///
    /// \param[in]  dst_ranges              Bounding boxes describing the offsets and sizes of the volume
    ///                                     blocks that will be written, defined in non-normalized
    ///                                     volume coordinates.
    /// \param[in]  nb_dst_ranges           The number of dst_range bounding boxes.
    /// \param[in]  src_rdma_buffer_offsets Array defining the offsets of the individual volume sub-blocks
    ///                                     in the linear source buffer. These offsets need to be defined
    ///                                     as numbers of typed elements according the the voxel type of
    ///                                     the volume brick. If this parameter is 0, the offsets will
    ///                                     be derived from the \c dst_ranges parameter assuming a tight
    ///                                     packing of the volume sub-blocks in the source buffer.
    /// \param[in]  src_rdma_buffer         Source RDMA buffer of voxel values that will be written to
    ///                                     this destination buffer.
    ///
    /// \returns                            True if the write operation was successful, false otherwise.
    ///
    virtual bool write_multiple(
        const mi::math::Bbox_struct<mi::Sint32, 3>* dst_ranges,
        mi::Uint32                                  nb_dst_ranges,
        const mi::Size*                             src_rdma_buffer_offsets,
        const mi::neuraylib::IRDMA_buffer*          src_rdma_buffer) = 0;

    /// Query the internal buffer information of the destination buffer instance to gain access
    /// to the internal buffer data for direct write operations.
    ///
    /// \returns                    An instance of \c Internal_buffer_info describing the internal
    ///                             buffer data for direct use.
    ///
    virtual Internal_buffer_info get_internal_buffer_info() const = 0;

    /// Creates an RDMA buffer that is a wrapper for of the internal buffer.
    ///
    /// \param[in]  rdma_ctx        The RDMA context used for wrapping the internal buffer.
    ///
    /// \returns                    he RDMA buffer wrapping the internal buffer data,
    ///                             or 0 in case of failure.
    ///
    virtual mi::neuraylib::IRDMA_buffer* wrap_internal_buffer(mi::neuraylib::IRDMA_context* rdma_ctx) const = 0;
};

/// Single-channel 8bit unsigned per voxel volume compute destination buffer.
///
/// \ingroup nv_index_data_computing
///
class IDistributed_compute_destination_buffer_3d_volume_uint8 :
    public mi::base::Interface_declare<0x45065a39,0xa261,0x453f,0xa7,0xb4,0x1,0x25,0xae,0x9c,0x4,0x4f,
                                       IDistributed_compute_destination_buffer_3d_volume_typed<mi::Uint8> >
{};

/// Single-channel 16bit unsigned per voxel volume compute destination buffer.
///
/// \ingroup nv_index_data_computing
///
class IDistributed_compute_destination_buffer_3d_volume_uint16 :
    public mi::base::Interface_declare<0x9fd3ee6d,0x34ad,0x4bc0,0xa2,0x16,0x65,0xb2,0xb7,0x1e,0x3b,0x96,
                                       IDistributed_compute_destination_buffer_3d_volume_typed<mi::Uint16> >
{};

/// Single-channel 32bit floating point per voxel volume compute destination buffer.
///
/// \ingroup nv_index_data_computing
///
class IDistributed_compute_destination_buffer_3d_volume_float32 :
    public mi::base::Interface_declare<0xe8347ed0,0x7980,0x4ae8,0xa1,0xf3,0x4b,0x50,0xd6,0xa,0xcd,0x24,
                                       IDistributed_compute_destination_buffer_3d_volume_typed<mi::Float32> >
{};

/// Four-channel 8bit per channel unsigned integer per voxel volume compute destination buffer.
///
/// \ingroup nv_index_data_computing
///
class IDistributed_compute_destination_buffer_3d_volume_rgba8 :
    public mi::base::Interface_declare<0xffb5524d,0xc006,0x41e9,0x9e,0x99,0xfc,0x6e,0xd0,0xb,0x38,0x10,
                                       IDistributed_compute_destination_buffer_3d_volume_typed<mi::math::Vector_struct<mi::Uint8, 4> > >
{};

/// Compute-destination buffer for 3D sparse-volume generation techniques.
///
/// Upon applying an \c IDistributed_compute_technique attribute to a \c ISparse_volume_scene_element scene element
/// a \c IDistributed_compute_destination_buffer_3d_sparse_volume is passed to the \c IDistributed_compute_technique::launch_compute()
/// method.
///
/// \ingroup nv_index_data_computing
///
class IDistributed_compute_destination_buffer_3d_sparse_volume :
    public mi::base::Interface_declare<0x9da831bb,0x8425,0x4590,0xaa,0x10,0x8,0xcc,0x8d,0x5f,0x90,0xc1,
                                       nv::index::IDistributed_compute_destination_buffer>
{
public:
    /// Returns the bounding box of the volume subset for which the compute technique
    /// is required to generate values.
    ///
    /// The rendering system computes and initializes the bounding box of the volume subset.
    ///
    /// \return     The bounding box of the volume subset, defined in non-normalized
    ///             volume coordinates.
    ///
    virtual mi::math::Bbox_struct<mi::Sint32, 3> get_volume_subset_data_bbox() const = 0;

    /// Returns the clipped bounding box of the volume subset for which the compute technique
    /// is required to generate values. This bounding box describes the part of the 
    /// complete volume subset which is potentially visible due to clipping the volume
    /// dataset by the global or volume defined clip-regions.
    ///
    /// The clipped bounding box describes the parts of the volume that are required to
    /// be written in order to achieve a consistent rendered image of the volume dataset.
    ///
    /// The rendering system computes and initializes the bounding box of the volume subset.
    ///
    /// \return     The clipped bounding box of the volume subset, defined in non-normalized
    ///             volume coordinates.
    ///
    virtual mi::math::Bbox_struct<mi::Sint32, 3> get_clipped_volume_subset_data_bbox() const = 0;

    /// Returns the bounding box of the volume subset for which the compute technique
    /// is required to generate values containing already computed voxel values.
    ///
    /// This bounding box can be used to reduce the computing workload when parts of
    /// the volume subset were already generated by a previous invocation of the compute
    /// technique, for instance when the global or volume defined regions of interest
    /// have changed.
    ///
    /// The rendering system computes and initializes the bounding box of the volume subset.
    ///
    /// \return     The bounding box of the volume subset containing already computed voxel
    ///             values, defined in non-normalized volume coordinates.
    ///
    virtual mi::math::Bbox_struct<mi::Sint32, 3> get_already_computed_volume_subset_data_bbox() const = 0;

    /// Returns the volume data-subset for which the compute technique is required to
    /// generate voxel values.
    ///
    /// \return     An interface pointer to an instance of \c ISparse_volume_subset.
    ///
    virtual ISparse_volume_subset* get_distributed_data_subset() = 0;
};

/// Compute-destination buffer for irregular volume generation techniques.
///
/// Upon applying an \c IDistributed_compute_technique attribute to a \c IIrregular_volume_scene_element scene element
/// a \c IDistributed_compute_destination_buffer_irregular_volume is passed to the \c IDistributed_compute_technique::launch_compute()
/// method.
///
/// \ingroup nv_index_data_computing
///
class IDistributed_compute_destination_buffer_irregular_volume :
    public mi::base::Interface_declare<0x384f6eca,0xd09c,0x47a1,0xa0,0x91,0x1e,0x5f,0xc3,0xfb,0x47,0x6,
                                       nv::index::IDistributed_compute_destination_buffer>
{
public:
    /// Returns the bounding box of the volume subset for which the compute technique
    /// is required to generate values.
    ///
    /// The rendering system computes and initializes the bounding box of the volume subset.
    ///
    /// \return     The bounding box of the volume subset, defined in non-normalized
    ///             volume coordinates.
    ///
    virtual mi::math::Bbox_struct<mi::Float32, 3> get_volume_subset_data_bbox() const = 0;

    /// Returns the volume data-subset for which the compute technique is required to
    /// generate data values.
    ///
    /// \return     An interface pointer to an instance of \c IIrregular_volume_subset.
    ///
    virtual IIrregular_volume_subset* get_distributed_data_subset() = 0;
};

/// The interface class exposes intersections points that can be used, for
/// instance, to texture or shade the surface of geometry.
///
/// The IndeX library implements the serializable interface, which enables
/// user-defined classes to distribute an instance of the class to different
/// hosts in the cluster environment using DiCE's serialization and
/// deserialization mechanism.  Furthermore, the interface class exposes the
/// intersections points through the interface method
/// generate_intersection_points(). The internal implementation of this method
/// creates the intersection points on the fly whenever the method is
/// called. That is, all the intersection points never need to be communicated
/// to nodes in the cluster. Instead, the instance of the interface class itself
/// is sent to compute the intersection points on the remote machines on
/// request.
///
/// \ingroup nv_index_data_computing
///
class IDistributed_compute_intersection_points :
    public mi::base::Interface_declare<0xd985cb6a,0xe5c2,0x4c40,0x95,0xe3,0x29,0xa7,0x22,0x3e,0x35,0x9f,
                                       mi::neuraylib::ISerializable>
{
public:
    /// The interface method computes the intersections of rays with the
    /// geometry and returns a buffer of all intersection points to a
    /// user-defined computing class.  The renderer computes the intersection
    /// points based on the present viewing parameters so that all intersection
    /// points match the internal rendering.
    ///
    /// \param[out] nb_points The number of intersection points returned by the
    ///                       interface call.
    ///
    /// \return               The intersection points. They are defined in the local
    ///                       coordinate system of the geometry, that is, x and
    ///                       y will be in the range [0, extent], while the
    ///                       z-component will be 0. The ownership remains with the
    ///                       interface class.
    ///
    virtual const mi::math::Vector_struct<mi::Float32, 3>* generate_intersection_points(
        mi::Uint32& nb_points) = 0;
};

/// Compute-destination buffer for 2D texture generation techniques.
///
/// Upon applying an \c IDistributed_compute_technique attribute to a \c IPlane or \c IRegular_heightfield scene element
/// a \c IDistributed_compute_destination_buffer_2d_texture is passed to the \c IDistributed_compute_technique::launch_compute()
/// method.
///
/// Based on the 2D area returned by \c get_screen_space_area() a user-defined compute technique can choose, for
/// instance, an appropriate level-of-detail or the least compute-intensive generation technique, for example,
/// by either rendering into a 2D buffer or a buffer that corresponds to the ray/geometry intersection.
///
/// \ingroup nv_index_data_computing
///
class IDistributed_compute_destination_buffer_2d_texture :
    public mi::base::Interface_declare<0x1ea87c20,0xdae0,0x4b81,0xa3,0x16,0xa0,0x52,0x2d,0xf7,0xb4,0x3c,
                                       nv::index::IDistributed_compute_destination_buffer>
{
public:
    /// The layout of the buffer.
    ///
    /// The buffer's layout is defined by the user-defined texture generation
    /// technique.
    ///
    /// Setting the buffer layout to \c TWO_DIMENSIONAL_ARRAY is in most
    /// situations the most appropriate way to represent a texture tile. Then,
    /// all texture values are stored in consecutive order in x-first and y-last
    /// order and the value x=0 and y=0 represents the lower left texture value
    /// of the texture tile.
    ///
    /// The texture generation technique could set the layout to \c
    /// ONE_DIMENSIONAL_ARRAY to indicate that every entry in the texture buffer
    /// corresponds to a texture value for precomputed ray/object
    /// intersection. A ray/object intersection is only meaningful if the screen
    /// space area covered by the subregion is small compared to the size of the
    /// tile.
    ///
    enum Buffer_layout
    {
        ONE_DIMENSIONAL_ARRAY = 0,  ///< Buffer layout that corresponds to a 1D array of ray/geometry intersections
        TWO_DIMENSIONAL_ARRAY = 1   ///< Buffer layout that corresponds to a 2D array
    };

    /// Texture destination buffer format description.
    ///
    /// The buffer format defines the type and number of components of each texture element.
    ///
    enum Buffer_format
    {
        INTENSITY_UINT8 = 0,        ///< 8-bit integer used for indexing a color table of 256 entries
        RGBA_UINT8      = 1,        ///< 8-bit integer per RGBA component
        RGBA_FLOAT32    = 2         ///< 32-bit float per RGBA component
    };

    /// Texture buffer configuration.
    ///
    /// This structure defines the basic buffer parameters required by the rendering system to
    /// allocate the required buffer storage (see \c generate_buffer_storage).
    ///
    /// The covered area is the 2D area of the geometry's surface that a 2D texture tile covers.
    /// The covered area is typically larger than the object's surface area because the returned
    /// 2D tile has to have integral width and height resolution while the surface area is given
    /// in floating point values. (See \c get_surface_area().)
    ///
    /// The associated compute technique has to compute and set the covered area. The covered area
    /// is required to enable the calling rendering system to compute the texture coordinates to
    /// correctly texture map the tile onto the geometry's 2D surface area.
    ///
    /// If the texture buffer layout specifies a 2D array, then the 2D resolution of the 2D tile needs
    /// to be specified. The resolution needs to be known to the calling rendering system to enable
    /// valid accesses to the texture's 2D array.
    ///
    /// If the texture buffer layout specifies an array of isolated texture values, then the resolution
    /// needs to be specified as (number of intersection points, 0) and each buffer entry at the end needs
    /// to correspond to exactly one intersection point and the number of texture values has to correspond to
    /// the number of intersections.
    ///
    struct Buffer_config
    {
        Buffer_layout                           layout;
        /// Texture destination buffer format.
        Buffer_format                           format;
        mi::math::Bbox_struct<mi::Float32, 2>   covered_area;
        mi::math::Vector_struct<mi::Uint32, 2>  resolution;
    };

    /// Generate buffer storage.
    ///
    /// This function initializes the buffer storage according to the passed instance of \c Buffer_config.
    /// At any point during the lifetime of an \c IDistributed_compute_destination_buffer_2d_texture instance there can only be a
    /// single valid buffer storage. Multiple calls to this function will invalidate previous instances of the buffer
    /// storage and generate a new valid instance according the newly passed buffer config.
    ///
    /// \param[in]  buffer_cfg      The texture buffer config parameters.
    ///
    /// \return                     True if a valid storage was generated, false otherwise.
    ///
    virtual bool generate_buffer_storage(const Buffer_config& buffer_cfg) = 0;

    /// Get the texture buffer config parameters of the currently valid buffer storage.
    ///
    /// When this function is called before initializing a valid buffer storage (\c generate_buffer_storage()) the
    /// returned instance of \c Buffer_config will describe an invalid mesh (i.e. covered_area and resolution will
    /// describe an empty buffer).
    ///
    /// \return     The texture buffer config parameters of the currently valid buffer storage.
    /// 
    virtual const Buffer_config& get_buffer_config() const = 0;

    /// Get the current valid texture buffer storage.
    ///
    /// When this function is called before initializing a valid buffer storage (\c generate_buffer_storage()) the 
    /// returned value will be invalid (i.e. value \c 0). The ownership with the returned buffer remains with
    /// the instance of \c IDistributed_compute_destination_buffer_2d_texture.
    ///
    /// \return     The currently valid texture buffer storage.
    ///
    virtual mi::Uint8* get_buffer_storage() const = 0;

    /// Returns the per-subregion data of the geometry associated with this
    /// buffer.  The data type depends on the type of geometry:
    /// - For heightfields, the data type is \c IRegular_heightfield_patch,
    ///   which allows access to individual height values.
    /// - Planes do not provide per-subregion data.
    ///
    /// \return Per-subregion data or 0 if no data is available.
    virtual const IDistributed_data_subset* get_subregion_geometry_data() const = 0;


    /// Returns the 2D surface area for which the generation of the texture
    /// buffer is requested.
    ///
    /// It is not required that the texture generation technique computes a
    /// texture that covers the 2D area exactly, but the texture usually is
    /// slightly larger. For that, the covered area has to be set appropriately
    /// by the user-defined texturing technique. (See set_covered_area().)
    ///
    /// \return The 2D area that shall be textured by the returned texture.  The
    ///         area is defined in the object's local coordinate system.
    ///
    virtual mi::math::Bbox_struct<mi::Float32, 2> get_surface_area() const = 0;

    /// The texture generation can rely on pre-computed ray/geometry
    /// intersections. The interface method exposes all ray/geometry
    /// intersection points with respect to the given subregion. The
    /// intersection points enable the technique to compute the corresponding
    /// texture values.
    ///
    /// \return An instance of the class \c IDistributed_compute_intersection_points that contains all
    ///         ray/geometry intersection points given in the object's local
    ///         coordinate system. The caller is responsible to releasing the
    ///         object.
    ///
    virtual IDistributed_compute_intersection_points* get_intersection_points() const = 0;
};

/// \todo Documentation missing.
///
/// \ingroup nv_index_data_computing
///
class IDistributed_compute_destination_buffer_2d_texture_LOD_configuration :
    public mi::base::Interface_declare<0xfb33be9,0x8b65,0x400d,0xb3,0xfe,0xc2,0x3a,0x47,0x2d,0x4e,0xcf>
{
public:
    struct LOD_level_info
    {
        mi::math::Vector_struct<mi::Uint32, 2>  mip_level_image_resolution;     ///< Image resolution for specified mipmap-level
        mi::math::Bbox_struct<mi::Uint32, 2>    mip_level_image_tile_bounds;    ///< Image-tile bounds for specified mipmap-level
        mi::Float32                             mip_level_selection_distance;   ///< World-distance for selection of specified mipmap-level
    };

    /// Number of mipmap-levels in the configuration
    virtual mi::Uint32 get_nb_mipmap_levels() const = 0;
    virtual void set_nb_mipmap_levels(mi::Uint32 nb_mipmaps) = 0;

    virtual LOD_level_info get_mip_level_info(mi::Uint32 mip_level) const = 0;
    virtual void set_mip_level_info(
        mi::Uint32            mip_level,
        const LOD_level_info& mip_level_info) = 0;
};

/// Compute-destination buffer for 2D LOD-texture generation techniques.
/// 
/// Upon applying an \c IDistributed_compute_technique_LOD attribute to a \c
/// IPlane scene element a \c
/// IDistributed_compute_destination_buffer_2d_texture_LOD is passed to the \c
/// IDistributed_compute_technique::launch_compute() method.
/// 
/// Based on a \c
/// IDistributed_compute_destination_buffer_2d_texture_LOD_configuration, either
/// generated through the \c generate_LOD_configuration() method as the best
/// fitting proposal from NVIDIA IndeX or entirely defined by the user-defined
/// compute-technique, an instance of this class is configured by setting up the
/// LOD-buffer storage (\c generate_LOD_buffer_storage()). This configuration is
/// used by NVIDIA IndeX to request actually required mipmap-levels for a compute-
/// texture tile. The actual required mipmap-levels directly depend on the
/// current camera and view on the current scene.
/// 
/// It is possible that an existing, in a previous \c
/// IDistributed_compute_technique::launch_compute() configured, instance of this
/// class is again passed into the \c
/// IDistributed_compute_technique::launch_compute() method in order to fill in
/// missing, previously not required mipmap-level data. In such cases the method
/// \c is_LOD_buffer_storage_initialized() should be used to prevent re-
/// initialization of internal texture-data storage and repeated texture-mipmap
/// data inputs.
/// 
/// This class also allows a user-defined implementation to set an active LOD-
/// level range if it does not want to send certain mipmap-level data to NVIDIA
/// IndeX. For example, for previewing a certain compute-technique it may be
/// desired to first send low-resolution data to preview preliminary compute
/// results before generating and sending the high-resolution data. For such use-
/// cases the \c set_active_LOD_level_range() method can be used to limit the
/// active LOD-range.
/// 
/// After configuring the destination buffer and potentially setting the active
/// LOD-range the actually required compute-tile mipmap-levels can be queried
/// using the \c get_required_LOD_levels() method. The requested data can then be
/// written to the data-buffer returned by the \c get_LOD_level_buffer_storage()
/// method.
///
/// \ingroup nv_index_data_computing
///
class IDistributed_compute_destination_buffer_2d_texture_LOD :
    public mi::base::Interface_declare<0xb25d2721,0xab95,0x450c,0x8d,0x64,0xd0,0xc5,0xd1,0xaa,0xac,0xca,
                                       nv::index::IDistributed_compute_destination_buffer>
{
public:
    /// Texture destination buffer format description.
    ///
    /// The buffer format defines the type and number of components of each texture element.
    ///
    enum Buffer_format
    {
        FORMAT_INVALID          = 0x00,
        FORMAT_SCALAR_UINT8     = 0x01,        ///< 8-bit integer used for indexing a color table of 256 entries
        FORMAT_RGBA_UINT8       = 0x02,        ///< 8-bit integer per RGBA component
        FORMAT_RGBA_FLOAT32     = 0x03         ///< 32-bit float per RGBA component
    };

    /// Generate an instance of \c IDistributed_compute_destination_buffer_2d_texture_LOD_configuration.
    /// 
    /// The returned instance of the LOD-configuration can directly be used to
    /// configure and generate the internal LOD-buffer storage (\c
    /// generate_LOD_buffer_storage()), or a user-defined compute-technique can fill
    /// in custom requirements to the LOD-configuration before configuring the
    /// storage.
    /// 
    /// \note   In order to ensure correct memory management and reference counting
    ///         use \c mi::base::Handle to manage the lifetime of the returned interface
    ///         pointer.
    /// 
    /// \param [in] global_texture_resolution   The global texture resulution for which to
    ///                                         generate the compute-texture tile LOD-
    ///                                         configuration.
    /// \param [in] texture_tile_surface_area   The tile-surface area for which to generate
    ///                                         the compute-texture tile LOD-configuration.
    ///                                         This usually corresponds to the values
    ///                                         returned but the \c get_surface_area() method.
    /// \param [in] texture_tile_border         In order to allow for the implementation of
    ///                                         custom filter-kernels in rendering kernel
    ///                                         programs it may be required to have an
    ///                                         overlapping border between compute-texture
    ///                                         tile data. This allows a user-defined compute-
    ///                                         technique to directly set the required tile
    ///                                         border.
    ///
    /// \return A valid interface-pointer to an instance of \c
    ///         IDistributed_compute_destination_buffer_2d_texture_LOD_configuration. In case
    ///         of failure a 0-pointer is returned.
    ///
    virtual IDistributed_compute_destination_buffer_2d_texture_LOD_configuration* generate_LOD_configuration(
        const mi::math::Vector_struct<mi::Uint32, 2>& global_texture_resolution,
        const mi::math::Bbox_struct<mi::Float32, 2>&  texture_tile_surface_area,
        mi::Uint32                                    texture_tile_border) const = 0;

    /// \brief Generate LOD-buffer storage.
    ///        
    /// This function initializes the buffer storage according to the passed instance
    /// of \c IDistributed_compute_destination_buffer_2d_texture_LOD_configuration
    /// and the requested \c Buffer_format. At any point during the lifetime of an \c
    /// IDistributed_compute_destination_buffer_2d_texture_LOD instance there can
    /// only be a single valid buffer storage. Multiple calls to this function will
    /// invalidate previous instances of the buffer storage and generate a new valid
    /// instance according the newly passed configuration.
    /// 
    /// \param [in] lod_config                  The LOD-configuration parameters.
    /// \param [in] texture_buffer_format       The texture buffer format.
    ///             
    /// \return     True if a valid storage was generated, false otherwise.
    ///         
    virtual bool generate_LOD_buffer_storage(
        const IDistributed_compute_destination_buffer_2d_texture_LOD_configuration* lod_config,
        Buffer_format                                                               texture_buffer_format) = 0;

    /// Query if the LOD-buffer storage is initialized.
    ///
    /// \returns    True if a valid storage is initialized, false otherwise.
    ///             
    virtual bool is_LOD_buffer_storage_initialized() const = 0;

    /// \brief Returns the currently active \c IDistributed_compute_destination_buffer_2d_texture_LOD_configuration.
    /// 
    /// \note   In order to ensure correct memory management and reference counting use
    ///         \c mi::base::Handle to manage the lifetime of the returned interface pointer.
    ///            
    /// \return The currently active \c
    ///         IDistributed_compute_destination_buffer_2d_texture_LOD_configuration, or a 0-
    ///         pointer if the current storage was not yet configured.
    ///         
    virtual const IDistributed_compute_destination_buffer_2d_texture_LOD_configuration* get_active_LOD_configuration() const = 0;


    /// Returns the currently active \c Buffer_format.
    /// 
    /// \returns The currently active \c Buffer_format, or a \c FORMAT_INVALID if the
    ///          current storage was not yet configured.
    /// 
    virtual Buffer_format get_texture_buffer_format() const = 0;

    /// Set the active LOD-level range to be used by NVIDIA IndeX.
    /// 
    /// The active LOD-level range limits the data NVIDIA IndeX is requesting to be written
    /// to this LOD-texture instance and accesses during rendering.
    /// 
    /// \param[in]  lod_level_range     The LOD-range to be used by NVIDIA IndeX.
    ///             
    virtual void set_active_LOD_level_range(
        const mi::math::Vector_struct<mi::Uint32, 2>& lod_level_range) = 0;

    /// Returns the currently active LOD-level range to be used by NVIDIA IndeX.
    /// 
    /// \returns    The currently active LOD-level range.
    /// 
    virtual mi::math::Vector_struct<mi::Uint32, 2>  get_active_LOD_level_range() const = 0;

    /// Query the required LOD-levels for which to generate and write data to this LOD-texture instance.
    /// 
    /// \param[out] nb_required_levels          The number of required LOD-levels.
    /// \param[out] required_levels             An array containing the required LOD-level indices.
    /// 
    virtual void get_required_LOD_levels(
        mi::Uint32&  nb_required_levels,
        mi::Uint32*& required_levels) const = 0;

    /// Query the currently valid texture buffer storage for a particular compute-tile LOD-level.
    /// 
    /// When this function is called before initializing a valid buffer storage (\c generate_LOD_buffer_storage()) the
    /// returned value will be invalid (i.e. value \c 0). The ownership with the returned buffer remains with
    /// the instance of \c IDistributed_compute_destination_buffer_2d_texture_LOD.
    ///
    /// \param[in]  lod_level                   The LOD-level for which to return the valid storage pointer.
    ///             
    /// \return     The currently valid texture buffer storage for the requested LOD-level.
    ///
    virtual mi::Uint8* get_LOD_level_buffer_storage(
        mi::Uint32 lod_level) = 0;

    /// Returns the per-subregion data of the geometry associated with this
    /// buffer.  The data type depends on the type of geometry:
    /// - For heightfields, the data type is \c IRegular_heightfield_patch,
    ///   which allows access to individual height values.
    /// - Planes do not provide per-subregion data.
    ///
    /// \return Per-subregion data or 0 if no data is available.
    virtual const IDistributed_data_subset* get_subregion_geometry_data() const = 0;

    /// Returns the 2D surface area for which the generation of the texture
    /// buffer is requested.
    ///
    /// It is not required that the texture generation technique computes a
    /// texture that covers the 2D area exactly, but the texture usually is
    /// slightly larger. For that, the covered area has to be set appropriately
    /// by the user-defined texturing technique. (See set_covered_area().)
    ///
    /// \return The 2D area that shall be textured by the returned texture.  The
    ///         area is defined in the object's local coordinate system.
    ///
    virtual mi::math::Bbox_struct<mi::Float32, 2> get_surface_area() const = 0;
};

} // namespace index
} // namespace nv

#endif // NVIDIA_INDEX_IDISTRIBUTED_COMPUTE_DESTINATION_BUFFER_H
