module Vulkan.Utils.ShaderQQ.Backend.Shaderc.Internal ( compileShaderQ , compileShader ) where import Control.Monad.IO.Class import Data.ByteString ( ByteString ) import qualified Data.ByteString as BS import Data.FileEmbed import Language.Haskell.TH import System.Exit import System.IO.Temp import System.Process.Typed import Vulkan.Utils.ShaderQQ.ShaderType import qualified Vulkan.Utils.ShaderQQ.GLSL as GLSL import qualified Vulkan.Utils.ShaderQQ.HLSL as HLSL import Vulkan.Utils.ShaderQQ.Backend.Shaderc import Vulkan.Utils.ShaderQQ.Backend.Internal -- * Utilities -- | Compile a GLSL/HLSL shader to SPIR-V using glslc (from the shaderc project) -- -- Messages are converted to GHC warnings or errors depending on compilation success. compileShaderQ :: Maybe String -- ^ Argument to pass to `--target-spv` -> ShaderType -- ^ Argument to specify between glsl/hlsl shader -> String -- ^ stage -> Maybe String -- ^ Argument to specify entry-point function name for hlsl -> String -- ^ glsl or hlsl shader code -> Q Exp -- ^ Spir-V bytecode compileShaderQ targetSpv shaderType stage entryPoint code = do loc <- location (warnings, result) <- compileShader (Just loc) targetSpv shaderType stage entryPoint code bs <- messageProcess "glslc" reportWarning fail (warnings, result) bsToExp bs -- | Compile a GLSL/HLSL shader to spir-v using glslc compileShader :: MonadIO m => Maybe Loc -- ^ Source location -> Maybe String -- ^ Argument to pass to `--target-spv` -> ShaderType -- ^ Argument to specify between glsl/hlsl shader -> String -- ^ stage -> Maybe String -- ^ Argument to specify entry-point function name for hlsl -> String -- ^ glsl or hlsl shader code -> m ([ShadercWarning], Either [ShadercError] ByteString) -- ^ Spir-V bytecode with warnings or errors compileShader loc targetSpv shaderType stage entryPoint code = liftIO $ withSystemTempDirectory "th-shader" $ \dir -> do let codeWithLineDirective = maybe code (case shaderType of GLSL -> GLSL.insertLineDirective code HLSL -> HLSL.insertLineDirective code ) loc let shader = dir <> "/shader." <> stage spirv = dir <> "/shader.spv" writeFile shader codeWithLineDirective let targetArgs = case targetSpv of Nothing -> [] Just t -> ["--target-spv=" <> t] -- https://github.com/google/shaderc/blob/01dd72d6079ebdc0f96859365ba7abb1b62758bf/glslc/src/main.cc#L64 entryPointArgs = case entryPoint of Nothing -> [] Just name -> case shaderType of GLSL -> [] HLSL -> ["-fentry-point=" <> name] args = targetArgs ++ entryPointArgs ++ ["-fshader-stage=" <> stage, "-x", show shaderType, shader, "-o", spirv] (rc, out, err) <- readProcess $ proc "glslc" args let (warnings, errors) = processShadercMessages (out <> err) case rc of ExitSuccess -> do bs <- BS.readFile spirv pure (warnings, Right bs) ExitFailure _rc -> pure (warnings, Left errors)