public Video(IDisposableResource parent, IApplication application, DepthStencilFormats depthStencilFormats, bool vSync) : base(parent) { try { int depthBit = 16, stencilBit = 0; switch (depthStencilFormats) { case DepthStencilFormats.None: depthBit = 0; stencilBit = 0; break; case DepthStencilFormats.Defualt: #if iOS || ANDROID || NaCl || RPI depthBit = 16; stencilBit = 0; #else depthBit = 24; stencilBit = 0; #endif break; case DepthStencilFormats.Depth24Stencil8: depthBit = 24; stencilBit = 8; break; case DepthStencilFormats.Depth16: depthBit = 16; stencilBit = 0; break; case DepthStencilFormats.Depth24: depthBit = 24; stencilBit = 0; break; case DepthStencilFormats.Depth32: depthBit = 32; stencilBit = 0; break; default: Debug.ThrowError("Video", "Unsuported DepthStencilFormat type"); break; } currentTextures = new Texture2D[8]; currentSamplerStates = new SamplerState[8]; #if WIN32 || OSX || LINUX || NaCl BackBufferSize = application.FrameSize; this.application = application; #else BackBufferSize = application.FrameSize; this.application = application; #endif #if WIN32 //Get DC handle = application.Handle; dc = WGL.GetDC(handle); WGL.SwapBuffers(dc); //Set BackBuffer format WGL.PIXELFORMATDESCRIPTOR pfd = new WGL.PIXELFORMATDESCRIPTOR(); WGL.ZeroPixelDescriptor(ref pfd); pfd.nVersion = 1; pfd.dwFlags = WGL.PFD_DRAW_TO_WINDOW | WGL.PFD_SUPPORT_OPENGL | WGL.PFD_DOUBLEBUFFER; pfd.iPixelType = (byte)WGL.PFD_TYPE_RGBA; //pfd.cColorBits = 24; //pfd.cAlphaBits = 8; pfd.cDepthBits = (byte)depthBit; pfd.cStencilBits = (byte)stencilBit; pfd.iLayerType = (byte)WGL.PFD_MAIN_PLANE; unsafe { pfd.nSize = (ushort)sizeof(WGL.PIXELFORMATDESCRIPTOR); } int pixelFormatIndex = WGL.ChoosePixelFormat(dc, ref pfd); if (pixelFormatIndex == 0) { Debug.ThrowError("Video", "ChoosePixelFormat failed"); } if (WGL.SetPixelFormat(dc, pixelFormatIndex, ref pfd) == 0) { Debug.ThrowError("Video", "Failed to set PixelFormat"); } ctx = WGL.CreateContext(dc); if (ctx == IntPtr.Zero) { Debug.ThrowError("Video", "Failed to create GL context"); } if (WGL.MakeCurrent(dc, ctx) == 0) { Debug.ThrowError("Video", "Failed to make GL context current"); } WGL.Init(); WGL.SwapInterval(vSync ? 1 : 0); // -1 for smart vsync #endif #if RPI unsafe { // Init Pi video RaspberryPi.bcm_host_init(); const int piDisplay = 0; uint piWidth = 0, piHeight = 0; if (RaspberryPi.graphics_get_display_size(piDisplay, &piWidth, &piHeight) < 0) { Debug.ThrowError("Video", "Failed to get display size"); } Console.WriteLine("piWidth - " + piWidth); Console.WriteLine("piHeight - " + piHeight); BackBufferSize = new Size2((int)piWidth, (int)piHeight); IntPtr dispman_display = RaspberryPi.vc_dispmanx_display_open(piDisplay); if (dispman_display == IntPtr.Zero) { Debug.ThrowError("Video", "Failed: vc_dispmanx_display_open"); } IntPtr dispman_update = RaspberryPi.vc_dispmanx_update_start(0); if (dispman_update == IntPtr.Zero) { Debug.ThrowError("Video", "Failed: vc_dispmanx_update_start"); } var dstRect = new RaspberryPi.VC_RECT_T() { x = 0, y = 0, width = (int)piWidth, height = (int)piHeight }; var srcRect = new RaspberryPi.VC_RECT_T() { x = 0, y = 0, width = ((int)piWidth) << 16, height = ((int)piHeight) << 16 }; IntPtr dispman_element = RaspberryPi.vc_dispmanx_element_add(dispman_update, dispman_display, 0, &dstRect, IntPtr.Zero, &srcRect, RaspberryPi.DISPMANX_PROTECTION_NONE, IntPtr.Zero, IntPtr.Zero, 0); if (dispman_element == IntPtr.Zero) { Debug.ThrowError("Video", "Failed: vc_dispmanx_element_add"); } nativeWindow = new RaspberryPi.DISPMANX_WINDOW_T() { element = dispman_element, width = (int)piWidth, height = (int)piHeight }; windowHandle = GCHandle.Alloc(nativeWindow, GCHandleType.Pinned); RaspberryPi.vc_dispmanx_update_submit_sync(dispman_update); // Init EGL handle = application.Handle; GL.GetError(); //NOTE: THIS MUST BE HERE SO THAT libGLES LOADS BEFORE libEGL dc = EGL.GetDisplay(IntPtr.Zero); int major, minor; if (!EGL.Initialize(dc, out major, out minor)) { Debug.ThrowError("Video", string.Format("Failed to initialize display connection, Error {0}", EGL.GetError())); } int[] pixelFormat = new int[] { //EGL.RENDERABLE_TYPE, EGL.OPENGL_ES2_BIT, //EGL.RED_SIZE, 5, //EGL.GREEN_SIZE, 6, //EGL.BLUE_SIZE, 5, //EGL.ALPHA_SIZE, 0,//EGL.DONT_CARE, EGL.SURFACE_TYPE, EGL.WINDOW_BIT, EGL.DEPTH_SIZE, depthBit, //EGL.STENCIL_SIZE, stencilBit,//EGL.DONT_CARE,//<<<<<<<<<< Test enabling this! //EGL.SAMPLE_BUFFERS, 0, //EGL.SAMPLES, 0, //EGL.MIN_SWAP_INTERVAL, 0, //EGL.MAX_SWAP_INTERVAL, 1, EGL.NONE, }; int num_configs; var configs = new IntPtr(); if (EGL.ChooseConfig(dc, pixelFormat, &configs, 1, &num_configs) == 0 || num_configs == 0) { Debug.ThrowError("Video", string.Format("Failed to retrieve GraphicsMode, error {0}", EGL.GetError())); } if (EGL.BindAPI(EGL.OPENGL_ES_API) == 0) { Debug.ThrowError("Video", "Failed to bind GLES API"); } ; int[] attrib_list = new int[] { EGL.CONTEXT_CLIENT_VERSION, 2, EGL.NONE }; ctx = EGL.CreateContext(dc, configs, IntPtr.Zero, attrib_list); if (ctx == IntPtr.Zero) { Debug.ThrowError("Video", "Failed to create context"); } surface = EGL.CreateWindowSurface(dc, configs, windowHandle.AddrOfPinnedObject(), null); //surface = EGL.CreateWindowSurface(dc, configs[0], handle, null);// <<<<<<<<<<<<<<<<<<<<<<<<<<<< used in x11 if (surface == IntPtr.Zero) { Debug.ThrowError("Video", "Failed to create window surface"); } if (EGL.MakeCurrent(dc, surface, surface, ctx) == 0) { Debug.ThrowError("Video", "Failed to make EGL context current"); } //if (EGL.SwapInterval(dc, vSync ? 1 : 0) == 0) Debug.ThrowError("Video", "Failed to set vSync"); checkForEGLError(); } #elif LINUX //Get DC handle = application.Handle; dc = X11.XOpenDisplay(IntPtr.Zero); int screen = X11.XDefaultScreen(dc); //Set Pixel format int[] attrbs = { GLX.RGBA, GLX.DOUBLEBUFFER,// 1, //GLX.RED_SIZE, 8, //GLX.GREEN_SIZE, 8, //GLX.BLUE_SIZE, 8, //GLX.ALPHA_SIZE, 8, GLX.DEPTH_SIZE,depthBit, GLX.NONE }; IntPtr visual = GLX.ChooseVisual(dc, screen, attrbs); if (visual == IntPtr.Zero) { Debug.ThrowError("Video", "Failed to get visual"); } ctx = GLX.CreateContext(dc, visual, new IntPtr(0), true); GLX.MakeCurrent(dc, handle, ctx); bool failed = false; try { GLX.SwapIntervalSGI(vSync ? 1 : 0); } catch { failed = true; } if (failed) { GLX.Init(); GLX.SwapIntervalMesa(vSync ? 1 : 0); } #endif #if OSX var attribs = new object[] { NSOpenGLPixelFormatAttribute.Window, NSOpenGLPixelFormatAttribute.Accelerated, NSOpenGLPixelFormatAttribute.NoRecovery, NSOpenGLPixelFormatAttribute.DoubleBuffer, NSOpenGLPixelFormatAttribute.ColorSize, 24, NSOpenGLPixelFormatAttribute.AlphaSize, 8, NSOpenGLPixelFormatAttribute.DepthSize, depthBit }; var pixelFormat = new NSOpenGLPixelFormat(attribs); if (pixelFormat == null) { Debug.ThrowError("Video", "NSOpenGLPixelFormat failed"); } NSContext = new NSOpenGLContext(pixelFormat, null); if (NSContext == null) { Debug.ThrowError("Video", "Failed to create GL context"); } NSContext.MakeCurrentContext(); NSContext.SwapInterval = vSync; NSContext.View = application.View; ctx = NSContext.CGLContext.Handle; OS.NSContext = NSContext; /*//Get DC * dc = CGL.DisplayIDToOpenGLDisplayMask(CGL.MainDisplayID()); * if (dc == IntPtr.Zero) Debug.ThrowError("Video", "Failed to get DC"); * * //Set BackBuffer format * int[] attributes = * { * //(int)CGL.PixelFormatAttribute.kCGLPFADoubleBuffer, * //(int)CGL.PixelFormatAttribute.kCGLPFADisplayMask, dc.ToInt32(), * //(int)CGL.PixelFormatAttribute.kCGLPFAWindow, * (int)CGL.PixelFormatAttribute.kCGLPFAAccelerated, * (int)CGL.PixelFormatAttribute.kCGLPFAColorSize, 32, * (int)CGL.PixelFormatAttribute.kCGLPFADepthSize, depthBit, * 0 * }; * * IntPtr pixelFormat = IntPtr.Zero; * int pixelFormatCount = 0; * int error = CGL.ChoosePixelFormat(attributes, ref pixelFormat, ref pixelFormatCount); * if (error != 0 || pixelFormat == IntPtr.Zero) * { * Debug.ThrowError("Video", "ChoosePixelFormat failed"); * } * * error = CGL.CreateContext(pixelFormat, IntPtr.Zero, ref ctx); * if (error != 0 || ctx == IntPtr.Zero) * { * Debug.ThrowError("Video", "Failed to create GL fullscreen context"); * } * * CGL.SetCurrentContext(ctx);*/ #endif #if iOS // GL will be created by the Application #endif #if ANDROID // GL will be created by the Application #endif #if NaCl var frame = application.FrameSize; int[] attribs = { (int)PPAPI.Graphics3DAttrib.PP_GRAPHICS3DATTRIB_ALPHA_SIZE, 8,// Try to disable this to see if it gets rid of alpha blending presintation issues (int)PPAPI.Graphics3DAttrib.PP_GRAPHICS3DATTRIB_DEPTH_SIZE, depthBit, (int)PPAPI.Graphics3DAttrib.PP_GRAPHICS3DATTRIB_STENCIL_SIZE, stencilBit, (int)PPAPI.Graphics3DAttrib.PP_GRAPHICS3DATTRIB_SAMPLES, 0, (int)PPAPI.Graphics3DAttrib.PP_GRAPHICS3DATTRIB_SAMPLE_BUFFERS, 0, (int)PPAPI.Graphics3DAttrib.PP_GRAPHICS3DATTRIB_WIDTH, frame.Width, (int)PPAPI.Graphics3DAttrib.PP_GRAPHICS3DATTRIB_HEIGHT, frame.Height, (int)PPAPI.Graphics3DAttrib.PP_GRAPHICS3DATTRIB_NONE }; graphics = OS.GetGraphics(); if (graphics == IntPtr.Zero) { Debug.ThrowError("Video", "Failed to get Graphics object"); } IntPtr pbbInstance = OS.GetPBBInstance(); if (graphics == IntPtr.Zero) { Debug.ThrowError("Video", "Failed to get PBBInstance object"); } IntPtr gles = OS.GetGlES(); if (gles == IntPtr.Zero) { Debug.ThrowError("Video", "Failed to get GLES object"); } context = PPAPI.InitOpenGL(OS.GetInstance(), graphics, pbbInstance, attribs, gles); if (context == 0) { Debug.ThrowError("Video", "Failed to create GL context"); } PPAPI.SetCurrentContextPPAPI(context); PPAPI.StartSwapBufferLoop(graphics, context); #endif checkForError(); //Setup defualt OpenGL characteristics GL.FrontFace(GL.CCW); // Get Caps Caps = new Caps(); Caps.MaxShaderVersion = ShaderVersions.Unknown; unsafe { int max = 0; GL.GetIntegerv(GL.MAX_TEXTURE_SIZE, &max); Caps.MaxTextureSize = max; // SEEMS TO MESS UP ON OSX //GL.GetIntegerv(GL.MAX_VERTEX_UNIFORM_VECTORS, &max); //Caps.MaxVertexConstants = max; //GL.GetIntegerv(GL.MAX_FRAGMENT_UNIFORM_VECTORS, &max); //Caps.MaxPixelConstants = max; #if RPI byte *shaderVersionPtr = null; #else byte *shaderVersionPtr = GL.GetString(GL.SHADING_LANGUAGE_VERSION); #endif string shaderVersion = ""; while (shaderVersionPtr != null && shaderVersionPtr[0] != 0) { shaderVersion += (char)shaderVersionPtr[0]; shaderVersionPtr++; } #if iOS || RPI shaderVersion = "1.0"; #elif ANDROID shaderVersion = shaderVersion.Substring(shaderVersion.Length - 4, 4); #elif NaCl shaderVersion = shaderVersion.Substring(18, 3); #else shaderVersion = shaderVersion.Substring(0, 4); #endif float shaderValue = Convert.ToSingle(shaderVersion); Caps.Version = Versions.GL1; FileTag = ""; #if iOS || ANDROID || NaCl || RPI if (shaderValue >= 1.0f) { Caps.Version = Versions.GL2; FileTag = "GLES2_"; Caps.MaxShaderVersion = ShaderVersions.GLSL_1_00; } #else if (shaderValue >= 1.1f) { Caps.Version = Versions.GL2; FileTag = "GL2_"; Caps.MaxShaderVersion = ShaderVersions.GLSL_1_10; } if (shaderValue >= 1.2f) { Caps.Version = Versions.GL2; FileTag = "GL2_"; Caps.MaxShaderVersion = ShaderVersions.GLSL_1_20; } // GL3 not supported in GLSL 1.30 becuase 'gl_InstanceID' only exists in GLSL 1.40 /*if (shaderValue >= 1.3f) * { * Caps.Version = Versions.GL3; * IShader.FileTag = "GL3_"; * Caps.MaxShaderVersion = ShaderVersions.GLSL_1_30; * }*/ if (shaderValue >= 1.4f) { Caps.Version = Versions.GL3; FileTag = "GL3_"; Caps.MaxShaderVersion = ShaderVersions.GLSL_1_40; } if (shaderValue >= 1.5f) { Caps.Version = Versions.GL3; FileTag = "GL3_"; Caps.MaxShaderVersion = ShaderVersions.GLSL_1_50; } if (shaderValue >= 3.3f) { Caps.Version = Versions.GL3; FileTag = "GL3_"; Caps.MaxShaderVersion = ShaderVersions.GLSL_3_30; } //if (shaderValue >= 4.0f) Caps.MaxShaderVersion = ShaderVersions.GLSL_4_00; //if (shaderValue >= 4.1f) Caps.MaxShaderVersion = ShaderVersions.GLSL_4_10; //if (shaderValue >= 4.2f) Caps.MaxShaderVersion = ShaderVersions.GLSL_4_20; #endif if (Caps.Version == Versions.GL1) { Debug.ThrowError("Video", "OpenGL 2 or higher is required.\nAre your video card drivers up to date?"); } byte * extensionsPtr = GL.GetString(GL.EXTENSIONS); string extensionValues = ""; while (extensionsPtr != null && extensionsPtr[0] != 0) { extensionValues += (char)extensionsPtr[0]; extensionsPtr++; } var extensions = extensionValues.Split(' '); foreach (var ext in extensions) { switch (ext) { case "GL_instanced_arrays": Caps.HardwareInstancing = true; break; case "GL_ARB_instanced_arrays": Caps.HardwareInstancing = true; break; case "GL_EXT_texture_compression_s3tc": Caps.TextureCompression_S3TC = true; break; case "GL_AMD_compressed_ATC_texture": Caps.TextureCompression_ATC = true; break; case "GL_ATI_texture_compression_atitc": Caps.TextureCompression_ATC = true; break; case "GL_IMG_texture_compression_pvrtc": Caps.TextureCompression_PVR = true; break; } //Console.WriteLine(ext); } } checkForError(); // Init Ext GL.Init(); } catch (Exception e) { Dispose(); throw e; } }