forked from mirrors/gecko-dev
		
	 bebb9f9181
			
		
	
	
		bebb9f9181
		
	
	
	
	
		
			
			It is bringing some minor changes # ignore-this-changeset Differential Revision: https://phabricator.services.mozilla.com/D90795
		
			
				
	
	
		
			569 lines
		
	
	
	
		
			20 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			569 lines
		
	
	
	
		
			20 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 | |
| /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 | |
| /* This Source Code Form is subject to the terms of the Mozilla Public
 | |
|  * License, v. 2.0. If a copy of the MPL was not distributed with this
 | |
|  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 | |
| 
 | |
| #include "Blur.h"
 | |
| 
 | |
| #include <string.h>
 | |
| 
 | |
| #ifdef _MIPS_ARCH_LOONGSON3A
 | |
| 
 | |
| #  include "MMIHelpers.h"
 | |
| 
 | |
| namespace mozilla {
 | |
| namespace gfx {
 | |
| 
 | |
| typedef struct {
 | |
|   double l;
 | |
|   double h;
 | |
| } __m128i;
 | |
| 
 | |
| MOZ_ALWAYS_INLINE
 | |
| __m128i loadUnaligned128(__m128i* p) {
 | |
|   __m128i v;
 | |
| 
 | |
|   asm volatile(
 | |
|       ".set push \n\t"
 | |
|       ".set arch=loongson3a \n\t"
 | |
|       "gsldlc1 %[vh], 0xf(%[p]) \n\t"
 | |
|       "gsldrc1 %[vh], 0x8(%[p]) \n\t"
 | |
|       "gsldlc1 %[vl], 0x7(%[p]) \n\t"
 | |
|       "gsldrc1 %[vl], 0x0(%[p]) \n\t"
 | |
|       ".set pop \n\t"
 | |
|       : [vh] "=f"(v.h), [vl] "=f"(v.l)
 | |
|       : [p] "r"(p)
 | |
|       : "memory");
 | |
| 
 | |
|   return v;
 | |
| }
 | |
| 
 | |
| MOZ_ALWAYS_INLINE
 | |
| __m128i Divide(__m128i aValues, __m128i aDivisor) {
 | |
|   uint64_t tmp;
 | |
|   double srl32;
 | |
|   __m128i mask, ra, p4321, t1, t2;
 | |
| 
 | |
|   asm volatile(
 | |
|       ".set push \n\t"
 | |
|       ".set arch=loongson3a \n\t"
 | |
|       "li %[tmp], 0x80000000 \n\t"
 | |
|       "mtc1 %[tmp], %[ral] \n\t"
 | |
|       "xor %[maskl], %[maskl], %[maskl] \n\t"
 | |
|       "mov.d %[rah], %[ral] \n\t"
 | |
|       "li %[tmp], 0xffffffff \n\t"
 | |
|       "mthc1 %[tmp], %[maskl] \n\t"
 | |
|       "mov.d %[maskh], %[maskl] \n\t"
 | |
|       ".set pop \n\t"
 | |
|       : [rah] "=f"(ra.h), [ral] "=f"(ra.l), [maskh] "=f"(mask.h),
 | |
|         [maskl] "=f"(mask.l), [tmp] "=&r"(tmp));
 | |
| 
 | |
|   asm volatile(
 | |
|       ".set push \n\t"
 | |
|       ".set arch=loongson3a \n\t"
 | |
|       "ori %[tmp], $0, 32 \n\t"
 | |
|       "mtc1 %[tmp], %[srl32] \n\t" _mm_pmuluw(t1, av, ad)
 | |
|           _mm_psrld(t2, av, srl32) _mm_pmuluw(t2, t2, ad)
 | |
|       // Add 1 << 31 before shifting or masking the lower 32 bits away, so that
 | |
|       // the result is rounded.
 | |
|       _mm_paddd(t1, t1, ra) _mm_psrld(t1, t1, srl32) _mm_paddd(t2, t2, ra)
 | |
|           _mm_and(t2, t2, mask) _mm_or(p4321, t1, t2) ".set pop \n\t"
 | |
|       : [p4321h] "=&f"(p4321.h), [p4321l] "=&f"(p4321.l), [t1h] "=&f"(t1.h),
 | |
|         [t1l] "=&f"(t1.l), [t2h] "=&f"(t2.h), [t2l] "=&f"(t2.l),
 | |
|         [srl32] "=&f"(srl32), [tmp] "=&r"(tmp)
 | |
|       : [rah] "f"(ra.h), [ral] "f"(ra.l), [maskh] "f"(mask.h),
 | |
|         [maskl] "f"(mask.l), [avh] "f"(aValues.h), [avl] "f"(aValues.l),
 | |
|         [adh] "f"(aDivisor.h), [adl] "f"(aDivisor.l));
 | |
| 
 | |
|   return p4321;
 | |
| }
 | |
| 
 | |
| MOZ_ALWAYS_INLINE
 | |
| __m128i BlurFourPixels(const __m128i& aTopLeft, const __m128i& aTopRight,
 | |
|                        const __m128i& aBottomRight, const __m128i& aBottomLeft,
 | |
|                        const __m128i& aDivisor) {
 | |
|   __m128i values;
 | |
| 
 | |
|   asm volatile(
 | |
|       ".set push \n\t"
 | |
|       ".set arch=loongson3a \n\t" _mm_psubw(val, abr, atr)
 | |
|           _mm_psubw(val, val, abl) _mm_paddw(val, val, atl) ".set pop \n\t"
 | |
|       : [valh] "=&f"(values.h), [vall] "=&f"(values.l)
 | |
|       : [abrh] "f"(aBottomRight.h), [abrl] "f"(aBottomRight.l),
 | |
|         [atrh] "f"(aTopRight.h), [atrl] "f"(aTopRight.l),
 | |
|         [ablh] "f"(aBottomLeft.h), [abll] "f"(aBottomLeft.l),
 | |
|         [atlh] "f"(aTopLeft.h), [atll] "f"(aTopLeft.l));
 | |
| 
 | |
|   return Divide(values, aDivisor);
 | |
| }
 | |
| 
 | |
| MOZ_ALWAYS_INLINE
 | |
| void LoadIntegralRowFromRow(uint32_t* aDest, const uint8_t* aSource,
 | |
|                             int32_t aSourceWidth, int32_t aLeftInflation,
 | |
|                             int32_t aRightInflation) {
 | |
|   int32_t currentRowSum = 0;
 | |
| 
 | |
|   for (int x = 0; x < aLeftInflation; x++) {
 | |
|     currentRowSum += aSource[0];
 | |
|     aDest[x] = currentRowSum;
 | |
|   }
 | |
|   for (int x = aLeftInflation; x < (aSourceWidth + aLeftInflation); x++) {
 | |
|     currentRowSum += aSource[(x - aLeftInflation)];
 | |
|     aDest[x] = currentRowSum;
 | |
|   }
 | |
|   for (int x = (aSourceWidth + aLeftInflation);
 | |
|        x < (aSourceWidth + aLeftInflation + aRightInflation); x++) {
 | |
|     currentRowSum += aSource[aSourceWidth - 1];
 | |
|     aDest[x] = currentRowSum;
 | |
|   }
 | |
| }
 | |
| 
 | |
| // This function calculates an integral of four pixels stored in the 4
 | |
| // 32-bit integers on aPixels. i.e. for { 30, 50, 80, 100 } this returns
 | |
| // { 30, 80, 160, 260 }. This seems to be the fastest way to do this after
 | |
| // much testing.
 | |
| MOZ_ALWAYS_INLINE
 | |
| __m128i AccumulatePixelSums(__m128i aPixels) {
 | |
|   uint64_t tr;
 | |
|   double tmp, s4, s64;
 | |
|   __m128i sumPixels, currentPixels, zero;
 | |
| 
 | |
|   asm volatile (
 | |
|     ".set push \n\t"
 | |
|     ".set arch=loongson3a \n\t"
 | |
|     _mm_xor(z, z, z)
 | |
|     "li %[tr], 64 \n\t"
 | |
|     "mtc1 %[tr], %[s64] \n\t"
 | |
|     "li %[tr], 32 \n\t"
 | |
|     "mtc1 %[tr], %[s4] \n\t"
 | |
|     _mm_psllq(cp, ap, s4, s64, t)
 | |
|     _mm_paddw(sp, ap, cp)
 | |
|     _mm_punpckldq(cp, z, sp)
 | |
|     _mm_paddw(sp, sp, cp)
 | |
|     ".set pop \n\t"
 | |
|     :[sph]"=&f"(sumPixels.h), [spl]"=&f"(sumPixels.l),
 | |
|      [cph]"=&f"(currentPixels.h), [cpl]"=&f"(currentPixels.l),
 | |
|      [zh]"=&f"(zero.h), [zl]"=&f"(zero.l),
 | |
|      [s4]"=&f"(s4), [s64]"=&f"(s64), [t]"=&f"(tmp), [tr]"=&r"(tr)
 | |
|     :[aph]"f"(aPixels.h), [apl]"f"(aPixels.l)
 | |
|   );
 | |
| 
 | |
|   return sumPixels;
 | |
| }
 | |
| 
 | |
| MOZ_ALWAYS_INLINE
 | |
| void GenerateIntegralImage_LS3(int32_t aLeftInflation, int32_t aRightInflation,
 | |
|                                int32_t aTopInflation, int32_t aBottomInflation,
 | |
|                                uint32_t* aIntegralImage,
 | |
|                                size_t aIntegralImageStride, uint8_t* aSource,
 | |
|                                int32_t aSourceStride, const IntSize& aSize) {
 | |
|   MOZ_ASSERT(!(aLeftInflation & 3));
 | |
| 
 | |
|   uint32_t stride32bit = aIntegralImageStride / 4;
 | |
| 
 | |
|   IntSize integralImageSize(aSize.width + aLeftInflation + aRightInflation,
 | |
|                             aSize.height + aTopInflation + aBottomInflation);
 | |
| 
 | |
|   LoadIntegralRowFromRow(aIntegralImage, aSource, aSize.width, aLeftInflation,
 | |
|                          aRightInflation);
 | |
| 
 | |
|   for (int y = 1; y < aTopInflation + 1; y++) {
 | |
|     uint32_t* intRow = aIntegralImage + (y * stride32bit);
 | |
|     uint32_t* intPrevRow = aIntegralImage + (y - 1) * stride32bit;
 | |
|     uint32_t* intFirstRow = aIntegralImage;
 | |
| 
 | |
|     for (int x = 0; x < integralImageSize.width; x += 4) {
 | |
|       __m128i firstRow, previousRow;
 | |
| 
 | |
|       asm volatile (
 | |
|         ".set push \n\t"
 | |
|         ".set arch=loongson3a \n\t"
 | |
|         "gslqc1 %[frh], %[frl], (%[fr]) \n\t"
 | |
|         "gslqc1 %[prh], %[prl], (%[pr]) \n\t"
 | |
|         _mm_paddw(fr, fr, pr)
 | |
|         "gssqc1 %[frh], %[frl], (%[r]) \n\t"
 | |
|         ".set pop \n\t"
 | |
|         :[frh]"=&f"(firstRow.h), [frl]"=&f"(firstRow.l),
 | |
|          [prh]"=&f"(previousRow.h), [prl]"=&f"(previousRow.l)
 | |
|         :[fr]"r"(intFirstRow + x), [pr]"r"(intPrevRow + x),
 | |
|          [r]"r"(intRow + x)
 | |
|         :"memory"
 | |
|       );
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   uint64_t tmp;
 | |
|   double s44, see;
 | |
|   __m128i zero;
 | |
|   asm volatile(
 | |
|       ".set push \n\t"
 | |
|       ".set arch=loongson3a \n\t"
 | |
|       "li %[tmp], 0xee \n\t"
 | |
|       "mtc1 %[tmp], %[see] \n\t"
 | |
|       "li %[tmp], 0x44 \n\t"
 | |
|       "mtc1 %[tmp], %[s44] \n\t" _mm_xor(zero, zero, zero) ".set pop \n\t"
 | |
|       : [tmp] "=&r"(tmp), [s44] "=f"(s44), [see] "=f"(see),
 | |
|         [zeroh] "=f"(zero.h), [zerol] "=f"(zero.l));
 | |
|   for (int y = aTopInflation + 1; y < (aSize.height + aTopInflation); y++) {
 | |
|     __m128i currentRowSum;
 | |
|     uint32_t* intRow = aIntegralImage + (y * stride32bit);
 | |
|     uint32_t* intPrevRow = aIntegralImage + (y - 1) * stride32bit;
 | |
|     uint8_t* sourceRow = aSource + aSourceStride * (y - aTopInflation);
 | |
|     uint32_t pixel = sourceRow[0];
 | |
| 
 | |
|     asm volatile(
 | |
|         ".set push \n\t"
 | |
|         ".set arch=loongson3a \n\t" _mm_xor(cr, cr, cr) ".set pop \n\t"
 | |
|         : [crh] "=f"(currentRowSum.h), [crl] "=f"(currentRowSum.l));
 | |
|     for (int x = 0; x < aLeftInflation; x += 4) {
 | |
|       __m128i sumPixels, t;
 | |
|       asm volatile(
 | |
|           ".set push \n\t"
 | |
|           ".set arch=loongson3a \n\t"
 | |
|           "mtc1 %[pix], %[spl] \n\t"
 | |
|           "punpcklwd %[spl], %[spl], %[spl] \n\t"
 | |
|           "mov.d %[sph], %[spl] \n\t"
 | |
|           "pshufh %[sph], %[spl], %[s44] \n\t"
 | |
|           "pshufh %[spl], %[spl], %[s44] \n\t"
 | |
|           ".set pop \n\t"
 | |
|           : [sph] "=&f"(sumPixels.h), [spl] "=&f"(sumPixels.l)
 | |
|           : [pix] "r"(pixel), [s44] "f"(s44));
 | |
|       sumPixels = AccumulatePixelSums(sumPixels);
 | |
|       asm volatile (
 | |
|         ".set push \n\t"
 | |
|         ".set arch=loongson3a \n\t"
 | |
|         _mm_paddw(sp, sp, cr)
 | |
|         "pshufh %[crh], %[sph], %[see] \n\t"
 | |
|         "pshufh %[crl], %[sph], %[see] \n\t"
 | |
|         "gslqc1 %[th], %[tl], (%[pr]) \n\t"
 | |
|         _mm_paddw(t, sp, t)
 | |
|         "gssqc1 %[th], %[tl], (%[r]) \n\t"
 | |
|         ".set pop \n\t"
 | |
|         :[th]"=&f"(t.h), [tl]"=&f"(t.l),
 | |
|          [sph]"+f"(sumPixels.h), [spl]"+f"(sumPixels.l),
 | |
|          [crh]"+f"(currentRowSum.h), [crl]"+f"(currentRowSum.l)
 | |
|         :[r]"r"(intRow + x), [pr]"r"(intPrevRow + x), [see]"f"(see)
 | |
|         :"memory"
 | |
|       );
 | |
|     }
 | |
|     for (int x = aLeftInflation; x < (aSize.width + aLeftInflation); x += 4) {
 | |
|       uint32_t pixels = *(uint32_t*)(sourceRow + (x - aLeftInflation));
 | |
|       __m128i sumPixels, t;
 | |
| 
 | |
|       // It's important to shuffle here. When we exit this loop currentRowSum
 | |
|       // has to be set to sumPixels, so that the following loop can get the
 | |
|       // correct pixel for the currentRowSum. The highest order pixel in
 | |
|       // currentRowSum could've originated from accumulation in the stride.
 | |
|       asm volatile(
 | |
|           ".set push \n\t"
 | |
|           ".set arch=loongson3a \n\t"
 | |
|           "pshufh %[crl], %[crh], %[see] \n\t"
 | |
|           "pshufh %[crh], %[crh], %[see] \n\t"
 | |
|           "mtc1 %[pix], %[spl] \n\t"
 | |
|           "punpcklwd %[spl], %[spl], %[spl] \n\t"
 | |
|           "mov.d %[sph], %[spl] \n\t" _mm_punpcklbh(sp, sp, zero)
 | |
|               _mm_punpcklhw(sp, sp, zero) ".set pop \n\t"
 | |
|           : [sph] "=&f"(sumPixels.h), [spl] "=&f"(sumPixels.l),
 | |
|             [crh] "+f"(currentRowSum.h), [crl] "+f"(currentRowSum.l)
 | |
|           : [pix] "r"(pixels), [see] "f"(see), [zeroh] "f"(zero.h),
 | |
|             [zerol] "f"(zero.l));
 | |
|       sumPixels = AccumulatePixelSums(sumPixels);
 | |
|       asm volatile (
 | |
|         ".set push \n\t"
 | |
|         ".set arch=loongson3a \n\t"
 | |
|         _mm_paddw(sp, sp, cr)
 | |
|         "mov.d %[crh], %[sph] \n\t"
 | |
|         "mov.d %[crl], %[spl] \n\t"
 | |
|         "gslqc1 %[th], %[tl], (%[pr]) \n\t"
 | |
|         _mm_paddw(t, sp, t)
 | |
|         "gssqc1 %[th], %[tl], (%[r]) \n\t"
 | |
|         ".set pop \n\t"
 | |
|         :[th]"=&f"(t.h), [tl]"=&f"(t.l),
 | |
|          [sph]"+f"(sumPixels.h), [spl]"+f"(sumPixels.l),
 | |
|          [crh]"+f"(currentRowSum.h), [crl]"+f"(currentRowSum.l)
 | |
|         :[r]"r"(intRow + x), [pr]"r"(intPrevRow + x)
 | |
|         :"memory"
 | |
|       );
 | |
|     }
 | |
| 
 | |
|     pixel = sourceRow[aSize.width - 1];
 | |
|     int x = (aSize.width + aLeftInflation);
 | |
|     if ((aSize.width & 3)) {
 | |
|       // Deal with unaligned portion. Get the correct pixel from currentRowSum,
 | |
|       // see explanation above.
 | |
|       uint32_t intCurrentRowSum =
 | |
|           ((uint32_t*)¤tRowSum)[(aSize.width % 4) - 1];
 | |
|       for (; x < integralImageSize.width; x++) {
 | |
|         // We could be unaligned here!
 | |
|         if (!(x & 3)) {
 | |
|           // aligned!
 | |
|           asm volatile(
 | |
|               ".set push \n\t"
 | |
|               ".set arch=loongson3a \n\t"
 | |
|               "mtc1 %[cr], %[crl] \n\t"
 | |
|               "punpcklwd %[crl], %[crl], %[crl] \n\t"
 | |
|               "mov.d %[crh], %[crl] \n\t"
 | |
|               ".set pop \n\t"
 | |
|               : [crh] "=f"(currentRowSum.h), [crl] "=f"(currentRowSum.l)
 | |
|               : [cr] "r"(intCurrentRowSum));
 | |
|           break;
 | |
|         }
 | |
|         intCurrentRowSum += pixel;
 | |
|         intRow[x] = intPrevRow[x] + intCurrentRowSum;
 | |
|       }
 | |
|     } else {
 | |
|       asm volatile(
 | |
|           ".set push \n\t"
 | |
|           ".set arch=loongson3a \n\t"
 | |
|           "pshufh %[crl], %[crh], %[see] \n\t"
 | |
|           "pshufh %[crh], %[crh], %[see] \n\t"
 | |
|           ".set pop \n\t"
 | |
|           : [crh] "+f"(currentRowSum.h), [crl] "+f"(currentRowSum.l)
 | |
|           : [see] "f"(see));
 | |
|     }
 | |
|     for (; x < integralImageSize.width; x += 4) {
 | |
|       __m128i sumPixels, t;
 | |
|       asm volatile(
 | |
|           ".set push \n\t"
 | |
|           ".set arch=loongson3a \n\t"
 | |
|           "mtc1 %[pix], %[spl] \n\t"
 | |
|           "punpcklwd %[spl], %[spl], %[spl] \n\t"
 | |
|           "mov.d %[sph], %[spl] \n\t"
 | |
|           ".set pop \n\t"
 | |
|           : [sph] "=f"(sumPixels.h), [spl] "=f"(sumPixels.l)
 | |
|           : [pix] "r"(pixel));
 | |
|       sumPixels = AccumulatePixelSums(sumPixels);
 | |
|       asm volatile (
 | |
|         ".set push \n\t"
 | |
|         ".set arch=loongson3a \n\t"
 | |
|         _mm_paddw(sp, sp, cr)
 | |
|         "pshufh %[crh], %[sph], %[see] \n\t"
 | |
|         "pshufh %[crl], %[sph], %[see] \n\t"
 | |
|         "gslqc1 %[th], %[tl], (%[pr]) \n\t"
 | |
|         _mm_paddw(t, sp, t)
 | |
|         "gssqc1 %[th], %[tl], (%[r]) \n\t"
 | |
|         ".set pop \n\t"
 | |
|         :[th]"=&f"(t.h), [tl]"=&f"(t.l),
 | |
|          [sph]"+f"(sumPixels.h), [spl]"+f"(sumPixels.l),
 | |
|          [crh]"+f"(currentRowSum.h), [crl]"+f"(currentRowSum.l)
 | |
|         :[r]"r"(intRow + x), [pr]"r"(intPrevRow + x), [see]"f"(see)
 | |
|         :"memory"
 | |
|       );
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   if (aBottomInflation) {
 | |
|     // Store the last valid row of our source image in the last row of
 | |
|     // our integral image. This will be overwritten with the correct values
 | |
|     // in the upcoming loop.
 | |
|     LoadIntegralRowFromRow(
 | |
|         aIntegralImage + (integralImageSize.height - 1) * stride32bit,
 | |
|         aSource + (aSize.height - 1) * aSourceStride, aSize.width,
 | |
|         aLeftInflation, aRightInflation);
 | |
| 
 | |
|     for (int y = aSize.height + aTopInflation; y < integralImageSize.height;
 | |
|          y++) {
 | |
|       __m128i* intRow = (__m128i*)(aIntegralImage + (y * stride32bit));
 | |
|       __m128i* intPrevRow = (__m128i*)(aIntegralImage + (y - 1) * stride32bit);
 | |
|       __m128i* intLastRow =
 | |
|           (__m128i*)(aIntegralImage +
 | |
|                      (integralImageSize.height - 1) * stride32bit);
 | |
| 
 | |
|       for (int x = 0; x < integralImageSize.width; x += 4) {
 | |
|         __m128i t1, t2;
 | |
|         asm volatile (
 | |
|           ".set push \n\t"
 | |
|           ".set arch=loongson3a \n\t"
 | |
|           "gslqc1 %[t1h], %[t1l], (%[lr]) \n\t"
 | |
|           "gslqc1 %[t2h], %[t2l], (%[pr]) \n\t"
 | |
|           _mm_paddw(t1, t1, t2)
 | |
|           "gssqc1 %[t1h], %[t1l], (%[r]) \n\t"
 | |
|           ".set pop \n\t"
 | |
|           :[t1h]"=&f"(t1.h), [t1l]"=&f"(t1.l),
 | |
|            [t2h]"=&f"(t2.h), [t2l]"=&f"(t2.l)
 | |
|           :[r]"r"(intRow + (x / 4)),
 | |
|            [lr]"r"(intLastRow + (x / 4)),
 | |
|            [pr]"r"(intPrevRow + (x / 4))
 | |
|           :"memory"
 | |
|       );
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Attempt to do an in-place box blur using an integral image.
 | |
|  */
 | |
