• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1  //---------------------------------------------------------------------------//
2  // Copyright (c) 2013-2014 Kyle Lutz <kyle.r.lutz@gmail.com>
3  //
4  // Distributed under the Boost Software License, Version 1.0
5  // See accompanying file LICENSE_1_0.txt or copy at
6  // http://www.boost.org/LICENSE_1_0.txt
7  //
8  // See http://boostorg.github.com/compute for more information.
9  //---------------------------------------------------------------------------//
10  
11  #include <iostream>
12  #include <algorithm>
13  
14  #include <QtGlobal>
15  #if QT_VERSION >= 0x050000
16  #include <QtWidgets>
17  #else
18  #include <QtGui>
19  #endif
20  #include <QtOpenGL>
21  
22  #include <boost/program_options.hpp>
23  
24  #ifndef Q_MOC_RUN
25  #include <boost/compute/command_queue.hpp>
26  #include <boost/compute/kernel.hpp>
27  #include <boost/compute/program.hpp>
28  #include <boost/compute/system.hpp>
29  #include <boost/compute/image/image2d.hpp>
30  #include <boost/compute/image/image_sampler.hpp>
31  #include <boost/compute/interop/qt.hpp>
32  #include <boost/compute/interop/opengl.hpp>
33  #include <boost/compute/utility/source.hpp>
34  #endif // Q_MOC_RUN
35  
36  namespace compute = boost::compute;
37  namespace po = boost::program_options;
38  
39  // opencl source code
40  const char source[] = BOOST_COMPUTE_STRINGIZE_SOURCE(
41      __kernel void resize_image(__read_only image2d_t input,
42                                 const sampler_t sampler,
43                                 __write_only image2d_t output)
44      {
45          const uint x = get_global_id(0);
46          const uint y = get_global_id(1);
47  
48          const float w = get_image_width(output);
49          const float h = get_image_height(output);
50  
51          float2 coord = { ((float) x / w) * get_image_width(input),
52                           ((float) y / h) * get_image_height(input) };
53  
54          float4 pixel = read_imagef(input, sampler, coord);
55          write_imagef(output, (int2)(x, h - y - 1), pixel);
56      };
57  );
58  
59  class ImageWidget : public QGLWidget
60  {
61      Q_OBJECT
62  
63  public:
64      ImageWidget(QString fileName, QWidget *parent = 0);
65      ~ImageWidget();
66  
67      void initializeGL();
68      void resizeGL(int width, int height);
69      void paintGL();
70  
71  private:
72      QImage qt_image_;
73      compute::context context_;
74      compute::command_queue queue_;
75      compute::program program_;
76      compute::image2d image_;
77      compute::image_sampler sampler_;
78      GLuint gl_texture_;
79      compute::opengl_texture cl_texture_;
80  };
81  
ImageWidget(QString fileName,QWidget * parent)82  ImageWidget::ImageWidget(QString fileName, QWidget *parent)
83      : QGLWidget(parent),
84        qt_image_(fileName)
85  {
86      gl_texture_ = 0;
87  }
88  
~ImageWidget()89  ImageWidget::~ImageWidget()
90  {
91  }
92  
initializeGL()93  void ImageWidget::initializeGL()
94  {
95      // setup opengl
96      glDisable(GL_LIGHTING);
97  
98      // create the OpenGL/OpenCL shared context
99      context_ = compute::opengl_create_shared_context();
100  
101      // get gpu device
102      compute::device gpu = context_.get_device();
103      std::cout << "device: " << gpu.name() << std::endl;
104  
105      // setup command queue
106      queue_ = compute::command_queue(context_, gpu);
107  
108      // allocate image on the device
109      compute::image_format format =
110          compute::qt_qimage_format_to_image_format(qt_image_.format());
111  
112      image_ = compute::image2d(
113          context_, qt_image_.width(), qt_image_.height(), format, CL_MEM_READ_ONLY
114      );
115  
116      // transfer image to the device
117      compute::qt_copy_qimage_to_image2d(qt_image_, image_, queue_);
118  
119      // setup image sampler (use CL_FILTER_NEAREST to disable linear interpolation)
120      sampler_ = compute::image_sampler(
121          context_, false, CL_ADDRESS_NONE, CL_FILTER_LINEAR
122      );
123  
124      // build resize program
125      program_ = compute::program::build_with_source(source, context_);
126  }
127  
resizeGL(int width,int height)128  void ImageWidget::resizeGL(int width, int height)
129  {
130  #if QT_VERSION >= 0x050000
131      // scale height/width based on device pixel ratio
132      width /= windowHandle()->devicePixelRatio();
133      height /= windowHandle()->devicePixelRatio();
134  #endif
135  
136      // resize viewport
137      glViewport(0, 0, width, height);
138  
139      // delete old texture
140      if(gl_texture_){
141        glDeleteTextures(1, &gl_texture_);
142        gl_texture_ = 0;
143      }
144  
145      // generate new texture
146      glGenTextures(1, &gl_texture_);
147      glBindTexture(GL_TEXTURE_2D, gl_texture_);
148      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
149      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
150      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
151      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
152      glTexImage2D(
153          GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0
154      );
155  
156      // create opencl object for the texture
157      cl_texture_ = compute::opengl_texture(
158          context_, GL_TEXTURE_2D, 0, gl_texture_, CL_MEM_WRITE_ONLY
159      );
160  }
161  
paintGL()162  void ImageWidget::paintGL()
163  {
164      float w = width();
165      float h = height();
166  
167      glMatrixMode(GL_PROJECTION);
168      glLoadIdentity();
169      glOrtho(0.0, w, 0.0, h, -1.0, 1.0);
170      glMatrixMode(GL_MODELVIEW);
171      glLoadIdentity();
172  
173      // setup the resize kernel
174      compute::kernel kernel(program_, "resize_image");
175      kernel.set_arg(0, image_);
176      kernel.set_arg(1, sampler_);
177      kernel.set_arg(2, cl_texture_);
178  
179      // acquire the opengl texture so it can be used in opencl
180      compute::opengl_enqueue_acquire_gl_objects(1, &cl_texture_.get(), queue_);
181  
182      // execute the resize kernel
183      const size_t global_work_offset[] = { 0, 0 };
184      const size_t global_work_size[] = { size_t(width()), size_t(height()) };
185  
186      queue_.enqueue_nd_range_kernel(
187          kernel, 2, global_work_offset, global_work_size, 0
188      );
189  
190      // release the opengl texture so it can be used by opengl
191      compute::opengl_enqueue_release_gl_objects(1, &cl_texture_.get(), queue_);
192  
193      // ensure opencl is finished before rendering in opengl
194      queue_.finish();
195  
196      // draw a single quad with the resized image texture
197      glEnable(GL_TEXTURE_2D);
198      glBindTexture(GL_TEXTURE_2D, gl_texture_);
199  
200      glBegin(GL_QUADS);
201      glTexCoord2f(0, 0); glVertex2f(0, 0);
202      glTexCoord2f(0, 1); glVertex2f(0, h);
203      glTexCoord2f(1, 1); glVertex2f(w, h);
204      glTexCoord2f(1, 0); glVertex2f(w, 0);
205      glEnd();
206  }
207  
208  // the resize image example demonstrates how to interactively resize a
209  // 2D image and display it using OpenGL. a image sampler is used to perform
210  // hardware-accelerated linear interpolation for the resized image.
main(int argc,char * argv[])211  int main(int argc, char *argv[])
212  {
213      // setup command line arguments
214      po::options_description options("options");
215      options.add_options()
216          ("help", "show usage instructions")
217          ("file", po::value<std::string>(), "image file name (e.g. /path/to/image.png)")
218      ;
219      po::positional_options_description positional_options;
220      positional_options.add("file", 1);
221  
222      // parse command line
223      po::variables_map vm;
224      po::store(
225          po::command_line_parser(argc, argv)
226              .options(options)
227              .positional(positional_options)
228              .run(),
229          vm
230      );
231      po::notify(vm);
232  
233      // check for file argument
234      if(vm.count("help") || !vm.count("file")){
235          std::cout << options << std::endl;
236          return -1;
237      }
238  
239      // get file name
240      std::string file_name = vm["file"].as<std::string>();
241  
242      // setup qt application
243      QApplication app(argc, argv);
244  
245      // setup image widget
246      ImageWidget widget(QString::fromStdString(file_name));
247      widget.show();
248  
249      // run qt application
250      return app.exec();
251  }
252  
253  #include "resize_image.moc"
254