From 40df46f94e250000f471870229931a00a027b32f Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Mon, 10 Oct 2016 07:39:02 +0200 Subject: [PATCH] Implement OpenGL versions of GPU objects --- src/gl/system/gl_swframebuffer.cpp | 313 +++++++++++++++++++++++++---- src/gl/system/gl_swframebuffer.h | 75 ++++--- 2 files changed, 327 insertions(+), 61 deletions(-) diff --git a/src/gl/system/gl_swframebuffer.cpp b/src/gl/system/gl_swframebuffer.cpp index e0ff2be477..e03f1fd9c5 100644 --- a/src/gl/system/gl_swframebuffer.cpp +++ b/src/gl/system/gl_swframebuffer.cpp @@ -92,30 +92,30 @@ IMPLEMENT_CLASS(OpenGLSWFrameBuffer) const char *const OpenGLSWFrameBuffer::ShaderNames[OpenGLSWFrameBuffer::NUM_SHADERS] = { - "NormalColor.fp", - "NormalColorPal.fp", - "NormalColorInv.fp", - "NormalColorPalInv.fp", + "NormalColor", + "NormalColorPal", + "NormalColorInv", + "NormalColorPalInv", - "RedToAlpha.fp", - "RedToAlphaInv.fp", + "RedToAlpha", + "RedToAlphaInv", - "VertexColor.fp", + "VertexColor", - "SpecialColormap.fp", - "SpecialColorMapPal.fp", + "SpecialColormap", + "SpecialColorMapPal", - "InGameColormap.fp", - "InGameColormapDesat.fp", - "InGameColormapInv.fp", - "InGameColormapInvDesat.fp", - "InGameColormapPal.fp", - "InGameColormapPalDesat.fp", - "InGameColormapPalInv.fp", - "InGameColormapPalInvDesat.fp", + "InGameColormap", + "InGameColormapDesat", + "InGameColormapInv", + "InGameColormapInvDesat", + "InGameColormapPal", + "InGameColormapPalDesat", + "InGameColormapPalInv", + "InGameColormapPalInvDesat", - "BurnWipe.fp", - "GammaCorrection.fp", + "BurnWipe", + "GammaCorrection", }; OpenGLSWFrameBuffer::OpenGLSWFrameBuffer(void *hMonitor, int width, int height, int bits, int refreshHz, bool fullscreen) : @@ -209,6 +209,256 @@ OpenGLSWFrameBuffer::~OpenGLSWFrameBuffer() delete[] QuadExtra; } +bool OpenGLSWFrameBuffer::CreatePixelShader(const void *vertexsrc, const void *fragmentsrc, HWPixelShader **outShader) +{ + auto shader = std::make_unique(); + + shader->Program = glCreateProgram(); + shader->VertexShader = glCreateShader(GL_VERTEX_SHADER); + shader->FragmentShader = glCreateShader(GL_FRAGMENT_SHADER); + + { + int lengths[1] = { (int)strlen((const char*)vertexsrc) }; + const char *sources[1] = { (const char*)vertexsrc }; + glShaderSource(shader->VertexShader, 1, sources, lengths); + glCompileShader(shader->VertexShader); + } + + { + int lengths[1] = { (int)strlen((const char*)fragmentsrc) }; + const char *sources[1] = { (const char*)fragmentsrc }; + glShaderSource(shader->FragmentShader, 1, sources, lengths); + glCompileShader(shader->FragmentShader); + } + + GLint status = 0; + glGetShaderiv(shader->VertexShader, GL_COMPILE_STATUS, &status); + if (status != GL_FALSE) glGetShaderiv(shader->FragmentShader, GL_COMPILE_STATUS, &status); + if (status == GL_FALSE) + { + *outShader = nullptr; + return false; + } + + 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, "Position"); + glBindAttribLocation(shader->Program, 1, "Color0"); + glBindAttribLocation(shader->Program, 2, "Color1"); + glBindAttribLocation(shader->Program, 3, "TexCoord"); + + *outShader = shader.release(); + return true; +} + +bool OpenGLSWFrameBuffer::CreateVertexBuffer(int size, HWVertexBuffer **outVertexBuffer) +{ + auto obj = std::make_unique(); + + GLint oldBinding = 0; + glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &oldBinding); + + glGenVertexArrays(1, (GLuint*)&obj->VertexArray); + glGenBuffers(1, (GLuint*)&obj->Buffer); + glBindVertexArray(obj->VertexArray); + glBindBuffer(GL_ARRAY_BUFFER, obj->Buffer); + glBufferData(GL_ARRAY_BUFFER, size, nullptr, GL_STREAM_DRAW); + glEnableVertexAttribArray(0); + glEnableVertexAttribArray(1); + glEnableVertexAttribArray(2); + glEnableVertexAttribArray(3); + glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, sizeof(FBVERTEX), (const GLvoid*)offsetof(FBVERTEX, x)); + glVertexAttribPointer(1, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(FBVERTEX), (const GLvoid*)offsetof(FBVERTEX, color0)); + glVertexAttribPointer(2, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(FBVERTEX), (const GLvoid*)offsetof(FBVERTEX, color1)); + glVertexAttribPointer(3, 2, GL_FLOAT, GL_FALSE, sizeof(FBVERTEX), (const GLvoid*)offsetof(FBVERTEX, tu)); + + glBindBuffer(GL_ARRAY_BUFFER, 0); + glBindVertexArray(oldBinding); + + *outVertexBuffer = obj.release(); + return true; +} + +bool OpenGLSWFrameBuffer::CreateIndexBuffer(int size, HWIndexBuffer **outIndexBuffer) +{ + auto obj = std::make_unique(); + + GLint oldBinding = 0; + glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, &oldBinding); + + glGenBuffers(1, (GLuint*)&obj->Buffer); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, obj->Buffer); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, size, nullptr, GL_STREAM_DRAW); + + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, oldBinding); + + *outIndexBuffer = obj.release(); + return true; +} + +bool OpenGLSWFrameBuffer::CreateTexture(int width, int height, int levels, int format, HWTexture **outTexture) +{ + auto obj = std::make_unique(); + + GLint oldBinding = 0; + glGetIntegerv(GL_TEXTURE_BINDING_2D, &oldBinding); + + glGenTextures(1, (GLuint*)&obj->Texture); + glBindTexture(GL_TEXTURE_2D, obj->Texture); + GLenum srcformat; + switch (format) + { + case GL_R8: srcformat = GL_RED; break; + case GL_RGBA8: srcformat = GL_RGBA; 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; + case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: srcformat = GL_RGBA; break; + default: + I_FatalError("Unknown format passed to CreateTexture"); + return false; + } + glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, srcformat, GL_UNSIGNED_BYTE, nullptr); + + glBindTexture(GL_TEXTURE_2D, oldBinding); + + *outTexture = obj.release(); + 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::SetPixelShaderConstantF(int uniformIndex, const float *data, int vec4fcount) +{ + glUniform4fv(uniformIndex, vec4fcount, data); +} + +void OpenGLSWFrameBuffer::SetHWPixelShader(HWPixelShader *shader) +{ + if (shader) + glUseProgram(shader->Program); + else + glUseProgram(0); +} + +void OpenGLSWFrameBuffer::SetStreamSource(HWVertexBuffer *vertexBuffer) +{ + if (vertexBuffer) + glBindVertexArray(vertexBuffer->VertexArray); + else + glBindVertexArray(0); +} + +void OpenGLSWFrameBuffer::SetIndices(HWIndexBuffer *indexBuffer) +{ + if (indexBuffer) + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer->Buffer); + else + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); +} + +void OpenGLSWFrameBuffer::DrawTriangleFans(int count, const FBVERTEX *vertices) +{ + GLint oldBinding = 0; + glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &oldBinding); + + if (!StreamVertexBuffer) + { + StreamVertexBuffer = std::make_unique(); + glGenVertexArrays(1, (GLuint*)&StreamVertexBuffer->VertexArray); + glGenBuffers(1, (GLuint*)&StreamVertexBuffer->Buffer); + glBindVertexArray(StreamVertexBuffer->VertexArray); + glBindBuffer(GL_ARRAY_BUFFER, StreamVertexBuffer->Buffer); + glBufferData(GL_ARRAY_BUFFER, count * sizeof(FBVERTEX), vertices, GL_STREAM_DRAW); + glEnableVertexAttribArray(0); + glEnableVertexAttribArray(1); + glEnableVertexAttribArray(2); + glEnableVertexAttribArray(3); + glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, sizeof(FBVERTEX), (const GLvoid*)offsetof(FBVERTEX, x)); + glVertexAttribPointer(1, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(FBVERTEX), (const GLvoid*)offsetof(FBVERTEX, color0)); + glVertexAttribPointer(2, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(FBVERTEX), (const GLvoid*)offsetof(FBVERTEX, color1)); + glVertexAttribPointer(3, 2, GL_FLOAT, GL_FALSE, sizeof(FBVERTEX), (const GLvoid*)offsetof(FBVERTEX, tu)); + } + else + { + glBindVertexArray(StreamVertexBuffer->VertexArray); + glBindBuffer(GL_ARRAY_BUFFER, StreamVertexBuffer->Buffer); + glBufferData(GL_ARRAY_BUFFER, count * sizeof(FBVERTEX), vertices, GL_STREAM_DRAW); + } + + glDrawArrays(GL_TRIANGLE_FAN, 0, count); + + glBindBuffer(GL_ARRAY_BUFFER, 0); + glBindVertexArray(oldBinding); +} + +void OpenGLSWFrameBuffer::DrawPoints(int count, const FBVERTEX *vertices) +{ + GLint oldBinding = 0; + glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &oldBinding); + + if (!StreamVertexBuffer) + { + StreamVertexBuffer = std::make_unique(); + glGenVertexArrays(1, (GLuint*)&StreamVertexBuffer->VertexArray); + glGenBuffers(1, (GLuint*)&StreamVertexBuffer->Buffer); + glBindVertexArray(StreamVertexBuffer->VertexArray); + glBindBuffer(GL_ARRAY_BUFFER, StreamVertexBuffer->Buffer); + glBufferData(GL_ARRAY_BUFFER, count * sizeof(FBVERTEX), vertices, GL_STREAM_DRAW); + glEnableVertexAttribArray(0); + glEnableVertexAttribArray(1); + glEnableVertexAttribArray(2); + glEnableVertexAttribArray(3); + glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, sizeof(FBVERTEX), (const GLvoid*)offsetof(FBVERTEX, x)); + glVertexAttribPointer(1, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(FBVERTEX), (const GLvoid*)offsetof(FBVERTEX, color0)); + glVertexAttribPointer(2, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(FBVERTEX), (const GLvoid*)offsetof(FBVERTEX, color1)); + glVertexAttribPointer(3, 2, GL_FLOAT, GL_FALSE, sizeof(FBVERTEX), (const GLvoid*)offsetof(FBVERTEX, tu)); + } + else + { + glBindVertexArray(StreamVertexBuffer->VertexArray); + glBindBuffer(GL_ARRAY_BUFFER, StreamVertexBuffer->Buffer); + glBufferData(GL_ARRAY_BUFFER, count * sizeof(FBVERTEX), vertices, GL_STREAM_DRAW); + } + + glDrawArrays(GL_POINTS, 0, count); + + glBindBuffer(GL_ARRAY_BUFFER, 0); + glBindVertexArray(oldBinding); +} + +void OpenGLSWFrameBuffer::DrawLineList(int count) +{ + glDrawArrays(GL_LINES, 0, count); +} + +void OpenGLSWFrameBuffer::DrawTriangleList(int minIndex, int numVertices, int startIndex, int primitiveCount) +{ + glDrawRangeElements(GL_TRIANGLES, minIndex, minIndex + numVertices - 1, primitiveCount * 3, GL_UNSIGNED_SHORT, (const void*)(startIndex * sizeof(uint16_t))); +} + +void OpenGLSWFrameBuffer::Present() +{ + SwapBuffers(); +} + //========================================================================== // // OpenGLSWFrameBuffer :: SetInitialState @@ -274,7 +524,6 @@ bool OpenGLSWFrameBuffer::CreateResources() { return false; } - CreateGammaTexture(); CreateBlockSurfaces(); return true; } @@ -293,7 +542,7 @@ bool OpenGLSWFrameBuffer::LoadShaders() static const char models[][4] = { "30/", "20/", "14/" }; FString shaderdir, shaderpath; unsigned model, i; - int lump; + int lump, lumpvert; // We determine the best available model simply by trying them all in // order of decreasing preference. @@ -304,12 +553,13 @@ bool OpenGLSWFrameBuffer::LoadShaders() for (i = 0; i < NUM_SHADERS; ++i) { shaderpath = shaderdir; - shaderpath += ShaderNames[i]; - lump = Wads.CheckNumForFullName(shaderpath); - if (lump >= 0) + lump = Wads.CheckNumForFullName(shaderpath + ShaderNames[i] + ".fp"); + lumpvert = Wads.CheckNumForFullName(shaderpath + ShaderNames[i] + ".vp"); + if (lump >= 0 && lumpvert >= 0) { FMemLump data = Wads.ReadLump(lump); - if (!CreatePixelShader((uint32_t *)data.GetMem(), &Shaders[i]) && i < SHADER_BurnWipe) + FMemLump datavert = Wads.ReadLump(lumpvert); + if (!CreatePixelShader(datavert.GetMem(), data.GetMem(), &Shaders[i]) && i < SHADER_BurnWipe) { break; } @@ -533,17 +783,6 @@ bool OpenGLSWFrameBuffer::CreatePaletteTexture() return true; } -//========================================================================== -// -// OpenGLSWFrameBuffer :: CreateGammaTexture -// -//========================================================================== - -bool OpenGLSWFrameBuffer::CreateGammaTexture() -{ - return false; -} - //========================================================================== // // OpenGLSWFrameBuffer :: CreateVertexes @@ -3293,7 +3532,7 @@ void OpenGLSWFrameBuffer::SetTexture(int tnum, HWTexture *texture) { Texture[tnum] = texture; glActiveTexture(GL_TEXTURE0 + tnum); - glBindTexture(GL_TEXTURE_2D, texture->Handle); + glBindTexture(GL_TEXTURE_2D, texture->Texture); if (Texture[tnum]->WrapS != SamplerWrapS[tnum]) { Texture[tnum]->WrapS = SamplerWrapS[tnum]; diff --git a/src/gl/system/gl_swframebuffer.h b/src/gl/system/gl_swframebuffer.h index 30e7715abc..14ed2ec131 100644 --- a/src/gl/system/gl_swframebuffer.h +++ b/src/gl/system/gl_swframebuffer.h @@ -110,7 +110,7 @@ private: void UnlockRect() { } bool GetSurfaceLevel(int level, HWSurface **outSurface) { *outSurface = nullptr; return false; } - int Handle = 0; + int Texture = 0; int WrapS = 0; int WrapT = 0; int Format = 0; @@ -119,44 +119,70 @@ private: class HWVertexBuffer { public: + ~HWVertexBuffer() + { + if (Buffer != 0) glDeleteVertexArrays(1, (GLuint*)&VertexArray); + if (Buffer != 0) glDeleteBuffers(1, (GLuint*)&Buffer); + } + FBVERTEX *Lock() { return nullptr; } void Unlock() { } + + int Buffer = 0; + int VertexArray = 0; }; class HWIndexBuffer { public: + ~HWIndexBuffer() + { + if (Buffer != 0) glDeleteBuffers(1, (GLuint*)&Buffer); + } + uint16_t *Lock() { return nullptr; } void Unlock() { } + + int Buffer = 0; }; class HWPixelShader { public: + ~HWPixelShader() + { + if (Program != 0) glDeleteProgram(Program); + if (VertexShader != 0) glDeleteShader(VertexShader); + if (FragmentShader != 0) glDeleteShader(FragmentShader); + } + + int Program = 0; + int VertexShader = 0; + int FragmentShader = 0; }; - bool CreatePixelShader(const void *src, HWPixelShader **outShader) { *outShader = nullptr; return false; } - bool CreateVertexBuffer(int size, HWVertexBuffer **outVertexBuffer) { *outVertexBuffer = nullptr; return false; } - bool CreateIndexBuffer(int size, HWIndexBuffer **outIndexBuffer) { *outIndexBuffer = nullptr; return false; } - bool CreateOffscreenPlainSurface(int width, int height, int format, HWSurface **outSurface) { *outSurface = nullptr; return false; } - bool CreateTexture(int width, int height, int levels, int format, HWTexture **outTexture) { *outTexture = nullptr; return false; } - bool CreateRenderTarget(int width, int height, int format, HWSurface **outSurface) { *outSurface = nullptr; return false; } - bool GetBackBuffer(HWSurface **outSurface) { *outSurface = nullptr; return false; } - bool GetRenderTarget(int index, HWSurface **outSurface) { *outSurface = nullptr; return false; } - 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) { return true; } - void SetGammaRamp(const GammaRamp *ramp) { } - void SetPixelShaderConstantF(int uniformIndex, const float *data, int vec4fcount) { } - void SetHWPixelShader(HWPixelShader *shader) { } - void SetStreamSource(HWVertexBuffer *vertexBuffer) { } - void SetIndices(HWIndexBuffer *indexBuffer) { } - void DrawTriangleFans(int count, const FBVERTEX *vertices) { } - void DrawPoints(int count, const FBVERTEX *vertices) { } - void DrawLineList(int count) { } - void DrawTriangleList(int minIndex, int numVertices, int startIndex, int primitiveCount) { } - void Present() { } + bool CreatePixelShader(const void *vertexsrc, const void *fragmentsrc, 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); + void SetStreamSource(HWVertexBuffer *vertexBuffer); + void SetIndices(HWIndexBuffer *indexBuffer); + void DrawTriangleFans(int count, const FBVERTEX *vertices); + void DrawPoints(int count, const FBVERTEX *vertices); + void DrawLineList(int count); + void DrawTriangleList(int minIndex, int numVertices, int startIndex, int primitiveCount); + void Present(); static uint32_t ColorARGB(uint32_t a, uint32_t r, uint32_t g, uint32_t b) { return ((a & 0xff) << 24) | ((r & 0xff) << 16) | ((g & 0xff) << 8) | ((b) & 0xff); } static uint32_t ColorRGBA(uint32_t a, uint32_t r, uint32_t g, uint32_t b) { return ColorARGB(a, r, g, b); } @@ -346,7 +372,6 @@ private: void CreateBlockSurfaces(); bool CreateFBTexture(); bool CreatePaletteTexture(); - bool CreateGammaTexture(); bool CreateVertexes(); void UploadPalette(); void UpdateGammaTexture(float igamma); @@ -386,6 +411,8 @@ private: template static void SafeRelease(T &x) { if (x != nullptr) { delete x; x = nullptr; } } + std::unique_ptr StreamVertexBuffer; + BOOL AlphaTestEnabled; BOOL AlphaBlendEnabled; int AlphaBlendOp;