| void AlphaBoxBlur::BoxBlur_LS3(uint8_t* aData, int32_t aLeftLobe,
 | |
|                                int32_t aRightLobe, int32_t aTopLobe,
 | |
|                                int32_t aBottomLobe, uint32_t* aIntegralImage,
 | |
|                                size_t aIntegralImageStride) const {
 | |
|   IntSize size = GetSize();
 | |
| 
 | |
|   MOZ_ASSERT(size.height > 0);
 | |
| 
 | |
|   // Our 'left' or 'top' lobe will include the current pixel. i.e. when
 | |
|   // looking at an integral image the value of a pixel at 'x,y' is calculated
 | |
|   // using the value of the integral image values above/below that.
 | |
|   aLeftLobe++;
 | |
|   aTopLobe++;
 | |
|   int32_t boxSize = (aLeftLobe + aRightLobe) * (aTopLobe + aBottomLobe);
 | |
| 
 | |
|   MOZ_ASSERT(boxSize > 0);
 | |
| 
 | |
|   if (boxSize == 1) {
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   uint32_t reciprocal = uint32_t((uint64_t(1) << 32) / boxSize);
 | |
| 
 | |
|   uint32_t stride32bit = aIntegralImageStride / 4;
 | |
|   int32_t leftInflation = RoundUpToMultipleOf4(aLeftLobe).value();
 | |
| 
 | |
|   GenerateIntegralImage_LS3(leftInflation, aRightLobe, aTopLobe, aBottomLobe,
 | |
|                             aIntegralImage, aIntegralImageStride, aData,
 | |
|                             mStride, size);
 | |
| 
 | |
|   __m128i divisor, zero;
 | |
|   asm volatile(
 | |
|       ".set push \n\t"
 | |
|       ".set arch=loongson3a \n\t"
 | |
|       "mtc1 %[rec], %[divl] \n\t"
 | |
|       "punpcklwd %[divl], %[divl], %[divl] \n\t"
 | |
|       "mov.d %[divh], %[divl] \n\t" _mm_xor(zero, zero, zero) ".set pop \n\t"
 | |
|       : [divh] "=f"(divisor.h), [divl] "=f"(divisor.l), [zeroh] "=f"(zero.h),
 | |
|         [zerol] "=f"(zero.l)
 | |
|       : [rec] "r"(reciprocal));
 | |
| 
 | |
|   // This points to the start of the rectangle within the IntegralImage that
 | |
|   // overlaps the surface being blurred.
 | |
|   uint32_t* innerIntegral =
 | |
|       aIntegralImage + (aTopLobe * stride32bit) + leftInflation;
 | |
| 
 | |
|   IntRect skipRect = mSkipRect;
 | |
|   int32_t stride = mStride;
 | |
|   uint8_t* data = aData;
 | |
|   for (int32_t y = 0; y < size.height; y++) {
 | |
|     bool inSkipRectY = y > skipRect.y && y < skipRect.YMost();
 | |
| 
 | |
|     uint32_t* topLeftBase =
 | |
|         innerIntegral + ((y - aTopLobe) * ptrdiff_t(stride32bit) - aLeftLobe);
 | |
|     uint32_t* topRightBase =
 | |
|         innerIntegral + ((y - aTopLobe) * ptrdiff_t(stride32bit) + aRightLobe);
 | |
|     uint32_t* bottomRightBase =
 | |
|         innerIntegral +
 | |
|         ((y + aBottomLobe) * ptrdiff_t(stride32bit) + aRightLobe);
 | |
|     uint32_t* bottomLeftBase =
 | |
|         innerIntegral +
 | |
|         ((y + aBottomLobe) * ptrdiff_t(stride32bit) - aLeftLobe);
 | |
| 
 | |
|     int32_t x = 0;
 | |
|     // Process 16 pixels at a time for as long as possible.
 | |
|     for (; x <= size.width - 16; x += 16) {
 | |
|       if (inSkipRectY && x > skipRect.x && x < skipRect.XMost()) {
 | |
|         x = skipRect.XMost() - 16;
 | |
|         // Trigger early jump on coming loop iterations, this will be reset
 | |
|         // next line anyway.
 | |
|         inSkipRectY = false;
 | |
|         continue;
 | |
|       }
 | |
| 
 | |
|       __m128i topLeft;
 | |
|       __m128i topRight;
 | |
|       __m128i bottomRight;
 | |
|       __m128i bottomLeft;
 | |
| 
 | |
|       topLeft = loadUnaligned128((__m128i*)(topLeftBase + x));
 | |
|       topRight = loadUnaligned128((__m128i*)(topRightBase + x));
 | |
|       bottomRight = loadUnaligned128((__m128i*)(bottomRightBase + x));
 | |
|       bottomLeft = loadUnaligned128((__m128i*)(bottomLeftBase + x));
 | |
|       __m128i result1 =
 | |
|           BlurFourPixels(topLeft, topRight, bottomRight, bottomLeft, divisor);
 | |
| 
 | |
|       topLeft = loadUnaligned128((__m128i*)(topLeftBase + x + 4));
 | |
|       topRight = loadUnaligned128((__m128i*)(topRightBase + x + 4));
 | |
|       bottomRight = loadUnaligned128((__m128i*)(bottomRightBase + x + 4));
 | |
|       bottomLeft = loadUnaligned128((__m128i*)(bottomLeftBase + x + 4));
 | |
|       __m128i result2 =
 | |
|           BlurFourPixels(topLeft, topRight, bottomRight, bottomLeft, divisor);
 | |
| 
 | |
|       topLeft = loadUnaligned128((__m128i*)(topLeftBase + x + 8));
 | |
|       topRight = loadUnaligned128((__m128i*)(topRightBase + x + 8));
 | |
|       bottomRight = loadUnaligned128((__m128i*)(bottomRightBase + x + 8));
 | |
|       bottomLeft = loadUnaligned128((__m128i*)(bottomLeftBase + x + 8));
 | |
|       __m128i result3 =
 | |
|           BlurFourPixels(topLeft, topRight, bottomRight, bottomLeft, divisor);
 | |
| 
 | |
|       topLeft = loadUnaligned128((__m128i*)(topLeftBase + x + 12));
 | |
|       topRight = loadUnaligned128((__m128i*)(topRightBase + x + 12));
 | |
|       bottomRight = loadUnaligned128((__m128i*)(bottomRightBase + x + 12));
 | |
|       bottomLeft = loadUnaligned128((__m128i*)(bottomLeftBase + x + 12));
 | |
|       __m128i result4 =
 | |
|           BlurFourPixels(topLeft, topRight, bottomRight, bottomLeft, divisor);
 | |
| 
 | |
|       double t;
 | |
|       __m128i final;
 | |
|       asm volatile (
 | |
|         ".set push \n\t"
 | |
|         ".set arch=loongson3a \n\t"
 | |
|         _mm_packsswh(r3, r3, r4, t)
 | |
|         _mm_packsswh(f, r1, r2, t)
 | |
|         _mm_packushb(f, f, r3, t)
 | |
|         "gssdlc1 %[fh], 0xf(%[d]) \n\t"
 | |
|         "gssdrc1 %[fh], 0x8(%[d]) \n\t"
 | |
|         "gssdlc1 %[fl], 0x7(%[d]) \n\t"
 | |
|         "gssdrc1 %[fl], 0x0(%[d]) \n\t"
 | |
|         ".set pop \n\t"
 | |
|         :[fh]"=&f"(final.h), [fl]"=&f"(final.l),
 | |
|          [r3h]"+f"(result3.h), [r3l]"+f"(result3.l),
 | |
|          [t]"=&f"(t)
 | |
|         :[r1h]"f"(result1.h), [r1l]"f"(result1.l),
 | |
|          [r2h]"f"(result2.h), [r2l]"f"(result2.l),
 | |
|          [r4h]"f"(result4.h), [r4l]"f"(result4.l),
 | |
|          [d]"r"(data + stride * y + x)
 | |
|         :"memory"
 | |
|       );
 | |
|     }
 | |
| 
 | |
|     // Process the remaining pixels 4 bytes at a time.
 | |
|     for (; x < size.width; x += 4) {
 | |
|       if (inSkipRectY && x > skipRect.x && x < skipRect.XMost()) {
 | |
|         x = skipRect.XMost() - 4;
 | |
|         // Trigger early jump on coming loop iterations, this will be reset
 | |
|         // next line anyway.
 | |
|         inSkipRectY = false;
 | |
|         continue;
 | |
|       }
 | |
|       __m128i topLeft = loadUnaligned128((__m128i*)(topLeftBase + x));
 | |
|       __m128i topRight = loadUnaligned128((__m128i*)(topRightBase + x));
 | |
|       __m128i bottomRight = loadUnaligned128((__m128i*)(bottomRightBase + x));
 | |
|       __m128i bottomLeft = loadUnaligned128((__m128i*)(bottomLeftBase + x));
 | |
| 
 | |
|       __m128i result =
 | |
|           BlurFourPixels(topLeft, topRight, bottomRight, bottomLeft, divisor);
 | |
| 
 | |
|       double t;
 | |
|       __m128i final;
 | |
|       asm volatile (
 | |
|         ".set push \n\t"
 | |
|         ".set arch=loongson3a \n\t"
 | |
|         _mm_packsswh(f, r, zero, t)
 | |
|         _mm_packushb(f, f, zero, t)
 | |
|         "swc1 %[fl], (%[d]) \n\t"
 | |
|         ".set pop \n\t"
 | |
|         :[fh]"=&f"(final.h), [fl]"=&f"(final.l),
 | |
|          [t]"=&f"(t)
 | |
|         :[d]"r"(data + stride * y + x),
 | |
|          [rh]"f"(result.h), [rl]"f"(result.l),
 | |
|          [zeroh]"f"(zero.h), [zerol]"f"(zero.l)
 | |
|         :"memory"
 | |
|       );
 | |
|     }
 | |
|   }
 | |
| }
 | |
| 
 | |
| }  // namespace gfx
 | |
| }  // namespace mozilla
 | |
| 
 | |
| #endif /* _MIPS_ARCH_LOONGSON3A */
 |