From b60cb19622c95cac90b73415498b620c6a3a14d9 Mon Sep 17 00:00:00 2001 From: Krogoth100 <84379085+Krogoth100@users.noreply.github.com> Date: Tue, 1 Aug 2023 15:25:34 +0300 Subject: [PATCH] GL::State & Texture bind cosmetic (#927) * Texture binding cosmetic Eliminate "duplicate" of FormatToQuery (Format2Query), move FormatToQuery -> TextureFormat.h and make it extern (only 1 instance among all units). Gate unaccepted texture targets for Lua via switch. * GL::State State is implemented as a namespace. Use it like this: using namespace GL::State; auto stateChange = StateChange(DepthMask(GL_TRUE), Viewport(0,0,1,1)); ... stateChange.pop() or { auto stateChange = StateChange(...); ... // stateChange destructed } Unknown status is implemented via union. It should be safe, no practical value should collide with it. * Update GL::State Enabled "capability" ("binary") attributes Corrected previous union usage, it now uses a pair (not optional, because it works with values when false) Todo: BindTexture, ClipDistance * Update, should be ready StateChange > PushState PushState should be ready, but is not test yet. Shall be testing. +ClipDistance attribute. Note, it doesn't check how many clip distances are available, it just runs gl function as it should. Check clip distances, if you need, prior to ClipDistance code. Replace glPushAttrib with PushState in some places where its easy * >SubState + operator << PushState > SubState Add operator << to modify state --- rts/Game/UI/MiniMap.cpp | 17 ++- rts/Game/UI/MouseHandler.cpp | 16 +- rts/Lua/LuaOpenGL.cpp | 7 +- rts/Lua/LuaTextures.cpp | 49 +++--- rts/Lua/LuaTextures.h | 3 - rts/Rendering/CMakeLists.txt | 2 + rts/Rendering/GL/State.cpp | 3 + rts/Rendering/GL/State.h | 182 +++++++++++++++++++++++ rts/Rendering/GL/SubState.h | 61 ++++++++ rts/Rendering/GL/TexBind.h | 45 ++++++ rts/Rendering/GL/glHelpers.h | 93 ++++++++++++ rts/Rendering/GL/myGL.cpp | 10 +- rts/Rendering/GL/myGL.h | 13 -- rts/Rendering/HUDDrawer.cpp | 37 +++-- rts/Rendering/HUDDrawer.h | 4 +- rts/Rendering/Textures/TextureFormat.cpp | 126 ++++++++++++++++ rts/Rendering/Textures/TextureFormat.h | 114 +------------- rts/System/TemplateUtils.hpp | 63 +++++--- 18 files changed, 638 insertions(+), 207 deletions(-) create mode 100644 rts/Rendering/GL/State.cpp create mode 100644 rts/Rendering/GL/State.h create mode 100644 rts/Rendering/GL/SubState.h create mode 100644 rts/Rendering/GL/TexBind.h create mode 100644 rts/Rendering/GL/glHelpers.h create mode 100644 rts/Rendering/Textures/TextureFormat.cpp diff --git a/rts/Game/UI/MiniMap.cpp b/rts/Game/UI/MiniMap.cpp index bde30f28c1..ff8a628262 100644 --- a/rts/Game/UI/MiniMap.cpp +++ b/rts/Game/UI/MiniMap.cpp @@ -35,6 +35,7 @@ #include "Rendering/GL/myGL.h" #include "Rendering/GL/glExtra.h" #include "Rendering/GL/RenderBuffers.h" +#include "Rendering/GL/SubState.h" #include "Rendering/Textures/Bitmap.h" #include "Sim/Units/CommandAI/CommandAI.h" #include "Sim/Units/Unit.h" @@ -50,6 +51,9 @@ #include "System/FileSystem/SimpleParser.h" #include "System/Sound/ISoundChannels.h" +using namespace GL::State; + + CONFIG(std::string, MiniMapGeometry).defaultValue("2 2 200 200"); CONFIG(bool, MiniMapFullProxy).defaultValue(true); CONFIG(int, MiniMapButtonSize).defaultValue(16); @@ -1128,17 +1132,18 @@ void CMiniMap::Draw() { glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glPushAttrib(GL_DEPTH_BUFFER_BIT); - glDisable(GL_DEPTH_TEST); - glDepthFunc(GL_LEQUAL); - glDepthMask(GL_FALSE); + + auto state = GL::SubState( + DepthTest(GL_FALSE), + DepthFunc(GL_LEQUAL), + DepthMask(GL_FALSE)); + glDisable(GL_TEXTURE_2D); glMatrixMode(GL_MODELVIEW); if (minimized) { DrawMinimizedButtonQuad(); DrawMinimizedButtonLoop(); - glPopAttrib(); glEnable(GL_TEXTURE_2D); return; } @@ -1148,8 +1153,6 @@ void CMiniMap::Draw() DrawFrame(); DrawButtons(); } - - glPopAttrib(); } // draw minimap itself diff --git a/rts/Game/UI/MouseHandler.cpp b/rts/Game/UI/MouseHandler.cpp index 4b5259cc91..db66bb06fc 100644 --- a/rts/Game/UI/MouseHandler.cpp +++ b/rts/Game/UI/MouseHandler.cpp @@ -25,6 +25,7 @@ #include "Rendering/Fonts/glFont.h" #include "Rendering/GL/myGL.h" #include "Rendering/GL/RenderBuffers.h" +#include "Rendering/GL/SubState.h" #include "Rendering/Textures/Bitmap.h" #include "Sim/Features/Feature.h" #include "Sim/Units/Unit.h" @@ -46,6 +47,8 @@ #include #include +using namespace GL::State; + CONFIG(bool, HardwareCursor).defaultValue(false).description("Sets hardware mouse cursor rendering. If you have a low framerate, your mouse cursor will seem \"laggy\". Setting hardware cursor will render the mouse cursor separately from spring and the mouse will behave normally. Note, not all GPU drivers support it in fullscreen mode!"); CONFIG(bool, InvertMouse).defaultValue(false); @@ -572,20 +575,17 @@ void CMouseHandler::DrawSelectionBox() const {tpLeft , cmdColors.mouseBox}, }); - glPushAttrib(GL_ENABLE_BIT); - glDisable(GL_DEPTH_TEST); - glEnable(GL_BLEND); - glBlendFunc((GLenum)cmdColors.MouseBoxBlendSrc(), (GLenum)cmdColors.MouseBoxBlendDst()); + auto state = GL::SubState( + DepthTest(GL_FALSE), + Blending(GL_TRUE), + BlendFunc((GLenum)cmdColors.MouseBoxBlendSrc(), (GLenum)cmdColors.MouseBoxBlendDst()), + LineWidth(cmdColors.MouseBoxLineWidth())); - glLineWidth(cmdColors.MouseBoxLineWidth()); sh.Enable(); rb.DrawArrays(GL_LINE_LOOP); sh.Disable(); - glLineWidth(1.0f); - - glPopAttrib(); } int2 CMouseHandler::GetViewMouseCenter() const diff --git a/rts/Lua/LuaOpenGL.cpp b/rts/Lua/LuaOpenGL.cpp index 2ec5bb2f67..c6ddd575ad 100644 --- a/rts/Lua/LuaOpenGL.cpp +++ b/rts/Lua/LuaOpenGL.cpp @@ -56,6 +56,7 @@ #include "Rendering/Env/WaterRendering.h" #include "Rendering/Env/MapRendering.h" #include "Rendering/GL/glExtra.h" +#include "Rendering/GL/TexBind.h" #include "Rendering/Models/3DModel.h" #include "Rendering/Shaders/Shader.h" #include "Rendering/Textures/Bitmap.h" @@ -3627,12 +3628,8 @@ int LuaOpenGL::GenerateMipmap(lua_State* L) if (tex == nullptr) return 0; - GLint currentBinding; - assert(LuaTextures::Format2Query.find(tex->target) != LuaTextures::Format2Query.end()); - glGetIntegerv(LuaTextures::Format2Query.find(tex->target)->second, ¤tBinding); - glBindTexture(tex->target, tex->id); + auto texBind = GL::TexBind(tex->target, tex->id); glGenerateMipmapEXT(tex->target); - glBindTexture(tex->target, currentBinding); return 0; } diff --git a/rts/Lua/LuaTextures.cpp b/rts/Lua/LuaTextures.cpp index 690bd298e8..fcad5f7112 100644 --- a/rts/Lua/LuaTextures.cpp +++ b/rts/Lua/LuaTextures.cpp @@ -4,6 +4,7 @@ #include "Rendering/Textures/TextureFormat.h" #include "Rendering/GlobalRendering.h" #include "Rendering/GL/FBO.h" +#include "Rendering/GL/TexBind.h" #include "System/SpringMath.h" #include "System/StringUtil.h" #include "System/Log/ILog.h" @@ -13,33 +14,42 @@ #include "fmt/format.h" -const spring::unordered_map LuaTextures::Format2Query = -{ - { GL_TEXTURE_1D , GL_TEXTURE_BINDING_1D }, - { GL_TEXTURE_2D , GL_TEXTURE_BINDING_2D }, - { GL_TEXTURE_3D , GL_TEXTURE_BINDING_3D }, -// { GL_TEXTURE_1D_ARRAY , GL_TEXTURE_BINDING_1D_ARRAY }, - { GL_TEXTURE_2D_ARRAY , GL_TEXTURE_BINDING_2D_ARRAY }, -// { GL_TEXTURE_RECTANGLE , GL_TEXTURE_BINDING_RECTANGLE }, - { GL_TEXTURE_CUBE_MAP , GL_TEXTURE_BINDING_CUBE_MAP }, -// { GL_TEXTURE_BUFFER , GL_TEXTURE_BINDING_BUFFER }, - { GL_TEXTURE_2D_MULTISAMPLE , GL_TEXTURE_BINDING_2D_MULTISAMPLE }, -// { GL_TEXTURE_2D_MULTISAMPLE_ARRAY, GL_TEXTURE_BINDING_2D_MULTISAMPLE_ARRAY }, -}; +namespace Impl { + static inline bool IsValidLuaTextureTarget(GLenum target) { + switch(target) { + case GL_TEXTURE_1D: + case GL_TEXTURE_2D: + case GL_TEXTURE_3D: + //case GL_TEXTURE_1D_ARRAY: + case GL_TEXTURE_2D_ARRAY: + //case GL_TEXTURE_RECTANGLE: + case GL_TEXTURE_CUBE_MAP: + //case GL_TEXTURE_BUFFER: + case GL_TEXTURE_2D_MULTISAMPLE: + //case GL_TEXTURE_2D_MULTISAMPLE_ARRAY: + return true; + default: break; + } + return false; + } +} /******************************************************************************/ /******************************************************************************/ std::string LuaTextures::Create(const Texture& tex) { - GLint currentBinding = 0; - - if (Format2Query.find(tex.target) == Format2Query.end()) { + GLenum query = 0; + if (Impl::IsValidLuaTextureTarget(tex.target)) { + query = GL::GetBindingQueryFromTarget(tex.target); + } + if (!query) { LOG_L(L_ERROR, "[LuaTextures::%s] texture-target %d is not supported", __func__, tex.target); return ""; } - glGetIntegerv(Format2Query.find(tex.target)->second, ¤tBinding); + GLint currentBinding; + glGetIntegerv(query, ¤tBinding); GLuint texID; glGenTextures(1, &texID); @@ -254,11 +264,8 @@ void LuaTextures::ApplyParams(const Texture& tex) const void LuaTextures::ChangeParams(const Texture& tex) const { - GLint currentBinding = 0; - glGetIntegerv(GL_TEXTURE_BINDING_2D, ¤tBinding); - glBindTexture(tex.target, tex.id); + auto texBind = GL::TexBind(tex.target, tex.id); ApplyParams(tex); - glBindTexture(GL_TEXTURE_2D, currentBinding); // revert the current binding } diff --git a/rts/Lua/LuaTextures.h b/rts/Lua/LuaTextures.h index c2bf45ece9..64922adc4d 100644 --- a/rts/Lua/LuaTextures.h +++ b/rts/Lua/LuaTextures.h @@ -7,7 +7,6 @@ #include #include "Rendering/GL/myGL.h" -#include "System/UnorderedMap.hpp" class LuaTextures { @@ -73,8 +72,6 @@ class LuaTextures { const Texture* GetInfo(const std::string& name) const { return (GetInfo(GetIdx(name))); } Texture* GetInfo(const std::string& name) { return (GetInfo(GetIdx(name))); } -public: - static const spring::unordered_map Format2Query; private: int lastCode; diff --git a/rts/Rendering/CMakeLists.txt b/rts/Rendering/CMakeLists.txt index b5a0efa159..0b7b6a272c 100644 --- a/rts/Rendering/CMakeLists.txt +++ b/rts/Rendering/CMakeLists.txt @@ -63,6 +63,7 @@ set(sources_engine_Rendering "${CMAKE_CURRENT_SOURCE_DIR}/GL/VBO.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/GL/VAO.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/GL/glExtra.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/GL/State.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/GL/myGL.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/VK/VkInit.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/VK/VkInfo.cpp" @@ -115,6 +116,7 @@ set(sources_engine_Rendering "${CMAKE_CURRENT_SOURCE_DIR}/Textures/NamedTextures.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/Textures/S3OTextureHandler.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/Textures/TAPalette.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/Textures/TextureFormat.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/Textures/TextureAtlas.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/Textures/TexturesSet.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/Textures/nv_dds.cpp" diff --git a/rts/Rendering/GL/State.cpp b/rts/Rendering/GL/State.cpp new file mode 100644 index 0000000000..0d23711efe --- /dev/null +++ b/rts/Rendering/GL/State.cpp @@ -0,0 +1,3 @@ +#include "State.h" + +decltype(GL::State::Attributes) GL::State::Attributes; \ No newline at end of file diff --git a/rts/Rendering/GL/State.h b/rts/Rendering/GL/State.h new file mode 100644 index 0000000000..18aa66bcde --- /dev/null +++ b/rts/Rendering/GL/State.h @@ -0,0 +1,182 @@ +/* This file is part of the Recoil engine (GPL v2 or later), see LICENSE.html */ + +#pragma once + +#include "myGL.h" +#include "glHelpers.h" +#include "System/TemplateUtils.hpp" +#include +#include +#include + +/* + GL::State doesn't represent active GL state. + It represents GL state, that was last applied by GL::SubState objects, or any other object that performs state change via this interface. + + If a state was not set by a SubState object, it is internally set to Unknown. + When a state is Unknown and SubState object requests it, the state is fetched from GL. + When the last existing SubState object reverts a state, it is set back to Unknown. + Setting back to Unknown after the last SubState object enforces fetch from GL every time the first SubState object is created, + but makes it possible to insert SubState object in any part of the code without serious restrictions to the whole prior code. + + User must make sure that ordinary GL commands that are not tracked do not collide with SubState object's modifications during its lifetime. +*/ + +namespace GL +{ + +template class StateAttribute { +private: + using GLParamsType = spring::func_ptr_signature_t; + using StatusType = bool; + static constexpr StatusType Unknown = false; + static constexpr StatusType WasUnknown = false; + +public: + using ValueType = std::pair; + + inline StateAttribute() : value(Unknown, GLParamsType()) {}; + + inline operator ValueType() const + { + return (value.first != Unknown) + ? value + : ValueType(WasUnknown, FetchEffectualStateAttribValues(GLParamNames...)); + } + inline StateAttribute& operator=(const ValueType& newValue) + { + if (value != newValue) { + value = newValue; + glSetAny(newValue.second); + } + return *this; + } + +private: + ValueType value; +}; + +template struct UniqueStateAttributeValueType { +public: + using AttributeType = AttributeT; + using AttributeValueType = typename AttributeType::ValueType; + + template + inline UniqueStateAttributeValueType(ArgTypes&&... valueConstructionArgs) + : value(true, typename AttributeValueType::second_type(std::forward(valueConstructionArgs)...)) + {} + template, AttributeValueType>, bool> = true> + inline UniqueStateAttributeValueType(Type&& valueSample) + : value(valueSample) + {} + + inline operator const AttributeValueType&() const { return value; } + +private: + AttributeValueType value; +}; + +#define ATTRIBUTE(name) name##Attribute +#define ATTRIBUTE_TYPE_DEFS(name, ...) \ + using ATTRIBUTE(name) = StateAttribute<&(gl##name), __VA_ARGS__>; \ + using name = UniqueStateAttributeValueType; +#define CAPABILITY_ATTRIBUTE_TYPE_DEFS(name, glParamName) \ + using ATTRIBUTE(name) = StateAttribute; \ + using name = UniqueStateAttributeValueType; +#define MULTI_CAPABILITY_ATTRIBUTE_TYPE_DEFS(name, glParamName) \ + template using ATTRIBUTE(name) = StateAttribute; \ + template using name = UniqueStateAttributeValueType>; + +namespace State { + ATTRIBUTE_TYPE_DEFS (PolygonMode, GL_POLYGON_MODE); + ATTRIBUTE_TYPE_DEFS (PolygonOffset, GL_POLYGON_OFFSET_FACTOR, GL_POLYGON_OFFSET_UNITS); + CAPABILITY_ATTRIBUTE_TYPE_DEFS (PolygonOffsetFill, GL_POLYGON_OFFSET_FILL); + CAPABILITY_ATTRIBUTE_TYPE_DEFS (PolygonOffsetLine, GL_POLYGON_OFFSET_LINE); + CAPABILITY_ATTRIBUTE_TYPE_DEFS (PolygonOffsetPoint, GL_POLYGON_OFFSET_POINT); + + ATTRIBUTE_TYPE_DEFS (LineWidth, GL_LINE_WIDTH); + + ATTRIBUTE_TYPE_DEFS (Viewport, GL_VIEWPORT); + + ATTRIBUTE_TYPE_DEFS (FrontFace, GL_FRONT_FACE); + CAPABILITY_ATTRIBUTE_TYPE_DEFS (Culling, GL_CULL_FACE); + ATTRIBUTE_TYPE_DEFS (CullFace, GL_CULL_FACE_MODE); + MULTI_CAPABILITY_ATTRIBUTE_TYPE_DEFS (ClipDistance, GL_CLIP_DISTANCE0); + + CAPABILITY_ATTRIBUTE_TYPE_DEFS (ScissorTest, GL_SCISSOR_TEST); + ATTRIBUTE_TYPE_DEFS (Scissor, GL_SCISSOR_BOX); + + CAPABILITY_ATTRIBUTE_TYPE_DEFS (DepthTest, GL_DEPTH_TEST); + ATTRIBUTE_TYPE_DEFS (DepthFunc, GL_DEPTH_FUNC); + ATTRIBUTE_TYPE_DEFS (DepthRangef, GL_DEPTH_RANGE); + CAPABILITY_ATTRIBUTE_TYPE_DEFS (DepthClamp, GL_DEPTH_CLAMP); + ATTRIBUTE_TYPE_DEFS (DepthMask, GL_DEPTH_WRITEMASK); + + CAPABILITY_ATTRIBUTE_TYPE_DEFS (StencilTest, GL_STENCIL_TEST); + + CAPABILITY_ATTRIBUTE_TYPE_DEFS (AlphaTest, GL_ALPHA_TEST); + ATTRIBUTE_TYPE_DEFS (AlphaFunc, GL_ALPHA_TEST_FUNC, GL_ALPHA_TEST_REF); + + CAPABILITY_ATTRIBUTE_TYPE_DEFS (Blending, GL_BLEND); + ATTRIBUTE_TYPE_DEFS (BlendFunc, GL_BLEND_SRC, GL_BLEND_DST); + ATTRIBUTE_TYPE_DEFS (BlendColor, GL_BLEND_COLOR); + ATTRIBUTE_TYPE_DEFS (ColorMask, GL_COLOR_WRITEMASK); + + CAPABILITY_ATTRIBUTE_TYPE_DEFS (PrimitiveRestart, GL_PRIMITIVE_RESTART); + ATTRIBUTE_TYPE_DEFS (PrimitiveRestartIndex, GL_PRIMITIVE_RESTART_INDEX); + + CAPABILITY_ATTRIBUTE_TYPE_DEFS (Multisampling, GL_MULTISAMPLE); + CAPABILITY_ATTRIBUTE_TYPE_DEFS (AlphaToCoverage, GL_SAMPLE_ALPHA_TO_COVERAGE); + CAPABILITY_ATTRIBUTE_TYPE_DEFS (AlphaToOne, GL_SAMPLE_ALPHA_TO_ONE); + + CAPABILITY_ATTRIBUTE_TYPE_DEFS (CubemapSeamless, GL_TEXTURE_CUBE_MAP_SEAMLESS); + CAPABILITY_ATTRIBUTE_TYPE_DEFS (PointSize, GL_PROGRAM_POINT_SIZE); + + extern std::tuple< + ATTRIBUTE(PolygonMode), + ATTRIBUTE(PolygonOffsetFill), + ATTRIBUTE(PolygonOffsetLine), + ATTRIBUTE(PolygonOffsetPoint), + ATTRIBUTE(LineWidth), + ATTRIBUTE(Viewport), + ATTRIBUTE(FrontFace), + ATTRIBUTE(Culling), + ATTRIBUTE(CullFace), + ATTRIBUTE(ClipDistance)<0>, + ATTRIBUTE(ClipDistance)<1>, + ATTRIBUTE(ClipDistance)<2>, + ATTRIBUTE(ClipDistance)<3>, + ATTRIBUTE(ClipDistance)<4>, + ATTRIBUTE(ClipDistance)<5>, + ATTRIBUTE(ClipDistance)<6>, + ATTRIBUTE(ClipDistance)<7>, + ATTRIBUTE(ScissorTest), + ATTRIBUTE(Scissor), + ATTRIBUTE(DepthTest), + ATTRIBUTE(DepthFunc), + ATTRIBUTE(DepthRangef), + ATTRIBUTE(DepthClamp), + ATTRIBUTE(DepthMask), + ATTRIBUTE(StencilTest), + ATTRIBUTE(AlphaTest), + ATTRIBUTE(AlphaFunc), + ATTRIBUTE(Blending), + ATTRIBUTE(BlendFunc), + ATTRIBUTE(BlendColor), + ATTRIBUTE(ColorMask), + ATTRIBUTE(PrimitiveRestart), + ATTRIBUTE(PrimitiveRestartIndex), + ATTRIBUTE(Multisampling), + ATTRIBUTE(AlphaToCoverage), + ATTRIBUTE(AlphaToOne), + ATTRIBUTE(CubemapSeamless), + ATTRIBUTE(PointSize) + > Attributes; +}; + +#undef ATTRIBUTE +#undef ATTRIBUTE_TYPE_DEFS +#undef CAPABILITY_ATTRIBUTE_TYPE_DEFS +#undef MULTI_CAPABILITY_ATTRIBUTE_TYPE_DEFS + +} \ No newline at end of file diff --git a/rts/Rendering/GL/SubState.h b/rts/Rendering/GL/SubState.h new file mode 100644 index 0000000000..fe0b945e6e --- /dev/null +++ b/rts/Rendering/GL/SubState.h @@ -0,0 +1,61 @@ +/* This file is part of the Recoil engine (GPL v2 or later), see LICENSE.html */ + +#pragma once + +#include "State.h" +#include "System/TemplateUtils.hpp" +#include +#include +#include + +namespace GL +{ + +namespace Impl +{ +template class SubState { +private: + using ValuesType = std::tuple; + +public: + inline SubState(UniqueAttributeValueTypes... newValues) + { + ((std::get(savedValues) = std::get(State::Attributes)), ...); + ((std::get(State::Attributes) = newValues), ...); + } + + template, bool> = true> + inline const SubState& operator<<(UniqueAttributeValueType newValue) const + { + if (pushed) { + std::get(State::Attributes) = newValue; + } + return *this; + } + + inline void pop() + { + if (pushed) { + ((std::get(State::Attributes) = std::get(savedValues)), ...); + pushed = false; + } + } + + inline ~SubState() + { + pop(); + } + +private: + ValuesType savedValues; + bool pushed = true; +}; +} + +template +auto SubState(ArgTypes&&... args) +{ + return Impl::SubState(std::forward(args)...); +} + +} \ No newline at end of file diff --git a/rts/Rendering/GL/TexBind.h b/rts/Rendering/GL/TexBind.h new file mode 100644 index 0000000000..7ca5aff087 --- /dev/null +++ b/rts/Rendering/GL/TexBind.h @@ -0,0 +1,45 @@ +/* This file is part of the Recoil engine (GPL v2 or later), see LICENSE.html */ + +#pragma once + +#include "myGL.h" +#include "glHelpers.h" + +namespace GL +{ + +// A texture bind control object, that automatically unbinds texture and restores active tex unit upon destruction +// When constucted without exact slot, will also restore the previously bound texture to the contemporary slot +class TexBind { +public: + inline TexBind(unsigned slot, GLenum target, GLuint textureID) + : stateTexUnit(GL::FetchEffectualStateAttribValue(GL_ACTIVE_TEXTURE)), + texUnit(GL_TEXTURE0+slot), + target(target), + restoredTextureID(0) + { + if (stateTexUnit != texUnit) glActiveTexture(texUnit); + glBindTexture(target, textureID); + } + inline TexBind(GLenum target, GLuint textureID) + : stateTexUnit(GL::FetchEffectualStateAttribValue(GL_ACTIVE_TEXTURE)), + texUnit(stateTexUnit), + target(target), + restoredTextureID(GL::FetchCurrentSlotTextureID(target)) + { + glBindTexture(target, textureID); + } + + inline ~TexBind() + { + glActiveTexture(texUnit); + glBindTexture(target, restoredTextureID); + if (stateTexUnit != texUnit) glActiveTexture(stateTexUnit); + } + +private: + const GLenum stateTexUnit, texUnit, target; + const GLuint restoredTextureID; +}; + +} diff --git a/rts/Rendering/GL/glHelpers.h b/rts/Rendering/GL/glHelpers.h new file mode 100644 index 0000000000..23a110116f --- /dev/null +++ b/rts/Rendering/GL/glHelpers.h @@ -0,0 +1,93 @@ +/* This file is part of the Recoil engine (GPL v2 or later), see LICENSE.html */ + +#pragma once + +#include "myGL.h" +#include "Rendering/Textures/TextureFormat.h" +#include +#include + + +// Get gl parameter values into a homogenous GL-typed variable (single or array) +// Must pass expectedValuesN to convert from GLint to other integer types (GLenum, GLsizei and such) +template +inline void glGetAny(GLenum paramName, GLType* data, const int expectedValuesN = -1) +{ + GLint ints[expectedValuesN]; + glGetIntegerv(paramName, ints); + std::move(ints, ints+expectedValuesN, data); +} +template<> +inline void glGetAny(GLenum paramName, GLint* data, const int) +{ + glGetIntegerv(paramName, data); +} +template<> +inline void glGetAny(GLenum paramName, GLboolean* data, const int) +{ + glGetBooleanv(paramName, data); +} +template<> +inline void glGetAny(GLenum paramName, GLfloat* data, const int) +{ + glGetFloatv(paramName, data); +} +template<> +inline void glGetAny(GLenum paramName, GLdouble* data, const int) +{ + glGetDoublev(paramName, data); +} + + +namespace GL +{ + +// Fetch value of a single value parameter, not more than that +template +inline ResultType FetchEffectualStateAttribValue(GLenum paramName) +{ + ResultType resultValue; + glGetAny(paramName, &resultValue, 1); + return resultValue; +} + +template +inline ResultTupleType FetchEffectualStateAttribValues(GLenum paramName) +{ + ResultTupleType resultTuple; + glGetAny(paramName, &std::get<0>(resultTuple), std::tuple_size_v); + return resultTuple; +} +template +inline ResultTupleType FetchEffectualStateAttribValues(GLenum firstParamName, GLenum secondParamName) +{ + ResultTupleType resultTuple; + glGetAny(firstParamName, &std::get<0>(resultTuple), std::tuple_size_v/2); + glGetAny(secondParamName, &std::get/2-1>(resultTuple), std::tuple_size_v/2); + return resultTuple; +} + +inline GLuint FetchCurrentSlotTextureID(GLenum target) { + GLenum query = GL::GetBindingQueryFromTarget(target); + assert(query); + GLuint currentSlotTextureID; + glGetAny(query, ¤tSlotTextureID, 1); + return currentSlotTextureID; +} + +} + +// Set gl attribute, whether it is capability (glEnable/glDisable) or dedicated, via this single interface +// Pass DedicatedGLFuncPtrPtr *if* it exists, nullptr if it doesn't +template +inline void glSetAny(AttribValuesTupleType newValues) +{ + if constexpr(DedicatedGLFuncPtrPtr) + { + std::apply(*DedicatedGLFuncPtrPtr, newValues); + } + else // glEnable/glDisable(attribute) + { + (std::get<0>(newValues) == GL_TRUE? glEnable : glDisable)(GLParamName...); + } +} diff --git a/rts/Rendering/GL/myGL.cpp b/rts/Rendering/GL/myGL.cpp index fdf135947a..c988370450 100644 --- a/rts/Rendering/GL/myGL.cpp +++ b/rts/Rendering/GL/myGL.cpp @@ -17,6 +17,7 @@ #include "Rendering/GlobalRenderingInfo.h" #include "Rendering/Textures/Bitmap.h" #include "Rendering/GL/VBO.h" +#include "Rendering/GL/TexBind.h" #include "System/Log/ILog.h" #include "System/Exceptions.h" #include "System/StringUtil.h" @@ -254,12 +255,7 @@ void WorkaroundATIPointSizeBug() void glSpringGetTexParams(GLenum target, GLuint textureID, GLint level, TextureParameters& tp) { - GLint currentBinding; - const auto it = FormatToQuery.find(target); - assert(it != FormatToQuery.end()); - glGetIntegerv(it->second, ¤tBinding); - - glBindTexture(target, textureID); + auto texBind = GL::TexBind(target, textureID); glGetTexLevelParameteriv(target, level, GL_TEXTURE_INTERNAL_FORMAT, &tp.intFmt); glGetTexLevelParameteriv(target, level, GL_TEXTURE_WIDTH, &tp.sizeX); @@ -293,8 +289,6 @@ void glSpringGetTexParams(GLenum target, GLuint textureID, GLint level, TextureP (tp.bpp >> 3); } } - - glBindTexture(target, currentBinding); } void glSaveTexture(const GLuint textureID, const char* filename, int level) diff --git a/rts/Rendering/GL/myGL.h b/rts/Rendering/GL/myGL.h index 12addf419e..5551e1f77d 100644 --- a/rts/Rendering/GL/myGL.h +++ b/rts/Rendering/GL/myGL.h @@ -43,19 +43,6 @@ #define GL_INVALID_INDEX -1 #endif -static const spring::unordered_map FormatToQuery { - { GL_TEXTURE_1D , GL_TEXTURE_BINDING_1D }, - { GL_TEXTURE_2D , GL_TEXTURE_BINDING_2D }, - { GL_TEXTURE_3D , GL_TEXTURE_BINDING_3D }, - { GL_TEXTURE_1D_ARRAY , GL_TEXTURE_BINDING_1D_ARRAY }, - { GL_TEXTURE_2D_ARRAY , GL_TEXTURE_BINDING_2D_ARRAY }, - { GL_TEXTURE_RECTANGLE , GL_TEXTURE_BINDING_RECTANGLE }, - { GL_TEXTURE_CUBE_MAP , GL_TEXTURE_BINDING_CUBE_MAP }, - { GL_TEXTURE_BUFFER , GL_TEXTURE_BINDING_BUFFER }, - { GL_TEXTURE_2D_MULTISAMPLE , GL_TEXTURE_BINDING_2D_MULTISAMPLE }, - { GL_TEXTURE_2D_MULTISAMPLE_ARRAY, GL_TEXTURE_BINDING_2D_MULTISAMPLE_ARRAY }, -}; - struct TextureParameters { GLint intFmt; GLint sizeX; diff --git a/rts/Rendering/HUDDrawer.cpp b/rts/Rendering/HUDDrawer.cpp index f83e42590d..72dfcb39a9 100644 --- a/rts/Rendering/HUDDrawer.cpp +++ b/rts/Rendering/HUDDrawer.cpp @@ -5,6 +5,7 @@ #include "Rendering/Fonts/glFont.h" #include "Rendering/GlobalRendering.h" #include "Rendering/GL/myGL.h" +#include "Rendering/GL/SubState.h" #include "Game/Camera.h" #include "Game/GlobalUnsynced.h" #include "Game/Players/Player.h" @@ -18,15 +19,17 @@ #include +using namespace GL::State; + + HUDDrawer* HUDDrawer::GetInstance() { static HUDDrawer hud; return &hud; } -void HUDDrawer::PushState() +void HUDDrawer::PushMatrices() { - glPushAttrib(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_ENABLE_BIT); glPushMatrix(); glMatrixMode(GL_PROJECTION); glPushMatrix(); @@ -36,14 +39,13 @@ void HUDDrawer::PushState() glPushMatrix(); glLoadIdentity(); } -void HUDDrawer::PopState() +void HUDDrawer::PopMatrices() { glMatrixMode(GL_PROJECTION); glPopMatrix(); glMatrixMode(GL_MODELVIEW); glPopMatrix(); glPopMatrix(); - glPopAttrib(); } void HUDDrawer::DrawModel(const CUnit* unit) @@ -188,7 +190,6 @@ void HUDDrawer::DrawWeaponStates(const CUnit* unit) void HUDDrawer::DrawTargetReticle(const CUnit* unit) { glDisable(GL_TEXTURE_2D); - glDisable(GL_DEPTH_TEST); // draw the reticle in world coordinates glMatrixMode(GL_PROJECTION); @@ -279,20 +280,24 @@ void HUDDrawer::Draw(const CUnit* unit) if (unit == nullptr || !draw) return; - PushState(); - glDisable(GL_DEPTH_TEST); - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + PushMatrices(); - glPushMatrix(); - DrawUnitDirectionArrow(unit); - DrawCameraDirectionArrow(unit); - glPopMatrix(); + auto state = GL::SubState( + DepthTest(GL_FALSE), + Blending(GL_TRUE), + BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)); - glEnable(GL_DEPTH_TEST); - DrawModel(unit); + glPushMatrix(); + DrawUnitDirectionArrow(unit); + DrawCameraDirectionArrow(unit); + glPopMatrix(); + state << DepthTest(GL_TRUE); + DrawModel(unit); DrawWeaponStates(unit); + + state << DepthTest(GL_FALSE); DrawTargetReticle(unit); - PopState(); + + PopMatrices(); } diff --git a/rts/Rendering/HUDDrawer.h b/rts/Rendering/HUDDrawer.h index 5ff067ffb5..93a91fd397 100644 --- a/rts/Rendering/HUDDrawer.h +++ b/rts/Rendering/HUDDrawer.h @@ -15,8 +15,8 @@ struct HUDDrawer { static HUDDrawer* GetInstance(); private: - void PushState(); - void PopState(); + void PushMatrices(); + void PopMatrices(); void DrawModel(const CUnit*); void DrawUnitDirectionArrow(const CUnit*); diff --git a/rts/Rendering/Textures/TextureFormat.cpp b/rts/Rendering/Textures/TextureFormat.cpp new file mode 100644 index 0000000000..fc3bcaa4f8 --- /dev/null +++ b/rts/Rendering/Textures/TextureFormat.cpp @@ -0,0 +1,126 @@ +#include "TextureFormat.h" + +GLenum GL::GetInternalFormatDataFormat(GLenum internalFormat) { + GLenum dataFormat; + switch (internalFormat) { + case GL_R8UI: + case GL_R16UI: + case GL_R32UI: { + dataFormat = GL_RED_INTEGER; + } break; + case GL_RG8UI: + case GL_RG16UI: + case GL_RG32UI: { + dataFormat = GL_RG_INTEGER; + } break; + case GL_RGB10_A2UI: { + dataFormat = GL_RGB_INTEGER; + } break; + case GL_RGBA8UI: + case GL_RGBA16UI: + case GL_RGBA32UI: { + dataFormat = GL_RGBA_INTEGER; + } break; + case GL_R8: + case GL_R16: + case GL_R16F: + case GL_R32F: { + dataFormat = GL_RED; + } break; + case GL_DEPTH_COMPONENT: + case GL_DEPTH_COMPONENT16: + case GL_DEPTH_COMPONENT24: + case GL_DEPTH_COMPONENT32: + case GL_DEPTH_COMPONENT32F: { + dataFormat = GL_DEPTH_COMPONENT; + } break; + case GL_RG8: + case GL_RG16: + case GL_RG16F: + case GL_RG32F: { + dataFormat = GL_RG; + } break; + case GL_RGB10_A2: + case GL_R11F_G11F_B10F: { + dataFormat = GL_RGB; + } break; + case GL_RGBA8: + case GL_RGBA16: + case GL_RGBA16F: + case GL_RGBA32F: + default: { + dataFormat = GL_RGBA; + } break; + } + return dataFormat; +} + +GLenum GL::GetInternalFormatDataType(GLenum internalFormat) { + GLenum dataType; + switch (internalFormat) { + case GL_RGBA16F: + case GL_RG16F: + case GL_R16F: { + dataType = GL_HALF_FLOAT; + } break; + case GL_RGBA32F: + case GL_RG32F: + case GL_R32F: + case GL_DEPTH_COMPONENT32F: { + dataType = GL_FLOAT; + } break; + case GL_RGBA32UI: + case GL_RG32UI: + case GL_R32UI: + case GL_DEPTH_COMPONENT32: { + dataType = GL_UNSIGNED_INT; + } break; + case GL_DEPTH_COMPONENT24: { + dataType = GL_UNSIGNED_INT_24_8; + } break; + case GL_RGBA16: + case GL_RGBA16UI: + case GL_RG16: + case GL_RG16UI: + case GL_R16: + case GL_R16UI: + case GL_DEPTH_COMPONENT16: { + dataType = GL_UNSIGNED_SHORT; + } break; + case GL_R11F_G11F_B10F: { + dataType = GL_UNSIGNED_INT_10F_11F_11F_REV; + } break; + case GL_RGB10_A2: + case GL_RGB10_A2UI: { + dataType = GL_UNSIGNED_INT_2_10_10_10_REV; + } break; + case GL_RGBA8: + case GL_RGBA8UI: + case GL_RG8: + case GL_RG8UI: + case GL_R8: + case GL_R8UI: + case GL_DEPTH_COMPONENT: + default: { + dataType = GL_UNSIGNED_BYTE; + } break; + } + return dataType; +} + +GLenum GL::GetBindingQueryFromTarget(GLenum target) { + switch (target) { + case GL_TEXTURE_1D: return GL_TEXTURE_BINDING_1D; + case GL_TEXTURE_2D: return GL_TEXTURE_BINDING_2D; + case GL_TEXTURE_3D: return GL_TEXTURE_BINDING_3D; + case GL_TEXTURE_1D_ARRAY: return GL_TEXTURE_BINDING_1D_ARRAY; + case GL_TEXTURE_2D_ARRAY: return GL_TEXTURE_BINDING_2D_ARRAY; + case GL_TEXTURE_RECTANGLE: return GL_TEXTURE_BINDING_RECTANGLE; + case GL_TEXTURE_CUBE_MAP: return GL_TEXTURE_BINDING_CUBE_MAP; + case GL_TEXTURE_BUFFER: return GL_TEXTURE_BINDING_BUFFER; + case GL_TEXTURE_2D_MULTISAMPLE: return GL_TEXTURE_BINDING_2D_MULTISAMPLE; + case GL_TEXTURE_2D_MULTISAMPLE_ARRAY: return GL_TEXTURE_BINDING_2D_MULTISAMPLE_ARRAY; + default: break; + } + return 0; +} diff --git a/rts/Rendering/Textures/TextureFormat.h b/rts/Rendering/Textures/TextureFormat.h index 39bfe40315..1a8356e9eb 100644 --- a/rts/Rendering/Textures/TextureFormat.h +++ b/rts/Rendering/Textures/TextureFormat.h @@ -1,117 +1,17 @@ -/* This file is part of the Spring engine (GPL v2 or later), see LICENSE.html */ +/* This file is part of the Recoil engine (GPL v2 or later), see LICENSE.html */ #ifndef TEXTURE_FORMAT_H #define TEXTURE_FORMAT_H +#include "Rendering/GL/myGL.h" + namespace GL { - inline GLenum GetInternalFormatDataFormat(GLenum internalFormat) { - GLenum dataFormat; - switch (internalFormat) { - case GL_R8UI: - case GL_R16UI: - case GL_R32UI: { - dataFormat = GL_RED_INTEGER; - } break; - case GL_RG8UI: - case GL_RG16UI: - case GL_RG32UI: { - dataFormat = GL_RG_INTEGER; - } break; - case GL_RGB10_A2UI: { - dataFormat = GL_RGB_INTEGER; - } break; - case GL_RGBA8UI: - case GL_RGBA16UI: - case GL_RGBA32UI: { - dataFormat = GL_RGBA_INTEGER; - } break; - case GL_R8: - case GL_R16: - case GL_R16F: - case GL_R32F: { - dataFormat = GL_RED; - } break; - case GL_DEPTH_COMPONENT: - case GL_DEPTH_COMPONENT16: - case GL_DEPTH_COMPONENT24: - case GL_DEPTH_COMPONENT32: - case GL_DEPTH_COMPONENT32F: { - dataFormat = GL_DEPTH_COMPONENT; - } break; - case GL_RG8: - case GL_RG16: - case GL_RG16F: - case GL_RG32F: { - dataFormat = GL_RG; - } break; - case GL_RGB10_A2: - case GL_R11F_G11F_B10F: { - dataFormat = GL_RGB; - } break; - case GL_RGBA8: - case GL_RGBA16: - case GL_RGBA16F: - case GL_RGBA32F: - default: { - dataFormat = GL_RGBA; - } break; - } - return dataFormat; - } + GLenum GetInternalFormatDataFormat(GLenum internalFormat); + + GLenum GetInternalFormatDataType(GLenum internalFormat); - inline GLenum GetInternalFormatDataType(GLenum internalFormat) { - GLenum dataType; - switch (internalFormat) { - case GL_RGBA16F: - case GL_RG16F: - case GL_R16F: { - dataType = GL_HALF_FLOAT; - } break; - case GL_RGBA32F: - case GL_RG32F: - case GL_R32F: - case GL_DEPTH_COMPONENT32F: { - dataType = GL_FLOAT; - } break; - case GL_RGBA32UI: - case GL_RG32UI: - case GL_R32UI: - case GL_DEPTH_COMPONENT32: { - dataType = GL_UNSIGNED_INT; - } break; - case GL_DEPTH_COMPONENT24: { - dataType = GL_UNSIGNED_INT_24_8; - } break; - case GL_RGBA16: - case GL_RGBA16UI: - case GL_RG16: - case GL_RG16UI: - case GL_R16: - case GL_R16UI: - case GL_DEPTH_COMPONENT16: { - dataType = GL_UNSIGNED_SHORT; - } break; - case GL_R11F_G11F_B10F: { - dataType = GL_UNSIGNED_INT_10F_11F_11F_REV; - } break; - case GL_RGB10_A2: - case GL_RGB10_A2UI: { - dataType = GL_UNSIGNED_INT_2_10_10_10_REV; - } break; - case GL_RGBA8: - case GL_RGBA8UI: - case GL_RG8: - case GL_RG8UI: - case GL_R8: - case GL_R8UI: - case GL_DEPTH_COMPONENT: - default: { - dataType = GL_UNSIGNED_BYTE; - } break; - } - return dataType; - } + GLenum GetBindingQueryFromTarget(GLenum target); } #endif // TEXTURE_FORMAT_H diff --git a/rts/System/TemplateUtils.hpp b/rts/System/TemplateUtils.hpp index d80b68c176..f5e021ced0 100644 --- a/rts/System/TemplateUtils.hpp +++ b/rts/System/TemplateUtils.hpp @@ -2,6 +2,7 @@ #include #include +#include namespace spring { template struct bool_pack; @@ -135,25 +136,16 @@ namespace spring { template using return_type_t = typename return_type::type; + - template - struct func_signature; + template + struct tuple_contains_type; - template - struct func_signature - { - using type = std::tuple; - }; - template< - typename F, - std::enable_if_t::value, bool> = true - > - auto arg_types_tuple_t(const F&) -> typename func_signature::type; - template< - typename F, - std::enable_if_t::value, bool> = true - > - auto arg_types_tuple_t(const F*) -> typename func_signature::type; + template + struct tuple_contains_type, Type> : std::disjunction...> {}; + + template + constexpr inline bool tuple_contains_type_v = tuple_contains_type::value; template @@ -170,4 +162,41 @@ namespace spring { }; template constexpr size_t tuple_type_index_v = tuple_type_index::value; + + + template + struct func_signature; + + template + struct func_signature { + using type = std::tuple; + }; + + template + using func_signature_t = typename func_signature::type; + + template< + typename F, + std::enable_if_t::value, bool> = true + > + auto arg_types_tuple_t(const F&) -> typename func_signature::type; + template< + typename F, + std::enable_if_t::value, bool> = true + > + auto arg_types_tuple_t(const F*) -> typename func_signature::type; + + + // This particular helper accepts a nullptr, in which case it falls back to a specified default signature, or just an empty tuple + template + struct func_ptr_signature { + using type = func_signature_t>>; + }; + template + struct func_ptr_signature { + using type = std::tuple; + }; + + template + using func_ptr_signature_t = typename func_ptr_signature::type; }; \ No newline at end of file