lambdacube-engine-0.1.1: Graphics/LambdaCube/RenderSystem/GL/GLCapabilities.hs
module Graphics.LambdaCube.RenderSystem.GL.GLCapabilities where
import Data.Set (Set)
import qualified Data.Set as Set
import Graphics.Rendering.OpenGL (($=))
import qualified Graphics.Rendering.OpenGL as GL
import Graphics.LambdaCube.Types
import Graphics.LambdaCube.RenderSystemCapabilities
{-
vendor, renderer, glVersion, glExtensions, shadingLanguageVersion,
majorMinor, contextProfile
vendor :: GettableStateVar String
renderer :: GettableStateVar String
glVersion :: GettableStateVar String
glExtensions :: GettableStateVar [String]
shadingLanguageVersion :: GettableStateVar String
= DriverVersion
{ dvMajor :: Int
, dvMinor :: Int
, dvRelease :: Int
, dvBuild :: Int
}
-}
--mkRenderSystemCapabilities :: IO RenderSystemCapabilities
mkGLCapabilities = do
vendorS <- GL.get GL.vendor
versionS <- GL.get GL.glVersion
extSList <- GL.get GL.glExtensions
shLngVerS <- GL.get GL.shadingLanguageVersion
-- setup driver version
{-
StringVector tokens = StringUtil::split(mGLSupport->getGLVersion(), ".");
if (!tokens.empty())
{
mDriverVersion.major = StringConverter::parseInt(tokens[0]);
if (tokens.size() > 1)
mDriverVersion.minor = StringConverter::parseInt(tokens[1]);
if (tokens.size() > 2)
mDriverVersion.release = StringConverter::parseInt(tokens[2]);
}
mDriverVersion.build = 0;
-}
-- setup device name
deviceName <- GL.get GL.renderer
{-
const char* deviceName = (const char*)glGetString(GL_RENDERER);
rsc->setDeviceName(deviceName);
-}
-- setup vendor
let v = words vendorS
vendorName = if elem "NVIDIA" v then GPU_NVIDIA
else if elem "ATI" v then GPU_ATI
else if elem "Intel" v then GPU_INTEL
else if elem "S3" v then GPU_S3
else if elem "Matrox" v then GPU_MATROX
else if elem "3DLabs" v then GPU_3DLABS
else if elem "SiS" v then GPU_SIS
else GPU_UNKNOWN
(major,minor) <- GL.get $ GL.majorMinor GL.glVersion
-- setup capabilities
let ext = Set.fromList extSList
glVer a b = major > a || (major >= a && minor >= b)
supports s = Set.member s ext
driverVersion = DriverVersion major minor 0 0 -- TODO
caps0 =
[ RSC_FIXED_FUNCTION -- Supports fixed-function
, RSC_SCISSOR_TEST -- Scissor test is standard in GL 1.2 (is it emulated on some cards though?)
, RSC_USER_CLIP_PLANES -- As are user clipping planes
, RSC_VERTEX_FORMAT_UBYTE4 -- UBYTE4 always supported
, RSC_INFINITE_FAR_PLANE -- Infinite far plane always supported
, RSC_TEXTURE_3D -- 3D textures should be supported by GL 1.2, which is our minimum version
]
-- Check for hardware mipmapping support.
caps1 = if not (glVer 1 4 || supports "GL_SGIS_generate_mipmap") then [] else
[RSC_AUTOMIPMAP] -- FIXME
{-
case vendorName of
{ GPU_ATI -> [] -- Apple & Linux ATI drivers have faults in hardware mipmap generation
-- The Intel 915G frequently corrupts textures when using hardware mip generation
-- I'm not currently sure how many generations of hardware this affects,
-- so for now, be safe.
; GPU_INTEL -> []
; GPU_SIS -> [] -- SiS chipsets also seem to have problems with this
; _ -> [RSC_AUTOMIPMAP]
}
-}
-- Check for blending support
caps2 = if (glVer 1 3 || supports "GL_ARB_texture_env_combine" || supports "GL_EXT_texture_env_combine") then [RSC_BLENDING] else []
-- Check for Multitexturing support and set number of texture units
numTexUnits <- case glVer 1 3 || supports "GL_ARB_multitexture" of
{ True -> do
GL.TextureUnit mtu <- GL.get GL.maxTextureUnit
mtimu <- case supports "GL_ARB_fragment_program" of
{ True -> do
-- Also check GL_MAX_TEXTURE_IMAGE_UNITS_ARB since NV at least
-- only increased this on the FX/6x00 series
GL.get GL.maxTextureImageUnits
; False -> return 0
}
-- FIXME: enable at becoming hgl binding
return mtimu -- $ max mtu (fromIntegral mtimu)
; False -> return 1
}
-- Check for Anisotropy support
let caps3 = if (supports "GL_EXT_texture_filter_anisotropic") then [RSC_ANISOTROPY] else []
-- Check for DOT3 support
caps4 = if (glVer 1 3 || supports "GL_ARB_texture_env_dot3" || supports "GL_EXT_texture_env_dot3") then [RSC_DOT3] else []
-- Check for cube mapping
caps5 = if (glVer 1 3 || supports "GL_ARB_texture_cube_map" || supports "GL_EXT_texture_cube_map") then [RSC_CUBEMAPPING] else []
-- Point sprites
caps6 = if (glVer 2 0 || supports "GL_ARB_point_sprite") then [RSC_POINT_SPRITES] else []
-- Check for point parameters
caps7 = if (glVer 1 4) then [RSC_POINT_EXTENDED_PARAMETERS] else []
caps8 = if (supports "GL_ARB_point_parameters") then [RSC_POINT_EXTENDED_PARAMETERS_ARB] else []
caps9 = if (supports "GL_EXT_point_parameters") then [RSC_POINT_EXTENDED_PARAMETERS_EXT] else []
-- Check for hardware stencil support and set bit depth
stencilBits <- GL.get GL.stencilBits
let caps10 = if stencilBits > 0 then [RSC_HWSTENCIL] else []
caps11 = if not (glVer 1 5 || supports "GL_ARB_vertex_buffer_object") then [] else
[RSC_VBO] ++ (if not (supports "GL_ARB_vertex_buffer_object") then [RSC_GL1_5_NOVBO] else [])
-- TODO: haskell gl binding does not support query for GL_MAX_PROGRAM_LOCAL_PARAMETERS_ARB
{-
if(GLEW_ARB_vertex_program)
{
rsc->setCapability(RSC_VERTEX_PROGRAM);
// Vertex Program Properties
rsc->setVertexProgramConstantBoolCount(0);
rsc->setVertexProgramConstantIntCount(0);
GLint floatConstantCount;
glGetProgramivARB(GL_VERTEX_PROGRAM_ARB, GL_MAX_PROGRAM_LOCAL_PARAMETERS_ARB, &floatConstantCount);
rsc->setVertexProgramConstantFloatCount(floatConstantCount);
rsc->addShaderProfile("arbvp1");
if (GLEW_NV_vertex_program2_option)
{
rsc->addShaderProfile("vp30");
}
if (GLEW_NV_vertex_program3)
{
rsc->addShaderProfile("vp40");
}
if (GLEW_NV_vertex_program4)
{
rsc->addShaderProfile("gp4vp");
rsc->addShaderProfile("gpu_vp");
}
}
-}
(prof1,caps12) = if supports "GL_NV_register_combiners2" && supports "GL_NV_texture_shader" then (["fp20"],[RSC_FRAGMENT_PROGRAM]) else ([],[])
-- check for ATI fragment shader support
-- no boolean params allowed
-- no integer params allowed
-- only 8 Vector4 constant floats supported
(prof2,caps13,fragConstBool,fragConstInt,fragConstFloat) = if supports "GL_ATI_fragment_shader" then (["ps_1_4","ps_1_3","ps_1_2","ps_1_1"],[RSC_FRAGMENT_PROGRAM],0,0,8) else ([],[],0,0,0)
-- TODO
------------------------------------------------------------------------------
{-
(prof,cap,fragConstBool,fragConstInt,fragConstFloat) <- case supports "GL_ARB_fragment_program" of
{ True -> do
-- Fragment Program Properties
return ([],[RSC_FRAGMENT_PROGRAM],0,0,)
; False -> ([],[],0,0,0)
}
-}
{-
if (GLEW_ARB_fragment_program)
{
rsc->setCapability(RSC_FRAGMENT_PROGRAM);
// Fragment Program Properties
rsc->setFragmentProgramConstantBoolCount(0);
rsc->setFragmentProgramConstantIntCount(0);
GLint floatConstantCount;
glGetProgramivARB(GL_FRAGMENT_PROGRAM_ARB, GL_MAX_PROGRAM_LOCAL_PARAMETERS_ARB, &floatConstantCount);
rsc->setFragmentProgramConstantFloatCount(floatConstantCount);
rsc->addShaderProfile("arbfp1");
if (GLEW_NV_fragment_program_option)
{
rsc->addShaderProfile("fp30");
}
if (GLEW_NV_fragment_program2)
{
rsc->addShaderProfile("fp40");
}
}
-}
------------------------------------------------------------------------------
-- Check if GLSL is supported
prof3 = if glVer 2 0 ||
(supports "GL_ARB_shading_language_100"
&& supports "GL_ARB_shader_objects"
&& supports "GL_ARB_fragment_shader"
&& supports "GL_ARB_vertex_shader") then ["glsl"] else []
-- TODO
--------------------------------------------------------------------------------------
-- Check if geometry shaders are supported
{-
(cap,prof,boolC,intC,floatC,outVertN) <- case glVer 2 0 && supports "GL_EXT_geometry_shader4" of
{ True -> do
return ([RSC_GEOMETRY_PROGRAM],["nvgp4","gpu_gp","gp4gp"],0,0,)
; False -> return ([],[],0,0,0,0)
}
-}
{-
// Check if geometry shaders are supported
if (GLEW_VERSION_2_0 &&
GLEW_EXT_geometry_shader4)
{
rsc->setCapability(RSC_GEOMETRY_PROGRAM);
rsc->addShaderProfile("nvgp4");
//Also add the CG profiles
rsc->addShaderProfile("gpu_gp");
rsc->addShaderProfile("gp4gp");
rsc->setGeometryProgramConstantBoolCount(0);
rsc->setGeometryProgramConstantIntCount(0);
GLint floatConstantCount;
glGetProgramivARB(GL_GEOMETRY_PROGRAM_NV, GL_MAX_PROGRAM_LOCAL_PARAMETERS_ARB, &floatConstantCount);
rsc->setGeometryProgramConstantFloatCount(floatConstantCount);
GLint maxOutputVertices;
glGetIntegerv(GL_MAX_GEOMETRY_OUTPUT_VERTICES_EXT,&maxOutputVertices);
rsc->setGeometryProgramNumOutputVertices(maxOutputVertices);
}
-}
--------------------------------------------------------------------------------------
-- Check if render to vertex buffer (transform feedback in OpenGL)
caps14 = if (glVer 2 0 && supports "GL_NV_transform_feedback") then [RSC_HWRENDER_TO_VERTEX_BUFFER] else []
-- Check for texture compression
caps15 = if not (glVer 1 3 || supports "GL_ARB_texture_compression") then [] else
[RSC_TEXTURE_COMPRESSION]
-- Check for dxt compression
--------------------------------------------------------------------------------
{- FIXME: we should disable DXT on (apple && ati && ppc)
-- if defined(__APPLE__) && defined(__PPC__)
-- // Apple on ATI & PPC has errors in DXT
-- if (mGLSupport->getGLVendor().find("ATI") == std::string::npos)
-- endif
-}
--------------------------------------------------------------------------------
++ (if supports "GL_EXT_texture_compression_s3tc" then [RSC_TEXTURE_COMPRESSION_DXT] else [])
-- Check for vtc compression
++ (if supports "GL_NV_texture_compression_vtc" then [RSC_TEXTURE_COMPRESSION_VTC] else [])
-- 2-sided stencil?
caps16 = if (glVer 2 0 || supports "GL_EXT_stencil_two_side") then [RSC_TWO_SIDED_STENCIL] else []
caps17 = if (glVer 1 4 || supports "GL_EXT_stencil_wrap") then [RSC_STENCIL_WRAP] else []
-- Check for hardware occlusion support
caps18 = case glVer 1 5 || supports "GL_ARB_occlusion_query" of
-- Some buggy driver claim that it is GL 1.5 compliant and not support ARB_occlusion_query
{ True -> [RSC_HWOCCLUSION] ++ (if not (supports "GL_ARB_occlusion_query") then [RSC_GL1_5_NOHWOCCLUSION] else [])
-- Support NV extension too for old hardware
; False -> if supports "GL_NV_occlusion_query" then [RSC_HWOCCLUSION] else []
}
-- Check for non-power-of-2 texture support
caps19 = if (supports "GL_ARB_texture_non_power_of_two") then [RSC_NON_POWER_OF_2_TEXTURES] else []
-- Check for Float textures
caps20 = if (supports "GL_ATI_texture_float" || supports "GL_ARB_texture_float") then [RSC_TEXTURE_FLOAT] else []
-- Check for framebuffer object extension
(numMTR,caps21) <- case supports "GL_EXT_framebuffer_object" of
{ True -> do
-- Probe number of draw buffers
-- Only makes sense with FBO support, so probe here
(n,c) <- case glVer 2 0 || supports "GL_ARB_draw_buffers" || supports "GL_ATI_draw_buffers" of
{ True -> do
m <- GL.get GL.maxDrawBuffers
-- Before GL version 2.0, we need to get one of the extensions
let cp = case (glVer 2 0, supports "GL_ARB_draw_buffers", supports "GL_ATI_draw_buffers") of
{ (False,True,True) -> [RSC_FBO_ARB,RSC_FBO_ATI]
; (False,True,False) -> [RSC_FBO_ARB]
; (False,False,True) -> [RSC_FBO_ATI]
; _ -> []
}
-- Set FBO flag for all 3 'subtypes'
return (m,[RSC_MRT_DIFFERENT_BIT_DEPTHS,RSC_FBO] ++ cp)
; False -> return (0,[])
}
return (n,RSC_HWRENDER_TO_TEXTURE:c)
; False -> do
-- TODO
----------------------------------------------
{-
// Check GLSupport for PBuffer support
if(mGLSupport->supportsPBuffers())
{
// Use PBuffers
rsc->setCapability(RSC_HWRENDER_TO_TEXTURE);
rsc->setCapability(RSC_PBUFFER);
}
-}
----------------------------------------------
return (0,[])
}
------------------------------------------------------
-- FIXE: haskell gl binding does not have query for GL_POINT_SIZE_RANGE
-- Point size
(_,maxPointSize) <- GL.get GL.pointSizeRange
{-
if (GLEW_VERSION_1_4)
{
float ps;
glGetFloatv(GL_POINT_SIZE_MAX, &ps);
rsc->setMaxPointSize(ps);
}
else
{
GLint vSize[2];
glGetIntegerv(GL_POINT_SIZE_RANGE,vSize);
rsc->setMaxPointSize(vSize[1]);
}
-}
-- Point size: Ends here
------------------------------------------------------
-- Vertex texture fetching
(numVertTexUnits,caps22,vertTexUnitsShared) <- case supports "GL_ARB_vertex_shader" of
{ True -> do
vunits <- GL.get GL.maxVertexTextureImageUnits
-- GL always shares vertex and fragment texture units (for now?)
return (vunits,if vunits > 0 then [RSC_VERTEX_TEXTURE_FETCH] else [], True)
; False -> return (0,[],False)
}
-- Mipmap LOD biasing?
let caps23 = if (glVer 1 4 || supports "GL_EXT_texture_lod_bias") then [RSC_MIPMAP_LOD_BIAS] else []
-- Alpha to coverage?
-- Alpha to coverage always 'supported' when MSAA is available
-- although card may ignore it if it doesn't specifically support A2C
caps24 = if (supports "GL_ARB_multisample") then [RSC_ALPHA_TO_COVERAGE] else []
-- Advanced blending operations
caps25 = if (glVer 2 0) then [RSC_ADVANCED_BLEND_OPERATIONS] else []
return RenderSystemCapabilities
{ rscDriverVersion = driverVersion
, rscVendor = vendorName
-- , rscNumWorldMatrices :: Int -- ^ The number of world matrices available
, rscNumTextureUnits = fromIntegral numTexUnits
, rscStencilBufferBitDepth = fromIntegral stencilBits
-- , rscNumVertexBlendMatrices :: Int
, rscCapabilities = Set.fromList $ caps0 ++ caps1 ++ caps2 ++ caps3 ++ caps4 ++ caps5 ++ caps6 ++ caps7 ++ caps8 ++ caps9
++ caps10 ++ caps11 ++ caps12 ++ caps13 ++ caps14 ++ caps15 ++ caps16 ++ caps17 ++ caps18 ++ caps19
++ caps20 ++ caps21 ++ caps22 ++ caps23 ++ caps24 ++ caps25
, rscDeviceName = deviceName
, rscRenderSystemName = "OpenGL Rendering Subsystem"
-- TODO
, rscVertexProgramConstantFloatCount = undefined
, rscVertexProgramConstantIntCount = undefined
, rscVertexProgramConstantBoolCount = undefined
, rscGeometryProgramConstantFloatCount = undefined
, rscGeometryProgramConstantIntCount = undefined
, rscGeometryProgramConstantBoolCount = undefined
, rscFragmentProgramConstantFloatCount = fragConstFloat
, rscFragmentProgramConstantIntCount = fragConstInt
, rscFragmentProgramConstantBoolCount = fragConstBool
, rscNumMultiRenderTargets = fromIntegral numMTR
, rscMaxPointSize = realToFrac maxPointSize
, rscNonPOW2TexturesLimited = False
, rscNumVertexTextureUnits = fromIntegral numVertTexUnits
, rscVertexTextureUnitsShared = vertTexUnitsShared
-- TODO
, rscGeometryProgramNumOutputVertices = undefined
, rscSupportedShaderProfiles = Set.fromList $ prof1 ++ prof2 ++ prof3
}