1 /* 2 * Copyright (C) 2013 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 18 #include "rsCpuIntrinsic.h" 19 #include "rsCpuIntrinsicInlines.h" 20 21 #ifdef RS_COMPATIBILITY_LIB 22 #include "rsCompatibilityLib.h" 23 #endif 24 25 #ifndef RS_COMPATIBILITY_LIB 26 #include "hardware/gralloc.h" 27 #endif 28 29 using namespace android; 30 using namespace android::renderscript; 31 32 namespace android { 33 namespace renderscript { 34 35 36 class RsdCpuScriptIntrinsicYuvToRGB : public RsdCpuScriptIntrinsic { 37 public: 38 virtual void populateScript(Script *); 39 virtual void invokeFreeChildren(); 40 41 virtual void setGlobalObj(uint32_t slot, ObjectBase *data); 42 43 virtual ~RsdCpuScriptIntrinsicYuvToRGB(); 44 RsdCpuScriptIntrinsicYuvToRGB(RsdCpuReferenceImpl *ctx, const Script *s, const Element *e); 45 46 protected: 47 ObjectBaseRef<Allocation> alloc; 48 49 static void kernel(const RsForEachStubParamStruct *p, 50 uint32_t xstart, uint32_t xend, 51 uint32_t instep, uint32_t outstep); 52 }; 53 54 } 55 } 56 57 58 void RsdCpuScriptIntrinsicYuvToRGB::setGlobalObj(uint32_t slot, ObjectBase *data) { 59 rsAssert(slot == 0); 60 alloc.set(static_cast<Allocation *>(data)); 61 } 62 63 64 65 66 static uchar4 rsYuvToRGBA_uchar4(uchar y, uchar u, uchar v) { 67 short Y = ((short)y) - 16; 68 short U = ((short)u) - 128; 69 short V = ((short)v) - 128; 70 71 short4 p; 72 p.x = (Y * 298 + V * 409 + 128) >> 8; 73 p.y = (Y * 298 - U * 100 - V * 208 + 128) >> 8; 74 p.z = (Y * 298 + U * 516 + 128) >> 8; 75 p.w = 255; 76 if(p.x < 0) { 77 p.x = 0; 78 } 79 if(p.x > 255) { 80 p.x = 255; 81 } 82 if(p.y < 0) { 83 p.y = 0; 84 } 85 if(p.y > 255) { 86 p.y = 255; 87 } 88 if(p.z < 0) { 89 p.z = 0; 90 } 91 if(p.z > 255) { 92 p.z = 255; 93 } 94 95 return (uchar4){p.x, p.y, p.z, p.w}; 96 } 97 98 99 static short YuvCoeff[] = { 100 298, 409, -100, 516, -208, 255, 0, 0, 101 16, 16, 16, 16, 16, 16, 16, 16, 102 128, 128, 128, 128, 128, 128, 128, 128, 103 298, 298, 298, 298, 298, 298, 298, 298, 104 255, 255, 255, 255, 255, 255, 255, 255 105 106 107 }; 108 109 extern "C" void rsdIntrinsicYuv_K(void *dst, const uchar *Y, const uchar *uv, uint32_t count, const short *param); 110 extern "C" void rsdIntrinsicYuvR_K(void *dst, const uchar *Y, const uchar *uv, uint32_t count, const short *param); 111 extern "C" void rsdIntrinsicYuv2_K(void *dst, const uchar *Y, const uchar *u, const uchar *v, uint32_t count, const short *param); 112 113 void RsdCpuScriptIntrinsicYuvToRGB::kernel(const RsForEachStubParamStruct *p, 114 uint32_t xstart, uint32_t xend, 115 uint32_t instep, uint32_t outstep) { 116 RsdCpuScriptIntrinsicYuvToRGB *cp = (RsdCpuScriptIntrinsicYuvToRGB *)p->usr; 117 if (!cp->alloc.get()) { 118 ALOGE("YuvToRGB executed without input, skipping"); 119 return; 120 } 121 const uchar *pinY = (const uchar *)cp->alloc->mHal.drvState.lod[0].mallocPtr; 122 if (pinY == NULL) { 123 ALOGE("YuvToRGB executed without data, skipping"); 124 return; 125 } 126 127 size_t strideY = cp->alloc->mHal.drvState.lod[0].stride; 128 129 // calculate correct stride in legacy case 130 if (cp->alloc->mHal.drvState.lod[0].dimY == 0) { 131 strideY = p->dimX; 132 } 133 const uchar *Y = pinY + (p->y * strideY); 134 135 uchar4 *out = (uchar4 *)p->out; 136 uint32_t x1 = xstart; 137 uint32_t x2 = xend; 138 139 size_t cstep = cp->alloc->mHal.drvState.yuv.step; 140 141 const uchar *pinU = (const uchar *)cp->alloc->mHal.drvState.lod[1].mallocPtr; 142 const size_t strideU = cp->alloc->mHal.drvState.lod[1].stride; 143 const uchar *u = pinU + ((p->y >> 1) * strideU); 144 145 const uchar *pinV = (const uchar *)cp->alloc->mHal.drvState.lod[2].mallocPtr; 146 const size_t strideV = cp->alloc->mHal.drvState.lod[2].stride; 147 const uchar *v = pinV + ((p->y >> 1) * strideV); 148 149 //ALOGE("pinY, %p, Y, %p, p->y, %d, strideY, %d", pinY, Y, p->y, strideY); 150 //ALOGE("pinU, %p, U, %p, p->y, %d, strideU, %d", pinU, u, p->y, strideU); 151 //ALOGE("pinV, %p, V, %p, p->y, %d, strideV, %d", pinV, v, p->y, strideV); 152 //ALOGE("dimX, %d, dimY, %d", cp->alloc->mHal.drvState.lod[0].dimX, cp->alloc->mHal.drvState.lod[0].dimY); 153 //ALOGE("p->dimX, %d, p->dimY, %d", p->dimX, p->dimY); 154 155 if (pinU == NULL) { 156 // Legacy yuv support didn't fill in uv 157 v = ((uint8_t *)cp->alloc->mHal.drvState.lod[0].mallocPtr) + 158 (strideY * p->dimY) + 159 ((p->y >> 1) * strideY); 160 u = v + 1; 161 cstep = 2; 162 } 163 164 #if defined(ARCH_ARM_HAVE_VFP) 165 if((x2 > x1) && gArchUseSIMD) { 166 // The neon paths may over-read by up to 8 bytes 167 int32_t len = (x2 - x1 - 8) >> 3; 168 if(len > 0) { 169 if (cstep == 1) { 170 rsdIntrinsicYuv2_K(out, Y, u, v, len, YuvCoeff); 171 x1 += len << 3; 172 out += len << 3; 173 } else if (cstep == 2) { 174 // Check for proper interleave 175 intptr_t ipu = (intptr_t)u; 176 intptr_t ipv = (intptr_t)v; 177 178 if (ipu == (ipv + 1)) { 179 rsdIntrinsicYuv_K(out, Y, v, len, YuvCoeff); 180 x1 += len << 3; 181 out += len << 3; 182 } else if (ipu == (ipv - 1)) { 183 rsdIntrinsicYuvR_K(out, Y, u, len, YuvCoeff); 184 x1 += len << 3; 185 out += len << 3; 186 } 187 188 } 189 } 190 } 191 #endif 192 193 if(x2 > x1) { 194 // ALOGE("y %i %i %i", p->y, x1, x2); 195 while(x1 < x2) { 196 int cx = (x1 >> 1) * cstep; 197 *out = rsYuvToRGBA_uchar4(Y[x1], u[cx], v[cx]); 198 out++; 199 x1++; 200 *out = rsYuvToRGBA_uchar4(Y[x1], u[cx], v[cx]); 201 out++; 202 x1++; 203 } 204 } 205 206 } 207 208 RsdCpuScriptIntrinsicYuvToRGB::RsdCpuScriptIntrinsicYuvToRGB( 209 RsdCpuReferenceImpl *ctx, const Script *s, const Element *e) 210 : RsdCpuScriptIntrinsic(ctx, s, e, RS_SCRIPT_INTRINSIC_ID_YUV_TO_RGB) { 211 212 mRootPtr = &kernel; 213 } 214 215 RsdCpuScriptIntrinsicYuvToRGB::~RsdCpuScriptIntrinsicYuvToRGB() { 216 } 217 218 void RsdCpuScriptIntrinsicYuvToRGB::populateScript(Script *s) { 219 s->mHal.info.exportedVariableCount = 1; 220 } 221 222 void RsdCpuScriptIntrinsicYuvToRGB::invokeFreeChildren() { 223 alloc.clear(); 224 } 225 226 227 RsdCpuScriptImpl * rsdIntrinsic_YuvToRGB(RsdCpuReferenceImpl *ctx, 228 const Script *s, const Element *e) { 229 return new RsdCpuScriptIntrinsicYuvToRGB(ctx, s, e); 230 } 231 232 233