1 /*
2 * Copyright (c) 2022 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;
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 };
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) {
316 weight += samples[i].a;
317 }
318 if (weight > 0.0) {
319 for (int i = 0; i < 5; ++i) {
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;
333
334 CORE_RELAXEDP vec4 color = vec4(0);
335
336 CORE_RELAXEDP vec4 samples[1 + 2 * CORE_BLUR_FILTER_SIZE];
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), (vec2(fragCoord) + currOffset) * invTexSize, 0);
343 weight += samples[idx * 2 - 1].a;
344 samples[idx * 2] = textureLod(sampler2D(tex, sampl), (vec2(fragCoord) - currOffset) * invTexSize, 0);
345 weight += samples[idx * 2].a;
346 }
347 if (weight > 0.0) {
348 weight = 1.0 / weight;
349 color = samples[0] * CORE_BLUR_WEIGHTS[0] * weight;
350 for (int idx = 1; idx < CORE_BLUR_FILTER_SIZE; ++idx) {
351 color += samples[idx * 2 - 1] * CORE_BLUR_WEIGHTS[idx] * weight;
352 color += samples[idx * 2] * CORE_BLUR_WEIGHTS[idx] * weight;
353 }
354 } else {
355 color = samples[0];
356 }
357
358 return color;
359 }
360
SoftDownscaleRGBLayer(texture2DArray tex,sampler sampl,const vec2 fragCoord,const vec2 uv,const vec3 dirLayer,const vec2 invTexSize)361 vec3 SoftDownscaleRGBLayer(
362 texture2DArray tex, sampler sampl, const vec2 fragCoord, const vec2 uv, const vec3 dirLayer, const vec2 invTexSize)
363 {
364 #if (CORE_BLUR_SOFT_HEAVY_SAMPLES == 1)
365
366 // first, 9 samples (calculate coefficients)
367 const float diagCoeff = (1.0f / 32.0f);
368 const float stepCoeff = (2.0f / 32.0f);
369 const float centerCoeff = (4.0f / 32.0f);
370
371 const vec2 ts = invTexSize;
372
373 vec3 color = textureLod(sampler2DArray(tex, sampl), vec3(uv.x - ts.x, uv.y - ts.y, dirLayer.z), 0).xyz * diagCoeff;
374 color += textureLod(sampler2DArray(tex, sampl), vec3(uv.x, uv.y - ts.y, dirLayer.z), 0).xyz * stepCoeff;
375 color += textureLod(sampler2DArray(tex, sampl), vec3(uv.x + ts.x, uv.y - ts.y, dirLayer.z), 0).xyz * diagCoeff;
376
377 color += textureLod(sampler2DArray(tex, sampl), vec3(uv.x - ts.x, uv.y, dirLayer.z), 0).xyz * stepCoeff;
378 color += textureLod(sampler2DArray(tex, sampl), vec3(uv.x, uv.y, dirLayer.z), 0).xyz * centerCoeff;
379 color += textureLod(sampler2DArray(tex, sampl), vec3(uv.x + ts.x, uv.y, dirLayer.z), 0).xyz * stepCoeff;
380
381 color += textureLod(sampler2DArray(tex, sampl), vec3(uv.x - ts.x, uv.y + ts.y, dirLayer.z), 0).xyz * diagCoeff;
382 color += textureLod(sampler2DArray(tex, sampl), vec3(uv.x, uv.y + ts.y, dirLayer.z), 0).xyz * centerCoeff;
383 color += textureLod(sampler2DArray(tex, sampl), vec3(uv.x + ts.x, uv.y + ts.y, dirLayer.z), 0).xyz * diagCoeff;
384
385 // then center square
386 const vec2 ths = ts * 0.5;
387
388 color += textureLod(sampler2DArray(tex, sampl), vec3(uv.x - ths.x, uv.y - ths.y, dirLayer.z), 0).xyz * centerCoeff;
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
393 #else
394
395 const vec2 ths = invTexSize * 0.5;
396
397 // center
398 vec3 color = textureLod(sampler2DArray(tex, sampl), vec3(uv + ths, dirLayer.z), 0).xyz * 0.5;
399 // corners
400 // 1.0 / 8.0 = 0.125
401 color = textureLod(sampler2DArray(tex, sampl), vec3(uv - ths, dirLayer.z), 0).xyz * 0.125 + color;
402 color = textureLod(sampler2DArray(tex, sampl), vec3(uv.x + ths.x, uv.y - ths.y, 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 + ths, dirLayer.z), 0).xyz * 0.125 + color;
405
406 #endif
407
408 return color;
409 }
410
DownscaleRGBALayer(texture2DArray tex,sampler sampl,const vec2 fragCoord,const vec2 uv,const vec3 dirLayer,const vec2 invTexSize)411 vec4 DownscaleRGBALayer(
412 texture2DArray tex, sampler sampl, const vec2 fragCoord, const vec2 uv, const vec3 dirLayer, const vec2 invTexSize)
413 {
414 return textureLod(sampler2DArray(tex, sampl), vec3(uv, dirLayer.z), 0);
415 }
416 #endif
417
418 #endif // API_RENDER_SHADERS_COMMON_CORE_BLUR_COMMON_H
419