blob: 950a10f08de0718101fd3be1dd7c3a069fac8828 [file] [log] [blame]
// Copyright (C) 2016 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Package shadertools wraps around external C code for manipulating shaders.
package shadertools
//#cgo LDFLAGS: -lspv -lkhronos -lstdc++ -lpthread -lm
//#include "../../cc/Spv-Manager/libmanager.h"
//#include <stdlib.h>
//// Workaround for https://github.com/golang/go/issues/8756 (fixed in go 1.8):
//#cgo windows LDFLAGS: -Wl,--allow-multiple-definition
import "C"
import "unsafe"
// Instruction represents a SPIR-V instruction.
type Instruction struct {
Id uint32 // Result id.
Opcode uint32 // Opcode.
Words []uint32 // Operands.
Name string // Optional symbol name.
}
// CodeWithDebugInfo is the result returned by ConvertGlsl.
type CodeWithDebugInfo struct {
Ok bool // Whether the call succeeds.
Message string // Error message if failed.
SourceCode string // Modified GLSL.
DisassemblyString string // Diassembly of modified GLSL.
Info []Instruction // A set of SPIR-V debug instructions.
}
// Options controls how ConvertGlsl converts its passed-in GLSL source code.
type Option struct {
// Whether the passed-in shader is of the fragment stage.
IsFragmentShader bool
// Whether the passed-in shader is of the vertex stage.
IsVertexShader bool
// Whether to add prefix to all non-builtin symbols.
PrefixNames bool
// The name prefix to be added to all non-builtin symbols.
NamesPrefix string /* optional */
// Whether to create a corresponding output variable for each input variable.
AddOutputsForInputs bool
// The name prefix of added output variables.
OutputPrefix string /* optional */
// Whether to make the generated GLSL code debuggable.
MakeDebuggable bool
// Whether to check the generated GLSL code compiles again.
CheckAfterChanges bool
// Whether to disassemble the generated GLSL code.
Disassemble bool
}
// ConvertGlsl modifies the given GLSL according to the options specified via
// option and returns the modification status and result. Possible
// modifications includes creating output variables for input variables,
// prefixing all non-builtin symbols with a given prefix, etc.
func ConvertGlsl(source string, option *Option) CodeWithDebugInfo {
np := C.CString(option.NamesPrefix)
op := C.CString(option.OutputPrefix)
opts := C.struct_options_t{
is_fragment_shader: C.bool(option.IsFragmentShader),
is_vertex_shader: C.bool(option.IsVertexShader),
prefix_names: C.bool(option.PrefixNames),
names_prefix: np,
add_outputs_for_inputs: C.bool(option.AddOutputsForInputs),
output_prefix: op,
make_debuggable: C.bool(option.MakeDebuggable),
check_after_changes: C.bool(option.CheckAfterChanges),
disassemble: C.bool(option.Disassemble),
}
csource := C.CString(source)
result := C.convertGlsl(csource, C.size_t(len(source)), &opts)
C.free(unsafe.Pointer(np))
C.free(unsafe.Pointer(op))
C.free(unsafe.Pointer(csource))
ret := CodeWithDebugInfo{
Ok: bool(result.ok),
Message: C.GoString(result.message),
SourceCode: C.GoString(result.source_code),
DisassemblyString: C.GoString(result.disassembly_string),
// TODO: copy all instructions
}
C.deleteGlslCodeWithDebug(result)
return ret
}
// DisassembleSpirvBinary disassembles the given SPIR-V binary words by calling
// SPIRV-Tools and returns the disassembly. Returns an empty string if
// diassembling fails.
func DisassembleSpirvBinary(words []uint32) string {
source := ""
if len(words) > 0 {
spirv := C.getDisassembleText((*C.uint32_t)(&words[0]), C.size_t(len(words)))
source = C.GoString(spirv)
C.deleteDisassembleText(spirv)
}
return source
}
// AssembleSpirvText assembles the given SPIR-V text chars by calling
// SPIRV-Tools and returns the slice for the encoded binary. Returns nil
// if assembling fails.
func AssembleSpirvText(chars string) []uint32 {
text := C.CString(chars)
spirv := C.assembleToBinary(text)
C.free(unsafe.Pointer(text))
if spirv == nil {
return nil
}
count := uint64(spirv.words_num)
words := make([]uint32, count)
// TODO: Remove the following hack and encoding the data without using unsafe.
data := (*[1 << 30]uint32)(unsafe.Pointer(spirv.words))[:count:count]
copy(words, data)
C.deleteBinary(spirv)
return words
}