refactor(app): compose world rendering startup
Move Region/environment, mandatory modern rendering, terrain, WB, texture, and sampler construction behind the typed Phase-4 composition boundary. Give every fallible GL constructor prefix retryable ownership so partial startup failure cannot leak or replay resource deletion while preserving the accepted render path and DAT inputs. Co-authored-by: Codex <codex@openai.com>
This commit is contained in:
parent
cd7b519f78
commit
6a2fe98cc4
22 changed files with 1983 additions and 634 deletions
|
|
@ -1,4 +1,5 @@
|
|||
using Chorizite.Core.Render;
|
||||
using AcDream.App.Rendering;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Silk.NET.OpenGL;
|
||||
using System;
|
||||
|
|
@ -161,7 +162,7 @@ namespace AcDream.App.Rendering.Wb {
|
|||
|
||||
if (string.IsNullOrWhiteSpace(vertShaderSource) || string.IsNullOrWhiteSpace(fragShaderSource)) {
|
||||
_log.LogError($"Shader {Name} has no source code!");
|
||||
return;
|
||||
throw new InvalidOperationException($"Shader {Name} has no source code.");
|
||||
}
|
||||
|
||||
if (_device.HasOpenGL43 && _device.HasBindless) {
|
||||
|
|
@ -170,41 +171,47 @@ namespace AcDream.App.Rendering.Wb {
|
|||
fragShaderSource = fragShaderSource.Replace("#version 330 core", replacement);
|
||||
}
|
||||
|
||||
uint vertexShader = CompileShader(ShaderType.VertexShader, Name, vertShaderSource);
|
||||
uint fragmentShader = CompileShader(ShaderType.FragmentShader, Name, fragShaderSource);
|
||||
var resources = new ResourceCleanupGroup();
|
||||
uint prog = 0;
|
||||
bool accountingPublished = false;
|
||||
try {
|
||||
prog = ShaderProgramConstruction.Build(
|
||||
new GlShaderProgramBuildApi(GL),
|
||||
vertShaderSource,
|
||||
fragShaderSource);
|
||||
uint ownedProgram = prog;
|
||||
var unpublishedProgramRelease = new RetryableGpuResourceRelease(
|
||||
() => GlResourceCommand.DeleteProgram(
|
||||
GL,
|
||||
ownedProgram,
|
||||
$"delete unpublished WB shader program {ownedProgram}"),
|
||||
() => {
|
||||
if (accountingPublished)
|
||||
{
|
||||
GpuMemoryTracker.TrackResourceDeallocation(
|
||||
GpuResourceType.Shader);
|
||||
}
|
||||
});
|
||||
resources.Add("WB shader program", unpublishedProgramRelease.Run);
|
||||
|
||||
var prog = GL.CreateProgram();
|
||||
GLHelpers.CheckErrors(GL, true);
|
||||
GL.AttachShader(prog, vertexShader);
|
||||
GLHelpers.CheckErrors(GL, true);
|
||||
GL.AttachShader(prog, fragmentShader);
|
||||
GLHelpers.CheckErrors(GL, true);
|
||||
GL.LinkProgram(prog);
|
||||
GLHelpers.CheckErrors(GL, true);
|
||||
// Bind SceneData uniform block to point 0 if it exists.
|
||||
GlResourceCommand.Execute(GL, $"configure shader {Name} SceneData binding", () => {
|
||||
uint sceneDataIndex = GL.GetUniformBlockIndex(prog, "SceneData");
|
||||
if (sceneDataIndex != uint.MaxValue)
|
||||
GL.UniformBlockBinding(prog, sceneDataIndex, 0);
|
||||
});
|
||||
|
||||
GL.GetProgram(prog, GLEnum.LinkStatus, out int success);
|
||||
GLHelpers.CheckErrors(GL);
|
||||
if (success != 1) {
|
||||
var infoLog = GL.GetProgramInfoLog(prog);
|
||||
_log.LogError($"Error: shader {Name} link failed: {infoLog}");
|
||||
GL.DeleteProgram(prog);
|
||||
return;
|
||||
}
|
||||
else {
|
||||
_log.LogTrace($"{(Program != 0 ? "Reloaded" : "Loaded")} shader: {Name}");
|
||||
GpuMemoryTracker.TrackResourceAllocation(GpuResourceType.Shader);
|
||||
accountingPublished = true;
|
||||
resources.TransferAll();
|
||||
} catch (Exception constructionFailure) {
|
||||
_log.LogError(constructionFailure, "Failed to construct shader {ShaderName}", Name);
|
||||
resources.RollbackConstructionAndThrow(
|
||||
$"Shader {Name} construction failed and its GL program did not cleanly roll back.",
|
||||
constructionFailure);
|
||||
}
|
||||
|
||||
// Bind SceneData uniform block to point 0 if it exists
|
||||
var sceneDataIndex = GL.GetUniformBlockIndex(prog, "SceneData");
|
||||
if (sceneDataIndex != uint.MaxValue) {
|
||||
GL.UniformBlockBinding(prog, sceneDataIndex, 0);
|
||||
GLHelpers.CheckErrors(GL);
|
||||
}
|
||||
|
||||
GL.DeleteShader(vertexShader);
|
||||
GLHelpers.CheckErrors(GL);
|
||||
GL.DeleteShader(fragmentShader);
|
||||
GLHelpers.CheckErrors(GL);
|
||||
_log.LogTrace($"{(Program != 0 ? "Reloaded" : "Loaded")} shader: {Name}");
|
||||
|
||||
if (Program != 0) {
|
||||
Unload();
|
||||
|
|
@ -212,32 +219,12 @@ namespace AcDream.App.Rendering.Wb {
|
|||
_uniformLocations.Clear();
|
||||
_uniformValues.Clear();
|
||||
|
||||
GpuMemoryTracker.TrackResourceAllocation(GpuResourceType.Shader);
|
||||
Program = prog;
|
||||
ProgramId = prog;
|
||||
NeedsLoad = false;
|
||||
GLHelpers.CheckErrors(GL);
|
||||
}
|
||||
|
||||
private uint CompileShader(ShaderType shaderType, string name, string shaderSource) {
|
||||
uint shader = GL.CreateShader(shaderType);
|
||||
GLHelpers.CheckErrors(GL);
|
||||
|
||||
GL.ShaderSource(shader, shaderSource);
|
||||
GLHelpers.CheckErrors(GL);
|
||||
GL.CompileShader(shader);
|
||||
GLHelpers.CheckErrors(GL);
|
||||
|
||||
GL.GetShader(shader, ShaderParameterName.CompileStatus, out int success);
|
||||
GLHelpers.CheckErrors(GL);
|
||||
if (success != 1) {
|
||||
var infoLog = GL.GetShaderInfoLog(shader);
|
||||
_log.LogError($"Error: {name}:{shaderType} compilation failed: {infoLog}");
|
||||
}
|
||||
|
||||
return shader;
|
||||
}
|
||||
|
||||
public override void Bind() {
|
||||
lock (_lock) {
|
||||
SetActive();
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue