Phase O Task 3 — verbatim-copy GL infra from Chorizite.OpenGLSDLBackend
into src/AcDream.App/Rendering/Wb/ (namespace AcDream.App.Rendering.Wb).
18 files extracted (all namespace-changed; no algorithm changes):
OpenGLGraphicsDevice, ManagedGLTexture, ManagedGLTextureArray,
ManagedGLVertexBuffer, ManagedGLIndexBuffer, ManagedGLVertexArray,
ManagedGLFrameBuffer, ManagedGLUniformBuffer, GLSLShader, GLHelpers,
GLStateScope, GpuMemoryTracker, SceneData, DebugRenderSettings,
TextureParameters, TextureFormatExtensions, BufferUsageExtensions,
EmbeddedResourceReader.
3 internals promoted to public (O-D9):
EmbeddedResourceReader, TextureFormatExtensions, BufferUsageExtensions.
SixLabors.ImageSharp not reachable: TextureHelpers was placed in
AcDream.Core (no GL/ImageSharp dep); only the GL types went to App.
TextureHelpers.GetCompressedLayerSize added to AcDream.Core.Rendering.Wb
(was in Chorizite.OpenGLSDLBackend.Lib.TextureHelpers; uses
Chorizite.Core.Render.Enums.TextureFormat which Core gets transitively
via the still-present WB project refs).
T3/T4 boundary interims:
- WbMeshAdapter._graphicsDevice stays Chorizite.OpenGLSDLBackend.OpenGLGraphicsDevice
(T4 will swap it when ObjectMeshManager is extracted).
- OpenGLGraphicsDevice.ParticleBatcher deferred to null! (T4 extracts
ParticleBatcher alongside ObjectMeshManager; can't pass `this` of our
new type to the WB-original ctor before T4).
- ManagedGLTextureArray uses our TextureHelpers via explicit alias.
- IUniformBuffer is in Chorizite.Core.dll under Chorizite.OpenGLSDLBackend
namespace (unusual packaging); resolved via type alias.
- AcDream.App.csproj gets explicit Chorizite.Core 0.0.18 PackageReference
(IUniformBuffer + other Chorizite.Core types now used directly in App).
Build green. Test baseline 1147+8 maintained (1902 passing, 8 pre-existing
MotionInterpreterTests failures unrelated to T3).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
104 lines
4.2 KiB
C#
104 lines
4.2 KiB
C#
using Chorizite.Core.Render;
|
|
using Silk.NET.OpenGL;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using System.Threading.Tasks;
|
|
|
|
namespace AcDream.App.Rendering.Wb {
|
|
/// <summary>
|
|
/// Implementation of a framebuffer for OpenGL ES 3.0 using Silk.NET.
|
|
/// </summary>
|
|
public class ManagedGLFramebuffer : IFramebuffer {
|
|
private readonly OpenGLGraphicsDevice _device;
|
|
private GL _gl => _device.GL;
|
|
private readonly uint _fboId;
|
|
private readonly uint _depthStencilRenderbuffer; // 0 if not used
|
|
private readonly ITexture _texture;
|
|
private readonly int _width;
|
|
private readonly int _height;
|
|
|
|
public ITexture Texture => _texture;
|
|
public IntPtr NativeHandle => new IntPtr(_fboId);
|
|
|
|
public ManagedGLFramebuffer(OpenGLGraphicsDevice device, ITexture texture, int width, int height, bool hasDepthStencil) {
|
|
_device = device;
|
|
_texture = texture;
|
|
_width = width;
|
|
_height = height;
|
|
|
|
// Generate and bind the framebuffer
|
|
_fboId = _gl.GenFramebuffer();
|
|
GpuMemoryTracker.TrackResourceAllocation(GpuResourceType.FBO);
|
|
_gl.BindFramebuffer(FramebufferTarget.Framebuffer, _fboId);
|
|
|
|
// Attach the texture as the color attachment
|
|
_gl.FramebufferTexture2D(
|
|
FramebufferTarget.Framebuffer,
|
|
FramebufferAttachment.ColorAttachment0,
|
|
TextureTarget.Texture2D,
|
|
(uint)texture.NativePtr.ToInt32(),
|
|
0
|
|
);
|
|
|
|
// Create and attach a depth-stencil renderbuffer if requested
|
|
if (true || hasDepthStencil) {
|
|
_depthStencilRenderbuffer = _gl.GenRenderbuffer();
|
|
GpuMemoryTracker.TrackResourceAllocation(GpuResourceType.RBO);
|
|
_gl.BindRenderbuffer(RenderbufferTarget.Renderbuffer, _depthStencilRenderbuffer);
|
|
_gl.RenderbufferStorage(
|
|
RenderbufferTarget.Renderbuffer,
|
|
InternalFormat.Depth24Stencil8,
|
|
(uint)width,
|
|
(uint)height
|
|
);
|
|
_gl.FramebufferRenderbuffer(
|
|
FramebufferTarget.Framebuffer,
|
|
FramebufferAttachment.DepthStencilAttachment,
|
|
RenderbufferTarget.Renderbuffer,
|
|
_depthStencilRenderbuffer
|
|
);
|
|
GpuMemoryTracker.TrackAllocation(_width * _height * 4, GpuResourceType.RBO); // Depth24Stencil8 is 4 bytes per pixel
|
|
}
|
|
|
|
// Check framebuffer completeness
|
|
var status = _gl.CheckFramebufferStatus(FramebufferTarget.Framebuffer);
|
|
if (status != GLEnum.FramebufferComplete) {
|
|
_gl.BindFramebuffer(FramebufferTarget.Framebuffer, 0);
|
|
_gl.DeleteFramebuffer(_fboId);
|
|
if (_depthStencilRenderbuffer != 0) {
|
|
_gl.DeleteRenderbuffer(_depthStencilRenderbuffer);
|
|
}
|
|
throw new InvalidOperationException($"Framebuffer creation failed: {status}");
|
|
}
|
|
|
|
var error = _gl.GetError();
|
|
if (error != GLEnum.NoError) {
|
|
throw new InvalidOperationException($"OpenGL error during framebuffer setup: {error}");
|
|
}
|
|
|
|
// Unbind the framebuffer
|
|
_gl.BindFramebuffer(FramebufferTarget.Framebuffer, 0);
|
|
}
|
|
|
|
public void Dispose() {
|
|
var fboId = _fboId;
|
|
var depthStencilRenderbuffer = _depthStencilRenderbuffer;
|
|
var width = _width;
|
|
var height = _height;
|
|
|
|
_device.QueueGLAction(gl => {
|
|
if (fboId != 0) {
|
|
gl.DeleteFramebuffer(fboId);
|
|
GpuMemoryTracker.TrackResourceDeallocation(GpuResourceType.FBO);
|
|
}
|
|
if (depthStencilRenderbuffer != 0) {
|
|
gl.DeleteRenderbuffer(depthStencilRenderbuffer);
|
|
GpuMemoryTracker.TrackResourceDeallocation(GpuResourceType.RBO);
|
|
GpuMemoryTracker.TrackDeallocation(width * height * 4, GpuResourceType.RBO);
|
|
}
|
|
});
|
|
}
|
|
}
|
|
}
|