From 098f8d07385abe5fa582dcb2a1f86b3bfc2f9405 Mon Sep 17 00:00:00 2001 From: Swung0x48 Date: Tue, 17 Feb 2026 11:17:03 +0800 Subject: [PATCH] [Feat] (MG_Backend/DirectVulkan): move demo pipeline creation to gl side --- .../MG_Backend/DirectVulkan/DirectVulkan.cpp | 4 + .../DirectVulkan/Renderer/VulkanRenderer.cpp | 144 ++++++------------ .../DirectVulkan/Renderer/VulkanRenderer.h | 7 +- .../MG_Test/Backend/DirectVulkan/TestExec.cpp | 100 +++++++++++- 4 files changed, 151 insertions(+), 104 deletions(-) diff --git a/MobileGL/MG_Backend/DirectVulkan/DirectVulkan.cpp b/MobileGL/MG_Backend/DirectVulkan/DirectVulkan.cpp index 051c39c4..e2255cf3 100644 --- a/MobileGL/MG_Backend/DirectVulkan/DirectVulkan.cpp +++ b/MobileGL/MG_Backend/DirectVulkan/DirectVulkan.cpp @@ -83,6 +83,8 @@ namespace MobileGL::MG_Backend::DirectVulkan { payload.drawArray.mode = mode; payload.drawArray.first = 0; payload.drawArray.count = count; + const auto currentProgram = MG_State::pGLContext->GetCurrentProgram(); + payload.drawArray.program = currentProgram ? currentProgram.get() : nullptr; payload.drawArray.vertexArray = vao.get(); payload.indexType = type; payload.indexData = indexData->data() + byteOffset; @@ -142,6 +144,8 @@ namespace MobileGL::MG_Backend::DirectVulkan { payload.mode = mode; payload.first = first; payload.count = count; + const auto currentProgram = MG_State::pGLContext->GetCurrentProgram(); + payload.program = currentProgram ? currentProgram.get() : nullptr; const auto vao = MG_State::pGLContext->GetBoundVertexArray(); payload.vertexArray = vao ? vao.get() : nullptr; diff --git a/MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanRenderer.cpp b/MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanRenderer.cpp index 6efbc261..e0a29432 100644 --- a/MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanRenderer.cpp +++ b/MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanRenderer.cpp @@ -59,27 +59,17 @@ namespace MobileGL::MG_Backend::DirectVulkan { Shutdown(); } - const char* demoFS = R"(#version 460 - layout(location = 0) in vec3 fragColor; - layout(location = 0) out vec4 outColor; - void main() { - outColor = vec4(fragColor, 1.0); - } -)"; - const char* demoVS = R"(#version 460 - layout(location = 0) out vec3 fragColor; - vec2 positions[3] = vec2[](vec2(0.0, -0.5), vec2(0.5, 0.5), vec2(-0.5, 0.5)); - vec3 colors[3] = vec3[](vec3(1.0, 0.0, 0.0), vec3(0.0, 1.0, 0.0), vec3(0.0, 0.0, 1.0)); - void main() { - gl_Position = vec4(positions[gl_VertexID], 0.0, 1.0); - fragColor = colors[gl_VertexID]; - } -)"; - VkPipeline VulkanRenderer::GetOrCreatePipeline( - Uint64 programHash, Uint64 vertexInputHash, const VkPipelineVertexInputStateCreateInfo& vertexInputState) { + const MG_State::GLState::ProgramObject& program, Uint64 vertexInputHash, + const VkPipelineVertexInputStateCreateInfo& vertexInputState) { MOBILEGL_ASSERT(m_pipelineFactory != nullptr, "PipelineFactory is not initialized"); - MOBILEGL_ASSERT(!m_demoPipelineStages.empty(), "GetOrCreatePipeline requires shader stages"); + MOBILEGL_ASSERT(m_programFactory != nullptr, "ProgramFactory is not initialized"); + auto& stages = m_programFactory->GetOrCreatePipelineShaderStages(program, ProgramFactory::CompileOptionBit::None); + if (stages.empty()) { + MGLOG_W("GetOrCreatePipeline skipped: program has no shader stages"); + return VK_NULL_HANDLE; + } + const Uint64 programHash = m_programFactory->ComputeHash(program, ProgramFactory::CompileOptionBit::None); PipelineFactory::PipelineCreatePayload payload{}; payload.programHash = programHash; @@ -88,52 +78,17 @@ namespace MobileGL::MG_Backend::DirectVulkan { payload.renderPass = m_renderPassLoad; payload.subpass = 0; payload.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; - payload.stages = &m_demoPipelineStages; + payload.stages = &stages; payload.vertexInputState = &vertexInputState; return m_pipelineFactory->GetOrCreatePipeline(payload); } void VulkanRenderer::PrepareDemoPipeline() { - MGLOG_D("PrepareDemoRes called"); - - // Create shader&program object - auto programObject = MG_State::GLState::ProgramObject(0); - auto vsObject = MakeShared(ShaderStage::Vertex, 0); - vsObject->SetShaderSource(demoVS); - vsObject->Compile(); - if (!vsObject->GetCompileStatus()) { - MGLOG_E("Vertex shader compilation failed: %s", vsObject->GetInfoLog().c_str()); - return; - } - auto fsObject = MakeShared(ShaderStage::Fragment, 1); - fsObject->SetShaderSource(demoFS); - fsObject->Compile(); - if (!fsObject->GetCompileStatus()) { - MGLOG_E("Fragment shader compilation failed: %s", fsObject->GetInfoLog().c_str()); - return; - } - programObject.AttachShader(vsObject); - programObject.AttachShader(fsObject); - programObject.Link(); - if (!programObject.GetLinkStatus()) { - MGLOG_E("Program linking failed: %s", programObject.GetInfoLog().c_str()); - return; - } - - auto& stages = m_programFactory->GetOrCreatePipelineShaderStages(programObject, ProgramFactory::CompileOptionBit::None); - m_demoProgramHash = m_programFactory->ComputeHash(programObject, ProgramFactory::CompileOptionBit::None); - m_demoPipelineStages = stages; + MGLOG_D("PrepareDemoPipeline called"); VkPipelineLayoutCreateInfo plci{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO}; VK_VERIFY(vkCreatePipelineLayout(m_device, &plci, nullptr, &m_pipelineLayout), "vkCreatePipelineLayout"); - VertexInputStateBuilder vertexInputBuilder; - const auto& vertexInput = vertexInputBuilder.Build(); - m_pipeline = GetOrCreatePipeline(m_demoProgramHash, 0, vertexInput); - - // vkDestroyShaderModule(m_device, vs, nullptr); - // vkDestroyShaderModule(m_device, fs, nullptr); - MGLOG_I("PrepareDemoPipeline completed"); } @@ -179,10 +134,9 @@ namespace MobileGL::MG_Backend::DirectVulkan { m_frameContext.Destroy(m_device, m_commandPool); - m_pipeline = VK_NULL_HANDLE; - if (m_pipelineLayout != VK_NULL_HANDLE) { vkDestroyPipelineLayout(m_device, m_pipelineLayout, nullptr); + m_pipelineLayout = VK_NULL_HANDLE; } ShutdownSwapchain(); @@ -422,13 +376,23 @@ namespace MobileGL::MG_Backend::DirectVulkan { VkCommandBuffer& commandBuffer = frame.commandBuffer; const auto swapchainExtent = m_swapchainObject.GetExtent(); - VkPipeline pipelineToBind = m_pipeline; - if (vertexInputState) { - pipelineToBind = GetOrCreatePipeline(m_demoProgramHash, vertexInputState->hash, vertexInputState->state); - if (pipelineToBind == VK_NULL_HANDLE) { - MGLOG_W("DrawArrays skipped: failed to create/get pipeline variant"); - return; - } + if (payload.program == nullptr) { + MGLOG_W("DrawArrays skipped: no current program is bound"); + return; + } + + const Uint64 vertexInputHash = vertexInputState ? vertexInputState->hash : 0; + const VkPipelineVertexInputStateCreateInfo* vertexInputInfo = + vertexInputState ? &vertexInputState->state : nullptr; + if (!vertexInputInfo) { + VertexInputStateBuilder emptyVertexInputBuilder; + vertexInputInfo = &emptyVertexInputBuilder.Build(); + } + + VkPipeline pipelineToBind = GetOrCreatePipeline(*payload.program, vertexInputHash, *vertexInputInfo); + if (pipelineToBind == VK_NULL_HANDLE) { + MGLOG_W("DrawArrays skipped: failed to create/get pipeline"); + return; } if (vertexInputState && !vertexInputState->bindings.empty()) { @@ -526,13 +490,23 @@ namespace MobileGL::MG_Backend::DirectVulkan { vertexInputState = &m_vertexInputStateFactory->GetOrCreateVertexInputState(*payload.drawArray.vertexArray); } - VkPipeline pipelineToBind = m_pipeline; - if (vertexInputState) { - pipelineToBind = GetOrCreatePipeline(m_demoProgramHash, vertexInputState->hash, vertexInputState->state); - if (pipelineToBind == VK_NULL_HANDLE) { - MGLOG_W("DrawElements skipped: failed to create/get pipeline variant"); - return; - } + if (payload.drawArray.program == nullptr) { + MGLOG_W("DrawElements skipped: no current program is bound"); + return; + } + + const Uint64 vertexInputHash = vertexInputState ? vertexInputState->hash : 0; + const VkPipelineVertexInputStateCreateInfo* vertexInputInfo = + vertexInputState ? &vertexInputState->state : nullptr; + if (!vertexInputInfo) { + VertexInputStateBuilder emptyVertexInputBuilder; + vertexInputInfo = &emptyVertexInputBuilder.Build(); + } + + VkPipeline pipelineToBind = GetOrCreatePipeline(*payload.drawArray.program, vertexInputHash, *vertexInputInfo); + if (pipelineToBind == VK_NULL_HANDLE) { + MGLOG_W("DrawElements skipped: failed to create/get pipeline"); + return; } if (vertexInputState && !vertexInputState->bindings.empty()) { @@ -633,24 +607,8 @@ namespace MobileGL::MG_Backend::DirectVulkan { VkCommandBuffer& commandBuffer = frame.commandBuffer; const auto swapchainExtent = m_swapchainObject.GetExtent(); - // Render commands - vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipeline); - - VkViewport viewport{}; - viewport.x = 0.0f; - viewport.y = 0.0f; - viewport.width = static_cast(swapchainExtent.width); - viewport.height = static_cast(swapchainExtent.height); - viewport.minDepth = 0.0f; - viewport.maxDepth = 1.0f; - vkCmdSetViewport(commandBuffer, 0, 1, &viewport); - - VkRect2D scissor{}; - scissor.offset = {0, 0}; - scissor.extent = swapchainExtent; - vkCmdSetScissor(commandBuffer, 0, 1, &scissor); - - vkCmdDraw(commandBuffer, 3, 1, 0, 0); + (void)commandBuffer; + (void)swapchainExtent; } void VulkanRenderer::Present() { @@ -1392,12 +1350,6 @@ namespace MobileGL::MG_Backend::DirectVulkan { if (m_pipelineFactory) { m_pipelineFactory->DestroyAll(); } - m_pipeline = VK_NULL_HANDLE; - if (!m_demoPipelineStages.empty() && m_pipelineLayout != VK_NULL_HANDLE && m_pipelineFactory) { - VertexInputStateBuilder vertexInputBuilder; - const auto& vertexInput = vertexInputBuilder.Build(); - m_pipeline = GetOrCreatePipeline(m_demoProgramHash, 0, vertexInput); - } if (m_frameContext.GetFrameCount() > 0) { m_frameContext.GetCurrent().isCommandRecording = false; m_frameContext.GetCurrent().hasCommandBufferRecorded = false; diff --git a/MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanRenderer.h b/MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanRenderer.h index a20978e3..84a9b4e8 100644 --- a/MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanRenderer.h +++ b/MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanRenderer.h @@ -20,6 +20,7 @@ #include "../VkIncludes.h" namespace MobileGL::MG_State::GLState { + class ProgramObject; class VertexArrayObject; } @@ -30,6 +31,7 @@ namespace MobileGL::MG_Backend::DirectVulkan { GLenum mode = GL_TRIANGLES; GLint first = 0; GLsizei count = 0; + const MG_State::GLState::ProgramObject* program = nullptr; const MG_State::GLState::VertexArrayObject* vertexArray = nullptr; Bool hasPositionStream = false; const void* positionData = nullptr; @@ -117,9 +119,6 @@ namespace MobileGL::MG_Backend::DirectVulkan { Vector m_depthStencilImageLayouts; VkPipelineLayout m_pipelineLayout = VK_NULL_HANDLE; - VkPipeline m_pipeline = VK_NULL_HANDLE; - Uint64 m_demoProgramHash = 0; - Vector m_demoPipelineStages; VkBufferObject m_vertexBuffer; VkBufferObject m_indexBuffer; @@ -153,7 +152,7 @@ namespace MobileGL::MG_Backend::DirectVulkan { VkRenderPass CreateDefaultRenderPass(VkAttachmentLoadOp loadOp); void CreateDefaultFramebuffers(); void PrepareDemoPipeline(); - VkPipeline GetOrCreatePipeline(Uint64 programHash, Uint64 vertexInputHash, + VkPipeline GetOrCreatePipeline(const MG_State::GLState::ProgramObject& program, Uint64 vertexInputHash, const VkPipelineVertexInputStateCreateInfo& vertexInputState); void TransitionSwapchainImageToColorAttachment(VkCommandBuffer commandBuffer, Uint32 imageIndex); void TransitionDepthStencilImageToAttachment(VkCommandBuffer commandBuffer, Uint32 imageIndex); diff --git a/MobileGL/MG_Test/Backend/DirectVulkan/TestExec.cpp b/MobileGL/MG_Test/Backend/DirectVulkan/TestExec.cpp index d16f4ded..6bd6740c 100644 --- a/MobileGL/MG_Test/Backend/DirectVulkan/TestExec.cpp +++ b/MobileGL/MG_Test/Backend/DirectVulkan/TestExec.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include #define GLFW_INCLUDE_NONE @@ -40,6 +41,50 @@ namespace MobileGL { void MG_Initialize(); } +static bool CheckShaderCompile(GLuint shader, const char* label) { + GLint status = GL_FALSE; + glGetShaderiv(shader, GL_COMPILE_STATUS, &status); + if (status == GL_TRUE) { + return true; + } + + GLint logLength = 0; + glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &logLength); + std::string log; + if (logLength > 0) { + log.resize(static_cast(logLength)); + GLsizei written = 0; + glGetShaderInfoLog(shader, logLength, &written, log.data()); + if (written >= 0 && static_cast(written) < log.size()) { + log.resize(static_cast(written)); + } + } + std::cerr << label << " compile failed: " << log << std::endl; + return false; +} + +static bool CheckProgramLink(GLuint program) { + GLint status = GL_FALSE; + glGetProgramiv(program, GL_LINK_STATUS, &status); + if (status == GL_TRUE) { + return true; + } + + GLint logLength = 0; + glGetProgramiv(program, GL_INFO_LOG_LENGTH, &logLength); + std::string log; + if (logLength > 0) { + log.resize(static_cast(logLength)); + GLsizei written = 0; + glGetProgramInfoLog(program, logLength, &written, log.data()); + if (written >= 0 && static_cast(written) < log.size()) { + log.resize(static_cast(written)); + } + } + std::cerr << "Program link failed: " << log << std::endl; + return false; +} + int main() { glfwInit(); @@ -89,11 +134,52 @@ int main() { glGenVertexArrays(1, &vao); glBindVertexArray(vao); - static constexpr GLushort kTriangleIndices[] = {0, 1, 2}; + static constexpr GLushort kQuadIndices[] = {0, 1, 2, 2, 3, 0}; GLuint ebo = 0; glGenBuffers(1, &ebo); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo); - glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(kTriangleIndices), kTriangleIndices, GL_STATIC_DRAW); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(kQuadIndices), kQuadIndices, GL_STATIC_DRAW); + + static constexpr const char* kVertexShaderSource = R"(#version 330 core +void main() { + const vec2 kPositions[4] = vec2[]( + vec2(-0.6, -0.6), + vec2( 0.6, -0.6), + vec2( 0.6, 0.6), + vec2(-0.6, 0.6) + ); + gl_Position = vec4(kPositions[gl_VertexID], 0.0, 1.0); +})"; + static constexpr const char* kFragmentShaderSource = R"(#version 330 core +layout(location = 0) out vec4 outColor; +void main() { + outColor = vec4(0.95, 0.85, 0.2, 1.0); +})"; + + const GLuint vs = glCreateShader(GL_VERTEX_SHADER); + glShaderSource(vs, 1, &kVertexShaderSource, nullptr); + glCompileShader(vs); + if (!CheckShaderCompile(vs, "Vertex shader")) { + return 1; + } + + const GLuint fs = glCreateShader(GL_FRAGMENT_SHADER); + glShaderSource(fs, 1, &kFragmentShaderSource, nullptr); + glCompileShader(fs); + if (!CheckShaderCompile(fs, "Fragment shader")) { + return 1; + } + + const GLuint program = glCreateProgram(); + glAttachShader(program, vs); + glAttachShader(program, fs); + glLinkProgram(program); + if (!CheckProgramLink(program)) { + return 1; + } + glUseProgram(program); + glDeleteShader(vs); + glDeleteShader(fs); int i = 0; while(!glfwWindowShouldClose(window)) { @@ -104,12 +190,18 @@ int main() { else glClearColor(0.0f, 1.0f, 0.0f, 1.0f); glClear(GL_COLOR_BUFFER_BIT); - if (i % 500 > 250) - glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_SHORT, nullptr); + if (i % 500 > 250) { + glUseProgram(program); + glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, nullptr); + } eglSwapBuffers(display, surface); ++i; } + glDeleteProgram(program); + glDeleteBuffers(1, &ebo); + glDeleteVertexArrays(1, &vao); + glfwDestroyWindow(window); glfwTerminate();