1 #include "shaders_common.h"
2 
3 static const char *output_fragment = GLSL(
4    // We're sampling from the internal framebuffer texture
5    uniform sampler2D fb;
6    // Framebuffer sampling: 0: Normal 16bpp mode, 1: Use 24bpp mode
7    uniform int depth_24bpp;
8    // Internal resolution upscaling factor. Necessary for proper 24bpp
9    // display since we need to know how the pixels are laid out in RAM.
10    uniform uint internal_upscaling;
11    // Coordinates of the top-left displayed pixel in VRAM (1x resolution)
12    uniform uvec2 offset;
13    // Normalized relative offset in the displayed area in VRAM. Absolute
14    // coordinates must take `offset` into account.
15    in vec2 frag_fb_coord;
16 
17    out vec4 frag_color;
18 
19    // Take a normalized color and convert it into a 16bit 1555 ABGR
20    // integer in the format used internally by the Playstation GPU.
21    uint rebuild_color(vec4 color) {
22       uint a = uint(floor(color.a + 0.5));
23       uint r = uint(floor(color.r * 31. + 0.5));
24       uint g = uint(floor(color.g * 31. + 0.5));
25       uint b = uint(floor(color.b * 31. + 0.5));
26 
27       return (a << 15) | (b << 10) | (g << 5) | r;
28    }
29 
30    void main() {
31       vec3 color;
32 
33       if (depth_24bpp == 0) {
34          // Use the regular 16bpp mode, fetch directly from the framebuffer
35          // texture. The alpha/mask bit is ignored here.
36 	vec2 off = vec2(offset) / vec2(1024., 512.);
37 
38 	color = texture(fb, frag_fb_coord + off).rgb;
39       } else {
40          // In this mode we have to interpret the framebuffer as containing
41          // 24bit RGB values instead of the usual 16bits 1555.
42          ivec2 fb_size = textureSize(fb, 0);
43 
44          uint x_24 = uint(frag_fb_coord.x * float(fb_size.x));
45          uint y = uint(frag_fb_coord.y * float(fb_size.y));
46 
47          uint x_native = x_24 / internal_upscaling;
48 
49          x_24 = x_native * internal_upscaling;
50 
51          // The 24bit color is stored over two 16bit pixels, convert the
52          // coordinates
53          uint x0_16 = (x_24 * 3U) / 2U;
54 
55 	 // Add the offsets
56 	 x0_16 += offset.x * internal_upscaling;
57 	 y     += offset.y * internal_upscaling;
58 
59          // Move on to the next pixel at native resolution
60          uint x1_16 = x0_16 + internal_upscaling;
61 
62          uint col0 = rebuild_color(texelFetch(fb, ivec2(x0_16, y), 0));
63          uint col1 = rebuild_color(texelFetch(fb, ivec2(x1_16, y), 0));
64 
65          uint col = (col1 << 16) | col0;
66 
67          // If we're drawing an odd 24 bit pixel we're starting in the
68          // middle of a 16bit cell so we need to adjust accordingly.
69          col >>= 8U * (x_native & 1U);
70 
71          // Finally we can extract and normalize the 24bit pixel
72          float b = float((col >> 16U) & 0xffU) / 255.;
73          float g = float((col >> 8U) & 0xffU) / 255.;
74          float r = float(col & 0xffU) / 255.;
75 
76          color = vec3(r, g, b);
77       }
78 
79       frag_color = vec4(color, 1.0);
80    }
81 );
82