shaderprecomp: remove ShaderSourceID

`ShaderSourceID` was confusing as there was no guarantee the same ID is
used for the same source if Ebitengine versions are different.

`ShaderSource` should be kept as the built-in shader contents should not
be exposed.

Updates #2861
Closes #2999
This commit is contained in:
Hajime Hoshi 2024-05-26 22:58:12 +09:00
parent 83ae577c80
commit 4818768965
11 changed files with 37 additions and 92 deletions

View File

@ -40,7 +40,7 @@ func run() error {
if errors.Is(err, exec.ErrNotFound) { if errors.Is(err, exec.ErrNotFound) {
fmt.Fprintln(os.Stderr, "fxc.exe not found. Please install Windows SDK.") fmt.Fprintln(os.Stderr, "fxc.exe not found. Please install Windows SDK.")
fmt.Fprintln(os.Stderr, "See https://learn.microsoft.com/en-us/windows/win32/direct3dtools/fxc for more details.") fmt.Fprintln(os.Stderr, "See https://learn.microsoft.com/en-us/windows/win32/direct3dtools/fxc for more details.")
fmt.Fprintln(os.Stderr, "On PowerShell, you can add a path to the PATH environment variable temporarily like:") fmt.Fprintln(os.Stderr, "HINT: On PowerShell, you can add a path to the PATH environment variable temporarily like:")
fmt.Fprintln(os.Stderr) fmt.Fprintln(os.Stderr)
fmt.Fprintln(os.Stderr, ` & (Get-Process -Id $PID).Path { $env:PATH="C:\Program Files (x86)\Windows Kits\10\bin\10.0.22621.0\x64;"+$env:PATH; go generate .\examples\shaderprecomp\fxc\ }`) fmt.Fprintln(os.Stderr, ` & (Get-Process -Id $PID).Path { $env:PATH="C:\Program Files (x86)\Windows Kits\10\bin\10.0.22621.0\x64;"+$env:PATH; go generate .\examples\shaderprecomp\fxc\ }`)
fmt.Fprintln(os.Stderr) fmt.Fprintln(os.Stderr)
@ -61,33 +61,27 @@ func run() error {
if err != nil { if err != nil {
return err return err
} }
defaultSrc, err := shaderprecomp.NewShaderSource(defaultSrcBytes) srcs = append(srcs, shaderprecomp.NewShaderSource(defaultSrcBytes))
if err != nil {
return err
}
srcs = append(srcs, defaultSrc)
for _, src := range srcs { for i, src := range srcs {
// Avoid using errgroup.Group. // Avoid using errgroup.Group.
// Compiling sources in parallel causes a mixed error message on the console. // Compiling sources in parallel causes a mixed error message on the console.
if err := compile(src, tmpdir); err != nil { if err := compile(src, i, tmpdir); err != nil {
return err return err
} }
} }
return nil return nil
} }
func generateHSLSFiles(source *shaderprecomp.ShaderSource, tmpdir string) (vs, ps string, err error) { func generateHSLSFiles(source *shaderprecomp.ShaderSource, index int, tmpdir string) (vs, ps string, err error) {
id := source.ID().String() vsHLSLFilePath := filepath.Join(tmpdir, fmt.Sprintf("%d_vs.hlsl", index))
vsHLSLFilePath := filepath.Join(tmpdir, id+"_vs.hlsl")
vsf, err := os.Create(vsHLSLFilePath) vsf, err := os.Create(vsHLSLFilePath)
if err != nil { if err != nil {
return "", "", err return "", "", err
} }
defer vsf.Close() defer vsf.Close()
psHLSLFilePath := filepath.Join(tmpdir, id+"_ps.hlsl") psHLSLFilePath := filepath.Join(tmpdir, fmt.Sprintf("%d_ps.hlsl", index))
psf, err := os.Create(psHLSLFilePath) psf, err := os.Create(psHLSLFilePath)
if err != nil { if err != nil {
return "", "", err return "", "", err
@ -101,17 +95,15 @@ func generateHSLSFiles(source *shaderprecomp.ShaderSource, tmpdir string) (vs, p
return vsHLSLFilePath, psHLSLFilePath, nil return vsHLSLFilePath, psHLSLFilePath, nil
} }
func compile(source *shaderprecomp.ShaderSource, tmpdir string) error { func compile(source *shaderprecomp.ShaderSource, index int, tmpdir string) error {
// Generate HLSL files. Make sure this process doesn't have any handlers of the files. // Generate HLSL files. Make sure this process doesn't have any handlers of the files.
// Without closing the files, fxc.exe cannot access the files. // Without closing the files, fxc.exe cannot access the files.
vsHLSLFilePath, psHLSLFilePath, err := generateHSLSFiles(source, tmpdir) vsHLSLFilePath, psHLSLFilePath, err := generateHSLSFiles(source, index, tmpdir)
if err != nil { if err != nil {
return err return err
} }
id := source.ID().String() vsFXCFilePath := fmt.Sprintf("%d_vs.fxc", index)
vsFXCFilePath := id + "_vs.fxc"
cmd := exec.Command("fxc.exe", "/nologo", "/O3", "/T", shaderprecomp.HLSLVertexShaderProfile, "/E", shaderprecomp.HLSLVertexShaderEntryPoint, "/Fo", vsFXCFilePath, vsHLSLFilePath) cmd := exec.Command("fxc.exe", "/nologo", "/O3", "/T", shaderprecomp.HLSLVertexShaderProfile, "/E", shaderprecomp.HLSLVertexShaderEntryPoint, "/Fo", vsFXCFilePath, vsHLSLFilePath)
cmd.Stdout = os.Stdout cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr cmd.Stderr = os.Stderr
@ -119,7 +111,7 @@ func compile(source *shaderprecomp.ShaderSource, tmpdir string) error {
return err return err
} }
psFXCFilePath := id + "_ps.fxc" psFXCFilePath := fmt.Sprintf("%d_ps.fxc", index)
cmd = exec.Command("fxc.exe", "/nologo", "/O3", "/T", shaderprecomp.HLSLPixelShaderProfile, "/E", shaderprecomp.HLSLPixelShaderEntryPoint, "/Fo", psFXCFilePath, psHLSLFilePath) cmd = exec.Command("fxc.exe", "/nologo", "/O3", "/T", shaderprecomp.HLSLPixelShaderProfile, "/E", shaderprecomp.HLSLPixelShaderEntryPoint, "/Fo", psFXCFilePath, psHLSLFilePath)
cmd.Stdout = os.Stdout cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr cmd.Stderr = os.Stderr

View File

@ -20,6 +20,7 @@
package main package main
import ( import (
"fmt"
"os" "os"
"os/exec" "os/exec"
"path/filepath" "path/filepath"
@ -46,26 +47,20 @@ func run() error {
if err != nil { if err != nil {
return err return err
} }
defaultSrc, err := shaderprecomp.NewShaderSource(defaultSrcBytes) srcs = append(srcs, shaderprecomp.NewShaderSource(defaultSrcBytes))
if err != nil {
return err
}
srcs = append(srcs, defaultSrc)
for _, src := range srcs { for i, src := range srcs {
// Avoid using errgroup.Group. // Avoid using errgroup.Group.
// Compiling sources in parallel causes a mixed error message on the console. // Compiling sources in parallel causes a mixed error message on the console.
if err := compile(src, tmpdir); err != nil { if err := compile(src, i, tmpdir); err != nil {
return err return err
} }
} }
return nil return nil
} }
func compile(source *shaderprecomp.ShaderSource, tmpdir string) error { func compile(source *shaderprecomp.ShaderSource, index int, tmpdir string) error {
id := source.ID().String() metalFilePath := filepath.Join(tmpdir, fmt.Sprintf("%d.metal", index))
metalFilePath := filepath.Join(tmpdir, id+".metal")
f, err := os.Create(metalFilePath) f, err := os.Create(metalFilePath)
if err != nil { if err != nil {
@ -80,14 +75,14 @@ func compile(source *shaderprecomp.ShaderSource, tmpdir string) error {
return err return err
} }
irFilePath := filepath.Join(tmpdir, id+".ir") irFilePath := filepath.Join(tmpdir, fmt.Sprintf("%d.ir", index))
cmd := exec.Command("xcrun", "-sdk", "macosx", "metal", "-o", irFilePath, "-c", metalFilePath) cmd := exec.Command("xcrun", "-sdk", "macosx", "metal", "-o", irFilePath, "-c", metalFilePath)
cmd.Stderr = os.Stderr cmd.Stderr = os.Stderr
if err := cmd.Run(); err != nil { if err := cmd.Run(); err != nil {
return err return err
} }
metallibFilePath := id + ".metallib" metallibFilePath := fmt.Sprintf("%d.metallib", index)
cmd = exec.Command("xcrun", "-sdk", "macosx", "metallib", "-o", metallibFilePath, irFilePath) cmd = exec.Command("xcrun", "-sdk", "macosx", "metallib", "-o", metallibFilePath, irFilePath)
cmd.Stderr = os.Stderr cmd.Stderr = os.Stderr
if err := cmd.Run(); err != nil { if err := cmd.Run(); err != nil {

View File

@ -29,14 +29,10 @@ var metallibs embed.FS
func registerPrecompiledShaders() error { func registerPrecompiledShaders() error {
srcs := shaderprecomp.AppendBuildinShaderSources(nil) srcs := shaderprecomp.AppendBuildinShaderSources(nil)
defaultShaderSource, err := shaderprecomp.NewShaderSource(defaultShaderSourceBytes) srcs = append(srcs, shaderprecomp.NewShaderSource(defaultShaderSourceBytes))
if err != nil {
return err
}
srcs = append(srcs, defaultShaderSource)
for _, src := range srcs { for i, src := range srcs {
name := src.ID().String() + ".metallib" name := fmt.Sprintf("%d.metallib", i)
lib, err := metallibs.ReadFile("metallib/" + name) lib, err := metallibs.ReadFile("metallib/" + name)
if err != nil { if err != nil {
if errors.Is(err, fs.ErrNotExist) { if errors.Is(err, fs.ErrNotExist) {

View File

@ -31,14 +31,10 @@ var fxcs embed.FS
func registerPrecompiledShaders() error { func registerPrecompiledShaders() error {
srcs := shaderprecomp.AppendBuildinShaderSources(nil) srcs := shaderprecomp.AppendBuildinShaderSources(nil)
defaultShaderSource, err := shaderprecomp.NewShaderSource(defaultShaderSourceBytes) srcs = append(srcs, shaderprecomp.NewShaderSource(defaultShaderSourceBytes))
if err != nil {
return err
}
srcs = append(srcs, defaultShaderSource)
for _, src := range srcs { for i, src := range srcs {
vsname := src.ID().String() + "_vs.fxc" vsname := fmt.Sprintf("%d_vs.fxc", i)
vs, err := fxcs.ReadFile("fxc/" + vsname) vs, err := fxcs.ReadFile("fxc/" + vsname)
if err != nil { if err != nil {
if errors.Is(err, fs.ErrNotExist) { if errors.Is(err, fs.ErrNotExist) {
@ -48,7 +44,7 @@ func registerPrecompiledShaders() error {
return err return err
} }
psname := src.ID().String() + "_ps.fxc" psname := fmt.Sprintf("%d_ps.fxc", i)
ps, err := fxcs.ReadFile("fxc/" + psname) ps, err := fxcs.ReadFile("fxc/" + psname)
if err != nil { if err != nil {
if errors.Is(err, fs.ErrNotExist) { if errors.Is(err, fs.ErrNotExist) {

View File

@ -70,8 +70,8 @@ func (c *precompiledFXCs) get(hash shaderir.SourceHash) ([]byte, []byte) {
var thePrecompiledFXCs precompiledFXCs var thePrecompiledFXCs precompiledFXCs
func RegisterPrecompiledFXCs(hash shaderir.SourceHash, vertex, pixel []byte) { func RegisterPrecompiledFXCs(source []byte, vertex, pixel []byte) {
thePrecompiledFXCs.put(hash, vertex, pixel) thePrecompiledFXCs.put(shaderir.CalcSourceHash(source), vertex, pixel)
} }
var vertexShaderCache = map[string]*_ID3DBlob{} var vertexShaderCache = map[string]*_ID3DBlob{}

View File

@ -51,8 +51,8 @@ func (c *precompiledLibraries) get(hash shaderir.SourceHash) []byte {
var thePrecompiledLibraries precompiledLibraries var thePrecompiledLibraries precompiledLibraries
func RegisterPrecompiledLibrary(hash shaderir.SourceHash, bin []byte) { func RegisterPrecompiledLibrary(source []byte, bin []byte) {
thePrecompiledLibraries.put(hash, bin) thePrecompiledLibraries.put(shaderir.CalcSourceHash(source), bin)
} }
type shaderRpsKey struct { type shaderRpsKey struct {

View File

@ -18,10 +18,6 @@
package playstation5 package playstation5
import ( func RegisterPrecompiledShaders(source []byte, vertex, pixel []byte) {
"github.com/hajimehoshi/ebiten/v2/internal/shaderir"
)
func RegisterPrecompiledShaders(hash shaderir.SourceHash, vertex, pixel []byte) {
// TODO: Implement this. // TODO: Implement this.
} }

View File

@ -16,8 +16,6 @@ package shaderprecomp
import ( import (
"github.com/hajimehoshi/ebiten/v2/internal/builtinshader" "github.com/hajimehoshi/ebiten/v2/internal/builtinshader"
"github.com/hajimehoshi/ebiten/v2/internal/graphics"
"github.com/hajimehoshi/ebiten/v2/internal/shaderir"
) )
// AppendBuildinShaderSources appends all the built-in shader sources to the given slice. // AppendBuildinShaderSources appends all the built-in shader sources to the given slice.
@ -27,11 +25,7 @@ import (
// AppendBuildinShaderSources is concurrent-safe. // AppendBuildinShaderSources is concurrent-safe.
func AppendBuildinShaderSources(sources []*ShaderSource) []*ShaderSource { func AppendBuildinShaderSources(sources []*ShaderSource) []*ShaderSource {
for _, s := range builtinshader.AppendShaderSources(nil) { for _, s := range builtinshader.AppendShaderSources(nil) {
src, err := NewShaderSource(s) sources = append(sources, NewShaderSource(s))
if err != nil {
panic(err)
}
sources = append(sources, src)
} }
return sources return sources
} }
@ -39,32 +33,11 @@ func AppendBuildinShaderSources(sources []*ShaderSource) []*ShaderSource {
// ShaderSource is an object encapsulating a shader source code. // ShaderSource is an object encapsulating a shader source code.
type ShaderSource struct { type ShaderSource struct {
source []byte source []byte
id ShaderSourceID
} }
// NewShaderSource creates a new ShaderSource object from the given source code. // NewShaderSource creates a new ShaderSource object from the given source code.
func NewShaderSource(source []byte) (*ShaderSource, error) { func NewShaderSource(source []byte) *ShaderSource {
hash, err := graphics.CalcSourceHash(source)
if err != nil {
return nil, err
}
return &ShaderSource{ return &ShaderSource{
source: source, source: source,
id: ShaderSourceID(hash), }
}, nil
}
// ID returns a unique identifier for the shader source.
// The ShaderSourceID value must be the same for the same shader source and the same Ebitengine version.
// There is no guarantee that the ShaderSourceID value is the same between different Ebitengine versions.
func (s *ShaderSource) ID() ShaderSourceID {
return s.id
}
// ShaderSourceID is a uniuqe identifier for a shader source.
type ShaderSourceID [16]byte
// String returns a string representation of the shader source ID.
func (s ShaderSourceID) String() string {
return shaderir.SourceHash(s).String()
} }

View File

@ -21,7 +21,6 @@ import (
"github.com/hajimehoshi/ebiten/v2/internal/graphics" "github.com/hajimehoshi/ebiten/v2/internal/graphics"
"github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver/metal" "github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver/metal"
"github.com/hajimehoshi/ebiten/v2/internal/shaderir"
"github.com/hajimehoshi/ebiten/v2/internal/shaderir/msl" "github.com/hajimehoshi/ebiten/v2/internal/shaderir/msl"
) )
@ -45,5 +44,5 @@ func CompileToMSL(w io.Writer, source *ShaderSource) error {
// //
// RegisterMetalLibrary is concurrent-safe. // RegisterMetalLibrary is concurrent-safe.
func RegisterMetalLibrary(source *ShaderSource, library []byte) { func RegisterMetalLibrary(source *ShaderSource, library []byte) {
metal.RegisterPrecompiledLibrary(shaderir.SourceHash(source.ID()), library) metal.RegisterPrecompiledLibrary(source.source, library)
} }

View File

@ -21,7 +21,6 @@ import (
"github.com/hajimehoshi/ebiten/v2/internal/graphics" "github.com/hajimehoshi/ebiten/v2/internal/graphics"
"github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver/playstation5" "github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver/playstation5"
"github.com/hajimehoshi/ebiten/v2/internal/shaderir"
"github.com/hajimehoshi/ebiten/v2/internal/shaderir/pssl" "github.com/hajimehoshi/ebiten/v2/internal/shaderir/pssl"
) )
@ -47,5 +46,5 @@ func CompileToPSSL(vertexWriter, pixelWriter io.Writer, source *ShaderSource) er
// //
// RegisterPlayStationShaders is concurrent-safe. // RegisterPlayStationShaders is concurrent-safe.
func RegisterPlayStationShaders(source *ShaderSource, vertexShader, pixelShader []byte) { func RegisterPlayStationShaders(source *ShaderSource, vertexShader, pixelShader []byte) {
playstation5.RegisterPrecompiledShaders(shaderir.SourceHash(source.ID()), vertexShader, pixelShader) playstation5.RegisterPrecompiledShaders(source.source, vertexShader, pixelShader)
} }

View File

@ -21,7 +21,6 @@ import (
"github.com/hajimehoshi/ebiten/v2/internal/graphics" "github.com/hajimehoshi/ebiten/v2/internal/graphics"
"github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver/directx" "github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver/directx"
"github.com/hajimehoshi/ebiten/v2/internal/shaderir"
"github.com/hajimehoshi/ebiten/v2/internal/shaderir/hlsl" "github.com/hajimehoshi/ebiten/v2/internal/shaderir/hlsl"
) )
@ -63,5 +62,5 @@ func CompileToHLSL(vertexWriter, pixelWriter io.Writer, source *ShaderSource) er
// //
// RegisterFXCs is concurrent-safe. // RegisterFXCs is concurrent-safe.
func RegisterFXCs(source *ShaderSource, vertexFXC, pixelFXC []byte) { func RegisterFXCs(source *ShaderSource, vertexFXC, pixelFXC []byte) {
directx.RegisterPrecompiledFXCs(shaderir.SourceHash(source.ID()), vertexFXC, pixelFXC) directx.RegisterPrecompiledFXCs(source.source, vertexFXC, pixelFXC)
} }