Refactoring of tiles opencl implementation:
[blender.git] / source / blender / compositor / operations / COM_WriteBufferOperation.cpp
1 /*
2  * Copyright 2011, Blender Foundation.
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * Contributor: 
19  *              Jeroen Bakker 
20  *              Monique Dewanchand
21  */
22
23 #include "COM_WriteBufferOperation.h"
24 #include "COM_defines.h"
25 #include <stdio.h>
26 #include "COM_OpenCLDevice.h"
27
28 WriteBufferOperation::WriteBufferOperation() : NodeOperation()
29 {
30         this->addInputSocket(COM_DT_COLOR);
31         this->memoryProxy = new MemoryProxy();
32         this->memoryProxy->setWriteBufferOperation(this);
33         this->memoryProxy->setExecutor(NULL);
34 }
35 WriteBufferOperation::~WriteBufferOperation()
36 {
37         if (this->memoryProxy) {
38                 delete this->memoryProxy;
39                 this->memoryProxy = NULL;
40         }
41 }
42
43 void WriteBufferOperation::executePixel(float *color, float x, float y, PixelSampler sampler, MemoryBuffer *inputBuffers[])
44 {
45         input->read(color, x, y, sampler, inputBuffers);
46 }
47
48 void WriteBufferOperation::initExecution()
49 {
50         this->input = this->getInputOperation(0);
51         this->memoryProxy->allocate(this->width, this->height);
52 }
53
54 void WriteBufferOperation::deinitExecution()
55 {
56         this->input = NULL;
57         this->memoryProxy->free();
58 }
59
60 void WriteBufferOperation::executeRegion(rcti *rect, unsigned int tileNumber, MemoryBuffer **memoryBuffers)
61 {
62         //MemoryBuffer *memoryBuffer = MemoryManager::getMemoryBuffer(this->getMemoryProxy(), tileNumber);
63         MemoryBuffer *memoryBuffer = this->memoryProxy->getBuffer();
64         float *buffer = memoryBuffer->getBuffer();
65         if (this->input->isComplex()) {
66                 void *data = this->input->initializeTileData(rect, memoryBuffers);
67                 int x1 = rect->xmin;
68                 int y1 = rect->ymin;
69                 int x2 = rect->xmax;
70                 int y2 = rect->ymax;
71                 int x;
72                 int y;
73                 bool breaked = false;
74                 for (y = y1; y < y2 && (!breaked); y++) {
75                         int offset4 = (y * memoryBuffer->getWidth() + x1) * COM_NUMBER_OF_CHANNELS;
76                         for (x = x1; x < x2; x++) {
77                                 input->read(&(buffer[offset4]), x, y, memoryBuffers, data);
78                                 offset4 += COM_NUMBER_OF_CHANNELS;
79
80                         }
81                         if (isBreaked()) {
82                                 breaked = true;
83                         }
84
85                 }
86                 if (data) {
87                         this->input->deinitializeTileData(rect, memoryBuffers, data);
88                         data = NULL;
89                 }
90         }
91         else {
92                 int x1 = rect->xmin;
93                 int y1 = rect->ymin;
94                 int x2 = rect->xmax;
95                 int y2 = rect->ymax;
96
97                 int x;
98                 int y;
99                 bool breaked = false;
100                 for (y = y1; y < y2 && (!breaked); y++) {
101                         int offset4 = (y * memoryBuffer->getWidth() + x1) * COM_NUMBER_OF_CHANNELS;
102                         for (x = x1; x < x2; x++) {
103                                 input->read(&(buffer[offset4]), x, y, COM_PS_NEAREST, memoryBuffers);
104                                 offset4 += COM_NUMBER_OF_CHANNELS;
105                         }
106                         if (isBreaked()) {
107                                 breaked = true;
108                         }
109                 }
110         }
111         memoryBuffer->setCreatedState();
112 }
113
114 void WriteBufferOperation::executeOpenCLRegion(OpenCLDevice* device, rcti *rect, unsigned int chunkNumber, MemoryBuffer **inputMemoryBuffers, MemoryBuffer *outputBuffer)
115 {
116         float *outputFloatBuffer = outputBuffer->getBuffer();
117         cl_int error;
118         /*
119          * 1. create cl_mem from outputbuffer
120          * 2. call NodeOperation (input) executeOpenCLChunk(.....)
121          * 3. schedule readback from opencl to main device (outputbuffer)
122          * 4. schedule native callback
123          *
124          * note: list of cl_mem will be filled by 2, and needs to be cleaned up by 4
125          */
126         // STEP 1
127         const unsigned int outputBufferWidth = outputBuffer->getWidth();
128         const unsigned int outputBufferHeight = outputBuffer->getHeight();
129
130         const cl_image_format imageFormat = {
131                 CL_RGBA,
132                 CL_FLOAT
133         };
134
135         cl_mem clOutputBuffer = clCreateImage2D(device->getContext(), CL_MEM_WRITE_ONLY | CL_MEM_USE_HOST_PTR, &imageFormat, outputBufferWidth, outputBufferHeight, 0, outputFloatBuffer, &error);
136         if (error != CL_SUCCESS) { printf("CLERROR[%d]: %s\n", error, clewErrorString(error));  }
137         
138         // STEP 2
139         list<cl_mem> *clMemToCleanUp = new list<cl_mem>();
140         clMemToCleanUp->push_back(clOutputBuffer);
141         list<cl_kernel> *clKernelsToCleanUp = new list<cl_kernel>();
142
143         this->input->executeOpenCL(device, outputBuffer, clOutputBuffer, inputMemoryBuffers, clMemToCleanUp, clKernelsToCleanUp);
144
145         // STEP 3
146
147         size_t origin[3] = {0, 0, 0};
148         size_t region[3] = {outputBufferWidth, outputBufferHeight, 1};
149
150 //      clFlush(queue);
151 //      clFinish(queue);
152
153         error = clEnqueueBarrier(device->getQueue());
154         if (error != CL_SUCCESS) { printf("CLERROR[%d]: %s\n", error, clewErrorString(error));  }
155         error = clEnqueueReadImage(device->getQueue(), clOutputBuffer, CL_TRUE, origin, region, 0, 0, outputFloatBuffer, 0, NULL, NULL);
156         if (error != CL_SUCCESS) { printf("CLERROR[%d]: %s\n", error, clewErrorString(error));  }
157         
158         this->getMemoryProxy()->getBuffer()->copyContentFrom(outputBuffer);
159         
160         // STEP 4
161
162         
163         while (clMemToCleanUp->size() > 0) {
164                 cl_mem mem = clMemToCleanUp->front();
165                 error = clReleaseMemObject(mem);
166                 if (error != CL_SUCCESS) { printf("CLERROR[%d]: %s\n", error, clewErrorString(error));  }
167                 clMemToCleanUp->pop_front();
168         }
169
170         while (clKernelsToCleanUp->size() > 0) {
171                 cl_kernel kernel = clKernelsToCleanUp->front();
172                 error = clReleaseKernel(kernel);
173                 if (error != CL_SUCCESS) { printf("CLERROR[%d]: %s\n", error, clewErrorString(error));  }
174                 clKernelsToCleanUp->pop_front();
175         }
176         delete clKernelsToCleanUp;
177 }
178
179 void WriteBufferOperation::readResolutionFromInputSocket()
180 {
181         NodeOperation *inputOperation = this->getInputOperation(0);
182         this->setWidth(inputOperation->getWidth());
183         this->setHeight(inputOperation->getHeight());
184 }