diff options
author | codeworkx <daniel.hillenbrand@codeworkx.de> | 2012-05-20 12:00:36 +0200 |
---|---|---|
committer | codeworkx <daniel.hillenbrand@codeworkx.de> | 2012-05-20 12:00:36 +0200 |
commit | 62f02ba4f4b7b561aa15408ebd9951600bdd71aa (patch) | |
tree | ac05dc645945a58edbc26e96df1a78ac16f27706 /exynos/multimedia/utils | |
parent | e54debb12ecdf92d12acab00a261c0c5a6ef1d64 (diff) | |
download | android_hardware_samsung-62f02ba4f4b7b561aa15408ebd9951600bdd71aa.tar.gz android_hardware_samsung-62f02ba4f4b7b561aa15408ebd9951600bdd71aa.tar.bz2 android_hardware_samsung-62f02ba4f4b7b561aa15408ebd9951600bdd71aa.zip |
exynos: reorganized and updated from insignal
Changes needed on exynos4210 devices:
libcsc -> libseccscapi
libswconverter -> remove
TARGET_HAL_PATH := hardware/samsung/exynos4/hal
TARGET_OMX_PATH := hardware/samsung/exynos/multimedia/openmax
$(call inherit-product, hardware/samsung/exynos4210.mk)
Change-Id: Ic59ef95b85ef37b3f38fb36cf6a364a5414685ee
Diffstat (limited to 'exynos/multimedia/utils')
21 files changed, 7335 insertions, 0 deletions
diff --git a/exynos/multimedia/utils/Android.mk b/exynos/multimedia/utils/Android.mk new file mode 100644 index 0000000..6571161 --- /dev/null +++ b/exynos/multimedia/utils/Android.mk @@ -0,0 +1 @@ +include $(all-subdir-makefiles) diff --git a/exynos/multimedia/utils/csc/Android.mk b/exynos/multimedia/utils/csc/Android.mk new file mode 100644 index 0000000..3bc3577 --- /dev/null +++ b/exynos/multimedia/utils/csc/Android.mk @@ -0,0 +1,11 @@ +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) + +ifeq ($(filter-out exynos4,$(TARGET_BOARD_PLATFORM)),) +include $(LOCAL_PATH)/exynos4/Android.mk +endif + +ifeq ($(filter-out exynos5,$(TARGET_BOARD_PLATFORM)),) +include $(LOCAL_PATH)/exynos5/Android.mk +endif diff --git a/exynos/multimedia/utils/csc/exynos4/Android.mk b/exynos/multimedia/utils/csc/exynos4/Android.mk new file mode 100644 index 0000000..e7ed4e2 --- /dev/null +++ b/exynos/multimedia/utils/csc/exynos4/Android.mk @@ -0,0 +1,42 @@ +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) + +LOCAL_COPY_HEADERS_TO := libsecmm +LOCAL_COPY_HEADERS := \ + color_space_convertor.h \ + csc_fimc.h + +LOCAL_MODULE_TAGS := optional + +LOCAL_SRC_FILES := \ + color_space_convertor.c \ + csc_linear_to_tiled_crop_neon.s \ + csc_linear_to_tiled_interleave_crop_neon.s \ + csc_tiled_to_linear_crop_neon.s \ + csc_tiled_to_linear_deinterleave_crop_neon.s \ + csc_interleave_memcpy_neon.s \ + csc_fimc.cpp + +LOCAL_C_INCLUDES := \ + $(TOP)/$(TARGET_OMX_PATH)/include/khronos \ + $(TOP)/$(TARGET_OMX_PATH)/include/sec \ + $(TOP)/$(TARGET_HAL_PATH)/include \ + $(TOP)/$(TARGET_HAL_PATH)/libhwconverter + +ifeq ($(BOARD_USE_SAMSUNG_COLORFORMAT), true) +LOCAL_CFLAGS += -DUSE_SAMSUNG_COLORFORMAT +endif + +LOCAL_MODULE := libseccscapi + +LOCAL_PRELINK_MODULE := false + +LOCAL_CFLAGS := + +LOCAL_ARM_MODE := arm + +LOCAL_STATIC_LIBRARIES := +LOCAL_SHARED_LIBRARIES := liblog libfimc libhwconverter + +include $(BUILD_STATIC_LIBRARY) diff --git a/exynos/multimedia/utils/csc/exynos4/color_space_convertor.c b/exynos/multimedia/utils/csc/exynos4/color_space_convertor.c new file mode 100644 index 0000000..7a4c559 --- /dev/null +++ b/exynos/multimedia/utils/csc/exynos4/color_space_convertor.c @@ -0,0 +1,1732 @@ +/* + * + * Copyright 2010 Samsung Electronics S.LSI Co. LTD + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * @file color_space_convertor.c + * + * @brief SEC_OMX specific define + * + * @author ShinWon Lee (shinwon.lee@samsung.com) + * + * @version 1.0 + * + * @history + * 2011.7.01 : Create + */ + +#include "stdio.h" +#include "stdlib.h" +#include "color_space_convertor.h" + +/* + * Get tiled address of position(x,y) + * + * @param x_size + * width of tiled[in] + * + * @param y_size + * height of tiled[in] + * + * @param x_pos + * x position of tield[in] + * + * @param src_size + * y position of tield[in] + * + * @return + * address of tiled data + */ +static int tile_4x2_read(int x_size, int y_size, int x_pos, int y_pos) +{ + int pixel_x_m1, pixel_y_m1; + int roundup_x, roundup_y; + int linear_addr0, linear_addr1, bank_addr ; + int x_addr; + int trans_addr; + + pixel_x_m1 = x_size -1; + pixel_y_m1 = y_size -1; + + roundup_x = ((pixel_x_m1 >> 7) + 1); + roundup_y = ((pixel_x_m1 >> 6) + 1); + + x_addr = x_pos >> 2; + + if ((y_size <= y_pos+32) && ( y_pos < y_size) && + (((pixel_y_m1 >> 5) & 0x1) == 0) && (((y_pos >> 5) & 0x1) == 0)) { + linear_addr0 = (((y_pos & 0x1f) <<4) | (x_addr & 0xf)); + linear_addr1 = (((y_pos >> 6) & 0xff) * roundup_x + ((x_addr >> 6) & 0x3f)); + + if (((x_addr >> 5) & 0x1) == ((y_pos >> 5) & 0x1)) + bank_addr = ((x_addr >> 4) & 0x1); + else + bank_addr = 0x2 | ((x_addr >> 4) & 0x1); + } else { + linear_addr0 = (((y_pos & 0x1f) << 4) | (x_addr & 0xf)); + linear_addr1 = (((y_pos >> 6) & 0xff) * roundup_x + ((x_addr >> 5) & 0x7f)); + + if (((x_addr >> 5) & 0x1) == ((y_pos >> 5) & 0x1)) + bank_addr = ((x_addr >> 4) & 0x1); + else + bank_addr = 0x2 | ((x_addr >> 4) & 0x1); + } + + linear_addr0 = linear_addr0 << 2; + trans_addr = (linear_addr1 <<13) | (bank_addr << 11) | linear_addr0; + + return trans_addr; +} + +/* + * De-interleaves src to dest1, dest2 + * + * @param dest1 + * Address of de-interleaved data[out] + * + * @param dest2 + * Address of de-interleaved data[out] + * + * @param src + * Address of interleaved data[in] + * + * @param src_size + * Size of interleaved data[in] + */ +static void csc_deinterleave_memcpy( + unsigned char *dest1, + unsigned char *dest2, + unsigned char *src, + unsigned int src_size) +{ + unsigned int i = 0; + for(i=0; i<src_size/2; i++) { + dest1[i] = src[i*2]; + dest2[i] = src[i*2+1]; + } +} + +/* + * Interleaves src1, src2 to dest + * + * @param dest + * Address of interleaved data[out] + * + * @param src1 + * Address of de-interleaved data[in] + * + * @param src2 + * Address of de-interleaved data[in] + * + * @param src_size + * Size of de-interleaved data[in] + */ +static void csc_interleave_memcpy( + unsigned char *dest, + unsigned char *src1, + unsigned char *src2, + unsigned int src_size) +{ + unsigned int i = 0; + for(i=0; i<src_size; i++) { + dest[i * 2] = src1[i]; + dest[i * 2 + 1] = src2[i]; + } +} + +/* + * Converts tiled data to linear + * Crops left, top, right, buttom + * 1. Y of NV12T to Y of YUV420P + * 2. Y of NV12T to Y of YUV420S + * 3. UV of NV12T to UV of YUV420S + * + * @param yuv420_dest + * Y or UV plane address of YUV420[out] + * + * @param nv12t_src + * Y or UV plane address of NV12T[in] + * + * @param yuv420_width + * Width of YUV420[in] + * + * @param yuv420_height + * Y: Height of YUV420, UV: Height/2 of YUV420[in] + * + * @param left + * Crop size of left + * + * @param top + * Crop size of top + * + * @param right + * Crop size of right + * + * @param buttom + * Crop size of buttom + */ +static void csc_tiled_to_linear_crop( + unsigned char *yuv420_dest, + unsigned char *nv12t_src, + unsigned int yuv420_width, + unsigned int yuv420_height, + unsigned int left, + unsigned int top, + unsigned int right, + unsigned int buttom) +{ + unsigned int i, j; + unsigned int tiled_offset = 0, tiled_offset1 = 0; + unsigned int linear_offset = 0; + unsigned int temp1 = 0, temp2 = 0, temp3 = 0, temp4 = 0; + + temp3 = yuv420_width-right; + temp1 = temp3-left; + /* real width is greater than or equal 256 */ + if (temp1 >= 256) { + for (i=top; i<yuv420_height-buttom; i=i+1) { + j = left; + temp3 = (j>>8)<<8; + temp3 = temp3>>6; + temp4 = i>>5; + if (temp4 & 0x1) { + /* odd fomula: 2+x+(x>>2)<<2+x_block_num*(y-1) */ + tiled_offset = temp4-1; + temp1 = ((yuv420_width+127)>>7)<<7; + tiled_offset = tiled_offset*(temp1>>6); + tiled_offset = tiled_offset+temp3; + tiled_offset = tiled_offset+2; + temp1 = (temp3>>2)<<2; + tiled_offset = tiled_offset+temp1; + tiled_offset = tiled_offset<<11; + tiled_offset1 = tiled_offset+2048*2; + temp4 = 8; + } else { + temp2 = ((yuv420_height+31)>>5)<<5; + if ((i+32)<temp2) { + /* even1 fomula: x+((x+2)>>2)<<2+x_block_num*y */ + temp1 = temp3+2; + temp1 = (temp1>>2)<<2; + tiled_offset = temp3+temp1; + temp1 = ((yuv420_width+127)>>7)<<7; + tiled_offset = tiled_offset+temp4*(temp1>>6); + tiled_offset = tiled_offset<<11; + tiled_offset1 = tiled_offset+2048*6; + temp4 = 8; + } else { + /* even2 fomula: x+x_block_num*y */ + temp1 = ((yuv420_width+127)>>7)<<7; + tiled_offset = temp4*(temp1>>6); + tiled_offset = tiled_offset+temp3; + tiled_offset = tiled_offset<<11; + tiled_offset1 = tiled_offset+2048*2; + temp4 = 4; + } + } + + temp1 = i&0x1F; + tiled_offset = tiled_offset+64*(temp1); + tiled_offset1 = tiled_offset1+64*(temp1); + temp2 = yuv420_width-left-right; + linear_offset = temp2*(i-top); + temp3 = ((j+256)>>8)<<8; + temp3 = temp3-j; + temp1 = left&0x3F; + if (temp3 > 192) { + memcpy(yuv420_dest+linear_offset, nv12t_src+tiled_offset+temp1, 64-temp1); + temp2 = ((left+63)>>6)<<6; + temp3 = ((yuv420_width-right)>>6)<<6; + if (temp2 == temp3) { + temp2 = yuv420_width-right-(64-temp1); + } + memcpy(yuv420_dest+linear_offset+64-temp1, nv12t_src+tiled_offset+2048, 64); + memcpy(yuv420_dest+linear_offset+128-temp1, nv12t_src+tiled_offset1, 64); + memcpy(yuv420_dest+linear_offset+192-temp1, nv12t_src+tiled_offset1+2048, 64); + linear_offset = linear_offset+256-temp1; + } else if (temp3 > 128) { + memcpy(yuv420_dest+linear_offset, nv12t_src+tiled_offset+2048+temp1, 64-temp1); + memcpy(yuv420_dest+linear_offset+64-temp1, nv12t_src+tiled_offset1, 64); + memcpy(yuv420_dest+linear_offset+128-temp1, nv12t_src+tiled_offset1+2048, 64); + linear_offset = linear_offset+192-temp1; + } else if (temp3 > 64) { + memcpy(yuv420_dest+linear_offset, nv12t_src+tiled_offset1+temp1, 64-temp1); + memcpy(yuv420_dest+linear_offset+64-temp1, nv12t_src+tiled_offset1+2048, 64); + linear_offset = linear_offset+128-temp1; + } else if (temp3 > 0) { + memcpy(yuv420_dest+linear_offset, nv12t_src+tiled_offset1+2048+temp1, 64-temp1); + linear_offset = linear_offset+64-temp1; + } + + tiled_offset = tiled_offset+temp4*2048; + j = (left>>8)<<8; + j = j + 256; + temp2 = yuv420_width-right-256; + for (; j<=temp2; j=j+256) { + memcpy(yuv420_dest+linear_offset, nv12t_src+tiled_offset, 64); + tiled_offset1 = tiled_offset1+temp4*2048; + memcpy(yuv420_dest+linear_offset+64, nv12t_src+tiled_offset+2048, 64); + memcpy(yuv420_dest+linear_offset+128, nv12t_src+tiled_offset1, 64); + tiled_offset = tiled_offset+temp4*2048; + memcpy(yuv420_dest+linear_offset+192, nv12t_src+tiled_offset1+2048, 64); + linear_offset = linear_offset+256; + } + + tiled_offset1 = tiled_offset1+temp4*2048; + temp2 = yuv420_width-right-j; + if (temp2 > 192) { + memcpy(yuv420_dest+linear_offset, nv12t_src+tiled_offset, 64); + memcpy(yuv420_dest+linear_offset+64, nv12t_src+tiled_offset+2048, 64); + memcpy(yuv420_dest+linear_offset+128, nv12t_src+tiled_offset1, 64); + memcpy(yuv420_dest+linear_offset+192, nv12t_src+tiled_offset1+2048, temp2-192); + } else if (temp2 > 128) { + memcpy(yuv420_dest+linear_offset, nv12t_src+tiled_offset, 64); + memcpy(yuv420_dest+linear_offset+64, nv12t_src+tiled_offset+2048, 64); + memcpy(yuv420_dest+linear_offset+128, nv12t_src+tiled_offset1, temp2-128); + } else if (temp2 > 64) { + memcpy(yuv420_dest+linear_offset, nv12t_src+tiled_offset, 64); + memcpy(yuv420_dest+linear_offset+64, nv12t_src+tiled_offset+2048, temp2-64); + } else { + memcpy(yuv420_dest+linear_offset, nv12t_src+tiled_offset, temp2); + } + } + } else if (temp1 >= 64) { + for (i=top; i<(yuv420_height-buttom); i=i+1) { + j = left; + tiled_offset = tile_4x2_read(yuv420_width, yuv420_height, j, i); + temp2 = ((j+64)>>6)<<6; + temp2 = temp2-j; + linear_offset = temp1*(i-top); + temp4 = j&0x3; + tiled_offset = tiled_offset+temp4; + memcpy(yuv420_dest+linear_offset, nv12t_src+tiled_offset, temp2); + linear_offset = linear_offset+temp2; + j = j+temp2; + if ((j+64) <= temp3) { + tiled_offset = tile_4x2_read(yuv420_width, yuv420_height, j, i); + memcpy(yuv420_dest+linear_offset, nv12t_src+tiled_offset, 64); + linear_offset = linear_offset+64; + j = j+64; + } + if ((j+64) <= temp3) { + tiled_offset = tile_4x2_read(yuv420_width, yuv420_height, j, i); + memcpy(yuv420_dest+linear_offset, nv12t_src+tiled_offset, 64); + linear_offset = linear_offset+64; + j = j+64; + } + if (j < temp3) { + tiled_offset = tile_4x2_read(yuv420_width, yuv420_height, j, i); + temp2 = temp3-j; + memcpy(yuv420_dest+linear_offset, nv12t_src+tiled_offset, temp2); + } + } + } else { + for (i=top; i<(yuv420_height-buttom); i=i+1) { + linear_offset = temp1*(i-top); + for (j=left; j<(yuv420_width-right); j=j+2) { + tiled_offset = tile_4x2_read(yuv420_width, yuv420_height, j, i); + temp4 = j&0x3; + tiled_offset = tiled_offset+temp4; + memcpy(yuv420_dest+linear_offset, nv12t_src+tiled_offset, 2); + linear_offset = linear_offset+2; + } + } + } +} + +/* + * Converts and Deinterleaves tiled data to linear + * Crops left, top, right, buttom + * 1. UV of NV12T to UV of YUV420P + * + * @param yuv420_u_dest + * U plane address of YUV420P[out] + * + * @param yuv420_v_dest + * V plane address of YUV420P[out] + * + * @param nv12t_src + * UV plane address of NV12T[in] + * + * @param yuv420_width + * Width of YUV420[in] + * + * @param yuv420_uv_height + * Height/2 of YUV420[in] + * + * @param left + * Crop size of left + * + * @param top + * Crop size of top + * + * @param right + * Crop size of right + * + * @param buttom + * Crop size of buttom + */ +static void csc_tiled_to_linear_deinterleave_crop( + unsigned char *yuv420_u_dest, + unsigned char *yuv420_v_dest, + unsigned char *nv12t_uv_src, + unsigned int yuv420_width, + unsigned int yuv420_uv_height, + unsigned int left, + unsigned int top, + unsigned int right, + unsigned int buttom) +{ + unsigned int i, j; + unsigned int tiled_offset = 0, tiled_offset1 = 0; + unsigned int linear_offset = 0; + unsigned int temp1 = 0, temp2 = 0, temp3 = 0, temp4 = 0; + + temp3 = yuv420_width-right; + temp1 = temp3-left; + /* real width is greater than or equal 256 */ + if (temp1 >= 256) { + for (i=top; i<yuv420_uv_height-buttom; i=i+1) { + j = left; + temp3 = (j>>8)<<8; + temp3 = temp3>>6; + temp4 = i>>5; + if (temp4 & 0x1) { + /* odd fomula: 2+x+(x>>2)<<2+x_block_num*(y-1) */ + tiled_offset = temp4-1; + temp1 = ((yuv420_width+127)>>7)<<7; + tiled_offset = tiled_offset*(temp1>>6); + tiled_offset = tiled_offset+temp3; + tiled_offset = tiled_offset+2; + temp1 = (temp3>>2)<<2; + tiled_offset = tiled_offset+temp1; + tiled_offset = tiled_offset<<11; + tiled_offset1 = tiled_offset+2048*2; + temp4 = 8; + } else { + temp2 = ((yuv420_uv_height+31)>>5)<<5; + if ((i+32)<temp2) { + /* even1 fomula: x+((x+2)>>2)<<2+x_block_num*y */ + temp1 = temp3+2; + temp1 = (temp1>>2)<<2; + tiled_offset = temp3+temp1; + temp1 = ((yuv420_width+127)>>7)<<7; + tiled_offset = tiled_offset+temp4*(temp1>>6); + tiled_offset = tiled_offset<<11; + tiled_offset1 = tiled_offset+2048*6; + temp4 = 8; + } else { + /* even2 fomula: x+x_block_num*y */ + temp1 = ((yuv420_width+127)>>7)<<7; + tiled_offset = temp4*(temp1>>6); + tiled_offset = tiled_offset+temp3; + tiled_offset = tiled_offset<<11; + tiled_offset1 = tiled_offset+2048*2; + temp4 = 4; + } + } + + temp1 = i&0x1F; + tiled_offset = tiled_offset+64*(temp1); + tiled_offset1 = tiled_offset1+64*(temp1); + temp2 = yuv420_width-left-right; + linear_offset = temp2*(i-top)/2; + temp3 = ((j+256)>>8)<<8; + temp3 = temp3-j; + temp1 = left&0x3F; + if (temp3 > 192) { + csc_deinterleave_memcpy(yuv420_u_dest+linear_offset, yuv420_v_dest+linear_offset, nv12t_uv_src+tiled_offset+temp1, 64-temp1); + csc_deinterleave_memcpy(yuv420_u_dest+linear_offset+(32-temp1/2), + yuv420_v_dest+linear_offset+(32-temp1/2), + nv12t_uv_src+tiled_offset+2048, 64); + csc_deinterleave_memcpy(yuv420_u_dest+linear_offset+(64-temp1/2), + yuv420_v_dest+linear_offset+(64-temp1/2), + nv12t_uv_src+tiled_offset1, 64); + csc_deinterleave_memcpy(yuv420_u_dest+linear_offset+(96-temp1/2), + yuv420_v_dest+linear_offset+(96-temp1/2), + nv12t_uv_src+tiled_offset1+2048, 64); + linear_offset = linear_offset+128-temp1/2; + } else if (temp3 > 128) { + csc_deinterleave_memcpy(yuv420_u_dest+linear_offset, + yuv420_v_dest+linear_offset, + nv12t_uv_src+tiled_offset+2048+temp1, 64-temp1); + csc_deinterleave_memcpy(yuv420_u_dest+linear_offset+(32-temp1/2), + yuv420_v_dest+linear_offset+(32-temp1/2), + nv12t_uv_src+tiled_offset1, 64); + csc_deinterleave_memcpy(yuv420_u_dest+linear_offset+(64-temp1/2), + yuv420_v_dest+linear_offset+(64-temp1/2), + nv12t_uv_src+tiled_offset1+2048, 64); + linear_offset = linear_offset+96-temp1/2; + } else if (temp3 > 64) { + csc_deinterleave_memcpy(yuv420_u_dest+linear_offset, + yuv420_v_dest+linear_offset, + nv12t_uv_src+tiled_offset1+temp1, 64-temp1); + csc_deinterleave_memcpy(yuv420_u_dest+linear_offset+(32-temp1/2), + yuv420_v_dest+linear_offset+(32-temp1/2), + nv12t_uv_src+tiled_offset1+2048, 64); + linear_offset = linear_offset+64-temp1/2; + } else if (temp3 > 0) { + csc_deinterleave_memcpy(yuv420_u_dest+linear_offset, + yuv420_v_dest+linear_offset, + nv12t_uv_src+tiled_offset1+2048+temp1, 64-temp1); + linear_offset = linear_offset+32-temp1/2; + } + + tiled_offset = tiled_offset+temp4*2048; + j = (left>>8)<<8; + j = j + 256; + temp2 = yuv420_width-right-256; + for (; j<=temp2; j=j+256) { + csc_deinterleave_memcpy(yuv420_u_dest+linear_offset, + yuv420_v_dest+linear_offset, + nv12t_uv_src+tiled_offset, 64); + tiled_offset1 = tiled_offset1+temp4*2048; + csc_deinterleave_memcpy(yuv420_u_dest+linear_offset+32, + yuv420_v_dest+linear_offset+32, + nv12t_uv_src+tiled_offset+2048, 64); + csc_deinterleave_memcpy(yuv420_u_dest+linear_offset+64, + yuv420_v_dest+linear_offset+64, + nv12t_uv_src+tiled_offset1, 64); + tiled_offset = tiled_offset+temp4*2048; + csc_deinterleave_memcpy(yuv420_u_dest+linear_offset+96, + yuv420_v_dest+linear_offset+96, + nv12t_uv_src+tiled_offset1+2048, 64); + linear_offset = linear_offset+128; + } + + tiled_offset1 = tiled_offset1+temp4*2048; + temp2 = yuv420_width-right-j; + if (temp2 > 192) { + csc_deinterleave_memcpy(yuv420_u_dest+linear_offset, + yuv420_v_dest+linear_offset, + nv12t_uv_src+tiled_offset, 64); + csc_deinterleave_memcpy(yuv420_u_dest+linear_offset+32, + yuv420_v_dest+linear_offset+32, + nv12t_uv_src+tiled_offset+2048, 64); + csc_deinterleave_memcpy(yuv420_u_dest+linear_offset+64, + yuv420_v_dest+linear_offset+64, + nv12t_uv_src+tiled_offset1, 64); + csc_deinterleave_memcpy(yuv420_u_dest+linear_offset+96, + yuv420_v_dest+linear_offset+96, + nv12t_uv_src+tiled_offset1+2048, temp2-192); + } else if (temp2 > 128) { + csc_deinterleave_memcpy(yuv420_u_dest+linear_offset, + yuv420_v_dest+linear_offset, + nv12t_uv_src+tiled_offset, 64); + csc_deinterleave_memcpy(yuv420_u_dest+linear_offset+32, + yuv420_v_dest+linear_offset+32, + nv12t_uv_src+tiled_offset+2048, 64); + csc_deinterleave_memcpy(yuv420_u_dest+linear_offset+64, + yuv420_v_dest+linear_offset+64, + nv12t_uv_src+tiled_offset1, temp2-128); + } else if (temp2 > 64) { + csc_deinterleave_memcpy(yuv420_u_dest+linear_offset, + yuv420_v_dest+linear_offset, + nv12t_uv_src+tiled_offset, 64); + csc_deinterleave_memcpy(yuv420_u_dest+linear_offset+32, + yuv420_v_dest+linear_offset+32, + nv12t_uv_src+tiled_offset+2048, temp2-64); + } else { + csc_deinterleave_memcpy(yuv420_u_dest+linear_offset, + yuv420_v_dest+linear_offset, + nv12t_uv_src+tiled_offset, temp2); + } + } + } else if (temp1 >= 64) { + for (i=top; i<(yuv420_uv_height-buttom); i=i+1) { + j = left; + tiled_offset = tile_4x2_read(yuv420_width, yuv420_uv_height, j, i); + temp2 = ((j+64)>>6)<<6; + temp2 = temp2-j; + temp3 = yuv420_width-right; + temp4 = temp3-left; + linear_offset = temp4*(i-top)/2; + temp4 = j&0x3; + tiled_offset = tiled_offset+temp4; + csc_deinterleave_memcpy(yuv420_u_dest+linear_offset, + yuv420_v_dest+linear_offset, + nv12t_uv_src+tiled_offset, temp2); + linear_offset = linear_offset+temp2/2; + j = j+temp2; + if ((j+64) <= temp3) { + tiled_offset = tile_4x2_read(yuv420_width, yuv420_uv_height, j, i); + csc_deinterleave_memcpy(yuv420_u_dest+linear_offset, + yuv420_v_dest+linear_offset, + nv12t_uv_src+tiled_offset, 64); + linear_offset = linear_offset+32; + j = j+64; + } + if ((j+64) <= temp3) { + tiled_offset = tile_4x2_read(yuv420_width, yuv420_uv_height, j, i); + csc_deinterleave_memcpy(yuv420_u_dest+linear_offset, + yuv420_v_dest+linear_offset, + nv12t_uv_src+tiled_offset, 64); + linear_offset = linear_offset+32; + j = j+64; + } + if (j < temp3) { + tiled_offset = tile_4x2_read(yuv420_width, yuv420_uv_height, j, i); + temp1 = temp3-j; + csc_deinterleave_memcpy(yuv420_u_dest+linear_offset, + yuv420_v_dest+linear_offset, + nv12t_uv_src+tiled_offset, temp1); + } + } + } else { + for (i=top; i<(yuv420_uv_height-buttom); i=i+1) { + temp3 = yuv420_width-right; + temp4 = temp3-left; + linear_offset = temp4*(i-top)/2; + for (j=left; j<(yuv420_width-right); j=j+2) { + tiled_offset = tile_4x2_read(yuv420_width, yuv420_uv_height, j, i); + temp3 = j&0x3; + tiled_offset = tiled_offset+temp3; + csc_deinterleave_memcpy(yuv420_u_dest+linear_offset, + yuv420_v_dest+linear_offset, + nv12t_uv_src+tiled_offset, 2); + linear_offset = linear_offset+1; + } + } + } +} + +/* + * Converts linear data to tiled + * Crops left, top, right, buttom + * 1. Y of YUV420P to Y of NV12T + * 2. Y of YUV420S to Y of NV12T + * 3. UV of YUV420S to UV of NV12T + * + * @param nv12t_dest + * Y or UV plane address of NV12T[out] + * + * @param yuv420_src + * Y or UV plane address of YUV420P(S)[in] + * + * @param yuv420_width + * Width of YUV420[in] + * + * @param yuv420_height + * Y: Height of YUV420, UV: Height/2 of YUV420[in] + * + * @param left + * Crop size of left + * + * @param top + * Crop size of top + * + * @param right + * Crop size of right + * + * @param buttom + * Crop size of buttom + */ +static void csc_linear_to_tiled_crop( + unsigned char *nv12t_dest, + unsigned char *yuv420_src, + unsigned int yuv420_width, + unsigned int yuv420_height, + unsigned int left, + unsigned int top, + unsigned int right, + unsigned int buttom) +{ + unsigned int i, j; + unsigned int tiled_x_index = 0, tiled_y_index = 0; + unsigned int aligned_x_size = 0, aligned_y_size = 0; + unsigned int tiled_offset = 0; + unsigned int temp1 = 0, temp2 = 0; + + aligned_y_size = ((yuv420_height-top-buttom)>>5)<<5; + aligned_x_size = ((yuv420_width-left-right)>>6)<<6; + + for (i=0; i<aligned_y_size; i=i+32) { + for (j=0; j<aligned_x_size; j=j+64) { + tiled_offset = 0; + tiled_x_index = j>>6; + tiled_y_index = i>>5; + if (tiled_y_index & 0x1) { + /* odd fomula: 2+x+(x>>2)<<2+x_block_num*(y-1) */ + tiled_offset = tiled_y_index-1; + temp1 = (((yuv420_width-left-right)+127)>>7)<<7; + tiled_offset = tiled_offset*(temp1>>6); + tiled_offset = tiled_offset+tiled_x_index; + tiled_offset = tiled_offset+2; + temp1 = (tiled_x_index>>2)<<2; + tiled_offset = tiled_offset+temp1; + tiled_offset = tiled_offset<<11; + } else { + temp2 = (((yuv420_height-top-buttom)+31)>>5)<<5; + if ((i+32)<temp2) { + /* even1 fomula: x+((x+2)>>2)<<2+x_block_num*y */ + temp1 = tiled_x_index+2; + temp1 = (temp1>>2)<<2; + tiled_offset = tiled_x_index+temp1; + temp1 = (((yuv420_width-left-right)+127)>>7)<<7; + tiled_offset = tiled_offset+tiled_y_index*(temp1>>6); + tiled_offset = tiled_offset<<11; + } else { + /* even2 fomula: x+x_block_num*y */ + temp1 = (((yuv420_width-left-right)+127)>>7)<<7; + tiled_offset = tiled_y_index*(temp1>>6); + tiled_offset = tiled_offset+tiled_x_index; + tiled_offset = tiled_offset<<11; + } + } + + memcpy(nv12t_dest+tiled_offset, yuv420_src+left+j+yuv420_width*(i+top), 64); + memcpy(nv12t_dest+tiled_offset+64*1, yuv420_src+left+j+yuv420_width*(i+top+1), 64); + memcpy(nv12t_dest+tiled_offset+64*2, yuv420_src+left+j+yuv420_width*(i+top+2), 64); + memcpy(nv12t_dest+tiled_offset+64*3, yuv420_src+left+j+yuv420_width*(i+top+3), 64); + memcpy(nv12t_dest+tiled_offset+64*4, yuv420_src+left+j+yuv420_width*(i+top+4), 64); + memcpy(nv12t_dest+tiled_offset+64*5, yuv420_src+left+j+yuv420_width*(i+top+5), 64); + memcpy(nv12t_dest+tiled_offset+64*6, yuv420_src+left+j+yuv420_width*(i+top+6), 64); + memcpy(nv12t_dest+tiled_offset+64*7, yuv420_src+left+j+yuv420_width*(i+top+7), 64); + memcpy(nv12t_dest+tiled_offset+64*8, yuv420_src+left+j+yuv420_width*(i+top+8), 64); + memcpy(nv12t_dest+tiled_offset+64*9, yuv420_src+left+j+yuv420_width*(i+top+9), 64); + memcpy(nv12t_dest+tiled_offset+64*10, yuv420_src+left+j+yuv420_width*(i+top+10), 64); + memcpy(nv12t_dest+tiled_offset+64*11, yuv420_src+left+j+yuv420_width*(i+top+11), 64); + memcpy(nv12t_dest+tiled_offset+64*12, yuv420_src+left+j+yuv420_width*(i+top+12), 64); + memcpy(nv12t_dest+tiled_offset+64*13, yuv420_src+left+j+yuv420_width*(i+top+13), 64); + memcpy(nv12t_dest+tiled_offset+64*14, yuv420_src+left+j+yuv420_width*(i+top+14), 64); + memcpy(nv12t_dest+tiled_offset+64*15, yuv420_src+left+j+yuv420_width*(i+top+15), 64); + memcpy(nv12t_dest+tiled_offset+64*16, yuv420_src+left+j+yuv420_width*(i+top+16), 64); + memcpy(nv12t_dest+tiled_offset+64*17, yuv420_src+left+j+yuv420_width*(i+top+17), 64); + memcpy(nv12t_dest+tiled_offset+64*18, yuv420_src+left+j+yuv420_width*(i+top+18), 64); + memcpy(nv12t_dest+tiled_offset+64*19, yuv420_src+left+j+yuv420_width*(i+top+19), 64); + memcpy(nv12t_dest+tiled_offset+64*20, yuv420_src+left+j+yuv420_width*(i+top+20), 64); + memcpy(nv12t_dest+tiled_offset+64*21, yuv420_src+left+j+yuv420_width*(i+top+21), 64); + memcpy(nv12t_dest+tiled_offset+64*22, yuv420_src+left+j+yuv420_width*(i+top+22), 64); + memcpy(nv12t_dest+tiled_offset+64*23, yuv420_src+left+j+yuv420_width*(i+top+23), 64); + memcpy(nv12t_dest+tiled_offset+64*24, yuv420_src+left+j+yuv420_width*(i+top+24), 64); + memcpy(nv12t_dest+tiled_offset+64*25, yuv420_src+left+j+yuv420_width*(i+top+25), 64); + memcpy(nv12t_dest+tiled_offset+64*26, yuv420_src+left+j+yuv420_width*(i+top+26), 64); + memcpy(nv12t_dest+tiled_offset+64*27, yuv420_src+left+j+yuv420_width*(i+top+27), 64); + memcpy(nv12t_dest+tiled_offset+64*28, yuv420_src+left+j+yuv420_width*(i+top+28), 64); + memcpy(nv12t_dest+tiled_offset+64*29, yuv420_src+left+j+yuv420_width*(i+top+29), 64); + memcpy(nv12t_dest+tiled_offset+64*30, yuv420_src+left+j+yuv420_width*(i+top+30), 64); + memcpy(nv12t_dest+tiled_offset+64*31, yuv420_src+left+j+yuv420_width*(i+top+31), 64); + } + } + + for (i=aligned_y_size; i<(yuv420_height-top-buttom); i=i+2) { + for (j=0; j<aligned_x_size; j=j+64) { + tiled_offset = 0; + tiled_x_index = j>>6; + tiled_y_index = i>>5; + if (tiled_y_index & 0x1) { + /* odd fomula: 2+x+(x>>2)<<2+x_block_num*(y-1) */ + tiled_offset = tiled_y_index-1; + temp1 = (((yuv420_width-left-right)+127)>>7)<<7; + tiled_offset = tiled_offset*(temp1>>6); + tiled_offset = tiled_offset+tiled_x_index; + tiled_offset = tiled_offset+2; + temp1 = (tiled_x_index>>2)<<2; + tiled_offset = tiled_offset+temp1; + tiled_offset = tiled_offset<<11; + } else { + temp2 = (((yuv420_height-top-buttom)+31)>>5)<<5; + if ((i+32)<temp2) { + /* even1 fomula: x+((x+2)>>2)<<2+x_block_num*y */ + temp1 = tiled_x_index+2; + temp1 = (temp1>>2)<<2; + tiled_offset = tiled_x_index+temp1; + temp1 = (((yuv420_width-left-right)+127)>>7)<<7; + tiled_offset = tiled_offset+tiled_y_index*(temp1>>6); + tiled_offset = tiled_offset<<11; + } else { + /* even2 fomula: x+x_block_num*y */ + temp1 = (((yuv420_width-left-right)+127)>>7)<<7; + tiled_offset = tiled_y_index*(temp1>>6); + tiled_offset = tiled_offset+tiled_x_index; + tiled_offset = tiled_offset<<11; + } + } + + temp1 = i&0x1F; + memcpy(nv12t_dest+tiled_offset+64*(temp1), yuv420_src+left+j+yuv420_width*(i+top), 64); + memcpy(nv12t_dest+tiled_offset+64*(temp1+1), yuv420_src+left+j+yuv420_width*(i+top+1), 64); + } + } + + for (i=0; i<(yuv420_height-top-buttom); i=i+2) { + for (j=aligned_x_size; j<(yuv420_width-left-right); j=j+2) { + tiled_offset = 0; + tiled_x_index = j>>6; + tiled_y_index = i>>5; + if (tiled_y_index & 0x1) { + /* odd fomula: 2+x+(x>>2)<<2+x_block_num*(y-1) */ + tiled_offset = tiled_y_index-1; + temp1 = (((yuv420_width-left-right)+127)>>7)<<7; + tiled_offset = tiled_offset*(temp1>>6); + tiled_offset = tiled_offset+tiled_x_index; + tiled_offset = tiled_offset+2; + temp1 = (tiled_x_index>>2)<<2; + tiled_offset = tiled_offset+temp1; + tiled_offset = tiled_offset<<11; + } else { + temp2 = (((yuv420_height-top-buttom)+31)>>5)<<5; + if ((i+32)<temp2) { + /* even1 fomula: x+((x+2)>>2)<<2+x_block_num*y */ + temp1 = tiled_x_index+2; + temp1 = (temp1>>2)<<2; + tiled_offset = tiled_x_index+temp1; + temp1 = (((yuv420_width-left-right)+127)>>7)<<7; + tiled_offset = tiled_offset+tiled_y_index*(temp1>>6); + tiled_offset = tiled_offset<<11; + } else { + /* even2 fomula: x+x_block_num*y */ + temp1 = (((yuv420_width-left-right)+127)>>7)<<7; + tiled_offset = tiled_y_index*(temp1>>6); + tiled_offset = tiled_offset+tiled_x_index; + tiled_offset = tiled_offset<<11; + } + } + + temp1 = i&0x1F; + temp2 = j&0x3F; + memcpy(nv12t_dest+tiled_offset+temp2+64*(temp1), yuv420_src+left+j+yuv420_width*(i+top), 2); + memcpy(nv12t_dest+tiled_offset+temp2+64*(temp1+1), yuv420_src+left+j+yuv420_width*(i+top+1), 2); + } + } + +} + +/* + * Converts and Interleaves linear to tiled + * Crops left, top, right, buttom + * 1. UV of YUV420P to UV of NV12T + * + * @param nv12t_uv_dest + * UV plane address of NV12T[out] + * + * @param yuv420p_u_src + * U plane address of YUV420P[in] + * + * @param yuv420p_v_src + * V plane address of YUV420P[in] + * + * @param yuv420_width + * Width of YUV420[in] + * + * @param yuv420_uv_height + * Height/2 of YUV420[in] + * + * @param left + * Crop size of left + * + * @param top + * Crop size of top + * + * @param right + * Crop size of right + * + * @param buttom + * Crop size of buttom + */ +static void csc_linear_to_tiled_interleave_crop( + unsigned char *nv12t_uv_dest, + unsigned char *yuv420_u_src, + unsigned char *yuv420_v_src, + unsigned int yuv420_width, + unsigned int yuv420_height, + unsigned int left, + unsigned int top, + unsigned int right, + unsigned int buttom) +{ + unsigned int i, j; + unsigned int tiled_x_index = 0, tiled_y_index = 0; + unsigned int aligned_x_size = 0, aligned_y_size = 0; + unsigned int tiled_offset = 0; + unsigned int temp1 = 0, temp2 = 0; + + aligned_y_size = ((yuv420_height-top-buttom)>>5)<<5; + aligned_x_size = ((yuv420_width-left-right)>>6)<<6; + + for (i=0; i<aligned_y_size; i=i+32) { + for (j=0; j<aligned_x_size; j=j+64) { + tiled_offset = 0; + tiled_x_index = j>>6; + tiled_y_index = i>>5; + if (tiled_y_index & 0x1) { + /* odd fomula: 2+x+(x>>2)<<2+x_block_num*(y-1) */ + tiled_offset = tiled_y_index-1; + temp1 = (((yuv420_width-left-right)+127)>>7)<<7; + tiled_offset = tiled_offset*(temp1>>6); + tiled_offset = tiled_offset+tiled_x_index; + tiled_offset = tiled_offset+2; + temp1 = (tiled_x_index>>2)<<2; + tiled_offset = tiled_offset+temp1; + tiled_offset = tiled_offset<<11; + } else { + temp2 = (((yuv420_height-top-buttom)+31)>>5)<<5; + if ((i+32)<temp2) { + /* even1 fomula: x+((x+2)>>2)<<2+x_block_num*y */ + temp1 = tiled_x_index+2; + temp1 = (temp1>>2)<<2; + tiled_offset = tiled_x_index+temp1; + temp1 = (((yuv420_width-left-right)+127)>>7)<<7; + tiled_offset = tiled_offset+tiled_y_index*(temp1>>6); + tiled_offset = tiled_offset<<11; + } else { + /* even2 fomula: x+x_block_num*y */ + temp1 = (((yuv420_width-left-right)+127)>>7)<<7; + tiled_offset = tiled_y_index*(temp1>>6); + tiled_offset = tiled_offset+tiled_x_index; + tiled_offset = tiled_offset<<11; + } + } + + csc_interleave_memcpy(nv12t_uv_dest+tiled_offset, + yuv420_u_src+left/2+j/2+yuv420_width/2*(i+top), + yuv420_v_src+left/2+j/2+yuv420_width/2*(i+top), 32); + csc_interleave_memcpy(nv12t_uv_dest+tiled_offset+64*1, + yuv420_u_src+left/2+j/2+yuv420_width/2*(i+top+1), + yuv420_v_src+left/2+j/2+yuv420_width/2*(i+top+1), 32); + csc_interleave_memcpy(nv12t_uv_dest+tiled_offset+64*2, + yuv420_u_src+left/2+j/2+yuv420_width/2*(i+top+2), + yuv420_v_src+left/2+j/2+yuv420_width/2*(i+top+2), 32); + csc_interleave_memcpy(nv12t_uv_dest+tiled_offset+64*3, + yuv420_u_src+left/2+j/2+yuv420_width/2*(i+top+3), + yuv420_v_src+left/2+j/2+yuv420_width/2*(i+top+3), 32); + csc_interleave_memcpy(nv12t_uv_dest+tiled_offset+64*4, + yuv420_u_src+left/2+j/2+yuv420_width/2*(i+top+4), + yuv420_v_src+left/2+j/2+yuv420_width/2*(i+top+4), 32); + csc_interleave_memcpy(nv12t_uv_dest+tiled_offset+64*5, + yuv420_u_src+left/2+j/2+yuv420_width/2*(i+top+5), + yuv420_v_src+left/2+j/2+yuv420_width/2*(i+top+5), 32); + csc_interleave_memcpy(nv12t_uv_dest+tiled_offset+64*6, + yuv420_u_src+left/2+j/2+yuv420_width/2*(i+top+6), + yuv420_v_src+left/2+j/2+yuv420_width/2*(i+top+6), 32); + csc_interleave_memcpy(nv12t_uv_dest+tiled_offset+64*7, + yuv420_u_src+left/2+j/2+yuv420_width/2*(i+top+7), + yuv420_v_src+left/2+j/2+yuv420_width/2*(i+top+7), 32); + csc_interleave_memcpy(nv12t_uv_dest+tiled_offset+64*8, + yuv420_u_src+left/2+j/2+yuv420_width/2*(i+top+8), + yuv420_v_src+left/2+j/2+yuv420_width/2*(i+top+8), 32); + csc_interleave_memcpy(nv12t_uv_dest+tiled_offset+64*9, + yuv420_u_src+left/2+j/2+yuv420_width/2*(i+top+9), + yuv420_v_src+left/2+j/2+yuv420_width/2*(i+top+9), 32); + csc_interleave_memcpy(nv12t_uv_dest+tiled_offset+64*10, + yuv420_u_src+left/2+j/2+yuv420_width/2*(i+top+10), + yuv420_v_src+left/2+j/2+yuv420_width/2*(i+top+10), 32); + csc_interleave_memcpy(nv12t_uv_dest+tiled_offset+64*11, + yuv420_u_src+left/2+j/2+yuv420_width/2*(i+top+11), + yuv420_v_src+left/2+j/2+yuv420_width/2*(i+top+11), 32); + csc_interleave_memcpy(nv12t_uv_dest+tiled_offset+64*12, + yuv420_u_src+left/2+j/2+yuv420_width/2*(i+top+12), + yuv420_v_src+left/2+j/2+yuv420_width/2*(i+top+12), 32); + csc_interleave_memcpy(nv12t_uv_dest+tiled_offset+64*13, + yuv420_u_src+left/2+j/2+yuv420_width/2*(i+top+13), + yuv420_v_src+left/2+j/2+yuv420_width/2*(i+top+13), 32); + csc_interleave_memcpy(nv12t_uv_dest+tiled_offset+64*14, + yuv420_u_src+left/2+j/2+yuv420_width/2*(i+top+14), + yuv420_v_src+left/2+j/2+yuv420_width/2*(i+top+14), 32); + csc_interleave_memcpy(nv12t_uv_dest+tiled_offset+64*15, + yuv420_u_src+left/2+j/2+yuv420_width/2*(i+top+15), + yuv420_v_src+left/2+j/2+yuv420_width/2*(i+top+15), 32); + csc_interleave_memcpy(nv12t_uv_dest+tiled_offset+64*16, + yuv420_u_src+left/2+j/2+yuv420_width/2*(i+top+16), + yuv420_v_src+left/2+j/2+yuv420_width/2*(i+top+16), 32); + csc_interleave_memcpy(nv12t_uv_dest+tiled_offset+64*17, + yuv420_u_src+left/2+j/2+yuv420_width/2*(i+top+17), + yuv420_v_src+left/2+j/2+yuv420_width/2*(i+top+17), 32); + csc_interleave_memcpy(nv12t_uv_dest+tiled_offset+64*18, + yuv420_u_src+left/2+j/2+yuv420_width/2*(i+top+18), + yuv420_v_src+left/2+j/2+yuv420_width/2*(i+top+18), 32); + csc_interleave_memcpy(nv12t_uv_dest+tiled_offset+64*19, + yuv420_u_src+left/2+j/2+yuv420_width/2*(i+top+19), + yuv420_v_src+left/2+j/2+yuv420_width/2*(i+top+19), 32); + csc_interleave_memcpy(nv12t_uv_dest+tiled_offset+64*20, + yuv420_u_src+left/2+j/2+yuv420_width/2*(i+top+20), + yuv420_v_src+left/2+j/2+yuv420_width/2*(i+top+20), 32); + csc_interleave_memcpy(nv12t_uv_dest+tiled_offset+64*21, + yuv420_u_src+left/2+j/2+yuv420_width/2*(i+top+21), + yuv420_v_src+left/2+j/2+yuv420_width/2*(i+top+21), 32); + csc_interleave_memcpy(nv12t_uv_dest+tiled_offset+64*22, + yuv420_u_src+left/2+j/2+yuv420_width/2*(i+top+22), + yuv420_v_src+left/2+j/2+yuv420_width/2*(i+top+22), 32); + csc_interleave_memcpy(nv12t_uv_dest+tiled_offset+64*23, + yuv420_u_src+left/2+j/2+yuv420_width/2*(i+top+23), + yuv420_v_src+left/2+j/2+yuv420_width/2*(i+top+23), 32); + csc_interleave_memcpy(nv12t_uv_dest+tiled_offset+64*24, + yuv420_u_src+left/2+j/2+yuv420_width/2*(i+top+24), + yuv420_v_src+left/2+j/2+yuv420_width/2*(i+top+24), 32); + csc_interleave_memcpy(nv12t_uv_dest+tiled_offset+64*25, + yuv420_u_src+left/2+j/2+yuv420_width/2*(i+top+25), + yuv420_v_src+left/2+j/2+yuv420_width/2*(i+top+25), 32); + csc_interleave_memcpy(nv12t_uv_dest+tiled_offset+64*26, + yuv420_u_src+left/2+j/2+yuv420_width/2*(i+top+26), + yuv420_v_src+left/2+j/2+yuv420_width/2*(i+top+26), 32); + csc_interleave_memcpy(nv12t_uv_dest+tiled_offset+64*27, + yuv420_u_src+left/2+j/2+yuv420_width/2*(i+top+27), + yuv420_v_src+left/2+j/2+yuv420_width/2*(i+top+27), 32); + csc_interleave_memcpy(nv12t_uv_dest+tiled_offset+64*28, + yuv420_u_src+left/2+j/2+yuv420_width/2*(i+top+28), + yuv420_v_src+left/2+j/2+yuv420_width/2*(i+top+28), 32); + csc_interleave_memcpy(nv12t_uv_dest+tiled_offset+64*29, + yuv420_u_src+left/2+j/2+yuv420_width/2*(i+top+29), + yuv420_v_src+left/2+j/2+yuv420_width/2*(i+top+29), 32); + csc_interleave_memcpy(nv12t_uv_dest+tiled_offset+64*30, + yuv420_u_src+left/2+j/2+yuv420_width/2*(i+top+30), + yuv420_v_src+left/2+j/2+yuv420_width/2*(i+top+30), 32); + csc_interleave_memcpy(nv12t_uv_dest+tiled_offset+64*31, + yuv420_u_src+left/2+j/2+yuv420_width/2*(i+top+31), + yuv420_v_src+left/2+j/2+yuv420_width/2*(i+top+31), 32); + + } + } + + for (i=aligned_y_size; i<(yuv420_height-top-buttom); i=i+1) { + for (j=0; j<aligned_x_size; j=j+64) { + tiled_offset = 0; + tiled_x_index = j>>6; + tiled_y_index = i>>5; + if (tiled_y_index & 0x1) { + /* odd fomula: 2+x+(x>>2)<<2+x_block_num*(y-1) */ + tiled_offset = tiled_y_index-1; + temp1 = (((yuv420_width-left-right)+127)>>7)<<7; + tiled_offset = tiled_offset*(temp1>>6); + tiled_offset = tiled_offset+tiled_x_index; + tiled_offset = tiled_offset+2; + temp1 = (tiled_x_index>>2)<<2; + tiled_offset = tiled_offset+temp1; + tiled_offset = tiled_offset<<11; + } else { + temp2 = (((yuv420_height-top-buttom)+31)>>5)<<5; + if ((i+32)<temp2) { + /* even1 fomula: x+((x+2)>>2)<<2+x_block_num*y */ + temp1 = tiled_x_index+2; + temp1 = (temp1>>2)<<2; + tiled_offset = tiled_x_index+temp1; + temp1 = (((yuv420_width-left-right)+127)>>7)<<7; + tiled_offset = tiled_offset+tiled_y_index*(temp1>>6); + tiled_offset = tiled_offset<<11; + } else { + /* even2 fomula: x+x_block_num*y */ + temp1 = (((yuv420_width-left-right)+127)>>7)<<7; + tiled_offset = tiled_y_index*(temp1>>6); + tiled_offset = tiled_offset+tiled_x_index; + tiled_offset = tiled_offset<<11; + } + } + temp1 = i&0x1F; + csc_interleave_memcpy(nv12t_uv_dest+tiled_offset+64*(temp1), + yuv420_u_src+left/2+j/2+yuv420_width/2*(i+top), + yuv420_v_src+left/2+j/2+yuv420_width/2*(i+top), 32); + } + } + + for (i=0; i<(yuv420_height-top-buttom); i=i+1) { + for (j=aligned_x_size; j<(yuv420_width-left-right); j=j+2) { + tiled_offset = 0; + tiled_x_index = j>>6; + tiled_y_index = i>>5; + if (tiled_y_index & 0x1) { + /* odd fomula: 2+x+(x>>2)<<2+x_block_num*(y-1) */ + tiled_offset = tiled_y_index-1; + temp1 = (((yuv420_width-left-right)+127)>>7)<<7; + tiled_offset = tiled_offset*(temp1>>6); + tiled_offset = tiled_offset+tiled_x_index; + tiled_offset = tiled_offset+2; + temp1 = (tiled_x_index>>2)<<2; + tiled_offset = tiled_offset+temp1; + tiled_offset = tiled_offset<<11; + } else { + temp2 = (((yuv420_height-top-buttom)+31)>>5)<<5; + if ((i+32)<temp2) { + /* even1 fomula: x+((x+2)>>2)<<2+x_block_num*y */ + temp1 = tiled_x_index+2; + temp1 = (temp1>>2)<<2; + tiled_offset = tiled_x_index+temp1; + temp1 = (((yuv420_width-left-right)+127)>>7)<<7; + tiled_offset = tiled_offset+tiled_y_index*(temp1>>6); + tiled_offset = tiled_offset<<11; + } else { + /* even2 fomula: x+x_block_num*y */ + temp1 = (((yuv420_width-left-right)+127)>>7)<<7; + tiled_offset = tiled_y_index*(temp1>>6); + tiled_offset = tiled_offset+tiled_x_index; + tiled_offset = tiled_offset<<11; + } + } + temp1 = i&0x1F; + temp2 = j&0x3F; + csc_interleave_memcpy(nv12t_uv_dest+tiled_offset+temp2+64*(temp1), + yuv420_u_src+left/2+j/2+yuv420_width/2*(i+top), + yuv420_v_src+left/2+j/2+yuv420_width/2*(i+top), 1); + } + } + +} + + +/* + * Converts tiled data to linear + * Crops left, top, right, buttom + * 1. Y of NV12T to Y of YUV420P + * 2. Y of NV12T to Y of YUV420S + * 3. UV of NV12T to UV of YUV420S + * + * @param yuv420_dest + * Y or UV plane address of YUV420[out] + * + * @param nv12t_src + * Y or UV plane address of NV12T[in] + * + * @param yuv420_width + * Width of YUV420[in] + * + * @param yuv420_height + * Y: Height of YUV420, UV: Height/2 of YUV420[in] + * + * @param left + * Crop size of left + * + * @param top + * Crop size of top + * + * @param right + * Crop size of right + * + * @param buttom + * Crop size of buttom + */ +void csc_tiled_to_linear_crop_neon( + unsigned char *yuv420_dest, + unsigned char *nv12t_src, + unsigned int yuv420_width, + unsigned int yuv420_height, + unsigned int left, + unsigned int top, + unsigned int right, + unsigned int buttom); + +/* + * Converts and Deinterleaves tiled data to linear + * Crops left, top, right, buttom + * 1. UV of NV12T to UV of YUV420P + * + * @param yuv420_u_dest + * U plane address of YUV420P[out] + * + * @param yuv420_v_dest + * V plane address of YUV420P[out] + * + * @param nv12t_src + * UV plane address of NV12T[in] + * + * @param yuv420_width + * Width of YUV420[in] + * + * @param yuv420_uv_height + * Height/2 of YUV420[in] + * + * @param left + * Crop size of left + * + * @param top + * Crop size of top + * + * @param right + * Crop size of right + * + * @param buttom + * Crop size of buttom + */ +void csc_tiled_to_linear_deinterleave_crop_neon( + unsigned char *yuv420_u_dest, + unsigned char *yuv420_v_dest, + unsigned char *nv12t_uv_src, + unsigned int yuv420_width, + unsigned int yuv420_uv_height, + unsigned int left, + unsigned int top, + unsigned int right, + unsigned int buttom); + +/* + * Converts linear data to tiled + * Crops left, top, right, buttom + * 1. Y of YUV420P to Y of NV12T + * 2. Y of YUV420S to Y of NV12T + * 3. UV of YUV420S to UV of NV12T + * + * @param nv12t_dest + * Y or UV plane address of NV12T[out] + * + * @param yuv420_src + * Y or UV plane address of YUV420P(S)[in] + * + * @param yuv420_width + * Width of YUV420[in] + * + * @param yuv420_height + * Y: Height of YUV420, UV: Height/2 of YUV420[in] + * + * @param left + * Crop size of left + * + * @param top + * Crop size of top + * + * @param right + * Crop size of right + * + * @param buttom + * Crop size of buttom + */ +void csc_linear_to_tiled_crop_neon( + unsigned char *nv12t_dest, + unsigned char *yuv420_src, + unsigned int yuv420_width, + unsigned int yuv420_height, + unsigned int left, + unsigned int top, + unsigned int right, + unsigned int buttom); + +/* + * Converts and Interleaves linear to tiled + * Crops left, top, right, buttom + * 1. UV of YUV420P to UV of NV12T + * + * @param nv12t_uv_dest + * UV plane address of NV12T[out] + * + * @param yuv420p_u_src + * U plane address of YUV420P[in] + * + * @param yuv420p_v_src + * V plane address of YUV420P[in] + * + * @param yuv420_width + * Width of YUV420[in] + * + * @param yuv420_uv_height + * Height/2 of YUV420[in] + * + * @param left + * Crop size of left + * + * @param top + * Crop size of top + * + * @param right + * Crop size of right + * + * @param buttom + * Crop size of buttom + */ +void csc_linear_to_tiled_interleave_crop_neon( + unsigned char *nv12t_uv_dest, + unsigned char *yuv420_u_src, + unsigned char *yuv420_v_src, + unsigned int yuv420_width, + unsigned int yuv420_height, + unsigned int left, + unsigned int top, + unsigned int right, + unsigned int buttom); + +/* + * Converts tiled data to linear. + * 1. y of nv12t to y of yuv420p + * 2. y of nv12t to y of yuv420s + * + * @param dst + * y address of yuv420[out] + * + * @param src + * y address of nv12t[in] + * + * @param yuv420_width + * real width of yuv420[in] + * it should be even + * + * @param yuv420_height + * real height of yuv420[in] + * it should be even. + * + */ +void csc_tiled_to_linear_y( + unsigned char *y_dst, + unsigned char *y_src, + unsigned int width, + unsigned int height) +{ + csc_tiled_to_linear_crop(y_dst, y_src, width, height, 0, 0, 0, 0); +} + +/* + * Converts tiled data to linear + * 1. uv of nv12t to y of yuv420s + * + * @param dst + * uv address of yuv420s[out] + * + * @param src + * uv address of nv12t[in] + * + * @param yuv420_width + * real width of yuv420s[in] + * + * @param yuv420_height + * real height of yuv420s[in] + * + */ +void csc_tiled_to_linear_uv( + unsigned char *uv_dst, + unsigned char *uv_src, + unsigned int width, + unsigned int height) +{ + csc_tiled_to_linear_crop(uv_dst, uv_src, width, height, 0, 0, 0, 0); +} + +/* + * Converts tiled data to linear + * 1. uv of nt12t to uv of yuv420p + * + * @param u_dst + * u address of yuv420p[out] + * + * @param v_dst + * v address of yuv420p[out] + * + * @param uv_src + * uv address of nt12t[in] + * + * @param yuv420_width + * real width of yuv420p[in] + * + * @param yuv420_height + * real height of yuv420p[in] + */ +void csc_tiled_to_linear_uv_deinterleave( + unsigned char *u_dst, + unsigned char *v_dst, + unsigned char *uv_src, + unsigned int width, + unsigned int height) +{ + csc_tiled_to_linear_deinterleave_crop(u_dst, v_dst, uv_src, width, height, + 0, 0, 0, 0); +} + +/* + * Converts linear data to tiled + * 1. y of yuv420 to y of nv12t + * + * @param dst + * y address of nv12t[out] + * + * @param src + * y address of yuv420[in] + * + * @param yuv420_width + * real width of yuv420[in] + * it should be even + * + * @param yuv420_height + * real height of yuv420[in] + * it should be even. + * + */ +void csc_linear_to_tiled_y( + unsigned char *y_dst, + unsigned char *y_src, + unsigned int width, + unsigned int height) +{ + csc_linear_to_tiled_crop(y_dst, y_src, width, height, 0, 0, 0, 0); +} + +/* + * Converts and interleaves linear data to tiled + * 1. uv of nv12t to uv of yuv420 + * + * @param dst + * uv address of nv12t[out] + * + * @param src + * u address of yuv420[in] + * + * @param src + * v address of yuv420[in] + * + * @param yuv420_width + * real width of yuv420[in] + * + * @param yuv420_height + * real height of yuv420[in] + * + */ +void csc_linear_to_tiled_uv( + unsigned char *uv_dst, + unsigned char *u_src, + unsigned char *v_src, + unsigned int width, + unsigned int height) +{ + csc_linear_to_tiled_interleave_crop(uv_dst, u_src, v_src, width, height, + 0, 0, 0, 0); +} + +/* + * Converts tiled data to linear for mfc 6.x + * 1. Y of NV12T to Y of YUV420P + * 2. Y of NV12T to Y of YUV420S + * + * @param dst + * Y address of YUV420[out] + * + * @param src + * Y address of NV12T[in] + * + * @param yuv420_width + * real width of YUV420[in] + * + * @param yuv420_height + * Y: real height of YUV420[in] + * + */ +void csc_tiled_to_linear_y_neon( + unsigned char *y_dst, + unsigned char *y_src, + unsigned int width, + unsigned int height) +{ + csc_tiled_to_linear_crop_neon(y_dst, y_src, width, height, 0, 0, 0, 0); +} + +/* + * Converts tiled data to linear for mfc 6.x + * 1. UV of NV12T to Y of YUV420S + * + * @param u_dst + * UV plane address of YUV420P[out] + * + * @param nv12t_src + * Y or UV plane address of NV12T[in] + * + * @param yuv420_width + * real width of YUV420[in] + * + * @param yuv420_height + * (real height)/2 of YUV420[in] + */ +void csc_tiled_to_linear_uv_neon( + unsigned char *uv_dst, + unsigned char *uv_src, + unsigned int width, + unsigned int height) +{ + csc_tiled_to_linear_crop_neon(uv_dst, uv_src, width, height, 0, 0, 0, 0); +} + +/* + * Converts tiled data to linear for mfc 6.x + * Deinterleave src to u_dst, v_dst + * 1. UV of NV12T to Y of YUV420P + * + * @param u_dst + * U plane address of YUV420P[out] + * + * @param v_dst + * V plane address of YUV420P[out] + * + * @param nv12t_src + * Y or UV plane address of NV12T[in] + * + * @param yuv420_width + * real width of YUV420[in] + * + * @param yuv420_height + * (real height)/2 of YUV420[in] + */ +void csc_tiled_to_linear_uv_deinterleave_neon( + unsigned char *u_dst, + unsigned char *v_dst, + unsigned char *uv_src, + unsigned int width, + unsigned int height) +{ + csc_tiled_to_linear_deinterleave_crop_neon(u_dst, v_dst, uv_src, width, height, + 0, 0, 0, 0); +} + +/* + * Converts linear data to tiled + * 1. y of yuv420 to y of nv12t + * + * @param dst + * y address of nv12t[out] + * + * @param src + * y address of yuv420[in] + * + * @param yuv420_width + * real width of yuv420[in] + * it should be even + * + * @param yuv420_height + * real height of yuv420[in] + * it should be even. + * + */ +void csc_linear_to_tiled_y_neon( + unsigned char *y_dst, + unsigned char *y_src, + unsigned int width, + unsigned int height) +{ + csc_linear_to_tiled_crop_neon(y_dst, y_src, width, height, 0, 0, 0, 0); +} + +/* + * Converts and interleaves linear data to tiled + * 1. uv of nv12t to uv of yuv420 + * + * @param dst + * uv address of nv12t[out] + * + * @param src + * u address of yuv420[in] + * + * @param src + * v address of yuv420[in] + * + * @param yuv420_width + * real width of yuv420[in] + * + * @param yuv420_height + * real height of yuv420[in] + * + */ +void csc_linear_to_tiled_uv_neon( + unsigned char *uv_dst, + unsigned char *u_src, + unsigned char *v_src, + unsigned int width, + unsigned int height) +{ + csc_linear_to_tiled_interleave_crop_neon(uv_dst, u_src, v_src, + width, height, 0, 0, 0, 0); +} + +/* + * Converts RGB565 to YUV420P + * + * @param y_dst + * Y plane address of YUV420P[out] + * + * @param u_dst + * U plane address of YUV420P[out] + * + * @param v_dst + * V plane address of YUV420P[out] + * + * @param rgb_src + * Address of RGB565[in] + * + * @param width + * Width of RGB565[in] + * + * @param height + * Height of RGB565[in] + */ +void csc_RGB565_to_YUV420P( + unsigned char *y_dst, + unsigned char *u_dst, + unsigned char *v_dst, + unsigned char *rgb_src, + unsigned int width, + unsigned int height) +{ + unsigned int i, j; + unsigned int tmp; + + unsigned int R, G, B; + unsigned int Y, U, V; + + unsigned int offset1 = width * height; + unsigned int offset2 = width/2 * height/2; + + unsigned short int *pSrc = (unsigned short int *)rgb_src; + + unsigned char *pDstY = (unsigned char *)y_dst; + unsigned char *pDstU = (unsigned char *)u_dst; + unsigned char *pDstV = (unsigned char *)v_dst; + + unsigned int yIndex = 0; + unsigned int uIndex = 0; + unsigned int vIndex = 0; + + for (j = 0; j < height; j++) { + for (i = 0; i < width; i++) { + tmp = pSrc[j * width + i]; + + R = (tmp & 0x0000F800) >> 8; + G = (tmp & 0x000007E0) >> 3; + B = (tmp & 0x0000001F); + B = B << 3; + + Y = ((66 * R) + (129 * G) + (25 * B) + 128); + Y = Y >> 8; + Y += 16; + + pDstY[yIndex++] = (unsigned char)Y; + + if ((j % 2) == 0 && (i % 2) == 0) { + U = ((-38 * R) - (74 * G) + (112 * B) + 128); + U = U >> 8; + U += 128; + V = ((112 * R) - (94 * G) - (18 * B) + 128); + V = V >> 8; + V += 128; + + pDstU[uIndex++] = (unsigned char)U; + pDstV[vIndex++] = (unsigned char)V; + } + } + } +} + +/* + * Converts RGB565 to YUV420SP + * + * @param y_dst + * Y plane address of YUV420SP[out] + * + * @param uv_dst + * UV plane address of YUV420SP[out] + * + * @param rgb_src + * Address of RGB565[in] + * + * @param width + * Width of RGB565[in] + * + * @param height + * Height of RGB565[in] + */ +void csc_RGB565_to_YUV420SP( + unsigned char *y_dst, + unsigned char *uv_dst, + unsigned char *rgb_src, + unsigned int width, + unsigned int height) +{ + unsigned int i, j; + unsigned int tmp; + + unsigned int R, G, B; + unsigned int Y, U, V; + + unsigned int offset = width * height; + + unsigned short int *pSrc = (unsigned short int *)rgb_src; + + unsigned char *pDstY = (unsigned char *)y_dst; + unsigned char *pDstUV = (unsigned char *)uv_dst; + + unsigned int yIndex = 0; + unsigned int uvIndex = 0; + + for (j = 0; j < height; j++) { + for (i = 0; i < width; i++) { + tmp = pSrc[j * width + i]; + + R = (tmp & 0x0000F800) >> 11; + R = R * 8; + G = (tmp & 0x000007E0) >> 5; + G = G * 4; + B = (tmp & 0x0000001F); + B = B * 8; + + Y = ((66 * R) + (129 * G) + (25 * B) + 128); + Y = Y >> 8; + Y += 16; + + pDstY[yIndex++] = (unsigned char)Y; + + if ((j % 2) == 0 && (i % 2) == 0) { + U = ((-38 * R) - (74 * G) + (112 * B) + 128); + U = U >> 8; + U += 128; + V = ((112 * R) - (94 * G) - (18 * B) + 128); + V = V >> 8; + V += 128; + + pDstUV[uvIndex++] = (unsigned char)U; + pDstUV[uvIndex++] = (unsigned char)V; + } + } + } +} + +void csc_ARGB8888_to_YUV420SP( + unsigned char *y_dst, + unsigned char *uv_dst, + unsigned char *rgb_src, + unsigned int width, + unsigned int height) +{ + unsigned int i, j; + unsigned int tmp; + + unsigned int R, G, B; + unsigned int Y, U, V; + + unsigned int offset = width * height; + + unsigned int *pSrc = (unsigned int *)rgb_src; + + unsigned char *pDstY = (unsigned char *)y_dst; + unsigned char *pDstUV = (unsigned char *)uv_dst; + + unsigned int yIndex = 0; + unsigned int uvIndex = 0; + + for (j = 0; j < height; j++) { + for (i = 0; i < width; i++) { + tmp = pSrc[j * width + i]; + + R = (tmp & 0x00FF0000) >> 16; + G = (tmp & 0x0000FF00) >> 8; + B = (tmp & 0x000000FF); + + Y = ((66 * R) + (129 * G) + (25 * B) + 128); + Y = Y >> 8; + Y += 16; + + pDstY[yIndex++] = (unsigned char)Y; + + if ((j % 2) == 0 && (i % 2) == 0) { + U = ((-38 * R) - (74 * G) + (112 * B) + 128); + U = U >> 8; + U += 128; + V = ((112 * R) - (94 * G) - (18 * B) + 128); + V = V >> 8; + V += 128; + + pDstUV[uvIndex++] = (unsigned char)U; + pDstUV[uvIndex++] = (unsigned char)V; + } + } + } +}
\ No newline at end of file diff --git a/exynos/multimedia/utils/csc/exynos4/color_space_convertor.h b/exynos/multimedia/utils/csc/exynos4/color_space_convertor.h new file mode 100644 index 0000000..92c0a6d --- /dev/null +++ b/exynos/multimedia/utils/csc/exynos4/color_space_convertor.h @@ -0,0 +1,414 @@ +/* + * + * Copyright 2010 Samsung Electronics S.LSI Co. LTD + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * @file color_space_convertor.h + * @brief SEC_OMX specific define. It support MFC 5.x tiled. + * NV12T(tiled) layout: + * Each element is not pixel. It is 64x32 pixel block. + * uv pixel block is interleaved as u v u v u v ... + * y1 y2 y7 y8 y9 y10 y15 y16 + * y3 y4 y5 y6 y11 y12 y13 y14 + * y17 y18 y23 y24 y25 y26 y31 y32 + * y19 y20 y21 y22 y27 y28 y29 y30 + * uv1 uv2 uv7 uv8 uv9 uv10 uv15 uv16 + * uv3 uv4 uv5 uv6 uv11 uv12 uv13 uv14 + * YUV420Planar(linear) layout: + * Each element is not pixel. It is 64x32 pixel block. + * y1 y2 y3 y4 y5 y6 y7 y8 + * y9 y10 y11 y12 y13 y14 y15 y16 + * y17 y18 y19 y20 y21 y22 y23 y24 + * y25 y26 y27 y28 y29 y30 y31 y32 + * u1 u2 u3 u4 u5 u6 u7 u8 + * v1 v2 v3 v4 v5 v6 v7 v8 + * YUV420Semiplanar(linear) layout: + * Each element is not pixel. It is 64x32 pixel block. + * uv pixel block is interleaved as u v u v u v ... + * y1 y2 y3 y4 y5 y6 y7 y8 + * y9 y10 y11 y12 y13 y14 y15 y16 + * y17 y18 y19 y20 y21 y22 y23 y24 + * y25 y26 y27 y28 y29 y30 y31 y32 + * uv1 uv2 uv3 uv4 uv5 uv6 uv7 uv8 + * uv9 uv10 uv11 uv12 uv13 uv14 uv15 uv16 + * @author ShinWon Lee (shinwon.lee@samsung.com) + * @version 1.0 + * @history + * 2011.07.01 : Create + * 2011.12.01 : Added csc functions + */ + +#ifndef COLOR_SPACE_CONVERTOR_H_ +#define COLOR_SPACE_CONVERTOR_H_ + +/*--------------------------------------------------------------------------------*/ +/* Format Conversion API */ +/*--------------------------------------------------------------------------------*/ +/* + * Interleaves src1, src2 to dest + * + * @param dest + * Address of interleaved data[out] + * + * @param src1 + * Address of de-interleaved data[in] + * + * @param src2 + * Address of de-interleaved data[in] + * + * @param src_size + * Size of de-interleaved data[in] + */ +/* +void csc_interleave_memcpy( + unsigned char *dest, + unsigned char *src1, + unsigned char *src2, + unsigned int src_size); +*/ +/* C Code */ +/* + * Converts tiled data to linear + * 1. y of nv12t to y of yuv420p + * 2. y of nv12t to y of yuv420s + * + * @param dst + * y address of yuv420[out] + * + * @param src + * y address of nv12t[in] + * + * @param yuv420_width + * real width of yuv420[in] + * it should be even + * + * @param yuv420_height + * real height of yuv420[in] + * it should be even. + * + */ +void csc_tiled_to_linear_y( + unsigned char *y_dst, + unsigned char *y_src, + unsigned int width, + unsigned int height); + +/* + * Converts tiled data to linear + * 1. uv of nv12t to y of yuv420s + * + * @param dst + * uv address of yuv420s[out] + * + * @param src + * uv address of nv12t[in] + * + * @param yuv420_width + * real width of yuv420s[in] + * + * @param yuv420_height + * real height of yuv420s[in] + * + */ +void csc_tiled_to_linear_uv( + unsigned char *uv_dst, + unsigned char *uv_src, + unsigned int width, + unsigned int height); + +/* + * Converts tiled data to linear + * 1. uv of nt12t to uv of yuv420p + * + * @param u_dst + * u address of yuv420p[out] + * + * @param v_dst + * v address of yuv420p[out] + * + * @param uv_src + * uv address of nt12t[in] + * + * @param yuv420_width + * real width of yuv420p[in] + * + * @param yuv420_height + * real height of yuv420p[in] + */ +void csc_tiled_to_linear_uv_deinterleave( + unsigned char *u_dst, + unsigned char *v_dst, + unsigned char *uv_src, + unsigned int width, + unsigned int height); + +/* + * Converts linear data to tiled + * 1. y of yuv420 to y of nv12t + * + * @param dst + * y address of nv12t[out] + * + * @param src + * y address of yuv420[in] + * + * @param yuv420_width + * real width of yuv420[in] + * it should be even + * + * @param yuv420_height + * real height of yuv420[in] + * it should be even. + * + */ +void csc_linear_to_tiled_y( + unsigned char *y_dst, + unsigned char *y_src, + unsigned int width, + unsigned int height); + +/* + * Converts and interleaves linear data to tiled + * 1. uv of nv12t to uv of yuv420 + * + * @param dst + * uv address of nv12t[out] + * + * @param src + * u address of yuv420[in] + * + * @param src + * v address of yuv420[in] + * + * @param yuv420_width + * real width of yuv420[in] + * + * @param yuv420_height + * real height of yuv420[in] + * + */ +void csc_linear_to_tiled_uv( + unsigned char *uv_dst, + unsigned char *u_src, + unsigned char *v_src, + unsigned int width, + unsigned int height); + +/* + * Converts tiled data to linear for mfc 6.x + * 1. Y of NV12T to Y of YUV420P + * 2. Y of NV12T to Y of YUV420S + * + * @param dst + * Y address of YUV420[out] + * + * @param src + * Y address of NV12T[in] + * + * @param yuv420_width + * real width of YUV420[in] + * + * @param yuv420_height + * Y: real height of YUV420[in] + * + */ +void csc_tiled_to_linear_y_neon( + unsigned char *y_dst, + unsigned char *y_src, + unsigned int width, + unsigned int height); + +/* + * Converts tiled data to linear for mfc 6.x + * 1. UV of NV12T to Y of YUV420S + * + * @param u_dst + * UV plane address of YUV420P[out] + * + * @param nv12t_src + * Y or UV plane address of NV12T[in] + * + * @param yuv420_width + * real width of YUV420[in] + * + * @param yuv420_height + * (real height)/2 of YUV420[in] + */ +void csc_tiled_to_linear_uv_neon( + unsigned char *uv_dst, + unsigned char *uv_src, + unsigned int width, + unsigned int height); + +/* + * Converts tiled data to linear for mfc 6.x + * Deinterleave src to u_dst, v_dst + * 1. UV of NV12T to Y of YUV420P + * + * @param u_dst + * U plane address of YUV420P[out] + * + * @param v_dst + * V plane address of YUV420P[out] + * + * @param nv12t_src + * Y or UV plane address of NV12T[in] + * + * @param yuv420_width + * real width of YUV420[in] + * + * @param yuv420_height + * (real height)/2 of YUV420[in] + */ +void csc_tiled_to_linear_uv_deinterleave_neon( + unsigned char *u_dst, + unsigned char *v_dst, + unsigned char *uv_src, + unsigned int width, + unsigned int height); + +/* + * Converts linear data to tiled + * 1. y of yuv420 to y of nv12t + * + * @param dst + * y address of nv12t[out] + * + * @param src + * y address of yuv420[in] + * + * @param yuv420_width + * real width of yuv420[in] + * it should be even + * + * @param yuv420_height + * real height of yuv420[in] + * it should be even. + * + */ +void csc_linear_to_tiled_y_neon( + unsigned char *y_dst, + unsigned char *y_src, + unsigned int width, + unsigned int height); + +/* + * Converts and interleaves linear data to tiled + * 1. uv of nv12t to uv of yuv420 + * + * @param dst + * uv address of nv12t[out] + * + * @param src + * u address of yuv420[in] + * + * @param src + * v address of yuv420[in] + * + * @param yuv420_width + * real width of yuv420[in] + * + * @param yuv420_height + * real height of yuv420[in] + * + */ +void csc_linear_to_tiled_uv_neon( + unsigned char *uv_dst, + unsigned char *u_src, + unsigned char *v_src, + unsigned int width, + unsigned int height); + +/* + * Converts RGB565 to YUV420P + * + * @param y_dst + * Y plane address of YUV420P[out] + * + * @param u_dst + * U plane address of YUV420P[out] + * + * @param v_dst + * V plane address of YUV420P[out] + * + * @param rgb_src + * Address of RGB565[in] + * + * @param width + * Width of RGB565[in] + * + * @param height + * Height of RGB565[in] + */ +void csc_RGB565_to_YUV420P( + unsigned char *y_dst, + unsigned char *u_dst, + unsigned char *v_dst, + unsigned char *rgb_src, + unsigned int width, + unsigned int height); + +/* + * Converts RGB565 to YUV420S + * + * @param y_dst + * Y plane address of YUV420S[out] + * + * @param uv_dst + * UV plane address of YUV420S[out] + * + * @param rgb_src + * Address of RGB565[in] + * + * @param width + * Width of RGB565[in] + * + * @param height + * Height of RGB565[in] + */ +void csc_RGB565_to_YUV420SP( + unsigned char *y_dst, + unsigned char *uv_dst, + unsigned char *rgb_src, + unsigned int width, + unsigned int height); + +/* + * Converts ARGB888 to YUV420SP + * + * @param y_dst + * Y plane address of YUV420SP[out] + * + * @param uv_dst + * UV plane address of YUV420SP[out] + * + * @param rgb_src + * Address of ARGB888[in] + * + * @param width + * Width of ARGB888[in] + * + * @param height + * Height of ARGB888[in] + */ +void csc_ARGB8888_to_YUV420SP( + unsigned char *y_dst, + unsigned char *uv_dst, + unsigned char *rgb_src, + unsigned int width, + unsigned int height); + +#endif /*COLOR_SPACE_CONVERTOR_H_*/ diff --git a/exynos/multimedia/utils/csc/exynos4/csc_fimc.cpp b/exynos/multimedia/utils/csc/exynos4/csc_fimc.cpp new file mode 100644 index 0000000..7c458b2 --- /dev/null +++ b/exynos/multimedia/utils/csc/exynos4/csc_fimc.cpp @@ -0,0 +1,134 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * @file csc_fimc.cpp + * + * @brief csc_fimc use fimc1 to color space convertion + * + * @author ShinWon Lee (shinwon.lee@samsung.com) + * + * @version 1.0 + * + * @history + * 2011.11.01 : Create + */ + +#include <utils/Log.h> +#include <dlfcn.h> + +#include "SEC_OMX_Def.h" +#include "csc_fimc.h" +#include "HardwareConverter.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * create and open fimc handle + * + * @return + * fimc handle + */ +void *csc_fimc_open() +{ + HardwareConverter *hw_converter = NULL; + + hw_converter = new HardwareConverter; + if (hw_converter->bHWconvert_flag == 0) { + delete hw_converter; + hw_converter = NULL; + LOGE("%s LINE = %d HardwareConverter failed", __func__, __LINE__); + } + + return (void *)hw_converter; +} + +/* + * close and destroy fimc handle + * + * @param handle + * fimc handle[in] + * + * @return + * pass or fail + */ +CSC_FIMC_ERROR_CODE csc_fimc_close(void *handle) +{ + HardwareConverter *hw_converter = (HardwareConverter *)handle; + + if (hw_converter != NULL) + delete hw_converter; + + return CSC_FIMC_RET_OK; +} + +/* + * convert color space nv12t to omxformat + * + * @param handle + * fimc handle[in] + * + * @param dst_addr + * y,u,v address of dst_addr[out] + * + * @param src_addr + * y,uv address of src_addr.Format is nv12t[in] + * + * @param width + * width of dst image[in] + * + * @param height + * height of dst image[in] + * + * @param omxformat + * omxformat of dst image[in] + * + * @return + * pass or fail + */ +CSC_FIMC_ERROR_CODE csc_fimc_convert_nv12t( + void *handle, + void **dst_addr, + void **src_addr, + unsigned int width, + unsigned int height, + OMX_COLOR_FORMATTYPE omxformat) +{ + CSC_FIMC_ERROR_CODE ret = CSC_FIMC_RET_OK; + HardwareConverter *hw_converter = (HardwareConverter *)handle; + + if (hw_converter == NULL) { + ret = CSC_FIMC_RET_FAIL; + goto EXIT; + } + + hw_converter->convert( + (void *)src_addr, (void *)dst_addr, + (OMX_COLOR_FORMATTYPE)OMX_SEC_COLOR_FormatNV12TPhysicalAddress, + width, height, omxformat); + + ret = CSC_FIMC_RET_OK; + +EXIT: + + return ret; +} + +#ifdef __cplusplus +} +#endif diff --git a/exynos/multimedia/utils/csc/exynos4/csc_fimc.h b/exynos/multimedia/utils/csc/exynos4/csc_fimc.h new file mode 100644 index 0000000..3ae24ac --- /dev/null +++ b/exynos/multimedia/utils/csc/exynos4/csc_fimc.h @@ -0,0 +1,106 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * @file csc_fimc.h + * + * @brief csc_fimc use fimc1 to color space convertion + * + * @author ShinWon Lee (shinwon.lee@samsung.com) + * + * @version 1.0 + * + * @history + * 2011.11.01 : Create + */ + +#ifndef CSC_FIMC_H + +#define CSC_FIMC_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include <OMX_Video.h> + +/*--------------------------------------------------------------------------------*/ +/* Structure and Type */ +/*--------------------------------------------------------------------------------*/ +typedef enum { + CSC_FIMC_RET_OK = 0, + CSC_FIMC_RET_FAIL = -1 +} CSC_FIMC_ERROR_CODE; + +/*--------------------------------------------------------------------------------*/ +/* CSC FIMC APIs */ +/*--------------------------------------------------------------------------------*/ +/* + * create and open fimc handle + * + * @return + * fimc handle + */ +void *csc_fimc_open(); + +/* + * close and destroy fimc handle + * + * @param handle + * fimc handle[in] + * + * @return + * error code + */ +CSC_FIMC_ERROR_CODE csc_fimc_close(void *handle); + +/* + * convert color space nv12t to omxformat + * + * @param handle + * fimc handle[in] + * + * @param dst_addr + * y,u,v address of dst_addr[out] + * + * @param src_addr + * y,uv address of src_addr.Format is nv12t[in] + * + * @param width + * width of dst image[in] + * + * @param height + * height of dst image[in] + * + * @param omxformat + * omxformat of dst image[in] + * + * @return + * error code + */ +CSC_FIMC_ERROR_CODE csc_fimc_convert_nv12t( + void *handle, + void **dst_addr, + void **src_addr, + unsigned int width, + unsigned int height, + OMX_COLOR_FORMATTYPE omxformat); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/exynos/multimedia/utils/csc/exynos4/csc_interleave_memcpy_neon.s b/exynos/multimedia/utils/csc/exynos4/csc_interleave_memcpy_neon.s new file mode 100644 index 0000000..3d2b41f --- /dev/null +++ b/exynos/multimedia/utils/csc/exynos4/csc_interleave_memcpy_neon.s @@ -0,0 +1,120 @@ +/* + * + * Copyright 2012 Samsung Electronics S.LSI Co. LTD + * + * Licensed under the Apache License, Version 2.0 (the "License") + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * @file csc_linear_to_tiled_crop_neon.s + * @brief SEC_OMX specific define + * @author ShinWon Lee (shinwon.lee@samsung.com) + * @version 1.0 + * @history + * 2012.01.04 : Create + */ + +/* + * Interleave src1, src2 to dst + * + * @param dest + * dst address[out] + * + * @param src1 + * src1 address[in] + * + * @param src2 + * src2 address[in] + * + * @param src_size + * src_size or src1 + */ + + .arch armv7-a + .text + .global csc_interleave_memcpy_neon + .type csc_interleave_memcpy_neon, %function +csc_interleave_memcpy_neon: + .fnstart + + @r0 dest + @r1 src1 + @r2 src2 + @r3 src_size + @r4 + @r5 + @r6 + @r7 + @r8 temp1 + @r9 temp2 + @r10 dest_addr + @r11 src1_addr + @r12 src2_addr + @r14 i + + stmfd sp!, {r8-r12,r14} @ backup registers + + mov r10, r0 + mov r11, r1 + mov r12, r2 + mov r14, r3 + + cmp r14, #128 + blt LESS_THAN_128 + +LOOP_128: + vld1.8 {q0}, [r11]! + vld1.8 {q2}, [r11]! + vld1.8 {q4}, [r11]! + vld1.8 {q6}, [r11]! + vld1.8 {q8}, [r11]! + vld1.8 {q10}, [r11]! + vld1.8 {q12}, [r11]! + vld1.8 {q14}, [r11]! + vld1.8 {q1}, [r12]! + vld1.8 {q3}, [r12]! + vld1.8 {q5}, [r12]! + vld1.8 {q7}, [r12]! + vld1.8 {q9}, [r12]! + vld1.8 {q11}, [r12]! + vld1.8 {q13}, [r12]! + vld1.8 {q15}, [r12]! + + vst2.8 {q0, q1}, [r10]! + vst2.8 {q2, q3}, [r10]! + vst2.8 {q4, q5}, [r10]! + vst2.8 {q6, q7}, [r10]! + vst2.8 {q8, q9}, [r10]! + vst2.8 {q10, q11}, [r10]! + vst2.8 {q12, q13}, [r10]! + vst2.8 {q14, q15}, [r10]! + + sub r14, #128 + cmp r14, #128 + bgt LOOP_128 + +LESS_THAN_128: + cmp r14, #0 + beq RESTORE_REG + +LOOP_1: + ldrb r8, [r11], #1 + ldrb r9, [r12], #1 + strb r8, [r10], #1 + strb r9, [r10], #1 + subs r14, #1 + bne LOOP_1 + +RESTORE_REG: + ldmfd sp!, {r8-r12,r15} @ restore registers + .fnend diff --git a/exynos/multimedia/utils/csc/exynos4/csc_linear_to_tiled_crop_neon.s b/exynos/multimedia/utils/csc/exynos4/csc_linear_to_tiled_crop_neon.s new file mode 100644 index 0000000..745d495 --- /dev/null +++ b/exynos/multimedia/utils/csc/exynos4/csc_linear_to_tiled_crop_neon.s @@ -0,0 +1,492 @@ +/* + * + * Copyright 2010 Samsung Electronics S.LSI Co. LTD + * + * Licensed under the Apache License, Version 2.0 (the "License") + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * @file csc_linear_to_tiled_crop_neon.s + * @brief SEC_OMX specific define + * @author ShinWon Lee (shinwon.lee@samsung.com) + * @version 1.0 + * @history + * 2011.8.04 : Create + */ + +/* + * Converts linear data to tiled + * Crops left, top, right, buttom + * 1. Y of YUV420P to Y of NV12T + * 2. Y of YUV420S to Y of NV12T + * 3. UV of YUV420S to UV of NV12T + * + * @param nv12t_dest + * Y or UV plane address of NV12T[out] + * + * @param yuv420_src + * Y or UV plane address of YUV420P(S)[in] + * + * @param yuv420_width + * Width of YUV420[in] + * + * @param yuv420_height + * Y: Height of YUV420, UV: Height/2 of YUV420[in] + * + * @param left + * Crop size of left. It should be even. + * + * @param top + * Crop size of top. It should be even. + * + * @param right + * Crop size of right. It should be even. + * + * @param buttom + * Crop size of buttom. It should be even. + */ + + .arch armv7-a + .text + .global csc_linear_to_tiled_crop_neon + .type csc_linear_to_tiled_crop_neon, %function +csc_linear_to_tiled_crop_neon: + .fnstart + + @r0 tiled_dest + @r1 linear_src + @r2 yuv420_width + @r3 yuv420_height + @r4 j + @r5 i + @r6 nn(tiled_addr) + @r7 mm(linear_addr) + @r8 aligned_x_size + @r9 aligned_y_size + @r10 temp1 + @r11 temp2 + @r12 temp3 + @r14 temp4 + + stmfd sp!, {r4-r12,r14} @ backup registers + + ldr r11, [sp, #44] @ top + ldr r14, [sp, #52] @ buttom + ldr r10, [sp, #40] @ left + ldr r12, [sp, #48] @ right + + sub r9, r3, r11 @ aligned_y_size = ((yuv420_height-top-buttom)>>5)<<5 + sub r9, r9, r14 + bic r9, r9, #0x1F + + sub r8, r2, r10 @ aligned_x_size = ((yuv420_width-left-right)>>6)<<6 + sub r8, r8, r12 + bic r8, r8, #0x3F + + mov r5, #0 @ i = 0 +LOOP_ALIGNED_Y_SIZE: + + mov r4, #0 @ j = 0 +LOOP_ALIGNED_X_SIZE: + + bl GET_TILED_OFFSET + + ldr r10, [sp, #44] @ r10 = top + ldr r14, [sp, #40] @ r14 = left + add r10, r5, r10 @ temp1 = linear_x_size*(i+top) + mul r10, r2, r10 + add r7, r1, r4 @ linear_addr = linear_src+j + add r7, r7, r10 @ linear_addr = linear_addr+temp1 + add r7, r7, r14 @ linear_addr = linear_addr+left + sub r10, r2, #32 + + pld [r7, r2] + vld1.8 {q0, q1}, [r7]! @ load {linear_src, 64} + pld [r7, r2] + vld1.8 {q2, q3}, [r7], r10 + pld [r7, r2] + vld1.8 {q4, q5}, [r7]! @ load {linear_src+linear_x_size*1, 64} + pld [r7, r2] + vld1.8 {q6, q7}, [r7], r10 + pld [r7, r2] + vld1.8 {q8, q9}, [r7]! @ load {linear_src+linear_x_size*2, 64} + pld [r7, r2] + vld1.8 {q10, q11}, [r7], r10 + pld [r7, r2] + vld1.8 {q12, q13}, [r7]! @ load {linear_src+linear_x_size*3, 64} + pld [r7, r2] + vld1.8 {q14, q15}, [r7], r10 + add r6, r0, r6 @ tiled_addr = tiled_dest+tiled_addr + vst1.8 {q0, q1}, [r6]! @ store {tiled_addr} + vst1.8 {q2, q3}, [r6]! + vst1.8 {q4, q5}, [r6]! @ store {tiled_addr+64*1} + vst1.8 {q6, q7}, [r6]! + vst1.8 {q8, q9}, [r6]! @ store {tiled_addr+64*2} + vst1.8 {q10, q11}, [r6]! + vst1.8 {q12, q13}, [r6]! @ store {tiled_addr+64*3} + vst1.8 {q14, q15}, [r6]! + + pld [r7, r2] + vld1.8 {q0, q1}, [r7]! @ load {linear_src+linear_x_size*4, 64} + pld [r7, r2] + vld1.8 {q2, q3}, [r7], r10 + pld [r7, r2] + vld1.8 {q4, q5}, [r7]! @ load {linear_src+linear_x_size*5, 64} + pld [r7, r2] + vld1.8 {q6, q7}, [r7], r10 + pld [r7, r2] + vld1.8 {q8, q9}, [r7]! @ load {linear_src+linear_x_size*6, 64} + pld [r7, r2] + vld1.8 {q10, q11}, [r7], r10 + pld [r7, r2] + vld1.8 {q12, q13}, [r7]! @ load {linear_src+linear_x_size*7, 64} + pld [r7, r2] + vld1.8 {q14, q15}, [r7], r10 + vst1.8 {q0, q1}, [r6]! @ store {tiled_addr+64*4} + vst1.8 {q2, q3}, [r6]! + vst1.8 {q4, q5}, [r6]! @ store {tiled_addr+64*5} + vst1.8 {q6, q7}, [r6]! + vst1.8 {q8, q9}, [r6]! @ store {tiled_addr+64*6} + vst1.8 {q10, q11}, [r6]! + vst1.8 {q12, q13}, [r6]! @ store {tiled_addr+64*7} + vst1.8 {q14, q15}, [r6]! + + pld [r7, r2] + vld1.8 {q0, q1}, [r7]! @ load {linear_src+linear_x_size*8, 64} + pld [r7, r2] + vld1.8 {q2, q3}, [r7], r10 + pld [r7, r2] + vld1.8 {q4, q5}, [r7]! @ load {linear_src+linear_x_size*9, 64} + pld [r7, r2] + vld1.8 {q6, q7}, [r7], r10 + pld [r7, r2] + vld1.8 {q8, q9}, [r7]! @ load {linear_src+linear_x_size*10, 64} + pld [r7, r2] + vld1.8 {q10, q11}, [r7], r10 + pld [r7, r2] + vld1.8 {q12, q13}, [r7]! @ load {linear_src+linear_x_size*11, 64} + pld [r7, r2] + vld1.8 {q14, q15}, [r7], r10 + vst1.8 {q0, q1}, [r6]! @ store {tiled_addr+64*8} + vst1.8 {q2, q3}, [r6]! + vst1.8 {q4, q5}, [r6]! @ store {tiled_addr+64*9} + vst1.8 {q6, q7}, [r6]! + vst1.8 {q8, q9}, [r6]! @ store {tiled_addr+64*10} + vst1.8 {q10, q11}, [r6]! + vst1.8 {q12, q13}, [r6]! @ store {tiled_addr+64*11} + vst1.8 {q14, q15}, [r6]! + + pld [r7, r2] + vld1.8 {q0, q1}, [r7]! @ load {linear_src+linear_x_size*12, 64} + pld [r7, r2] + vld1.8 {q2, q3}, [r7], r10 + pld [r7, r2] + vld1.8 {q4, q5}, [r7]! @ load {linear_src+linear_x_size*13, 64} + pld [r7, r2] + vld1.8 {q6, q7}, [r7], r10 + pld [r7, r2] + vld1.8 {q8, q9}, [r7]! @ load {linear_src+linear_x_size*14, 64} + pld [r7, r2] + vld1.8 {q10, q11}, [r7], r10 + pld [r7, r2] + vld1.8 {q12, q13}, [r7]! @ load {linear_src+linear_x_size*15, 64} + pld [r7, r2] + vld1.8 {q14, q15}, [r7], r10 + vst1.8 {q0, q1}, [r6]! @ store {tiled_addr+64*12} + vst1.8 {q2, q3}, [r6]! + vst1.8 {q4, q5}, [r6]! @ store {tiled_addr+64*13} + vst1.8 {q6, q7}, [r6]! + vst1.8 {q8, q9}, [r6]! @ store {tiled_addr+64*14} + vst1.8 {q10, q11}, [r6]! + vst1.8 {q12, q13}, [r6]! @ store {tiled_addr+64*15} + vst1.8 {q14, q15}, [r6]! + + pld [r7, r2] + vld1.8 {q0, q1}, [r7]! @ load {linear_src+linear_x_size*16, 64} + pld [r7, r2] + vld1.8 {q2, q3}, [r7], r10 + pld [r7, r2] + vld1.8 {q4, q5}, [r7]! @ load {linear_src+linear_x_size*17, 64} + pld [r7, r2] + vld1.8 {q6, q7}, [r7], r10 + pld [r7, r2] + vld1.8 {q8, q9}, [r7]! @ load {linear_src+linear_x_size*18, 64} + pld [r7, r2] + vld1.8 {q10, q11}, [r7], r10 + pld [r7, r2] + vld1.8 {q12, q13}, [r7]! @ load {linear_src+linear_x_size*19, 64} + pld [r7, r2] + vld1.8 {q14, q15}, [r7], r10 + vst1.8 {q0, q1}, [r6]! @ store {tiled_addr+64*16} + vst1.8 {q2, q3}, [r6]! + vst1.8 {q4, q5}, [r6]! @ store {tiled_addr+64*17} + vst1.8 {q6, q7}, [r6]! + vst1.8 {q8, q9}, [r6]! @ store {tiled_addr+64*18} + vst1.8 {q10, q11}, [r6]! + vst1.8 {q12, q13}, [r6]! @ store {tiled_addr+64*19} + vst1.8 {q14, q15}, [r6]! + + pld [r7, r2] + vld1.8 {q0, q1}, [r7]! @ load {linear_src+linear_x_size*20, 64} + pld [r7, r2] + vld1.8 {q2, q3}, [r7], r10 + pld [r7, r2] + vld1.8 {q4, q5}, [r7]! @ load {linear_src+linear_x_size*21, 64} + pld [r7, r2] + vld1.8 {q6, q7}, [r7], r10 + pld [r7, r2] + vld1.8 {q8, q9}, [r7]! @ load {linear_src+linear_x_size*22, 64} + pld [r7, r2] + vld1.8 {q10, q11}, [r7], r10 + pld [r7, r2] + vld1.8 {q12, q13}, [r7]! @ load {linear_src+linear_x_size*23, 64} + pld [r7, r2] + vld1.8 {q14, q15}, [r7], r10 + vst1.8 {q0, q1}, [r6]! @ store {tiled_addr+64*20} + vst1.8 {q2, q3}, [r6]! + vst1.8 {q4, q5}, [r6]! @ store {tiled_addr+64*21} + vst1.8 {q6, q7}, [r6]! + vst1.8 {q8, q9}, [r6]! @ store {tiled_addr+64*22} + vst1.8 {q10, q11}, [r6]! + vst1.8 {q12, q13}, [r6]! @ store {tiled_addr+64*23} + vst1.8 {q14, q15}, [r6]! + + pld [r7, r2] + vld1.8 {q0, q1}, [r7]! @ load {linear_src+linear_x_size*24, 64} + pld [r7, r2] + vld1.8 {q2, q3}, [r7], r10 + pld [r7, r2] + vld1.8 {q4, q5}, [r7]! @ load {linear_src+linear_x_size*25, 64} + pld [r7, r2] + vld1.8 {q6, q7}, [r7], r10 + pld [r7, r2] + vld1.8 {q8, q9}, [r7]! @ load {linear_src+linear_x_size*26, 64} + pld [r7, r2] + vld1.8 {q10, q11}, [r7], r10 + pld [r7, r2] + vld1.8 {q12, q13}, [r7]! @ load {linear_src+linear_x_size*27, 64} + pld [r7, r2] + vld1.8 {q14, q15}, [r7], r10 + vst1.8 {q0, q1}, [r6]! @ store {tiled_addr+64*24} + vst1.8 {q2, q3}, [r6]! + vst1.8 {q4, q5}, [r6]! @ store {tiled_addr+64*25} + vst1.8 {q6, q7}, [r6]! + vst1.8 {q8, q9}, [r6]! @ store {tiled_addr+64*26} + vst1.8 {q10, q11}, [r6]! + vst1.8 {q12, q13}, [r6]! @ store {tiled_addr+64*27} + vst1.8 {q14, q15}, [r6]! + + pld [r7, r2] + vld1.8 {q0, q1}, [r7]! @ load {linear_src+linear_x_size*28, 64} + pld [r7, r2] + vld1.8 {q2, q3}, [r7], r10 + pld [r7, r2] + vld1.8 {q4, q5}, [r7]! @ load {linear_src+linear_x_size*29, 64} + pld [r7, r2] + vld1.8 {q6, q7}, [r7], r10 + pld [r7, r2] + vld1.8 {q8, q9}, [r7]! @ load {linear_src+linear_x_size*30, 64} + pld [r7, r2] + vld1.8 {q10, q11}, [r7], r10 + vld1.8 {q12, q13}, [r7]! @ load {linear_src+linear_x_size*31, 64} + vld1.8 {q14, q15}, [r7], r10 + vst1.8 {q0, q1}, [r6]! @ store {tiled_addr+64*28} + vst1.8 {q2, q3}, [r6]! + vst1.8 {q4, q5}, [r6]! @ store {tiled_addr+64*29} + vst1.8 {q6, q7}, [r6]! + vst1.8 {q8, q9}, [r6]! @ store {tiled_addr+64*30} + vst1.8 {q10, q11}, [r6]! + vst1.8 {q12, q13}, [r6]! @ store {tiled_addr+64*31} + vst1.8 {q14, q15}, [r6]! + + add r4, r4, #64 @ j = j+64 + cmp r4, r8 @ j<aligned_x_size + blt LOOP_ALIGNED_X_SIZE + + add r5, r5, #32 @ i = i+32 + cmp r5, r9 @ i<aligned_y_size + blt LOOP_ALIGNED_Y_SIZE + + ldr r10, [sp, #44] @ r10 = top + ldr r11, [sp, #52] @ r11 = buttom + sub r10, r3, r10 + sub r10, r10, r11 + cmp r5, r10 @ i == (yuv420_height-top-buttom) + beq LOOP_LINEAR_Y_SIZE_2_START + +LOOP_LINEAR_Y_SIZE_1: + + mov r4, #0 @ j = 0 +LOOP_ALIGNED_X_SIZE_1: + + bl GET_TILED_OFFSET + + ldr r10, [sp, #44] @ r10 = top + ldr r14, [sp, #40] @ r14 = left + add r10, r5, r10 @ temp1 = yuv420_width*(i+top) + mul r10, r2, r10 + add r7, r1, r4 @ linear_addr = linear_src+j + add r7, r7, r10 @ linear_addr = linear_addr+temp1 + add r7, r7, r14 @ linear_addr = linear_addr+left + sub r10, r2, #32 @ temp1 = yuv420_width-32 + + pld [r7, r2] + vld1.8 {q0, q1}, [r7]! @ load {linear_src, 64} + pld [r7, r2] + vld1.8 {q2, q3}, [r7], r10 + vld1.8 {q4, q5}, [r7]! @ load {linear_src+linear_x_size*1, 64} + vld1.8 {q6, q7}, [r7] + add r6, r0, r6 @ tiled_addr = tiled_dest+tiled_addr + and r10, r5, #0x1F @ temp1 = i&0x1F + mov r10, r10, lsl #6 @ temp1 = 64*temp1 + add r6, r6, r10 @ tiled_addr = tiled_addr+temp1 + vst1.8 {q0, q1}, [r6]! @ store {tiled_addr} + vst1.8 {q2, q3}, [r6]! + vst1.8 {q4, q5}, [r6]! @ store {tiled_addr+64*1} + vst1.8 {q6, q7}, [r6]! + + add r4, r4, #64 @ j = j+64 + cmp r4, r8 @ j<aligned_x_size + blt LOOP_ALIGNED_X_SIZE_1 + + add r5, r5, #2 @ i = i+2 + ldr r10, [sp, #44] @ r10 = top + ldr r14, [sp, #52] @ r14 = buttom + sub r10, r3, r10 + sub r10, r10, r14 + cmp r5, r10 @ i<yuv420_height-top-buttom + blt LOOP_LINEAR_Y_SIZE_1 + +LOOP_LINEAR_Y_SIZE_2_START: + ldr r10, [sp, #40] @ r10 = left + ldr r11, [sp, #48] @ r11 = right + sub r10, r2, r10 + sub r10, r10, r11 + cmp r8, r10 @ aligned_x_size == (yuv420_width-left-right) + beq RESTORE_REG + + mov r5, #0 @ i = 0 +LOOP_LINEAR_Y_SIZE_2: + + mov r4, r8 @ j = aligned_x_size +LOOP_LINEAR_X_SIZE_2: + + bl GET_TILED_OFFSET + + ldr r10, [sp, #44] @ r14 = top + ldr r14, [sp, #40] @ r10 = left + add r10, r5, r10 + mul r10, r2, r10 @ temp1 = linear_x_size*(i+top) + add r7, r1, r4 @ linear_addr = linear_src+j + add r7, r7, r10 @ linear_addr = linear_addr+temp1 + add r7, r7, r14 @ linear_addr = linear_addr+left + + add r6, r0, r6 @ tiled_addr = tiled_dest+tiled_addr + and r11, r5, #0x1F @ temp2 = i&0x1F + mov r11, r11, lsl #6 @ temp2 = 64*temp2 + add r6, r6, r11 @ tiled_addr = tiled_addr+temp2 + and r11, r4, #0x3F @ temp2 = j&0x3F + add r6, r6, r11 @ tiled_addr = tiled_addr+temp2 + + ldrh r10, [r7], r2 + ldrh r11, [r7] + strh r10, [r6], #64 + strh r11, [r6] + + ldr r12, [sp, #40] @ r12 = left + ldr r14, [sp, #48] @ r14 = right + add r4, r4, #2 @ j = j+2 + sub r12, r2, r12 + sub r12, r12, r14 + cmp r4, r12 @ j<(yuv420_width-left-right) + blt LOOP_LINEAR_X_SIZE_2 + + ldr r12, [sp, #44] @ r12 = top + ldr r14, [sp, #52] @ r14 = buttom + add r5, r5, #2 @ i = i+2 + sub r12, r3, r12 + sub r12, r12, r14 + cmp r5, r12 @ i<(yuv420_height-top-buttom) + blt LOOP_LINEAR_Y_SIZE_2 + +RESTORE_REG: + ldmfd sp!, {r4-r12,r15} @ restore registers + +GET_TILED_OFFSET: + + mov r11, r5, asr #5 @ temp2 = i>>5 + mov r10, r4, asr #6 @ temp1 = j>>6 + + and r12, r11, #0x1 @ if (temp2 & 0x1) + cmp r12, #0x1 + bne GET_TILED_OFFSET_EVEN_FORMULA_1 + +GET_TILED_OFFSET_ODD_FORMULA: + sub r6, r11, #1 @ tiled_addr = temp2-1 + + ldr r7, [sp, #40] @ left + add r12, r2, #127 @ temp3 = linear_x_size+127 + sub r12, r12, r7 + ldr r7, [sp, #48] @ right + sub r12, r12, r7 + bic r12, r12, #0x7F @ temp3 = (temp3 >>7)<<7 + mov r12, r12, asr #6 @ temp3 = temp3>>6 + mul r6, r6, r12 @ tiled_addr = tiled_addr*temp3 + add r6, r6, r10 @ tiled_addr = tiled_addr+temp1 + add r6, r6, #2 @ tiled_addr = tiled_addr+2 + bic r12, r10, #0x3 @ temp3 = (temp1>>2)<<2 + add r6, r6, r12 @ tiled_addr = tiled_addr+temp3 + mov r6, r6, lsl #11 @ tiled_addr = tiled_addr<<11 + b GET_TILED_OFFSET_RETURN + +GET_TILED_OFFSET_EVEN_FORMULA_1: + ldr r7, [sp, #44] @ top + add r12, r3, #31 @ temp3 = linear_y_size+31 + sub r12, r12, r7 + ldr r7, [sp, #52] @ buttom + sub r12, r12, r7 + bic r12, r12, #0x1F @ temp3 = (temp3>>5)<<5 + sub r12, r12, #32 @ temp3 = temp3 - 32 + cmp r5, r12 @ if (i<(temp3-32)) { + bge GET_TILED_OFFSET_EVEN_FORMULA_2 + add r12, r10, #2 @ temp3 = temp1+2 + bic r12, r12, #3 @ temp3 = (temp3>>2)<<2 + add r6, r10, r12 @ tiled_addr = temp1+temp3 + ldr r7, [sp, #40] @ left + add r12, r2, #127 @ temp3 = linear_x_size+127 + sub r12, r12, r7 + ldr r7, [sp, #48] @ right + sub r12, r12, r7 + bic r12, r12, #0x7F @ temp3 = (temp3>>7)<<7 + mov r12, r12, asr #6 @ temp3 = temp3>>6 + mul r11, r11, r12 @ tiled_y_index = tiled_y_index*temp3 + add r6, r6, r11 @ tiled_addr = tiled_addr+tiled_y_index + mov r6, r6, lsl #11 @ + b GET_TILED_OFFSET_RETURN + +GET_TILED_OFFSET_EVEN_FORMULA_2: + ldr r7, [sp, #40] @ left + add r12, r2, #127 @ temp3 = linear_x_size+127 + sub r12, r12, r7 + ldr r7, [sp, #48] @ right + sub r12, r12, r7 + bic r12, r12, #0x7F @ temp3 = (temp3>>7)<<7 + mov r12, r12, asr #6 @ temp3 = temp3>>6 + mul r6, r11, r12 @ tiled_addr = temp2*temp3 + add r6, r6, r10 @ tiled_addr = tiled_addr+temp3 + mov r6, r6, lsl #11 @ tiled_addr = tiled_addr<<11@ + +GET_TILED_OFFSET_RETURN: + mov pc, lr + + .fnend diff --git a/exynos/multimedia/utils/csc/exynos4/csc_linear_to_tiled_interleave_crop_neon.s b/exynos/multimedia/utils/csc/exynos4/csc_linear_to_tiled_interleave_crop_neon.s new file mode 100644 index 0000000..6a054fa --- /dev/null +++ b/exynos/multimedia/utils/csc/exynos4/csc_linear_to_tiled_interleave_crop_neon.s @@ -0,0 +1,563 @@ +/* + * + * Copyright 2010 Samsung Electronics S.LSI Co. LTD + * + * Licensed under the Apache License, Version 2.0 (the "License") + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * @file csc_linear_to_tiled_interleave_crop_neon.s + * @brief SEC_OMX specific define + * @author ShinWon Lee (shinwon.lee@samsung.com) + * @version 1.0 + * @history + * 2011.8.04 : Create + */ + +/* + * Converts tiled data to linear + * Crops left, top, right, buttom + * 1. Y of NV12T to Y of YUV420P + * 2. Y of NV12T to Y of YUV420S + * 3. UV of NV12T to UV of YUV420S + * + * @param yuv420_dest + * Y or UV plane address of YUV420[out] + * + * @param nv12t_src + * Y or UV plane address of NV12T[in] + * + * @param yuv420_width + * Width of YUV420[in] + * + * @param yuv420_height + * Y: Height of YUV420, UV: Height/2 of YUV420[in] + * + * @param left + * Crop size of left. It should be even. + * + * @param top + * Crop size of top. It should be even. + * + * @param right + * Crop size of right. It should be even. + * + * @param buttom + * Crop size of buttom. It should be even. + */ + + .arch armv7-a + .text + .global csc_linear_to_tiled_interleave_crop_neon + .type csc_linear_to_tiled_interleave_crop_neon, %function +csc_linear_to_tiled_interleave_crop_neon: + .fnstart + + @r0 tiled_dest + @r1 linear_src_u + @r2 linear_src_v + @r3 yuv420_width + @r4 yuv420_height + @r5 j + @r6 i + @r7 tiled_addr + @r8 linear_addr + @r9 aligned_x_size + @r10 aligned_y_size + @r11 temp1 + @r12 temp2 + @r14 temp3 + + stmfd sp!, {r4-r12,r14} @ backup registers + + ldr r4, [sp, #40] @ load linear_y_size to r4 + + ldr r10, [sp, #48] @ r10 = top + ldr r14, [sp, #56] @ r14 = buttom + ldr r11, [sp, #44] @ r11 = left + ldr r12, [sp, #52] @ r12 = right + + sub r10, r4, r10 @ aligned_y_size = ((yuv420_height-top-buttom)>>5)<<5 + sub r10, r10, r14 + bic r10, r10, #0x1F + sub r11, r3, r11 @ aligned_x_size = ((yuv420_width-left-right)>>6)<<6 + sub r11, r11, r12 + bic r9, r11, #0x3F + + mov r6, #0 @ i = 0 +LOOP_ALIGNED_Y_SIZE: + + mov r5, #0 @ j = 0 +LOOP_ALIGNED_X_SIZE: + + bl GET_TILED_OFFSET + + ldr r12, [sp, #48] @ r12 = top + ldr r8, [sp, #44] @ r8 = left + + mov r11, r3, asr #1 @ temp1 = (yuv420_width/2)*(i+top) + add r12, r6, r12 + mul r11, r11, r12 + add r11, r11, r5, asr #1 @ temp1 = temp1+j/2 + add r11, r11, r8, asr #1 @ temp1 = temp1+left/2 + + mov r12, r3, asr #1 @ temp2 = yuv420_width/2 + sub r12, r12, #16 @ temp2 = yuv420_width-16 + + add r8, r1, r11 @ linear_addr = linear_src_u+temp1 + add r11, r2, r11 @ temp1 = linear_src_v+temp1 + add r7, r0, r7 @ tiled_addr = tiled_dest+tiled_addr + + pld [r8, r3] + vld1.8 {q0}, [r8]! @ load {linear_src_u, 32} + vld1.8 {q2}, [r8], r12 + pld [r8, r3] + vld1.8 {q4}, [r8]! @ load {linear_src_u+(linear_x_size/2)*1, 32} + vld1.8 {q6}, [r8], r12 + pld [r11] + vld1.8 {q8}, [r8]! @ load {linear_src_u+(linear_x_size/2)*2, 32} + vld1.8 {q10}, [r8], r12 + pld [r11, r3, asr #1] + vld1.8 {q12}, [r8]! @ load {linear_src_u+(linear_x_size/2)*3, 32} + vld1.8 {q14}, [r8], r12 + pld [r11, r3] + vld1.8 {q1}, [r11]! @ load {linear_src_v, 32} + vld1.8 {q3}, [r11], r12 + pld [r11, r3] + vld1.8 {q5}, [r11]! @ load {linear_src_v+(linear_x_size/2)*1, 32} + vld1.8 {q7}, [r11], r12 + pld [r8] + vld1.8 {q9}, [r11]! @ load {linear_src_v+(linear_x_size/2)*2, 32} + vld1.8 {q11}, [r11], r12 + pld [r8, r3, asr #1] + vld1.8 {q13}, [r11]! @ load {linear_src_v+(linear_x_size/2)*3, 32} + vld1.8 {q15}, [r11], r12 + vst2.8 {q0, q1}, [r7]! @ store {tiled_addr} + vst2.8 {q2, q3}, [r7]! + vst2.8 {q4, q5}, [r7]! @ store {tiled_addr+64*1} + vst2.8 {q6, q7}, [r7]! + vst2.8 {q8, q9}, [r7]! @ store {tiled_addr+64*2} + vst2.8 {q10, q11}, [r7]! + vst2.8 {q12, q13}, [r7]! @ store {tiled_addr+64*3} + vst2.8 {q14, q15}, [r7]! + + pld [r8, r3] + vld1.8 {q0}, [r8]! @ load {linear_src_u+(linear_x_size/2)*4, 32} + vld1.8 {q2}, [r8], r12 + pld [r8, r3] + vld1.8 {q4}, [r8]! @ load {linear_src_u+(linear_x_size/2)*5, 32} + vld1.8 {q6}, [r8], r12 + pld [r11] + vld1.8 {q8}, [r8]! @ load {linear_src_u+(linear_x_size/2)*6, 32} + vld1.8 {q10}, [r8], r12 + pld [r11, r3, asr #1] + vld1.8 {q12}, [r8]! @ load {linear_src_u+(linear_x_size/2)*7, 32} + vld1.8 {q14}, [r8], r12 + pld [r11, r3] + vld1.8 {q1}, [r11]! @ load {linear_src_v+(linear_x_size/2)*4, 32} + vld1.8 {q3}, [r11], r12 + pld [r11, r3] + vld1.8 {q5}, [r11]! @ load {linear_src_v+(linear_x_size/2)*5, 32} + vld1.8 {q7}, [r11], r12 + pld [r8] + vld1.8 {q9}, [r11]! @ load {linear_src_v+(linear_x_size/2)*6, 32} + vld1.8 {q11}, [r11], r12 + pld [r8, r3, asr #1] + vld1.8 {q13}, [r11]! @ load {linear_src_v+(linear_x_size/2)*7, 32} + vld1.8 {q15}, [r11], r12 + vst2.8 {q0, q1}, [r7]! @ store {tiled_addr+64*4} + vst2.8 {q2, q3}, [r7]! + vst2.8 {q4, q5}, [r7]! @ store {tiled_addr+64*5} + vst2.8 {q6, q7}, [r7]! + vst2.8 {q8, q9}, [r7]! @ store {tiled_addr+64*6} + vst2.8 {q10, q11}, [r7]! + vst2.8 {q12, q13}, [r7]! @ store {tiled_addr+64*7} + vst2.8 {q14, q15}, [r7]! + + pld [r8, r3] + vld1.8 {q0}, [r8]! @ load {linear_src_u+(linear_x_size/2)*8, 32} + vld1.8 {q2}, [r8], r12 + pld [r8, r3] + vld1.8 {q4}, [r8]! @ load {linear_src_u+(linear_x_size/2)*9, 32} + vld1.8 {q6}, [r8], r12 + pld [r11] + vld1.8 {q8}, [r8]! @ load {linear_src_u+(linear_x_size/2)*10, 32} + vld1.8 {q10}, [r8], r12 + pld [r11, r3, asr #1] + vld1.8 {q12}, [r8]! @ load {linear_src_u+(linear_x_size/2)*11, 32} + vld1.8 {q14}, [r8], r12 + pld [r11, r3] + vld1.8 {q1}, [r11]! @ load {linear_src_v+(linear_x_size/2)*8, 32} + vld1.8 {q3}, [r11], r12 + pld [r11, r3] + vld1.8 {q5}, [r11]! @ load {linear_src_v+(linear_x_size/2)*9, 32} + vld1.8 {q7}, [r11], r12 + pld [r8] + vld1.8 {q9}, [r11]! @ load {linear_src_v+(linear_x_size/2)*10, 32} + vld1.8 {q11}, [r11], r12 + pld [r8, r3, asr #1] + vld1.8 {q13}, [r11]! @ load {linear_src_v+(linear_x_size/2)*11, 32} + vld1.8 {q15}, [r11], r12 + vst2.8 {q0, q1}, [r7]! @ store {tiled_addr+64*8} + vst2.8 {q2, q3}, [r7]! + vst2.8 {q4, q5}, [r7]! @ store {tiled_addr+64*9} + vst2.8 {q6, q7}, [r7]! + vst2.8 {q8, q9}, [r7]! @ store {tiled_addr+64*10} + vst2.8 {q10, q11}, [r7]! + vst2.8 {q12, q13}, [r7]! @ store {tiled_addr+64*11} + vst2.8 {q14, q15}, [r7]! + + pld [r8, r3] + vld1.8 {q0}, [r8]! @ load {linear_src_u+(linear_x_size/2)*12, 32} + vld1.8 {q2}, [r8], r12 + pld [r8, r3] + vld1.8 {q4}, [r8]! @ load {linear_src_u+(linear_x_size/2)*13, 32} + vld1.8 {q6}, [r8], r12 + pld [r11] + vld1.8 {q8}, [r8]! @ load {linear_src_u+(linear_x_size/2)*14, 32} + vld1.8 {q10}, [r8], r12 + pld [r11, r3, asr #1] + vld1.8 {q12}, [r8]! @ load {linear_src_u+(linear_x_size/2)*15, 32} + vld1.8 {q14}, [r8], r12 + pld [r11, r3] + vld1.8 {q1}, [r11]! @ load {linear_src_v+(linear_x_size/2)*12, 32} + vld1.8 {q3}, [r11], r12 + pld [r11, r3] + vld1.8 {q5}, [r11]! @ load {linear_src_v+(linear_x_size/2)*13, 32} + vld1.8 {q7}, [r11], r12 + pld [r8] + vld1.8 {q9}, [r11]! @ load {linear_src_v+(linear_x_size/2)*14, 32} + vld1.8 {q11}, [r11], r12 + pld [r8, r3, asr #1] + vld1.8 {q13}, [r11]! @ load {linear_src_v+(linear_x_size/2)*15, 32} + vld1.8 {q15}, [r11], r12 + vst2.8 {q0, q1}, [r7]! @ store {tiled_addr+64*12} + vst2.8 {q2, q3}, [r7]! + vst2.8 {q4, q5}, [r7]! @ store {tiled_addr+64*13} + vst2.8 {q6, q7}, [r7]! + vst2.8 {q8, q9}, [r7]! @ store {tiled_addr+64*14} + vst2.8 {q10, q11}, [r7]! + vst2.8 {q12, q13}, [r7]! @ store {tiled_addr+64*15} + vst2.8 {q14, q15}, [r7]! + + pld [r8, r3] + vld1.8 {q0}, [r8]! @ load {linear_src_u+(linear_x_size/2)*16, 32} + vld1.8 {q2}, [r8], r12 + pld [r8, r3] + vld1.8 {q4}, [r8]! @ load {linear_src_u+(linear_x_size/2)*17, 32} + vld1.8 {q6}, [r8], r12 + pld [r11] + vld1.8 {q8}, [r8]! @ load {linear_src_u+(linear_x_size/2)*18, 32} + vld1.8 {q10}, [r8], r12 + pld [r11, r3, asr #1] + vld1.8 {q12}, [r8]! @ load {linear_src_u+(linear_x_size/2)*19, 32} + vld1.8 {q14}, [r8], r12 + pld [r11, r3] + vld1.8 {q1}, [r11]! @ load {linear_src_v+(linear_x_size/2)*16, 32} + vld1.8 {q3}, [r11], r12 + pld [r11, r3] + vld1.8 {q5}, [r11]! @ load {linear_src_v+(linear_x_size/2)*17, 32} + vld1.8 {q7}, [r11], r12 + pld [r8] + vld1.8 {q9}, [r11]! @ load {linear_src_v+(linear_x_size/2)*18, 32} + vld1.8 {q11}, [r11], r12 + pld [r8, r3, asr #1] + vld1.8 {q13}, [r11]! @ load {linear_src_v+(linear_x_size/2)*19, 32} + vld1.8 {q15}, [r11], r12 + vst2.8 {q0, q1}, [r7]! @ store {tiled_addr+64*16} + vst2.8 {q2, q3}, [r7]! + vst2.8 {q4, q5}, [r7]! @ store {tiled_addr+64*17} + vst2.8 {q6, q7}, [r7]! + vst2.8 {q8, q9}, [r7]! @ store {tiled_addr+64*18} + vst2.8 {q10, q11}, [r7]! + vst2.8 {q12, q13}, [r7]! @ store {tiled_addr+64*19} + vst2.8 {q14, q15}, [r7]! + + pld [r8, r3] + vld1.8 {q0}, [r8]! @ load {linear_src_u+(linear_x_size/2)*20, 32} + vld1.8 {q2}, [r8], r12 + pld [r8, r3] + vld1.8 {q4}, [r8]! @ load {linear_src_u+(linear_x_size/2)*21, 32} + vld1.8 {q6}, [r8], r12 + pld [r11] + vld1.8 {q8}, [r8]! @ load {linear_src_u+(linear_x_size/2)*22, 32} + vld1.8 {q10}, [r8], r12 + pld [r11, r3, asr #1] + vld1.8 {q12}, [r8]! @ load {linear_src_u+(linear_x_size/2)*23, 32} + vld1.8 {q14}, [r8], r12 + pld [r11, r3] + vld1.8 {q1}, [r11]! @ load {linear_src_v+(linear_x_size/2)*20, 32} + vld1.8 {q3}, [r11], r12 + pld [r11, r3] + vld1.8 {q5}, [r11]! @ load {linear_src_v+(linear_x_size/2)*21, 32} + vld1.8 {q7}, [r11], r12 + pld [r8] + vld1.8 {q9}, [r11]! @ load {linear_src_v+(linear_x_size/2)*22, 32} + vld1.8 {q11}, [r11], r12 + pld [r8, r3, asr #1] + vld1.8 {q13}, [r11]! @ load {linear_src_v+(linear_x_size/2)*23, 32} + vld1.8 {q15}, [r11], r12 + vst2.8 {q0, q1}, [r7]! @ store {tiled_addr+64*20} + vst2.8 {q2, q3}, [r7]! + vst2.8 {q4, q5}, [r7]! @ store {tiled_addr+64*21} + vst2.8 {q6, q7}, [r7]! + vst2.8 {q8, q9}, [r7]! @ store {tiled_addr+64*22} + vst2.8 {q10, q11}, [r7]! + vst2.8 {q12, q13}, [r7]! @ store {tiled_addr+64*23} + vst2.8 {q14, q15}, [r7]! + + pld [r8, r3] + vld1.8 {q0}, [r8]! @ load {linear_src_u+(linear_x_size/2)*24, 32} + vld1.8 {q2}, [r8], r12 + pld [r8, r3] + vld1.8 {q4}, [r8]! @ load {linear_src_u+(linear_x_size/2)*25, 32} + vld1.8 {q6}, [r8], r12 + pld [r11] + vld1.8 {q8}, [r8]! @ load {linear_src_u+(linear_x_size/2)*26, 32} + vld1.8 {q10}, [r8], r12 + pld [r11, r3, asr #1] + vld1.8 {q12}, [r8]! @ load {linear_src_u+(linear_x_size/2)*27, 32} + vld1.8 {q14}, [r8], r12 + pld [r11, r3] + vld1.8 {q1}, [r11]! @ load {linear_src_v+(linear_x_size/2)*24, 32} + vld1.8 {q3}, [r11], r12 + pld [r11, r3] + vld1.8 {q5}, [r11]! @ load {linear_src_v+(linear_x_size/2)*25, 32} + vld1.8 {q7}, [r11], r12 + pld [r8] + vld1.8 {q9}, [r11]! @ load {linear_src_v+(linear_x_size/2)*26, 32} + vld1.8 {q11}, [r11], r12 + pld [r8, r3, asr #1] + vld1.8 {q13}, [r11]! @ load {linear_src_v+(linear_x_size/2)*27, 32} + vld1.8 {q15}, [r11], r12 + vst2.8 {q0, q1}, [r7]! @ store {tiled_addr+64*24} + vst2.8 {q2, q3}, [r7]! + vst2.8 {q4, q5}, [r7]! @ store {tiled_addr+64*25} + vst2.8 {q6, q7}, [r7]! + vst2.8 {q8, q9}, [r7]! @ store {tiled_addr+64*26} + vst2.8 {q10, q11}, [r7]! + vst2.8 {q12, q13}, [r7]! @ store {tiled_addr+64*27} + vst2.8 {q14, q15}, [r7]! + + pld [r8, r3] + vld1.8 {q0}, [r8]! @ load {linear_src_u+(linear_x_size/2)*28, 32} + vld1.8 {q2}, [r8], r12 + pld [r8, r3] + vld1.8 {q4}, [r8]! @ load {linear_src_u+(linear_x_size/2)*29, 32} + vld1.8 {q6}, [r8], r12 + pld [r11] + vld1.8 {q8}, [r8]! @ load {linear_src_u+(linear_x_size/2)*30, 32} + vld1.8 {q10}, [r8], r12 + pld [r11, r3, asr #1] + vld1.8 {q12}, [r8]! @ load {linear_src_u+(linear_x_size/2)*31, 32} + vld1.8 {q14}, [r8], r12 + pld [r11, r3] + vld1.8 {q1}, [r11]! @ load {linear_src_v+(linear_x_size/2)*28, 32} + vld1.8 {q3}, [r11], r12 + pld [r11, r3] + vld1.8 {q5}, [r11]! @ load {linear_src_v+(linear_x_size/2)*29, 32} + vld1.8 {q7}, [r11], r12 + vld1.8 {q9}, [r11]! @ load {linear_src_v+(linear_x_size/2)*30, 32} + vld1.8 {q11}, [r11], r12 + vld1.8 {q13}, [r11]! @ load {linear_src_v+(linear_x_size/2)*31, 32} + vld1.8 {q15}, [r11], r12 + vst2.8 {q0, q1}, [r7]! @ store {tiled_addr+64*28} + vst2.8 {q2, q3}, [r7]! + vst2.8 {q4, q5}, [r7]! @ store {tiled_addr+64*29} + vst2.8 {q6, q7}, [r7]! + vst2.8 {q8, q9}, [r7]! @ store {tiled_addr+64*30} + vst2.8 {q10, q11}, [r7]! + vst2.8 {q12, q13}, [r7]! @ store {tiled_addr+64*31} + vst2.8 {q14, q15}, [r7]! + + add r5, r5, #64 @ j = j+64 + cmp r5, r9 @ j<aligned_x_size + blt LOOP_ALIGNED_X_SIZE + + add r6, r6, #32 @ i = i+32 + cmp r6, r10 @ i<aligned_y_size + blt LOOP_ALIGNED_Y_SIZE + + cmp r6, r4 + beq LOOP_LINEAR_Y_SIZE_2_START + +LOOP_LINEAR_Y_SIZE_1: + + mov r5, #0 @ j = 0 +LOOP_ALIGNED_X_SIZE_1: + + bl GET_TILED_OFFSET + + ldr r12, [sp, #48] @ r12 = top + ldr r8, [sp, #44] @ r8 = left + + mov r11, r3, asr #1 @ temp1 = (yuv420_width/2)*(i+top) + add r12, r6, r12 + mul r11, r11, r12 + add r11, r11, r5, asr #1 @ temp1 = temp1+j/2 + add r11, r11, r8, asr #1 @ temp1 = temp1+left/2 + + add r8, r1, r11 @ linear_addr = linear_src_u+temp1 + add r11, r2, r11 @ temp1 = linear_src_v+temp1 + add r7, r0, r7 @ tiled_addr = tiled_dest+tiled_addr + and r14, r6, #0x1F @ temp3 = i&0x1F@ + mov r14, r14, lsl #6 @ temp3 = temp3*64 + add r7, r7, r14 @ tiled_addr = tiled_addr+temp3 + + vld1.8 {q0}, [r8]! @ load {linear_src_u, 32} + vld1.8 {q2}, [r8] + vld1.8 {q1}, [r11]! @ load {linear_src_v, 32} + vld1.8 {q3}, [r11] + vst2.8 {q0, q1}, [r7]! @ store {tiled_addr} + vst2.8 {q2, q3}, [r7]! + + add r5, r5, #64 @ j = j+64 + cmp r5, r9 @ j<aligned_x_size + blt LOOP_ALIGNED_X_SIZE_1 + + ldr r12, [sp, #48] @ r12 = top + ldr r8, [sp, #56] @ r8 = buttom + add r6, r6, #1 @ i = i+1 + sub r12, r4, r12 + sub r12, r12, r8 + cmp r6, r12 @ i<(yuv420_height-top-buttom) + blt LOOP_LINEAR_Y_SIZE_1 + +LOOP_LINEAR_Y_SIZE_2_START: + cmp r5, r3 + beq RESTORE_REG + + mov r6, #0 @ i = 0 +LOOP_LINEAR_Y_SIZE_2: + + mov r5, r9 @ j = aligned_x_size +LOOP_LINEAR_X_SIZE_2: + + bl GET_TILED_OFFSET + + ldr r12, [sp, #48] @ r12 = top + ldr r8, [sp, #44] @ r8 = left + + mov r11, r3, asr #1 @ temp1 = (yuv420_width/2)*(i+top) + add r12, r6, r12 + mul r11, r11, r12 + add r11, r11, r5, asr #1 @ temp1 = temp1+j/2 + add r11, r11, r8, asr #1 @ temp1 = temp1+left/2 + + mov r12, r3, asr #1 @ temp2 = linear_x_size/2 + sub r12, r12, #1 @ temp2 = linear_x_size-1 + + add r8, r1, r11 @ linear_addr = linear_src_u+temp1 + add r11, r2, r11 @ temp1 = linear_src_v+temp1 + add r7, r0, r7 @ tiled_addr = tiled_dest+tiled_addr + and r14, r6, #0x1F @ temp3 = i&0x1F@ + mov r14, r14, lsl #6 @ temp3 = temp3*64 + add r7, r7, r14 @ tiled_addr = tiled_addr+temp3 + and r14, r5, #0x3F @ temp3 = j&0x3F + add r7, r7, r14 @ tiled_addr = tiled_addr+temp3 + + ldrb r10, [r8], #1 + ldrb r14, [r11], #1 + mov r14, r14, lsl #8 + orr r10, r10, r14 + strh r10, [r7], #2 + + ldr r12, [sp, #44] @ r12 = left + ldr r8, [sp, #52] @ r8 = right + add r5, r5, #2 @ j = j+2 + sub r12, r3, r12 + sub r12, r12, r8 + cmp r5, r12 @ j<(yuv420_width-left-right) + blt LOOP_LINEAR_X_SIZE_2 + + ldr r12, [sp, #48] @ r12 = top + ldr r8, [sp, #56] @ r8 = buttom + add r6, r6, #1 @ i = i+1 + sub r12, r4, r12 + sub r12, r12, r8 + cmp r6, r12 @ i<(yuv420_height-top-buttom) + blt LOOP_LINEAR_Y_SIZE_2 + +RESTORE_REG: + ldmfd sp!, {r4-r12,r15} @ restore registers + +GET_TILED_OFFSET: + stmfd sp!, {r14} + + mov r12, r6, asr #5 @ temp2 = i>>5 + mov r11, r5, asr #6 @ temp1 = j>>6 + + and r14, r12, #0x1 @ if (temp2 & 0x1) + cmp r14, #0x1 + bne GET_TILED_OFFSET_EVEN_FORMULA_1 + +GET_TILED_OFFSET_ODD_FORMULA: + + ldr r7, [sp, #48] @ r7 = left , (r14 was pushed to stack) + ldr r8, [sp, #56] @ r8 = right , (r14 was pushed to stack) + sub r14, r3, r7 + sub r14, r14, r8 + add r14, r14, #127 @ temp3 = (((yuv420_width-left-right)+127)>>7)<<7 + bic r14, r14, #0x7F @ temp3 = (temp3 >>7)<<7 + mov r14, r14, asr #6 @ temp3 = temp3>>6 + sub r7, r12, #1 @ tiled_addr = temp2-1 + mul r7, r7, r14 @ tiled_addr = tiled_addr*temp3 + add r7, r7, r11 @ tiled_addr = tiled_addr+temp1 + add r7, r7, #2 @ tiled_addr = tiled_addr+2 + bic r14, r11, #0x3 @ temp3 = (temp1>>2)<<2 + add r7, r7, r14 @ tiled_addr = tiled_addr+temp3 + mov r7, r7, lsl #11 @ tiled_addr = tiled_addr<<11 + b GET_TILED_OFFSET_RETURN + +GET_TILED_OFFSET_EVEN_FORMULA_1: + ldr r7, [sp, #52] @ r7 = top, (r14 was pushed to stack) + ldr r8, [sp, #60] @ r8 = buttom, (r14 was pushed to stack) + sub r14, r4, r7 + sub r14, r14, r8 + add r14, r14, #31 @ temp3 = (((yuv420_height-top-buttom)+31)>>5)<<5 + bic r14, r14, #0x1F @ temp3 = (temp3>>5)<<5 + sub r14, r14, #32 @ temp3 = temp3 - 32 + cmp r6, r14 @ if (i<(temp3-32)) { + bge GET_TILED_OFFSET_EVEN_FORMULA_2 + add r14, r11, #2 @ temp3 = temp1+2 + bic r14, r14, #3 @ temp3 = (temp3>>2)<<2 + add r7, r11, r14 @ tiled_addr = temp1+temp3 + ldr r8, [sp, #48] @ r8 = left, (r14 was pushed to stack) + sub r14, r3, r8 + ldr r8, [sp, #56] @ r8 = right, (r14 was pushed to stack) + sub r14, r14, r8 + add r14, r14, #127 @ temp3 = (((yuv420_width-left-right)+127)>>7)<<7 + bic r14, r14, #0x7F @ temp3 = (temp3>>7)<<7 + mov r14, r14, asr #6 @ temp3 = temp3>>6 + mul r12, r12, r14 @ tiled_y_index = tiled_y_index*temp3 + add r7, r7, r12 @ tiled_addr = tiled_addr+tiled_y_index + mov r7, r7, lsl #11 @ + b GET_TILED_OFFSET_RETURN + +GET_TILED_OFFSET_EVEN_FORMULA_2: + ldr r8, [sp, #48] @ r8 = left, (r14 was pushed to stack) + sub r14, r3, r8 + ldr r8, [sp, #56] @ r8 = right, (r14 was pushed to stack) + sub r14, r14, r8 + add r14, r14, #127 @ temp3 = (((yuv420_width-left-right)+127)>>7)<<7 + bic r14, r14, #0x7F @ temp3 = (temp3>>7)<<7 + mov r14, r14, asr #6 @ temp3 = temp3>>6 + mul r7, r12, r14 @ tiled_addr = temp2*temp3 + add r7, r7, r11 @ tiled_addr = tiled_addr+temp3 + mov r7, r7, lsl #11 @ tiled_addr = tiled_addr<<11@ + +GET_TILED_OFFSET_RETURN: + ldmfd sp!, {r15} @ restore registers + + .fnend + diff --git a/exynos/multimedia/utils/csc/exynos4/csc_tiled_to_linear_crop_neon.s b/exynos/multimedia/utils/csc/exynos4/csc_tiled_to_linear_crop_neon.s new file mode 100644 index 0000000..da86ac6 --- /dev/null +++ b/exynos/multimedia/utils/csc/exynos4/csc_tiled_to_linear_crop_neon.s @@ -0,0 +1,701 @@ +/* + * + * Copyright 2010 Samsung Electronics S.LSI Co. LTD + * + * Licensed under the Apache License, Version 2.0 (the "License") + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * @file csc_tiled_to_linear_crop_neon.s + * @brief SEC_OMX specific define + * @author ShinWon Lee (shinwon.lee@samsung.com) + * @version 1.0 + * @history + * 2011.8.04 : Create + */ + +/* + * Converts tiled data to linear + * Crops left, top, right, buttom + * 1. Y of NV12T to Y of YUV420P + * 2. Y of NV12T to Y of YUV420S + * 3. UV of NV12T to UV of YUV420S + * + * @param yuv420_dest + * Y or UV plane address of YUV420[out] + * + * @param nv12t_src + * Y or UV plane address of NV12T[in] + * + * @param yuv420_width + * Width of YUV420[in] + * + * @param yuv420_height + * Y: Height of YUV420, UV: Height/2 of YUV420[in] + * + * @param left + * Crop size of left. It should be even. + * + * @param top + * Crop size of top. It should be even. + * + * @param right + * Crop size of right. It should be even. + * + * @param buttom + * Crop size of buttom. It should be even. + */ + + .arch armv7-a + .text + .global csc_tiled_to_linear_crop_neon + .type csc_tiled_to_linear_crop_neon, %function +csc_tiled_to_linear_crop_neon: + .fnstart + + @r0 yuv420_dest + @r1 nv12t_src + @r2 yuv420_width + @r3 yuv420_height + @r4 + @r5 i + @r6 j + @r7 tiled_offset + @r8 tiled_offset1 + @r9 linear_offset + @r10 temp1 + @r11 temp2 + @r12 temp3 + @r14 temp4 + + stmfd sp!, {r4-r12,r14} @ backup registers + + ldr r12, [sp, #48] @ r12 = right + ldr r10, [sp, #40] @ r10 = left + sub r12, r2, r12 @ temp3 = yuv420_width-right@ + sub r10, r12, r10 @ temp1 = temp3-left@ + cmp r10, #256 @ if (temp1 >= 256) + blt LOOP_HEIGHT_64_START + + ldr r5, [sp, #44] @ i = top +LOOP_HEIGHT_256: + ldr r6, [sp, #40] @ j = left + mov r14, r5, asr #5 @ temp4 = i>>5 + bic r12, r6, #0xFF @ temp3 = (j>>8)<<8 + mov r12, r12, asr #6 @ temp3 = temp3>>6 + and r11, r14, #0x1 @ if (temp4 & 0x1) + cmp r11, #0x1 + bne LOOP_HEIGHT_256_GET_TILED_EVEN +LOOP_HEIGHT_256_GET_TILED_ODD: + sub r7, r14, #1 @ tiled_offset = temp4-1 + add r10, r2, #127 @ temp1 = ((yuv420_width+127)>>7)<<7 + bic r10, r10, #0x7F + mov r10, r10, asr #6 @ tiled_offset = tiled_offset*(temp1>>6) + mul r7, r7, r10 + add r7, r7, r12 @ tiled_offset = tiled_offset+temp3 + add r7, r7, #2 @ tiled_offset = tiled_offset+2 + bic r10, r12, #0x3 @ temp1 = (temp3>>2)<<2 + add r7, r7, r10 @ tiled_offset = tiled_offset+temp1 + mov r7, r7, lsl #11 @ tiled_offset = tiled_offset<<11 + add r8, r7, #4096 @ tiled_offset1 = tiled_offset+2048*2 + mov r14, #8 + b LOOP_HEIGHT_256_GET_TILED_END + +LOOP_HEIGHT_256_GET_TILED_EVEN: + add r11, r3, #31 @ temp2 = ((yuv420_height+31)>>5)<<5 + bic r11, r11, #0x1F + add r10, r5, #32 @ if ((i+32)<temp2) + cmp r10, r11 + bge LOOP_HEIGHT_256_GET_TILED_EVEN1 + add r10, r12, #2 @ temp1 = temp3+2 + bic r10, r10, #0x3 @ temp1 = (temp1>>2)<<2 + add r7, r12, r10 @ tiled_offset = temp3+temp1@ + add r10, r2, #127 @ temp1 = ((yuv420_width+127)>>7)<<7 + bic r10, r10, #0x7F + mov r10, r10, asr #6 @ tiled_offset = tiled_offset+temp4*(temp1>>6) + mla r7, r14, r10, r7 + mov r7, r7, lsl #11 @ tiled_offset = tiled_offset<<11 + add r8, r7, #12288 @ tiled_offset1 = tiled_offset+2048*6 + mov r14, #8 + b LOOP_HEIGHT_256_GET_TILED_END + +LOOP_HEIGHT_256_GET_TILED_EVEN1: + add r10, r2, #127 @ temp1 = ((yuv420_width+127)>>7)<<7 + bic r10, r10, #0x7F + mov r10, r10, asr #6 @ tiled_offset = temp4*(temp1>>6) + mul r7, r14, r10 + add r7, r7, r12 @ tiled_offset = tiled_offset+temp3 + mov r7, r7, lsl #11 @ tiled_offset = tiled_offset<<11 + add r8, r7, #4096 @ tiled_offset1 = tiled_offset+2048*2 + mov r14, #4 + +LOOP_HEIGHT_256_GET_TILED_END: + + ldr r12, [sp, #48] @ right + ldr r9, [sp, #44] @ top + and r10, r5, #0x1F @ temp1 = i&0x1F + add r7, r7, r10, lsl #6 @ tiled_offset = tiled_offset+64*(temp1) + add r8, r8, r10, lsl #6 @ tiled_offset1 = tiled_offset1+64*(temp1) + sub r11, r2, r6 @ temp2 = yuv420_width-left(==j)-right + sub r11, r11, r12 + sub r9, r5, r9 @ linear_offset = temp2*(i-top)@ + mul r9, r11, r9 + add r12, r6, #256 @ temp3 = ((j+256)>>8)<<8@ + bic r12, r12, #0xFF + sub r12, r12, r6 @ temp3 = temp3-j@ + and r10, r6, #0x3F @ temp1 = left(==j)&0x3F + + cmp r12, #192 @ if (temp3 > 192) + ble LOOP_HEIGHT_256_LEFT_192 + add r11, r1, r7 @ r11 = nv12t_src+tiled_offset+temp1 + add r11, r11, r10 + pld [r11] + add r12, r1, r7 @ r12 = nv12t_src+tiled_offset+2048 + pld [r11, #32] + add r12, r12, #2048 + pld [r12] + cmp r10, #0 + pld [r12, #32] + stmnefd sp!, {r9-r12, r14} @ backup registers + rsbne r10, r10, #64 + blne MEMCOPY_UNDER_64 + ldmnefd sp!, {r9-r12, r14} @ restore registers + bne LOOP_HEIGHT_256_LEFT_256_64 + vld1.8 {q0, q1}, [r11]! @ load {nv12t_src+tiled_offset+temp1, 64} + vld1.8 {q2, q3}, [r11] + add r11, r0, r9 @ r11 = yuv420_dest+linear_offset + vst1.8 {q0, q1}, [r11]! @ store {yuv420_dest+linear_offset, 64} + vst1.8 {q2, q3}, [r11]! +LOOP_HEIGHT_256_LEFT_256_64: + add r11, r1, r8 @ r11 = nv12t_src+tiled_offset1 + pld [r11] + vld1.8 {q4, q5}, [r12]! @ load {nv12t_src+tiled_offset+2048, 64} + pld [r11, #32] + vld1.8 {q6, q7}, [r12] + add r12, r11, #2048 @ r12 = nv12t_src+tiled_offset1+2048 + pld [r12] + vld1.8 {q8, q9}, [r11]! @ load {nv12t_src+tiled_offset1, 64} + pld [r12, #32] + vld1.8 {q10, q11}, [r11] + vld1.8 {q12, q13}, [r12]! @ load {nv12t_src+tiled_offset1+2048, 64} + vld1.8 {q14, q15}, [r12] + + sub r11, r0, r10 @ r11 = yuv420_dest+linear_offset+64-temp1 + add r12, r9, #64 + add r11, r11, r12 + + vst1.8 {q4, q5}, [r11]! @ store {yuv420_dest+linear_offset+64-temp1, 64} + vst1.8 {q6, q7}, [r11]! + vst1.8 {q8, q9}, [r11]! @ store {yuv420_dest+linear_offset+128-temp1, 64} + vst1.8 {q10, q11}, [r11]! + vst1.8 {q12, q13}, [r11]! @ store {yuv420_dest+linear_offset+192-temp1, 64} + vst1.8 {q14, q15}, [r11]! + + add r9, r9, #256 + sub r9, r9, r10 + b LOOP_HEIGHT_256_LEFT_END + +LOOP_HEIGHT_256_LEFT_192: + cmp r12, #128 @ if (temp3 > 128) + ble LOOP_HEIGHT_256_LEFT_128 + add r11, r1, r7 @ r11 = nv12t_src+tiled_offset+2048+temp1 + add r11, r11, r10 + add r11, r11, #2048 + pld [r11] + add r12, r1, r8 @ r12 = nv12t_src+tiled_offset1 + pld [r11, #32] + cmp r10, #0 + pld [r12] + stmnefd sp!, {r9-r12, r14} @ backup registers + pld [r12, #32] + rsbne r10, r10, #64 + blne MEMCOPY_UNDER_64 + ldmnefd sp!, {r9-r12, r14} @ restore registers + bne LOOP_HEIGHT_256_LEFT_192_64 + vld1.8 {q0, q1}, [r11]! @ load {nv12t_src+tiled_offset+2048+temp1, 64} + vld1.8 {q2, q3}, [r11] + add r11, r0, r9 @ r11 = yuv420_dest+linear_offset + vst1.8 {q0, q1}, [r11]! @ store {yuv420_dest+linear_offset, 64} + vst1.8 {q2, q3}, [r11]! +LOOP_HEIGHT_256_LEFT_192_64: + add r11, r1, r8 @ r11 = nv12t_src+tiled_offset1+2048 + add r11, r11, #2048 + pld [r11] + vld1.8 {q4, q5}, [r12]! @ load {nv12t_src+tiled_offset1, 64} + pld [r11, #32] + vld1.8 {q6, q7}, [r12] + vld1.8 {q8, q9}, [r11]! @ load {nv12t_src+tiled_offset1+2048, 64} + vld1.8 {q10, q11}, [r11] + + sub r11, r0, r10 @ r11 = yuv420_dest+linear_offset+64-temp1 + add r12, r9, #64 + add r11, r11, r12 + + vst1.8 {q4, q5}, [r11]! @ store {yuv420_dest+linear_offset+64-temp1, 64} + vst1.8 {q6, q7}, [r11]! + vst1.8 {q8, q9}, [r11]! @ store {yuv420_dest+linear_offset+128-temp1, 64} + vst1.8 {q10, q11}, [r11]! + + add r9, r9, #192 + sub r9, r9, r10 + b LOOP_HEIGHT_256_LEFT_END + +LOOP_HEIGHT_256_LEFT_128: + cmp r12, #64 @ if (temp3 > 64) + ble LOOP_HEIGHT_256_LEFT_64 + add r11, r1, r8 @ r11 = nv12t_src+tiled_offset1+temp1 + add r11, r11, r10 + pld [r11] + add r12, r1, r8 @ r12 = nv12t_src+tiled_offset1 + add r12, r12, #2048 + pld [r11, #32] + cmp r10, #0 + pld [r12] + stmnefd sp!, {r9-r12, r14} @ backup registers + pld [r12, #32] + rsbne r10, r10, #64 + blne MEMCOPY_UNDER_64 + ldmnefd sp!, {r9-r12, r14} @ restore registers + bne LOOP_HEIGHT_256_LEFT_128_64 + vld1.8 {q0, q1}, [r11]! @ load {nv12t_src+tiled_offset1+temp1, 64} + vld1.8 {q2, q3}, [r11] + add r11, r0, r9 @ r11 = yuv420_dest+linear_offset + vst1.8 {q0, q1}, [r11]! @ store {yuv420_dest+linear_offset, 64} + vst1.8 {q2, q3}, [r11]! +LOOP_HEIGHT_256_LEFT_128_64: + vld1.8 {q4, q5}, [r12]! @ load {nv12t_src+tiled_offset1, 64} + vld1.8 {q6, q7}, [r12] + + sub r11, r0, r10 @ r11 = yuv420_dest+linear_offset+64-temp1 + add r12, r9, #64 + add r11, r11, r12 + + vst1.8 {q4, q5}, [r11]! @ store {yuv420_dest+linear_offset+64-temp1, 64} + vst1.8 {q6, q7}, [r11]! + + add r9, r9, #128 + sub r9, r9, r10 + b LOOP_HEIGHT_256_LEFT_END + +LOOP_HEIGHT_256_LEFT_64: + add r11, r1, r8 @ r11 = nv12t_src+tiled_offset1+2048+temp1 + add r11, r11, #2048 + add r11, r11, r10 + cmp r10, #0 + pld [r11] + stmnefd sp!, {r9-r12, r14} @ backup registers + pld [r11, #32] + rsbne r10, r10, #64 + blne MEMCOPY_UNDER_64 + ldmnefd sp!, {r9-r12, r14} @ restore registers + bne LOOP_HEIGHT_256_LEFT_64_64 + vld1.8 {q0, q1}, [r11]! @ load {nv12t_src+tiled_offset1+temp1, 64} + vld1.8 {q2, q3}, [r11] + add r11, r0, r9 @ r11 = yuv420_dest+linear_offset + vst1.8 {q0, q1}, [r11]! @ store {yuv420_dest+linear_offset, 64} + vst1.8 {q2, q3}, [r11]! +LOOP_HEIGHT_256_LEFT_64_64: + add r9, r9, #64 + sub r9, r9, r10 + +LOOP_HEIGHT_256_LEFT_END: + + ldr r12, [sp, #48] @ right + add r7, r7, r14, lsl #11 @ tiled_offset = tiled_offset+temp4*2048 + add r10, r1, r7 @ r10 = nv12t_src+tiled_offset + pld [r10] + bic r6, r6, #0xFF @ j = (left>>8)<<8 + pld [r10, #32] + add r6, r6, #256 @ j = j + 256 + sub r11, r2, r12 @ temp2 = yuv420_width-right-256 + sub r11, r11, #256 + cmp r6, r11 + bgt LOOP_HEIGHT_256_WIDTH_END + +LOOP_HEIGHT_256_WIDTH: + add r12, r10, #2048 @ r12 = nv12t_src+tiled_offset+2048 + pld [r12] + vld1.8 {q0, q1}, [r10]! @ load {nv12t_src+tiled_offset, 64} + pld [r12, #32] + vld1.8 {q2, q3}, [r10] + + add r8, r8, r14, lsl #11 @ tiled_offset1 = tiled_offset1+temp4*2048 + add r10, r1, r8 @ r10 = nv12t_src+tiled_offset1 + pld [r10] + vld1.8 {q4, q5}, [r12]! @ load {nv12t_src+tiled_offset+2048, 64} + pld [r10, #32] + vld1.8 {q6, q7}, [r12] + + add r12, r10, #2048 @ r12 = nv12t_src+tiled_offset+2048 + pld [r12] + vld1.8 {q8, q9}, [r10]! @ load {nv12t_src+tiled_offset+2048, 64} + pld [r12, #32] + vld1.8 {q10, q11}, [r10] + + add r7, r7, r14, lsl #11 @ tiled_offset = tiled_offset+temp4*2048 + add r10, r1, r7 + pld [r10] + vld1.8 {q12, q13}, [r12]! @ load {nv12t_src+tiled_offset+2048, 64} + pld [r10, #32] + vld1.8 {q14, q15}, [r12] + + add r12, r0, r9 @ r12 = yuv420_dest+linear_offset + vst1.8 {q0, q1}, [r12]! + vst1.8 {q2, q3}, [r12]! + vst1.8 {q4, q5}, [r12]! + vst1.8 {q6, q7}, [r12]! + vst1.8 {q8, q9}, [r12]! + vst1.8 {q10, q11}, [r12]! + vst1.8 {q12, q13}, [r12]! + vst1.8 {q14, q15}, [r12]! + add r9, r9, #256 @ linear_offset = linear_offset+256 + + add r12, r10, #2048 @ r12 = nv12t_src+tiled_offset+2048 + + add r6, r6, #256 @ j=j+256 + cmp r6, r11 @ j<=temp2 + ble LOOP_HEIGHT_256_WIDTH + +LOOP_HEIGHT_256_WIDTH_END: + + add r8, r8, r14, lsl #11 @ tiled_offset1 = tiled_offset1+temp4*2048 + ldr r14, [sp, #48] @ right + sub r11, r2, r6 @ temp2 = yuv420_width-right-j + sub r11, r11, r14 + cmp r11, #0 + beq LOOP_HEIGHT_256_RIGHT_END + cmp r11, #192 + ble LOOP_HEIGHT_256_RIGHT_192 + add r12, r10, #2048 + pld [r12] + vld1.8 {q0, q1}, [r10]! @ load {nv12t_src+tiled_offset} + pld [r12, #32] + vld1.8 {q2, q3}, [r10] + + add r10, r1, r8 @ r10 = nv12t_src+tiled_offset1 + pld [r10] + vld1.8 {q4, q5}, [r12]! @ load {nv12t_src+tiled_offset+2048} + pld [r10, #32] + vld1.8 {q6, q7}, [r12] + + add r14, r10, #2048 @ r10 = nv12t_src+tiled_offset1+2048 + pld [r14] + vld1.8 {q8, q9}, [r10]! @ load {nv12t_src+tiled_offset1} + pld [r14, #32] + vld1.8 {q10, q11}, [r10] + + add r12, r0, r9 @ r12 = yuv420_dest+linear_offset + vst1.8 {q0, q1}, [r12]! + vst1.8 {q2, q3}, [r12]! + vst1.8 {q4, q5}, [r12]! + vst1.8 {q6, q7}, [r12]! + vst1.8 {q8, q9}, [r12]! + vst1.8 {q10, q11}, [r12]! + add r9, r9, #192 @ linear_offset = linear_offset+192 + + stmfd sp!, {r9-r12, r14} @ backup registers + sub r10, r11, #192 + mov r11, r14 + bl MEMCOPY_UNDER_64 + ldmfd sp!, {r9-r12, r14} @ restore registers + b LOOP_HEIGHT_256_RIGHT_END + +LOOP_HEIGHT_256_RIGHT_192: + cmp r11, #128 + ble LOOP_HEIGHT_256_RIGHT_128 + add r12, r10, #2048 + pld [r12] + vld1.8 {q0, q1}, [r10]! @ load {nv12t_src+tiled_offset} + pld [r12, #32] + vld1.8 {q2, q3}, [r10] + + add r14, r1, r8 @ r10 = nv12t_src+tiled_offset1 + pld [r14] + vld1.8 {q4, q5}, [r12]! @ load {nv12t_src+tiled_offset+2048} + pld [r14, #32] + vld1.8 {q6, q7}, [r12] + + add r12, r0, r9 @ r12 = yuv420_dest+linear_offset + vst1.8 {q0, q1}, [r12]! + vst1.8 {q2, q3}, [r12]! + vst1.8 {q4, q5}, [r12]! + vst1.8 {q6, q7}, [r12]! + add r9, r9, #128 @ linear_offset = linear_offset+128 + + stmfd sp!, {r9-r12, r14} @ backup registers + sub r10, r11, #128 + mov r11, r14 + bl MEMCOPY_UNDER_64 + ldmfd sp!, {r9-r12, r14} @ restore registers + b LOOP_HEIGHT_256_RIGHT_END + +LOOP_HEIGHT_256_RIGHT_128: + cmp r11, #64 + ble LOOP_HEIGHT_256_RIGHT_64 + add r14, r10, #2048 + pld [r14] + vld1.8 {q0, q1}, [r10]! @ load {nv12t_src+tiled_offset} + pld [r14, #32] + vld1.8 {q2, q3}, [r10] + + add r12, r0, r9 @ r12 = yuv420_dest+linear_offset + vst1.8 {q0, q1}, [r12]! + vst1.8 {q2, q3}, [r12]! + add r9, r9, #64 @ linear_offset = linear_offset+64 + + stmfd sp!, {r9-r12, r14} @ backup registers + sub r10, r11, #64 + mov r11, r14 + bl MEMCOPY_UNDER_64 + ldmfd sp!, {r9-r12, r14} @ restore registers + b LOOP_HEIGHT_256_RIGHT_END + +LOOP_HEIGHT_256_RIGHT_64: + stmfd sp!, {r9-r12, r14} @ backup registers + mov r14, r11 + mov r11, r10 + mov r10, r14 + bl MEMCOPY_UNDER_64 + ldmfd sp!, {r9-r12, r14} @ restore registers + +LOOP_HEIGHT_256_RIGHT_END: + + ldr r14, [sp, #52] @ buttom + add r5, r5, #1 @ i=i+1 + sub r14, r3, r14 @ i<yuv420_height-buttom + cmp r5, r14 + blt LOOP_HEIGHT_256 + b RESTORE_REG + +LOOP_HEIGHT_64_START: + cmp r10, #64 @ if (temp1 >= 64) + blt LOOP_HEIGHT_2_START + + ldr r5, [sp, #44] @ i = top +LOOP_HEIGHT_64: + ldr r6, [sp, #40] @ j = left + stmfd sp!, {r0-r3, r12} @ backup parameters + mov r0, r2 + mov r1, r3 + mov r2, r6 + mov r3, r5 + bl tile_4x2_read_asm + mov r7, r0 + ldmfd sp!, {r0-r3, r12} @ restore parameters + ldr r9, [sp, #44] @ linear_offset = top + add r11, r6, #64 @ temp2 = ((j+64)>>6)<<6 + bic r11, r11, #0x3F + sub r11, r11, r6 @ temp2 = temp2-j + sub r9, r5, r9 @ linear_offset = temp1*(i-top) + mul r9, r9, r10 + and r14, r6, #0x3 @ temp4 = j&0x3 + add r7, r7, r14 @ tiled_offset = tiled_offset+temp4 + stmfd sp!, {r9-r12} @ backup parameters + mov r10, r11 + add r11, r1, r7 + bl MEMCOPY_UNDER_64 + ldmfd sp!, {r9-r12} @ restore parameters + add r9, r9, r11 @ linear_offset = linear_offset+temp2 + add r6, r6, r11 @ j = j+temp2@ + + add r14, r6, #64 + cmp r14, r12 + bgt LOOP_HEIGHT_64_1 + stmfd sp!, {r0-r3, r12} @ backup parameters + mov r0, r2 + mov r1, r3 + mov r2, r6 + mov r3, r5 + bl tile_4x2_read_asm + mov r7, r0 + ldmfd sp!, {r0-r3, r12} @ restore parameters + add r7, r1, r7 + vld1.8 {q0, q1}, [r7]! + vld1.8 {q2, q3}, [r7] + add r7, r0, r9 + vst1.8 {q0, q1}, [r7]! + vst1.8 {q2, q3}, [r7] + add r9, r9, #64 + add r6, r6, #64 + +LOOP_HEIGHT_64_1: + add r14, r6, #64 + cmp r14, r12 + bgt LOOP_HEIGHT_64_2 + stmfd sp!, {r0-r3, r12} @ backup parameters + mov r0, r2 + mov r1, r3 + mov r2, r6 + mov r3, r5 + bl tile_4x2_read_asm + mov r7, r0 + ldmfd sp!, {r0-r3, r12} @ restore parameters + add r7, r1, r7 + vld1.8 {q0, q1}, [r7]! + vld1.8 {q2, q3}, [r7] + add r7, r0, r9 + vst1.8 {q0, q1}, [r7]! + vst1.8 {q2, q3}, [r7] + add r9, r9, #64 + add r6, r6, #64 + +LOOP_HEIGHT_64_2: + cmp r6, r12 + bge LOOP_HEIGHT_64_3 + stmfd sp!, {r0-r3, r12} @ backup parameters + mov r0, r2 + mov r1, r3 + mov r2, r6 + mov r3, r5 + bl tile_4x2_read_asm + mov r7, r0 + ldmfd sp!, {r0-r3, r12} @ restore parameters + sub r11, r12, r6 + stmfd sp!, {r9-r12} @ backup parameters + mov r10, r11 + add r11, r1, r7 + bl MEMCOPY_UNDER_64 + ldmfd sp!, {r9-r12} @ restore parameters + +LOOP_HEIGHT_64_3: + + ldr r14, [sp, #52] @ buttom + add r5, r5, #1 @ i=i+1 + sub r14, r3, r14 @ i<yuv420_height-buttom + cmp r5, r14 + blt LOOP_HEIGHT_64 + b RESTORE_REG + +LOOP_HEIGHT_2_START: + + ldr r5, [sp, #44] @ i = top +LOOP_HEIGHT_2: + + ldr r6, [sp, #40] @ j = left + ldr r9, [sp, #44] @ linear_offset = top + add r11, r6, #64 @ temp2 = ((j+64)>>6)<<6 + bic r11, r11, #0x3F + sub r11, r11, r6 @ temp2 = temp2-j + sub r9, r5, r9 @ linear_offset = temp1*(i-top) + mul r9, r10, r9 + add r9, r0, r9 @ linear_offset = linear_dst+linear_offset +LOOP_HEIGHT_2_WIDTH: + stmfd sp!, {r0-r3, r12} @ backup parameters + mov r0, r2 + mov r1, r3 + mov r2, r6 + mov r3, r5 + bl tile_4x2_read_asm + mov r7, r0 + ldmfd sp!, {r0-r3, r12} @ restore parameters + + and r14, r6, #0x3 @ temp4 = j&0x3@ + add r7, r7, r14 @ tiled_offset = tiled_offset+temp4@ + add r7, r1, r7 + + ldrh r14, [r7] + strh r14, [r9], #2 + + ldr r14, [sp, #48] @ right + add r6, r6, #2 @ j=j+2 + sub r14, r2, r14 @ j<yuv420_width-right + cmp r6, r14 + blt LOOP_HEIGHT_2_WIDTH + + ldr r14, [sp, #52] @ buttom + add r5, r5, #1 @ i=i+1 + sub r14, r3, r14 @ i<yuv420_height-buttom + cmp r5, r14 + blt LOOP_HEIGHT_2 + +RESTORE_REG: + ldmfd sp!, {r4-r12,r15} @ restore registers + +MEMCOPY_UNDER_64: @ count=r10, src=r11 + cmp r10, #32 + add r9, r0, r9 @ r9 = yuv420_dest+linear_offset + blt MEMCOPY_UNDER_32 + vld1.8 {q0, q1}, [r11]! @ load {nv12t_src+tiled_offset+temp1, 64} + sub r10, r10, #32 + cmp r10, #0 + vst1.8 {q0, q1}, [r9]! @ load {nv12t_src+tiled_offset+temp1, 64} + beq MEMCOPY_UNDER_END +MEMCOPY_UNDER_32: + cmp r10, #16 + blt MEMCOPY_UNDER_16 + vld1.8 {q0}, [r11]! @ load {nv12t_src+tiled_offset+temp1, 64} + sub r10, r10, #16 + cmp r10, #0 + vst1.8 {q0}, [r9]! @ load {nv12t_src+tiled_offset+temp1, 64} + beq MEMCOPY_UNDER_END +MEMCOPY_UNDER_16: + ldrb r12, [r11], #1 + strb r12, [r9], #1 + subs r10, r10, #1 + bne MEMCOPY_UNDER_16 + +MEMCOPY_UNDER_END: + and r10, r6, #0x3F @ temp1 = left(==j)&0x3F + cmp r10, #0 + mov pc, lr + +tile_4x2_read_asm: +LFB0: + add ip, r3, #32 + sub r0, r0, #1 + cmp r1, ip + cmple r3, r1 + mov ip, r2, asr #2 + mov r0, r0, asr #7 + stmfd sp!, {r4, r5, lr} +LCFI0: + add r0, r0, #1 + bge L2 + sub r1, r1, #1 + tst r1, #32 + bne L2 + tst r3, #32 + bne L2 + mov r4, r2, asr #7 + and r1, r3, #31 + eor r4, r4, r3, asr #5 + ubfx r3, r3, #6, #8 + tst r4, #1 + ubfx r4, r2, #8, #6 + and ip, ip, #15 + mov r2, r2, asr #6 + mla r3, r0, r3, r4 + orr r1, ip, r1, asl #4 + b L9 +L2: + mov r2, ip, asr #5 + and r4, r3, #31 + eor r1, r2, r3, asr #5 + and r5, r2, #127 + ubfx r3, r3, #6, #8 + tst r1, #1 + and r1, ip, #15 + mov r2, ip, asr #4 + mla r3, r0, r3, r5 + orr r1, r1, r4, asl #4 +L9: + andne r2, r2, #1 + andeq r2, r2, #1 + orrne r2, r2, #2 + mov r1, r1, asl #2 + orr r3, r1, r3, asl #13 + orr r0, r3, r2, asl #11 + ldmfd sp!, {r4, r5, pc} +LFE0: + .fnend + diff --git a/exynos/multimedia/utils/csc/exynos4/csc_tiled_to_linear_deinterleave_crop_neon.s b/exynos/multimedia/utils/csc/exynos4/csc_tiled_to_linear_deinterleave_crop_neon.s new file mode 100644 index 0000000..45a749d --- /dev/null +++ b/exynos/multimedia/utils/csc/exynos4/csc_tiled_to_linear_deinterleave_crop_neon.s @@ -0,0 +1,786 @@ +/* + * + * Copyright 2010 Samsung Electronics S.LSI Co. LTD + * + * Licensed under the Apache License, Version 2.0 (the "License") + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * @file csc_tiled_to_linear_deinterleave_crop_neon.s + * @brief SEC_OMX specific define + * @author ShinWon Lee (shinwon.lee@samsung.com) + * @version 1.0 + * @history + * 2011.8.04 : Create + */ + +/* + * Converts and Deinterleaves tiled data to linear + * Crops left, top, right, buttom + * 1. UV of NV12T to UV of YUV420P + * + * @param yuv420_u_dest + * U plane address of YUV420P[out] + * + * @param yuv420_v_dest + * V plane address of YUV420P[out] + * + * @param nv12t_src + * UV plane address of NV12T[in] + * + * @param yuv420_width + * Width of YUV420[in] + * + * @param yuv420_uv_height + * Height/2 of YUV420[in] + * + * @param left + * Crop size of left. It should be even. + * + * @param top + * Crop size of top. It should be even. + * + * @param right + * Crop size of right. It should be even. + * + * @param buttom + * Crop size of buttom. It should be even. + */ + + .arch armv7-a + .text + .global csc_tiled_to_linear_deinterleave_crop_neon + .type csc_tiled_to_linear_deinterleave_crop_neon, %function +csc_tiled_to_linear_deinterleave_crop_neon: + .fnstart + + @r0 yuv420_u_dest + @r1 yuv420_v_dest + @r2 nv12t_src + @r3 yuv420_width + @r4 yuv420_height + @r5 i + @r6 j + @r7 tiled_offset + @r8 tiled_offset1 + @r9 linear_offset + @r10 temp1 + @r11 temp2 + @r12 temp3 + @r14 temp4 + + stmfd sp!, {r4-r12,r14} @ backup registers + + ldr r4, [sp, #40] @ r4 = yuv420_height + + ldr r12, [sp, #52] @ r12 = right + ldr r10, [sp, #44] @ r10 = left + sub r12, r3, r12 @ temp3 = yuv420_width-right@ + sub r10, r12, r10 @ temp1 = temp3-left@ + cmp r10, #256 @ if (temp1 >= 256) + blt LOOP_HEIGHT_64_START + + ldr r5, [sp, #48] @ top +LOOP_HEIGHT_256: + ldr r6, [sp, #44] @ j = left + mov r14, r5, asr #5 @ temp4 = i>>5 + bic r12, r6, #0xFF @ temp3 = (j>>8)<<8 + mov r12, r12, asr #6 @ temp3 = temp3>>6 + and r11, r14, #0x1 @ if (temp4 & 0x1) + cmp r11, #0x1 + bne LOOP_HEIGHT_256_GET_TILED_EVEN +LOOP_HEIGHT_256_GET_TILED_ODD: + sub r7, r14, #1 @ tiled_offset = temp4-1 + add r10, r3, #127 @ temp1 = ((yuv420_width+127)>>7)<<7 + bic r10, r10, #0x7F + mov r10, r10, asr #6 @ tiled_offset = tiled_offset*(temp1>>6) + mul r7, r7, r10 + add r7, r7, r12 @ tiled_offset = tiled_offset+temp3 + add r7, r7, #2 @ tiled_offset = tiled_offset+2 + bic r10, r12, #0x3 @ temp1 = (temp3>>2)<<2 + add r7, r7, r10 @ tiled_offset = tiled_offset+temp1 + mov r7, r7, lsl #11 @ tiled_offset = tiled_offset<<11 + add r8, r7, #4096 @ tiled_offset1 = tiled_offset+2048*2 + mov r14, #8 + b LOOP_HEIGHT_256_GET_TILED_END + +LOOP_HEIGHT_256_GET_TILED_EVEN: + add r11, r4, #31 @ temp2 = ((yuv420_height+31)>>5)<<5 + bic r11, r11, #0x1F + add r10, r5, #32 @ if ((i+32)<temp2) + cmp r10, r11 + bge LOOP_HEIGHT_256_GET_TILED_EVEN1 + add r10, r12, #2 @ temp1 = temp3+2 + bic r10, r10, #0x3 @ temp1 = (temp1>>2)<<2 + add r7, r12, r10 @ tiled_offset = temp3+temp1@ + add r10, r3, #127 @ temp1 = ((yuv420_width+127)>>7)<<7 + bic r10, r10, #0x7F + mov r10, r10, asr #6 @ tiled_offset = tiled_offset+temp4*(temp1>>6) + mla r7, r14, r10, r7 + mov r7, r7, lsl #11 @ tiled_offset = tiled_offset<<11 + add r8, r7, #12288 @ tiled_offset1 = tiled_offset+2048*6 + mov r14, #8 + b LOOP_HEIGHT_256_GET_TILED_END + +LOOP_HEIGHT_256_GET_TILED_EVEN1: + add r10, r3, #127 @ temp1 = ((yuv420_width+127)>>7)<<7 + bic r10, r10, #0x7F + mov r10, r10, asr #6 @ tiled_offset = temp4*(temp1>>6) + mul r7, r14, r10 + add r7, r7, r12 @ tiled_offset = tiled_offset+temp3 + mov r7, r7, lsl #11 @ tiled_offset = tiled_offset<<11 + add r8, r7, #4096 @ tiled_offset1 = tiled_offset+2048*2 + mov r14, #4 + +LOOP_HEIGHT_256_GET_TILED_END: + + ldr r12, [sp, #52] @ right + ldr r9, [sp, #48] @ top + and r10, r5, #0x1F @ temp1 = i&0x1F + add r7, r7, r10, lsl #6 @ tiled_offset = tiled_offset+64*(temp1) + add r8, r8, r10, lsl #6 @ tiled_offset1 = tiled_offset1+64*(temp1) + sub r11, r3, r6 @ temp2 = yuv420_width-left(==j)-right + sub r11, r11, r12 + sub r9, r5, r9 @ linear_offset = temp2*(i-top)/2@ + mul r9, r11, r9 + mov r9, r9, asr #1 + add r12, r6, #256 @ temp3 = ((j+256)>>8)<<8@ + bic r12, r12, #0xFF + sub r12, r12, r6 @ temp3 = temp3-j@ + and r10, r6, #0x3F @ temp1 = left(==j)&0x3F + + cmp r12, #192 @ if (temp3 > 192) + ble LOOP_HEIGHT_256_LEFT_192 + add r11, r2, r7 @ r11 = nv12t_src+tiled_offset+temp1 + add r11, r11, r10 + pld [r11] + add r12, r2, r7 @ r12 = nv12t_src+tiled_offset+2048 + pld [r11, #32] + add r12, r12, #2048 + pld [r12] + cmp r10, #0 + pld [r12, #32] + stmnefd sp!, {r8-r12, r14} @ backup registers + rsbne r10, r10, #64 + blne INTERLEAVED_MEMCOPY_UNDER_64 + ldmnefd sp!, {r8-r12, r14} @ restore registers + bne LOOP_HEIGHT_256_LEFT_256_64 + vld2.8 {q0, q1}, [r11]! @ load {nv12t_src+tiled_offset+temp1, 64} + vld2.8 {q2, q3}, [r11] + add r11, r0, r9 @ r11 = yuv420_u_dest+linear_offset + vst1.8 {q0}, [r11]! + vst1.8 {q2}, [r11]! + add r11, r1, r9 @ r11 = yuv420_v_dest+linear_offset + vst1.8 {q1}, [r11]! + vst1.8 {q3}, [r11]! +LOOP_HEIGHT_256_LEFT_256_64: + add r11, r2, r8 @ r11 = nv12t_src+tiled_offset1 + pld [r11] + vld2.8 {q4, q5}, [r12]! @ load {nv12t_src+tiled_offset+2048, 64} + pld [r11, #32] + vld2.8 {q6, q7}, [r12] + add r12, r11, #2048 @ r12 = nv12t_src+tiled_offset1+2048 + pld [r12] + vld2.8 {q8, q9}, [r11]! @ load {nv12t_src+tiled_offset1, 64} + pld [r12, #32] + vld2.8 {q10, q11}, [r11] + vld2.8 {q12, q13}, [r12]! @ load {nv12t_src+tiled_offset1+2048, 64} + vld2.8 {q14, q15}, [r12] + + add r11, r0, r9 @ r11 = yuv420_u_dest+linear_offset+32-temp1/2 + add r11, r11, #32 + sub r11, r11, r10, asr #1 + vst1.8 {q4}, [r11]! + vst1.8 {q6}, [r11]! + vst1.8 {q8}, [r11]! + vst1.8 {q10}, [r11]! + vst1.8 {q12}, [r11]! + vst1.8 {q14}, [r11]! + + add r11, r1, r9 @ r11 = yuv420_v_dest+linear_offset+32-temp1/2 + add r11, r11, #32 + sub r11, r11, r10, asr #1 + vst1.8 {q5}, [r11]! + vst1.8 {q7}, [r11]! + vst1.8 {q9}, [r11]! + vst1.8 {q11}, [r11]! + vst1.8 {q13}, [r11]! + vst1.8 {q15}, [r11]! + + add r9, r9, #128 + sub r9, r9, r10, asr #1 + b LOOP_HEIGHT_256_LEFT_END + +LOOP_HEIGHT_256_LEFT_192: + cmp r12, #128 @ if (temp3 > 128) + ble LOOP_HEIGHT_256_LEFT_128 + add r11, r2, r7 @ r11 = nv12t_src+tiled_offset+2048+temp1 + add r11, r11, r10 + add r11, r11, #2048 + pld [r11] + add r12, r2, r8 @ r12 = nv12t_src+tiled_offset1 + pld [r11, #32] + cmp r10, #0 + pld [r12] + stmnefd sp!, {r8-r12, r14} @ backup registers + pld [r12, #32] + rsbne r10, r10, #64 + blne INTERLEAVED_MEMCOPY_UNDER_64 + ldmnefd sp!, {r8-r12, r14} @ restore registers + bne LOOP_HEIGHT_256_LEFT_192_64 + vld2.8 {q0, q1}, [r11]! @ load {nv12t_src+tiled_offset+2048+temp1, 64} + vld2.8 {q2, q3}, [r11] + add r11, r0, r9 @ r11 = yuv420_u_dest+linear_offset + vst1.8 {q0}, [r11]! + vst1.8 {q2}, [r11]! + add r11, r1, r9 @ r11 = yuv420_v_dest+linear_offset + vst1.8 {q1}, [r11]! + vst1.8 {q3}, [r11]! +LOOP_HEIGHT_256_LEFT_192_64: + add r11, r2, r8 @ r11 = nv12t_src+tiled_offset1+2048 + add r11, r11, #2048 + pld [r11] + vld2.8 {q4, q5}, [r12]! @ load {nv12t_src+tiled_offset1, 64} + pld [r11, #32] + vld2.8 {q6, q7}, [r12] + vld2.8 {q8, q9}, [r11]! @ load {nv12t_src+tiled_offset1+2048, 64} + vld2.8 {q10, q11}, [r11] + + add r11, r0, r9 @ r11 = yuv420_u_dest+linear_offset+32-temp1/2 + add r11, r11, #32 + sub r11, r11, r10, asr #1 + vst1.8 {q4}, [r11]! + vst1.8 {q6}, [r11]! + vst1.8 {q8}, [r11]! + vst1.8 {q10}, [r11]! + + add r11, r1, r9 @ r11 = yuv420_v_dest+linear_offset+32-temp1/2 + add r11, r11, #32 + sub r11, r11, r10, asr #1 + vst1.8 {q5}, [r11]! + vst1.8 {q7}, [r11]! + vst1.8 {q9}, [r11]! + vst1.8 {q11}, [r11]! + + add r9, r9, #96 + sub r9, r9, r10, asr #1 + b LOOP_HEIGHT_256_LEFT_END + +LOOP_HEIGHT_256_LEFT_128: + cmp r12, #64 @ if (temp3 > 64) + ble LOOP_HEIGHT_256_LEFT_64 + add r11, r2, r8 @ r11 = nv12t_src+tiled_offset1+temp1 + add r11, r11, r10 + pld [r11] + add r12, r2, r8 @ r12 = nv12t_src+tiled_offset1 + add r12, r12, #2048 + pld [r11, #32] + cmp r10, #0 + pld [r12] + stmnefd sp!, {r8-r12, r14} @ backup registers + pld [r12, #32] + rsbne r10, r10, #64 + blne INTERLEAVED_MEMCOPY_UNDER_64 + ldmnefd sp!, {r8-r12, r14} @ restore registers + bne LOOP_HEIGHT_256_LEFT_128_64 + vld2.8 {q0, q1}, [r11]! @ load {nv12t_src+tiled_offset1+temp1, 64} + vld2.8 {q2, q3}, [r11] + add r11, r0, r9 @ r11 = yuv420_u_dest+linear_offset + vst1.8 {q0}, [r11]! + vst1.8 {q2}, [r11]! + add r11, r1, r9 @ r11 = yuv420_v_dest+linear_offset + vst1.8 {q1}, [r11]! + vst1.8 {q3}, [r11]! +LOOP_HEIGHT_256_LEFT_128_64: + vld2.8 {q4, q5}, [r12]! @ load {nv12t_src+tiled_offset1, 64} + vld2.8 {q6, q7}, [r12] + + add r11, r0, r9 @ r11 = yuv420_u_dest+linear_offset+32-temp1/2 + add r11, r11, #32 + sub r11, r11, r10, asr #1 + vst1.8 {q4}, [r11]! + vst1.8 {q6}, [r11]! + + add r11, r1, r9 @ r11 = yuv420_v_dest+linear_offset+32-temp1/2 + add r11, r11, #32 + sub r11, r11, r10, asr #1 + vst1.8 {q5}, [r11]! + vst1.8 {q7}, [r11]! + + add r9, r9, #64 + sub r9, r9, r10, asr #1 + b LOOP_HEIGHT_256_LEFT_END + +LOOP_HEIGHT_256_LEFT_64: + add r11, r2, r8 @ r11 = nv12t_src+tiled_offset1+2048+temp1 + add r11, r11, #2048 + add r11, r11, r10 + cmp r10, #0 + pld [r11] + stmnefd sp!, {r8-r12, r14} @ backup registers + pld [r11, #32] + rsbne r10, r10, #64 + blne INTERLEAVED_MEMCOPY_UNDER_64 + ldmnefd sp!, {r8-r12, r14} @ restore registers + bne LOOP_HEIGHT_256_LEFT_64_64 + vld2.8 {q0, q1}, [r11]! @ load {nv12t_src+tiled_offset1+temp1, 64} + vld2.8 {q2, q3}, [r11] + add r11, r0, r9 @ r11 = yuv420_dest+linear_offset + vst1.8 {q0, q1}, [r11]! @ store {yuv420_dest+linear_offset, 64} + vst1.8 {q2, q3}, [r11]! +LOOP_HEIGHT_256_LEFT_64_64: + add r9, r9, #32 + sub r9, r9, r10, asr #1 + +LOOP_HEIGHT_256_LEFT_END: + + ldr r12, [sp, #52] @ right + add r7, r7, r14, lsl #11 @ tiled_offset = tiled_offset+temp4*2048 + add r10, r2, r7 @ r10 = nv12t_src+tiled_offset + pld [r10] + bic r6, r6, #0xFF @ j = (left>>8)<<8 + pld [r10, #32] + add r6, r6, #256 @ j = j + 256 + sub r11, r3, r12 @ temp2 = yuv420_width-right-256 + sub r11, r11, #256 + cmp r6, r11 + bgt LOOP_HEIGHT_256_WIDTH_END + +LOOP_HEIGHT_256_WIDTH: + add r12, r10, #2048 @ r12 = nv12t_src+tiled_offset+2048 + pld [r12] + vld2.8 {q0, q1}, [r10]! @ load {nv12t_src+tiled_offset, 64} + pld [r12, #32] + vld2.8 {q2, q3}, [r10] + + add r8, r8, r14, lsl #11 @ tiled_offset1 = tiled_offset1+temp4*2048 + add r10, r2, r8 @ r10 = nv12t_src+tiled_offset1 + pld [r10] + vld2.8 {q4, q5}, [r12]! @ load {nv12t_src+tiled_offset+2048, 64} + pld [r10, #32] + vld2.8 {q6, q7}, [r12] + + add r12, r10, #2048 @ r12 = nv12t_src+tiled_offset+2048 + pld [r12] + vld2.8 {q8, q9}, [r10]! @ load {nv12t_src+tiled_offset+2048, 64} + pld [r12, #32] + vld2.8 {q10, q11}, [r10] + + add r7, r7, r14, lsl #11 @ tiled_offset = tiled_offset+temp4*2048 + add r10, r2, r7 + pld [r10] + vld2.8 {q12, q13}, [r12]! @ load {nv12t_src+tiled_offset+2048, 64} + pld [r10, #32] + vld2.8 {q14, q15}, [r12] + + add r12, r0, r9 @ r12 = yuv420_u_dest+linear_offset + vst1.8 {q0}, [r12]! + vst1.8 {q2}, [r12]! + vst1.8 {q4}, [r12]! + vst1.8 {q6}, [r12]! + vst1.8 {q8}, [r12]! + vst1.8 {q10}, [r12]! + vst1.8 {q12}, [r12]! + vst1.8 {q14}, [r12]! + add r12, r1, r9 @ r12 = yuv420_v_dest+linear_offset + vst1.8 {q1}, [r12]! + vst1.8 {q3}, [r12]! + vst1.8 {q5}, [r12]! + vst1.8 {q7}, [r12]! + vst1.8 {q9}, [r12]! + vst1.8 {q11}, [r12]! + vst1.8 {q13}, [r12]! + vst1.8 {q15}, [r12]! + add r9, r9, #128 @ linear_offset = linear_offset+128 + + add r12, r10, #2048 @ r12 = nv12t_src+tiled_offset+2048 + + add r6, r6, #256 @ j=j+256 + cmp r6, r11 @ j<=temp2 + ble LOOP_HEIGHT_256_WIDTH + +LOOP_HEIGHT_256_WIDTH_END: + + add r8, r8, r14, lsl #11 @ tiled_offset1 = tiled_offset1+temp4*2048 + ldr r14, [sp, #52] @ right + sub r11, r3, r6 @ temp2 = yuv420_width-right-j + sub r11, r11, r14 + cmp r11, #0 + beq LOOP_HEIGHT_256_RIGHT_END + cmp r11, #192 + ble LOOP_HEIGHT_256_RIGHT_192 + add r12, r10, #2048 + pld [r12] + vld2.8 {q0, q1}, [r10]! @ load {nv12t_src+tiled_offset} + pld [r12, #32] + vld2.8 {q2, q3}, [r10] + + add r10, r2, r8 @ r10 = nv12t_src+tiled_offset1 + pld [r10] + vld2.8 {q4, q5}, [r12]! @ load {nv12t_src+tiled_offset+2048} + pld [r10, #32] + vld2.8 {q6, q7}, [r12] + + add r14, r10, #2048 @ r10 = nv12t_src+tiled_offset1+2048 + pld [r14] + vld2.8 {q8, q9}, [r10]! @ load {nv12t_src+tiled_offset1} + pld [r14, #32] + vld2.8 {q10, q11}, [r10] + + add r12, r0, r9 @ r12 = yuv420_u_dest+linear_offset + vst1.8 {q0}, [r12]! + vst1.8 {q2}, [r12]! + vst1.8 {q4}, [r12]! + vst1.8 {q6}, [r12]! + vst1.8 {q8}, [r12]! + vst1.8 {q10}, [r12]! + add r12, r1, r9 @ r12 = yuv420_v_dest+linear_offset + vst1.8 {q1}, [r12]! + vst1.8 {q3}, [r12]! + vst1.8 {q5}, [r12]! + vst1.8 {q7}, [r12]! + vst1.8 {q9}, [r12]! + vst1.8 {q11}, [r12]! + add r9, r9, #96 @ linear_offset = linear_offset+96 + + stmfd sp!, {r8-r12, r14} @ backup registers + sub r10, r11, #192 + mov r11, r14 + bl INTERLEAVED_MEMCOPY_UNDER_64 + ldmfd sp!, {r8-r12, r14} @ restore registers + b LOOP_HEIGHT_256_RIGHT_END + +LOOP_HEIGHT_256_RIGHT_192: + cmp r11, #128 + ble LOOP_HEIGHT_256_RIGHT_128 + add r12, r10, #2048 + pld [r12] + vld2.8 {q0, q1}, [r10]! @ load {nv12t_src+tiled_offset} + pld [r12, #32] + vld2.8 {q2, q3}, [r10] + + add r14, r2, r8 @ r10 = nv12t_src+tiled_offset1 + pld [r14] + vld2.8 {q4, q5}, [r12]! @ load {nv12t_src+tiled_offset+2048} + pld [r14, #32] + vld2.8 {q6, q7}, [r12] + + add r12, r0, r9 @ r12 = yuv420_u_dest+linear_offset + vst1.8 {q0}, [r12]! + vst1.8 {q2}, [r12]! + vst1.8 {q4}, [r12]! + vst1.8 {q6}, [r12]! + add r12, r1, r9 @ r12 = yuv420_v_dest+linear_offset + vst1.8 {q1}, [r12]! + vst1.8 {q3}, [r12]! + vst1.8 {q5}, [r12]! + vst1.8 {q7}, [r12]! + add r9, r9, #64 @ linear_offset = linear_offset+64 + + stmfd sp!, {r8-r12, r14} @ backup registers + sub r10, r11, #128 + mov r11, r14 + bl INTERLEAVED_MEMCOPY_UNDER_64 + ldmfd sp!, {r8-r12, r14} @ restore registers + b LOOP_HEIGHT_256_RIGHT_END + +LOOP_HEIGHT_256_RIGHT_128: + cmp r11, #64 + ble LOOP_HEIGHT_256_RIGHT_64 + add r14, r10, #2048 + pld [r14] + vld2.8 {q0, q1}, [r10]! @ load {nv12t_src+tiled_offset} + pld [r14, #32] + vld2.8 {q2, q3}, [r10] + + add r12, r0, r9 @ r12 = yuv420_u_dest+linear_offset + vst1.8 {q0}, [r12]! + vst1.8 {q2}, [r12]! + add r12, r1, r9 @ r12 = yuv420_v_dest+linear_offset + vst1.8 {q1}, [r12]! + vst1.8 {q3}, [r12]! + add r9, r9, #32 @ linear_offset = linear_offset+32 + + stmfd sp!, {r8-r12, r14} @ backup registers + sub r10, r11, #64 + mov r11, r14 + bl INTERLEAVED_MEMCOPY_UNDER_64 + ldmfd sp!, {r8-r12, r14} @ restore registers + b LOOP_HEIGHT_256_RIGHT_END + +LOOP_HEIGHT_256_RIGHT_64: + stmfd sp!, {r8-r12, r14} @ backup registers + mov r14, r11 + mov r11, r10 + mov r10, r14 + bl INTERLEAVED_MEMCOPY_UNDER_64 + ldmfd sp!, {r8-r12, r14} @ restore registers + +LOOP_HEIGHT_256_RIGHT_END: + + ldr r14, [sp, #56] @ buttom + add r5, r5, #1 @ i=i+1 + sub r14, r4, r14 @ i<yuv420_height-buttom + cmp r5, r14 + blt LOOP_HEIGHT_256 + b RESTORE_REG + +LOOP_HEIGHT_64_START: + cmp r10, #64 @ if (temp1 >= 64) + blt LOOP_HEIGHT_2_START + + ldr r5, [sp, #48] @ i = top +LOOP_HEIGHT_64: + ldr r6, [sp, #44] @ j = left + stmfd sp!, {r0-r3, r12} @ backup parameters + mov r0, r3 + mov r1, r4 + mov r2, r6 + mov r3, r5 + bl tile_4x2_read_asm + mov r7, r0 + ldmfd sp!, {r0-r3, r12} @ restore parameters + ldr r9, [sp, #48] @ linear_offset = top + ldr r12, [sp, #52] @ r12 = right + add r11, r6, #64 @ temp2 = ((j+64)>>6)<<6 + bic r11, r11, #0x3F + sub r11, r11, r6 @ temp2 = temp2-j + sub r12, r3, r12 @ temp3 = yuv420_width-right + sub r14, r12, r6 @ temp4 = temp3-left + sub r9, r5, r9 @ linear_offset = temp4*(i-top)/2 + mul r9, r9, r14 + mov r9, r9, asr #1 + and r14, r6, #0x3 @ temp4 = j&0x3 + add r7, r7, r14 @ tiled_offset = tiled_offset+temp4 + stmfd sp!, {r9-r12} @ backup parameters + mov r10, r11 + add r11, r2, r7 + bl INTERLEAVED_MEMCOPY_UNDER_64 + ldmfd sp!, {r9-r12} @ restore parameters + add r9, r9, r11, asr #1 @ linear_offset = linear_offset+temp2/2 + add r6, r6, r11 @ j = j+temp2@ + + add r14, r6, #64 + cmp r14, r12 + bgt LOOP_HEIGHT_64_1 + stmfd sp!, {r0-r3, r12} @ backup parameters + mov r0, r3 + mov r1, r4 + mov r2, r6 + mov r3, r5 + bl tile_4x2_read_asm + mov r7, r0 + ldmfd sp!, {r0-r3, r12} @ restore parameters + add r7, r2, r7 + vld2.8 {q0, q1}, [r7]! + vld2.8 {q2, q3}, [r7] + add r7, r0, r9 + vst1.8 {q0}, [r7]! + vst1.8 {q2}, [r7] + add r7, r1, r9 + vst1.8 {q1}, [r7]! + vst1.8 {q3}, [r7] + add r9, r9, #32 + add r6, r6, #64 + +LOOP_HEIGHT_64_1: + add r14, r6, #64 + cmp r14, r12 + bgt LOOP_HEIGHT_64_2 + stmfd sp!, {r0-r3, r12} @ backup parameters + mov r0, r3 + mov r1, r4 + mov r2, r6 + mov r3, r5 + bl tile_4x2_read_asm + mov r7, r0 + ldmfd sp!, {r0-r3, r12} @ restore parameters + add r7, r2, r7 + vld2.8 {q0, q1}, [r7]! + vld2.8 {q2, q3}, [r7] + add r7, r0, r9 + vst1.8 {q0}, [r7]! + vst1.8 {q2}, [r7] + add r7, r1, r9 + vst1.8 {q1}, [r7]! + vst1.8 {q3}, [r7] + add r9, r9, #32 + add r6, r6, #64 + +LOOP_HEIGHT_64_2: + cmp r6, r12 + bge LOOP_HEIGHT_64_3 + stmfd sp!, {r0-r3, r12} @ backup parameters + mov r0, r3 + mov r1, r4 + mov r2, r6 + mov r3, r5 + bl tile_4x2_read_asm + mov r7, r0 + ldmfd sp!, {r0-r3, r12} @ restore parameters + sub r11, r12, r6 + stmfd sp!, {r9-r12} @ backup parameters + mov r10, r11 + add r11, r2, r7 + bl INTERLEAVED_MEMCOPY_UNDER_64 + ldmfd sp!, {r9-r12} @ restore parameters + +LOOP_HEIGHT_64_3: + + ldr r14, [sp, #56] @ buttom + add r5, r5, #1 @ i=i+1 + sub r14, r4, r14 @ i<yuv420_height-buttom + cmp r5, r14 + blt LOOP_HEIGHT_64 + b RESTORE_REG + +LOOP_HEIGHT_2_START: + + ldr r5, [sp, #48] @ i = top +LOOP_HEIGHT_2: + + ldr r12, [sp, #52] @ linear_offset = right + ldr r6, [sp, #44] @ j = left + ldr r9, [sp, #48] @ linear_offset = top + + sub r12, r3, r12 @ temp3 = yuv420_width-right + sub r14, r12, r6 @ temp4 = temp3-left@ + sub r9, r5, r9 @ r9 = i-top + mul r9, r14, r9 @ temp4*(i-top) + mov r9, r9, lsr #1 @ linear_offset = temp4*(i-top)/2 + add r11, r0, r9 + add r12, r1, r9 +LOOP_HEIGHT_2_WIDTH: + stmfd sp!, {r0-r3, r12} @ backup parameters + mov r0, r2 + mov r1, r3 + mov r2, r6 + mov r3, r5 + bl tile_4x2_read_asm + mov r7, r0 + ldmfd sp!, {r0-r3, r12} @ restore parameters + + and r14, r6, #0x3 @ temp4 = j&0x3@ + add r7, r7, r14 @ tiled_offset = tiled_offset+temp4@ + add r7, r2, r7 + + ldrh r14, [r7] + strb r14, [r11], #1 + mov r14, r14, lsr #8 + strb r14, [r12], #1 + + ldr r14, [sp, #52] @ right + add r6, r6, #2 @ j=j+2 + sub r14, r3, r14 @ j<yuv420_width-right + cmp r6, r14 + blt LOOP_HEIGHT_2_WIDTH + + ldr r14, [sp, #56] @ buttom + add r5, r5, #1 @ i=i+1 + sub r14, r4, r14 @ i<yuv420_height-buttom + cmp r5, r14 + blt LOOP_HEIGHT_2 + +RESTORE_REG: + ldmfd sp!, {r4-r12,r15} @ restore registers + +INTERLEAVED_MEMCOPY_UNDER_64: @ count=r10, src=r11 + cmp r10, #32 + blt INTERLEAVED_MEMCOPY_UNDER_32 + vld2.8 {q0, q1}, [r11]! @ load {nv12t_src+tiled_offset+temp1, 64} + sub r10, r10, #32 + cmp r10, #0 + add r12, r0, r9 @ r12 = yuv420_u_dest+linear_offset + vst1.8 {q0}, [r12] @ load {nv12t_src+tiled_offset+temp1, 64} + add r12, r1, r9 @ r12 = yuv420_v_dest+linear_offset + vst1.8 {q1}, [r12] @ load {nv12t_src+tiled_offset+temp1, 64} + add r9, r9, #16 + beq INTERLEAVED_MEMCOPY_UNDER_END +INTERLEAVED_MEMCOPY_UNDER_32: + cmp r10, #16 + blt INTERLEAVED_MEMCOPY_UNDER_16 + vld2.8 {q0}, [r11]! @ load {nv12t_src+tiled_offset+temp1, 64} + sub r10, r10, #16 + cmp r10, #0 + add r12, r0, r9 @ r12 = yuv420_u_dest+linear_offset + vst1.8 {d0}, [r12]! @ load {nv12t_src+tiled_offset+temp1, 64} + add r12, r1, r9 @ r12 = yuv420_v_dest+linear_offset + vst1.8 {d1}, [r12]! @ load {nv12t_src+tiled_offset+temp1, 64} + add r9, r9, #8 + beq INTERLEAVED_MEMCOPY_UNDER_END +INTERLEAVED_MEMCOPY_UNDER_16: + ldrh r12, [r11], #2 + add r8, r0, r9 @ r8 = yuv420_u_dest+linear_offset + strb r12, [r8] + add r8, r1, r9 @ r8 = yuv420_v_dest+linear_offset + mov r12, r12, lsr #8 + strb r12, [r8] + subs r10, r10, #2 + add r9, r9, #1 + bne INTERLEAVED_MEMCOPY_UNDER_16 + +INTERLEAVED_MEMCOPY_UNDER_END: + and r10, r6, #0x3F @ temp1 = left(==j)&0x3F + cmp r10, #0 + mov pc, lr + +tile_4x2_read_asm: +LFB0: + add ip, r3, #32 + sub r0, r0, #1 + cmp r1, ip + cmple r3, r1 + mov ip, r2, asr #2 + mov r0, r0, asr #7 + stmfd sp!, {r4, r5, lr} +LCFI0: + add r0, r0, #1 + bge L2 + sub r1, r1, #1 + tst r1, #32 + bne L2 + tst r3, #32 + bne L2 + mov r4, r2, asr #7 + and r1, r3, #31 + eor r4, r4, r3, asr #5 + ubfx r3, r3, #6, #8 + tst r4, #1 + ubfx r4, r2, #8, #6 + and ip, ip, #15 + mov r2, r2, asr #6 + mla r3, r0, r3, r4 + orr r1, ip, r1, asl #4 + b L9 +L2: + mov r2, ip, asr #5 + and r4, r3, #31 + eor r1, r2, r3, asr #5 + and r5, r2, #127 + ubfx r3, r3, #6, #8 + tst r1, #1 + and r1, ip, #15 + mov r2, ip, asr #4 + mla r3, r0, r3, r5 + orr r1, r1, r4, asl #4 +L9: + andne r2, r2, #1 + andeq r2, r2, #1 + orrne r2, r2, #2 + mov r1, r1, asl #2 + orr r3, r1, r3, asl #13 + orr r0, r3, r2, asl #11 + ldmfd sp!, {r4, r5, pc} +LFE0: + .fnend + diff --git a/exynos/multimedia/utils/csc/exynos5/Android.mk b/exynos/multimedia/utils/csc/exynos5/Android.mk new file mode 100644 index 0000000..955a3e2 --- /dev/null +++ b/exynos/multimedia/utils/csc/exynos5/Android.mk @@ -0,0 +1,35 @@ +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) + +LOCAL_COPY_HEADERS_TO := libsecmm +LOCAL_COPY_HEADERS := \ + color_space_convertor.h \ + csc_fimc.h + +LOCAL_MODULE_TAGS := optional + +LOCAL_SRC_FILES := \ + color_space_convertor.c \ + csc_fimc.cpp \ + csc_tiled_to_linear_y_neon.s \ + csc_tiled_to_linear_uv_neon.s \ + csc_tiled_to_linear_uv_deinterleave_neon.s \ + csc_interleave_memcpy_neon.s + +LOCAL_C_INCLUDES := \ + $(TOP)/device/samsung/multimedia/openmax/include/khronos \ + $(TOP)/device/samsung/$(TARGET_BOARD_PLATFORM)/include + +LOCAL_MODULE := libseccscapi + +LOCAL_PRELINK_MODULE := false + +LOCAL_CFLAGS := + +LOCAL_ARM_MODE := arm + +LOCAL_STATIC_LIBRARIES := +LOCAL_SHARED_LIBRARIES := liblog libfimc + +include $(BUILD_STATIC_LIBRARY) diff --git a/exynos/multimedia/utils/csc/exynos5/color_space_convertor.c b/exynos/multimedia/utils/csc/exynos5/color_space_convertor.c new file mode 100644 index 0000000..a651d62 --- /dev/null +++ b/exynos/multimedia/utils/csc/exynos5/color_space_convertor.c @@ -0,0 +1,640 @@ +/* + * + * Copyright 2010 Samsung Electronics S.LSI Co. LTD + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * @file color_space_convertor.c + * + * @brief SEC_OMX specific define. It support MFC 6.x tiled. + * + * @author ShinWon Lee (shinwon.lee@samsung.com) + * + * @version 1.0 + * + * @history + * 2011.12.01 : Create + */ + +#include "stdio.h" +#include "stdlib.h" +#include "color_space_convertor.h" + +/* 2D Configurable tiled memory access (TM) + * Return the linear address from tiled position (x, y) */ +unsigned int Tile2D_To_Linear( + unsigned int width, + unsigned int height, + unsigned int xpos, + unsigned int ypos, + int crFlag) +{ + int tileNumX; + int tileX, tileY; + int tileAddr; + int offset; + int addr; + + width = ((width + 15) / 16) * 16; + tileNumX = width / 16; + + /* crFlag - 0: Y plane, 1: CbCr plane */ + if (crFlag == 0) { + tileX = xpos / 16; + tileY = ypos / 16; + tileAddr = tileY * tileNumX + tileX; + offset = (ypos & 15) * 16 + (xpos & 15); + addr = (tileAddr << 8) | offset; + } else { + tileX = xpos / 16; + tileY = ypos / 8; + tileAddr = tileY * tileNumX + tileX; + offset = (ypos & 7) * 16 + (xpos & 15); + addr = (tileAddr << 7) | offset; + } + + return addr; +} + +/* + * De-interleaves src to dest1, dest2 + * + * @param dest1 + * Address of de-interleaved data[out] + * + * @param dest2 + * Address of de-interleaved data[out] + * + * @param src + * Address of interleaved data[in] + * + * @param src_size + * Size of interleaved data[in] + */ +void csc_deinterleave_memcpy( + unsigned char *dest1, + unsigned char *dest2, + unsigned char *src, + unsigned int src_size) +{ + unsigned int i = 0; + for(i=0; i<src_size/2; i++) { + dest1[i] = src[i*2]; + dest2[i] = src[i*2+1]; + } +} + +/* + * Interleaves src1, src2 to dest + * + * @param dest + * Address of interleaved data[out] + * + * @param src1 + * Address of de-interleaved data[in] + * + * @param src2 + * Address of de-interleaved data[in] + * + * @param src_size + * Size of de-interleaved data[in] + */ +void csc_interleave_memcpy( + unsigned char *dest, + unsigned char *src1, + unsigned char *src2, + unsigned int src_size) +{ + unsigned int i = 0; + for(i=0; i<src_size; i++) { + dest[i*2] = src1[i]; + dest[i*2+1] = src2[i]; + } +} + +/* + * Converts tiled data to linear for mfc 6.x tiled + * 1. y of nv12t to y of yuv420p + * 2. y of nv12t to y of yuv420s + * + * @param dst + * y address of yuv420[out] + * + * @param src + * y address of nv12t[in] + * + * @param yuv420_width + * real width of yuv420[in] + * it should be even + * + * @param yuv420_height + * real height of yuv420[in] + * it should be even. + * + */ +void csc_tiled_to_linear_y( + unsigned char *y_dst, + unsigned char *y_src, + unsigned int width, + unsigned int height) +{ + unsigned int i, j, k; + unsigned int aligned_width, aligned_height; + unsigned int tiled_width; + unsigned int src_offset, dst_offset; + + aligned_height = height & (~0xF); + aligned_width = width & (~0xF); + tiled_width = ((width + 15) >> 4) << 4; + + for (i = 0; i < aligned_height; i = i + 16) { + for (j = 0; j<aligned_width; j = j + 16) { + src_offset = (tiled_width * i) + (j << 4); + dst_offset = width * i + j; + for (k = 0; k < 8; k++) { + memcpy(y_dst + dst_offset, y_src + src_offset, 16); + src_offset += 16; + dst_offset += width; + memcpy(y_dst + dst_offset, y_src + src_offset, 16); + src_offset += 16; + dst_offset += width; + } + } + if (aligned_width != width) { + src_offset = (tiled_width * i) + (j << 4); + dst_offset = width * i + j; + for (k = 0; k < 8; k++) { + memcpy(y_dst + dst_offset, y_src + src_offset, width - j); + src_offset += 16; + dst_offset += width; + memcpy(y_dst + dst_offset, y_src + src_offset, width - j); + src_offset += 16; + dst_offset += width; + } + } + } + + if (aligned_height != height) { + for (j = 0; j<aligned_width; j = j + 16) { + src_offset = (tiled_width * i) + (j << 4); + dst_offset = width * i + j; + for (k = 0; k < height - aligned_height; k = k + 2) { + memcpy(y_dst + dst_offset, y_src + src_offset, 16); + src_offset += 16; + dst_offset += width; + memcpy(y_dst + dst_offset, y_src + src_offset, 16); + src_offset += 16; + dst_offset += width; + } + } + if (aligned_width != width) { + src_offset = (tiled_width * i) + (j << 4); + dst_offset = width * i + j; + for (k = 0; k < height - aligned_height; k = k + 2) { + memcpy(y_dst + dst_offset, y_src + src_offset, width - j); + src_offset += 16; + dst_offset += width; + memcpy(y_dst + dst_offset, y_src + src_offset, width - j); + src_offset += 16; + dst_offset += width; + } + } + } +} + +/* + * Converts tiled data to linear for mfc 6.x tiled + * 1. uv of nv12t to uv of yuv420s + * + * @param dst + * uv address of yuv420s[out] + * + * @param src + * uv address of nv12t[in] + * + * @param yuv420_width + * real width of yuv420s[in] + * + * @param yuv420_height + * real height of yuv420s[in] + * + */ +void csc_tiled_to_linear_uv( + unsigned char *uv_dst, + unsigned char *uv_src, + unsigned int width, + unsigned int height) +{ + unsigned int i, j, k; + unsigned int aligned_width, aligned_height; + unsigned int tiled_width; + unsigned int src_offset, dst_offset; + + aligned_height = height & (~0x7); + aligned_width = width & (~0xF); + tiled_width = ((width + 15) >> 4) << 4; + + for (i = 0; i < aligned_height; i = i + 8) { + for (j = 0; j<aligned_width; j = j + 16) { + src_offset = (tiled_width * i) + (j << 3); + dst_offset = width * i + j; + for (k = 0; k < 4; k++) { + memcpy(uv_dst + dst_offset, uv_src + src_offset, 16); + src_offset += 16; + dst_offset += width; + memcpy(uv_dst + dst_offset, uv_src + src_offset, 16); + src_offset += 16; + dst_offset += width; + } + } + if (aligned_width != width) { + src_offset = (tiled_width * i) + (j << 3); + dst_offset = width * i + j; + for (k = 0; k < 4; k++) { + memcpy(uv_dst + dst_offset, uv_src + src_offset, width - j); + src_offset += 16; + dst_offset += width; + memcpy(uv_dst + dst_offset, uv_src + src_offset, width - j); + src_offset += 16; + dst_offset += width; + } + } + } + + if (aligned_height != height) { + for (j = 0; j<aligned_width; j = j + 16) { + src_offset = (tiled_width * i) + (j << 3); + dst_offset = width * i + j; + for (k = 0; k < height - aligned_height; k = k + 1) { + memcpy(uv_dst + dst_offset, uv_src + src_offset, 16); + src_offset += 16; + dst_offset += width; + } + } + if (aligned_width != width) { + src_offset = (tiled_width * i) + (j << 3); + dst_offset = width * i + j; + for (k = 0; k < height - aligned_height; k = k + 1) { + memcpy(uv_dst + dst_offset, uv_src + src_offset, width - j); + src_offset += 16; + dst_offset += width; + } + } + } +} + +/* + * Converts tiled data to linear for mfc 6.x tiled + * 1. uv of nt12t to uv of yuv420p + * + * @param u_dst + * u address of yuv420p[out] + * + * @param v_dst + * v address of yuv420p[out] + * + * @param uv_src + * uv address of nt12t[in] + * + * @param yuv420_width + * real width of yuv420p[in] + * + * @param yuv420_height + * real height of yuv420p[in] + */ +void csc_tiled_to_linear_uv_deinterleave( + unsigned char *u_dst, + unsigned char *v_dst, + unsigned char *uv_src, + unsigned int width, + unsigned int height) +{ + unsigned int i, j, k; + unsigned int aligned_width, aligned_height; + unsigned int tiled_width; + unsigned int src_offset, dst_offset; + + aligned_height = height & (~0x7); + aligned_width = width & (~0xF); + tiled_width = ((width + 15) >> 4) << 4; + + for (i = 0; i < aligned_height; i = i + 8) { + for (j = 0; j<aligned_width; j = j + 16) { + src_offset = (tiled_width * i) + (j << 3); + dst_offset = (width >> 1) * i + (j >> 1); + for (k = 0; k < 4; k++) { + csc_deinterleave_memcpy(u_dst + dst_offset, v_dst + dst_offset, + uv_src + src_offset, 16); + src_offset += 16; + dst_offset += width >> 1; + csc_deinterleave_memcpy(u_dst + dst_offset, v_dst + dst_offset, + uv_src + src_offset, 16); + src_offset += 16; + dst_offset += width >> 1; + } + } + if (aligned_width != width) { + src_offset = (tiled_width * i) + (j << 3); + dst_offset = (width >> 1) * i + (j >> 1); + for (k = 0; k < 4; k++) { + csc_deinterleave_memcpy(u_dst + dst_offset, v_dst + dst_offset, + uv_src + src_offset, width - j); + src_offset += 16; + dst_offset += width >> 1; + csc_deinterleave_memcpy(u_dst + dst_offset, v_dst + dst_offset, + uv_src + src_offset, width - j); + src_offset += 16; + dst_offset += width >> 1; + } + } + } + if (aligned_height != height) { + for (j = 0; j<aligned_width; j = j + 16) { + src_offset = (tiled_width * i) + (j << 3); + dst_offset = (width >> 1) * i + (j >> 1); + for (k = 0; k < height - aligned_height; k = k + 1) { + csc_deinterleave_memcpy(u_dst + dst_offset, v_dst + dst_offset, + uv_src + src_offset, 16); + src_offset += 16; + dst_offset += width >> 1; + } + } + if (aligned_width != width) { + src_offset = (tiled_width * i) + (j << 3); + dst_offset = (width >> 1) * i + (j >> 1); + for (k = 0; k < height - aligned_height; k = k + 1) { + csc_deinterleave_memcpy(u_dst + dst_offset, v_dst + dst_offset, + uv_src + src_offset, width - j); + src_offset += 16; + dst_offset += width >> 1; + } + } + } +} + +/* + * Converts linear data to tiled + * It supports mfc 6.x tiled + * 1. y of yuv420 to y of nv12t + * + * @param dst + * y address of nv12t[out] + * + * @param src + * y address of yuv420[in] + * + * @param yuv420_width + * real width of yuv420[in] + * it should be even + * + * @param yuv420_height + * real height of yuv420[in] + * it should be even. + * + */ +void csc_linear_to_tiled_y( + unsigned char *y_dst, + unsigned char *y_src, + unsigned int width, + unsigned int height) +{ + +} + +/* + * Converts and interleaves linear data to tiled + * It supports mfc 6.x tiled + * 1. uv of nv12t to uv of yuv420 + * + * @param dst + * uv address of nv12t[out] + * + * @param src + * u address of yuv420[in] + * + * @param src + * v address of yuv420[in] + * + * @param yuv420_width + * real width of yuv420[in] + * + * @param yuv420_height + * real height of yuv420[in] + * + */ +void csc_linear_to_tiled_uv( + unsigned char *uv_dst, + unsigned char *u_src, + unsigned char *v_src, + unsigned int width, + unsigned int height) +{ + +} + +void Tile2D_To_YUV420(unsigned char *Y_plane, unsigned char *Cb_plane, unsigned char *Cr_plane, + unsigned int y_addr, unsigned int c_addr, unsigned int width, unsigned int height) +{ + int x, y, j, k, l; + int out_of_width, actual_width; + unsigned int base_addr, data; + + // y: 0, 16, 32, ... + for (y = 0; y < height; y += 16) { + // x: 0, 16, 32, ... + for (x = 0; x < width; x += 16) { + out_of_width = (x + 16) > width ? 1 : 0; + base_addr = y_addr + Tile2D_To_Linear(width, height, x, y, 0); + + for (k = 0; (k < 16) && ((y + k) < height); k++) { + actual_width = out_of_width ? ((width%4)?((width%16) / 4 + 1) : ((width%16) / 4)) : 4; + for (l = 0; l < actual_width; l++) { + data = *((unsigned int*)(base_addr + 16*k + l*4)); + for (j = 0; (j < 4) && (x + l*4 + j) < width; j++) { + Y_plane[(y+k)*width + x + l*4 +j] = (data>>(8*j))&0xff; + } + } + } + } + } + + for (y = 0; y < height/2; y += 8) { + for (x = 0; x < width; x += 16) { + out_of_width = (x + 16) > width ? 1 : 0; + base_addr = c_addr + Tile2D_To_Linear(width, height/2, x, y, 1); + for (k = 0; (k < 8) && ((y+k) < height/2); k++) { + actual_width = out_of_width ? ((width%4) ? ((width%16) / 4 + 1) : ((width%16) / 4)) : 4; + for (l = 0; l < actual_width; l++) { + data = *((unsigned int*)(base_addr + 16*k + l*4)); + for (j = 0; (j < 2) && (x/2 + l*2 +j) < width/2; j++) { + Cb_plane[(y+k)*width/2 + x/2 + l*2 +j] = (data>> (8*2*j))&0xff; + Cr_plane[(y+k)*width/2 + x/2 + l*2 +j] = (data>>(8*2*j+8))&0xff; + } + } + } + } + } +} + +/* + * Converts RGB565 to YUV420P + * + * @param y_dst + * Y plane address of YUV420P[out] + * + * @param u_dst + * U plane address of YUV420P[out] + * + * @param v_dst + * V plane address of YUV420P[out] + * + * @param rgb_src + * Address of RGB565[in] + * + * @param width + * Width of RGB565[in] + * + * @param height + * Height of RGB565[in] + */ +void csc_RGB565_to_YUV420P( + unsigned char *y_dst, + unsigned char *u_dst, + unsigned char *v_dst, + unsigned char *rgb_src, + int width, + int height) +{ + unsigned int i, j; + unsigned int tmp; + + unsigned int R, G, B; + unsigned int Y, U, V; + + unsigned int offset1 = width * height; + unsigned int offset2 = width/2 * height/2; + + unsigned short int *pSrc = (unsigned short int *)rgb_src; + + unsigned char *pDstY = (unsigned char *)y_dst; + unsigned char *pDstU = (unsigned char *)u_dst; + unsigned char *pDstV = (unsigned char *)v_dst; + + unsigned int yIndex = 0; + unsigned int uIndex = 0; + unsigned int vIndex = 0; + + for (j = 0; j < height; j++) { + for (i = 0; i < width; i++) { + tmp = pSrc[j * width + i]; + + R = (tmp & 0x0000F800) >> 8; + G = (tmp & 0x000007E0) >> 3; + B = (tmp & 0x0000001F); + B = B << 3; + + Y = ((66 * R) + (129 * G) + (25 * B) + 128); + Y = Y >> 8; + Y += 16; + + pDstY[yIndex++] = (unsigned char)Y; + + if ((j % 2) == 0 && (i % 2) == 0) { + U = ((-38 * R) - (74 * G) + (112 * B) + 128); + U = U >> 8; + U += 128; + V = ((112 * R) - (94 * G) - (18 * B) + 128); + V = V >> 8; + V += 128; + + pDstU[uIndex++] = (unsigned char)U; + pDstV[vIndex++] = (unsigned char)V; + } + } + } +} + +/* + * Converts RGB565 to YUV420SP + * + * @param y_dst + * Y plane address of YUV420SP[out] + * + * @param uv_dst + * UV plane address of YUV420SP[out] + * + * @param rgb_src + * Address of RGB565[in] + * + * @param width + * Width of RGB565[in] + * + * @param height + * Height of RGB565[in] + */ +void csc_RGB565_to_YUV420SP( + unsigned char *y_dst, + unsigned char *uv_dst, + unsigned char *rgb_src, + int width, + int height) +{ + unsigned int i, j; + unsigned int tmp; + + unsigned int R, G, B; + unsigned int Y, U, V; + + unsigned int offset = width * height; + + unsigned short int *pSrc = (unsigned short int *)rgb_src; + + unsigned char *pDstY = (unsigned char *)y_dst; + unsigned char *pDstUV = (unsigned char *)uv_dst; + + unsigned int yIndex = 0; + unsigned int uvIndex = 0; + + for (j = 0; j < height; j++) { + for (i = 0; i < width; i++) { + tmp = pSrc[j * width + i]; + + R = (tmp & 0x0000F800) >> 11; + R = R * 8; + G = (tmp & 0x000007E0) >> 5; + G = G * 4; + B = (tmp & 0x0000001F); + B = B * 8; + + Y = ((66 * R) + (129 * G) + (25 * B) + 128); + Y = Y >> 8; + Y += 16; + + pDstY[yIndex++] = (unsigned char)Y; + + if ((j % 2) == 0 && (i % 2) == 0) { + U = ((-38 * R) - (74 * G) + (112 * B) + 128); + U = U >> 8; + U += 128; + V = ((112 * R) - (94 * G) - (18 * B) + 128); + V = V >> 8; + V += 128; + + pDstUV[uvIndex++] = (unsigned char)U; + pDstUV[uvIndex++] = (unsigned char)V; + } + } + } +} diff --git a/exynos/multimedia/utils/csc/exynos5/color_space_convertor.h b/exynos/multimedia/utils/csc/exynos5/color_space_convertor.h new file mode 100644 index 0000000..202011e --- /dev/null +++ b/exynos/multimedia/utils/csc/exynos5/color_space_convertor.h @@ -0,0 +1,411 @@ +/* + * + * Copyright 2010 Samsung Electronics S.LSI Co. LTD + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * @file color_space_convertor.h + * @brief SEC_OMX specific define. It support MFC 6.x tiled. + * NV12T(tiled) layout: + * Each element is not pixel. It is 64x32 pixel block. + * uv pixel block is interleaved as u v u v u v ... + * y1 y2 y7 y8 y9 y10 y15 y16 + * y3 y4 y5 y6 y11 y12 y13 y14 + * y17 y18 y23 y24 y25 y26 y31 y32 + * y19 y20 y21 y22 y27 y28 y29 y30 + * uv1 uv2 uv7 uv8 uv9 uv10 uv15 uv16 + * uv3 uv4 uv5 uv6 uv11 uv12 uv13 uv14 + * YUV420Planar(linear) layout: + * Each element is not pixel. It is 64x32 pixel block. + * y1 y2 y3 y4 y5 y6 y7 y8 + * y9 y10 y11 y12 y13 y14 y15 y16 + * y17 y18 y19 y20 y21 y22 y23 y24 + * y25 y26 y27 y28 y29 y30 y31 y32 + * u1 u2 u3 u4 u5 u6 u7 u8 + * v1 v2 v3 v4 v5 v6 v7 v8 + * YUV420Semiplanar(linear) layout: + * Each element is not pixel. It is 64x32 pixel block. + * uv pixel block is interleaved as u v u v u v ... + * y1 y2 y3 y4 y5 y6 y7 y8 + * y9 y10 y11 y12 y13 y14 y15 y16 + * y17 y18 y19 y20 y21 y22 y23 y24 + * y25 y26 y27 y28 y29 y30 y31 y32 + * uv1 uv2 uv3 uv4 uv5 uv6 uv7 uv8 + * uv9 uv10 uv11 uv12 uv13 uv14 uv15 uv16 + * @author ShinWon Lee (shinwon.lee@samsung.com) + * @version 1.0 + * @history + * 2011.12.01 : Create + */ + +#ifndef COLOR_SPACE_CONVERTOR_H_ +#define COLOR_SPACE_CONVERTOR_H_ + +/*--------------------------------------------------------------------------------*/ +/* Format Conversion API */ +/*--------------------------------------------------------------------------------*/ +/* C Code */ +/* + * De-interleaves src to dest1, dest2 + * + * @param dest1 + * Address of de-interleaved data[out] + * + * @param dest2 + * Address of de-interleaved data[out] + * + * @param src + * Address of interleaved data[in] + * + * @param src_size + * Size of interleaved data[in] + */ +void csc_deinterleave_memcpy( + unsigned char *dest1, + unsigned char *dest2, + unsigned char *src, + unsigned int src_size); + +/* + * Interleaves src1, src2 to dest + * + * @param dest + * Address of interleaved data[out] + * + * @param src1 + * Address of de-interleaved data[in] + * + * @param src2 + * Address of de-interleaved data[in] + * + * @param src_size + * Size of de-interleaved data[in] + */ +void csc_interleave_memcpy( + unsigned char *dest, + unsigned char *src1, + unsigned char *src2, + unsigned int src_size); + +/* + * Converts tiled data to linear + * It supports mfc 6.x tiled + * 1. y of nv12t to y of yuv420p + * 2. y of nv12t to y of yuv420s + * + * @param dst + * y address of yuv420[out] + * + * @param src + * y address of nv12t[in] + * + * @param yuv420_width + * real width of yuv420[in] + * it should be even + * + * @param yuv420_height + * real height of yuv420[in] + * it should be even. + * + */ +void csc_tiled_to_linear_y( + unsigned char *y_dst, + unsigned char *y_src, + unsigned int width, + unsigned int height); + +/* + * Converts tiled data to linear + * It supports mfc 6.x tiled + * 1. uv of nv12t to y of yuv420s + * + * @param dst + * uv address of yuv420s[out] + * + * @param src + * uv address of nv12t[in] + * + * @param yuv420_width + * real width of yuv420s[in] + * + * @param yuv420_height + * real height of yuv420s[in] + * + */ +void csc_tiled_to_linear_uv( + unsigned char *uv_dst, + unsigned char *uv_src, + unsigned int width, + unsigned int height); + +/* + * Converts tiled data to linear + * It supports mfc 6.x tiled + * 1. uv of nt12t to uv of yuv420p + * + * @param u_dst + * u address of yuv420p[out] + * + * @param v_dst + * v address of yuv420p[out] + * + * @param uv_src + * uv address of nt12t[in] + * + * @param yuv420_width + * real width of yuv420p[in] + * + * @param yuv420_height + * real height of yuv420p[in] + */ +void csc_tiled_to_linear_uv_deinterleave( + unsigned char *u_dst, + unsigned char *v_dst, + unsigned char *uv_src, + unsigned int width, + unsigned int height); + +/* + * Converts linear data to tiled + * It supports mfc 6.x tiled + * 1. y of yuv420 to y of nv12t + * + * @param dst + * y address of nv12t[out] + * + * @param src + * y address of yuv420[in] + * + * @param yuv420_width + * real width of yuv420[in] + * it should be even + * + * @param yuv420_height + * real height of yuv420[in] + * it should be even. + * + */ +void csc_linear_to_tiled_y( + unsigned char *y_dst, + unsigned char *y_src, + unsigned int width, + unsigned int height); + +/* + * Converts and interleaves linear data to tiled + * It supports mfc 6.x tiled + * 1. uv of nv12t to uv of yuv420 + * + * @param dst + * uv address of nv12t[out] + * + * @param src + * u address of yuv420[in] + * + * @param src + * v address of yuv420[in] + * + * @param yuv420_width + * real width of yuv420[in] + * + * @param yuv420_height + * real height of yuv420[in] + * + */ +void csc_linear_to_tiled_uv( + unsigned char *uv_dst, + unsigned char *u_src, + unsigned char *v_src, + unsigned int width, + unsigned int height); + +/* + * Converts RGB565 to YUV420P + * + * @param y_dst + * Y plane address of YUV420P[out] + * + * @param u_dst + * U plane address of YUV420P[out] + * + * @param v_dst + * V plane address of YUV420P[out] + * + * @param rgb_src + * Address of RGB565[in] + * + * @param width + * Width of RGB565[in] + * + * @param height + * Height of RGB565[in] + */ +void csc_RGB565_to_YUV420P( + unsigned char *y_dst, + unsigned char *u_dst, + unsigned char *v_dst, + unsigned char *rgb_src, + int width, + int height); + +/* + * Converts RGB565 to YUV420S + * + * @param y_dst + * Y plane address of YUV420S[out] + * + * @param uv_dst + * UV plane address of YUV420S[out] + * + * @param rgb_src + * Address of RGB565[in] + * + * @param width + * Width of RGB565[in] + * + * @param height + * Height of RGB565[in] + */ +void csc_RGB565_to_YUV420SP( + unsigned char *y_dst, + unsigned char *uv_dst, + unsigned char *rgb_src, + int width, + int height); + +/* + * Converts tiled data to linear for mfc 6.x + * 1. Y of NV12T to Y of YUV420P + * 2. Y of NV12T to Y of YUV420S + * + * @param dst + * Y address of YUV420[out] + * + * @param src + * Y address of NV12T[in] + * + * @param yuv420_width + * real width of YUV420[in] + * + * @param yuv420_height + * Y: real height of YUV420[in] + * + */ +void csc_tiled_to_linear_y_neon( + unsigned char *y_dst, + unsigned char *y_src, + unsigned int width, + unsigned int height); + +/* + * Converts tiled data to linear for mfc 6.x + * 1. UV of NV12T to Y of YUV420S + * + * @param u_dst + * UV plane address of YUV420P[out] + * + * @param nv12t_src + * Y or UV plane address of NV12T[in] + * + * @param yuv420_width + * real width of YUV420[in] + * + * @param yuv420_height + * (real height)/2 of YUV420[in] + */ +void csc_tiled_to_linear_uv_neon( + unsigned char *uv_dst, + unsigned char *uv_src, + unsigned int width, + unsigned int height); + +/* + * Converts tiled data to linear for mfc 6.x + * Deinterleave src to u_dst, v_dst + * 1. UV of NV12T to Y of YUV420P + * + * @param u_dst + * U plane address of YUV420P[out] + * + * @param v_dst + * V plane address of YUV420P[out] + * + * @param nv12t_src + * Y or UV plane address of NV12T[in] + * + * @param yuv420_width + * real width of YUV420[in] + * + * @param yuv420_height + * (real height)/2 of YUV420[in] + */ +void csc_tiled_to_linear_uv_deinterleave_neon( + unsigned char *u_dst, + unsigned char *v_dst, + unsigned char *uv_src, + unsigned int width, + unsigned int height); + +/* + * Converts linear data to tiled + * It supports mfc 6.x tiled + * 1. y of yuv420 to y of nv12t + * + * @param dst + * y address of nv12t[out] + * + * @param src + * y address of yuv420[in] + * + * @param yuv420_width + * real width of yuv420[in] + * it should be even + * + * @param yuv420_height + * real height of yuv420[in] + * it should be even. + * + */ +void csc_linear_to_tiled_y_neon( + unsigned char *y_dst, + unsigned char *y_src, + unsigned int width, + unsigned int height); + +/* + * Converts and interleave linear data to tiled + * It supports mfc 6.x tiled + * 1. uv of nv12t to uv of yuv420 + * + * @param dst + * uv address of yuv420[out] + * + * @param src + * uv address of nv12t[in] + * + * @param yuv420_width + * real width of yuv420[in] + * + * @param yuv420_height + * real height of yuv420[in] + * + */ +void csc_linear_to_tiled_uv_neon( + unsigned char *uv_dst, + unsigned char *uv_src, + unsigned int width, + unsigned int height); + +#endif /*COLOR_SPACE_CONVERTOR_H_*/ diff --git a/exynos/multimedia/utils/csc/exynos5/csc_fimc.cpp b/exynos/multimedia/utils/csc/exynos5/csc_fimc.cpp new file mode 100644 index 0000000..89d0f97 --- /dev/null +++ b/exynos/multimedia/utils/csc/exynos5/csc_fimc.cpp @@ -0,0 +1,225 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * @file csc_fimc.cpp + * + * @brief csc_fimc use fimc1 to color space convertion + * + * @author ShinWon Lee (shinwon.lee@samsung.com) + * + * @version 1.0 + * + * @history + * 2011.11.01 : Create + */ + +#include <utils/Log.h> +#include <dlfcn.h> + +#include "SecFimc.h" +#include "csc_fimc.h" + +#define ALIGN(value, base) (((value) + (base) - 1) & ~((base) - 1)) + +unsigned int OMXtoHarPixelFomrat(OMX_COLOR_FORMATTYPE ColorFormat) +{ + unsigned int v4l2_format = 0; + switch (ColorFormat) { + case OMX_COLOR_FormatYUV420Planar: + v4l2_format = HAL_PIXEL_FORMAT_YCbCr_420_P; + break; + case OMX_COLOR_FormatYUV420SemiPlanar: + v4l2_format = HAL_PIXEL_FORMAT_YCbCr_420_SP; + break; + default: + v4l2_format = HAL_PIXEL_FORMAT_YCbCr_420_P; + break; + } + return v4l2_format; +} + +/* + * create and open fimc handle + * + * @return + * fimc handle + */ +void *csc_fimc_open() +{ + SecFimc *(*create_instance)(); + void (*destroy_instance)(void *); + SecFimc *handle_fimc = NULL; + void* hdl = NULL; + + hdl = dlopen("libfimc.so", RTLD_NOW); + if (hdl == NULL) { + LOGE("%s:: load libfimc.so failed", __func__); + return NULL; + } + + create_instance = (SecFimc *(*)())dlsym(hdl, "create_instance"); + handle_fimc = (SecFimc *)create_instance(); + if (handle_fimc == NULL) { + LOGE("%s:: create handle_fimc failed", __func__); + return NULL; + } + + if (!handle_fimc->create(SecFimc::DEV_1, SecFimc::MODE_MULTI_BUF, 1)) { + destroy_instance = (void (*)(void *))dlsym(hdl, "destroy_instance"); + destroy_instance(handle_fimc); + LOGE("%s:: create() failed", __func__); + return NULL; + } + return (void *)handle_fimc; +} + +/* + * close and destroy fimc handle + * + * @param handle + * fimc handle[in] + * + * @return + * pass or fail + */ +CSC_FIMC_ERROR_CODE csc_fimc_close(void *handle) +{ + void (*destroy_instance)(void *); + SecFimc *handle_fimc = (SecFimc *)handle; + void* hdl = NULL; + + if (!handle_fimc->destroy()) { + LOGE("%s:: destroy() failed", __func__); + return CSC_FIMC_RET_FAIL; + } + + hdl = dlopen("libfimc.so", RTLD_NOW); + if (hdl == NULL) { + LOGE("%s:: load libfimc.so failed", __func__); + return CSC_FIMC_RET_FAIL; + } + + destroy_instance = (void (*)(void *))dlsym(hdl, "destroy_instance"); + destroy_instance(handle); + + return CSC_FIMC_RET_OK; +} + +/* + * convert color space nv12t to omxformat + * + * @param handle + * fimc handle[in] + * + * @param dst_addr + * y,u,v address of dst_addr[out] + * + * @param src_addr + * y,uv address of src_addr.Format is nv12t[in] + * + * @param width + * width of dst image[in] + * + * @param height + * height of dst image[in] + * + * @param omxformat + * omxformat of dst image[in] + * + * @return + * pass or fail + */ +CSC_FIMC_ERROR_CODE csc_fimc_convert_nv12t( + void *handle, + void **dst_addr, + void **src_addr, + unsigned int width, + unsigned int height, + OMX_COLOR_FORMATTYPE omxformat) +{ + int rotate_value = 0; + + SecFimc *handle_fimc = (SecFimc *)handle; + + unsigned int src_crop_x = 0; + unsigned int src_crop_y = 0; + unsigned int src_crop_width = width; + unsigned int src_crop_height = height; + + unsigned int dst_crop_x = 0; + unsigned int dst_crop_y = 0; + unsigned int dst_crop_width = width; + unsigned int dst_crop_height = height; + + unsigned int HarPixelformat = 0; + HarPixelformat = OMXtoHarPixelFomrat(omxformat); + + // set post processor configuration + if (!handle_fimc->setSrcParams(width, height, src_crop_x, src_crop_y, + &src_crop_width, &src_crop_height, + HAL_PIXEL_FORMAT_CUSTOM_YCbCr_420_SP_TILED)) { + LOGE("%s:: setSrcParms() failed", __func__); + return CSC_FIMC_RET_FAIL; + } + + if (!handle_fimc->setSrcAddr((unsigned int)src_addr[0], + (unsigned int)src_addr[1], + (unsigned int)src_addr[1], + HAL_PIXEL_FORMAT_CUSTOM_YCbCr_420_SP_TILED)) { + LOGE("%s:: setSrcPhyAddr() failed", __func__); + return CSC_FIMC_RET_FAIL; + } + + if (!handle_fimc->setRotVal(rotate_value)) { + LOGE("%s:: setRotVal() failed", __func__); + return CSC_FIMC_RET_FAIL; + } + + if (!handle_fimc->setDstParams(width, height, dst_crop_x, dst_crop_y, + &dst_crop_width, &dst_crop_height, + HarPixelformat)) { + LOGE("%s:: setDstParams() failed", __func__); + return CSC_FIMC_RET_FAIL; + } + + switch (omxformat) { + case OMX_COLOR_FormatYUV420SemiPlanar: + if (!handle_fimc->setDstAddr((unsigned int)(dst_addr[0]), + (unsigned int)(dst_addr[1]), + (unsigned int)(dst_addr[1]))) { + LOGE("%s:: setDstPhyAddr() failed", __func__); + return CSC_FIMC_RET_FAIL; + } + break; + case OMX_COLOR_FormatYUV420Planar: + default: + if (!handle_fimc->setDstAddr((unsigned int)(dst_addr[0]), + (unsigned int)(dst_addr[1]), + (unsigned int)(dst_addr[2]))) { + LOGE("%s:: setDstPhyAddr() failed", __func__); + return CSC_FIMC_RET_FAIL; + } + break; + } + + if (!handle_fimc->draw(0, 0)) { + LOGE("%s:: handleOneShot() failed", __func__); + return CSC_FIMC_RET_FAIL; + } + + return CSC_FIMC_RET_OK; +} diff --git a/exynos/multimedia/utils/csc/exynos5/csc_fimc.h b/exynos/multimedia/utils/csc/exynos5/csc_fimc.h new file mode 100644 index 0000000..3ae24ac --- /dev/null +++ b/exynos/multimedia/utils/csc/exynos5/csc_fimc.h @@ -0,0 +1,106 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * @file csc_fimc.h + * + * @brief csc_fimc use fimc1 to color space convertion + * + * @author ShinWon Lee (shinwon.lee@samsung.com) + * + * @version 1.0 + * + * @history + * 2011.11.01 : Create + */ + +#ifndef CSC_FIMC_H + +#define CSC_FIMC_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include <OMX_Video.h> + +/*--------------------------------------------------------------------------------*/ +/* Structure and Type */ +/*--------------------------------------------------------------------------------*/ +typedef enum { + CSC_FIMC_RET_OK = 0, + CSC_FIMC_RET_FAIL = -1 +} CSC_FIMC_ERROR_CODE; + +/*--------------------------------------------------------------------------------*/ +/* CSC FIMC APIs */ +/*--------------------------------------------------------------------------------*/ +/* + * create and open fimc handle + * + * @return + * fimc handle + */ +void *csc_fimc_open(); + +/* + * close and destroy fimc handle + * + * @param handle + * fimc handle[in] + * + * @return + * error code + */ +CSC_FIMC_ERROR_CODE csc_fimc_close(void *handle); + +/* + * convert color space nv12t to omxformat + * + * @param handle + * fimc handle[in] + * + * @param dst_addr + * y,u,v address of dst_addr[out] + * + * @param src_addr + * y,uv address of src_addr.Format is nv12t[in] + * + * @param width + * width of dst image[in] + * + * @param height + * height of dst image[in] + * + * @param omxformat + * omxformat of dst image[in] + * + * @return + * error code + */ +CSC_FIMC_ERROR_CODE csc_fimc_convert_nv12t( + void *handle, + void **dst_addr, + void **src_addr, + unsigned int width, + unsigned int height, + OMX_COLOR_FORMATTYPE omxformat); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/exynos/multimedia/utils/csc/exynos5/csc_interleave_memcpy_neon.s b/exynos/multimedia/utils/csc/exynos5/csc_interleave_memcpy_neon.s new file mode 100644 index 0000000..3d2b41f --- /dev/null +++ b/exynos/multimedia/utils/csc/exynos5/csc_interleave_memcpy_neon.s @@ -0,0 +1,120 @@ +/* + * + * Copyright 2012 Samsung Electronics S.LSI Co. LTD + * + * Licensed under the Apache License, Version 2.0 (the "License") + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * @file csc_linear_to_tiled_crop_neon.s + * @brief SEC_OMX specific define + * @author ShinWon Lee (shinwon.lee@samsung.com) + * @version 1.0 + * @history + * 2012.01.04 : Create + */ + +/* + * Interleave src1, src2 to dst + * + * @param dest + * dst address[out] + * + * @param src1 + * src1 address[in] + * + * @param src2 + * src2 address[in] + * + * @param src_size + * src_size or src1 + */ + + .arch armv7-a + .text + .global csc_interleave_memcpy_neon + .type csc_interleave_memcpy_neon, %function +csc_interleave_memcpy_neon: + .fnstart + + @r0 dest + @r1 src1 + @r2 src2 + @r3 src_size + @r4 + @r5 + @r6 + @r7 + @r8 temp1 + @r9 temp2 + @r10 dest_addr + @r11 src1_addr + @r12 src2_addr + @r14 i + + stmfd sp!, {r8-r12,r14} @ backup registers + + mov r10, r0 + mov r11, r1 + mov r12, r2 + mov r14, r3 + + cmp r14, #128 + blt LESS_THAN_128 + +LOOP_128: + vld1.8 {q0}, [r11]! + vld1.8 {q2}, [r11]! + vld1.8 {q4}, [r11]! + vld1.8 {q6}, [r11]! + vld1.8 {q8}, [r11]! + vld1.8 {q10}, [r11]! + vld1.8 {q12}, [r11]! + vld1.8 {q14}, [r11]! + vld1.8 {q1}, [r12]! + vld1.8 {q3}, [r12]! + vld1.8 {q5}, [r12]! + vld1.8 {q7}, [r12]! + vld1.8 {q9}, [r12]! + vld1.8 {q11}, [r12]! + vld1.8 {q13}, [r12]! + vld1.8 {q15}, [r12]! + + vst2.8 {q0, q1}, [r10]! + vst2.8 {q2, q3}, [r10]! + vst2.8 {q4, q5}, [r10]! + vst2.8 {q6, q7}, [r10]! + vst2.8 {q8, q9}, [r10]! + vst2.8 {q10, q11}, [r10]! + vst2.8 {q12, q13}, [r10]! + vst2.8 {q14, q15}, [r10]! + + sub r14, #128 + cmp r14, #128 + bgt LOOP_128 + +LESS_THAN_128: + cmp r14, #0 + beq RESTORE_REG + +LOOP_1: + ldrb r8, [r11], #1 + ldrb r9, [r12], #1 + strb r8, [r10], #1 + strb r9, [r10], #1 + subs r14, #1 + bne LOOP_1 + +RESTORE_REG: + ldmfd sp!, {r8-r12,r15} @ restore registers + .fnend diff --git a/exynos/multimedia/utils/csc/exynos5/csc_tiled_to_linear_uv_deinterleave_neon.s b/exynos/multimedia/utils/csc/exynos5/csc_tiled_to_linear_uv_deinterleave_neon.s new file mode 100644 index 0000000..1e76a2e --- /dev/null +++ b/exynos/multimedia/utils/csc/exynos5/csc_tiled_to_linear_uv_deinterleave_neon.s @@ -0,0 +1,249 @@ +/* + * + * Copyright 2010 Samsung Electronics S.LSI Co. LTD + * + * Licensed under the Apache License, Version 2.0 (the "License") + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * @file csc_tiled_to_linear_uv_deinterleave_neon.s + * @brief SEC_OMX specific define. It support MFC 6.x tiled. + * @author ShinWon Lee (shinwon.lee@samsung.com) + * @version 1.0 + * @history + * 2011.12.01 : Create + */ + +/* + * Converts and Deinterleave tiled data to linear for mfc 6.x + * 1. UV of NV12T to Y of YUV420P + * + * @param u_dst + * U address of YUV420[out] + * + * @param v_dst + * V address of YUV420[out] + * + * @param uv_src + * UV address of NV12T[in] + * + * @param yuv420_width + * real width of YUV420[in]. It should be even. + * + * @param yuv420_height + * real height of YUV420[in] It should be even. + */ + + .arch armv7-a + .text + .global csc_tiled_to_linear_uv_deinterleave_neon + .type csc_tiled_to_linear_uv_deinterleave_neon, %function +csc_tiled_to_linear_uv_deinterleave_neon: + .fnstart + + .equ CACHE_LINE_SIZE, 64 + + @r0 u_dst + @r1 v_dst + @r2 uv_src + @r3 width + @r4 height + @r5 i + @r6 j + @r7 dst_offset + @r8 src_offset + @r9 aligned_height + @r10 aligned_width + @r11 tiled_width + @r12 temp1 + @r14 temp2 + + stmfd sp!, {r4-r12,r14} @ backup registers + ldr r4, [sp, #40] @ r4 = height + + bic r9, r4, #0x7 @ aligned_height = height & (~0x7) + bic r10, r3, #0xF @ aligned_width = width & (~0xF) + add r11, r3, #15 @ tiled_width = ((width + 15) >> 4) << 4 + mov r11, r11, asr #4 + mov r11, r11, lsl #4 + + mov r5, #0 +LOOP_MAIN_ALIGNED_HEIGHT: + mul r8, r11, r5 @ src_offset = tiled_width * i + mov r6, #0 + add r8, r2, r8 @ src_offset = uv_src + src_offset +LOOP_MAIN_ALIGNED_WIDTH: + mov r12, r3, asr #1 @ temp1 = (width >> 1) * i + (j >> 1) + mul r12, r12, r5 + + pld [r8, #CACHE_LINE_SIZE] + vld2.8 {q0, q1}, [r8]! + add r12, r12, r6, asr #1 + vld2.8 {q2, q3}, [r8]! + add r7, r0, r12 @ dst_offset = u_dst + temp1 + pld [r8, #CACHE_LINE_SIZE] + vld2.8 {q4, q5}, [r8]! + mov r14, r3, asr #1 @ temp2 = width / 2 + vld2.8 {q6, q7}, [r8]! + + vst1.8 {d0}, [r7], r14 + vst1.8 {d1}, [r7], r14 + vst1.8 {d4}, [r7], r14 + vst1.8 {d5}, [r7], r14 + vst1.8 {d8}, [r7], r14 + vst1.8 {d9}, [r7], r14 + vst1.8 {d12}, [r7], r14 + vst1.8 {d13}, [r7], r14 + + add r7, r1, r12 @ dst_offset = v_dst + temp1 + + vst1.8 {d2}, [r7], r14 + vst1.8 {d3}, [r7], r14 + vst1.8 {d6}, [r7], r14 + vst1.8 {d7}, [r7], r14 + vst1.8 {d10}, [r7], r14 + vst1.8 {d11}, [r7], r14 + add r6, r6, #16 + vst1.8 {d14}, [r7], r14 + cmp r6, r10 + vst1.8 {d15}, [r7], r14 + blt LOOP_MAIN_ALIGNED_WIDTH + +MAIN_REMAIN_WIDTH_START: + cmp r10, r3 @ if (aligned_width != width) { + beq MAIN_REMAIN_WIDTH_END + stmfd sp!, {r0-r2,r4} @ backup registers + mul r8, r11, r5 @ src_offset = (tiled_width * i) + (j << 3) + add r8, r8, r6, lsl #3 + add r8, r2, r8 @ r8 = uv_src + src_offset + mov r12, r3, asr #1 @ temp1 = (width >> 1) * i + (j >> 1) + mul r12, r12, r5 + add r12, r12, r6, asr #1 + add r7, r0, r12 @ r7 = u_dst + temp1 + add r12, r1, r12 @ r12 = v_dst + temp1 + sub r14, r3, r6 @ r14 = (width - j) / 2 + mov r14, r14, asr #1 + + mov r4, #0 +LOOP_MAIN_REMAIN_HEIGHT: + mov r0, #0 @ r0 is index in de-interleave +LOOP_MAIN_REMAIN_WIDTH: + ldrb r1, [r8], #1 + ldrb r2, [r8], #1 + strb r1, [r7], #1 + strb r2, [r12], #1 + add r0, #1 + cmp r0, r14 + blt LOOP_MAIN_REMAIN_WIDTH + + sub r8, r8, r14, lsl #1 + sub r7, r7, r14 + sub r12, r12, r14 + add r8, r8, #16 + add r7, r7, r3, asr #1 + add r12, r12, r3, asr #1 + + add r4, #1 + cmp r4, #8 + blt LOOP_MAIN_REMAIN_HEIGHT + ldmfd sp!, {r0-r2,r4} @ restore registers +MAIN_REMAIN_WIDTH_END: + + add r5, r5, #8 + cmp r5, r9 + blt LOOP_MAIN_ALIGNED_HEIGHT + +REMAIN_HEIGHT_START: + cmp r9, r4 @ if (aligned_height != height) { + beq REMAIN_HEIGHT_END + + mov r6, #0 +LOOP_REMAIN_HEIGHT_WIDTH16: + mul r8, r11, r5 @ src_offset = (tiled_width * i) + (j << 3) + add r8, r8, r6, lsl #3 + add r8, r2, r8 @ src_offset = uv_src + src_offset + + mov r12, r3, asr #1 @ temp1 = (width >> 1) * i + (j >> 1) + mul r12, r12, r5 + add r12, r12, r6, asr #1 + add r7, r0, r12 @ r7 = u_dst + temp1 + add r12, r1, r12 @ r12 = v_dst + temp1 + mov r14, r3, asr #1 @ temp2 = width / 2 + + stmfd sp!, {r0-r1} @ backup registers + mov r0, #0 + sub r1, r4, r9 +LOOP_REMAIN_HEIGHT_WIDTH16_HEIGHT1: + vld2.8 {d0, d1}, [r8]! + vst1.8 {d0}, [r7], r14 + vst1.8 {d1}, [r12], r14 + + add r0, r0, #1 + cmp r0, r1 + blt LOOP_REMAIN_HEIGHT_WIDTH16_HEIGHT1 + ldmfd sp!, {r0-r1} @ restore registers + + add r6, r6, #16 + cmp r6, r10 + blt LOOP_REMAIN_HEIGHT_WIDTH16 + +REMAIN_HEIGHT_REMAIN_WIDTH_START: + cmp r10, r3 + beq REMAIN_HEIGHT_REMAIN_WIDTH_END + mul r8, r11, r5 @ src_offset = (tiled_width * i) + (j << 3) + add r8, r8, r6, lsl #3 + add r8, r2, r8 @ src_offset = uv_src + src_offset + + mov r12, r3, asr #1 @ temp1 = (width >> 1) * i + (j >> 1) + mul r12, r12, r5 + add r12, r12, r6, asr #1 + add r7, r0, r12 @ r7 = u_dst + temp1 + add r12, r1, r12 @ r12 = v_dst + temp1 + sub r14, r3, r6 @ r14 = (width - j) /2 + mov r14, r14, asr #1 + + stmfd sp!, {r0-r2,r4-r5} @ backup registers + mov r0, #0 + sub r1, r4, r9 +LOOP_REMAIN_HEIGHT_REMAIN_WIDTH_HEIGHT1: + + mov r4, #0 +LOOP_REMAIN_HEIGHT_REMAIN_WIDTH_HEIGHT1_WIDTHx: + ldrb r2, [r8], #1 + ldrb r5, [r8], #1 + strb r2, [r7], #1 + strb r5, [r12], #1 + add r4, #1 + cmp r4, r14 + blt LOOP_REMAIN_HEIGHT_REMAIN_WIDTH_HEIGHT1_WIDTHx + + sub r8, r8, r14, lsl #1 + sub r7, r7, r14 + sub r12, r12, r14 + add r8, r8, #16 + add r7, r7, r3, asr #1 + add r12, r12, r3, asr #1 + + add r0, r0, #1 + cmp r0, r1 + blt LOOP_REMAIN_HEIGHT_REMAIN_WIDTH_HEIGHT1 + ldmfd sp!, {r0-r2,r4-r5} @ restore registers + +REMAIN_HEIGHT_REMAIN_WIDTH_END: + +REMAIN_HEIGHT_END: + +RESTORE_REG: + ldmfd sp!, {r4-r12,r15} @ restore registers + + .fnend diff --git a/exynos/multimedia/utils/csc/exynos5/csc_tiled_to_linear_uv_neon.s b/exynos/multimedia/utils/csc/exynos5/csc_tiled_to_linear_uv_neon.s new file mode 100644 index 0000000..ad58419 --- /dev/null +++ b/exynos/multimedia/utils/csc/exynos5/csc_tiled_to_linear_uv_neon.s @@ -0,0 +1,216 @@ +/* + * + * Copyright 2010 Samsung Electronics S.LSI Co. LTD + * + * Licensed under the Apache License, Version 2.0 (the "License") + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * @file csc_tiled_to_linear_uv.s + * @brief SEC_OMX specific define. It support MFC 6.x tiled. + * @author ShinWon Lee (shinwon.lee@samsung.com) + * @version 1.0 + * @history + * 2011.12.01 : Create + */ + +/* + * Converts tiled data to linear for mfc 6.x tiled + * 1. uv of nv12t to y of yuv420s + * + * @param dst + * uv address of yuv420s[out] + * + * @param src + * uv address of nv12t[in] + * + * @param yuv420_width + * real width of yuv420s[in] + * + * @param yuv420_height + * real height of yuv420s[in] + * + */ + .arch armv7-a + .text + .global csc_tiled_to_linear_uv_neon + .type csc_tiled_to_linear_uv_neon, %function +csc_tiled_to_linear_uv_neon: + .fnstart + + .equ CACHE_LINE_SIZE, 64 + + @r0 y_dst + @r1 y_src + @r2 width + @r3 height + @r4 temp3 + @r5 i + @r6 j + @r7 dst_offset + @r8 src_offset + @r9 aligned_height + @r10 aligned_width + @r11 tiled_width + @r12 temp1 + @r14 temp2 + + stmfd sp!, {r4-r12,r14} @ backup registers + ldr r4, [sp, #40] @ r4 = height + + bic r9, r3, #0x7 @ aligned_height = height & (~0xF) + bic r10, r2, #0xF @ aligned_width = width & (~0xF) + add r11, r2, #15 @ tiled_width = ((width + 15) >> 4) << 4 + mov r11, r11, asr #4 + mov r11, r11, lsl #4 + + mov r5, #0 +LOOP_MAIN_ALIGNED_HEIGHT: + mul r8, r11, r5 @ src_offset = tiled_width * i + mov r6, #0 + add r8, r1, r8 @ src_offset = y_src + src_offset +LOOP_MAIN_ALIGNED_WIDTH: + pld [r8, #CACHE_LINE_SIZE] + vld1.8 {q0, q1}, [r8]! + mul r12, r2, r5 @ temp1 = width * i + j; + vld1.8 {q2, q3}, [r8]! + add r12, r12, r6 + pld [r8, #CACHE_LINE_SIZE] + vld1.8 {q4, q5}, [r8]! + add r7, r0, r12 @ dst_offset = y_dst + temp1 + vld1.8 {q6, q7}, [r8]! + + vst1.8 {q0}, [r7], r2 + vst1.8 {q1}, [r7], r2 + vst1.8 {q2}, [r7], r2 + vst1.8 {q3}, [r7], r2 + vst1.8 {q4}, [r7], r2 + vst1.8 {q5}, [r7], r2 + vst1.8 {q6}, [r7], r2 + vst1.8 {q7}, [r7], r2 + add r6, r6, #16 + cmp r6, r10 + blt LOOP_MAIN_ALIGNED_WIDTH + +MAIN_REMAIN_WIDTH_START: + cmp r10, r2 @ if (aligned_width != width) { + beq MAIN_REMAIN_WIDTH_END + + mul r8, r11, r5 @ src_offset = (tiled_width * i) + (j << 3); + add r8, r8, r6, lsl #3 + add r8, r1, r8 @ r8 = y_src + src_offset + + mul r12, r2, r5 @ temp1 = width * i + j; + add r12, r12, r6 + add r7, r0, r12 @ r7 = y_dst + temp1 + sub r14, r2, r6 @ r14 = width - j + + stmfd sp!, {r0-r1} @ backup registers + mov r1, #0 +LOOP_MAIN_REMAIN_HEIGHT: + mov r0, #0 @ r0 is index in memcpy +LOOP_MAIN_REMAIN_WIDTH: + ldrh r4, [r8], #2 + strh r4, [r7], #2 + add r0, #2 + cmp r0, r14 + blt LOOP_MAIN_REMAIN_WIDTH + + sub r8, r8, r14 + sub r7, r7, r14 + add r8, r8, #16 + add r7, r7, r2 + + add r1, #1 + cmp r1, #8 + blt LOOP_MAIN_REMAIN_HEIGHT + ldmfd sp!, {r0-r1} @ restore registers +MAIN_REMAIN_WIDTH_END: + + add r5, r5, #8 + cmp r5, r9 + blt LOOP_MAIN_ALIGNED_HEIGHT + +REMAIN_HEIGHT_START: + cmp r9, r3 @ if (aligned_height != height) { + beq REMAIN_HEIGHT_END + + mov r6, #0 +LOOP_REMAIN_HEIGHT_WIDTH16: + mul r8, r11, r5 @ src_offset = (tiled_width * i) + (j << 3) + add r8, r8, r6, lsl #3 + add r8, r1, r8 @ src_offset = y_src + src_offset + + mul r12, r2, r5 @ temp1 = width * i + j; + add r12, r12, r6 + add r7, r0, r12 @ r7 = y_dst + temp1 + + sub r12, r3, r9 + mov r14, #0 +LOOP_REMAIN_HEIGHT_WIDTH16_HEIGHT1: + vld1.8 {q0}, [r8]! + vld1.8 {q1}, [r8]! + vst1.8 {q0}, [r7], r2 + vst1.8 {q1}, [r7], r2 + + add r14, r14, #2 + cmp r14, r12 + blt LOOP_REMAIN_HEIGHT_WIDTH16_HEIGHT1 + + add r6, r6, #16 + cmp r6, r10 + blt LOOP_REMAIN_HEIGHT_WIDTH16 + +REMAIN_HEIGHT_REMAIN_WIDTH_START: + cmp r10, r2 + beq REMAIN_HEIGHT_REMAIN_WIDTH_END + mul r8, r11, r5 @ src_offset = (tiled_width * i) + (j << 3) + add r8, r8, r6, lsl #3 + add r8, r1, r8 @ src_offset = y_src + src_offset + + mul r12, r2, r5 @ temp1 = width * i + j; + add r12, r12, r6 + add r7, r0, r12 @ r7 = y_dst + temp1 + + stmfd sp!, {r0-r1,r3} @ backup registers + mov r0, #0 + sub r1, r3, r9 +LOOP_REMAIN_HEIGHT_REMAIN_WIDTH_HEIGHT1: + + sub r14, r2, r6 + mov r4, #0 +LOOP_REMAIN_HEIGHT_REMAIN_WIDTH_HEIGHT1_WIDTHx: + ldrh r3, [r8], #2 + strh r3, [r7], #2 + add r4, #2 + cmp r4, r14 + blt LOOP_REMAIN_HEIGHT_REMAIN_WIDTH_HEIGHT1_WIDTHx + + sub r8, r8, r14 + sub r7, r7, r14 + add r8, r8, #16 + add r7, r7, r2 + + add r0, r0, #1 + cmp r0, r1 + blt LOOP_REMAIN_HEIGHT_REMAIN_WIDTH_HEIGHT1 + ldmfd sp!, {r0-r1,r3} @ restore registers + +REMAIN_HEIGHT_REMAIN_WIDTH_END: + +REMAIN_HEIGHT_END: + +RESTORE_REG: + ldmfd sp!, {r4-r12,r15} @ restore registers + + .fnend diff --git a/exynos/multimedia/utils/csc/exynos5/csc_tiled_to_linear_y_neon.s b/exynos/multimedia/utils/csc/exynos5/csc_tiled_to_linear_y_neon.s new file mode 100644 index 0000000..1aa3b13 --- /dev/null +++ b/exynos/multimedia/utils/csc/exynos5/csc_tiled_to_linear_y_neon.s @@ -0,0 +1,231 @@ +/* + * + * Copyright 2010 Samsung Electronics S.LSI Co. LTD + * + * Licensed under the Apache License, Version 2.0 (the "License") + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * @file csc_tiled_to_linear_y.s + * @brief SEC_OMX specific define. It support MFC 6.x tiled. + * @author ShinWon Lee (shinwon.lee@samsung.com) + * @version 1.0 + * @history + * 2011.12.01 : Create + */ + +/* + * Converts tiled data to linear for mfc 6.x + * 1. Y of NV12T to Y of YUV420P + * 2. Y of NV12T to Y of YUV420S + * + * @param dst + * Y address of YUV420[out] + * + * @param src + * Y address of NV12T[in] + * + * @param yuv420_width + * real width of YUV420[in]. It should be even. + * + * @param yuv420_height + * real height of YUV420[in] It should be even. + * + */ + .arch armv7-a + .text + .global csc_tiled_to_linear_y_neon + .type csc_tiled_to_linear_y_neon, %function +csc_tiled_to_linear_y_neon: + .fnstart + + .equ CACHE_LINE_SIZE, 64 + + @r0 y_dst + @r1 y_src + @r2 width + @r3 height + @r4 temp3 + @r5 i + @r6 j + @r7 dst_offset + @r8 src_offset + @r9 aligned_height + @r10 aligned_width + @r11 tiled_width + @r12 temp1 + @r14 temp2 + + stmfd sp!, {r4-r12,r14} @ backup registers + ldr r4, [sp, #40] @ r4 = height + + bic r9, r3, #0xF @ aligned_height = height & (~0xF) + bic r10, r2, #0xF @ aligned_width = width & (~0xF) + add r11, r2, #15 @ tiled_width = ((width + 15) >> 4) << 4 + mov r11, r11, asr #4 + mov r11, r11, lsl #4 + + mov r5, #0 +LOOP_MAIN_ALIGNED_HEIGHT: + mul r8, r11, r5 @ src_offset = tiled_width * i + mov r6, #0 + add r8, r1, r8 @ src_offset = y_src + src_offset +LOOP_MAIN_ALIGNED_WIDTH: + pld [r8, #CACHE_LINE_SIZE] + vld1.8 {q0, q1}, [r8]! + vld1.8 {q2, q3}, [r8]! + pld [r8, #CACHE_LINE_SIZE] + vld1.8 {q4, q5}, [r8]! + vld1.8 {q6, q7}, [r8]! + mul r12, r2, r5 @ temp1 = width * i + j; + pld [r8, #CACHE_LINE_SIZE] + vld1.8 {q8, q9}, [r8]! + add r12, r12, r6 + vld1.8 {q10, q11}, [r8]! + add r7, r0, r12 @ dst_offset = y_dst + temp1 + pld [r8, #CACHE_LINE_SIZE] + vld1.8 {q12, q13}, [r8]! + vld1.8 {q14, q15}, [r8]! + + vst1.8 {q0}, [r7], r2 + vst1.8 {q1}, [r7], r2 + vst1.8 {q2}, [r7], r2 + vst1.8 {q3}, [r7], r2 + vst1.8 {q4}, [r7], r2 + vst1.8 {q5}, [r7], r2 + vst1.8 {q6}, [r7], r2 + vst1.8 {q7}, [r7], r2 + vst1.8 {q8}, [r7], r2 + vst1.8 {q9}, [r7], r2 + vst1.8 {q10}, [r7], r2 + vst1.8 {q11}, [r7], r2 + vst1.8 {q12}, [r7], r2 + vst1.8 {q13}, [r7], r2 + add r6, r6, #16 + vst1.8 {q14}, [r7], r2 + cmp r6, r10 + vst1.8 {q15}, [r7], r2 + blt LOOP_MAIN_ALIGNED_WIDTH + +MAIN_REMAIN_WIDTH_START: + cmp r10, r2 @ if (aligned_width != width) { + beq MAIN_REMAIN_WIDTH_END + + mul r8, r11, r5 @ src_offset = (tiled_width * i) + (j << 4); + add r8, r8, r6, lsl #4 + add r8, r1, r8 @ r8 = y_src + src_offset + + mul r12, r2, r5 @ temp1 = width * i + j; + add r12, r12, r6 + add r7, r0, r12 @ r7 = y_dst + temp1 + sub r14, r2, r6 @ r14 = width - j + + stmfd sp!, {r0-r1} @ backup registers + mov r1, #0 +LOOP_MAIN_REMAIN_HEIGHT: + mov r0, #0 @ r0 is index in memcpy +LOOP_MAIN_REMAIN_WIDTH: + ldrh r4, [r8], #2 + strh r4, [r7], #2 + add r0, #2 + cmp r0, r14 + blt LOOP_MAIN_REMAIN_WIDTH + + sub r8, r8, r14 + sub r7, r7, r14 + add r8, r8, #16 + add r7, r7, r2 + + add r1, #1 + cmp r1, #16 + blt LOOP_MAIN_REMAIN_HEIGHT + ldmfd sp!, {r0-r1} @ restore registers +MAIN_REMAIN_WIDTH_END: + + add r5, r5, #16 + cmp r5, r9 + blt LOOP_MAIN_ALIGNED_HEIGHT + +REMAIN_HEIGHT_START: + cmp r9, r3 @ if (aligned_height != height) { + beq REMAIN_HEIGHT_END + + mov r6, #0 +LOOP_REMAIN_HEIGHT_WIDTH16: + mul r8, r11, r5 @ src_offset = (tiled_width * i) + (j << 4) + add r8, r8, r6, lsl #4 + add r8, r1, r8 @ src_offset = y_src + src_offset + + mul r12, r2, r5 @ temp1 = width * i + j; + add r12, r12, r6 + add r7, r0, r12 @ r7 = y_dst + temp1 + + sub r12, r3, r9 + mov r14, #0 +LOOP_REMAIN_HEIGHT_WIDTH16_HEIGHT1: + vld1.8 {q0}, [r8]! + vld1.8 {q1}, [r8]! + vst1.8 {q0}, [r7], r2 + vst1.8 {q1}, [r7], r2 + + add r14, r14, #2 + cmp r14, r12 + blt LOOP_REMAIN_HEIGHT_WIDTH16_HEIGHT1 + + add r6, r6, #16 + cmp r6, r10 + blt LOOP_REMAIN_HEIGHT_WIDTH16 + +REMAIN_HEIGHT_REMAIN_WIDTH_START: + cmp r10, r2 + beq REMAIN_HEIGHT_REMAIN_WIDTH_END + mul r8, r11, r5 @ src_offset = (tiled_width * i) + (j << 4) + add r8, r8, r6, lsl #4 + add r8, r1, r8 @ src_offset = y_src + src_offset + + mul r12, r2, r5 @ temp1 = width * i + j; + add r12, r12, r6 + add r7, r0, r12 @ r7 = y_dst + temp1 + + stmfd sp!, {r0-r1,r3} @ backup registers + mov r0, #0 + sub r1, r3, r9 +LOOP_REMAIN_HEIGHT_REMAIN_WIDTH_HEIGHT1: + + sub r14, r2, r6 + mov r4, #0 +LOOP_REMAIN_HEIGHT_REMAIN_WIDTH_HEIGHT1_WIDTHx: + ldrh r3, [r8], #2 + strh r3, [r7], #2 + add r4, #2 + cmp r4, r14 + blt LOOP_REMAIN_HEIGHT_REMAIN_WIDTH_HEIGHT1_WIDTHx + + sub r8, r8, r14 + sub r7, r7, r14 + add r8, r8, #16 + add r7, r7, r2 + + add r0, r0, #1 + cmp r0, r1 + blt LOOP_REMAIN_HEIGHT_REMAIN_WIDTH_HEIGHT1 + ldmfd sp!, {r0-r1,r3} @ restore registers + +REMAIN_HEIGHT_REMAIN_WIDTH_END: + +REMAIN_HEIGHT_END: + +RESTORE_REG: + ldmfd sp!, {r4-r12,r15} @ restore registers + + .fnend |