1 /*
2  * Copyright (c) 2024 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #ifndef API_RENDER_SHADERS_COMMON_CORE_BLUR_COMMON_H
17 #define API_RENDER_SHADERS_COMMON_CORE_BLUR_COMMON_H
18 
19 // includes
20 #include "render_compatibility_common.h"
21 
22 // specialization for CORE_BLUR_COLOR_TYPE.
23 // These are defines instead of contants to avoid extra code generation in shaders.
24 #define CORE_BLUR_TYPE_RGBA 0
25 #define CORE_BLUR_TYPE_R 1
26 #define CORE_BLUR_TYPE_RG 2
27 #define CORE_BLUR_TYPE_RGB 3
28 #define CORE_BLUR_TYPE_A 4
29 #define CORE_BLUR_TYPE_SOFT_DOWNSCALE_RGB 5
30 #define CORE_BLUR_TYPE_DOWNSCALE_RGBA 6
31 #define CORE_BLUR_TYPE_DOWNSCALE_RGBA_DOF 7
32 #define CORE_BLUR_TYPE_RGBA_DOF 8
33 #define CORE_BLUR_FILTER_SIZE 3
34 
35 #ifndef VULKAN
36 #include <render/namespace.h>
37 RENDER_BEGIN_NAMESPACE()
38 #endif
39 
40 #ifndef VULKAN
41 RENDER_END_NAMESPACE()
42 #endif
43 
44 #ifdef VULKAN
45 /**
46  http://rastergrid.com/blog/2010/09/efficient-gaussian-blur-with-linear-sampling/
47 */
48 
49 const float CORE_BLUR_OFFSETS[CORE_BLUR_FILTER_SIZE] = { 0.0, 1.3846153846, 3.2307692308 };
50 const float CORE_BLUR_WEIGHTS[CORE_BLUR_FILTER_SIZE] = { 0.2270270270, 0.3162162162, 0.0702702703 };
51 
GaussianBlurRGBA(texture2D tex,sampler sampl,const vec2 fragCoord,const vec2 uv,const vec2 dir,const vec2 invTexSize)52 vec4 GaussianBlurRGBA(
53     texture2D tex, sampler sampl, const vec2 fragCoord, const vec2 uv, const vec2 dir, const vec2 invTexSize)
54 {
55     vec4 color = textureLod(sampler2D(tex, sampl), uv, 0) * CORE_BLUR_WEIGHTS[0];
56 
57     for (int idx = 1; idx < CORE_BLUR_FILTER_SIZE; ++idx) {
58         vec2 currOffset = vec2(CORE_BLUR_OFFSETS[idx]) * dir.xy;
59 
60         color +=
61             textureLod(sampler2D(tex, sampl), (vec2(fragCoord) + currOffset) * invTexSize, 0) * CORE_BLUR_WEIGHTS[idx];
62         color +=
63             textureLod(sampler2D(tex, sampl), (vec2(fragCoord) - currOffset) * invTexSize, 0) * CORE_BLUR_WEIGHTS[idx];
64     }
65 
66     return color;
67 }
68 
GaussianBlurRGB(texture2D tex,sampler sampl,const vec2 fragCoord,const vec2 uv,const vec2 dir,const vec2 invTexSize)69 vec3 GaussianBlurRGB(
70     texture2D tex, sampler sampl, const vec2 fragCoord, const vec2 uv, const vec2 dir, const vec2 invTexSize)
71 {
72     vec3 color = textureLod(sampler2D(tex, sampl), uv, 0).xyz * CORE_BLUR_WEIGHTS[0];
73 
74     for (int idx = 1; idx < CORE_BLUR_FILTER_SIZE; ++idx) {
75         vec2 currOffset = vec2(CORE_BLUR_OFFSETS[idx]) * dir.xy;
76 
77         color += textureLod(sampler2D(tex, sampl), (vec2(fragCoord) + currOffset) * invTexSize, 0).xyz *
78                  CORE_BLUR_WEIGHTS[idx];
79         color += textureLod(sampler2D(tex, sampl), (vec2(fragCoord) - currOffset) * invTexSize, 0).xyz *
80                  CORE_BLUR_WEIGHTS[idx];
81     }
82 
83     return color;
84 }
85 
GaussianBlurRG(texture2D tex,sampler sampl,const vec2 fragCoord,const vec2 uv,const vec2 dir,const vec2 invTexSize)86 vec2 GaussianBlurRG(
87     texture2D tex, sampler sampl, const vec2 fragCoord, const vec2 uv, const vec2 dir, const vec2 invTexSize)
88 {
89     vec2 color = textureLod(sampler2D(tex, sampl), uv, 0).xy * CORE_BLUR_WEIGHTS[0];
90 
91     for (int idx = 1; idx < CORE_BLUR_FILTER_SIZE; ++idx) {
92         vec2 currOffset = vec2(CORE_BLUR_OFFSETS[idx]) * dir.xy;
93 
94         color += textureLod(sampler2D(tex, sampl), (vec2(fragCoord) + currOffset) * invTexSize, 0).xy *
95                  CORE_BLUR_WEIGHTS[idx];
96         color += textureLod(sampler2D(tex, sampl), (vec2(fragCoord) - currOffset) * invTexSize, 0).xy *
97                  CORE_BLUR_WEIGHTS[idx];
98     }
99 
100     return color;
101 }
102 
GaussianBlurR(texture2D tex,sampler sampl,const vec2 fragCoord,const vec2 uv,const vec2 dir,const vec2 invTexSize)103 float GaussianBlurR(
104     texture2D tex, sampler sampl, const vec2 fragCoord, const vec2 uv, const vec2 dir, const vec2 invTexSize)
105 {
106     float color = textureLod(sampler2D(tex, sampl), uv, 0).x * CORE_BLUR_WEIGHTS[0];
107 
108     for (int idx = 1; idx < CORE_BLUR_FILTER_SIZE; ++idx) {
109         vec2 currOffset = vec2(CORE_BLUR_OFFSETS[idx]) * dir.xy;
110 
111         color += textureLod(sampler2D(tex, sampl), (vec2(fragCoord) + currOffset) * invTexSize, 0).x *
112                  CORE_BLUR_WEIGHTS[idx];
113         color += textureLod(sampler2D(tex, sampl), (vec2(fragCoord) - currOffset) * invTexSize, 0).x *
114                  CORE_BLUR_WEIGHTS[idx];
115     }
116 
117     return color;
118 }
119 
GaussianBlurA(texture2D tex,sampler sampl,const vec2 fragCoord,const vec2 uv,const vec2 dir,const vec2 invTexSize)120 float GaussianBlurA(
121     texture2D tex, sampler sampl, const vec2 fragCoord, const vec2 uv, const vec2 dir, const vec2 invTexSize)
122 {
123     float alpha = textureLod(sampler2D(tex, sampl), uv, 0).a * CORE_BLUR_WEIGHTS[0];
124 
125     for (int idx = 1; idx < CORE_BLUR_FILTER_SIZE; ++idx) {
126         vec2 currOffset = vec2(CORE_BLUR_OFFSETS[idx]) * dir.xy;
127 
128         alpha += textureLod(sampler2D(tex, sampl), (vec2(fragCoord) + currOffset, 0) * invTexSize, 0).a *
129                  CORE_BLUR_WEIGHTS[idx];
130         alpha += textureLod(sampler2D(tex, sampl), (vec2(fragCoord) - currOffset, 0) * invTexSize, 0).a *
131                  CORE_BLUR_WEIGHTS[idx];
132     }
133 
134     return alpha;
135 }
136 
GaussianBlurRGBALayer(texture2DArray tex,sampler sampl,const vec2 fragCoord,const vec2 uv,const vec3 dirLayer,const vec2 invTexSize)137 vec4 GaussianBlurRGBALayer(
138     texture2DArray tex, sampler sampl, const vec2 fragCoord, const vec2 uv, const vec3 dirLayer, const vec2 invTexSize)
139 {
140     vec4 color = textureLod(sampler2DArray(tex, sampl), vec3(uv, dirLayer.z), 0) * CORE_BLUR_WEIGHTS[0];
141 
142     for (int idx = 1; idx < CORE_BLUR_FILTER_SIZE; ++idx) {
143         vec2 currOffset = vec2(CORE_BLUR_OFFSETS[idx]) * dirLayer.xy;
144 
145         color +=
146             textureLod(sampler2DArray(tex, sampl), vec3((vec2(fragCoord) + currOffset) * invTexSize, dirLayer.z), 0) *
147             CORE_BLUR_WEIGHTS[idx];
148         color +=
149             textureLod(sampler2DArray(tex, sampl), vec3((vec2(fragCoord) - currOffset) * invTexSize, dirLayer.z), 0) *
150             CORE_BLUR_WEIGHTS[idx];
151     }
152 
153     return color;
154 }
155 
GaussianBlurRGBLayer(texture2DArray tex,sampler sampl,const vec2 fragCoord,const vec2 uv,const vec3 dirLayer,const vec2 invTexSize)156 vec3 GaussianBlurRGBLayer(
157     texture2DArray tex, sampler sampl, const vec2 fragCoord, const vec2 uv, const vec3 dirLayer, const vec2 invTexSize)
158 {
159     vec3 color = textureLod(sampler2DArray(tex, sampl), vec3(uv, dirLayer.z), 0).xyz * CORE_BLUR_WEIGHTS[0];
160 
161     for (int idx = 1; idx < CORE_BLUR_FILTER_SIZE; ++idx) {
162         vec2 currOffset = vec2(CORE_BLUR_OFFSETS[idx]) * dirLayer.xy;
163 
164         color +=
165             textureLod(sampler2DArray(tex, sampl), vec3((vec2(fragCoord) + currOffset) * invTexSize, dirLayer.z), 0)
166                 .xyz *
167             CORE_BLUR_WEIGHTS[idx];
168         color +=
169             textureLod(sampler2DArray(tex, sampl), vec3((vec2(fragCoord) - currOffset) * invTexSize, dirLayer.z), 0)
170                 .xyz *
171             CORE_BLUR_WEIGHTS[idx];
172     }
173 
174     return color;
175 }
176 
GaussianBlurRGLayer(texture2DArray tex,sampler sampl,const vec2 fragCoord,const vec2 uv,const vec3 dirLayer,const vec2 invTexSize)177 vec2 GaussianBlurRGLayer(
178     texture2DArray tex, sampler sampl, const vec2 fragCoord, const vec2 uv, const vec3 dirLayer, const vec2 invTexSize)
179 {
180     vec2 color = textureLod(sampler2DArray(tex, sampl), vec3(uv, dirLayer.z), 0).xy * CORE_BLUR_WEIGHTS[0];
181 
182     for (int idx = 1; idx < CORE_BLUR_FILTER_SIZE; ++idx) {
183         vec2 currOffset = vec2(CORE_BLUR_OFFSETS[idx]) * dirLayer.xy;
184 
185         color +=
186             textureLod(sampler2DArray(tex, sampl), vec3((vec2(fragCoord) + currOffset) * invTexSize, dirLayer.z), 0)
187                 .xy *
188             CORE_BLUR_WEIGHTS[idx];
189         color +=
190             textureLod(sampler2DArray(tex, sampl), vec3((vec2(fragCoord) - currOffset) * invTexSize, dirLayer.z), 0)
191                 .xy *
192             CORE_BLUR_WEIGHTS[idx];
193     }
194 
195     return color;
196 }
197 
GaussianBlurRLayer(texture2DArray tex,sampler sampl,const vec2 fragCoord,const vec2 uv,const vec3 dirLayer,const vec2 invTexSize)198 float GaussianBlurRLayer(
199     texture2DArray tex, sampler sampl, const vec2 fragCoord, const vec2 uv, const vec3 dirLayer, const vec2 invTexSize)
200 {
201     float color = textureLod(sampler2DArray(tex, sampl), vec3(uv, dirLayer.z), 0).x * CORE_BLUR_WEIGHTS[0];
202 
203     for (int idx = 1; idx < CORE_BLUR_FILTER_SIZE; ++idx) {
204         vec2 currOffset = vec2(CORE_BLUR_OFFSETS[idx]) * dirLayer.xy;
205 
206         color +=
207             textureLod(sampler2DArray(tex, sampl), vec3((vec2(fragCoord) + currOffset) * invTexSize, dirLayer.z), 0).x *
208             CORE_BLUR_WEIGHTS[idx];
209         color +=
210             textureLod(sampler2DArray(tex, sampl), vec3((vec2(fragCoord) - currOffset) * invTexSize, dirLayer.z), 0).x *
211             CORE_BLUR_WEIGHTS[idx];
212     }
213 
214     return color;
215 }
216 
GaussianBlurALayer(texture2DArray tex,sampler sampl,const vec2 fragCoord,const vec2 uv,const vec3 dirLayer,const vec2 invTexSize)217 float GaussianBlurALayer(
218     texture2DArray tex, sampler sampl, const vec2 fragCoord, const vec2 uv, const vec3 dirLayer, const vec2 invTexSize)
219 {
220     float alpha = textureLod(sampler2DArray(tex, sampl), vec3(uv, dirLayer.z), 0).a * CORE_BLUR_WEIGHTS[0];
221 
222     for (int idx = 1; idx < CORE_BLUR_FILTER_SIZE; ++idx) {
223         vec2 currOffset = vec2(CORE_BLUR_OFFSETS[idx]) * dirLayer.xy;
224 
225         alpha +=
226             textureLod(sampler2DArray(tex, sampl), vec3((vec2(fragCoord) + currOffset, 0) * invTexSize, dirLayer.z), 0)
227                 .a *
228             CORE_BLUR_WEIGHTS[idx];
229         alpha +=
230             textureLod(sampler2DArray(tex, sampl), vec3((vec2(fragCoord) - currOffset, 0) * invTexSize, dirLayer.z), 0)
231                 .a *
232             CORE_BLUR_WEIGHTS[idx];
233     }
234 
235     return alpha;
236 }
237 
238 #define CORE_BLUR_SOFT_HEAVY_SAMPLES 0
239 // NOTE: dir not used
SoftDownscaleRGB(texture2D tex,sampler sampl,const vec2 fragCoord,const vec2 uv,const vec2 dir,const vec2 invTexSize)240 vec3 SoftDownscaleRGB(
241     texture2D tex, sampler sampl, const vec2 fragCoord, const vec2 uv, const vec2 dir, const vec2 invTexSize)
242 {
243 #if (CORE_BLUR_SOFT_HEAVY_SAMPLES == 1)
244 
245     // first, 9 samples (calculate coefficients)
246     const float diagCoeff = (1.0f / 32.0f);
247     const float stepCoeff = (2.0f / 32.0f);
248     const float centerCoeff = (4.0f / 32.0f);
249 
250     const vec2 ts = invTexSize;
251 
252     vec3 color = textureLod(sampler2D(tex, sampl), vec2(uv.x - ts.x, uv.y - ts.y), 0).xyz * diagCoeff;
253     color += textureLod(sampler2D(tex, sampl), vec2(uv.x, uv.y - ts.y), 0).xyz * stepCoeff;
254     color += textureLod(sampler2D(tex, sampl), vec2(uv.x + ts.x, uv.y - ts.y), 0).xyz * diagCoeff;
255 
256     color += textureLod(sampler2D(tex, sampl), vec2(uv.x - ts.x, uv.y), 0).xyz * stepCoeff;
257     color += textureLod(sampler2D(tex, sampl), vec2(uv.x, uv.y), 0).xyz * centerCoeff;
258     color += textureLod(sampler2D(tex, sampl), vec2(uv.x + ts.x, uv.y), 0).xyz * stepCoeff;
259 
260     color += textureLod(sampler2D(tex, sampl), vec2(uv.x - ts.x, uv.y + ts.y), 0).xyz * diagCoeff;
261     color += textureLod(sampler2D(tex, sampl), vec2(uv.x, uv.y + ts.y), 0).xyz * centerCoeff;
262     color += textureLod(sampler2D(tex, sampl), vec2(uv.x + ts.x, uv.y + ts.y), 0).xyz * diagCoeff;
263 
264     // then center square
265     const vec2 ths = ts * 0.5;
266 
267     color += textureLod(sampler2D(tex, sampl), vec2(uv.x - ths.x, uv.y - ths.y), 0).xyz * centerCoeff;
268     color += textureLod(sampler2D(tex, sampl), vec2(uv.x + ths.x, uv.y - ths.y), 0).xyz * centerCoeff;
269     color += textureLod(sampler2D(tex, sampl), vec2(uv.x - ths.x, uv.y + ths.y), 0).xyz * centerCoeff;
270     color += textureLod(sampler2D(tex, sampl), vec2(uv.x + ths.x, uv.y + ths.y), 0).xyz * centerCoeff;
271 
272 #else
273 
274     const vec2 ths = invTexSize * 0.5;
275 
276     // center
277     vec3 color = textureLod(sampler2D(tex, sampl), uv + ths, 0).xyz * 0.5;
278     // corners
279     // 1.0 / 8.0 = 0.125
280     color = textureLod(sampler2D(tex, sampl), uv - ths, 0).xyz * 0.125 + color;
281     color = textureLod(sampler2D(tex, sampl), vec2(uv.x + ths.x, uv.y - ths.y), 0).xyz * 0.125 + color;
282     color = textureLod(sampler2D(tex, sampl), vec2(uv.x - ths.x, uv.y + ths.y), 0).xyz * 0.125 + color;
283     color = textureLod(sampler2D(tex, sampl), uv + ths, 0).xyz * 0.125 + color;
284 
285 #endif
286 
287     return color;
288 }
289 
DownscaleRGBA(texture2D tex,sampler sampl,const vec2 fragCoord,const vec2 uv,const vec2 dir,const vec2 invTexSize)290 vec4 DownscaleRGBA(
291     texture2D tex, sampler sampl, const vec2 fragCoord, const vec2 uv, const vec2 dir, const vec2 invTexSize)
292 {
293     return textureLod(sampler2D(tex, sampl), uv, 0);
294 }
295 
DownscaleRGBADof(texture2D tex,sampler sampl,const vec2 fragCoord,const vec2 uv,const vec2 dir,const vec2 invTexSize)296 vec4 DownscaleRGBADof(
297     texture2D tex, sampler sampl, const vec2 fragCoord, const vec2 uv, const vec2 dir, const vec2 invTexSize)
298 {
299     const vec2 ths = invTexSize * 0.5; // 0.5: half
300 
301     vec4 color = vec4(0);
302 
303     // 1.0 / 8.0 = 0.125
304     float weights[5] = { 0.5, 0.125, 0.125, 0.125, 0.125 }; // 0.5: weight, 0.125: weight
305     vec4 samples[5] = {
306         // center
307         textureLod(sampler2D(tex, sampl), uv, 0),
308         // corners
309         textureLod(sampler2D(tex, sampl), uv - ths, 0),
310         textureLod(sampler2D(tex, sampl), vec2(uv.x + ths.x, uv.y - ths.y), 0),
311         textureLod(sampler2D(tex, sampl), vec2(uv.x - ths.x, uv.y + ths.y), 0),
312         textureLod(sampler2D(tex, sampl), uv + ths, 0),
313     };
314     float weight = 0.0;
315     for (int i = 0; i < 5; ++i) { // 5: size
316         weight += samples[i].a;
317     }
318     if (weight > 0.0) {
319         for (int i = 0; i < 5; ++i) { // 5:size
320             color += samples[i] * weights[i];
321         }
322     } else {
323         color = samples[0];
324     }
325 
326     return color;
327 }
328 
BlurRGBADof(texture2D tex,sampler sampl,const vec2 fragCoord,const vec2 uv,const vec2 dir,const vec2 invTexSize)329 vec4 BlurRGBADof(
330     texture2D tex, sampler sampl, const vec2 fragCoord, const vec2 uv, const vec2 dir, const vec2 invTexSize)
331 {
332     const vec2 ths = invTexSize * 0.5; // 0.5:half
333 
334     CORE_RELAXEDP vec4 color = vec4(0);
335 
336     CORE_RELAXEDP vec4 samples[1 + 2 * CORE_BLUR_FILTER_SIZE]; // 2: idx
337     samples[0] = textureLod(sampler2D(tex, sampl), uv, 0);
338     float weight = samples[0].a;
339     for (int idx = 1; idx < CORE_BLUR_FILTER_SIZE; ++idx) {
340         vec2 currOffset = vec2(CORE_BLUR_OFFSETS[idx]) * dir.xy;
341 
342         samples[idx * 2 - 1] = textureLod(sampler2D(tex, sampl), // 2 : idx
343             (vec2(fragCoord) + currOffset) * invTexSize, 0); // 2: index
344         weight += samples[idx * 2 - 1].a; // 2: size
345         samples[idx * 2] = textureLod(sampler2D(tex, sampl), (vec2(fragCoord) - currOffset) * invTexSize, 0); // 2:idx
346         weight += samples[idx * 2].a; // 2: size
347     }
348     if (weight > 0.0) {
349         weight = 1.0 / weight;
350         color = samples[0] * CORE_BLUR_WEIGHTS[0] * weight;
351         for (int idx = 1; idx < CORE_BLUR_FILTER_SIZE; ++idx) {
352             color += samples[idx * 2 - 1] * CORE_BLUR_WEIGHTS[idx] * weight; // 2: idx
353             color += samples[idx * 2] * CORE_BLUR_WEIGHTS[idx] * weight; // 2 : idex
354         }
355     } else {
356         color = samples[0];
357     }
358 
359     return color;
360 }
361 
SoftDownscaleRGBLayer(texture2DArray tex,sampler sampl,const vec2 fragCoord,const vec2 uv,const vec3 dirLayer,const vec2 invTexSize)362 vec3 SoftDownscaleRGBLayer(
363     texture2DArray tex, sampler sampl, const vec2 fragCoord, const vec2 uv, const vec3 dirLayer, const vec2 invTexSize)
364 {
365 #if (CORE_BLUR_SOFT_HEAVY_SAMPLES == 1)
366 
367     // first, 9 samples (calculate coefficients)
368     const float diagCoeff = (1.0f / 32.0f); // 32.0: param
369     const float stepCoeff = (2.0f / 32.0f); // 2.0: param, 32.0: param
370     const float centerCoeff = (4.0f / 32.0f); //4.0: param, 32.0: param
371 
372     const vec2 ts = invTexSize;
373 
374     vec3 color = textureLod(sampler2DArray(tex, sampl), vec3(uv.x - ts.x, uv.y - ts.y, dirLayer.z), 0).xyz * diagCoeff;
375     color += textureLod(sampler2DArray(tex, sampl), vec3(uv.x, uv.y - ts.y, dirLayer.z), 0).xyz * stepCoeff;
376     color += textureLod(sampler2DArray(tex, sampl), vec3(uv.x + ts.x, uv.y - ts.y, dirLayer.z), 0).xyz * diagCoeff;
377 
378     color += textureLod(sampler2DArray(tex, sampl), vec3(uv.x - ts.x, uv.y, dirLayer.z), 0).xyz * stepCoeff;
379     color += textureLod(sampler2DArray(tex, sampl), vec3(uv.x, uv.y, dirLayer.z), 0).xyz * centerCoeff;
380     color += textureLod(sampler2DArray(tex, sampl), vec3(uv.x + ts.x, uv.y, dirLayer.z), 0).xyz * stepCoeff;
381 
382     color += textureLod(sampler2DArray(tex, sampl), vec3(uv.x - ts.x, uv.y + ts.y, dirLayer.z), 0).xyz * diagCoeff;
383     color += textureLod(sampler2DArray(tex, sampl), vec3(uv.x, uv.y + ts.y, dirLayer.z), 0).xyz * centerCoeff;
384     color += textureLod(sampler2DArray(tex, sampl), vec3(uv.x + ts.x, uv.y + ts.y, dirLayer.z), 0).xyz * diagCoeff;
385 
386     // then center square
387     const vec2 ths = ts * 0.5;
388 
389     color += textureLod(sampler2DArray(tex, sampl), vec3(uv.x - ths.x, uv.y - ths.y, dirLayer.z), 0).xyz * centerCoeff;
390     color += textureLod(sampler2DArray(tex, sampl), vec3(uv.x + ths.x, uv.y - ths.y, dirLayer.z), 0).xyz * centerCoeff;
391     color += textureLod(sampler2DArray(tex, sampl), vec3(uv.x - ths.x, uv.y + ths.y, dirLayer.z), 0).xyz * centerCoeff;
392     color += textureLod(sampler2DArray(tex, sampl), vec3(uv.x + ths.x, uv.y + ths.y, dirLayer.z), 0).xyz * centerCoeff;
393 
394 #else
395 
396     const vec2 ths = invTexSize * 0.5;
397 
398     // center
399     vec3 color = textureLod(sampler2DArray(tex, sampl), vec3(uv + ths, dirLayer.z), 0).xyz * 0.5;
400     // corners
401     // 1.0 / 8.0 = 0.125
402     color = textureLod(sampler2DArray(tex, sampl), vec3(uv - ths, dirLayer.z), 0).xyz * 0.125 + color;
403     color = textureLod(sampler2DArray(tex, sampl), vec3(uv.x + ths.x, uv.y - ths.y, dirLayer.z), 0).xyz * 0.125 + color;
404     color = textureLod(sampler2DArray(tex, sampl), vec3(uv.x - ths.x, uv.y + ths.y, dirLayer.z), 0).xyz * 0.125 + color;
405     color = textureLod(sampler2DArray(tex, sampl), vec3(uv + ths, dirLayer.z), 0).xyz * 0.125 + color;
406 
407 #endif
408 
409     return color;
410 }
411 
DownscaleRGBALayer(texture2DArray tex,sampler sampl,const vec2 fragCoord,const vec2 uv,const vec3 dirLayer,const vec2 invTexSize)412 vec4 DownscaleRGBALayer(
413     texture2DArray tex, sampler sampl, const vec2 fragCoord, const vec2 uv, const vec3 dirLayer, const vec2 invTexSize)
414 {
415     return textureLod(sampler2DArray(tex, sampl), vec3(uv, dirLayer.z), 0);
416 }
417 #endif
418 
419 #endif // API_RENDER_SHADERS_COMMON_CORE_BLUR_COMMON_H
420