diff options
Diffstat (limited to 'source/blender/compositor/operations/COM_WriteBufferOperation.cc')
-rw-r--r-- | source/blender/compositor/operations/COM_WriteBufferOperation.cc | 228 |
1 files changed, 228 insertions, 0 deletions
diff --git a/source/blender/compositor/operations/COM_WriteBufferOperation.cc b/source/blender/compositor/operations/COM_WriteBufferOperation.cc new file mode 100644 index 00000000000..8d38dbfe180 --- /dev/null +++ b/source/blender/compositor/operations/COM_WriteBufferOperation.cc @@ -0,0 +1,228 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Copyright 2011, Blender Foundation. + */ + +#include "COM_WriteBufferOperation.h" +#include "COM_OpenCLDevice.h" +#include "COM_defines.h" +#include <cstdio> + +WriteBufferOperation::WriteBufferOperation(DataType datatype) +{ + this->addInputSocket(datatype); + this->m_memoryProxy = new MemoryProxy(datatype); + this->m_memoryProxy->setWriteBufferOperation(this); + this->m_memoryProxy->setExecutor(nullptr); +} +WriteBufferOperation::~WriteBufferOperation() +{ + if (this->m_memoryProxy) { + delete this->m_memoryProxy; + this->m_memoryProxy = nullptr; + } +} + +void WriteBufferOperation::executePixelSampled(float output[4], + float x, + float y, + PixelSampler sampler) +{ + this->m_input->readSampled(output, x, y, sampler); +} + +void WriteBufferOperation::initExecution() +{ + this->m_input = this->getInputOperation(0); + this->m_memoryProxy->allocate(this->m_width, this->m_height); +} + +void WriteBufferOperation::deinitExecution() +{ + this->m_input = nullptr; + this->m_memoryProxy->free(); +} + +void WriteBufferOperation::executeRegion(rcti *rect, unsigned int /*tileNumber*/) +{ + MemoryBuffer *memoryBuffer = this->m_memoryProxy->getBuffer(); + float *buffer = memoryBuffer->getBuffer(); + const int num_channels = memoryBuffer->get_num_channels(); + if (this->m_input->isComplex()) { + void *data = this->m_input->initializeTileData(rect); + int x1 = rect->xmin; + int y1 = rect->ymin; + int x2 = rect->xmax; + int y2 = rect->ymax; + int x; + int y; + bool breaked = false; + for (y = y1; y < y2 && (!breaked); y++) { + int offset4 = (y * memoryBuffer->getWidth() + x1) * num_channels; + for (x = x1; x < x2; x++) { + this->m_input->read(&(buffer[offset4]), x, y, data); + offset4 += num_channels; + } + if (isBraked()) { + breaked = true; + } + } + if (data) { + this->m_input->deinitializeTileData(rect, data); + data = nullptr; + } + } + else { + int x1 = rect->xmin; + int y1 = rect->ymin; + int x2 = rect->xmax; + int y2 = rect->ymax; + + int x; + int y; + bool breaked = false; + for (y = y1; y < y2 && (!breaked); y++) { + int offset4 = (y * memoryBuffer->getWidth() + x1) * num_channels; + for (x = x1; x < x2; x++) { + this->m_input->readSampled(&(buffer[offset4]), x, y, COM_PS_NEAREST); + offset4 += num_channels; + } + if (isBraked()) { + breaked = true; + } + } + } + memoryBuffer->setCreatedState(); +} + +void WriteBufferOperation::executeOpenCLRegion(OpenCLDevice *device, + rcti * /*rect*/, + unsigned int /*chunkNumber*/, + MemoryBuffer **inputMemoryBuffers, + MemoryBuffer *outputBuffer) +{ + float *outputFloatBuffer = outputBuffer->getBuffer(); + cl_int error; + /* + * 1. create cl_mem from outputbuffer + * 2. call NodeOperation (input) executeOpenCLChunk(.....) + * 3. schedule read back from opencl to main device (outputbuffer) + * 4. schedule native callback + * + * note: list of cl_mem will be filled by 2, and needs to be cleaned up by 4 + */ + // STEP 1 + const unsigned int outputBufferWidth = outputBuffer->getWidth(); + const unsigned int outputBufferHeight = outputBuffer->getHeight(); + + const cl_image_format *imageFormat = OpenCLDevice::determineImageFormat(outputBuffer); + + cl_mem clOutputBuffer = clCreateImage2D(device->getContext(), + CL_MEM_WRITE_ONLY | CL_MEM_USE_HOST_PTR, + imageFormat, + outputBufferWidth, + outputBufferHeight, + 0, + outputFloatBuffer, + &error); + if (error != CL_SUCCESS) { + printf("CLERROR[%d]: %s\n", error, clewErrorString(error)); + } + + // STEP 2 + std::list<cl_mem> *clMemToCleanUp = new std::list<cl_mem>(); + clMemToCleanUp->push_back(clOutputBuffer); + std::list<cl_kernel> *clKernelsToCleanUp = new std::list<cl_kernel>(); + + this->m_input->executeOpenCL(device, + outputBuffer, + clOutputBuffer, + inputMemoryBuffers, + clMemToCleanUp, + clKernelsToCleanUp); + + // STEP 3 + + size_t origin[3] = {0, 0, 0}; + size_t region[3] = {outputBufferWidth, outputBufferHeight, 1}; + + // clFlush(queue); + // clFinish(queue); + + error = clEnqueueBarrier(device->getQueue()); + if (error != CL_SUCCESS) { + printf("CLERROR[%d]: %s\n", error, clewErrorString(error)); + } + error = clEnqueueReadImage(device->getQueue(), + clOutputBuffer, + CL_TRUE, + origin, + region, + 0, + 0, + outputFloatBuffer, + 0, + nullptr, + nullptr); + if (error != CL_SUCCESS) { + printf("CLERROR[%d]: %s\n", error, clewErrorString(error)); + } + + this->getMemoryProxy()->getBuffer()->copyContentFrom(outputBuffer); + + // STEP 4 + while (!clMemToCleanUp->empty()) { + cl_mem mem = clMemToCleanUp->front(); + error = clReleaseMemObject(mem); + if (error != CL_SUCCESS) { + printf("CLERROR[%d]: %s\n", error, clewErrorString(error)); + } + clMemToCleanUp->pop_front(); + } + + while (!clKernelsToCleanUp->empty()) { + cl_kernel kernel = clKernelsToCleanUp->front(); + error = clReleaseKernel(kernel); + if (error != CL_SUCCESS) { + printf("CLERROR[%d]: %s\n", error, clewErrorString(error)); + } + clKernelsToCleanUp->pop_front(); + } + delete clKernelsToCleanUp; +} + +void WriteBufferOperation::determineResolution(unsigned int resolution[2], + unsigned int preferredResolution[2]) +{ + NodeOperation::determineResolution(resolution, preferredResolution); + /* make sure there is at least one pixel stored in case the input is a single value */ + m_single_value = false; + if (resolution[0] == 0) { + resolution[0] = 1; + m_single_value = true; + } + if (resolution[1] == 0) { + resolution[1] = 1; + m_single_value = true; + } +} + +void WriteBufferOperation::readResolutionFromInputSocket() +{ + NodeOperation *inputOperation = this->getInputOperation(0); + this->setWidth(inputOperation->getWidth()); + this->setHeight(inputOperation->getHeight()); +} |