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