From 7e501c6dffd30b5770e886c3dfc6a33c1738093e Mon Sep 17 00:00:00 2001 From: Rhys Weatherley Date: Fri, 19 Nov 2010 08:04:43 +1000 Subject: Convenience functions for rounding work sizes --- examples/opencl/colorize/colorizewidget.cpp | 2 +- examples/opencl/imagedrawing/imagewidget.cpp | 18 ++++---- examples/opencl/pathdrawing/pathwidget.cpp | 10 ++-- examples/opencl/pathdrawing/pathwidget.h | 1 - src/opencl/qclkernel.cpp | 29 +++++++++++- src/opencl/qclkernel.h | 19 ++++++++ src/opencl/qclworksize.cpp | 27 +++++++++++ src/opencl/qclworksize.h | 2 + tests/auto/qcl/tst_qcl.cpp | 68 ++++++++++++++++++++++++++++ 9 files changed, 156 insertions(+), 20 deletions(-) diff --git a/examples/opencl/colorize/colorizewidget.cpp b/examples/opencl/colorize/colorizewidget.cpp index b5d7c41..4f2f1ab 100644 --- a/examples/opencl/colorize/colorizewidget.cpp +++ b/examples/opencl/colorize/colorizewidget.cpp @@ -58,7 +58,7 @@ ColorizeWidget::ColorizeWidget(QWidget *parent) colorize = program.createKernel("colorize"); colorize.setGlobalWorkSize(img.size()); - colorize.setLocalWorkSize(8, 8); + colorize.setLocalWorkSize(colorize.bestLocalWorkSizeImage2D()); } ColorizeWidget::~ColorizeWidget() diff --git a/examples/opencl/imagedrawing/imagewidget.cpp b/examples/opencl/imagedrawing/imagewidget.cpp index b2770ee..9a3c7c5 100644 --- a/examples/opencl/imagedrawing/imagewidget.cpp +++ b/examples/opencl/imagedrawing/imagewidget.cpp @@ -53,10 +53,10 @@ ImageWidget::ImageWidget(QWidget *parent) program = context.buildProgramFromSourceFile(QLatin1String(":/imagedrawing.cl")); fillRectWithColor = program.createKernel("fillRectWithColor"); - fillRectWithColor.setLocalWorkSize(8, 8); + fillRectWithColor.setLocalWorkSize(fillRectWithColor.bestLocalWorkSizeImage2D()); drawImageKernel = program.createKernel("drawImage"); - drawImageKernel.setLocalWorkSize(8, 8); + drawImageKernel.setLocalWorkSize(drawImageKernel.bestLocalWorkSizeImage2D()); flower = context.createImage2DCopy (QImage(QLatin1String(":/flower.jpg")), QCLMemoryObject::ReadOnly); @@ -104,9 +104,9 @@ void ImageWidget::fillRect(int x, int y, int width, int height, const QColor& color) { // Round up the global work size so we can process the - // rectangle in 8x8 local work size units. The kernel will + // rectangle in local work size units. The kernel will // ignore pixels that are outside the rectangle limits. - fillRectWithColor.setGlobalWorkSize((width + 7) & ~7, (height + 7) & ~7); + fillRectWithColor.setRoundedGlobalWorkSize(width, height); fillRectWithColor(surfaceImage, x, y, x + width, y + height, color); } @@ -126,9 +126,8 @@ void ImageWidget::drawImage(const QCLImage2D& image, int x, int y, float opacity if (srcRect.isEmpty() || dstRect.isEmpty()) return; - // Set the global work size to the destination size rounded up to 8. - drawImageKernel.setGlobalWorkSize - ((dstRect.width() + 7) & ~7, (dstRect.height() + 7) & ~7); + // Set the global work size to the destination size rounded up to local. + drawImageKernel.setRoundedGlobalWorkSize(dstRect.size()); // Draw the image. QVector4D src(srcRect.x(), srcRect.y(), srcRect.width(), srcRect.height()); @@ -158,9 +157,8 @@ void ImageWidget::drawScaledImage if (srcRect.isEmpty() || dstRect.isEmpty()) return; - // Set the global work size to the destination size rounded up to 8. - drawImageKernel.setGlobalWorkSize - ((dstRect.width() + 7) & ~7, (dstRect.height() + 7) & ~7); + // Set the global work size to the destination size rounded up to local. + drawImageKernel.setRoundedGlobalWorkSize(dstRect.size()); // Draw the image. QVector4D src(srcRect.x(), srcRect.y(), srcRect.width(), srcRect.height()); diff --git a/examples/opencl/pathdrawing/pathwidget.cpp b/examples/opencl/pathdrawing/pathwidget.cpp index 070341f..57404e1 100644 --- a/examples/opencl/pathdrawing/pathwidget.cpp +++ b/examples/opencl/pathdrawing/pathwidget.cpp @@ -52,11 +52,7 @@ PathWidget::PathWidget(QWidget *parent) program = context.buildProgramFromSourceFile(QLatin1String(":/pathdrawing.cl")); fillRectWithColor = program.createKernel("fillRectWithColor"); - if (fillRectWithColor.bestLocalWorkSizeImage2D().width() == 8) - workSize = 8; - else - workSize = 1; - fillRectWithColor.setLocalWorkSize(workSize, workSize); + fillRectWithColor.setLocalWorkSize(fillRectWithColor.bestLocalWorkSizeImage2D()); } PathWidget::~PathWidget() @@ -91,8 +87,8 @@ void PathWidget::fillRect(int x, int y, int width, int height, const QColor& color) { // Round up the global work size so we can process the - // rectangle in 8x8 local work size units. The kernel will + // rectangle in local work size units. The kernel will // ignore pixels that are outside the rectangle limits. - fillRectWithColor.setGlobalWorkSize((width + workSize - 1) & ~(workSize - 1), (height + workSize - 1) & ~(workSize - 1)); + fillRectWithColor.setRoundedGlobalWorkSize(width, height); fillRectWithColor(surfaceImage, x, y, x + width, y + height, color); } diff --git a/examples/opencl/pathdrawing/pathwidget.h b/examples/opencl/pathdrawing/pathwidget.h index 512f94a..e084dc4 100644 --- a/examples/opencl/pathdrawing/pathwidget.h +++ b/examples/opencl/pathdrawing/pathwidget.h @@ -60,7 +60,6 @@ private: QCLProgram program; QCLKernel fillRectWithColor; - int workSize; QSize windowSize; QCLImage2D surfaceImage; diff --git a/src/opencl/qclkernel.cpp b/src/opencl/qclkernel.cpp index 58a0db8..e23d820 100644 --- a/src/opencl/qclkernel.cpp +++ b/src/opencl/qclkernel.cpp @@ -418,7 +418,7 @@ QCLWorkSize QCLKernel::globalWorkSize() const /*! Sets the global work size for this instance of the kernel to \a size. - \sa globalWorkSize(), setLocalWorkSize() + \sa globalWorkSize(), setLocalWorkSize(), setRoundedGlobalWorkSize() */ void QCLKernel::setGlobalWorkSize(const QCLWorkSize &size) { @@ -442,6 +442,33 @@ void QCLKernel::setGlobalWorkSize(const QCLWorkSize &size) \a width x \a height x \a depth. */ +/*! + \fn void QCLKernel::setRoundedGlobalWorkSize(const QCLWorkSize &size) + + Sets the global work size for this instance of the kernel to \a size, + after rounding it up to the next multiple of localWorkSize(). + + \sa globalWorkSize(), QCLWorkSize::roundTo() +*/ + +/*! + \fn void QCLKernel::setRoundedGlobalWorkSize(size_t width, size_t height) + \overload + + Sets the global work size for this instance of the kernel to + \a width x \a height, after rounding it up to the next multiple + of localWorkSize(). +*/ + +/*! + \fn void QCLKernel::setRoundedGlobalWorkSize(size_t width, size_t height, size_t depth) + \overload + + Sets the global work size for this instance of the kernel to + \a width x \a height x \a depth, after rounding it up to the + next multiple of localWorkSize(). +*/ + /*! \fn void QCLKernel::setLocalWorkSize(size_t width, size_t height) \overload diff --git a/src/opencl/qclkernel.h b/src/opencl/qclkernel.h index b03676b..e886aa6 100644 --- a/src/opencl/qclkernel.h +++ b/src/opencl/qclkernel.h @@ -101,6 +101,10 @@ public: void setGlobalWorkSize(size_t width, size_t height); void setGlobalWorkSize(size_t width, size_t height, size_t depth); + void setRoundedGlobalWorkSize(const QCLWorkSize &size); + void setRoundedGlobalWorkSize(size_t width, size_t height); + void setRoundedGlobalWorkSize(size_t width, size_t height, size_t depth); + QCLWorkSize localWorkSize() const; void setLocalWorkSize(const QCLWorkSize &size); void setLocalWorkSize(size_t width, size_t height); @@ -298,6 +302,21 @@ inline void QCLKernel::setGlobalWorkSize(size_t width, size_t height, size_t dep setGlobalWorkSize(QCLWorkSize(width, height, depth)); } +inline void QCLKernel::setRoundedGlobalWorkSize(const QCLWorkSize &size) +{ + setGlobalWorkSize(size.roundTo(localWorkSize())); +} + +inline void QCLKernel::setRoundedGlobalWorkSize(size_t width, size_t height) +{ + setRoundedGlobalWorkSize(QCLWorkSize(width, height)); +} + +inline void QCLKernel::setRoundedGlobalWorkSize(size_t width, size_t height, size_t depth) +{ + setRoundedGlobalWorkSize(QCLWorkSize(width, height, depth)); +} + inline void QCLKernel::setLocalWorkSize(size_t width, size_t height) { setLocalWorkSize(QCLWorkSize(width, height)); diff --git a/src/opencl/qclworksize.cpp b/src/opencl/qclworksize.cpp index 840dc39..eb47213 100644 --- a/src/opencl/qclworksize.cpp +++ b/src/opencl/qclworksize.cpp @@ -222,6 +222,33 @@ QCLWorkSize QCLWorkSize::toLocalWorkSize(const QCLDevice &device) const device.maximumWorkItemsPerGroup()); } +static inline size_t qt_cl_round_to(size_t value, size_t multiple) +{ + if (multiple <= 1) + return value; + size_t remainder = value % multiple; + if (!remainder) + return value; + else + return value + multiple - remainder; +} + +/*! + Returns the result of rounding this work size up to a multiple of \a size. +*/ +QCLWorkSize QCLWorkSize::roundTo(const QCLWorkSize &size) const +{ + if (m_dim == 1) + return QCLWorkSize(qt_cl_round_to(m_sizes[0], size.m_sizes[0])); + else if (m_dim == 2) + return QCLWorkSize(qt_cl_round_to(m_sizes[0], size.m_sizes[0]), + qt_cl_round_to(m_sizes[1], size.m_sizes[1])); + else + return QCLWorkSize(qt_cl_round_to(m_sizes[0], size.m_sizes[0]), + qt_cl_round_to(m_sizes[1], size.m_sizes[1]), + qt_cl_round_to(m_sizes[2], size.m_sizes[2])); +} + /*! Returns the string form of this work size, with components separated by 'x'. diff --git a/src/opencl/qclworksize.h b/src/opencl/qclworksize.h index 290197c..d13bfd5 100644 --- a/src/opencl/qclworksize.h +++ b/src/opencl/qclworksize.h @@ -82,6 +82,8 @@ public: (const QCLWorkSize &maxWorkItemSize, size_t maxItemsPerGroup) const; QCLWorkSize toLocalWorkSize(const QCLDevice &device) const; + QCLWorkSize roundTo(const QCLWorkSize &size) const; + QString toString() const; static QCLWorkSize fromString(const QString &str); diff --git a/tests/auto/qcl/tst_qcl.cpp b/tests/auto/qcl/tst_qcl.cpp index 81de300..07d8a02 100644 --- a/tests/auto/qcl/tst_qcl.cpp +++ b/tests/auto/qcl/tst_qcl.cpp @@ -65,6 +65,8 @@ private slots: void eventProfiling(); void sampler(); void workSize(); + void roundWorkSize_data(); + void roundWorkSize(); void imageFormat(); void qimageFormat_data(); void qimageFormat(); @@ -605,6 +607,72 @@ void tst_QCL::workSize() QVERIFY(size4 == QCLWorkSize()); } +// Test QCLWorkSize::roundTo(). +void tst_QCL::roundWorkSize_data() +{ + QTest::addColumn("value"); + QTest::addColumn("multiple"); + QTest::addColumn("result"); + + QTest::newRow("0-20") << 0 << 20 << 0; + QTest::newRow("23-20") << 23 << 20 << 40; + QTest::newRow("23-2") << 23 << 2 << 24; + QTest::newRow("23-1") << 23 << 1 << 23; + QTest::newRow("23-0") << 23 << 0 << 23; +} +void tst_QCL::roundWorkSize() +{ + QFETCH(int, value); + QFETCH(int, multiple); + QFETCH(int, result); + + size_t svalue = size_t(value); + size_t smultiple = size_t(multiple); + size_t sresult = size_t(result); + + QCLWorkSize size1(svalue); + QCLWorkSize size2 = size1.roundTo(smultiple); + QCOMPARE(size2.width(), sresult); + QCOMPARE(size2.height(), size_t(1)); + QCOMPARE(size2.depth(), size_t(1)); + QCOMPARE(size2.dimensions(), size_t(1)); + + QCLWorkSize size3(svalue, 1); + QCLWorkSize size4 = size3.roundTo(QCLWorkSize(smultiple, smultiple)); + QCOMPARE(size4.width(), sresult); + QCOMPARE(size4.height(), smultiple ? smultiple : size_t(1)); + QCOMPARE(size4.depth(), size_t(1)); + QCOMPARE(size4.dimensions(), size_t(2)); + + QCLWorkSize size5(1, svalue); + QCLWorkSize size6 = size5.roundTo(QCLWorkSize(smultiple, smultiple)); + QCOMPARE(size6.width(), smultiple ? smultiple : size_t(1)); + QCOMPARE(size6.height(), sresult); + QCOMPARE(size6.depth(), size_t(1)); + QCOMPARE(size6.dimensions(), size_t(2)); + + QCLWorkSize size7(svalue, 1, 1); + QCLWorkSize size8 = size7.roundTo(QCLWorkSize(smultiple, smultiple, smultiple)); + QCOMPARE(size8.width(), sresult); + QCOMPARE(size8.height(), smultiple ? smultiple : size_t(1)); + QCOMPARE(size8.depth(), smultiple ? smultiple : size_t(1)); + QCOMPARE(size8.dimensions(), size_t(3)); + + QCLWorkSize size9(1, svalue, 1); + QCLWorkSize size10 = size9.roundTo(QCLWorkSize(smultiple, smultiple, smultiple)); + QCOMPARE(size10.width(), smultiple ? smultiple : size_t(1)); + QCOMPARE(size10.height(), sresult); + QCOMPARE(size10.depth(), smultiple ? smultiple : size_t(1)); + QCOMPARE(size10.dimensions(), size_t(3)); + + QCLWorkSize size11(1, 1, svalue); + QCLWorkSize size12 = size11.roundTo(QCLWorkSize(smultiple, smultiple, smultiple)); + QCOMPARE(size12.width(), smultiple ? smultiple : size_t(1)); + QCOMPARE(size12.height(), smultiple ? smultiple : size_t(1)); + QCOMPARE(size12.depth(), sresult); + QCOMPARE(size12.dimensions(), size_t(3)); +} + // Test QCLImageFormat. void tst_QCL::imageFormat() { -- cgit v1.2.3