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 <algorithm>
20 #include <math.h>
21 #include <sstream>
22 #include <stdlib.h>
23
24 #include "atomic_ops.h"
25
26 #include "COM_ChunkOrder.h"
27 #include "COM_Debug.h"
28 #include "COM_ExecutionGroup.h"
29 #include "COM_ExecutionSystem.h"
30 #include "COM_ReadBufferOperation.h"
31 #include "COM_ViewerOperation.h"
32 #include "COM_WorkScheduler.h"
33 #include "COM_WriteBufferOperation.h"
34 #include "COM_defines.h"
35
36 #include "BLI_math.h"
37 #include "BLI_string.h"
38 #include "BLT_translation.h"
39 #include "MEM_guardedalloc.h"
40 #include "PIL_time.h"
41 #include "WM_api.h"
42 #include "WM_types.h"
43
ExecutionGroup()44 ExecutionGroup::ExecutionGroup()
45 {
46 this->m_isOutput = false;
47 this->m_complex = false;
48 this->m_chunkExecutionStates = NULL;
49 this->m_bTree = NULL;
50 this->m_height = 0;
51 this->m_width = 0;
52 this->m_cachedMaxReadBufferOffset = 0;
53 this->m_numberOfXChunks = 0;
54 this->m_numberOfYChunks = 0;
55 this->m_numberOfChunks = 0;
56 this->m_initialized = false;
57 this->m_openCL = false;
58 this->m_singleThreaded = false;
59 this->m_chunksFinished = 0;
60 BLI_rcti_init(&this->m_viewerBorder, 0, 0, 0, 0);
61 this->m_executionStartTime = 0;
62 }
63
getRenderPriotrity()64 CompositorPriority ExecutionGroup::getRenderPriotrity()
65 {
66 return this->getOutputOperation()->getRenderPriority();
67 }
68
canContainOperation(NodeOperation * operation)69 bool ExecutionGroup::canContainOperation(NodeOperation *operation)
70 {
71 if (!this->m_initialized) {
72 return true;
73 }
74
75 if (operation->isReadBufferOperation()) {
76 return true;
77 }
78 if (operation->isWriteBufferOperation()) {
79 return false;
80 }
81 if (operation->isSetOperation()) {
82 return true;
83 }
84
85 /* complex groups don't allow further ops (except read buffer and values, see above) */
86 if (m_complex) {
87 return false;
88 }
89 /* complex ops can't be added to other groups (except their own, which they initialize, see
90 * above) */
91 if (operation->isComplex()) {
92 return false;
93 }
94
95 return true;
96 }
97
addOperation(NodeOperation * operation)98 bool ExecutionGroup::addOperation(NodeOperation *operation)
99 {
100 if (!canContainOperation(operation)) {
101 return false;
102 }
103
104 if (!operation->isReadBufferOperation() && !operation->isWriteBufferOperation()) {
105 m_complex = operation->isComplex();
106 m_openCL = operation->isOpenCL();
107 m_singleThreaded = operation->isSingleThreaded();
108 m_initialized = true;
109 }
110
111 m_operations.push_back(operation);
112
113 return true;
114 }
115
getOutputOperation() const116 NodeOperation *ExecutionGroup::getOutputOperation() const
117 {
118 return this
119 ->m_operations[0]; /* the first operation of the group is always the output operation. */
120 }
121
initExecution()122 void ExecutionGroup::initExecution()
123 {
124 if (this->m_chunkExecutionStates != NULL) {
125 MEM_freeN(this->m_chunkExecutionStates);
126 }
127 unsigned int index;
128 determineNumberOfChunks();
129
130 this->m_chunkExecutionStates = NULL;
131 if (this->m_numberOfChunks != 0) {
132 this->m_chunkExecutionStates = (ChunkExecutionState *)MEM_mallocN(
133 sizeof(ChunkExecutionState) * this->m_numberOfChunks, __func__);
134 for (index = 0; index < this->m_numberOfChunks; index++) {
135 this->m_chunkExecutionStates[index] = COM_ES_NOT_SCHEDULED;
136 }
137 }
138
139 unsigned int maxNumber = 0;
140
141 for (index = 0; index < this->m_operations.size(); index++) {
142 NodeOperation *operation = this->m_operations[index];
143 if (operation->isReadBufferOperation()) {
144 ReadBufferOperation *readOperation = (ReadBufferOperation *)operation;
145 this->m_cachedReadOperations.push_back(readOperation);
146 maxNumber = max(maxNumber, readOperation->getOffset());
147 }
148 }
149 maxNumber++;
150 this->m_cachedMaxReadBufferOffset = maxNumber;
151 }
152
deinitExecution()153 void ExecutionGroup::deinitExecution()
154 {
155 if (this->m_chunkExecutionStates != NULL) {
156 MEM_freeN(this->m_chunkExecutionStates);
157 this->m_chunkExecutionStates = NULL;
158 }
159 this->m_numberOfChunks = 0;
160 this->m_numberOfXChunks = 0;
161 this->m_numberOfYChunks = 0;
162 this->m_cachedReadOperations.clear();
163 this->m_bTree = NULL;
164 }
determineResolution(unsigned int resolution[2])165 void ExecutionGroup::determineResolution(unsigned int resolution[2])
166 {
167 NodeOperation *operation = this->getOutputOperation();
168 resolution[0] = operation->getWidth();
169 resolution[1] = operation->getHeight();
170 this->setResolution(resolution);
171 BLI_rcti_init(&this->m_viewerBorder, 0, this->m_width, 0, this->m_height);
172 }
173
determineNumberOfChunks()174 void ExecutionGroup::determineNumberOfChunks()
175 {
176 if (this->m_singleThreaded) {
177 this->m_numberOfXChunks = 1;
178 this->m_numberOfYChunks = 1;
179 this->m_numberOfChunks = 1;
180 }
181 else {
182 const float chunkSizef = this->m_chunkSize;
183 const int border_width = BLI_rcti_size_x(&this->m_viewerBorder);
184 const int border_height = BLI_rcti_size_y(&this->m_viewerBorder);
185 this->m_numberOfXChunks = ceil(border_width / chunkSizef);
186 this->m_numberOfYChunks = ceil(border_height / chunkSizef);
187 this->m_numberOfChunks = this->m_numberOfXChunks * this->m_numberOfYChunks;
188 }
189 }
190
191 /**
192 * this method is called for the top execution groups. containing the compositor node or the
193 * preview node or the viewer node)
194 */
execute(ExecutionSystem * graph)195 void ExecutionGroup::execute(ExecutionSystem *graph)
196 {
197 const CompositorContext &context = graph->getContext();
198 const bNodeTree *bTree = context.getbNodeTree();
199 if (this->m_width == 0 || this->m_height == 0) {
200 return;
201 } /** \note Break out... no pixels to calculate. */
202 if (bTree->test_break && bTree->test_break(bTree->tbh)) {
203 return;
204 } /** \note Early break out for blur and preview nodes. */
205 if (this->m_numberOfChunks == 0) {
206 return;
207 } /** \note Early break out. */
208 unsigned int chunkNumber;
209
210 this->m_executionStartTime = PIL_check_seconds_timer();
211
212 this->m_chunksFinished = 0;
213 this->m_bTree = bTree;
214 unsigned int index;
215 unsigned int *chunkOrder = (unsigned int *)MEM_mallocN(
216 sizeof(unsigned int) * this->m_numberOfChunks, __func__);
217
218 for (chunkNumber = 0; chunkNumber < this->m_numberOfChunks; chunkNumber++) {
219 chunkOrder[chunkNumber] = chunkNumber;
220 }
221 NodeOperation *operation = this->getOutputOperation();
222 float centerX = 0.5;
223 float centerY = 0.5;
224 OrderOfChunks chunkorder = COM_ORDER_OF_CHUNKS_DEFAULT;
225
226 if (operation->isViewerOperation()) {
227 ViewerOperation *viewer = (ViewerOperation *)operation;
228 centerX = viewer->getCenterX();
229 centerY = viewer->getCenterY();
230 chunkorder = viewer->getChunkOrder();
231 }
232
233 const int border_width = BLI_rcti_size_x(&this->m_viewerBorder);
234 const int border_height = BLI_rcti_size_y(&this->m_viewerBorder);
235
236 switch (chunkorder) {
237 case COM_TO_RANDOM:
238 for (index = 0; index < 2 * this->m_numberOfChunks; index++) {
239 int index1 = rand() % this->m_numberOfChunks;
240 int index2 = rand() % this->m_numberOfChunks;
241 int s = chunkOrder[index1];
242 chunkOrder[index1] = chunkOrder[index2];
243 chunkOrder[index2] = s;
244 }
245 break;
246 case COM_TO_CENTER_OUT: {
247 ChunkOrderHotspot *hotspots[1];
248 hotspots[0] = new ChunkOrderHotspot(border_width * centerX, border_height * centerY, 0.0f);
249 rcti rect;
250 ChunkOrder *chunkOrders = (ChunkOrder *)MEM_mallocN(
251 sizeof(ChunkOrder) * this->m_numberOfChunks, __func__);
252 for (index = 0; index < this->m_numberOfChunks; index++) {
253 determineChunkRect(&rect, index);
254 chunkOrders[index].setChunkNumber(index);
255 chunkOrders[index].setX(rect.xmin - this->m_viewerBorder.xmin);
256 chunkOrders[index].setY(rect.ymin - this->m_viewerBorder.ymin);
257 chunkOrders[index].determineDistance(hotspots, 1);
258 }
259
260 std::sort(&chunkOrders[0], &chunkOrders[this->m_numberOfChunks - 1]);
261 for (index = 0; index < this->m_numberOfChunks; index++) {
262 chunkOrder[index] = chunkOrders[index].getChunkNumber();
263 }
264
265 delete hotspots[0];
266 MEM_freeN(chunkOrders);
267 break;
268 }
269 case COM_TO_RULE_OF_THIRDS: {
270 ChunkOrderHotspot *hotspots[9];
271 unsigned int tx = border_width / 6;
272 unsigned int ty = border_height / 6;
273 unsigned int mx = border_width / 2;
274 unsigned int my = border_height / 2;
275 unsigned int bx = mx + 2 * tx;
276 unsigned int by = my + 2 * ty;
277
278 float addition = this->m_numberOfChunks / COM_RULE_OF_THIRDS_DIVIDER;
279 hotspots[0] = new ChunkOrderHotspot(mx, my, addition * 0);
280 hotspots[1] = new ChunkOrderHotspot(tx, my, addition * 1);
281 hotspots[2] = new ChunkOrderHotspot(bx, my, addition * 2);
282 hotspots[3] = new ChunkOrderHotspot(bx, by, addition * 3);
283 hotspots[4] = new ChunkOrderHotspot(tx, ty, addition * 4);
284 hotspots[5] = new ChunkOrderHotspot(bx, ty, addition * 5);
285 hotspots[6] = new ChunkOrderHotspot(tx, by, addition * 6);
286 hotspots[7] = new ChunkOrderHotspot(mx, ty, addition * 7);
287 hotspots[8] = new ChunkOrderHotspot(mx, by, addition * 8);
288 rcti rect;
289 ChunkOrder *chunkOrders = (ChunkOrder *)MEM_mallocN(
290 sizeof(ChunkOrder) * this->m_numberOfChunks, __func__);
291 for (index = 0; index < this->m_numberOfChunks; index++) {
292 determineChunkRect(&rect, index);
293 chunkOrders[index].setChunkNumber(index);
294 chunkOrders[index].setX(rect.xmin - this->m_viewerBorder.xmin);
295 chunkOrders[index].setY(rect.ymin - this->m_viewerBorder.ymin);
296 chunkOrders[index].determineDistance(hotspots, 9);
297 }
298
299 std::sort(&chunkOrders[0], &chunkOrders[this->m_numberOfChunks]);
300
301 for (index = 0; index < this->m_numberOfChunks; index++) {
302 chunkOrder[index] = chunkOrders[index].getChunkNumber();
303 }
304
305 delete hotspots[0];
306 delete hotspots[1];
307 delete hotspots[2];
308 delete hotspots[3];
309 delete hotspots[4];
310 delete hotspots[5];
311 delete hotspots[6];
312 delete hotspots[7];
313 delete hotspots[8];
314 MEM_freeN(chunkOrders);
315 break;
316 }
317 case COM_TO_TOP_DOWN:
318 default:
319 break;
320 }
321
322 DebugInfo::execution_group_started(this);
323 DebugInfo::graphviz(graph);
324
325 bool breaked = false;
326 bool finished = false;
327 unsigned int startIndex = 0;
328 const int maxNumberEvaluated = BLI_system_thread_count() * 2;
329
330 while (!finished && !breaked) {
331 bool startEvaluated = false;
332 finished = true;
333 int numberEvaluated = 0;
334
335 for (index = startIndex;
336 index < this->m_numberOfChunks && numberEvaluated < maxNumberEvaluated;
337 index++) {
338 chunkNumber = chunkOrder[index];
339 int yChunk = chunkNumber / this->m_numberOfXChunks;
340 int xChunk = chunkNumber - (yChunk * this->m_numberOfXChunks);
341 const ChunkExecutionState state = this->m_chunkExecutionStates[chunkNumber];
342 if (state == COM_ES_NOT_SCHEDULED) {
343 scheduleChunkWhenPossible(graph, xChunk, yChunk);
344 finished = false;
345 startEvaluated = true;
346 numberEvaluated++;
347
348 if (bTree->update_draw) {
349 bTree->update_draw(bTree->udh);
350 }
351 }
352 else if (state == COM_ES_SCHEDULED) {
353 finished = false;
354 startEvaluated = true;
355 numberEvaluated++;
356 }
357 else if (state == COM_ES_EXECUTED && !startEvaluated) {
358 startIndex = index + 1;
359 }
360 }
361
362 WorkScheduler::finish();
363
364 if (bTree->test_break && bTree->test_break(bTree->tbh)) {
365 breaked = true;
366 }
367 }
368 DebugInfo::execution_group_finished(this);
369 DebugInfo::graphviz(graph);
370
371 MEM_freeN(chunkOrder);
372 }
373
getInputBuffersOpenCL(int chunkNumber)374 MemoryBuffer **ExecutionGroup::getInputBuffersOpenCL(int chunkNumber)
375 {
376 rcti rect;
377 vector<MemoryProxy *> memoryproxies;
378 unsigned int index;
379 determineChunkRect(&rect, chunkNumber);
380
381 this->determineDependingMemoryProxies(&memoryproxies);
382 MemoryBuffer **memoryBuffers = (MemoryBuffer **)MEM_callocN(
383 sizeof(MemoryBuffer *) * this->m_cachedMaxReadBufferOffset, __func__);
384 rcti output;
385 for (index = 0; index < this->m_cachedReadOperations.size(); index++) {
386 ReadBufferOperation *readOperation =
387 (ReadBufferOperation *)this->m_cachedReadOperations[index];
388 MemoryProxy *memoryProxy = readOperation->getMemoryProxy();
389 this->determineDependingAreaOfInterest(&rect, readOperation, &output);
390 MemoryBuffer *memoryBuffer = memoryProxy->getExecutor()->constructConsolidatedMemoryBuffer(
391 memoryProxy, &output);
392 memoryBuffers[readOperation->getOffset()] = memoryBuffer;
393 }
394 return memoryBuffers;
395 }
396
constructConsolidatedMemoryBuffer(MemoryProxy * memoryProxy,rcti * rect)397 MemoryBuffer *ExecutionGroup::constructConsolidatedMemoryBuffer(MemoryProxy *memoryProxy,
398 rcti *rect)
399 {
400 MemoryBuffer *imageBuffer = memoryProxy->getBuffer();
401 MemoryBuffer *result = new MemoryBuffer(memoryProxy, rect);
402 result->copyContentFrom(imageBuffer);
403 return result;
404 }
405
finalizeChunkExecution(int chunkNumber,MemoryBuffer ** memoryBuffers)406 void ExecutionGroup::finalizeChunkExecution(int chunkNumber, MemoryBuffer **memoryBuffers)
407 {
408 if (this->m_chunkExecutionStates[chunkNumber] == COM_ES_SCHEDULED) {
409 this->m_chunkExecutionStates[chunkNumber] = COM_ES_EXECUTED;
410 }
411
412 atomic_add_and_fetch_u(&this->m_chunksFinished, 1);
413 if (memoryBuffers) {
414 for (unsigned int index = 0; index < this->m_cachedMaxReadBufferOffset; index++) {
415 MemoryBuffer *buffer = memoryBuffers[index];
416 if (buffer) {
417 if (buffer->isTemporarily()) {
418 memoryBuffers[index] = NULL;
419 delete buffer;
420 }
421 }
422 }
423 MEM_freeN(memoryBuffers);
424 }
425 if (this->m_bTree) {
426 // status report is only performed for top level Execution Groups.
427 float progress = this->m_chunksFinished;
428 progress /= this->m_numberOfChunks;
429 this->m_bTree->progress(this->m_bTree->prh, progress);
430
431 char buf[128];
432 BLI_snprintf(buf,
433 sizeof(buf),
434 TIP_("Compositing | Tile %u-%u"),
435 this->m_chunksFinished,
436 this->m_numberOfChunks);
437 this->m_bTree->stats_draw(this->m_bTree->sdh, buf);
438 }
439 }
440
determineChunkRect(rcti * rect,const unsigned int xChunk,const unsigned int yChunk) const441 inline void ExecutionGroup::determineChunkRect(rcti *rect,
442 const unsigned int xChunk,
443 const unsigned int yChunk) const
444 {
445 const int border_width = BLI_rcti_size_x(&this->m_viewerBorder);
446 const int border_height = BLI_rcti_size_y(&this->m_viewerBorder);
447
448 if (this->m_singleThreaded) {
449 BLI_rcti_init(
450 rect, this->m_viewerBorder.xmin, border_width, this->m_viewerBorder.ymin, border_height);
451 }
452 else {
453 const unsigned int minx = xChunk * this->m_chunkSize + this->m_viewerBorder.xmin;
454 const unsigned int miny = yChunk * this->m_chunkSize + this->m_viewerBorder.ymin;
455 const unsigned int width = min((unsigned int)this->m_viewerBorder.xmax, this->m_width);
456 const unsigned int height = min((unsigned int)this->m_viewerBorder.ymax, this->m_height);
457 BLI_rcti_init(rect,
458 min(minx, this->m_width),
459 min(minx + this->m_chunkSize, width),
460 min(miny, this->m_height),
461 min(miny + this->m_chunkSize, height));
462 }
463 }
464
determineChunkRect(rcti * rect,const unsigned int chunkNumber) const465 void ExecutionGroup::determineChunkRect(rcti *rect, const unsigned int chunkNumber) const
466 {
467 const unsigned int yChunk = chunkNumber / this->m_numberOfXChunks;
468 const unsigned int xChunk = chunkNumber - (yChunk * this->m_numberOfXChunks);
469 determineChunkRect(rect, xChunk, yChunk);
470 }
471
allocateOutputBuffer(int,rcti * rect)472 MemoryBuffer *ExecutionGroup::allocateOutputBuffer(int /*chunkNumber*/, rcti *rect)
473 {
474 // we assume that this method is only called from complex execution groups.
475 NodeOperation *operation = this->getOutputOperation();
476 if (operation->isWriteBufferOperation()) {
477 WriteBufferOperation *writeOperation = (WriteBufferOperation *)operation;
478 MemoryBuffer *buffer = new MemoryBuffer(writeOperation->getMemoryProxy(), rect);
479 return buffer;
480 }
481 return NULL;
482 }
483
scheduleAreaWhenPossible(ExecutionSystem * graph,rcti * area)484 bool ExecutionGroup::scheduleAreaWhenPossible(ExecutionSystem *graph, rcti *area)
485 {
486 if (this->m_singleThreaded) {
487 return scheduleChunkWhenPossible(graph, 0, 0);
488 }
489 // find all chunks inside the rect
490 // determine minxchunk, minychunk, maxxchunk, maxychunk where x and y are chunknumbers
491
492 int indexx, indexy;
493 int minx = max_ii(area->xmin - m_viewerBorder.xmin, 0);
494 int maxx = min_ii(area->xmax - m_viewerBorder.xmin, m_viewerBorder.xmax - m_viewerBorder.xmin);
495 int miny = max_ii(area->ymin - m_viewerBorder.ymin, 0);
496 int maxy = min_ii(area->ymax - m_viewerBorder.ymin, m_viewerBorder.ymax - m_viewerBorder.ymin);
497 int minxchunk = minx / (int)m_chunkSize;
498 int maxxchunk = (maxx + (int)m_chunkSize - 1) / (int)m_chunkSize;
499 int minychunk = miny / (int)m_chunkSize;
500 int maxychunk = (maxy + (int)m_chunkSize - 1) / (int)m_chunkSize;
501 minxchunk = max_ii(minxchunk, 0);
502 minychunk = max_ii(minychunk, 0);
503 maxxchunk = min_ii(maxxchunk, (int)m_numberOfXChunks);
504 maxychunk = min_ii(maxychunk, (int)m_numberOfYChunks);
505
506 bool result = true;
507 for (indexx = minxchunk; indexx < maxxchunk; indexx++) {
508 for (indexy = minychunk; indexy < maxychunk; indexy++) {
509 if (!scheduleChunkWhenPossible(graph, indexx, indexy)) {
510 result = false;
511 }
512 }
513 }
514
515 return result;
516 }
517
scheduleChunk(unsigned int chunkNumber)518 bool ExecutionGroup::scheduleChunk(unsigned int chunkNumber)
519 {
520 if (this->m_chunkExecutionStates[chunkNumber] == COM_ES_NOT_SCHEDULED) {
521 this->m_chunkExecutionStates[chunkNumber] = COM_ES_SCHEDULED;
522 WorkScheduler::schedule(this, chunkNumber);
523 return true;
524 }
525 return false;
526 }
527
scheduleChunkWhenPossible(ExecutionSystem * graph,int xChunk,int yChunk)528 bool ExecutionGroup::scheduleChunkWhenPossible(ExecutionSystem *graph, int xChunk, int yChunk)
529 {
530 if (xChunk < 0 || xChunk >= (int)this->m_numberOfXChunks) {
531 return true;
532 }
533 if (yChunk < 0 || yChunk >= (int)this->m_numberOfYChunks) {
534 return true;
535 }
536 int chunkNumber = yChunk * this->m_numberOfXChunks + xChunk;
537 // chunk is already executed
538 if (this->m_chunkExecutionStates[chunkNumber] == COM_ES_EXECUTED) {
539 return true;
540 }
541
542 // chunk is scheduled, but not executed
543 if (this->m_chunkExecutionStates[chunkNumber] == COM_ES_SCHEDULED) {
544 return false;
545 }
546
547 // chunk is nor executed nor scheduled.
548 vector<MemoryProxy *> memoryProxies;
549 this->determineDependingMemoryProxies(&memoryProxies);
550
551 rcti rect;
552 determineChunkRect(&rect, xChunk, yChunk);
553 unsigned int index;
554 bool canBeExecuted = true;
555 rcti area;
556
557 for (index = 0; index < this->m_cachedReadOperations.size(); index++) {
558 ReadBufferOperation *readOperation =
559 (ReadBufferOperation *)this->m_cachedReadOperations[index];
560 BLI_rcti_init(&area, 0, 0, 0, 0);
561 MemoryProxy *memoryProxy = memoryProxies[index];
562 determineDependingAreaOfInterest(&rect, readOperation, &area);
563 ExecutionGroup *group = memoryProxy->getExecutor();
564
565 if (group != NULL) {
566 if (!group->scheduleAreaWhenPossible(graph, &area)) {
567 canBeExecuted = false;
568 }
569 }
570 else {
571 throw "ERROR";
572 }
573 }
574
575 if (canBeExecuted) {
576 scheduleChunk(chunkNumber);
577 }
578
579 return false;
580 }
581
determineDependingAreaOfInterest(rcti * input,ReadBufferOperation * readOperation,rcti * output)582 void ExecutionGroup::determineDependingAreaOfInterest(rcti *input,
583 ReadBufferOperation *readOperation,
584 rcti *output)
585 {
586 this->getOutputOperation()->determineDependingAreaOfInterest(input, readOperation, output);
587 }
588
determineDependingMemoryProxies(vector<MemoryProxy * > * memoryProxies)589 void ExecutionGroup::determineDependingMemoryProxies(vector<MemoryProxy *> *memoryProxies)
590 {
591 unsigned int index;
592 for (index = 0; index < this->m_cachedReadOperations.size(); index++) {
593 ReadBufferOperation *readOperation =
594 (ReadBufferOperation *)this->m_cachedReadOperations[index];
595 memoryProxies->push_back(readOperation->getMemoryProxy());
596 }
597 }
598
isOpenCL()599 bool ExecutionGroup::isOpenCL()
600 {
601 return this->m_openCL;
602 }
603
setViewerBorder(float xmin,float xmax,float ymin,float ymax)604 void ExecutionGroup::setViewerBorder(float xmin, float xmax, float ymin, float ymax)
605 {
606 NodeOperation *operation = this->getOutputOperation();
607
608 if (operation->isViewerOperation() || operation->isPreviewOperation()) {
609 BLI_rcti_init(&this->m_viewerBorder,
610 xmin * this->m_width,
611 xmax * this->m_width,
612 ymin * this->m_height,
613 ymax * this->m_height);
614 }
615 }
616
setRenderBorder(float xmin,float xmax,float ymin,float ymax)617 void ExecutionGroup::setRenderBorder(float xmin, float xmax, float ymin, float ymax)
618 {
619 NodeOperation *operation = this->getOutputOperation();
620
621 if (operation->isOutputOperation(true)) {
622 /* Basically, setting border need to happen for only operations
623 * which operates in render resolution buffers (like compositor
624 * output nodes).
625 *
626 * In this cases adding border will lead to mapping coordinates
627 * from output buffer space to input buffer spaces when executing
628 * operation.
629 *
630 * But nodes like viewer and file output just shall display or
631 * safe the same exact buffer which goes to their input, no need
632 * in any kind of coordinates mapping.
633 */
634
635 bool operationNeedsBorder = !(operation->isViewerOperation() ||
636 operation->isPreviewOperation() ||
637 operation->isFileOutputOperation());
638
639 if (operationNeedsBorder) {
640 BLI_rcti_init(&this->m_viewerBorder,
641 xmin * this->m_width,
642 xmax * this->m_width,
643 ymin * this->m_height,
644 ymax * this->m_height);
645 }
646 }
647 }
648