MIPS: dspr2: added optimization for (un)filters
HorizontalFilter VerticalFilter GradientFilter HorizontalUnfilter VerticalUnfilter GradientUnfilter Change-Id: I54055b4767c37719691811072e95bf79c1f627b1
This commit is contained in:
		
				
					committed by
					
						
						Gerrit Code Review
					
				
			
			
				
	
			
			
			
						parent
						
							137e609016
						
					
				
				
					commit
					b4dc4069a2
				
			@@ -44,6 +44,7 @@ LOCAL_SRC_FILES := \
 | 
				
			|||||||
    src/dsp/enc_mips32.c \
 | 
					    src/dsp/enc_mips32.c \
 | 
				
			||||||
    src/dsp/enc_neon.$(NEON) \
 | 
					    src/dsp/enc_neon.$(NEON) \
 | 
				
			||||||
    src/dsp/enc_sse2.c \
 | 
					    src/dsp/enc_sse2.c \
 | 
				
			||||||
 | 
					    src/dsp/filters_mips_dsp_r2.c \
 | 
				
			||||||
    src/dsp/lossless.c \
 | 
					    src/dsp/lossless.c \
 | 
				
			||||||
    src/dsp/lossless_mips32.c \
 | 
					    src/dsp/lossless_mips32.c \
 | 
				
			||||||
    src/dsp/lossless_neon.$(NEON) \
 | 
					    src/dsp/lossless_neon.$(NEON) \
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -178,6 +178,7 @@ DSP_DEC_OBJS = \
 | 
				
			|||||||
    $(DIROBJ)\dsp\dec_mips32.obj \
 | 
					    $(DIROBJ)\dsp\dec_mips32.obj \
 | 
				
			||||||
    $(DIROBJ)\dsp\dec_neon.obj \
 | 
					    $(DIROBJ)\dsp\dec_neon.obj \
 | 
				
			||||||
    $(DIROBJ)\dsp\dec_sse2.obj \
 | 
					    $(DIROBJ)\dsp\dec_sse2.obj \
 | 
				
			||||||
 | 
					    $(DIROBJ)\dsp\filters_mips_dsp_r2.obj \
 | 
				
			||||||
    $(DIROBJ)\dsp\lossless.obj \
 | 
					    $(DIROBJ)\dsp\lossless.obj \
 | 
				
			||||||
    $(DIROBJ)\dsp\lossless_mips32.obj \
 | 
					    $(DIROBJ)\dsp\lossless_mips32.obj \
 | 
				
			||||||
    $(DIROBJ)\dsp\lossless_neon.obj \
 | 
					    $(DIROBJ)\dsp\lossless_neon.obj \
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -114,6 +114,7 @@ DSP_DEC_OBJS = \
 | 
				
			|||||||
    src/dsp/dec_mips32.o \
 | 
					    src/dsp/dec_mips32.o \
 | 
				
			||||||
    src/dsp/dec_neon.o \
 | 
					    src/dsp/dec_neon.o \
 | 
				
			||||||
    src/dsp/dec_sse2.o \
 | 
					    src/dsp/dec_sse2.o \
 | 
				
			||||||
 | 
					    src/dsp/filters_mips_dsp_r2.o \
 | 
				
			||||||
    src/dsp/lossless.o \
 | 
					    src/dsp/lossless.o \
 | 
				
			||||||
    src/dsp/lossless_mips32.o \
 | 
					    src/dsp/lossless_mips32.o \
 | 
				
			||||||
    src/dsp/lossless_neon.o \
 | 
					    src/dsp/lossless_neon.o \
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -16,6 +16,7 @@ COMMON_SOURCES += dec_clip_tables.c
 | 
				
			|||||||
COMMON_SOURCES += dec_mips32.c
 | 
					COMMON_SOURCES += dec_mips32.c
 | 
				
			||||||
COMMON_SOURCES += dec_neon.c
 | 
					COMMON_SOURCES += dec_neon.c
 | 
				
			||||||
