[Feat] (Diligent, EGL): wire EGL window swapchain creation via Diligent ISwapChain

- Add CreateSwapChain to renderer using IEngineFactoryVk::CreateSwapChainVk
- InitWindowSurface creates the swapchain for native window surfaces
- Present now presents the active swapchain; ReleaseEGLResources releases it
- InitPbufferSurface keeps offscreen target for pbuffer EGL surfaces
- Update handoff; 16 Diligent tests pass
This commit is contained in:
BZLZHH
2026-08-23 10:46:06 +08:00
parent d7e79409b3
commit 14dfbeeed9
5 changed files with 109 additions and 5 deletions
+2 -1
View File
@@ -117,6 +117,7 @@ Working tree is clean.
Verified locally on Turnip Adreno 750:
- Diligent device/context creation
- EGL window-surface swapchain creation path through Diligent `ISwapChain` (offscreen tests still use the offscreen target)
- GL 3.2 / GLSL 1.50 capability advertisement
- Offscreen color + depth rendering
- Clear color and depth
@@ -219,7 +220,7 @@ Notes:
- User framebuffers now support texture color attachments, renderbuffer color readback, multiple simultaneous color targets, and depth/stencil texture or renderbuffer attachments.
- Textures auto-sync `ITextureObject` → Diligent resources, including mip levels and sampler state; compressed textures and integer/3-channel formats that Diligent lacks are still skipped.
- Global UBO (default-block `glUniform*`) and named application UBO blocks (through `glBindBufferBase`/`glUniformBlockBinding`) now upload and bind; SSBOs are still not fed from frontend buffer bindings.
- No swapchain / EGL window surface presentation yet; `Present()` only flushes and `SetSwapInterval` is a no-op.
- Swapchain creation is now wired for native EGL window surfaces via `Diligent::ISwapChain`; `Present()` presents the active swap chain when present and otherwise flushes the offscreen target. Actual on-screen EGL presentation is still untested in this headless environment, and the X11 display/connection fields are not yet plumbed through `WindowHandle`. `SetSwapInterval` remains a no-op.
- No transform feedback / GPU-accelerated queries / non-color readback; fence sync and timer queries use CPU fallbacks.
- Draw range, multi-draw, instanced-draw wrappers, clear-buffer, blit, read-pixels, CopyTexImage*, CopyImageSubData, GenerateMipmap, GetTexImage/GetTextureImage and indirect draws are now wired; buffer subdata paths still remain.
- A last-PSO cache now avoids recreating the pipeline when program/render-state/topology/VAO layout is unchanged; texture/UBO resources are still rebound dynamically per draw.
@@ -813,8 +813,32 @@ namespace MobileGL::MG_Backend::DiligentBackend {
}
Bool BackendObject_Diligent::InitWindowSurface() {
// Skeleton: no native swapchain creation yet.
return true;
if (!m_windowHandle.Handle) {
MGLOG_E("BackendObject_Diligent::InitWindowSurface failed: native window handle is null");
return false;
}
if (m_pRenderer == nullptr || m_pFactoryVk == nullptr) {
MGLOG_E("BackendObject_Diligent::InitWindowSurface failed: renderer/factory is not ready");
return false;
}
return m_pRenderer->CreateSwapChain(m_pFactoryVk, m_windowHandle,
m_windowHandle.Width, m_windowHandle.Height);
}
Bool BackendObject_Diligent::InitPbufferSurface(EGLint width, EGLint height) {
// The Diligent backend keeps its offscreen target for pbuffer EGL surfaces.
// A future enhancement can resize/recreate the offscreen target to match the
// pbuffer dimensions.
(void)width;
(void)height;
return m_pRenderer != nullptr;
}
void BackendObject_Diligent::ReleaseEGLResources() {
if (m_pRenderer != nullptr) {
m_pRenderer->ReleaseSwapChain();
}
BackendObject::ReleaseEGLResources();
}
const RendererInfo& BackendObject_Diligent::GetRendererInfo() const {
@@ -42,12 +42,14 @@ namespace MobileGL::MG_Backend::DiligentBackend {
void Initialize() override;
Bool InitCapabilities() override;
Bool InitWindowSurface() override;
Bool InitPbufferSurface(EGLint width, EGLint height) override;
const RendererInfo& GetRendererInfo() const override;
String GetBackendAPIVersionString() const override;
const GlobalBackendFunctionsTable& GetBackendFunctions() const override;
const DynamicBackendParameters& GetDynamicParameters() const override;
BackendType GetBackendType() const override;
void ReleaseEGLResources() override;
DiligentRenderer* GetRenderer();
@@ -14,8 +14,11 @@
#include <PipelineState.h>
#include <InputLayout.h>
#include <Sampler.h>
#include <SwapChain.h>
#include <NativeWindow.h>
#include <ShaderResourceBinding.h>
#include <ShaderResourceVariable.h>
#include <EngineFactoryVk.h>
#include <MG_State/GLState/Core.h>
#include <MG_State/GLState/ProgramState/ProgramObject.h>
@@ -378,6 +381,45 @@ void main()
return true;
}
Bool DiligentRenderer::CreateSwapChain(::Diligent::IEngineFactoryVk* factory, const WindowHandle& handle,
Uint32 width, Uint32 height) {
if (factory == nullptr || m_pDevice == nullptr || m_pContext == nullptr || handle.Handle == nullptr) {
MGLOG_E("DiligentRenderer::CreateSwapChain: invalid factory/device/context/window");
return false;
}
::Diligent::SwapChainDesc desc;
desc.Width = width > 0 ? width : std::max<Uint32>(handle.Width, 1);
desc.Height = height > 0 ? height : std::max<Uint32>(handle.Height, 1);
desc.ColorBufferFormat = ::Diligent::TEX_FORMAT_RGBA8_UNORM_SRGB;
desc.DepthBufferFormat = ::Diligent::TEX_FORMAT_D24_UNORM_S8_UINT;
desc.BufferCount = 2;
::Diligent::NativeWindow nativeWindow{};
#if PLATFORM_ANDROID
nativeWindow.pAWindow = handle.Handle;
#elif PLATFORM_LINUX
// X11 Window IDs are integers that the frontend stores as a void* handle.
// The X11 display/connection could not be plumbed through WindowHandle yet;
// swapchain creation on X11 may need those fields filled by a future change.
nativeWindow.WindowId = static_cast<::Diligent::Uint32>(
reinterpret_cast<uintptr_t>(handle.Handle));
#else
(void)nativeWindow;
#endif
::Diligent::RefCntAutoPtr<::Diligent::ISwapChain> pSwapChain;
factory->CreateSwapChainVk(m_pDevice, m_pContext, desc, nativeWindow, &pSwapChain);
if (!pSwapChain) {
MGLOG_E("DiligentRenderer::CreateSwapChain: failed to create swap chain");
return false;
}
m_pSwapChain = pSwapChain;
m_width = desc.Width;
m_height = desc.Height;
return true;
}
Bool DiligentRenderer::CreateOffscreenTargets() {
::Diligent::TextureDesc texDesc;
texDesc.Name = "MobileGL Diligent offscreen color target";
@@ -867,7 +909,19 @@ void main()
return false;
}
auto useSwapChainTargets = [&]() -> Bool {
if (m_pSwapChain && m_pSwapChain->GetCurrentBackBufferRTV()) {
rtvs.push_back(m_pSwapChain->GetCurrentBackBufferRTV());
dsv = m_pSwapChain->GetDepthBufferDSV();
return true;
}
return false;
};
if (MG_State::pGLContext == nullptr) {
if (useSwapChainTargets()) {
return true;
}
if (m_pColorRTV) {
rtvs.push_back(m_pColorRTV.RawPtr());
}
@@ -877,6 +931,9 @@ void main()
auto drawFbo = MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Draw).GetBoundObject();
if (!drawFbo || drawFbo->IsDefaultFramebuffer()) {
if (useSwapChainTargets()) {
return true;
}
if (m_pColorRTV) {
rtvs.push_back(m_pColorRTV.RawPtr());
}
@@ -1641,6 +1698,9 @@ void main()
}
::Diligent::RefCntAutoPtr<::Diligent::ITexture> pSrcTexture = m_pColorTarget;
if (m_pSwapChain && m_pSwapChain->GetCurrentBackBufferRTV()) {
pSrcTexture = m_pSwapChain->GetCurrentBackBufferRTV()->GetTexture();
}
if (MG_State::pGLContext != nullptr) {
auto readFbo = MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Read).GetBoundObject();
if (readFbo && !readFbo->IsDefaultFramebuffer()) {
@@ -1970,9 +2030,15 @@ void main()
return true;
}
void DiligentRenderer::ReleaseSwapChain() {
m_pSwapChain.Release();
}
void DiligentRenderer::Present() {
// Offscreen renderer: nothing to present yet.
if (m_pContext) {
if (m_pSwapChain) {
m_pSwapChain->Present(0);
} else if (m_pContext) {
// Offscreen renderer: nothing to present yet.
m_pContext->Flush();
}
}
@@ -20,6 +20,10 @@
#include <RefCntAutoPtr.hpp>
namespace MobileGL::MG_Backend {
struct WindowHandle;
}
namespace Diligent {
struct IRenderDevice;
struct IDeviceContext;
@@ -29,6 +33,8 @@ namespace Diligent {
struct IBuffer;
struct ISampler;
struct IShaderResourceBinding;
struct ISwapChain;
struct IEngineFactoryVk;
}
namespace MobileGL::MG_State::GLState {
@@ -55,6 +61,9 @@ namespace MobileGL::MG_Backend::DiligentBackend {
void ClearStencil(Uint32 stencil);
void DrawTriangle();
void DrawVertices(const Float* vertices, Uint32 vertexCount);
// Creates a real Diligent swap chain for a native EGL window surface.
Bool CreateSwapChain(::Diligent::IEngineFactoryVk* factory, const WindowHandle& handle,
Uint32 width, Uint32 height);
// Creates a simple 2D RGBA8 texture from CPU data and makes it available
// to state PSOs under the shader variable name "g_Texture".
Bool CreateTestTexture(const void* data, Uint32 width, Uint32 height);
@@ -73,6 +82,7 @@ namespace MobileGL::MG_Backend::DiligentBackend {
void CopyTextureSubData(MG_State::GLState::ITextureObject& src, MG_State::GLState::ITextureObject& dst);
void GenerateMipmap(MG_State::GLState::ITextureObject& texture);
Bool ReadTextureImage(MG_State::GLState::ITextureObject& texture, Uint32 level, void* pixels);
void ReleaseSwapChain();
void Present();
::Diligent::IRenderDevice* GetDevice() const { return m_pDevice; }
@@ -115,6 +125,7 @@ namespace MobileGL::MG_Backend::DiligentBackend {
::Diligent::RefCntAutoPtr<::Diligent::ITextureView> m_pColorRTV;
::Diligent::RefCntAutoPtr<::Diligent::ITexture> m_pDepthTarget;
::Diligent::RefCntAutoPtr<::Diligent::ITextureView> m_pDepthDSV;
::Diligent::RefCntAutoPtr<::Diligent::ISwapChain> m_pSwapChain;
::Diligent::RefCntAutoPtr<::Diligent::ITexture> m_pTestTexture;
::Diligent::RefCntAutoPtr<::Diligent::ITextureView> m_pTestSRV;
::Diligent::RefCntAutoPtr<::Diligent::ISampler> m_pTestSampler;