1 /*=========================================================================
2 
3   Program:   Visualization Toolkit
4   Module:    vtkDataTransferHelper.h
5 
6   Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
7   All rights reserved.
8   See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
9 
10      This software is distributed WITHOUT ANY WARRANTY; without even
11      the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
12      PURPOSE.  See the above copyright notice for more information.
13 
14 =========================================================================*/
15 /**
16  * @class   vtkDataTransferHelper
17  * @brief   is a helper class that aids in transferring
18  *  data between CPU memory and GPU memory.
19  *
20  *
21  *  vtkDataTransferHelper is a helper class that aids in transferring data
22  *  between the CPU memory and the GPU memory. The data in GPU memory is
23  *  stored as textures which that in CPU memory is stored as vtkDataArray.
24  *  vtkDataTransferHelper provides API to transfer only a sub-extent of CPU
25  *  structured data to/from the GPU.
26  *
27  * @sa
28  *  vtkPixelBufferObject vtkTextureObject vtkOpenGLExtensionManager
29  */
30 
31 #ifndef vtkDataTransferHelper_h
32 #define vtkDataTransferHelper_h
33 
34 #include "vtkObject.h"
35 #include "vtkRenderingOpenGL2Module.h" // For export macro
36 #include "vtkSmartPointer.h"           // needed for vtkSmartPointer.
37 #include "vtkWeakPointer.h"            // needed for vtkWeakPointer.
38 
39 class vtkDataArray;
40 class vtkPixelBufferObject;
41 class vtkTextureObject;
42 class vtkRenderWindow;
43 
44 class VTKRENDERINGOPENGL2_EXPORT vtkDataTransferHelper : public vtkObject
45 {
46 public:
47   static vtkDataTransferHelper* New();
48   vtkTypeMacro(vtkDataTransferHelper, vtkObject);
49   void PrintSelf(ostream& os, vtkIndent indent) override;
50 
51   ///@{
52   /**
53    * Get/Set the context. Context must be a vtkOpenGLRenderWindow.
54    * This does not increase the reference count of the
55    * context to avoid reference loops.
56    * SetContext() may raise an error if the OpenGL context does not support the
57    * required OpenGL extensions.
58    */
59   void SetContext(vtkRenderWindow* context);
60   vtkRenderWindow* GetContext();
61   ///@}
62 
63   ///@{
64   /**
65    * Set the CPU data extent. The extent matches the vtkDataArray size.
66    * If the vtkDataArray comes from an vtkImageData and it is part of the
67    * point data, it is usually the vtkImageData extent.
68    * It can be on cell data too, but in this case it does not match the
69    * vtkImageData extent.
70    * If the vtkDataArray comes from a vtkDataSet, just
71    * set it to a one-dimenstional extent equal to the number of tuples.
72    * Initial value is (0,0,0,0,0,0), a valid one tuple array.
73    */
74   vtkSetVector6Macro(CPUExtent, int);
75   vtkGetVector6Macro(CPUExtent, int);
76   ///@}
77 
78   ///@{
79   /**
80    * Set the GPU data extent. This is the sub-extent to copy from or to the GPU.
81    * This extent matches the size of the data to transfer.
82    * GPUExtent and TextureExtent don't have to match (GPUExtent can be 1D
83    * whereas TextureExtent is 2D) but the number of elements have to match.
84    * Initial value is (0,0,0,0,0,0), a valid one tuple array.
85    */
86   vtkSetVector6Macro(GPUExtent, int);
87   vtkGetVector6Macro(GPUExtent, int);
88   ///@}
89 
90   ///@{
91   /**
92    * Set the texture data extent. This is the extent of the texture image that
93    * will receive the data. This extent matches the size of the data to
94    * transfer. If it is set to an invalid extent, GPUExtent is used.
95    * See more comment on GPUExtent.
96    * Initial value is an invalid extent.
97    */
98   vtkSetVector6Macro(TextureExtent, int);
99   vtkGetVector6Macro(TextureExtent, int);
100   ///@}
101 
102   /**
103    * Tells if the given extent (6 int) is valid. True if min
104    * extent<=max extent.
105    * \pre extent_exists: extent!=0
106    */
107   bool GetExtentIsValid(int* extent);
108 
109   /**
110    * Tells if CPUExtent is valid. True if min extent<=max extent.
111    */
112   bool GetCPUExtentIsValid();
113 
114   /**
115    * Tells if GPUExtent is valid. True if min extent<=max extent.
116    */
117   bool GetGPUExtentIsValid();
118 
119   /**
120    * Tells if TextureExtent is valid. True if min extent<=max extent.
121    */
122   bool GetTextureExtentIsValid();
123 
124   ///@{
125   /**
126    * Define the minimal dimension of the texture regardless of the dimensions
127    * of the TextureExtent. Initial value is 1.
128    * A texture extent can have a given dimension 0D (one value), 1D, 2D or 3D.
129    * By default 0D and 1D are translated into a 1D texture, 2D is translated
130    * into a 2D texture, 3D is translated into a 3D texture. To make life easier
131    * when writing GLSL code and use only one type of sampler (ex: sampler2d),
132    * the default behavior can be changed by forcing a type of texture with
133    * this ivar.
134    * 1: default behavior. Initial value.
135    * 2: force 0D and 1D to be in a 2D texture
136    * 3: force 0D, 1D and 2D texture to be in a 3D texture.
137    */
138   vtkSetMacro(MinTextureDimension, int);
139   vtkGetMacro(MinTextureDimension, int);
140   ///@}
141 
142   ///@{
143   /**
144    * Get/Set the CPU data buffer. Initial value is 0.
145    */
146   vtkGetObjectMacro(Array, vtkDataArray);
147   void SetArray(vtkDataArray* array);
148   ///@}
149 
150   ///@{
151   /**
152    * Get/Set the GPU data buffer. Initial value is 0.
153    */
154   vtkGetObjectMacro(Texture, vtkTextureObject);
155   void SetTexture(vtkTextureObject* texture);
156   ///@}
157 
158   /**
159    * Old comment.
160    * Upload Extent from CPU data buffer to GPU.
161    * The WholeExtent must match the Array size.
162    * New comment.
163    * Upload GPUExtent from CPU vtkDataArray to GPU texture.
164    * It is possible to send a subset of the components or to specify and
165    * order of components or both. If components=0, componentList is ignored
166    * and all components are passed, a texture cannot have more than 4
167    * components.
168    * \pre array_exists: array!=0
169    * \pre array_not_empty: array->GetNumberOfTuples()>0
170    * \pre valid_cpu_extent: this->GetCPUExtentIsValid()
171    * \pre valid_cpu_extent_size:
172    * (CPUExtent[1]-CPUExtent[0]+1)*(CPUExtent[3]-CPUExtent[2]+1)*(CPUExtent[5]-CPUExtent[4]+1)==array->GetNumberOfTuples()
173    * \pre valid_gpu_extent: this->GetGPUExtentIsValid()
174    * \pre gpu_extent_in_cpu_extent: CPUExtent[0]<=GPUExtent[0] && GPUExtent[1]<=CPUExtent[1] &&
175    * CPUExtent[2]<=GPUExtent[2] && GPUExtent[3]<=CPUExtent[3] && CPUExtent[4]<=GPUExtent[4] &&
176    * GPUExtent[5]<=CPUExtent[5] \pre gpu_texture_size: !this->GetTextureExtentIsValid() ||
177    * (GPUExtent[1]-GPUExtent[0]+1)*(GPUExtent[3]-GPUExtent[2]+1)*(GPUExtent[5]-GPUExtent[4]+1)==(TextureExtent[1]-TextureExtent[0]+1)*(TextureExtent[3]-TextureExtent[2]+1)*(TextureExtent[5]-TextureExtent[4]+1)
178    * \pre texture_can_exist_or_not: texture==0 || texture!=0
179    * \pre valid_components: (components==0 && componentList==0 && array->GetNumberOfComponents()<=4)
180    * || (components>=1 && components<=array->GetNumberOfComponents() && components<=4 &&
181    * componentList!=0)
182    */
183   bool Upload(int components = 0, int* componentList = nullptr);
184 
185   /**
186    * old comment:
187    * Download Extent from GPU data buffer to CPU.
188    * GPU data size must exactly match Extent.
189    * CPU data buffer will be resized to match WholeExtent in which only the
190    * Extent will be filled with the GPU data.
191    * new comment:
192    * Download GPUExtent from GPU texture to CPU vtkDataArray.
193    * If Array is not provided, it will be created with the size of CPUExtent.
194    * But only the tuples covered by GPUExtent will be download. In this case,
195    * if GPUExtent does not cover all GPUExtent, some of the vtkDataArray will
196    * be uninitialized.
197    * Reminder: A=>B <=> !A||B
198    * \pre texture_exists: texture!=0
199    * \pre array_not_empty: array==0 || array->GetNumberOfTuples()>0
200    * \pre valid_cpu_extent: this->GetCPUExtentIsValid()
201    * \pre valid_cpu_extent_size: array==0 ||
202    * (CPUExtent[1]-CPUExtent[0]+1)*(CPUExtent[3]-CPUExtent[2]+1)*(CPUExtent[5]-CPUExtent[4]+1)==array->GetNumberOfTuples()
203    * \pre valid_gpu_extent: this->GetGPUExtentIsValid()
204    * \pre gpu_extent_in_cpu_extent: CPUExtent[0]<=GPUExtent[0] && GPUExtent[1]<=CPUExtent[1] &&
205    * CPUExtent[2]<=GPUExtent[2] && GPUExtent[3]<=CPUExtent[3] && CPUExtent[4]<=GPUExtent[4] &&
206    * GPUExtent[5]<=CPUExtent[5] \pre gpu_texture_size: !this->GetTextureExtentIsValid() ||
207    * (GPUExtent[1]-GPUExtent[0]+1)*(GPUExtent[3]-GPUExtent[2]+1)*(GPUExtent[5]-GPUExtent[4]+1)==(TextureExtent[1]-TextureExtent[0]+1)*(TextureExtent[3]-TextureExtent[2]+1)*(TextureExtent[5]-TextureExtent[4]+1)
208    * \pre valid_components: array==0 || array->GetNumberOfComponents()<=4
209    * \pre components_match: array==0 || (texture->GetComponents()==array->GetNumberOfComponents())
210    */
211   bool Download();
212 
213   ///@{
214   /**
215    * Splits the download in two operations
216    * * Asynchronously download from texture memory to PBO (DownloadAsync1()).
217    * * Copy from pbo to user array (DownloadAsync2()).
218    */
219   bool DownloadAsync1();
220   bool DownloadAsync2();
221   ///@}
222 
223   bool GetShaderSupportsTextureInt();
224   void SetShaderSupportsTextureInt(bool value);
225 
226   /**
227    * Returns if the context supports the required extensions.
228    */
229   static bool IsSupported(vtkRenderWindow* renWin);
230 
231 protected:
232   vtkDataTransferHelper();
233   ~vtkDataTransferHelper() override;
234 
235   int CPUExtent[6];
236   int GPUExtent[6];
237   int TextureExtent[6];
238 
239   vtkWeakPointer<vtkRenderWindow> Context;
240   vtkTextureObject* Texture;
241   vtkDataArray* Array;
242   bool ShaderSupportsTextureInt;
243   int MinTextureDimension;
244 
245   vtkSmartPointer<vtkPixelBufferObject> AsyncDownloadPBO;
246 
247   vtkPixelBufferObject* GetPBO();
248 
249   // We try to reuse the PBO if possible.
250   vtkSmartPointer<vtkPixelBufferObject> PBO;
251 
252 private:
253   vtkDataTransferHelper(const vtkDataTransferHelper&) = delete;
254   void operator=(const vtkDataTransferHelper&) = delete;
255 };
256 
257 #endif
258