COMMON_SOURCES += dsp.h
 | 
					COMMON_SOURCES += dsp.h
 | 
				
			||||||
 | 
					COMMON_SOURCES += filters_mips_dsp_r2.c
 | 
				
			||||||
COMMON_SOURCES += lossless.c
 | 
					COMMON_SOURCES += lossless.c
 | 
				
			||||||
COMMON_SOURCES += lossless.h
 | 
					COMMON_SOURCES += lossless.h
 | 
				
			||||||
COMMON_SOURCES += lossless_mips32.c
 | 
					COMMON_SOURCES += lossless_mips32.c
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -290,9 +290,20 @@ void (*WebPApplyAlphaMultiply4444)(uint8_t*, int, int, int);
 | 
				
			|||||||
//------------------------------------------------------------------------------
 | 
					//------------------------------------------------------------------------------
 | 
				
			||||||
// Init function
 | 
					// Init function
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern void VP8FiltersInitMIPSdspR2(void);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void WebPInitAlphaProcessing(void) {
 | 
					void WebPInitAlphaProcessing(void) {
 | 
				
			||||||
  WebPMultARGBRow = MultARGBRow;
 | 
					  WebPMultARGBRow = MultARGBRow;
 | 
				
			||||||
  WebPMultRow = MultRow;
 | 
					  WebPMultRow = MultRow;
 | 
				
			||||||
  WebPApplyAlphaMultiply = ApplyAlphaMultiply;
 | 
					  WebPApplyAlphaMultiply = ApplyAlphaMultiply;
 | 
				
			||||||
  WebPApplyAlphaMultiply4444 = ApplyAlphaMultiply_16b;
 | 
					  WebPApplyAlphaMultiply4444 = ApplyAlphaMultiply_16b;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // If defined, use CPUInfo() to overwrite some pointers with faster versions.
 | 
				
			||||||
 | 
					  if (VP8GetCPUInfo != NULL) {
 | 
				
			||||||
 | 
					#if defined(WEBP_USE_MIPS_DSP_R2)
 | 
				
			||||||
 | 
					    if (VP8GetCPUInfo(kMIPSdspR2)) {
 | 
				
			||||||
 | 
					      VP8FiltersInitMIPSdspR2();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										331
									
								
								src/dsp/filters_mips_dsp_r2.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										331
									
								
								src/dsp/filters_mips_dsp_r2.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,331 @@
 | 
				
			|||||||
 | 
					// Copyright 2014 Google Inc. All Rights Reserved.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// Use of this source code is governed by a BSD-style license
 | 
				
			||||||
 | 
					// that can be found in the COPYING file in the root of the source
 | 
				
			||||||
 | 
					// tree. An additional intellectual property rights grant can be found
 | 
				
			||||||
 | 
					// in the file PATENTS. All contributing project authors may
 | 
				
			||||||
 | 
					// be found in the AUTHORS file in the root of the source tree.
 | 
				
			||||||
 | 
					// -----------------------------------------------------------------------------
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// Spatial prediction using various filters
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// Author(s): Branimir Vasic (branimir.vasic@imgtec.com)
 | 
				
			||||||
 | 
					//            Djordje Pesut (djordje.pesut@imgtec.com)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "./dsp.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if defined(WEBP_USE_MIPS_DSP_R2)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "../utils/filters.h"
 | 
				
			||||||
 | 
					#include <assert.h>
 | 
				
			||||||
 | 
					#include <stdlib.h>
 | 
				
			||||||
 | 
					#include <string.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					// Helpful macro.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# define SANITY_CHECK(in, out)                                                 \
 | 
				
			||||||
 | 
					  assert(in != NULL);                                                          \
 | 
				
			||||||
 | 
					  assert(out != NULL);                                                         \
 | 
				
			||||||
 | 
					  assert(width > 0);                                                           \
 | 
				
			||||||
 | 
					  assert(height > 0);                                                          \
 | 
				
			||||||
 | 
					  assert(stride >= width);                                                     \
 | 
				
			||||||
 | 
					  assert(row >= 0 && num_rows > 0 && row + num_rows <= height);                \
 | 
				
			||||||
 | 
					  (void)height;  // Silence unused warning.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define DO_PREDICT_LINE(SRC, PRED, DST, LENGTH, INVERSE) do {                  \
 | 
				
			||||||
 | 
					    const uint8_t* psrc = (uint8_t*)(SRC);                                     \
 | 
				
			||||||
 | 
					    const uint8_t* ppred = (uint8_t*)(PRED);                                   \
 | 
				
			||||||
 | 
					    uint8_t* pdst = (uint8_t*)(DST);                                           \
 | 
				
			||||||
 | 
					    const int ilength = (int)(LENGTH);                                         \
 | 
				
			||||||
 | 
					    int temp0, temp1, temp2, temp3, temp4, temp5, temp6, temp7;                \
 | 
				
			||||||
 | 
					    __asm__ volatile (                                                         \
 | 
				
			||||||
 | 
					      ".set      push                                   \n\t"                  \
 | 
				
			||||||
 | 
					      ".set      noreorder                              \n\t"                  \
 | 
				
			||||||
 | 
					      "srl       %[temp0],    %[length],    0x3         \n\t"                  \
 | 
				
			||||||
 | 
					      "beqz      %[temp0],    2f                        \n\t"                  \
 | 
				
			||||||
 | 
					      " andi     %[temp7],    %[length],    0x7         \n\t"                  \
 | 
				
			||||||
 | 
					    "1:                                                 \n\t"                  \
 | 
				
			||||||
 | 
					      "ulw       %[temp1],    0(%[src])                 \n\t"                  \
 | 
				
			||||||
 | 
					      "ulw       %[temp2],    0(%[pred])                \n\t"                  \
 | 
				
			||||||
 | 
					      "ulw       %[temp3],    4(%[src])                 \n\t"                  \
 | 
				
			||||||
 | 
					      "ulw       %[temp4],    4(%[pred])                \n\t"                  \
 | 
				
			||||||
 | 
					      "addiu     %[src],      %[src],       8           \n\t"                  \
 | 
				
			||||||
 | 
					    ".if "#INVERSE"                                     \n\t"                  \
 | 
				
			||||||
 | 
					      "addu.qb   %[temp5],    %[temp1],     %[temp2]    \n\t"                  \
 | 
				
			||||||
 | 
					      "addu.qb   %[temp6],    %[temp3],     %[temp4]    \n\t"                  \
 | 
				
			||||||
 | 
					    ".else                                              \n\t"                  \
 | 
				
			||||||
 | 
					      "subu.qb   %[temp5],    %[temp1],     %[temp2]    \n\t"                  \
 | 
				
			||||||
 | 
					      "subu.qb   %[temp6],    %[temp3],     %[temp4]    \n\t"                  \
 | 
				
			||||||
 | 
					    ".endif                                             \n\t"                  \
 | 
				
			||||||
 | 
					      "addiu     %[pred],     %[pred],      8           \n\t"                  \
 | 
				
			||||||
 | 
					      "usw       %[temp5],    0(%[dst])                 \n\t"                  \
 | 
				
			||||||
 | 
					      "usw       %[temp6],    4(%[dst])                 \n\t"                  \
 | 
				
			||||||
 | 
					      "addiu     %[temp0],    %[temp0],     -1          \n\t"                  \
 | 
				
			||||||
 | 
					      "bnez      %[temp0],    1b                        \n\t"                  \
 | 
				
			||||||
 | 
					      " addiu    %[dst],      %[dst],       8           \n\t"                  \
 | 
				
			||||||
 | 
					      "beqz      %[temp7],    3f                        \n\t"                  \
 | 
				
			||||||
 | 
					      " nop                                             \n\t"                  \
 | 
				
			||||||
 | 
					    "2:                                                 \n\t"                  \
 | 
				
			||||||
 | 
					      "lbu       %[temp1],    0(%[src])                 \n\t"                  \
 | 
				
			||||||
 | 
					      "lbu       %[temp2],    0(%[pred])                \n\t"                  \
 | 
				
			||||||
 | 
					      "addiu     %[src],      %[src],       1           \n\t"                  \
 | 
				
			||||||
 | 
					      "addiu     %[pred],     %[pred],      1           \n\t"                  \
 | 
				
			||||||
 | 
					    ".if "#INVERSE"                                     \n\t"                  \
 | 
				
			||||||
 | 
					      "addu      %[temp3],    %[temp1],     %[temp2]    \n\t"                  \
 | 
				
			||||||
 | 
					    ".else                                              \n\t"                  \
 | 
				
			||||||
 | 
					      "subu      %[temp3],    %[temp1],     %[temp2]    \n\t"                  \
 | 
				
			||||||
 | 
					    ".endif                                             \n\t"                  \
 | 
				
			||||||
 | 
					      "sb        %[temp3],    0(%[dst])                 \n\t"                  \
 | 
				
			||||||
 | 
					      "addiu     %[temp7],    %[temp7],     -1          \n\t"                  \
 | 
				
			||||||
 | 
					      "bnez      %[temp7],    2b                        \n\t"                  \
 | 
				
			||||||
 | 
					      " addiu    %[dst],      %[dst],       1           \n\t"                  \
 | 
				
			||||||
 | 
					    "3:                                                 \n\t"                  \
 | 
				
			||||||
 | 
					      ".set      pop                                    \n\t"                  \
 | 
				
			||||||
 | 
					      : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), [temp2]"=&r"(temp2),         \
 | 
				
			||||||
 | 
					        [temp3]"=&r"(temp3), [temp4]"=&r"(temp4), [temp5]"=&r"(temp5),         \
 | 
				
			||||||
 | 
					        [temp6]"=&r"(temp6), [temp7]"=&r"(temp7), [pred]"+r"(ppred),           \
 | 
				
			||||||
 | 
					        [dst]"+r"(pdst), [src]"+r"(psrc)                                       \
 | 
				
			||||||
 | 
					      : [length]"r"(ilength)                                                   \
 | 
				
			||||||
 | 
					      : "memory"                                                               \
 | 
				
			||||||
 | 
					    );                                                                         \
 | 
				
			||||||
 | 
					  } while (0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static WEBP_INLINE void PredictLine(const uint8_t* src, const uint8_t* pred,
 | 
				
			||||||
 | 
					                                    uint8_t* dst, int length, int inverse) {
 | 
				
			||||||
 | 
					  if (inverse) {
 | 
				
			||||||
 | 
					    DO_PREDICT_LINE(src, pred, dst, length, 1);
 | 
				
			||||||
 | 
					  } else {
 | 
				
			||||||
 | 
					    DO_PREDICT_LINE(src, pred, dst, length, 0);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define PREDICT_LINE_ONE_PASS(SRC, PRED, DST, INVERSE) do {                    \
 | 
				
			||||||
 | 
					    int temp1, temp2, temp3;                                                   \
 | 
				
			||||||
 | 
					    __asm__ volatile (                                                         \
 | 
				
			||||||
 | 
					      "lbu       %[temp1],   0(%[src])               \n\t"                     \
 | 
				
			||||||
 | 
					      "lbu       %[temp2],   0(%[pred])              \n\t"                     \
 | 
				
			||||||
 | 
					    ".if "#INVERSE"                                  \n\t"                     \
 | 
				
			||||||
 | 
					      "addu      %[temp3],   %[temp1],   %[temp2]    \n\t"                     \
 | 
				
			||||||
 | 
					    ".else                                           \n\t"                     \
 | 
				
			||||||
 | 
					      "subu      %[temp3],   %[temp1],   %[temp2]    \n\t"                     \
 | 
				
			||||||
 | 
					    ".endif                                          \n\t"                     \
 | 
				
			||||||
 | 
					      "sb        %[temp3],   0(%[dst])               \n\t"                     \
 | 
				
			||||||
 | 
					      : [temp1]"=&r"(temp1), [temp2]"=&r"(temp2), [temp3]"=&r"(temp3)          \
 | 
				
			||||||
 | 
					      : [pred]"r"((PRED)), [dst]"r"((DST)), [src]"r"((SRC))                    \
 | 
				
			||||||
 | 
					      : "memory"                                                               \
 | 
				
			||||||
 | 
					    );                                                                         \
 | 
				
			||||||
 | 
					  } while (0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					// Horizontal filter.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define FILTER_LINE_BY_LINE(INVERSE) do {                                      \
 | 
				
			||||||
 | 
					    while (row < last_row) {                                                   \
 | 
				
			||||||
 | 
					      PREDICT_LINE_ONE_PASS(in, preds - stride, out, INVERSE);                 \
 | 
				
			||||||
 | 
					      DO_PREDICT_LINE(in + 1, preds, out + 1, width - 1, INVERSE);             \
 | 
				
			||||||
 | 
					      ++row;                                                                   \
 | 
				
			||||||
 | 
					      preds += stride;                                                         \
 | 
				
			||||||
 | 
					      in += stride;                                                            \
 | 
				
			||||||
 | 
					      out += stride;                                                           \
 | 
				
			||||||
 | 
					    }                                                                          \
 | 
				
			||||||
 | 
					  } while (0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static WEBP_INLINE void DoHorizontalFilter(const uint8_t* in,
 | 
				
			||||||
 | 
					                                           int width, int height, int stride,
 | 
				
			||||||
 | 
					                                           int row, int num_rows,
 | 
				
			||||||
 | 
					                                           int inverse, uint8_t* out) {
 | 
				
			||||||
 | 
					  const uint8_t* preds;
 | 
				
			||||||
 | 
					  const size_t start_offset = row * stride;
 | 
				
			||||||
 | 
					  const int last_row = row + num_rows;
 | 
				
			||||||
 | 
					  SANITY_CHECK(in, out);
 | 
				
			||||||
 | 
					  in += start_offset;
 | 
				
			||||||
 | 
					  out += start_offset;
 | 
				
			||||||
 | 
					  preds = inverse ? out : in;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (row == 0) {
 | 
				
			||||||
 | 
					    // Leftmost pixel is the same as input for topmost scanline.
 | 
				
			||||||
 | 
					    out[0] = in[0];
 | 
				
			||||||
 | 
					    PredictLine(in + 1, preds, out + 1, width - 1, inverse);
 | 
				
			||||||
 | 
					    row = 1;
 | 
				
			||||||
 | 
					    preds += stride;
 | 
				
			||||||
 | 
					    in += stride;
 | 
				
			||||||
 | 
					    out += stride;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Filter line-by-line.
 | 
				
			||||||
 | 
					  if (inverse) {
 | 
				
			||||||
 | 
					    FILTER_LINE_BY_LINE(1);
 | 
				
			||||||
 | 
					  } else {
 | 
				
			||||||
 | 
					    FILTER_LINE_BY_LINE(0);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#undef FILTER_LINE_BY_LINE
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void HorizontalFilter(const uint8_t* data, int width, int height,
 | 
				
			||||||
 | 
					                             int stride, uint8_t* filtered_data) {
 | 
				
			||||||
 | 
					  DoHorizontalFilter(data, width, height, stride, 0, height, 0, filtered_data);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void HorizontalUnfilter(int width, int height, int stride, int row,
 | 
				
			||||||
 | 
					                               int num_rows, uint8_t* data) {
 | 
				
			||||||
 | 
					  DoHorizontalFilter(data, width, height, stride, row, num_rows, 1, data);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					// Vertical filter.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define FILTER_LINE_BY_LINE(INVERSE) do {                                      \
 | 
				
			||||||
 | 
					    while (row < last_row) {                                                   \
 | 
				
			||||||
 | 
					      DO_PREDICT_LINE(in, preds, out, width, INVERSE);                         \
 | 
				
			||||||
 | 
					      ++row;                                                                   \
 | 
				
			||||||
 | 
					      preds += stride;                                                         \
 | 
				
			||||||
 | 
					      in += stride;                                                            \
 | 
				
			||||||
 | 
					      out += stride;                                                           \
 | 
				
			||||||
 | 
					    }                                                                          \
 | 
				
			||||||
 | 
					  } while (0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static WEBP_INLINE void DoVerticalFilter(const uint8_t* in,
 | 
				
			||||||
 | 
					                                         int width, int height, int stride,
 | 
				
			||||||
 | 
					                                         int row, int num_rows,
 | 
				
			||||||
 | 
					                                         int inverse, uint8_t* out) {
 | 
				
			||||||
 | 
					  const uint8_t* preds;
 | 
				
			||||||
 | 
					  const size_t start_offset = row * stride;
 | 
				
			||||||
 | 
					  const int last_row = row + num_rows;
 | 
				
			||||||
 | 
					  SANITY_CHECK(in, out);
 | 
				
			||||||
 | 
					  in += start_offset;
 | 
				
			||||||
 | 
					  out += start_offset;
 | 
				
			||||||
 | 
					  preds = inverse ? out : in;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (row == 0) {
 | 
				
			||||||
 | 
					    // Very first top-left pixel is copied.
 | 
				
			||||||
 | 
					    out[0] = in[0];
 | 
				
			||||||
 | 
					    // Rest of top scan-line is left-predicted.
 | 
				
			||||||
 | 
					    PredictLine(in + 1, preds, out + 1, width - 1, inverse);
 | 
				
			||||||
 | 
					    row = 1;
 | 
				
			||||||
 | 
					    in += stride;
 | 
				
			||||||
 | 
					    out += stride;
 | 
				
			||||||
 | 
					  } else {
 | 
				
			||||||
 | 
					    // We are starting from in-between. Make sure 'preds' points to prev row.
 | 
				
			||||||
 | 
					    preds -= stride;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Filter line-by-line.
 | 
				
			||||||
 | 
					  if (inverse) {
 | 
				
			||||||
 | 
					    FILTER_LINE_BY_LINE(1);
 | 
				
			||||||
 | 
					  } else {
 | 
				
			||||||
 | 
					    FILTER_LINE_BY_LINE(0);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#undef FILTER_LINE_BY_LINE
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void VerticalFilter(const uint8_t* data, int width, int height,
 | 
				
			||||||
 | 
					                           int stride, uint8_t* filtered_data) {
 | 
				
			||||||
 | 
					  DoVerticalFilter(data, width, height, stride, 0, height, 0, filtered_data);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void VerticalUnfilter(int width, int height, int stride, int row,
 | 
				
			||||||
 | 
					                             int num_rows, uint8_t* data) {
 | 
				
			||||||
 | 
					  DoVerticalFilter(data, width, height, stride, row, num_rows, 1, data);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					// Gradient filter.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static WEBP_INLINE int GradientPredictor(uint8_t a, uint8_t b, uint8_t c) {
 | 
				
			||||||
 | 
					  int temp0;
 | 
				
			||||||
 | 
					  __asm__ volatile (
 | 
				
			||||||
 | 
					    "addu             %[temp0],   %[a],       %[b]        \n\t"
 | 
				
			||||||
 | 
					    "subu             %[temp0],   %[temp0],   %[c]        \n\t"
 | 
				
			||||||
 | 
					    "shll_s.w         %[temp0],   %[temp0],   23          \n\t"
 | 
				
			||||||
 | 
					    "precrqu_s.qb.ph  %[temp0],   %[temp0],   $zero       \n\t"
 | 
				
			||||||
 | 
					    "srl              %[temp0],   %[temp0],   24          \n\t"
 | 
				
			||||||
 | 
					    : [temp0]"=&r"(temp0)
 | 
				
			||||||
 | 
					    : [a]"r"(a),[b]"r"(b),[c]"r"(c)
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					  return temp0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define FILTER_LINE_BY_LINE(INVERSE, PREDS, OPERATION) do {                    \
 | 
				
			||||||
 | 
					    while (row < last_row) {                                                   \
 | 
				
			||||||
 | 
					      int w;                                                                   \
 | 
				
			||||||
 | 
					      PREDICT_LINE_ONE_PASS(in, PREDS - stride, out, INVERSE);                 \
 | 
				
			||||||
 | 
					      for (w = 1; w < width; ++w) {                                            \
 | 
				
			||||||
 | 
					        const int pred = GradientPredictor(PREDS[w - 1],                       \
 | 
				
			||||||
 | 
					                                           PREDS[w - stride],                  \
 | 
				
			||||||
 | 
					                                           PREDS[w - stride - 1]);             \
 | 
				
			||||||
 | 
					        out[w] = in[w] OPERATION pred;                                         \
 | 
				
			||||||
 | 
					      }                                                                        \
 | 
				
			||||||
 | 
					      ++row;                                                                   \
 | 
				
			||||||
 | 
					      in += stride;                                                            \
 | 
				
			||||||
 | 
					      out += stride;                                                           \
 | 
				
			||||||
 | 
					    }                                                                          \
 | 
				
			||||||
 | 
					  } while (0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static WEBP_INLINE void DoGradientFilter(const uint8_t* in,
 | 
				
			||||||
 | 
					                                         int width, int height, int stride,
 | 
				
			||||||
 | 
					                                         int row, int num_rows,
 | 
				
			||||||
 | 
					                                         int inverse, uint8_t* out) {
 | 
				
			||||||
 | 
					  const uint8_t* preds;
 | 
				
			||||||
 | 
					  const size_t start_offset = row * stride;
 | 
				
			||||||
 | 
					  const int last_row = row + num_rows;
 | 
				
			||||||
 | 
					  SANITY_CHECK(in, out);
 | 
				
			||||||
 | 
					  in += start_offset;
 | 
				
			||||||
 | 
					  out += start_offset;
 | 
				
			||||||
 | 
					  preds = inverse ? out : in;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // left prediction for top scan-line
 | 
				
			||||||
 | 
					  if (row == 0) {
 | 
				
			||||||
 | 
					    out[0] = in[0];
 | 
				
			||||||
 | 
					    PredictLine(in + 1, preds, out + 1, width - 1, inverse);
 | 
				
			||||||
 | 
					    row = 1;
 | 
				
			||||||
 | 
					    preds += stride;
 | 
				
			||||||
 | 
					    in += stride;
 | 
				
			||||||
 | 
					    out += stride;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Filter line-by-line.
 | 
				
			||||||
 | 
					  if (inverse) {
 | 
				
			||||||
 | 
					    FILTER_LINE_BY_LINE(1, out, +);
 | 
				
			||||||
 | 
					  } else {
 | 
				
			||||||
 | 
					    FILTER_LINE_BY_LINE(0, in, -);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#undef FILTER_LINE_BY_LINE
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void GradientFilter(const uint8_t* data, int width, int height,
 | 
				
			||||||
 | 
					                           int stride, uint8_t* filtered_data) {
 | 
				
			||||||
 | 
					  DoGradientFilter(data, width, height, stride, 0, height, 0, filtered_data);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void GradientUnfilter(int width, int height, int stride, int row,
 | 
				
			||||||
 | 
					                             int num_rows, uint8_t* data) {
 | 
				
			||||||
 | 
					  DoGradientFilter(data, width, height, stride, row, num_rows, 1, data);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#undef PREDICT_LINE_ONE_PASS
 | 
				
			||||||
 | 
					#undef DO_PREDICT_LINE
 | 
				
			||||||
 | 
					#undef SANITY_CHECK
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif  // WEBP_USE_MIPS_DSP_R2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern void VP8FiltersInitMIPSdspR2(void);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void VP8FiltersInitMIPSdspR2(void) {
 | 
				
			||||||
 | 
					#if defined(WEBP_USE_MIPS_DSP_R2)
 | 
				
			||||||
 | 
					  WebPFilters[WEBP_FILTER_HORIZONTAL] = HorizontalFilter;
 | 
				
			||||||
 | 
					  WebPFilters[WEBP_FILTER_VERTICAL] = VerticalFilter;
 | 
				
			||||||
 | 
					  WebPFilters[WEBP_FILTER_GRADIENT] = GradientFilter;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  WebPUnfilters[WEBP_FILTER_HORIZONTAL] = HorizontalUnfilter;
 | 
				
			||||||
 | 
					  WebPUnfilters[WEBP_FILTER_VERTICAL] = VerticalUnfilter;
 | 
				
			||||||
 | 
					  WebPUnfilters[WEBP_FILTER_GRADIENT] = GradientUnfilter;
 | 
				
			||||||
 | 
					#endif  // WEBP_USE_MIPS_DSP_R2
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//------------------------------------------------------------------------------
 | 
				
			||||||
@@ -248,14 +248,14 @@ WEBP_FILTER_TYPE EstimateBestFilter(const uint8_t* data,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
//------------------------------------------------------------------------------
 | 
					//------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const WebPFilterFunc WebPFilters[WEBP_FILTER_LAST] = {
 | 
					WebPFilterFunc WebPFilters[WEBP_FILTER_LAST] = {
 | 
				
			||||||
  NULL,              // WEBP_FILTER_NONE
 | 
					  NULL,              // WEBP_FILTER_NONE
 | 
				
			||||||
  HorizontalFilter,  // WEBP_FILTER_HORIZONTAL
 | 
					  HorizontalFilter,  // WEBP_FILTER_HORIZONTAL
 | 
				
			||||||
  VerticalFilter,    // WEBP_FILTER_VERTICAL
 | 
					  VerticalFilter,    // WEBP_FILTER_VERTICAL
 | 
				
			||||||
  GradientFilter     // WEBP_FILTER_GRADIENT
 | 
					  GradientFilter     // WEBP_FILTER_GRADIENT
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const WebPUnfilterFunc WebPUnfilters[WEBP_FILTER_LAST] = {
 | 
					WebPUnfilterFunc WebPUnfilters[WEBP_FILTER_LAST] = {
 | 
				
			||||||
  NULL,                // WEBP_FILTER_NONE
 | 
					  NULL,                // WEBP_FILTER_NONE
 | 
				
			||||||
  HorizontalUnfilter,  // WEBP_FILTER_HORIZONTAL
 | 
					  HorizontalUnfilter,  // WEBP_FILTER_HORIZONTAL
 | 
				
			||||||
  VerticalUnfilter,    // WEBP_FILTER_VERTICAL
 | 
					  VerticalUnfilter,    // WEBP_FILTER_VERTICAL
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -41,12 +41,12 @@ typedef void (*WebPUnfilterFunc)(int width, int height, int stride,
 | 
				
			|||||||
// in raster order.
 | 
					// in raster order.
 | 
				
			||||||
// 'stride' is number of bytes per scan line (with possible padding).
 | 
					// 'stride' is number of bytes per scan line (with possible padding).
 | 
				
			||||||
// 'out' should be pre-allocated.
 | 
					// 'out' should be pre-allocated.
 | 
				
			||||||
extern const WebPFilterFunc WebPFilters[WEBP_FILTER_LAST];
 | 
					extern WebPFilterFunc WebPFilters[WEBP_FILTER_LAST];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// In-place reconstruct the original data from the given filtered data.
 | 
					// In-place reconstruct the original data from the given filtered data.
 | 
				
			||||||
// The reconstruction will be done for 'num_rows' rows starting from 'row'
 | 
					// The reconstruction will be done for 'num_rows' rows starting from 'row'
 | 
				
			||||||
// (assuming rows upto 'row - 1' are already reconstructed).
 | 
					// (assuming rows upto 'row - 1' are already reconstructed).
 | 
				
			||||||
extern const WebPUnfilterFunc WebPUnfilters[WEBP_FILTER_LAST];
 | 
					extern WebPUnfilterFunc WebPUnfilters[WEBP_FILTER_LAST];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Fast estimate of a potentially good filter.
 | 
					// Fast estimate of a potentially good filter.
 | 
				
			||||||
WEBP_FILTER_TYPE EstimateBestFilter(const uint8_t* data,
 | 
					WEBP_FILTER_TYPE EstimateBestFilter(const uint8_t* data,
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user