vulkan-utils-0.5.0: src/Vulkan/Utils/ShaderQQ/Backend/Shaderc/Internal.hs
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)