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