122 lines
4.5 KiB
C++
122 lines
4.5 KiB
C++
|
|
|
|
#ifndef _ofxsProcessing_h_
|
|
#define _ofxsProcessing_h_
|
|
|
|
// Copyright OpenFX and contributors to the OpenFX project.
|
|
// SPDX-License-Identifier: BSD-3-Clause
|
|
|
|
#include <cassert>
|
|
#include <algorithm>
|
|
|
|
#include "ofxsImageEffect.h"
|
|
#include "ofxsMultiThread.h"
|
|
|
|
/** @file This file contains a useful base class that can be used to process images
|
|
|
|
The code below is not so much a skin on the base OFX classes, but code used in implementing
|
|
specific image processing algorithms. As such it does not sit in the support include lib, but in
|
|
its own include directory.
|
|
*/
|
|
|
|
namespace OFX {
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// base class to process images with
|
|
class ImageProcessor : public OFX::MultiThread::Processor {
|
|
protected :
|
|
OFX::ImageEffect &_effect; /**< @brief effect to render with */
|
|
OFX::Image *_dstImg; /**< @brief image to process into */
|
|
OfxRectI _renderWindow; /**< @brief render window to use */
|
|
|
|
public :
|
|
/** @brief ctor */
|
|
ImageProcessor(OFX::ImageEffect &effect)
|
|
: _effect(effect)
|
|
, _dstImg(0)
|
|
{
|
|
_renderWindow.x1 = _renderWindow.y1 = _renderWindow.x2 = _renderWindow.y2 = 0;
|
|
}
|
|
|
|
/** @brief set the destination image */
|
|
void setDstImg(OFX::Image *v) {_dstImg = v; }
|
|
|
|
/** @brief reset the render window */
|
|
void setRenderWindow(OfxRectI rect) {_renderWindow = rect;}
|
|
|
|
/** @brief overridden from OFX::MultiThread::Processor. This function is called once on each SMP thread by the base class */
|
|
void multiThreadFunction(unsigned int threadId, unsigned int nThreads)
|
|
{
|
|
// slice the y range into the number of threads it has
|
|
unsigned int dy = _renderWindow.y2 - _renderWindow.y1;
|
|
// the following is equivalent to std::ceil(dy/(double)nThreads);
|
|
unsigned int h = (dy+nThreads-1)/nThreads;
|
|
if (h == 0) {
|
|
// there are more threads than lines to process
|
|
h = 1;
|
|
}
|
|
if (threadId * h >= dy) {
|
|
// empty render subwindow
|
|
return;
|
|
}
|
|
unsigned int y1 = _renderWindow.y1 + threadId * h;
|
|
|
|
unsigned int step = (threadId + 1) * h;
|
|
unsigned int y2 = _renderWindow.y1 + (step < dy ? step : dy);
|
|
|
|
OfxRectI win = _renderWindow;
|
|
win.y1 = y1; win.y2 = y2;
|
|
|
|
// and render that thread on each
|
|
multiThreadProcessImages(win);
|
|
}
|
|
|
|
/** @brief called before any MP is done */
|
|
virtual void preProcess(void) {}
|
|
|
|
/** @brief this is called by multiThreadFunction to actually process images, override in derived classes */
|
|
virtual void multiThreadProcessImages(OfxRectI window) = 0;
|
|
|
|
/** @brief called before any MP is done */
|
|
virtual void postProcess(void) {}
|
|
|
|
/** @brief called to process everything */
|
|
virtual void process(void)
|
|
{
|
|
// If _dstImg was set, check that the _renderWindow is lying into dstBounds
|
|
if (_dstImg) {
|
|
const OfxRectI& dstBounds = _dstImg->getBounds();
|
|
// is the renderWindow within dstBounds ?
|
|
assert(dstBounds.x1 <= _renderWindow.x1 && _renderWindow.x2 <= dstBounds.x2 &&
|
|
dstBounds.y1 <= _renderWindow.y1 && _renderWindow.y2 <= dstBounds.y2);
|
|
// exit gracefully in case of error
|
|
if (!(dstBounds.x1 <= _renderWindow.x1 && _renderWindow.x2 <= dstBounds.x2 &&
|
|
dstBounds.y1 <= _renderWindow.y1 && _renderWindow.y2 <= dstBounds.y2) ||
|
|
(_renderWindow.x1 >= _renderWindow.x2) ||
|
|
(_renderWindow.y1 >= _renderWindow.y2)) {
|
|
return;
|
|
}
|
|
}
|
|
|
|
// call the pre MP pass
|
|
preProcess();
|
|
|
|
// make sure there are at least 4096 pixels per CPU and at least 1 line par CPU
|
|
unsigned int nCPUs = (std::min(_renderWindow.x2 - _renderWindow.x1, 4096) *
|
|
(_renderWindow.y2 - _renderWindow.y1)) / 4096;
|
|
// make sure the number of CPUs is valid (and use at least 1 CPU)
|
|
nCPUs = std::max(1u, std::min(nCPUs, OFX::MultiThread::getNumCPUs()));
|
|
|
|
// call the base multi threading code, should put a pre & post thread calls in too
|
|
multiThread(nCPUs);
|
|
|
|
// call the post MP pass
|
|
postProcess();
|
|
}
|
|
|
|
};
|
|
|
|
|
|
};
|
|
#endif
|