1#version 450
2precision highp float;
3precision highp int;
4
5#ifdef TEXTURED
6#define FILTERS
7#endif
8
9#include "common.h"
10#include "primitive.h"
11
12layout(set = 0, binding = 4) uniform sampler2D uHighResTexture;
13layout(push_constant, std430) uniform Push
14{
15	ivec4 hd_texture_vram_rect; // The area of vram this hd texture covers
16	ivec4 hd_texture_texel_rect; // The area of this hd texture's own texels that may currently be used
17} push;
18#ifdef TEXTURED
19#include "hdtextures.h"
20
21const int OPAQUE = 0;
22const int SEMI_TRANS = 1;
23const int SEMI_TRANS_OPAQUE = 2;
24layout(constant_id = 0) const int TRANSPARENCY_MODE = OPAQUE;
25
26const int FILTER_NEAREST = 0;
27const int FILTER_XBR = 1;
28const int FILTER_SABR = 2;
29const int FILTER_BILINEAR = 3;
30const int FILTER_3POINT = 4;
31const int FILTER_JINC2 = 5;
32layout(constant_id = 1) const int FILTER_TYPE = FILTER_NEAREST;
33#endif
34
35void main()
36{
37	float opacity = 1.0;
38#ifdef TEXTURED
39	vec4 NNColor;
40
41	bool fastpath = (vParam.z & 0x100) != 0;
42	bool hd_enabled = !fastpath && (vParam.z & 0x200) == 0;
43	bool cache_hit = (vParam.z & 0x400) != 0;
44
45	vec4 hdColor;
46	if (fastpath) {
47		NNColor = sample_hd_fast(vUV);
48	} else if (hd_enabled && sample_hd_texture_nearest_hack(vUV, hdColor)) {
49		NNColor = hdColor;
50	} else {
51		NNColor = sample_vram_atlas(clamp_coord(vUV));
52	}
53
54	// Even for opaque draw calls, this pixel is transparent.
55	// Sample in NN space since we need to do an exact test against 0.0.
56	// Doing it in a filtered domain is a bit awkward.
57	// In this pass, only accept opaque pixels.
58	if (TRANSPARENCY_MODE == SEMI_TRANS_OPAQUE)
59		if (all(equal(NNColor, vec4(0.0))) || NNColor.a > 0.5)
60			discard;
61
62	// To avoid opaque pixels from bleeding into the semi-transparent parts,
63	// sample nearest-neighbor only in semi-transparent parts of the image.
64	vec4 color = NNColor;
65
66	// texture filtering
67	if (FILTER_TYPE == FILTER_XBR)
68		color = sample_vram_xbr(opacity);
69	if (FILTER_TYPE == FILTER_BILINEAR)
70		color = sample_vram_bilinear(opacity);
71	if (FILTER_TYPE == FILTER_SABR)
72		color = sample_vram_sabr(opacity);
73	if (FILTER_TYPE == FILTER_JINC2)
74		color = sample_vram_jinc2(opacity);
75	if (FILTER_TYPE == FILTER_3POINT)
76		color = sample_vram_3point(opacity);
77
78	if (TRANSPARENCY_MODE == OPAQUE || TRANSPARENCY_MODE == SEMI_TRANS)
79		if (color.a == 0.0 && all(equal(vec4(NNColor), vec4(0.0))))
80			discard;
81
82	// hd texture filtering
83	if (hd_enabled) {
84		bool valid = true;
85		vec4 hd_color = sample_hd_texture_trilinear(vUV, valid);
86		if (valid) {
87			color = hd_color;
88			opacity = hd_color.a;
89		}
90	}
91
92	if (opacity < 0.5)
93		discard;
94
95	vec3 shaded = color.rgb * vColor.rgb * (255.0 / 128.0);
96	FragColor = vec4(shaded, NNColor.a + vColor.a);
97#else
98	FragColor = vColor;
99#endif
100
101	// Get round down behavior instead of round-to-nearest.
102	// This is required for various "fade" out effects.
103	// However, don't accidentially round down if we are already rounded to avoid
104	// unintended feedback effects.
105	FragColor.rgb -= 0.49 / 255.0;
106
107#if 0
108#if defined(TEXTURED)
109	if ((vParam.z & 0x100) != 0)
110		FragColor.rgb += textureLod(uDitherLUT, gl_FragCoord.xy * 0.25, 0.0).xxx - 4.0 / 255.0;
111#endif
112	FragColor.rgb = quantize_bgr555(FragColor.rgb);
113#endif
114}
115