diff --git a/MobileGL/Defines.h b/MobileGL/Defines.h index 5c9734c1..d3bb8810 100644 --- a/MobileGL/Defines.h +++ b/MobileGL/Defines.h @@ -38,7 +38,7 @@ #define MOBILEGL_BACKEND_TYPE_DIRECT_GLES 3 // ====================== MobileGL configurations ======================= // -#define MOBILEGL_LOG_ACTIVE_LEVEL MOBILEGL_LOG_LEVEL_FATAL +#define MOBILEGL_LOG_ACTIVE_LEVEL MOBILEGL_LOG_LEVEL_INFO #define MOBILEGL_LOG_ENABLE_CONSOLE 0 #define MOBILEGL_LOG_ENABLE_FILE 1 diff --git a/MobileGL/MG_Backend/Backends.h b/MobileGL/MG_Backend/Backends.h index e42ef270..89a57ec9 100644 --- a/MobileGL/MG_Backend/Backends.h +++ b/MobileGL/MG_Backend/Backends.h @@ -24,7 +24,7 @@ namespace MobileGL { .Extensions = {}, // OpenGL Extensions .IsCompatibilityProfile = false // Is Compatibility Profile }, - .BackendCapability = {} // Backend Capability + .BackendCapability = {.AllowVSOnlyPrograms = false} // Backend Capability }; } @@ -47,7 +47,7 @@ namespace MobileGL { V_OpenGL33}, .IsCompatibilityProfile = false // Is Compatibility Profile }, - .BackendCapability = {} // Backend Capability + .BackendCapability = {.AllowVSOnlyPrograms = false} // Backend Capability }; inline RendererInfo RendererInfoMetal = { @@ -63,7 +63,7 @@ namespace MobileGL { V_OpenGL33}, .IsCompatibilityProfile = false // Is Compatibility Profile }, - .BackendCapability = {} // Backend Capability + .BackendCapability = {.AllowVSOnlyPrograms = false} // Backend Capability }; } // namespace Diligent @@ -81,7 +81,7 @@ namespace MobileGL { V_OpenGL33, E_GL_ARB_draw_buffers_blend}, .IsCompatibilityProfile = false // Is Compatibility Profile }, - .BackendCapability = {} // Backend Capability + .BackendCapability = {.AllowVSOnlyPrograms = false} // Backend Capability }; } // namespace DirectGLES diff --git a/MobileGL/MG_Impl/GLImpl/Program/GL_Program.cpp b/MobileGL/MG_Impl/GLImpl/Program/GL_Program.cpp index 688be6c7..9ab7a29f 100644 --- a/MobileGL/MG_Impl/GLImpl/Program/GL_Program.cpp +++ b/MobileGL/MG_Impl/GLImpl/Program/GL_Program.cpp @@ -6,6 +6,7 @@ // End of Source File Header #include "GL_Program.h" +#include "Config.h" #include "MG_Util/Converters/GLToStr/GLEnumConverter.h" #include #include @@ -475,7 +476,7 @@ namespace MobileGL { auto programObject = TryToGetProgramObject(program); if (!programObject) return; MGLOG_D("%s: linking program %d", __func__, program); - programObject->Link(); + programObject->Link(!MG_Config::RendererInfoPtr->BackendCapability.AllowVSOnlyPrograms); } void ShaderSource_State(GLuint shader, GLsizei count, const GLchar* const* string, const GLint* length) { diff --git a/MobileGL/MG_State/GLState/ProgramState/ProgramObject.cpp b/MobileGL/MG_State/GLState/ProgramState/ProgramObject.cpp index 33d46e5f..27e30236 100644 --- a/MobileGL/MG_State/GLState/ProgramState/ProgramObject.cpp +++ b/MobileGL/MG_State/GLState/ProgramState/ProgramObject.cpp @@ -12,6 +12,11 @@ #include #include +const char* kDefaultFragmentShaderSource = R"(#version 460 core +layout(location = 0) out vec4 FragColor; +void main() {} +)"; + namespace MobileGL { namespace MG_State { namespace GLState { @@ -58,7 +63,38 @@ namespace MobileGL { return count; } - void ProgramObject::Link() { + void ProgramObject::AddDefaultFragmentShaderIfMissing() { + Bool needsDefaultFS = false; + for (const auto& shader : m_shaders) { + auto stage = shader->GetShaderStage(); + if (stage == ShaderStage::Vertex) { + needsDefaultFS = true; + continue; + } + if (stage == ShaderStage::Fragment) { + needsDefaultFS = false; + return; + } + } + + if (!needsDefaultFS) return; + + MGLOG_D("ProgramObject %u: No fragment shader attached, adding default fragment shader.", + m_externalIndex); + SharedPtr defaultFS = MakeShared(ShaderStage::Fragment, 0); + defaultFS->SetShaderSource(kDefaultFragmentShaderSource); + defaultFS->Compile(); // TODO: use a global default FS object. + auto status = defaultFS->GetCompileStatus(); + if (!status) { + MGLOG_E("ProgramObject %u: Failed to compile default fragment shader. InfoLog:\n%s", + m_externalIndex, defaultFS->GetInfoLog().c_str()); + return; + } + m_shaders.push_back(defaultFS); + MGLOG_D("ProgramObject %u: Default fragment shader added.", m_externalIndex); + } + + void ProgramObject::Link(Bool addDefaultFSIfMissingForRenderingPipelineProgram) { MGLOG_D("ProgramObject %u: Link start, shaders to link: %zu", m_externalIndex, m_shaders.size()); // Remove detached shaders first for (const auto& detachedShader : m_detachedShaders) { @@ -69,6 +105,10 @@ namespace MobileGL { Vector shaderTypes(m_shaders.size()); Vector> shaders(m_shaders.size()); + if (addDefaultFSIfMissingForRenderingPipelineProgram) { + AddDefaultFragmentShaderIfMissing(); + } + for (SizeT i = 0; i < m_shaders.size(); i++) { shaderTypes[i] = MG_Util::ConvertShaderStageToGLEnum(m_shaders[i]->GetShaderStage()); MGLOG_D("ProgramObject %u: Preparing shader[%zu] stage %s at %p", m_externalIndex, i, diff --git a/MobileGL/MG_State/GLState/ProgramState/ProgramObject.h b/MobileGL/MG_State/GLState/ProgramState/ProgramObject.h index 1592a620..dfc22b5a 100644 --- a/MobileGL/MG_State/GLState/ProgramState/ProgramObject.h +++ b/MobileGL/MG_State/GLState/ProgramState/ProgramObject.h @@ -21,7 +21,7 @@ namespace MobileGL { bool AttachShader(SharedPtr shader); SizeT DetachShader(SharedPtr shader); SizeT RemoveShader(SharedPtr shader); - void Link(); + void Link(Bool addDefaultFSIfMissingForRenderingPipelineProgram = false); void MarkAsDeleted(); void SetExplicitVertexInLocation(Uint index, const char* name); @@ -120,6 +120,7 @@ namespace MobileGL { void DoReflection(); void GenerateBinary(); void WaitUntilGenerationCompleted(); + void AddDefaultFragmentShaderIfMissing(); const Uint m_externalIndex = 0; Vector> m_shaders; diff --git a/MobileGL/MG_Util/Types.h b/MobileGL/MG_Util/Types.h index af64a258..73ea6997 100644 --- a/MobileGL/MG_Util/Types.h +++ b/MobileGL/MG_Util/Types.h @@ -248,7 +248,9 @@ namespace MobileGL { } }; - struct BackendCap {}; + struct BackendCap { + Bool AllowVSOnlyPrograms = false; + }; struct GLInfo { Version TargetGLVersion;