1 /*******************************************************************************
2 * Copyright 2016-2019 Intel Corporation.
3 *
4 * This software and the related documents are Intel copyrighted  materials,  and
5 * your use of  them is  governed by the  express license  under which  they were
6 * provided to you (License).  Unless the License provides otherwise, you may not
7 * use, modify, copy, publish, distribute,  disclose or transmit this software or
8 * the related documents without Intel's prior written permission.
9 *
10 * This software and the related documents  are provided as  is,  with no express
11 * or implied  warranties,  other  than those  that are  expressly stated  in the
12 * License.
13 *******************************************************************************/
14 
15 #include "iw_owni.h"
16 #include "iw/iw_image.h"
17 
18 IW_DECL(IppStatus) llwiCopyMakeBorder(const void *pSrc, IwSize srcStep, void *pDst, IwSize dstStep,
19     IwiSize size, IppDataType dataType, int channels, IwiBorderSize borderSize, IwiBorderType border, const Ipp64f *pBorderVal);
20 
21 /* /////////////////////////////////////////////////////////////////////////////
22 //                   Utility functions
23 ///////////////////////////////////////////////////////////////////////////// */
iwiMaskToSize(IppiMaskSize mask)24 IW_DECL(IwiSize) iwiMaskToSize(IppiMaskSize mask)
25 {
26     IwiSize size;
27     size.width  = 0;
28     size.height = 0;
29 
30     switch(mask)
31     {
32     case ippMskSize1x3:
33         size.width  = 1;
34         size.height = 3;
35         return size;
36     case ippMskSize1x5:
37         size.width  = 1;
38         size.height = 5;
39         return size;
40     case ippMskSize3x1:
41         size.width  = 3;
42         size.height = 1;
43         return size;
44     case ippMskSize3x3:
45         size.width  = 3;
46         size.height = 3;
47         return size;
48     case ippMskSize5x1:
49         size.width  = 5;
50         size.height = 1;
51         return size;
52     case ippMskSize5x5:
53         size.width  = 5;
54         size.height = 5;
55         return size;
56     default:
57         return size;
58     }
59 }
60 
owniChDescriptorToCode(IwiChDescriptor chDesc,int srcChannels,int dstChannels)61 IW_DECL(OwniChCodes) owniChDescriptorToCode(IwiChDescriptor chDesc, int srcChannels, int dstChannels)
62 {
63     if(srcChannels == dstChannels)
64     {
65         if((int)OWN_DESC_GET_CH(chDesc) != srcChannels)
66             chDesc = iwiChDesc_None;
67     }
68     else
69         chDesc = iwiChDesc_None;
70 
71     switch(srcChannels)
72     {
73     case 1:
74         switch(dstChannels)
75         {
76         case 1:
77             switch(chDesc)
78             {
79             case iwiChDesc_None:    return owniC1;
80             default:                return owniC_Invalid;
81             }
82         case 3:
83             switch(chDesc)
84             {
85             case iwiChDesc_None:    return owniC1C3;
86             default:                return owniC_Invalid;
87             }
88         case 4:
89             switch(chDesc)
90             {
91             case iwiChDesc_None:    return owniC1C4;
92             default:                return owniC_Invalid;
93             }
94         default: return owniC_Invalid;
95         }
96     case 3:
97         switch(dstChannels)
98         {
99         case 1:
100             switch(chDesc)
101             {
102             case iwiChDesc_None:    return owniC3C1;
103             default:                return owniC_Invalid;
104             }
105         case 3:
106             switch(chDesc)
107             {
108             case iwiChDesc_None:    return owniC3;
109             default:                return owniC_Invalid;
110             }
111         case 4:
112             switch(chDesc)
113             {
114             case iwiChDesc_None:    return owniC3C4;
115             default:                return owniC_Invalid;
116             }
117         default: return owniC_Invalid;
118         }
119     case 4:
120         switch(dstChannels)
121         {
122         case 1:
123             switch(chDesc)
124             {
125             case iwiChDesc_None: return owniC4C1;
126             default:             return owniC_Invalid;
127             }
128         case 3:
129             switch(chDesc)
130             {
131             case iwiChDesc_None: return owniC4C3;
132             default:             return owniC_Invalid;
133             }
134         case 4:
135             switch(chDesc)
136             {
137             case iwiChDesc_None:    return owniC4;
138             case iwiChDesc_C4M1110: return owniC4M1110;
139             case iwiChDesc_C4M1000: return owniC4M1000;
140             case iwiChDesc_C4M1001: return owniC4M1001;
141             case iwiChDesc_C4M1XX0: return owniC4M1RR0;
142             case iwiChDesc_C4M1XX1: return owniC4M1RR1;
143             default:                return owniC_Invalid;
144             }
145         default: return owniC_Invalid;
146         }
147     default: return owniC_Invalid;
148     }
149 }
150 
151 /* /////////////////////////////////////////////////////////////////////////////
152 //                   IwiImage - Image structure
153 ///////////////////////////////////////////////////////////////////////////// */
iwiImage_Init(IwiImage * pImage)154 IW_DECL(void) iwiImage_Init(IwiImage *pImage)
155 {
156     if(!pImage)
157         return;
158 
159     pImage->m_channels    = 0;
160     pImage->m_dataType    = ipp8u;
161     pImage->m_typeSize    = 0;
162     pImage->m_size.width  = 0;
163     pImage->m_size.height = 0;
164     pImage->m_pBuffer     = NULL;
165     pImage->m_ptr         = NULL;
166     pImage->m_ptrConst    = NULL;
167     pImage->m_step        = 0;
168 
169     pImage->m_inMemSize.left = pImage->m_inMemSize.right  = 0;
170     pImage->m_inMemSize.top  = pImage->m_inMemSize.bottom = 0;
171 }
172 
iwiImage_InitExternal(IwiImage * pImage,IwiSize size,IppDataType dataType,int channels,IwiBorderSize const * pInMemBorder,void * pBuffer,IwSize step)173 IW_DECL(IppStatus) iwiImage_InitExternal(IwiImage *pImage, IwiSize size, IppDataType dataType, int channels, IwiBorderSize const *pInMemBorder, void *pBuffer, IwSize step)
174 {
175     if(!pImage)
176         return ippStsNullPtrErr;
177 
178     iwiImage_Init(pImage);
179     if(channels < 0)
180         return ippStsNumChannelsErr;
181     if(size.width < 0 || size.height < 0)
182         return ippStsSizeErr;
183 
184     pImage->m_typeSize = iwTypeToSize(dataType);
185     if(!pImage->m_typeSize)
186         return ippStsDataTypeErr;
187 
188     pImage->m_dataType = dataType;
189     pImage->m_size     = size;
190     pImage->m_channels = channels;
191 
192     if(pInMemBorder)
193     {
194         if(owniBorderSizeIsNegative(pInMemBorder))
195             return iwStsBorderNegSizeErr;
196 
197         pImage->m_inMemSize.left   = pInMemBorder->left;
198         pImage->m_inMemSize.right  = pInMemBorder->right;
199         pImage->m_inMemSize.top    = pInMemBorder->top;
200         pImage->m_inMemSize.bottom = pInMemBorder->bottom;
201     }
202 
203     pImage->m_ptr      = pBuffer;
204     pImage->m_ptrConst = pImage->m_ptr;
205     pImage->m_step     = step;
206 
207     return ippStsNoErr;
208 }
209 
iwiImage_InitExternalConst(IwiImage * pImage,IwiSize size,IppDataType dataType,int channels,IwiBorderSize const * pInMemBorder,const void * pBuffer,IwSize step)210 IW_DECL(IppStatus) iwiImage_InitExternalConst(IwiImage *pImage, IwiSize size, IppDataType dataType, int channels, IwiBorderSize const *pInMemBorder, const void *pBuffer, IwSize step)
211 {
212     if(!pImage)
213         return ippStsNullPtrErr;
214 
215     iwiImage_Init(pImage);
216 
217     if(channels < 0)
218         return ippStsNumChannelsErr;
219     if(size.width < 0 || size.height < 0)
220         return ippStsSizeErr;
221 
222     pImage->m_typeSize = iwTypeToSize(dataType);
223     if(!pImage->m_typeSize)
224         return ippStsDataTypeErr;
225 
226     pImage->m_dataType = dataType;
227     pImage->m_size     = size;
228     pImage->m_channels = channels;
229 
230     if(pInMemBorder)
231     {
232         if(owniBorderSizeIsNegative(pInMemBorder))
233             return iwStsBorderNegSizeErr;
234 
235         pImage->m_inMemSize.left   = pInMemBorder->left;
236         pImage->m_inMemSize.right  = pInMemBorder->right;
237         pImage->m_inMemSize.top    = pInMemBorder->top;
238         pImage->m_inMemSize.bottom = pInMemBorder->bottom;
239     }
240 
241     pImage->m_ptrConst = pBuffer;
242     pImage->m_step     = step;
243 
244     return ippStsNoErr;
245 }
246 
iwiImage_Alloc(IwiImage * pImage,IwiSize size,IppDataType dataType,int channels,IwiBorderSize const * pInMemBorder)247 IW_DECL(IppStatus) iwiImage_Alloc(IwiImage *pImage, IwiSize size, IppDataType dataType, int channels, IwiBorderSize const *pInMemBorder)
248 {
249     IwSize     step;
250     IwiSize    allocSize;
251 
252     if(!pImage)
253         return ippStsNullPtrErr;
254 
255     iwiImage_Release(pImage);
256 
257     if(size.width < 0 || size.height < 0)
258         return ippStsSizeErr;
259 
260     if(channels < 0)
261         return ippStsNumChannelsErr;
262 
263     pImage->m_typeSize = iwTypeToSize(dataType);
264     if(!pImage->m_typeSize)
265         return ippStsDataTypeErr;
266 
267     pImage->m_dataType = dataType;
268     pImage->m_size     = size;
269     pImage->m_channels = channels;
270 
271     if(pInMemBorder)
272     {
273         if(owniBorderSizeIsNegative(pInMemBorder))
274             return iwStsBorderNegSizeErr;
275 
276         pImage->m_inMemSize.left   = pInMemBorder->left;
277         pImage->m_inMemSize.right  = pInMemBorder->right;
278         pImage->m_inMemSize.top    = pInMemBorder->top;
279         pImage->m_inMemSize.bottom = pInMemBorder->bottom;
280     }
281     allocSize.width  = pImage->m_size.width + pImage->m_inMemSize.left + pImage->m_inMemSize.right;
282     allocSize.height = pImage->m_size.height + pImage->m_inMemSize.top + pImage->m_inMemSize.bottom;
283     step             = allocSize.width*pImage->m_typeSize*pImage->m_channels;
284     if(!step || !allocSize.height) // zero size memory request
285         return ippStsNoErr;
286 
287     if(allocSize.height > 1 && step*allocSize.height > 64)
288     {
289         // Align rows by cache lines
290         if(step < 16)
291             step = 16;
292         else if(step < 32)
293             step = 32;
294         else
295             step = owniAlignStep(step, 64);
296     }
297 
298     pImage->m_pBuffer = ippsMalloc_8u_L(step*allocSize.height);
299     if(!pImage->m_pBuffer)
300         return ippStsMemAllocErr;
301 
302     pImage->m_ptr      = (Ipp8u*)pImage->m_pBuffer + pImage->m_inMemSize.left*pImage->m_typeSize*pImage->m_channels + step*pImage->m_inMemSize.top;
303     pImage->m_ptrConst = pImage->m_ptr;
304     pImage->m_step     = step;
305 
306     return ippStsNoErr;
307 }
308 
iwiImage_Release(IwiImage * pImage)309 IW_DECL(void) iwiImage_Release(IwiImage *pImage)
310 {
311     if(!pImage)
312         return;
313 
314     if(pImage->m_pBuffer)
315     {
316         ippsFree(pImage->m_pBuffer);
317         pImage->m_pBuffer  = NULL;
318         pImage->m_ptr      = NULL;
319         pImage->m_ptrConst = NULL;
320         pImage->m_step     = 0;
321     }
322 }
323 
iwiImage_GetPtr(const IwiImage * pImage,IwSize y,IwSize x,int ch)324 IW_DECL(void*) iwiImage_GetPtr(const IwiImage *pImage, IwSize y, IwSize x, int ch)
325 {
326     if(!pImage || !pImage->m_ptr)
327         return NULL;
328     return (((Ipp8u*)pImage->m_ptr) + pImage->m_step*y + x*pImage->m_typeSize*pImage->m_channels + ch*pImage->m_typeSize);
329 }
330 
iwiImage_GetPtrConst(const IwiImage * pImage,IwSize y,IwSize x,int ch)331 IW_DECL(const void*) iwiImage_GetPtrConst(const IwiImage *pImage, IwSize y, IwSize x, int ch)
332 {
333     if(!pImage || !pImage->m_ptrConst)
334         return NULL;
335     return (((const Ipp8u*)pImage->m_ptrConst) + pImage->m_step*y + x*pImage->m_typeSize*pImage->m_channels + ch*pImage->m_typeSize);
336 }
337 
iwiImage_BorderAdd(IwiImage * pImage,IwiBorderSize borderSize)338 IW_DECL(IppStatus) iwiImage_BorderAdd(IwiImage *pImage, IwiBorderSize borderSize)
339 {
340     if(!pImage || !pImage->m_ptrConst)
341         return ippStsNullPtrErr;
342 
343     if(owniBorderSizeIsNegative(&borderSize))
344         return iwStsBorderNegSizeErr;
345 
346     if(borderSize.left + borderSize.right >= pImage->m_size.width)
347         return ippStsSizeErr;
348     if(borderSize.top + borderSize.bottom >= pImage->m_size.height)
349         return ippStsSizeErr;
350 
351     if(pImage->m_ptr)
352         pImage->m_ptrConst = pImage->m_ptr = iwiImage_GetPtr(pImage, borderSize.top, borderSize.left, 0);
353     else
354         pImage->m_ptrConst = iwiImage_GetPtrConst(pImage, borderSize.top, borderSize.left, 0);
355     pImage->m_size.width  = pImage->m_size.width  - borderSize.left - borderSize.right;
356     pImage->m_size.height = pImage->m_size.height - borderSize.top  - borderSize.bottom;
357     pImage->m_inMemSize.left   += borderSize.left;
358     pImage->m_inMemSize.top    += borderSize.top;
359     pImage->m_inMemSize.right  += borderSize.right;
360     pImage->m_inMemSize.bottom += borderSize.bottom;
361 
362     return ippStsNoErr;
363 }
364 
iwiImage_BorderSub(IwiImage * pImage,IwiBorderSize borderSize)365 IW_DECL(IppStatus) iwiImage_BorderSub(IwiImage *pImage, IwiBorderSize borderSize)
366 {
367     if(!pImage || !pImage->m_ptrConst)
368         return ippStsNullPtrErr;
369 
370     if(owniBorderSizeIsNegative(&borderSize))
371         return iwStsBorderNegSizeErr;
372 
373     if(borderSize.left > pImage->m_inMemSize.left)
374         return ippStsOutOfRangeErr;
375     if(borderSize.top > pImage->m_inMemSize.top)
376         return ippStsOutOfRangeErr;
377     if(borderSize.right > pImage->m_inMemSize.right)
378         return ippStsOutOfRangeErr;
379     if(borderSize.bottom > pImage->m_inMemSize.bottom)
380         return ippStsOutOfRangeErr;
381 
382     if(pImage->m_ptr)
383         pImage->m_ptrConst = pImage->m_ptr = iwiImage_GetPtr(pImage, -borderSize.top, -borderSize.left, 0);
384     else
385         pImage->m_ptrConst = iwiImage_GetPtrConst(pImage, -borderSize.top, -borderSize.left, 0);
386     pImage->m_size.width  = pImage->m_size.width  + borderSize.left + borderSize.right;
387     pImage->m_size.height = pImage->m_size.height + borderSize.top  + borderSize.bottom;
388     pImage->m_inMemSize.left   -= borderSize.left;
389     pImage->m_inMemSize.top    -= borderSize.top;
390     pImage->m_inMemSize.right  -= borderSize.right;
391     pImage->m_inMemSize.bottom -= borderSize.bottom;
392 
393     return ippStsNoErr;
394 }
395 
iwiImage_BorderSet(IwiImage * pImage,IwiBorderSize borderSize)396 IW_DECL(IppStatus) iwiImage_BorderSet(IwiImage *pImage, IwiBorderSize borderSize)
397 {
398     IwSize diffLeft, diffTop, diffRight, diffBottom;
399 
400     if(!pImage || !pImage->m_ptrConst)
401         return ippStsNullPtrErr;
402 
403     if(owniBorderSizeIsNegative(&borderSize))
404         return iwStsBorderNegSizeErr;
405 
406     diffLeft    = borderSize.left    - pImage->m_inMemSize.left;
407     diffTop     = borderSize.top     - pImage->m_inMemSize.top;
408     diffRight   = borderSize.right   - pImage->m_inMemSize.right;
409     diffBottom  = borderSize.bottom  - pImage->m_inMemSize.bottom;
410 
411     if(diffLeft+diffRight >= pImage->m_size.width)
412         return ippStsSizeErr;
413     if(diffTop+diffBottom >= pImage->m_size.height)
414         return ippStsSizeErr;
415 
416     if(pImage->m_ptr)
417         pImage->m_ptrConst = pImage->m_ptr = iwiImage_GetPtr(pImage, diffTop, diffLeft, 0);
418     else
419         pImage->m_ptrConst = iwiImage_GetPtrConst(pImage, diffTop, diffLeft, 0);
420     pImage->m_size.width  = pImage->m_size.width  - (diffLeft + diffRight);
421     pImage->m_size.height = pImage->m_size.height - (diffTop + diffBottom);
422     pImage->m_inMemSize   = borderSize;
423 
424     return ippStsNoErr;
425 }
426 
iwiImage_RoiSet(IwiImage * pImage,IwiRoi roi)427 IW_DECL(IppStatus) iwiImage_RoiSet(IwiImage *pImage, IwiRoi roi)
428 {
429     if(!pImage || !pImage->m_ptrConst)
430         return ippStsNullPtrErr;
431 
432     // Unroll border
433     if(pImage->m_ptr)
434         pImage->m_ptrConst = pImage->m_ptr = iwiImage_GetPtr(pImage, -pImage->m_inMemSize.top, -pImage->m_inMemSize.left, 0);
435     else
436         pImage->m_ptrConst = iwiImage_GetPtrConst(pImage, -pImage->m_inMemSize.top, -pImage->m_inMemSize.left, 0);
437     pImage->m_size.width  = pImage->m_size.width  + pImage->m_inMemSize.left + pImage->m_inMemSize.right;
438     pImage->m_size.height = pImage->m_size.height + pImage->m_inMemSize.top  + pImage->m_inMemSize.bottom;
439     roi.x += pImage->m_inMemSize.left;
440     roi.y += pImage->m_inMemSize.top;
441 
442     // ROI saturation
443     if(roi.width < 0) // Inverted ROI
444     {
445         roi.x     = roi.x + roi.width;
446         roi.width = -roi.width;
447     }
448     if(roi.x < 0) // "Left" saturation
449     {
450         roi.width += roi.x;
451         roi.x = 0;
452     }
453     if(roi.x + roi.width > pImage->m_size.width) // "Right" saturation
454     {
455         if(roi.x > pImage->m_size.width)
456         {
457             roi.x = pImage->m_size.width;
458             roi.width = 0;
459         }
460         else
461             roi.width = pImage->m_size.width - roi.x;
462     }
463 
464     if(roi.height < 0) // Inverted ROI
465     {
466         roi.y      = roi.y + roi.height;
467         roi.height = -roi.height;
468     }
469     if(roi.y < 0) // "Left" saturation
470     {
471         roi.height += roi.y;
472         roi.y = 0;
473     }
474     if(roi.y + roi.height > pImage->m_size.height) // "Right" saturation
475     {
476         if(roi.y > pImage->m_size.height)
477         {
478             roi.y = pImage->m_size.height;
479             roi.height = 0;
480         }
481         else
482             roi.height = pImage->m_size.height - roi.y;
483     }
484 
485     // Rebuild border
486     pImage->m_inMemSize.left   = roi.x;
487     pImage->m_inMemSize.top    = roi.y;
488     pImage->m_inMemSize.right  = pImage->m_size.width  - roi.x - roi.width;
489     pImage->m_inMemSize.bottom = pImage->m_size.height - roi.y - roi.height;
490     pImage->m_size.width    = roi.width;
491     pImage->m_size.height   = roi.height;
492     if(pImage->m_ptr)
493         pImage->m_ptrConst = pImage->m_ptr = iwiImage_GetPtr(pImage, pImage->m_inMemSize.top, pImage->m_inMemSize.left, 0);
494     else
495         pImage->m_ptrConst = iwiImage_GetPtrConst(pImage, pImage->m_inMemSize.top, pImage->m_inMemSize.left, 0);
496 
497     return ippStsNoErr;
498 }
499 
iwiImage_GetRoiImage(const IwiImage * pImage,IwiRoi roi)500 IW_DECL(IwiImage) iwiImage_GetRoiImage(const IwiImage *pImage, IwiRoi roi)
501 {
502     IwiImage image;
503 
504     iwiImage_Init(&image);
505     if(!pImage || !pImage->m_ptrConst)
506         return image;
507 
508     if(pImage->m_ptr)
509     {
510         if(iwiImage_InitExternal(&image, pImage->m_size, pImage->m_dataType, pImage->m_channels, &pImage->m_inMemSize, pImage->m_ptr, pImage->m_step) < 0)
511         {
512             iwiImage_Init(&image);
513             return image;
514         }
515     }
516     else
517     {
518         if(iwiImage_InitExternalConst(&image, pImage->m_size, pImage->m_dataType, pImage->m_channels, &pImage->m_inMemSize, pImage->m_ptrConst, pImage->m_step) < 0)
519         {
520             iwiImage_Init(&image);
521             return image;
522         }
523     }
524     if(iwiImage_RoiSet(&image, roi) < 0)
525     {
526         iwiImage_Init(&image);
527         return image;
528     }
529     return image;
530 }
531 
532 /* /////////////////////////////////////////////////////////////////////////////
533 //                   IW Tiling
534 ///////////////////////////////////////////////////////////////////////////// */
owniSuggestTileSize_k2(const IwiImage * pImage,IwiSize kernelSize,double multiplier)535 IW_DECL(IwiSize) owniSuggestTileSize_k2(const IwiImage *pImage, IwiSize kernelSize, double multiplier)
536 {
537     float      nCaches;
538     IwiSize    roi       = {0,0};
539     IwSize     opMemory  = (IwSize)(pImage->m_size.width*pImage->m_size.height*pImage->m_typeSize*pImage->m_channels*multiplier);
540     IwSize     minHeight = IPP_MAX(kernelSize.height, 64);
541     IwSize     minWidth  = IPP_MAX(kernelSize.width, 64);
542     IppCache  *pCache;
543     int        l2cache = 262144;
544     //int        l3cache = 1048576;
545     if(ippGetCacheParams(&pCache) >= 0 && pCache[0].type != 0 && pCache[1].type != 0)
546     {
547         if(pCache[2].type != 0)
548         {
549             l2cache = pCache[2].size;
550             //if(pCache[3].type != 0)
551             //    l3cache = pCache[3].size;
552         }
553     }
554 
555     nCaches = ((float)opMemory/l2cache);
556     if(nCaches < 1)     // Cache is enough to contain all operations
557         return pImage->m_size;
558     else if(pImage->m_size.height <= minHeight) // Height is small, divide by width only
559     {
560         roi.width  = (IwSize)((pImage->m_size.width+nCaches-1)/nCaches);
561         roi.height = kernelSize.height;
562     }
563     else // General case
564     {
565         IwSize pixChunk = (IwSize)((pImage->m_size.width*pImage->m_size.height)/nCaches);
566         roi.height      = (pixChunk+pImage->m_size.width-1)/pImage->m_size.width;
567         roi.width       = pImage->m_size.width;
568         if(roi.height < minHeight && roi.width > minWidth) // Not enough space to process whole row efficiently, divide row
569         {
570             while(roi.height < minHeight)
571             {
572                 roi.width /= 2;
573                 roi.height = (pixChunk+roi.width-1)/roi.width;
574             }
575         }
576     }
577     return roi;
578 }
579 
580 /* /////////////////////////////////////////////////////////////////////////////
581 //                   Manual tiling control
582 ///////////////////////////////////////////////////////////////////////////// */
iwiTile_GetTileBorder(IwiRoi roi,IwiBorderType border,IwiBorderSize borderSize,IwiSize srcImageSize)583 IW_DECL(IwiBorderType) iwiTile_GetTileBorder(IwiRoi roi, IwiBorderType border, IwiBorderSize borderSize, IwiSize srcImageSize)
584 {
585     owniTile_GetTileBorder(&border, &roi, &borderSize, &srcImageSize);
586     return border;
587 }
588 
iwiTile_GetMinTileSize(IwiBorderType border,IwiBorderSize borderSize)589 IW_DECL(IwiSize) iwiTile_GetMinTileSize(IwiBorderType border, IwiBorderSize borderSize)
590 {
591     IwiSize size;
592     if(border&ippBorderInMemLeft)
593         borderSize.left   = 0;
594     if(border&ippBorderInMemRight)
595         borderSize.right  = 0;
596     if(border&ippBorderInMemTop)
597         borderSize.top    = 0;
598     if(border&ippBorderInMemBottom)
599         borderSize.bottom = 0;
600 
601     border      = OWN_GET_PURE_BORDER(border);
602     size.width  = IPP_MAX(borderSize.left, borderSize.right);
603     size.height = IPP_MAX(borderSize.top, borderSize.bottom);
604     if(size.width == 0)
605         size.width  = 1;
606     if(size.height == 0)
607         size.height = 1;
608     if(border == ippBorderMirror)
609     {
610         size.width++;
611         size.height++;
612     }
613     return size;
614 }
615 
iwiTile_CorrectBordersOverlap(IwiRoi roi,IwiBorderType border,IwiBorderSize borderSize,IwiSize srcImageSize)616 IW_DECL(IwiRoi) iwiTile_CorrectBordersOverlap(IwiRoi roi, IwiBorderType border, IwiBorderSize borderSize, IwiSize srcImageSize)
617 {
618     owniTile_CorrectBordersOverlap(&roi, NULL, &border, &borderSize, &borderSize, &srcImageSize);
619     return roi;
620 }
621 
622 /* /////////////////////////////////////////////////////////////////////////////
623 //                   IwiTile tiling
624 ///////////////////////////////////////////////////////////////////////////// */
owniTile_BoundToSize(IwiRoi * pRoi,IwiSize * pMinSize)625 IW_DECL(int) owniTile_BoundToSize(IwiRoi *pRoi, IwiSize *pMinSize)
626 {
627     if(pRoi->x >= pMinSize->width)
628         return 0;
629     else if(pRoi->x < 0)
630         pRoi->x = 0;
631     if(pRoi->y >= pMinSize->height)
632         return 0;
633     else if(pRoi->y < 0)
634         pRoi->y = 0;
635 
636     if(pRoi->width + pRoi->x > pMinSize->width)
637         pRoi->width  = pMinSize->width  - pRoi->x;
638     if(pRoi->height + pRoi->y > pMinSize->height)
639         pRoi->height = pMinSize->height - pRoi->y;
640 
641     if(pRoi->width <= 0 || pRoi->height <= 0)
642         return 0;
643     else
644     {
645         pMinSize->width  = pRoi->width;
646         pMinSize->height = pRoi->height;
647         return 1;
648     }
649 }
650 
651 
owniTile_CorrectBordersOverlap(IwiRoi * pRoi,IwiSize * pMinSize,const IwiBorderType * pBorder,const IwiBorderSize * pBorderSize,const IwiBorderSize * pBorderSizeAcc,const IwiSize * pSrcImageSize)652 IW_DECL(int) owniTile_CorrectBordersOverlap(IwiRoi *pRoi, IwiSize *pMinSize, const IwiBorderType *pBorder, const IwiBorderSize *pBorderSize, const IwiBorderSize *pBorderSizeAcc, const IwiSize *pSrcImageSize)
653 {
654     int corrected = 0;
655 
656     // Check right border
657     if(pBorderSize->right > 1 && !(*pBorder&ippBorderInMemRight))
658     {
659         IwSize rightPos  = pRoi->x + pRoi->width; // Get right tile border position
660         IwSize leftCheck = pRoi->x + (pBorderSizeAcc->left - pBorderSize->left) + (pBorderSizeAcc->right - pBorderSize->right); // Reconstruct previous tile position
661 
662         // Border-phobic tile part
663         if(rightPos < pSrcImageSize->width &&
664             (rightPos + pBorderSize->right) > pSrcImageSize->width)
665         {
666             pRoi->width = pSrcImageSize->width - pBorderSize->right - pRoi->x;
667             corrected = 1;
668         }
669         // Border-filing tile part
670         else if(leftCheck < pSrcImageSize->width &&
671             (leftCheck + pBorderSize->right) > pSrcImageSize->width)
672         {
673             pRoi->x     = pSrcImageSize->width - pBorderSize->right - (pBorderSizeAcc->left - pBorderSize->left)*2;
674             pRoi->width = pSrcImageSize->width - pRoi->x;
675             corrected = 1;
676         }
677     }
678 
679     // Check bottom border
680     if(pBorderSize->bottom > 1 && !(*pBorder&ippBorderInMemBottom))
681     {
682         IwSize bottomPos = pRoi->y + pRoi->height; // Get bottom tile border position
683         IwSize topCheck  = pRoi->y + (pBorderSizeAcc->top - pBorderSize->top) + (pBorderSizeAcc->bottom - pBorderSize->bottom); // Reconstruct previous tile position
684 
685         // Border-phobic tile part
686         if(bottomPos < pSrcImageSize->height &&
687             (bottomPos + pBorderSize->bottom) > pSrcImageSize->height)
688         {
689             pRoi->height = pSrcImageSize->height - pBorderSize->bottom - pRoi->y;
690             corrected = 1;
691         }
692         // Border-filing tile part
693         else if(topCheck < pSrcImageSize->height &&
694             (topCheck + pBorderSize->bottom) > pSrcImageSize->height)
695         {
696             pRoi->y      = pSrcImageSize->height - pBorderSize->bottom - (pBorderSizeAcc->top - pBorderSize->top)*2;
697             pRoi->height = pSrcImageSize->height - pRoi->y;
698             corrected = 1;
699         }
700     }
701 
702     if(corrected && pMinSize)
703     {
704         pMinSize->width  = pRoi->width;
705         pMinSize->height = pRoi->height;
706     }
707 
708     return corrected;
709 }
710 
owniTile_GetTileBorder(IwiBorderType * pBorder,const IwiRoi * pRoi,const IwiBorderSize * pBorderSize,const IwiSize * pSrcImageSize)711 IW_DECL(void) owniTile_GetTileBorder(IwiBorderType *pBorder, const IwiRoi *pRoi, const IwiBorderSize *pBorderSize, const IwiSize *pSrcImageSize)
712 {
713     if((*pBorder & ippBorderInMem) != ippBorderInMem)
714     {
715         int flags = (*pBorder)&(~0xF);
716 
717         // Check left border
718         if(pBorderSize->left && (pRoi->x >= pBorderSize->left))
719             flags |= ippBorderInMemLeft;
720 
721         // Check top border
722         if(pBorderSize->top && (pRoi->y >= pBorderSize->top))
723             flags |= ippBorderInMemTop;
724 
725         // Check right border
726         if(pBorderSize->right && (pRoi->x + pRoi->width + pBorderSize->right <= pSrcImageSize->width))
727             flags |= ippBorderInMemRight;
728 
729         // Check bottom border
730         if(pBorderSize->bottom && (pRoi->y + pRoi->height + pBorderSize->bottom <= pSrcImageSize->height))
731             flags |= ippBorderInMemBottom;
732 
733         // If we have full InMem, then we should pass pure InMem border to function
734         if(flags == ippBorderInMem)
735             *pBorder = ippBorderInMem;
736         else
737             *pBorder = (IwiBorderType)((*pBorder)|flags);
738     }
739 }
740 
741 /* /////////////////////////////////////////////////////////////////////////////
742 //                   IwiTile pipeline tiling
743 ///////////////////////////////////////////////////////////////////////////// */
744 
owniTilePipeline_GetRoot(const IwiTile * pTile)745 static IW_INLINE IwiTile* owniTilePipeline_GetRoot(const IwiTile *pTile)
746 {
747     IwiTile *pRoiRoot = (IwiTile*)pTile;
748     if(!pTile || pTile->m_initialized != ownTileInitPipe)
749         return NULL;
750     while(pRoiRoot->m_pParent)
751         pRoiRoot = pRoiRoot->m_pParent;
752     return pRoiRoot;
753 }
owniTilePipeline_InitCheck(const IwiTile * pTile)754 static IW_INLINE IppStatus owniTilePipeline_InitCheck(const IwiTile *pTile)
755 {
756     if(!pTile)
757         return ippStsNullPtrErr;
758 
759     if(pTile->m_initialized != ownTileInitPipe)
760         return ippStsContextMatchErr;
761 
762     return ippStsNoErr;
763 }
764 
iwiTile_SetRoi(IwiRoi tileRoi)765 IW_DECL(IwiTile) iwiTile_SetRoi(IwiRoi tileRoi)
766 {
767     IwiTile roi = {0};
768     roi.m_dstRoi      = tileRoi;
769     roi.m_initialized = ownTileInitSimple;
770     return roi;
771 }
772 
owniTilePipeline_GetSrcSizeMax(IwiRoi * pSrcRoiSize,IwiSize * pDstMaxTile,IwiSize * pDstImageSize,const IwiTileTransform * pTransformStruct)773 static IppStatus owniTilePipeline_GetSrcSizeMax(IwiRoi *pSrcRoiSize, IwiSize *pDstMaxTile, IwiSize *pDstImageSize, const IwiTileTransform *pTransformStruct)
774 {
775     IwiRoi   srcTemp   = {0, 0, 0, 0};
776     IwiRoi   dstRoi    = {0, 0, 0, 0};
777     pSrcRoiSize->width  = 0;
778     pSrcRoiSize->height = 0;
779     dstRoi.width  = pDstMaxTile->width;
780     dstRoi.height = pDstMaxTile->height;
781 
782     for(dstRoi.x = 0; dstRoi.x <= pDstImageSize->width - dstRoi.width; dstRoi.x++)
783     {
784         if(pTransformStruct->getSrcRoiFun(dstRoi, &srcTemp, pTransformStruct->pParams))
785             return ippStsErr;
786 
787         pSrcRoiSize->width = IPP_MAX(pSrcRoiSize->width, srcTemp.width);
788     }
789 
790     for(dstRoi.y = 0; dstRoi.y <= pDstImageSize->height - dstRoi.height; dstRoi.y++)
791     {
792         if(pTransformStruct->getSrcRoiFun(dstRoi, &srcTemp, pTransformStruct->pParams))
793             return ippStsErr;
794 
795         pSrcRoiSize->height = IPP_MAX(pSrcRoiSize->height, srcTemp.height);
796     }
797 
798     pSrcRoiSize->x = 0;
799     pSrcRoiSize->y = 0;
800 
801     return ippStsNoErr;
802 }
803 
owniTilePipeline_BuildBorder(const IwiTile * pTile,IwiImage * pSrcImage,IwiBorderType * pBorder,const Ipp64f * pBorderVal,const IwiBorderSize * pBorderSize)804 static IppStatus owniTilePipeline_BuildBorder(const IwiTile *pTile, IwiImage *pSrcImage, IwiBorderType *pBorder, const Ipp64f *pBorderVal, const IwiBorderSize *pBorderSize)
805 {
806     IppStatus status;
807 
808     if(((*pBorder)&ippBorderInMem) != ippBorderInMem)
809     {
810         if(pBorderSize)
811             status = llwiCopyMakeBorder(pSrcImage->m_ptrConst, pSrcImage->m_step, pSrcImage->m_ptr, pSrcImage->m_step, pSrcImage->m_size,
812                 pSrcImage->m_dataType, pSrcImage->m_channels, *pBorderSize, *pBorder, pBorderVal);
813         else
814             status = llwiCopyMakeBorder(pSrcImage->m_ptrConst, pSrcImage->m_step, pSrcImage->m_ptr, pSrcImage->m_step, pSrcImage->m_size,
815                 pSrcImage->m_dataType, pSrcImage->m_channels, pTile->m_borderSize, *pBorder, pBorderVal);
816         if(status < 0)
817             return status;
818 
819         *pBorder = ippBorderInMem;
820     }
821 
822     return ippStsNoErr;
823 }
824 
owniTilePipeline_ProcBorder(const IwiTile * pTile,IwiImage * pSrcImage,IwiBorderType * pBorder,const Ipp64f * pBorderVal)825 IW_DECL(IppStatus) owniTilePipeline_ProcBorder(const IwiTile *pTile, IwiImage *pSrcImage, IwiBorderType *pBorder, const Ipp64f *pBorderVal)
826 {
827     *pBorder = pTile->m_borderType;
828     owniTile_GetTileBorder(pBorder, &pTile->m_srcRoi, &pTile->m_borderSize, &pTile->m_srcImageSize);
829 
830     if(pTile->m_pChild)
831     {
832         IppStatus     status;
833         IwiBorderSize borderSize     = pTile->m_borderSize;
834         IwiBorderSize borderSizeDiff = {0, 0, 0, 0};
835         int           overlap        = 0;
836         IwSize        rightPos       = pTile->m_srcRoi.x + pTile->m_srcRoi.width;
837         IwSize        bottomPos      = pTile->m_srcRoi.y + pTile->m_srcRoi.height;
838 
839         // Pre-process partial InMem border. Shift buffer in InMem boundary and extrapolate the rest
840         // Check left border
841         if(pTile->m_borderSize.left && (pTile->m_srcRoi.x > 0 && pTile->m_srcRoi.x < pTile->m_borderSize.left))
842         {
843             borderSizeDiff.left = pTile->m_srcRoi.x;
844             borderSize.left    -= borderSizeDiff.left;
845             overlap             = 1;
846         }
847 
848         // Check top border
849         if(pTile->m_borderSize.top && (pTile->m_srcRoi.y > 0 && pTile->m_srcRoi.y < pTile->m_borderSize.top))
850         {
851             borderSizeDiff.top = pTile->m_srcRoi.y;
852             borderSize.top    -= borderSizeDiff.top;
853             overlap            = 1;
854         }
855 
856         // Check right border
857         if(pTile->m_borderSize.right && (rightPos + pTile->m_borderSize.right > pTile->m_srcImageSize.width && rightPos < pTile->m_srcImageSize.width))
858         {
859             borderSizeDiff.right = pTile->m_srcImageSize.width - rightPos;
860             borderSize.right    -= borderSizeDiff.right;
861             overlap              = 1;
862         }
863 
864         // Check bottom border
865         if(pTile->m_borderSize.bottom && (bottomPos + pTile->m_borderSize.bottom > pTile->m_srcImageSize.height && bottomPos < pTile->m_srcImageSize.height))
866         {
867             borderSizeDiff.bottom = pTile->m_srcImageSize.height - bottomPos;
868             borderSize.bottom    -= borderSizeDiff.bottom;
869             overlap               = 1;
870         }
871 
872         if(overlap)
873         {
874             IwiImage tmpImage;
875 
876             iwiImage_InitExternal(&tmpImage, pSrcImage->m_size, pSrcImage->m_dataType, pSrcImage->m_channels, &pSrcImage->m_inMemSize, pSrcImage->m_ptr, pSrcImage->m_step);
877 
878             status = iwiImage_BorderSub(&tmpImage, borderSizeDiff);
879             if(status < 0)
880                 return status;
881 
882             // Extrapolate border for intermediate buffers
883             return owniTilePipeline_BuildBorder(pTile, &tmpImage, pBorder, pBorderVal, &borderSize);
884         }
885         else
886         {
887             // Extrapolate border for intermediate buffers
888             return owniTilePipeline_BuildBorder(pTile, pSrcImage, pBorder, pBorderVal, &borderSize);
889         }
890     }
891     return ippStsNoErr;
892 }
893 
owniTilePipeline_InitCommon(IwiTile * pTile,const IwiBorderType * pBorderType,const IwiBorderSize * pBorderSize,const IwiTileTransform * pTransformStruct)894 static IppStatus owniTilePipeline_InitCommon(IwiTile *pTile, const IwiBorderType *pBorderType, const IwiBorderSize *pBorderSize, const IwiTileTransform *pTransformStruct)
895 {
896     IppStatus status;
897 
898     if(pTile->m_maxTileSize.width > pTile->m_dstImageSize.width)
899         pTile->m_maxTileSize.width = pTile->m_dstImageSize.width;
900     if(pTile->m_maxTileSize.height > pTile->m_dstImageSize.height)
901         pTile->m_maxTileSize.height = pTile->m_dstImageSize.height;
902 
903     if(pTransformStruct && pTransformStruct->getSrcRoiFun)
904     {
905         pTile->m_transformStruct = *pTransformStruct;
906 
907         status = owniTilePipeline_GetSrcSizeMax(&pTile->m_srcRoi, &pTile->m_maxTileSize, &pTile->m_dstExImageSize, pTransformStruct);
908         if(status < 0)
909             return status;
910 
911         pTile->m_srcImageSize  = pTile->m_transformStruct.srcImageSize;
912         pTile->m_srcBufferSize = pTile->m_transformStruct.srcImageSize;
913     }
914 
915     pTile->m_borderType = ippBorderRepl;
916     if(pBorderSize)
917     {
918         pTile->m_borderSize = *pBorderSize;
919         if(pBorderType)
920         {
921             pTile->m_borderType = *pBorderType;
922             if(pTile->m_borderType&ippBorderInMemLeft)
923             {
924                 pTile->m_externalMemAcc.left += pTile->m_borderSize.left;
925                 pTile->m_externalMem.left = pTile->m_borderSize.left;
926             }
927             if(pTile->m_borderType&ippBorderInMemRight)
928             {
929                 pTile->m_externalMemAcc.right += pTile->m_borderSize.right;
930                 pTile->m_externalMem.right = pTile->m_borderSize.right;
931             }
932             if(pTile->m_borderType&ippBorderInMemTop)
933             {
934                 pTile->m_externalMemAcc.top += pTile->m_borderSize.top;
935                 pTile->m_externalMem.top = pTile->m_borderSize.top;
936             }
937             if(pTile->m_borderType&ippBorderInMemBottom)
938             {
939                 pTile->m_externalMemAcc.bottom += pTile->m_borderSize.bottom;
940                 pTile->m_externalMem.bottom = pTile->m_borderSize.bottom;
941             }
942 
943             pTile->m_srcExImageSize.width  += (pTile->m_externalMem.left + pTile->m_externalMem.right);
944             pTile->m_srcExImageSize.height += (pTile->m_externalMem.top + pTile->m_externalMem.bottom);
945         }
946 
947         pTile->m_borderSizeAcc.left   += pTile->m_borderSize.left;
948         pTile->m_borderSizeAcc.top    += pTile->m_borderSize.top;
949         pTile->m_borderSizeAcc.right  += pTile->m_borderSize.right;
950         pTile->m_borderSizeAcc.bottom += pTile->m_borderSize.bottom;
951     }
952 
953     return ippStsNoErr;
954 }
955 
iwiTilePipeline_Init(IwiTile * pTile,IwiSize tileSizeMax,IwiSize imageSize,const IwiBorderType * pBorderType,const IwiBorderSize * pBorderSize,const IwiTileTransform * pTransformStruct)956 IW_DECL(IppStatus) iwiTilePipeline_Init(IwiTile *pTile, IwiSize tileSizeMax, IwiSize imageSize, const IwiBorderType *pBorderType, const IwiBorderSize *pBorderSize, const IwiTileTransform *pTransformStruct)
957 {
958     IppStatus status;
959 
960     if(!pTile)
961         return ippStsNullPtrErr;
962 
963     ippsZero_8u((Ipp8u*)pTile, sizeof(IwiTile));
964 
965     if(tileSizeMax.width <= 0 || tileSizeMax.height <= 0)
966         return ippStsSizeErr;
967 
968     if(tileSizeMax.width > imageSize.width)
969         tileSizeMax.width = imageSize.width;
970     if(tileSizeMax.height > imageSize.height)
971         tileSizeMax.height = imageSize.height;
972 
973     pTile->m_maxTileSize   = tileSizeMax;
974 
975     pTile->m_srcRoi.width  = pTile->m_dstRoi.width  = pTile->m_maxTileSize.width;
976     pTile->m_srcRoi.height = pTile->m_dstRoi.height = pTile->m_maxTileSize.height;
977 
978     pTile->m_srcImageSize   = pTile->m_dstImageSize   = imageSize;
979     pTile->m_dstBufferSize  = pTile->m_srcBufferSize  = imageSize;
980     pTile->m_dstExImageSize = pTile->m_srcExImageSize = imageSize;
981 
982     status = owniTilePipeline_InitCommon(pTile, pBorderType, pBorderSize, pTransformStruct);
983     if(status < 0)
984         return status;
985 
986     pTile->m_initialized   = ownTileInitPipe;
987     return ippStsNoErr;
988 }
989 
iwiTilePipeline_InitChild(IwiTile * pTile,IwiTile * pParent,const IwiBorderType * pBorderType,const IwiBorderSize * pBorderSize,const IwiTileTransform * pTransformStruct)990 IW_DECL(IppStatus) iwiTilePipeline_InitChild(IwiTile *pTile, IwiTile *pParent, const IwiBorderType *pBorderType, const IwiBorderSize *pBorderSize, const IwiTileTransform *pTransformStruct)
991 {
992     IppStatus status = owniTilePipeline_InitCheck(pParent);
993     if(status < 0)
994         return status;
995 
996     if(!pTile)
997         return ippStsNullPtrErr;
998 
999     ippsZero_8u((Ipp8u*)pTile, sizeof(IwiTile));
1000 
1001     pParent->m_pChild = pTile;
1002     pTile->m_pParent   = pParent;
1003 
1004     pTile->m_maxTileSize.width  = pParent->m_srcRoi.width  + pParent->m_borderSize.left + pParent->m_borderSize.right;
1005     pTile->m_maxTileSize.height = pParent->m_srcRoi.height + pParent->m_borderSize.top  + pParent->m_borderSize.bottom;
1006     if(pParent->m_borderType == ippBorderMirror)
1007     {
1008         if(pParent->m_borderSize.left || pParent->m_borderSize.right)
1009             pTile->m_maxTileSize.width++;
1010         if(pParent->m_borderSize.top || pParent->m_borderSize.bottom)
1011             pTile->m_maxTileSize.height++;
1012     }
1013 
1014     pTile->m_dstImageSize    = pParent->m_srcImageSize;
1015     pTile->m_dstExImageSize  = pParent->m_srcExImageSize;
1016     pTile->m_srcExImageSize  = pTile->m_dstExImageSize;
1017 
1018     pTile->m_srcRoi.width  = pTile->m_dstRoi.width  = pTile->m_maxTileSize.width;
1019     pTile->m_srcRoi.height = pTile->m_dstRoi.height = pTile->m_maxTileSize.height;
1020 
1021     pTile->m_dstBufferSize.width  = pParent->m_srcBufferSize.width  = pTile->m_dstRoi.width;
1022     pTile->m_dstBufferSize.height = pParent->m_srcBufferSize.height = pTile->m_dstRoi.height;
1023 
1024     pTile->m_srcBufferSize  = pTile->m_dstImageSize;
1025     pTile->m_srcImageSize   = pTile->m_dstImageSize;
1026     pTile->m_borderSizeAcc  = pParent->m_borderSizeAcc;
1027     pTile->m_externalMemAcc = pParent->m_externalMemAcc;
1028 
1029     status = owniTilePipeline_InitCommon(pTile, pBorderType, pBorderSize, pTransformStruct);
1030     if(status < 0)
1031         return status;
1032 
1033     pTile->m_initialized = pParent->m_initialized;
1034     return ippStsNoErr;
1035 }
1036 
iwiTilePipeline_Release(IwiTile * pTile)1037 IW_DECL(void) iwiTilePipeline_Release(IwiTile *pTile)
1038 {
1039     pTile = owniTilePipeline_GetRoot(pTile);
1040     if(owniTilePipeline_InitCheck(pTile) < 0)
1041         return;
1042 
1043     while(pTile)
1044     {
1045         // Nothing to actually deallocate yet, but this may be helpful in the future.
1046         pTile->m_initialized = ownTileInitNone;
1047 
1048         pTile = pTile->m_pChild;
1049     }
1050 }
1051 
iwiTilePipeline_SetRoi(IwiTile * pTile,IwiRoi tileRoi)1052 IW_DECL(IppStatus) iwiTilePipeline_SetRoi(IwiTile *pTile, IwiRoi tileRoi)
1053 {
1054     IppStatus  status;
1055     IwiTile   *pRoot          = NULL;
1056     int        hasScaling     = 0;
1057     double     scaleX         = 1;
1058     double     scaleY         = 1;
1059 
1060     pRoot  = owniTilePipeline_GetRoot(pTile);
1061     status = owniTilePipeline_InitCheck(pTile);
1062     if(status < 0)
1063         return status;
1064 
1065     if(tileRoi.x < 0)
1066         tileRoi.x = 0;
1067     if(tileRoi.y < 0)
1068         tileRoi.y = 0;
1069 
1070     if(tileRoi.width <= 0 || tileRoi.height <= 0)
1071         return ippStsSizeErr;
1072 
1073     if(tileRoi.width > pRoot->m_maxTileSize.width)
1074         tileRoi.width  = pRoot->m_maxTileSize.width;
1075     if(tileRoi.height > pRoot->m_maxTileSize.height)
1076         tileRoi.height = pRoot->m_maxTileSize.height;
1077 
1078     pTile = pRoot;
1079     while(pTile)
1080     {
1081         if(pTile->m_pParent)
1082         {
1083             pTile->m_dstRoi        = pTile->m_pParent->m_srcRoi;
1084             pTile->m_untaintDstPos = pTile->m_pParent->m_untaintSrcPos;
1085 
1086             pTile->m_dstRoi.width    += pTile->m_pParent->m_borderSize.left;
1087             pTile->m_dstRoi.x        -= pTile->m_pParent->m_borderSize.left;
1088             pTile->m_untaintDstPos.x -= pTile->m_pParent->m_borderSize.left;
1089 
1090             pTile->m_dstRoi.height    += pTile->m_pParent->m_borderSize.top;
1091             pTile->m_dstRoi.y         -= pTile->m_pParent->m_borderSize.top;
1092             pTile->m_untaintDstPos.y  -= pTile->m_pParent->m_borderSize.top;
1093 
1094             pTile->m_dstRoi.width  += pTile->m_pParent->m_borderSize.right;
1095             pTile->m_dstRoi.height += pTile->m_pParent->m_borderSize.bottom;
1096 
1097             if(pTile->m_dstRoi.x < 0)
1098             {
1099                 if(!pTile->m_pParent->m_externalMem.left)
1100                 {
1101                     pTile->m_dstRoi.width += pTile->m_dstRoi.x;
1102                     pTile->m_dstRoi.x = 0;
1103                 }
1104             }
1105 
1106             if(pTile->m_dstRoi.y < 0)
1107             {
1108                 if(!pTile->m_pParent->m_externalMem.top)
1109                 {
1110                     pTile->m_dstRoi.height += pTile->m_dstRoi.y;
1111                     pTile->m_dstRoi.y = 0;
1112                 }
1113             }
1114 
1115             if(pTile->m_dstRoi.x + pTile->m_dstRoi.width > pTile->m_dstImageSize.width + pTile->m_pParent->m_externalMemAcc.right)
1116                 pTile->m_dstRoi.width = pTile->m_dstImageSize.width - pTile->m_dstRoi.x + pTile->m_pParent->m_externalMemAcc.right;
1117             if(pTile->m_dstRoi.y + pTile->m_dstRoi.height > pTile->m_dstImageSize.height + pTile->m_pParent->m_externalMemAcc.bottom)
1118                 pTile->m_dstRoi.height = pTile->m_dstImageSize.height - pTile->m_dstRoi.y + pTile->m_pParent->m_externalMemAcc.bottom;
1119         }
1120         else
1121         {
1122             pTile->m_dstRoi          = tileRoi;
1123             pTile->m_untaintDstPos.x = pTile->m_dstRoi.x;
1124             pTile->m_untaintDstPos.y = pTile->m_dstRoi.y;
1125 
1126             if(pTile->m_dstRoi.x + pTile->m_dstRoi.width > pTile->m_dstImageSize.width)
1127                 pTile->m_dstRoi.width = pTile->m_dstImageSize.width - pTile->m_dstRoi.x;
1128             if(pTile->m_dstRoi.y + pTile->m_dstRoi.height > pTile->m_dstImageSize.height)
1129                 pTile->m_dstRoi.height = pTile->m_dstImageSize.height - pTile->m_dstRoi.y;
1130         }
1131 
1132         if(pTile->m_transformStruct.getSrcRoiFun)
1133         {
1134             // Scaling function should process partial borders correctly, so no overlap check is needed
1135             if(pTile->m_transformStruct.getSrcRoiFun(pTile->m_dstRoi, &pTile->m_srcRoi, pTile->m_transformStruct.pParams))
1136                 return ippStsErr;
1137 
1138             if(pTile->m_untaintDstPos.x < 0)
1139             {
1140            //     pTile->m_srcRoi.x
1141            //     pTile->m_untaintSrcPos.x = pTile->m_untaintDstPos.x + pTile->m_srcRoi.x;
1142            //     pTile->m_srcRoi.width += -pTile->m_untaintDstPos.x;
1143             }
1144             if(pTile->m_untaintDstPos.y < 0)
1145             {
1146                 pTile->m_untaintSrcPos.y = pTile->m_untaintDstPos.y + pTile->m_srcRoi.y;
1147           //      pTile->m_srcRoi.height += -pTile->m_untaintDstPos.y;
1148             }
1149 
1150             if(pTile->m_pParent)
1151             {
1152                 if(pTile->m_srcRoi.x + pTile->m_srcRoi.width > pTile->m_srcImageSize.width + pTile->m_pParent->m_externalMemAcc.right)
1153                     pTile->m_srcRoi.width = pTile->m_srcImageSize.width - pTile->m_srcRoi.x + pTile->m_pParent->m_externalMemAcc.right;
1154                 if(pTile->m_srcRoi.y + pTile->m_srcRoi.height > pTile->m_srcImageSize.height + pTile->m_pParent->m_externalMemAcc.bottom)
1155                     pTile->m_srcRoi.height = pTile->m_srcImageSize.height - pTile->m_srcRoi.y + pTile->m_pParent->m_externalMemAcc.bottom;
1156             }
1157 
1158             //hasScaling = 1;
1159         }
1160         else
1161         {
1162             pTile->m_srcRoi        = pTile->m_dstRoi;
1163             pTile->m_untaintSrcPos = pTile->m_untaintDstPos;
1164 
1165             if(!pTile->m_pChild) // Correction is required only for the first tile int the pipe since all other tiles use iwiCreateBorder function
1166             {
1167                 IwiRoi correctRoi = pTile->m_dstRoi;
1168 
1169                 // Shift source tile and start again
1170                 if(owniTile_CorrectBordersOverlap(&correctRoi, NULL, &pTile->m_borderType, &pTile->m_borderSize, &pTile->m_borderSizeAcc, &pTile->m_srcImageSize))
1171                 {
1172                     if(hasScaling)
1173                     {
1174                         tileRoi.x      += (IwSize)((correctRoi.x-pTile->m_srcRoi.x)*(scaleX + 0.5));
1175                         tileRoi.y      += (IwSize)((correctRoi.y-pTile->m_srcRoi.y)*(scaleY + 0.5));
1176                         tileRoi.width  += (IwSize)((correctRoi.width-pTile->m_srcRoi.width)*(scaleX + 0.5));
1177                         tileRoi.height += (IwSize)((correctRoi.height-pTile->m_srcRoi.height)*(scaleY + 0.5));
1178                     }
1179                     else
1180                     {
1181                         tileRoi.x      += correctRoi.x-pTile->m_srcRoi.x;
1182                         tileRoi.y      += correctRoi.y-pTile->m_srcRoi.y;
1183                         tileRoi.width  += correctRoi.width-pTile->m_srcRoi.width;
1184                         tileRoi.height += correctRoi.height-pTile->m_srcRoi.height;
1185                     }
1186 
1187                     hasScaling     = 0;
1188                     scaleX         = 1;
1189                     scaleY         = 1;
1190                     pTile = pRoot;
1191                     continue;
1192                 }
1193             }
1194         }
1195 
1196         // Dst offset
1197         pTile->m_boundDstRoi = pTile->m_dstRoi;
1198         if(pTile->m_pParent)
1199         {
1200             // Intermediate dst buffer is aligned so that actual src image for parent will always be in the center
1201             if(pTile->m_untaintDstPos.x < 0 && !pTile->m_pParent->m_externalMem.left)
1202             {
1203                 if(pTile->m_pParent->m_untaintDstPos.x <= 0)
1204                     pTile->m_boundDstRoi.x  = pTile->m_pParent->m_untaintDstPos.x - pTile->m_untaintDstPos.x;
1205                 else
1206                     pTile->m_boundDstRoi.x  = -pTile->m_untaintDstPos.x;
1207             }
1208             else
1209                 pTile->m_boundDstRoi.x = 0;
1210 
1211             if(pTile->m_untaintDstPos.y < 0 && !pTile->m_pParent->m_externalMem.top)
1212             {
1213                 if(pTile->m_pParent->m_untaintDstPos.y <= 0)
1214                     pTile->m_boundDstRoi.y  = pTile->m_pParent->m_untaintDstPos.y - pTile->m_untaintDstPos.y;
1215                 else
1216                     pTile->m_boundDstRoi.y  = -pTile->m_untaintDstPos.y;
1217             }
1218             else
1219                 pTile->m_boundDstRoi.y = 0;
1220         }
1221 
1222         // Src offset
1223         pTile->m_boundSrcRoi = pTile->m_srcRoi;
1224         if(pTile->m_pChild)
1225         {
1226             // Intermediate src buffer is aligned to point inside border
1227             pTile->m_boundSrcRoi.x = pTile->m_borderSize.left;
1228             pTile->m_boundSrcRoi.y = pTile->m_borderSize.top;
1229         }
1230         else
1231         {
1232             // Shift source image to make InMem border a part of ROI
1233             if(pTile->m_pParent)
1234             {
1235                 if(pTile->m_untaintSrcPos.x < 0)
1236                 {
1237                     if(pTile->m_pParent->m_externalMemAcc.left >= -pTile->m_untaintSrcPos.x)
1238                         pTile->m_boundSrcRoi.x = pTile->m_untaintSrcPos.x;
1239                     else
1240                         pTile->m_boundSrcRoi.x = 0;
1241                 }
1242 
1243                 if(pTile->m_untaintSrcPos.y < 0)
1244                 {
1245                     if(pTile->m_pParent->m_externalMemAcc.top >= -pTile->m_untaintSrcPos.y)
1246                         pTile->m_boundSrcRoi.y = pTile->m_untaintSrcPos.y;
1247                     else
1248                         pTile->m_boundSrcRoi.y = 0;
1249                 }
1250             }
1251         }
1252 
1253         pTile = pTile->m_pChild;
1254     }
1255 
1256     return ippStsNoErr;
1257 }
1258 
iwiTilePipeline_GetDstBufferSize(const IwiTile * pTile,IwiSize * pDstSize)1259 IW_DECL(IppStatus) iwiTilePipeline_GetDstBufferSize(const IwiTile *pTile, IwiSize *pDstSize)
1260 {
1261     IppStatus status = owniTilePipeline_InitCheck(pTile);
1262     if(status < 0)
1263         return status;
1264     if(!pDstSize)
1265         return ippStsNullPtrErr;
1266 
1267     *pDstSize = pTile->m_dstBufferSize;
1268 
1269     return ippStsNoErr;
1270 }
1271 
iwiTilePipeline_GetChildSrcImageSize(const IwiTile * pTile,IwiSize srcOrigSize,IwiSize * pSrcFullSize)1272 IW_DECL(IppStatus) iwiTilePipeline_GetChildSrcImageSize(const IwiTile *pTile, IwiSize srcOrigSize, IwiSize *pSrcFullSize)
1273 {
1274     IppStatus status = owniTilePipeline_InitCheck(pTile);
1275     if(status < 0)
1276         return status;
1277     if(!pSrcFullSize)
1278         return ippStsNullPtrErr;
1279 
1280     pSrcFullSize->width  = srcOrigSize.width  + pTile->m_externalMemAcc.left + pTile->m_externalMemAcc.right;
1281     pSrcFullSize->height = srcOrigSize.height + pTile->m_externalMemAcc.top + pTile->m_externalMemAcc.bottom;
1282 
1283     return ippStsNoErr;
1284 }
1285 
iwiTilePipeline_GetChildDstImageSize(const IwiTile * pTile,IwiSize dstOrigSize,IwiSize * pDstFullSize)1286 IW_DECL(IppStatus) iwiTilePipeline_GetChildDstImageSize(const IwiTile *pTile, IwiSize dstOrigSize, IwiSize *pDstFullSize)
1287 {
1288     IppStatus status = owniTilePipeline_InitCheck(pTile);
1289     if(status < 0)
1290         return status;
1291     if(!pDstFullSize)
1292         return ippStsNullPtrErr;
1293 
1294     pDstFullSize->width  = dstOrigSize.width  + pTile->m_externalMemAcc.left + pTile->m_externalMemAcc.right;
1295     pDstFullSize->height = dstOrigSize.height + pTile->m_externalMemAcc.top + pTile->m_externalMemAcc.bottom;
1296 
1297     return ippStsNoErr;
1298 }
1299 
iwiTilePipeline_BuildBorder(const IwiTile * pTile,IwiImage * pSrcImage,IwiBorderType * pBorder,const Ipp64f * pBorderVal)1300 IW_DECL(IppStatus) iwiTilePipeline_BuildBorder(const IwiTile *pTile, IwiImage *pSrcImage, IwiBorderType *pBorder, const Ipp64f *pBorderVal)
1301 {
1302     IppStatus status;
1303 
1304     if(!pBorder)
1305         return ippStsNullPtrErr;
1306 
1307     status = owniTilePipeline_InitCheck(pTile);
1308     if(status < 0)
1309         return status;
1310 
1311     status = owniCheckImageWrite(pSrcImage);
1312     if(status < 0)
1313         return status;
1314 
1315     return owniTilePipeline_BuildBorder(pTile, pSrcImage, pBorder, pBorderVal, NULL);
1316 }
1317 
iwiTilePipeline_GetBoundedSrcRoi(const IwiTile * pTile,IwiRoi * pBoundedRoi)1318 IW_DECL(IppStatus) iwiTilePipeline_GetBoundedSrcRoi(const IwiTile *pTile, IwiRoi *pBoundedRoi)
1319 {
1320     IppStatus status = owniTilePipeline_InitCheck(pTile);
1321     if(status < 0)
1322         return status;
1323     if(!pBoundedRoi)
1324         return ippStsNullPtrErr;
1325 
1326     *pBoundedRoi = pTile->m_boundSrcRoi;
1327 
1328     return ippStsNoErr;
1329 }
1330 
iwiTilePipeline_GetBoundedDstRoi(const IwiTile * pTile,IwiRoi * pBoundedRoi)1331 IW_DECL(IppStatus) iwiTilePipeline_GetBoundedDstRoi(const IwiTile *pTile, IwiRoi *pBoundedRoi)
1332 {
1333     IppStatus status = owniTilePipeline_InitCheck(pTile);
1334     if(status < 0)
1335         return status;
1336     if(!pBoundedRoi)
1337         return ippStsNullPtrErr;
1338 
1339     *pBoundedRoi = pTile->m_boundDstRoi;
1340 
1341     return ippStsNoErr;
1342 }
1343 
iwiTilePipeline_GetTileBorder(const IwiTile * pTile,IwiBorderType * pBorder)1344 IW_DECL(IppStatus) iwiTilePipeline_GetTileBorder(const IwiTile *pTile, IwiBorderType *pBorder)
1345 {
1346     IppStatus status = owniTilePipeline_InitCheck(pTile);
1347     if(status < 0)
1348         return status;
1349     if(!pBorder)
1350         return ippStsNullPtrErr;
1351 
1352     owniTile_GetTileBorder(pBorder, &pTile->m_srcRoi, &pTile->m_borderSize, &pTile->m_srcImageSize);
1353     return ippStsNoErr;
1354 }
1355 
iwiTilePipeline_GetMinTileSize(const IwiTile * pTile,IwiSize * pMinTileSize)1356 IW_DECL(IppStatus) iwiTilePipeline_GetMinTileSize(const IwiTile *pTile, IwiSize *pMinTileSize)
1357 {
1358     IppStatus       status;
1359     const IwiTile  *pRoot;
1360 
1361     if(!pMinTileSize)
1362         return ippStsNullPtrErr;
1363     pRoot  = owniTilePipeline_GetRoot(pTile);
1364     status = owniTilePipeline_InitCheck(pTile);
1365     if(status < 0)
1366         return status;
1367 
1368     // Check width
1369     pTile = pRoot;
1370     while(pTile)
1371     {
1372         if(!pTile->m_pChild)
1373         {
1374             *pMinTileSize   = iwiTile_GetMinTileSize(pTile->m_borderType, pTile->m_borderSize);
1375             if(pTile->m_pParent && (pMinTileSize->width > 1 || pMinTileSize->height > 1))
1376             {
1377                 *pMinTileSize = iwiTile_GetMinTileSize(pTile->m_borderType, pTile->m_borderSizeAcc);
1378             }
1379 
1380             return ippStsNoErr;
1381         }
1382 
1383         pTile = pTile->m_pChild;
1384     }
1385 
1386     return ippStsNoErr;
1387 }
1388 
1389