1 /* This file is part of the Pangolin Project.
2  * http://github.com/stevenlovegrove/Pangolin
3  *
4  * Copyright (c) 2011 Steven Lovegrove
5  *
6  * Permission is hereby granted, free of charge, to any person
7  * obtaining a copy of this software and associated documentation
8  * files (the "Software"), to deal in the Software without
9  * restriction, including without limitation the rights to use,
10  * copy, modify, merge, publish, distribute, sublicense, and/or sell
11  * copies of the Software, and to permit persons to whom the
12  * Software is furnished to do so, subject to the following
13  * conditions:
14  *
15  * The above copyright notice and this permission notice shall be
16  * included in all copies or substantial portions of the Software.
17  *
18  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
20  * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
22  * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
23  * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
24  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
25  * OTHER DEALINGS IN THE SOFTWARE.
26  */
27 
28 #pragma once
29 
30 #include <algorithm>
31 #include <cuda_runtime.h>
32 #include <cuda_gl_interop.h>
33 
34 #include "gl.h"
35 
36 namespace pangolin
37 {
38 
39 ////////////////////////////////////////////////
40 // Interface
41 ////////////////////////////////////////////////
42 
43 struct GlBufferCudaPtr : public GlBuffer
44 {
45     //! Default constructor represents 'no buffer'
46     GlBufferCudaPtr();
47 
48     GlBufferCudaPtr(GlBufferType buffer_type, GLuint size_bytes, unsigned int cudause /*= cudaGraphicsMapFlagsNone*/, GLenum gluse /*= GL_DYNAMIC_DRAW*/ );
49     GlBufferCudaPtr(GlBufferType buffer_type, GLuint num_elements, GLenum datatype, GLuint count_per_element, unsigned int cudause /*= cudaGraphicsMapFlagsNone*/, GLenum gluse /*= GL_DYNAMIC_DRAW*/ );
50 
51     PANGOLIN_DEPRECATED
52     GlBufferCudaPtr(GlBufferType buffer_type, GLuint width, GLuint height, GLenum datatype, GLuint count_per_element, unsigned int cudause /*= cudaGraphicsMapFlagsNone*/, GLenum gluse /*= GL_DYNAMIC_DRAW*/ );
53 
54     ~GlBufferCudaPtr();
55 
56     void Reinitialise(GlBufferType buffer_type, GLuint size_bytes, unsigned int cudause /*= cudaGraphicsMapFlagsNone*/, GLenum gluse /*= GL_DYNAMIC_DRAW*/ );
57     void Reinitialise(GlBufferType buffer_type, GLuint num_elements, GLenum datatype, GLuint count_per_element, unsigned int cudause /*= cudaGraphicsMapFlagsNone*/, GLenum gluse /*= GL_DYNAMIC_DRAW*/ );
58 
59     /**
60      * Use parameters from another @c GlBufferCudaPtr to initialize this buffer.
61      */
62     void Reinitialise(const GlBufferCudaPtr& other);
63 
64     unsigned int cuda_use;
65     cudaGraphicsResource* cuda_res;
66 };
67 
68 struct GlTextureCudaArray : GlTexture
69 {
70     GlTextureCudaArray();
71     // Some internal_formats aren't accepted. I have trouble with GL_RGB8
72     GlTextureCudaArray(int width, int height, GLint internal_format, bool sampling_linear = true, int border = 0, GLenum glformat = GL_RGBA, GLenum gltype = GL_UNSIGNED_BYTE, GLvoid* data = NULL);
73     ~GlTextureCudaArray();
74 
75     void Reinitialise(int width, int height, GLint internal_format, bool sampling_linear = true, int border = 0, GLenum glformat = GL_RGBA, GLenum gltype = GL_UNSIGNED_BYTE, GLvoid* data = NULL) override;
76     cudaGraphicsResource* cuda_res;
77 };
78 
79 struct CudaScopedMappedPtr
80 {
81     CudaScopedMappedPtr(const GlBufferCudaPtr& buffer);
82     ~CudaScopedMappedPtr();
83     void* operator*();
84     cudaGraphicsResource* res;
85 
86 private:
CudaScopedMappedPtrCudaScopedMappedPtr87     CudaScopedMappedPtr(const CudaScopedMappedPtr&) {}
88 };
89 
90 struct CudaScopedMappedArray
91 {
92     CudaScopedMappedArray(const GlTextureCudaArray& tex);
93     ~CudaScopedMappedArray();
94     cudaArray* operator*();
95     cudaGraphicsResource* res;
96 
97 private:
CudaScopedMappedArrayCudaScopedMappedArray98     CudaScopedMappedArray(const CudaScopedMappedArray&) {}
99 };
100 
101 void CopyPboToTex(GlBufferCudaPtr& buffer, GlTexture& tex);
102 
103 void swap(GlBufferCudaPtr& a, GlBufferCudaPtr& b);
104 
105 ////////////////////////////////////////////////
106 // Implementation
107 ////////////////////////////////////////////////
108 
GlBufferCudaPtr()109 inline GlBufferCudaPtr::GlBufferCudaPtr()
110     : cuda_res(0)
111 {
112 }
113 
GlBufferCudaPtr(GlBufferType buffer_type,GLuint size_bytes,unsigned int cudause,GLenum gluse)114 inline GlBufferCudaPtr::GlBufferCudaPtr(GlBufferType buffer_type, GLuint size_bytes, unsigned int cudause /*= cudaGraphicsMapFlagsNone*/, GLenum gluse /*= GL_DYNAMIC_DRAW*/ )
115     : cuda_res(0)
116 {
117     Reinitialise(buffer_type, size_bytes, cudause, gluse);
118 }
119 
GlBufferCudaPtr(GlBufferType buffer_type,GLuint num_elements,GLenum datatype,GLuint count_per_element,unsigned int cudause,GLenum gluse)120 inline GlBufferCudaPtr::GlBufferCudaPtr(GlBufferType buffer_type, GLuint num_elements, GLenum datatype, GLuint count_per_element, unsigned int cudause, GLenum gluse )
121     : cuda_res(0)
122 {
123     Reinitialise(buffer_type, num_elements, datatype, count_per_element, cudause, gluse);
124 }
125 
GlBufferCudaPtr(GlBufferType buffer_type,GLuint width,GLuint height,GLenum datatype,GLuint count_per_element,unsigned int cudause,GLenum gluse)126 inline GlBufferCudaPtr::GlBufferCudaPtr(GlBufferType buffer_type, GLuint width, GLuint height, GLenum datatype, GLuint count_per_element, unsigned int cudause /*= cudaGraphicsMapFlagsNone*/, GLenum gluse /*= GL_DYNAMIC_DRAW*/ )
127     : cuda_res(0)
128 {
129     Reinitialise(buffer_type, width*height, datatype, count_per_element, cudause, gluse);
130 }
131 
~GlBufferCudaPtr()132 inline GlBufferCudaPtr::~GlBufferCudaPtr()
133 {
134     if(cuda_res) {
135         cudaGraphicsUnregisterResource(cuda_res);
136     }
137 }
138 
Reinitialise(GlBufferType buffer_type,GLuint size_bytes,unsigned int cudause,GLenum gluse)139 inline void GlBufferCudaPtr::Reinitialise(GlBufferType buffer_type, GLuint size_bytes, unsigned int cudause /*= cudaGraphicsMapFlagsNone*/, GLenum gluse /*= GL_DYNAMIC_DRAW*/ )
140 {
141     GlBufferCudaPtr::Reinitialise(buffer_type, size_bytes, GL_BYTE, 1, cudause, gluse);
142 }
143 
Reinitialise(GlBufferType buffer_type,GLuint num_elements,GLenum datatype,GLuint count_per_element,unsigned int cudause,GLenum gluse)144 inline void GlBufferCudaPtr::Reinitialise(GlBufferType buffer_type, GLuint num_elements, GLenum datatype, GLuint count_per_element, unsigned int cudause /*= cudaGraphicsMapFlagsNone*/, GLenum gluse /*= GL_DYNAMIC_DRAW*/ )
145 {
146     if(cuda_res) {
147         cudaGraphicsUnregisterResource(cuda_res);
148     }
149     GlBuffer::Reinitialise(buffer_type, num_elements, datatype, count_per_element, gluse);
150 
151     cuda_use = cudause;
152     cudaGraphicsGLRegisterBuffer( &cuda_res, bo, cudause );
153 }
154 
Reinitialise(const GlBufferCudaPtr & other)155 inline void GlBufferCudaPtr::Reinitialise(const GlBufferCudaPtr& other)
156 {
157   Reinitialise(other.buffer_type, other.num_elements, other.datatype, other.count_per_element, other.cuda_use, other.gluse);
158 }
159 
GlTextureCudaArray()160 inline GlTextureCudaArray::GlTextureCudaArray()
161     : GlTexture(), cuda_res(0)
162 {
163     // Not a texture
164 }
165 
GlTextureCudaArray(int width,int height,GLint internal_format,bool sampling_linear,int border,GLenum glformat,GLenum gltype,GLvoid * data)166 inline GlTextureCudaArray::GlTextureCudaArray(int width, int height, GLint internal_format, bool sampling_linear, int border, GLenum glformat, GLenum gltype, GLvoid *data)
167     :GlTexture(width,height,internal_format, sampling_linear, border, glformat, gltype, data)
168 {
169     // TODO: specify flags too
170     const cudaError_t err = cudaGraphicsGLRegisterImage(&cuda_res, tid, GL_TEXTURE_2D, cudaGraphicsMapFlagsNone);
171     if( err != cudaSuccess ) {
172         std::cout << "cudaGraphicsGLRegisterImage failed: " << err << std::endl;
173     }
174 }
175 
~GlTextureCudaArray()176 inline GlTextureCudaArray::~GlTextureCudaArray()
177 {
178     if(cuda_res) {
179         cudaGraphicsUnregisterResource(cuda_res);
180     }
181 }
182 
Reinitialise(int width,int height,GLint internal_format,bool sampling_linear,int border,GLenum glformat,GLenum gltype,GLvoid * data)183 inline void GlTextureCudaArray::Reinitialise(int width, int height, GLint internal_format, bool sampling_linear, int border, GLenum glformat, GLenum gltype, GLvoid* data)
184 {
185     if(cuda_res) {
186         cudaGraphicsUnregisterResource(cuda_res);
187     }
188 
189     GlTexture::Reinitialise(width, height, internal_format, sampling_linear, border, glformat, gltype, data);
190 
191     const cudaError_t err = cudaGraphicsGLRegisterImage(&cuda_res, tid, GL_TEXTURE_2D, cudaGraphicsMapFlagsNone);
192     if( err != cudaSuccess ) {
193         std::cout << "cudaGraphicsGLRegisterImage failed: " << err << std::endl;
194     }
195 }
196 
CudaScopedMappedPtr(const GlBufferCudaPtr & buffer)197 inline CudaScopedMappedPtr::CudaScopedMappedPtr(const GlBufferCudaPtr& buffer)
198     : res(buffer.cuda_res)
199 {
200     cudaGraphicsMapResources(1, &res, 0);
201 }
202 
~CudaScopedMappedPtr()203 inline CudaScopedMappedPtr::~CudaScopedMappedPtr()
204 {
205     cudaGraphicsUnmapResources(1, &res, 0);
206 }
207 
208 inline void* CudaScopedMappedPtr::operator*()
209 {
210     size_t num_bytes;
211     void* d_ptr;
212     cudaGraphicsResourceGetMappedPointer(&d_ptr,&num_bytes,res);
213     return d_ptr;
214 }
215 
CudaScopedMappedArray(const GlTextureCudaArray & tex)216 inline CudaScopedMappedArray::CudaScopedMappedArray(const GlTextureCudaArray& tex)
217     : res(tex.cuda_res)
218 {
219     cudaGraphicsMapResources(1, &res);
220 }
221 
~CudaScopedMappedArray()222 inline CudaScopedMappedArray::~CudaScopedMappedArray()
223 {
224     cudaGraphicsUnmapResources(1, &res);
225 }
226 
227 inline cudaArray* CudaScopedMappedArray::operator*()
228 {
229     cudaArray* array;
230     cudaGraphicsSubResourceGetMappedArray(&array, res, 0, 0);
231     return array;
232 }
233 
CopyPboToTex(const GlBufferCudaPtr & buffer,GlTexture & tex,GLenum buffer_layout,GLenum buffer_data_type)234 inline void CopyPboToTex(const GlBufferCudaPtr& buffer, GlTexture& tex, GLenum buffer_layout, GLenum buffer_data_type )
235 {
236     buffer.Bind();
237     tex.Bind();
238     glTexImage2D(GL_TEXTURE_2D, 0, tex.internal_format, tex.width, tex.height, 0, buffer_layout, buffer_data_type, 0);
239     buffer.Unbind();
240     tex.Unbind();
241 }
242 
243 template<typename T>
CopyDevMemtoTex(T * d_img,size_t pitch,GlTextureCudaArray & tex)244 inline void CopyDevMemtoTex(T* d_img, size_t pitch, GlTextureCudaArray& tex )
245 {
246     CudaScopedMappedArray arr_tex(tex);
247     cudaMemcpy2DToArray(*arr_tex, 0, 0, d_img, pitch, tex.width*sizeof(T), tex.height, cudaMemcpyDeviceToDevice );
248 }
249 
swap(GlBufferCudaPtr & a,GlBufferCudaPtr & b)250 inline void swap(GlBufferCudaPtr& a, GlBufferCudaPtr& b)
251 {
252     std::swap(a.bo, b.bo);
253     std::swap(a.cuda_res, b.cuda_res);
254     std::swap(a.buffer_type, b.buffer_type);
255 }
256 
257 
258 }
259