Blender  V2.93
COM_BokehBlurOperation.cc
Go to the documentation of this file.
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  *
16  * Copyright 2011, Blender Foundation.
17  */
18 
19 #include "COM_BokehBlurOperation.h"
20 #include "BLI_math.h"
21 #include "COM_OpenCLDevice.h"
22 
23 #include "RE_pipeline.h"
24 
25 namespace blender::compositor {
26 
28 {
34 
35  flags.complex = true;
36  flags.open_cl = true;
37 
38  this->m_size = 1.0f;
39  this->m_sizeavailable = false;
40  this->m_inputProgram = nullptr;
41  this->m_inputBokehProgram = nullptr;
42  this->m_inputBoundingBoxReader = nullptr;
43 
44  this->m_extend_bounds = false;
45 }
46 
48 {
49  lockMutex();
50  if (!this->m_sizeavailable) {
51  updateSize();
52  }
53  void *buffer = getInputOperation(0)->initializeTileData(nullptr);
54  unlockMutex();
55  return buffer;
56 }
57 
59 {
60  initMutex();
61  this->m_inputProgram = getInputSocketReader(0);
62  this->m_inputBokehProgram = getInputSocketReader(1);
63  this->m_inputBoundingBoxReader = getInputSocketReader(2);
64 
65  int width = this->m_inputBokehProgram->getWidth();
66  int height = this->m_inputBokehProgram->getHeight();
67 
68  float dimension = MIN2(width, height);
69 
70  this->m_bokehMidX = width / 2.0f;
71  this->m_bokehMidY = height / 2.0f;
72  this->m_bokehDimension = dimension / 2.0f;
74 }
75 
76 void BokehBlurOperation::executePixel(float output[4], int x, int y, void *data)
77 {
78  float color_accum[4];
79  float tempBoundingBox[4];
80  float bokeh[4];
81 
82  this->m_inputBoundingBoxReader->readSampled(tempBoundingBox, x, y, PixelSampler::Nearest);
83  if (tempBoundingBox[0] > 0.0f) {
84  float multiplier_accum[4] = {0.0f, 0.0f, 0.0f, 0.0f};
85  MemoryBuffer *inputBuffer = (MemoryBuffer *)data;
86  const rcti &input_rect = inputBuffer->get_rect();
87  float *buffer = inputBuffer->getBuffer();
88  int bufferwidth = inputBuffer->getWidth();
89  int bufferstartx = input_rect.xmin;
90  int bufferstarty = input_rect.ymin;
91  const float max_dim = MAX2(this->getWidth(), this->getHeight());
92  int pixelSize = this->m_size * max_dim / 100.0f;
93  zero_v4(color_accum);
94 
95  if (pixelSize < 2) {
96  this->m_inputProgram->readSampled(color_accum, x, y, PixelSampler::Nearest);
97  multiplier_accum[0] = 1.0f;
98  multiplier_accum[1] = 1.0f;
99  multiplier_accum[2] = 1.0f;
100  multiplier_accum[3] = 1.0f;
101  }
102  int miny = y - pixelSize;
103  int maxy = y + pixelSize;
104  int minx = x - pixelSize;
105  int maxx = x + pixelSize;
106  miny = MAX2(miny, input_rect.ymin);
107  minx = MAX2(minx, input_rect.xmin);
108  maxy = MIN2(maxy, input_rect.ymax);
109  maxx = MIN2(maxx, input_rect.xmax);
110 
111  int step = getStep();
112  int offsetadd = getOffsetAdd() * COM_DATA_TYPE_COLOR_CHANNELS;
113 
114  float m = this->m_bokehDimension / pixelSize;
115  for (int ny = miny; ny < maxy; ny += step) {
116  int bufferindex = ((minx - bufferstartx) * COM_DATA_TYPE_COLOR_CHANNELS) +
117  ((ny - bufferstarty) * COM_DATA_TYPE_COLOR_CHANNELS * bufferwidth);
118  for (int nx = minx; nx < maxx; nx += step) {
119  float u = this->m_bokehMidX - (nx - x) * m;
120  float v = this->m_bokehMidY - (ny - y) * m;
121  this->m_inputBokehProgram->readSampled(bokeh, u, v, PixelSampler::Nearest);
122  madd_v4_v4v4(color_accum, bokeh, &buffer[bufferindex]);
123  add_v4_v4(multiplier_accum, bokeh);
124  bufferindex += offsetadd;
125  }
126  }
127  output[0] = color_accum[0] * (1.0f / multiplier_accum[0]);
128  output[1] = color_accum[1] * (1.0f / multiplier_accum[1]);
129  output[2] = color_accum[2] * (1.0f / multiplier_accum[2]);
130  output[3] = color_accum[3] * (1.0f / multiplier_accum[3]);
131  }
132  else {
133  this->m_inputProgram->readSampled(output, x, y, PixelSampler::Nearest);
134  }
135 }
136 
138 {
139  deinitMutex();
140  this->m_inputProgram = nullptr;
141  this->m_inputBokehProgram = nullptr;
142  this->m_inputBoundingBoxReader = nullptr;
143 }
144 
146  ReadBufferOperation *readOperation,
147  rcti *output)
148 {
149  rcti newInput;
150  rcti bokehInput;
151  const float max_dim = MAX2(this->getWidth(), this->getHeight());
152 
153  if (this->m_sizeavailable) {
154  newInput.xmax = input->xmax + (this->m_size * max_dim / 100.0f);
155  newInput.xmin = input->xmin - (this->m_size * max_dim / 100.0f);
156  newInput.ymax = input->ymax + (this->m_size * max_dim / 100.0f);
157  newInput.ymin = input->ymin - (this->m_size * max_dim / 100.0f);
158  }
159  else {
160  newInput.xmax = input->xmax + (10.0f * max_dim / 100.0f);
161  newInput.xmin = input->xmin - (10.0f * max_dim / 100.0f);
162  newInput.ymax = input->ymax + (10.0f * max_dim / 100.0f);
163  newInput.ymin = input->ymin - (10.0f * max_dim / 100.0f);
164  }
165 
166  NodeOperation *operation = getInputOperation(1);
167  bokehInput.xmax = operation->getWidth();
168  bokehInput.xmin = 0;
169  bokehInput.ymax = operation->getHeight();
170  bokehInput.ymin = 0;
171  if (operation->determineDependingAreaOfInterest(&bokehInput, readOperation, output)) {
172  return true;
173  }
174  operation = getInputOperation(0);
175  if (operation->determineDependingAreaOfInterest(&newInput, readOperation, output)) {
176  return true;
177  }
178  operation = getInputOperation(2);
179  if (operation->determineDependingAreaOfInterest(input, readOperation, output)) {
180  return true;
181  }
182  if (!this->m_sizeavailable) {
183  rcti sizeInput;
184  sizeInput.xmin = 0;
185  sizeInput.ymin = 0;
186  sizeInput.xmax = 5;
187  sizeInput.ymax = 5;
188  operation = getInputOperation(3);
189  if (operation->determineDependingAreaOfInterest(&sizeInput, readOperation, output)) {
190  return true;
191  }
192  }
193  return false;
194 }
195 
197  MemoryBuffer *outputMemoryBuffer,
198  cl_mem clOutputBuffer,
199  MemoryBuffer **inputMemoryBuffers,
200  std::list<cl_mem> *clMemToCleanUp,
201  std::list<cl_kernel> * /*clKernelsToCleanUp*/)
202 {
203  cl_kernel kernel = device->COM_clCreateKernel("bokehBlurKernel", nullptr);
204  if (!this->m_sizeavailable) {
205  updateSize();
206  }
207  const float max_dim = MAX2(this->getWidth(), this->getHeight());
208  cl_int radius = this->m_size * max_dim / 100.0f;
209  cl_int step = this->getStep();
210 
212  kernel, 0, -1, clMemToCleanUp, inputMemoryBuffers, this->m_inputBoundingBoxReader);
214  kernel, 1, 4, clMemToCleanUp, inputMemoryBuffers, this->m_inputProgram);
216  kernel, 2, -1, clMemToCleanUp, inputMemoryBuffers, this->m_inputBokehProgram);
217  device->COM_clAttachOutputMemoryBufferToKernelParameter(kernel, 3, clOutputBuffer);
218  device->COM_clAttachMemoryBufferOffsetToKernelParameter(kernel, 5, outputMemoryBuffer);
219  clSetKernelArg(kernel, 6, sizeof(cl_int), &radius);
220  clSetKernelArg(kernel, 7, sizeof(cl_int), &step);
221  device->COM_clAttachSizeToKernelParameter(kernel, 8, this);
222 
223  device->COM_clEnqueueRange(kernel, outputMemoryBuffer, 9, this);
224 }
225 
226 void BokehBlurOperation::updateSize()
227 {
228  if (!this->m_sizeavailable) {
229  float result[4];
230  this->getInputSocketReader(3)->readSampled(result, 0, 0, PixelSampler::Nearest);
231  this->m_size = result[0];
232  CLAMP(this->m_size, 0.0f, 10.0f);
233  this->m_sizeavailable = true;
234  }
235 }
236 
237 void BokehBlurOperation::determineResolution(unsigned int resolution[2],
238  unsigned int preferredResolution[2])
239 {
240  NodeOperation::determineResolution(resolution, preferredResolution);
241  if (this->m_extend_bounds) {
242  const float max_dim = MAX2(resolution[0], resolution[1]);
243  resolution[0] += 2 * this->m_size * max_dim / 100.0f;
244  resolution[1] += 2 * this->m_size * max_dim / 100.0f;
245  }
246 }
247 
248 } // namespace blender::compositor
MINLINE void add_v4_v4(float r[4], const float a[4])
MINLINE void madd_v4_v4v4(float r[4], const float a[4], const float b[4])
MINLINE void zero_v4(float r[4])
#define MAX2(a, b)
#define MIN2(a, b)
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint GLsizei GLsizei GLenum type _GL_VOID_RET _GL_VOID GLsizei GLenum GLenum const void *pixels _GL_VOID_RET _GL_VOID const void *pointer _GL_VOID_RET _GL_VOID GLdouble v _GL_VOID_RET _GL_VOID GLfloat v _GL_VOID_RET _GL_VOID GLint GLint i2 _GL_VOID_RET _GL_VOID GLint j _GL_VOID_RET _GL_VOID GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble GLdouble GLdouble zFar _GL_VOID_RET _GL_UINT GLdouble *equation _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLenum GLfloat *v _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLfloat *values _GL_VOID_RET _GL_VOID GLushort *values _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLenum GLdouble *params _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_BOOL GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLushort pattern _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble u2 _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLdouble GLdouble v2 _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLdouble ny
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint GLsizei width
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei height
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint y
Group RGB to Bright Vector Camera CLAMP
ATTR_WARN_UNUSED_RESULT const BMVert * v
#define output
void executePixel(float output[4], int x, int y, void *data) override
void determineResolution(unsigned int resolution[2], unsigned int preferredResolution[2]) override
determine the resolution of this node
void executeOpenCL(OpenCLDevice *device, MemoryBuffer *outputMemoryBuffer, cl_mem clOutputBuffer, MemoryBuffer **inputMemoryBuffers, std::list< cl_mem > *clMemToCleanUp, std::list< cl_kernel > *clKernelsToCleanUp) override
custom handle to add new tasks to the OpenCL command queue in order to execute a chunk on an GPUDevic...
bool determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, rcti *output) override
void * initializeTileData(rcti *rect) override
a MemoryBuffer contains access to the data of a chunk
const rcti & get_rect() const
get the rect of this MemoryBuffer
const int getWidth() const
get the width of this MemoryBuffer
float * getBuffer()
get the data of this MemoryBuffer
NodeOperation contains calculation logic.
virtual void * initializeTileData(rcti *)
void readSampled(float result[4], float x, float y, PixelSampler sampler)
void addInputSocket(DataType datatype, ResizeMode resize_mode=ResizeMode::Center)
NodeOperation * getInputOperation(unsigned int inputSocketindex)
void addOutputSocket(DataType datatype)
virtual void determineResolution(unsigned int resolution[2], unsigned int preferredResolution[2])
determine the resolution of this node
SocketReader * getInputSocketReader(unsigned int inputSocketindex)
virtual bool determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, rcti *output)
device representing an GPU OpenCL device. an instance of this class represents a single cl_device
void COM_clAttachMemoryBufferOffsetToKernelParameter(cl_kernel kernel, int offsetIndex, MemoryBuffer *memoryBuffers)
cl_mem COM_clAttachMemoryBufferToKernelParameter(cl_kernel kernel, int parameterIndex, int offsetIndex, std::list< cl_mem > *cleanup, MemoryBuffer **inputMemoryBuffers, SocketReader *reader)
void COM_clEnqueueRange(cl_kernel kernel, MemoryBuffer *outputMemoryBuffer)
void COM_clAttachOutputMemoryBufferToKernelParameter(cl_kernel kernel, int parameterIndex, cl_mem clOutputMemoryBuffer)
void COM_clAttachSizeToKernelParameter(cl_kernel kernel, int offsetIndex, NodeOperation *operation)
cl_kernel COM_clCreateKernel(const char *kernelname, std::list< cl_kernel > *clKernelsToCleanUp)
@ None
The bottom left of the input image is the bottom left of the working area of the node,...
__kernel void ccl_constant KernelData ccl_global void ccl_global char ccl_global int ccl_global char ccl_global unsigned int ccl_global float * buffer
constexpr int COM_DATA_TYPE_COLOR_CHANNELS
Definition: COM_defines.h:53
int ymin
Definition: DNA_vec_types.h:80
int ymax
Definition: DNA_vec_types.h:80
int xmin
Definition: DNA_vec_types.h:79
int xmax
Definition: DNA_vec_types.h:79