1/*
2 * Copyright (C) 2011 University of Szeged
3 * Copyright (C) 2011 Zoltan Herczeg
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY UNIVERSITY OF SZEGED ``AS IS'' AND ANY
15 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL UNIVERSITY OF SZEGED OR
18 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27#include "config.h"
28#include "FELightingNeonSIMD.h"
29
30#if CPU(ARM) && ENABLE(ARM_NEON) && COMPILER(GCC)
31
32namespace WebCore {
33
34// These constants are copied to the following SIMD registers:
35// ALPHAX_Q ALPHAY_Q REMAPX_D REMAPY_D
36
37short s_FELightingConstantsForNeon[] __attribute__((aligned(0x10))) = {
38 // Alpha coefficients.
39 -2, 1, 0, -1, 2, 1, 0, -1,
40 0, -1, -2, -1, 0, 1, 2, 1,
41 // Remapping indicies.
42 0x0f0e, 0x0302, 0x0504, 0x0706,
43 0x0b0a, 0x1312, 0x1514, 0x1716,
44};
45
46#define ASSTRING(str) #str
47#define TOSTRING(value) ASSTRING(value)
48
49#define PIXELS_OFFSET TOSTRING(0)
50#define WIDTH_OFFSET TOSTRING(4)
51#define HEIGHT_OFFSET TOSTRING(8)
52#define FLAGS_OFFSET TOSTRING(12)
53#define SPECULAR_EXPONENT_OFFSET TOSTRING(16)
54#define CONE_EXPONENT_OFFSET TOSTRING(20)
55#define FLOAT_ARGUMENTS_OFFSET TOSTRING(24)
56#define DRAWING_CONSTANTS_OFFSET TOSTRING(28)
57#define NL "\n"
58
59// Register allocation
60#define PAINTING_DATA_R "r11"
61#define RESET_WIDTH_R PAINTING_DATA_R
62#define PIXELS_R "r4"
63#define WIDTH_R "r5"
64#define HEIGHT_R "r6"
65#define FLAGS_R "r7"
66#define SPECULAR_EXPONENT_R "r8"
67#define CONE_EXPONENT_R "r10"
68#define SCANLINE_R "r12"
69
70#define TMP1_Q "q0"
71#define TMP1_D0 "d0"
72#define TMP1_S0 "s0"
73#define TMP1_S1 "s1"
74#define TMP1_D1 "d1"
75#define TMP1_S2 "s2"
76#define TMP1_S3 "s3"
77#define TMP2_Q "q1"
78#define TMP2_D0 "d2"
79#define TMP2_S0 "s4"
80#define TMP2_S1 "s5"
81#define TMP2_D1 "d3"
82#define TMP2_S2 "s6"
83#define TMP2_S3 "s7"
84#define TMP3_Q "q2"
85#define TMP3_D0 "d4"
86#define TMP3_S0 "s8"
87#define TMP3_S1 "s9"
88#define TMP3_D1 "d5"
89#define TMP3_S2 "s10"
90#define TMP3_S3 "s11"
91
92#define COSINE_OF_ANGLE "s12"
93#define POWF_INT_S "s13"
94#define POWF_FRAC_S "s14"
95#define SPOT_COLOR_Q "q4"
96
97// Because of VMIN and VMAX CONST_ZERO_S and CONST_ONE_S
98// must be placed on the same side of the double vector
99
100// Current pixel position
101#define POSITION_Q "q5"
102#define POSITION_X_S "s20"
103#define POSITION_Y_S "s21"
104#define POSITION_Z_S "s22"
105#define CONST_ZERO_HI_D "d11"
106#define CONST_ZERO_S "s23"
107
108// -------------------------------
109// Variable arguments
110// Misc arguments
111#define READ1_RANGE "d12-d15"
112#define READ2_RANGE "d16-d19"
113#define READ3_RANGE "d20-d21"
114
115#define SCALE_S "s24"
116#define SCALE_DIV4_S "s25"
117#define DIFFUSE_CONST_S "s26"
118
119// Light source position
120#define CONE_CUT_OFF_S "s28"
121#define CONE_FULL_LIGHT_S "s29"
122#define CONE_CUT_OFF_RANGE_S "s30"
123#define CONST_ONE_HI_D "d15"
124#define CONST_ONE_S "s31"
125
126#define LIGHT_Q "q8"
127#define DIRECTION_Q "q9"
128#define COLOR_Q "q10"
129// -------------------------------
130// Constant coefficients
131#define READ4_RANGE "d22-d25"
132#define READ5_RANGE "d26-d27"
133
134#define ALPHAX_Q "q11"
135#define ALPHAY_Q "q12"
136#define REMAPX_D "d26"
137#define REMAPY_D "d27"
138// -------------------------------
139
140#define ALL_ROWS_D "{d28,d29,d30}"
141#define TOP_ROW_D "d28"
142#define MIDDLE_ROW_D "d29"
143#define BOTTOM_ROW_D "d30"
144
145#define GET_LENGTH(source, temp) \
146 "vmul.f32 " temp##_Q ", " source##_Q ", " source##_Q NL \
147 "vadd.f32 " source##_S3 ", " temp##_S0 ", " temp##_S1 NL \
148 "vadd.f32 " source##_S3 ", " source##_S3 ", " temp##_S2 NL \
149 "vsqrt.f32 " source##_S3 ", " source##_S3 NL
150
151// destination##_S3 can contain the multiply of length.
152#define DOT_PRODUCT(destination, source1, source2) \
153 "vmul.f32 " destination##_Q ", " source1##_Q ", " source2##_Q NL \
154 "vadd.f32 " destination##_S0 ", " destination##_S0 ", " destination##_S1 NL \
155 "vadd.f32 " destination##_S0 ", " destination##_S0 ", " destination##_S2 NL
156
157#define MULTIPLY_BY_DIFFUSE_CONST(normalVectorLength, dotProductLength) \
158 "tst " FLAGS_R ", #" TOSTRING(FLAG_DIFFUSE_CONST_IS_1) NL \
159 "vmuleq.f32 " TMP2_S1 ", " DIFFUSE_CONST_S ", " normalVectorLength NL \
160 "vdiveq.f32 " TMP2_S1 ", " TMP2_S1 ", " dotProductLength NL \
161 "vdivne.f32 " TMP2_S1 ", " normalVectorLength ", " dotProductLength NL
162
163#define POWF_SQR(value, exponent, current, remaining) \
164 "tst " exponent ", #" ASSTRING(current) NL \
165 "vmulne.f32 " value ", " value ", " POWF_INT_S NL \
166 "tst " exponent ", #" ASSTRING(remaining) NL \
167 "vmulne.f32 " POWF_INT_S ", " POWF_INT_S ", " POWF_INT_S NL
168
169#define POWF_SQRT(value, exponent, current, remaining) \
170 "tst " exponent ", #" ASSTRING(remaining) NL \
171 "vsqrtne.f32 " POWF_FRAC_S ", " POWF_FRAC_S NL \
172 "tst " exponent ", #" ASSTRING(current) NL \
173 "vmulne.f32 " value ", " value ", " POWF_FRAC_S NL
174
175#define POWF(value, exponent) \
176 "tst " exponent ", #0xfc0" NL \
177 "vmovne.f32 " POWF_INT_S ", " value NL \
178 "tst " exponent ", #0x03f" NL \
179 "vmovne.f32 " POWF_FRAC_S ", " value NL \
180 "vmov.f32 " value ", " CONST_ONE_S NL \
181 \
182 POWF_SQR(value, exponent, 0x040, 0xf80) \
183 POWF_SQR(value, exponent, 0x080, 0xf00) \
184 POWF_SQR(value, exponent, 0x100, 0xe00) \
185 POWF_SQR(value, exponent, 0x200, 0xc00) \
186 POWF_SQR(value, exponent, 0x400, 0x800) \
187 "tst " exponent ", #0x800" NL \
188 "vmulne.f32 " value ", " value ", " POWF_INT_S NL \
189 \
190 POWF_SQRT(value, exponent, 0x20, 0x3f) \
191 POWF_SQRT(value, exponent, 0x10, 0x1f) \
192 POWF_SQRT(value, exponent, 0x08, 0x0f) \
193 POWF_SQRT(value, exponent, 0x04, 0x07) \
194 POWF_SQRT(value, exponent, 0x02, 0x03) \
195 POWF_SQRT(value, exponent, 0x01, 0x01)
196
197asm (
198".globl " TOSTRING(neonDrawLighting) NL
199TOSTRING(neonDrawLighting) ":" NL
200 // Must be aligned to 8 bytes.
201 "stmdb sp!, {r4-r8, r10, r11, lr}" NL
202 "vstmdb sp!, {d8-d15}" NL
203 "mov " PAINTING_DATA_R ", r0" NL
204 "ldr r0, [" PAINTING_DATA_R ", #" FLOAT_ARGUMENTS_OFFSET "]" NL
205 "ldr r1, [" PAINTING_DATA_R ", #" DRAWING_CONSTANTS_OFFSET "]" NL
206 "ldr " PIXELS_R ", [" PAINTING_DATA_R ", #" PIXELS_OFFSET "]" NL
207 "ldr " WIDTH_R ", [" PAINTING_DATA_R ", #" WIDTH_OFFSET "]" NL
208 "ldr " HEIGHT_R ", [" PAINTING_DATA_R ", #" HEIGHT_OFFSET "]" NL
209 "ldr " FLAGS_R ", [" PAINTING_DATA_R ", #" FLAGS_OFFSET "]" NL
210 "ldr " SPECULAR_EXPONENT_R ", [" PAINTING_DATA_R ", #" SPECULAR_EXPONENT_OFFSET "]" NL
211 "ldr " CONE_EXPONENT_R ", [" PAINTING_DATA_R ", #" CONE_EXPONENT_OFFSET "]" NL
212 "vld1.f32 { " READ1_RANGE " }, [r0]!" NL
213 "vld1.f32 { " READ2_RANGE " }, [r0]!" NL
214 "vld1.f32 { " READ3_RANGE " }, [r0]!" NL
215 "vld1.s16 {" READ4_RANGE "}, [r1]!" NL
216 "vld1.s16 {" READ5_RANGE "}, [r1]!" NL
217 "mov " SCANLINE_R ", " WIDTH_R ", lsl #2" NL
218 "add " SCANLINE_R ", " SCANLINE_R ", #8" NL
219 "add " PIXELS_R ", " PIXELS_R ", " SCANLINE_R NL
220 "add " PIXELS_R ", " PIXELS_R ", #3" NL
221 "mov r0, #0" NL
222 "vmov.f32 " CONST_ZERO_S ", r0" NL
223 "vmov.f32 " POSITION_Y_S ", " CONST_ONE_S NL
224 "tst " FLAGS_R ", #" TOSTRING(FLAG_SPOT_LIGHT) NL
225 "vmov.f32 " SPOT_COLOR_Q ", " COLOR_Q NL
226 "mov " RESET_WIDTH_R ", " WIDTH_R NL
227
228".mainloop:" NL
229 "mov r3, #3" NL
230 "vmov.f32 " POSITION_X_S ", " CONST_ONE_S NL
231
232".scanline:" NL
233 // Reading the next pixel to the ROW data.
234 "ldrb r0, [" PIXELS_R ", -" SCANLINE_R "]" NL
235 "ldrb r1, [" PIXELS_R ", +" SCANLINE_R "]" NL
236 "ldrb r2, [" PIXELS_R "], #4" NL
237 "vext.s16 " TOP_ROW_D ", " TOP_ROW_D ", " TOP_ROW_D ", #3" NL
238 "vext.s16 " MIDDLE_ROW_D ", " MIDDLE_ROW_D ", " MIDDLE_ROW_D ", #3" NL
239 "vext.s16 " BOTTOM_ROW_D ", " BOTTOM_ROW_D ", " BOTTOM_ROW_D ", #3" NL
240 "vmov.s16 " TOP_ROW_D "[1], r0" NL
241 "vmov.s16 " MIDDLE_ROW_D "[1], r2" NL
242 "vmov.s16 " BOTTOM_ROW_D "[1], r1" NL
243
244 "subs r3, r3, #1" NL
245 "bne .scanline" NL
246
247 // Light vector goes to TMP1_Q.
248 "tst " FLAGS_R ", #" TOSTRING(FLAG_POINT_LIGHT | FLAG_SPOT_LIGHT) NL
249 "beq .distantLight" NL
250
251 "vmov.s16 r3, " MIDDLE_ROW_D "[2]" NL
252 "vmov.f32 " POSITION_Z_S ", r3" NL
253 "vcvt.f32.s32 " POSITION_Z_S ", " POSITION_Z_S NL
254 "vmul.f32 " POSITION_Z_S ", " POSITION_Z_S ", " SCALE_S NL
255
256 "vsub.f32 " TMP1_Q ", " LIGHT_Q ", " POSITION_Q NL
257 GET_LENGTH(TMP1, TMP2)
258
259 "tst " FLAGS_R ", #" TOSTRING(FLAG_SPOT_LIGHT) NL
260 "bne .cosineOfAngle" NL
261".visiblePixel:" NL
262
263 // Moving the 8 alpha value to ALPHA.
264 "vtbl.8 " TMP3_D0 ", " ALL_ROWS_D ", " REMAPX_D NL
265 "vtbl.8 " TMP3_D1 ", " ALL_ROWS_D ", " REMAPY_D NL
266
267 // Multiply by ALPHAX and ALPHAY.
268 "vmul.s16 " TMP2_Q ", " TMP3_Q ", " ALPHAX_Q NL
269 "vpadd.s16 " TMP2_D0 ", " TMP2_D0 ", " TMP2_D1 NL
270 "vpadd.s16 " TMP2_D0 ", " TMP2_D0 ", " TMP2_D0 NL
271 "vpadd.s16 " TMP2_D0 ", " TMP2_D0 ", " TMP2_D0 NL
272 "vmov.s16 r0, " TMP2_D0 "[0]" NL
273
274 "vmul.s16 " TMP2_Q ", " TMP3_Q ", " ALPHAY_Q NL
275 "vpadd.s16 " TMP2_D0 ", " TMP2_D0 ", " TMP2_D1 NL
276 "vpadd.s16 " TMP2_D0 ", " TMP2_D0 ", " TMP2_D0 NL
277 "vpadd.s16 " TMP2_D0 ", " TMP2_D0 ", " TMP2_D0 NL
278 "vmov.s16 r1, " TMP2_D0 "[0]" NL
279
280 // Calculating light.
281 "tst " FLAGS_R ", #" TOSTRING(FLAG_SPOT_LIGHT) NL
282 "beq .endLight" NL
283
284 "vneg.f32 " TMP3_S1 ", " COSINE_OF_ANGLE NL
285 "tst " FLAGS_R ", #" TOSTRING(FLAG_CONE_EXPONENT_IS_1) NL
286 "beq .coneExpPowf" NL
287".coneExpPowfFinished:" NL
288
289 "vcmp.f32 " COSINE_OF_ANGLE ", " CONE_FULL_LIGHT_S NL
290 "fmstat" NL
291 "bhi .cutOff" NL
292".cutOffFinished:" NL
293
294 "vmin.f32 " TMP3_D0 ", " TMP3_D0 ", " CONST_ONE_HI_D NL
295 "vmul.f32 " COLOR_Q ", " SPOT_COLOR_Q ", " TMP3_D0 "[1]" NL
296
297".endLight:" NL
298 // r0 contains normalVector X.
299 // r1 contains normalVector Y.
300 // TMP1_Q contains the light vector and its length.
301 // COLOR_Q contains the color of the light vector.
302
303 // Testing both r0 and r1 are zero (Normal vector is (0, 0, 1)).
304 "orrs r2, r0, r1" NL
305 "bne .normalVectorIsNonZero" NL
306
307 "tst " FLAGS_R ", #" TOSTRING(FLAG_SPECULAR_LIGHT) NL
308 "bne .specularLight1" NL
309
310 MULTIPLY_BY_DIFFUSE_CONST(TMP1_S2, TMP1_S3)
311 "b .lightStrengthCalculated" NL
312
313".specularLight1:" NL
314 // Calculating specular lighting light strength.
315 "vadd.f32 " TMP1_S2 ", " TMP1_S2 ", " TMP1_S3 NL
316 GET_LENGTH(TMP1, TMP2)
317
318 "tst " FLAGS_R ", #" TOSTRING(FLAG_SPECULAR_EXPONENT_IS_1) NL
319 "vdiveq.f32 " TMP2_S1 ", " TMP1_S2 ", " TMP1_S3 NL
320 "beq .specularExpPowf" NL
321
322 MULTIPLY_BY_DIFFUSE_CONST(TMP1_S2, TMP1_S3)
323 "b .lightStrengthCalculated" NL
324
325".normalVectorIsNonZero:" NL
326 // Calculating specular lighting light strength.
327 "vmov.s32 " TMP2_S0 ", r0" NL
328 "vcvt.f32.s32 " TMP2_S0 ", " TMP2_S0 NL
329 "vmul.f32 " TMP2_S0 ", " TMP2_S0 ", " SCALE_DIV4_S NL
330 "vmov.s32 " TMP2_S1 ", r1" NL
331 "vcvt.f32.s32 " TMP2_S1 ", " TMP2_S1 NL
332 "vmul.f32 " TMP2_S1 ", " TMP2_S1 ", " SCALE_DIV4_S NL
333 "vmov.f32 " TMP2_S2 ", " CONST_ONE_S NL
334 GET_LENGTH(TMP2, TMP3)
335
336 "tst " FLAGS_R ", #" TOSTRING(FLAG_SPECULAR_LIGHT) NL
337 "bne .specularLight2" NL
338
339 // Calculating diffuse lighting light strength.
340 DOT_PRODUCT(TMP3, TMP2, TMP1)
341 MULTIPLY_BY_DIFFUSE_CONST(TMP3_S0, TMP3_S3)
342 "b .lightStrengthCalculated" NL
343
344".specularLight2:" NL
345 // Calculating specular lighting light strength.
346 "vadd.f32 " TMP1_S2 ", " TMP1_S2 ", " TMP1_S3 NL
347 GET_LENGTH(TMP1, TMP3)
348 DOT_PRODUCT(TMP3, TMP2, TMP1)
349
350 "tst " FLAGS_R ", #" TOSTRING(FLAG_SPECULAR_EXPONENT_IS_1) NL
351 "vdiveq.f32 " TMP2_S1 ", " TMP3_S0 ", " TMP3_S3 NL
352 "beq .specularExpPowf" NL
353 MULTIPLY_BY_DIFFUSE_CONST(TMP3_S0, TMP3_S3)
354
355".lightStrengthCalculated:" NL
356 // TMP2_S1 contains the light strength.
357 "vmax.f32 " TMP2_D0 ", " TMP2_D0 ", " CONST_ZERO_HI_D NL
358 "vmin.f32 " TMP2_D0 ", " TMP2_D0 ", " CONST_ONE_HI_D NL
359 "vmul.f32 " TMP3_Q ", " COLOR_Q ", " TMP2_D0 "[1]" NL
360 "vcvt.u32.f32 " TMP3_Q ", " TMP3_Q NL
361 "vmov.u32 r2, r3, " TMP3_S0 ", " TMP3_S1 NL
362 "strb r2, [" PIXELS_R ", #-11]" NL
363 "strb r3, [" PIXELS_R ", #-10]" NL
364 "vmov.u32 r2, " TMP3_S2 NL
365 "strb r2, [" PIXELS_R ", #-9]" NL
366
367 // Continue scanline.
368".invisiblePixel:" NL
369 "vadd.f32 " POSITION_X_S ", " CONST_ONE_S NL
370 "mov r3, #1" NL
371 "subs " WIDTH_R ", " WIDTH_R ", #1" NL
372 "bne .scanline" NL
373
374 // Next line
375 "vadd.f32 " POSITION_Y_S ", " CONST_ONE_S NL
376 "mov " WIDTH_R ", " RESET_WIDTH_R NL
377 "subs " HEIGHT_R ", " HEIGHT_R ", #1" NL
378 "bne .mainloop" NL
379
380 "vldmia sp!, {d8-d15}" NL
381 "ldmia sp!, {r4-r8, r10, r11, pc}" NL
382
383".distantLight:" NL
384 "vmov.f32 " TMP1_Q ", " LIGHT_Q NL
385 "b .visiblePixel" NL
386
387".cosineOfAngle:" NL
388 DOT_PRODUCT(TMP3, TMP1, DIRECTION)
389 "vdiv.f32 " COSINE_OF_ANGLE ", " TMP3_S0 ", " TMP1_S3 NL
390 "vcmp.f32 " COSINE_OF_ANGLE ", " CONE_CUT_OFF_S NL
391 "fmstat" NL
392 "bls .visiblePixel" NL
393 "mov r0, #0" NL
394 "strh r0, [" PIXELS_R ", #-11]" NL
395 "strb r0, [" PIXELS_R ", #-9]" NL
396 "b .invisiblePixel" NL
397
398".cutOff:" NL
399 "vsub.f32 " TMP3_S0 ", " CONE_CUT_OFF_S ", " COSINE_OF_ANGLE NL
400 "vdiv.f32 " TMP3_S0 ", " TMP3_S0 ", " CONE_CUT_OFF_RANGE_S NL
401 "vmul.f32 " TMP3_S1 ", " TMP3_S1 ", " TMP3_S0 NL
402 "b .cutOffFinished" NL
403
404".coneExpPowf:" NL
405 POWF(TMP3_S1, CONE_EXPONENT_R)
406 "b .coneExpPowfFinished" NL
407
408".specularExpPowf:" NL
409 POWF(TMP2_S1, SPECULAR_EXPONENT_R)
410 "tst " FLAGS_R ", #" TOSTRING(FLAG_DIFFUSE_CONST_IS_1) NL
411 "vmuleq.f32 " TMP2_S1 ", " TMP2_S1 ", " DIFFUSE_CONST_S NL
412 "b .lightStrengthCalculated" NL
413);
414
415} // namespace WebCore
416
417#endif // CPU(ARM) && ENABLE(ARM_NEON) && COMPILER(GCC)