1/*M///////////////////////////////////////////////////////////////////////////////////////
2//
3//  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
4//
5//  By downloading, copying, installing or using the software you agree to this license.
6//  If you do not agree to this license, do not download, install,
7//  copy or use the software.
8//
9//
10//                           License Agreement
11//                For Open Source Computer Vision Library
12//
13// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
14// Copyright (C) 2009, Willow Garage Inc., all rights reserved.
15// Third party copyrights are property of their respective owners.
16//
17// Redistribution and use in source and binary forms, with or without modification,
18// are permitted provided that the following conditions are met:
19//
20//   * Redistribution's of source code must retain the above copyright notice,
21//     this list of conditions and the following disclaimer.
22//
23//   * Redistribution's in binary form must reproduce the above copyright notice,
24//     this list of conditions and the following disclaimer in the documentation
25//     and/or other materials provided with the distribution.
26//
27//   * The name of the copyright holders may not be used to endorse or promote products
28//     derived from this software without specific prior written permission.
29//
30// This software is provided by the copyright holders and contributors "as is" and
31// any express or implied warranties, including, but not limited to, the implied
32// warranties of merchantability and fitness for a particular purpose are disclaimed.
33// In no event shall the Intel Corporation or contributors be liable for any direct,
34// indirect, incidental, special, exemplary, or consequential damages
35// (including, but not limited to, procurement of substitute goods or services;
36// loss of use, data, or profits; or business interruption) however caused
37// and on any theory of liability, whether in contract, strict liability,
38// or tort (including negligence or otherwise) arising in any way out of
39// the use of this software, even if advised of the possibility of such damage.
40//
41//M*/
42
43#include "precomp.hpp"
44
45#ifdef HAVE_OPENGL
46#  include "gl_core_3_1.hpp"
47#  ifdef HAVE_CUDA
48#    include <cuda_gl_interop.h>
49#  endif
50#endif
51
52using namespace cv;
53using namespace cv::cuda;
54
55namespace
56{
57    #ifndef HAVE_OPENGL
58        inline void throw_no_ogl() { CV_Error(cv::Error::OpenGlNotSupported, "The library is compiled without OpenGL support"); }
59    #else
60        inline void throw_no_ogl() { CV_Error(cv::Error::OpenGlApiCallError, "OpenGL context doesn't exist"); }
61
62    bool checkError(const char* file, const int line, const char* func = 0)
63    {
64        GLenum err = gl::GetError();
65
66        if (err != gl::NO_ERROR_)
67        {
68            const char* msg;
69
70            switch (err)
71            {
72            case gl::INVALID_ENUM:
73                msg = "An unacceptable value is specified for an enumerated argument";
74                break;
75
76            case gl::INVALID_VALUE:
77                msg = "A numeric argument is out of range";
78                break;
79
80            case gl::INVALID_OPERATION:
81                msg = "The specified operation is not allowed in the current state";
82                break;
83
84            case gl::OUT_OF_MEMORY:
85                msg = "There is not enough memory left to execute the command";
86                break;
87
88            default:
89                msg = "Unknown error";
90            };
91
92            cvError(CV_OpenGlApiCallError, func, msg, file, line);
93
94            return false;
95        }
96
97        return true;
98    }
99    #endif
100
101    #define CV_CheckGlError() CV_DbgAssert( (checkError(__FILE__, __LINE__, CV_Func)) )
102} // namespace
103
104#ifdef HAVE_OPENGL
105namespace
106{
107    const GLenum gl_types[] = { gl::UNSIGNED_BYTE, gl::BYTE, gl::UNSIGNED_SHORT, gl::SHORT, gl::INT, gl::FLOAT, gl::DOUBLE };
108}
109#endif
110
111////////////////////////////////////////////////////////////////////////
112// setGlDevice
113
114void cv::cuda::setGlDevice(int device)
115{
116#ifndef HAVE_OPENGL
117    (void) device;
118    throw_no_ogl();
119#else
120    #ifndef HAVE_CUDA
121        (void) device;
122        throw_no_cuda();
123    #else
124        cudaSafeCall( cudaGLSetGLDevice(device) );
125    #endif
126#endif
127}
128
129////////////////////////////////////////////////////////////////////////
130// CudaResource
131
132#if defined(HAVE_OPENGL) && defined(HAVE_CUDA)
133
134namespace
135{
136    class CudaResource
137    {
138    public:
139        CudaResource();
140        ~CudaResource();
141
142        void registerBuffer(GLuint buffer);
143        void release();
144
145        void copyFrom(const void* src, size_t spitch, size_t width, size_t height, cudaStream_t stream = 0);
146        void copyTo(void* dst, size_t dpitch, size_t width, size_t height, cudaStream_t stream = 0);
147
148        void* map(cudaStream_t stream = 0);
149        void unmap(cudaStream_t stream = 0);
150
151    private:
152        cudaGraphicsResource_t resource_;
153        GLuint buffer_;
154
155        class GraphicsMapHolder;
156    };
157
158    CudaResource::CudaResource() : resource_(0), buffer_(0)
159    {
160    }
161
162    CudaResource::~CudaResource()
163    {
164        release();
165    }
166
167    void CudaResource::registerBuffer(GLuint buffer)
168    {
169        CV_DbgAssert( buffer != 0 );
170
171        if (buffer_ == buffer)
172            return;
173
174        cudaGraphicsResource_t resource;
175        cudaSafeCall( cudaGraphicsGLRegisterBuffer(&resource, buffer, cudaGraphicsMapFlagsNone) );
176
177        release();
178
179        resource_ = resource;
180        buffer_ = buffer;
181    }
182
183    void CudaResource::release()
184    {
185        if (resource_)
186            cudaGraphicsUnregisterResource(resource_);
187
188        resource_ = 0;
189        buffer_ = 0;
190    }
191
192    class CudaResource::GraphicsMapHolder
193    {
194    public:
195        GraphicsMapHolder(cudaGraphicsResource_t* resource, cudaStream_t stream);
196        ~GraphicsMapHolder();
197
198        void reset();
199
200    private:
201        cudaGraphicsResource_t* resource_;
202        cudaStream_t stream_;
203    };
204
205    CudaResource::GraphicsMapHolder::GraphicsMapHolder(cudaGraphicsResource_t* resource, cudaStream_t stream) : resource_(resource), stream_(stream)
206    {
207        if (resource_)
208            cudaSafeCall( cudaGraphicsMapResources(1, resource_, stream_) );
209    }
210
211    CudaResource::GraphicsMapHolder::~GraphicsMapHolder()
212    {
213        if (resource_)
214            cudaGraphicsUnmapResources(1, resource_, stream_);
215    }
216
217    void CudaResource::GraphicsMapHolder::reset()
218    {
219        resource_ = 0;
220    }
221
222    void CudaResource::copyFrom(const void* src, size_t spitch, size_t width, size_t height, cudaStream_t stream)
223    {
224        CV_DbgAssert( resource_ != 0 );
225
226        GraphicsMapHolder h(&resource_, stream);
227        (void) h;
228
229        void* dst;
230        size_t size;
231        cudaSafeCall( cudaGraphicsResourceGetMappedPointer(&dst, &size, resource_) );
232
233        CV_DbgAssert( width * height == size );
234
235        if (stream == 0)
236            cudaSafeCall( cudaMemcpy2D(dst, width, src, spitch, width, height, cudaMemcpyDeviceToDevice) );
237        else
238            cudaSafeCall( cudaMemcpy2DAsync(dst, width, src, spitch, width, height, cudaMemcpyDeviceToDevice, stream) );
239    }
240
241    void CudaResource::copyTo(void* dst, size_t dpitch, size_t width, size_t height, cudaStream_t stream)
242    {
243        CV_DbgAssert( resource_ != 0 );
244
245        GraphicsMapHolder h(&resource_, stream);
246        (void) h;
247
248        void* src;
249        size_t size;
250        cudaSafeCall( cudaGraphicsResourceGetMappedPointer(&src, &size, resource_) );
251
252        CV_DbgAssert( width * height == size );
253
254        if (stream == 0)
255            cudaSafeCall( cudaMemcpy2D(dst, dpitch, src, width, width, height, cudaMemcpyDeviceToDevice) );
256        else
257            cudaSafeCall( cudaMemcpy2DAsync(dst, dpitch, src, width, width, height, cudaMemcpyDeviceToDevice, stream) );
258    }
259
260    void* CudaResource::map(cudaStream_t stream)
261    {
262        CV_DbgAssert( resource_ != 0 );
263
264        GraphicsMapHolder h(&resource_, stream);
265
266        void* ptr;
267        size_t size;
268        cudaSafeCall( cudaGraphicsResourceGetMappedPointer(&ptr, &size, resource_) );
269
270        h.reset();
271
272        return ptr;
273    }
274
275    void CudaResource::unmap(cudaStream_t stream)
276    {
277        CV_Assert( resource_ != 0 );
278
279        cudaGraphicsUnmapResources(1, &resource_, stream);
280    }
281}
282
283#endif
284
285////////////////////////////////////////////////////////////////////////
286// ogl::Buffer
287
288#ifndef HAVE_OPENGL
289
290class cv::ogl::Buffer::Impl
291{
292};
293
294#else
295
296class cv::ogl::Buffer::Impl
297{
298public:
299    static const Ptr<Impl>& empty();
300
301    Impl(GLuint bufId, bool autoRelease);
302    Impl(GLsizeiptr size, const GLvoid* data, GLenum target, bool autoRelease);
303    ~Impl();
304
305    void bind(GLenum target) const;
306
307    void copyFrom(GLuint srcBuf, GLsizeiptr size);
308
309    void copyFrom(GLsizeiptr size, const GLvoid* data);
310    void copyTo(GLsizeiptr size, GLvoid* data) const;
311
312    void* mapHost(GLenum access);
313    void unmapHost();
314
315#ifdef HAVE_CUDA
316    void copyFrom(const void* src, size_t spitch, size_t width, size_t height, cudaStream_t stream = 0);
317    void copyTo(void* dst, size_t dpitch, size_t width, size_t height, cudaStream_t stream = 0) const;
318
319    void* mapDevice(cudaStream_t stream = 0);
320    void unmapDevice(cudaStream_t stream = 0);
321#endif
322
323    void setAutoRelease(bool flag) { autoRelease_ = flag; }
324
325    GLuint bufId() const { return bufId_; }
326
327private:
328    Impl();
329
330    GLuint bufId_;
331    bool autoRelease_;
332
333#ifdef HAVE_CUDA
334    mutable CudaResource cudaResource_;
335#endif
336};
337
338const Ptr<cv::ogl::Buffer::Impl>& cv::ogl::Buffer::Impl::empty()
339{
340    static Ptr<Impl> p(new Impl);
341    return p;
342}
343
344cv::ogl::Buffer::Impl::Impl() : bufId_(0), autoRelease_(false)
345{
346}
347
348cv::ogl::Buffer::Impl::Impl(GLuint abufId, bool autoRelease) : bufId_(abufId), autoRelease_(autoRelease)
349{
350    CV_Assert( gl::IsBuffer(abufId) == gl::TRUE_ );
351}
352
353cv::ogl::Buffer::Impl::Impl(GLsizeiptr size, const GLvoid* data, GLenum target, bool autoRelease) : bufId_(0), autoRelease_(autoRelease)
354{
355    gl::GenBuffers(1, &bufId_);
356    CV_CheckGlError();
357
358    CV_Assert( bufId_ != 0 );
359
360    gl::BindBuffer(target, bufId_);
361    CV_CheckGlError();
362
363    gl::BufferData(target, size, data, gl::DYNAMIC_DRAW);
364    CV_CheckGlError();
365
366    gl::BindBuffer(target, 0);
367    CV_CheckGlError();
368}
369
370cv::ogl::Buffer::Impl::~Impl()
371{
372    if (autoRelease_ && bufId_)
373        gl::DeleteBuffers(1, &bufId_);
374}
375
376void cv::ogl::Buffer::Impl::bind(GLenum target) const
377{
378    gl::BindBuffer(target, bufId_);
379    CV_CheckGlError();
380}
381
382void cv::ogl::Buffer::Impl::copyFrom(GLuint srcBuf, GLsizeiptr size)
383{
384    gl::BindBuffer(gl::COPY_WRITE_BUFFER, bufId_);
385    CV_CheckGlError();
386
387    gl::BindBuffer(gl::COPY_READ_BUFFER, srcBuf);
388    CV_CheckGlError();
389
390    gl::CopyBufferSubData(gl::COPY_READ_BUFFER, gl::COPY_WRITE_BUFFER, 0, 0, size);
391    CV_CheckGlError();
392}
393
394void cv::ogl::Buffer::Impl::copyFrom(GLsizeiptr size, const GLvoid* data)
395{
396    gl::BindBuffer(gl::COPY_WRITE_BUFFER, bufId_);
397    CV_CheckGlError();
398
399    gl::BufferSubData(gl::COPY_WRITE_BUFFER, 0, size, data);
400    CV_CheckGlError();
401}
402
403void cv::ogl::Buffer::Impl::copyTo(GLsizeiptr size, GLvoid* data) const
404{
405    gl::BindBuffer(gl::COPY_READ_BUFFER, bufId_);
406    CV_CheckGlError();
407
408    gl::GetBufferSubData(gl::COPY_READ_BUFFER, 0, size, data);
409    CV_CheckGlError();
410}
411
412void* cv::ogl::Buffer::Impl::mapHost(GLenum access)
413{
414    gl::BindBuffer(gl::COPY_READ_BUFFER, bufId_);
415    CV_CheckGlError();
416
417    GLvoid* data = gl::MapBuffer(gl::COPY_READ_BUFFER, access);
418    CV_CheckGlError();
419
420    return data;
421}
422
423void cv::ogl::Buffer::Impl::unmapHost()
424{
425    gl::UnmapBuffer(gl::COPY_READ_BUFFER);
426}
427
428#ifdef HAVE_CUDA
429
430void cv::ogl::Buffer::Impl::copyFrom(const void* src, size_t spitch, size_t width, size_t height, cudaStream_t stream)
431{
432    cudaResource_.registerBuffer(bufId_);
433    cudaResource_.copyFrom(src, spitch, width, height, stream);
434}
435
436void cv::ogl::Buffer::Impl::copyTo(void* dst, size_t dpitch, size_t width, size_t height, cudaStream_t stream) const
437{
438    cudaResource_.registerBuffer(bufId_);
439    cudaResource_.copyTo(dst, dpitch, width, height, stream);
440}
441
442void* cv::ogl::Buffer::Impl::mapDevice(cudaStream_t stream)
443{
444    cudaResource_.registerBuffer(bufId_);
445    return cudaResource_.map(stream);
446}
447
448void cv::ogl::Buffer::Impl::unmapDevice(cudaStream_t stream)
449{
450    cudaResource_.unmap(stream);
451}
452
453#endif // HAVE_CUDA
454
455#endif // HAVE_OPENGL
456
457cv::ogl::Buffer::Buffer() : rows_(0), cols_(0), type_(0)
458{
459#ifndef HAVE_OPENGL
460    throw_no_ogl();
461#else
462    impl_ = Impl::empty();
463#endif
464}
465
466cv::ogl::Buffer::Buffer(int arows, int acols, int atype, unsigned int abufId, bool autoRelease) : rows_(0), cols_(0), type_(0)
467{
468#ifndef HAVE_OPENGL
469    (void) arows;
470    (void) acols;
471    (void) atype;
472    (void) abufId;
473    (void) autoRelease;
474    throw_no_ogl();
475#else
476    impl_.reset(new Impl(abufId, autoRelease));
477    rows_ = arows;
478    cols_ = acols;
479    type_ = atype;
480#endif
481}
482
483cv::ogl::Buffer::Buffer(Size asize, int atype, unsigned int abufId, bool autoRelease) : rows_(0), cols_(0), type_(0)
484{
485#ifndef HAVE_OPENGL
486    (void) asize;
487    (void) atype;
488    (void) abufId;
489    (void) autoRelease;
490    throw_no_ogl();
491#else
492    impl_.reset(new Impl(abufId, autoRelease));
493    rows_ = asize.height;
494    cols_ = asize.width;
495    type_ = atype;
496#endif
497}
498
499cv::ogl::Buffer::Buffer(InputArray arr, Target target, bool autoRelease) : rows_(0), cols_(0), type_(0)
500{
501#ifndef HAVE_OPENGL
502    (void) arr;
503    (void) target;
504    (void) autoRelease;
505    throw_no_ogl();
506#else
507    const int kind = arr.kind();
508
509    switch (kind)
510    {
511    case _InputArray::OPENGL_BUFFER:
512    case _InputArray::CUDA_GPU_MAT:
513        copyFrom(arr, target, autoRelease);
514        break;
515
516    default:
517        {
518            Mat mat = arr.getMat();
519            CV_Assert( mat.isContinuous() );
520            const GLsizeiptr asize = mat.rows * mat.cols * mat.elemSize();
521            impl_.reset(new Impl(asize, mat.data, target, autoRelease));
522            rows_ = mat.rows;
523            cols_ = mat.cols;
524            type_ = mat.type();
525            break;
526        }
527    }
528#endif
529}
530
531void cv::ogl::Buffer::create(int arows, int acols, int atype, Target target, bool autoRelease)
532{
533#ifndef HAVE_OPENGL
534    (void) arows;
535    (void) acols;
536    (void) atype;
537    (void) target;
538    (void) autoRelease;
539    throw_no_ogl();
540#else
541    if (rows_ != arows || cols_ != acols || type_ != atype)
542    {
543        const GLsizeiptr asize = arows * acols * CV_ELEM_SIZE(atype);
544        impl_.reset(new Impl(asize, 0, target, autoRelease));
545        rows_ = arows;
546        cols_ = acols;
547        type_ = atype;
548    }
549#endif
550}
551
552void cv::ogl::Buffer::release()
553{
554#ifdef HAVE_OPENGL
555    if (impl_)
556        impl_->setAutoRelease(true);
557    impl_ = Impl::empty();
558    rows_ = 0;
559    cols_ = 0;
560    type_ = 0;
561#endif
562}
563
564void cv::ogl::Buffer::setAutoRelease(bool flag)
565{
566#ifndef HAVE_OPENGL
567    (void) flag;
568    throw_no_ogl();
569#else
570    impl_->setAutoRelease(flag);
571#endif
572}
573
574void cv::ogl::Buffer::copyFrom(InputArray arr, Target target, bool autoRelease)
575{
576#ifndef HAVE_OPENGL
577    (void) arr;
578    (void) target;
579    (void) autoRelease;
580    throw_no_ogl();
581#else
582    const int kind = arr.kind();
583
584    const Size asize = arr.size();
585    const int atype = arr.type();
586    create(asize, atype, target, autoRelease);
587
588    switch (kind)
589    {
590    case _InputArray::OPENGL_BUFFER:
591        {
592            ogl::Buffer buf = arr.getOGlBuffer();
593            impl_->copyFrom(buf.bufId(), asize.area() * CV_ELEM_SIZE(atype));
594            break;
595        }
596
597    case _InputArray::CUDA_GPU_MAT:
598        {
599            #ifndef HAVE_CUDA
600                throw_no_cuda();
601            #else
602                GpuMat dmat = arr.getGpuMat();
603                impl_->copyFrom(dmat.data, dmat.step, dmat.cols * dmat.elemSize(), dmat.rows);
604            #endif
605
606            break;
607        }
608
609    default:
610        {
611            Mat mat = arr.getMat();
612            CV_Assert( mat.isContinuous() );
613            impl_->copyFrom(asize.area() * CV_ELEM_SIZE(atype), mat.data);
614        }
615    }
616#endif
617}
618
619void cv::ogl::Buffer::copyFrom(InputArray arr, cuda::Stream& stream, Target target, bool autoRelease)
620{
621#ifndef HAVE_OPENGL
622    (void) arr;
623    (void) stream;
624    (void) target;
625    (void) autoRelease;
626    throw_no_ogl();
627#else
628    #ifndef HAVE_CUDA
629        (void) arr;
630        (void) stream;
631        (void) target;
632        (void) autoRelease;
633        throw_no_cuda();
634    #else
635        GpuMat dmat = arr.getGpuMat();
636
637        create(dmat.size(), dmat.type(), target, autoRelease);
638
639        impl_->copyFrom(dmat.data, dmat.step, dmat.cols * dmat.elemSize(), dmat.rows, cuda::StreamAccessor::getStream(stream));
640    #endif
641#endif
642}
643
644void cv::ogl::Buffer::copyTo(OutputArray arr) const
645{
646#ifndef HAVE_OPENGL
647    (void) arr;
648    throw_no_ogl();
649#else
650    const int kind = arr.kind();
651
652    switch (kind)
653    {
654    case _InputArray::OPENGL_BUFFER:
655        {
656            arr.getOGlBufferRef().copyFrom(*this);
657            break;
658        }
659
660    case _InputArray::CUDA_GPU_MAT:
661        {
662            #ifndef HAVE_CUDA
663                throw_no_cuda();
664            #else
665                GpuMat& dmat = arr.getGpuMatRef();
666                dmat.create(rows_, cols_, type_);
667                impl_->copyTo(dmat.data, dmat.step, dmat.cols * dmat.elemSize(), dmat.rows);
668            #endif
669
670            break;
671        }
672
673    default:
674        {
675            arr.create(rows_, cols_, type_);
676            Mat mat = arr.getMat();
677            CV_Assert( mat.isContinuous() );
678            impl_->copyTo(mat.rows * mat.cols * mat.elemSize(), mat.data);
679        }
680    }
681#endif
682}
683
684void cv::ogl::Buffer::copyTo(OutputArray arr, cuda::Stream& stream) const
685{
686#ifndef HAVE_OPENGL
687    (void) arr;
688    (void) stream;
689    throw_no_ogl();
690#else
691    #ifndef HAVE_CUDA
692        (void) arr;
693        (void) stream;
694        throw_no_cuda();
695    #else
696        arr.create(rows_, cols_, type_);
697        GpuMat dmat = arr.getGpuMat();
698        impl_->copyTo(dmat.data, dmat.step, dmat.cols * dmat.elemSize(), dmat.rows, cuda::StreamAccessor::getStream(stream));
699    #endif
700#endif
701}
702
703cv::ogl::Buffer cv::ogl::Buffer::clone(Target target, bool autoRelease) const
704{
705#ifndef HAVE_OPENGL
706    (void) target;
707    (void) autoRelease;
708    throw_no_ogl();
709    return cv::ogl::Buffer();
710#else
711    ogl::Buffer buf;
712    buf.copyFrom(*this, target, autoRelease);
713    return buf;
714#endif
715}
716
717void cv::ogl::Buffer::bind(Target target) const
718{
719#ifndef HAVE_OPENGL
720    (void) target;
721    throw_no_ogl();
722#else
723    impl_->bind(target);
724#endif
725}
726
727void cv::ogl::Buffer::unbind(Target target)
728{
729#ifndef HAVE_OPENGL
730    (void) target;
731    throw_no_ogl();
732#else
733    gl::BindBuffer(target, 0);
734    CV_CheckGlError();
735#endif
736}
737
738Mat cv::ogl::Buffer::mapHost(Access access)
739{
740#ifndef HAVE_OPENGL
741    (void) access;
742    throw_no_ogl();
743    return Mat();
744#else
745    return Mat(rows_, cols_, type_, impl_->mapHost(access));
746#endif
747}
748
749void cv::ogl::Buffer::unmapHost()
750{
751#ifndef HAVE_OPENGL
752    throw_no_ogl();
753#else
754    return impl_->unmapHost();
755#endif
756}
757
758GpuMat cv::ogl::Buffer::mapDevice()
759{
760#ifndef HAVE_OPENGL
761    throw_no_ogl();
762    return GpuMat();
763#else
764    #ifndef HAVE_CUDA
765        throw_no_cuda();
766        return GpuMat();
767    #else
768        return GpuMat(rows_, cols_, type_, impl_->mapDevice());
769    #endif
770#endif
771}
772
773void cv::ogl::Buffer::unmapDevice()
774{
775#ifndef HAVE_OPENGL
776    throw_no_ogl();
777#else
778    #ifndef HAVE_CUDA
779        throw_no_cuda();
780    #else
781        impl_->unmapDevice();
782    #endif
783#endif
784}
785
786cuda::GpuMat cv::ogl::Buffer::mapDevice(cuda::Stream& stream)
787{
788#ifndef HAVE_OPENGL
789    (void) stream;
790    throw_no_ogl();
791    return GpuMat();
792#else
793    #ifndef HAVE_CUDA
794        (void) stream;
795        throw_no_cuda();
796        return GpuMat();
797    #else
798        return GpuMat(rows_, cols_, type_, impl_->mapDevice(cuda::StreamAccessor::getStream(stream)));
799    #endif
800#endif
801}
802
803void cv::ogl::Buffer::unmapDevice(cuda::Stream& stream)
804{
805#ifndef HAVE_OPENGL
806    (void) stream;
807    throw_no_ogl();
808#else
809    #ifndef HAVE_CUDA
810        (void) stream;
811        throw_no_cuda();
812    #else
813        impl_->unmapDevice(cuda::StreamAccessor::getStream(stream));
814    #endif
815#endif
816}
817
818unsigned int cv::ogl::Buffer::bufId() const
819{
820#ifndef HAVE_OPENGL
821    throw_no_ogl();
822    return 0;
823#else
824    return impl_->bufId();
825#endif
826}
827
828
829//////////////////////////////////////////////////////////////////////////////////////////
830// ogl::Texture
831
832#ifndef HAVE_OPENGL
833
834class cv::ogl::Texture2D::Impl
835{
836};
837
838#else
839
840class cv::ogl::Texture2D::Impl
841{
842public:
843    static const Ptr<Impl> empty();
844
845    Impl(GLuint texId, bool autoRelease);
846    Impl(GLint internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid* pixels, bool autoRelease);
847    ~Impl();
848
849    void copyFrom(GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels);
850    void copyTo(GLenum format, GLenum type, GLvoid* pixels) const;
851
852    void bind() const;
853
854    void setAutoRelease(bool flag) { autoRelease_ = flag; }
855
856    GLuint texId() const { return texId_; }
857
858private:
859    Impl();
860
861    GLuint texId_;
862    bool autoRelease_;
863};
864
865const Ptr<cv::ogl::Texture2D::Impl> cv::ogl::Texture2D::Impl::empty()
866{
867    static Ptr<Impl> p(new Impl);
868    return p;
869}
870
871cv::ogl::Texture2D::Impl::Impl() : texId_(0), autoRelease_(false)
872{
873}
874
875cv::ogl::Texture2D::Impl::Impl(GLuint atexId, bool autoRelease) : texId_(atexId), autoRelease_(autoRelease)
876{
877    CV_Assert( gl::IsTexture(atexId) == gl::TRUE_ );
878}
879
880cv::ogl::Texture2D::Impl::Impl(GLint internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid* pixels, bool autoRelease) : texId_(0), autoRelease_(autoRelease)
881{
882    gl::GenTextures(1, &texId_);
883    CV_CheckGlError();
884
885    CV_Assert(texId_ != 0);
886
887    gl::BindTexture(gl::TEXTURE_2D, texId_);
888    CV_CheckGlError();
889
890    gl::PixelStorei(gl::UNPACK_ALIGNMENT, 1);
891    CV_CheckGlError();
892
893    gl::TexImage2D(gl::TEXTURE_2D, 0, internalFormat, width, height, 0, format, type, pixels);
894    CV_CheckGlError();
895
896    gl::GenerateMipmap(gl::TEXTURE_2D);
897    CV_CheckGlError();
898}
899
900cv::ogl::Texture2D::Impl::~Impl()
901{
902    if (autoRelease_ && texId_)
903        gl::DeleteTextures(1, &texId_);
904}
905
906void cv::ogl::Texture2D::Impl::copyFrom(GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels)
907{
908    gl::BindTexture(gl::TEXTURE_2D, texId_);
909    CV_CheckGlError();
910
911    gl::PixelStorei(gl::UNPACK_ALIGNMENT, 1);
912    CV_CheckGlError();
913
914    gl::TexSubImage2D(gl::TEXTURE_2D, 0, 0, 0, width, height, format, type, pixels);
915    CV_CheckGlError();
916
917    gl::GenerateMipmap(gl::TEXTURE_2D);
918    CV_CheckGlError();
919}
920
921void cv::ogl::Texture2D::Impl::copyTo(GLenum format, GLenum type, GLvoid* pixels) const
922{
923    gl::BindTexture(gl::TEXTURE_2D, texId_);
924    CV_CheckGlError();
925
926    gl::PixelStorei(gl::PACK_ALIGNMENT, 1);
927    CV_CheckGlError();
928
929    gl::GetTexImage(gl::TEXTURE_2D, 0, format, type, pixels);
930    CV_CheckGlError();
931}
932
933void cv::ogl::Texture2D::Impl::bind() const
934{
935    gl::BindTexture(gl::TEXTURE_2D, texId_);
936    CV_CheckGlError();
937}
938
939#endif // HAVE_OPENGL
940
941cv::ogl::Texture2D::Texture2D() : rows_(0), cols_(0), format_(NONE)
942{
943#ifndef HAVE_OPENGL
944    throw_no_ogl();
945#else
946    impl_ = Impl::empty();
947#endif
948}
949
950cv::ogl::Texture2D::Texture2D(int arows, int acols, Format aformat, unsigned int atexId, bool autoRelease) : rows_(0), cols_(0), format_(NONE)
951{
952#ifndef HAVE_OPENGL
953    (void) arows;
954    (void) acols;
955    (void) aformat;
956    (void) atexId;
957    (void) autoRelease;
958    throw_no_ogl();
959#else
960    impl_.reset(new Impl(atexId, autoRelease));
961    rows_ = arows;
962    cols_ = acols;
963    format_ = aformat;
964#endif
965}
966
967cv::ogl::Texture2D::Texture2D(Size asize, Format aformat, unsigned int atexId, bool autoRelease) : rows_(0), cols_(0), format_(NONE)
968{
969#ifndef HAVE_OPENGL
970    (void) asize;
971    (void) aformat;
972    (void) atexId;
973    (void) autoRelease;
974    throw_no_ogl();
975#else
976    impl_.reset(new Impl(atexId, autoRelease));
977    rows_ = asize.height;
978    cols_ = asize.width;
979    format_ = aformat;
980#endif
981}
982
983cv::ogl::Texture2D::Texture2D(InputArray arr, bool autoRelease) : rows_(0), cols_(0), format_(NONE)
984{
985#ifndef HAVE_OPENGL
986    (void) arr;
987    (void) autoRelease;
988    throw_no_ogl();
989#else
990    const int kind = arr.kind();
991
992    const Size asize = arr.size();
993    const int atype = arr.type();
994
995    const int depth = CV_MAT_DEPTH(atype);
996    const int cn = CV_MAT_CN(atype);
997
998    CV_Assert( depth <= CV_32F );
999    CV_Assert( cn == 1 || cn == 3 || cn == 4 );
1000
1001    const Format internalFormats[] =
1002    {
1003        NONE, DEPTH_COMPONENT, NONE, RGB, RGBA
1004    };
1005    const GLenum srcFormats[] =
1006    {
1007        0, gl::DEPTH_COMPONENT, 0, gl::BGR, gl::BGRA
1008    };
1009
1010    switch (kind)
1011    {
1012    case _InputArray::OPENGL_BUFFER:
1013        {
1014            ogl::Buffer buf = arr.getOGlBuffer();
1015            buf.bind(ogl::Buffer::PIXEL_UNPACK_BUFFER);
1016            impl_.reset(new Impl(internalFormats[cn], asize.width, asize.height, srcFormats[cn], gl_types[depth], 0, autoRelease));
1017            ogl::Buffer::unbind(ogl::Buffer::PIXEL_UNPACK_BUFFER);
1018            break;
1019        }
1020
1021    case _InputArray::CUDA_GPU_MAT:
1022        {
1023            #ifndef HAVE_CUDA
1024                throw_no_cuda();
1025            #else
1026                GpuMat dmat = arr.getGpuMat();
1027                ogl::Buffer buf(dmat, ogl::Buffer::PIXEL_UNPACK_BUFFER);
1028                buf.setAutoRelease(true);
1029                buf.bind(ogl::Buffer::PIXEL_UNPACK_BUFFER);
1030                impl_.reset(new Impl(internalFormats[cn], asize.width, asize.height, srcFormats[cn], gl_types[depth], 0, autoRelease));
1031                ogl::Buffer::unbind(ogl::Buffer::PIXEL_UNPACK_BUFFER);
1032            #endif
1033
1034            break;
1035        }
1036
1037    default:
1038        {
1039            Mat mat = arr.getMat();
1040            CV_Assert( mat.isContinuous() );
1041            ogl::Buffer::unbind(ogl::Buffer::PIXEL_UNPACK_BUFFER);
1042            impl_.reset(new Impl(internalFormats[cn], asize.width, asize.height, srcFormats[cn], gl_types[depth], mat.data, autoRelease));
1043            break;
1044        }
1045    }
1046
1047    rows_ = asize.height;
1048    cols_ = asize.width;
1049    format_ = internalFormats[cn];
1050#endif
1051}
1052
1053void cv::ogl::Texture2D::create(int arows, int acols, Format aformat, bool autoRelease)
1054{
1055#ifndef HAVE_OPENGL
1056    (void) arows;
1057    (void) acols;
1058    (void) aformat;
1059    (void) autoRelease;
1060    throw_no_ogl();
1061#else
1062    if (rows_ != arows || cols_ != acols || format_ != aformat)
1063    {
1064        ogl::Buffer::unbind(ogl::Buffer::PIXEL_UNPACK_BUFFER);
1065        impl_.reset(new Impl(aformat, acols, arows, aformat, gl::FLOAT, 0, autoRelease));
1066        rows_ = arows;
1067        cols_ = acols;
1068        format_ = aformat;
1069    }
1070#endif
1071}
1072
1073void cv::ogl::Texture2D::release()
1074{
1075#ifdef HAVE_OPENGL
1076    if (impl_)
1077        impl_->setAutoRelease(true);
1078    impl_ = Impl::empty();
1079    rows_ = 0;
1080    cols_ = 0;
1081    format_ = NONE;
1082#endif
1083}
1084
1085void cv::ogl::Texture2D::setAutoRelease(bool flag)
1086{
1087#ifndef HAVE_OPENGL
1088    (void) flag;
1089    throw_no_ogl();
1090#else
1091    impl_->setAutoRelease(flag);
1092#endif
1093}
1094
1095void cv::ogl::Texture2D::copyFrom(InputArray arr, bool autoRelease)
1096{
1097#ifndef HAVE_OPENGL
1098    (void) arr;
1099    (void) autoRelease;
1100    throw_no_ogl();
1101#else
1102    const int kind = arr.kind();
1103
1104    const Size asize = arr.size();
1105    const int atype = arr.type();
1106
1107    const int depth = CV_MAT_DEPTH(atype);
1108    const int cn = CV_MAT_CN(atype);
1109
1110    CV_Assert( depth <= CV_32F );
1111    CV_Assert( cn == 1 || cn == 3 || cn == 4 );
1112
1113    const Format internalFormats[] =
1114    {
1115        NONE, DEPTH_COMPONENT, NONE, RGB, RGBA
1116    };
1117    const GLenum srcFormats[] =
1118    {
1119        0, gl::DEPTH_COMPONENT, 0, gl::BGR, gl::BGRA
1120    };
1121
1122    create(asize, internalFormats[cn], autoRelease);
1123
1124    switch(kind)
1125    {
1126    case _InputArray::OPENGL_BUFFER:
1127        {
1128            ogl::Buffer buf = arr.getOGlBuffer();
1129            buf.bind(ogl::Buffer::PIXEL_UNPACK_BUFFER);
1130            impl_->copyFrom(asize.width, asize.height, srcFormats[cn], gl_types[depth], 0);
1131            ogl::Buffer::unbind(ogl::Buffer::PIXEL_UNPACK_BUFFER);
1132            break;
1133        }
1134
1135    case _InputArray::CUDA_GPU_MAT:
1136        {
1137            #ifndef HAVE_CUDA
1138                throw_no_cuda();
1139            #else
1140                GpuMat dmat = arr.getGpuMat();
1141                ogl::Buffer buf(dmat, ogl::Buffer::PIXEL_UNPACK_BUFFER);
1142                buf.setAutoRelease(true);
1143                buf.bind(ogl::Buffer::PIXEL_UNPACK_BUFFER);
1144                impl_->copyFrom(asize.width, asize.height, srcFormats[cn], gl_types[depth], 0);
1145                ogl::Buffer::unbind(ogl::Buffer::PIXEL_UNPACK_BUFFER);
1146            #endif
1147
1148            break;
1149        }
1150
1151    default:
1152        {
1153            Mat mat = arr.getMat();
1154            CV_Assert( mat.isContinuous() );
1155            ogl::Buffer::unbind(ogl::Buffer::PIXEL_UNPACK_BUFFER);
1156            impl_->copyFrom(asize.width, asize.height, srcFormats[cn], gl_types[depth], mat.data);
1157        }
1158    }
1159#endif
1160}
1161
1162void cv::ogl::Texture2D::copyTo(OutputArray arr, int ddepth, bool autoRelease) const
1163{
1164#ifndef HAVE_OPENGL
1165    (void) arr;
1166    (void) ddepth;
1167    (void) autoRelease;
1168    throw_no_ogl();
1169#else
1170    const int kind = arr.kind();
1171
1172    const int cn = format_ == DEPTH_COMPONENT ? 1: format_ == RGB ? 3 : 4;
1173    const GLenum dstFormat = format_ == DEPTH_COMPONENT ? gl::DEPTH_COMPONENT : format_ == RGB ? gl::BGR : gl::BGRA;
1174
1175    switch(kind)
1176    {
1177    case _InputArray::OPENGL_BUFFER:
1178        {
1179            ogl::Buffer& buf = arr.getOGlBufferRef();
1180            buf.create(rows_, cols_, CV_MAKE_TYPE(ddepth, cn), ogl::Buffer::PIXEL_PACK_BUFFER, autoRelease);
1181            buf.bind(ogl::Buffer::PIXEL_PACK_BUFFER);
1182            impl_->copyTo(dstFormat, gl_types[ddepth], 0);
1183            ogl::Buffer::unbind(ogl::Buffer::PIXEL_PACK_BUFFER);
1184            break;
1185        }
1186
1187    case _InputArray::CUDA_GPU_MAT:
1188        {
1189            #ifndef HAVE_CUDA
1190                throw_no_cuda();
1191            #else
1192                ogl::Buffer buf(rows_, cols_, CV_MAKE_TYPE(ddepth, cn), ogl::Buffer::PIXEL_PACK_BUFFER);
1193                buf.setAutoRelease(true);
1194                buf.bind(ogl::Buffer::PIXEL_PACK_BUFFER);
1195                impl_->copyTo(dstFormat, gl_types[ddepth], 0);
1196                ogl::Buffer::unbind(ogl::Buffer::PIXEL_PACK_BUFFER);
1197                buf.copyTo(arr);
1198            #endif
1199
1200            break;
1201        }
1202
1203    default:
1204        {
1205            arr.create(rows_, cols_, CV_MAKE_TYPE(ddepth, cn));
1206            Mat mat = arr.getMat();
1207            CV_Assert( mat.isContinuous() );
1208            ogl::Buffer::unbind(ogl::Buffer::PIXEL_PACK_BUFFER);
1209            impl_->copyTo(dstFormat, gl_types[ddepth], mat.data);
1210        }
1211    }
1212#endif
1213}
1214
1215void cv::ogl::Texture2D::bind() const
1216{
1217#ifndef HAVE_OPENGL
1218    throw_no_ogl();
1219#else
1220    impl_->bind();
1221#endif
1222}
1223
1224unsigned int cv::ogl::Texture2D::texId() const
1225{
1226#ifndef HAVE_OPENGL
1227    throw_no_ogl();
1228    return 0;
1229#else
1230    return impl_->texId();
1231#endif
1232}
1233
1234
1235////////////////////////////////////////////////////////////////////////
1236// ogl::Arrays
1237
1238void cv::ogl::Arrays::setVertexArray(InputArray vertex)
1239{
1240    const int cn = vertex.channels();
1241    const int depth = vertex.depth();
1242
1243    CV_Assert( cn == 2 || cn == 3 || cn == 4 );
1244    CV_Assert( depth == CV_16S || depth == CV_32S || depth == CV_32F || depth == CV_64F );
1245
1246    if (vertex.kind() == _InputArray::OPENGL_BUFFER)
1247        vertex_ = vertex.getOGlBuffer();
1248    else
1249        vertex_.copyFrom(vertex);
1250
1251    size_ = vertex_.size().area();
1252}
1253
1254void cv::ogl::Arrays::resetVertexArray()
1255{
1256    vertex_.release();
1257    size_ = 0;
1258}
1259
1260void cv::ogl::Arrays::setColorArray(InputArray color)
1261{
1262    const int cn = color.channels();
1263
1264    CV_Assert( cn == 3 || cn == 4 );
1265
1266    if (color.kind() == _InputArray::OPENGL_BUFFER)
1267        color_ = color.getOGlBuffer();
1268    else
1269        color_.copyFrom(color);
1270}
1271
1272void cv::ogl::Arrays::resetColorArray()
1273{
1274    color_.release();
1275}
1276
1277void cv::ogl::Arrays::setNormalArray(InputArray normal)
1278{
1279    const int cn = normal.channels();
1280    const int depth = normal.depth();
1281
1282    CV_Assert( cn == 3 );
1283    CV_Assert( depth == CV_8S || depth == CV_16S || depth == CV_32S || depth == CV_32F || depth == CV_64F );
1284
1285    if (normal.kind() == _InputArray::OPENGL_BUFFER)
1286        normal_ = normal.getOGlBuffer();
1287    else
1288        normal_.copyFrom(normal);
1289}
1290
1291void cv::ogl::Arrays::resetNormalArray()
1292{
1293    normal_.release();
1294}
1295
1296void cv::ogl::Arrays::setTexCoordArray(InputArray texCoord)
1297{
1298    const int cn = texCoord.channels();
1299    const int depth = texCoord.depth();
1300
1301    CV_Assert( cn >= 1 && cn <= 4 );
1302    CV_Assert( depth == CV_16S || depth == CV_32S || depth == CV_32F || depth == CV_64F );
1303
1304    if (texCoord.kind() == _InputArray::OPENGL_BUFFER)
1305        texCoord_ = texCoord.getOGlBuffer();
1306    else
1307        texCoord_.copyFrom(texCoord);
1308}
1309
1310void cv::ogl::Arrays::resetTexCoordArray()
1311{
1312    texCoord_.release();
1313}
1314
1315void cv::ogl::Arrays::release()
1316{
1317    resetVertexArray();
1318    resetColorArray();
1319    resetNormalArray();
1320    resetTexCoordArray();
1321}
1322
1323void cv::ogl::Arrays::setAutoRelease(bool flag)
1324{
1325    vertex_.setAutoRelease(flag);
1326    color_.setAutoRelease(flag);
1327    normal_.setAutoRelease(flag);
1328    texCoord_.setAutoRelease(flag);
1329}
1330
1331void cv::ogl::Arrays::bind() const
1332{
1333#ifndef HAVE_OPENGL
1334    throw_no_ogl();
1335#else
1336    CV_Assert( texCoord_.empty() || texCoord_.size().area() == size_ );
1337    CV_Assert( normal_.empty() || normal_.size().area() == size_ );
1338    CV_Assert( color_.empty() || color_.size().area() == size_ );
1339
1340    if (texCoord_.empty())
1341    {
1342        gl::DisableClientState(gl::TEXTURE_COORD_ARRAY);
1343        CV_CheckGlError();
1344    }
1345    else
1346    {
1347        gl::EnableClientState(gl::TEXTURE_COORD_ARRAY);
1348        CV_CheckGlError();
1349
1350        texCoord_.bind(ogl::Buffer::ARRAY_BUFFER);
1351
1352        gl::TexCoordPointer(texCoord_.channels(), gl_types[texCoord_.depth()], 0, 0);
1353        CV_CheckGlError();
1354    }
1355
1356    if (normal_.empty())
1357    {
1358        gl::DisableClientState(gl::NORMAL_ARRAY);
1359        CV_CheckGlError();
1360    }
1361    else
1362    {
1363        gl::EnableClientState(gl::NORMAL_ARRAY);
1364        CV_CheckGlError();
1365
1366        normal_.bind(ogl::Buffer::ARRAY_BUFFER);
1367
1368        gl::NormalPointer(gl_types[normal_.depth()], 0, 0);
1369        CV_CheckGlError();
1370    }
1371
1372    if (color_.empty())
1373    {
1374        gl::DisableClientState(gl::COLOR_ARRAY);
1375        CV_CheckGlError();
1376    }
1377    else
1378    {
1379        gl::EnableClientState(gl::COLOR_ARRAY);
1380        CV_CheckGlError();
1381
1382        color_.bind(ogl::Buffer::ARRAY_BUFFER);
1383
1384        const int cn = color_.channels();
1385
1386        gl::ColorPointer(cn, gl_types[color_.depth()], 0, 0);
1387        CV_CheckGlError();
1388    }
1389
1390    if (vertex_.empty())
1391    {
1392        gl::DisableClientState(gl::VERTEX_ARRAY);
1393        CV_CheckGlError();
1394    }
1395    else
1396    {
1397        gl::EnableClientState(gl::VERTEX_ARRAY);
1398        CV_CheckGlError();
1399
1400        vertex_.bind(ogl::Buffer::ARRAY_BUFFER);
1401
1402        gl::VertexPointer(vertex_.channels(), gl_types[vertex_.depth()], 0, 0);
1403        CV_CheckGlError();
1404    }
1405
1406    ogl::Buffer::unbind(ogl::Buffer::ARRAY_BUFFER);
1407#endif
1408}
1409
1410////////////////////////////////////////////////////////////////////////
1411// Rendering
1412
1413void cv::ogl::render(const ogl::Texture2D& tex, Rect_<double> wndRect, Rect_<double> texRect)
1414{
1415#ifndef HAVE_OPENGL
1416    (void) tex;
1417    (void) wndRect;
1418    (void) texRect;
1419    throw_no_ogl();
1420#else
1421    if (!tex.empty())
1422    {
1423        gl::MatrixMode(gl::PROJECTION);
1424        gl::LoadIdentity();
1425        gl::Ortho(0.0, 1.0, 1.0, 0.0, -1.0, 1.0);
1426        CV_CheckGlError();
1427
1428        gl::MatrixMode(gl::MODELVIEW);
1429        gl::LoadIdentity();
1430        CV_CheckGlError();
1431
1432        gl::Disable(gl::LIGHTING);
1433        CV_CheckGlError();
1434
1435        tex.bind();
1436
1437        gl::Enable(gl::TEXTURE_2D);
1438        CV_CheckGlError();
1439
1440        gl::TexEnvi(gl::TEXTURE_ENV, gl::TEXTURE_ENV_MODE, gl::REPLACE);
1441        CV_CheckGlError();
1442
1443        gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MIN_FILTER, gl::LINEAR);
1444        CV_CheckGlError();
1445
1446        const float vertex[] =
1447        {
1448            wndRect.x, wndRect.y, 0.0f,
1449            wndRect.x, (wndRect.y + wndRect.height), 0.0f,
1450            wndRect.x + wndRect.width, (wndRect.y + wndRect.height), 0.0f,
1451            wndRect.x + wndRect.width, wndRect.y, 0.0f
1452        };
1453        const float texCoords[] =
1454        {
1455            texRect.x, texRect.y,
1456            texRect.x, texRect.y + texRect.height,
1457            texRect.x + texRect.width, texRect.y + texRect.height,
1458            texRect.x + texRect.width, texRect.y
1459        };
1460
1461        ogl::Buffer::unbind(ogl::Buffer::ARRAY_BUFFER);
1462
1463        gl::EnableClientState(gl::TEXTURE_COORD_ARRAY);
1464        CV_CheckGlError();
1465
1466        gl::TexCoordPointer(2, gl::FLOAT, 0, texCoords);
1467        CV_CheckGlError();
1468
1469        gl::DisableClientState(gl::NORMAL_ARRAY);
1470        gl::DisableClientState(gl::COLOR_ARRAY);
1471        CV_CheckGlError();
1472
1473        gl::EnableClientState(gl::VERTEX_ARRAY);
1474        CV_CheckGlError();
1475
1476        gl::VertexPointer(3, gl::FLOAT, 0, vertex);
1477        CV_CheckGlError();
1478
1479        gl::DrawArrays(gl::QUADS, 0, 4);
1480        CV_CheckGlError();
1481    }
1482#endif
1483}
1484
1485void cv::ogl::render(const ogl::Arrays& arr, int mode, Scalar color)
1486{
1487#ifndef HAVE_OPENGL
1488    (void) arr;
1489    (void) mode;
1490    (void) color;
1491    throw_no_ogl();
1492#else
1493    if (!arr.empty())
1494    {
1495        gl::Color3d(color[0] / 255.0, color[1] / 255.0, color[2] / 255.0);
1496
1497        arr.bind();
1498
1499        gl::DrawArrays(mode, 0, arr.size());
1500    }
1501#endif
1502}
1503
1504void cv::ogl::render(const ogl::Arrays& arr, InputArray indices, int mode, Scalar color)
1505{
1506#ifndef HAVE_OPENGL
1507    (void) arr;
1508    (void) indices;
1509    (void) mode;
1510    (void) color;
1511    throw_no_ogl();
1512#else
1513    if (!arr.empty() && !indices.empty())
1514    {
1515        gl::Color3d(color[0] / 255.0, color[1] / 255.0, color[2] / 255.0);
1516
1517        arr.bind();
1518
1519        const int kind = indices.kind();
1520
1521        switch (kind)
1522        {
1523        case _InputArray::OPENGL_BUFFER :
1524            {
1525                ogl::Buffer buf = indices.getOGlBuffer();
1526
1527                const int depth = buf.depth();
1528
1529                CV_Assert( buf.channels() == 1 );
1530                CV_Assert( depth <= CV_32S );
1531
1532                GLenum type;
1533                if (depth < CV_16U)
1534                    type = gl::UNSIGNED_BYTE;
1535                else if (depth < CV_32S)
1536                    type = gl::UNSIGNED_SHORT;
1537                else
1538                    type = gl::UNSIGNED_INT;
1539
1540                buf.bind(ogl::Buffer::ELEMENT_ARRAY_BUFFER);
1541
1542                gl::DrawElements(mode, buf.size().area(), type, 0);
1543
1544                ogl::Buffer::unbind(ogl::Buffer::ELEMENT_ARRAY_BUFFER);
1545
1546                break;
1547            }
1548
1549        default:
1550            {
1551                Mat mat = indices.getMat();
1552
1553                const int depth = mat.depth();
1554
1555                CV_Assert( mat.channels() == 1 );
1556                CV_Assert( depth <= CV_32S );
1557                CV_Assert( mat.isContinuous() );
1558
1559                GLenum type;
1560                if (depth < CV_16U)
1561                    type = gl::UNSIGNED_BYTE;
1562                else if (depth < CV_32S)
1563                    type = gl::UNSIGNED_SHORT;
1564                else
1565                    type = gl::UNSIGNED_INT;
1566
1567                ogl::Buffer::unbind(ogl::Buffer::ELEMENT_ARRAY_BUFFER);
1568
1569                gl::DrawElements(mode, mat.size().area(), type, mat.data);
1570            }
1571        }
1572    }
1573#endif
1574}
1575