resize_image.cpp 7.2 KB

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