wgpu-hs-0.1.0.0: src-internal/WGPU/Internal/Device.hs
{-# LANGUAGE ForeignFunctionInterface #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# OPTIONS_GHC -Wno-deferred-type-errors #-}
-- |
-- Module : WGPU.Internal.Device.
-- Description : Device (open connection to a device).
module WGPU.Internal.Device
( -- * Types
Device (..),
DeviceDescriptor (..),
Features (..),
Limits (..),
-- * Functions
requestDevice,
)
where
import Control.Concurrent (MVar, newEmptyMVar, putMVar, takeMVar)
import Control.Monad.IO.Class (liftIO)
import Control.Monad.Trans.Cont (ContT (ContT), evalContT)
import Data.Default (Default, def)
import Data.Text (Text)
import qualified Data.Text as Text
import Data.Word (Word32)
import Foreign (Ptr, freeHaskellFunPtr, nullPtr, with)
import WGPU.Internal.Adapter (Adapter, adapterInst, wgpuAdapter)
import WGPU.Internal.ChainedStruct (ChainedStruct (EmptyChain, PtrChain))
import WGPU.Internal.Instance (Instance, wgpuHsInstance)
import WGPU.Internal.Memory (ToRaw, raw, rawPtr, showWithPtr)
import WGPU.Raw.Generated.Enum.WGPUNativeFeature (WGPUNativeFeature)
import qualified WGPU.Raw.Generated.Enum.WGPUNativeFeature as WGPUNativeFeature
import qualified WGPU.Raw.Generated.Enum.WGPUNativeSType as WGPUSType
import qualified WGPU.Raw.Generated.Fun as RawFun
import qualified WGPU.Raw.Generated.Struct.WGPUDeviceDescriptor as WGPUDeviceDescriptor
import WGPU.Raw.Generated.Struct.WGPUDeviceExtras (WGPUDeviceExtras)
import qualified WGPU.Raw.Generated.Struct.WGPUDeviceExtras as WGPUDeviceExtras
import WGPU.Raw.Types (WGPUDevice (WGPUDevice), WGPURequestDeviceCallback)
-------------------------------------------------------------------------------
-- | An open connection to a graphics and/or compute device.
--
-- A 'Device' may be created using the 'requestDevice' function.
data Device = Device
{ deviceInst :: !Instance,
wgpuDevice :: !WGPUDevice
}
instance Show Device where
show d =
let Device _ (WGPUDevice ptr) = d
in showWithPtr "Device" ptr
instance Eq Device where
(==) d1 d2 =
let Device _ (WGPUDevice d1_ptr) = d1
Device _ (WGPUDevice d2_ptr) = d2
in d1_ptr == d2_ptr
instance ToRaw Device WGPUDevice where
raw = pure . wgpuDevice
-------------------------------------------------------------------------------
-- | Device features that are not guaranteed to be supported.
--
-- * NOTE: The Rust API currently has far more extensive @Features@. Perhaps
-- they have not yet been ported to the C API?
-- <https://docs.rs/wgpu-types/0.9.0/wgpu_types/struct.Features.html>
newtype Features = Features
{ textureAdapterSpecificFormatFeatures :: Bool
}
deriving (Eq, Show)
instance Default Features where
def =
Features
{ textureAdapterSpecificFormatFeatures = False
}
instance ToRaw Features WGPUNativeFeature where
raw Features {..} =
pure $
if textureAdapterSpecificFormatFeatures
then WGPUNativeFeature.TEXTURE_ADAPTER_SPECIFIC_FORMAT_FEATURES
else 0
-------------------------------------------------------------------------------
-- | Device limits.
--
-- Represents the set of limits an adapter/device supports.
data Limits = Limits
{ -- | Maximum allowed value for the width of a 1D texture.
maxTextureDimension1D :: !Word32,
-- | Maximum allowed value for the width and height of a 2D texture.
maxTextureDimension2D :: !Word32,
-- | Maximum allowed value for the width, height or depth of a 3D texture.
maxTextureDimension3D :: !Word32,
-- | Maximum allowed value for the array layers of a texture.
maxTextureArrayLayers :: !Word32,
-- | Amount of bind groups that can be attached to a pipeline at the same
-- time.
maxBindGroups :: !Word32,
-- | Amount of storage buffer bindings that can be dynamic in a single
-- pipeline.
maxDynamicStorageBuffersPerPipelineLayout :: !Word32,
-- | Amount of sampled textures visible in a single shader stage.
maxStorageBuffersPerShaderStage :: !Word32,
-- | Maximum size in bytes of a binding to a uniform buffer.
maxStorageBufferBindingSize :: !Word32
}
deriving (Eq, Show)
instance Default Limits where
def =
Limits
{ maxTextureDimension1D = 0,
maxTextureDimension2D = 0,
maxTextureDimension3D = 0,
maxTextureArrayLayers = 0,
maxBindGroups = 0,
maxDynamicStorageBuffersPerPipelineLayout = 0,
maxStorageBuffersPerShaderStage = 0,
maxStorageBufferBindingSize = 0
}
-------------------------------------------------------------------------------
-- | Describes a 'Device'.
data DeviceDescriptor = DeviceDescriptor
{ -- | Debug label for the device.
deviceLabel :: !Text,
-- | Features that the device should support.
features :: !Features,
-- | Limits that the device should support (minimum values).
limits :: !Limits
}
deriving (Eq, Show)
instance Default DeviceDescriptor where
def =
DeviceDescriptor
{ deviceLabel = Text.empty,
features = def,
limits = def
}
instance ToRaw DeviceDescriptor WGPUDeviceExtras where
raw DeviceDescriptor {..} = do
chain_ptr <- raw (EmptyChain WGPUSType.DeviceExtras)
label_ptr <- rawPtr deviceLabel
n_nativeFeatures <- raw features
pure
WGPUDeviceExtras.WGPUDeviceExtras
{ chain = chain_ptr,
maxTextureDimension1D = maxTextureDimension1D limits,
maxTextureDimension2D = maxTextureDimension2D limits,
maxTextureDimension3D = maxTextureDimension3D limits,
maxTextureArrayLayers = maxTextureArrayLayers limits,
maxBindGroups = maxBindGroups limits,
maxDynamicStorageBuffersPerPipelineLayout =
maxDynamicStorageBuffersPerPipelineLayout limits,
maxStorageBuffersPerShaderStage =
maxStorageBuffersPerShaderStage limits,
maxStorageBufferBindingSize =
maxStorageBufferBindingSize limits,
nativeFeatures = n_nativeFeatures,
label = label_ptr,
tracePath = nullPtr
}
-- | Requests a connection to a physical device, creating a logical device.
--
-- This action blocks until an available device is returned.
requestDevice ::
-- | @Adapter@ for which the device will be returned.
Adapter ->
-- | The features and limits requested for the device.
DeviceDescriptor ->
-- | The returned @Device@, if it could be retrieved.
IO (Maybe Device)
requestDevice adapter deviceDescriptor = evalContT $ do
let inst = adapterInst adapter
deviceMVar :: MVar WGPUDevice <- liftIO newEmptyMVar
let deviceCallback :: WGPUDevice -> Ptr () -> IO ()
deviceCallback device _ = putMVar deviceMVar device
deviceCallback_c <- liftIO $ mkDeviceCallback deviceCallback
deviceExtras_ptr <- rawPtr deviceDescriptor
nextInChain_ptr <- rawPtr (PtrChain WGPUSType.DeviceExtras deviceExtras_ptr)
deviceDescriptor_ptr <-
ContT . with $
WGPUDeviceDescriptor.WGPUDeviceDescriptor
{ nextInChain = nextInChain_ptr
}
liftIO $
RawFun.wgpuAdapterRequestDevice
(wgpuHsInstance inst)
(wgpuAdapter adapter)
deviceDescriptor_ptr
deviceCallback_c
nullPtr
device <- liftIO $ takeMVar deviceMVar
liftIO $ freeHaskellFunPtr deviceCallback_c
pure $ case device of
WGPUDevice ptr | ptr == nullPtr -> Nothing
WGPUDevice _ -> Just (Device inst device)
foreign import ccall "wrapper"
mkDeviceCallback ::
(WGPUDevice -> Ptr () -> IO ()) -> IO WGPURequestDeviceCallback