Files
DeSmuME-Core/src/cocoa/OGLDisplayOutput.cpp
T
2018-11-25 22:06:36 -06:00

6411 lines
248 KiB
C++
Executable File

/*
Copyright (C) 2014-2015 DeSmuME team
This file is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.
This file is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with the this software. If not, see <http://www.gnu.org/licenses/>.
*/
#include "OGLDisplayOutput.h"
#include "cocoa_globals.h"
#include "utilities.h"
#include "../filter/videofilter.h"
// VERTEX SHADER FOR DISPLAY OUTPUT
static const char *Sample1x1OutputVertShader_100 = {"\
ATTRIBUTE vec2 inPosition; \n\
ATTRIBUTE vec2 inTexCoord0; \n\
\n\
uniform vec2 viewSize; \n\
uniform float scalar; \n\
uniform float angleDegrees; \n\
\n\
VARYING vec2 texCoord[1]; \n\
\n\
void main() \n\
{ \n\
float angleRadians = radians(angleDegrees); \n\
\n\
mat2 projection = mat2( vec2(2.0/viewSize.x, 0.0), \n\
vec2( 0.0, 2.0/viewSize.y)); \n\
\n\
mat2 rotation = mat2( vec2(cos(angleRadians), -sin(angleRadians)), \n\
vec2(sin(angleRadians), cos(angleRadians))); \n\
\n\
mat2 scale = mat2( vec2(scalar, 0.0), \n\
vec2( 0.0, scalar)); \n\
\n\
texCoord[0] = inTexCoord0; \n\
gl_Position = vec4(projection * rotation * scale * inPosition, 0.0, 1.0);\n\
} \n\
"};
static const char *BicubicSample4x4Output_VertShader_110 = {"\
//---------------------------------------\n\
// Input Pixel Mapping: 06|07|08|09\n\
// 05|00|01|10\n\
// 04|03|02|11\n\
// 15|14|13|12\n\
\n\
ATTRIBUTE vec2 inPosition;\n\
ATTRIBUTE vec2 inTexCoord0;\n\
\n\
uniform vec2 viewSize; \n\
uniform float scalar; \n\
uniform float angleDegrees; \n\
\n\
VARYING vec2 texCoord[16];\n\
\n\
void main()\n\
{\n\
float angleRadians = radians(angleDegrees); \n\
\n\
mat2 projection = mat2( vec2(2.0/viewSize.x, 0.0), \n\
vec2( 0.0, 2.0/viewSize.y)); \n\
\n\
mat2 rotation = mat2( vec2(cos(angleRadians), -sin(angleRadians)), \n\
vec2(sin(angleRadians), cos(angleRadians))); \n\
\n\
mat2 scale = mat2( vec2(scalar, 0.0), \n\
vec2( 0.0, scalar)); \n\
\n\
vec2 xystart = floor(inTexCoord0 - 0.5) + 0.5;\n\
\n\
texCoord[ 6] = xystart + vec2(-1.0,-1.0);\n\
texCoord[ 7] = xystart + vec2( 0.0,-1.0);\n\
texCoord[ 8] = xystart + vec2( 1.0,-1.0);\n\
texCoord[ 9] = xystart + vec2( 2.0,-1.0);\n\
\n\
texCoord[ 5] = xystart + vec2(-1.0, 0.0);\n\
texCoord[ 0] = xystart + vec2( 0.0, 0.0); // Center pixel\n\
texCoord[ 1] = xystart + vec2( 1.0, 0.0);\n\
texCoord[10] = xystart + vec2( 2.0, 0.0);\n\
\n\
texCoord[ 4] = xystart + vec2(-1.0, 1.0);\n\
texCoord[ 3] = xystart + vec2( 0.0, 1.0);\n\
texCoord[ 2] = xystart + vec2( 1.0, 1.0);\n\
texCoord[11] = xystart + vec2( 2.0, 1.0);\n\
\n\
texCoord[15] = xystart + vec2(-1.0, 2.0);\n\
texCoord[14] = xystart + vec2( 0.0, 2.0);\n\
texCoord[13] = xystart + vec2( 1.0, 2.0);\n\
texCoord[12] = xystart + vec2( 2.0, 2.0);\n\
\n\
gl_Position = vec4(projection * rotation * scale * inPosition, 0.0, 1.0);\n\
}\n\
"};
static const char *BicubicSample5x5Output_VertShader_110 = {"\
//---------------------------------------\n\
// Input Pixel Mapping: 20|21|22|23|24\n\
// 19|06|07|08|09\n\
// 18|05|00|01|10\n\
// 17|04|03|02|11\n\
// 16|15|14|13|12\n\
\n\
ATTRIBUTE vec2 inPosition;\n\
ATTRIBUTE vec2 inTexCoord0;\n\
\n\
uniform vec2 viewSize; \n\
uniform float scalar; \n\
uniform float angleDegrees; \n\
\n\
VARYING vec2 texCoord[25];\n\
\n\
void main()\n\
{\n\
float angleRadians = radians(angleDegrees); \n\
\n\
mat2 projection = mat2( vec2(2.0/viewSize.x, 0.0), \n\
vec2( 0.0, 2.0/viewSize.y)); \n\
\n\
mat2 rotation = mat2( vec2(cos(angleRadians), -sin(angleRadians)), \n\
vec2(sin(angleRadians), cos(angleRadians))); \n\
\n\
mat2 scale = mat2( vec2(scalar, 0.0), \n\
vec2( 0.0, scalar)); \n\
\n\
vec2 xystart = floor(inTexCoord0 - 0.5) + 0.5;\n\
\n\
texCoord[20] = xystart + vec2(-2.0,-2.0);\n\
texCoord[21] = xystart + vec2(-1.0,-2.0);\n\
texCoord[22] = xystart + vec2( 0.0,-2.0);\n\
texCoord[23] = xystart + vec2( 1.0,-2.0);\n\
texCoord[24] = xystart + vec2( 2.0,-2.0);\n\
\n\
texCoord[19] = xystart + vec2(-2.0,-1.0);\n\
texCoord[ 6] = xystart + vec2(-1.0,-1.0);\n\
texCoord[ 7] = xystart + vec2( 0.0,-1.0);\n\
texCoord[ 8] = xystart + vec2( 1.0,-1.0);\n\
texCoord[ 9] = xystart + vec2( 2.0,-1.0);\n\
\n\
texCoord[18] = xystart + vec2(-2.0, 0.0);\n\
texCoord[ 5] = xystart + vec2(-1.0, 0.0);\n\
texCoord[ 0] = xystart + vec2( 0.0, 0.0); // Center pixel\n\
texCoord[ 1] = xystart + vec2( 1.0, 0.0);\n\
texCoord[10] = xystart + vec2( 2.0, 0.0);\n\
\n\
texCoord[17] = xystart + vec2(-2.0, 1.0);\n\
texCoord[ 4] = xystart + vec2(-1.0, 1.0);\n\
texCoord[ 3] = xystart + vec2( 0.0, 1.0);\n\
texCoord[ 2] = xystart + vec2( 1.0, 1.0);\n\
texCoord[11] = xystart + vec2( 2.0, 1.0);\n\
\n\
texCoord[16] = xystart + vec2(-2.0, 2.0);\n\
texCoord[15] = xystart + vec2(-1.0, 2.0);\n\
texCoord[14] = xystart + vec2( 0.0, 2.0);\n\
texCoord[13] = xystart + vec2( 1.0, 2.0);\n\
texCoord[12] = xystart + vec2( 2.0, 2.0);\n\
\n\
gl_Position = vec4(projection * rotation * scale * inPosition, 0.0, 1.0);\n\
}\n\
"};
static const char *BicubicSample6x6Output_VertShader_110 = {"\
//---------------------------------------\n\
// Input Pixel Mapping: 20|21|22|23|24|25\n\
// 19|06|07|08|09|26\n\
// 18|05|00|01|10|27\n\
// 17|04|03|02|11|28\n\
// 16|15|14|13|12|29\n\
// 35|34|33|32|31|30\n\
\n\
ATTRIBUTE vec2 inPosition;\n\
ATTRIBUTE vec2 inTexCoord0;\n\
\n\
uniform vec2 viewSize; \n\
uniform float scalar; \n\
uniform float angleDegrees; \n\
\n\
VARYING vec2 texCoord[36];\n\
\n\
void main()\n\
{\n\
float angleRadians = radians(angleDegrees); \n\
\n\
mat2 projection = mat2( vec2(2.0/viewSize.x, 0.0), \n\
vec2( 0.0, 2.0/viewSize.y)); \n\
\n\
mat2 rotation = mat2( vec2(cos(angleRadians), -sin(angleRadians)), \n\
vec2(sin(angleRadians), cos(angleRadians))); \n\
\n\
mat2 scale = mat2( vec2(scalar, 0.0), \n\
vec2( 0.0, scalar)); \n\
\n\
vec2 xystart = floor(inTexCoord0 - 0.5) + 0.5;\n\
\n\
texCoord[20] = xystart + vec2(-2.0,-2.0);\n\
texCoord[21] = xystart + vec2(-1.0,-2.0);\n\
texCoord[22] = xystart + vec2( 0.0,-2.0);\n\
texCoord[23] = xystart + vec2( 1.0,-2.0);\n\
texCoord[24] = xystart + vec2( 2.0,-2.0);\n\
texCoord[25] = xystart + vec2( 3.0,-2.0);\n\
\n\
texCoord[19] = xystart + vec2(-2.0,-1.0);\n\
texCoord[ 6] = xystart + vec2(-1.0,-1.0);\n\
texCoord[ 7] = xystart + vec2( 0.0,-1.0);\n\
texCoord[ 8] = xystart + vec2( 1.0,-1.0);\n\
texCoord[ 9] = xystart + vec2( 2.0,-1.0);\n\
texCoord[26] = xystart + vec2( 3.0,-1.0);\n\
\n\
texCoord[18] = xystart + vec2(-2.0, 0.0);\n\
texCoord[ 5] = xystart + vec2(-1.0, 0.0);\n\
texCoord[ 0] = xystart + vec2( 0.0, 0.0); // Center pixel\n\
texCoord[ 1] = xystart + vec2( 1.0, 0.0);\n\
texCoord[10] = xystart + vec2( 2.0, 0.0);\n\
texCoord[27] = xystart + vec2( 3.0, 0.0);\n\
\n\
texCoord[17] = xystart + vec2(-2.0, 1.0);\n\
texCoord[ 4] = xystart + vec2(-1.0, 1.0);\n\
texCoord[ 3] = xystart + vec2( 0.0, 1.0);\n\
texCoord[ 2] = xystart + vec2( 1.0, 1.0);\n\
texCoord[11] = xystart + vec2( 2.0, 1.0);\n\
texCoord[28] = xystart + vec2( 3.0, 1.0);\n\
\n\
texCoord[16] = xystart + vec2(-2.0, 2.0);\n\
texCoord[15] = xystart + vec2(-1.0, 2.0);\n\
texCoord[14] = xystart + vec2( 0.0, 2.0);\n\
texCoord[13] = xystart + vec2( 1.0, 2.0);\n\
texCoord[12] = xystart + vec2( 2.0, 2.0);\n\
texCoord[29] = xystart + vec2( 3.0, 2.0);\n\
\n\
texCoord[35] = xystart + vec2(-2.0, 3.0);\n\
texCoord[34] = xystart + vec2(-1.0, 3.0);\n\
texCoord[33] = xystart + vec2( 0.0, 3.0);\n\
texCoord[32] = xystart + vec2( 1.0, 3.0);\n\
texCoord[31] = xystart + vec2( 2.0, 3.0);\n\
texCoord[30] = xystart + vec2( 3.0, 3.0);\n\
\n\
gl_Position = vec4(projection * rotation * scale * inPosition, 0.0, 1.0);\n\
}\n\
"};
// FRAGMENT SHADER FOR DISPLAY OUTPUT
static const char *PassthroughOutputFragShader_110 = {"\
VARYING vec2 texCoord[1];\n\
uniform sampler2DRect tex;\n\
\n\
void main()\n\
{\n\
OUT_FRAG_COLOR.rgb = SAMPLE3_TEX_RECT(tex, texCoord[0]);\n\
OUT_FRAG_COLOR.a = 1.0;\n\
}\n\
"};
// VERTEX SHADER FOR VIDEO FILTERS
static const char *Sample1x1_VertShader_110 = {"\
// For reference, the pixels are mapped as follows:\n\
// Start at center pixel 0 (p0), and circle around it\n\
// in a clockwise fashion, starting from the right.\n\
//---------------------------------------\n\
// Input Pixel Mapping: 20|21|22|23|24\n\
// 19|06|07|08|09\n\
// 18|05|00|01|10\n\
// 17|04|03|02|11\n\
// 16|15|14|13|12\n\
\n\
ATTRIBUTE vec2 inPosition;\n\
ATTRIBUTE vec2 inTexCoord0;\n\
VARYING vec2 texCoord[1];\n\
\n\
void main()\n\
{\n\
texCoord[0] = inTexCoord0;\n\
gl_Position = vec4(inPosition, 0.0, 1.0);\n\
}\n\
"};
static const char *Sample2x2_VertShader_110 = {"\
//---------------------------------------\n\
// Input Pixel Mapping: 00|01\n\
// 03|02\n\
\n\
ATTRIBUTE vec2 inPosition;\n\
ATTRIBUTE vec2 inTexCoord0;\n\
VARYING vec2 texCoord[4];\n\
\n\
void main()\n\
{\n\
texCoord[0] = inTexCoord0 + vec2( 0.0, 0.0); // Center pixel\n\
texCoord[1] = inTexCoord0 + vec2( 1.0, 0.0);\n\
texCoord[3] = inTexCoord0 + vec2( 0.0, 1.0);\n\
texCoord[2] = inTexCoord0 + vec2( 1.0, 1.0);\n\
\n\
gl_Position = vec4(inPosition, 0.0, 1.0);\n\
}\n\
"};
static const char *Sample3x3_VertShader_110 = {"\
//---------------------------------------\n\
// Input Pixel Mapping: 06|07|08\n\
// 05|00|01\n\
// 04|03|02\n\
\n\
ATTRIBUTE vec2 inPosition;\n\
ATTRIBUTE vec2 inTexCoord0;\n\
VARYING vec2 texCoord[9];\n\
\n\
void main()\n\
{\n\
texCoord[6] = inTexCoord0 + vec2(-1.0,-1.0);\n\
texCoord[7] = inTexCoord0 + vec2( 0.0,-1.0);\n\
texCoord[8] = inTexCoord0 + vec2( 1.0,-1.0);\n\
\n\
texCoord[5] = inTexCoord0 + vec2(-1.0, 0.0);\n\
texCoord[0] = inTexCoord0 + vec2( 0.0, 0.0); // Center pixel\n\
texCoord[1] = inTexCoord0 + vec2( 1.0, 0.0);\n\
\n\
texCoord[4] = inTexCoord0 + vec2(-1.0, 1.0);\n\
texCoord[3] = inTexCoord0 + vec2( 0.0, 1.0);\n\
texCoord[2] = inTexCoord0 + vec2( 1.0, 1.0);\n\
\n\
gl_Position = vec4(inPosition, 0.0, 1.0);\n\
}\n\
"};
static const char *Sample4x4_VertShader_110 = {"\
//---------------------------------------\n\
// Input Pixel Mapping: 06|07|08|09\n\
// 05|00|01|10\n\
// 04|03|02|11\n\
// 15|14|13|12\n\
\n\
ATTRIBUTE vec2 inPosition;\n\
ATTRIBUTE vec2 inTexCoord0;\n\
VARYING vec2 texCoord[16];\n\
\n\
void main()\n\
{\n\
texCoord[ 6] = inTexCoord0 + vec2(-1.0,-1.0);\n\
texCoord[ 7] = inTexCoord0 + vec2( 0.0,-1.0);\n\
texCoord[ 8] = inTexCoord0 + vec2( 1.0,-1.0);\n\
texCoord[ 9] = inTexCoord0 + vec2( 2.0,-1.0);\n\
\n\
texCoord[ 5] = inTexCoord0 + vec2(-1.0, 0.0);\n\
texCoord[ 0] = inTexCoord0 + vec2( 0.0, 0.0); // Center pixel\n\
texCoord[ 1] = inTexCoord0 + vec2( 1.0, 0.0);\n\
texCoord[10] = inTexCoord0 + vec2( 2.0, 0.0);\n\
\n\
texCoord[ 4] = inTexCoord0 + vec2(-1.0, 1.0);\n\
texCoord[ 3] = inTexCoord0 + vec2( 0.0, 1.0);\n\
texCoord[ 2] = inTexCoord0 + vec2( 1.0, 1.0);\n\
texCoord[11] = inTexCoord0 + vec2( 2.0, 1.0);\n\
\n\
texCoord[15] = inTexCoord0 + vec2(-1.0, 2.0);\n\
texCoord[14] = inTexCoord0 + vec2( 0.0, 2.0);\n\
texCoord[13] = inTexCoord0 + vec2( 1.0, 2.0);\n\
texCoord[12] = inTexCoord0 + vec2( 2.0, 2.0);\n\
\n\
gl_Position = vec4(inPosition, 0.0, 1.0);\n\
}\n\
"};
static const char *Sample5x5_VertShader_110 = {"\
//---------------------------------------\n\
// Input Pixel Mapping: 20|21|22|23|24\n\
// 19|06|07|08|09\n\
// 18|05|00|01|10\n\
// 17|04|03|02|11\n\
// 16|15|14|13|12\n\
\n\
ATTRIBUTE vec2 inPosition;\n\
ATTRIBUTE vec2 inTexCoord0;\n\
VARYING vec2 texCoord[25];\n\
\n\
void main()\n\
{\n\
texCoord[20] = inTexCoord0 + vec2(-2.0,-2.0);\n\
texCoord[21] = inTexCoord0 + vec2(-1.0,-2.0);\n\
texCoord[22] = inTexCoord0 + vec2( 0.0,-2.0);\n\
texCoord[23] = inTexCoord0 + vec2( 1.0,-2.0);\n\
texCoord[24] = inTexCoord0 + vec2( 2.0,-2.0);\n\
\n\
texCoord[19] = inTexCoord0 + vec2(-2.0,-1.0);\n\
texCoord[ 6] = inTexCoord0 + vec2(-1.0,-1.0);\n\
texCoord[ 7] = inTexCoord0 + vec2( 0.0,-1.0);\n\
texCoord[ 8] = inTexCoord0 + vec2( 1.0,-1.0);\n\
texCoord[ 9] = inTexCoord0 + vec2( 2.0,-1.0);\n\
\n\
texCoord[18] = inTexCoord0 + vec2(-2.0, 0.0);\n\
texCoord[ 5] = inTexCoord0 + vec2(-1.0, 0.0);\n\
texCoord[ 0] = inTexCoord0 + vec2( 0.0, 0.0); // Center pixel\n\
texCoord[ 1] = inTexCoord0 + vec2( 1.0, 0.0);\n\
texCoord[10] = inTexCoord0 + vec2( 2.0, 0.0);\n\
\n\
texCoord[17] = inTexCoord0 + vec2(-2.0, 1.0);\n\
texCoord[ 4] = inTexCoord0 + vec2(-1.0, 1.0);\n\
texCoord[ 3] = inTexCoord0 + vec2( 0.0, 1.0);\n\
texCoord[ 2] = inTexCoord0 + vec2( 1.0, 1.0);\n\
texCoord[11] = inTexCoord0 + vec2( 2.0, 1.0);\n\
\n\
texCoord[16] = inTexCoord0 + vec2(-2.0, 2.0);\n\
texCoord[15] = inTexCoord0 + vec2(-1.0, 2.0);\n\
texCoord[14] = inTexCoord0 + vec2( 0.0, 2.0);\n\
texCoord[13] = inTexCoord0 + vec2( 1.0, 2.0);\n\
texCoord[12] = inTexCoord0 + vec2( 2.0, 2.0);\n\
\n\
gl_Position = vec4(inPosition, 0.0, 1.0);\n\
}\n\
"};
// FRAGMENT SHADER PASSTHROUGH FOR FILTERS
static const char *PassthroughFragShader_110 = {"\
VARYING vec2 texCoord[1];\n\
uniform sampler2DRect tex;\n\
\n\
void main()\n\
{\n\
OUT_FRAG_COLOR.rgb = SAMPLE3_TEX_RECT(tex, texCoord[0]);\n\
OUT_FRAG_COLOR.a;\n\
}\n\
"};
// FRAGMENT SHADER FOR DEPOSTERIZATION
static const char *FilterDeposterizeFragShader_110 = {"\
VARYING vec2 texCoord[9];\n\
uniform sampler2DRect tex;\n\
\n\
vec3 InterpLTE(vec3 pixA, vec3 pixB, vec3 threshold)\n\
{\n\
vec3 interpPix = mix(pixA, pixB, 0.5);\n\
vec3 pixCompare = vec3( lessThanEqual(abs(pixB - pixA), threshold) );\n\
\n\
return mix(pixA, interpPix, pixCompare);\n\
}\n\
\n\
//---------------------------------------\n\
// Input Pixel Mapping: 06|07|08\n\
// 05|00|01\n\
// 04|03|02\n\
//\n\
// Output Pixel Mapping: A\n\
\n\
void main()\n\
{\n\
vec3 src[9];\n\
src[0] = SAMPLE3_TEX_RECT(tex, texCoord[0]);\n\
src[1] = SAMPLE3_TEX_RECT(tex, texCoord[1]);\n\
src[2] = SAMPLE3_TEX_RECT(tex, texCoord[2]);\n\
src[3] = SAMPLE3_TEX_RECT(tex, texCoord[3]);\n\
src[4] = SAMPLE3_TEX_RECT(tex, texCoord[4]);\n\
src[5] = SAMPLE3_TEX_RECT(tex, texCoord[5]);\n\
src[6] = SAMPLE3_TEX_RECT(tex, texCoord[6]);\n\
src[7] = SAMPLE3_TEX_RECT(tex, texCoord[7]);\n\
src[8] = SAMPLE3_TEX_RECT(tex, texCoord[8]);\n\
\n\
const vec3 threshold = vec3(0.1020);\n\
\n\
float weight[2];\n\
weight[0] = 0.90;\n\
weight[1] = weight[0] * 0.60;\n\
\n\
vec3 blend[9];\n\
blend[0] = src[0];\n\
blend[1] = InterpLTE(src[0], src[1], threshold);\n\
blend[2] = InterpLTE(src[0], src[2], threshold);\n\
blend[3] = InterpLTE(src[0], src[3], threshold);\n\
blend[4] = InterpLTE(src[0], src[4], threshold);\n\
blend[5] = InterpLTE(src[0], src[5], threshold);\n\
blend[6] = InterpLTE(src[0], src[6], threshold);\n\
blend[7] = InterpLTE(src[0], src[7], threshold);\n\
blend[8] = InterpLTE(src[0], src[8], threshold);\n\
\n\
OUT_FRAG_COLOR.rgb = mix(\n\
mix(\n\
mix(\n\
mix(blend[0], blend[5], weight[0]), mix(blend[0], blend[1], weight[0]),\n\
0.50),\n\
mix(\n\
mix(blend[0], blend[7], weight[0]), mix(blend[0], blend[3], weight[0]),\n\
0.50),\n\
0.50),\n\
mix(\n\
mix(\n\
mix(blend[0], blend[6], weight[1]), mix(blend[0], blend[2], weight[1]),\n\
0.50),\n\
mix(\n\
mix(blend[0], blend[8], weight[1]), mix(blend[0], blend[4], weight[1]),\n\
0.50),\n\
0.50),\n\
0.25);\n\
OUT_FRAG_COLOR.a = 1.0;\n\
}\n\
"};
static const char *FilterBicubicBSplineFragShader_110 = {"\
VARYING vec2 texCoord[16];\n\
uniform sampler2DRect tex;\n\
\n\
vec4 WeightBSpline(float f)\n\
{\n\
return vec4(((1.0-f)*(1.0-f)*(1.0-f)) / 6.0,\n\
(4.0 - 6.0*f*f + 3.0*f*f*f) / 6.0,\n\
(1.0 + 3.0*f + 3.0*f*f - 3.0*f*f*f) / 6.0,\n\
f*f*f / 6.0);\n\
}\n\
\n\
//---------------------------------------\n\
// Input Pixel Mapping: 06|07|08|09\n\
// 05|00|01|10\n\
// 04|03|02|11\n\
// 15|14|13|12\n\
\n\
void main()\n\
{\n\
vec2 f = fract(texCoord[0]);\n\
vec4 wx = WeightBSpline(f.x);\n\
vec4 wy = WeightBSpline(f.y);\n\
\n\
// Normalize weights\n\
wx /= dot(wx, vec4(1.0));\n\
wy /= dot(wy, vec4(1.0));\n\
\n\
OUT_FRAG_COLOR.rgb = (SAMPLE3_TEX_RECT(tex, texCoord[ 6]) * wx.r\n\
+ SAMPLE3_TEX_RECT(tex, texCoord[ 7]) * wx.g\n\
+ SAMPLE3_TEX_RECT(tex, texCoord[ 8]) * wx.b\n\
+ SAMPLE3_TEX_RECT(tex, texCoord[ 9]) * wx.a) * wy.r\n\
+ (SAMPLE3_TEX_RECT(tex, texCoord[ 5]) * wx.r\n\
+ SAMPLE3_TEX_RECT(tex, texCoord[ 0]) * wx.g\n\
+ SAMPLE3_TEX_RECT(tex, texCoord[ 1]) * wx.b\n\
+ SAMPLE3_TEX_RECT(tex, texCoord[10]) * wx.a) * wy.g\n\
+ (SAMPLE3_TEX_RECT(tex, texCoord[ 4]) * wx.r\n\
+ SAMPLE3_TEX_RECT(tex, texCoord[ 3]) * wx.g\n\
+ SAMPLE3_TEX_RECT(tex, texCoord[ 2]) * wx.b\n\
+ SAMPLE3_TEX_RECT(tex, texCoord[11]) * wx.a) * wy.b\n\
+ (SAMPLE3_TEX_RECT(tex, texCoord[15]) * wx.r\n\
+ SAMPLE3_TEX_RECT(tex, texCoord[14]) * wx.g\n\
+ SAMPLE3_TEX_RECT(tex, texCoord[13]) * wx.b\n\
+ SAMPLE3_TEX_RECT(tex, texCoord[12]) * wx.a) * wy.a;\n\
OUT_FRAG_COLOR.a;\n\
}\n\
"};
static const char *FilterBicubicBSplineFastFragShader_110 = {"\
VARYING vec2 texCoord[1];\n\
uniform sampler2DRect tex;\n\
\n\
void main()\n\
{\n\
vec2 texCenterPosition = floor(texCoord[0] - 0.5) + 0.5;\n\
vec2 f = abs(texCoord[0] - texCenterPosition);\n\
\n\
vec2 w0 = ((1.0-f)*(1.0-f)*(1.0-f)) / 6.0;\n\
vec2 w1 = (4.0 - 6.0*f*f + 3.0*f*f*f) / 6.0;\n\
vec2 w3 = f*f*f / 6.0;\n\
vec2 w2 = 1.0 - w0 - w1 - w3;\n\
\n\
vec2 s0 = w0 + w1;\n\
vec2 s1 = w2 + w3;\n\
\n\
vec2 t0 = texCenterPosition - 1.0 + (w1 / s0);\n\
vec2 t1 = texCenterPosition + 1.0 + (w3 / s1);\n\
\n\
OUT_FRAG_COLOR.rgb = (SAMPLE3_TEX_RECT(tex, vec2(t0.x, t0.y)) * s0.x +\n\
SAMPLE3_TEX_RECT(tex, vec2(t1.x, t0.y)) * s1.x) * s0.y +\n\
(SAMPLE3_TEX_RECT(tex, vec2(t0.x, t1.y)) * s0.x +\n\
SAMPLE3_TEX_RECT(tex, vec2(t1.x, t1.y)) * s1.x) * s1.y;\n\
OUT_FRAG_COLOR.a;\n\
}\n\
"};
static const char *FilterBicubicMitchellNetravaliFragShader_110 = {"\
VARYING vec2 texCoord[16];\n\
uniform sampler2DRect tex;\n\
\n\
vec4 WeightMitchellNetravali(float f)\n\
{\n\
return vec4((1.0 - 9.0*f + 15.0*f*f - 7.0*f*f*f) / 18.0,\n\
(16.0 - 36.0*f*f + 21.0*f*f*f) / 18.0,\n\
(1.0 + 9.0*f + 27.0*f*f - 21.0*f*f*f) / 18.0,\n\
(7.0*f*f*f - 6.0*f*f) / 18.0);\n\
}\n\
\n\
//---------------------------------------\n\
// Input Pixel Mapping: 06|07|08|09\n\
// 05|00|01|10\n\
// 04|03|02|11\n\
// 15|14|13|12\n\
\n\
void main()\n\
{\n\
vec2 f = fract(texCoord[0]);\n\
vec4 wx = WeightMitchellNetravali(f.x);\n\
vec4 wy = WeightMitchellNetravali(f.y);\n\
\n\
// Normalize weights\n\
wx /= dot(wx, vec4(1.0));\n\
wy /= dot(wy, vec4(1.0));\n\
\n\
OUT_FRAG_COLOR.rgb = (SAMPLE3_TEX_RECT(tex, texCoord[ 6]) * wx.r\n\
+ SAMPLE3_TEX_RECT(tex, texCoord[ 7]) * wx.g\n\
+ SAMPLE3_TEX_RECT(tex, texCoord[ 8]) * wx.b\n\
+ SAMPLE3_TEX_RECT(tex, texCoord[ 9]) * wx.a) * wy.r\n\
+ (SAMPLE3_TEX_RECT(tex, texCoord[ 5]) * wx.r\n\
+ SAMPLE3_TEX_RECT(tex, texCoord[ 0]) * wx.g\n\
+ SAMPLE3_TEX_RECT(tex, texCoord[ 1]) * wx.b\n\
+ SAMPLE3_TEX_RECT(tex, texCoord[10]) * wx.a) * wy.g\n\
+ (SAMPLE3_TEX_RECT(tex, texCoord[ 4]) * wx.r\n\
+ SAMPLE3_TEX_RECT(tex, texCoord[ 3]) * wx.g\n\
+ SAMPLE3_TEX_RECT(tex, texCoord[ 2]) * wx.b\n\
+ SAMPLE3_TEX_RECT(tex, texCoord[11]) * wx.a) * wy.b\n\
+ (SAMPLE3_TEX_RECT(tex, texCoord[15]) * wx.r\n\
+ SAMPLE3_TEX_RECT(tex, texCoord[14]) * wx.g\n\
+ SAMPLE3_TEX_RECT(tex, texCoord[13]) * wx.b\n\
+ SAMPLE3_TEX_RECT(tex, texCoord[12]) * wx.a) * wy.a;\n\
OUT_FRAG_COLOR.a = 1.0;\n\
}\n\
"};
static const char *FilterBicubicMitchellNetravaliFastFragShader_110 = {"\
VARYING vec2 texCoord[1];\n\
uniform sampler2DRect tex;\n\
\n\
void main()\n\
{\n\
vec2 texCenterPosition = floor(texCoord[0] - 0.5) + 0.5;\n\
vec2 f = abs(texCoord[0] - texCenterPosition);\n\
\n\
vec2 w0 = (1.0 - 9.0*f + 15.0*f*f - 7.0*f*f*f) / 18.0;\n\
vec2 w1 = (16.0 - 36.0*f*f + 21.0*f*f*f) / 18.0;\n\
vec2 w3 = (7.0*f*f*f - 6.0*f*f) / 18.0;\n\
vec2 w2 = 1.0 - w0 - w1 - w3;\n\
\n\
vec2 s0 = w0 + w1;\n\
vec2 s1 = w2 + w3;\n\
\n\
vec2 t0 = texCenterPosition - 1.0 + (w1 / s0);\n\
vec2 t1 = texCenterPosition + 1.0 + (w3 / s1);\n\
\n\
OUT_FRAG_COLOR.rgb = (SAMPLE3_TEX_RECT(tex, vec2(t0.x, t0.y)) * s0.x +\n\
SAMPLE3_TEX_RECT(tex, vec2(t1.x, t0.y)) * s1.x) * s0.y +\n\
(SAMPLE3_TEX_RECT(tex, vec2(t0.x, t1.y)) * s0.x +\n\
SAMPLE3_TEX_RECT(tex, vec2(t1.x, t1.y)) * s1.x) * s1.y;\n\
OUT_FRAG_COLOR.a = 1.0;\n\
}\n\
"};
static const char *FilterLanczos2FragShader_110 = {"\
#define PI 3.1415926535897932384626433832795\n\
#define RADIUS 2.0\n\
#define FIX(c) max(abs(c), 1e-5)\n\
\n\
VARYING vec2 texCoord[16];\n\
uniform sampler2DRect tex;\n\
\n\
vec4 WeightLanczos2(float f)\n\
{\n\
vec4 sample = FIX(PI * vec4(1.0 + f, f, 1.0 - f, 2.0 - f));\n\
return ( sin(sample) * sin(sample / RADIUS) / (sample * sample) );\n\
}\n\
\n\
//---------------------------------------\n\
// Input Pixel Mapping: 06|07|08|09\n\
// 05|00|01|10\n\
// 04|03|02|11\n\
// 15|14|13|12\n\
\n\
void main()\n\
{\n\
vec2 f = fract(texCoord[0]);\n\
vec4 wx = WeightLanczos2(f.x);\n\
vec4 wy = WeightLanczos2(f.y);\n\
\n\
// Normalize weights\n\
wx /= dot(wx, vec4(1.0));\n\
wy /= dot(wy, vec4(1.0));\n\
\n\
OUT_FRAG_COLOR.rgb = (SAMPLE3_TEX_RECT(tex, texCoord[ 6]) * wx.r\n\
+ SAMPLE3_TEX_RECT(tex, texCoord[ 7]) * wx.g\n\
+ SAMPLE3_TEX_RECT(tex, texCoord[ 8]) * wx.b\n\
+ SAMPLE3_TEX_RECT(tex, texCoord[ 9]) * wx.a) * wy.r\n\
+ (SAMPLE3_TEX_RECT(tex, texCoord[ 5]) * wx.r\n\
+ SAMPLE3_TEX_RECT(tex, texCoord[ 0]) * wx.g\n\
+ SAMPLE3_TEX_RECT(tex, texCoord[ 1]) * wx.b\n\
+ SAMPLE3_TEX_RECT(tex, texCoord[10]) * wx.a) * wy.g\n\
+ (SAMPLE3_TEX_RECT(tex, texCoord[ 4]) * wx.r\n\
+ SAMPLE3_TEX_RECT(tex, texCoord[ 3]) * wx.g\n\
+ SAMPLE3_TEX_RECT(tex, texCoord[ 2]) * wx.b\n\
+ SAMPLE3_TEX_RECT(tex, texCoord[11]) * wx.a) * wy.b\n\
+ (SAMPLE3_TEX_RECT(tex, texCoord[15]) * wx.r\n\
+ SAMPLE3_TEX_RECT(tex, texCoord[14]) * wx.g\n\
+ SAMPLE3_TEX_RECT(tex, texCoord[13]) * wx.b\n\
+ SAMPLE3_TEX_RECT(tex, texCoord[12]) * wx.a) * wy.a;\n\
OUT_FRAG_COLOR.a = 1.0;\n\
}\n\
"};
static const char *FilterLanczos3FragShader_110 = {"\
#define PI 3.1415926535897932384626433832795\n\
#define RADIUS 3.0\n\
#define FIX(c) max(abs(c), 1e-5)\n\
\n\
#if GPU_TIER >= SHADERSUPPORT_HIGH_TIER\n\
VARYING vec2 texCoord[36];\n\
#elif GPU_TIER >= SHADERSUPPORT_MID_TIER\n\
VARYING vec2 texCoord[25];\n\
#else\n\
VARYING vec2 texCoord[16];\n\
#endif\n\
uniform sampler2DRect tex;\n\
\n\
vec3 weight3(float x)\n\
{\n\
vec3 sample = FIX(2.0 * PI * vec3(x - 1.5, x - 0.5, x + 0.5));\n\
return ( sin(sample) * sin(sample / RADIUS) / (sample * sample) );\n\
}\n\
\n\
//---------------------------------------\n\
// Input Pixel Mapping: 20|21|22|23|24|25\n\
// 19|06|07|08|09|26\n\
// 18|05|00|01|10|27\n\
// 17|04|03|02|11|28\n\
// 16|15|14|13|12|29\n\
// 35|34|33|32|31|30\n\
\n\
void main()\n\
{\n\
vec2 f = fract(texCoord[0]);\n\
vec3 wx1 = weight3(0.5 - f.x * 0.5);\n\
vec3 wx2 = weight3(1.0 - f.x * 0.5);\n\
vec3 wy1 = weight3(0.5 - f.y * 0.5);\n\
vec3 wy2 = weight3(1.0 - f.y * 0.5);\n\
\n\
// Normalize weights\n\
float sumX = dot(wx1, vec3(1.0)) + dot(wx2, vec3(1.0));\n\
float sumY = dot(wy1, vec3(1.0)) + dot(wy2, vec3(1.0));\n\
wx1 /= sumX;\n\
wx2 /= sumX;\n\
wy1 /= sumY;\n\
wy2 /= sumY;\n\
\n\
#if GPU_TIER >= SHADERSUPPORT_HIGH_TIER\n\
OUT_FRAG_COLOR.rgb = (SAMPLE3_TEX_RECT(tex, texCoord[20]) * wx1.r\n\
+ SAMPLE3_TEX_RECT(tex, texCoord[21]) * wx2.r\n\
+ SAMPLE3_TEX_RECT(tex, texCoord[22]) * wx1.g\n\
+ SAMPLE3_TEX_RECT(tex, texCoord[23]) * wx2.g\n\
+ SAMPLE3_TEX_RECT(tex, texCoord[24]) * wx1.b\n\
+ SAMPLE3_TEX_RECT(tex, texCoord[25]) * wx2.b) * wy1.r\n\
+ (SAMPLE3_TEX_RECT(tex, texCoord[19]) * wx1.r\n\
+ SAMPLE3_TEX_RECT(tex, texCoord[ 6]) * wx2.r\n\
+ SAMPLE3_TEX_RECT(tex, texCoord[ 7]) * wx1.g\n\
+ SAMPLE3_TEX_RECT(tex, texCoord[ 8]) * wx2.g\n\
+ SAMPLE3_TEX_RECT(tex, texCoord[ 9]) * wx1.b\n\
+ SAMPLE3_TEX_RECT(tex, texCoord[26]) * wx2.b) * wy2.r\n\
+ (SAMPLE3_TEX_RECT(tex, texCoord[18]) * wx1.r\n\
+ SAMPLE3_TEX_RECT(tex, texCoord[ 5]) * wx2.r\n\
+ SAMPLE3_TEX_RECT(tex, texCoord[ 0]) * wx1.g\n\
+ SAMPLE3_TEX_RECT(tex, texCoord[ 1]) * wx2.g\n\
+ SAMPLE3_TEX_RECT(tex, texCoord[10]) * wx1.b\n\
+ SAMPLE3_TEX_RECT(tex, texCoord[27]) * wx2.b) * wy1.g\n\
+ (SAMPLE3_TEX_RECT(tex, texCoord[17]) * wx1.r\n\
+ SAMPLE3_TEX_RECT(tex, texCoord[ 4]) * wx2.r\n\
+ SAMPLE3_TEX_RECT(tex, texCoord[ 3]) * wx1.g\n\
+ SAMPLE3_TEX_RECT(tex, texCoord[ 2]) * wx2.g\n\
+ SAMPLE3_TEX_RECT(tex, texCoord[11]) * wx1.b\n\
+ SAMPLE3_TEX_RECT(tex, texCoord[28]) * wx2.b) * wy2.g\n\
+ (SAMPLE3_TEX_RECT(tex, texCoord[16]) * wx1.r\n\
+ SAMPLE3_TEX_RECT(tex, texCoord[15]) * wx2.r\n\
+ SAMPLE3_TEX_RECT(tex, texCoord[14]) * wx1.g\n\
+ SAMPLE3_TEX_RECT(tex, texCoord[13]) * wx2.g\n\
+ SAMPLE3_TEX_RECT(tex, texCoord[12]) * wx1.b\n\
+ SAMPLE3_TEX_RECT(tex, texCoord[29]) * wx2.b) * wy1.b\n\
+ (SAMPLE3_TEX_RECT(tex, texCoord[35]) * wx1.r\n\
+ SAMPLE3_TEX_RECT(tex, texCoord[34]) * wx2.r\n\
+ SAMPLE3_TEX_RECT(tex, texCoord[33]) * wx1.g\n\
+ SAMPLE3_TEX_RECT(tex, texCoord[32]) * wx2.g\n\
+ SAMPLE3_TEX_RECT(tex, texCoord[31]) * wx1.b\n\
+ SAMPLE3_TEX_RECT(tex, texCoord[30]) * wx2.b) * wy2.b;\n\
#elif GPU_TIER >= SHADERSUPPORT_MID_TIER\n\
OUT_FRAG_COLOR.rgb = (SAMPLE3_TEX_RECT(tex, texCoord[20]) * wx1.r\n\
+ SAMPLE3_TEX_RECT(tex, texCoord[21]) * wx2.r\n\
+ SAMPLE3_TEX_RECT(tex, texCoord[22]) * wx1.g\n\
+ SAMPLE3_TEX_RECT(tex, texCoord[23]) * wx2.g\n\
+ SAMPLE3_TEX_RECT(tex, texCoord[24]) * wx1.b\n\
+ SAMPLE3_TEX_RECT(tex, texCoord[ 0] + vec2( 3.0,-2.0)) * wx2.b) * wy1.r\n\
+ (SAMPLE3_TEX_RECT(tex, texCoord[19]) * wx1.r\n\
+ SAMPLE3_TEX_RECT(tex, texCoord[ 6]) * wx2.r\n\
+ SAMPLE3_TEX_RECT(tex, texCoord[ 7]) * wx1.g\n\
+ SAMPLE3_TEX_RECT(tex, texCoord[ 8]) * wx2.g\n\
+ SAMPLE3_TEX_RECT(tex, texCoord[ 9]) * wx1.b\n\
+ SAMPLE3_TEX_RECT(tex, texCoord[ 0] + vec2( 3.0,-1.0)) * wx2.b) * wy2.r\n\
+ (SAMPLE3_TEX_RECT(tex, texCoord[18]) * wx1.r\n\
+ SAMPLE3_TEX_RECT(tex, texCoord[ 5]) * wx2.r\n\
+ SAMPLE3_TEX_RECT(tex, texCoord[ 0]) * wx1.g\n\
+ SAMPLE3_TEX_RECT(tex, texCoord[ 1]) * wx2.g\n\
+ SAMPLE3_TEX_RECT(tex, texCoord[10]) * wx1.b\n\
+ SAMPLE3_TEX_RECT(tex, texCoord[ 0] + vec2( 3.0, 0.0)) * wx2.b) * wy1.g\n\
+ (SAMPLE3_TEX_RECT(tex, texCoord[17]) * wx1.r\n\
+ SAMPLE3_TEX_RECT(tex, texCoord[ 4]) * wx2.r\n\
+ SAMPLE3_TEX_RECT(tex, texCoord[ 3]) * wx1.g\n\
+ SAMPLE3_TEX_RECT(tex, texCoord[ 2]) * wx2.g\n\
+ SAMPLE3_TEX_RECT(tex, texCoord[11]) * wx1.b\n\
+ SAMPLE3_TEX_RECT(tex, texCoord[ 0] + vec2( 3.0, 1.0)) * wx2.b) * wy2.g\n\
+ (SAMPLE3_TEX_RECT(tex, texCoord[16]) * wx1.r\n\
+ SAMPLE3_TEX_RECT(tex, texCoord[15]) * wx2.r\n\
+ SAMPLE3_TEX_RECT(tex, texCoord[14]) * wx1.g\n\
+ SAMPLE3_TEX_RECT(tex, texCoord[13]) * wx2.g\n\
+ SAMPLE3_TEX_RECT(tex, texCoord[12]) * wx1.b\n\
+ SAMPLE3_TEX_RECT(tex, texCoord[ 0] + vec2( 3.0, 2.0)) * wx2.b) * wy1.b\n\
+ (SAMPLE3_TEX_RECT(tex, texCoord[ 0] + vec2(-2.0, 3.0)) * wx1.r\n\
+ SAMPLE3_TEX_RECT(tex, texCoord[ 0] + vec2(-1.0, 3.0)) * wx2.r\n\
+ SAMPLE3_TEX_RECT(tex, texCoord[ 0] + vec2( 0.0, 3.0)) * wx1.g\n\
+ SAMPLE3_TEX_RECT(tex, texCoord[ 0] + vec2( 1.0, 3.0)) * wx2.g\n\
+ SAMPLE3_TEX_RECT(tex, texCoord[ 0] + vec2( 2.0, 3.0)) * wx1.b\n\
+ SAMPLE3_TEX_RECT(tex, texCoord[ 0] + vec2( 3.0, 3.0)) * wx2.b) * wy2.b;\n\
#else\n\
OUT_FRAG_COLOR.rgb = (SAMPLE3_TEX_RECT(tex, texCoord[ 0] + vec2(-2.0,-2.0)) * wx1.r\n\
+ SAMPLE3_TEX_RECT(tex, texCoord[ 0] + vec2(-1.0,-2.0)) * wx2.r\n\
+ SAMPLE3_TEX_RECT(tex, texCoord[ 0] + vec2( 0.0,-2.0)) * wx1.g\n\
+ SAMPLE3_TEX_RECT(tex, texCoord[ 0] + vec2( 1.0,-2.0)) * wx2.g\n\
+ SAMPLE3_TEX_RECT(tex, texCoord[ 0] + vec2( 2.0,-2.0)) * wx1.b\n\
+ SAMPLE3_TEX_RECT(tex, texCoord[ 0] + vec2( 3.0,-2.0)) * wx2.b) * wy1.r\n\
+ (SAMPLE3_TEX_RECT(tex, texCoord[ 0] + vec2(-2.0,-1.0)) * wx1.r\n\
+ SAMPLE3_TEX_RECT(tex, texCoord[ 6]) * wx2.r\n\
+ SAMPLE3_TEX_RECT(tex, texCoord[ 7]) * wx1.g\n\
+ SAMPLE3_TEX_RECT(tex, texCoord[ 8]) * wx2.g\n\
+ SAMPLE3_TEX_RECT(tex, texCoord[ 9]) * wx1.b\n\
+ SAMPLE3_TEX_RECT(tex, texCoord[ 0] + vec2( 3.0,-1.0)) * wx2.b) * wy2.r\n\
+ (SAMPLE3_TEX_RECT(tex, texCoord[ 0] + vec2(-2.0, 0.0)) * wx1.r\n\
+ SAMPLE3_TEX_RECT(tex, texCoord[ 5]) * wx2.r\n\
+ SAMPLE3_TEX_RECT(tex, texCoord[ 0]) * wx1.g\n\
+ SAMPLE3_TEX_RECT(tex, texCoord[ 1]) * wx2.g\n\
+ SAMPLE3_TEX_RECT(tex, texCoord[10]) * wx1.b\n\
+ SAMPLE3_TEX_RECT(tex, texCoord[ 0] + vec2( 3.0, 0.0)) * wx2.b) * wy1.g\n\
+ (SAMPLE3_TEX_RECT(tex, texCoord[ 0] + vec2(-2.0, 1.0)) * wx1.r\n\
+ SAMPLE3_TEX_RECT(tex, texCoord[ 4]) * wx2.r\n\
+ SAMPLE3_TEX_RECT(tex, texCoord[ 3]) * wx1.g\n\
+ SAMPLE3_TEX_RECT(tex, texCoord[ 2]) * wx2.g\n\
+ SAMPLE3_TEX_RECT(tex, texCoord[11]) * wx1.b\n\
+ SAMPLE3_TEX_RECT(tex, texCoord[ 0] + vec2( 3.0, 1.0)) * wx2.b) * wy2.g\n\
+ (SAMPLE3_TEX_RECT(tex, texCoord[ 0] + vec2(-2.0, 2.0)) * wx1.r\n\
+ SAMPLE3_TEX_RECT(tex, texCoord[15]) * wx2.r\n\
+ SAMPLE3_TEX_RECT(tex, texCoord[14]) * wx1.g\n\
+ SAMPLE3_TEX_RECT(tex, texCoord[13]) * wx2.g\n\
+ SAMPLE3_TEX_RECT(tex, texCoord[12]) * wx1.b\n\
+ SAMPLE3_TEX_RECT(tex, texCoord[ 0] + vec2( 3.0, 2.0)) * wx2.b) * wy1.b\n\
+ (SAMPLE3_TEX_RECT(tex, texCoord[ 0] + vec2(-2.0, 3.0)) * wx1.r\n\
+ SAMPLE3_TEX_RECT(tex, texCoord[ 0] + vec2(-1.0, 3.0)) * wx2.r\n\
+ SAMPLE3_TEX_RECT(tex, texCoord[ 0] + vec2( 0.0, 3.0)) * wx1.g\n\
+ SAMPLE3_TEX_RECT(tex, texCoord[ 0] + vec2( 1.0, 3.0)) * wx2.g\n\
+ SAMPLE3_TEX_RECT(tex, texCoord[ 0] + vec2( 2.0, 3.0)) * wx1.b\n\
+ SAMPLE3_TEX_RECT(tex, texCoord[ 0] + vec2( 3.0, 3.0)) * wx2.b) * wy2.b;\n\
#endif\n\
OUT_FRAG_COLOR.a = 1.0;\n\
}\n\
"};
static const char *Scalar2xScanlineFragShader_110 = {"\
VARYING vec2 texCoord[1];\n\
uniform sampler2DRect tex;\n\
\n\
//---------------------------------------\n\
// Input Pixel Mapping: 00\n\
//\n\
// Output Pixel Mapping: A|B\n\
// C|D\n\
\n\
void main()\n\
{\n\
vec2 f = step(0.5, fract(texCoord[0]));\n\
float w = mix( mix(1.000, 0.875, f.x), mix(0.875, 0.750, f.x), f.y );\n\
\n\
OUT_FRAG_COLOR.rgb = SAMPLE3_TEX_RECT(tex, texCoord[0]) * w;\n\
OUT_FRAG_COLOR.a = 1.0;\n\
}\n\
"};
static const char *Scalar2xEPXFragShader_110 = {"\
VARYING vec2 texCoord[9];\n\
uniform sampler2DRect tex;\n\
\n\
float reduce(vec3 color)\n\
{\n\
return dot(color, vec3(65536.0, 256.0, 1.0));\n\
}\n\
\n\
//---------------------------------------\n\
// Input Pixel Mapping: --|07|--\n\
// 05|00|01\n\
// --|03|--\n\
//\n\
// Output Pixel Mapping: A|B\n\
// C|D\n\
\n\
void main()\n\
{\n\
vec3 src7 = SAMPLE3_TEX_RECT(tex, texCoord[7]);\n\
vec3 src5 = SAMPLE3_TEX_RECT(tex, texCoord[5]);\n\
vec3 src0 = SAMPLE3_TEX_RECT(tex, texCoord[0]);\n\
vec3 src1 = SAMPLE3_TEX_RECT(tex, texCoord[1]);\n\
vec3 src3 = SAMPLE3_TEX_RECT(tex, texCoord[3]);\n\
float v7 = reduce(src7);\n\
float v5 = reduce(src5);\n\
float v1 = reduce(src1);\n\
float v3 = reduce(src3);\n\
\n\
bool pixCompare = (v5 != v1) && (v7 != v3);\n\
vec3 outA = (pixCompare && (v7 == v5)) ? src7 : src0;\n\
vec3 outB = (pixCompare && (v1 == v7)) ? src1 : src0;\n\
vec3 outC = (pixCompare && (v5 == v3)) ? src5 : src0;\n\
vec3 outD = (pixCompare && (v3 == v1)) ? src3 : src0;\n\
\n\
vec2 f = step(0.5, fract(texCoord[0]));\n\
OUT_FRAG_COLOR.rgb = mix( mix(outA, outB, f.x), mix(outC, outD, f.x), f.y );\n\
OUT_FRAG_COLOR.a = 1.0;\n\
}\n\
"};
static const char *Scalar2xEPXPlusFragShader_110 = {"\
VARYING vec2 texCoord[9];\n\
uniform sampler2DRect tex;\n\
\n\
float dist(vec3 pixA, vec3 pixB)\n\
{\n\
return dot(abs(pixA - pixB), vec3(2.0, 3.0, 3.0));\n\
}\n\
\n\
//---------------------------------------\n\
// Input Pixel Mapping: --|07|--\n\
// 05|00|01\n\
// --|03|--\n\
//\n\
// Output Pixel Mapping: A|B\n\
// C|D\n\
\n\
void main()\n\
{\n\
vec3 src7 = SAMPLE3_TEX_RECT(tex, texCoord[7]);\n\
vec3 src5 = SAMPLE3_TEX_RECT(tex, texCoord[5]);\n\
vec3 src0 = SAMPLE3_TEX_RECT(tex, texCoord[0]);\n\
vec3 src1 = SAMPLE3_TEX_RECT(tex, texCoord[1]);\n\
vec3 src3 = SAMPLE3_TEX_RECT(tex, texCoord[3]);\n\
\n\
vec3 outA = ( dist(src5, src7) < min(dist(src5, src3), dist(src1, src7)) ) ? mix(src5, src7, 0.5) : src0;\n\
vec3 outB = ( dist(src1, src7) < min(dist(src5, src7), dist(src1, src3)) ) ? mix(src1, src7, 0.5) : src0;\n\
vec3 outC = ( dist(src5, src3) < min(dist(src5, src7), dist(src1, src3)) ) ? mix(src5, src3, 0.5) : src0;\n\
vec3 outD = ( dist(src1, src3) < min(dist(src5, src3), dist(src1, src7)) ) ? mix(src1, src3, 0.5) : src0;\n\
\n\
vec2 f = step(0.5, fract(texCoord[0]));\n\
OUT_FRAG_COLOR.rgb = mix( mix(outA, outB, f.x), mix(outC, outD, f.x), f.y );\n\
OUT_FRAG_COLOR.a = 1.0;\n\
}\n\
"};
static const char *Scalar2xSaIFragShader_110 = {"\
VARYING vec2 texCoord[16];\n\
uniform sampler2DRect tex;\n\
\n\
const vec3 dt = vec3(65536.0, 256.0, 1.0);\n\
\n\
float GetResult(float v1, float v2, float v3, float v4)\n\
{\n\
return sign(abs(v1-v3)+abs(v1-v4))-sign(abs(v2-v3)+abs(v2-v4));\n\
}\n\
\n\
float reduce(vec3 color)\n\
{\n\
return dot(color, dt);\n\
}\n\
//---------------------------------------\n\
// Input Pixel Mapping: 06|07|08|09\n\
// 05|00|01|10\n\
// 04|03|02|11\n\
// 15|14|13|12\n\
//\n\
// Output Pixel Mapping: A|B\n\
// C|D\n\
\n\
//---------------------------------------\n\
// 2xSaI Pixel Mapping: I|E|F|J\n\
// G|A|B|K\n\
// H|C|D|L\n\
// M|N|O|P\n\
\n\
void main()\n\
{\n\
vec2 f = step(0.5, fract(texCoord[0]));\n\
\n\
float Iv = reduce( SAMPLE3_TEX_RECT(tex, texCoord[6]).rgb );\n\
float Ev = reduce( SAMPLE3_TEX_RECT(tex, texCoord[7]).rgb );\n\
float Fv = reduce( SAMPLE3_TEX_RECT(tex, texCoord[8]).rgb );\n\
float Jv = reduce( SAMPLE3_TEX_RECT(tex, texCoord[9]).rgb );\n\
\n\
float Gv = reduce( SAMPLE3_TEX_RECT(tex, texCoord[5]).rgb );\n\
vec3 Ac = SAMPLE3_TEX_RECT(tex, texCoord[0]).rgb; float Av = reduce(Ac);\n\
vec3 Bc = SAMPLE3_TEX_RECT(tex, texCoord[1]).rgb; float Bv = reduce(Bc);\n\
float Kv = reduce( SAMPLE3_TEX_RECT(tex, texCoord[10]).rgb );\n\
\n\
float Hv = reduce( SAMPLE3_TEX_RECT(tex, texCoord[4]).rgb );\n\
vec3 Cc = SAMPLE3_TEX_RECT(tex, texCoord[3]).rgb; float Cv = reduce(Cc);\n\
vec3 Dc = SAMPLE3_TEX_RECT(tex, texCoord[2]).rgb; float Dv = reduce(Dc);\n\
float Lv = reduce( SAMPLE3_TEX_RECT(tex, texCoord[11]).rgb );\n\
\n\
float Mv = reduce( SAMPLE3_TEX_RECT(tex, texCoord[15]).rgb );\n\
float Nv = reduce( SAMPLE3_TEX_RECT(tex, texCoord[14]).rgb );\n\
float Ov = reduce( SAMPLE3_TEX_RECT(tex, texCoord[13]).rgb );\n\
// Pv is unused, so skip this one.\n\
\n\
vec3 outA = Ac;\n\
vec3 outB = Ac;\n\
vec3 outC = Ac;\n\
vec3 outD = Ac;\n\
\n\
bool compAD = (Av == Dv);\n\
bool compBC = (Bv == Cv);\n\
\n\
if (compAD && !compBC)\n\
{\n\
outB = ((Av == Ev) && (Bv == Lv)) || ((Av == Cv) && (Av == Fv) && (Bv != Ev) && (Bv == Jv)) ? Ac : mix(Ac, Bc, 0.5);\n\
outC = ((Av == Gv) && (Cv == Ov)) || ((Av == Bv) && (Av == Hv) && (Cv != Gv) && (Cv == Mv)) ? Ac : mix(Ac, Cc, 0.5);\n\
}\n\
else if (!compAD && compBC)\n\
{\n\
outB = ((Bv == Fv) && (Av == Hv)) || ((Bv == Ev) && (Bv == Dv) && (Av != Fv) && (Av == Iv)) ? Bc : mix(Ac, Bc, 0.5);\n\
outC = ((Cv == Hv) && (Av == Fv)) || ((Cv == Gv) && (Cv == Dv) && (Av != Hv) && (Av == Iv)) ? Cc : mix(Ac, Cc, 0.5);\n\
outD = Bc;\n\
}\n\
else if (compAD && compBC)\n\
{\n\
outB = (Av == Bv) ? Ac : mix(Ac, Bc, 0.5);\n\
outC = (Av == Bv) ? Ac : mix(Ac, Cc, 0.5);\n\
\n\
float r = (Av == Bv) ? 1.0 : GetResult(Av, Bv, Gv, Ev) - GetResult(Bv, Av, Kv, Fv) - GetResult(Bv, Av, Hv, Nv) + GetResult(Av, Bv, Lv, Ov);\n\
outD = (r > 0.0) ? Ac : ( (r < 0.0) ? Bc : mix( mix(Ac, Bc, 0.5), mix(Cc, Dc, 0.5), 0.5) );\n\
}\n\
else\n\
{\n\
outB = ((Av == Cv) && (Av == Fv) && (Bv != Ev) && (Bv == Jv)) ? Ac : ( ((Bv == Ev) && (Bv == Dv) && (Av != Fv) && (Av == Iv)) ? Bc : mix(Ac, Bc, 0.5) );\n\
outC = ((Av == Bv) && (Av == Hv) && (Cv != Gv) && (Cv == Mv)) ? Ac : ( ((Cv == Gv) && (Cv == Dv) && (Av != Hv) && (Av == Iv)) ? Cc : mix(Ac, Cc, 0.5) );\n\
outD = mix( mix(Ac, Bc, 0.5), mix(Cc, Dc, 0.5), 0.5 );\n\
}\n\
\n\
OUT_FRAG_COLOR.rgb = mix( mix(outA, outB, f.x), mix(outC, outD, f.x), f.y );\n\
OUT_FRAG_COLOR.a = 1.0;\n\
}\n\
"};
static const char *ScalarSuper2xSaIFragShader_110 = {"\
VARYING vec2 texCoord[16];\n\
uniform sampler2DRect tex;\n\
\n\
const vec3 dt = vec3(65536.0, 256.0, 1.0);\n\
\n\
float GetResult(float v1, float v2, float v3, float v4)\n\
{\n\
return sign(abs(v1-v3)+abs(v1-v4))-sign(abs(v2-v3)+abs(v2-v4));\n\
}\n\
\n\
float reduce(vec3 color)\n\
{\n\
return dot(color, dt);\n\
}\n\
\n\
//---------------------------------------\n\
// Input Pixel Mapping: 06|07|08|09\n\
// 05|00|01|10\n\
// 04|03|02|11\n\
// 15|14|13|12\n\
//\n\
// Output Pixel Mapping: A|B\n\
// C|D\n\
\n\
//---------------------------------------\n\
// S2xSaI Pixel Mapping: I|E|F|J\n\
// G|A|B|K\n\
// H|C|D|L\n\
// M|N|O|P\n\
\n\
void main()\n\
{\n\
vec2 f = step(0.5, fract(texCoord[0]));\n\
\n\
float Iv = reduce( SAMPLE3_TEX_RECT(tex, texCoord[6]).rgb );\n\
float Ev = reduce( SAMPLE3_TEX_RECT(tex, texCoord[7]).rgb );\n\
float Fv = reduce( SAMPLE3_TEX_RECT(tex, texCoord[8]).rgb );\n\
float Jv = reduce( SAMPLE3_TEX_RECT(tex, texCoord[9]).rgb );\n\
\n\
float Gv = reduce( SAMPLE3_TEX_RECT(tex, texCoord[5]).rgb );\n\
vec3 Ac = SAMPLE3_TEX_RECT(tex, texCoord[0]).rgb; float Av = reduce(Ac);\n\
vec3 Bc = SAMPLE3_TEX_RECT(tex, texCoord[1]).rgb; float Bv = reduce(Bc);\n\
float Kv = reduce( SAMPLE3_TEX_RECT(tex, texCoord[10]).rgb );\n\
\n\
float Hv = reduce( SAMPLE3_TEX_RECT(tex, texCoord[4]).rgb );\n\
vec3 Cc = SAMPLE3_TEX_RECT(tex, texCoord[3]).rgb; float Cv = reduce(Cc);\n\
vec3 Dc = SAMPLE3_TEX_RECT(tex, texCoord[2]).rgb; float Dv = reduce(Dc);\n\
float Lv = reduce( SAMPLE3_TEX_RECT(tex, texCoord[11]).rgb );\n\
\n\
float Mv = reduce( SAMPLE3_TEX_RECT(tex, texCoord[15]).rgb );\n\
float Nv = reduce( SAMPLE3_TEX_RECT(tex, texCoord[14]).rgb );\n\
float Ov = reduce( SAMPLE3_TEX_RECT(tex, texCoord[13]).rgb );\n\
float Pv = reduce( SAMPLE3_TEX_RECT(tex, texCoord[12]).rgb );\n\
\n\
bool compAD = (Av == Dv);\n\
bool compBC = (Bv == Cv);\n\
\n\
vec3 outA = ( (compBC && !compAD && (Hv == Cv) && (Cv != Fv)) || ((Gv == Cv) && (Dv == Cv) && (Hv != Av) && (Cv != Iv)) ) ? mix(Ac, Cc, 0.5) : Ac;\n\
vec3 outB = Bc;\n\
vec3 outC = ( (compAD && !compBC && (Gv == Av) && (Av != Ov)) || ((Av == Hv) && (Av == Bv) && (Gv != Cv) && (Av != Mv)) ) ? mix(Ac, Cc, 0.5) : Cc;\n\
vec3 outD = Dc;\n\
\n\
if (compBC && !compAD)\n\
{\n\
outB = outD = Cc;\n\
}\n\
else if (!compBC && compAD)\n\
{\n\
outB = outD = Ac;\n\
}\n\
else if (compBC && compAD)\n\
{\n\
float r = GetResult(Bv, Av, Hv, Nv) + GetResult(Bv, Av, Gv, Ev) + GetResult(Bv, Av, Ov, Lv) + GetResult(Bv, Av, Fv, Kv);\n\
outB = outD = (r > 0.0) ? Bc : ( (r < 0.0) ? Ac : mix(Ac, Bc, 0.5) );\n\
}\n\
else\n\
{\n\
outB = ( (Bv == Dv) && (Bv == Ev) && (Av != Fv) && (Bv != Iv) ) ? mix(Ac, Bc, 0.75) : ( ( (Av == Cv) && (Av == Fv) && (Ev != Bv) && (Av != Jv) ) ? mix(Ac, Bc, 0.25) : mix(Ac, Bc, 0.5) );\n\
outD = ( (Bv == Dv) && (Dv == Nv) && (Cv != Ov) && (Dv != Mv) ) ? mix(Cc, Dc, 0.75) : ( ( (Av == Cv) && (Cv == Ov) && (Nv != Dv) && (Cv != Pv) ) ? mix(Cc, Dc, 0.25) : mix(Cc, Dc, 0.5) );\n\
}\n\
\n\
OUT_FRAG_COLOR.rgb = mix( mix(outA, outB, f.x), mix(outC, outD, f.x), f.y );\n\
OUT_FRAG_COLOR.a = 1.0;\n\
}\n\
"};
static const char *ScalarSuperEagle2xFragShader_110 = {"\
VARYING vec2 texCoord[16];\n\
uniform sampler2DRect tex;\n\
\n\
const vec3 dt = vec3(65536.0, 256.0, 1.0);\n\
\n\
float GetResult(float v1, float v2, float v3, float v4)\n\
{\n\
return sign(abs(v1-v3)+abs(v1-v4))-sign(abs(v2-v3)+abs(v2-v4));\n\
}\n\
\n\
float reduce(vec3 color)\n\
{\n\
return dot(color, dt);\n\
}\n\
\n\
//---------------------------------------\n\
// Input Pixel Mapping: --|07|08|--\n\
// 05|00|01|10\n\
// 04|03|02|11\n\
// --|14|13|--\n\
//\n\
// Output Pixel Mapping: A|B\n\
// C|D\n\
\n\
//---------------------------------------\n\
// SEagle Pixel Mapping: -|E|F|-\n\
// G|A|B|K\n\
// H|C|D|L\n\
// -|N|O|-\n\
\n\
void main()\n\
{\n\
vec2 f = step(0.5, fract(texCoord[0]));\n\
\n\
float Ev = reduce( SAMPLE3_TEX_RECT(tex, texCoord[7]).rgb );\n\
float Fv = reduce( SAMPLE3_TEX_RECT(tex, texCoord[8]).rgb );\n\
\n\
float Gv = reduce( SAMPLE3_TEX_RECT(tex, texCoord[5]).rgb );\n\
vec3 Ac = SAMPLE3_TEX_RECT(tex, texCoord[0]).rgb; float Av = reduce(Ac);\n\
vec3 Bc = SAMPLE3_TEX_RECT(tex, texCoord[1]).rgb; float Bv = reduce(Bc);\n\
float Kv = reduce( SAMPLE3_TEX_RECT(tex, texCoord[10]).rgb );\n\
\n\
float Hv = reduce( SAMPLE3_TEX_RECT(tex, texCoord[4]).rgb );\n\
vec3 Cc = SAMPLE3_TEX_RECT(tex, texCoord[3]).rgb; float Cv = reduce(Cc);\n\
vec3 Dc = SAMPLE3_TEX_RECT(tex, texCoord[2]).rgb; float Dv = reduce(Dc);\n\
float Lv = reduce( SAMPLE3_TEX_RECT(tex, texCoord[11]).rgb );\n\
\n\
float Nv = reduce( SAMPLE3_TEX_RECT(tex, texCoord[14]).rgb );\n\
float Ov = reduce( SAMPLE3_TEX_RECT(tex, texCoord[13]).rgb );\n\
\n\
vec3 outA = Ac;\n\
vec3 outB = Bc;\n\
vec3 outC = Cc;\n\
vec3 outD = Dc;\n\
bool compAD = (Av == Dv);\n\
bool compBC = (Bv == Cv);\n\
\n\
if (compBC && !compAD)\n\
{\n\
outA = (Cv == Hv || Bv == Fv) ? mix(Ac, Cc, 0.75) : mix(Ac, Bc, 0.5);\n\
//outA = mix( mix(Ac, Bc, 0.5), mix(Ac, Cc, 0.75), float(Cv == Hv || Bv == Fv) );\n\
outB = Cc;\n\
//outC = Cc;\n\
outD = mix( mix(Dc, Cc, 0.5), mix(Dc, Cc, 0.75), float(Bv == Kv || Cv == Nv) );\n\
}\n\
else if (!compBC && compAD)\n\
{\n\
//outA = Ac;\n\
outB = mix( mix(Ac, Bc, 0.5), mix(Ac, Bc, 0.25), float(Av == Ev || Dv == Lv) );\n\
outC = mix( mix(Cc, Dc, 0.5), mix(Ac, Cc, 0.25), float(Dv == Ov || Av == Gv) );\n\
outD = Ac;\n\
}\n\
else if (compBC && compAD)\n\
{\n\
float r = GetResult(Bv, Av, Hv, Nv) + GetResult(Bv, Av, Gv, Ev) + GetResult(Bv, Av, Ov, Lv) + GetResult(Bv, Av, Fv, Kv);\n\
if (r > 0.0)\n\
{\n\
outA = mix(Ac, Bc, 0.5);\n\
outB = Cc;\n\
//outC = Cc;\n\
outD = outA;\n\
}\n\
else if (r < 0.0)\n\
{\n\
//outA = Ac;\n\
outB = mix(Ac, Bc, 0.5);\n\
outC = outB;\n\
outD = Ac;\n\
}\n\
else\n\
{\n\
//outA = Ac;\n\
outB = Cc;\n\
//outC = Cc;\n\
outD = Ac;\n\
}\n\
}\n\
else\n\
{\n\
outA = mix(mix(Bc, Cc, 0.5), Ac, 0.75);\n\
outB = mix(mix(Ac, Dc, 0.5), Bc, 0.75);\n\
outC = mix(mix(Ac, Dc, 0.5), Cc, 0.75);\n\
outD = mix(mix(Bc, Cc, 0.5), Dc, 0.75);\n\
}\n\
\n\
OUT_FRAG_COLOR.rgb = mix( mix(outA, outB, f.x), mix(outC, outD, f.x), f.y );\n\
OUT_FRAG_COLOR.a = 1.0;\n\
}\n\
"};
static const char *ScalerLQ2xFragShader_110 = {"\
VARYING vec2 texCoord[9];\n\
uniform sampler2DRect tex;\n\
uniform sampler3D lut;\n\
\n\
float reduce(vec3 color)\n\
{\n\
return dot(color, vec3(65536.0, 256.0, 1.0));\n\
}\n\
\n\
vec3 Lerp(vec3 weight, vec3 p1, vec3 p2, vec3 p3)\n\
{\n\
return p1*weight.r + p2*weight.g + p3*weight.b;\n\
}\n\
\n\
//---------------------------------------\n\
// Input Pixel Mapping: 06|07|08\n\
// 05|00|01\n\
// 04|03|02\n\
//\n\
// Output Pixel Mapping: 00|01\n\
// 02|03\n\
\n\
//---------------------------------------\n\
// LQ2x Pixel Mapping: 0|1|2\n\
// 3|4|5\n\
// 6|7|8\n\
\n\
void main()\n\
{\n\
vec3 src[9];\n\
src[0] = SAMPLE3_TEX_RECT(tex, texCoord[6]).rgb;\n\
src[1] = SAMPLE3_TEX_RECT(tex, texCoord[7]).rgb;\n\
src[2] = SAMPLE3_TEX_RECT(tex, texCoord[8]).rgb;\n\
src[3] = SAMPLE3_TEX_RECT(tex, texCoord[5]).rgb;\n\
src[4] = SAMPLE3_TEX_RECT(tex, texCoord[0]).rgb;\n\
src[5] = SAMPLE3_TEX_RECT(tex, texCoord[1]).rgb;\n\
src[6] = SAMPLE3_TEX_RECT(tex, texCoord[4]).rgb;\n\
src[7] = SAMPLE3_TEX_RECT(tex, texCoord[3]).rgb;\n\
src[8] = SAMPLE3_TEX_RECT(tex, texCoord[2]).rgb;\n\
\n\
float v[9];\n\
v[0] = reduce(src[0]);\n\
v[1] = reduce(src[1]);\n\
v[2] = reduce(src[2]);\n\
v[3] = reduce(src[3]);\n\
v[4] = reduce(src[4]);\n\
v[5] = reduce(src[5]);\n\
v[6] = reduce(src[6]);\n\
v[7] = reduce(src[7]);\n\
v[8] = reduce(src[8]);\n\
\n\
float pattern = (float(v[0] != v[4]) * 1.0) +\n\
(float(v[1] != v[4]) * 2.0) +\n\
(float(v[2] != v[4]) * 4.0) +\n\
(float(v[3] != v[4]) * 8.0) +\n\
(float(v[5] != v[4]) * 16.0) +\n\
(float(v[6] != v[4]) * 32.0) +\n\
(float(v[7] != v[4]) * 64.0) +\n\
(float(v[8] != v[4]) * 128.0);\n\
\n\
float compare = (float(v[1] != v[5]) * 1.0) +\n\
(float(v[5] != v[7]) * 2.0) +\n\
(float(v[7] != v[3]) * 4.0) +\n\
(float(v[3] != v[1]) * 8.0);\n\
\n\
vec2 f = step(0.5, fract(texCoord[0]));\n\
float k = (f.y*2.0) + f.x;\n\
vec3 p = SAMPLE3_TEX_3D(lut, vec3(((pattern*2.0+0.0)+0.5)/512.0, (k+0.5)/4.0, (compare+0.5)/16.0));\n\
vec3 w = SAMPLE3_TEX_3D(lut, vec3(((pattern*2.0+1.0)+0.5)/512.0, (k+0.5)/4.0, (compare+0.5)/16.0));\n\
\n\
vec3 dst[3];\n\
dst[0] = mix(src[0], mix(src[1], mix(src[2], mix(src[3], mix(src[4], mix(src[5], mix(src[6], mix(src[7], src[8], step(8.0*30.95/255.0, p.r)), step(7.0*30.95/255.0, p.r)), step(6.0*30.95/255.0, p.r)), step(5.0*30.95/255.0, p.r)), step(4.0*30.95/255.0, p.r)), step(3.0*30.95/255.0, p.r)), step(2.0*30.95/255.0, p.r)), step(1.0*30.95/255.0, p.r));\n\
dst[1] = mix(src[0], mix(src[1], mix(src[2], mix(src[3], mix(src[4], mix(src[5], mix(src[6], mix(src[7], src[8], step(8.0*30.95/255.0, p.g)), step(7.0*30.95/255.0, p.g)), step(6.0*30.95/255.0, p.g)), step(5.0*30.95/255.0, p.g)), step(4.0*30.95/255.0, p.g)), step(3.0*30.95/255.0, p.g)), step(2.0*30.95/255.0, p.g)), step(1.0*30.95/255.0, p.g));\n\
dst[2] = mix(src[0], mix(src[1], mix(src[2], mix(src[3], mix(src[4], mix(src[5], mix(src[6], mix(src[7], src[8], step(8.0*30.95/255.0, p.b)), step(7.0*30.95/255.0, p.b)), step(6.0*30.95/255.0, p.b)), step(5.0*30.95/255.0, p.b)), step(4.0*30.95/255.0, p.b)), step(3.0*30.95/255.0, p.b)), step(2.0*30.95/255.0, p.b)), step(1.0*30.95/255.0, p.b));\n\
\n\
OUT_FRAG_COLOR.rgb = Lerp(w, dst[0], dst[1], dst[2]);\n\
OUT_FRAG_COLOR.a = 1.0;\n\
}\n\
"};
static const char *ScalerLQ2xSFragShader_110 = {"\
VARYING vec2 texCoord[9];\n\
uniform sampler2DRect tex;\n\
uniform sampler3D lut;\n\
\n\
vec3 Lerp(vec3 weight, vec3 p1, vec3 p2, vec3 p3)\n\
{\n\
return p1*weight.r + p2*weight.g + p3*weight.b;\n\
}\n\
\n\
//---------------------------------------\n\
// Input Pixel Mapping: 06|07|08\n\
// 05|00|01\n\
// 04|03|02\n\
//\n\
// Output Pixel Mapping: 00|01\n\
// 02|03\n\
\n\
//---------------------------------------\n\
// LQ2xS Pixel Mapping: 0|1|2\n\
// 3|4|5\n\
// 6|7|8\n\
\n\
void main()\n\
{\n\
vec3 src[9];\n\
src[0] = SAMPLE3_TEX_RECT(tex, texCoord[6]).rgb;\n\
src[1] = SAMPLE3_TEX_RECT(tex, texCoord[7]).rgb;\n\
src[2] = SAMPLE3_TEX_RECT(tex, texCoord[8]).rgb;\n\
src[3] = SAMPLE3_TEX_RECT(tex, texCoord[5]).rgb;\n\
src[4] = SAMPLE3_TEX_RECT(tex, texCoord[0]).rgb;\n\
src[5] = SAMPLE3_TEX_RECT(tex, texCoord[1]).rgb;\n\
src[6] = SAMPLE3_TEX_RECT(tex, texCoord[4]).rgb;\n\
src[7] = SAMPLE3_TEX_RECT(tex, texCoord[3]).rgb;\n\
src[8] = SAMPLE3_TEX_RECT(tex, texCoord[2]).rgb;\n\
\n\
float b[9];\n\
float minBright = 10.0;\n\
float maxBright = 0.0;\n\
\n\
for (int i = 0; i < 9; i++)\n\
{\n\
b[i] = (src[i].r + src[i].r + src[i].r) + (src[i].g + src[i].g + src[i].g) + (src[i].b + src[i].b);\n\
minBright = min(minBright, b[i]);\n\
maxBright = max(maxBright, b[i]);\n\
}\n\
\n\
float diffBright = (maxBright - minBright) / 16.0;\n\
float pattern = step((0.5*1.0/127.5), diffBright) * ((float(abs(b[0] - b[4]) > diffBright) * 1.0) +\n\
(float(abs(b[1] - b[4]) > diffBright) * 2.0) +\n\
(float(abs(b[2] - b[4]) > diffBright) * 4.0) +\n\
(float(abs(b[3] - b[4]) > diffBright) * 8.0) +\n\
(float(abs(b[5] - b[4]) > diffBright) * 16.0) +\n\
(float(abs(b[6] - b[4]) > diffBright) * 32.0) +\n\
(float(abs(b[7] - b[4]) > diffBright) * 64.0) +\n\
(float(abs(b[8] - b[4]) > diffBright) * 128.0));\n\
\n\
vec2 f = step(0.5, fract(texCoord[0]));\n\
float k = (f.y*2.0) + f.x;\n\
vec3 p = SAMPLE3_TEX_3D(lut, vec3(((pattern*2.0+0.0)+0.5)/512.0, (k+0.5)/4.0, 0.5/16.0));\n\
vec3 w = SAMPLE3_TEX_3D(lut, vec3(((pattern*2.0+1.0)+0.5)/512.0, (k+0.5)/4.0, 0.5/16.0));\n\
\n\
vec3 dst[3];\n\
dst[0] = mix(src[0], mix(src[1], mix(src[2], mix(src[3], mix(src[4], mix(src[5], mix(src[6], mix(src[7], src[8], step(8.0*30.95/255.0, p.r)), step(7.0*30.95/255.0, p.r)), step(6.0*30.95/255.0, p.r)), step(5.0*30.95/255.0, p.r)), step(4.0*30.95/255.0, p.r)), step(3.0*30.95/255.0, p.r)), step(2.0*30.95/255.0, p.r)), step(1.0*30.95/255.0, p.r));\n\
dst[1] = mix(src[0], mix(src[1], mix(src[2], mix(src[3], mix(src[4], mix(src[5], mix(src[6], mix(src[7], src[8], step(8.0*30.95/255.0, p.g)), step(7.0*30.95/255.0, p.g)), step(6.0*30.95/255.0, p.g)), step(5.0*30.95/255.0, p.g)), step(4.0*30.95/255.0, p.g)), step(3.0*30.95/255.0, p.g)), step(2.0*30.95/255.0, p.g)), step(1.0*30.95/255.0, p.g));\n\
dst[2] = mix(src[0], mix(src[1], mix(src[2], mix(src[3], mix(src[4], mix(src[5], mix(src[6], mix(src[7], src[8], step(8.0*30.95/255.0, p.b)), step(7.0*30.95/255.0, p.b)), step(6.0*30.95/255.0, p.b)), step(5.0*30.95/255.0, p.b)), step(4.0*30.95/255.0, p.b)), step(3.0*30.95/255.0, p.b)), step(2.0*30.95/255.0, p.b)), step(1.0*30.95/255.0, p.b));\n\
\n\
OUT_FRAG_COLOR.rgb = Lerp(w, dst[0], dst[1], dst[2]);\n\
OUT_FRAG_COLOR.a = 1.0;\n\
}\n\
"};
static const char *ScalerHQ2xFragShader_110 = {"\
VARYING vec2 texCoord[9];\n\
uniform sampler2DRect tex;\n\
uniform sampler3D lut;\n\
\n\
bool InterpDiff(vec3 p1, vec3 p2)\n\
{\n\
vec3 diff = p1 - p2;\n\
vec3 yuv = vec3( diff.r + diff.g + diff.b,\n\
diff.r - diff.b,\n\
-diff.r + (2.0*diff.g) - diff.b );\n\
yuv = abs(yuv);\n\
\n\
return any( greaterThan(yuv, vec3(192.0/255.0, 28.0/255.0, 48.0/255.0)) );\n\
}\n\
\n\
vec3 Lerp(vec3 weight, vec3 p1, vec3 p2, vec3 p3)\n\
{\n\
return p1*weight.r + p2*weight.g + p3*weight.b;\n\
}\n\
\n\
//---------------------------------------\n\
// Input Pixel Mapping: 06|07|08\n\
// 05|00|01\n\
// 04|03|02\n\
//\n\
// Output Pixel Mapping: 00|01\n\
// 02|03\n\
\n\
//---------------------------------------\n\
// HQ2x Pixel Mapping: 0|1|2\n\
// 3|4|5\n\
// 6|7|8\n\
\n\
void main()\n\
{\n\
vec3 src[9];\n\
src[0] = SAMPLE3_TEX_RECT(tex, texCoord[6]).rgb;\n\
src[1] = SAMPLE3_TEX_RECT(tex, texCoord[7]).rgb;\n\
src[2] = SAMPLE3_TEX_RECT(tex, texCoord[8]).rgb;\n\
src[3] = SAMPLE3_TEX_RECT(tex, texCoord[5]).rgb;\n\
src[4] = SAMPLE3_TEX_RECT(tex, texCoord[0]).rgb;\n\
src[5] = SAMPLE3_TEX_RECT(tex, texCoord[1]).rgb;\n\
src[6] = SAMPLE3_TEX_RECT(tex, texCoord[4]).rgb;\n\
src[7] = SAMPLE3_TEX_RECT(tex, texCoord[3]).rgb;\n\
src[8] = SAMPLE3_TEX_RECT(tex, texCoord[2]).rgb;\n\
\n\
float pattern = (float(InterpDiff(src[0], src[4])) * 1.0) +\n\
(float(InterpDiff(src[1], src[4])) * 2.0) +\n\
(float(InterpDiff(src[2], src[4])) * 4.0) +\n\
(float(InterpDiff(src[3], src[4])) * 8.0) +\n\
(float(InterpDiff(src[5], src[4])) * 16.0) +\n\
(float(InterpDiff(src[6], src[4])) * 32.0) +\n\
(float(InterpDiff(src[7], src[4])) * 64.0) +\n\
(float(InterpDiff(src[8], src[4])) * 128.0);\n\
\n\
float compare = (float(InterpDiff(src[1], src[5])) * 1.0) +\n\
(float(InterpDiff(src[5], src[7])) * 2.0) +\n\
(float(InterpDiff(src[7], src[3])) * 4.0) +\n\
(float(InterpDiff(src[3], src[1])) * 8.0);\n\
\n\
vec2 f = step(0.5, fract(texCoord[0]));\n\
float k = (f.y*2.0) + f.x;\n\
vec3 p = SAMPLE3_TEX_3D(lut, vec3(((pattern*2.0+0.0)+0.5)/512.0, (k+0.5)/4.0, (compare+0.5)/16.0));\n\
vec3 w = SAMPLE3_TEX_3D(lut, vec3(((pattern*2.0+1.0)+0.5)/512.0, (k+0.5)/4.0, (compare+0.5)/16.0));\n\
\n\
vec3 dst[3];\n\
dst[0] = mix(src[0], mix(src[1], mix(src[2], mix(src[3], mix(src[4], mix(src[5], mix(src[6], mix(src[7], src[8], step(8.0*30.95/255.0, p.r)), step(7.0*30.95/255.0, p.r)), step(6.0*30.95/255.0, p.r)), step(5.0*30.95/255.0, p.r)), step(4.0*30.95/255.0, p.r)), step(3.0*30.95/255.0, p.r)), step(2.0*30.95/255.0, p.r)), step(1.0*30.95/255.0, p.r));\n\
dst[1] = mix(src[0], mix(src[1], mix(src[2], mix(src[3], mix(src[4], mix(src[5], mix(src[6], mix(src[7], src[8], step(8.0*30.95/255.0, p.g)), step(7.0*30.95/255.0, p.g)), step(6.0*30.95/255.0, p.g)), step(5.0*30.95/255.0, p.g)), step(4.0*30.95/255.0, p.g)), step(3.0*30.95/255.0, p.g)), step(2.0*30.95/255.0, p.g)), step(1.0*30.95/255.0, p.g));\n\
dst[2] = mix(src[0], mix(src[1], mix(src[2], mix(src[3], mix(src[4], mix(src[5], mix(src[6], mix(src[7], src[8], step(8.0*30.95/255.0, p.b)), step(7.0*30.95/255.0, p.b)), step(6.0*30.95/255.0, p.b)), step(5.0*30.95/255.0, p.b)), step(4.0*30.95/255.0, p.b)), step(3.0*30.95/255.0, p.b)), step(2.0*30.95/255.0, p.b)), step(1.0*30.95/255.0, p.b));\n\
\n\
OUT_FRAG_COLOR.rgb = Lerp(w, dst[0], dst[1], dst[2]);\n\
OUT_FRAG_COLOR.a = 1.0;\n\
}\n\
"};
static const char *ScalerHQ2xSFragShader_110 = {"\
VARYING vec2 texCoord[9];\n\
uniform sampler2DRect tex;\n\
uniform sampler3D lut;\n\
\n\
vec3 Lerp(vec3 weight, vec3 p1, vec3 p2, vec3 p3)\n\
{\n\
return p1*weight.r + p2*weight.g + p3*weight.b;\n\
}\n\
\n\
//---------------------------------------\n\
// Input Pixel Mapping: 06|07|08\n\
// 05|00|01\n\
// 04|03|02\n\
//\n\
// Output Pixel Mapping: 00|01\n\
// 02|03\n\
\n\
//---------------------------------------\n\
// HQ2xS Pixel Mapping: 0|1|2\n\
// 3|4|5\n\
// 6|7|8\n\
\n\
void main()\n\
{\n\
vec3 src[9];\n\
src[0] = SAMPLE3_TEX_RECT(tex, texCoord[6]).rgb;\n\
src[1] = SAMPLE3_TEX_RECT(tex, texCoord[7]).rgb;\n\
src[2] = SAMPLE3_TEX_RECT(tex, texCoord[8]).rgb;\n\
src[3] = SAMPLE3_TEX_RECT(tex, texCoord[5]).rgb;\n\
src[4] = SAMPLE3_TEX_RECT(tex, texCoord[0]).rgb;\n\
src[5] = SAMPLE3_TEX_RECT(tex, texCoord[1]).rgb;\n\
src[6] = SAMPLE3_TEX_RECT(tex, texCoord[4]).rgb;\n\
src[7] = SAMPLE3_TEX_RECT(tex, texCoord[3]).rgb;\n\
src[8] = SAMPLE3_TEX_RECT(tex, texCoord[2]).rgb;\n\
\n\
float b[9];\n\
float minBright = 10.0;\n\
float maxBright = 0.0;\n\
\n\
for (int i = 0; i < 9; i++)\n\
{\n\
b[i] = (src[i].r + src[i].r + src[i].r) + (src[i].g + src[i].g + src[i].g) + (src[i].b + src[i].b);\n\
minBright = min(minBright, b[i]);\n\
maxBright = max(maxBright, b[i]);\n\
}\n\
\n\
float diffBright = (maxBright - minBright) * (7.0/16.0);\n\
float pattern = step((3.5*7.0/892.5), diffBright) * ((float(abs(b[0] - b[4]) > diffBright) * 1.0) +\n\
(float(abs(b[1] - b[4]) > diffBright) * 2.0) +\n\
(float(abs(b[2] - b[4]) > diffBright) * 4.0) +\n\
(float(abs(b[3] - b[4]) > diffBright) * 8.0) +\n\
(float(abs(b[5] - b[4]) > diffBright) * 16.0) +\n\
(float(abs(b[6] - b[4]) > diffBright) * 32.0) +\n\
(float(abs(b[7] - b[4]) > diffBright) * 64.0) +\n\
(float(abs(b[8] - b[4]) > diffBright) * 128.0));\n\
\n\
vec2 f = step(0.5, fract(texCoord[0]));\n\
float k = (f.y*2.0) + f.x;\n\
vec3 p = SAMPLE3_TEX_3D(lut, vec3(((pattern*2.0+0.0)+0.5)/512.0, (k+0.5)/4.0, 0.5/16.0));\n\
vec3 w = SAMPLE3_TEX_3D(lut, vec3(((pattern*2.0+1.0)+0.5)/512.0, (k+0.5)/4.0, 0.5/16.0));\n\
\n\
vec3 dst[3];\n\
dst[0] = mix(src[0], mix(src[1], mix(src[2], mix(src[3], mix(src[4], mix(src[5], mix(src[6], mix(src[7], src[8], step(8.0*30.95/255.0, p.r)), step(7.0*30.95/255.0, p.r)), step(6.0*30.95/255.0, p.r)), step(5.0*30.95/255.0, p.r)), step(4.0*30.95/255.0, p.r)), step(3.0*30.95/255.0, p.r)), step(2.0*30.95/255.0, p.r)), step(1.0*30.95/255.0, p.r));\n\
dst[1] = mix(src[0], mix(src[1], mix(src[2], mix(src[3], mix(src[4], mix(src[5], mix(src[6], mix(src[7], src[8], step(8.0*30.95/255.0, p.g)), step(7.0*30.95/255.0, p.g)), step(6.0*30.95/255.0, p.g)), step(5.0*30.95/255.0, p.g)), step(4.0*30.95/255.0, p.g)), step(3.0*30.95/255.0, p.g)), step(2.0*30.95/255.0, p.g)), step(1.0*30.95/255.0, p.g));\n\
dst[2] = mix(src[0], mix(src[1], mix(src[2], mix(src[3], mix(src[4], mix(src[5], mix(src[6], mix(src[7], src[8], step(8.0*30.95/255.0, p.b)), step(7.0*30.95/255.0, p.b)), step(6.0*30.95/255.0, p.b)), step(5.0*30.95/255.0, p.b)), step(4.0*30.95/255.0, p.b)), step(3.0*30.95/255.0, p.b)), step(2.0*30.95/255.0, p.b)), step(1.0*30.95/255.0, p.b));\n\
\n\
OUT_FRAG_COLOR.rgb = Lerp(w, dst[0], dst[1], dst[2]);\n\
OUT_FRAG_COLOR.a = 1.0;\n\
}\n\
"};
static const char *ScalerHQ4xFragShader_110 = {"\
VARYING vec2 texCoord[9];\n\
uniform sampler2DRect tex;\n\
uniform sampler3D lut;\n\
\n\
bool InterpDiff(vec3 p1, vec3 p2)\n\
{\n\
vec3 diff = p1 - p2;\n\
vec3 yuv = vec3( diff.r + diff.g + diff.b,\n\
diff.r - diff.b,\n\
-diff.r + (2.0*diff.g) - diff.b );\n\
yuv = abs(yuv);\n\
\n\
return any( greaterThan(yuv, vec3(192.0/255.0, 28.0/255.0, 48.0/255.0)) );\n\
}\n\
\n\
vec3 Lerp(vec3 weight, vec3 p1, vec3 p2, vec3 p3)\n\
{\n\
return p1*weight.r + p2*weight.g + p3*weight.b;\n\
}\n\
\n\
//---------------------------------------\n\
// Input Pixel Mapping: 06|07|08\n\
// 05|00|01\n\
// 04|03|02\n\
//\n\
// Output Pixel Mapping: 00|01|02|03\n\
// 04|05|06|07\n\
// 08|09|10|11\n\
// 12|13|14|15\n\
\n\
//---------------------------------------\n\
// HQ4x Pixel Mapping: 0|1|2\n\
// 3|4|5\n\
// 6|7|8\n\
\n\
void main()\n\
{\n\
vec3 src[9];\n\
src[0] = SAMPLE3_TEX_RECT(tex, texCoord[6]).rgb;\n\
src[1] = SAMPLE3_TEX_RECT(tex, texCoord[7]).rgb;\n\
src[2] = SAMPLE3_TEX_RECT(tex, texCoord[8]).rgb;\n\
src[3] = SAMPLE3_TEX_RECT(tex, texCoord[5]).rgb;\n\
src[4] = SAMPLE3_TEX_RECT(tex, texCoord[0]).rgb;\n\
src[5] = SAMPLE3_TEX_RECT(tex, texCoord[1]).rgb;\n\
src[6] = SAMPLE3_TEX_RECT(tex, texCoord[4]).rgb;\n\
src[7] = SAMPLE3_TEX_RECT(tex, texCoord[3]).rgb;\n\
src[8] = SAMPLE3_TEX_RECT(tex, texCoord[2]).rgb;\n\
\n\
float pattern = (float(InterpDiff(src[0], src[4])) * 1.0) +\n\
(float(InterpDiff(src[1], src[4])) * 2.0) +\n\
(float(InterpDiff(src[2], src[4])) * 4.0) +\n\
(float(InterpDiff(src[3], src[4])) * 8.0) +\n\
(float(InterpDiff(src[5], src[4])) * 16.0) +\n\
(float(InterpDiff(src[6], src[4])) * 32.0) +\n\
(float(InterpDiff(src[7], src[4])) * 64.0) +\n\
(float(InterpDiff(src[8], src[4])) * 128.0);\n\
\n\
float compare = (float(InterpDiff(src[1], src[5])) * 1.0) +\n\
(float(InterpDiff(src[5], src[7])) * 2.0) +\n\
(float(InterpDiff(src[7], src[3])) * 4.0) +\n\
(float(InterpDiff(src[3], src[1])) * 8.0);\n\
\n\
vec2 f = mix( mix(vec2(0.0,0.0), vec2(1.0,1.0), step(0.25, fract(texCoord[0]))), mix(vec2(2.0,2.0), vec2(3.0,3.0), step(0.75, fract(texCoord[0]))), step(0.5, fract(texCoord[0])) );\n\
float k = (f.y*4.0) + f.x;\n\
vec3 p = SAMPLE3_TEX_3D(lut, vec3(((pattern*2.0+0.0)+0.5)/512.0, (k+0.5)/16.0, (compare+0.5)/16.0));\n\
vec3 w = SAMPLE3_TEX_3D(lut, vec3(((pattern*2.0+1.0)+0.5)/512.0, (k+0.5)/16.0, (compare+0.5)/16.0));\n\
\n\
vec3 dst[3];\n\
dst[0] = mix(src[0], mix(src[1], mix(src[2], mix(src[3], mix(src[4], mix(src[5], mix(src[6], mix(src[7], src[8], step(8.0*30.95/255.0, p.r)), step(7.0*30.95/255.0, p.r)), step(6.0*30.95/255.0, p.r)), step(5.0*30.95/255.0, p.r)), step(4.0*30.95/255.0, p.r)), step(3.0*30.95/255.0, p.r)), step(2.0*30.95/255.0, p.r)), step(1.0*30.95/255.0, p.r));\n\
dst[1] = mix(src[0], mix(src[1], mix(src[2], mix(src[3], mix(src[4], mix(src[5], mix(src[6], mix(src[7], src[8], step(8.0*30.95/255.0, p.g)), step(7.0*30.95/255.0, p.g)), step(6.0*30.95/255.0, p.g)), step(5.0*30.95/255.0, p.g)), step(4.0*30.95/255.0, p.g)), step(3.0*30.95/255.0, p.g)), step(2.0*30.95/255.0, p.g)), step(1.0*30.95/255.0, p.g));\n\
dst[2] = mix(src[0], mix(src[1], mix(src[2], mix(src[3], mix(src[4], mix(src[5], mix(src[6], mix(src[7], src[8], step(8.0*30.95/255.0, p.b)), step(7.0*30.95/255.0, p.b)), step(6.0*30.95/255.0, p.b)), step(5.0*30.95/255.0, p.b)), step(4.0*30.95/255.0, p.b)), step(3.0*30.95/255.0, p.b)), step(2.0*30.95/255.0, p.b)), step(1.0*30.95/255.0, p.b));\n\
\n\
OUT_FRAG_COLOR.rgb = Lerp(w, dst[0], dst[1], dst[2]);\n\
OUT_FRAG_COLOR.a = 1.0;\n\
}\n\
"};
static const char *ScalerHQ4xSFragShader_110 = {"\
VARYING vec2 texCoord[9];\n\
uniform sampler2DRect tex;\n\
uniform sampler3D lut;\n\
\n\
vec3 Lerp(vec3 weight, vec3 p1, vec3 p2, vec3 p3)\n\
{\n\
return p1*weight.r + p2*weight.g + p3*weight.b;\n\
}\n\
\n\
//---------------------------------------\n\
// Input Pixel Mapping: 06|07|08\n\
// 05|00|01\n\
// 04|03|02\n\
//\n\
// Output Pixel Mapping: 00|01|02|03\n\
// 04|05|06|07\n\
// 08|09|10|11\n\
// 12|13|14|15\n\
\n\
//---------------------------------------\n\
// HQ4xS Pixel Mapping: 0|1|2\n\
// 3|4|5\n\
// 6|7|8\n\
\n\
void main()\n\
{\n\
vec3 src[9];\n\
src[0] = SAMPLE3_TEX_RECT(tex, texCoord[6]).rgb;\n\
src[1] = SAMPLE3_TEX_RECT(tex, texCoord[7]).rgb;\n\
src[2] = SAMPLE3_TEX_RECT(tex, texCoord[8]).rgb;\n\
src[3] = SAMPLE3_TEX_RECT(tex, texCoord[5]).rgb;\n\
src[4] = SAMPLE3_TEX_RECT(tex, texCoord[0]).rgb;\n\
src[5] = SAMPLE3_TEX_RECT(tex, texCoord[1]).rgb;\n\
src[6] = SAMPLE3_TEX_RECT(tex, texCoord[4]).rgb;\n\
src[7] = SAMPLE3_TEX_RECT(tex, texCoord[3]).rgb;\n\
src[8] = SAMPLE3_TEX_RECT(tex, texCoord[2]).rgb;\n\
\n\
float b[9];\n\
float minBright = 10.0;\n\
float maxBright = 0.0;\n\
\n\
for (int i = 0; i < 9; i++)\n\
{\n\
b[i] = (src[i].r + src[i].r + src[i].r) + (src[i].g + src[i].g + src[i].g) + (src[i].b + src[i].b);\n\
minBright = min(minBright, b[i]);\n\
maxBright = max(maxBright, b[i]);\n\
}\n\
\n\
float diffBright = (maxBright - minBright) * (7.0/16.0);\n\
float pattern = step((3.5*7.0/892.5), diffBright) * ((float(abs(b[0] - b[4]) > diffBright) * 1.0) +\n\
(float(abs(b[1] - b[4]) > diffBright) * 2.0) +\n\
(float(abs(b[2] - b[4]) > diffBright) * 4.0) +\n\
(float(abs(b[3] - b[4]) > diffBright) * 8.0) +\n\
(float(abs(b[5] - b[4]) > diffBright) * 16.0) +\n\
(float(abs(b[6] - b[4]) > diffBright) * 32.0) +\n\
(float(abs(b[7] - b[4]) > diffBright) * 64.0) +\n\
(float(abs(b[8] - b[4]) > diffBright) * 128.0));\n\
\n\
vec2 f = mix( mix(vec2(0.0,0.0), vec2(1.0,1.0), step(0.25, fract(texCoord[0]))), mix(vec2(2.0,2.0), vec2(3.0,3.0), step(0.75, fract(texCoord[0]))), step(0.5, fract(texCoord[0])) );\n\
float k = (f.y*4.0) + f.x;\n\
vec3 p = SAMPLE3_TEX_3D(lut, vec3(((pattern*2.0+0.0)+0.5)/512.0, (k+0.5)/16.0, 0.5/16.0));\n\
vec3 w = SAMPLE3_TEX_3D(lut, vec3(((pattern*2.0+1.0)+0.5)/512.0, (k+0.5)/16.0, 0.5/16.0));\n\
\n\
vec3 dst[3];\n\
dst[0] = mix(src[0], mix(src[1], mix(src[2], mix(src[3], mix(src[4], mix(src[5], mix(src[6], mix(src[7], src[8], step(8.0*30.95/255.0, p.r)), step(7.0*30.95/255.0, p.r)), step(6.0*30.95/255.0, p.r)), step(5.0*30.95/255.0, p.r)), step(4.0*30.95/255.0, p.r)), step(3.0*30.95/255.0, p.r)), step(2.0*30.95/255.0, p.r)), step(1.0*30.95/255.0, p.r));\n\
dst[1] = mix(src[0], mix(src[1], mix(src[2], mix(src[3], mix(src[4], mix(src[5], mix(src[6], mix(src[7], src[8], step(8.0*30.95/255.0, p.g)), step(7.0*30.95/255.0, p.g)), step(6.0*30.95/255.0, p.g)), step(5.0*30.95/255.0, p.g)), step(4.0*30.95/255.0, p.g)), step(3.0*30.95/255.0, p.g)), step(2.0*30.95/255.0, p.g)), step(1.0*30.95/255.0, p.g));\n\
dst[2] = mix(src[0], mix(src[1], mix(src[2], mix(src[3], mix(src[4], mix(src[5], mix(src[6], mix(src[7], src[8], step(8.0*30.95/255.0, p.b)), step(7.0*30.95/255.0, p.b)), step(6.0*30.95/255.0, p.b)), step(5.0*30.95/255.0, p.b)), step(4.0*30.95/255.0, p.b)), step(3.0*30.95/255.0, p.b)), step(2.0*30.95/255.0, p.b)), step(1.0*30.95/255.0, p.b));\n\
\n\
OUT_FRAG_COLOR.rgb = Lerp(w, dst[0], dst[1], dst[2]);\n\
OUT_FRAG_COLOR.a = 1.0;\n\
}\n\
"};
static const char *Scaler2xBRZFragShader_110 = {"\
#define BLEND_NONE 0\n\
#define BLEND_NORMAL 1\n\
#define BLEND_DOMINANT 2\n\
#define LUMINANCE_WEIGHT 1.0\n\
#define EQUAL_COLOR_TOLERANCE 30.0/255.0\n\
#define STEEP_DIRECTION_THRESHOLD 2.2\n\
#define DOMINANT_DIRECTION_THRESHOLD 3.6\n\
#define M_PI 3.1415926535897932384626433832795\n\
\n\
#if GPU_TIER >= SHADERSUPPORT_MID_TIER\n\
VARYING vec2 texCoord[25];\n\
#else\n\
VARYING vec2 texCoord[16];\n\
#endif\n\
uniform sampler2DRect tex;\n\
\n\
float reduce(const vec3 color)\n\
{\n\
return dot(color, vec3(65536.0, 256.0, 1.0));\n\
}\n\
\n\
float DistYCbCr(const vec3 pixA, const vec3 pixB)\n\
{\n\
const vec3 w = vec3(0.2627, 0.6780, 0.0593);\n\
const float scaleB = 0.5 / (1.0 - w.b);\n\
const float scaleR = 0.5 / (1.0 - w.r);\n\
vec3 diff = pixA - pixB;\n\
float Y = dot(diff, w);\n\
float Cb = scaleB * (diff.b - Y);\n\
float Cr = scaleR * (diff.r - Y);\n\
\n\
return sqrt( ((LUMINANCE_WEIGHT*Y) * (LUMINANCE_WEIGHT*Y)) + (Cb * Cb) + (Cr * Cr) );\n\
}\n\
\n\
bool IsPixEqual(const vec3 pixA, const vec3 pixB)\n\
{\n\
return (DistYCbCr(pixA, pixB) < EQUAL_COLOR_TOLERANCE);\n\
}\n\
\n\
bool IsBlendingNeeded(const ivec4 blend)\n\
{\n\
return any(notEqual(blend, ivec4(BLEND_NONE)));\n\
}\n\
\n\
#if GPU_TIER < SHADERSUPPORT_MID_TIER\n\
void ScalePixel(const ivec4 blend, const vec3 k[9], inout vec3 dst[4])\n\
{\n\
// This is the optimized version of xBRZ's blending logic. It's behavior\n\
// should be identical to the original blending logic below.\n\
float v0 = reduce(k[0]);\n\
float v4 = reduce(k[4]);\n\
float v5 = reduce(k[5]);\n\
float v7 = reduce(k[7]);\n\
float v8 = reduce(k[8]);\n\
\n\
float dist_01_04 = DistYCbCr(k[1], k[4]);\n\
float dist_03_08 = DistYCbCr(k[3], k[8]);\n\
bool haveShallowLine = (STEEP_DIRECTION_THRESHOLD * dist_01_04 <= dist_03_08) && (v0 != v4) && (v5 != v4);\n\
bool haveSteepLine = (STEEP_DIRECTION_THRESHOLD * dist_03_08 <= dist_01_04) && (v0 != v8) && (v7 != v8);\n\
bool needBlend = (blend[2] != BLEND_NONE);\n\
bool doLineBlend = ( blend[2] >= BLEND_DOMINANT ||\n\
!((blend[1] != BLEND_NONE && !IsPixEqual(k[0], k[4])) ||\n\
(blend[3] != BLEND_NONE && !IsPixEqual(k[0], k[8])) ||\n\
(IsPixEqual(k[4], k[3]) && IsPixEqual(k[3], k[2]) && IsPixEqual(k[2], k[1]) && IsPixEqual(k[1], k[8]) && !IsPixEqual(k[0], k[2])) ) );\n\
\n\
vec3 blendPix = ( DistYCbCr(k[0], k[1]) <= DistYCbCr(k[0], k[3]) ) ? k[1] : k[3];\n\
dst[1] = mix(dst[1], blendPix, (needBlend && doLineBlend && haveSteepLine) ? 0.25 : 0.00);\n\
dst[2] = mix(dst[2], blendPix, (needBlend) ? ((doLineBlend) ? ((haveShallowLine) ? ((haveSteepLine) ? 5.0/6.0 : 0.75) : ((haveSteepLine) ? 0.75 : 0.50)) : 1.0 - (M_PI/4.0)) : 0.00);\n\
dst[3] = mix(dst[3], blendPix, (needBlend && doLineBlend && haveShallowLine) ? 0.25 : 0.00);\n\
\n\
// Let's keep xBRZ's original blending logic around for reference.\n\
/*\n\
if (blend[2] == BLEND_NONE)\n\
{\n\
return;\n\
}\n\
\n\
vec3 blendPix = ( DistYCbCr(k[0], k[1]) <= DistYCbCr(k[0], k[3]) ) ? k[1] : k[3];\n\
\n\
if ( DoLineBlend(blend, k) )\n\
{\n\
float v0 = reduce(k[0]);\n\
float v4 = reduce(k[4]);\n\
float v5 = reduce(k[5]);\n\
float v7 = reduce(k[7]);\n\
float v8 = reduce(k[8]);\n\
\n\
float dist_01_04 = DistYCbCr(k[1], k[4]);\n\
float dist_03_08 = DistYCbCr(k[3], k[8]);\n\
bool haveShallowLine = (STEEP_DIRECTION_THRESHOLD * dist_01_04 <= dist_03_08) && (v0 != v4) && (v5 != v4);\n\
bool haveSteepLine = (STEEP_DIRECTION_THRESHOLD * dist_03_08 <= dist_01_04) && (v0 != v8) && (v7 != v8);\n\
\n\
if (haveShallowLine)\n\
{\n\
if (haveSteepLine)\n\
{\n\
// Blend line steep and shallow\n\
dst[3] = mix(dst[3], blendPix, 0.25);\n\
dst[1] = mix(dst[1], blendPix, 0.25);\n\
dst[2] = mix(dst[2], blendPix, 5.0/6.0);\n\
}\n\
else\n\
{\n\
// Blend line shallow\n\
dst[3] = mix(dst[3], blendPix, 0.25);\n\
dst[2] = mix(dst[2], blendPix, 0.75);\n\
}\n\
}\n\
else\n\
{\n\
if (haveSteepLine)\n\
{\n\
// Blend line steep\n\
dst[1] = mix(dst[1], blendPix, 0.25);\n\
dst[2] = mix(dst[2], blendPix, 0.75);\n\
}\n\
else\n\
{\n\
// Blend line diagonal\n\
dst[2] = mix(dst[2], blendPix, 0.50);\n\
}\n\
}\n\
}\n\
else\n\
{\n\
// Blend corner\n\
dst[2] = mix(dst[2], blendPix, 1.0 - (M_PI/4.0));\n\
}\n\
*/\n\
}\n\
#endif\n\
\n\
//---------------------------------------\n\
// Input Pixel Mapping: --|21|22|23|--\n\
// 19|06|07|08|09\n\
// 18|05|00|01|10\n\
// 17|04|03|02|11\n\
// --|15|14|13|--\n\
//\n\
// Output Pixel Mapping: 00|01\n\
// 03|02\n\
\n\
void main()\n\
{\n\
#if GPU_TIER >= SHADERSUPPORT_MID_TIER\n\
vec3 src[25];\n\
src[ 0] = SAMPLE3_TEX_RECT(tex, texCoord[ 0]).rgb;\n\
src[ 1] = SAMPLE3_TEX_RECT(tex, texCoord[ 1]).rgb;\n\
src[ 2] = SAMPLE3_TEX_RECT(tex, texCoord[ 2]).rgb;\n\
src[ 3] = SAMPLE3_TEX_RECT(tex, texCoord[ 3]).rgb;\n\
src[ 4] = SAMPLE3_TEX_RECT(tex, texCoord[ 4]).rgb;\n\
src[ 5] = SAMPLE3_TEX_RECT(tex, texCoord[ 5]).rgb;\n\
src[ 6] = SAMPLE3_TEX_RECT(tex, texCoord[ 6]).rgb;\n\
src[ 7] = SAMPLE3_TEX_RECT(tex, texCoord[ 7]).rgb;\n\
src[ 8] = SAMPLE3_TEX_RECT(tex, texCoord[ 8]).rgb;\n\
src[ 9] = SAMPLE3_TEX_RECT(tex, texCoord[ 9]).rgb;\n\
src[10] = SAMPLE3_TEX_RECT(tex, texCoord[10]).rgb;\n\
src[11] = SAMPLE3_TEX_RECT(tex, texCoord[11]).rgb;\n\
src[12] = SAMPLE3_TEX_RECT(tex, texCoord[12]).rgb;\n\
src[13] = SAMPLE3_TEX_RECT(tex, texCoord[13]).rgb;\n\
src[14] = SAMPLE3_TEX_RECT(tex, texCoord[14]).rgb;\n\
src[15] = SAMPLE3_TEX_RECT(tex, texCoord[15]).rgb;\n\
src[16] = SAMPLE3_TEX_RECT(tex, texCoord[16]).rgb;\n\
src[17] = SAMPLE3_TEX_RECT(tex, texCoord[17]).rgb;\n\
src[18] = SAMPLE3_TEX_RECT(tex, texCoord[18]).rgb;\n\
src[19] = SAMPLE3_TEX_RECT(tex, texCoord[19]).rgb;\n\
src[20] = SAMPLE3_TEX_RECT(tex, texCoord[20]).rgb;\n\
src[21] = SAMPLE3_TEX_RECT(tex, texCoord[21]).rgb;\n\
src[22] = SAMPLE3_TEX_RECT(tex, texCoord[22]).rgb;\n\
src[23] = SAMPLE3_TEX_RECT(tex, texCoord[23]).rgb;\n\
src[24] = SAMPLE3_TEX_RECT(tex, texCoord[24]).rgb;\n\
#else\n\
vec3 src[16];\n\
src[ 0] = SAMPLE3_TEX_RECT(tex, texCoord[ 0]).rgb;\n\
src[ 1] = SAMPLE3_TEX_RECT(tex, texCoord[ 1]).rgb;\n\
src[ 2] = SAMPLE3_TEX_RECT(tex, texCoord[ 2]).rgb;\n\
src[ 3] = SAMPLE3_TEX_RECT(tex, texCoord[ 3]).rgb;\n\
src[ 4] = SAMPLE3_TEX_RECT(tex, texCoord[ 4]).rgb;\n\
src[ 5] = SAMPLE3_TEX_RECT(tex, texCoord[ 5]).rgb;\n\
src[ 6] = SAMPLE3_TEX_RECT(tex, texCoord[ 6]).rgb;\n\
src[ 7] = SAMPLE3_TEX_RECT(tex, texCoord[ 7]).rgb;\n\
src[ 8] = SAMPLE3_TEX_RECT(tex, texCoord[ 8]).rgb;\n\
src[ 9] = SAMPLE3_TEX_RECT(tex, texCoord[ 9]).rgb;\n\
src[10] = SAMPLE3_TEX_RECT(tex, texCoord[10]).rgb;\n\
src[11] = SAMPLE3_TEX_RECT(tex, texCoord[11]).rgb;\n\
src[12] = SAMPLE3_TEX_RECT(tex, texCoord[12]).rgb;\n\
src[13] = SAMPLE3_TEX_RECT(tex, texCoord[13]).rgb;\n\
src[14] = SAMPLE3_TEX_RECT(tex, texCoord[14]).rgb;\n\
src[15] = SAMPLE3_TEX_RECT(tex, texCoord[15]).rgb;\n\
#endif\n\
\n\
float v[9];\n\
v[0] = reduce(src[0]);\n\
v[1] = reduce(src[1]);\n\
v[2] = reduce(src[2]);\n\
v[3] = reduce(src[3]);\n\
v[4] = reduce(src[4]);\n\
v[5] = reduce(src[5]);\n\
v[6] = reduce(src[6]);\n\
v[7] = reduce(src[7]);\n\
v[8] = reduce(src[8]);\n\
\n\
ivec4 blendResult = ivec4(BLEND_NONE);\n\
\n\
// Preprocess corners\n\
// Pixel Tap Mapping: --|--|--|--|--\n\
// --|--|07|08|--\n\
// --|05|00|01|10\n\
// --|04|03|02|11\n\
// --|--|14|13|--\n\
\n\
// Corner (1, 1)\n\
if ( !((v[0] == v[1] && v[3] == v[2]) || (v[0] == v[3] && v[1] == v[2])) )\n\
{\n\
float dist_03_01 = DistYCbCr(src[ 4], src[ 0]) + DistYCbCr(src[ 0], src[ 8]) + DistYCbCr(src[14], src[ 2]) + DistYCbCr(src[ 2], src[10]) + (4.0 * DistYCbCr(src[ 3], src[ 1]));\n\
float dist_00_02 = DistYCbCr(src[ 5], src[ 3]) + DistYCbCr(src[ 3], src[13]) + DistYCbCr(src[ 7], src[ 1]) + DistYCbCr(src[ 1], src[11]) + (4.0 * DistYCbCr(src[ 0], src[ 2]));\n\
bool dominantGradient = (DOMINANT_DIRECTION_THRESHOLD * dist_03_01) < dist_00_02;\n\
blendResult[2] = ((dist_03_01 < dist_00_02) && (v[0] != v[1]) && (v[0] != v[3])) ? ((dominantGradient) ? BLEND_DOMINANT : BLEND_NORMAL) : BLEND_NONE;\n\
}\n\
\n\
\n\
// Pixel Tap Mapping: --|--|--|--|--\n\
// --|06|07|--|--\n\
// 18|05|00|01|--\n\
// 17|04|03|02|--\n\
// --|15|14|--|--\n\
// Corner (0, 1)\n\
if ( !((v[5] == v[0] && v[4] == v[3]) || (v[5] == v[4] && v[0] == v[3])) )\n\
{\n\
#if GPU_TIER >= SHADERSUPPORT_MID_TIER\n\
float dist_04_00 = DistYCbCr(src[17], src[ 5]) + DistYCbCr(src[ 5], src[ 7]) + DistYCbCr(src[15], src[ 3]) + DistYCbCr(src[ 3], src[ 1]) + (4.0 * DistYCbCr(src[ 4], src[ 0]));\n\
float dist_05_03 = DistYCbCr(src[18], src[ 4]) + DistYCbCr(src[ 4], src[14]) + DistYCbCr(src[ 6], src[ 0]) + DistYCbCr(src[ 0], src[ 2]) + (4.0 * DistYCbCr(src[ 5], src[ 3]));\n\
#else\n\
vec3 src17 = SAMPLE3_TEX_RECT(tex, texCoord[0] + vec2(-2.0, 1.0)).rgb;\n\
vec3 src18 = SAMPLE3_TEX_RECT(tex, texCoord[0] + vec2(-2.0, 0.0)).rgb;\n\
float dist_04_00 = DistYCbCr(src17 , src[ 5]) + DistYCbCr(src[ 5], src[ 7]) + DistYCbCr(src[15], src[ 3]) + DistYCbCr(src[ 3], src[ 1]) + (4.0 * DistYCbCr(src[ 4], src[ 0]));\n\
float dist_05_03 = DistYCbCr(src18 , src[ 4]) + DistYCbCr(src[ 4], src[14]) + DistYCbCr(src[ 6], src[ 0]) + DistYCbCr(src[ 0], src[ 2]) + (4.0 * DistYCbCr(src[ 5], src[ 3]));\n\
#endif\n\
bool dominantGradient = (DOMINANT_DIRECTION_THRESHOLD * dist_05_03) < dist_04_00;\n\
blendResult[3] = ((dist_04_00 > dist_05_03) && (v[0] != v[5]) && (v[0] != v[3])) ? ((dominantGradient) ? BLEND_DOMINANT : BLEND_NORMAL) : BLEND_NONE;\n\
}\n\
\n\
// Pixel Tap Mapping: --|--|22|23|--\n\
// --|06|07|08|09\n\
// --|05|00|01|10\n\
// --|--|03|02|--\n\
// --|--|--|--|--\n\
// Corner (1, 0)\n\
if ( !((v[7] == v[8] && v[0] == v[1]) || (v[7] == v[0] && v[8] == v[1])) )\n\
{\n\
#if GPU_TIER >= SHADERSUPPORT_MID_TIER\n\
float dist_00_08 = DistYCbCr(src[ 5], src[ 7]) + DistYCbCr(src[ 7], src[23]) + DistYCbCr(src[ 3], src[ 1]) + DistYCbCr(src[ 1], src[ 9]) + (4.0 * DistYCbCr(src[ 0], src[ 8]));\n\
float dist_07_01 = DistYCbCr(src[ 6], src[ 0]) + DistYCbCr(src[ 0], src[ 2]) + DistYCbCr(src[22], src[ 8]) + DistYCbCr(src[ 8], src[10]) + (4.0 * DistYCbCr(src[ 7], src[ 1]));\n\
#else\n\
vec3 src22 = SAMPLE3_TEX_RECT(tex, texCoord[0] + vec2(0.0, -2.0)).rgb;\n\
vec3 src23 = SAMPLE3_TEX_RECT(tex, texCoord[0] + vec2(1.0, -2.0)).rgb;\n\
float dist_00_08 = DistYCbCr(src[ 5], src[ 7]) + DistYCbCr(src[ 7], src23 ) + DistYCbCr(src[ 3], src[ 1]) + DistYCbCr(src[ 1], src[ 9]) + (4.0 * DistYCbCr(src[ 0], src[ 8]));\n\
float dist_07_01 = DistYCbCr(src[ 6], src[ 0]) + DistYCbCr(src[ 0], src[ 2]) + DistYCbCr(src22 , src[ 8]) + DistYCbCr(src[ 8], src[10]) + (4.0 * DistYCbCr(src[ 7], src[ 1]));\n\
#endif\n\
bool dominantGradient = (DOMINANT_DIRECTION_THRESHOLD * dist_07_01) < dist_00_08;\n\
blendResult[1] = ((dist_00_08 > dist_07_01) && (v[0] != v[7]) && (v[0] != v[1])) ? ((dominantGradient) ? BLEND_DOMINANT : BLEND_NORMAL) : BLEND_NONE;\n\
}\n\
\n\
// Pixel Tap Mapping: --|21|22|--|--\n\
// 19|06|07|08|--\n\
// 18|05|00|01|--\n\
// --|04|03|--|--\n\
// --|--|--|--|--\n\
// Corner (0, 0)\n\
if ( !((v[6] == v[7] && v[5] == v[0]) || (v[6] == v[5] && v[7] == v[0])) )\n\
{\n\
#if GPU_TIER >= SHADERSUPPORT_MID_TIER\n\
float dist_05_07 = DistYCbCr(src[18], src[ 6]) + DistYCbCr(src[ 6], src[22]) + DistYCbCr(src[ 4], src[ 0]) + DistYCbCr(src[ 0], src[ 8]) + (4.0 * DistYCbCr(src[ 5], src[ 7]));\n\
float dist_06_00 = DistYCbCr(src[19], src[ 5]) + DistYCbCr(src[ 5], src[ 3]) + DistYCbCr(src[21], src[ 7]) + DistYCbCr(src[ 7], src[ 1]) + (4.0 * DistYCbCr(src[ 6], src[ 0]));\n\
#else\n\
vec3 src18 = SAMPLE3_TEX_RECT(tex, texCoord[0] + vec2(-2.0, 0.0)).rgb;\n\
vec3 src19 = SAMPLE3_TEX_RECT(tex, texCoord[0] + vec2(-2.0, -1.0)).rgb;\n\
vec3 src21 = SAMPLE3_TEX_RECT(tex, texCoord[0] + vec2(-1.0, -2.0)).rgb;\n\
vec3 src22 = SAMPLE3_TEX_RECT(tex, texCoord[0] + vec2( 0.0, -2.0)).rgb;\n\
float dist_05_07 = DistYCbCr(src18 , src[ 6]) + DistYCbCr(src[ 6], src22 ) + DistYCbCr(src[ 4], src[ 0]) + DistYCbCr(src[ 0], src[ 8]) + (4.0 * DistYCbCr(src[ 5], src[ 7]));\n\
float dist_06_00 = DistYCbCr(src19 , src[ 5]) + DistYCbCr(src[ 5], src[ 3]) + DistYCbCr(src21 , src[ 7]) + DistYCbCr(src[ 7], src[ 1]) + (4.0 * DistYCbCr(src[ 6], src[ 0]));\n\
#endif\n\
bool dominantGradient = (DOMINANT_DIRECTION_THRESHOLD * dist_05_07) < dist_06_00;\n\
blendResult[0] = ((dist_05_07 < dist_06_00) && (v[0] != v[5]) && (v[0] != v[7])) ? ((dominantGradient) ? BLEND_DOMINANT : BLEND_NORMAL) : BLEND_NONE;\n\
}\n\
\n\
vec3 dst[4];\n\
dst[0] = src[0];\n\
dst[1] = src[0];\n\
dst[2] = src[0];\n\
dst[3] = src[0];\n\
\n\
// Scale pixel\n\
if (IsBlendingNeeded(blendResult))\n\
{\n\
#if GPU_TIER >= SHADERSUPPORT_MID_TIER\n\
float dist_01_04 = DistYCbCr(src[1], src[4]);\n\
float dist_03_08 = DistYCbCr(src[3], src[8]);\n\
bool haveShallowLine = (STEEP_DIRECTION_THRESHOLD * dist_01_04 <= dist_03_08) && (v[0] != v[4]) && (v[5] != v[4]);\n\
bool haveSteepLine = (STEEP_DIRECTION_THRESHOLD * dist_03_08 <= dist_01_04) && (v[0] != v[8]) && (v[7] != v[8]);\n\
bool needBlend = (blendResult[2] != BLEND_NONE);\n\
bool doLineBlend = ( blendResult[2] >= BLEND_DOMINANT ||\n\
!((blendResult[1] != BLEND_NONE && !IsPixEqual(src[0], src[4])) ||\n\
(blendResult[3] != BLEND_NONE && !IsPixEqual(src[0], src[8])) ||\n\
(IsPixEqual(src[4], src[3]) && IsPixEqual(src[3], src[2]) && IsPixEqual(src[2], src[1]) && IsPixEqual(src[1], src[8]) && !IsPixEqual(src[0], src[2])) ) );\n\
\n\
vec3 blendPix = ( DistYCbCr(src[0], src[1]) <= DistYCbCr(src[0], src[3]) ) ? src[1] : src[3];\n\
dst[1] = mix(dst[1], blendPix, (needBlend && doLineBlend && haveSteepLine) ? 0.25 : 0.00);\n\
dst[2] = mix(dst[2], blendPix, (needBlend) ? ((doLineBlend) ? ((haveShallowLine) ? ((haveSteepLine) ? 5.0/6.0 : 0.75) : ((haveSteepLine) ? 0.75 : 0.50)) : 1.0 - (M_PI/4.0)) : 0.00);\n\
dst[3] = mix(dst[3], blendPix, (needBlend && doLineBlend && haveShallowLine) ? 0.25 : 0.00);\n\
\n\
\n\
dist_01_04 = DistYCbCr(src[7], src[2]);\n\
dist_03_08 = DistYCbCr(src[1], src[6]);\n\
haveShallowLine = (STEEP_DIRECTION_THRESHOLD * dist_01_04 <= dist_03_08) && (v[0] != v[2]) && (v[3] != v[2]);\n\
haveSteepLine = (STEEP_DIRECTION_THRESHOLD * dist_03_08 <= dist_01_04) && (v[0] != v[6]) && (v[5] != v[6]);\n\
needBlend = (blendResult[1] != BLEND_NONE);\n\
doLineBlend = ( blendResult[1] >= BLEND_DOMINANT ||\n\
!((blendResult[0] != BLEND_NONE && !IsPixEqual(src[0], src[2])) ||\n\
(blendResult[2] != BLEND_NONE && !IsPixEqual(src[0], src[6])) ||\n\
(IsPixEqual(src[2], src[1]) && IsPixEqual(src[1], src[8]) && IsPixEqual(src[8], src[7]) && IsPixEqual(src[7], src[6]) && !IsPixEqual(src[0], src[8])) ) );\n\
\n\
blendPix = ( DistYCbCr(src[0], src[7]) <= DistYCbCr(src[0], src[1]) ) ? src[7] : src[1];\n\
dst[0] = mix(dst[0], blendPix, (needBlend && doLineBlend && haveSteepLine) ? 0.25 : 0.00);\n\
dst[1] = mix(dst[1], blendPix, (needBlend) ? ((doLineBlend) ? ((haveShallowLine) ? ((haveSteepLine) ? 5.0/6.0 : 0.75) : ((haveSteepLine) ? 0.75 : 0.50)) : 1.0 - (M_PI/4.0)) : 0.00);\n\
dst[2] = mix(dst[2], blendPix, (needBlend && doLineBlend && haveShallowLine) ? 0.25 : 0.00);\n\
\n\
\n\
dist_01_04 = DistYCbCr(src[5], src[8]);\n\
dist_03_08 = DistYCbCr(src[7], src[4]);\n\
haveShallowLine = (STEEP_DIRECTION_THRESHOLD * dist_01_04 <= dist_03_08) && (v[0] != v[8]) && (v[1] != v[8]);\n\
haveSteepLine = (STEEP_DIRECTION_THRESHOLD * dist_03_08 <= dist_01_04) && (v[0] != v[4]) && (v[3] != v[4]);\n\
needBlend = (blendResult[0] != BLEND_NONE);\n\
doLineBlend = ( blendResult[0] >= BLEND_DOMINANT ||\n\
!((blendResult[3] != BLEND_NONE && !IsPixEqual(src[0], src[8])) ||\n\
(blendResult[1] != BLEND_NONE && !IsPixEqual(src[0], src[4])) ||\n\
(IsPixEqual(src[8], src[7]) && IsPixEqual(src[7], src[6]) && IsPixEqual(src[6], src[5]) && IsPixEqual(src[5], src[4]) && !IsPixEqual(src[0], src[6])) ) );\n\
\n\
blendPix = ( DistYCbCr(src[0], src[5]) <= DistYCbCr(src[0], src[7]) ) ? src[5] : src[7];\n\
dst[3] = mix(dst[3], blendPix, (needBlend && doLineBlend && haveSteepLine) ? 0.25 : 0.00);\n\
dst[0] = mix(dst[0], blendPix, (needBlend) ? ((doLineBlend) ? ((haveShallowLine) ? ((haveSteepLine) ? 5.0/6.0 : 0.75) : ((haveSteepLine) ? 0.75 : 0.50)) : 1.0 - (M_PI/4.0)) : 0.00);\n\
dst[1] = mix(dst[1], blendPix, (needBlend && doLineBlend && haveShallowLine) ? 0.25 : 0.00);\n\
\n\
\n\
dist_01_04 = DistYCbCr(src[3], src[6]);\n\
dist_03_08 = DistYCbCr(src[5], src[2]);\n\
haveShallowLine = (STEEP_DIRECTION_THRESHOLD * dist_01_04 <= dist_03_08) && (v[0] != v[6]) && (v[7] != v[6]);\n\
haveSteepLine = (STEEP_DIRECTION_THRESHOLD * dist_03_08 <= dist_01_04) && (v[0] != v[2]) && (v[1] != v[2]);\n\
needBlend = (blendResult[3] != BLEND_NONE);\n\
doLineBlend = ( blendResult[3] >= BLEND_DOMINANT ||\n\
!((blendResult[2] != BLEND_NONE && !IsPixEqual(src[0], src[6])) ||\n\
(blendResult[0] != BLEND_NONE && !IsPixEqual(src[0], src[2])) ||\n\
(IsPixEqual(src[6], src[5]) && IsPixEqual(src[5], src[4]) && IsPixEqual(src[4], src[3]) && IsPixEqual(src[3], src[2]) && !IsPixEqual(src[0], src[4])) ) );\n\
\n\
blendPix = ( DistYCbCr(src[0], src[3]) <= DistYCbCr(src[0], src[5]) ) ? src[3] : src[5];\n\
dst[2] = mix(dst[2], blendPix, (needBlend && doLineBlend && haveSteepLine) ? 0.25 : 0.00);\n\
dst[3] = mix(dst[3], blendPix, (needBlend) ? ((doLineBlend) ? ((haveShallowLine) ? ((haveSteepLine) ? 5.0/6.0 : 0.75) : ((haveSteepLine) ? 0.75 : 0.50)) : 1.0 - (M_PI/4.0)) : 0.00);\n\
dst[0] = mix(dst[0], blendPix, (needBlend && doLineBlend && haveShallowLine) ? 0.25 : 0.00);\n\
\n\
#else\n\
vec3 k[9];\n\
vec3 tempDst3;\n\
\n\
k[0] = src[0];\n\
k[1] = src[1];\n\
k[2] = src[2];\n\
k[3] = src[3];\n\
k[4] = src[4];\n\
k[5] = src[5];\n\
k[6] = src[6];\n\
k[7] = src[7];\n\
k[8] = src[8];\n\
ScalePixel(blendResult.xyzw, k, dst);\n\
\n\
k[1] = src[7];\n\
k[2] = src[8];\n\
k[3] = src[1];\n\
k[4] = src[2];\n\
k[5] = src[3];\n\
k[6] = src[4];\n\
k[7] = src[5];\n\
k[8] = src[6];\n\
tempDst3 = dst[3];\n\
dst[3] = dst[2];\n\
dst[2] = dst[1];\n\
dst[1] = dst[0];\n\
dst[0] = tempDst3;\n\
ScalePixel(blendResult.wxyz, k, dst);\n\
\n\
k[1] = src[5];\n\
k[2] = src[6];\n\
k[3] = src[7];\n\
k[4] = src[8];\n\
k[5] = src[1];\n\
k[6] = src[2];\n\
k[7] = src[3];\n\
k[8] = src[4];\n\
tempDst3 = dst[3];\n\
dst[3] = dst[2];\n\
dst[2] = dst[1];\n\
dst[1] = dst[0];\n\
dst[0] = tempDst3;\n\
ScalePixel(blendResult.zwxy, k, dst);\n\
\n\
k[1] = src[3];\n\
k[2] = src[4];\n\
k[3] = src[5];\n\
k[4] = src[6];\n\
k[5] = src[7];\n\
k[6] = src[8];\n\
k[7] = src[1];\n\
k[8] = src[2];\n\
tempDst3 = dst[3];\n\
dst[3] = dst[2];\n\
dst[2] = dst[1];\n\
dst[1] = dst[0];\n\
dst[0] = tempDst3;\n\
ScalePixel(blendResult.yzwx, k, dst);\n\
\n\
// Rotate the destination pixels back to 0 degrees.\n\
tempDst3 = dst[3];\n\
dst[3] = dst[2];\n\
dst[2] = dst[1];\n\
dst[1] = dst[0];\n\
dst[0] = tempDst3;\n\
#endif\n\
}\n\
\n\
vec2 f = step(0.5, fract(texCoord[0]));\n\
OUT_FRAG_COLOR.rgb = mix( mix(dst[0], dst[1], f.x),\n\
mix(dst[3], dst[2], f.x), f.y );\n\
OUT_FRAG_COLOR.a = 1.0;\n\
}\n\
"};
static const char *Scaler3xBRZFragShader_110 = {"\
#define BLEND_NONE 0\n\
#define BLEND_NORMAL 1\n\
#define BLEND_DOMINANT 2\n\
#define LUMINANCE_WEIGHT 1.0\n\
#define EQUAL_COLOR_TOLERANCE 30.0/255.0\n\
#define STEEP_DIRECTION_THRESHOLD 2.2\n\
#define DOMINANT_DIRECTION_THRESHOLD 3.6\n\
#define M_PI 3.1415926535897932384626433832795\n\
\n\
#if GPU_TIER >= SHADERSUPPORT_MID_TIER\n\
VARYING vec2 texCoord[25];\n\
#else\n\
VARYING vec2 texCoord[16];\n\
#endif\n\
uniform sampler2DRect tex;\n\
\n\
float reduce(const vec3 color)\n\
{\n\
return dot(color, vec3(65536.0, 256.0, 1.0));\n\
}\n\
\n\
float DistYCbCr(const vec3 pixA, const vec3 pixB)\n\
{\n\
const vec3 w = vec3(0.2627, 0.6780, 0.0593);\n\
const float scaleB = 0.5 / (1.0 - w.b);\n\
const float scaleR = 0.5 / (1.0 - w.r);\n\
vec3 diff = pixA - pixB;\n\
float Y = dot(diff, w);\n\
float Cb = scaleB * (diff.b - Y);\n\
float Cr = scaleR * (diff.r - Y);\n\
\n\
return sqrt( ((LUMINANCE_WEIGHT*Y) * (LUMINANCE_WEIGHT*Y)) + (Cb * Cb) + (Cr * Cr) );\n\
}\n\
\n\
bool IsPixEqual(const vec3 pixA, const vec3 pixB)\n\
{\n\
return (DistYCbCr(pixA, pixB) < EQUAL_COLOR_TOLERANCE);\n\
}\n\
\n\
bool IsBlendingNeeded(const ivec4 blend)\n\
{\n\
return any(notEqual(blend, ivec4(BLEND_NONE)));\n\
}\n\
\n\
#if GPU_TIER < SHADERSUPPORT_MID_TIER\n\
void ScalePixel(const ivec4 blend, const vec3 k[9], inout vec3 dst[9])\n\
{\n\
// This is the optimized version of xBRZ's blending logic. It's behavior\n\
// should be identical to the original blending logic below.\n\
float v0 = reduce(k[0]);\n\
float v4 = reduce(k[4]);\n\
float v5 = reduce(k[5]);\n\
float v7 = reduce(k[7]);\n\
float v8 = reduce(k[8]);\n\
\n\
float dist_01_04 = DistYCbCr(k[1], k[4]);\n\
float dist_03_08 = DistYCbCr(k[3], k[8]);\n\
bool haveShallowLine = (STEEP_DIRECTION_THRESHOLD * dist_01_04 <= dist_03_08) && (v0 != v4) && (v5 != v4);\n\
bool haveSteepLine = (STEEP_DIRECTION_THRESHOLD * dist_03_08 <= dist_01_04) && (v0 != v8) && (v7 != v8);\n\
bool needBlend = (blend[2] != BLEND_NONE);\n\
bool doLineBlend = ( blend[2] >= BLEND_DOMINANT ||\n\
!((blend[1] != BLEND_NONE && !IsPixEqual(k[0], k[4])) ||\n\
(blend[3] != BLEND_NONE && !IsPixEqual(k[0], k[8])) ||\n\
(IsPixEqual(k[4], k[3]) && IsPixEqual(k[3], k[2]) && IsPixEqual(k[2], k[1]) && IsPixEqual(k[1], k[8]) && !IsPixEqual(k[0], k[2])) ) );\n\
\n\
vec3 blendPix = ( DistYCbCr(k[0], k[1]) <= DistYCbCr(k[0], k[3]) ) ? k[1] : k[3];\n\
dst[1] = mix(dst[1], blendPix, (needBlend && doLineBlend) ? ((haveSteepLine) ? 0.750 : ((haveShallowLine) ? 0.250 : 0.125)) : 0.000);\n\
dst[2] = mix(dst[2], blendPix, (needBlend) ? ((doLineBlend) ? ((!haveShallowLine && !haveSteepLine) ? 0.875 : 1.000) : 0.4545939598) : 0.000);\n\
dst[3] = mix(dst[3], blendPix, (needBlend && doLineBlend) ? ((haveShallowLine) ? 0.750 : ((haveSteepLine) ? 0.250 : 0.125)) : 0.000);\n\
dst[4] = mix(dst[4], blendPix, (needBlend && doLineBlend && haveShallowLine) ? 0.250 : 0.000);\n\
dst[8] = mix(dst[8], blendPix, (needBlend && doLineBlend && haveSteepLine) ? 0.250 : 0.000);\n\
\n\
// Let's keep xBRZ's original blending logic around for reference.\n\
/*\n\
if (blend[2] == BLEND_NONE)\n\
{\n\
return;\n\
}\n\
\n\
vec3 blendPix = ( DistYCbCr(k[0], k[1]) <= DistYCbCr(k[0], k[3]) ) ? k[1] : k[3];\n\
\n\
if ( DoLineBlend(blend, k) )\n\
{\n\
float v0 = reduce(k[0]);\n\
float v4 = reduce(k[4]);\n\
float v5 = reduce(k[5]);\n\
float v7 = reduce(k[7]);\n\
float v8 = reduce(k[8]);\n\
\n\
float dist_01_04 = DistYCbCr(k[1], k[4]);\n\
float dist_03_08 = DistYCbCr(k[3], k[8]);\n\
bool haveShallowLine = (STEEP_DIRECTION_THRESHOLD * dist_01_04 <= dist_03_08) && (v0 != v4) && (v5 != v4);\n\
bool haveSteepLine = (STEEP_DIRECTION_THRESHOLD * dist_03_08 <= dist_01_04) && (v0 != v8) && (v7 != v8);\n\
\n\
if (haveShallowLine)\n\
{\n\
if (haveSteepLine)\n\
{\n\
// Blend line steep and shallow\n\
dst[4] = mix(dst[4], blendPix, 0.25);\n\
dst[8] = mix(dst[8], blendPix, 0.25);\n\
dst[3] = mix(dst[3], blendPix, 0.75);\n\
dst[1] = mix(dst[1], blendPix, 0.75);\n\
dst[2] = mix(dst[2], blendPix, 1.00);\n\
}\n\
else\n\
{\n\
// Blend line shallow\n\
dst[4] = mix(dst[4], blendPix, 0.25);\n\
dst[1] = mix(dst[1], blendPix, 0.25);\n\
dst[3] = mix(dst[3], blendPix, 0.75);\n\
dst[2] = mix(dst[2], blendPix, 1.00);\n\
}\n\
}\n\
else\n\
{\n\
if (haveSteepLine)\n\
{\n\
// Blend line steep\n\
dst[8] = mix(dst[8], blendPix, 0.25);\n\
dst[3] = mix(dst[3], blendPix, 0.25);\n\
dst[1] = mix(dst[1], blendPix, 0.75);\n\
dst[2] = mix(dst[2], blendPix, 1.00);\n\
}\n\
else\n\
{\n\
// Blend line diagonal\n\
dst[1] = mix(dst[1], blendPix, 0.125);\n\
dst[3] = mix(dst[3], blendPix, 0.125);\n\
dst[2] = mix(dst[2], blendPix, 0.875);\n\
}\n\
}\n\
}\n\
else\n\
{\n\
// Blend corner\n\
dst[2] = mix(dst[2], blendPix, 0.4545939598);\n\
}\n\
*/\n\
}\n\
#endif\n\
\n\
//---------------------------------------\n\
// Input Pixel Mapping: --|21|22|23|--\n\
// 19|06|07|08|09\n\
// 18|05|00|01|10\n\
// 17|04|03|02|11\n\
// --|15|14|13|--\n\
//\n\
// Output Pixel Mapping: 06|07|08\n\
// 05|00|01\n\
// 04|03|02\n\
\n\
void main()\n\
{\n\
#if GPU_TIER >= SHADERSUPPORT_MID_TIER\n\
vec3 src[25];\n\
src[ 0] = SAMPLE3_TEX_RECT(tex, texCoord[ 0]);\n\
src[ 1] = SAMPLE3_TEX_RECT(tex, texCoord[ 1]);\n\
src[ 2] = SAMPLE3_TEX_RECT(tex, texCoord[ 2]);\n\
src[ 3] = SAMPLE3_TEX_RECT(tex, texCoord[ 3]);\n\
src[ 4] = SAMPLE3_TEX_RECT(tex, texCoord[ 4]);\n\
src[ 5] = SAMPLE3_TEX_RECT(tex, texCoord[ 5]);\n\
src[ 6] = SAMPLE3_TEX_RECT(tex, texCoord[ 6]);\n\
src[ 7] = SAMPLE3_TEX_RECT(tex, texCoord[ 7]);\n\
src[ 8] = SAMPLE3_TEX_RECT(tex, texCoord[ 8]);\n\
src[ 9] = SAMPLE3_TEX_RECT(tex, texCoord[ 9]);\n\
src[10] = SAMPLE3_TEX_RECT(tex, texCoord[10]);\n\
src[11] = SAMPLE3_TEX_RECT(tex, texCoord[11]);\n\
src[12] = SAMPLE3_TEX_RECT(tex, texCoord[12]);\n\
src[13] = SAMPLE3_TEX_RECT(tex, texCoord[13]);\n\
src[14] = SAMPLE3_TEX_RECT(tex, texCoord[14]);\n\
src[15] = SAMPLE3_TEX_RECT(tex, texCoord[15]);\n\
src[16] = SAMPLE3_TEX_RECT(tex, texCoord[16]);\n\
src[17] = SAMPLE3_TEX_RECT(tex, texCoord[17]);\n\
src[18] = SAMPLE3_TEX_RECT(tex, texCoord[18]);\n\
src[19] = SAMPLE3_TEX_RECT(tex, texCoord[19]);\n\
src[20] = SAMPLE3_TEX_RECT(tex, texCoord[20]);\n\
src[21] = SAMPLE3_TEX_RECT(tex, texCoord[21]);\n\
src[22] = SAMPLE3_TEX_RECT(tex, texCoord[22]);\n\
src[23] = SAMPLE3_TEX_RECT(tex, texCoord[23]);\n\
src[24] = SAMPLE3_TEX_RECT(tex, texCoord[24]);\n\
#else\n\
vec3 src[16];\n\
src[ 0] = SAMPLE3_TEX_RECT(tex, texCoord[ 0]);\n\
src[ 1] = SAMPLE3_TEX_RECT(tex, texCoord[ 1]);\n\
src[ 2] = SAMPLE3_TEX_RECT(tex, texCoord[ 2]);\n\
src[ 3] = SAMPLE3_TEX_RECT(tex, texCoord[ 3]);\n\
src[ 4] = SAMPLE3_TEX_RECT(tex, texCoord[ 4]);\n\
src[ 5] = SAMPLE3_TEX_RECT(tex, texCoord[ 5]);\n\
src[ 6] = SAMPLE3_TEX_RECT(tex, texCoord[ 6]);\n\
src[ 7] = SAMPLE3_TEX_RECT(tex, texCoord[ 7]);\n\
src[ 8] = SAMPLE3_TEX_RECT(tex, texCoord[ 8]);\n\
src[ 9] = SAMPLE3_TEX_RECT(tex, texCoord[ 9]);\n\
src[10] = SAMPLE3_TEX_RECT(tex, texCoord[10]);\n\
src[11] = SAMPLE3_TEX_RECT(tex, texCoord[11]);\n\
src[12] = SAMPLE3_TEX_RECT(tex, texCoord[12]);\n\
src[13] = SAMPLE3_TEX_RECT(tex, texCoord[13]);\n\
src[14] = SAMPLE3_TEX_RECT(tex, texCoord[14]);\n\
src[15] = SAMPLE3_TEX_RECT(tex, texCoord[15]);\n\
#endif\n\
\n\
float v[9];\n\
v[0] = reduce(src[0]);\n\
v[1] = reduce(src[1]);\n\
v[2] = reduce(src[2]);\n\
v[3] = reduce(src[3]);\n\
v[4] = reduce(src[4]);\n\
v[5] = reduce(src[5]);\n\
v[6] = reduce(src[6]);\n\
v[7] = reduce(src[7]);\n\
v[8] = reduce(src[8]);\n\
\n\
ivec4 blendResult = ivec4(BLEND_NONE);\n\
\n\
// Preprocess corners\n\
// Pixel Tap Mapping: --|--|--|--|--\n\
// --|--|07|08|--\n\
// --|05|00|01|10\n\
// --|04|03|02|11\n\
// --|--|14|13|--\n\
\n\
// Corner (1, 1)\n\
if ( !((v[0] == v[1] && v[3] == v[2]) || (v[0] == v[3] && v[1] == v[2])) )\n\
{\n\
float dist_03_01 = DistYCbCr(src[ 4], src[ 0]) + DistYCbCr(src[ 0], src[ 8]) + DistYCbCr(src[14], src[ 2]) + DistYCbCr(src[ 2], src[10]) + (4.0 * DistYCbCr(src[ 3], src[ 1]));\n\
float dist_00_02 = DistYCbCr(src[ 5], src[ 3]) + DistYCbCr(src[ 3], src[13]) + DistYCbCr(src[ 7], src[ 1]) + DistYCbCr(src[ 1], src[11]) + (4.0 * DistYCbCr(src[ 0], src[ 2]));\n\
bool dominantGradient = (DOMINANT_DIRECTION_THRESHOLD * dist_03_01) < dist_00_02;\n\
blendResult[2] = ((dist_03_01 < dist_00_02) && (v[0] != v[1]) && (v[0] != v[3])) ? ((dominantGradient) ? BLEND_DOMINANT : BLEND_NORMAL) : BLEND_NONE;\n\
}\n\
\n\
\n\
// Pixel Tap Mapping: --|--|--|--|--\n\
// --|06|07|--|--\n\
// 18|05|00|01|--\n\
// 17|04|03|02|--\n\
// --|15|14|--|--\n\
// Corner (0, 1)\n\
if ( !((v[5] == v[0] && v[4] == v[3]) || (v[5] == v[4] && v[0] == v[3])) )\n\
{\n\
#if GPU_TIER >= SHADERSUPPORT_MID_TIER\n\
float dist_04_00 = DistYCbCr(src[17], src[ 5]) + DistYCbCr(src[ 5], src[ 7]) + DistYCbCr(src[15], src[ 3]) + DistYCbCr(src[ 3], src[ 1]) + (4.0 * DistYCbCr(src[ 4], src[ 0]));\n\
float dist_05_03 = DistYCbCr(src[18], src[ 4]) + DistYCbCr(src[ 4], src[14]) + DistYCbCr(src[ 6], src[ 0]) + DistYCbCr(src[ 0], src[ 2]) + (4.0 * DistYCbCr(src[ 5], src[ 3]));\n\
#else\n\
vec3 src17 = SAMPLE3_TEX_RECT(tex, texCoord[0] + vec2(-2.0, 1.0));\n\
vec3 src18 = SAMPLE3_TEX_RECT(tex, texCoord[0] + vec2(-2.0, 0.0));\n\
float dist_04_00 = DistYCbCr(src17 , src[ 5]) + DistYCbCr(src[ 5], src[ 7]) + DistYCbCr(src[15], src[ 3]) + DistYCbCr(src[ 3], src[ 1]) + (4.0 * DistYCbCr(src[ 4], src[ 0]));\n\
float dist_05_03 = DistYCbCr(src18 , src[ 4]) + DistYCbCr(src[ 4], src[14]) + DistYCbCr(src[ 6], src[ 0]) + DistYCbCr(src[ 0], src[ 2]) + (4.0 * DistYCbCr(src[ 5], src[ 3]));\n\
#endif\n\
bool dominantGradient = (DOMINANT_DIRECTION_THRESHOLD * dist_05_03) < dist_04_00;\n\
blendResult[3] = ((dist_04_00 > dist_05_03) && (v[0] != v[5]) && (v[0] != v[3])) ? ((dominantGradient) ? BLEND_DOMINANT : BLEND_NORMAL) : BLEND_NONE;\n\
}\n\
\n\
// Pixel Tap Mapping: --|--|22|23|--\n\
// --|06|07|08|09\n\
// --|05|00|01|10\n\
// --|--|03|02|--\n\
// --|--|--|--|--\n\
// Corner (1, 0)\n\
if ( !((v[7] == v[8] && v[0] == v[1]) || (v[7] == v[0] && v[8] == v[1])) )\n\
{\n\
#if GPU_TIER >= SHADERSUPPORT_MID_TIER\n\
float dist_00_08 = DistYCbCr(src[ 5], src[ 7]) + DistYCbCr(src[ 7], src[23]) + DistYCbCr(src[ 3], src[ 1]) + DistYCbCr(src[ 1], src[ 9]) + (4.0 * DistYCbCr(src[ 0], src[ 8]));\n\
float dist_07_01 = DistYCbCr(src[ 6], src[ 0]) + DistYCbCr(src[ 0], src[ 2]) + DistYCbCr(src[22], src[ 8]) + DistYCbCr(src[ 8], src[10]) + (4.0 * DistYCbCr(src[ 7], src[ 1]));\n\
#else\n\
vec3 src22 = SAMPLE3_TEX_RECT(tex, texCoord[0] + vec2(0.0, -2.0));\n\
vec3 src23 = SAMPLE3_TEX_RECT(tex, texCoord[0] + vec2(1.0, -2.0));\n\
float dist_00_08 = DistYCbCr(src[ 5], src[ 7]) + DistYCbCr(src[ 7], src23 ) + DistYCbCr(src[ 3], src[ 1]) + DistYCbCr(src[ 1], src[ 9]) + (4.0 * DistYCbCr(src[ 0], src[ 8]));\n\
float dist_07_01 = DistYCbCr(src[ 6], src[ 0]) + DistYCbCr(src[ 0], src[ 2]) + DistYCbCr(src22 , src[ 8]) + DistYCbCr(src[ 8], src[10]) + (4.0 * DistYCbCr(src[ 7], src[ 1]));\n\
#endif\n\
bool dominantGradient = (DOMINANT_DIRECTION_THRESHOLD * dist_07_01) < dist_00_08;\n\
blendResult[1] = ((dist_00_08 > dist_07_01) && (v[0] != v[7]) && (v[0] != v[1])) ? ((dominantGradient) ? BLEND_DOMINANT : BLEND_NORMAL) : BLEND_NONE;\n\
}\n\
\n\
// Pixel Tap Mapping: --|21|22|--|--\n\
// 19|06|07|08|--\n\
// 18|05|00|01|--\n\
// --|04|03|--|--\n\
// --|--|--|--|--\n\
// Corner (0, 0)\n\
if ( !((v[6] == v[7] && v[5] == v[0]) || (v[6] == v[5] && v[7] == v[0])) )\n\
{\n\
#if GPU_TIER >= SHADERSUPPORT_MID_TIER\n\
float dist_05_07 = DistYCbCr(src[18], src[ 6]) + DistYCbCr(src[ 6], src[22]) + DistYCbCr(src[ 4], src[ 0]) + DistYCbCr(src[ 0], src[ 8]) + (4.0 * DistYCbCr(src[ 5], src[ 7]));\n\
float dist_06_00 = DistYCbCr(src[19], src[ 5]) + DistYCbCr(src[ 5], src[ 3]) + DistYCbCr(src[21], src[ 7]) + DistYCbCr(src[ 7], src[ 1]) + (4.0 * DistYCbCr(src[ 6], src[ 0]));\n\
#else\n\
vec3 src18 = SAMPLE3_TEX_RECT(tex, texCoord[0] + vec2(-2.0, 0.0));\n\
vec3 src19 = SAMPLE3_TEX_RECT(tex, texCoord[0] + vec2(-2.0, -1.0));\n\
vec3 src21 = SAMPLE3_TEX_RECT(tex, texCoord[0] + vec2(-1.0, -2.0));\n\
vec3 src22 = SAMPLE3_TEX_RECT(tex, texCoord[0] + vec2( 0.0, -2.0));\n\
float dist_05_07 = DistYCbCr(src18 , src[ 6]) + DistYCbCr(src[ 6], src22 ) + DistYCbCr(src[ 4], src[ 0]) + DistYCbCr(src[ 0], src[ 8]) + (4.0 * DistYCbCr(src[ 5], src[ 7]));\n\
float dist_06_00 = DistYCbCr(src19 , src[ 5]) + DistYCbCr(src[ 5], src[ 3]) + DistYCbCr(src21 , src[ 7]) + DistYCbCr(src[ 7], src[ 1]) + (4.0 * DistYCbCr(src[ 6], src[ 0]));\n\
#endif\n\
bool dominantGradient = (DOMINANT_DIRECTION_THRESHOLD * dist_05_07) < dist_06_00;\n\
blendResult[0] = ((dist_05_07 < dist_06_00) && (v[0] != v[5]) && (v[0] != v[7])) ? ((dominantGradient) ? BLEND_DOMINANT : BLEND_NORMAL) : BLEND_NONE;\n\
}\n\
\n\
vec3 dst[9];\n\
dst[0] = src[0];\n\
dst[1] = src[0];\n\
dst[2] = src[0];\n\
dst[3] = src[0];\n\
dst[4] = src[0];\n\
dst[5] = src[0];\n\
dst[6] = src[0];\n\
dst[7] = src[0];\n\
dst[8] = src[0];\n\
\n\
// Scale pixel\n\
if (IsBlendingNeeded(blendResult))\n\
{\n\
#if GPU_TIER >= SHADERSUPPORT_MID_TIER\n\
float dist_01_04 = DistYCbCr(src[1], src[4]);\n\
float dist_03_08 = DistYCbCr(src[3], src[8]);\n\
bool haveShallowLine = (STEEP_DIRECTION_THRESHOLD * dist_01_04 <= dist_03_08) && (v[0] != v[4]) && (v[5] != v[4]);\n\
bool haveSteepLine = (STEEP_DIRECTION_THRESHOLD * dist_03_08 <= dist_01_04) && (v[0] != v[8]) && (v[7] != v[8]);\n\
bool needBlend = (blendResult[2] != BLEND_NONE);\n\
bool doLineBlend = ( blendResult[2] >= BLEND_DOMINANT ||\n\
!((blendResult[1] != BLEND_NONE && !IsPixEqual(src[0], src[4])) ||\n\
(blendResult[3] != BLEND_NONE && !IsPixEqual(src[0], src[8])) ||\n\
(IsPixEqual(src[4], src[3]) && IsPixEqual(src[3], src[2]) && IsPixEqual(src[2], src[1]) && IsPixEqual(src[1], src[8]) && !IsPixEqual(src[0], src[2])) ) );\n\
\n\
vec3 blendPix = ( DistYCbCr(src[0], src[1]) <= DistYCbCr(src[0], src[3]) ) ? src[1] : src[3];\n\
dst[1] = mix(dst[1], blendPix, (needBlend && doLineBlend) ? ((haveSteepLine) ? 0.750 : ((haveShallowLine) ? 0.250 : 0.125)) : 0.000);\n\
dst[2] = mix(dst[2], blendPix, (needBlend) ? ((doLineBlend) ? ((!haveShallowLine && !haveSteepLine) ? 0.875 : 1.000) : 0.4545939598) : 0.000);\n\
dst[3] = mix(dst[3], blendPix, (needBlend && doLineBlend) ? ((haveShallowLine) ? 0.750 : ((haveSteepLine) ? 0.250 : 0.125)) : 0.000);\n\
dst[4] = mix(dst[4], blendPix, (needBlend && doLineBlend && haveShallowLine) ? 0.250 : 0.000);\n\
dst[8] = mix(dst[8], blendPix, (needBlend && doLineBlend && haveSteepLine) ? 0.250 : 0.000);\n\
\n\
\n\
dist_01_04 = DistYCbCr(src[7], src[2]);\n\
dist_03_08 = DistYCbCr(src[1], src[6]);\n\
haveShallowLine = (STEEP_DIRECTION_THRESHOLD * dist_01_04 <= dist_03_08) && (v[0] != v[2]) && (v[3] != v[2]);\n\
haveSteepLine = (STEEP_DIRECTION_THRESHOLD * dist_03_08 <= dist_01_04) && (v[0] != v[6]) && (v[5] != v[6]);\n\
needBlend = (blendResult[1] != BLEND_NONE);\n\
doLineBlend = ( blendResult[1] >= BLEND_DOMINANT ||\n\
!((blendResult[0] != BLEND_NONE && !IsPixEqual(src[0], src[2])) ||\n\
(blendResult[2] != BLEND_NONE && !IsPixEqual(src[0], src[6])) ||\n\
(IsPixEqual(src[2], src[1]) && IsPixEqual(src[1], src[8]) && IsPixEqual(src[8], src[7]) && IsPixEqual(src[7], src[6]) && !IsPixEqual(src[0], src[8])) ) );\n\
\n\
blendPix = ( DistYCbCr(src[0], src[7]) <= DistYCbCr(src[0], src[1]) ) ? src[7] : src[1];\n\
dst[7] = mix(dst[7], blendPix, (needBlend && doLineBlend) ? ((haveSteepLine) ? 0.750 : ((haveShallowLine) ? 0.250 : 0.125)) : 0.000);\n\
dst[8] = mix(dst[8], blendPix, (needBlend) ? ((doLineBlend) ? ((!haveShallowLine && !haveSteepLine) ? 0.875 : 1.000) : 0.4545939598) : 0.000);\n\
dst[1] = mix(dst[1], blendPix, (needBlend && doLineBlend) ? ((haveShallowLine) ? 0.750 : ((haveSteepLine) ? 0.250 : 0.125)) : 0.000);\n\
dst[2] = mix(dst[2], blendPix, (needBlend && doLineBlend && haveShallowLine) ? 0.250 : 0.000);\n\
dst[6] = mix(dst[6], blendPix, (needBlend && doLineBlend && haveSteepLine) ? 0.250 : 0.000);\n\
\n\
\n\
dist_01_04 = DistYCbCr(src[5], src[8]);\n\
dist_03_08 = DistYCbCr(src[7], src[4]);\n\
haveShallowLine = (STEEP_DIRECTION_THRESHOLD * dist_01_04 <= dist_03_08) && (v[0] != v[8]) && (v[1] != v[8]);\n\
haveSteepLine = (STEEP_DIRECTION_THRESHOLD * dist_03_08 <= dist_01_04) && (v[0] != v[4]) && (v[3] != v[4]);\n\
needBlend = (blendResult[0] != BLEND_NONE);\n\
doLineBlend = ( blendResult[0] >= BLEND_DOMINANT ||\n\
!((blendResult[3] != BLEND_NONE && !IsPixEqual(src[0], src[8])) ||\n\
(blendResult[1] != BLEND_NONE && !IsPixEqual(src[0], src[4])) ||\n\
(IsPixEqual(src[8], src[7]) && IsPixEqual(src[7], src[6]) && IsPixEqual(src[6], src[5]) && IsPixEqual(src[5], src[4]) && !IsPixEqual(src[0], src[6])) ) );\n\
\n\
blendPix = ( DistYCbCr(src[0], src[5]) <= DistYCbCr(src[0], src[7]) ) ? src[5] : src[7];\n\
dst[5] = mix(dst[5], blendPix, (needBlend && doLineBlend) ? ((haveSteepLine) ? 0.750 : ((haveShallowLine) ? 0.250 : 0.125)) : 0.000);\n\
dst[6] = mix(dst[6], blendPix, (needBlend) ? ((doLineBlend) ? ((!haveShallowLine && !haveSteepLine) ? 0.875 : 1.000) : 0.4545939598) : 0.000);\n\
dst[7] = mix(dst[7], blendPix, (needBlend && doLineBlend) ? ((haveShallowLine) ? 0.750 : ((haveSteepLine) ? 0.250 : 0.125)) : 0.000);\n\
dst[8] = mix(dst[8], blendPix, (needBlend && doLineBlend && haveShallowLine) ? 0.250 : 0.000);\n\
dst[4] = mix(dst[4], blendPix, (needBlend && doLineBlend && haveSteepLine) ? 0.250 : 0.000);\n\
\n\
\n\
dist_01_04 = DistYCbCr(src[3], src[6]);\n\
dist_03_08 = DistYCbCr(src[5], src[2]);\n\
haveShallowLine = (STEEP_DIRECTION_THRESHOLD * dist_01_04 <= dist_03_08) && (v[0] != v[6]) && (v[7] != v[6]);\n\
haveSteepLine = (STEEP_DIRECTION_THRESHOLD * dist_03_08 <= dist_01_04) && (v[0] != v[2]) && (v[1] != v[2]);\n\
needBlend = (blendResult[3] != BLEND_NONE);\n\
doLineBlend = ( blendResult[3] >= BLEND_DOMINANT ||\n\
!((blendResult[2] != BLEND_NONE && !IsPixEqual(src[0], src[6])) ||\n\
(blendResult[0] != BLEND_NONE && !IsPixEqual(src[0], src[2])) ||\n\
(IsPixEqual(src[6], src[5]) && IsPixEqual(src[5], src[4]) && IsPixEqual(src[4], src[3]) && IsPixEqual(src[3], src[2]) && !IsPixEqual(src[0], src[4])) ) );\n\
\n\
blendPix = ( DistYCbCr(src[0], src[3]) <= DistYCbCr(src[0], src[5]) ) ? src[3] : src[5];\n\
dst[3] = mix(dst[3], blendPix, (needBlend && doLineBlend) ? ((haveSteepLine) ? 0.750 : ((haveShallowLine) ? 0.250 : 0.125)) : 0.000);\n\
dst[4] = mix(dst[4], blendPix, (needBlend) ? ((doLineBlend) ? ((!haveShallowLine && !haveSteepLine) ? 0.875 : 1.000) : 0.4545939598) : 0.000);\n\
dst[5] = mix(dst[5], blendPix, (needBlend && doLineBlend) ? ((haveShallowLine) ? 0.750 : ((haveSteepLine) ? 0.250 : 0.125)) : 0.000);\n\
dst[6] = mix(dst[6], blendPix, (needBlend && doLineBlend && haveShallowLine) ? 0.250 : 0.000);\n\
dst[2] = mix(dst[2], blendPix, (needBlend && doLineBlend && haveSteepLine) ? 0.250 : 0.000);\n\
\n\
#else\n\
vec3 k[9];\n\
vec3 tempDst8;\n\
vec3 tempDst7;\n\
\n\
k[8] = src[8];\n\
k[7] = src[7];\n\
k[6] = src[6];\n\
k[5] = src[5];\n\
k[4] = src[4];\n\
k[3] = src[3];\n\
k[2] = src[2];\n\
k[1] = src[1];\n\
k[0] = src[0];\n\
ScalePixel(blendResult.xyzw, k, dst);\n\
\n\
k[8] = src[6];\n\
k[7] = src[5];\n\
k[6] = src[4];\n\
k[5] = src[3];\n\
k[4] = src[2];\n\
k[3] = src[1];\n\
k[2] = src[8];\n\
k[1] = src[7];\n\
tempDst8 = dst[8];\n\
tempDst7 = dst[7];\n\
dst[8] = dst[6];\n\
dst[7] = dst[5];\n\
dst[6] = dst[4];\n\
dst[5] = dst[3];\n\
dst[4] = dst[2];\n\
dst[3] = dst[1];\n\
dst[2] = tempDst8;\n\
dst[1] = tempDst7;\n\
ScalePixel(blendResult.wxyz, k, dst);\n\
\n\
k[8] = src[4];\n\
k[7] = src[3];\n\
k[6] = src[2];\n\
k[5] = src[1];\n\
k[4] = src[8];\n\
k[3] = src[7];\n\
k[2] = src[6];\n\
k[1] = src[5];\n\
tempDst8 = dst[8];\n\
tempDst7 = dst[7];\n\
dst[8] = dst[6];\n\
dst[7] = dst[5];\n\
dst[6] = dst[4];\n\
dst[5] = dst[3];\n\
dst[4] = dst[2];\n\
dst[3] = dst[1];\n\
dst[2] = tempDst8;\n\
dst[1] = tempDst7;\n\
ScalePixel(blendResult.zwxy, k, dst);\n\
\n\
k[8] = src[2];\n\
k[7] = src[1];\n\
k[6] = src[8];\n\
k[5] = src[7];\n\
k[4] = src[6];\n\
k[3] = src[5];\n\
k[2] = src[4];\n\
k[1] = src[3];\n\
tempDst8 = dst[8];\n\
tempDst7 = dst[7];\n\
dst[8] = dst[6];\n\
dst[7] = dst[5];\n\
dst[6] = dst[4];\n\
dst[5] = dst[3];\n\
dst[4] = dst[2];\n\
dst[3] = dst[1];\n\
dst[2] = tempDst8;\n\
dst[1] = tempDst7;\n\
ScalePixel(blendResult.yzwx, k, dst);\n\
\n\
// Rotate the destination pixels back to 0 degrees.\n\
tempDst8 = dst[8];\n\
tempDst7 = dst[7];\n\
dst[8] = dst[6];\n\
dst[7] = dst[5];\n\
dst[6] = dst[4];\n\
dst[5] = dst[3];\n\
dst[4] = dst[2];\n\
dst[3] = dst[1];\n\
dst[2] = tempDst8;\n\
dst[1] = tempDst7;\n\
#endif\n\
}\n\
\n\
vec2 f = fract(texCoord[0]);\n\
OUT_FRAG_COLOR.rgb = mix( mix( dst[6], mix(dst[7], dst[8], step(0.6, f.x)), step(0.3, f.x)),\n\
mix( mix(dst[5], mix(dst[0], dst[1], step(0.6, f.x)), step(0.3, f.x)),\n\
mix(dst[4], mix(dst[3], dst[2], step(0.6, f.x)), step(0.3, f.x)), step(0.6, f.y)),\n\
step(0.3, f.y) );\n\
OUT_FRAG_COLOR.a = 1.0;\n\
}\n\
"};
static const char *Scaler4xBRZFragShader_110 = {"\
#define BLEND_NONE 0\n\
#define BLEND_NORMAL 1\n\
#define BLEND_DOMINANT 2\n\
#define LUMINANCE_WEIGHT 1.0\n\
#define EQUAL_COLOR_TOLERANCE 30.0/255.0\n\
#define STEEP_DIRECTION_THRESHOLD 2.2\n\
#define DOMINANT_DIRECTION_THRESHOLD 3.6\n\
#define M_PI 3.1415926535897932384626433832795\n\
\n\
#if GPU_TIER >= SHADERSUPPORT_MID_TIER\n\
VARYING vec2 texCoord[25];\n\
#else\n\
VARYING vec2 texCoord[16];\n\
#endif\n\
uniform sampler2DRect tex;\n\
\n\
float reduce(const vec3 color)\n\
{\n\
return dot(color, vec3(65536.0, 256.0, 1.0));\n\
}\n\
\n\
float DistYCbCr(const vec3 pixA, const vec3 pixB)\n\
{\n\
const vec3 w = vec3(0.2627, 0.6780, 0.0593);\n\
const float scaleB = 0.5 / (1.0 - w.b);\n\
const float scaleR = 0.5 / (1.0 - w.r);\n\
vec3 diff = pixA - pixB;\n\
float Y = dot(diff, w);\n\
float Cb = scaleB * (diff.b - Y);\n\
float Cr = scaleR * (diff.r - Y);\n\
\n\
return sqrt( ((LUMINANCE_WEIGHT*Y) * (LUMINANCE_WEIGHT*Y)) + (Cb * Cb) + (Cr * Cr) );\n\
}\n\
\n\
bool IsPixEqual(const vec3 pixA, const vec3 pixB)\n\
{\n\
return (DistYCbCr(pixA, pixB) < EQUAL_COLOR_TOLERANCE);\n\
}\n\
\n\
bool IsBlendingNeeded(const ivec4 blend)\n\
{\n\
return any(notEqual(blend, ivec4(BLEND_NONE)));\n\
}\n\
\n\
#if GPU_TIER < SHADERSUPPORT_MID_TIER\n\
void ScalePixel(const ivec4 blend, const vec3 k[9], inout vec3 dst[16])\n\
{\n\
// This is the optimized version of xBRZ's blending logic. It's behavior\n\
// should be identical to the original blending logic below.\n\
float v0 = reduce(k[0]);\n\
float v4 = reduce(k[4]);\n\
float v5 = reduce(k[5]);\n\
float v7 = reduce(k[7]);\n\
float v8 = reduce(k[8]);\n\
\n\
float dist_01_04 = DistYCbCr(k[1], k[4]);\n\
float dist_03_08 = DistYCbCr(k[3], k[8]);\n\
bool haveShallowLine = (STEEP_DIRECTION_THRESHOLD * dist_01_04 <= dist_03_08) && (v0 != v4) && (v5 != v4);\n\
bool haveSteepLine = (STEEP_DIRECTION_THRESHOLD * dist_03_08 <= dist_01_04) && (v0 != v8) && (v7 != v8);\n\
bool needBlend = (blend[2] != BLEND_NONE);\n\
bool doLineBlend = ( blend[2] >= BLEND_DOMINANT ||\n\
!((blend[1] != BLEND_NONE && !IsPixEqual(k[0], k[4])) ||\n\
(blend[3] != BLEND_NONE && !IsPixEqual(k[0], k[8])) ||\n\
(IsPixEqual(k[4], k[3]) && IsPixEqual(k[3], k[2]) && IsPixEqual(k[2], k[1]) && IsPixEqual(k[1], k[8]) && !IsPixEqual(k[0], k[2])) ) );\n\
\n\
vec3 blendPix = ( DistYCbCr(k[0], k[1]) <= DistYCbCr(k[0], k[3]) ) ? k[1] : k[3];\n\
dst[ 2] = mix(dst[ 2], blendPix, (needBlend && doLineBlend) ? ((haveShallowLine) ? ((haveSteepLine) ? 1.0/3.0 : 0.25) : ((haveSteepLine) ? 0.25 : 0.00)) : 0.00);\n\
dst[ 9] = mix(dst[ 9], blendPix, (needBlend && doLineBlend && haveSteepLine) ? 0.25 : 0.00);\n\
dst[10] = mix(dst[10], blendPix, (needBlend && doLineBlend && haveSteepLine) ? 0.75 : 0.00);\n\
dst[11] = mix(dst[11], blendPix, (needBlend) ? ((doLineBlend) ? ((haveSteepLine) ? 1.00 : ((haveShallowLine) ? 0.75 : 0.50)) : 0.08677704501) : 0.00);\n\
dst[12] = mix(dst[12], blendPix, (needBlend) ? ((doLineBlend) ? 1.00 : 0.6848532563) : 0.00);\n\
dst[13] = mix(dst[13], blendPix, (needBlend) ? ((doLineBlend) ? ((haveShallowLine) ? 1.00 : ((haveSteepLine) ? 0.75 : 0.50)) : 0.08677704501) : 0.00);\n\
dst[14] = mix(dst[14], blendPix, (needBlend && doLineBlend && haveShallowLine) ? 0.75 : 0.00);\n\
dst[15] = mix(dst[15], blendPix, (needBlend && doLineBlend && haveShallowLine) ? 0.25 : 0.00);\n\
\n\
// Let's keep xBRZ's original blending logic around for reference.\n\
/*\n\
if (blend[2] == BLEND_NONE)\n\
{\n\
return;\n\
}\n\
\n\
vec3 blendPix = ( DistYCbCr(k[0], k[1]) <= DistYCbCr(k[0], k[3]) ) ? k[1] : k[3];\n\
\n\
if ( DoLineBlend(blend, k) )\n\
{\n\
float v0 = reduce(k[0]);\n\
float v4 = reduce(k[4]);\n\
float v5 = reduce(k[5]);\n\
float v7 = reduce(k[7]);\n\
float v8 = reduce(k[8]);\n\
\n\
float dist_01_04 = DistYCbCr(k[1], k[4]);\n\
float dist_03_08 = DistYCbCr(k[3], k[8]);\n\
bool haveShallowLine = (STEEP_DIRECTION_THRESHOLD * dist_01_04 <= dist_03_08) && (v0 != v4) && (v5 != v4);\n\
bool haveSteepLine = (STEEP_DIRECTION_THRESHOLD * dist_03_08 <= dist_01_04) && (v0 != v8) && (v7 != v8);\n\
\n\
if (haveShallowLine)\n\
{\n\
if (haveSteepLine)\n\
{\n\
// Blend line steep and shallow\n\
dst[14] = mix(dst[14], blendPix, 0.75);\n\
dst[10] = mix(dst[10], blendPix, 0.75);\n\
dst[15] = mix(dst[15], blendPix, 0.25);\n\
dst[ 9] = mix(dst[ 9], blendPix, 0.25);\n\
dst[ 2] = mix(dst[ 2], blendPix, 1.0/3.0);\n\
dst[12] = mix(dst[12], blendPix, 1.00);\n\
dst[11] = mix(dst[11], blendPix, 1.00);\n\
dst[13] = mix(dst[13], blendPix, 1.00);\n\
}\n\
else\n\
{\n\
// Blend line shallow\n\
dst[15] = mix(dst[15], blendPix, 0.25);\n\
dst[ 2] = mix(dst[ 2], blendPix, 0.25);\n\
dst[14] = mix(dst[14], blendPix, 0.75);\n\
dst[11] = mix(dst[11], blendPix, 0.75);\n\
dst[13] = mix(dst[13], blendPix, 1.00);\n\
dst[12] = mix(dst[12], blendPix, 1.00);\n\
}\n\
}\n\
else\n\
{\n\
if (haveSteepLine)\n\
{\n\
// Blend line steep\n\
dst[ 9] = mix(dst[ 9], blendPix, 0.25);\n\
dst[ 2] = mix(dst[ 2], blendPix, 0.25);\n\
dst[10] = mix(dst[10], blendPix, 0.75);\n\
dst[13] = mix(dst[13], blendPix, 0.75);\n\
dst[11] = mix(dst[11], blendPix, 1.00);\n\
dst[12] = mix(dst[12], blendPix, 1.00);\n\
}\n\
else\n\
{\n\
// Blend line diagonal\n\
dst[13] = mix(dst[13], blendPix, 0.50);\n\
dst[11] = mix(dst[11], blendPix, 0.50);\n\
dst[12] = mix(dst[12], blendPix, 1.00);\n\
}\n\
}\n\
}\n\
else\n\
{\n\
// Blend corner\n\
dst[12] = mix(dst[12], blendPix, 0.6848532563);\n\
dst[11] = mix(dst[11], blendPix, 0.08677704501);\n\
dst[13] = mix(dst[13], blendPix, 0.08677704501);\n\
}\n\
*/\n\
}\n\
#endif\n\
\n\
//---------------------------------------\n\
// Input Pixel Mapping: --|21|22|23|--\n\
// 19|06|07|08|09\n\
// 18|05|00|01|10\n\
// 17|04|03|02|11\n\
// --|15|14|13|--\n\
//\n\
// Output Pixel Mapping: 06|07|08|09\n\
// 05|00|01|10\n\
// 04|03|02|11\n\
// 15|14|13|12\n\
\n\
void main()\n\
{\n\
#if GPU_TIER >= SHADERSUPPORT_MID_TIER\n\
vec3 src[25];\n\
src[ 0] = SAMPLE3_TEX_RECT(tex, texCoord[ 0]).rgb;\n\
src[ 1] = SAMPLE3_TEX_RECT(tex, texCoord[ 1]).rgb;\n\
src[ 2] = SAMPLE3_TEX_RECT(tex, texCoord[ 2]).rgb;\n\
src[ 3] = SAMPLE3_TEX_RECT(tex, texCoord[ 3]).rgb;\n\
src[ 4] = SAMPLE3_TEX_RECT(tex, texCoord[ 4]).rgb;\n\
src[ 5] = SAMPLE3_TEX_RECT(tex, texCoord[ 5]).rgb;\n\
src[ 6] = SAMPLE3_TEX_RECT(tex, texCoord[ 6]).rgb;\n\
src[ 7] = SAMPLE3_TEX_RECT(tex, texCoord[ 7]).rgb;\n\
src[ 8] = SAMPLE3_TEX_RECT(tex, texCoord[ 8]).rgb;\n\
src[ 9] = SAMPLE3_TEX_RECT(tex, texCoord[ 9]).rgb;\n\
src[10] = SAMPLE3_TEX_RECT(tex, texCoord[10]).rgb;\n\
src[11] = SAMPLE3_TEX_RECT(tex, texCoord[11]).rgb;\n\
src[12] = SAMPLE3_TEX_RECT(tex, texCoord[12]).rgb;\n\
src[13] = SAMPLE3_TEX_RECT(tex, texCoord[13]).rgb;\n\
src[14] = SAMPLE3_TEX_RECT(tex, texCoord[14]).rgb;\n\
src[15] = SAMPLE3_TEX_RECT(tex, texCoord[15]).rgb;\n\
src[16] = SAMPLE3_TEX_RECT(tex, texCoord[16]).rgb;\n\
src[17] = SAMPLE3_TEX_RECT(tex, texCoord[17]).rgb;\n\
src[18] = SAMPLE3_TEX_RECT(tex, texCoord[18]).rgb;\n\
src[19] = SAMPLE3_TEX_RECT(tex, texCoord[19]).rgb;\n\
src[20] = SAMPLE3_TEX_RECT(tex, texCoord[20]).rgb;\n\
src[21] = SAMPLE3_TEX_RECT(tex, texCoord[21]).rgb;\n\
src[22] = SAMPLE3_TEX_RECT(tex, texCoord[22]).rgb;\n\
src[23] = SAMPLE3_TEX_RECT(tex, texCoord[23]).rgb;\n\
src[24] = SAMPLE3_TEX_RECT(tex, texCoord[24]).rgb;\n\
#else\n\
vec3 src[16];\n\
src[ 0] = SAMPLE3_TEX_RECT(tex, texCoord[ 0]).rgb;\n\
src[ 1] = SAMPLE3_TEX_RECT(tex, texCoord[ 1]).rgb;\n\
src[ 2] = SAMPLE3_TEX_RECT(tex, texCoord[ 2]).rgb;\n\
src[ 3] = SAMPLE3_TEX_RECT(tex, texCoord[ 3]).rgb;\n\
src[ 4] = SAMPLE3_TEX_RECT(tex, texCoord[ 4]).rgb;\n\
src[ 5] = SAMPLE3_TEX_RECT(tex, texCoord[ 5]).rgb;\n\
src[ 6] = SAMPLE3_TEX_RECT(tex, texCoord[ 6]).rgb;\n\
src[ 7] = SAMPLE3_TEX_RECT(tex, texCoord[ 7]).rgb;\n\
src[ 8] = SAMPLE3_TEX_RECT(tex, texCoord[ 8]).rgb;\n\
src[ 9] = SAMPLE3_TEX_RECT(tex, texCoord[ 9]).rgb;\n\
src[10] = SAMPLE3_TEX_RECT(tex, texCoord[10]).rgb;\n\
src[11] = SAMPLE3_TEX_RECT(tex, texCoord[11]).rgb;\n\
src[12] = SAMPLE3_TEX_RECT(tex, texCoord[12]).rgb;\n\
src[13] = SAMPLE3_TEX_RECT(tex, texCoord[13]).rgb;\n\
src[14] = SAMPLE3_TEX_RECT(tex, texCoord[14]).rgb;\n\
src[15] = SAMPLE3_TEX_RECT(tex, texCoord[15]).rgb;\n\
#endif\n\
\n\
float v[9];\n\
v[0] = reduce(src[0]);\n\
v[1] = reduce(src[1]);\n\
v[2] = reduce(src[2]);\n\
v[3] = reduce(src[3]);\n\
v[4] = reduce(src[4]);\n\
v[5] = reduce(src[5]);\n\
v[6] = reduce(src[6]);\n\
v[7] = reduce(src[7]);\n\
v[8] = reduce(src[8]);\n\
\n\
ivec4 blendResult = ivec4(BLEND_NONE);\n\
\n\
// Preprocess corners\n\
// Pixel Tap Mapping: --|--|--|--|--\n\
// --|--|07|08|--\n\
// --|05|00|01|10\n\
// --|04|03|02|11\n\
// --|--|14|13|--\n\
\n\
// Corner (1, 1)\n\
if ( !((v[0] == v[1] && v[3] == v[2]) || (v[0] == v[3] && v[1] == v[2])) )\n\
{\n\
float dist_03_01 = DistYCbCr(src[ 4], src[ 0]) + DistYCbCr(src[ 0], src[ 8]) + DistYCbCr(src[14], src[ 2]) + DistYCbCr(src[ 2], src[10]) + (4.0 * DistYCbCr(src[ 3], src[ 1]));\n\
float dist_00_02 = DistYCbCr(src[ 5], src[ 3]) + DistYCbCr(src[ 3], src[13]) + DistYCbCr(src[ 7], src[ 1]) + DistYCbCr(src[ 1], src[11]) + (4.0 * DistYCbCr(src[ 0], src[ 2]));\n\
bool dominantGradient = (DOMINANT_DIRECTION_THRESHOLD * dist_03_01) < dist_00_02;\n\
blendResult[2] = ((dist_03_01 < dist_00_02) && (v[0] != v[1]) && (v[0] != v[3])) ? ((dominantGradient) ? BLEND_DOMINANT : BLEND_NORMAL) : BLEND_NONE;\n\
}\n\
\n\
\n\
// Pixel Tap Mapping: --|--|--|--|--\n\
// --|06|07|--|--\n\
// 18|05|00|01|--\n\
// 17|04|03|02|--\n\
// --|15|14|--|--\n\
// Corner (0, 1)\n\
if ( !((v[5] == v[0] && v[4] == v[3]) || (v[5] == v[4] && v[0] == v[3])) )\n\
{\n\
#if GPU_TIER >= SHADERSUPPORT_MID_TIER\n\
float dist_04_00 = DistYCbCr(src[17], src[ 5]) + DistYCbCr(src[ 5], src[ 7]) + DistYCbCr(src[15], src[ 3]) + DistYCbCr(src[ 3], src[ 1]) + (4.0 * DistYCbCr(src[ 4], src[ 0]));\n\
float dist_05_03 = DistYCbCr(src[18], src[ 4]) + DistYCbCr(src[ 4], src[14]) + DistYCbCr(src[ 6], src[ 0]) + DistYCbCr(src[ 0], src[ 2]) + (4.0 * DistYCbCr(src[ 5], src[ 3]));\n\
#else\n\
vec3 src17 = SAMPLE3_TEX_RECT(tex, texCoord[0] + vec2(-2.0, 1.0)).rgb;\n\
vec3 src18 = SAMPLE3_TEX_RECT(tex, texCoord[0] + vec2(-2.0, 0.0)).rgb;\n\
float dist_04_00 = DistYCbCr(src17 , src[ 5]) + DistYCbCr(src[ 5], src[ 7]) + DistYCbCr(src[15], src[ 3]) + DistYCbCr(src[ 3], src[ 1]) + (4.0 * DistYCbCr(src[ 4], src[ 0]));\n\
float dist_05_03 = DistYCbCr(src18 , src[ 4]) + DistYCbCr(src[ 4], src[14]) + DistYCbCr(src[ 6], src[ 0]) + DistYCbCr(src[ 0], src[ 2]) + (4.0 * DistYCbCr(src[ 5], src[ 3]));\n\
#endif\n\
bool dominantGradient = (DOMINANT_DIRECTION_THRESHOLD * dist_05_03) < dist_04_00;\n\
blendResult[3] = ((dist_04_00 > dist_05_03) && (v[0] != v[5]) && (v[0] != v[3])) ? ((dominantGradient) ? BLEND_DOMINANT : BLEND_NORMAL) : BLEND_NONE;\n\
}\n\
\n\
// Pixel Tap Mapping: --|--|22|23|--\n\
// --|06|07|08|09\n\
// --|05|00|01|10\n\
// --|--|03|02|--\n\
// --|--|--|--|--\n\
// Corner (1, 0)\n\
if ( !((v[7] == v[8] && v[0] == v[1]) || (v[7] == v[0] && v[8] == v[1])) )\n\
{\n\
#if GPU_TIER >= SHADERSUPPORT_MID_TIER\n\
float dist_00_08 = DistYCbCr(src[ 5], src[ 7]) + DistYCbCr(src[ 7], src[23]) + DistYCbCr(src[ 3], src[ 1]) + DistYCbCr(src[ 1], src[ 9]) + (4.0 * DistYCbCr(src[ 0], src[ 8]));\n\
float dist_07_01 = DistYCbCr(src[ 6], src[ 0]) + DistYCbCr(src[ 0], src[ 2]) + DistYCbCr(src[22], src[ 8]) + DistYCbCr(src[ 8], src[10]) + (4.0 * DistYCbCr(src[ 7], src[ 1]));\n\
#else\n\
vec3 src22 = SAMPLE3_TEX_RECT(tex, texCoord[0] + vec2(0.0, -2.0)).rgb;\n\
vec3 src23 = SAMPLE3_TEX_RECT(tex, texCoord[0] + vec2(1.0, -2.0)).rgb;\n\
float dist_00_08 = DistYCbCr(src[ 5], src[ 7]) + DistYCbCr(src[ 7], src23 ) + DistYCbCr(src[ 3], src[ 1]) + DistYCbCr(src[ 1], src[ 9]) + (4.0 * DistYCbCr(src[ 0], src[ 8]));\n\
float dist_07_01 = DistYCbCr(src[ 6], src[ 0]) + DistYCbCr(src[ 0], src[ 2]) + DistYCbCr(src22 , src[ 8]) + DistYCbCr(src[ 8], src[10]) + (4.0 * DistYCbCr(src[ 7], src[ 1]));\n\
#endif\n\
bool dominantGradient = (DOMINANT_DIRECTION_THRESHOLD * dist_07_01) < dist_00_08;\n\
blendResult[1] = ((dist_00_08 > dist_07_01) && (v[0] != v[7]) && (v[0] != v[1])) ? ((dominantGradient) ? BLEND_DOMINANT : BLEND_NORMAL) : BLEND_NONE;\n\
}\n\
\n\
// Pixel Tap Mapping: --|21|22|--|--\n\
// 19|06|07|08|--\n\
// 18|05|00|01|--\n\
// --|04|03|--|--\n\
// --|--|--|--|--\n\
// Corner (0, 0)\n\
if ( !((v[6] == v[7] && v[5] == v[0]) || (v[6] == v[5] && v[7] == v[0])) )\n\
{\n\
#if GPU_TIER >= SHADERSUPPORT_MID_TIER\n\
float dist_05_07 = DistYCbCr(src[18], src[ 6]) + DistYCbCr(src[ 6], src[22]) + DistYCbCr(src[ 4], src[ 0]) + DistYCbCr(src[ 0], src[ 8]) + (4.0 * DistYCbCr(src[ 5], src[ 7]));\n\
float dist_06_00 = DistYCbCr(src[19], src[ 5]) + DistYCbCr(src[ 5], src[ 3]) + DistYCbCr(src[21], src[ 7]) + DistYCbCr(src[ 7], src[ 1]) + (4.0 * DistYCbCr(src[ 6], src[ 0]));\n\
#else\n\
vec3 src18 = SAMPLE3_TEX_RECT(tex, texCoord[0] + vec2(-2.0, 0.0)).rgb;\n\
vec3 src19 = SAMPLE3_TEX_RECT(tex, texCoord[0] + vec2(-2.0, -1.0)).rgb;\n\
vec3 src21 = SAMPLE3_TEX_RECT(tex, texCoord[0] + vec2(-1.0, -2.0)).rgb;\n\
vec3 src22 = SAMPLE3_TEX_RECT(tex, texCoord[0] + vec2( 0.0, -2.0)).rgb;\n\
float dist_05_07 = DistYCbCr(src18 , src[ 6]) + DistYCbCr(src[ 6], src22 ) + DistYCbCr(src[ 4], src[ 0]) + DistYCbCr(src[ 0], src[ 8]) + (4.0 * DistYCbCr(src[ 5], src[ 7]));\n\
float dist_06_00 = DistYCbCr(src19 , src[ 5]) + DistYCbCr(src[ 5], src[ 3]) + DistYCbCr(src21 , src[ 7]) + DistYCbCr(src[ 7], src[ 1]) + (4.0 * DistYCbCr(src[ 6], src[ 0]));\n\
#endif\n\
bool dominantGradient = (DOMINANT_DIRECTION_THRESHOLD * dist_05_07) < dist_06_00;\n\
blendResult[0] = ((dist_05_07 < dist_06_00) && (v[0] != v[5]) && (v[0] != v[7])) ? ((dominantGradient) ? BLEND_DOMINANT : BLEND_NORMAL) : BLEND_NONE;\n\
}\n\
\n\
vec3 dst[16];\n\
dst[ 0] = src[0];\n\
dst[ 1] = src[0];\n\
dst[ 2] = src[0];\n\
dst[ 3] = src[0];\n\
dst[ 4] = src[0];\n\
dst[ 5] = src[0];\n\
dst[ 6] = src[0];\n\
dst[ 7] = src[0];\n\
dst[ 8] = src[0];\n\
dst[ 9] = src[0];\n\
dst[10] = src[0];\n\
dst[11] = src[0];\n\
dst[12] = src[0];\n\
dst[13] = src[0];\n\
dst[14] = src[0];\n\
dst[15] = src[0];\n\
\n\
// Scale pixel\n\
if (IsBlendingNeeded(blendResult))\n\
{\n\
#if GPU_TIER >= SHADERSUPPORT_MID_TIER\n\
float dist_01_04 = DistYCbCr(src[1], src[4]);\n\
float dist_03_08 = DistYCbCr(src[3], src[8]);\n\
bool haveShallowLine = (STEEP_DIRECTION_THRESHOLD * dist_01_04 <= dist_03_08) && (v[0] != v[4]) && (v[5] != v[4]);\n\
bool haveSteepLine = (STEEP_DIRECTION_THRESHOLD * dist_03_08 <= dist_01_04) && (v[0] != v[8]) && (v[7] != v[8]);\n\
bool needBlend = (blendResult[2] != BLEND_NONE);\n\
bool doLineBlend = ( blendResult[2] >= BLEND_DOMINANT ||\n\
!((blendResult[1] != BLEND_NONE && !IsPixEqual(src[0], src[4])) ||\n\
(blendResult[3] != BLEND_NONE && !IsPixEqual(src[0], src[8])) ||\n\
(IsPixEqual(src[4], src[3]) && IsPixEqual(src[3], src[2]) && IsPixEqual(src[2], src[1]) && IsPixEqual(src[1], src[8]) && !IsPixEqual(src[0], src[2])) ) );\n\
\n\
vec3 blendPix = ( DistYCbCr(src[0], src[1]) <= DistYCbCr(src[0], src[3]) ) ? src[1] : src[3];\n\
dst[ 2] = mix(dst[ 2], blendPix, (needBlend && doLineBlend) ? ((haveShallowLine) ? ((haveSteepLine) ? 1.0/3.0 : 0.25) : ((haveSteepLine) ? 0.25 : 0.00)) : 0.00);\n\
dst[ 9] = mix(dst[ 9], blendPix, (needBlend && doLineBlend && haveSteepLine) ? 0.25 : 0.00);\n\
dst[10] = mix(dst[10], blendPix, (needBlend && doLineBlend && haveSteepLine) ? 0.75 : 0.00);\n\
dst[11] = mix(dst[11], blendPix, (needBlend) ? ((doLineBlend) ? ((haveSteepLine) ? 1.00 : ((haveShallowLine) ? 0.75 : 0.50)) : 0.08677704501) : 0.00);\n\
dst[12] = mix(dst[12], blendPix, (needBlend) ? ((doLineBlend) ? 1.00 : 0.6848532563) : 0.00);\n\
dst[13] = mix(dst[13], blendPix, (needBlend) ? ((doLineBlend) ? ((haveShallowLine) ? 1.00 : ((haveSteepLine) ? 0.75 : 0.50)) : 0.08677704501) : 0.00);\n\
dst[14] = mix(dst[14], blendPix, (needBlend && doLineBlend && haveShallowLine) ? 0.75 : 0.00);\n\
dst[15] = mix(dst[15], blendPix, (needBlend && doLineBlend && haveShallowLine) ? 0.25 : 0.00);\n\
\n\
\n\
dist_01_04 = DistYCbCr(src[7], src[2]);\n\
dist_03_08 = DistYCbCr(src[1], src[6]);\n\
haveShallowLine = (STEEP_DIRECTION_THRESHOLD * dist_01_04 <= dist_03_08) && (v[0] != v[2]) && (v[3] != v[2]);\n\
haveSteepLine = (STEEP_DIRECTION_THRESHOLD * dist_03_08 <= dist_01_04) && (v[0] != v[6]) && (v[5] != v[6]);\n\
needBlend = (blendResult[1] != BLEND_NONE);\n\
doLineBlend = ( blendResult[1] >= BLEND_DOMINANT ||\n\
!((blendResult[0] != BLEND_NONE && !IsPixEqual(src[0], src[2])) ||\n\
(blendResult[2] != BLEND_NONE && !IsPixEqual(src[0], src[6])) ||\n\
(IsPixEqual(src[2], src[1]) && IsPixEqual(src[1], src[8]) && IsPixEqual(src[8], src[7]) && IsPixEqual(src[7], src[6]) && !IsPixEqual(src[0], src[8])) ) );\n\
\n\
blendPix = ( DistYCbCr(src[0], src[7]) <= DistYCbCr(src[0], src[1]) ) ? src[7] : src[1];\n\
dst[ 1] = mix(dst[ 1], blendPix, (needBlend && doLineBlend) ? ((haveShallowLine) ? ((haveSteepLine) ? 1.0/3.0 : 0.25) : ((haveSteepLine) ? 0.25 : 0.00)) : 0.00);\n\
dst[ 6] = mix(dst[ 6], blendPix, (needBlend && doLineBlend && haveSteepLine) ? 0.25 : 0.00);\n\
dst[ 7] = mix(dst[ 7], blendPix, (needBlend && doLineBlend && haveSteepLine) ? 0.75 : 0.00);\n\
dst[ 8] = mix(dst[ 8], blendPix, (needBlend) ? ((doLineBlend) ? ((haveSteepLine) ? 1.00 : ((haveShallowLine) ? 0.75 : 0.50)) : 0.08677704501) : 0.00);\n\
dst[ 9] = mix(dst[ 9], blendPix, (needBlend) ? ((doLineBlend) ? 1.00 : 0.6848532563) : 0.00);\n\
dst[10] = mix(dst[10], blendPix, (needBlend) ? ((doLineBlend) ? ((haveShallowLine) ? 1.00 : ((haveSteepLine) ? 0.75 : 0.50)) : 0.08677704501) : 0.00);\n\
dst[11] = mix(dst[11], blendPix, (needBlend && doLineBlend && haveShallowLine) ? 0.75 : 0.00);\n\
dst[12] = mix(dst[12], blendPix, (needBlend && doLineBlend && haveShallowLine) ? 0.25 : 0.00);\n\
\n\
\n\
dist_01_04 = DistYCbCr(src[5], src[8]);\n\
dist_03_08 = DistYCbCr(src[7], src[4]);\n\
haveShallowLine = (STEEP_DIRECTION_THRESHOLD * dist_01_04 <= dist_03_08) && (v[0] != v[8]) && (v[1] != v[8]);\n\
haveSteepLine = (STEEP_DIRECTION_THRESHOLD * dist_03_08 <= dist_01_04) && (v[0] != v[4]) && (v[3] != v[4]);\n\
needBlend = (blendResult[0] != BLEND_NONE);\n\
doLineBlend = ( blendResult[0] >= BLEND_DOMINANT ||\n\
!((blendResult[3] != BLEND_NONE && !IsPixEqual(src[0], src[8])) ||\n\
(blendResult[1] != BLEND_NONE && !IsPixEqual(src[0], src[4])) ||\n\
(IsPixEqual(src[8], src[7]) && IsPixEqual(src[7], src[6]) && IsPixEqual(src[6], src[5]) && IsPixEqual(src[5], src[4]) && !IsPixEqual(src[0], src[6])) ) );\n\
\n\
blendPix = ( DistYCbCr(src[0], src[5]) <= DistYCbCr(src[0], src[7]) ) ? src[5] : src[7];\n\
dst[ 0] = mix(dst[ 0], blendPix, (needBlend && doLineBlend) ? ((haveShallowLine) ? ((haveSteepLine) ? 1.0/3.0 : 0.25) : ((haveSteepLine) ? 0.25 : 0.00)) : 0.00);\n\
dst[15] = mix(dst[15], blendPix, (needBlend && doLineBlend && haveSteepLine) ? 0.25 : 0.00);\n\
dst[ 4] = mix(dst[ 4], blendPix, (needBlend && doLineBlend && haveSteepLine) ? 0.75 : 0.00);\n\
dst[ 5] = mix(dst[ 5], blendPix, (needBlend) ? ((doLineBlend) ? ((haveSteepLine) ? 1.00 : ((haveShallowLine) ? 0.75 : 0.50)) : 0.08677704501) : 0.00);\n\
dst[ 6] = mix(dst[ 6], blendPix, (needBlend) ? ((doLineBlend) ? 1.00 : 0.6848532563) : 0.00);\n\
dst[ 7] = mix(dst[ 7], blendPix, (needBlend) ? ((doLineBlend) ? ((haveShallowLine) ? 1.00 : ((haveSteepLine) ? 0.75 : 0.50)) : 0.08677704501) : 0.00);\n\
dst[ 8] = mix(dst[ 8], blendPix, (needBlend && doLineBlend && haveShallowLine) ? 0.75 : 0.00);\n\
dst[ 9] = mix(dst[ 9], blendPix, (needBlend && doLineBlend && haveShallowLine) ? 0.25 : 0.00);\n\
\n\
\n\
dist_01_04 = DistYCbCr(src[3], src[6]);\n\
dist_03_08 = DistYCbCr(src[5], src[2]);\n\
haveShallowLine = (STEEP_DIRECTION_THRESHOLD * dist_01_04 <= dist_03_08) && (v[0] != v[6]) && (v[7] != v[6]);\n\
haveSteepLine = (STEEP_DIRECTION_THRESHOLD * dist_03_08 <= dist_01_04) && (v[0] != v[2]) && (v[1] != v[2]);\n\
needBlend = (blendResult[3] != BLEND_NONE);\n\
doLineBlend = ( blendResult[3] >= BLEND_DOMINANT ||\n\
!((blendResult[2] != BLEND_NONE && !IsPixEqual(src[0], src[6])) ||\n\
(blendResult[0] != BLEND_NONE && !IsPixEqual(src[0], src[2])) ||\n\
(IsPixEqual(src[6], src[5]) && IsPixEqual(src[5], src[4]) && IsPixEqual(src[4], src[3]) && IsPixEqual(src[3], src[2]) && !IsPixEqual(src[0], src[4])) ) );\n\
\n\
blendPix = ( DistYCbCr(src[0], src[3]) <= DistYCbCr(src[0], src[5]) ) ? src[3] : src[5];\n\
dst[ 3] = mix(dst[ 3], blendPix, (needBlend && doLineBlend) ? ((haveShallowLine) ? ((haveSteepLine) ? 1.0/3.0 : 0.25) : ((haveSteepLine) ? 0.25 : 0.00)) : 0.00);\n\
dst[12] = mix(dst[12], blendPix, (needBlend && doLineBlend && haveSteepLine) ? 0.25 : 0.00);\n\
dst[13] = mix(dst[13], blendPix, (needBlend && doLineBlend && haveSteepLine) ? 0.75 : 0.00);\n\
dst[14] = mix(dst[14], blendPix, (needBlend) ? ((doLineBlend) ? ((haveSteepLine) ? 1.00 : ((haveShallowLine) ? 0.75 : 0.50)) : 0.08677704501) : 0.00);\n\
dst[15] = mix(dst[15], blendPix, (needBlend) ? ((doLineBlend) ? 1.00 : 0.6848532563) : 0.00);\n\
dst[ 4] = mix(dst[ 4], blendPix, (needBlend) ? ((doLineBlend) ? ((haveShallowLine) ? 1.00 : ((haveSteepLine) ? 0.75 : 0.50)) : 0.08677704501) : 0.00);\n\
dst[ 5] = mix(dst[ 5], blendPix, (needBlend && doLineBlend && haveShallowLine) ? 0.75 : 0.00);\n\
dst[ 6] = mix(dst[ 6], blendPix, (needBlend && doLineBlend && haveShallowLine) ? 0.25 : 0.00);\n\
\n\
#else\n\
vec3 k[9];\n\
vec3 tempDst15;\n\
vec3 tempDst14;\n\
vec3 tempDst13;\n\
vec3 tempDst3;\n\
\n\
k[8] = src[8];\n\
k[7] = src[7];\n\
k[6] = src[6];\n\
k[5] = src[5];\n\
k[4] = src[4];\n\
k[3] = src[3];\n\
k[2] = src[2];\n\
k[1] = src[1];\n\
k[0] = src[0];\n\
ScalePixel(blendResult.xyzw, k, dst);\n\
\n\
k[8] = src[6];\n\
k[7] = src[5];\n\
k[6] = src[4];\n\
k[5] = src[3];\n\
k[4] = src[2];\n\
k[3] = src[1];\n\
k[2] = src[8];\n\
k[1] = src[7];\n\
tempDst15 = dst[15];\n\
tempDst14 = dst[14];\n\
tempDst13 = dst[13];\n\
tempDst3 = dst[ 3];\n\
dst[15] = dst[12];\n\
dst[14] = dst[11];\n\
dst[13] = dst[10];\n\
dst[12] = dst[ 9];\n\
dst[11] = dst[ 8];\n\
dst[10] = dst[ 7];\n\
dst[ 9] = dst[ 6];\n\
dst[ 8] = dst[ 5];\n\
dst[ 7] = dst[ 4];\n\
dst[ 6] = tempDst15;\n\
dst[ 5] = tempDst14;\n\
dst[ 4] = tempDst13;\n\
dst[ 3] = dst[ 2];\n\
dst[ 2] = dst[ 1];\n\
dst[ 1] = dst[ 0];\n\
dst[ 0] = tempDst3;\n\
ScalePixel(blendResult.wxyz, k, dst);\n\
\n\
k[8] = src[4];\n\
k[7] = src[3];\n\
k[6] = src[2];\n\
k[5] = src[1];\n\
k[4] = src[8];\n\
k[3] = src[7];\n\
k[2] = src[6];\n\
k[1] = src[5];\n\
tempDst15 = dst[15];\n\
tempDst14 = dst[14];\n\
tempDst13 = dst[13];\n\
tempDst3 = dst[ 3];\n\
dst[15] = dst[12];\n\
dst[14] = dst[11];\n\
dst[13] = dst[10];\n\
dst[12] = dst[ 9];\n\
dst[11] = dst[ 8];\n\
dst[10] = dst[ 7];\n\
dst[ 9] = dst[ 6];\n\
dst[ 8] = dst[ 5];\n\
dst[ 7] = dst[ 4];\n\
dst[ 6] = tempDst15;\n\
dst[ 5] = tempDst14;\n\
dst[ 4] = tempDst13;\n\
dst[ 3] = dst[ 2];\n\
dst[ 2] = dst[ 1];\n\
dst[ 1] = dst[ 0];\n\
dst[ 0] = tempDst3;\n\
ScalePixel(blendResult.zwxy, k, dst);\n\
\n\
k[8] = src[2];\n\
k[7] = src[1];\n\
k[6] = src[8];\n\
k[5] = src[7];\n\
k[4] = src[6];\n\
k[3] = src[5];\n\
k[2] = src[4];\n\
k[1] = src[3];\n\
tempDst15 = dst[15];\n\
tempDst14 = dst[14];\n\
tempDst13 = dst[13];\n\
tempDst3 = dst[ 3];\n\
dst[15] = dst[12];\n\
dst[14] = dst[11];\n\
dst[13] = dst[10];\n\
dst[12] = dst[ 9];\n\
dst[11] = dst[ 8];\n\
dst[10] = dst[ 7];\n\
dst[ 9] = dst[ 6];\n\
dst[ 8] = dst[ 5];\n\
dst[ 7] = dst[ 4];\n\
dst[ 6] = tempDst15;\n\
dst[ 5] = tempDst14;\n\
dst[ 4] = tempDst13;\n\
dst[ 3] = dst[ 2];\n\
dst[ 2] = dst[ 1];\n\
dst[ 1] = dst[ 0];\n\
dst[ 0] = tempDst3;\n\
ScalePixel(blendResult.yzwx, k, dst);\n\
\n\
// Rotate the destination pixels back to 0 degrees.\n\
tempDst15 = dst[15];\n\
tempDst14 = dst[14];\n\
tempDst13 = dst[13];\n\
tempDst3 = dst[ 3];\n\
dst[15] = dst[12];\n\
dst[14] = dst[11];\n\
dst[13] = dst[10];\n\
dst[12] = dst[ 9];\n\
dst[11] = dst[ 8];\n\
dst[10] = dst[ 7];\n\
dst[ 9] = dst[ 6];\n\
dst[ 8] = dst[ 5];\n\
dst[ 7] = dst[ 4];\n\
dst[ 6] = tempDst15;\n\
dst[ 5] = tempDst14;\n\
dst[ 4] = tempDst13;\n\
dst[ 3] = dst[ 2];\n\
dst[ 2] = dst[ 1];\n\
dst[ 1] = dst[ 0];\n\
dst[ 0] = tempDst3;\n\
#endif\n\
}\n\
\n\
vec2 f = fract(texCoord[0]);\n\
OUT_FRAG_COLOR.rgb = mix( mix( mix( mix(dst[ 6], dst[ 7], step(0.25, f.x)), mix(dst[ 8], dst[ 9], step(0.75, f.x)), step(0.50, f.x)),\n\
mix( mix(dst[ 5], dst[ 0], step(0.25, f.x)), mix(dst[ 1], dst[10], step(0.75, f.x)), step(0.50, f.x)), step(0.25, f.y)),\n\
mix( mix( mix(dst[ 4], dst[ 3], step(0.25, f.x)), mix(dst[ 2], dst[11], step(0.75, f.x)), step(0.50, f.x)),\n\
mix( mix(dst[15], dst[14], step(0.25, f.x)), mix(dst[13], dst[12], step(0.75, f.x)), step(0.50, f.x)), step(0.75, f.y)),\n\
step(0.50, f.y));\n\
OUT_FRAG_COLOR.a = 1.0;\n\
}\n\
"};
static const char *Scaler5xBRZFragShader_110 = {"\
#define BLEND_NONE 0\n\
#define BLEND_NORMAL 1\n\
#define BLEND_DOMINANT 2\n\
#define LUMINANCE_WEIGHT 1.0\n\
#define EQUAL_COLOR_TOLERANCE 30.0/255.0\n\
#define STEEP_DIRECTION_THRESHOLD 2.2\n\
#define DOMINANT_DIRECTION_THRESHOLD 3.6\n\
#define M_PI 3.1415926535897932384626433832795\n\
\n\
// Let's not even bother trying to support GPUs below Mid-tier.\n\
// The xBRZ pixel scalers are already pretty hefty as-is, and\n\
// this shader, having to calculate 25 pixel locations, is the\n\
// heftiest of all of them. Trust me -- older GPUs just can't\n\
// handle this one.\n\
\n\
VARYING vec2 texCoord[25];\n\
uniform sampler2DRect tex;\n\
\n\
float reduce(const vec3 color)\n\
{\n\
return dot(color, vec3(65536.0, 256.0, 1.0));\n\
}\n\
\n\
float DistYCbCr(const vec3 pixA, const vec3 pixB)\n\
{\n\
const vec3 w = vec3(0.2627, 0.6780, 0.0593);\n\
const float scaleB = 0.5 / (1.0 - w.b);\n\
const float scaleR = 0.5 / (1.0 - w.r);\n\
vec3 diff = pixA - pixB;\n\
float Y = dot(diff, w);\n\
float Cb = scaleB * (diff.b - Y);\n\
float Cr = scaleR * (diff.r - Y);\n\
\n\
return sqrt( ((LUMINANCE_WEIGHT*Y) * (LUMINANCE_WEIGHT*Y)) + (Cb * Cb) + (Cr * Cr) );\n\
}\n\
\n\
bool IsPixEqual(const vec3 pixA, const vec3 pixB)\n\
{\n\
return (DistYCbCr(pixA, pixB) < EQUAL_COLOR_TOLERANCE);\n\
}\n\
\n\
bool IsBlendingNeeded(const ivec4 blend)\n\
{\n\
return any(notEqual(blend, ivec4(BLEND_NONE)));\n\
}\n\
\n\
/*\n\
// Let's keep xBRZ's original blending logic around for reference.\n\
void ScalePixel(const ivec4 blend, const vec3 k[9], inout vec3 dst[25])\n\
{\n\
if (blend[2] == BLEND_NONE)\n\
{\n\
return;\n\
}\n\
\n\
vec3 blendPix = ( DistYCbCr(k[0], k[1]) <= DistYCbCr(k[0], k[3]) ) ? k[1] : k[3];\n\
\n\
if ( DoLineBlend(blend, k) )\n\
{\n\
float v0 = reduce(k[0]);\n\
float v4 = reduce(k[4]);\n\
float v5 = reduce(k[5]);\n\
float v7 = reduce(k[7]);\n\
float v8 = reduce(k[8]);\n\
\n\
float dist_01_04 = DistYCbCr(k[1], k[4]);\n\
float dist_03_08 = DistYCbCr(k[3], k[8]);\n\
bool haveShallowLine = (STEEP_DIRECTION_THRESHOLD * dist_01_04 <= dist_03_08) && (v0 != v4) && (v5 != v4);\n\
bool haveSteepLine = (STEEP_DIRECTION_THRESHOLD * dist_03_08 <= dist_01_04) && (v0 != v8) && (v7 != v8);\n\
\n\
if (haveShallowLine)\n\
{\n\
if (haveSteepLine)\n\
{\n\
// Blend line steep and shallow\n\
dst[24] = mix(dst[24], blendPix, 0.25);\n\
dst[ 1] = mix(dst[ 1], blendPix, 0.25);\n\
dst[ 9] = mix(dst[ 9], blendPix, 0.75);\n\
dst[16] = mix(dst[16], blendPix, 0.25);\n\
dst[ 3] = mix(dst[ 3], blendPix, 0.25);\n\
dst[15] = mix(dst[15], blendPix, 0.75);\n\
dst[10] = mix(dst[10], blendPix, 1.00);\n\
dst[11] = mix(dst[11], blendPix, 1.00);\n\
dst[14] = mix(dst[14], blendPix, 1.00);\n\
dst[13] = mix(dst[13], blendPix, 1.00);\n\
dst[12] = mix(dst[12], blendPix, 1.00);\n\
dst[ 2] = mix(dst[ 2], blendPix, 2.0/3.0);\n\
}\n\
else\n\
{\n\
// Blend line shallow\n\
dst[16] = mix(dst[16], blendPix, 0.25);\n\
dst[ 3] = mix(dst[ 3], blendPix, 0.25);\n\
dst[10] = mix(dst[10], blendPix, 0.25);\n\
dst[15] = mix(dst[15], blendPix, 0.75);\n\
dst[ 2] = mix(dst[ 2], blendPix, 0.75);\n\
dst[14] = mix(dst[14], blendPix, 1.00);\n\
dst[13] = mix(dst[13], blendPix, 1.00);\n\
dst[12] = mix(dst[12], blendPix, 1.00);\n\
dst[11] = mix(dst[11], blendPix, 1.00);\n\
}\n\
}\n\
else\n\
{\n\
if (haveSteepLine)\n\
{\n\
// Blend line steep\n\
dst[24] = mix(dst[24], blendPix, 0.25);\n\
dst[ 1] = mix(dst[ 1], blendPix, 0.25);\n\
dst[14] = mix(dst[14], blendPix, 0.25);\n\
dst[ 9] = mix(dst[ 9], blendPix, 0.75);\n\
dst[ 2] = mix(dst[ 2], blendPix, 0.75);\n\
dst[10] = mix(dst[10], blendPix, 1.00);\n\
dst[11] = mix(dst[11], blendPix, 1.00);\n\
dst[12] = mix(dst[12], blendPix, 1.00);\n\
dst[13] = mix(dst[13], blendPix, 1.00);\n\
}\n\
else\n\
{\n\
// Blend line diagonal\n\
dst[14] = mix(dst[14], blendPix, 0.125);\n\
dst[ 2] = mix(dst[ 2], blendPix, 0.125);\n\
dst[ 9] = mix(dst[ 9], blendPix, 0.125);\n\
dst[13] = mix(dst[13], blendPix, 0.875);\n\
dst[11] = mix(dst[11], blendPix, 0.875);\n\
dst[12] = mix(dst[12], blendPix, 1.000);\n\
}\n\
}\n\
}\n\
else\n\
{\n\
// Blend corner\n\
dst[12] = mix(dst[12], blendPix, 0.8631434088);\n\
dst[13] = mix(dst[13], blendPix, 0.2306749731);\n\
dst[11] = mix(dst[11], blendPix, 0.2306749731);\n\
}\n\
}\n\
*/\n\
//---------------------------------------\n\
// Input Pixel Mapping: --|21|22|23|--\n\
// 19|06|07|08|09\n\
// 18|05|00|01|10\n\
// 17|04|03|02|11\n\
// --|15|14|13|--\n\
//\n\
// Output Pixel Mapping: 20|21|22|23|24\n\
// 19|06|07|08|09\n\
// 18|05|00|01|10\n\
// 17|04|03|02|11\n\
// 16|15|14|13|12\n\
\n\
void main()\n\
{\n\
vec3 src[25];\n\
src[ 0] = SAMPLE3_TEX_RECT(tex, texCoord[ 0]).rgb;\n\
src[ 1] = SAMPLE3_TEX_RECT(tex, texCoord[ 1]).rgb;\n\
src[ 2] = SAMPLE3_TEX_RECT(tex, texCoord[ 2]).rgb;\n\
src[ 3] = SAMPLE3_TEX_RECT(tex, texCoord[ 3]).rgb;\n\
src[ 4] = SAMPLE3_TEX_RECT(tex, texCoord[ 4]).rgb;\n\
src[ 5] = SAMPLE3_TEX_RECT(tex, texCoord[ 5]).rgb;\n\
src[ 6] = SAMPLE3_TEX_RECT(tex, texCoord[ 6]).rgb;\n\
src[ 7] = SAMPLE3_TEX_RECT(tex, texCoord[ 7]).rgb;\n\
src[ 8] = SAMPLE3_TEX_RECT(tex, texCoord[ 8]).rgb;\n\
src[ 9] = SAMPLE3_TEX_RECT(tex, texCoord[ 9]).rgb;\n\
src[10] = SAMPLE3_TEX_RECT(tex, texCoord[10]).rgb;\n\
src[11] = SAMPLE3_TEX_RECT(tex, texCoord[11]).rgb;\n\
src[12] = SAMPLE3_TEX_RECT(tex, texCoord[12]).rgb;\n\
src[13] = SAMPLE3_TEX_RECT(tex, texCoord[13]).rgb;\n\
src[14] = SAMPLE3_TEX_RECT(tex, texCoord[14]).rgb;\n\
src[15] = SAMPLE3_TEX_RECT(tex, texCoord[15]).rgb;\n\
src[16] = SAMPLE3_TEX_RECT(tex, texCoord[16]).rgb;\n\
src[17] = SAMPLE3_TEX_RECT(tex, texCoord[17]).rgb;\n\
src[18] = SAMPLE3_TEX_RECT(tex, texCoord[18]).rgb;\n\
src[19] = SAMPLE3_TEX_RECT(tex, texCoord[19]).rgb;\n\
src[20] = SAMPLE3_TEX_RECT(tex, texCoord[20]).rgb;\n\
src[21] = SAMPLE3_TEX_RECT(tex, texCoord[21]).rgb;\n\
src[22] = SAMPLE3_TEX_RECT(tex, texCoord[22]).rgb;\n\
src[23] = SAMPLE3_TEX_RECT(tex, texCoord[23]).rgb;\n\
src[24] = SAMPLE3_TEX_RECT(tex, texCoord[24]).rgb;\n\
\n\
float v[9];\n\
v[0] = reduce(src[0]);\n\
v[1] = reduce(src[1]);\n\
v[2] = reduce(src[2]);\n\
v[3] = reduce(src[3]);\n\
v[4] = reduce(src[4]);\n\
v[5] = reduce(src[5]);\n\
v[6] = reduce(src[6]);\n\
v[7] = reduce(src[7]);\n\
v[8] = reduce(src[8]);\n\
\n\
ivec4 blendResult = ivec4(BLEND_NONE);\n\
\n\
// Preprocess corners\n\
// Pixel Tap Mapping: --|--|--|--|--\n\
// --|--|07|08|--\n\
// --|05|00|01|10\n\
// --|04|03|02|11\n\
// --|--|14|13|--\n\
\n\
// Corner (1, 1)\n\
if ( !((v[0] == v[1] && v[3] == v[2]) || (v[0] == v[3] && v[1] == v[2])) )\n\
{\n\
float dist_03_01 = DistYCbCr(src[ 4], src[ 0]) + DistYCbCr(src[ 0], src[ 8]) + DistYCbCr(src[14], src[ 2]) + DistYCbCr(src[ 2], src[10]) + (4.0 * DistYCbCr(src[ 3], src[ 1]));\n\
float dist_00_02 = DistYCbCr(src[ 5], src[ 3]) + DistYCbCr(src[ 3], src[13]) + DistYCbCr(src[ 7], src[ 1]) + DistYCbCr(src[ 1], src[11]) + (4.0 * DistYCbCr(src[ 0], src[ 2]));\n\
bool dominantGradient = (DOMINANT_DIRECTION_THRESHOLD * dist_03_01) < dist_00_02;\n\
blendResult[2] = ((dist_03_01 < dist_00_02) && (v[0] != v[1]) && (v[0] != v[3])) ? ((dominantGradient) ? BLEND_DOMINANT : BLEND_NORMAL) : BLEND_NONE;\n\
}\n\
\n\
\n\
// Pixel Tap Mapping: --|--|--|--|--\n\
// --|06|07|--|--\n\
// 18|05|00|01|--\n\
// 17|04|03|02|--\n\
// --|15|14|--|--\n\
// Corner (0, 1)\n\
if ( !((v[5] == v[0] && v[4] == v[3]) || (v[5] == v[4] && v[0] == v[3])) )\n\
{\n\
float dist_04_00 = DistYCbCr(src[17], src[ 5]) + DistYCbCr(src[ 5], src[ 7]) + DistYCbCr(src[15], src[ 3]) + DistYCbCr(src[ 3], src[ 1]) + (4.0 * DistYCbCr(src[ 4], src[ 0]));\n\
float dist_05_03 = DistYCbCr(src[18], src[ 4]) + DistYCbCr(src[ 4], src[14]) + DistYCbCr(src[ 6], src[ 0]) + DistYCbCr(src[ 0], src[ 2]) + (4.0 * DistYCbCr(src[ 5], src[ 3]));\n\
bool dominantGradient = (DOMINANT_DIRECTION_THRESHOLD * dist_05_03) < dist_04_00;\n\
blendResult[3] = ((dist_04_00 > dist_05_03) && (v[0] != v[5]) && (v[0] != v[3])) ? ((dominantGradient) ? BLEND_DOMINANT : BLEND_NORMAL) : BLEND_NONE;\n\
}\n\
\n\
// Pixel Tap Mapping: --|--|22|23|--\n\
// --|06|07|08|09\n\
// --|05|00|01|10\n\
// --|--|03|02|--\n\
// --|--|--|--|--\n\
// Corner (1, 0)\n\
if ( !((v[7] == v[8] && v[0] == v[1]) || (v[7] == v[0] && v[8] == v[1])) )\n\
{\n\
float dist_00_08 = DistYCbCr(src[ 5], src[ 7]) + DistYCbCr(src[ 7], src[23]) + DistYCbCr(src[ 3], src[ 1]) + DistYCbCr(src[ 1], src[ 9]) + (4.0 * DistYCbCr(src[ 0], src[ 8]));\n\
float dist_07_01 = DistYCbCr(src[ 6], src[ 0]) + DistYCbCr(src[ 0], src[ 2]) + DistYCbCr(src[22], src[ 8]) + DistYCbCr(src[ 8], src[10]) + (4.0 * DistYCbCr(src[ 7], src[ 1]));\n\
bool dominantGradient = (DOMINANT_DIRECTION_THRESHOLD * dist_07_01) < dist_00_08;\n\
blendResult[1] = ((dist_00_08 > dist_07_01) && (v[0] != v[7]) && (v[0] != v[1])) ? ((dominantGradient) ? BLEND_DOMINANT : BLEND_NORMAL) : BLEND_NONE;\n\
}\n\
\n\
// Pixel Tap Mapping: --|21|22|--|--\n\
// 19|06|07|08|--\n\
// 18|05|00|01|--\n\
// --|04|03|--|--\n\
// --|--|--|--|--\n\
// Corner (0, 0)\n\
if ( !((v[6] == v[7] && v[5] == v[0]) || (v[6] == v[5] && v[7] == v[0])) )\n\
{\n\
float dist_05_07 = DistYCbCr(src[18], src[ 6]) + DistYCbCr(src[ 6], src[22]) + DistYCbCr(src[ 4], src[ 0]) + DistYCbCr(src[ 0], src[ 8]) + (4.0 * DistYCbCr(src[ 5], src[ 7]));\n\
float dist_06_00 = DistYCbCr(src[19], src[ 5]) + DistYCbCr(src[ 5], src[ 3]) + DistYCbCr(src[21], src[ 7]) + DistYCbCr(src[ 7], src[ 1]) + (4.0 * DistYCbCr(src[ 6], src[ 0]));\n\
bool dominantGradient = (DOMINANT_DIRECTION_THRESHOLD * dist_05_07) < dist_06_00;\n\
blendResult[0] = ((dist_05_07 < dist_06_00) && (v[0] != v[5]) && (v[0] != v[7])) ? ((dominantGradient) ? BLEND_DOMINANT : BLEND_NORMAL) : BLEND_NONE;\n\
}\n\
\n\
vec3 dst[25];\n\
dst[ 0] = src[0];\n\
dst[ 1] = src[0];\n\
dst[ 2] = src[0];\n\
dst[ 3] = src[0];\n\
dst[ 4] = src[0];\n\
dst[ 5] = src[0];\n\
dst[ 6] = src[0];\n\
dst[ 7] = src[0];\n\
dst[ 8] = src[0];\n\
dst[ 9] = src[0];\n\
dst[10] = src[0];\n\
dst[11] = src[0];\n\
dst[12] = src[0];\n\
dst[13] = src[0];\n\
dst[14] = src[0];\n\
dst[15] = src[0];\n\
dst[16] = src[0];\n\
dst[17] = src[0];\n\
dst[18] = src[0];\n\
dst[19] = src[0];\n\
dst[20] = src[0];\n\
dst[21] = src[0];\n\
dst[22] = src[0];\n\
dst[23] = src[0];\n\
dst[24] = src[0];\n\
\n\
// Scale pixel\n\
if (IsBlendingNeeded(blendResult))\n\
{\n\
float dist_01_04 = DistYCbCr(src[1], src[4]);\n\
float dist_03_08 = DistYCbCr(src[3], src[8]);\n\
bool haveShallowLine = (STEEP_DIRECTION_THRESHOLD * dist_01_04 <= dist_03_08) && (v[0] != v[4]) && (v[5] != v[4]);\n\
bool haveSteepLine = (STEEP_DIRECTION_THRESHOLD * dist_03_08 <= dist_01_04) && (v[0] != v[8]) && (v[7] != v[8]);\n\
bool needBlend = (blendResult[2] != BLEND_NONE);\n\
bool doLineBlend = ( blendResult[2] >= BLEND_DOMINANT ||\n\
!((blendResult[1] != BLEND_NONE && !IsPixEqual(src[0], src[4])) ||\n\
(blendResult[3] != BLEND_NONE && !IsPixEqual(src[0], src[8])) ||\n\
(IsPixEqual(src[4], src[3]) && IsPixEqual(src[3], src[2]) && IsPixEqual(src[2], src[1]) && IsPixEqual(src[1], src[8]) && !IsPixEqual(src[0], src[2])) ) );\n\
\n\
vec3 blendPix = ( DistYCbCr(src[0], src[1]) <= DistYCbCr(src[0], src[3]) ) ? src[1] : src[3];\n\
dst[ 1] = mix(dst[ 1], blendPix, (needBlend && doLineBlend && haveSteepLine) ? 0.250 : 0.000);\n\
dst[ 2] = mix(dst[ 2], blendPix, (needBlend && doLineBlend) ? ((haveShallowLine) ? ((haveSteepLine) ? 2.0/3.0 : 0.750) : ((haveSteepLine) ? 0.750 : 0.125)) : 0.000);\n\
dst[ 3] = mix(dst[ 3], blendPix, (needBlend && doLineBlend && haveShallowLine) ? 0.250 : 0.000);\n\
dst[ 9] = mix(dst[ 9], blendPix, (needBlend && doLineBlend) ? ((haveSteepLine) ? 0.750 : ((haveShallowLine) ? 0.000 : 0.125)) : 0.000);\n\
dst[10] = mix(dst[10], blendPix, (needBlend && doLineBlend) ? ((haveSteepLine) ? 1.000 : ((haveShallowLine) ? 0.250 : 0.000)) : 0.000);\n\
dst[11] = mix(dst[11], blendPix, (needBlend) ? ((doLineBlend) ? ((!haveShallowLine && !haveSteepLine) ? 0.875 : 1.000) : 0.2306749731) : 0.000);\n\
dst[12] = mix(dst[12], blendPix, (needBlend) ? ((doLineBlend) ? 1.000 : 0.8631434088) : 0.000);\n\
dst[13] = mix(dst[13], blendPix, (needBlend) ? ((doLineBlend) ? ((!haveShallowLine && !haveSteepLine) ? 0.875 : 1.000) : 0.2306749731) : 0.000);\n\
dst[14] = mix(dst[14], blendPix, (needBlend && doLineBlend) ? ((haveShallowLine) ? 1.000 : ((haveSteepLine) ? 0.250 : 0.125)) : 0.000);\n\
dst[15] = mix(dst[15], blendPix, (needBlend && doLineBlend && haveShallowLine) ? 0.750 : 0.000);\n\
dst[16] = mix(dst[16], blendPix, (needBlend && doLineBlend && haveShallowLine) ? 0.250 : 0.000);\n\
dst[24] = mix(dst[24], blendPix, (needBlend && doLineBlend && haveSteepLine) ? 0.250 : 0.000);\n\
\n\
\n\
dist_01_04 = DistYCbCr(src[7], src[2]);\n\
dist_03_08 = DistYCbCr(src[1], src[6]);\n\
haveShallowLine = (STEEP_DIRECTION_THRESHOLD * dist_01_04 <= dist_03_08) && (v[0] != v[2]) && (v[3] != v[2]);\n\
haveSteepLine = (STEEP_DIRECTION_THRESHOLD * dist_03_08 <= dist_01_04) && (v[0] != v[6]) && (v[5] != v[6]);\n\
needBlend = (blendResult[1] != BLEND_NONE);\n\
doLineBlend = ( blendResult[1] >= BLEND_DOMINANT ||\n\
!((blendResult[0] != BLEND_NONE && !IsPixEqual(src[0], src[2])) ||\n\
(blendResult[2] != BLEND_NONE && !IsPixEqual(src[0], src[6])) ||\n\
(IsPixEqual(src[2], src[1]) && IsPixEqual(src[1], src[8]) && IsPixEqual(src[8], src[7]) && IsPixEqual(src[7], src[6]) && !IsPixEqual(src[0], src[8])) ) );\n\
\n\
blendPix = ( DistYCbCr(src[0], src[7]) <= DistYCbCr(src[0], src[1]) ) ? src[7] : src[1];\n\
dst[ 7] = mix(dst[ 7], blendPix, (needBlend && doLineBlend && haveSteepLine) ? 0.250 : 0.000);\n\
dst[ 8] = mix(dst[ 8], blendPix, (needBlend && doLineBlend) ? ((haveShallowLine) ? ((haveSteepLine) ? 2.0/3.0 : 0.750) : ((haveSteepLine) ? 0.750 : 0.125)) : 0.000);\n\
dst[ 1] = mix(dst[ 1], blendPix, (needBlend && doLineBlend && haveShallowLine) ? 0.250 : 0.000);\n\
dst[21] = mix(dst[21], blendPix, (needBlend && doLineBlend) ? ((haveSteepLine) ? 0.750 : ((haveShallowLine) ? 0.000 : 0.125)) : 0.000);\n\
dst[22] = mix(dst[22], blendPix, (needBlend && doLineBlend) ? ((haveSteepLine) ? 1.000 : ((haveShallowLine) ? 0.250 : 0.000)) : 0.000);\n\
dst[23] = mix(dst[23], blendPix, (needBlend) ? ((doLineBlend) ? ((!haveShallowLine && !haveSteepLine) ? 0.875 : 1.000) : 0.2306749731) : 0.000);\n\
dst[24] = mix(dst[24], blendPix, (needBlend) ? ((doLineBlend) ? 1.000 : 0.8631434088) : 0.000);\n\
dst[ 9] = mix(dst[ 9], blendPix, (needBlend) ? ((doLineBlend) ? ((!haveShallowLine && !haveSteepLine) ? 0.875 : 1.000) : 0.2306749731) : 0.000);\n\
dst[10] = mix(dst[10], blendPix, (needBlend && doLineBlend) ? ((haveShallowLine) ? 1.000 : ((haveSteepLine) ? 0.250 : 0.125)) : 0.000);\n\
dst[11] = mix(dst[11], blendPix, (needBlend && doLineBlend && haveShallowLine) ? 0.750 : 0.000);\n\
dst[12] = mix(dst[12], blendPix, (needBlend && doLineBlend && haveShallowLine) ? 0.250 : 0.000);\n\
dst[20] = mix(dst[20], blendPix, (needBlend && doLineBlend && haveSteepLine) ? 0.250 : 0.000);\n\
\n\
\n\
dist_01_04 = DistYCbCr(src[5], src[8]);\n\
dist_03_08 = DistYCbCr(src[7], src[4]);\n\
haveShallowLine = (STEEP_DIRECTION_THRESHOLD * dist_01_04 <= dist_03_08) && (v[0] != v[8]) && (v[1] != v[8]);\n\
haveSteepLine = (STEEP_DIRECTION_THRESHOLD * dist_03_08 <= dist_01_04) && (v[0] != v[4]) && (v[3] != v[4]);\n\
needBlend = (blendResult[0] != BLEND_NONE);\n\
doLineBlend = ( blendResult[0] >= BLEND_DOMINANT ||\n\
!((blendResult[3] != BLEND_NONE && !IsPixEqual(src[0], src[8])) ||\n\
(blendResult[1] != BLEND_NONE && !IsPixEqual(src[0], src[4])) ||\n\
(IsPixEqual(src[8], src[7]) && IsPixEqual(src[7], src[6]) && IsPixEqual(src[6], src[5]) && IsPixEqual(src[5], src[4]) && !IsPixEqual(src[0], src[6])) ) );\n\
\n\
blendPix = ( DistYCbCr(src[0], src[5]) <= DistYCbCr(src[0], src[7]) ) ? src[5] : src[7];\n\
dst[ 5] = mix(dst[ 5], blendPix, (needBlend && doLineBlend && haveSteepLine) ? 0.250 : 0.000);\n\
dst[ 6] = mix(dst[ 6], blendPix, (needBlend && doLineBlend) ? ((haveShallowLine) ? ((haveSteepLine) ? 2.0/3.0 : 0.750) : ((haveSteepLine) ? 0.750 : 0.125)) : 0.000);\n\
dst[ 7] = mix(dst[ 7], blendPix, (needBlend && doLineBlend && haveShallowLine) ? 0.250 : 0.000);\n\
dst[17] = mix(dst[17], blendPix, (needBlend && doLineBlend) ? ((haveSteepLine) ? 0.750 : ((haveShallowLine) ? 0.000 : 0.125)) : 0.000);\n\
dst[18] = mix(dst[18], blendPix, (needBlend && doLineBlend) ? ((haveSteepLine) ? 1.000 : ((haveShallowLine) ? 0.250 : 0.000)) : 0.000);\n\
dst[19] = mix(dst[19], blendPix, (needBlend) ? ((doLineBlend) ? ((!haveShallowLine && !haveSteepLine) ? 0.875 : 1.000) : 0.2306749731) : 0.000);\n\
dst[20] = mix(dst[20], blendPix, (needBlend) ? ((doLineBlend) ? 1.000 : 0.8631434088) : 0.000);\n\
dst[21] = mix(dst[21], blendPix, (needBlend) ? ((doLineBlend) ? ((!haveShallowLine && !haveSteepLine) ? 0.875 : 1.000) : 0.2306749731) : 0.000);\n\
dst[22] = mix(dst[22], blendPix, (needBlend && doLineBlend) ? ((haveShallowLine) ? 1.000 : ((haveSteepLine) ? 0.250 : 0.125)) : 0.000);\n\
dst[23] = mix(dst[23], blendPix, (needBlend && doLineBlend && haveShallowLine) ? 0.750 : 0.000);\n\
dst[24] = mix(dst[24], blendPix, (needBlend && doLineBlend && haveShallowLine) ? 0.250 : 0.000);\n\
dst[16] = mix(dst[16], blendPix, (needBlend && doLineBlend && haveSteepLine) ? 0.250 : 0.000);\n\
\n\
\n\
dist_01_04 = DistYCbCr(src[3], src[6]);\n\
dist_03_08 = DistYCbCr(src[5], src[2]);\n\
haveShallowLine = (STEEP_DIRECTION_THRESHOLD * dist_01_04 <= dist_03_08) && (v[0] != v[6]) && (v[7] != v[6]);\n\
haveSteepLine = (STEEP_DIRECTION_THRESHOLD * dist_03_08 <= dist_01_04) && (v[0] != v[2]) && (v[1] != v[2]);\n\
needBlend = (blendResult[3] != BLEND_NONE);\n\
doLineBlend = ( blendResult[3] >= BLEND_DOMINANT ||\n\
!((blendResult[2] != BLEND_NONE && !IsPixEqual(src[0], src[6])) ||\n\
(blendResult[0] != BLEND_NONE && !IsPixEqual(src[0], src[2])) ||\n\
(IsPixEqual(src[6], src[5]) && IsPixEqual(src[5], src[4]) && IsPixEqual(src[4], src[3]) && IsPixEqual(src[3], src[2]) && !IsPixEqual(src[0], src[4])) ) );\n\
\n\
blendPix = ( DistYCbCr(src[0], src[3]) <= DistYCbCr(src[0], src[5]) ) ? src[3] : src[5];\n\
dst[ 3] = mix(dst[ 3], blendPix, (needBlend && doLineBlend && haveSteepLine) ? 0.250 : 0.000);\n\
dst[ 4] = mix(dst[ 4], blendPix, (needBlend && doLineBlend) ? ((haveShallowLine) ? ((haveSteepLine) ? 2.0/3.0 : 0.750) : ((haveSteepLine) ? 0.750 : 0.125)) : 0.000);\n\
dst[ 5] = mix(dst[ 5], blendPix, (needBlend && doLineBlend && haveShallowLine) ? 0.250 : 0.000);\n\
dst[13] = mix(dst[13], blendPix, (needBlend && doLineBlend) ? ((haveSteepLine) ? 0.750 : ((haveShallowLine) ? 0.000 : 0.125)) : 0.000);\n\
dst[14] = mix(dst[14], blendPix, (needBlend && doLineBlend) ? ((haveSteepLine) ? 1.000 : ((haveShallowLine) ? 0.250 : 0.000)) : 0.000);\n\
dst[15] = mix(dst[15], blendPix, (needBlend) ? ((doLineBlend) ? ((!haveShallowLine && !haveSteepLine) ? 0.875 : 1.000) : 0.2306749731) : 0.000);\n\
dst[16] = mix(dst[16], blendPix, (needBlend) ? ((doLineBlend) ? 1.000 : 0.8631434088) : 0.000);\n\
dst[17] = mix(dst[17], blendPix, (needBlend) ? ((doLineBlend) ? ((!haveShallowLine && !haveSteepLine) ? 0.875 : 1.000) : 0.2306749731) : 0.000);\n\
dst[18] = mix(dst[18], blendPix, (needBlend && doLineBlend) ? ((haveShallowLine) ? 1.000 : ((haveSteepLine) ? 0.250 : 0.125)) : 0.000);\n\
dst[19] = mix(dst[19], blendPix, (needBlend && doLineBlend && haveShallowLine) ? 0.750 : 0.000);\n\
dst[20] = mix(dst[20], blendPix, (needBlend && doLineBlend && haveShallowLine) ? 0.250 : 0.000);\n\
dst[12] = mix(dst[12], blendPix, (needBlend && doLineBlend && haveSteepLine) ? 0.250 : 0.000);\n\
}\n\
\n\
vec2 f = fract(texCoord[0]);\n\
OUT_FRAG_COLOR.rgb = mix( mix( dst[20], mix( mix(dst[21], dst[22], step(0.40, f.x)), mix(dst[23], dst[24], step(0.80, f.x)), step(0.60, f.x)), step(0.20, f.x) ),\n\
mix ( mix( mix( dst[19], mix( mix(dst[ 6], dst[ 7], step(0.40, f.x)), mix(dst[ 8], dst[ 9], step(0.80, f.x)), step(0.60, f.x)), step(0.20, f.x) ),\n\
mix( dst[18], mix( mix(dst[ 5], dst[ 0], step(0.40, f.x)), mix(dst[ 1], dst[10], step(0.80, f.x)), step(0.60, f.x)), step(0.20, f.x) ), step(0.40, f.y)),\n\
mix( mix( dst[17], mix( mix(dst[ 4], dst[ 3], step(0.40, f.x)), mix(dst[ 2], dst[11], step(0.80, f.x)), step(0.60, f.x)), step(0.20, f.x) ),\n\
mix( dst[16], mix( mix(dst[15], dst[14], step(0.40, f.x)), mix(dst[13], dst[12], step(0.80, f.x)), step(0.60, f.x)), step(0.20, f.x) ), step(0.80, f.y)),\n\
step(0.60, f.y)),\n\
step(0.20, f.y));\n\
OUT_FRAG_COLOR.a = 1.0;\n\
}\n\
"};
enum OGLVertexAttributeID
{
OGLVertexAttributeID_Position = 0,
OGLVertexAttributeID_TexCoord0 = 8
};
typedef struct
{
uint8_t p0;
uint8_t p1;
uint8_t p2;
uint8_t w0;
uint8_t w1;
uint8_t w2;
} LUTValues;
static LUTValues *_LQ2xLUT = NULL;
static LUTValues *_HQ2xLUT = NULL;
static LUTValues *_HQ4xLUT = NULL;
static const GLint filterVtxBuffer[8] = {-1, -1, 1, -1, 1, 1, -1, 1};
static const GLubyte filterElementBuffer[6] = {0, 1, 2, 2, 3, 0};
static const GLubyte outputElementBuffer[12] = {0, 1, 2, 2, 3, 0, 4, 5, 6, 6, 7, 4};
void GetGLVersionOGL(GLint *outMajor, GLint *outMinor, GLint *outRevision)
{
const char *oglVersionString = (const char *)glGetString(GL_VERSION);
if (oglVersionString == NULL)
{
return;
}
size_t versionStringLength = 0;
// First, check for the dot in the revision string. There should be at
// least one present.
const char *versionStrEnd = strstr(oglVersionString, ".");
if (versionStrEnd == NULL)
{
return;
}
// Next, check for the space before the vendor-specific info (if present).
versionStrEnd = strstr(oglVersionString, " ");
if (versionStrEnd == NULL)
{
// If a space was not found, then the vendor-specific info is not present,
// and therefore the entire string must be the version number.
versionStringLength = strlen(oglVersionString);
}
else
{
// If a space was found, then the vendor-specific info is present,
// and therefore the version number is everything before the space.
versionStringLength = versionStrEnd - oglVersionString;
}
// Copy the version substring and parse it.
char *versionSubstring = (char *)malloc(versionStringLength * sizeof(char));
strncpy(versionSubstring, oglVersionString, versionStringLength);
unsigned int major = 0;
unsigned int minor = 0;
unsigned int revision = 0;
sscanf(versionSubstring, "%u.%u.%u", &major, &minor, &revision);
free(versionSubstring);
versionSubstring = NULL;
if (outMajor != NULL)
{
*outMajor = major;
}
if (outMinor != NULL)
{
*outMinor = minor;
}
if (outRevision != NULL)
{
*outRevision = revision;
}
}
OGLInfo* OGLInfoCreate_Legacy()
{
return new OGLInfo_Legacy;
}
void glBindVertexArray_LegacyAPPLE(GLuint vaoID)
{
glBindVertexArrayAPPLE(vaoID);
}
void glDeleteVertexArrays_LegacyAPPLE(GLsizei n, const GLuint *vaoIDs)
{
glDeleteVertexArraysAPPLE(n, vaoIDs);
}
void glGenVertexArrays_LegacyAPPLE(GLsizei n, GLuint *vaoIDs)
{
glGenVertexArraysAPPLE(n, vaoIDs);
}
OGLInfo* (*OGLInfoCreate_Func)() = &OGLInfoCreate_Legacy;
void (*glBindVertexArrayDESMUME)(GLuint id) = &glBindVertexArray_LegacyAPPLE;
void (*glDeleteVertexArraysDESMUME)(GLsizei n, const GLuint *ids) = &glDeleteVertexArrays_LegacyAPPLE;
void (*glGenVertexArraysDESMUME)(GLsizei n, GLuint *ids) = &glGenVertexArrays_LegacyAPPLE;
static LUTValues PackLUTValues(const uint8_t p0, const uint8_t p1, const uint8_t p2, const uint8_t w0, const uint8_t w1, const uint8_t w2)
{
const uint8_t wR = 256 / (w0 + w1 + w2);
return (LUTValues) {
p0*31,
p1*31,
p2*31,
(w1 == 0 && w2 == 0) ? 255 : w0*wR,
w1*wR,
w2*wR
};
}
static void InitHQnxLUTs()
{
static bool lutValuesInited = false;
if (lutValuesInited)
{
return;
}
_LQ2xLUT = (LUTValues *)malloc(256*(2*2)*16 * sizeof(LUTValues));
_HQ2xLUT = (LUTValues *)malloc(256*(2*2)*16 * sizeof(LUTValues));
_HQ4xLUT = (LUTValues *)malloc(256*(4*4)*16 * sizeof(LUTValues) + 4); // The bytes fix a mysterious crash that intermittently occurs. Don't know why this works... it just does.
#define MUR (compare & 0x01) // top-right
#define MDR (compare & 0x02) // bottom-right
#define MDL (compare & 0x04) // bottom-left
#define MUL (compare & 0x08) // top-left
#define IC(p0) PackLUTValues(p0, p0, p0, 1, 0, 0)
#define I11(p0,p1) PackLUTValues(p0, p1, p0, 1, 1, 0)
#define I211(p0,p1,p2) PackLUTValues(p0, p1, p2, 2, 1, 1)
#define I31(p0,p1) PackLUTValues(p0, p1, p0, 3, 1, 0)
#define I332(p0,p1,p2) PackLUTValues(p0, p1, p2, 3, 3, 2)
#define I431(p0,p1,p2) PackLUTValues(p0, p1, p2, 4, 3, 1)
#define I521(p0,p1,p2) PackLUTValues(p0, p1, p2, 5, 2, 1)
#define I53(p0,p1) PackLUTValues(p0, p1, p0, 5, 3, 0)
#define I611(p0,p1,p2) PackLUTValues(p0, p1, p2, 6, 1, 1)
#define I71(p0,p1) PackLUTValues(p0, p1, p0, 7, 1, 0)
#define I772(p0,p1,p2) PackLUTValues(p0, p1, p2, 7, 7, 2)
#define I97(p0,p1) PackLUTValues(p0, p1, p0, 9, 7, 0)
#define I1411(p0,p1,p2) PackLUTValues(p0, p1, p2, 14, 1, 1)
#define I151(p0,p1) PackLUTValues(p0, p1, p0, 15, 1, 0)
#define P0 _LQ2xLUT[pattern+(256*0)+(1024*compare)]
#define P1 _LQ2xLUT[pattern+(256*1)+(1024*compare)]
#define P2 _LQ2xLUT[pattern+(256*2)+(1024*compare)]
#define P3 _LQ2xLUT[pattern+(256*3)+(1024*compare)]
for (size_t compare = 0; compare < 16; compare++)
{
for (size_t pattern = 0; pattern < 256; pattern++)
{
switch (pattern)
{
#include "../filter/lq2x.h"
}
}
}
#undef P0
#undef P1
#undef P2
#undef P3
#define P0 _HQ2xLUT[pattern+(256*0)+(1024*compare)]
#define P1 _HQ2xLUT[pattern+(256*1)+(1024*compare)]
#define P2 _HQ2xLUT[pattern+(256*2)+(1024*compare)]
#define P3 _HQ2xLUT[pattern+(256*3)+(1024*compare)]
for (size_t compare = 0; compare < 16; compare++)
{
for (size_t pattern = 0; pattern < 256; pattern++)
{
switch (pattern)
{
#include "../filter/hq2x.h"
}
}
}
#undef P0
#undef P1
#undef P2
#undef P3
#define P(a, b) _HQ4xLUT[pattern+(256*((b*4)+a))+(4096*compare)]
#define I1(p0) PackLUTValues(p0, p0, p0, 1, 0, 0)
#define I2(i0, i1, p0, p1) PackLUTValues(p0, p1, p0, i0, i1, 0)
#define I3(i0, i1, i2, p0, p1, p2) PackLUTValues(p0, p1, p2, i0, i1, i2)
for (size_t compare = 0; compare < 16; compare++)
{
for (size_t pattern = 0; pattern < 256; pattern++)
{
switch (pattern)
{
#include "../filter/hq4x.dat"
}
}
}
#undef P
#undef I1
#undef I2
#undef I3
#undef MUR
#undef MDR
#undef MDL
#undef MUL
#undef IC
#undef I11
#undef I211
#undef I31
#undef I332
#undef I431
#undef I521
#undef I53
#undef I611
#undef I71
#undef I772
#undef I97
#undef I1411
#undef I151
lutValuesInited = true;
}
#pragma mark -
OGLInfo::OGLInfo()
{
GetGLVersionOGL(&_versionMajor, &_versionMinor, &_versionRevision);
_shaderSupport = ShaderSupport_Unsupported;
_useShader150 = false;
_isVBOSupported = false;
_isPBOSupported = false;
_isFBOSupported = false;
}
ShaderSupportTier OGLInfo::GetShaderSupport()
{
return this->_shaderSupport;
}
bool OGLInfo::IsUsingShader150()
{
return this->_useShader150;
}
bool OGLInfo::IsVBOSupported()
{
return this->_isVBOSupported;
}
bool OGLInfo::IsPBOSupported()
{
return this->_isPBOSupported;
}
bool OGLInfo::IsShaderSupported()
{
return (this->_shaderSupport != ShaderSupport_Unsupported);
}
bool OGLInfo::IsFBOSupported()
{
return this->_isFBOSupported;
}
OGLInfo_Legacy::OGLInfo_Legacy()
{
_shaderSupport = ShaderSupport_Unsupported;
_useShader150 = false;
// Check the OpenGL capabilities for this renderer
std::set<std::string> oglExtensionSet;
this->GetExtensionSetOGL(&oglExtensionSet);
_isVBOSupported = this->IsExtensionPresent(oglExtensionSet, "GL_ARB_vertex_buffer_object");
bool isShaderSupported = this->IsExtensionPresent(oglExtensionSet, "GL_ARB_shader_objects") &&
this->IsExtensionPresent(oglExtensionSet, "GL_ARB_vertex_shader") &&
this->IsExtensionPresent(oglExtensionSet, "GL_ARB_fragment_shader") &&
this->IsExtensionPresent(oglExtensionSet, "GL_ARB_vertex_program");
if (isShaderSupported)
{
if ( _versionMajor < 3 ||
(_versionMajor == 3 && _versionMinor < 2) )
{
if (_versionMajor < 2)
{
_shaderSupport = ShaderSupport_Unsupported;
}
else
{
GLint maxVaryingFloats = 0;
glGetIntegerv(GL_MAX_VARYING_FLOATS_ARB, &maxVaryingFloats);
if (_versionMajor == 2 && _versionMinor == 0)
{
if (maxVaryingFloats < 32)
{
_shaderSupport = ShaderSupport_BottomTier;
}
else
{
_shaderSupport = ShaderSupport_LowTier;
}
}
else
{
if (maxVaryingFloats < 32)
{
_shaderSupport = ShaderSupport_BottomTier;
}
else if (maxVaryingFloats < 60)
{
_shaderSupport = ShaderSupport_LowTier;
}
else if (maxVaryingFloats < 84)
{
_shaderSupport = ShaderSupport_MidTier;
}
else if (maxVaryingFloats < 108)
{
_shaderSupport = ShaderSupport_HighTier;
}
else if (maxVaryingFloats >= 108)
{
_shaderSupport = ShaderSupport_TopTier;
}
}
}
}
else
{
_useShader150 = true;
_shaderSupport = ShaderSupport_MidTier;
if (_versionMajor == 4)
{
if (_versionMinor <= 1)
{
_shaderSupport = ShaderSupport_HighTier;
}
else
{
_shaderSupport = ShaderSupport_TopTier;
}
}
}
}
_isPBOSupported = this->IsExtensionPresent(oglExtensionSet, "GL_ARB_vertex_buffer_object") &&
(this->IsExtensionPresent(oglExtensionSet, "GL_ARB_pixel_buffer_object") ||
this->IsExtensionPresent(oglExtensionSet, "GL_EXT_pixel_buffer_object"));
_isFBOSupported = this->IsExtensionPresent(oglExtensionSet, "GL_EXT_framebuffer_object");
}
void OGLInfo_Legacy::GetExtensionSetOGL(std::set<std::string> *oglExtensionSet)
{
std::string oglExtensionString = std::string((const char *)glGetString(GL_EXTENSIONS));
size_t extStringStartLoc = 0;
size_t delimiterLoc = oglExtensionString.find_first_of(' ', extStringStartLoc);
while (delimiterLoc != std::string::npos)
{
std::string extensionName = oglExtensionString.substr(extStringStartLoc, delimiterLoc - extStringStartLoc);
oglExtensionSet->insert(extensionName);
extStringStartLoc = delimiterLoc + 1;
delimiterLoc = oglExtensionString.find_first_of(' ', extStringStartLoc);
}
if (extStringStartLoc - oglExtensionString.length() > 0)
{
std::string extensionName = oglExtensionString.substr(extStringStartLoc, oglExtensionString.length() - extStringStartLoc);
oglExtensionSet->insert(extensionName);
}
}
bool OGLInfo_Legacy::IsExtensionPresent(const std::set<std::string> &oglExtensionSet, const std::string &extensionName) const
{
if (oglExtensionSet.size() == 0)
{
return false;
}
return (oglExtensionSet.find(extensionName) != oglExtensionSet.end());
}
#pragma mark -
OGLShaderProgram::OGLShaderProgram()
{
_vertexID = 0;
_fragmentID = 0;
_programID = glCreateProgram();
if (_programID == 0)
{
printf("OpenGL Error - Failed to create shader program.\n");
}
}
OGLShaderProgram::~OGLShaderProgram()
{
glDetachShader(this->_programID, this->_vertexID);
glDetachShader(this->_programID, this->_fragmentID);
glDeleteProgram(this->_programID);
glDeleteShader(this->_vertexID);
glDeleteShader(this->_fragmentID);
}
GLuint OGLShaderProgram::LoadShaderOGL(GLenum shaderType, const char *shaderProgram, bool useShader150)
{
GLint shaderStatus = GL_TRUE;
GLuint shaderID = glCreateShader(shaderType);
if (shaderID == 0)
{
printf("OpenGL Error - Failed to create %s.\n",
(shaderType == GL_VERTEX_SHADER) ? "GL_VERTEX_SHADER" : ((shaderType == GL_FRAGMENT_SHADER) ? "GL_FRAGMENT_SHADER" : "OTHER SHADER TYPE"));
return shaderID;
}
std::string shaderSupportStr;
// Convert _shaderSupport to std::string.
switch (_shaderSupport)
{
case ShaderSupport_BottomTier:
shaderSupportStr = "SHADERSUPPORT_BOTTOM_TIER";
break;
case ShaderSupport_LowTier:
shaderSupportStr = "SHADERSUPPORT_LOW_TIER";
break;
case ShaderSupport_MidTier:
shaderSupportStr = "SHADERSUPPORT_MID_TIER";
break;
case ShaderSupport_HighTier:
shaderSupportStr = "SHADERSUPPORT_HIGH_TIER";
break;
case ShaderSupport_TopTier:
shaderSupportStr = "SHADERSUPPORT_TOP_TIER";
break;
case ShaderSupport_FutureTier:
shaderSupportStr = "SHADERSUPPORT_FUTURE_TIER";
break;
default:
shaderSupportStr = "SHADERSUPPORT_UNSUPPORTED";
break;
}
std::string programSource;
if (useShader150)
{
programSource += "#version 150\n";
if (shaderType == GL_VERTEX_SHADER)
{
programSource += "#define ATTRIBUTE in\n";
programSource += "#define VARYING out\n";
}
else if (shaderType == GL_FRAGMENT_SHADER)
{
programSource += "#define VARYING in\n";
programSource += "#define SAMPLE3_TEX_RECT(t,c) texture(t,c).rgb\n";
programSource += "#define SAMPLE3_TEX_1D(t,c) texture(t,c).rgb\n";
programSource += "#define SAMPLE3_TEX_2D(t,c) texture(t,c).rgb\n";
programSource += "#define SAMPLE3_TEX_3D(t,c) texture(t,c).rgb\n";
programSource += "#define SAMPLE4_TEX_1D(t,c) texture(t,c)\n";
programSource += "#define SAMPLE4_TEX_2D(t,c) texture(t,c)\n";
programSource += "#define SAMPLE4_TEX_3D(t,c) texture(t,c)\n";
programSource += "#define OUT_FRAG_COLOR outFragColor\n\n\n";
programSource += "out vec4 outFragColor;\n\n";
}
}
else
{
programSource += "#version 110\n";
if (shaderType == GL_VERTEX_SHADER)
{
programSource += "#define ATTRIBUTE attribute\n";
programSource += "#define VARYING varying\n\n";
}
else if (shaderType == GL_FRAGMENT_SHADER)
{
programSource += "#extension GL_ARB_texture_rectangle : require\n";
programSource += "#define VARYING varying\n";
programSource += "#define SAMPLE3_TEX_RECT(t,c) texture2DRect(t,c).rgb\n";
programSource += "#define SAMPLE3_TEX_1D(t,c) texture1D(t,c).rgb\n";
programSource += "#define SAMPLE3_TEX_2D(t,c) texture2D(t,c).rgb\n";
programSource += "#define SAMPLE3_TEX_3D(t,c) texture3D(t,c).rgb\n";
programSource += "#define SAMPLE4_TEX_1D(t,c) texture1D(t,c)\n";
programSource += "#define SAMPLE4_TEX_2D(t,c) texture2D(t,c)\n";
programSource += "#define SAMPLE4_TEX_3D(t,c) texture3D(t,c)\n";
programSource += "#define OUT_FRAG_COLOR gl_FragColor\n\n";
}
}
programSource += "#define SHADERSUPPORT_UNSUPPORTED 0\n";
programSource += "#define SHADERSUPPORT_BOTTOM_TIER 1\n";
programSource += "#define SHADERSUPPORT_LOW_TIER 2\n";
programSource += "#define SHADERSUPPORT_MID_TIER 3\n";
programSource += "#define SHADERSUPPORT_HIGH_TIER 4\n";
programSource += "#define SHADERSUPPORT_TOP_TIER 5\n";
programSource += "#define SHADERSUPPORT_FUTURE_TIER 6\n";
programSource += "#define GPU_TIER " + shaderSupportStr + "\n\n";
programSource += shaderProgram;
const char *programSourceChar = programSource.c_str();
glShaderSource(shaderID, 1, (const GLchar **)&programSourceChar, NULL);
glCompileShader(shaderID);
glGetShaderiv(shaderID, GL_COMPILE_STATUS, &shaderStatus);
if (shaderStatus == GL_FALSE)
{
static const size_t logBytes = 16384; // 16KB should be more than enough
GLchar *logBuf = (GLchar *)calloc(logBytes, sizeof(GLchar));
GLsizei logSize = 0;
glGetShaderInfoLog(shaderID, logBytes * sizeof(GLchar), &logSize, logBuf);
printf("OpenGL Error - Failed to compile %s.\n%s\n",
(shaderType == GL_VERTEX_SHADER) ? "GL_VERTEX_SHADER" : ((shaderType == GL_FRAGMENT_SHADER) ? "GL_FRAGMENT_SHADER" : "OTHER SHADER TYPE"),
(char *)logBuf);
glDeleteShader(shaderID);
return shaderID;
}
return shaderID;
}
ShaderSupportTier OGLShaderProgram::GetShaderSupport()
{
return this->_shaderSupport;
}
void OGLShaderProgram::SetShaderSupport(const ShaderSupportTier theTier)
{
this->_shaderSupport = theTier;
}
GLuint OGLShaderProgram::GetVertexShaderID()
{
return this->_vertexID;
}
void OGLShaderProgram::SetVertexShaderOGL(const char *shaderProgram, bool useShader150)
{
if (this->_vertexID != 0)
{
glDetachShader(this->_programID, this->_vertexID);
glDeleteShader(this->_vertexID);
}
this->_vertexID = this->LoadShaderOGL(GL_VERTEX_SHADER, shaderProgram, useShader150);
if (this->_vertexID != 0)
{
glAttachShader(this->_programID, this->_vertexID);
glBindAttribLocation(this->_programID, OGLVertexAttributeID_Position, "inPosition");
glBindAttribLocation(this->_programID, OGLVertexAttributeID_TexCoord0, "inTexCoord0");
}
if (this->_vertexID != 0 && this->_fragmentID != 0)
{
this->LinkOGL();
}
}
GLuint OGLShaderProgram::GetFragmentShaderID()
{
return this->_fragmentID;
}
void OGLShaderProgram::SetFragmentShaderOGL(const char *shaderProgram, bool useShader150)
{
if (this->_fragmentID != 0)
{
glDetachShader(this->_programID, this->_fragmentID);
glDeleteShader(this->_fragmentID);
}
this->_fragmentID = this->LoadShaderOGL(GL_FRAGMENT_SHADER, shaderProgram, useShader150);
if (this->_fragmentID != 0)
{
glAttachShader(this->_programID, this->_fragmentID);
if (useShader150)
{
glBindFragDataLocationEXT(this->_programID, 0, "outFragColor");
}
}
if (this->_vertexID != 0 && this->_fragmentID != 0)
{
this->LinkOGL();
}
}
void OGLShaderProgram::SetVertexAndFragmentShaderOGL(const char *vertShaderProgram, const char *fragShaderProgram, bool useShader150)
{
if (this->_vertexID != 0)
{
glDetachShader(this->_programID, this->_vertexID);
glDeleteShader(this->_vertexID);
}
if (this->_fragmentID != 0)
{
glDetachShader(this->_programID, this->_fragmentID);
glDeleteShader(this->_fragmentID);
}
this->_vertexID = this->LoadShaderOGL(GL_VERTEX_SHADER, vertShaderProgram, useShader150);
this->_fragmentID = this->LoadShaderOGL(GL_FRAGMENT_SHADER, fragShaderProgram, useShader150);
if (this->_vertexID != 0)
{
glAttachShader(this->_programID, this->_vertexID);
glBindAttribLocation(this->_programID, OGLVertexAttributeID_Position, "inPosition");
glBindAttribLocation(this->_programID, OGLVertexAttributeID_TexCoord0, "inTexCoord0");
}
if (this->_fragmentID != 0)
{
glAttachShader(this->_programID, this->_fragmentID);
if (useShader150)
{
glBindFragDataLocationEXT(this->_programID, 0, "outFragColor");
}
}
if (this->_vertexID != 0 && this->_fragmentID != 0)
{
this->LinkOGL();
}
}
GLuint OGLShaderProgram::GetProgramID()
{
return this->_programID;
}
bool OGLShaderProgram::LinkOGL()
{
bool result = false;
GLint shaderStatus = GL_FALSE;
glLinkProgram(this->_programID);
glGetProgramiv(this->_programID, GL_LINK_STATUS, &shaderStatus);
if (shaderStatus == GL_FALSE)
{
printf("OpenGL Error - Failed to link shader program.\n");
return result;
}
glValidateProgram(this->_programID);
result = true;
return result;
}
#pragma mark -
OGLVideoOutput::OGLVideoOutput()
{
_info = OGLInfoCreate_Func();
_layerList = new std::vector<OGLVideoLayer *>;
_layerList->reserve(8);
// Render State Setup (common to both shaders and fixed-function pipeline)
glDisable(GL_BLEND);
glDisable(GL_DEPTH_TEST);
glDisable(GL_DITHER);
glDisable(GL_STENCIL_TEST);
// Set up fixed-function pipeline render states.
if (!this->_info->IsShaderSupported())
{
glDisable(GL_ALPHA_TEST);
glDisable(GL_LIGHTING);
glDisable(GL_FOG);
glEnable(GL_TEXTURE_RECTANGLE_ARB);
}
// Set up clear attributes
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
}
OGLVideoOutput::~OGLVideoOutput()
{
for (size_t i = 0; i < _layerList->size(); i++)
{
delete (*_layerList)[i];
}
delete _layerList;
delete _info;
}
void OGLVideoOutput::InitLayers()
{
for (size_t i = 0; i < _layerList->size(); i++)
{
delete (*_layerList)[i];
}
this->_layerList->clear();
this->_layerList->push_back(new OGLDisplayLayer(this));
}
OGLInfo* OGLVideoOutput::GetInfo()
{
return this->_info;
}
GLsizei OGLVideoOutput::GetViewportWidth()
{
return this->_viewportWidth;
}
GLsizei OGLVideoOutput::GetViewportHeight()
{
return this->_viewportHeight;
}
OGLDisplayLayer* OGLVideoOutput::GetDisplayLayer()
{
return (OGLDisplayLayer *)this->_layerList->at(0);
}
void OGLVideoOutput::SetViewportSizeOGL(GLsizei w, GLsizei h)
{
this->_viewportWidth = w;
this->_viewportHeight = h;
glViewport(0, 0, w, h);
for (size_t i = 0; i < _layerList->size(); i++)
{
(*_layerList)[i]->SetViewportSizeOGL(w, h);
}
}
void OGLVideoOutput::ProcessOGL()
{
for (size_t i = 0; i < _layerList->size(); i++)
{
(*_layerList)[i]->ProcessOGL();
}
}
void OGLVideoOutput::RenderOGL()
{
for (size_t i = 0; i < _layerList->size(); i++)
{
(*_layerList)[i]->RenderOGL();
}
}
#pragma mark -
OGLFilter::OGLFilter()
{
OGLFilterInit(1, 1, 1);
}
OGLFilter::OGLFilter(GLsizei srcWidth, GLsizei srcHeight, GLfloat scale = 1)
{
OGLFilterInit(srcWidth, srcHeight, scale);
}
OGLFilter::~OGLFilter()
{
if (_isVAOPresent)
{
glDeleteVertexArraysDESMUME(1, &this->_vaoID);
_isVAOPresent = false;
}
glDeleteFramebuffersEXT(1, &this->_fboID);
glDeleteTextures(1, &this->_texDstID);
glDeleteBuffers(1, &this->_vboVtxID);
glDeleteBuffers(1, &this->_vboTexCoordID);
glDeleteBuffers(1, &this->_vboElementID);
}
void OGLFilter::GetSupport(int vfTypeID, bool *outSupportCPU, bool *outSupportShader)
{
const char *cpuTypeIDString = VideoFilter::GetTypeStringByID((VideoFilterTypeID)vfTypeID);
*outSupportCPU = (strstr(cpuTypeIDString, VIDEOFILTERTYPE_UNKNOWN_STRING) == NULL);
*outSupportShader = (vfTypeID == VideoFilterTypeID_Nearest1_5X) ||
(vfTypeID == VideoFilterTypeID_Nearest2X) ||
(vfTypeID == VideoFilterTypeID_Scanline) ||
(vfTypeID == VideoFilterTypeID_EPX) ||
(vfTypeID == VideoFilterTypeID_EPXPlus) ||
(vfTypeID == VideoFilterTypeID_2xSaI) ||
(vfTypeID == VideoFilterTypeID_Super2xSaI) ||
(vfTypeID == VideoFilterTypeID_SuperEagle);
}
void OGLFilter::OGLFilterInit(GLsizei srcWidth, GLsizei srcHeight, GLfloat scale)
{
_program = new OGLShaderProgram;
_scale = scale;
_srcWidth = srcWidth;
_srcHeight = srcHeight;
_dstWidth = _srcWidth * _scale;
_dstHeight = _srcHeight * _scale;
_texCoordBuffer[0] = 0;
_texCoordBuffer[1] = 0;
_texCoordBuffer[2] = _srcWidth;
_texCoordBuffer[3] = 0;
_texCoordBuffer[4] = _srcWidth;
_texCoordBuffer[5] = _srcHeight;
_texCoordBuffer[6] = 0;
_texCoordBuffer[7] = _srcHeight;
glGenTextures(1, &_texDstID);
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, _texDstID);
glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA, _dstWidth, _dstHeight, 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL);
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);
glGenFramebuffersEXT(1, &_fboID);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, _fboID);
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_RECTANGLE_ARB, _texDstID, 0);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
glGenBuffers(1, &_vboVtxID);
glGenBuffers(1, &_vboTexCoordID);
glGenBuffers(1, &_vboElementID);
glBindBuffer(GL_ARRAY_BUFFER, _vboVtxID);
glBufferData(GL_ARRAY_BUFFER, sizeof(filterVtxBuffer), filterVtxBuffer, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, _vboTexCoordID);
glBufferData(GL_ARRAY_BUFFER, sizeof(_texCoordBuffer), _texCoordBuffer, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _vboElementID);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(filterElementBuffer), filterElementBuffer, GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glGenVertexArraysDESMUME(1, &_vaoID);
glBindVertexArrayDESMUME(_vaoID);
glBindBuffer(GL_ARRAY_BUFFER, _vboVtxID);
glVertexAttribPointer(OGLVertexAttributeID_Position, 2, GL_INT, GL_FALSE, 0, 0);
glBindBuffer(GL_ARRAY_BUFFER, _vboTexCoordID);
glVertexAttribPointer(OGLVertexAttributeID_TexCoord0, 2, GL_INT, GL_FALSE, 0, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _vboElementID);
glEnableVertexAttribArray(OGLVertexAttributeID_Position);
glEnableVertexAttribArray(OGLVertexAttributeID_TexCoord0);
glBindVertexArrayDESMUME(0);
_isVAOPresent = true;
}
OGLShaderProgram* OGLFilter::GetProgram()
{
return this->_program;
}
GLuint OGLFilter::GetDstTexID()
{
return this->_texDstID;
}
GLsizei OGLFilter::GetSrcWidth()
{
return this->_srcWidth;
}
GLsizei OGLFilter::GetSrcHeight()
{
return this->_srcHeight;
}
GLsizei OGLFilter::GetDstWidth()
{
return this->_dstWidth;
}
GLsizei OGLFilter::GetDstHeight()
{
return this->_dstHeight;
}
void OGLFilter::SetSrcSizeOGL(GLsizei w, GLsizei h)
{
this->_srcWidth = w;
this->_srcHeight = h;
this->_dstWidth = this->_srcWidth * this->_scale;
this->_dstHeight = this->_srcHeight * this->_scale;
this->_texCoordBuffer[2] = w;
this->_texCoordBuffer[4] = w;
this->_texCoordBuffer[5] = h;
this->_texCoordBuffer[7] = h;
glBindBuffer(GL_ARRAY_BUFFER, this->_vboTexCoordID);
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(this->_texCoordBuffer) , this->_texCoordBuffer);
glBindBuffer(GL_ARRAY_BUFFER, 0);
uint32_t *tempDstBuffer = (uint32_t *)calloc(this->_dstWidth * this->_dstHeight, sizeof(uint32_t));
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, this->_texDstID);
glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA, this->_dstWidth, this->_dstHeight, 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, tempDstBuffer);
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);
free(tempDstBuffer);
}
GLfloat OGLFilter::GetScale()
{
return this->_scale;
}
void OGLFilter::SetScaleOGL(GLfloat scale)
{
this->_scale = scale;
this->_dstWidth = this->_srcWidth * this->_scale;
this->_dstHeight = this->_srcHeight * this->_scale;
uint32_t *tempDstBuffer = (uint32_t *)calloc(this->_dstWidth * this->_dstHeight, sizeof(uint32_t));
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, this->_texDstID);
glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA, this->_dstWidth, this->_dstHeight, 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, tempDstBuffer);
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);
free(tempDstBuffer);
}
GLuint OGLFilter::RunFilterOGL(GLuint srcTexID)
{
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, this->_fboID);
glBindVertexArrayDESMUME(this->_vaoID);
glUseProgram(this->_program->GetProgramID());
glViewport(0, 0, this->_dstWidth, this->_dstHeight);
glClear(GL_COLOR_BUFFER_BIT);
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, srcTexID);
glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, 0);
glBindVertexArrayDESMUME(0);
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
return this->GetDstTexID();
}
void OGLFilter::DownloadDstBufferOGL(uint32_t *dstBuffer, size_t lineOffset, size_t readLineCount)
{
if (dstBuffer == NULL)
{
return;
}
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, this->_fboID);
glReadPixels(0, lineOffset, this->_dstWidth, readLineCount, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, dstBuffer);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
}
#pragma mark -
OGLFilterDeposterize::OGLFilterDeposterize(GLsizei srcWidth, GLsizei srcHeight, ShaderSupportTier theTier, bool useShader150)
{
SetSrcSizeOGL(srcWidth, srcHeight);
glGenTextures(1, &_texIntermediateID);
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, _texIntermediateID);
glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA, _dstWidth, _dstHeight, 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL);
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);
_program->SetShaderSupport(theTier);
_program->SetVertexShaderOGL(Sample3x3_VertShader_110, useShader150);
_program->SetFragmentShaderOGL(FilterDeposterizeFragShader_110, useShader150);
}
OGLFilterDeposterize::~OGLFilterDeposterize()
{
glDeleteTextures(1, &this->_texIntermediateID);
}
GLuint OGLFilterDeposterize::RunFilterOGL(GLuint srcTexID)
{
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, this->_fboID);
glBindVertexArrayDESMUME(this->_vaoID);
glUseProgram(this->_program->GetProgramID());
glViewport(0, 0, this->_dstWidth, this->_dstHeight);
glClear(GL_COLOR_BUFFER_BIT);
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_RECTANGLE_ARB, this->_texIntermediateID, 0);
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, srcTexID);
glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, 0);
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_RECTANGLE_ARB, this->_texDstID, 0);
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, this->_texIntermediateID);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, 0);
glBindVertexArrayDESMUME(0);
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
return this->GetDstTexID();
}
#pragma mark -
OGLImage::OGLImage(OGLInfo *oglInfo, GLsizei imageWidth, GLsizei imageHeight, GLsizei viewportWidth, GLsizei viewportHeight)
{
_needUploadVertices = true;
_useDeposterize = false;
_vtxElementPointer = 0;
_normalWidth = imageWidth;
_normalHeight = imageHeight;
_viewportWidth = viewportWidth;
_viewportHeight = viewportHeight;
_vf = new VideoFilter(_normalWidth, _normalHeight, VideoFilterTypeID_None, 0);
_vfMasterDstBuffer = (uint32_t *)calloc(_vf->GetDstWidth() * _vf->GetDstHeight(), sizeof(uint32_t));
_vf->SetDstBufferPtr(_vfMasterDstBuffer);
_displayTexFilter = GL_NEAREST;
glViewport(0, 0, _viewportWidth, _viewportHeight);
UpdateVertices();
UpdateTexCoords(_vf->GetDstWidth(), _vf->GetDstHeight());
// Set up textures
glGenTextures(1, &_texCPUFilterDstID);
glGenTextures(1, &_texVideoInputDataID);
_texVideoSourceID = _texVideoInputDataID;
_texVideoPixelScalerID = _texVideoInputDataID;
_texVideoOutputID = _texVideoInputDataID;
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, _texCPUFilterDstID);
glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_STORAGE_HINT_APPLE, GL_STORAGE_CACHED_APPLE);
glTextureRangeAPPLE(GL_TEXTURE_RECTANGLE_ARB, _vf->GetDstWidth() * _vf->GetDstHeight() * sizeof(uint32_t), _vfMasterDstBuffer);
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, _texVideoInputDataID);
glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA, _vf->GetSrcWidth(), _vf->GetSrcHeight(), 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, _vf->GetSrcBufferPtr());
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);
// Set up VBOs
glGenBuffersARB(1, &_vboVertexID);
glGenBuffersARB(1, &_vboTexCoordID);
glGenBuffersARB(1, &_vboElementID);
glBindBufferARB(GL_ARRAY_BUFFER_ARB, _vboVertexID);
glBufferDataARB(GL_ARRAY_BUFFER_ARB, sizeof(_vtxBuffer), _vtxBuffer, GL_STATIC_DRAW_ARB);
glBindBufferARB(GL_ARRAY_BUFFER_ARB, _vboTexCoordID);
glBufferDataARB(GL_ARRAY_BUFFER_ARB, sizeof(_texCoordBuffer), _texCoordBuffer, GL_STATIC_DRAW_ARB);
glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, _vboElementID);
glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, sizeof(GLubyte) * 6, outputElementBuffer, GL_STATIC_DRAW_ARB);
glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
// Set up VAO
glGenVertexArraysDESMUME(1, &_vaoMainStatesID);
glBindVertexArrayDESMUME(_vaoMainStatesID);
if (oglInfo->IsShaderSupported())
{
glBindBufferARB(GL_ARRAY_BUFFER_ARB, _vboVertexID);
glVertexAttribPointer(OGLVertexAttributeID_Position, 2, GL_INT, GL_FALSE, 0, 0);
glBindBufferARB(GL_ARRAY_BUFFER_ARB, _vboTexCoordID);
glVertexAttribPointer(OGLVertexAttributeID_TexCoord0, 2, GL_FLOAT, GL_FALSE, 0, 0);
glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, _vboElementID);
glEnableVertexAttribArray(OGLVertexAttributeID_Position);
glEnableVertexAttribArray(OGLVertexAttributeID_TexCoord0);
}
else
{
glBindBufferARB(GL_ARRAY_BUFFER_ARB, _vboVertexID);
glVertexPointer(2, GL_INT, 0, 0);
glBindBufferARB(GL_ARRAY_BUFFER_ARB, _vboTexCoordID);
glTexCoordPointer(2, GL_FLOAT, 0, 0);
glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, _vboElementID);
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
}
glBindVertexArrayDESMUME(0);
_isVAOPresent = true;
_pixelScaler = VideoFilterTypeID_None;
_useShader150 = oglInfo->IsUsingShader150();
_shaderSupport = oglInfo->GetShaderSupport();
_canUseShaderOutput = oglInfo->IsShaderSupported();
if (_canUseShaderOutput)
{
_finalOutputProgram = new OGLShaderProgram;
_finalOutputProgram->SetShaderSupport(_shaderSupport);
_finalOutputProgram->SetVertexAndFragmentShaderOGL(Sample1x1OutputVertShader_100, PassthroughOutputFragShader_110, _useShader150);
const GLuint finalOutputProgramID = _finalOutputProgram->GetProgramID();
glUseProgram(finalOutputProgramID);
_uniformFinalOutputAngleDegrees = glGetUniformLocation(finalOutputProgramID, "angleDegrees");
_uniformFinalOutputScalar = glGetUniformLocation(finalOutputProgramID, "scalar");
_uniformFinalOutputViewSize = glGetUniformLocation(finalOutputProgramID, "viewSize");
glUseProgram(0);
}
else
{
_finalOutputProgram = NULL;
}
_canUseShaderBasedFilters = (oglInfo->IsShaderSupported() && oglInfo->IsFBOSupported());
if (_canUseShaderBasedFilters)
{
_filterDeposterize = new OGLFilterDeposterize(_vf->GetSrcWidth(), _vf->GetSrcHeight(), _shaderSupport, _useShader150);
_shaderFilter = new OGLFilter(_vf->GetSrcWidth(), _vf->GetSrcHeight(), 1);
OGLShaderProgram *shaderFilterProgram = _shaderFilter->GetProgram();
shaderFilterProgram->SetShaderSupport(_shaderSupport);
shaderFilterProgram->SetVertexAndFragmentShaderOGL(Sample1x1_VertShader_110, PassthroughFragShader_110, _useShader150);
UploadHQnxLUTs();
}
else
{
_filterDeposterize = NULL;
_shaderFilter = NULL;
}
_useShaderBasedPixelScaler = false;
_filtersPreferGPU = true;
_outputFilter = OutputFilterTypeID_Bilinear;
}
OGLImage::~OGLImage()
{
if (_isVAOPresent)
{
glDeleteVertexArraysDESMUME(1, &this->_vaoMainStatesID);
_isVAOPresent = false;
}
glDeleteBuffersARB(1, &this->_vboVertexID);
glDeleteBuffersARB(1, &this->_vboTexCoordID);
glDeleteBuffersARB(1, &this->_vboElementID);
glDeleteTextures(1, &this->_texCPUFilterDstID);
glDeleteTextures(1, &this->_texVideoInputDataID);
glActiveTexture(GL_TEXTURE0 + 1);
glBindTexture(GL_TEXTURE_3D, 0);
glDeleteTextures(1, &this->_texLQ2xLUT);
glDeleteTextures(1, &this->_texHQ2xLUT);
glDeleteTextures(1, &this->_texHQ4xLUT);
glActiveTexture(GL_TEXTURE0);
if (_canUseShaderOutput)
{
glUseProgram(0);
delete this->_finalOutputProgram;
}
if (_canUseShaderBasedFilters)
{
delete this->_filterDeposterize;
delete this->_shaderFilter;
}
delete this->_vf;
free(_vfMasterDstBuffer);
}
void OGLImage::UploadHQnxLUTs()
{
InitHQnxLUTs();
glGenTextures(1, &_texLQ2xLUT);
glGenTextures(1, &_texHQ2xLUT);
glGenTextures(1, &_texHQ4xLUT);
glActiveTexture(GL_TEXTURE0 + 1);
glBindTexture(GL_TEXTURE_3D, _texLQ2xLUT);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexImage3D(GL_TEXTURE_3D, 0, GL_RGB, 256*2, 4, 16, 0, GL_BGR, GL_UNSIGNED_BYTE, _LQ2xLUT);
glBindTexture(GL_TEXTURE_3D, _texHQ2xLUT);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexImage3D(GL_TEXTURE_3D, 0, GL_RGB, 256*2, 4, 16, 0, GL_BGR, GL_UNSIGNED_BYTE, _HQ2xLUT);
glBindTexture(GL_TEXTURE_3D, _texHQ4xLUT);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexImage3D(GL_TEXTURE_3D, 0, GL_RGB, 256*2, 16, 16, 0, GL_BGR, GL_UNSIGNED_BYTE, _HQ4xLUT);
glBindTexture(GL_TEXTURE_3D, 0);
glActiveTexture(GL_TEXTURE0);
}
bool OGLImage::GetFiltersPreferGPU()
{
return this->_filtersPreferGPU;
}
void OGLImage::SetFiltersPreferGPUOGL(bool preferGPU)
{
this->_filtersPreferGPU = preferGPU;
this->_useShaderBasedPixelScaler = (preferGPU) ? this->SetGPUPixelScalerOGL(this->_pixelScaler) : false;
}
bool OGLImage::GetSourceDeposterize()
{
return this->_useDeposterize;
}
void OGLImage::SetSourceDeposterize(bool useDeposterize)
{
this->_useDeposterize = (this->_canUseShaderBasedFilters) ? useDeposterize : false;
}
void OGLImage::UpdateVertices()
{
const GLint w = this->_normalWidth;
const GLint h = this->_normalHeight;
_vtxBuffer[0] = -w/2; _vtxBuffer[1] = h/2;
_vtxBuffer[2] = w/2; _vtxBuffer[3] = h/2;
_vtxBuffer[4] = w/2; _vtxBuffer[5] = -h/2;
_vtxBuffer[6] = -w/2; _vtxBuffer[7] = -h/2;
this->_needUploadVertices = true;
}
void OGLImage::UpdateTexCoords(GLfloat s, GLfloat t)
{
_texCoordBuffer[0] = 0.0f; _texCoordBuffer[1] = 0.0f;
_texCoordBuffer[2] = s; _texCoordBuffer[3] = 0.0f;
_texCoordBuffer[4] = s; _texCoordBuffer[5] = t;
_texCoordBuffer[6] = 0.0f; _texCoordBuffer[7] = t;
}
bool OGLImage::CanUseShaderBasedFilters()
{
return this->_canUseShaderBasedFilters;
}
void OGLImage::GetNormalSize(double *w, double *h)
{
if (w == NULL || h == NULL)
{
return;
}
*w = this->_normalWidth;
*h = this->_normalHeight;
}
void OGLImage::UploadVerticesOGL()
{
glBindBufferARB(GL_ARRAY_BUFFER_ARB, this->_vboVertexID);
glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, 0, sizeof(this->_vtxBuffer), this->_vtxBuffer);
glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
this->_needUploadVertices = false;
}
void OGLImage::UploadTexCoordsOGL()
{
glBindBufferARB(GL_ARRAY_BUFFER_ARB, this->_vboTexCoordID);
glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, 0, sizeof(this->_texCoordBuffer), this->_texCoordBuffer);
glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
}
void OGLImage::UploadTransformationOGL()
{
const double w = this->_viewportWidth;
const double h = this->_viewportHeight;
const GLdouble s = GetMaxScalarInBounds(this->_normalWidth, this->_normalHeight, w, h);
if (this->_canUseShaderOutput)
{
glUniform2f(this->_uniformFinalOutputViewSize, w, h);
glUniform1f(this->_uniformFinalOutputAngleDegrees, 0.0f);
glUniform1f(this->_uniformFinalOutputScalar, s);
}
else
{
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(-w/2.0, -w/2.0 + w, -h/2.0, -h/2.0 + h, -1.0, 1.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glRotatef(0.0f, 0.0f, 0.0f, 1.0f);
glScalef(s, s, 1.0f);
}
glViewport(0, 0, this->_viewportWidth, this->_viewportHeight);
}
int OGLImage::GetOutputFilter()
{
return this->_outputFilter;
}
void OGLImage::SetOutputFilterOGL(const int filterID)
{
this->_displayTexFilter = GL_NEAREST;
if (this->_canUseShaderBasedFilters)
{
this->_outputFilter = filterID;
switch (filterID)
{
case OutputFilterTypeID_NearestNeighbor:
this->_finalOutputProgram->SetVertexAndFragmentShaderOGL(Sample1x1OutputVertShader_100, PassthroughOutputFragShader_110, _useShader150);
break;
case OutputFilterTypeID_Bilinear:
this->_finalOutputProgram->SetVertexAndFragmentShaderOGL(Sample1x1OutputVertShader_100, PassthroughOutputFragShader_110, _useShader150);
this->_displayTexFilter = GL_LINEAR;
break;
case OutputFilterTypeID_BicubicBSpline:
this->_finalOutputProgram->SetVertexAndFragmentShaderOGL(BicubicSample4x4Output_VertShader_110, FilterBicubicBSplineFragShader_110, _useShader150);
break;
case OutputFilterTypeID_BicubicMitchell:
this->_finalOutputProgram->SetVertexAndFragmentShaderOGL(BicubicSample4x4Output_VertShader_110, FilterBicubicMitchellNetravaliFragShader_110, _useShader150);
break;
case OutputFilterTypeID_Lanczos2:
this->_finalOutputProgram->SetVertexAndFragmentShaderOGL(BicubicSample4x4Output_VertShader_110, FilterLanczos2FragShader_110, _useShader150);
break;
case OutputFilterTypeID_Lanczos3:
{
if (this->_shaderSupport >= ShaderSupport_HighTier)
{
this->_finalOutputProgram->SetVertexAndFragmentShaderOGL(BicubicSample6x6Output_VertShader_110, FilterLanczos3FragShader_110, _useShader150);
}
else if (this->_shaderSupport >= ShaderSupport_MidTier)
{
this->_finalOutputProgram->SetVertexAndFragmentShaderOGL(BicubicSample5x5Output_VertShader_110, FilterLanczos3FragShader_110, _useShader150);
}
else
{
this->_finalOutputProgram->SetVertexAndFragmentShaderOGL(BicubicSample4x4Output_VertShader_110, FilterLanczos3FragShader_110, _useShader150);
}
break;
}
default:
this->_finalOutputProgram->SetVertexAndFragmentShaderOGL(Sample1x1OutputVertShader_100, PassthroughOutputFragShader_110, _useShader150);
this->_outputFilter = OutputFilterTypeID_NearestNeighbor;
break;
}
}
else
{
if (filterID == OutputFilterTypeID_Bilinear)
{
this->_displayTexFilter = GL_LINEAR;
this->_outputFilter = filterID;
}
else
{
this->_outputFilter = OutputFilterTypeID_NearestNeighbor;
}
}
}
int OGLImage::GetPixelScaler()
{
return (int)this->_pixelScaler;
}
void OGLImage::SetPixelScalerOGL(const int filterID)
{
std::string cpuTypeIDString = std::string( VideoFilter::GetTypeStringByID((VideoFilterTypeID)filterID) );
const VideoFilterTypeID newFilterID = (cpuTypeIDString != std::string(VIDEOFILTERTYPE_UNKNOWN_STRING)) ? (VideoFilterTypeID)filterID : VideoFilterTypeID_None;
this->SetCPUPixelScalerOGL(newFilterID);
this->_useShaderBasedPixelScaler = (this->GetFiltersPreferGPU()) ? this->SetGPUPixelScalerOGL(newFilterID) : false;
this->_pixelScaler = newFilterID;
}
bool OGLImage::SetGPUPixelScalerOGL(const VideoFilterTypeID filterID)
{
bool willUseShaderBasedPixelScaler = true;
if (!this->_canUseShaderBasedFilters || filterID == VideoFilterTypeID_None)
{
willUseShaderBasedPixelScaler = false;
return willUseShaderBasedPixelScaler;
}
OGLShaderProgram *shaderFilterProgram = _shaderFilter->GetProgram();
VideoFilterAttributes vfAttr = VideoFilter::GetAttributesByID((VideoFilterTypeID)filterID);
GLfloat vfScale = (GLfloat)vfAttr.scaleMultiply / (GLfloat)vfAttr.scaleDivide;
switch (filterID)
{
case VideoFilterTypeID_Nearest1_5X:
shaderFilterProgram->SetVertexAndFragmentShaderOGL(Sample1x1_VertShader_110, PassthroughFragShader_110, _useShader150);
break;
case VideoFilterTypeID_Nearest2X:
shaderFilterProgram->SetVertexAndFragmentShaderOGL(Sample1x1_VertShader_110, PassthroughFragShader_110, _useShader150);
break;
case VideoFilterTypeID_Scanline:
shaderFilterProgram->SetVertexAndFragmentShaderOGL(Sample1x1_VertShader_110, Scalar2xScanlineFragShader_110, _useShader150);
break;
case VideoFilterTypeID_EPX:
shaderFilterProgram->SetVertexAndFragmentShaderOGL(Sample3x3_VertShader_110, Scalar2xEPXFragShader_110, _useShader150);
break;
case VideoFilterTypeID_EPXPlus:
shaderFilterProgram->SetVertexAndFragmentShaderOGL(Sample3x3_VertShader_110, Scalar2xEPXPlusFragShader_110, _useShader150);
break;
case VideoFilterTypeID_2xSaI:
shaderFilterProgram->SetVertexAndFragmentShaderOGL(Sample4x4_VertShader_110, Scalar2xSaIFragShader_110, _useShader150);
break;
case VideoFilterTypeID_Super2xSaI:
shaderFilterProgram->SetVertexAndFragmentShaderOGL(Sample4x4_VertShader_110, ScalarSuper2xSaIFragShader_110, _useShader150);
break;
case VideoFilterTypeID_SuperEagle:
shaderFilterProgram->SetVertexAndFragmentShaderOGL(Sample4x4_VertShader_110, ScalarSuperEagle2xFragShader_110, _useShader150);
break;
case VideoFilterTypeID_LQ2X:
{
glActiveTexture(GL_TEXTURE0 + 1);
glBindTexture(GL_TEXTURE_3D, this->_texLQ2xLUT);
glActiveTexture(GL_TEXTURE0);
shaderFilterProgram->SetVertexAndFragmentShaderOGL(Sample3x3_VertShader_110, ScalerLQ2xFragShader_110, _useShader150);
glUseProgram(shaderFilterProgram->GetProgramID());
GLint uniformTexSampler = glGetUniformLocation(shaderFilterProgram->GetProgramID(), "tex");
glUniform1i(uniformTexSampler, 0);
uniformTexSampler = glGetUniformLocation(shaderFilterProgram->GetProgramID(), "lut");
glUniform1i(uniformTexSampler, 1);
glUseProgram(0);
break;
}
case VideoFilterTypeID_LQ2XS:
{
glActiveTexture(GL_TEXTURE0 + 1);
glBindTexture(GL_TEXTURE_3D, this->_texLQ2xLUT);
glActiveTexture(GL_TEXTURE0);
shaderFilterProgram->SetVertexAndFragmentShaderOGL(Sample3x3_VertShader_110, ScalerLQ2xSFragShader_110, _useShader150);
glUseProgram(shaderFilterProgram->GetProgramID());
GLint uniformTexSampler = glGetUniformLocation(shaderFilterProgram->GetProgramID(), "tex");
glUniform1i(uniformTexSampler, 0);
uniformTexSampler = glGetUniformLocation(shaderFilterProgram->GetProgramID(), "lut");
glUniform1i(uniformTexSampler, 1);
glUseProgram(0);
break;
}
case VideoFilterTypeID_HQ2X:
{
glActiveTexture(GL_TEXTURE0 + 1);
glBindTexture(GL_TEXTURE_3D, this->_texHQ2xLUT);
glActiveTexture(GL_TEXTURE0);
shaderFilterProgram->SetVertexAndFragmentShaderOGL(Sample3x3_VertShader_110, ScalerHQ2xFragShader_110, _useShader150);
glUseProgram(shaderFilterProgram->GetProgramID());
GLint uniformTexSampler = glGetUniformLocation(shaderFilterProgram->GetProgramID(), "tex");
glUniform1i(uniformTexSampler, 0);
uniformTexSampler = glGetUniformLocation(shaderFilterProgram->GetProgramID(), "lut");
glUniform1i(uniformTexSampler, 1);
glUseProgram(0);
break;
}
case VideoFilterTypeID_HQ2XS:
{
glActiveTexture(GL_TEXTURE0 + 1);
glBindTexture(GL_TEXTURE_3D, this->_texHQ2xLUT);
glActiveTexture(GL_TEXTURE0);
shaderFilterProgram->SetVertexAndFragmentShaderOGL(Sample3x3_VertShader_110, ScalerHQ2xSFragShader_110, _useShader150);
glUseProgram(shaderFilterProgram->GetProgramID());
GLint uniformTexSampler = glGetUniformLocation(shaderFilterProgram->GetProgramID(), "tex");
glUniform1i(uniformTexSampler, 0);
uniformTexSampler = glGetUniformLocation(shaderFilterProgram->GetProgramID(), "lut");
glUniform1i(uniformTexSampler, 1);
glUseProgram(0);
break;
}
case VideoFilterTypeID_HQ4X:
{
glActiveTexture(GL_TEXTURE0 + 1);
glBindTexture(GL_TEXTURE_3D, this->_texHQ4xLUT);
glActiveTexture(GL_TEXTURE0);
shaderFilterProgram->SetVertexAndFragmentShaderOGL(Sample3x3_VertShader_110, ScalerHQ4xFragShader_110, _useShader150);
glUseProgram(shaderFilterProgram->GetProgramID());
GLint uniformTexSampler = glGetUniformLocation(shaderFilterProgram->GetProgramID(), "tex");
glUniform1i(uniformTexSampler, 0);
uniformTexSampler = glGetUniformLocation(shaderFilterProgram->GetProgramID(), "lut");
glUniform1i(uniformTexSampler, 1);
glUseProgram(0);
break;
}
case VideoFilterTypeID_HQ4XS:
{
glActiveTexture(GL_TEXTURE0 + 1);
glBindTexture(GL_TEXTURE_3D, this->_texHQ4xLUT);
glActiveTexture(GL_TEXTURE0);
shaderFilterProgram->SetVertexAndFragmentShaderOGL(Sample3x3_VertShader_110, ScalerHQ4xSFragShader_110, _useShader150);
glUseProgram(shaderFilterProgram->GetProgramID());
GLint uniformTexSampler = glGetUniformLocation(shaderFilterProgram->GetProgramID(), "tex");
glUniform1i(uniformTexSampler, 0);
uniformTexSampler = glGetUniformLocation(shaderFilterProgram->GetProgramID(), "lut");
glUniform1i(uniformTexSampler, 1);
glUseProgram(0);
break;
}
case VideoFilterTypeID_2xBRZ:
{
if (this->_shaderSupport >= ShaderSupport_MidTier)
{
shaderFilterProgram->SetVertexAndFragmentShaderOGL(Sample5x5_VertShader_110, Scaler2xBRZFragShader_110, _useShader150);
}
else if (this->_shaderSupport >= ShaderSupport_LowTier)
{
shaderFilterProgram->SetVertexAndFragmentShaderOGL(Sample4x4_VertShader_110, Scaler2xBRZFragShader_110, _useShader150);
}
else
{
willUseShaderBasedPixelScaler = false;
}
break;
}
case VideoFilterTypeID_3xBRZ:
{
if (this->_shaderSupport >= ShaderSupport_MidTier)
{
shaderFilterProgram->SetVertexAndFragmentShaderOGL(Sample5x5_VertShader_110, Scaler3xBRZFragShader_110, _useShader150);
}
else if (this->_shaderSupport >= ShaderSupport_LowTier)
{
shaderFilterProgram->SetVertexAndFragmentShaderOGL(Sample4x4_VertShader_110, Scaler3xBRZFragShader_110, _useShader150);
}
else
{
willUseShaderBasedPixelScaler = false;
}
break;
}
case VideoFilterTypeID_4xBRZ:
{
if (this->_shaderSupport >= ShaderSupport_MidTier)
{
shaderFilterProgram->SetVertexAndFragmentShaderOGL(Sample5x5_VertShader_110, Scaler4xBRZFragShader_110, _useShader150);
}
else if (this->_shaderSupport >= ShaderSupport_LowTier)
{
shaderFilterProgram->SetVertexAndFragmentShaderOGL(Sample4x4_VertShader_110, Scaler4xBRZFragShader_110, _useShader150);
}
else
{
willUseShaderBasedPixelScaler = false;
}
break;
}
case VideoFilterTypeID_5xBRZ:
{
if (this->_shaderSupport >= ShaderSupport_MidTier)
{
shaderFilterProgram->SetVertexAndFragmentShaderOGL(Sample5x5_VertShader_110, Scaler5xBRZFragShader_110, _useShader150);
}
else
{
willUseShaderBasedPixelScaler = false;
}
break;
}
default:
willUseShaderBasedPixelScaler = false;
break;
}
if (willUseShaderBasedPixelScaler)
{
_shaderFilter->SetScaleOGL(vfScale);
}
return willUseShaderBasedPixelScaler;
}
void OGLImage::SetCPUPixelScalerOGL(const VideoFilterTypeID filterID)
{
bool needResizeTexture = false;
const VideoFilterAttributes newFilterAttr = VideoFilter::GetAttributesByID(filterID);
const GLsizei oldDstBufferWidth = this->_vf->GetDstWidth();
const GLsizei oldDstBufferHeight = this->_vf->GetDstHeight();
const GLsizei newDstBufferWidth = this->_vf->GetSrcWidth() * newFilterAttr.scaleMultiply / newFilterAttr.scaleDivide;
const GLsizei newDstBufferHeight = this->_vf->GetSrcHeight() * newFilterAttr.scaleMultiply / newFilterAttr.scaleDivide;
if (oldDstBufferWidth != newDstBufferWidth || oldDstBufferHeight != newDstBufferHeight)
{
needResizeTexture = true;
}
if (needResizeTexture)
{
uint32_t *oldMasterBuffer = _vfMasterDstBuffer;
uint32_t *newMasterBuffer = (uint32_t *)calloc(newDstBufferWidth * newDstBufferHeight, sizeof(uint32_t));
this->_vf->SetDstBufferPtr(newMasterBuffer);
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, this->_texCPUFilterDstID);
glTextureRangeAPPLE(GL_TEXTURE_RECTANGLE_ARB, newDstBufferWidth * newDstBufferHeight * sizeof(uint32_t), newMasterBuffer);
glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_STORAGE_HINT_APPLE, GL_STORAGE_CACHED_APPLE);
glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA, newDstBufferWidth, newDstBufferHeight, 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, newMasterBuffer);
glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);
_vfMasterDstBuffer = newMasterBuffer;
free(oldMasterBuffer);
}
this->_vf->ChangeFilterByID(filterID);
}
void OGLImage::LoadFrameOGL(const uint32_t *frameData, GLint x, GLint y, GLsizei w, GLsizei h)
{
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, this->_texVideoInputDataID);
glTexSubImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, x, y, w, h, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, frameData);
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);
memcpy(this->_vf->GetSrcBufferPtr(), frameData, w * h * sizeof(uint32_t));
}
void OGLImage::ProcessOGL()
{
VideoFilter *currentFilter = this->_vf;
const bool isUsingCPUPixelScaler = this->_pixelScaler != VideoFilterTypeID_None && !this->_useShaderBasedPixelScaler;
// Source
if (this->_useDeposterize)
{
this->_texVideoSourceID = this->_filterDeposterize->RunFilterOGL(this->_texVideoInputDataID);
if (isUsingCPUPixelScaler) // Hybrid CPU/GPU-based path (may cause a performance hit on pixel download)
{
this->_filterDeposterize->DownloadDstBufferOGL(currentFilter->GetSrcBufferPtr(), 0, this->_normalHeight);
}
}
else
{
this->_texVideoSourceID = this->_texVideoInputDataID;
}
// Pixel scaler
if (!isUsingCPUPixelScaler)
{
if (this->_useShaderBasedPixelScaler)
{
this->_texVideoPixelScalerID = this->_shaderFilter->RunFilterOGL(this->_texVideoSourceID);
this->UpdateTexCoords(this->_shaderFilter->GetDstWidth(), this->_shaderFilter->GetDstHeight());
}
else
{
this->_texVideoPixelScalerID = this->_texVideoSourceID;
this->UpdateTexCoords(this->_normalWidth, this->_normalHeight);
}
}
else
{
uint32_t *texData = currentFilter->RunFilter();
const GLfloat w = currentFilter->GetDstWidth();
const GLfloat h = currentFilter->GetDstHeight();
this->_texVideoPixelScalerID = this->_texCPUFilterDstID;
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, this->_texVideoPixelScalerID);
glTexSubImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, 0, 0, w, h, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, texData);
this->UpdateTexCoords(w, h);
}
// Output
this->_texVideoOutputID = this->_texVideoPixelScalerID;
this->UploadTexCoordsOGL();
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);
}
void OGLImage::RenderOGL()
{
glUseProgram(this->_finalOutputProgram->GetProgramID());
this->UploadTransformationOGL();
if (this->_needUploadVertices)
{
this->UploadVerticesOGL();
}
// Enable vertex attributes
glBindVertexArrayDESMUME(this->_vaoMainStatesID);
glClear(GL_COLOR_BUFFER_BIT);
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, this->_texVideoOutputID);
glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, this->_displayTexFilter);
glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, this->_displayTexFilter);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, this->_vtxElementPointer);
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);
// Disable vertex attributes
glBindVertexArrayDESMUME(0);
}
#pragma mark -
OGLDisplayLayer::OGLDisplayLayer(OGLVideoOutput *oglVO)
{
_output = oglVO;
_needUploadVertices = true;
_useDeposterize = false;
_displayMode = DS_DISPLAY_TYPE_DUAL;
_displayOrder = DS_DISPLAY_ORDER_MAIN_FIRST;
_displayOrientation = DS_DISPLAY_ORIENTATION_VERTICAL;
_gapScalar = 0.0f;
_rotation = 0.0f;
_normalWidth = GPU_DISPLAY_WIDTH;
_normalHeight = GPU_DISPLAY_HEIGHT*2.0 + (DS_DISPLAY_GAP*_gapScalar);
_vf[0] = new VideoFilter(GPU_DISPLAY_WIDTH, GPU_DISPLAY_HEIGHT, VideoFilterTypeID_None, 0);
_vf[1] = new VideoFilter(GPU_DISPLAY_WIDTH, GPU_DISPLAY_HEIGHT, VideoFilterTypeID_None, 0);
_vfDual = new VideoFilter(_vf[0]->GetSrcWidth(), _vf[0]->GetSrcHeight() + _vf[1]->GetSrcHeight(), VideoFilterTypeID_None, 2);
_vfMasterDstBuffer = (uint32_t *)calloc(_vfDual->GetDstWidth() * _vfDual->GetDstHeight(), sizeof(uint32_t));
_vf[0]->SetDstBufferPtr(_vfMasterDstBuffer);
_vf[1]->SetDstBufferPtr(_vfMasterDstBuffer + (_vf[0]->GetDstWidth() * _vf[0]->GetDstHeight()));
_vfDual->SetDstBufferPtr(_vfMasterDstBuffer);
_displayTexFilter[0] = GL_NEAREST;
_displayTexFilter[1] = GL_NEAREST;
_vtxBufferOffset = 0;
UpdateVertices();
UpdateTexCoords(_vf[0]->GetDstWidth(), _vf[0]->GetDstHeight());
// Set up textures
glGenTextures(2, _texCPUFilterDstID);
glGenTextures(2, _texVideoInputDataID);
_texVideoSourceID[0] = _texVideoInputDataID[0];
_texVideoSourceID[1] = _texVideoInputDataID[1];
_texVideoPixelScalerID[0] = _texVideoInputDataID[0];
_texVideoPixelScalerID[1] = _texVideoInputDataID[1];
_texVideoOutputID[0] = _texVideoInputDataID[0];
_texVideoOutputID[1] = _texVideoInputDataID[1];
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, _texCPUFilterDstID[0]);
glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_STORAGE_HINT_APPLE, GL_STORAGE_CACHED_APPLE);
glTextureRangeAPPLE(GL_TEXTURE_RECTANGLE_ARB, _vf[0]->GetDstWidth() * _vf[0]->GetDstHeight() * sizeof(uint32_t), _vfMasterDstBuffer);
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, _texCPUFilterDstID[1]);
glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_STORAGE_HINT_APPLE, GL_STORAGE_CACHED_APPLE);
glTextureRangeAPPLE(GL_TEXTURE_RECTANGLE_ARB, _vf[1]->GetDstWidth() * _vf[1]->GetDstHeight() * sizeof(uint32_t), _vfMasterDstBuffer + (_vf[0]->GetDstWidth() * _vf[0]->GetDstHeight()));
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, _texVideoInputDataID[0]);
glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA, _vf[0]->GetSrcWidth(), _vf[0]->GetSrcHeight(), 0, GL_BGRA, GL_UNSIGNED_SHORT_1_5_5_5_REV, _vf[0]->GetSrcBufferPtr());
glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, _texVideoInputDataID[1]);
glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA, _vf[1]->GetSrcWidth(), _vf[1]->GetSrcHeight(), 0, GL_BGRA, GL_UNSIGNED_SHORT_1_5_5_5_REV, _vf[1]->GetSrcBufferPtr());
glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);
// Set up VBOs
glGenBuffersARB(1, &this->_vboVertexID);
glGenBuffersARB(1, &this->_vboTexCoordID);
glGenBuffersARB(1, &this->_vboElementID);
glBindBufferARB(GL_ARRAY_BUFFER_ARB, this->_vboVertexID);
glBufferDataARB(GL_ARRAY_BUFFER_ARB, sizeof(GLint) * (2 * 8), this->vtxBuffer, GL_STATIC_DRAW_ARB);
glBindBufferARB(GL_ARRAY_BUFFER_ARB, this->_vboTexCoordID);
glBufferDataARB(GL_ARRAY_BUFFER_ARB, sizeof(GLfloat) * (2 * 8), this->texCoordBuffer, GL_STATIC_DRAW_ARB);
glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, this->_vboElementID);
glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, sizeof(GLubyte) * 12, outputElementBuffer, GL_STATIC_DRAW_ARB);
glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
// Set up VAO
glGenVertexArraysDESMUME(1, &this->_vaoMainStatesID);
glBindVertexArrayDESMUME(this->_vaoMainStatesID);
if (this->_output->GetInfo()->IsShaderSupported())
{
glBindBufferARB(GL_ARRAY_BUFFER_ARB, this->_vboVertexID);
glVertexAttribPointer(OGLVertexAttributeID_Position, 2, GL_INT, GL_FALSE, 0, 0);
glBindBufferARB(GL_ARRAY_BUFFER_ARB, this->_vboTexCoordID);
glVertexAttribPointer(OGLVertexAttributeID_TexCoord0, 2, GL_FLOAT, GL_FALSE, 0, 0);
glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, this->_vboElementID);
glEnableVertexAttribArray(OGLVertexAttributeID_Position);
glEnableVertexAttribArray(OGLVertexAttributeID_TexCoord0);
}
else
{
glBindBufferARB(GL_ARRAY_BUFFER_ARB, this->_vboVertexID);
glVertexPointer(2, GL_INT, 0, 0);
glBindBufferARB(GL_ARRAY_BUFFER_ARB, this->_vboTexCoordID);
glTexCoordPointer(2, GL_FLOAT, 0, 0);
glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, this->_vboElementID);
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
}
glBindVertexArrayDESMUME(0);
_isVAOPresent = true;
_pixelScaler = VideoFilterTypeID_None;
_useShader150 = this->_output->GetInfo()->IsUsingShader150();
_shaderSupport = this->_output->GetInfo()->GetShaderSupport();
_canUseShaderOutput = this->_output->GetInfo()->IsShaderSupported();
if (_canUseShaderOutput)
{
_finalOutputProgram = new OGLShaderProgram;
_finalOutputProgram->SetShaderSupport(_shaderSupport);
_finalOutputProgram->SetVertexAndFragmentShaderOGL(Sample1x1OutputVertShader_100, PassthroughOutputFragShader_110, _useShader150);
const GLuint finalOutputProgramID = _finalOutputProgram->GetProgramID();
glUseProgram(finalOutputProgramID);
_uniformFinalOutputAngleDegrees = glGetUniformLocation(finalOutputProgramID, "angleDegrees");
_uniformFinalOutputScalar = glGetUniformLocation(finalOutputProgramID, "scalar");
_uniformFinalOutputViewSize = glGetUniformLocation(finalOutputProgramID, "viewSize");
glUseProgram(0);
}
else
{
_finalOutputProgram = NULL;
}
_canUseShaderBasedFilters = (_canUseShaderOutput && _output->GetInfo()->IsFBOSupported());
if (_canUseShaderBasedFilters)
{
for (size_t i = 0; i < 2; i++)
{
_filterDeposterize[i] = new OGLFilterDeposterize(_vf[i]->GetSrcWidth(), _vf[i]->GetSrcHeight(), _shaderSupport, _useShader150);
_shaderFilter[i] = new OGLFilter(_vf[i]->GetSrcWidth(), _vf[i]->GetSrcHeight(), 1);
OGLShaderProgram *shaderFilterProgram = _shaderFilter[i]->GetProgram();
shaderFilterProgram->SetShaderSupport(_shaderSupport);
shaderFilterProgram->SetVertexAndFragmentShaderOGL(Sample1x1_VertShader_110, PassthroughFragShader_110, _useShader150);
}
UploadHQnxLUTs();
}
else
{
_filterDeposterize[0] = NULL;
_filterDeposterize[1] = NULL;
_shaderFilter[0] = NULL;
_shaderFilter[1] = NULL;
}
_useShaderBasedPixelScaler = false;
_filtersPreferGPU = true;
_outputFilter = OutputFilterTypeID_Bilinear;
}
OGLDisplayLayer::~OGLDisplayLayer()
{
if (_isVAOPresent)
{
glDeleteVertexArraysDESMUME(1, &this->_vaoMainStatesID);
_isVAOPresent = false;
}
glDeleteBuffersARB(1, &this->_vboVertexID);
glDeleteBuffersARB(1, &this->_vboTexCoordID);
glDeleteBuffersARB(1, &this->_vboElementID);
glDeleteTextures(2, this->_texCPUFilterDstID);
glDeleteTextures(2, this->_texVideoInputDataID);
glActiveTexture(GL_TEXTURE0 + 1);
glBindTexture(GL_TEXTURE_3D, 0);
glDeleteTextures(1, &this->_texLQ2xLUT);
glDeleteTextures(1, &this->_texHQ2xLUT);
glDeleteTextures(1, &this->_texHQ4xLUT);
glActiveTexture(GL_TEXTURE0);
if (_canUseShaderOutput)
{
glUseProgram(0);
delete this->_finalOutputProgram;
}
if (_canUseShaderBasedFilters)
{
delete this->_filterDeposterize[0];
delete this->_filterDeposterize[1];
delete this->_shaderFilter[0];
delete this->_shaderFilter[1];
}
delete this->_vf[0];
delete this->_vf[1];
delete this->_vfDual;
free(_vfMasterDstBuffer);
}
void OGLDisplayLayer::UploadHQnxLUTs()
{
InitHQnxLUTs();
glGenTextures(1, &_texLQ2xLUT);
glGenTextures(1, &_texHQ2xLUT);
glGenTextures(1, &_texHQ4xLUT);
glActiveTexture(GL_TEXTURE0 + 1);
glBindTexture(GL_TEXTURE_3D, _texLQ2xLUT);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexImage3D(GL_TEXTURE_3D, 0, GL_RGB, 256*2, 4, 16, 0, GL_BGR, GL_UNSIGNED_BYTE, _LQ2xLUT);
glBindTexture(GL_TEXTURE_3D, _texHQ2xLUT);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexImage3D(GL_TEXTURE_3D, 0, GL_RGB, 256*2, 4, 16, 0, GL_BGR, GL_UNSIGNED_BYTE, _HQ2xLUT);
glBindTexture(GL_TEXTURE_3D, _texHQ4xLUT);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexImage3D(GL_TEXTURE_3D, 0, GL_RGB, 256*2, 16, 16, 0, GL_BGR, GL_UNSIGNED_BYTE, _HQ4xLUT);
glBindTexture(GL_TEXTURE_3D, 0);
glActiveTexture(GL_TEXTURE0);
}
bool OGLDisplayLayer::GetFiltersPreferGPU()
{
return this->_filtersPreferGPU;
}
void OGLDisplayLayer::SetFiltersPreferGPUOGL(bool preferGPU)
{
this->_filtersPreferGPU = preferGPU;
this->_useShaderBasedPixelScaler = (preferGPU) ? this->SetGPUPixelScalerOGL(this->_pixelScaler) : false;
}
int OGLDisplayLayer::GetMode()
{
return this->_displayMode;
}
void OGLDisplayLayer::SetMode(int dispMode)
{
this->_displayMode = dispMode;
this->GetNormalSize(&this->_normalWidth, &this->_normalHeight);
this->UpdateVertices();
}
int OGLDisplayLayer::GetOrientation()
{
return this->_displayOrientation;
}
void OGLDisplayLayer::SetOrientation(int dispOrientation)
{
this->_displayOrientation = dispOrientation;
this->GetNormalSize(&this->_normalWidth, &this->_normalHeight);
this->UpdateVertices();
}
GLfloat OGLDisplayLayer::GetGapScalar()
{
return this->_gapScalar;
}
void OGLDisplayLayer::SetGapScalar(GLfloat theScalar)
{
this->_gapScalar = theScalar;
this->GetNormalSize(&this->_normalWidth, &this->_normalHeight);
this->UpdateVertices();
}
GLfloat OGLDisplayLayer::GetRotation()
{
return this->_rotation;
}
void OGLDisplayLayer::SetRotation(GLfloat theRotation)
{
this->_rotation = theRotation;
}
bool OGLDisplayLayer::GetSourceDeposterize()
{
return this->_useDeposterize;
}
void OGLDisplayLayer::SetSourceDeposterize(bool useDeposterize)
{
this->_useDeposterize = (this->_canUseShaderBasedFilters) ? useDeposterize : false;
}
int OGLDisplayLayer::GetOrder()
{
return this->_displayOrder;
}
void OGLDisplayLayer::SetOrder(int dispOrder)
{
this->_displayOrder = dispOrder;
if (this->_displayOrder == DS_DISPLAY_ORDER_MAIN_FIRST)
{
this->_vtxBufferOffset = 0;
}
else // dispOrder == DS_DISPLAY_ORDER_TOUCH_FIRST
{
this->_vtxBufferOffset = (2 * 8);
}
this->_needUploadVertices = true;
}
void OGLDisplayLayer::UpdateVertices()
{
const GLfloat w = GPU_DISPLAY_WIDTH;
const GLfloat h = GPU_DISPLAY_HEIGHT;
const GLfloat gap = DS_DISPLAY_GAP * this->_gapScalar / 2.0;
if (this->_displayMode == DS_DISPLAY_TYPE_DUAL)
{
// displayOrder == DS_DISPLAY_ORDER_MAIN_FIRST
if (this->_displayOrientation == DS_DISPLAY_ORIENTATION_VERTICAL)
{
vtxBuffer[0] = -w/2; vtxBuffer[1] = h+gap; // Top display, top left
vtxBuffer[2] = w/2; vtxBuffer[3] = h+gap; // Top display, top right
vtxBuffer[4] = w/2; vtxBuffer[5] = gap; // Top display, bottom right
vtxBuffer[6] = -w/2; vtxBuffer[7] = gap; // Top display, bottom left
vtxBuffer[8] = -w/2; vtxBuffer[9] = -gap; // Bottom display, top left
vtxBuffer[10] = w/2; vtxBuffer[11] = -gap; // Bottom display, top right
vtxBuffer[12] = w/2; vtxBuffer[13] = -(h+gap); // Bottom display, bottom right
vtxBuffer[14] = -w/2; vtxBuffer[15] = -(h+gap); // Bottom display, bottom left
}
else // displayOrientationID == DS_DISPLAY_ORIENTATION_HORIZONTAL
{
vtxBuffer[0] = -(w+gap); vtxBuffer[1] = h/2; // Left display, top left
vtxBuffer[2] = -gap; vtxBuffer[3] = h/2; // Left display, top right
vtxBuffer[4] = -gap; vtxBuffer[5] = -h/2; // Left display, bottom right
vtxBuffer[6] = -(w+gap); vtxBuffer[7] = -h/2; // Left display, bottom left
vtxBuffer[8] = gap; vtxBuffer[9] = h/2; // Right display, top left
vtxBuffer[10] = w+gap; vtxBuffer[11] = h/2; // Right display, top right
vtxBuffer[12] = w+gap; vtxBuffer[13] = -h/2; // Right display, bottom right
vtxBuffer[14] = gap; vtxBuffer[15] = -h/2; // Right display, bottom left
}
// displayOrder == DS_DISPLAY_ORDER_TOUCH_FIRST
memcpy(vtxBuffer + (2 * 8), vtxBuffer + (1 * 8), sizeof(GLint) * (1 * 8));
memcpy(vtxBuffer + (3 * 8), vtxBuffer + (0 * 8), sizeof(GLint) * (1 * 8));
}
else // displayModeID == DS_DISPLAY_TYPE_MAIN || displayModeID == DS_DISPLAY_TYPE_TOUCH
{
vtxBuffer[0] = -w/2; vtxBuffer[1] = h/2; // First display, top left
vtxBuffer[2] = w/2; vtxBuffer[3] = h/2; // First display, top right
vtxBuffer[4] = w/2; vtxBuffer[5] = -h/2; // First display, bottom right
vtxBuffer[6] = -w/2; vtxBuffer[7] = -h/2; // First display, bottom left
memcpy(vtxBuffer + (1 * 8), vtxBuffer + (0 * 8), sizeof(GLint) * (1 * 8)); // Second display
memcpy(vtxBuffer + (2 * 8), vtxBuffer + (0 * 8), sizeof(GLint) * (2 * 8)); // Second display
}
this->_needUploadVertices = true;
}
void OGLDisplayLayer::UpdateTexCoords(GLfloat s, GLfloat t)
{
texCoordBuffer[0] = 0.0f; texCoordBuffer[1] = 0.0f;
texCoordBuffer[2] = s; texCoordBuffer[3] = 0.0f;
texCoordBuffer[4] = s; texCoordBuffer[5] = t;
texCoordBuffer[6] = 0.0f; texCoordBuffer[7] = t;
memcpy(texCoordBuffer + (1 * 8), texCoordBuffer + (0 * 8), sizeof(GLint) * (1 * 8));
}
bool OGLDisplayLayer::CanUseShaderBasedFilters()
{
return this->_canUseShaderBasedFilters;
}
void OGLDisplayLayer::GetNormalSize(double *w, double *h)
{
if (w == NULL || h == NULL)
{
return;
}
if (this->_displayMode != DS_DISPLAY_TYPE_DUAL)
{
*w = GPU_DISPLAY_WIDTH;
*h = GPU_DISPLAY_HEIGHT;
return;
}
if (this->_displayOrientation == DS_DISPLAY_ORIENTATION_VERTICAL)
{
*w = GPU_DISPLAY_WIDTH;
*h = GPU_DISPLAY_HEIGHT * 2.0 + (DS_DISPLAY_GAP * this->_gapScalar);
}
else
{
*w = GPU_DISPLAY_WIDTH * 2.0 + (DS_DISPLAY_GAP * this->_gapScalar);
*h = GPU_DISPLAY_HEIGHT;
}
}
void OGLDisplayLayer::UploadVerticesOGL()
{
glBindBufferARB(GL_ARRAY_BUFFER_ARB, this->_vboVertexID);
glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, 0, sizeof(GLint) * (2 * 8), this->vtxBuffer + this->_vtxBufferOffset);
glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
this->_needUploadVertices = false;
}
void OGLDisplayLayer::UploadTexCoordsOGL()
{
glBindBufferARB(GL_ARRAY_BUFFER_ARB, this->_vboTexCoordID);
glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, 0, sizeof(GLfloat) * (2 * 8), this->texCoordBuffer);
glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
}
void OGLDisplayLayer::UploadTransformationOGL()
{
const double w = this->_viewportWidth;
const double h = this->_viewportHeight;
const CGSize checkSize = GetTransformedBounds(this->_normalWidth, this->_normalHeight, 1.0, this->_rotation);
const GLdouble s = GetMaxScalarInBounds(checkSize.width, checkSize.height, w, h);
if (this->_output->GetInfo()->IsShaderSupported())
{
glUniform2f(this->_uniformFinalOutputViewSize, w, h);
glUniform1f(this->_uniformFinalOutputAngleDegrees, this->_rotation);
glUniform1f(this->_uniformFinalOutputScalar, s);
}
else
{
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(-w/2.0, -w/2.0 + w, -h/2.0, -h/2.0 + h, -1.0, 1.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glRotatef(CLOCKWISE_DEGREES(this->_rotation), 0.0f, 0.0f, 1.0f);
glScalef(s, s, 1.0f);
}
glViewport(0, 0, this->_viewportWidth, this->_viewportHeight);
}
int OGLDisplayLayer::GetOutputFilter()
{
return this->_outputFilter;
}
void OGLDisplayLayer::SetOutputFilterOGL(const int filterID)
{
this->_displayTexFilter[0] = GL_NEAREST;
this->_displayTexFilter[1] = GL_NEAREST;
if (this->_canUseShaderBasedFilters)
{
this->_outputFilter = filterID;
switch (filterID)
{
case OutputFilterTypeID_NearestNeighbor:
this->_finalOutputProgram->SetVertexAndFragmentShaderOGL(Sample1x1OutputVertShader_100, PassthroughOutputFragShader_110, _useShader150);
break;
case OutputFilterTypeID_Bilinear:
this->_finalOutputProgram->SetVertexAndFragmentShaderOGL(Sample1x1OutputVertShader_100, PassthroughOutputFragShader_110, _useShader150);
this->_displayTexFilter[0] = GL_LINEAR;
this->_displayTexFilter[1] = GL_LINEAR;
break;
case OutputFilterTypeID_BicubicBSpline:
this->_finalOutputProgram->SetVertexAndFragmentShaderOGL(BicubicSample4x4Output_VertShader_110, FilterBicubicBSplineFragShader_110, _useShader150);
break;
case OutputFilterTypeID_BicubicMitchell:
this->_finalOutputProgram->SetVertexAndFragmentShaderOGL(BicubicSample4x4Output_VertShader_110, FilterBicubicMitchellNetravaliFragShader_110, _useShader150);
break;
case OutputFilterTypeID_Lanczos2:
this->_finalOutputProgram->SetVertexAndFragmentShaderOGL(BicubicSample4x4Output_VertShader_110, FilterLanczos2FragShader_110, _useShader150);
break;
case OutputFilterTypeID_Lanczos3:
{
if (this->_shaderSupport >= ShaderSupport_HighTier)
{
this->_finalOutputProgram->SetVertexAndFragmentShaderOGL(BicubicSample6x6Output_VertShader_110, FilterLanczos3FragShader_110, _useShader150);
}
else if (this->_shaderSupport >= ShaderSupport_MidTier)
{
this->_finalOutputProgram->SetVertexAndFragmentShaderOGL(BicubicSample5x5Output_VertShader_110, FilterLanczos3FragShader_110, _useShader150);
}
else
{
this->_finalOutputProgram->SetVertexAndFragmentShaderOGL(BicubicSample4x4Output_VertShader_110, FilterLanczos3FragShader_110, _useShader150);
}
break;
}
default:
this->_finalOutputProgram->SetVertexAndFragmentShaderOGL(Sample1x1OutputVertShader_100, PassthroughOutputFragShader_110, _useShader150);
this->_outputFilter = OutputFilterTypeID_NearestNeighbor;
break;
}
}
else
{
if (filterID == OutputFilterTypeID_Bilinear)
{
this->_displayTexFilter[0] = GL_LINEAR;
this->_displayTexFilter[1] = GL_LINEAR;
this->_outputFilter = filterID;
}
else
{
this->_outputFilter = OutputFilterTypeID_NearestNeighbor;
}
}
}
int OGLDisplayLayer::GetPixelScaler()
{
return (int)this->_pixelScaler;
}
void OGLDisplayLayer::SetPixelScalerOGL(const int filterID)
{
std::string cpuTypeIDString = std::string( VideoFilter::GetTypeStringByID((VideoFilterTypeID)filterID) );
const VideoFilterTypeID newFilterID = (cpuTypeIDString != std::string(VIDEOFILTERTYPE_UNKNOWN_STRING)) ? (VideoFilterTypeID)filterID : VideoFilterTypeID_None;
this->SetCPUPixelScalerOGL(newFilterID);
this->_useShaderBasedPixelScaler = (this->GetFiltersPreferGPU()) ? this->SetGPUPixelScalerOGL(newFilterID) : false;
this->_pixelScaler = newFilterID;
}
bool OGLDisplayLayer::SetGPUPixelScalerOGL(const VideoFilterTypeID filterID)
{
bool willUseShaderBasedPixelScaler = true;
if (!this->_canUseShaderBasedFilters || filterID == VideoFilterTypeID_None)
{
willUseShaderBasedPixelScaler = false;
return willUseShaderBasedPixelScaler;
}
for (size_t i = 0; i < 2; i++)
{
OGLShaderProgram *shaderFilterProgram = _shaderFilter[i]->GetProgram();
VideoFilterAttributes vfAttr = VideoFilter::GetAttributesByID((VideoFilterTypeID)filterID);
GLfloat vfScale = (GLfloat)vfAttr.scaleMultiply / (GLfloat)vfAttr.scaleDivide;
switch (filterID)
{
case VideoFilterTypeID_Nearest1_5X:
shaderFilterProgram->SetVertexAndFragmentShaderOGL(Sample1x1_VertShader_110, PassthroughFragShader_110, _useShader150);
break;
case VideoFilterTypeID_Nearest2X:
shaderFilterProgram->SetVertexAndFragmentShaderOGL(Sample1x1_VertShader_110, PassthroughFragShader_110, _useShader150);
break;
case VideoFilterTypeID_Scanline:
shaderFilterProgram->SetVertexAndFragmentShaderOGL(Sample1x1_VertShader_110, Scalar2xScanlineFragShader_110, _useShader150);
break;
case VideoFilterTypeID_EPX:
shaderFilterProgram->SetVertexAndFragmentShaderOGL(Sample3x3_VertShader_110, Scalar2xEPXFragShader_110, _useShader150);
break;
case VideoFilterTypeID_EPXPlus:
shaderFilterProgram->SetVertexAndFragmentShaderOGL(Sample3x3_VertShader_110, Scalar2xEPXPlusFragShader_110, _useShader150);
break;
case VideoFilterTypeID_2xSaI:
shaderFilterProgram->SetVertexAndFragmentShaderOGL(Sample4x4_VertShader_110, Scalar2xSaIFragShader_110, _useShader150);
break;
case VideoFilterTypeID_Super2xSaI:
shaderFilterProgram->SetVertexAndFragmentShaderOGL(Sample4x4_VertShader_110, ScalarSuper2xSaIFragShader_110, _useShader150);
break;
case VideoFilterTypeID_SuperEagle:
shaderFilterProgram->SetVertexAndFragmentShaderOGL(Sample4x4_VertShader_110, ScalarSuperEagle2xFragShader_110, _useShader150);
break;
case VideoFilterTypeID_LQ2X:
{
glActiveTexture(GL_TEXTURE0 + 1);
glBindTexture(GL_TEXTURE_3D, this->_texLQ2xLUT);
glActiveTexture(GL_TEXTURE0);
shaderFilterProgram->SetVertexAndFragmentShaderOGL(Sample3x3_VertShader_110, ScalerLQ2xFragShader_110, _useShader150);
glUseProgram(shaderFilterProgram->GetProgramID());
GLint uniformTexSampler = glGetUniformLocation(shaderFilterProgram->GetProgramID(), "tex");
glUniform1i(uniformTexSampler, 0);
uniformTexSampler = glGetUniformLocation(shaderFilterProgram->GetProgramID(), "lut");
glUniform1i(uniformTexSampler, 1);
glUseProgram(0);
break;
}
case VideoFilterTypeID_LQ2XS:
{
glActiveTexture(GL_TEXTURE0 + 1);
glBindTexture(GL_TEXTURE_3D, this->_texLQ2xLUT);
glActiveTexture(GL_TEXTURE0);
shaderFilterProgram->SetVertexAndFragmentShaderOGL(Sample3x3_VertShader_110, ScalerLQ2xSFragShader_110, _useShader150);
glUseProgram(shaderFilterProgram->GetProgramID());
GLint uniformTexSampler = glGetUniformLocation(shaderFilterProgram->GetProgramID(), "tex");
glUniform1i(uniformTexSampler, 0);
uniformTexSampler = glGetUniformLocation(shaderFilterProgram->GetProgramID(), "lut");
glUniform1i(uniformTexSampler, 1);
glUseProgram(0);
break;
}
case VideoFilterTypeID_HQ2X:
{
glActiveTexture(GL_TEXTURE0 + 1);
glBindTexture(GL_TEXTURE_3D, this->_texHQ2xLUT);
glActiveTexture(GL_TEXTURE0);
shaderFilterProgram->SetVertexAndFragmentShaderOGL(Sample3x3_VertShader_110, ScalerHQ2xFragShader_110, _useShader150);
glUseProgram(shaderFilterProgram->GetProgramID());
GLint uniformTexSampler = glGetUniformLocation(shaderFilterProgram->GetProgramID(), "tex");
glUniform1i(uniformTexSampler, 0);
uniformTexSampler = glGetUniformLocation(shaderFilterProgram->GetProgramID(), "lut");
glUniform1i(uniformTexSampler, 1);
glUseProgram(0);
break;
}
case VideoFilterTypeID_HQ2XS:
{
glActiveTexture(GL_TEXTURE0 + 1);
glBindTexture(GL_TEXTURE_3D, this->_texHQ2xLUT);
glActiveTexture(GL_TEXTURE0);
shaderFilterProgram->SetVertexAndFragmentShaderOGL(Sample3x3_VertShader_110, ScalerHQ2xSFragShader_110, _useShader150);
glUseProgram(shaderFilterProgram->GetProgramID());
GLint uniformTexSampler = glGetUniformLocation(shaderFilterProgram->GetProgramID(), "tex");
glUniform1i(uniformTexSampler, 0);
uniformTexSampler = glGetUniformLocation(shaderFilterProgram->GetProgramID(), "lut");
glUniform1i(uniformTexSampler, 1);
glUseProgram(0);
break;
}
case VideoFilterTypeID_HQ4X:
{
glActiveTexture(GL_TEXTURE0 + 1);
glBindTexture(GL_TEXTURE_3D, this->_texHQ4xLUT);
glActiveTexture(GL_TEXTURE0);
shaderFilterProgram->SetVertexAndFragmentShaderOGL(Sample3x3_VertShader_110, ScalerHQ4xFragShader_110, _useShader150);
glUseProgram(shaderFilterProgram->GetProgramID());
GLint uniformTexSampler = glGetUniformLocation(shaderFilterProgram->GetProgramID(), "tex");
glUniform1i(uniformTexSampler, 0);
uniformTexSampler = glGetUniformLocation(shaderFilterProgram->GetProgramID(), "lut");
glUniform1i(uniformTexSampler, 1);
glUseProgram(0);
break;
}
case VideoFilterTypeID_HQ4XS:
{
glActiveTexture(GL_TEXTURE0 + 1);
glBindTexture(GL_TEXTURE_3D, this->_texHQ4xLUT);
glActiveTexture(GL_TEXTURE0);
shaderFilterProgram->SetVertexAndFragmentShaderOGL(Sample3x3_VertShader_110, ScalerHQ4xSFragShader_110, _useShader150);
glUseProgram(shaderFilterProgram->GetProgramID());
GLint uniformTexSampler = glGetUniformLocation(shaderFilterProgram->GetProgramID(), "tex");
glUniform1i(uniformTexSampler, 0);
uniformTexSampler = glGetUniformLocation(shaderFilterProgram->GetProgramID(), "lut");
glUniform1i(uniformTexSampler, 1);
glUseProgram(0);
break;
}
case VideoFilterTypeID_2xBRZ:
{
if (this->_shaderSupport >= ShaderSupport_MidTier)
{
shaderFilterProgram->SetVertexAndFragmentShaderOGL(Sample5x5_VertShader_110, Scaler2xBRZFragShader_110, _useShader150);
}
else if (this->_shaderSupport >= ShaderSupport_LowTier)
{
shaderFilterProgram->SetVertexAndFragmentShaderOGL(Sample4x4_VertShader_110, Scaler2xBRZFragShader_110, _useShader150);
}
else
{
willUseShaderBasedPixelScaler = false;
}
break;
}
case VideoFilterTypeID_3xBRZ:
{
if (this->_shaderSupport >= ShaderSupport_MidTier)
{
shaderFilterProgram->SetVertexAndFragmentShaderOGL(Sample5x5_VertShader_110, Scaler3xBRZFragShader_110, _useShader150);
}
else if (this->_shaderSupport >= ShaderSupport_LowTier)
{
shaderFilterProgram->SetVertexAndFragmentShaderOGL(Sample4x4_VertShader_110, Scaler3xBRZFragShader_110, _useShader150);
}
else
{
willUseShaderBasedPixelScaler = false;
}
break;
}
case VideoFilterTypeID_4xBRZ:
{
if (this->_shaderSupport >= ShaderSupport_MidTier)
{
shaderFilterProgram->SetVertexAndFragmentShaderOGL(Sample5x5_VertShader_110, Scaler4xBRZFragShader_110, _useShader150);
}
else if (this->_shaderSupport >= ShaderSupport_LowTier)
{
shaderFilterProgram->SetVertexAndFragmentShaderOGL(Sample4x4_VertShader_110, Scaler4xBRZFragShader_110, _useShader150);
}
else
{
willUseShaderBasedPixelScaler = false;
}
break;
}
case VideoFilterTypeID_5xBRZ:
{
if (this->_shaderSupport >= ShaderSupport_MidTier)
{
shaderFilterProgram->SetVertexAndFragmentShaderOGL(Sample5x5_VertShader_110, Scaler5xBRZFragShader_110, _useShader150);
}
else
{
willUseShaderBasedPixelScaler = false;
}
break;
}
default:
willUseShaderBasedPixelScaler = false;
break;
}
if (willUseShaderBasedPixelScaler)
{
_shaderFilter[i]->SetScaleOGL(vfScale);
}
}
return willUseShaderBasedPixelScaler;
}
void OGLDisplayLayer::SetCPUPixelScalerOGL(const VideoFilterTypeID filterID)
{
bool needResizeTexture = false;
const VideoFilterAttributes newFilterAttr = VideoFilter::GetAttributesByID(filterID);
const GLsizei oldDstBufferWidth = this->_vf[0]->GetDstWidth() + this->_vf[1]->GetDstWidth();
const GLsizei oldDstBufferHeight = this->_vf[0]->GetDstHeight() + this->_vf[1]->GetDstHeight();
const GLsizei newDstBufferWidth = (this->_vf[0]->GetSrcWidth() + this->_vf[1]->GetSrcWidth()) * newFilterAttr.scaleMultiply / newFilterAttr.scaleDivide;
const GLsizei newDstBufferHeight = (this->_vf[0]->GetSrcHeight() + this->_vf[1]->GetSrcHeight()) * newFilterAttr.scaleMultiply / newFilterAttr.scaleDivide;
if (oldDstBufferWidth != newDstBufferWidth || oldDstBufferHeight != newDstBufferHeight)
{
needResizeTexture = true;
}
if (needResizeTexture)
{
uint32_t *oldMasterBuffer = _vfMasterDstBuffer;
uint32_t *newMasterBuffer = (uint32_t *)calloc(newDstBufferWidth * newDstBufferHeight, sizeof(uint32_t));
this->_vf[0]->SetDstBufferPtr(newMasterBuffer);
this->_vf[1]->SetDstBufferPtr(newMasterBuffer + ((this->_vf[0]->GetSrcWidth() * newFilterAttr.scaleMultiply / newFilterAttr.scaleDivide) * (this->_vf[0]->GetSrcHeight() * newFilterAttr.scaleMultiply / newFilterAttr.scaleDivide)) );
this->_vfDual->SetDstBufferPtr(newMasterBuffer);
const GLsizei newDstBufferSingleWidth = this->_vf[0]->GetSrcWidth() * newFilterAttr.scaleMultiply / newFilterAttr.scaleDivide;
const GLsizei newDstBufferSingleHeight = this->_vf[0]->GetSrcHeight() * newFilterAttr.scaleMultiply / newFilterAttr.scaleDivide;
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, this->_texCPUFilterDstID[0]);
glTextureRangeAPPLE(GL_TEXTURE_RECTANGLE_ARB, newDstBufferSingleWidth * newDstBufferSingleHeight * sizeof(uint32_t), newMasterBuffer);
glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_STORAGE_HINT_APPLE, GL_STORAGE_CACHED_APPLE);
glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA, newDstBufferSingleWidth, newDstBufferSingleHeight, 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, newMasterBuffer);
glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, this->_texCPUFilterDstID[1]);
glTextureRangeAPPLE(GL_TEXTURE_RECTANGLE_ARB, newDstBufferSingleWidth * newDstBufferSingleHeight * sizeof(uint32_t), newMasterBuffer + (newDstBufferSingleWidth * newDstBufferSingleHeight));
glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_STORAGE_HINT_APPLE, GL_STORAGE_CACHED_APPLE);
glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA, newDstBufferSingleWidth, newDstBufferSingleHeight, 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, newMasterBuffer + (newDstBufferSingleWidth * newDstBufferSingleHeight));
glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);
_vfMasterDstBuffer = newMasterBuffer;
free(oldMasterBuffer);
}
this->_vf[0]->ChangeFilterByID(filterID);
this->_vf[1]->ChangeFilterByID(filterID);
this->_vfDual->ChangeFilterByID(filterID);
}
void OGLDisplayLayer::LoadFrameOGL(const uint16_t *frameData, GLint x, GLint y, GLsizei w, GLsizei h)
{
const bool isUsingCPUPixelScaler = this->_pixelScaler != VideoFilterTypeID_None && !this->_useShaderBasedPixelScaler;
bool loadDualScreen = (y == 0) && (h > GPU_DISPLAY_HEIGHT);
bool loadSingleMainScreen = (y == 0);
bool loadSingleTouchScreen = (y > 0);
if (!isUsingCPUPixelScaler || this->_useDeposterize)
{
if (loadDualScreen)
{
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, this->_texVideoInputDataID[0]);
glTexSubImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, 0, 0, w, h/2, GL_RGBA, GL_UNSIGNED_SHORT_1_5_5_5_REV, frameData);
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, this->_texVideoInputDataID[1]);
glTexSubImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, 0, 0, w, h/2, GL_RGBA, GL_UNSIGNED_SHORT_1_5_5_5_REV, frameData + (w * (h/2)));
}
else if (loadSingleMainScreen)
{
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, this->_texVideoInputDataID[0]);
glTexSubImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, 0, 0, w, h, GL_RGBA, GL_UNSIGNED_SHORT_1_5_5_5_REV, frameData);
}
else if (loadSingleTouchScreen)
{
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, this->_texVideoInputDataID[1]);
glTexSubImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, 0, 0, w, h, GL_RGBA, GL_UNSIGNED_SHORT_1_5_5_5_REV, frameData);
}
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);
}
else
{
RGB555ToBGRA8888Buffer(frameData, (loadDualScreen) ? this->_vfDual->GetSrcBufferPtr() : this->_vf[(loadSingleMainScreen) ? 0 : 1]->GetSrcBufferPtr(), w * h);
}
}
void OGLDisplayLayer::ProcessOGL()
{
const bool isUsingCPUPixelScaler = this->_pixelScaler != VideoFilterTypeID_None && !this->_useShaderBasedPixelScaler;
const int displayMode = this->GetMode();
// Source
if (this->_useDeposterize)
{
this->_texVideoSourceID[0] = this->_filterDeposterize[0]->RunFilterOGL(this->_texVideoInputDataID[0]);
this->_texVideoSourceID[1] = this->_filterDeposterize[1]->RunFilterOGL(this->_texVideoInputDataID[1]);
if (isUsingCPUPixelScaler) // Hybrid CPU/GPU-based path (may cause a performance hit on pixel download)
{
switch (displayMode)
{
case DS_DISPLAY_TYPE_MAIN:
this->_filterDeposterize[0]->DownloadDstBufferOGL(this->_vf[0]->GetSrcBufferPtr(), 0, this->_filterDeposterize[0]->GetSrcHeight());
break;
case DS_DISPLAY_TYPE_TOUCH:
this->_filterDeposterize[1]->DownloadDstBufferOGL(this->_vf[1]->GetSrcBufferPtr(), 0, this->_filterDeposterize[1]->GetSrcHeight());
break;
case DS_DISPLAY_TYPE_DUAL:
this->_filterDeposterize[0]->DownloadDstBufferOGL(this->_vfDual->GetSrcBufferPtr(), 0, this->_filterDeposterize[0]->GetSrcHeight());
this->_filterDeposterize[1]->DownloadDstBufferOGL(this->_vfDual->GetSrcBufferPtr() + (this->_vf[0]->GetSrcWidth() * this->_vf[0]->GetSrcHeight()), 0, this->_filterDeposterize[1]->GetSrcHeight());
break;
default:
break;
}
}
}
else
{
this->_texVideoSourceID[0] = this->_texVideoInputDataID[0];
this->_texVideoSourceID[1] = this->_texVideoInputDataID[1];
}
// Pixel scaler
if (!isUsingCPUPixelScaler)
{
if (this->_useShaderBasedPixelScaler)
{
this->_texVideoPixelScalerID[0] = this->_shaderFilter[0]->RunFilterOGL(this->_texVideoSourceID[0]);
this->_texVideoPixelScalerID[1] = this->_shaderFilter[1]->RunFilterOGL(this->_texVideoSourceID[1]);
this->UpdateTexCoords(this->_shaderFilter[0]->GetDstWidth(), this->_shaderFilter[0]->GetDstHeight());
}
else
{
this->_texVideoPixelScalerID[0] = this->_texVideoSourceID[0];
this->_texVideoPixelScalerID[1] = this->_texVideoSourceID[1];
this->UpdateTexCoords(this->_vf[0]->GetSrcWidth(), this->_vf[0]->GetSrcHeight());
}
}
else
{
switch (displayMode)
{
case DS_DISPLAY_TYPE_MAIN:
{
uint32_t *texData = this->_vf[0]->RunFilter();
this->_texVideoPixelScalerID[0] = this->_texCPUFilterDstID[0];
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, this->_texVideoPixelScalerID[0]);
glTexSubImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, 0, 0, this->_vf[0]->GetDstWidth(), this->_vf[0]->GetDstHeight(), GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, texData);
break;
}
case DS_DISPLAY_TYPE_TOUCH:
{
uint32_t *texData = this->_vf[1]->RunFilter();
this->_texVideoPixelScalerID[1] = this->_texCPUFilterDstID[1];
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, this->_texVideoPixelScalerID[1]);
glTexSubImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, 0, 0, this->_vf[1]->GetDstWidth(), this->_vf[1]->GetDstHeight(), GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, texData);
break;
}
case DS_DISPLAY_TYPE_DUAL:
{
uint32_t *texData = this->_vfDual->RunFilter();
this->_texVideoPixelScalerID[0] = this->_texCPUFilterDstID[0];
this->_texVideoPixelScalerID[1] = this->_texCPUFilterDstID[1];
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, this->_texVideoPixelScalerID[0]);
glTexSubImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, 0, 0, this->_vf[0]->GetDstWidth(), this->_vf[0]->GetDstHeight(), GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, texData);
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, this->_texVideoPixelScalerID[1]);
glTexSubImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, 0, 0, this->_vf[1]->GetDstWidth(), this->_vf[1]->GetDstHeight(), GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, texData + (this->_vf[0]->GetDstWidth() * this->_vf[0]->GetDstHeight()));
break;
}
default:
break;
}
this->UpdateTexCoords(this->_vf[0]->GetDstWidth(), this->_vf[0]->GetDstHeight());
}
// Output
this->_texVideoOutputID[0] = this->_texVideoPixelScalerID[0];
this->_texVideoOutputID[1] = this->_texVideoPixelScalerID[1];
this->UploadTexCoordsOGL();
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);
}
void OGLDisplayLayer::RenderOGL()
{
glUseProgram(this->_finalOutputProgram->GetProgramID());
this->UploadTransformationOGL();
if (this->_needUploadVertices)
{
this->UploadVerticesOGL();
}
// Enable vertex attributes
glBindVertexArrayDESMUME(this->_vaoMainStatesID);
glClear(GL_COLOR_BUFFER_BIT);
switch (this->GetMode())
{
case DS_DISPLAY_TYPE_MAIN:
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, this->_texVideoOutputID[0]);
glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, this->_displayTexFilter[0]);
glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, this->_displayTexFilter[0]);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, 0);
break;
case DS_DISPLAY_TYPE_TOUCH:
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, this->_texVideoOutputID[1]);
glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, this->_displayTexFilter[1]);
glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, this->_displayTexFilter[1]);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, 0);
break;
case DS_DISPLAY_TYPE_DUAL:
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, this->_texVideoOutputID[0]);
glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, this->_displayTexFilter[0]);
glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, this->_displayTexFilter[0]);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, 0);
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, this->_texVideoOutputID[1]);
glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, this->_displayTexFilter[1]);
glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, this->_displayTexFilter[1]);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, (GLubyte *)(6 * sizeof(GLubyte)));
break;
default:
break;
}
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);
// Disable vertex attributes
glBindVertexArrayDESMUME(0);
}