diff --git a/src/gl/system/gl_swframebuffer.cpp b/src/gl/system/gl_swframebuffer.cpp index e03f1fd9c5..895508d8b1 100644 --- a/src/gl/system/gl_swframebuffer.cpp +++ b/src/gl/system/gl_swframebuffer.cpp @@ -71,7 +71,6 @@ #include "gl/utility/gl_templates.h" #include "gl/gl_functions.h" -CVAR(Bool, gl_antilag, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) CVAR(Int, gl_showpacks, 0, 0) #ifndef WIN32 // Defined in fb_d3d9 for Windows CVAR(Bool, vid_hwaalines, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) @@ -88,63 +87,66 @@ EXTERN_CVAR(Int, vid_refreshrate) extern cycle_t BlitCycles; +void gl_LoadExtensions(); + IMPLEMENT_CLASS(OpenGLSWFrameBuffer) -const char *const OpenGLSWFrameBuffer::ShaderNames[OpenGLSWFrameBuffer::NUM_SHADERS] = +const char *const OpenGLSWFrameBuffer::ShaderDefines[OpenGLSWFrameBuffer::NUM_SHADERS] = { - "NormalColor", - "NormalColorPal", - "NormalColorInv", - "NormalColorPalInv", + "#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 - "RedToAlpha", - "RedToAlphaInv", + "#define EREDTOALPHA\n#define INVERT 0", // RedToAlpha + "#define EREDTOALPHA\n#define INVERT 1", // RedToAlphaInv - "VertexColor", + "#define EVERTEXCOLOR", // VertexColor - "SpecialColormap", - "SpecialColorMapPal", + "#define ESPECIALCOLORMAP\n#define PALTEX 0\n#define INVERT 0", // SpecialColormap + "#define ESPECIALCOLORMAP\n#define PALTEX 1\n#define INVERT 0", // SpecialColorMapPal - "InGameColormap", - "InGameColormapDesat", - "InGameColormapInv", - "InGameColormapInvDesat", - "InGameColormapPal", - "InGameColormapPalDesat", - "InGameColormapPalInv", - "InGameColormapPalInvDesat", + "#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 - "BurnWipe", - "GammaCorrection", + "#define EBURNWIPE", // BurnWipe + "#define EGAMMACORRECTION", // GammaCorrection }; OpenGLSWFrameBuffer::OpenGLSWFrameBuffer(void *hMonitor, int width, int height, int bits, int refreshHz, bool fullscreen) : Super(hMonitor, width, height, bits, refreshHz, fullscreen) { + // To do: this needs to cooperate with the same static in OpenGLFrameBuffer::InitializeState + static bool first = true; + if (first) + { + ogl_LoadFunctions(); + } + gl_LoadExtensions(); + Super::InitializeState(); + // 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! - SetVSync(vid_vsync); + //SetVSync(vid_vsync); VertexBuffer = nullptr; IndexBuffer = nullptr; FBTexture = nullptr; - TempRenderTexture = nullptr; - RenderTexture[0] = nullptr; - RenderTexture[1] = nullptr; InitialWipeScreen = nullptr; ScreenshotTexture = nullptr; - ScreenshotSurface = nullptr; FinalWipeScreen = nullptr; PaletteTexture = nullptr; - GammaTexture = nullptr; - FrontCopySurface = nullptr; for (int i = 0; i < NUM_SHADERS; ++i) { Shaders[i] = nullptr; } GammaShader = nullptr; - BlockSurface[0] = nullptr; - BlockSurface[1] = nullptr; VSync = vid_vsync; BlendingRect.left = 0; BlendingRect.top = 0; @@ -160,9 +162,6 @@ OpenGLSWFrameBuffer::OpenGLSWFrameBuffer(void *hMonitor, int width, int height, QuadExtra = new BufferedTris[MAX_QUAD_BATCH]; Atlases = nullptr; PixelDoubling = 0; - SkipAt = -1; - CurrRenderTexture = 0; - RenderTextureToggle = 0; Gamma = 1.0; FlashColor0 = 0; @@ -180,7 +179,7 @@ OpenGLSWFrameBuffer::OpenGLSWFrameBuffer(void *hMonitor, int width, int height, memcpy(SourcePalette, GPalette.BaseColors, sizeof(PalEntry) * 256); - Windowed = !(static_cast(Video)->GoFullscreen(fullscreen)); + //Windowed = !(static_cast(Video)->GoFullscreen(fullscreen)); TrueHeight = height; /*if (fullscreen) @@ -209,7 +208,56 @@ OpenGLSWFrameBuffer::~OpenGLSWFrameBuffer() delete[] QuadExtra; } -bool OpenGLSWFrameBuffer::CreatePixelShader(const void *vertexsrc, const void *fragmentsrc, HWPixelShader **outShader) +OpenGLSWFrameBuffer::HWTexture::~HWTexture() +{ + if (Texture != 0) glDeleteTextures(1, (GLuint*)&Texture); + if (Buffer != 0) glDeleteBuffers(1, (GLuint*)&Buffer); +} + +OpenGLSWFrameBuffer::HWVertexBuffer::~HWVertexBuffer() +{ + if (VertexArray != 0) glDeleteVertexArrays(1, (GLuint*)&VertexArray); + if (Buffer != 0) glDeleteBuffers(1, (GLuint*)&Buffer); +} + +OpenGLSWFrameBuffer::FBVERTEX *OpenGLSWFrameBuffer::HWVertexBuffer::Lock() +{ + glBindBuffer(GL_ARRAY_BUFFER, Buffer); + return (FBVERTEX*)glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY); +} + +void OpenGLSWFrameBuffer::HWVertexBuffer::Unlock() +{ + glUnmapBuffer(GL_ARRAY_BUFFER); + glBindBuffer(GL_ARRAY_BUFFER, 0); +} + +OpenGLSWFrameBuffer::HWIndexBuffer::~HWIndexBuffer() +{ + if (Buffer != 0) glDeleteBuffers(1, (GLuint*)&Buffer); +} + +uint16_t *OpenGLSWFrameBuffer::HWIndexBuffer::Lock() +{ + glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, &LockedOldBinding); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, Buffer); + return (uint16_t*)glMapBuffer(GL_ELEMENT_ARRAY_BUFFER, GL_WRITE_ONLY); +} + +void OpenGLSWFrameBuffer::HWIndexBuffer::Unlock() +{ + glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, LockedOldBinding); +} + +OpenGLSWFrameBuffer::HWPixelShader::~HWPixelShader() +{ + if (Program != 0) glDeleteProgram(Program); + if (VertexShader != 0) glDeleteShader(VertexShader); + if (FragmentShader != 0) glDeleteShader(FragmentShader); +} + +bool OpenGLSWFrameBuffer::CreatePixelShader(FString vertexsrc, FString fragmentsrc, const FString &defines, HWPixelShader **outShader) { auto shader = std::make_unique(); @@ -217,25 +265,34 @@ bool OpenGLSWFrameBuffer::CreatePixelShader(const void *vertexsrc, const void *f 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 lengths[1] = { (int)strlen((const char*)vertexsrc) }; - const char *sources[1] = { (const char*)vertexsrc }; + int lengths[1] = { (int)vertexsrc.Len() }; + const char *sources[1] = { vertexsrc.GetChars() }; glShaderSource(shader->VertexShader, 1, sources, lengths); glCompileShader(shader->VertexShader); } { - int lengths[1] = { (int)strlen((const char*)fragmentsrc) }; - const char *sources[1] = { (const char*)fragmentsrc }; + int lengths[1] = { (int)fragmentsrc.Len() }; + const char *sources[1] = { fragmentsrc.GetChars() }; glShaderSource(shader->FragmentShader, 1, sources, lengths); glCompileShader(shader->FragmentShader); } GLint status = 0; + int errorShader = shader->VertexShader; glGetShaderiv(shader->VertexShader, GL_COMPILE_STATUS, &status); - if (status != GL_FALSE) glGetShaderiv(shader->FragmentShader, GL_COMPILE_STATUS, &status); + if (status != GL_FALSE) { errorShader = shader->FragmentShader; glGetShaderiv(shader->FragmentShader, GL_COMPILE_STATUS, &status); } if (status == GL_FALSE) { + static char buffer[10000]; + GLsizei length = 0; + buffer[0] = 0; + glGetShaderInfoLog(errorShader, 10000, &length, buffer); + *outShader = nullptr; return false; } @@ -308,6 +365,8 @@ bool OpenGLSWFrameBuffer::CreateTexture(int width, int height, int levels, int f { auto obj = std::make_unique(); + obj->Format = format; + GLint oldBinding = 0; glGetIntegerv(GL_TEXTURE_BINDING_2D, &oldBinding); @@ -317,7 +376,7 @@ bool OpenGLSWFrameBuffer::CreateTexture(int width, int height, int levels, int f switch (format) { case GL_R8: srcformat = GL_RED; break; - case GL_RGBA8: srcformat = GL_RGBA; break; + case GL_RGBA8: srcformat = GL_BGRA; break; case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: srcformat = GL_RGB; break; case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: srcformat = GL_RGBA; break; case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: srcformat = GL_RGBA; break; @@ -327,6 +386,8 @@ bool OpenGLSWFrameBuffer::CreateTexture(int width, int height, int levels, int f return false; } glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, srcformat, GL_UNSIGNED_BYTE, nullptr); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glBindTexture(GL_TEXTURE_2D, oldBinding); @@ -334,16 +395,9 @@ bool OpenGLSWFrameBuffer::CreateTexture(int width, int height, int levels, int f return true; } -bool OpenGLSWFrameBuffer::CreateOffscreenPlainSurface(int width, int height, int format, HWSurface **outSurface) { *outSurface = nullptr; return false; } -bool OpenGLSWFrameBuffer::CreateRenderTarget(int width, int height, int format, HWSurface **outSurface) { *outSurface = nullptr; return false; } -bool OpenGLSWFrameBuffer::GetBackBuffer(HWSurface **outSurface) { *outSurface = nullptr; return false; } -bool OpenGLSWFrameBuffer::GetRenderTarget(int index, HWSurface **outSurface) { *outSurface = nullptr; return false; } -void OpenGLSWFrameBuffer::GetRenderTargetData(HWSurface *a, HWSurface *b) { } - -void OpenGLSWFrameBuffer::ColorFill(HWSurface *surface, float red, float green, float blue) { } -void OpenGLSWFrameBuffer::StretchRect(HWSurface *src, const LTRBRect *srcrect, HWSurface *dest) { } -bool OpenGLSWFrameBuffer::SetRenderTarget(int index, HWSurface *surface) { return true; } -void OpenGLSWFrameBuffer::SetGammaRamp(const GammaRamp *ramp) { } +void OpenGLSWFrameBuffer::SetGammaRamp(const GammaRamp *ramp) +{ +} void OpenGLSWFrameBuffer::SetPixelShaderConstantF(int uniformIndex, const float *data, int vec4fcount) { @@ -487,7 +541,6 @@ void OpenGLSWFrameBuffer::SetInitialState() NeedGammaUpdate = true; NeedPalUpdate = true; - OldRenderTarget = nullptr; // This constant is used for grayscaling weights (.xyz) and color inversion (.w) float weights[4] = { 77 / 256.f, 143 / 256.f, 37 / 256.f, 1 }; @@ -524,7 +577,6 @@ bool OpenGLSWFrameBuffer::CreateResources() { return false; } - CreateBlockSurfaces(); return true; } @@ -539,42 +591,36 @@ bool OpenGLSWFrameBuffer::CreateResources() bool OpenGLSWFrameBuffer::LoadShaders() { - static const char models[][4] = { "30/", "20/", "14/" }; + int lumpvert = Wads.CheckNumForFullName("shaders/glsl/swshader.vp"); + int lumpfrag = Wads.CheckNumForFullName("shaders/glsl/swshader.fp"); + if (lumpvert < 0 || lumpfrag < 0) + return false; + + FString vertsource = Wads.ReadLump(lumpvert).GetString(); + FString fragsource = Wads.ReadLump(lumpfrag).GetString(); + FString shaderdir, shaderpath; - unsigned model, i; - int lump, lumpvert; + unsigned int i; // We determine the best available model simply by trying them all in // order of decreasing preference. - for (model = 0; model < countof(models); ++model) + for (i = 0; i < NUM_SHADERS; ++i) { - shaderdir = "shaders/gl/sm"; - shaderdir += models[model]; - for (i = 0; i < NUM_SHADERS; ++i) + shaderpath = shaderdir; + if (!CreatePixelShader(vertsource, fragsource, ShaderDefines[i], &Shaders[i]) && i < SHADER_BurnWipe) { - shaderpath = shaderdir; - lump = Wads.CheckNumForFullName(shaderpath + ShaderNames[i] + ".fp"); - lumpvert = Wads.CheckNumForFullName(shaderpath + ShaderNames[i] + ".vp"); - if (lump >= 0 && lumpvert >= 0) - { - FMemLump data = Wads.ReadLump(lump); - FMemLump datavert = Wads.ReadLump(lumpvert); - if (!CreatePixelShader(datavert.GetMem(), data.GetMem(), &Shaders[i]) && i < SHADER_BurnWipe) - { - break; - } - } - } - if (i == NUM_SHADERS) - { // Success! - return true; - } - // Failure. Release whatever managed to load (which is probably nothing.) - for (i = 0; i < NUM_SHADERS; ++i) - { - SafeRelease(Shaders[i]); + break; } } + if (i == NUM_SHADERS) + { // Success! + return true; + } + // Failure. Release whatever managed to load (which is probably nothing.) + for (i = 0; i < NUM_SHADERS; ++i) + { + SafeRelease(Shaders[i]); + } return false; } @@ -590,7 +636,6 @@ void OpenGLSWFrameBuffer::ReleaseResources() KillNativeTexs(); KillNativePals(); ReleaseDefaultPoolItems(); - SafeRelease(ScreenshotSurface); SafeRelease(ScreenshotTexture); SafeRelease(PaletteTexture); for (int i = 0; i < NUM_SHADERS; ++i) @@ -616,14 +661,9 @@ void OpenGLSWFrameBuffer::ReleaseDefaultPoolItems() { SafeRelease(FBTexture); SafeRelease(FinalWipeScreen); - SafeRelease(RenderTexture[0]); - SafeRelease(RenderTexture[1]); SafeRelease(InitialWipeScreen); SafeRelease(VertexBuffer); SafeRelease(IndexBuffer); - SafeRelease(BlockSurface[0]); - SafeRelease(BlockSurface[1]); - SafeRelease(FrontCopySurface); } bool OpenGLSWFrameBuffer::Reset() @@ -633,32 +673,10 @@ bool OpenGLSWFrameBuffer::Reset() { return false; } - CreateBlockSurfaces(); SetInitialState(); return true; } -//========================================================================== -// -// OpenGLSWFrameBuffer :: CreateBlockSurfaces -// -// Create blocking surfaces for antilag. It's okay if these can't be -// created; antilag just won't work. -// -//========================================================================== - -void OpenGLSWFrameBuffer::CreateBlockSurfaces() -{ - BlockNum = 0; - if (CreateOffscreenPlainSurface(16, 16, GL_RGBA8, &BlockSurface[0])) - { - if (!CreateOffscreenPlainSurface(16, 16, GL_RGBA8, &BlockSurface[1])) - { - SafeRelease(BlockSurface[0]); - } - } -} - //========================================================================== // // OpenGLSWFrameBuffer :: KillNativePals @@ -691,80 +709,11 @@ void OpenGLSWFrameBuffer::KillNativeTexs() } } -//========================================================================== -// -// OpenGLSWFrameBuffer :: CreateFBTexture -// -// Creates the "Framebuffer" texture. With the advent of hardware-assisted -// 2D, this is something of a misnomer now. The FBTexture is only used for -// uploading the software 3D image to video memory so that it can be drawn -// to the real frame buffer. -// -// It also creates the TempRenderTexture, since this seemed like a -// convenient place to do so. -// -//========================================================================== - bool OpenGLSWFrameBuffer::CreateFBTexture() { - if (!CreateTexture(Width, Height, 1, GL_R8, &FBTexture)) - { - int pow2width, pow2height, i; - - for (i = 1; i < Width; i <<= 1) {} pow2width = i; - for (i = 1; i < Height; i <<= 1) {} pow2height = i; - - if (!CreateTexture(pow2width, pow2height, 1, GL_R8, &FBTexture)) - { - return false; - } - else - { - FBWidth = pow2width; - FBHeight = pow2height; - } - } - else - { - FBWidth = Width; - FBHeight = Height; - } - RenderTextureToggle = 0; - RenderTexture[0] = nullptr; - RenderTexture[1] = nullptr; - if (!CreateTexture(FBWidth, FBHeight, 1, GL_RGBA8, &RenderTexture[0])) - { - return false; - } - if (Windowed || PixelDoubling) - { - // Windowed or pixel doubling: Create another render texture so we can flip between them. - RenderTextureToggle = 1; - if (!CreateTexture(FBWidth, FBHeight, 1, GL_RGBA8, &RenderTexture[1])) - { - return false; - } - } - else - { - // Fullscreen and not pixel doubling: Create a render target to have the back buffer copied to. - if (!CreateRenderTarget(Width, Height, GL_RGBA8, &FrontCopySurface)) - { - return false; - } - } - // Initialize the TempRenderTextures to black. - for (int i = 0; i <= RenderTextureToggle; ++i) - { - HWSurface *surf; - if (RenderTexture[i]->GetSurfaceLevel(0, &surf)) - { - ColorFill(surf, 0.0f, 0.0f, 0.0f); - delete surf; - } - } - TempRenderTexture = RenderTexture[0]; - CurrRenderTexture = 0; + CreateTexture(Width, Height, 1, GL_R8, &FBTexture); + FBWidth = Width; + FBHeight = Height; return true; } @@ -814,7 +763,7 @@ bool OpenGLSWFrameBuffer::CreateVertexes() void OpenGLSWFrameBuffer::CalcFullscreenCoords(FBVERTEX verts[4], bool viewarea_only, bool can_double, uint32_t color0, uint32_t color1) const { - float offset = OldRenderTarget != nullptr ? 0 : LBOffset; + float offset = LBOffset;//OldRenderTarget != nullptr ? 0 : LBOffset; float top = offset - 0.5f; float texright = float(Width) / float(FBWidth); float texbot = float(Height) / float(FBHeight); @@ -1042,18 +991,6 @@ void OpenGLSWFrameBuffer::Update() LOG("SetGammaRamp\n"); SetGammaRamp(&ramp); } - else - { - if (igamma != 1) - { - UpdateGammaTexture(igamma); - GammaShader = Shaders[SHADER_GammaCorrection]; - } - else - { - GammaShader = nullptr; - } - } psgamma[2] = psgamma[1] = psgamma[0] = igamma; psgamma[3] = 0.5; // For SM14 version SetPixelShaderConstantF(PSCONST_Gamma, psgamma, 1); @@ -1094,21 +1031,6 @@ void OpenGLSWFrameBuffer::Flip() DrawLetterbox(); DoWindowedGamma(); - CopyNextFrontBuffer(); - - // Attempt to counter input lag. - if (gl_antilag && BlockSurface[0] != nullptr) - { - LockedRect lr; - volatile int dummy; - ColorFill(BlockSurface[BlockNum], 0.0f, 0x20/255.0f, 0x50/255.0f); - BlockNum ^= 1; - if (BlockSurface[BlockNum]->LockRect(&lr, nullptr, false)) - { - dummy = *(int *)lr.pBits; - BlockSurface[BlockNum]->UnlockRect(); - } - } // Limiting the frame rate is as simple as waiting for the timer to signal this event. if (FPSLimitEvent != nullptr) { @@ -1117,13 +1039,6 @@ void OpenGLSWFrameBuffer::Flip() Present(); InScene = false; - if (RenderTextureToggle) - { - // Flip the TempRenderTexture to the other one now. - CurrRenderTexture ^= RenderTextureToggle; - TempRenderTexture = RenderTexture[CurrRenderTexture]; - } - if (Windowed) { int clientWidth = GetClientWidth(); @@ -1143,42 +1058,6 @@ void OpenGLSWFrameBuffer::Flip() } } -//========================================================================== -// -// OpenGLSWFrameBuffer :: CopyNextFrontBuffer -// -// Duplicates the contents of the back buffer that will become the front -// buffer upon Present into FrontCopySurface so that we can get the -// contents of the display without wasting time in GetFrontBufferData(). -// -//========================================================================== - -void OpenGLSWFrameBuffer::CopyNextFrontBuffer() -{ - HWSurface *backbuff; - - if (Windowed || PixelDoubling) - { - // Windowed mode or pixel doubling: TempRenderTexture has what we want - SafeRelease(FrontCopySurface); - if (TempRenderTexture->GetSurfaceLevel(0, &backbuff)) - { - FrontCopySurface = backbuff; - } - } - else - { - // Fullscreen, not pixel doubled: The back buffer has what we want, - // but it might be letter boxed. - if (GetBackBuffer(&backbuff)) - { - LTRBRect srcrect = { 0, LBOffsetI, Width, LBOffsetI + Height }; - StretchRect(backbuff, &srcrect, FrontCopySurface); - delete backbuff; - } - } -} - //========================================================================== // // OpenGLSWFrameBuffer :: PaintToWindow @@ -1207,50 +1086,49 @@ void OpenGLSWFrameBuffer::Draw3DPart(bool copy3d) { if (copy3d) { - LTRBRect texrect = { 0, 0, Width, Height }; - LockedRect lockrect; - - if ((FBWidth == Width && FBHeight == Height && - FBTexture->LockRect(&lockrect, nullptr, true)) || - FBTexture->LockRect(&lockrect, &texrect, false)) + if (FBTexture->Buffer == 0) { - if (lockrect.Pitch == Pitch && Pitch == Width) + glGenBuffers(1, (GLuint*)&FBTexture->Buffer); + glBindBuffer(GL_PIXEL_UNPACK_BUFFER, FBTexture->Buffer); + glBufferData(GL_PIXEL_UNPACK_BUFFER, Width * Height, nullptr, GL_STREAM_DRAW); + } + else + { + glBindBuffer(GL_PIXEL_UNPACK_BUFFER, FBTexture->Buffer); + } + + uint8_t *dest = (uint8_t*)glMapBuffer(GL_PIXEL_UNPACK_BUFFER, GL_WRITE_ONLY); + if (dest) + { + if (Pitch == Width) { - memcpy(lockrect.pBits, MemBuffer, Width * Height); + memcpy(dest, MemBuffer, Width * Height); } else { - uint8_t *dest = (uint8_t *)lockrect.pBits; uint8_t *src = MemBuffer; for (int y = 0; y < Height; y++) { memcpy(dest, src, Width); - dest += lockrect.Pitch; + dest += Width; src += Pitch; } } - FBTexture->UnlockRect(); + glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER); + GLint oldBinding = 0; + glGetIntegerv(GL_TEXTURE_BINDING_2D, &oldBinding); + glBindTexture(GL_TEXTURE_2D, FBTexture->Texture); + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, Width, Height, GL_R8, GL_UNSIGNED_BYTE, 0); + glBindTexture(GL_TEXTURE_2D, oldBinding); } + + glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); } InScene = true; if (vid_hwaalines) glEnable(GL_LINE_SMOOTH); else glDisable(GL_LINE_SMOOTH); - assert(OldRenderTarget == nullptr); - if (TempRenderTexture != nullptr && - ((Windowed && TempRenderTexture != FinalWipeScreen) || GatheringWipeScreen || PixelDoubling)) - { - HWSurface *targetsurf; - if (TempRenderTexture->GetSurfaceLevel(0, &targetsurf)) - { - if (GetRenderTarget(0, &OldRenderTarget)) - { - SetRenderTarget(0, targetsurf); - } - delete targetsurf; - } - } SetTexture(0, FBTexture); SetPaletteTexture(PaletteTexture, 256, BorderColor); @@ -1271,10 +1149,8 @@ void OpenGLSWFrameBuffer::Draw3DPart(bool copy3d) } else { - color0 = ColorValue(realfixedcolormap->ColorizeStart[0] / 2, - realfixedcolormap->ColorizeStart[1] / 2, realfixedcolormap->ColorizeStart[2] / 2, 0); - color1 = ColorValue(realfixedcolormap->ColorizeEnd[0] / 2, - realfixedcolormap->ColorizeEnd[1] / 2, realfixedcolormap->ColorizeEnd[2] / 2, 1); + color0 = ColorValue(realfixedcolormap->ColorizeStart[0] / 2, realfixedcolormap->ColorizeStart[1] / 2, realfixedcolormap->ColorizeStart[2] / 2, 0); + color1 = ColorValue(realfixedcolormap->ColorizeEnd[0] / 2, realfixedcolormap->ColorizeEnd[1] / 2, realfixedcolormap->ColorizeEnd[2] / 2, 1); SetPixelShader(Shaders[SHADER_SpecialColormapPal]); } } @@ -1323,7 +1199,7 @@ void OpenGLSWFrameBuffer::DrawLetterbox() void OpenGLSWFrameBuffer::DoWindowedGamma() { - if (OldRenderTarget != nullptr) + /*if (OldRenderTarget != nullptr) { FBVERTEX verts[4]; @@ -1336,49 +1212,28 @@ void OpenGLSWFrameBuffer::DoWindowedGamma() DrawTriangleFans(2, verts); delete OldRenderTarget; OldRenderTarget = nullptr; - } -} - -//========================================================================== -// -// OpenGLSWFrameBuffer :: UpdateGammaTexture -// -// Updates the gamma texture used by the PS14 shader. We only use the first -// half of the texture so that we needn't worry about imprecision causing -// it to grab from the border. -// -//========================================================================== - -void OpenGLSWFrameBuffer::UpdateGammaTexture(float igamma) -{ - LockedRect lockrect; - - if (GammaTexture != nullptr && GammaTexture->LockRect(&lockrect, nullptr, false)) - { - uint8_t *pix = (uint8_t *)lockrect.pBits; - for (int i = 0; i <= 128; ++i) - { - pix[i * 4 + 2] = pix[i * 4 + 1] = pix[i * 4] = uint8_t(255.f * powf(i / 128.f, igamma)); - pix[i * 4 + 3] = 255; - } - GammaTexture->UnlockRect(); - } + }*/ } void OpenGLSWFrameBuffer::UploadPalette() { - LockedRect lockrect; - - if (SkipAt < 0) + if (PaletteTexture->Buffer == 0) { - SkipAt = 256; + glGenBuffers(1, (GLuint*)&PaletteTexture->Buffer); + glBindBuffer(GL_PIXEL_UNPACK_BUFFER, PaletteTexture->Buffer); + glBufferData(GL_PIXEL_UNPACK_BUFFER, 256 * 4, nullptr, GL_STREAM_DRAW); } - if (PaletteTexture->LockRect(&lockrect, nullptr, false)) + else + { + glBindBuffer(GL_PIXEL_UNPACK_BUFFER, PaletteTexture->Buffer); + } + + uint8_t *pix = (uint8_t *)glMapBuffer(GL_PIXEL_UNPACK_BUFFER, GL_WRITE_ONLY); + if (pix) { - uint8_t *pix = (uint8_t *)lockrect.pBits; int i; - for (i = 0; i < SkipAt; ++i, pix += 4) + for (i = 0; i < 256; ++i, pix += 4) { pix[0] = SourcePalette[i].b; pix[1] = SourcePalette[i].g; @@ -1394,9 +1249,16 @@ void OpenGLSWFrameBuffer::UploadPalette() pix[2] = SourcePalette[i].r; pix[3] = 255; } - PaletteTexture->UnlockRect(); + glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER); + GLint oldBinding = 0; + glGetIntegerv(GL_TEXTURE_BINDING_2D, &oldBinding); + glBindTexture(GL_TEXTURE_2D, PaletteTexture->Texture); + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 256, 1, GL_BGRA, GL_UNSIGNED_BYTE, 0); + glBindTexture(GL_TEXTURE_2D, oldBinding); BorderColor = ColorXRGB(SourcePalette[255].r, SourcePalette[255].g, SourcePalette[255].b); } + + glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); } PalEntry *OpenGLSWFrameBuffer::GetPalette() @@ -1484,6 +1346,8 @@ void OpenGLSWFrameBuffer::SetBlendingRect(int x1, int y1, int x2, int y2) void OpenGLSWFrameBuffer::GetScreenshotBuffer(const uint8_t *&buffer, int &pitch, ESSType &color_type) { + Super::GetScreenshotBuffer(buffer, pitch, color_type); + /* LockedRect lrect; if (!Accel2D) @@ -1513,6 +1377,7 @@ void OpenGLSWFrameBuffer::GetScreenshotBuffer(const uint8_t *&buffer, int &pitch color_type = SS_BGRA; } } + */ } //========================================================================== @@ -1527,58 +1392,9 @@ void OpenGLSWFrameBuffer::ReleaseScreenshotBuffer() { Super::ReleaseScreenshotBuffer(); } - if (ScreenshotSurface != nullptr) - { - ScreenshotSurface->UnlockRect(); - delete ScreenshotSurface; - ScreenshotSurface = nullptr; - } SafeRelease(ScreenshotTexture); } -//========================================================================== -// -// OpenGLSWFrameBuffer :: GetCurrentScreen -// -// Returns a texture containing the pixels currently visible on-screen. -// -//========================================================================== - -OpenGLSWFrameBuffer::HWTexture *OpenGLSWFrameBuffer::GetCurrentScreen() -{ - HWTexture *tex; - HWSurface *surf; - bool hr; - - if (FrontCopySurface == nullptr) - { - return nullptr; - } - - hr = CreateTexture(FBWidth, FBHeight, 1, GL_RGBA8, &tex); - - if (!hr) - { - return nullptr; - } - if (!tex->GetSurfaceLevel(0, &surf)) - { - delete tex; - return nullptr; - } - - // Video -> System memory : use GetRenderTargetData - GetRenderTargetData(FrontCopySurface, surf); - delete surf; - - if (!hr) - { - delete tex; - return nullptr; - } - return tex; -} - /**************************************************************************/ /* 2D Stuff */ /**************************************************************************/ @@ -2013,7 +1829,6 @@ bool OpenGLSWFrameBuffer::OpenGLTex::Create(OpenGLSWFrameBuffer *fb, bool wrappi bool OpenGLSWFrameBuffer::OpenGLTex::Update() { - LockedRect lrect; LTRBRect rect; uint8_t *dest; @@ -2025,27 +1840,44 @@ bool OpenGLSWFrameBuffer::OpenGLTex::Update() int format = Box->Owner->Tex->Format; rect = Box->Area; - if (!Box->Owner->Tex->LockRect(&lrect, &rect, false)) + + if (Box->Owner->Tex->Buffer == 0) + glGenBuffers(1, (GLuint*)&Box->Owner->Tex->Buffer); + + int bytesPerPixel = 4; + switch (format) + { + case GL_R8: bytesPerPixel = 1; break; + case GL_RGBA8: bytesPerPixel = 4; break; + default: return false; + } + + glBindBuffer(GL_PIXEL_UNPACK_BUFFER, Box->Owner->Tex->Buffer); + glBufferData(GL_PIXEL_UNPACK_BUFFER, (rect.right - rect.left) * (rect.bottom - rect.top) * bytesPerPixel, nullptr, GL_STREAM_DRAW); + + int pitch = (rect.right - rect.left) * bytesPerPixel; + uint8_t *bits = (uint8_t *)glMapBuffer(GL_PIXEL_UNPACK_BUFFER, GL_WRITE_ONLY); + dest = bits; + if (!dest) { return false; } - dest = (uint8_t *)lrect.pBits; if (Box->Padded) { - dest += lrect.Pitch + (format == GL_R8 ? 1 : 4); + dest += pitch + (format == GL_R8 ? 1 : 4); } - GameTex->FillBuffer(dest, lrect.Pitch, GameTex->GetHeight(), ToTexFmt(format)); + GameTex->FillBuffer(dest, pitch, GameTex->GetHeight(), ToTexFmt(format)); if (Box->Padded) { // Clear top padding row. - dest = (uint8_t *)lrect.pBits; + dest = bits; int numbytes = GameTex->GetWidth() + 2; if (format != GL_R8) { numbytes <<= 2; } memset(dest, 0, numbytes); - dest += lrect.Pitch; + dest += pitch; // Clear left and right padding columns. if (format == GL_R8) { @@ -2053,7 +1885,7 @@ bool OpenGLSWFrameBuffer::OpenGLTex::Update() { dest[0] = 0; dest[numbytes - 1] = 0; - dest += lrect.Pitch; + dest += pitch; } } else @@ -2062,13 +1894,20 @@ bool OpenGLSWFrameBuffer::OpenGLTex::Update() { *(uint32_t *)dest = 0; *(uint32_t *)(dest + numbytes - 4) = 0; - dest += lrect.Pitch; + dest += pitch; } } // Clear bottom padding row. memset(dest, 0, numbytes); } - Box->Owner->Tex->UnlockRect(); + + glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER); + 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); + glBindTexture(GL_TEXTURE_2D, oldBinding); + glBindTexture(GL_PIXEL_UNPACK_BUFFER, 0); return true; } @@ -2199,18 +2038,28 @@ OpenGLSWFrameBuffer::OpenGLPal::~OpenGLPal() bool OpenGLSWFrameBuffer::OpenGLPal::Update() { - LockedRect lrect; uint32_t *buff; const PalEntry *pal; int skipat, i; assert(Tex != nullptr); - if (!Tex->LockRect(&lrect, nullptr, 0)) + if (Tex->Buffer == 0) + { + glGenBuffers(1, (GLuint*)&Tex->Buffer); + glBindBuffer(GL_PIXEL_UNPACK_BUFFER, Tex->Buffer); + glBufferData(GL_PIXEL_UNPACK_BUFFER, Remap->NumEntries * 4, nullptr, GL_STREAM_DRAW); + } + else + { + glBindBuffer(GL_PIXEL_UNPACK_BUFFER, Tex->Buffer); + } + + buff = (uint32_t *)glMapBuffer(GL_PIXEL_UNPACK_BUFFER, GL_WRITE_ONLY); + if (buff == nullptr) { return false; } - buff = (uint32_t *)lrect.pBits; pal = Remap->Palette; // See explanation in UploadPalette() for skipat rationale. @@ -2226,7 +2075,14 @@ bool OpenGLSWFrameBuffer::OpenGLPal::Update() } BorderColor = ColorARGB(pal[i].a, pal[i - 1].r, pal[i - 1].g, pal[i - 1].b); - Tex->UnlockRect(); + glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER); + GLint oldBinding = 0; + glGetIntegerv(GL_TEXTURE_BINDING_2D, &oldBinding); + glBindTexture(GL_TEXTURE_2D, Tex->Texture); + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, Remap->NumEntries, 1, GL_BGRA, GL_UNSIGNED_BYTE, 0); + glBindTexture(GL_TEXTURE_2D, oldBinding); + glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); + return true; } diff --git a/src/gl/system/gl_swframebuffer.h b/src/gl/system/gl_swframebuffer.h index 14ed2ec131..eed9b6f7f4 100644 --- a/src/gl/system/gl_swframebuffer.h +++ b/src/gl/system/gl_swframebuffer.h @@ -85,32 +85,18 @@ private: uint16_t red[256], green[256], blue[256]; }; - struct LockedRect - { - int Pitch; - void *pBits; - }; - struct LTRBRect { int left, top, right, bottom; }; - class HWSurface - { - public: - bool LockRect(LockedRect *outRect, LTRBRect *srcRect, bool discard) { outRect->Pitch = 0; outRect->pBits = nullptr; return false; } - void UnlockRect() { } - }; - class HWTexture { public: - bool LockRect(LockedRect *outRect, LTRBRect *srcRect, bool discard) { outRect->Pitch = 0; outRect->pBits = nullptr; return false; } - void UnlockRect() { } - bool GetSurfaceLevel(int level, HWSurface **outSurface) { *outSurface = nullptr; return false; } + ~HWTexture(); int Texture = 0; + int Buffer = 0; int WrapS = 0; int WrapT = 0; int Format = 0; @@ -119,60 +105,43 @@ private: class HWVertexBuffer { public: - ~HWVertexBuffer() - { - if (Buffer != 0) glDeleteVertexArrays(1, (GLuint*)&VertexArray); - if (Buffer != 0) glDeleteBuffers(1, (GLuint*)&Buffer); - } + ~HWVertexBuffer(); - FBVERTEX *Lock() { return nullptr; } - void Unlock() { } + FBVERTEX *Lock(); + void Unlock(); - int Buffer = 0; int VertexArray = 0; + int Buffer = 0; }; class HWIndexBuffer { public: - ~HWIndexBuffer() - { - if (Buffer != 0) glDeleteBuffers(1, (GLuint*)&Buffer); - } + ~HWIndexBuffer(); - uint16_t *Lock() { return nullptr; } - void Unlock() { } + uint16_t *Lock(); + void Unlock(); int Buffer = 0; + + private: + int LockedOldBinding = 0; }; class HWPixelShader { public: - ~HWPixelShader() - { - if (Program != 0) glDeleteProgram(Program); - if (VertexShader != 0) glDeleteShader(VertexShader); - if (FragmentShader != 0) glDeleteShader(FragmentShader); - } + ~HWPixelShader(); int Program = 0; int VertexShader = 0; int FragmentShader = 0; }; - bool CreatePixelShader(const void *vertexsrc, const void *fragmentsrc, HWPixelShader **outShader); + bool CreatePixelShader(FString vertexsrc, FString fragmentsrc, const FString &defines, HWPixelShader **outShader); bool CreateVertexBuffer(int size, HWVertexBuffer **outVertexBuffer); bool CreateIndexBuffer(int size, HWIndexBuffer **outIndexBuffer); - bool CreateOffscreenPlainSurface(int width, int height, int format, HWSurface **outSurface); bool CreateTexture(int width, int height, int levels, int format, HWTexture **outTexture); - bool CreateRenderTarget(int width, int height, int format, HWSurface **outSurface); - bool GetBackBuffer(HWSurface **outSurface); - bool GetRenderTarget(int index, HWSurface **outSurface); - void GetRenderTargetData(HWSurface *a, HWSurface *b); - void ColorFill(HWSurface *surface, float red, float green, float blue); - void StretchRect(HWSurface *src, const LTRBRect *srcrect, HWSurface *dest); - bool SetRenderTarget(int index, HWSurface *surface); void SetGammaRamp(const GammaRamp *ramp); void SetPixelShaderConstantF(int uniformIndex, const float *data, int vec4fcount); void SetHWPixelShader(HWPixelShader *shader); @@ -362,19 +331,17 @@ private: NUM_SHADERS }; - static const char *const ShaderNames[NUM_SHADERS]; + static const char *const ShaderDefines[NUM_SHADERS]; void Flip(); void SetInitialState(); bool CreateResources(); void ReleaseResources(); bool LoadShaders(); - void CreateBlockSurfaces(); bool CreateFBTexture(); bool CreatePaletteTexture(); bool CreateVertexes(); void UploadPalette(); - void UpdateGammaTexture(float igamma); void CalcFullscreenCoords(FBVERTEX verts[4], bool viewarea_only, bool can_double, uint32_t color0, uint32_t color1) const; bool Reset(); HWTexture *GetCurrentScreen(); @@ -397,7 +364,6 @@ private: void BeginLineBatch(); void EndLineBatch(); void EndBatch(); - void CopyNextFrontBuffer(); // State void EnableAlphaTest(BOOL enabled); @@ -431,10 +397,7 @@ private: int FlashAmount; int TrueHeight; int PixelDoubling; - int SkipAt; int LBOffsetI; - int RenderTextureToggle; - int CurrRenderTexture; float LBOffset; float Gamma; bool UpdatePending; @@ -448,34 +411,28 @@ private: bool GatheringWipeScreen; bool AALines; uint8_t BlockNum; - OpenGLPal *Palettes; - OpenGLTex *Textures; - Atlas *Atlases; + OpenGLPal *Palettes = nullptr; + OpenGLTex *Textures = nullptr; + Atlas *Atlases = nullptr; - HWTexture *FBTexture; - HWTexture *TempRenderTexture, *RenderTexture[2]; - HWTexture *PaletteTexture; - HWTexture *GammaTexture; - HWTexture *ScreenshotTexture; - HWSurface *ScreenshotSurface; - HWSurface *FrontCopySurface; + HWTexture *FBTexture = nullptr; + HWTexture *PaletteTexture = nullptr; + HWTexture *ScreenshotTexture = nullptr; - HWVertexBuffer *VertexBuffer; - FBVERTEX *VertexData; - HWIndexBuffer *IndexBuffer; - uint16_t *IndexData; - BufferedTris *QuadExtra; + HWVertexBuffer *VertexBuffer = nullptr; + FBVERTEX *VertexData = nullptr; + HWIndexBuffer *IndexBuffer = nullptr; + uint16_t *IndexData = nullptr; + BufferedTris *QuadExtra = nullptr; int VertexPos; int IndexPos; int QuadBatchPos; enum { BATCH_None, BATCH_Quads, BATCH_Lines } BatchType; HWPixelShader *Shaders[NUM_SHADERS]; - HWPixelShader *GammaShader; + HWPixelShader *GammaShader = nullptr; - HWSurface *BlockSurface[2]; - HWSurface *OldRenderTarget; - HWTexture *InitialWipeScreen, *FinalWipeScreen; + HWTexture *InitialWipeScreen = nullptr, *FinalWipeScreen = nullptr; class Wiper { diff --git a/src/win32/hardware.cpp b/src/win32/hardware.cpp index 787c0a4f38..2065a9072d 100644 --- a/src/win32/hardware.cpp +++ b/src/win32/hardware.cpp @@ -137,8 +137,9 @@ void I_InitGraphics () ticker.SetGenericRepDefault (val, CVAR_Bool); //currentrenderer = vid_renderer; - if (currentrenderer==1) Video = gl_CreateVideo(); - else Video = new Win32Video (0); + Video = gl_CreateVideo(); + //if (currentrenderer==1) Video = gl_CreateVideo(); + //else Video = new Win32Video (0); if (Video == NULL) I_FatalError ("Failed to initialize display"); diff --git a/src/win32/win32gliface.cpp b/src/win32/win32gliface.cpp index 5d68d84278..14d49c69bb 100644 --- a/src/win32/win32gliface.cpp +++ b/src/win32/win32gliface.cpp @@ -25,6 +25,7 @@ #include "gl/renderer/gl_renderer.h" #include "gl/system/gl_framebuffer.h" +#include "gl/system/gl_swframebuffer.h" extern "C" { _declspec(dllexport) DWORD NvOptimusEnablement = 0x00000001; @@ -386,7 +387,10 @@ DFrameBuffer *Win32GLVideo::CreateFrameBuffer(int width, int height, bool fs, DF //old->GetFlash(flashColor, flashAmount); delete old; } - fb = new OpenGLFrameBuffer(m_hMonitor, m_DisplayWidth, m_DisplayHeight, m_DisplayBits, m_DisplayHz, fs); + if (vid_renderer == 1) + fb = new OpenGLFrameBuffer(m_hMonitor, m_DisplayWidth, m_DisplayHeight, m_DisplayBits, m_DisplayHz, fs); + else + fb = new OpenGLSWFrameBuffer(m_hMonitor, m_DisplayWidth, m_DisplayHeight, m_DisplayBits, m_DisplayHz, fs); return fb; } diff --git a/wadsrc/static/shaders/glsl/swshader.fp b/wadsrc/static/shaders/glsl/swshader.fp new file mode 100644 index 0000000000..22364f4605 --- /dev/null +++ b/wadsrc/static/shaders/glsl/swshader.fp @@ -0,0 +1,146 @@ + +in vec4 PixelColor0; +in vec4 PixelColor1; +in vec4 PixelTexCoord0; + +out vec4 FragColor; + +uniform sampler2D Image;// : register(s0); +uniform sampler2D Palette;// : register(s1); +uniform sampler2D NewScreen;// : register(s0); +uniform sampler2D Burn;// : register(s1); + +uniform vec4 Desaturation;// : register(c1); // { Desat, 1 - Desat } +uniform vec4 PaletteMod;// : register(c2); +uniform vec4 Weights;// : register(c6); // RGB->Gray weighting { 77/256.0, 143/256.0, 37/256.0, 1 } +uniform vec4 Gamma;// : register(c7); + +vec4 TextureLookup(vec2 tex_coord) +{ +#if PALTEX + float index = texture(Image, tex_coord).x; + index = index * PaletteMod.x + PaletteMod.y; + return texture(Palette, vec2(index, 0.5)); +#else + return texture(Image, tex_coord); +#endif +} + +vec4 Invert(vec4 rgb) +{ +#if INVERT + rgb.rgb = Weights.www - rgb.xyz; +#endif + return rgb; +} + +float Grayscale(vec4 rgb) +{ + return dot(rgb.rgb, Weights.rgb); +} + +vec4 SampleTexture(vec2 tex_coord) +{ + return Invert(TextureLookup(tex_coord)); +} + +// Normal color calculation for most drawing modes. + +vec4 NormalColor(vec2 tex_coord, vec4 Flash, vec4 InvFlash) +{ + return Flash + SampleTexture(tex_coord) * InvFlash; +} + +// Copy the red channel to the alpha channel. Pays no attention to palettes. + +vec4 RedToAlpha(vec2 tex_coord, vec4 Flash, vec4 InvFlash) +{ + vec4 color = Invert(texture(Image, tex_coord)); + color.a = color.r; + return Flash + color * InvFlash; +} + +// Just return the value of c0. + +vec4 VertexColor(vec4 color) +{ + return color; +} + +// Emulate one of the special colormaps. (Invulnerability, gold, etc.) + +vec4 SpecialColormap(vec2 tex_coord, vec4 start, vec4 end) +{ + vec4 color = SampleTexture(tex_coord); + vec4 range = end - start; + // We can't store values greater than 1.0 in a color register, so we multiply + // the final result by 2 and expect the caller to divide the start and end by 2. + color.rgb = 2 * (start + Grayscale(color) * range).rgb; + // Duplicate alpha semantics of NormalColor. + color.a = start.a + color.a * end.a; + return color; +} + +// In-game colormap effect: fade to a particular color and multiply by another, with +// optional desaturation of the original color. Desaturation is stored in c1. +// Fade level is packed int fade.a. Fade.rgb has been premultiplied by alpha. +// Overall alpha is in color.a. +vec4 InGameColormap(vec2 tex_coord, vec4 color, vec4 fade) +{ + vec4 rgb = SampleTexture(tex_coord); + + // Desaturate +#if DESAT + vec3 intensity; + intensity.rgb = vec3(Grayscale(rgb) * Desaturation.x); + rgb.rgb = intensity.rgb + rgb.rgb * Desaturation.y; +#endif + + // Fade + rgb.rgb = rgb.rgb * fade.aaa + fade.rgb; + + // Shade and Alpha + rgb = rgb * color; + + return rgb; +} + +// Windowed gamma correction. + +vec4 GammaCorrection(vec2 tex_coord) +{ + vec4 color = texture(Image, tex_coord); + color.rgb = pow(color.rgb, Gamma.rgb); + return color; +} + +// The burn wipe effect. + +vec4 BurnWipe(vec4 coord) +{ + vec4 color = texture(NewScreen, coord.xy); + vec4 alpha = texture(Burn, coord.zw); + color.a = alpha.r * 2; + return color; +} + +void main() +{ +#if defined(ENORMALCOLOR) + FragColor = NormalColor(PixelTexCoord0.xy, PixelColor0, PixelColor1); +#elif defined(EREDTOALPHA) + FragColor = RedToAlpha(PixelTexCoord0.xy, PixelColor0, PixelColor1); +#elif defined(EVERTEXCOLOR) + FragColor = VertexColor(PixelColor0); +#elif defined(ESPECIALCOLORMAP) + FragColor = SpecialColormap(PixelTexCoord0.xy, PixelColor0, PixelColor1); +#elif defined(EINGAMECOLORMAP) + FragColor = InGameColormap(PixelTexCoord0.xy, PixelColor0, PixelColor1); +#elif defined(EBURNWIPE) + FragColor = BurnWipe(PixelTexCoord0); +#elif defined(EGAMMACORRECTION) + FragColor = GammaCorrection(PixelTexCoord0.xy); +#else + #error Entry point define is missing +#endif +} diff --git a/wadsrc/static/shaders/glsl/swshader.vp b/wadsrc/static/shaders/glsl/swshader.vp new file mode 100644 index 0000000000..4d00296cba --- /dev/null +++ b/wadsrc/static/shaders/glsl/swshader.vp @@ -0,0 +1,17 @@ + +in vec4 AttrPosition; +in vec4 AttrColor0; +in vec4 AttrColor1; +in vec4 AttrTexCoord0; + +out vec4 PixelColor0; +out vec4 PixelColor1; +out vec4 PixelTexCoord0; + +void main() +{ + gl_Position = AttrPosition; + PixelColor0 = AttrColor0; + PixelColor1 = AttrColor1; + PixelTexCoord0 = AttrTexCoord0; +}