• 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