Revert "shaderprecomp: remove ShaderSource and ShaderSourceID"

This reverts commit 8be3bb41d5.

Reason: removing `ShaderSource` unexpected exposes the source.

Updates #2999
This commit is contained in:
Hajime Hoshi 2024-05-26 22:45:12 +09:00
parent 8be3bb41d5
commit 83ae577c80
9 changed files with 91 additions and 53 deletions

View File

@ -20,10 +20,8 @@
package main package main
import ( import (
"encoding/hex"
"errors" "errors"
"fmt" "fmt"
"hash/fnv"
"os" "os"
"os/exec" "os/exec"
"path/filepath" "path/filepath"
@ -59,7 +57,11 @@ func run() error {
srcs := shaderprecomp.AppendBuildinShaderSources(nil) srcs := shaderprecomp.AppendBuildinShaderSources(nil)
defaultSrc, err := os.ReadFile(filepath.Join("..", "defaultshader.go")) defaultSrcBytes, err := os.ReadFile(filepath.Join("..", "defaultshader.go"))
if err != nil {
return err
}
defaultSrc, err := shaderprecomp.NewShaderSource(defaultSrcBytes)
if err != nil { if err != nil {
return err return err
} }
@ -75,7 +77,9 @@ func run() error {
return nil return nil
} }
func generateHSLSFiles(source []byte, id string, tmpdir string) (vs, ps string, err error) { func generateHSLSFiles(source *shaderprecomp.ShaderSource, tmpdir string) (vs, ps string, err error) {
id := source.ID().String()
vsHLSLFilePath := filepath.Join(tmpdir, id+"_vs.hlsl") vsHLSLFilePath := filepath.Join(tmpdir, id+"_vs.hlsl")
vsf, err := os.Create(vsHLSLFilePath) vsf, err := os.Create(vsHLSLFilePath)
if err != nil { if err != nil {
@ -97,18 +101,16 @@ func generateHSLSFiles(source []byte, id string, tmpdir string) (vs, ps string,
return vsHLSLFilePath, psHLSLFilePath, nil return vsHLSLFilePath, psHLSLFilePath, nil
} }
func compile(kageSource []byte, tmpdir string) error { func compile(source *shaderprecomp.ShaderSource, tmpdir string) error {
h := fnv.New32()
_, _ = h.Write(kageSource)
id := hex.EncodeToString(h.Sum(nil))
// 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(kageSource, id, tmpdir) vsHLSLFilePath, psHLSLFilePath, err := generateHSLSFiles(source, tmpdir)
if err != nil { if err != nil {
return err return err
} }
id := source.ID().String()
vsFXCFilePath := id + "_vs.fxc" 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

View File

@ -20,8 +20,6 @@
package main package main
import ( import (
"encoding/hex"
"hash/fnv"
"os" "os"
"os/exec" "os/exec"
"path/filepath" "path/filepath"
@ -44,7 +42,11 @@ func run() error {
srcs := shaderprecomp.AppendBuildinShaderSources(nil) srcs := shaderprecomp.AppendBuildinShaderSources(nil)
defaultSrc, err := os.ReadFile(filepath.Join("..", "defaultshader.go")) defaultSrcBytes, err := os.ReadFile(filepath.Join("..", "defaultshader.go"))
if err != nil {
return err
}
defaultSrc, err := shaderprecomp.NewShaderSource(defaultSrcBytes)
if err != nil { if err != nil {
return err return err
} }
@ -60,10 +62,8 @@ func run() error {
return nil return nil
} }
func compile(kageSource []byte, tmpdir string) error { func compile(source *shaderprecomp.ShaderSource, tmpdir string) error {
h := fnv.New32() id := source.ID().String()
_, _ = h.Write(kageSource)
id := hex.EncodeToString(h.Sum(nil))
metalFilePath := filepath.Join(tmpdir, id+".metal") metalFilePath := filepath.Join(tmpdir, id+".metal")
@ -73,7 +73,7 @@ func compile(kageSource []byte, tmpdir string) error {
} }
defer f.Close() defer f.Close()
if err := shaderprecomp.CompileToMSL(f, kageSource); err != nil { if err := shaderprecomp.CompileToMSL(f, source); err != nil {
return err return err
} }
if err := f.Sync(); err != nil { if err := f.Sync(); err != nil {

View File

@ -16,10 +16,8 @@ package main
import ( import (
"embed" "embed"
"encoding/hex"
"errors" "errors"
"fmt" "fmt"
"hash/fnv"
"io/fs" "io/fs"
"os" "os"
@ -31,16 +29,14 @@ var metallibs embed.FS
func registerPrecompiledShaders() error { func registerPrecompiledShaders() error {
srcs := shaderprecomp.AppendBuildinShaderSources(nil) srcs := shaderprecomp.AppendBuildinShaderSources(nil)
srcs = append(srcs, defaultShaderSourceBytes) defaultShaderSource, err := shaderprecomp.NewShaderSource(defaultShaderSourceBytes)
if err != nil {
return err
}
srcs = append(srcs, defaultShaderSource)
for _, src := range srcs { for _, src := range srcs {
// Calculate the hash of the source code to identify the Metal library. name := src.ID().String() + ".metallib"
// FNV is used as it is fast and the hash does not need to be secure.
h := fnv.New32()
_, _ = h.Write(src)
id := hex.EncodeToString(h.Sum(nil))
name := id + ".metallib"
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

@ -16,10 +16,8 @@ package main
import ( import (
"embed" "embed"
"encoding/hex"
"errors" "errors"
"fmt" "fmt"
"hash/fnv"
"io/fs" "io/fs"
"os" "os"
@ -33,16 +31,14 @@ var fxcs embed.FS
func registerPrecompiledShaders() error { func registerPrecompiledShaders() error {
srcs := shaderprecomp.AppendBuildinShaderSources(nil) srcs := shaderprecomp.AppendBuildinShaderSources(nil)
srcs = append(srcs, defaultShaderSourceBytes) defaultShaderSource, err := shaderprecomp.NewShaderSource(defaultShaderSourceBytes)
if err != nil {
return err
}
srcs = append(srcs, defaultShaderSource)
for _, src := range srcs { for _, src := range srcs {
// Calculate the hash of the source code to identify the Metal library. vsname := src.ID().String() + "_vs.fxc"
// FNV is used as it is fast and the hash does not need to be secure.
h := fnv.New32()
_, _ = h.Write(src)
id := hex.EncodeToString(h.Sum(nil))
vsname := id + "_vs.fxc"
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) {
@ -52,7 +48,7 @@ func registerPrecompiledShaders() error {
return err return err
} }
psname := id + "_ps.fxc" psname := src.ID().String() + "_ps.fxc"
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(kageSource []byte, vertex, pixel []byte) { func RegisterPrecompiledFXCs(hash shaderir.SourceHash, vertex, pixel []byte) {
thePrecompiledFXCs.put(shaderir.CalcSourceHash(kageSource), vertex, pixel) thePrecompiledFXCs.put(hash, 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(kageSource []byte, bin []byte) { func RegisterPrecompiledLibrary(hash shaderir.SourceHash, bin []byte) {
thePrecompiledLibraries.put(shaderir.CalcSourceHash(kageSource), bin) thePrecompiledLibraries.put(hash, bin)
} }
type shaderRpsKey struct { type shaderRpsKey struct {

View File

@ -16,6 +16,8 @@ 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.
@ -23,6 +25,46 @@ import (
// Do not modify the content of the shader source. // Do not modify the content of the shader source.
// //
// AppendBuildinShaderSources is concurrent-safe. // AppendBuildinShaderSources is concurrent-safe.
func AppendBuildinShaderSources(sources [][]byte) [][]byte { func AppendBuildinShaderSources(sources []*ShaderSource) []*ShaderSource {
return builtinshader.AppendShaderSources(sources) for _, s := range builtinshader.AppendShaderSources(nil) {
src, err := NewShaderSource(s)
if err != nil {
panic(err)
}
sources = append(sources, src)
}
return sources
}
// ShaderSource is an object encapsulating a shader source code.
type ShaderSource struct {
source []byte
id ShaderSourceID
}
// NewShaderSource creates a new ShaderSource object from the given source code.
func NewShaderSource(source []byte) (*ShaderSource, error) {
hash, err := graphics.CalcSourceHash(source)
if err != nil {
return nil, err
}
return &ShaderSource{
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,14 +21,15 @@ 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"
) )
// CompileToMSL compiles the shader source to Metal Shader Language, and writes the result to w. // CompileToMSL compiles the shader source to Metal Shader Language, and writes the result to w.
// //
// CompileToMSL is concurrent-safe. // CompileToMSL is concurrent-safe.
func CompileToMSL(w io.Writer, kageSource []byte) error { func CompileToMSL(w io.Writer, source *ShaderSource) error {
ir, err := graphics.CompileShader(kageSource) ir, err := graphics.CompileShader(source.source)
if err != nil { if err != nil {
return err return err
} }
@ -43,6 +44,6 @@ func CompileToMSL(w io.Writer, kageSource []byte) error {
// For more details, see https://developer.apple.com/documentation/metal/shader_libraries/building_a_shader_library_by_precompiling_source_files. // For more details, see https://developer.apple.com/documentation/metal/shader_libraries/building_a_shader_library_by_precompiling_source_files.
// //
// RegisterMetalLibrary is concurrent-safe. // RegisterMetalLibrary is concurrent-safe.
func RegisterMetalLibrary(kageSource []byte, library []byte) { func RegisterMetalLibrary(source *ShaderSource, library []byte) {
metal.RegisterPrecompiledLibrary(kageSource, library) metal.RegisterPrecompiledLibrary(shaderir.SourceHash(source.ID()), library)
} }

View File

@ -21,6 +21,7 @@ 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"
) )
@ -41,8 +42,8 @@ const (
// CompileToHLSL compiles the shader source to High-Level Shader Language to writers. // CompileToHLSL compiles the shader source to High-Level Shader Language to writers.
// //
// CompileToHLSL is concurrent-safe. // CompileToHLSL is concurrent-safe.
func CompileToHLSL(vertexWriter, pixelWriter io.Writer, kageSource []byte) error { func CompileToHLSL(vertexWriter, pixelWriter io.Writer, source *ShaderSource) error {
ir, err := graphics.CompileShader(kageSource) ir, err := graphics.CompileShader(source.source)
if err != nil { if err != nil {
return err return err
} }
@ -61,6 +62,6 @@ func CompileToHLSL(vertexWriter, pixelWriter io.Writer, kageSource []byte) error
// For more details, see https://learn.microsoft.com/en-us/windows/win32/direct3dtools/dx-graphics-tools-fxc-using. // For more details, see https://learn.microsoft.com/en-us/windows/win32/direct3dtools/dx-graphics-tools-fxc-using.
// //
// RegisterFXCs is concurrent-safe. // RegisterFXCs is concurrent-safe.
func RegisterFXCs(kageSource []byte, vertexFXC, pixelFXC []byte) { func RegisterFXCs(source *ShaderSource, vertexFXC, pixelFXC []byte) {
directx.RegisterPrecompiledFXCs(kageSource, vertexFXC, pixelFXC) directx.RegisterPrecompiledFXCs(shaderir.SourceHash(source.ID()), vertexFXC, pixelFXC)
} }