macOS support and Intel driver bug fixes

This commit is contained in:
Magnus Norddahl 2016-10-16 22:40:08 +02:00
parent 052f7900c2
commit f81d0d3964
5 changed files with 120 additions and 97 deletions

View File

@ -75,46 +75,62 @@
CVAR(Int, gl_showpacks, 0, 0)
#ifndef WIN32 // Defined in fb_d3d9 for Windows
CVAR(Bool, vid_hwaalines, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
CUSTOM_CVAR(Bool, vid_hw2d, true, CVAR_NOINITCALL)
{
V_SetBorderNeedRefresh();
ST_SetNeedRefresh();
}
#else
EXTERN_CVAR(Bool, vid_hwaalines)
EXTERN_CVAR(Bool, vid_hw2d)
#endif
EXTERN_CVAR(Bool, vid_hw2d)
EXTERN_CVAR(Bool, fullscreen)
EXTERN_CVAR(Float, Gamma)
EXTERN_CVAR(Bool, vid_vsync)
EXTERN_CVAR(Float, transsouls)
EXTERN_CVAR(Int, vid_refreshrate)
#ifdef WIN32
extern cycle_t BlitCycles;
#endif
void gl_LoadExtensions();
void gl_PrintStartupLog();
#ifndef WIN32
// This has to be in this file because system headers conflict Doom headers
DFrameBuffer *CreateGLSWFrameBuffer(int width, int height, bool fullscreen)
{
return new OpenGLSWFrameBuffer(NULL, width, height, 32, 60, fullscreen);
}
#endif
IMPLEMENT_CLASS(OpenGLSWFrameBuffer)
const char *const OpenGLSWFrameBuffer::ShaderDefines[OpenGLSWFrameBuffer::NUM_SHADERS] =
{
"#define ENORMALCOLOR\n#define PALTEX 0\n#define DINVERT 0", // NormalColor
"#define ENORMALCOLOR\n#define PALTEX 1\n#define INVERT 0", // NormalColorPal
"#define ENORMALCOLOR\n#define PALTEX 0\n#define INVERT 1", // NormalColorInv
"#define ENORMALCOLOR\n#define PALTEX 1\n#define INVERT 1", // NormalColorPalInv
"#define ENORMALCOLOR", // NormalColor
"#define ENORMALCOLOR\n#define PALTEX", // NormalColorPal
"#define ENORMALCOLOR\n#define INVERT", // NormalColorInv
"#define ENORMALCOLOR\n#define PALTEX\n#define INVERT", // NormalColorPalInv
"#define EREDTOALPHA\n#define INVERT 0", // RedToAlpha
"#define EREDTOALPHA\n#define INVERT 1", // RedToAlphaInv
"#define EREDTOALPHA", // RedToAlpha
"#define EREDTOALPHA\n#define INVERT", // RedToAlphaInv
"#define EVERTEXCOLOR", // VertexColor
"#define ESPECIALCOLORMAP\n#define PALTEX 0\n#define INVERT 0", // SpecialColormap
"#define ESPECIALCOLORMAP\n#define PALTEX 1\n#define INVERT 0", // SpecialColorMapPal
"#define ESPECIALCOLORMAP\n", // SpecialColormap
"#define ESPECIALCOLORMAP\n#define PALTEX", // SpecialColorMapPal
"#define EINGAMECOLORMAP\n#define PALTEX 0\n#define INVERT 0\n#define DESAT 0", // InGameColormap
"#define EINGAMECOLORMAP\n#define PALTEX 0\n#define INVERT 0\n#define DESAT 1", // InGameColormapDesat
"#define EINGAMECOLORMAP\n#define PALTEX 0\n#define INVERT 1\n#define DESAT 0", // InGameColormapInv
"#define EINGAMECOLORMAP\n#define PALTEX 0\n#define INVERT 1\n#define DESAT 1", // InGameColormapInvDesat
"#define EINGAMECOLORMAP\n#define PALTEX 1\n#define INVERT 0\n#define DESAT 0", // InGameColormapPal
"#define EINGAMECOLORMAP\n#define PALTEX 1\n#define INVERT 0\n#define DESAT 1", // InGameColormapPalDesat
"#define EINGAMECOLORMAP\n#define PALTEX 1\n#define INVERT 1\n#define DESAT 0", // InGameColormapPalInv
"#define EINGAMECOLORMAP\n#define PALTEX 1\n#define INVERT 1\n#define DESAT 1", // InGameColormapPalInvDesat
"#define EINGAMECOLORMAP", // InGameColormap
"#define EINGAMECOLORMAP\n#define DESAT", // InGameColormapDesat
"#define EINGAMECOLORMAP\n#define INVERT", // InGameColormapInv
"#define EINGAMECOLORMAP\n#define INVERT\n#define DESAT", // InGameColormapInvDesat
"#define EINGAMECOLORMAP\n#define PALTEX\n", // InGameColormapPal
"#define EINGAMECOLORMAP\n#define PALTEX\n#define DESAT", // InGameColormapPalDesat
"#define EINGAMECOLORMAP\n#define PALTEX\n#define INVERT", // InGameColormapPalInv
"#define EINGAMECOLORMAP\n#define PALTEX\n#define INVERT\n#define DESAT", // InGameColormapPalInvDesat
"#define EBURNWIPE", // BurnWipe
"#define EGAMMACORRECTION", // GammaCorrection
@ -131,6 +147,11 @@ OpenGLSWFrameBuffer::OpenGLSWFrameBuffer(void *hMonitor, int width, int height,
}
gl_LoadExtensions();
InitializeState();
if (first)
{
gl_PrintStartupLog();
first = false;
}
// SetVSync needs to be at the very top to workaround a bug in Nvidia's OpenGL driver.
// If wglSwapIntervalEXT is called after glBindFramebuffer in a frame the setting is not changed!
@ -197,6 +218,19 @@ OpenGLSWFrameBuffer::~OpenGLSWFrameBuffer()
delete[] QuadExtra;
}
void *OpenGLSWFrameBuffer::MapBuffer(int target, int size)
{
if (glMapBufferRange)
{
return (FBVERTEX*)glMapBufferRange(target, 0, size, GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_RANGE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT);
}
else
{
glBufferData(target, size, nullptr, GL_STREAM_DRAW);
return glMapBuffer(target, GL_WRITE_ONLY);
}
}
OpenGLSWFrameBuffer::HWFrameBuffer::~HWFrameBuffer()
{
if (Framebuffer != 0) glDeleteFramebuffers(1, (GLuint*)&Framebuffer);
@ -218,7 +252,7 @@ OpenGLSWFrameBuffer::HWVertexBuffer::~HWVertexBuffer()
OpenGLSWFrameBuffer::FBVERTEX *OpenGLSWFrameBuffer::HWVertexBuffer::Lock()
{
glBindBuffer(GL_ARRAY_BUFFER, Buffer);
return (FBVERTEX*)glMapBufferRange(GL_ARRAY_BUFFER, 0, Size, GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_RANGE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT);
return (FBVERTEX*)MapBuffer(GL_ARRAY_BUFFER, Size);
}
void OpenGLSWFrameBuffer::HWVertexBuffer::Unlock()
@ -236,7 +270,7 @@ uint16_t *OpenGLSWFrameBuffer::HWIndexBuffer::Lock()
{
glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, &LockedOldBinding);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, Buffer);
return (uint16_t*)glMapBufferRange(GL_ELEMENT_ARRAY_BUFFER, 0, Size, GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_RANGE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT);
return (uint16_t*)MapBuffer(GL_ELEMENT_ARRAY_BUFFER, Size);
}
void OpenGLSWFrameBuffer::HWIndexBuffer::Unlock()
@ -281,6 +315,7 @@ bool OpenGLSWFrameBuffer::CreateFrameBuffer(const FString &name, int width, int
if (result != GL_FRAMEBUFFER_COMPLETE)
{
//Printf("Framebuffer is not complete");
outFramebuffer = nullptr;
return false;
}
@ -296,9 +331,15 @@ bool OpenGLSWFrameBuffer::CreatePixelShader(FString vertexsrc, FString fragments
shader->Program = glCreateProgram();
shader->VertexShader = glCreateShader(GL_VERTEX_SHADER);
shader->FragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
vertexsrc = "#version 130\n" + defines + "\n#line 0\n" + vertexsrc;
fragmentsrc = "#version 130\n" + defines + "\n#line 0\n" + fragmentsrc;
int maxGlslVersion = 330;
int shaderVersion = MIN((int)round(gl.glslversion * 10) * 10, maxGlslVersion);
FString prefix;
prefix.AppendFormat("#version %d\n%s\n#line 0\n", shaderVersion, defines.GetChars());
vertexsrc = prefix + vertexsrc;
fragmentsrc = prefix + fragmentsrc;
{
int lengths[1] = { (int)vertexsrc.Len() };
@ -320,10 +361,11 @@ bool OpenGLSWFrameBuffer::CreatePixelShader(FString vertexsrc, FString fragments
if (status != GL_FALSE) { errorShader = shader->FragmentShader; glGetShaderiv(shader->FragmentShader, GL_COMPILE_STATUS, &status); }
if (status == GL_FALSE)
{
/*static char buffer[10000];
static char buffer[10000];
GLsizei length = 0;
buffer[0] = 0;
glGetShaderInfoLog(errorShader, 10000, &length, buffer);*/
glGetShaderInfoLog(errorShader, 10000, &length, buffer);
//Printf("Shader compile failed: %s", buffer);
*outShader = nullptr;
return false;
@ -332,17 +374,23 @@ bool OpenGLSWFrameBuffer::CreatePixelShader(FString vertexsrc, FString fragments
glAttachShader(shader->Program, shader->VertexShader);
glAttachShader(shader->Program, shader->FragmentShader);
glBindFragDataLocation(shader->Program, 0, "FragColor");
glLinkProgram(shader->Program);
glGetProgramiv(shader->Program, GL_LINK_STATUS, &status);
if (status == GL_FALSE)
{
*outShader = nullptr;
return false;
}
glBindAttribLocation(shader->Program, 0, "AttrPosition");
glBindAttribLocation(shader->Program, 1, "AttrColor0");
glBindAttribLocation(shader->Program, 2, "AttrColor1");
glBindAttribLocation(shader->Program, 3, "AttrTexCoord0");
glLinkProgram(shader->Program);
glGetProgramiv(shader->Program, GL_LINK_STATUS, &status);
if (status == GL_FALSE)
{
static char buffer[10000];
GLsizei length = 0;
buffer[0] = 0;
glGetProgramInfoLog(shader->Program, 10000, &length, buffer);
//Printf("Shader compile failed: %s", buffer);
*outShader = nullptr;
return false;
}
shader->ConstantLocations[PSCONST_Desaturation] = glGetUniformLocation(shader->Program, "Desaturation");
shader->ConstantLocations[PSCONST_PaletteMod] = glGetUniformLocation(shader->Program, "PaletteMod");
@ -767,8 +815,6 @@ bool OpenGLSWFrameBuffer::LoadShaders()
FString shaderdir, shaderpath;
unsigned int i;
// We determine the best available model simply by trying them all in
// order of decreasing preference.
for (i = 0; i < NUM_SHADERS; ++i)
{
shaderpath = shaderdir;
@ -804,7 +850,9 @@ bool OpenGLSWFrameBuffer::LoadShaders()
void OpenGLSWFrameBuffer::ReleaseResources()
{
#ifdef WIN32
I_SaveWindowedPos();
#endif
KillNativeTexs();
KillNativePals();
ReleaseDefaultPoolItems();
@ -1011,27 +1059,6 @@ int OpenGLSWFrameBuffer::GetPageCount()
return 1;
}
//==========================================================================
//
// OpenGLSWFrameBuffer :: PaletteChanged
//
//==========================================================================
void OpenGLSWFrameBuffer::PaletteChanged()
{
}
//==========================================================================
//
// OpenGLSWFrameBuffer :: QueryNewPalette
//
//==========================================================================
int OpenGLSWFrameBuffer::QueryNewPalette()
{
return 0;
}
//==========================================================================
//
// OpenGLSWFrameBuffer :: IsValid
@ -1043,17 +1070,6 @@ bool OpenGLSWFrameBuffer::IsValid()
return true;
}
//==========================================================================
//
// OpenGLSWFrameBuffer :: IsFullscreen
//
//==========================================================================
bool OpenGLSWFrameBuffer::IsFullscreen()
{
return !Windowed;
}
//==========================================================================
//
// OpenGLSWFrameBuffer :: Lock
@ -1080,8 +1096,6 @@ bool OpenGLSWFrameBuffer::Lock(bool buffered)
void OpenGLSWFrameBuffer::Unlock()
{
LOG1("Unlock <%d>\n", LockCount);
if (LockCount == 0)
{
return;
@ -1146,7 +1160,7 @@ void OpenGLSWFrameBuffer::Update()
NeedGammaUpdate = false;
igamma = 1 / Gamma;
if (!Windowed)
if (IsFullscreen())
{
GammaRamp ramp;
@ -1154,7 +1168,6 @@ void OpenGLSWFrameBuffer::Update()
{
ramp.blue[i] = ramp.green[i] = ramp.red[i] = uint16_t(65535.f * powf(i / 255.f, igamma));
}
LOG("SetGammaRamp\n");
SetGammaRamp(&ramp);
}
psgamma[2] = psgamma[1] = psgamma[0] = igamma;
@ -1168,8 +1181,10 @@ void OpenGLSWFrameBuffer::Update()
NeedPalUpdate = false;
}
#ifdef WIN32
BlitCycles.Reset();
BlitCycles.Clock();
#endif
LockCount = 0;
Draw3DPart(In2D <= 1);
@ -1178,8 +1193,10 @@ void OpenGLSWFrameBuffer::Update()
Flip();
}
#ifdef WIN32
BlitCycles.Unclock();
//LOG1 ("cycles = %d\n", BlitCycles);
#endif
Buffer = nullptr;
UpdatePending = false;
@ -1198,7 +1215,7 @@ void OpenGLSWFrameBuffer::Flip()
Present();
InScene = false;
if (Windowed)
if (!IsFullscreen())
{
int clientWidth = GetClientWidth();
int clientHeight = GetClientHeight();
@ -1221,6 +1238,8 @@ void OpenGLSWFrameBuffer::Flip()
//
//==========================================================================
#ifdef WIN32
bool OpenGLSWFrameBuffer::PaintToWindow()
{
if (LockCount != 0)
@ -1231,6 +1250,8 @@ bool OpenGLSWFrameBuffer::PaintToWindow()
return true;
}
#endif
//==========================================================================
//
// OpenGLSWFrameBuffer :: Draw3DPart
@ -1257,7 +1278,7 @@ void OpenGLSWFrameBuffer::Draw3DPart(bool copy3d)
FBTexture->CurrentBuffer = (FBTexture->CurrentBuffer + 1) & 1;
}
uint8_t *dest = (uint8_t*)glMapBufferRange(GL_PIXEL_UNPACK_BUFFER, 0, Width * Height, GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_RANGE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT);
uint8_t *dest = (uint8_t*)MapBuffer(GL_PIXEL_UNPACK_BUFFER, Width * Height);
if (dest)
{
if (Pitch == Width)
@ -1382,7 +1403,7 @@ void OpenGLSWFrameBuffer::UploadPalette()
PaletteTexture->CurrentBuffer = (PaletteTexture->CurrentBuffer + 1) & 1;
}
uint8_t *pix = (uint8_t*)glMapBufferRange(GL_PIXEL_UNPACK_BUFFER, 0, 256 * 4, GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_RANGE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT);
uint8_t *pix = (uint8_t*)MapBuffer(GL_PIXEL_UNPACK_BUFFER, 256 * 4);
if (pix)
{
int i;
@ -1427,7 +1448,6 @@ void OpenGLSWFrameBuffer::UpdatePalette()
bool OpenGLSWFrameBuffer::SetGamma(float gamma)
{
LOG1("SetGamma %g\n", gamma);
Gamma = gamma;
NeedGammaUpdate = true;
return true;
@ -1473,16 +1493,12 @@ void OpenGLSWFrameBuffer::SetVSync(bool vsync)
void OpenGLSWFrameBuffer::NewRefreshRate()
{
if (!Windowed)
if (IsFullscreen())
{
Reset();
}
}
void OpenGLSWFrameBuffer::Blank()
{
}
void OpenGLSWFrameBuffer::SetBlendingRect(int x1, int y1, int x2, int y2)
{
BlendingRect.left = x1;
@ -2013,7 +2029,7 @@ bool OpenGLSWFrameBuffer::OpenGLTex::Update()
Box->Owner->Tex->CurrentBuffer = (Box->Owner->Tex->CurrentBuffer + 1) & 1;
int pitch = (rect.right - rect.left) * bytesPerPixel;
uint8_t *bits = (uint8_t *)glMapBufferRange(GL_PIXEL_UNPACK_BUFFER, 0, buffersize, GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_RANGE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT);
uint8_t *bits = (uint8_t *)MapBuffer(GL_PIXEL_UNPACK_BUFFER, buffersize);
dest = bits;
if (!dest)
{
@ -2062,7 +2078,10 @@ bool OpenGLSWFrameBuffer::OpenGLTex::Update()
GLint oldBinding = 0;
glGetIntegerv(GL_TEXTURE_BINDING_2D, &oldBinding);
glBindTexture(GL_TEXTURE_2D, Box->Owner->Tex->Texture);
glTexSubImage2D(GL_TEXTURE_2D, 0, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, format == GL_RGBA8 ? GL_BGRA : GL_RED, GL_UNSIGNED_BYTE, 0);
if (format == GL_RGBA8)
glTexSubImage2D(GL_TEXTURE_2D, 0, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, GL_BGRA, GL_UNSIGNED_BYTE, 0);
else
glTexSubImage2D(GL_TEXTURE_2D, 0, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, GL_RED, GL_UNSIGNED_BYTE, 0);
glBindTexture(GL_TEXTURE_2D, oldBinding);
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
return true;
@ -2215,7 +2234,7 @@ bool OpenGLSWFrameBuffer::OpenGLPal::Update()
Tex->CurrentBuffer = (Tex->CurrentBuffer + 1) & 1;
}
buff = (uint32_t *)glMapBufferRange(GL_PIXEL_UNPACK_BUFFER, 0, Remap->NumEntries * 4, GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_RANGE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT);
buff = (uint32_t *)MapBuffer(GL_PIXEL_UNPACK_BUFFER, Remap->NumEntries * 4);
if (buff == nullptr)
{
return false;

View File

@ -19,7 +19,7 @@ class OpenGLSWFrameBuffer : public Win32GLFrameBuffer
DECLARE_CLASS(OpenGLSWFrameBuffer, Win32GLFrameBuffer)
#else
#include "sdlglvideo.h"
class OpenGLFrameBuffer : public SDLGLFB
class OpenGLSWFrameBuffer : public SDLGLFB
{
// typedef SDLGLFB Super; //[C]commented, DECLARE_CLASS defines this in linux
DECLARE_CLASS(OpenGLSWFrameBuffer, SDLGLFB)
@ -32,6 +32,7 @@ public:
OpenGLSWFrameBuffer(void *hMonitor, int width, int height, int bits, int refreshHz, bool fullscreen);
~OpenGLSWFrameBuffer();
bool IsValid() override;
bool Lock(bool buffered) override;
void Unlock() override;
@ -43,11 +44,6 @@ public:
bool SetFlash(PalEntry rgb, int amount) override;
void GetFlash(PalEntry &rgb, int &amount) override;
int GetPageCount() override;
bool IsFullscreen() override;
void PaletteChanged() override;
int QueryNewPalette() override;
void Blank() override;
bool PaintToWindow() override;
void SetVSync(bool vsync) override;
void NewRefreshRate() override;
void GetScreenshotBuffer(const uint8_t *&buffer, int &pitch, ESSType &color_type) override;
@ -68,8 +64,15 @@ public:
void WipeEndScreen() override;
bool WipeDo(int ticks) override;
void WipeCleanup() override;
#ifdef WIN32
void PaletteChanged() override { }
int QueryNewPalette() override { return 0; }
void Blank() override { }
bool PaintToWindow() override;
bool Is8BitMode() override { return false; }
int GetTrueHeight() override { return TrueHeight; }
#endif
private:
struct FBVERTEX
@ -195,6 +198,8 @@ private:
static uint32_t ColorRGBA(uint32_t r, uint32_t g, uint32_t b, uint32_t a) { return ColorARGB(a, r, g, b); }
static uint32_t ColorXRGB(uint32_t r, uint32_t g, uint32_t b) { return ColorARGB(0xff, r, g, b); }
static uint32_t ColorValue(float r, float g, float b, float a) { return ColorRGBA((uint32_t)(r * 255.0f), (uint32_t)(g * 255.0f), (uint32_t)(b * 255.0f), (uint32_t)(a * 255.0f)); }
static void *MapBuffer(int target, int size);
// The number of points for the vertex buffer.
enum { NUM_VERTS = 10240 };
@ -310,9 +315,6 @@ private:
BQS_InGameColormap,
};
struct PackedTexture;
struct Atlas;
struct BufferedTris
{
uint8_t Flags;

View File

@ -383,8 +383,8 @@ bool OpenGLSWFrameBuffer::Wiper_Melt::Run(int ticks, OpenGLSWFrameBuffer *fb)
}
if (ticks == 0)
{ // Only draw for the final tick.
RECT rect;
POINT dpt;
LTRBRect rect;
struct Point { int x, y; } dpt;
dpt.x = i * fbwidth / WIDTH;
dpt.y = MAX(0, y[i] * fbheight / HEIGHT);

View File

@ -101,6 +101,7 @@
@end
DFrameBuffer *CreateGLSWFrameBuffer(int width, int height, bool fullscreen);
EXTERN_CVAR(Bool, ticker )
EXTERN_CVAR(Bool, vid_vsync)
@ -483,7 +484,7 @@ NSOpenGLPixelFormat* CreatePixelFormat(const OpenGLProfile profile)
attributes[i++] = NSOpenGLPFAAllowOfflineRenderers;
}
if (NSAppKitVersionNumber >= AppKit10_7 && OpenGLProfile::Core == profile && 1 == vid_renderer)
if (NSAppKitVersionNumber >= AppKit10_7 && OpenGLProfile::Core == profile)
{
NSOpenGLPixelFormatAttribute profile = NSOpenGLProfileVersion3_2Core;
const char* const glversion = Args->CheckValue("-glversion");
@ -622,7 +623,8 @@ DFrameBuffer* CocoaVideo::CreateFrameBuffer(const int width, const int height, c
}
else
{
fb = new CocoaFrameBuffer(width, height, fullscreen);
//fb = new CocoaFrameBuffer(width, height, fullscreen);
fb = CreateGLSWFrameBuffer(width, height, fullscreen);
}
fb->SetFlash(flashColor, flashAmount);

View File

@ -17,7 +17,7 @@ uniform vec4 Gamma;
vec4 TextureLookup(vec2 tex_coord)
{
#if PALTEX
#if defined(PALTEX)
float index = texture(Image, tex_coord).x;
index = index * PaletteMod.x + PaletteMod.y;
return texture(Palette, vec2(index, 0.5));
@ -28,7 +28,7 @@ vec4 TextureLookup(vec2 tex_coord)
vec4 Invert(vec4 rgb)
{
#if INVERT
#if defined(INVERT)
rgb.rgb = Weights.www - rgb.xyz;
#endif
return rgb;
@ -90,7 +90,7 @@ vec4 InGameColormap(vec2 tex_coord, vec4 color, vec4 fade)
vec4 rgb = SampleTexture(tex_coord);
// Desaturate
#if DESAT
#if defined(DESAT)
vec3 intensity;
intensity.rgb = vec3(Grayscale(rgb) * Desaturation.x);
rgb.rgb = intensity.rgb + rgb.rgb * Desaturation.y;