191b21b921743173df486bb850312118ee252534
[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->m_memoryProxy = new MemoryProxy();
32         this->m_memoryProxy->setWriteBufferOperation(this);
33         this->m_memoryProxy->setExecutor(NULL);
34 }
35 WriteBufferOperation::~WriteBufferOperation()
36 {
37         if (this->m_memoryProxy) {
38                 delete this->m_memoryProxy;
39                 this->m_memoryProxy = NULL;
40         }
41 }
42
43 void WriteBufferOperation::executePixel(float *color, float x, float y, PixelSampler sampler, MemoryBuffer *inputBuffers[])
44 {
45         this->m_input->read(color, x, y, sampler, inputBuffers);
46 }
47
48 void WriteBufferOperation::initExecution()
49 {
50         this->m_input = this->getInputOperation(0);
51         this->m_memoryProxy->allocate(this->m_width, this->m_height);
52 }
53
54 void WriteBufferOperation::deinitExecution()
55 {
56         this->m_input = NULL;
57         this->m_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->m_memoryProxy->getBuffer();
64         float *buffer = memoryBuffer->getBuffer();
65         if (this->m_input->isComplex()) {
66                 bNode* bnode = this->m_input->getbNode();
67                 if (bnode && bnode->original) bnode->original->highlight++;
68
69                 void *data = this->m_input->initializeTileData(rect, memoryBuffers);
70                 int x1 = rect->xmin;
71                 int y1 = rect->ymin;
72                 int x2 = rect->xmax;
73                 int y2 = rect->ymax;
74                 int x;
75                 int y;
76                 bool breaked = false;
77                 for (y = y1; y < y2 && (!breaked); y++) {
78                         int offset4 = (y * memoryBuffer->getWidth() + x1) * COM_NUMBER_OF_CHANNELS;
79                         for (x = x1; x < x2; x++) {
80                                 this->m_input->read(&(buffer[offset4]), x, y, memoryBuffers, data);
81                                 offset4 += COM_NUMBER_OF_CHANNELS;
82
83                         }
84                         if (isBreaked()) {
85                                 breaked = true;
86                         }
87
88                 }
89                 if (data) {
90                         this->m_input->deinitializeTileData(rect, memoryBuffers, data);
91                         data = NULL;
92                 }
93                 if (bnode && bnode->original) bnode->original->highlight++;
94         }
95         else {
96                 int x1 = rect->xmin;
97                 int y1 = rect->ymin;
98                 int x2 = rect->xmax;
99                 int y2 = rect->ymax;
100
101                 int x;
102                 int y;
103                 bool breaked = false;
104                 for (y = y1; y < y2 && (!breaked); y++) {
105                         int offset4 = (y * memoryBuffer->getWidth() + x1) * COM_NUMBER_OF_CHANNELS;
106                         for (x = x1; x < x2; x++) {
107                                 this->m_input->read(&(buffer[offset4]), x, y, COM_PS_NEAREST, memoryBuffers);
108                                 offset4 += COM_NUMBER_OF_CHANNELS;
109                         }
110                         if (isBreaked()) {
111                                 breaked = true;
112                         }
113                 }
114         }
115         memoryBuffer->setCreatedState();
116 }
117
118 void WriteBufferOperation::executeOpenCLRegion(OpenCLDevice* device, rcti *rect, unsigned int chunkNumber, MemoryBuffer **inputMemoryBuffers, MemoryBuffer *outputBuffer)
119 {
120         float *outputFloatBuffer = outputBuffer->getBuffer();
121         cl_int error;
122         /*
123          * 1. create cl_mem from outputbuffer
124          * 2. call NodeOperation (input) executeOpenCLChunk(.....)
125          * 3. schedule readback from opencl to main device (outputbuffer)
126          * 4. schedule native callback
127          *
128          * note: list of cl_mem will be filled by 2, and needs to be cleaned up by 4
129          */
130         // STEP 1
131         const unsigned int outputBufferWidth = outputBuffer->getWidth();
132         const unsigned int outputBufferHeight = outputBuffer->getHeight();
133
134         const cl_image_format imageFormat = {
135                 CL_RGBA,
136                 CL_FLOAT
137         };
138
139         cl_mem clOutputBuffer = clCreateImage2D(device->getContext(), CL_MEM_WRITE_ONLY | CL_MEM_USE_HOST_PTR, &imageFormat, outputBufferWidth, outputBufferHeight, 0, outputFloatBuffer, &error);
140         if (error != CL_SUCCESS) { printf("CLERROR[%d]: %s\n", error, clewErrorString(error));  }
141         
142         // STEP 2
143         list<cl_mem> *clMemToCleanUp = new list<cl_mem>();
144         clMemToCleanUp->push_back(clOutputBuffer);
145         list<cl_kernel> *clKernelsToCleanUp = new list<cl_kernel>();
146         bNode* bnode = this->m_input->getbNode();
147         if (bnode && bnode->original) bnode->original->highlight++;
148
149         this->m_input->executeOpenCL(device, outputBuffer, clOutputBuffer, inputMemoryBuffers, clMemToCleanUp, clKernelsToCleanUp);
150
151         // STEP 3
152
153         size_t origin[3] = {0, 0, 0};
154         size_t region[3] = {outputBufferWidth, outputBufferHeight, 1};
155
156 //      clFlush(queue);
157 //      clFinish(queue);
158
159         error = clEnqueueBarrier(device->getQueue());
160         if (error != CL_SUCCESS) { printf("CLERROR[%d]: %s\n", error, clewErrorString(error));  }
161         error = clEnqueueReadImage(device->getQueue(), clOutputBuffer, CL_TRUE, origin, region, 0, 0, outputFloatBuffer, 0, NULL, NULL);
162         if (error != CL_SUCCESS) { printf("CLERROR[%d]: %s\n", error, clewErrorString(error));  }
163         
164         this->getMemoryProxy()->getBuffer()->copyContentFrom(outputBuffer);
165
166         if (bnode && bnode->original) bnode->original->highlight++;
167         // STEP 4
168
169         
170         while (clMemToCleanUp->size() > 0) {
171                 cl_mem mem = clMemToCleanUp->front();
172                 error = clReleaseMemObject(mem);
173                 if (error != CL_SUCCESS) { printf("CLERROR[%d]: %s\n", error, clewErrorString(error));  }
174                 clMemToCleanUp->pop_front();
175         }
176
177         while (clKernelsToCleanUp->size() > 0) {
178                 cl_kernel kernel = clKernelsToCleanUp->front();
179                 error = clReleaseKernel(kernel);
180                 if (error != CL_SUCCESS) { printf("CLERROR[%d]: %s\n", error, clewErrorString(error));  }
181                 clKernelsToCleanUp->pop_front();
182         }
183         delete clKernelsToCleanUp;
184 }
185
186 void WriteBufferOperation::readResolutionFromInputSocket()
187 {
188         NodeOperation *inputOperation = this->getInputOperation(0);
189         this->setWidth(inputOperation->getWidth());
190         this->setHeight(inputOperation->getHeight());
191 }