Files
aego/render/host/shaders.go
T
sanspie 5eb1832907
ci-platforms / darwin amd64 smoke (push) Skipped
ci / build (amd64, linux, ubuntu-24.04) (push) Failing after 15m28s
ci / release (push) Skipped
ci-platforms / windows amd64 smoke (push) Skipped
ci-platforms / darwin arm64 smoke (push) Skipped
ci / checks (push) Successful in 7m47s
Complete Stage 12 for v0.12.0
2026-11-05 11:46:53 +03:00

111 lines
3.3 KiB
Go

package host
import (
"errors"
"fmt"
"strings"
"aego/core/errs"
"aego/core/log"
"aego/engine/problems"
"aego/render/material"
"aego/render/shader"
)
// shaderErrors keeps the driver's shader errors (SHD009) mapped back to the shader's own lines.
type shaderErrors struct {
diags []problems.Diagnostic
rev uint64
}
func errField(err error, key string) string {
var e *errs.Error
if !errors.As(err, &e) {
return ""
}
for _, f := range e.Fields {
if f.Key == key {
if s, ok := f.Val.(string); ok {
return s
}
}
}
return ""
}
func (m *Module) shaderError(sh *material.Shader, variant int, err error) {
var mismatch material.DomainMismatch
if errors.As(err, &mismatch) {
// A wrong geometry assignment must not evict driver diagnostics or
// label a successfully linked shader as a rejected reload candidate.
m.eng.Log().With(log.Render).Error("material cannot be used on this geometry", log.F("code", material.MAT004), log.F("file", sh.Name), log.F("err", mismatch.Error()), log.F("asset", sh.ID.String()))
m.shaders.diags = append(m.shaders.diags, problems.Diagnostic{Code: material.MAT004, Severity: problems.Error, Owner: "render", Message: mismatch.Error(), Subject: problems.Subject{Kind: problems.SubjectAsset, Asset: sh.ID, File: sh.Name}})
m.shaders.rev++
return
}
m.shaderReady(sh)
backend := "GL33"
if m.eng.Caps().ESSL {
backend = "WebGL2"
}
stage := errField(err, "stage")
if stage == "" {
stage = "link/layout"
}
var names []string
if variant >= 0 && variant < len(sh.Variants) {
for i, k := range sh.Keywords {
if sh.Variants[variant].Mask&(1<<i) != 0 {
names = append(names, k)
}
}
}
variantName := strings.Join(names, "+")
if variantName == "" {
variantName = "default"
}
frag := errField(err, "stage") == "fragment"
diags := shader.MapLog(errField(err, "log"), sh.Maps[material.SourceIndex(frag, m.eng.Caps().ESSL)], sh.Files, shader.SHD009)
if len(diags) == 0 {
diags = []shader.Diag{{Code: shader.SHD009, File: sh.Name, Msg: err.Error()}}
}
lg := m.eng.Log().With(log.Render)
for _, d := range diags {
d.Msg = fmt.Sprintf("%s %s variant %s: %s", backend, stage, variantName, d.Msg)
lg.Error("shader candidate failed, the previous version stays", log.F("code", d.Code), log.F("file", d.File), log.F("line", d.Line), log.F("err", d.Msg), log.F("compiler_log", errField(err, "log")), log.F("asset", sh.ID.String()))
m.shaders.diags = append(m.shaders.diags, problems.Diagnostic{
Owner: ID, Code: d.Code, Severity: problems.Error, Message: d.Msg,
Subject: problems.Subject{Kind: problems.SubjectFile, Asset: sh.ID, File: d.File, Line: d.Line},
})
}
m.shaders.rev++
}
// ShaderProblems lists the shaders the driver refused, for the Problems panel.
func (m *Module) ShaderProblems() problems.Source {
return problems.Source{
Revision: func() uint64 { return m.shaders.rev },
Append: func(dst []problems.Diagnostic) []problems.Diagnostic {
return append(dst, m.shaders.diags...)
},
}
}
func (m *Module) shaderReady(sh *material.Shader) {
before := len(m.shaders.diags)
keep := m.shaders.diags[:0]
for _, d := range m.shaders.diags {
match := d.Subject.Asset == sh.ID
if sh.ID.IsZero() {
match = d.Subject.File == sh.Name
}
if !match {
keep = append(keep, d)
}
}
m.shaders.diags = keep
if len(keep) != before {
m.shaders.rev++
}
}