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 #include <cstdint>
18
19 #include "RenderScriptToolkit.h"
20 #include "TaskProcessor.h"
21 #include "Utils.h"
22
23 #define LOG_TAG "renderscript.toolkit.YuvToRgb"
24
25 namespace renderscript {
26
roundUpTo16(size_t val)27 inline size_t roundUpTo16(size_t val) {
28 return (val + 15u) & ~15u;
29 }
30
31 class YuvToRgbTask : public Task {
32 uchar4* mOut;
33 size_t mCstep;
34 size_t mStrideY;
35 size_t mStrideU;
36 size_t mStrideV;
37 const uchar* mInY;
38 const uchar* mInU;
39 const uchar* mInV;
40
41 void kernel(uchar4* out, uint32_t xstart, uint32_t xend, uint32_t currentY);
42 // Process a 2D tile of the overall work. threadIndex identifies which thread does the work.
43 void processData(int threadIndex, size_t startX, size_t startY, size_t endX,
44 size_t endY) override;
45
46 public:
YuvToRgbTask(const uint8_t * input,uint8_t * output,size_t sizeX,size_t sizeY,RenderScriptToolkit::YuvFormat format)47 YuvToRgbTask(const uint8_t* input, uint8_t* output, size_t sizeX, size_t sizeY,
48 RenderScriptToolkit::YuvFormat format)
49 : Task{sizeX, sizeY, 4, false, nullptr}, mOut{reinterpret_cast<uchar4*>(output)} {
50 switch (format) {
51 case RenderScriptToolkit::YuvFormat::NV21:
52 mCstep = 2;
53 mStrideY = sizeX;
54 mStrideU = mStrideY;
55 mStrideV = mStrideY;
56 mInY = reinterpret_cast<const uchar*>(input);
57 mInV = reinterpret_cast<const uchar*>(input + mStrideY * sizeY);
58 mInU = mInV + 1;
59 break;
60 case RenderScriptToolkit::YuvFormat::YV12:
61 mCstep = 1;
62 mStrideY = roundUpTo16(sizeX);
63 mStrideU = roundUpTo16(mStrideY >> 1u);
64 mStrideV = mStrideU;
65 mInY = reinterpret_cast<const uchar*>(input);
66 mInU = reinterpret_cast<const uchar*>(input + mStrideY * sizeY);
67 mInV = mInU + mStrideV * sizeY / 2;
68 break;
69 }
70 }
71 };
72
processData(int,size_t startX,size_t startY,size_t endX,size_t endY)73 void YuvToRgbTask::processData(int /* threadIndex */, size_t startX, size_t startY, size_t endX,
74 size_t endY) {
75 for (size_t y = startY; y < endY; y++) {
76 size_t offset = mSizeX * y + startX;
77 uchar4* out = mOut + offset;
78 kernel(out, startX, endX, y);
79 }
80 }
81
rsYuvToRGBA_uchar4(uchar y,uchar u,uchar v)82 static uchar4 rsYuvToRGBA_uchar4(uchar y, uchar u, uchar v) {
83 int16_t Y = ((int16_t)y) - 16;
84 int16_t U = ((int16_t)u) - 128;
85 int16_t V = ((int16_t)v) - 128;
86
87 short4 p;
88 p.x = (Y * 298 + V * 409 + 128) >> 8;
89 p.y = (Y * 298 - U * 100 - V * 208 + 128) >> 8;
90 p.z = (Y * 298 + U * 516 + 128) >> 8;
91 p.w = 255;
92 if(p.x < 0) {
93 p.x = 0;
94 }
95 if(p.x > 255) {
96 p.x = 255;
97 }
98 if(p.y < 0) {
99 p.y = 0;
100 }
101 if(p.y > 255) {
102 p.y = 255;
103 }
104 if(p.z < 0) {
105 p.z = 0;
106 }
107 if(p.z > 255) {
108 p.z = 255;
109 }
110
111 return (uchar4){static_cast<uchar>(p.x), static_cast<uchar>(p.y),
112 static_cast<uchar>(p.z), static_cast<uchar>(p.w)};
113 }
114
115 extern "C" void rsdIntrinsicYuv_K(void *dst, const uchar *Y, const uchar *uv, uint32_t xstart,
116 size_t xend);
117 extern "C" void rsdIntrinsicYuvR_K(void *dst, const uchar *Y, const uchar *uv, uint32_t xstart,
118 size_t xend);
119 extern "C" void rsdIntrinsicYuv2_K(void *dst, const uchar *Y, const uchar *u, const uchar *v,
120 size_t xstart, size_t xend);
121
kernel(uchar4 * out,uint32_t xstart,uint32_t xend,uint32_t currentY)122 void YuvToRgbTask::kernel(uchar4 *out, uint32_t xstart, uint32_t xend, uint32_t currentY) {
123 //ALOGI("kernel out %p, xstart=%u, xend=%u, currentY=%u", out, xstart, xend, currentY);
124
125 const uchar *y = mInY + (currentY * mStrideY);
126 const uchar *v = mInV + ((currentY >> 1) * mStrideV);
127 const uchar *u = mInU + ((currentY >> 1) * mStrideU);
128
129 //ALOGI("pinY %p, pinV %p, pinU %p", pinY, pinV, pinU);
130
131 uint32_t x1 = xstart;
132 uint32_t x2 = xend;
133
134 /*
135 ALOGE("pinY, %p, Y, %p, currentY, %d, strideY, %zu", pinY, y, currentY, mStrideY);
136 ALOGE("pinU, %p, U, %p, currentY, %d, strideU, %zu", pinU, u, currentY, mStrideU);
137 ALOGE("pinV, %p, V, %p, currentY, %d, strideV, %zu", pinV, v, currentY, mStrideV);
138 ALOGE("dimX, %d, dimY, %d", cp->alloc->mHal.drvState.lod[0].dimX,
139 cp->alloc->mHal.drvState.lod[0].dimY);
140 ALOGE("info->dim.x, %d, info->dim.y, %d", info->dim.x, info->dim.y);
141 uchar* pinY = (uchar*)mInY;
142 uchar* pinU = (uchar*)mInU;
143 uchar* pinV = (uchar*)mInV;
144 ALOGE("Y %p %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx "
145 "%02hhx %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx",
146 pinY, pinY[0], pinY[1], pinY[2], pinY[3], pinY[4], pinY[5], pinY[6], pinY[7], pinY[8],
147 pinY[9], pinY[10], pinY[11], pinY[12], pinY[13], pinY[14], pinY[15]);
148 ALOGE("Y %p %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx "
149 "%02hhx %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx",
150 pinY, pinY[16], pinY[17], pinY[18], pinY[19], pinY[20], pinY[21], pinY[22], pinY[23],
151 pinY[24], pinY[25], pinY[26], pinY[27], pinY[28], pinY[29], pinY[30], pinY[31]);
152 ALOGE("Y %p %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx "
153 "%02hhx %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx",
154 pinY, pinY[32], pinY[33], pinY[34], pinY[35], pinY[36], pinY[37], pinY[38], pinY[39],
155 pinY[40], pinY[41], pinY[42], pinY[43], pinY[44], pinY[45], pinY[46], pinY[47]);
156
157 ALOGE("U %p %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx "
158 "%02hhx %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx",
159 pinU, pinU[0], pinU[1], pinU[2], pinU[3], pinU[4], pinU[5], pinU[6], pinU[7], pinU[8],
160 pinU[9], pinU[10], pinU[11], pinU[12], pinU[13], pinU[14], pinU[15]);
161 ALOGE("U %p %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx "
162 "%02hhx %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx",
163 pinU, pinU[16], pinU[17], pinU[18], pinU[19], pinU[20], pinU[21], pinU[22], pinU[23],
164 pinU[24], pinU[25], pinU[26], pinU[27], pinU[28], pinU[29], pinU[30], pinU[31]);
165 ALOGE("U %p %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx "
166 "%02hhx %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx",
167 pinU, pinU[32], pinU[33], pinU[34], pinU[35], pinU[36], pinU[37], pinU[38], pinU[39],
168 pinU[40], pinU[41], pinU[42], pinU[43], pinU[44], pinU[45], pinU[46], pinU[47]);
169
170 ALOGE("V %p %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx "
171 "%02hhx %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx",
172 pinV, pinV[0], pinV[1], pinV[2], pinV[3], pinV[4], pinV[5], pinV[6], pinV[7], pinV[8],
173 pinV[9], pinV[10], pinV[11], pinV[12], pinV[13], pinV[14], pinV[15]);
174 ALOGE("V %p %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx "
175 "%02hhx %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx",
176 pinV, pinV[16], pinV[17], pinV[18], pinV[19], pinV[20], pinV[21], pinV[22], pinV[23],
177 pinV[24], pinV[25], pinV[26], pinV[27], pinV[28], pinV[29], pinV[30], pinV[31]);
178 ALOGE("V %p %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx "
179 "%02hhx %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx",
180 pinV, pinV[32], pinV[33], pinV[34], pinV[35], pinV[36], pinV[37], pinV[38], pinV[39],
181 pinV[40], pinV[41], pinV[42], pinV[43], pinV[44], pinV[45], pinV[46], pinV[47]);
182 */
183
184 /* If we start on an odd pixel then deal with it here and bump things along
185 * so that subsequent code can carry on with even-odd pairing assumptions.
186 */
187 if((x1 & 1) && (x2 > x1)) {
188 int cx = (x1 >> 1) * mCstep;
189 *out = rsYuvToRGBA_uchar4(y[x1], u[cx], v[cx]);
190 out++;
191 x1++;
192 }
193
194 #if defined(ARCH_ARM_USE_INTRINSICS)
195 if((x2 > x1) && mUsesSimd) {
196 int32_t len = x2 - x1;
197 if (mCstep == 1) {
198 rsdIntrinsicYuv2_K(out, y, u, v, x1, x2);
199 x1 += len;
200 out += len;
201 } else if (mCstep == 2) {
202 // Check for proper interleave
203 intptr_t ipu = (intptr_t)u;
204 intptr_t ipv = (intptr_t)v;
205
206 if (ipu == (ipv + 1)) {
207 rsdIntrinsicYuv_K(out, y, v, x1, x2);
208 x1 += len;
209 out += len;
210 } else if (ipu == (ipv - 1)) {
211 rsdIntrinsicYuvR_K(out, y, u, x1, x2);
212 x1 += len;
213 out += len;
214 }
215 }
216 }
217 #endif
218
219 if(x2 > x1) {
220 // ALOGE("y %i %i %i", currentY, x1, x2);
221 while(x1 < x2) {
222 int cx = (x1 >> 1) * mCstep;
223 *out = rsYuvToRGBA_uchar4(y[x1], u[cx], v[cx]);
224 out++;
225 x1++;
226 *out = rsYuvToRGBA_uchar4(y[x1], u[cx], v[cx]);
227 out++;
228 x1++;
229 }
230 }
231 }
232
yuvToRgb(const uint8_t * input,uint8_t * output,size_t sizeX,size_t sizeY,YuvFormat format)233 void RenderScriptToolkit::yuvToRgb(const uint8_t* input, uint8_t* output, size_t sizeX,
234 size_t sizeY, YuvFormat format) {
235 YuvToRgbTask task(input, output, sizeX, sizeY, format);
236 processor->doTask(&task);
237 }
238
239 } // namespace renderscript
240